summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/header/icmpv6.go
blob: 2eef64b4dea274bb65bcbbb8069bd12cc3e67f3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package header

import (
	"encoding/binary"

	"gvisor.dev/gvisor/pkg/tcpip"
	"gvisor.dev/gvisor/pkg/tcpip/buffer"
)

// ICMPv6 represents an ICMPv6 header stored in a byte array.
type ICMPv6 []byte

const (
	// ICMPv6HeaderSize is the size of the ICMPv6 header. That is, the
	// sum of the size of the ICMPv6 Type, Code and Checksum fields, as
	// per RFC 4443 section 2.1. After the ICMPv6 header, the ICMPv6
	// message body begins.
	ICMPv6HeaderSize = 4

	// ICMPv6MinimumSize is the minimum size of a valid ICMP packet.
	ICMPv6MinimumSize = 8

	// ICMPv6PayloadOffset is the offset of the payload in an
	// ICMP packet.
	ICMPv6PayloadOffset = 8

	// ICMPv6ProtocolNumber is the ICMP transport protocol number.
	ICMPv6ProtocolNumber tcpip.TransportProtocolNumber = 58

	// ICMPv6NeighborSolicitMinimumSize is the minimum size of a
	// neighbor solicitation packet.
	ICMPv6NeighborSolicitMinimumSize = ICMPv6HeaderSize + NDPNSMinimumSize

	// ICMPv6NeighborAdvertMinimumSize is the minimum size of a
	// neighbor advertisement packet.
	ICMPv6NeighborAdvertMinimumSize = ICMPv6HeaderSize + NDPNAMinimumSize

	// ICMPv6EchoMinimumSize is the minimum size of a valid echo packet.
	ICMPv6EchoMinimumSize = 8

	// ICMPv6ErrorHeaderSize is the size of an ICMP error packet header,
	// as per RFC 4443, Apendix A, item 4 and the errata.
	//   ... all ICMP error messages shall have exactly
	//   32 bits of type-specific data, so that receivers can reliably find
	//   the embedded invoking packet even when they don't recognize the
	//   ICMP message Type.
	ICMPv6ErrorHeaderSize = 8

	// ICMPv6DstUnreachableMinimumSize is the minimum size of a valid ICMP
	// destination unreachable packet.
	ICMPv6DstUnreachableMinimumSize = ICMPv6MinimumSize

	// ICMPv6PacketTooBigMinimumSize is the minimum size of a valid ICMP
	// packet-too-big packet.
	ICMPv6PacketTooBigMinimumSize = ICMPv6MinimumSize

	// icmpv6ChecksumOffset is the offset of the checksum field
	// in an ICMPv6 message.
	icmpv6ChecksumOffset = 2

	// icmpv6PointerOffset is the offset of the pointer
	// in an ICMPv6 Parameter problem message.
	icmpv6PointerOffset = 4

	// icmpv6MTUOffset is the offset of the MTU field in an ICMPv6
	// PacketTooBig message.
	icmpv6MTUOffset = 4

	// icmpv6IdentOffset is the offset of the ident field
	// in a ICMPv6 Echo Request/Reply message.
	icmpv6IdentOffset = 4

	// icmpv6SequenceOffset is the offset of the sequence field
	// in a ICMPv6 Echo Request/Reply message.
	icmpv6SequenceOffset = 6

	// NDPHopLimit is the expected IP hop limit value of 255 for received
	// NDP packets, as per RFC 4861 sections 4.1 - 4.5, 6.1.1, 6.1.2, 7.1.1,
	// 7.1.2 and 8.1. If the hop limit value is not 255, nodes MUST silently
	// drop the NDP packet. All outgoing NDP packets must use this value for
	// its IP hop limit field.
	NDPHopLimit = 255
)

// ICMPv6Type is the ICMP type field described in RFC 4443.
type ICMPv6Type byte

// Values for use in the Type field of ICMPv6 packet from RFC 4433.
const (
	ICMPv6DstUnreachable ICMPv6Type = 1
	ICMPv6PacketTooBig   ICMPv6Type = 2
	ICMPv6TimeExceeded   ICMPv6Type = 3
	ICMPv6ParamProblem   ICMPv6Type = 4
	ICMPv6EchoRequest    ICMPv6Type = 128
	ICMPv6EchoReply      ICMPv6Type = 129

	// Neighbor Discovery Protocol (NDP) messages, see RFC 4861.

	ICMPv6RouterSolicit   ICMPv6Type = 133
	ICMPv6RouterAdvert    ICMPv6Type = 134
	ICMPv6NeighborSolicit ICMPv6Type = 135
	ICMPv6NeighborAdvert  ICMPv6Type = 136
	ICMPv6RedirectMsg     ICMPv6Type = 137

	// Multicast Listener Discovery (MLD) messages, see RFC 2710.

	ICMPv6MulticastListenerQuery  ICMPv6Type = 130
	ICMPv6MulticastListenerReport ICMPv6Type = 131
	ICMPv6MulticastListenerDone   ICMPv6Type = 132
)

// IsErrorType returns true if the receiver is an ICMP error type.
func (typ ICMPv6Type) IsErrorType() bool {
	// Per RFC 4443 section 2.1:
	//   ICMPv6 messages are grouped into two classes: error messages and
	//   informational messages.  Error messages are identified as such by a
	//   zero in the high-order bit of their message Type field values.  Thus,
	//   error messages have message types from 0 to 127; informational
	//   messages have message types from 128 to 255.
	return typ&0x80 == 0
}

// ICMPv6Code is the ICMP Code field described in RFC 4443.
type ICMPv6Code byte

// ICMP codes used with Destination Unreachable (Type 1). As per RFC 4443
// section 3.1.
const (
	ICMPv6NetworkUnreachable ICMPv6Code = 0
	ICMPv6Prohibited         ICMPv6Code = 1
	ICMPv6BeyondScope        ICMPv6Code = 2
	ICMPv6AddressUnreachable ICMPv6Code = 3
	ICMPv6PortUnreachable    ICMPv6Code = 4
	ICMPv6Policy             ICMPv6Code = 5
	ICMPv6RejectRoute        ICMPv6Code = 6
)

// ICMP codes used with Time Exceeded (Type 3). As per RFC 4443 section 3.3.
const (
	ICMPv6HopLimitExceeded  ICMPv6Code = 0
	ICMPv6ReassemblyTimeout ICMPv6Code = 1
)

// ICMP codes used with Parameter Problem (Type 4). As per RFC 4443 section 3.4.
const (
	// ICMPv6ErroneousHeader indicates an erroneous header field was encountered.
	ICMPv6ErroneousHeader ICMPv6Code = 0

	// ICMPv6UnknownHeader indicates an unrecognized Next Header type encountered.
	ICMPv6UnknownHeader ICMPv6Code = 1

	// ICMPv6UnknownOption indicates an unrecognized IPv6 option was encountered.
	ICMPv6UnknownOption ICMPv6Code = 2
)

// ICMPv6UnusedCode is the code value used with ICMPv6 messages which don't use
// the code field. (Types not mentioned above.)
const ICMPv6UnusedCode ICMPv6Code = 0

// Type is the ICMP type field.
func (b ICMPv6) Type() ICMPv6Type { return ICMPv6Type(b[0]) }

// SetType sets the ICMP type field.
func (b ICMPv6) SetType(t ICMPv6Type) { b[0] = byte(t) }

// Code is the ICMP code field. Its meaning depends on the value of Type.
func (b ICMPv6) Code() ICMPv6Code { return ICMPv6Code(b[1]) }

// SetCode sets the ICMP code field.
func (b ICMPv6) SetCode(c ICMPv6Code) { b[1] = byte(c) }

// TypeSpecific returns the type specific data field.
func (b ICMPv6) TypeSpecific() uint32 {
	return binary.BigEndian.Uint32(b[icmpv6PointerOffset:])
}

// SetTypeSpecific sets the type specific data field.
func (b ICMPv6) SetTypeSpecific(val uint32) {
	binary.BigEndian.PutUint32(b[icmpv6PointerOffset:], val)
}

// Checksum is the ICMP checksum field.
func (b ICMPv6) Checksum() uint16 {
	return binary.BigEndian.Uint16(b[icmpv6ChecksumOffset:])
}

// SetChecksum sets the ICMP checksum field.
func (b ICMPv6) SetChecksum(checksum uint16) {
	binary.BigEndian.PutUint16(b[icmpv6ChecksumOffset:], checksum)
}

// SourcePort implements Transport.SourcePort.
func (ICMPv6) SourcePort() uint16 {
	return 0
}

// DestinationPort implements Transport.DestinationPort.
func (ICMPv6) DestinationPort() uint16 {
	return 0
}

// SetSourcePort implements Transport.SetSourcePort.
func (ICMPv6) SetSourcePort(uint16) {
}

// SetDestinationPort implements Transport.SetDestinationPort.
func (ICMPv6) SetDestinationPort(uint16) {
}

// MTU retrieves the MTU field from an ICMPv6 message.
func (b ICMPv6) MTU() uint32 {
	return binary.BigEndian.Uint32(b[icmpv6MTUOffset:])
}

// SetMTU sets the MTU field from an ICMPv6 message.
func (b ICMPv6) SetMTU(mtu uint32) {
	binary.BigEndian.PutUint32(b[icmpv6MTUOffset:], mtu)
}

// Ident retrieves the Ident field from an ICMPv6 message.
func (b ICMPv6) Ident() uint16 {
	return binary.BigEndian.Uint16(b[icmpv6IdentOffset:])
}

// SetIdent sets the Ident field from an ICMPv6 message.
func (b ICMPv6) SetIdent(ident uint16) {
	binary.BigEndian.PutUint16(b[icmpv6IdentOffset:], ident)
}

// Sequence retrieves the Sequence field from an ICMPv6 message.
func (b ICMPv6) Sequence() uint16 {
	return binary.BigEndian.Uint16(b[icmpv6SequenceOffset:])
}

// SetSequence sets the Sequence field from an ICMPv6 message.
func (b ICMPv6) SetSequence(sequence uint16) {
	binary.BigEndian.PutUint16(b[icmpv6SequenceOffset:], sequence)
}

// MessageBody returns the message body as defined by RFC 4443 section 2.1; the
// portion of the ICMPv6 buffer after the first ICMPv6HeaderSize bytes.
func (b ICMPv6) MessageBody() []byte {
	return b[ICMPv6HeaderSize:]
}

// Payload implements Transport.Payload.
func (b ICMPv6) Payload() []byte {
	return b[ICMPv6PayloadOffset:]
}

// ICMPv6Checksum calculates the ICMP checksum over the provided ICMPv6 header,
// IPv6 src/dst addresses and the payload.
func ICMPv6Checksum(h ICMPv6, src, dst tcpip.Address, vv buffer.VectorisedView) uint16 {
	// Calculate the IPv6 pseudo-header upper-layer checksum.
	xsum := Checksum([]byte(src), 0)
	xsum = Checksum([]byte(dst), xsum)
	var upperLayerLength [4]byte
	binary.BigEndian.PutUint32(upperLayerLength[:], uint32(len(h)+vv.Size()))
	xsum = Checksum(upperLayerLength[:], xsum)
	xsum = Checksum([]byte{0, 0, 0, uint8(ICMPv6ProtocolNumber)}, xsum)
	for _, v := range vv.Views() {
		xsum = Checksum(v, xsum)
	}

	// h[2:4] is the checksum itself, set it aside to avoid checksumming the checksum.
	h2, h3 := h[2], h[3]
	h[2], h[3] = 0, 0
	xsum = ^Checksum(h, xsum)
	h[2], h[3] = h2, h3

	return xsum
}