blob: 87b9d33d5131578d1bea4835a0ed9fcb84dba186 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301// Copyright 2012 Google, Inc. All rights reserved.
2// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
3//
4// Use of this source code is governed by a BSD-style license
5// that can be found in the LICENSE file in the root of the source
6// tree.
7
8package layers
9
10import (
11 "encoding/binary"
12 "errors"
13 "fmt"
14 "net"
15
16 "github.com/google/gopacket"
17)
18
19const (
20 // IPv6HopByHopOptionJumbogram code as defined in RFC 2675
21 IPv6HopByHopOptionJumbogram = 0xC2
22)
23
24const (
25 ipv6MaxPayloadLength = 65535
26)
27
28// IPv6 is the layer for the IPv6 header.
29type IPv6 struct {
30 // http://www.networksorcery.com/enp/protocol/ipv6.htm
31 BaseLayer
32 Version uint8
33 TrafficClass uint8
34 FlowLabel uint32
35 Length uint16
36 NextHeader IPProtocol
37 HopLimit uint8
38 SrcIP net.IP
39 DstIP net.IP
40 HopByHop *IPv6HopByHop
41 // hbh will be pointed to by HopByHop if that layer exists.
42 hbh IPv6HopByHop
43}
44
45// LayerType returns LayerTypeIPv6
46func (ipv6 *IPv6) LayerType() gopacket.LayerType { return LayerTypeIPv6 }
47
48// NetworkFlow returns this new Flow (EndpointIPv6, SrcIP, DstIP)
49func (ipv6 *IPv6) NetworkFlow() gopacket.Flow {
50 return gopacket.NewFlow(EndpointIPv6, ipv6.SrcIP, ipv6.DstIP)
51}
52
53// Search for Jumbo Payload TLV in IPv6HopByHop and return (length, true) if found
54func getIPv6HopByHopJumboLength(hopopts *IPv6HopByHop) (uint32, bool, error) {
55 var tlv *IPv6HopByHopOption
56
57 for _, t := range hopopts.Options {
58 if t.OptionType == IPv6HopByHopOptionJumbogram {
59 tlv = t
60 break
61 }
62 }
63 if tlv == nil {
64 // Not found
65 return 0, false, nil
66 }
67 if len(tlv.OptionData) != 4 {
68 return 0, false, errors.New("Jumbo length TLV data must have length 4")
69 }
70 l := binary.BigEndian.Uint32(tlv.OptionData)
71 if l <= ipv6MaxPayloadLength {
72 return 0, false, fmt.Errorf("Jumbo length cannot be less than %d", ipv6MaxPayloadLength+1)
73 }
74 // Found
75 return l, true, nil
76}
77
78// Adds zero-valued Jumbo TLV to IPv6 header if it does not exist
79// (if necessary add hop-by-hop header)
80func addIPv6JumboOption(ip6 *IPv6) {
81 var tlv *IPv6HopByHopOption
82
83 if ip6.HopByHop == nil {
84 // Add IPv6 HopByHop
85 ip6.HopByHop = &IPv6HopByHop{}
86 ip6.HopByHop.NextHeader = ip6.NextHeader
87 ip6.HopByHop.HeaderLength = 0
88 ip6.NextHeader = IPProtocolIPv6HopByHop
89 }
90 for _, t := range ip6.HopByHop.Options {
91 if t.OptionType == IPv6HopByHopOptionJumbogram {
92 tlv = t
93 break
94 }
95 }
96 if tlv == nil {
97 // Add Jumbo TLV
98 tlv = &IPv6HopByHopOption{}
99 ip6.HopByHop.Options = append(ip6.HopByHop.Options, tlv)
100 }
101 tlv.SetJumboLength(0)
102}
103
104// Set jumbo length in serialized IPv6 payload (starting with HopByHop header)
105func setIPv6PayloadJumboLength(hbh []byte) error {
106 pLen := len(hbh)
107 if pLen < 8 {
108 //HopByHop is minimum 8 bytes
109 return fmt.Errorf("Invalid IPv6 payload (length %d)", pLen)
110 }
111 hbhLen := int((hbh[1] + 1) * 8)
112 if hbhLen > pLen {
113 return fmt.Errorf("Invalid hop-by-hop length (length: %d, payload: %d", hbhLen, pLen)
114 }
115 offset := 2 //start with options
116 for offset < hbhLen {
117 opt := hbh[offset]
118 if opt == 0 {
119 //Pad1
120 offset++
121 continue
122 }
123 optLen := int(hbh[offset+1])
124 if opt == IPv6HopByHopOptionJumbogram {
125 if optLen == 4 {
126 binary.BigEndian.PutUint32(hbh[offset+2:], uint32(pLen))
127 return nil
128 }
129 return fmt.Errorf("Jumbo TLV too short (%d bytes)", optLen)
130 }
131 offset += 2 + optLen
132 }
133 return errors.New("Jumbo TLV not found")
134}
135
136// SerializeTo writes the serialized form of this layer into the
137// SerializationBuffer, implementing gopacket.SerializableLayer.
138// See the docs for gopacket.SerializableLayer for more info.
139func (ipv6 *IPv6) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
140 var jumbo bool
141 var err error
142
143 payload := b.Bytes()
144 pLen := len(payload)
145 if pLen > ipv6MaxPayloadLength {
146 jumbo = true
147 if opts.FixLengths {
148 // We need to set the length later because the hop-by-hop header may
149 // not exist or else need padding, so pLen may yet change
150 addIPv6JumboOption(ipv6)
151 } else if ipv6.HopByHop == nil {
152 return fmt.Errorf("Cannot fit payload length of %d into IPv6 packet", pLen)
153 } else {
154 _, ok, err := getIPv6HopByHopJumboLength(ipv6.HopByHop)
155 if err != nil {
156 return err
157 }
158 if !ok {
159 return errors.New("Missing jumbo length hop-by-hop option")
160 }
161 }
162 }
163
164 hbhAlreadySerialized := false
165 if ipv6.HopByHop != nil {
166 for _, l := range b.Layers() {
167 if l == LayerTypeIPv6HopByHop {
168 hbhAlreadySerialized = true
169 break
170 }
171 }
172 }
173 if ipv6.HopByHop != nil && !hbhAlreadySerialized {
174 if ipv6.NextHeader != IPProtocolIPv6HopByHop {
175 // Just fix it instead of throwing an error
176 ipv6.NextHeader = IPProtocolIPv6HopByHop
177 }
178 err = ipv6.HopByHop.SerializeTo(b, opts)
179 if err != nil {
180 return err
181 }
182 payload = b.Bytes()
183 pLen = len(payload)
184 if opts.FixLengths && jumbo {
185 err := setIPv6PayloadJumboLength(payload)
186 if err != nil {
187 return err
188 }
189 }
190 }
191
192 if !jumbo && pLen > ipv6MaxPayloadLength {
193 return errors.New("Cannot fit payload into IPv6 header")
194 }
195 bytes, err := b.PrependBytes(40)
196 if err != nil {
197 return err
198 }
199 bytes[0] = (ipv6.Version << 4) | (ipv6.TrafficClass >> 4)
200 bytes[1] = (ipv6.TrafficClass << 4) | uint8(ipv6.FlowLabel>>16)
201 binary.BigEndian.PutUint16(bytes[2:], uint16(ipv6.FlowLabel))
202 if opts.FixLengths {
203 if jumbo {
204 ipv6.Length = 0
205 } else {
206 ipv6.Length = uint16(pLen)
207 }
208 }
209 binary.BigEndian.PutUint16(bytes[4:], ipv6.Length)
210 bytes[6] = byte(ipv6.NextHeader)
211 bytes[7] = byte(ipv6.HopLimit)
212 if err := ipv6.AddressTo16(); err != nil {
213 return err
214 }
215 copy(bytes[8:], ipv6.SrcIP)
216 copy(bytes[24:], ipv6.DstIP)
217 return nil
218}
219
220// DecodeFromBytes implementation according to gopacket.DecodingLayer
221func (ipv6 *IPv6) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
222 if len(data) < 40 {
223 df.SetTruncated()
224 return fmt.Errorf("Invalid ip6 header. Length %d less than 40", len(data))
225 }
226 ipv6.Version = uint8(data[0]) >> 4
227 ipv6.TrafficClass = uint8((binary.BigEndian.Uint16(data[0:2]) >> 4) & 0x00FF)
228 ipv6.FlowLabel = binary.BigEndian.Uint32(data[0:4]) & 0x000FFFFF
229 ipv6.Length = binary.BigEndian.Uint16(data[4:6])
230 ipv6.NextHeader = IPProtocol(data[6])
231 ipv6.HopLimit = data[7]
232 ipv6.SrcIP = data[8:24]
233 ipv6.DstIP = data[24:40]
234 ipv6.HopByHop = nil
235 ipv6.BaseLayer = BaseLayer{data[:40], data[40:]}
236
237 // We treat a HopByHop IPv6 option as part of the IPv6 packet, since its
238 // options are crucial for understanding what's actually happening per packet.
239 if ipv6.NextHeader == IPProtocolIPv6HopByHop {
240 err := ipv6.hbh.DecodeFromBytes(ipv6.Payload, df)
241 if err != nil {
242 return err
243 }
244 ipv6.HopByHop = &ipv6.hbh
245 pEnd, jumbo, err := getIPv6HopByHopJumboLength(ipv6.HopByHop)
246 if err != nil {
247 return err
248 }
249 if jumbo && ipv6.Length == 0 {
250 pEnd := int(pEnd)
251 if pEnd > len(ipv6.Payload) {
252 df.SetTruncated()
253 pEnd = len(ipv6.Payload)
254 }
255 ipv6.Payload = ipv6.Payload[:pEnd]
256 return nil
257 } else if jumbo && ipv6.Length != 0 {
258 return errors.New("IPv6 has jumbo length and IPv6 length is not 0")
259 } else if !jumbo && ipv6.Length == 0 {
260 return errors.New("IPv6 length 0, but HopByHop header does not have jumbogram option")
261 } else {
262 ipv6.Payload = ipv6.Payload[ipv6.hbh.ActualLength:]
263 }
264 }
265
266 if ipv6.Length == 0 {
267 return fmt.Errorf("IPv6 length 0, but next header is %v, not HopByHop", ipv6.NextHeader)
268 }
269
270 pEnd := int(ipv6.Length)
271 if pEnd > len(ipv6.Payload) {
272 df.SetTruncated()
273 pEnd = len(ipv6.Payload)
274 }
275 ipv6.Payload = ipv6.Payload[:pEnd]
276
277 return nil
278}
279
280// CanDecode implementation according to gopacket.DecodingLayer
281func (ipv6 *IPv6) CanDecode() gopacket.LayerClass {
282 return LayerTypeIPv6
283}
284
285// NextLayerType implementation according to gopacket.DecodingLayer
286func (ipv6 *IPv6) NextLayerType() gopacket.LayerType {
287 if ipv6.HopByHop != nil {
288 return ipv6.HopByHop.NextHeader.LayerType()
289 }
290 return ipv6.NextHeader.LayerType()
291}
292
293func decodeIPv6(data []byte, p gopacket.PacketBuilder) error {
294 ip6 := &IPv6{}
295 err := ip6.DecodeFromBytes(data, p)
296 p.AddLayer(ip6)
297 p.SetNetworkLayer(ip6)
298 if ip6.HopByHop != nil {
299 p.AddLayer(ip6.HopByHop)
300 }
301 if err != nil {
302 return err
303 }
304 return p.NextDecoder(ip6.NextLayerType())
305}
306
307type ipv6HeaderTLVOption struct {
308 OptionType, OptionLength uint8
309 ActualLength int
310 OptionData []byte
311 OptionAlignment [2]uint8 // Xn+Y = [2]uint8{X, Y}
312}
313
314func (h *ipv6HeaderTLVOption) serializeTo(data []byte, fixLengths bool, dryrun bool) int {
315 if fixLengths {
316 h.OptionLength = uint8(len(h.OptionData))
317 }
318 length := int(h.OptionLength) + 2
319 if !dryrun {
320 data[0] = h.OptionType
321 data[1] = h.OptionLength
322 copy(data[2:], h.OptionData)
323 }
324 return length
325}
326
327func decodeIPv6HeaderTLVOption(data []byte, df gopacket.DecodeFeedback) (h *ipv6HeaderTLVOption, _ error) {
328 if len(data) < 2 {
329 df.SetTruncated()
330 return nil, errors.New("IPv6 header option too small")
331 }
332 h = &ipv6HeaderTLVOption{}
333 if data[0] == 0 {
334 h.ActualLength = 1
335 return
336 }
337 h.OptionType = data[0]
338 h.OptionLength = data[1]
339 h.ActualLength = int(h.OptionLength) + 2
340 if len(data) < h.ActualLength {
341 df.SetTruncated()
342 return nil, errors.New("IPv6 header TLV option too small")
343 }
344 h.OptionData = data[2:h.ActualLength]
345 return
346}
347
348func serializeTLVOptionPadding(data []byte, padLength int) {
349 if padLength <= 0 {
350 return
351 }
352 if padLength == 1 {
353 data[0] = 0x0
354 return
355 }
356 tlvLength := uint8(padLength) - 2
357 data[0] = 0x1
358 data[1] = tlvLength
359 if tlvLength != 0 {
360 for k := range data[2:] {
361 data[k+2] = 0x0
362 }
363 }
364 return
365}
366
367// If buf is 'nil' do a serialize dry run
368func serializeIPv6HeaderTLVOptions(buf []byte, options []*ipv6HeaderTLVOption, fixLengths bool) int {
369 var l int
370
371 dryrun := buf == nil
372 length := 2
373 for _, opt := range options {
374 if fixLengths {
375 x := int(opt.OptionAlignment[0])
376 y := int(opt.OptionAlignment[1])
377 if x != 0 {
378 n := length / x
379 offset := x*n + y
380 if offset < length {
381 offset += x
382 }
383 if length != offset {
384 pad := offset - length
385 if !dryrun {
386 serializeTLVOptionPadding(buf[length-2:], pad)
387 }
388 length += pad
389 }
390 }
391 }
392 if dryrun {
393 l = opt.serializeTo(nil, fixLengths, true)
394 } else {
395 l = opt.serializeTo(buf[length-2:], fixLengths, false)
396 }
397 length += l
398 }
399 if fixLengths {
400 pad := length % 8
401 if pad != 0 {
402 if !dryrun {
403 serializeTLVOptionPadding(buf[length-2:], pad)
404 }
405 length += pad
406 }
407 }
408 return length - 2
409}
410
411type ipv6ExtensionBase struct {
412 BaseLayer
413 NextHeader IPProtocol
414 HeaderLength uint8
415 ActualLength int
416}
417
418func decodeIPv6ExtensionBase(data []byte, df gopacket.DecodeFeedback) (i ipv6ExtensionBase, returnedErr error) {
419 if len(data) < 2 {
420 df.SetTruncated()
421 return ipv6ExtensionBase{}, fmt.Errorf("Invalid ip6-extension header. Length %d less than 2", len(data))
422 }
423 i.NextHeader = IPProtocol(data[0])
424 i.HeaderLength = data[1]
425 i.ActualLength = int(i.HeaderLength)*8 + 8
426 if len(data) < i.ActualLength {
427 return ipv6ExtensionBase{}, fmt.Errorf("Invalid ip6-extension header. Length %d less than specified length %d", len(data), i.ActualLength)
428 }
429 i.Contents = data[:i.ActualLength]
430 i.Payload = data[i.ActualLength:]
431 return
432}
433
434// IPv6ExtensionSkipper is a DecodingLayer which decodes and ignores v6
435// extensions. You can use it with a DecodingLayerParser to handle IPv6 stacks
436// which may or may not have extensions.
437type IPv6ExtensionSkipper struct {
438 NextHeader IPProtocol
439 BaseLayer
440}
441
442// DecodeFromBytes implementation according to gopacket.DecodingLayer
443func (i *IPv6ExtensionSkipper) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
444 extension, err := decodeIPv6ExtensionBase(data, df)
445 if err != nil {
446 return err
447 }
448 i.BaseLayer = BaseLayer{data[:extension.ActualLength], data[extension.ActualLength:]}
449 i.NextHeader = extension.NextHeader
450 return nil
451}
452
453// CanDecode implementation according to gopacket.DecodingLayer
454func (i *IPv6ExtensionSkipper) CanDecode() gopacket.LayerClass {
455 return LayerClassIPv6Extension
456}
457
458// NextLayerType implementation according to gopacket.DecodingLayer
459func (i *IPv6ExtensionSkipper) NextLayerType() gopacket.LayerType {
460 return i.NextHeader.LayerType()
461}
462
463// IPv6HopByHopOption is a TLV option present in an IPv6 hop-by-hop extension.
464type IPv6HopByHopOption ipv6HeaderTLVOption
465
466// IPv6HopByHop is the IPv6 hop-by-hop extension.
467type IPv6HopByHop struct {
468 ipv6ExtensionBase
469 Options []*IPv6HopByHopOption
470}
471
472// LayerType returns LayerTypeIPv6HopByHop.
473func (i *IPv6HopByHop) LayerType() gopacket.LayerType { return LayerTypeIPv6HopByHop }
474
475// SerializeTo implementation according to gopacket.SerializableLayer
476func (i *IPv6HopByHop) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
477 var bytes []byte
478 var err error
479
480 o := make([]*ipv6HeaderTLVOption, 0, len(i.Options))
481 for _, v := range i.Options {
482 o = append(o, (*ipv6HeaderTLVOption)(v))
483 }
484
485 l := serializeIPv6HeaderTLVOptions(nil, o, opts.FixLengths)
486 bytes, err = b.PrependBytes(l)
487 if err != nil {
488 return err
489 }
490 serializeIPv6HeaderTLVOptions(bytes, o, opts.FixLengths)
491
492 length := len(bytes) + 2
493 if length%8 != 0 {
494 return errors.New("IPv6HopByHop actual length must be multiple of 8")
495 }
496 bytes, err = b.PrependBytes(2)
497 if err != nil {
498 return err
499 }
500 bytes[0] = uint8(i.NextHeader)
501 if opts.FixLengths {
502 i.HeaderLength = uint8((length / 8) - 1)
503 }
504 bytes[1] = uint8(i.HeaderLength)
505 return nil
506}
507
508// DecodeFromBytes implementation according to gopacket.DecodingLayer
509func (i *IPv6HopByHop) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
510 var err error
511 i.ipv6ExtensionBase, err = decodeIPv6ExtensionBase(data, df)
512 if err != nil {
513 return err
514 }
515 i.Options = i.Options[:0]
516 offset := 2
517 for offset < i.ActualLength {
518 opt, err := decodeIPv6HeaderTLVOption(data[offset:], df)
519 if err != nil {
520 return err
521 }
522 i.Options = append(i.Options, (*IPv6HopByHopOption)(opt))
523 offset += opt.ActualLength
524 }
525 return nil
526}
527
528func decodeIPv6HopByHop(data []byte, p gopacket.PacketBuilder) error {
529 i := &IPv6HopByHop{}
530 err := i.DecodeFromBytes(data, p)
531 p.AddLayer(i)
532 if err != nil {
533 return err
534 }
535 return p.NextDecoder(i.NextHeader)
536}
537
538// SetJumboLength adds the IPv6HopByHopOptionJumbogram with the given length
539func (o *IPv6HopByHopOption) SetJumboLength(len uint32) {
540 o.OptionType = IPv6HopByHopOptionJumbogram
541 o.OptionLength = 4
542 o.ActualLength = 6
543 if o.OptionData == nil {
544 o.OptionData = make([]byte, 4)
545 }
546 binary.BigEndian.PutUint32(o.OptionData, len)
547 o.OptionAlignment = [2]uint8{4, 2}
548}
549
550// IPv6Routing is the IPv6 routing extension.
551type IPv6Routing struct {
552 ipv6ExtensionBase
553 RoutingType uint8
554 SegmentsLeft uint8
555 // This segment is supposed to be zero according to RFC2460, the second set of
556 // 4 bytes in the extension.
557 Reserved []byte
558 // SourceRoutingIPs is the set of IPv6 addresses requested for source routing,
559 // set only if RoutingType == 0.
560 SourceRoutingIPs []net.IP
561}
562
563// LayerType returns LayerTypeIPv6Routing.
564func (i *IPv6Routing) LayerType() gopacket.LayerType { return LayerTypeIPv6Routing }
565
566func decodeIPv6Routing(data []byte, p gopacket.PacketBuilder) error {
567 base, err := decodeIPv6ExtensionBase(data, p)
568 if err != nil {
569 return err
570 }
571 i := &IPv6Routing{
572 ipv6ExtensionBase: base,
573 RoutingType: data[2],
574 SegmentsLeft: data[3],
575 Reserved: data[4:8],
576 }
577 switch i.RoutingType {
578 case 0: // Source routing
579 if (i.ActualLength-8)%16 != 0 {
580 return fmt.Errorf("Invalid IPv6 source routing, length of type 0 packet %d", i.ActualLength)
581 }
582 for d := i.Contents[8:]; len(d) >= 16; d = d[16:] {
583 i.SourceRoutingIPs = append(i.SourceRoutingIPs, net.IP(d[:16]))
584 }
585 default:
586 return fmt.Errorf("Unknown IPv6 routing header type %d", i.RoutingType)
587 }
588 p.AddLayer(i)
589 return p.NextDecoder(i.NextHeader)
590}
591
592// IPv6Fragment is the IPv6 fragment header, used for packet
593// fragmentation/defragmentation.
594type IPv6Fragment struct {
595 BaseLayer
596 NextHeader IPProtocol
597 // Reserved1 is bits [8-16), from least to most significant, 0-indexed
598 Reserved1 uint8
599 FragmentOffset uint16
600 // Reserved2 is bits [29-31), from least to most significant, 0-indexed
601 Reserved2 uint8
602 MoreFragments bool
603 Identification uint32
604}
605
606// LayerType returns LayerTypeIPv6Fragment.
607func (i *IPv6Fragment) LayerType() gopacket.LayerType { return LayerTypeIPv6Fragment }
608
609func decodeIPv6Fragment(data []byte, p gopacket.PacketBuilder) error {
610 if len(data) < 8 {
611 p.SetTruncated()
612 return fmt.Errorf("Invalid ip6-fragment header. Length %d less than 8", len(data))
613 }
614 i := &IPv6Fragment{
615 BaseLayer: BaseLayer{data[:8], data[8:]},
616 NextHeader: IPProtocol(data[0]),
617 Reserved1: data[1],
618 FragmentOffset: binary.BigEndian.Uint16(data[2:4]) >> 3,
619 Reserved2: data[3] & 0x6 >> 1,
620 MoreFragments: data[3]&0x1 != 0,
621 Identification: binary.BigEndian.Uint32(data[4:8]),
622 }
623 p.AddLayer(i)
624 return p.NextDecoder(gopacket.DecodeFragment)
625}
626
627// IPv6DestinationOption is a TLV option present in an IPv6 destination options extension.
628type IPv6DestinationOption ipv6HeaderTLVOption
629
630// IPv6Destination is the IPv6 destination options header.
631type IPv6Destination struct {
632 ipv6ExtensionBase
633 Options []*IPv6DestinationOption
634}
635
636// LayerType returns LayerTypeIPv6Destination.
637func (i *IPv6Destination) LayerType() gopacket.LayerType { return LayerTypeIPv6Destination }
638
639// DecodeFromBytes implementation according to gopacket.DecodingLayer
640func (i *IPv6Destination) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
641 var err error
642 i.ipv6ExtensionBase, err = decodeIPv6ExtensionBase(data, df)
643 if err != nil {
644 return err
645 }
646 offset := 2
647 for offset < i.ActualLength {
648 opt, err := decodeIPv6HeaderTLVOption(data[offset:], df)
649 if err != nil {
650 return err
651 }
652 i.Options = append(i.Options, (*IPv6DestinationOption)(opt))
653 offset += opt.ActualLength
654 }
655 return nil
656}
657
658func decodeIPv6Destination(data []byte, p gopacket.PacketBuilder) error {
659 i := &IPv6Destination{}
660 err := i.DecodeFromBytes(data, p)
661 p.AddLayer(i)
662 if err != nil {
663 return err
664 }
665 return p.NextDecoder(i.NextHeader)
666}
667
668// SerializeTo writes the serialized form of this layer into the
669// SerializationBuffer, implementing gopacket.SerializableLayer.
670// See the docs for gopacket.SerializableLayer for more info.
671func (i *IPv6Destination) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
672 var bytes []byte
673 var err error
674
675 o := make([]*ipv6HeaderTLVOption, 0, len(i.Options))
676 for _, v := range i.Options {
677 o = append(o, (*ipv6HeaderTLVOption)(v))
678 }
679
680 l := serializeIPv6HeaderTLVOptions(nil, o, opts.FixLengths)
681 bytes, err = b.PrependBytes(l)
682 if err != nil {
683 return err
684 }
685 serializeIPv6HeaderTLVOptions(bytes, o, opts.FixLengths)
686
687 length := len(bytes) + 2
688 if length%8 != 0 {
689 return errors.New("IPv6Destination actual length must be multiple of 8")
690 }
691 bytes, err = b.PrependBytes(2)
692 if err != nil {
693 return err
694 }
695 bytes[0] = uint8(i.NextHeader)
696 if opts.FixLengths {
697 i.HeaderLength = uint8((length / 8) - 1)
698 }
699 bytes[1] = uint8(i.HeaderLength)
700 return nil
701}
702
703func checkIPv6Address(addr net.IP) error {
704 if len(addr) == net.IPv6len {
705 return nil
706 }
707 if len(addr) == net.IPv4len {
708 return errors.New("address is IPv4")
709 }
710 return fmt.Errorf("wrong length of %d bytes instead of %d", len(addr), net.IPv6len)
711}
712
713// AddressTo16 ensures IPv6.SrcIP and IPv6.DstIP are actually IPv6 addresses (i.e. 16 byte addresses)
714func (ipv6 *IPv6) AddressTo16() error {
715 if err := checkIPv6Address(ipv6.SrcIP); err != nil {
716 return fmt.Errorf("Invalid source IPv6 address (%s)", err)
717 }
718 if err := checkIPv6Address(ipv6.DstIP); err != nil {
719 return fmt.Errorf("Invalid destination IPv6 address (%s)", err)
720 }
721 return nil
722}