igmp.go raw

   1  // Copyright 2020 The gVisor Authors.
   2  //
   3  // Licensed under the Apache License, Version 2.0 (the "License");
   4  // you may not use this file except in compliance with the License.
   5  // You may obtain a copy of the License at
   6  //
   7  //     http://www.apache.org/licenses/LICENSE-2.0
   8  //
   9  // Unless required by applicable law or agreed to in writing, software
  10  // distributed under the License is distributed on an "AS IS" BASIS,
  11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12  // See the License for the specific language governing permissions and
  13  // limitations under the License.
  14  
  15  package header
  16  
  17  import (
  18  	"encoding/binary"
  19  	"fmt"
  20  	"time"
  21  
  22  	"gvisor.dev/gvisor/pkg/tcpip"
  23  	"gvisor.dev/gvisor/pkg/tcpip/checksum"
  24  )
  25  
  26  // IGMP represents an IGMP header stored in a byte array.
  27  type IGMP []byte
  28  
  29  // IGMP implements `Transport`.
  30  var _ Transport = (*IGMP)(nil)
  31  
  32  const (
  33  	// IGMPMinimumSize is the minimum size of a valid IGMP packet in bytes,
  34  	// as per RFC 2236, Section 2, Page 2.
  35  	IGMPMinimumSize = 8
  36  
  37  	// IGMPQueryMinimumSize is the minimum size of a valid Membership Query
  38  	// Message in bytes, as per RFC 2236, Section 2, Page 2.
  39  	IGMPQueryMinimumSize = 8
  40  
  41  	// IGMPReportMinimumSize is the minimum size of a valid Report Message in
  42  	// bytes, as per RFC 2236, Section 2, Page 2.
  43  	IGMPReportMinimumSize = 8
  44  
  45  	// IGMPLeaveMessageMinimumSize is the minimum size of a valid Leave Message
  46  	// in bytes, as per RFC 2236, Section 2, Page 2.
  47  	IGMPLeaveMessageMinimumSize = 8
  48  
  49  	// IGMPTTL is the TTL for all IGMP messages, as per RFC 2236, Section 3, Page
  50  	// 3.
  51  	IGMPTTL = 1
  52  
  53  	// igmpTypeOffset defines the offset of the type field in an IGMP message.
  54  	igmpTypeOffset = 0
  55  
  56  	// igmpMaxRespTimeOffset defines the offset of the MaxRespTime field in an
  57  	// IGMP message.
  58  	igmpMaxRespTimeOffset = 1
  59  
  60  	// igmpChecksumOffset defines the offset of the checksum field in an IGMP
  61  	// message.
  62  	igmpChecksumOffset = 2
  63  
  64  	// igmpGroupAddressOffset defines the offset of the Group Address field in an
  65  	// IGMP message.
  66  	igmpGroupAddressOffset = 4
  67  
  68  	// IGMPProtocolNumber is IGMP's transport protocol number.
  69  	IGMPProtocolNumber tcpip.TransportProtocolNumber = 2
  70  )
  71  
  72  // IGMPType is the IGMP type field as per RFC 2236.
  73  type IGMPType byte
  74  
  75  // Values for the IGMP Type described in RFC 2236 Section 2.1, Page 2.
  76  // Descriptions below come from there.
  77  const (
  78  	// IGMPMembershipQuery indicates that the message type is Membership Query.
  79  	// "There are two sub-types of Membership Query messages:
  80  	//	- General Query, used to learn which groups have members on an
  81  	//		attached network.
  82  	//	- Group-Specific Query, used to learn if a particular group
  83  	//		has any members on an attached network.
  84  	// These two messages are differentiated by the Group Address, as
  85  	// described in section 1.4 ."
  86  	IGMPMembershipQuery IGMPType = 0x11
  87  	// IGMPv1MembershipReport indicates that the message is a Membership Report
  88  	// generated by a host using the IGMPv1 protocol: "an additional type of
  89  	// message, for backwards-compatibility with IGMPv1"
  90  	IGMPv1MembershipReport IGMPType = 0x12
  91  	// IGMPv2MembershipReport indicates that the Message type is a Membership
  92  	// Report generated by a host using the IGMPv2 protocol.
  93  	IGMPv2MembershipReport IGMPType = 0x16
  94  	// IGMPLeaveGroup indicates that the message type is a Leave Group
  95  	// notification message.
  96  	IGMPLeaveGroup IGMPType = 0x17
  97  	// IGMPv3MembershipReport indicates that the message type is a IGMPv3 report.
  98  	IGMPv3MembershipReport IGMPType = 0x22
  99  )
 100  
 101  // Type is the IGMP type field.
 102  func (b IGMP) Type() IGMPType { return IGMPType(b[igmpTypeOffset]) }
 103  
 104  // SetType sets the IGMP type field.
 105  func (b IGMP) SetType(t IGMPType) { b[igmpTypeOffset] = byte(t) }
 106  
 107  // MaxRespTime gets the MaxRespTimeField. This is meaningful only in Membership
 108  // Query messages, in other cases it is set to 0 by the sender and ignored by
 109  // the receiver.
 110  func (b IGMP) MaxRespTime() time.Duration {
 111  	// As per RFC 2236 section 2.2,
 112  	//
 113  	//  The Max Response Time field is meaningful only in Membership Query
 114  	//  messages, and specifies the maximum allowed time before sending a
 115  	//  responding report in units of 1/10 second.  In all other messages, it
 116  	//  is set to zero by the sender and ignored by receivers.
 117  	return DecisecondToDuration(uint16(b[igmpMaxRespTimeOffset]))
 118  }
 119  
 120  // SetMaxRespTime sets the MaxRespTimeField.
 121  func (b IGMP) SetMaxRespTime(m byte) { b[igmpMaxRespTimeOffset] = m }
 122  
 123  // Checksum is the IGMP checksum field.
 124  func (b IGMP) Checksum() uint16 {
 125  	return binary.BigEndian.Uint16(b[igmpChecksumOffset:])
 126  }
 127  
 128  // SetChecksum sets the IGMP checksum field.
 129  func (b IGMP) SetChecksum(checksum uint16) {
 130  	binary.BigEndian.PutUint16(b[igmpChecksumOffset:], checksum)
 131  }
 132  
 133  // GroupAddress gets the Group Address field.
 134  func (b IGMP) GroupAddress() tcpip.Address {
 135  	return tcpip.AddrFrom4([4]byte(b[igmpGroupAddressOffset:][:IPv4AddressSize]))
 136  }
 137  
 138  // SetGroupAddress sets the Group Address field.
 139  func (b IGMP) SetGroupAddress(address tcpip.Address) {
 140  	addrBytes := address.As4()
 141  	if n := copy(b[igmpGroupAddressOffset:], addrBytes[:]); n != IPv4AddressSize {
 142  		panic(fmt.Sprintf("copied %d bytes, expected %d", n, IPv4AddressSize))
 143  	}
 144  }
 145  
 146  // SourcePort implements Transport.SourcePort.
 147  func (IGMP) SourcePort() uint16 {
 148  	return 0
 149  }
 150  
 151  // DestinationPort implements Transport.DestinationPort.
 152  func (IGMP) DestinationPort() uint16 {
 153  	return 0
 154  }
 155  
 156  // SetSourcePort implements Transport.SetSourcePort.
 157  func (IGMP) SetSourcePort(uint16) {
 158  }
 159  
 160  // SetDestinationPort implements Transport.SetDestinationPort.
 161  func (IGMP) SetDestinationPort(uint16) {
 162  }
 163  
 164  // Payload implements Transport.Payload.
 165  func (IGMP) Payload() []byte {
 166  	return nil
 167  }
 168  
 169  // IGMPCalculateChecksum calculates the IGMP checksum over the provided IGMP
 170  // header.
 171  func IGMPCalculateChecksum(h IGMP) uint16 {
 172  	// The header contains a checksum itself, set it aside to avoid checksumming
 173  	// the checksum and replace it afterwards.
 174  	existingXsum := h.Checksum()
 175  	h.SetChecksum(0)
 176  	xsum := ^checksum.Checksum(h, 0)
 177  	h.SetChecksum(existingXsum)
 178  	return xsum
 179  }
 180  
 181  // DecisecondToDuration converts a value representing deci-seconds to a
 182  // time.Duration.
 183  func DecisecondToDuration(ds uint16) time.Duration {
 184  	return time.Duration(ds) * time.Second / 10
 185  }
 186