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