github.com/flowerwrong/netstack@v0.0.0-20191009141956-e5848263af28/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/FlowerWrong/netstack/tcpip"
    21  	"github.com/FlowerWrong/netstack/tcpip/buffer"
    22  )
    23  
    24  // ICMPv6 represents an ICMPv6 header stored in a byte array.
    25  type ICMPv6 []byte
    26  
    27  const (
    28  	// ICMPv6MinimumSize is the minimum size of a valid ICMP packet.
    29  	ICMPv6MinimumSize = 8
    30  
    31  	// ICMPv6PayloadOffset is the offset of the payload in an
    32  	// ICMP packet.
    33  	ICMPv6PayloadOffset = 8
    34  
    35  	// ICMPv6ProtocolNumber is the ICMP transport protocol number.
    36  	ICMPv6ProtocolNumber tcpip.TransportProtocolNumber = 58
    37  
    38  	// ICMPv6NeighborSolicitMinimumSize is the minimum size of a
    39  	// neighbor solicitation packet.
    40  	ICMPv6NeighborSolicitMinimumSize = ICMPv6MinimumSize + 16
    41  
    42  	// ICMPv6NeighborAdvertSize is size of a neighbor advertisement.
    43  	ICMPv6NeighborAdvertSize = 32
    44  
    45  	// ICMPv6EchoMinimumSize is the minimum size of a valid ICMP echo packet.
    46  	ICMPv6EchoMinimumSize = 8
    47  
    48  	// ICMPv6DstUnreachableMinimumSize is the minimum size of a valid ICMP
    49  	// destination unreachable packet.
    50  	ICMPv6DstUnreachableMinimumSize = ICMPv6MinimumSize
    51  
    52  	// ICMPv6PacketTooBigMinimumSize is the minimum size of a valid ICMP
    53  	// packet-too-big packet.
    54  	ICMPv6PacketTooBigMinimumSize = ICMPv6MinimumSize
    55  
    56  	// icmpv6ChecksumOffset is the offset of the checksum field
    57  	// in an ICMPv6 message.
    58  	icmpv6ChecksumOffset = 2
    59  
    60  	// icmpv6MTUOffset is the offset of the MTU field in an ICMPv6
    61  	// PacketTooBig message.
    62  	icmpv6MTUOffset = 4
    63  
    64  	// icmpv6IdentOffset is the offset of the ident field
    65  	// in a ICMPv6 Echo Request/Reply message.
    66  	icmpv6IdentOffset = 4
    67  
    68  	// icmpv6SequenceOffset is the offset of the sequence field
    69  	// in a ICMPv6 Echo Request/Reply message.
    70  	icmpv6SequenceOffset = 6
    71  )
    72  
    73  // ICMPv6Type is the ICMP type field described in RFC 4443 and friends.
    74  type ICMPv6Type byte
    75  
    76  // Typical values of ICMPv6Type defined in RFC 4443.
    77  const (
    78  	ICMPv6DstUnreachable ICMPv6Type = 1
    79  	ICMPv6PacketTooBig   ICMPv6Type = 2
    80  	ICMPv6TimeExceeded   ICMPv6Type = 3
    81  	ICMPv6ParamProblem   ICMPv6Type = 4
    82  	ICMPv6EchoRequest    ICMPv6Type = 128
    83  	ICMPv6EchoReply      ICMPv6Type = 129
    84  
    85  	// Neighbor Discovery Protocol (NDP) messages, see RFC 4861.
    86  
    87  	ICMPv6RouterSolicit   ICMPv6Type = 133
    88  	ICMPv6RouterAdvert    ICMPv6Type = 134
    89  	ICMPv6NeighborSolicit ICMPv6Type = 135
    90  	ICMPv6NeighborAdvert  ICMPv6Type = 136
    91  	ICMPv6RedirectMsg     ICMPv6Type = 137
    92  )
    93  
    94  // Values for ICMP code as defined in RFC 4443.
    95  const (
    96  	ICMPv6PortUnreachable = 4
    97  )
    98  
    99  // Type is the ICMP type field.
   100  func (b ICMPv6) Type() ICMPv6Type { return ICMPv6Type(b[0]) }
   101  
   102  // SetType sets the ICMP type field.
   103  func (b ICMPv6) SetType(t ICMPv6Type) { b[0] = byte(t) }
   104  
   105  // Code is the ICMP code field. Its meaning depends on the value of Type.
   106  func (b ICMPv6) Code() byte { return b[1] }
   107  
   108  // SetCode sets the ICMP code field.
   109  func (b ICMPv6) SetCode(c byte) { b[1] = c }
   110  
   111  // Checksum is the ICMP checksum field.
   112  func (b ICMPv6) Checksum() uint16 {
   113  	return binary.BigEndian.Uint16(b[icmpv6ChecksumOffset:])
   114  }
   115  
   116  // SetChecksum calculates and sets the ICMP checksum field.
   117  func (b ICMPv6) SetChecksum(checksum uint16) {
   118  	binary.BigEndian.PutUint16(b[icmpv6ChecksumOffset:], checksum)
   119  }
   120  
   121  // SourcePort implements Transport.SourcePort.
   122  func (ICMPv6) SourcePort() uint16 {
   123  	return 0
   124  }
   125  
   126  // DestinationPort implements Transport.DestinationPort.
   127  func (ICMPv6) DestinationPort() uint16 {
   128  	return 0
   129  }
   130  
   131  // SetSourcePort implements Transport.SetSourcePort.
   132  func (ICMPv6) SetSourcePort(uint16) {
   133  }
   134  
   135  // SetDestinationPort implements Transport.SetDestinationPort.
   136  func (ICMPv6) SetDestinationPort(uint16) {
   137  }
   138  
   139  // MTU retrieves the MTU field from an ICMPv6 message.
   140  func (b ICMPv6) MTU() uint32 {
   141  	return binary.BigEndian.Uint32(b[icmpv6MTUOffset:])
   142  }
   143  
   144  // SetMTU sets the MTU field from an ICMPv6 message.
   145  func (b ICMPv6) SetMTU(mtu uint32) {
   146  	binary.BigEndian.PutUint32(b[icmpv6MTUOffset:], mtu)
   147  }
   148  
   149  // Ident retrieves the Ident field from an ICMPv6 message.
   150  func (b ICMPv6) Ident() uint16 {
   151  	return binary.BigEndian.Uint16(b[icmpv6IdentOffset:])
   152  }
   153  
   154  // SetIdent sets the Ident field from an ICMPv6 message.
   155  func (b ICMPv6) SetIdent(ident uint16) {
   156  	binary.BigEndian.PutUint16(b[icmpv6IdentOffset:], ident)
   157  }
   158  
   159  // Sequence retrieves the Sequence field from an ICMPv6 message.
   160  func (b ICMPv6) Sequence() uint16 {
   161  	return binary.BigEndian.Uint16(b[icmpv6SequenceOffset:])
   162  }
   163  
   164  // SetSequence sets the Sequence field from an ICMPv6 message.
   165  func (b ICMPv6) SetSequence(sequence uint16) {
   166  	binary.BigEndian.PutUint16(b[icmpv6SequenceOffset:], sequence)
   167  }
   168  
   169  // Payload implements Transport.Payload.
   170  func (b ICMPv6) Payload() []byte {
   171  	return b[ICMPv6PayloadOffset:]
   172  }
   173  
   174  // ICMPv6Checksum calculates the ICMP checksum over the provided ICMP header,
   175  // IPv6 src/dst addresses and the payload.
   176  func ICMPv6Checksum(h ICMPv6, src, dst tcpip.Address, vv buffer.VectorisedView) uint16 {
   177  	// Calculate the IPv6 pseudo-header upper-layer checksum.
   178  	xsum := Checksum([]byte(src), 0)
   179  	xsum = Checksum([]byte(dst), xsum)
   180  	var upperLayerLength [4]byte
   181  	binary.BigEndian.PutUint32(upperLayerLength[:], uint32(len(h)+vv.Size()))
   182  	xsum = Checksum(upperLayerLength[:], xsum)
   183  	xsum = Checksum([]byte{0, 0, 0, uint8(ICMPv6ProtocolNumber)}, xsum)
   184  	for _, v := range vv.Views() {
   185  		xsum = Checksum(v, xsum)
   186  	}
   187  
   188  	// h[2:4] is the checksum itself, set it aside to avoid checksumming the checksum.
   189  	h2, h3 := h[2], h[3]
   190  	h[2], h[3] = 0, 0
   191  	xsum = ^Checksum(h, xsum)
   192  	h[2], h[3] = h2, h3
   193  
   194  	return xsum
   195  }