github.com/google/netstack@v0.0.0-20191123085552-55fcc16cd0eb/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/google/netstack/tcpip"
    21  	"github.com/google/netstack/tcpip/buffer"
    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  	// ICMPv6NeighborAdvertSize is size of a neighbor advertisement
    53  	// including the NDP Target Link Layer option for an Ethernet
    54  	// address.
    55  	ICMPv6NeighborAdvertSize = ICMPv6HeaderSize + NDPNAMinimumSize + ndpTargetEthernetLinkLayerAddressSize
    56  
    57  	// ICMPv6EchoMinimumSize is the minimum size of a valid ICMP echo packet.
    58  	ICMPv6EchoMinimumSize = 8
    59  
    60  	// ICMPv6DstUnreachableMinimumSize is the minimum size of a valid ICMP
    61  	// destination unreachable packet.
    62  	ICMPv6DstUnreachableMinimumSize = ICMPv6MinimumSize
    63  
    64  	// ICMPv6PacketTooBigMinimumSize is the minimum size of a valid ICMP
    65  	// packet-too-big packet.
    66  	ICMPv6PacketTooBigMinimumSize = ICMPv6MinimumSize
    67  
    68  	// icmpv6ChecksumOffset is the offset of the checksum field
    69  	// in an ICMPv6 message.
    70  	icmpv6ChecksumOffset = 2
    71  
    72  	// icmpv6MTUOffset is the offset of the MTU field in an ICMPv6
    73  	// PacketTooBig message.
    74  	icmpv6MTUOffset = 4
    75  
    76  	// icmpv6IdentOffset is the offset of the ident field
    77  	// in a ICMPv6 Echo Request/Reply message.
    78  	icmpv6IdentOffset = 4
    79  
    80  	// icmpv6SequenceOffset is the offset of the sequence field
    81  	// in a ICMPv6 Echo Request/Reply message.
    82  	icmpv6SequenceOffset = 6
    83  
    84  	// NDPHopLimit is the expected IP hop limit value of 255 for received
    85  	// NDP packets, as per RFC 4861 sections 4.1 - 4.5, 6.1.1, 6.1.2, 7.1.1,
    86  	// 7.1.2 and 8.1. If the hop limit value is not 255, nodes MUST silently
    87  	// drop the NDP packet. All outgoing NDP packets must use this value for
    88  	// its IP hop limit field.
    89  	NDPHopLimit = 255
    90  )
    91  
    92  // ICMPv6Type is the ICMP type field described in RFC 4443 and friends.
    93  type ICMPv6Type byte
    94  
    95  // Typical values of ICMPv6Type defined in RFC 4443.
    96  const (
    97  	ICMPv6DstUnreachable ICMPv6Type = 1
    98  	ICMPv6PacketTooBig   ICMPv6Type = 2
    99  	ICMPv6TimeExceeded   ICMPv6Type = 3
   100  	ICMPv6ParamProblem   ICMPv6Type = 4
   101  	ICMPv6EchoRequest    ICMPv6Type = 128
   102  	ICMPv6EchoReply      ICMPv6Type = 129
   103  
   104  	// Neighbor Discovery Protocol (NDP) messages, see RFC 4861.
   105  
   106  	ICMPv6RouterSolicit   ICMPv6Type = 133
   107  	ICMPv6RouterAdvert    ICMPv6Type = 134
   108  	ICMPv6NeighborSolicit ICMPv6Type = 135
   109  	ICMPv6NeighborAdvert  ICMPv6Type = 136
   110  	ICMPv6RedirectMsg     ICMPv6Type = 137
   111  )
   112  
   113  // Values for ICMP code as defined in RFC 4443.
   114  const (
   115  	ICMPv6PortUnreachable = 4
   116  )
   117  
   118  // Type is the ICMP type field.
   119  func (b ICMPv6) Type() ICMPv6Type { return ICMPv6Type(b[0]) }
   120  
   121  // SetType sets the ICMP type field.
   122  func (b ICMPv6) SetType(t ICMPv6Type) { b[0] = byte(t) }
   123  
   124  // Code is the ICMP code field. Its meaning depends on the value of Type.
   125  func (b ICMPv6) Code() byte { return b[1] }
   126  
   127  // SetCode sets the ICMP code field.
   128  func (b ICMPv6) SetCode(c byte) { b[1] = c }
   129  
   130  // Checksum is the ICMP checksum field.
   131  func (b ICMPv6) Checksum() uint16 {
   132  	return binary.BigEndian.Uint16(b[icmpv6ChecksumOffset:])
   133  }
   134  
   135  // SetChecksum sets the ICMP checksum field.
   136  func (b ICMPv6) SetChecksum(checksum uint16) {
   137  	binary.BigEndian.PutUint16(b[icmpv6ChecksumOffset:], checksum)
   138  }
   139  
   140  // SourcePort implements Transport.SourcePort.
   141  func (ICMPv6) SourcePort() uint16 {
   142  	return 0
   143  }
   144  
   145  // DestinationPort implements Transport.DestinationPort.
   146  func (ICMPv6) DestinationPort() uint16 {
   147  	return 0
   148  }
   149  
   150  // SetSourcePort implements Transport.SetSourcePort.
   151  func (ICMPv6) SetSourcePort(uint16) {
   152  }
   153  
   154  // SetDestinationPort implements Transport.SetDestinationPort.
   155  func (ICMPv6) SetDestinationPort(uint16) {
   156  }
   157  
   158  // MTU retrieves the MTU field from an ICMPv6 message.
   159  func (b ICMPv6) MTU() uint32 {
   160  	return binary.BigEndian.Uint32(b[icmpv6MTUOffset:])
   161  }
   162  
   163  // SetMTU sets the MTU field from an ICMPv6 message.
   164  func (b ICMPv6) SetMTU(mtu uint32) {
   165  	binary.BigEndian.PutUint32(b[icmpv6MTUOffset:], mtu)
   166  }
   167  
   168  // Ident retrieves the Ident field from an ICMPv6 message.
   169  func (b ICMPv6) Ident() uint16 {
   170  	return binary.BigEndian.Uint16(b[icmpv6IdentOffset:])
   171  }
   172  
   173  // SetIdent sets the Ident field from an ICMPv6 message.
   174  func (b ICMPv6) SetIdent(ident uint16) {
   175  	binary.BigEndian.PutUint16(b[icmpv6IdentOffset:], ident)
   176  }
   177  
   178  // Sequence retrieves the Sequence field from an ICMPv6 message.
   179  func (b ICMPv6) Sequence() uint16 {
   180  	return binary.BigEndian.Uint16(b[icmpv6SequenceOffset:])
   181  }
   182  
   183  // SetSequence sets the Sequence field from an ICMPv6 message.
   184  func (b ICMPv6) SetSequence(sequence uint16) {
   185  	binary.BigEndian.PutUint16(b[icmpv6SequenceOffset:], sequence)
   186  }
   187  
   188  // NDPPayload returns the NDP payload buffer. That is, it returns the ICMPv6
   189  // packet's message body as defined by RFC 4443 section 2.1; the portion of the
   190  // ICMPv6 buffer after the first ICMPv6HeaderSize bytes.
   191  func (b ICMPv6) NDPPayload() []byte {
   192  	return b[ICMPv6HeaderSize:]
   193  }
   194  
   195  // Payload implements Transport.Payload.
   196  func (b ICMPv6) Payload() []byte {
   197  	return b[ICMPv6PayloadOffset:]
   198  }
   199  
   200  // ICMPv6Checksum calculates the ICMP checksum over the provided ICMPv6 header,
   201  // IPv6 src/dst addresses and the payload.
   202  func ICMPv6Checksum(h ICMPv6, src, dst tcpip.Address, vv buffer.VectorisedView) uint16 {
   203  	// Calculate the IPv6 pseudo-header upper-layer checksum.
   204  	xsum := Checksum([]byte(src), 0)
   205  	xsum = Checksum([]byte(dst), xsum)
   206  	var upperLayerLength [4]byte
   207  	binary.BigEndian.PutUint32(upperLayerLength[:], uint32(len(h)+vv.Size()))
   208  	xsum = Checksum(upperLayerLength[:], xsum)
   209  	xsum = Checksum([]byte{0, 0, 0, uint8(ICMPv6ProtocolNumber)}, xsum)
   210  	for _, v := range vv.Views() {
   211  		xsum = Checksum(v, xsum)
   212  	}
   213  
   214  	// h[2:4] is the checksum itself, set it aside to avoid checksumming the checksum.
   215  	h2, h3 := h[2], h[3]
   216  	h[2], h[3] = 0, 0
   217  	xsum = ^Checksum(h, xsum)
   218  	h[2], h[3] = h2, h3
   219  
   220  	return xsum
   221  }