icmpv4.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  // ICMPv4 represents an ICMPv4 header stored in a byte array.
  25  type ICMPv4 []byte
  26  
  27  const (
  28  	// ICMPv4PayloadOffset defines the start of ICMP payload.
  29  	ICMPv4PayloadOffset = 8
  30  
  31  	// ICMPv4MinimumSize is the minimum size of a valid ICMP packet.
  32  	ICMPv4MinimumSize = 8
  33  
  34  	// ICMPv4MinimumErrorPayloadSize Is the smallest number of bytes of an
  35  	// errant packet's transport layer that an ICMP error type packet should
  36  	// attempt to send as per RFC 792 (see each type) and RFC 1122
  37  	// section 3.2.2 which states:
  38  	//      Every ICMP error message includes the Internet header and at
  39  	//      least the first 8 data octets of the datagram that triggered
  40  	//      the error; more than 8 octets MAY be sent; this header and data
  41  	//      MUST be unchanged from the received datagram.
  42  	//
  43  	// RFC 792 shows:
  44  	//   0                   1                   2                   3
  45  	//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  46  	// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  47  	// |     Type      |     Code      |          Checksum             |
  48  	// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  49  	// |                             unused                            |
  50  	// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  51  	// |      Internet Header + 64 bits of Original Data Datagram      |
  52  	// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  53  	ICMPv4MinimumErrorPayloadSize = 8
  54  
  55  	// ICMPv4ProtocolNumber is the ICMP transport protocol number.
  56  	ICMPv4ProtocolNumber tcpip.TransportProtocolNumber = 1
  57  
  58  	// icmpv4ChecksumOffset is the offset of the checksum field
  59  	// in an ICMPv4 message.
  60  	icmpv4ChecksumOffset = 2
  61  
  62  	// icmpv4MTUOffset is the offset of the MTU field
  63  	// in an ICMPv4FragmentationNeeded message.
  64  	icmpv4MTUOffset = 6
  65  
  66  	// icmpv4IdentOffset is the offset of the ident field
  67  	// in an ICMPv4EchoRequest/Reply message.
  68  	icmpv4IdentOffset = 4
  69  
  70  	// icmpv4PointerOffset is the offset of the pointer field
  71  	// in an ICMPv4ParamProblem message.
  72  	icmpv4PointerOffset = 4
  73  
  74  	// icmpv4SequenceOffset is the offset of the sequence field
  75  	// in an ICMPv4EchoRequest/Reply message.
  76  	icmpv4SequenceOffset = 6
  77  )
  78  
  79  // ICMPv4Type is the ICMP type field described in RFC 792.
  80  type ICMPv4Type byte
  81  
  82  // ICMPv4Code is the ICMP code field described in RFC 792.
  83  type ICMPv4Code byte
  84  
  85  // Typical values of ICMPv4Type defined in RFC 792.
  86  const (
  87  	ICMPv4EchoReply      ICMPv4Type = 0
  88  	ICMPv4DstUnreachable ICMPv4Type = 3
  89  	ICMPv4SrcQuench      ICMPv4Type = 4
  90  	ICMPv4Redirect       ICMPv4Type = 5
  91  	ICMPv4Echo           ICMPv4Type = 8
  92  	ICMPv4TimeExceeded   ICMPv4Type = 11
  93  	ICMPv4ParamProblem   ICMPv4Type = 12
  94  	ICMPv4Timestamp      ICMPv4Type = 13
  95  	ICMPv4TimestampReply ICMPv4Type = 14
  96  	ICMPv4InfoRequest    ICMPv4Type = 15
  97  	ICMPv4InfoReply      ICMPv4Type = 16
  98  )
  99  
 100  // ICMP codes for ICMPv4 Time Exceeded messages as defined in RFC 792.
 101  const (
 102  	ICMPv4TTLExceeded       ICMPv4Code = 0
 103  	ICMPv4ReassemblyTimeout ICMPv4Code = 1
 104  )
 105  
 106  // ICMP codes for ICMPv4 Destination Unreachable messages as defined in RFC 792,
 107  // RFC 1122 section 3.2.2.1 and RFC 1812 section 5.2.7.1.
 108  const (
 109  	ICMPv4NetUnreachable            ICMPv4Code = 0
 110  	ICMPv4HostUnreachable           ICMPv4Code = 1
 111  	ICMPv4ProtoUnreachable          ICMPv4Code = 2
 112  	ICMPv4PortUnreachable           ICMPv4Code = 3
 113  	ICMPv4FragmentationNeeded       ICMPv4Code = 4
 114  	ICMPv4SourceRouteFailed         ICMPv4Code = 5
 115  	ICMPv4DestinationNetworkUnknown ICMPv4Code = 6
 116  	ICMPv4DestinationHostUnknown    ICMPv4Code = 7
 117  	ICMPv4SourceHostIsolated        ICMPv4Code = 8
 118  	ICMPv4NetProhibited             ICMPv4Code = 9
 119  	ICMPv4HostProhibited            ICMPv4Code = 10
 120  	ICMPv4NetUnreachableForTos      ICMPv4Code = 11
 121  	ICMPv4HostUnreachableForTos     ICMPv4Code = 12
 122  	ICMPv4AdminProhibited           ICMPv4Code = 13
 123  	ICMPv4HostPrecedenceViolation   ICMPv4Code = 14
 124  	ICMPv4PrecedenceCutInEffect     ICMPv4Code = 15
 125  )
 126  
 127  // ICMPv4UnusedCode is a code to use in ICMP messages where no code is needed.
 128  const ICMPv4UnusedCode ICMPv4Code = 0
 129  
 130  // Type is the ICMP type field.
 131  func (b ICMPv4) Type() ICMPv4Type { return ICMPv4Type(b[0]) }
 132  
 133  // SetType sets the ICMP type field.
 134  func (b ICMPv4) SetType(t ICMPv4Type) { b[0] = byte(t) }
 135  
 136  // Code is the ICMP code field. Its meaning depends on the value of Type.
 137  func (b ICMPv4) Code() ICMPv4Code { return ICMPv4Code(b[1]) }
 138  
 139  // SetCode sets the ICMP code field.
 140  func (b ICMPv4) SetCode(c ICMPv4Code) { b[1] = byte(c) }
 141  
 142  // Pointer returns the pointer field in a Parameter Problem packet.
 143  func (b ICMPv4) Pointer() byte { return b[icmpv4PointerOffset] }
 144  
 145  // SetPointer sets the pointer field in a Parameter Problem packet.
 146  func (b ICMPv4) SetPointer(c byte) { b[icmpv4PointerOffset] = c }
 147  
 148  // Checksum is the ICMP checksum field.
 149  func (b ICMPv4) Checksum() uint16 {
 150  	return binary.BigEndian.Uint16(b[icmpv4ChecksumOffset:])
 151  }
 152  
 153  // SetChecksum sets the ICMP checksum field.
 154  func (b ICMPv4) SetChecksum(cs uint16) {
 155  	checksum.Put(b[icmpv4ChecksumOffset:], cs)
 156  }
 157  
 158  // SourcePort implements Transport.SourcePort.
 159  func (ICMPv4) SourcePort() uint16 {
 160  	return 0
 161  }
 162  
 163  // DestinationPort implements Transport.DestinationPort.
 164  func (ICMPv4) DestinationPort() uint16 {
 165  	return 0
 166  }
 167  
 168  // SetSourcePort implements Transport.SetSourcePort.
 169  func (ICMPv4) SetSourcePort(uint16) {
 170  }
 171  
 172  // SetDestinationPort implements Transport.SetDestinationPort.
 173  func (ICMPv4) SetDestinationPort(uint16) {
 174  }
 175  
 176  // Payload implements Transport.Payload.
 177  func (b ICMPv4) Payload() []byte {
 178  	return b[ICMPv4PayloadOffset:]
 179  }
 180  
 181  // MTU retrieves the MTU field from an ICMPv4 message.
 182  func (b ICMPv4) MTU() uint16 {
 183  	return binary.BigEndian.Uint16(b[icmpv4MTUOffset:])
 184  }
 185  
 186  // SetMTU sets the MTU field from an ICMPv4 message.
 187  func (b ICMPv4) SetMTU(mtu uint16) {
 188  	binary.BigEndian.PutUint16(b[icmpv4MTUOffset:], mtu)
 189  }
 190  
 191  // Ident retrieves the Ident field from an ICMPv4 message.
 192  func (b ICMPv4) Ident() uint16 {
 193  	return binary.BigEndian.Uint16(b[icmpv4IdentOffset:])
 194  }
 195  
 196  // SetIdent sets the Ident field from an ICMPv4 message.
 197  func (b ICMPv4) SetIdent(ident uint16) {
 198  	binary.BigEndian.PutUint16(b[icmpv4IdentOffset:], ident)
 199  }
 200  
 201  // SetIdentWithChecksumUpdate sets the Ident field and updates the checksum.
 202  func (b ICMPv4) SetIdentWithChecksumUpdate(new uint16) {
 203  	old := b.Ident()
 204  	b.SetIdent(new)
 205  	b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new))
 206  }
 207  
 208  // Sequence retrieves the Sequence field from an ICMPv4 message.
 209  func (b ICMPv4) Sequence() uint16 {
 210  	return binary.BigEndian.Uint16(b[icmpv4SequenceOffset:])
 211  }
 212  
 213  // SetSequence sets the Sequence field from an ICMPv4 message.
 214  func (b ICMPv4) SetSequence(sequence uint16) {
 215  	binary.BigEndian.PutUint16(b[icmpv4SequenceOffset:], sequence)
 216  }
 217  
 218  // ICMPv4Checksum calculates the ICMP checksum over the provided ICMP header,
 219  // and payload.
 220  func ICMPv4Checksum(h ICMPv4, payloadCsum uint16) uint16 {
 221  	xsum := payloadCsum
 222  
 223  	// h[2:4] is the checksum itself, skip it to avoid checksumming the checksum.
 224  	xsum = checksum.Checksum(h[:2], xsum)
 225  	xsum = checksum.Checksum(h[4:], xsum)
 226  
 227  	return ^xsum
 228  }
 229