blob: 70e9c8d558a9c0d360e5e32d2780177a911a457c [file] [log] [blame]
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -07001// 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) (h *ipv6HeaderTLVOption) {
328 h = &ipv6HeaderTLVOption{}
329 if data[0] == 0 {
330 h.ActualLength = 1
331 return
332 }
333 h.OptionType = data[0]
334 h.OptionLength = data[1]
335 h.ActualLength = int(h.OptionLength) + 2
336 h.OptionData = data[2:h.ActualLength]
337 return
338}
339
340func serializeTLVOptionPadding(data []byte, padLength int) {
341 if padLength <= 0 {
342 return
343 }
344 if padLength == 1 {
345 data[0] = 0x0
346 return
347 }
348 tlvLength := uint8(padLength) - 2
349 data[0] = 0x1
350 data[1] = tlvLength
351 if tlvLength != 0 {
352 for k := range data[2:] {
353 data[k+2] = 0x0
354 }
355 }
356 return
357}
358
359// If buf is 'nil' do a serialize dry run
360func serializeIPv6HeaderTLVOptions(buf []byte, options []*ipv6HeaderTLVOption, fixLengths bool) int {
361 var l int
362
363 dryrun := buf == nil
364 length := 2
365 for _, opt := range options {
366 if fixLengths {
367 x := int(opt.OptionAlignment[0])
368 y := int(opt.OptionAlignment[1])
369 if x != 0 {
370 n := length / x
371 offset := x*n + y
372 if offset < length {
373 offset += x
374 }
375 if length != offset {
376 pad := offset - length
377 if !dryrun {
378 serializeTLVOptionPadding(buf[length-2:], pad)
379 }
380 length += pad
381 }
382 }
383 }
384 if dryrun {
385 l = opt.serializeTo(nil, fixLengths, true)
386 } else {
387 l = opt.serializeTo(buf[length-2:], fixLengths, false)
388 }
389 length += l
390 }
391 if fixLengths {
392 pad := length % 8
393 if pad != 0 {
394 if !dryrun {
395 serializeTLVOptionPadding(buf[length-2:], pad)
396 }
397 length += pad
398 }
399 }
400 return length - 2
401}
402
403type ipv6ExtensionBase struct {
404 BaseLayer
405 NextHeader IPProtocol
406 HeaderLength uint8
407 ActualLength int
408}
409
410func decodeIPv6ExtensionBase(data []byte, df gopacket.DecodeFeedback) (i ipv6ExtensionBase, returnedErr error) {
411 if len(data) < 2 {
412 df.SetTruncated()
413 return ipv6ExtensionBase{}, fmt.Errorf("Invalid ip6-extension header. Length %d less than 2", len(data))
414 }
415 i.NextHeader = IPProtocol(data[0])
416 i.HeaderLength = data[1]
417 i.ActualLength = int(i.HeaderLength)*8 + 8
418 if len(data) < i.ActualLength {
419 return ipv6ExtensionBase{}, fmt.Errorf("Invalid ip6-extension header. Length %d less than specified length %d", len(data), i.ActualLength)
420 }
421 i.Contents = data[:i.ActualLength]
422 i.Payload = data[i.ActualLength:]
423 return
424}
425
426// IPv6ExtensionSkipper is a DecodingLayer which decodes and ignores v6
427// extensions. You can use it with a DecodingLayerParser to handle IPv6 stacks
428// which may or may not have extensions.
429type IPv6ExtensionSkipper struct {
430 NextHeader IPProtocol
431 BaseLayer
432}
433
434// DecodeFromBytes implementation according to gopacket.DecodingLayer
435func (i *IPv6ExtensionSkipper) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
436 extension, err := decodeIPv6ExtensionBase(data, df)
437 if err != nil {
438 return err
439 }
440 i.BaseLayer = BaseLayer{data[:extension.ActualLength], data[extension.ActualLength:]}
441 i.NextHeader = extension.NextHeader
442 return nil
443}
444
445// CanDecode implementation according to gopacket.DecodingLayer
446func (i *IPv6ExtensionSkipper) CanDecode() gopacket.LayerClass {
447 return LayerClassIPv6Extension
448}
449
450// NextLayerType implementation according to gopacket.DecodingLayer
451func (i *IPv6ExtensionSkipper) NextLayerType() gopacket.LayerType {
452 return i.NextHeader.LayerType()
453}
454
455// IPv6HopByHopOption is a TLV option present in an IPv6 hop-by-hop extension.
456type IPv6HopByHopOption ipv6HeaderTLVOption
457
458// IPv6HopByHop is the IPv6 hop-by-hop extension.
459type IPv6HopByHop struct {
460 ipv6ExtensionBase
461 Options []*IPv6HopByHopOption
462}
463
464// LayerType returns LayerTypeIPv6HopByHop.
465func (i *IPv6HopByHop) LayerType() gopacket.LayerType { return LayerTypeIPv6HopByHop }
466
467// SerializeTo implementation according to gopacket.SerializableLayer
468func (i *IPv6HopByHop) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
469 var bytes []byte
470 var err error
471
472 o := make([]*ipv6HeaderTLVOption, 0, len(i.Options))
473 for _, v := range i.Options {
474 o = append(o, (*ipv6HeaderTLVOption)(v))
475 }
476
477 l := serializeIPv6HeaderTLVOptions(nil, o, opts.FixLengths)
478 bytes, err = b.PrependBytes(l)
479 if err != nil {
480 return err
481 }
482 serializeIPv6HeaderTLVOptions(bytes, o, opts.FixLengths)
483
484 length := len(bytes) + 2
485 if length%8 != 0 {
486 return errors.New("IPv6HopByHop actual length must be multiple of 8")
487 }
488 bytes, err = b.PrependBytes(2)
489 if err != nil {
490 return err
491 }
492 bytes[0] = uint8(i.NextHeader)
493 if opts.FixLengths {
494 i.HeaderLength = uint8((length / 8) - 1)
495 }
496 bytes[1] = uint8(i.HeaderLength)
497 return nil
498}
499
500// DecodeFromBytes implementation according to gopacket.DecodingLayer
501func (i *IPv6HopByHop) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
502 var err error
503 i.ipv6ExtensionBase, err = decodeIPv6ExtensionBase(data, df)
504 if err != nil {
505 return err
506 }
507 offset := 2
508 for offset < i.ActualLength {
509 opt := decodeIPv6HeaderTLVOption(data[offset:])
510 i.Options = append(i.Options, (*IPv6HopByHopOption)(opt))
511 offset += opt.ActualLength
512 }
513 return nil
514}
515
516func decodeIPv6HopByHop(data []byte, p gopacket.PacketBuilder) error {
517 i := &IPv6HopByHop{}
518 err := i.DecodeFromBytes(data, p)
519 p.AddLayer(i)
520 if err != nil {
521 return err
522 }
523 return p.NextDecoder(i.NextHeader)
524}
525
526// SetJumboLength adds the IPv6HopByHopOptionJumbogram with the given length
527func (o *IPv6HopByHopOption) SetJumboLength(len uint32) {
528 o.OptionType = IPv6HopByHopOptionJumbogram
529 o.OptionLength = 4
530 o.ActualLength = 6
531 if o.OptionData == nil {
532 o.OptionData = make([]byte, 4)
533 }
534 binary.BigEndian.PutUint32(o.OptionData, len)
535 o.OptionAlignment = [2]uint8{4, 2}
536}
537
538// IPv6Routing is the IPv6 routing extension.
539type IPv6Routing struct {
540 ipv6ExtensionBase
541 RoutingType uint8
542 SegmentsLeft uint8
543 // This segment is supposed to be zero according to RFC2460, the second set of
544 // 4 bytes in the extension.
545 Reserved []byte
546 // SourceRoutingIPs is the set of IPv6 addresses requested for source routing,
547 // set only if RoutingType == 0.
548 SourceRoutingIPs []net.IP
549}
550
551// LayerType returns LayerTypeIPv6Routing.
552func (i *IPv6Routing) LayerType() gopacket.LayerType { return LayerTypeIPv6Routing }
553
554func decodeIPv6Routing(data []byte, p gopacket.PacketBuilder) error {
555 base, err := decodeIPv6ExtensionBase(data, p)
556 if err != nil {
557 return err
558 }
559 i := &IPv6Routing{
560 ipv6ExtensionBase: base,
561 RoutingType: data[2],
562 SegmentsLeft: data[3],
563 Reserved: data[4:8],
564 }
565 switch i.RoutingType {
566 case 0: // Source routing
567 if (i.ActualLength-8)%16 != 0 {
568 return fmt.Errorf("Invalid IPv6 source routing, length of type 0 packet %d", i.ActualLength)
569 }
570 for d := i.Contents[8:]; len(d) >= 16; d = d[16:] {
571 i.SourceRoutingIPs = append(i.SourceRoutingIPs, net.IP(d[:16]))
572 }
573 default:
574 return fmt.Errorf("Unknown IPv6 routing header type %d", i.RoutingType)
575 }
576 p.AddLayer(i)
577 return p.NextDecoder(i.NextHeader)
578}
579
580// IPv6Fragment is the IPv6 fragment header, used for packet
581// fragmentation/defragmentation.
582type IPv6Fragment struct {
583 BaseLayer
584 NextHeader IPProtocol
585 // Reserved1 is bits [8-16), from least to most significant, 0-indexed
586 Reserved1 uint8
587 FragmentOffset uint16
588 // Reserved2 is bits [29-31), from least to most significant, 0-indexed
589 Reserved2 uint8
590 MoreFragments bool
591 Identification uint32
592}
593
594// LayerType returns LayerTypeIPv6Fragment.
595func (i *IPv6Fragment) LayerType() gopacket.LayerType { return LayerTypeIPv6Fragment }
596
597func decodeIPv6Fragment(data []byte, p gopacket.PacketBuilder) error {
598 if len(data) < 8 {
599 p.SetTruncated()
600 return fmt.Errorf("Invalid ip6-fragment header. Length %d less than 8", len(data))
601 }
602 i := &IPv6Fragment{
603 BaseLayer: BaseLayer{data[:8], data[8:]},
604 NextHeader: IPProtocol(data[0]),
605 Reserved1: data[1],
606 FragmentOffset: binary.BigEndian.Uint16(data[2:4]) >> 3,
607 Reserved2: data[3] & 0x6 >> 1,
608 MoreFragments: data[3]&0x1 != 0,
609 Identification: binary.BigEndian.Uint32(data[4:8]),
610 }
611 p.AddLayer(i)
612 return p.NextDecoder(gopacket.DecodeFragment)
613}
614
615// IPv6DestinationOption is a TLV option present in an IPv6 destination options extension.
616type IPv6DestinationOption ipv6HeaderTLVOption
617
618// IPv6Destination is the IPv6 destination options header.
619type IPv6Destination struct {
620 ipv6ExtensionBase
621 Options []*IPv6DestinationOption
622}
623
624// LayerType returns LayerTypeIPv6Destination.
625func (i *IPv6Destination) LayerType() gopacket.LayerType { return LayerTypeIPv6Destination }
626
627// DecodeFromBytes implementation according to gopacket.DecodingLayer
628func (i *IPv6Destination) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
629 var err error
630 i.ipv6ExtensionBase, err = decodeIPv6ExtensionBase(data, df)
631 if err != nil {
632 return err
633 }
634 offset := 2
635 for offset < i.ActualLength {
636 opt := decodeIPv6HeaderTLVOption(data[offset:])
637 i.Options = append(i.Options, (*IPv6DestinationOption)(opt))
638 offset += opt.ActualLength
639 }
640 return nil
641}
642
643func decodeIPv6Destination(data []byte, p gopacket.PacketBuilder) error {
644 i := &IPv6Destination{}
645 err := i.DecodeFromBytes(data, p)
646 p.AddLayer(i)
647 if err != nil {
648 return err
649 }
650 return p.NextDecoder(i.NextHeader)
651}
652
653// SerializeTo writes the serialized form of this layer into the
654// SerializationBuffer, implementing gopacket.SerializableLayer.
655// See the docs for gopacket.SerializableLayer for more info.
656func (i *IPv6Destination) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
657 var bytes []byte
658 var err error
659
660 o := make([]*ipv6HeaderTLVOption, 0, len(i.Options))
661 for _, v := range i.Options {
662 o = append(o, (*ipv6HeaderTLVOption)(v))
663 }
664
665 l := serializeIPv6HeaderTLVOptions(nil, o, opts.FixLengths)
666 bytes, err = b.PrependBytes(l)
667 if err != nil {
668 return err
669 }
670 serializeIPv6HeaderTLVOptions(bytes, o, opts.FixLengths)
671
672 length := len(bytes) + 2
673 if length%8 != 0 {
674 return errors.New("IPv6Destination actual length must be multiple of 8")
675 }
676 bytes, err = b.PrependBytes(2)
677 if err != nil {
678 return err
679 }
680 bytes[0] = uint8(i.NextHeader)
681 if opts.FixLengths {
682 i.HeaderLength = uint8((length / 8) - 1)
683 }
684 bytes[1] = uint8(i.HeaderLength)
685 return nil
686}
687
688func checkIPv6Address(addr net.IP) error {
689 if len(addr) == net.IPv6len {
690 return nil
691 }
692 if len(addr) == net.IPv4len {
693 return errors.New("address is IPv4")
694 }
695 return fmt.Errorf("wrong length of %d bytes instead of %d", len(addr), net.IPv6len)
696}
697
698// AddressTo16 ensures IPv6.SrcIP and IPv6.DstIP are actually IPv6 addresses (i.e. 16 byte addresses)
699func (ipv6 *IPv6) AddressTo16() error {
700 if err := checkIPv6Address(ipv6.SrcIP); err != nil {
701 return fmt.Errorf("Invalid source IPv6 address (%s)", err)
702 }
703 if err := checkIPv6Address(ipv6.DstIP); err != nil {
704 return fmt.Errorf("Invalid destination IPv6 address (%s)", err)
705 }
706 return nil
707}