github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/tcpip/header/igmp.go (about)

     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  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip"
    23  	"github.com/nicocha30/gvisor-ligolo/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  }