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

     1  // Copyright 2018 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  
    20  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip"
    21  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip/checksum"
    22  )
    23  
    24  // ICMPv6 represents an ICMPv6 header stored in a byte array.
    25  type ICMPv6 []byte
    26  
    27  const (
    28  	// ICMPv6HeaderSize is the size of the ICMPv6 header. That is, the
    29  	// sum of the size of the ICMPv6 Type, Code and Checksum fields, as
    30  	// per RFC 4443 section 2.1. After the ICMPv6 header, the ICMPv6
    31  	// message body begins.
    32  	ICMPv6HeaderSize = 4
    33  
    34  	// ICMPv6MinimumSize is the minimum size of a valid ICMP packet.
    35  	ICMPv6MinimumSize = 8
    36  
    37  	// ICMPv6PayloadOffset is the offset of the payload in an
    38  	// ICMP packet.
    39  	ICMPv6PayloadOffset = 8
    40  
    41  	// ICMPv6ProtocolNumber is the ICMP transport protocol number.
    42  	ICMPv6ProtocolNumber tcpip.TransportProtocolNumber = 58
    43  
    44  	// ICMPv6NeighborSolicitMinimumSize is the minimum size of a
    45  	// neighbor solicitation packet.
    46  	ICMPv6NeighborSolicitMinimumSize = ICMPv6HeaderSize + NDPNSMinimumSize
    47  
    48  	// ICMPv6NeighborAdvertMinimumSize is the minimum size of a
    49  	// neighbor advertisement packet.
    50  	ICMPv6NeighborAdvertMinimumSize = ICMPv6HeaderSize + NDPNAMinimumSize
    51  
    52  	// ICMPv6EchoMinimumSize is the minimum size of a valid echo packet.
    53  	ICMPv6EchoMinimumSize = 8
    54  
    55  	// ICMPv6ErrorHeaderSize is the size of an ICMP error packet header,
    56  	// as per RFC 4443, Apendix A, item 4 and the errata.
    57  	//   ... all ICMP error messages shall have exactly
    58  	//   32 bits of type-specific data, so that receivers can reliably find
    59  	//   the embedded invoking packet even when they don't recognize the
    60  	//   ICMP message Type.
    61  	ICMPv6ErrorHeaderSize = 8
    62  
    63  	// ICMPv6DstUnreachableMinimumSize is the minimum size of a valid ICMP
    64  	// destination unreachable packet.
    65  	ICMPv6DstUnreachableMinimumSize = ICMPv6MinimumSize
    66  
    67  	// ICMPv6PacketTooBigMinimumSize is the minimum size of a valid ICMP
    68  	// packet-too-big packet.
    69  	ICMPv6PacketTooBigMinimumSize = ICMPv6MinimumSize
    70  
    71  	// ICMPv6ChecksumOffset is the offset of the checksum field
    72  	// in an ICMPv6 message.
    73  	ICMPv6ChecksumOffset = 2
    74  
    75  	// icmpv6PointerOffset is the offset of the pointer
    76  	// in an ICMPv6 Parameter problem message.
    77  	icmpv6PointerOffset = 4
    78  
    79  	// icmpv6MTUOffset is the offset of the MTU field in an ICMPv6
    80  	// PacketTooBig message.
    81  	icmpv6MTUOffset = 4
    82  
    83  	// icmpv6IdentOffset is the offset of the ident field
    84  	// in a ICMPv6 Echo Request/Reply message.
    85  	icmpv6IdentOffset = 4
    86  
    87  	// icmpv6SequenceOffset is the offset of the sequence field
    88  	// in a ICMPv6 Echo Request/Reply message.
    89  	icmpv6SequenceOffset = 6
    90  
    91  	// NDPHopLimit is the expected IP hop limit value of 255 for received
    92  	// NDP packets, as per RFC 4861 sections 4.1 - 4.5, 6.1.1, 6.1.2, 7.1.1,
    93  	// 7.1.2 and 8.1. If the hop limit value is not 255, nodes MUST silently
    94  	// drop the NDP packet. All outgoing NDP packets must use this value for
    95  	// its IP hop limit field.
    96  	NDPHopLimit = 255
    97  )
    98  
    99  // ICMPv6Type is the ICMP type field described in RFC 4443.
   100  type ICMPv6Type byte
   101  
   102  // Values for use in the Type field of ICMPv6 packet from RFC 4433.
   103  const (
   104  	ICMPv6DstUnreachable ICMPv6Type = 1
   105  	ICMPv6PacketTooBig   ICMPv6Type = 2
   106  	ICMPv6TimeExceeded   ICMPv6Type = 3
   107  	ICMPv6ParamProblem   ICMPv6Type = 4
   108  	ICMPv6EchoRequest    ICMPv6Type = 128
   109  	ICMPv6EchoReply      ICMPv6Type = 129
   110  
   111  	// Neighbor Discovery Protocol (NDP) messages, see RFC 4861.
   112  
   113  	ICMPv6RouterSolicit   ICMPv6Type = 133
   114  	ICMPv6RouterAdvert    ICMPv6Type = 134
   115  	ICMPv6NeighborSolicit ICMPv6Type = 135
   116  	ICMPv6NeighborAdvert  ICMPv6Type = 136
   117  	ICMPv6RedirectMsg     ICMPv6Type = 137
   118  
   119  	// Multicast Listener Discovery (MLD) messages, see RFC 2710.
   120  
   121  	ICMPv6MulticastListenerQuery  ICMPv6Type = 130
   122  	ICMPv6MulticastListenerReport ICMPv6Type = 131
   123  	ICMPv6MulticastListenerDone   ICMPv6Type = 132
   124  
   125  	// Multicast Listener Discovert Version 2 (MLDv2) messages, see RFC 3810.
   126  
   127  	ICMPv6MulticastListenerV2Report ICMPv6Type = 143
   128  )
   129  
   130  // IsErrorType returns true if the receiver is an ICMP error type.
   131  func (typ ICMPv6Type) IsErrorType() bool {
   132  	// Per RFC 4443 section 2.1:
   133  	//   ICMPv6 messages are grouped into two classes: error messages and
   134  	//   informational messages.  Error messages are identified as such by a
   135  	//   zero in the high-order bit of their message Type field values.  Thus,
   136  	//   error messages have message types from 0 to 127; informational
   137  	//   messages have message types from 128 to 255.
   138  	return typ&0x80 == 0
   139  }
   140  
   141  // ICMPv6Code is the ICMP Code field described in RFC 4443.
   142  type ICMPv6Code byte
   143  
   144  // ICMP codes used with Destination Unreachable (Type 1). As per RFC 4443
   145  // section 3.1.
   146  const (
   147  	ICMPv6NetworkUnreachable ICMPv6Code = 0
   148  	ICMPv6Prohibited         ICMPv6Code = 1
   149  	ICMPv6BeyondScope        ICMPv6Code = 2
   150  	ICMPv6AddressUnreachable ICMPv6Code = 3
   151  	ICMPv6PortUnreachable    ICMPv6Code = 4
   152  	ICMPv6Policy             ICMPv6Code = 5
   153  	ICMPv6RejectRoute        ICMPv6Code = 6
   154  )
   155  
   156  // ICMP codes used with Time Exceeded (Type 3). As per RFC 4443 section 3.3.
   157  const (
   158  	ICMPv6HopLimitExceeded  ICMPv6Code = 0
   159  	ICMPv6ReassemblyTimeout ICMPv6Code = 1
   160  )
   161  
   162  // ICMP codes used with Parameter Problem (Type 4). As per RFC 4443 section 3.4.
   163  const (
   164  	// ICMPv6ErroneousHeader indicates an erroneous header field was encountered.
   165  	ICMPv6ErroneousHeader ICMPv6Code = 0
   166  
   167  	// ICMPv6UnknownHeader indicates an unrecognized Next Header type encountered.
   168  	ICMPv6UnknownHeader ICMPv6Code = 1
   169  
   170  	// ICMPv6UnknownOption indicates an unrecognized IPv6 option was encountered.
   171  	ICMPv6UnknownOption ICMPv6Code = 2
   172  )
   173  
   174  // ICMPv6UnusedCode is the code value used with ICMPv6 messages which don't use
   175  // the code field. (Types not mentioned above.)
   176  const ICMPv6UnusedCode ICMPv6Code = 0
   177  
   178  // Type is the ICMP type field.
   179  func (b ICMPv6) Type() ICMPv6Type { return ICMPv6Type(b[0]) }
   180  
   181  // SetType sets the ICMP type field.
   182  func (b ICMPv6) SetType(t ICMPv6Type) { b[0] = byte(t) }
   183  
   184  // Code is the ICMP code field. Its meaning depends on the value of Type.
   185  func (b ICMPv6) Code() ICMPv6Code { return ICMPv6Code(b[1]) }
   186  
   187  // SetCode sets the ICMP code field.
   188  func (b ICMPv6) SetCode(c ICMPv6Code) { b[1] = byte(c) }
   189  
   190  // TypeSpecific returns the type specific data field.
   191  func (b ICMPv6) TypeSpecific() uint32 {
   192  	return binary.BigEndian.Uint32(b[icmpv6PointerOffset:])
   193  }
   194  
   195  // SetTypeSpecific sets the type specific data field.
   196  func (b ICMPv6) SetTypeSpecific(val uint32) {
   197  	binary.BigEndian.PutUint32(b[icmpv6PointerOffset:], val)
   198  }
   199  
   200  // Checksum is the ICMP checksum field.
   201  func (b ICMPv6) Checksum() uint16 {
   202  	return binary.BigEndian.Uint16(b[ICMPv6ChecksumOffset:])
   203  }
   204  
   205  // SetChecksum sets the ICMP checksum field.
   206  func (b ICMPv6) SetChecksum(cs uint16) {
   207  	checksum.Put(b[ICMPv6ChecksumOffset:], cs)
   208  }
   209  
   210  // SourcePort implements Transport.SourcePort.
   211  func (ICMPv6) SourcePort() uint16 {
   212  	return 0
   213  }
   214  
   215  // DestinationPort implements Transport.DestinationPort.
   216  func (ICMPv6) DestinationPort() uint16 {
   217  	return 0
   218  }
   219  
   220  // SetSourcePort implements Transport.SetSourcePort.
   221  func (ICMPv6) SetSourcePort(uint16) {
   222  }
   223  
   224  // SetDestinationPort implements Transport.SetDestinationPort.
   225  func (ICMPv6) SetDestinationPort(uint16) {
   226  }
   227  
   228  // MTU retrieves the MTU field from an ICMPv6 message.
   229  func (b ICMPv6) MTU() uint32 {
   230  	return binary.BigEndian.Uint32(b[icmpv6MTUOffset:])
   231  }
   232  
   233  // SetMTU sets the MTU field from an ICMPv6 message.
   234  func (b ICMPv6) SetMTU(mtu uint32) {
   235  	binary.BigEndian.PutUint32(b[icmpv6MTUOffset:], mtu)
   236  }
   237  
   238  // Ident retrieves the Ident field from an ICMPv6 message.
   239  func (b ICMPv6) Ident() uint16 {
   240  	return binary.BigEndian.Uint16(b[icmpv6IdentOffset:])
   241  }
   242  
   243  // SetIdent sets the Ident field from an ICMPv6 message.
   244  func (b ICMPv6) SetIdent(ident uint16) {
   245  	binary.BigEndian.PutUint16(b[icmpv6IdentOffset:], ident)
   246  }
   247  
   248  // SetIdentWithChecksumUpdate sets the Ident field and updates the checksum.
   249  func (b ICMPv6) SetIdentWithChecksumUpdate(new uint16) {
   250  	old := b.Ident()
   251  	b.SetIdent(new)
   252  	b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new))
   253  }
   254  
   255  // Sequence retrieves the Sequence field from an ICMPv6 message.
   256  func (b ICMPv6) Sequence() uint16 {
   257  	return binary.BigEndian.Uint16(b[icmpv6SequenceOffset:])
   258  }
   259  
   260  // SetSequence sets the Sequence field from an ICMPv6 message.
   261  func (b ICMPv6) SetSequence(sequence uint16) {
   262  	binary.BigEndian.PutUint16(b[icmpv6SequenceOffset:], sequence)
   263  }
   264  
   265  // MessageBody returns the message body as defined by RFC 4443 section 2.1; the
   266  // portion of the ICMPv6 buffer after the first ICMPv6HeaderSize bytes.
   267  func (b ICMPv6) MessageBody() []byte {
   268  	return b[ICMPv6HeaderSize:]
   269  }
   270  
   271  // Payload implements Transport.Payload.
   272  func (b ICMPv6) Payload() []byte {
   273  	return b[ICMPv6PayloadOffset:]
   274  }
   275  
   276  // ICMPv6ChecksumParams contains parameters to calculate ICMPv6 checksum.
   277  type ICMPv6ChecksumParams struct {
   278  	Header      ICMPv6
   279  	Src         tcpip.Address
   280  	Dst         tcpip.Address
   281  	PayloadCsum uint16
   282  	PayloadLen  int
   283  }
   284  
   285  // ICMPv6Checksum calculates the ICMP checksum over the provided ICMPv6 header,
   286  // IPv6 src/dst addresses and the payload.
   287  func ICMPv6Checksum(params ICMPv6ChecksumParams) uint16 {
   288  	h := params.Header
   289  
   290  	xsum := PseudoHeaderChecksum(ICMPv6ProtocolNumber, params.Src, params.Dst, uint16(len(h)+params.PayloadLen))
   291  	xsum = checksum.Combine(xsum, params.PayloadCsum)
   292  
   293  	// h[2:4] is the checksum itself, skip it to avoid checksumming the checksum.
   294  	xsum = checksum.Checksum(h[:2], xsum)
   295  	xsum = checksum.Checksum(h[4:], xsum)
   296  
   297  	return ^xsum
   298  }
   299  
   300  // UpdateChecksumPseudoHeaderAddress updates the checksum to reflect an
   301  // updated address in the pseudo header.
   302  func (b ICMPv6) UpdateChecksumPseudoHeaderAddress(old, new tcpip.Address) {
   303  	b.SetChecksum(^checksumUpdate2ByteAlignedAddress(^b.Checksum(), old, new))
   304  }