blob: 22a1bde91f0927296f31372234c5cd2c7cd23306 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301// Copyright 2018 Google, Inc. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style license
4// that can be found in the LICENSE file in the root of the source
5// tree.
6
7package layers
8
9import (
10 "encoding/binary"
11 "errors"
12 "fmt"
13 "net"
14
15 "github.com/google/gopacket"
16)
17
18// DHCPv6MsgType represents a DHCPv6 operation
19type DHCPv6MsgType byte
20
21// Constants that represent DHCP operations
22const (
23 DHCPv6MsgTypeUnspecified DHCPv6MsgType = iota
24 DHCPv6MsgTypeSolicit
25 DHCPv6MsgTypeAdvertise
26 DHCPv6MsgTypeRequest
27 DHCPv6MsgTypeConfirm
28 DHCPv6MsgTypeRenew
29 DHCPv6MsgTypeRebind
30 DHCPv6MsgTypeReply
31 DHCPv6MsgTypeRelease
32 DHCPv6MsgTypeDecline
33 DHCPv6MsgTypeReconfigure
34 DHCPv6MsgTypeInformationRequest
35 DHCPv6MsgTypeRelayForward
36 DHCPv6MsgTypeRelayReply
37)
38
39// String returns a string version of a DHCPv6MsgType.
40func (o DHCPv6MsgType) String() string {
41 switch o {
42 case DHCPv6MsgTypeUnspecified:
43 return "Unspecified"
44 case DHCPv6MsgTypeSolicit:
45 return "Solicit"
46 case DHCPv6MsgTypeAdvertise:
47 return "Advertise"
48 case DHCPv6MsgTypeRequest:
49 return "Request"
50 case DHCPv6MsgTypeConfirm:
51 return "Confirm"
52 case DHCPv6MsgTypeRenew:
53 return "Renew"
54 case DHCPv6MsgTypeRebind:
55 return "Rebind"
56 case DHCPv6MsgTypeReply:
57 return "Reply"
58 case DHCPv6MsgTypeRelease:
59 return "Release"
60 case DHCPv6MsgTypeDecline:
61 return "Decline"
62 case DHCPv6MsgTypeReconfigure:
63 return "Reconfigure"
64 case DHCPv6MsgTypeInformationRequest:
65 return "InformationRequest"
66 case DHCPv6MsgTypeRelayForward:
67 return "RelayForward"
68 case DHCPv6MsgTypeRelayReply:
69 return "RelayReply"
70 default:
71 return "Unknown"
72 }
73}
74
75// DHCPv6 contains data for a single DHCP packet.
76type DHCPv6 struct {
77 BaseLayer
78 MsgType DHCPv6MsgType
79 HopCount uint8
80 LinkAddr net.IP
81 PeerAddr net.IP
82 TransactionID []byte
83 Options DHCPv6Options
84}
85
86// LayerType returns gopacket.LayerTypeDHCPv6
87func (d *DHCPv6) LayerType() gopacket.LayerType { return LayerTypeDHCPv6 }
88
89// DecodeFromBytes decodes the given bytes into this layer.
90func (d *DHCPv6) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
91 if len(data) < 4 {
92 df.SetTruncated()
93 return fmt.Errorf("DHCPv6 length %d too short", len(data))
94 }
95 d.BaseLayer = BaseLayer{Contents: data}
96 d.Options = d.Options[:0]
97 d.MsgType = DHCPv6MsgType(data[0])
98
99 offset := 0
100 if d.MsgType == DHCPv6MsgTypeRelayForward || d.MsgType == DHCPv6MsgTypeRelayReply {
101 if len(data) < 34 {
102 df.SetTruncated()
103 return fmt.Errorf("DHCPv6 length %d too short for message type %d", len(data), d.MsgType)
104 }
105 d.HopCount = data[1]
106 d.LinkAddr = net.IP(data[2:18])
107 d.PeerAddr = net.IP(data[18:34])
108 offset = 34
109 } else {
110 d.TransactionID = data[1:4]
111 offset = 4
112 }
113
114 stop := len(data)
115 for offset < stop {
116 o := DHCPv6Option{}
117 if err := o.decode(data[offset:]); err != nil {
118 return err
119 }
120 d.Options = append(d.Options, o)
121 offset += int(o.Length) + 4 // 2 from option code, 2 from option length
122 }
123
124 return nil
125}
126
127// Len returns the length of a DHCPv6 packet.
128func (d *DHCPv6) Len() int {
129 n := 1
130 if d.MsgType == DHCPv6MsgTypeRelayForward || d.MsgType == DHCPv6MsgTypeRelayReply {
131 n += 33
132 } else {
133 n += 3
134 }
135
136 for _, o := range d.Options {
137 n += int(o.Length) + 4 // 2 from option code, 2 from option length
138 }
139
140 return n
141}
142
143// SerializeTo writes the serialized form of this layer into the
144// SerializationBuffer, implementing gopacket.SerializableLayer.
145// See the docs for gopacket.SerializableLayer for more info.
146func (d *DHCPv6) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
147 plen := int(d.Len())
148
149 data, err := b.PrependBytes(plen)
150 if err != nil {
151 return err
152 }
153
154 offset := 0
155 data[0] = byte(d.MsgType)
156 if d.MsgType == DHCPv6MsgTypeRelayForward || d.MsgType == DHCPv6MsgTypeRelayReply {
157 data[1] = byte(d.HopCount)
158 copy(data[2:18], d.LinkAddr.To16())
159 copy(data[18:34], d.PeerAddr.To16())
160 offset = 34
161 } else {
162 copy(data[1:4], d.TransactionID)
163 offset = 4
164 }
165
166 if len(d.Options) > 0 {
167 for _, o := range d.Options {
168 if err := o.encode(data[offset:], opts); err != nil {
169 return err
170 }
171 offset += int(o.Length) + 4 // 2 from option code, 2 from option length
172 }
173 }
174 return nil
175}
176
177// CanDecode returns the set of layer types that this DecodingLayer can decode.
178func (d *DHCPv6) CanDecode() gopacket.LayerClass {
179 return LayerTypeDHCPv6
180}
181
182// NextLayerType returns the layer type contained by this DecodingLayer.
183func (d *DHCPv6) NextLayerType() gopacket.LayerType {
184 return gopacket.LayerTypePayload
185}
186
187func decodeDHCPv6(data []byte, p gopacket.PacketBuilder) error {
188 dhcp := &DHCPv6{}
189 err := dhcp.DecodeFromBytes(data, p)
190 if err != nil {
191 return err
192 }
193 p.AddLayer(dhcp)
194 return p.NextDecoder(gopacket.LayerTypePayload)
195}
196
197// DHCPv6StatusCode represents a DHCP status code - RFC-3315
198type DHCPv6StatusCode uint16
199
200// Constants for the DHCPv6StatusCode.
201const (
202 DHCPv6StatusCodeSuccess DHCPv6StatusCode = iota
203 DHCPv6StatusCodeUnspecFail
204 DHCPv6StatusCodeNoAddrsAvail
205 DHCPv6StatusCodeNoBinding
206 DHCPv6StatusCodeNotOnLink
207 DHCPv6StatusCodeUseMulticast
208)
209
210// String returns a string version of a DHCPv6StatusCode.
211func (o DHCPv6StatusCode) String() string {
212 switch o {
213 case DHCPv6StatusCodeSuccess:
214 return "Success"
215 case DHCPv6StatusCodeUnspecFail:
216 return "UnspecifiedFailure"
217 case DHCPv6StatusCodeNoAddrsAvail:
218 return "NoAddressAvailable"
219 case DHCPv6StatusCodeNoBinding:
220 return "NoBinding"
221 case DHCPv6StatusCodeNotOnLink:
222 return "NotOnLink"
223 case DHCPv6StatusCodeUseMulticast:
224 return "UseMulticast"
225 default:
226 return "Unknown"
227 }
228}
229
230// DHCPv6DUIDType represents a DHCP DUID - RFC-3315
231type DHCPv6DUIDType uint16
232
233// Constants for the DHCPv6DUIDType.
234const (
235 DHCPv6DUIDTypeLLT DHCPv6DUIDType = iota + 1
236 DHCPv6DUIDTypeEN
237 DHCPv6DUIDTypeLL
238 DHCPv6DUIDTypeUUID
239)
240
241// String returns a string version of a DHCPv6DUIDType.
242func (o DHCPv6DUIDType) String() string {
243 switch o {
244 case DHCPv6DUIDTypeLLT:
245 return "LLT"
246 case DHCPv6DUIDTypeEN:
247 return "EN"
248 case DHCPv6DUIDTypeLL:
249 return "LL"
250 case DHCPv6DUIDTypeUUID:
251 return "UUID"
252 default:
253 return "Unknown"
254 }
255}
256
257// DHCPv6DUID means DHCP Unique Identifier as stated in RFC 3315, section 9 (https://tools.ietf.org/html/rfc3315#page-19)
258type DHCPv6DUID struct {
259 Type DHCPv6DUIDType
260 // LLT, LL
261 HardwareType []byte
262 // EN
263 EnterpriseNumber []byte
264 // LLT
265 Time []byte
266 // LLT, LL
267 LinkLayerAddress net.HardwareAddr
268 // EN
269 Identifier []byte
270 // UUID
271 UniqueIdentifier []byte
272}
273
274// DecodeFromBytes decodes the given bytes into a DHCPv6DUID
275func (d *DHCPv6DUID) DecodeFromBytes(data []byte) error {
276 if len(data) < 2 {
277 return fmt.Errorf("Not enough bytes to decode: %d", len(data))
278 }
279
280 d.Type = DHCPv6DUIDType(binary.BigEndian.Uint16(data[:2]))
281 if d.Type == DHCPv6DUIDTypeLLT || d.Type == DHCPv6DUIDTypeLL {
282 if len(data) < 4 {
283 return fmt.Errorf("Not enough bytes to decode: %d", len(data))
284 }
285 d.HardwareType = data[2:4]
286 }
287
288 if d.Type == DHCPv6DUIDTypeLLT {
289 if len(data) < 8 {
290 return fmt.Errorf("Not enough bytes to decode: %d", len(data))
291 }
292 d.Time = data[4:8]
293 d.LinkLayerAddress = net.HardwareAddr(data[8:])
294 } else if d.Type == DHCPv6DUIDTypeEN {
295 if len(data) < 6 {
296 return fmt.Errorf("Not enough bytes to decode: %d", len(data))
297 }
298 d.EnterpriseNumber = data[2:6]
299 d.Identifier = data[6:]
300 } else if d.Type == DHCPv6DUIDTypeUUID {
301 d.UniqueIdentifier = data[2:]
302 } else { // DHCPv6DUIDTypeLL
303 if len(data) < 4 {
304 return fmt.Errorf("Not enough bytes to decode: %d", len(data))
305 }
306 d.LinkLayerAddress = net.HardwareAddr(data[4:])
307 }
308
309 return nil
310}
311
312// Encode encodes the DHCPv6DUID in a slice of bytes
313func (d *DHCPv6DUID) Encode() []byte {
314 length := d.Len()
315 data := make([]byte, length)
316 binary.BigEndian.PutUint16(data[0:2], uint16(d.Type))
317
318 if d.Type == DHCPv6DUIDTypeLLT || d.Type == DHCPv6DUIDTypeLL {
319 copy(data[2:4], d.HardwareType)
320 }
321
322 if d.Type == DHCPv6DUIDTypeLLT {
323 copy(data[4:8], d.Time)
324 copy(data[8:], d.LinkLayerAddress)
325 } else if d.Type == DHCPv6DUIDTypeEN {
326 copy(data[2:6], d.EnterpriseNumber)
327 copy(data[6:], d.Identifier)
328 } else {
329 copy(data[4:], d.LinkLayerAddress)
330 }
331
332 return data
333}
334
335// Len returns the length of the DHCPv6DUID, respecting the type
336func (d *DHCPv6DUID) Len() int {
337 length := 2 // d.Type
338 if d.Type == DHCPv6DUIDTypeLLT {
339 length += 2 /*HardwareType*/ + 4 /*d.Time*/ + len(d.LinkLayerAddress)
340 } else if d.Type == DHCPv6DUIDTypeEN {
341 length += 4 /*d.EnterpriseNumber*/ + len(d.Identifier)
342 } else { // LL
343 length += 2 /*d.HardwareType*/ + len(d.LinkLayerAddress)
344 }
345
346 return length
347}
348
349func (d *DHCPv6DUID) String() string {
350 duid := "Type: " + d.Type.String() + ", "
351 if d.Type == DHCPv6DUIDTypeLLT {
352 duid += fmt.Sprintf("HardwareType: %v, Time: %v, LinkLayerAddress: %v", d.HardwareType, d.Time, d.LinkLayerAddress)
353 } else if d.Type == DHCPv6DUIDTypeEN {
354 duid += fmt.Sprintf("EnterpriseNumber: %v, Identifier: %v", d.EnterpriseNumber, d.Identifier)
355 } else { // DHCPv6DUIDTypeLL
356 duid += fmt.Sprintf("HardwareType: %v, LinkLayerAddress: %v", d.HardwareType, d.LinkLayerAddress)
357 }
358 return duid
359}
360
361func decodeDHCPv6DUID(data []byte) (*DHCPv6DUID, error) {
362 duid := &DHCPv6DUID{}
363 err := duid.DecodeFromBytes(data)
364 if err != nil {
365 return nil, err
366 }
367 return duid, nil
368}
369
370type DHCPv6IAPD struct {
371 IAID [4]byte
372 T1 uint32
373 T2 uint32
374 PD DHCPv6PD
375}
376
377type DHCPv6PD struct {
378 PrefLifeTime uint32
379 ValidLifeTime uint32
380 PrefixLength byte
381 Prefix net.IP
382}
383
384// DecodeFromBytes decodes the given bytes into a DHCPv6DUID
385func (d *DHCPv6IAPD) DecodeFromBytes(data []byte) error {
386 if len(data) != 41 {
387 return errors.New("Not enough bytes to decode: " + string(len(data)))
388 }
389
390 copy(d.IAID[:], data[:4])
391 d.T1 = binary.BigEndian.Uint32(data[4:8])
392 d.T2 = binary.BigEndian.Uint32(data[8:12])
393
394 PDType := binary.BigEndian.Uint16(data[12:14])
395 if PDType != uint16(DHCPv6OptIAPrefix) {
396 return errors.New("Invalid IE Included: " + string(PDType))
397 }
398 PDLen := binary.BigEndian.Uint16(data[14:16])
399 if PDLen != 25 {
400 return errors.New("Invalid Length for PD: " + string(PDLen))
401 }
402 if err := (&d.PD).DecodeFromBytes(data[16:]); err != nil {
403 return err
404 }
405 return nil
406}
407
408func (pd *DHCPv6PD) DecodeFromBytes(data []byte) error {
409 pd.PrefLifeTime = binary.BigEndian.Uint32(data[0:4])
410 pd.ValidLifeTime = binary.BigEndian.Uint32(data[4:8])
411 pd.PrefixLength = data[8]
412 pd.Prefix = data[9:]
413 return nil
414}
415
416func (d *DHCPv6IAPD) Encode() []byte {
417 length := 41
418 data := make([]byte, length)
419 copy(data[0:4], d.IAID[:])
420 binary.BigEndian.PutUint32(data[4:8], d.T1)
421 binary.BigEndian.PutUint32(data[8:12], d.T2)
422 binary.BigEndian.PutUint16(data[12:14], uint16(DHCPv6OptIAPrefix))
423 binary.BigEndian.PutUint16(data[14:16], 25)
424 x := (&d.PD).Encode()
425 copy(data[16:41], x)
426 return data
427}
428
429func (pd *DHCPv6PD) Encode() []byte {
430 data := make([]byte, 25)
431 binary.BigEndian.PutUint32(data[0:4], pd.PrefLifeTime)
432 binary.BigEndian.PutUint32(data[4:8], pd.ValidLifeTime)
433 data[8] = pd.PrefixLength
434 copy(data[9:25], pd.Prefix)
435 return data
436}
437
438// Implementation of Remote ID of DHCPv6 used by LDRA
439// Defined in RFC 6221
440type DHCPv6RemoteId struct {
441 EnterpriseID [4]byte
442 RemoteId []byte
443}
444
445func (d *DHCPv6RemoteId) Encode() []byte {
446 length := 4 + len(d.RemoteId)
447 data := make([]byte, length)
448 copy(data[0:4], d.EnterpriseID[:])
449 copy(data[4:], d.RemoteId)
450 return data
451}
452
453func (d *DHCPv6RemoteId) DecodeFromBytes(data []byte) error {
454 copy(d.EnterpriseID[:], data[0:4])
455 copy(d.RemoteId, data[4:])
456 return nil
457}
458
459// Implementation of Interface Id of DHCPv6 used by LDRA
460// Defined in RFC 6221
461type DHCPv6IntfId struct {
462 Data []byte
463}
464
465func (d *DHCPv6IntfId) Encode() []byte {
466 length := len(d.Data)
467 data := make([]byte, length)
468 copy(data[0:length], d.Data)
469 return data
470}
471
472func (d *DHCPv6IntfId) DecodeFromBytes(data []byte) error {
473 copy(d.Data, data)
474 return nil
475}
476
477type DHCPv6IANA struct {
478 IAID [4]byte
479 T1 uint32
480 T2 uint32
481 IA DHCPv6IA
482}
483
484type DHCPv6IA struct {
485 PrefLifeTime uint32
486 ValidLifeTime uint32
487 IPv6Addr net.IP
488}
489
490// DecodeFromBytes decodes the given bytes into a DHCPv6DUID
491func (d *DHCPv6IANA) DecodeFromBytes(data []byte) error {
492 if len(data) != 40 {
493 return errors.New("Not enough bytes to decode: " + string(len(data)))
494 }
495
496 copy(d.IAID[:], data[:4])
497 d.T1 = binary.BigEndian.Uint32(data[4:8])
498 d.T2 = binary.BigEndian.Uint32(data[8:12])
499
500 IAType := binary.BigEndian.Uint16(data[12:14])
501 if IAType != uint16(DHCPv6OptIAAddr) {
502 return errors.New("Invalid IE Included: " + string(IAType))
503 }
504 IALen := binary.BigEndian.Uint16(data[14:16])
505 if IALen != 24 {
506 return errors.New("Invalid Length for PD: " + string(IALen))
507 }
508 if err := (&d.IA).DecodeFromBytes(data[16:]); err != nil {
509 return err
510 }
511 return nil
512}
513
514func (ia *DHCPv6IA) DecodeFromBytes(data []byte) error {
515 ia.IPv6Addr = data[0:16]
516 ia.PrefLifeTime = binary.BigEndian.Uint32(data[16:20])
517 ia.ValidLifeTime = binary.BigEndian.Uint32(data[20:])
518
519 return nil
520}
521
522func (d *DHCPv6IANA) Encode() []byte {
523 length := 40
524 data := make([]byte, length)
525 copy(data[0:4], d.IAID[:])
526 binary.BigEndian.PutUint32(data[4:8], d.T1)
527 binary.BigEndian.PutUint32(data[8:12], d.T2)
528 binary.BigEndian.PutUint16(data[12:14], uint16(DHCPv6OptIAPrefix))
529 binary.BigEndian.PutUint16(data[14:16], 24)
530 x := (&d.IA).Encode()
531 copy(data[16:40], x)
532 return data
533}
534
535func (ia *DHCPv6IA) Encode() []byte {
536 data := make([]byte, 24)
537 copy(data[0:16], ia.IPv6Addr)
538 binary.BigEndian.PutUint32(data[16:20], ia.PrefLifeTime)
539 binary.BigEndian.PutUint32(data[20:24], ia.ValidLifeTime)
540 return data
541}