// Copyright 2020 The gVisor Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package header import ( "encoding/binary" "fmt" "time" "gvisor.dev/gvisor/pkg/tcpip" ) // IGMP represents an IGMP header stored in a byte array. type IGMP []byte // IGMP implements `Transport`. var _ Transport = (*IGMP)(nil) const ( // IGMPMinimumSize is the minimum size of a valid IGMP packet in bytes, // as per RFC 2236, Section 2, Page 2. IGMPMinimumSize = 8 // IGMPQueryMinimumSize is the minimum size of a valid Membership Query // Message in bytes, as per RFC 2236, Section 2, Page 2. IGMPQueryMinimumSize = 8 // IGMPReportMinimumSize is the minimum size of a valid Report Message in // bytes, as per RFC 2236, Section 2, Page 2. IGMPReportMinimumSize = 8 // IGMPLeaveMessageMinimumSize is the minimum size of a valid Leave Message // in bytes, as per RFC 2236, Section 2, Page 2. IGMPLeaveMessageMinimumSize = 8 // IGMPTTL is the TTL for all IGMP messages, as per RFC 2236, Section 3, Page // 3. IGMPTTL = 1 // igmpTypeOffset defines the offset of the type field in an IGMP message. igmpTypeOffset = 0 // igmpMaxRespTimeOffset defines the offset of the MaxRespTime field in an // IGMP message. igmpMaxRespTimeOffset = 1 // igmpChecksumOffset defines the offset of the checksum field in an IGMP // message. igmpChecksumOffset = 2 // igmpGroupAddressOffset defines the offset of the Group Address field in an // IGMP message. igmpGroupAddressOffset = 4 // IGMPProtocolNumber is IGMP's transport protocol number. IGMPProtocolNumber tcpip.TransportProtocolNumber = 2 ) // IGMPType is the IGMP type field as per RFC 2236. type IGMPType byte // Values for the IGMP Type described in RFC 2236 Section 2.1, Page 2. // Descriptions below come from there. const ( // IGMPMembershipQuery indicates that the message type is Membership Query. // "There are two sub-types of Membership Query messages: // - General Query, used to learn which groups have members on an // attached network. // - Group-Specific Query, used to learn if a particular group // has any members on an attached network. // These two messages are differentiated by the Group Address, as // described in section 1.4 ." IGMPMembershipQuery IGMPType = 0x11 // IGMPv1MembershipReport indicates that the message is a Membership Report // generated by a host using the IGMPv1 protocol: "an additional type of // message, for backwards-compatibility with IGMPv1" IGMPv1MembershipReport IGMPType = 0x12 // IGMPv2MembershipReport indicates that the Message type is a Membership // Report generated by a host using the IGMPv2 protocol. IGMPv2MembershipReport IGMPType = 0x16 // IGMPLeaveGroup indicates that the message type is a Leave Group // notification message. IGMPLeaveGroup IGMPType = 0x17 ) // Type is the IGMP type field. func (b IGMP) Type() IGMPType { return IGMPType(b[igmpTypeOffset]) } // SetType sets the IGMP type field. func (b IGMP) SetType(t IGMPType) { b[igmpTypeOffset] = byte(t) } // MaxRespTime gets the MaxRespTimeField. This is meaningful only in Membership // Query messages, in other cases it is set to 0 by the sender and ignored by // the receiver. func (b IGMP) MaxRespTime() time.Duration { // As per RFC 2236 section 2.2, // // The Max Response Time field is meaningful only in Membership Query // messages, and specifies the maximum allowed time before sending a // responding report in units of 1/10 second. In all other messages, it // is set to zero by the sender and ignored by receivers. return DecisecondToDuration(b[igmpMaxRespTimeOffset]) } // SetMaxRespTime sets the MaxRespTimeField. func (b IGMP) SetMaxRespTime(m byte) { b[igmpMaxRespTimeOffset] = m } // Checksum is the IGMP checksum field. func (b IGMP) Checksum() uint16 { return binary.BigEndian.Uint16(b[igmpChecksumOffset:]) } // SetChecksum sets the IGMP checksum field. func (b IGMP) SetChecksum(checksum uint16) { binary.BigEndian.PutUint16(b[igmpChecksumOffset:], checksum) } // GroupAddress gets the Group Address field. func (b IGMP) GroupAddress() tcpip.Address { return tcpip.Address(b[igmpGroupAddressOffset:][:IPv4AddressSize]) } // SetGroupAddress sets the Group Address field. func (b IGMP) SetGroupAddress(address tcpip.Address) { if n := copy(b[igmpGroupAddressOffset:], address); n != IPv4AddressSize { panic(fmt.Sprintf("copied %d bytes, expected %d", n, IPv4AddressSize)) } } // SourcePort implements Transport.SourcePort. func (IGMP) SourcePort() uint16 { return 0 } // DestinationPort implements Transport.DestinationPort. func (IGMP) DestinationPort() uint16 { return 0 } // SetSourcePort implements Transport.SetSourcePort. func (IGMP) SetSourcePort(uint16) { } // SetDestinationPort implements Transport.SetDestinationPort. func (IGMP) SetDestinationPort(uint16) { } // Payload implements Transport.Payload. func (IGMP) Payload() []byte { return nil } // IGMPCalculateChecksum calculates the IGMP checksum over the provided IGMP // header. func IGMPCalculateChecksum(h IGMP) uint16 { // The header contains a checksum itself, set it aside to avoid checksumming // the checksum and replace it afterwards. existingXsum := h.Checksum() h.SetChecksum(0) xsum := ^Checksum(h, 0) h.SetChecksum(existingXsum) return xsum } // DecisecondToDuration converts a value representing deci-seconds to a // time.Duration. func DecisecondToDuration(ds uint8) time.Duration { return time.Duration(ds) * time.Second / 10 }