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