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
|
package dhcpv6
import (
"fmt"
"net"
"github.com/u-root/uio/uio"
)
// Opt4RD represents a 4RD option. It is only a container for 4RD_*_RULE options
type Opt4RD struct {
FourRDOptions
}
// Code returns the Option Code for this option
func (op *Opt4RD) Code() OptionCode {
return Option4RD
}
// ToBytes serializes this option
func (op *Opt4RD) ToBytes() []byte {
return op.Options.ToBytes()
}
// String returns a human-readable representation of the option
func (op *Opt4RD) String() string {
return fmt.Sprintf("%s: {Options=%v}", op.Code(), op.Options)
}
// LongString returns a multi-line human-readable representation of the option
func (op *Opt4RD) LongString(indentSpace int) string {
return fmt.Sprintf("%s: Options=%v", op.Code(), op.Options.LongString(indentSpace))
}
// FromBytes builds an Opt4RD structure from a sequence of bytes.
// The input data does not include option code and length bytes
func (op *Opt4RD) FromBytes(data []byte) error {
return op.Options.FromBytes(data)
}
// FourRDOptions are options that can be encapsulated with the 4RD option.
type FourRDOptions struct {
Options
}
// MapRules returns the map rules associated with the 4RD option.
//
// "The OPTION_4RD DHCPv6 option contains at least one encapsulated
// OPTION_4RD_MAP_RULE option." (RFC 7600 Section 4.9)
func (frdo FourRDOptions) MapRules() []*Opt4RDMapRule {
opts := frdo.Options.Get(Option4RDMapRule)
var mrs []*Opt4RDMapRule
for _, o := range opts {
if m, ok := o.(*Opt4RDMapRule); ok {
mrs = append(mrs, m)
}
}
return mrs
}
// NonMapRule returns the non-map-rule associated with this option.
//
// "The OPTION_4RD DHCPv6 option contains ... a maximum of one
// encapsulated OPTION_4RD_NON_MAP_RULE option." (RFC 7600 Section 4.9)
func (frdo FourRDOptions) NonMapRule() *Opt4RDNonMapRule {
opt := frdo.Options.GetOne(Option4RDNonMapRule)
if opt == nil {
return nil
}
nmr, ok := opt.(*Opt4RDNonMapRule)
if !ok {
return nil
}
return nmr
}
// Opt4RDMapRule represents a 4RD Mapping Rule option.
//
// The option is described in RFC 7600 Section 4.9. The 4RD mapping rules are
// described in RFC 7600 Section 4.2.
type Opt4RDMapRule struct {
// Prefix4 is the IPv4 prefix mapped by this rule
Prefix4 net.IPNet
// Prefix6 is the IPv6 prefix mapped by this rule
Prefix6 net.IPNet
// EABitsLength is the number of bits of an address used in constructing the mapped address
EABitsLength uint8
// WKPAuthorized determines if well-known ports are assigned to addresses in an A+P mapping
// It can only be set if the length of Prefix4 + EABits > 32
WKPAuthorized bool
}
const (
// opt4RDWKPAuthorizedMask is the mask for the WKPAuthorized flag in its
// byte in Opt4RDMapRule
opt4RDWKPAuthorizedMask = 1 << 7
// opt4RDHubAndSpokeMask is the mask for the HubAndSpoke flag in its
// byte in Opt4RDNonMapRule
opt4RDHubAndSpokeMask = 1 << 7
// opt4RDTrafficClassMask is the mask for the TrafficClass flag in its
// byte in Opt4RDNonMapRule
opt4RDTrafficClassMask = 1 << 0
)
// Code returns the option code representing this option
func (op *Opt4RDMapRule) Code() OptionCode { return Option4RDMapRule }
// ToBytes serializes this option
func (op *Opt4RDMapRule) ToBytes() []byte {
buf := uio.NewBigEndianBuffer(nil)
p4Len, _ := op.Prefix4.Mask.Size()
p6Len, _ := op.Prefix6.Mask.Size()
buf.Write8(uint8(p4Len))
buf.Write8(uint8(p6Len))
buf.Write8(op.EABitsLength)
if op.WKPAuthorized {
buf.Write8(opt4RDWKPAuthorizedMask)
} else {
buf.Write8(0)
}
if op.Prefix4.IP.To4() == nil {
// The API prevents us from returning an error here
// We just write zeros instead, which is pretty bad behaviour
buf.Write32(0)
} else {
buf.WriteBytes(op.Prefix4.IP.To4())
}
if op.Prefix6.IP.To16() == nil {
buf.Write64(0)
buf.Write64(0)
} else {
buf.WriteBytes(op.Prefix6.IP.To16())
}
return buf.Data()
}
// String returns a human-readable description of this option
func (op *Opt4RDMapRule) String() string {
return fmt.Sprintf("%s: {Prefix4=%s, Prefix6=%s, EA-Bits=%d, WKPAuthorized=%t}",
op.Code(), op.Prefix4.String(), op.Prefix6.String(), op.EABitsLength, op.WKPAuthorized)
}
// FromBytes builds an Opt4RDMapRule structure from a sequence of bytes.
// The input data does not include option code and length bytes.
func (op *Opt4RDMapRule) FromBytes(data []byte) error {
buf := uio.NewBigEndianBuffer(data)
op.Prefix4.Mask = net.CIDRMask(int(buf.Read8()), 32)
op.Prefix6.Mask = net.CIDRMask(int(buf.Read8()), 128)
op.EABitsLength = buf.Read8()
op.WKPAuthorized = (buf.Read8() & opt4RDWKPAuthorizedMask) != 0
op.Prefix4.IP = net.IP(buf.CopyN(net.IPv4len))
op.Prefix6.IP = net.IP(buf.CopyN(net.IPv6len))
return buf.FinError()
}
// Opt4RDNonMapRule represents 4RD parameters other than mapping rules
type Opt4RDNonMapRule struct {
// HubAndSpoke is whether the network topology is hub-and-spoke or meshed
HubAndSpoke bool
// TrafficClass is an optional 8-bit tunnel traffic class identifier
TrafficClass *uint8
// DomainPMTU is the Path MTU for this 4RD domain
DomainPMTU uint16
}
// Code returns the option code for this option
func (op *Opt4RDNonMapRule) Code() OptionCode {
return Option4RDNonMapRule
}
// ToBytes serializes this option
func (op *Opt4RDNonMapRule) ToBytes() []byte {
buf := uio.NewBigEndianBuffer(nil)
var flags uint8
var trafficClassValue uint8
if op.HubAndSpoke {
flags |= opt4RDHubAndSpokeMask
}
if op.TrafficClass != nil {
flags |= opt4RDTrafficClassMask
trafficClassValue = *op.TrafficClass
}
buf.Write8(flags)
buf.Write8(trafficClassValue)
buf.Write16(op.DomainPMTU)
return buf.Data()
}
// String returns a human-readable description of this option
func (op *Opt4RDNonMapRule) String() string {
var tClass interface{} = false
if op.TrafficClass != nil {
tClass = *op.TrafficClass
}
return fmt.Sprintf("%s: {HubAndSpoke=%t, TrafficClass=%v, DomainPMTU=%d}", op.Code(), op.HubAndSpoke, tClass, op.DomainPMTU)
}
// FromBytes builds an Opt4RDNonMapRule structure from a sequence of bytes.
// The input data does not include option code and length bytes
func (op *Opt4RDNonMapRule) FromBytes(data []byte) error {
buf := uio.NewBigEndianBuffer(data)
flags := buf.Read8()
op.HubAndSpoke = flags&opt4RDHubAndSpokeMask != 0
tClass := buf.Read8()
if flags&opt4RDTrafficClassMask != 0 {
op.TrafficClass = &tClass
}
op.DomainPMTU = buf.Read16()
return buf.FinError()
}
|