icmpv6.go raw

   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  	"gvisor.dev/gvisor/pkg/tcpip"
  21  	"gvisor.dev/gvisor/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, Appendix 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  }
 305