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