summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/header/ndp_router_advert.go
blob: 7d6efa0837b36f0c6dedb9a3d994ae1e27dd557b (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
// Copyright 2019 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"
	"fmt"
	"time"
)

var _ fmt.Stringer = NDPRoutePreference(0)

// NDPRoutePreference is the preference values for default routers or
// more-specific routes.
//
// As per RFC 4191 section 2.1,
//
//   Default router preferences and preferences for more-specific routes
//   are encoded the same way.
//
//   Preference values are encoded as a two-bit signed integer, as
//   follows:
//
//      01      High
//      00      Medium (default)
//      11      Low
//      10      Reserved - MUST NOT be sent
//
//   Note that implementations can treat the value as a two-bit signed
//   integer.
//
//   Having just three values reinforces that they are not metrics and
//   more values do not appear to be necessary for reasonable scenarios.
type NDPRoutePreference uint8

const (
	// HighRoutePreference indicates a high preference, as per
	// RFC 4191 section 2.1.
	HighRoutePreference NDPRoutePreference = 0b01

	// MediumRoutePreference indicates a medium preference, as per
	// RFC 4191 section 2.1.
	//
	// This is the default preference value.
	MediumRoutePreference = 0b00

	// LowRoutePreference indicates a low preference, as per
	// RFC 4191 section 2.1.
	LowRoutePreference = 0b11

	// ReservedRoutePreference is a reserved preference value, as per
	// RFC 4191 section 2.1.
	//
	// It MUST NOT be sent.
	ReservedRoutePreference = 0b10
)

// String implements fmt.Stringer.
func (p NDPRoutePreference) String() string {
	switch p {
	case HighRoutePreference:
		return "HighRoutePreference"
	case MediumRoutePreference:
		return "MediumRoutePreference"
	case LowRoutePreference:
		return "LowRoutePreference"
	case ReservedRoutePreference:
		return "ReservedRoutePreference"
	default:
		return fmt.Sprintf("NDPRoutePreference(%d)", p)
	}
}

// NDPRouterAdvert is an NDP Router Advertisement message. It will only contain
// the body of an ICMPv6 packet.
//
// See RFC 4861 section 4.2 and RFC 4191 section 2.2 for more details.
type NDPRouterAdvert []byte

// As per RFC 4191 section 2.2,
//
//       0                   1                   2                   3
//       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
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      |     Type      |     Code      |          Checksum             |
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      | Cur Hop Limit |M|O|H|Prf|Resvd|       Router Lifetime         |
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      |                         Reachable Time                        |
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      |                          Retrans Timer                        |
//      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      |   Options ...
//      +-+-+-+-+-+-+-+-+-+-+-+-
const (
	// NDPRAMinimumSize is the minimum size of a valid NDP Router
	// Advertisement message (body of an ICMPv6 packet).
	NDPRAMinimumSize = 12

	// ndpRACurrHopLimitOffset is the byte of the Curr Hop Limit field
	// within an NDPRouterAdvert.
	ndpRACurrHopLimitOffset = 0

	// ndpRAFlagsOffset is the byte with the NDP RA bit-fields/flags
	// within an NDPRouterAdvert.
	ndpRAFlagsOffset = 1

	// ndpRAManagedAddrConfFlagMask is the mask of the Managed Address
	// Configuration flag within the bit-field/flags byte of an
	// NDPRouterAdvert.
	ndpRAManagedAddrConfFlagMask = (1 << 7)

	// ndpRAOtherConfFlagMask is the mask of the Other Configuration flag
	// within the bit-field/flags byte of an NDPRouterAdvert.
	ndpRAOtherConfFlagMask = (1 << 6)

	// ndpDefaultRouterPreferenceShift is the shift of the Prf (Default Router
	// Preference) field within the flags byte of an NDPRouterAdvert.
	ndpDefaultRouterPreferenceShift = 3

	// ndpDefaultRouterPreferenceMask is the mask of the Prf (Default Router
	// Preference) field within the flags byte of an NDPRouterAdvert.
	ndpDefaultRouterPreferenceMask = (0b11 << ndpDefaultRouterPreferenceShift)

	// ndpRARouterLifetimeOffset is the start of the 2-byte Router Lifetime
	// field within an NDPRouterAdvert.
	ndpRARouterLifetimeOffset = 2

	// ndpRAReachableTimeOffset is the start of the 4-byte Reachable Time
	// field within an NDPRouterAdvert.
	ndpRAReachableTimeOffset = 4

	// ndpRARetransTimerOffset is the start of the 4-byte Retrans Timer
	// field within an NDPRouterAdvert.
	ndpRARetransTimerOffset = 8

	// ndpRAOptionsOffset is the start of the NDP options in an
	// NDPRouterAdvert.
	ndpRAOptionsOffset = 12
)

// CurrHopLimit returns the value of the Curr Hop Limit field.
func (b NDPRouterAdvert) CurrHopLimit() uint8 {
	return b[ndpRACurrHopLimitOffset]
}

// ManagedAddrConfFlag returns the value of the Managed Address Configuration
// flag.
func (b NDPRouterAdvert) ManagedAddrConfFlag() bool {
	return b[ndpRAFlagsOffset]&ndpRAManagedAddrConfFlagMask != 0
}

// OtherConfFlag returns the value of the Other Configuration flag.
func (b NDPRouterAdvert) OtherConfFlag() bool {
	return b[ndpRAFlagsOffset]&ndpRAOtherConfFlagMask != 0
}

// DefaultRouterPreference returns the Default Router Preference field.
func (b NDPRouterAdvert) DefaultRouterPreference() NDPRoutePreference {
	return NDPRoutePreference((b[ndpRAFlagsOffset] & ndpDefaultRouterPreferenceMask) >> ndpDefaultRouterPreferenceShift)
}

// RouterLifetime returns the lifetime associated with the default router. A
// value of 0 means the source of the Router Advertisement is not a default
// router and SHOULD NOT appear on the default router list. Note, a value of 0
// only means that the router should not be used as a default router, it does
// not apply to other information contained in the Router Advertisement.
func (b NDPRouterAdvert) RouterLifetime() time.Duration {
	// The field is the time in seconds, as per RFC 4861 section 4.2.
	return time.Second * time.Duration(binary.BigEndian.Uint16(b[ndpRARouterLifetimeOffset:]))
}

// ReachableTime returns the time that a node assumes a neighbor is reachable
// after having received a reachability confirmation. A value of 0 means
// that it is unspecified by the source of the Router Advertisement message.
func (b NDPRouterAdvert) ReachableTime() time.Duration {
	// The field is the time in milliseconds, as per RFC 4861 section 4.2.
	return time.Millisecond * time.Duration(binary.BigEndian.Uint32(b[ndpRAReachableTimeOffset:]))
}

// RetransTimer returns the time between retransmitted Neighbor Solicitation
// messages. A value of 0 means that it is unspecified by the source of the
// Router Advertisement message.
func (b NDPRouterAdvert) RetransTimer() time.Duration {
	// The field is the time in milliseconds, as per RFC 4861 section 4.2.
	return time.Millisecond * time.Duration(binary.BigEndian.Uint32(b[ndpRARetransTimerOffset:]))
}

// Options returns an NDPOptions of the the options body.
func (b NDPRouterAdvert) Options() NDPOptions {
	return NDPOptions(b[ndpRAOptionsOffset:])
}