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 }