1 // Copyright 2012 Google, Inc. All rights reserved.
2 // Copyright 2009-2011 Andreas Krennmair. All rights reserved.
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
16 "github.com/google/gopacket"
20 IPv6HopByHopOptionJumbogram = 0xC2 // RFC 2675
24 ipv6MaxPayloadLength = 65535
27 // IPv6 is the layer for the IPv6 header.
29 // http://www.networksorcery.com/enp/protocol/ipv6.htm
39 HopByHop *IPv6HopByHop
40 // hbh will be pointed to by HopByHop if that layer exists.
44 // LayerType returns LayerTypeIPv6
45 func (i *IPv6) LayerType() gopacket.LayerType { return LayerTypeIPv6 }
47 func (i *IPv6) NetworkFlow() gopacket.Flow {
48 return gopacket.NewFlow(EndpointIPv6, i.SrcIP, i.DstIP)
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
55 for _, t := range hopopts.Options {
56 if t.OptionType == IPv6HopByHopOptionJumbogram {
65 if len(tlv.OptionData) != 4 {
66 return 0, false, errors.New("Jumbo length TLV data must have length 4")
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)
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
81 if ip6.HopByHop == nil {
83 ip6.HopByHop = &IPv6HopByHop{}
84 ip6.HopByHop.NextHeader = ip6.NextHeader
85 ip6.HopByHop.HeaderLength = 0
86 ip6.NextHeader = IPProtocolIPv6HopByHop
88 for _, t := range ip6.HopByHop.Options {
89 if t.OptionType == IPv6HopByHopOptionJumbogram {
96 tlv = &IPv6HopByHopOption{}
97 ip6.HopByHop.Options = append(ip6.HopByHop.Options, tlv)
102 // Set jumbo length in serialized IPv6 payload (starting with HopByHop header)
103 func setIPv6PayloadJumboLength(hbh []byte) error {
106 //HopByHop is minimum 8 bytes
107 return fmt.Errorf("Invalid IPv6 payload (length %d)", pLen)
109 hbhLen := int((hbh[1] + 1) * 8)
111 return fmt.Errorf("Invalid hop-by-hop length (length: %d, payload: %d", hbhLen, pLen)
113 offset := 2 //start with options
114 for offset < hbhLen {
121 optLen := int(hbh[offset+1])
122 if opt == IPv6HopByHopOptionJumbogram {
124 binary.BigEndian.PutUint32(hbh[offset+2:], uint32(pLen))
127 return fmt.Errorf("Jumbo TLV too short (%d bytes)", optLen)
131 return errors.New("Jumbo TLV not found")
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 {
143 if pLen > ipv6MaxPayloadLength {
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)
152 _, ok, err := getIPv6HopByHopJumboLength(ip6.HopByHop)
157 return errors.New("Missing jumbo length hop-by-hop option")
161 if ip6.HopByHop != nil {
162 if ip6.NextHeader != IPProtocolIPv6HopByHop {
163 // Just fix it instead of throwing an error
164 ip6.NextHeader = IPProtocolIPv6HopByHop
166 err = ip6.HopByHop.SerializeTo(b, opts)
172 if opts.FixLengths && jumbo {
173 err := setIPv6PayloadJumboLength(payload)
179 if !jumbo && pLen > ipv6MaxPayloadLength {
180 return errors.New("Cannot fit payload into IPv6 header")
182 bytes, err := b.PrependBytes(40)
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))
193 ip6.Length = uint16(pLen)
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 {
202 copy(bytes[8:], ip6.SrcIP)
203 copy(bytes[24:], ip6.DstIP)
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]
217 ip6.BaseLayer = BaseLayer{data[:40], data[40:]}
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)
226 ip6.HopByHop = &ip6.hbh
227 pEnd, jumbo, err := getIPv6HopByHopJumboLength(ip6.HopByHop)
231 if jumbo && ip6.Length == 0 {
233 if pEnd > len(ip6.Payload) {
235 pEnd = len(ip6.Payload)
237 ip6.Payload = ip6.Payload[:pEnd]
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")
247 return fmt.Errorf("IPv6 length 0, but next header is %v, not HopByHop", ip6.NextHeader)
249 pEnd := int(ip6.Length)
250 if pEnd > len(ip6.Payload) {
252 pEnd = len(ip6.Payload)
254 ip6.Payload = ip6.Payload[:pEnd]
259 func (i *IPv6) CanDecode() gopacket.LayerClass {
263 func (i *IPv6) NextLayerType() gopacket.LayerType {
264 if i.HopByHop != nil {
265 return i.HopByHop.NextHeader.LayerType()
267 return i.NextHeader.LayerType()
270 func decodeIPv6(data []byte, p gopacket.PacketBuilder) error {
272 err := ip6.DecodeFromBytes(data, p)
274 p.SetNetworkLayer(ip6)
275 if ip6.HopByHop != nil {
276 p.AddLayer(ip6.HopByHop)
281 return p.NextDecoder(ip6.NextLayerType())
284 type ipv6HeaderTLVOption struct {
285 OptionType, OptionLength uint8
288 OptionAlignment [2]uint8 // Xn+Y = [2]uint8{X, Y}
291 func (h *ipv6HeaderTLVOption) serializeTo(data []byte, fixLengths bool, dryrun bool) int {
293 h.OptionLength = uint8(len(h.OptionData))
295 length := int(h.OptionLength) + 2
297 data[0] = h.OptionType
298 data[1] = h.OptionLength
299 copy(data[2:], h.OptionData)
304 func decodeIPv6HeaderTLVOption(data []byte) (h *ipv6HeaderTLVOption) {
305 h = &ipv6HeaderTLVOption{}
310 h.OptionType = data[0]
311 h.OptionLength = data[1]
312 h.ActualLength = int(h.OptionLength) + 2
313 h.OptionData = data[2:h.ActualLength]
317 func serializeTLVOptionPadding(data []byte, padLength int) {
325 tlvLength := uint8(padLength) - 2
329 for k := range data[2:] {
336 // If buf is 'nil' do a serialize dry run
337 func serializeIPv6HeaderTLVOptions(buf []byte, options []*ipv6HeaderTLVOption, fixLengths bool) int {
342 for _, opt := range options {
344 x := int(opt.OptionAlignment[0])
345 y := int(opt.OptionAlignment[1])
352 if length != offset {
353 pad := offset - length
355 serializeTLVOptionPadding(buf[length-2:], pad)
362 l = opt.serializeTo(nil, fixLengths, true)
364 l = opt.serializeTo(buf[length-2:], fixLengths, false)
372 serializeTLVOptionPadding(buf[length-2:], pad)
380 type ipv6ExtensionBase struct {
382 NextHeader IPProtocol
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:]
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
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
411 func (i *IPv6ExtensionSkipper) CanDecode() gopacket.LayerClass {
412 return LayerClassIPv6Extension
415 func (i *IPv6ExtensionSkipper) NextLayerType() gopacket.LayerType {
416 return i.NextHeader.LayerType()
419 // IPv6HopByHopOption is a TLV option present in an IPv6 hop-by-hop extension.
420 type IPv6HopByHopOption ipv6HeaderTLVOption
422 // IPv6HopByHop is the IPv6 hop-by-hop extension.
423 type IPv6HopByHop struct {
425 Options []*IPv6HopByHopOption
428 // LayerType returns LayerTypeIPv6HopByHop.
429 func (i *IPv6HopByHop) LayerType() gopacket.LayerType { return LayerTypeIPv6HopByHop }
431 func (i *IPv6HopByHop) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
435 o := make([]*ipv6HeaderTLVOption, 0, len(i.Options))
436 for _, v := range i.Options {
437 o = append(o, (*ipv6HeaderTLVOption)(v))
440 l := serializeIPv6HeaderTLVOptions(nil, o, opts.FixLengths)
441 bytes, err = b.PrependBytes(l)
445 serializeIPv6HeaderTLVOptions(bytes, o, opts.FixLengths)
447 length := len(bytes) + 2
449 return errors.New("IPv6HopByHop actual length must be multiple of 8")
451 bytes, err = b.PrependBytes(2)
455 bytes[0] = uint8(i.NextHeader)
457 i.HeaderLength = uint8((length / 8) - 1)
459 bytes[1] = uint8(i.HeaderLength)
463 func (i *IPv6HopByHop) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
464 i.ipv6ExtensionBase = decodeIPv6ExtensionBase(data)
466 for offset < i.ActualLength {
467 opt := decodeIPv6HeaderTLVOption(data[offset:])
468 i.Options = append(i.Options, (*IPv6HopByHopOption)(opt))
469 offset += opt.ActualLength
474 func decodeIPv6HopByHop(data []byte, p gopacket.PacketBuilder) error {
476 err := i.DecodeFromBytes(data, p)
481 return p.NextDecoder(i.NextHeader)
484 func (o *IPv6HopByHopOption) SetJumboLength(len uint32) {
485 o.OptionType = IPv6HopByHopOptionJumbogram
488 if o.OptionData == nil {
489 o.OptionData = make([]byte, 4)
491 binary.BigEndian.PutUint32(o.OptionData, len)
492 o.OptionAlignment = [2]uint8{4, 2}
495 // IPv6Routing is the IPv6 routing extension.
496 type IPv6Routing struct {
500 // This segment is supposed to be zero according to RFC2460, the second set of
501 // 4 bytes in the extension.
503 // SourceRoutingIPs is the set of IPv6 addresses requested for source routing,
504 // set only if RoutingType == 0.
505 SourceRoutingIPs []net.IP
508 // LayerType returns LayerTypeIPv6Routing.
509 func (i *IPv6Routing) LayerType() gopacket.LayerType { return LayerTypeIPv6Routing }
511 func decodeIPv6Routing(data []byte, p gopacket.PacketBuilder) error {
513 ipv6ExtensionBase: decodeIPv6ExtensionBase(data),
514 RoutingType: data[2],
515 SegmentsLeft: data[3],
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)
523 for d := i.Contents[8:]; len(d) >= 16; d = d[16:] {
524 i.SourceRoutingIPs = append(i.SourceRoutingIPs, net.IP(d[:16]))
527 return fmt.Errorf("Unknown IPv6 routing header type %d", i.RoutingType)
530 return p.NextDecoder(i.NextHeader)
533 // IPv6Fragment is the IPv6 fragment header, used for packet
534 // fragmentation/defragmentation.
535 type IPv6Fragment struct {
537 NextHeader IPProtocol
538 // Reserved1 is bits [8-16), from least to most significant, 0-indexed
540 FragmentOffset uint16
541 // Reserved2 is bits [29-31), from least to most significant, 0-indexed
544 Identification uint32
547 // LayerType returns LayerTypeIPv6Fragment.
548 func (i *IPv6Fragment) LayerType() gopacket.LayerType { return LayerTypeIPv6Fragment }
550 func decodeIPv6Fragment(data []byte, p gopacket.PacketBuilder) error {
552 BaseLayer: BaseLayer{data[:8], data[8:]},
553 NextHeader: IPProtocol(data[0]),
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]),
561 return p.NextDecoder(gopacket.DecodeFragment)
564 // IPv6DestinationOption is a TLV option present in an IPv6 destination options extension.
565 type IPv6DestinationOption ipv6HeaderTLVOption
567 // IPv6Destination is the IPv6 destination options header.
568 type IPv6Destination struct {
570 Options []*IPv6DestinationOption
573 // LayerType returns LayerTypeIPv6Destination.
574 func (i *IPv6Destination) LayerType() gopacket.LayerType { return LayerTypeIPv6Destination }
576 func (i *IPv6Destination) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
577 i.ipv6ExtensionBase = decodeIPv6ExtensionBase(data)
579 for offset < i.ActualLength {
580 opt := decodeIPv6HeaderTLVOption(data[offset:])
581 i.Options = append(i.Options, (*IPv6DestinationOption)(opt))
582 offset += opt.ActualLength
587 func decodeIPv6Destination(data []byte, p gopacket.PacketBuilder) error {
588 i := &IPv6Destination{}
589 err := i.DecodeFromBytes(data, p)
594 return p.NextDecoder(i.NextHeader)
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 {
604 o := make([]*ipv6HeaderTLVOption, 0, len(i.Options))
605 for _, v := range i.Options {
606 o = append(o, (*ipv6HeaderTLVOption)(v))
609 l := serializeIPv6HeaderTLVOptions(nil, o, opts.FixLengths)
610 bytes, err = b.PrependBytes(l)
614 serializeIPv6HeaderTLVOptions(bytes, o, opts.FixLengths)
616 length := len(bytes) + 2
618 return errors.New("IPv6Destination actual length must be multiple of 8")
620 bytes, err = b.PrependBytes(2)
624 bytes[0] = uint8(i.NextHeader)
626 i.HeaderLength = uint8((length / 8) - 1)
628 bytes[1] = uint8(i.HeaderLength)
632 func checkIPv6Address(addr net.IP) error {
633 if len(addr) == net.IPv6len {
636 if len(addr) == net.IPv4len {
637 return errors.New("address is IPv4")
639 return fmt.Errorf("wrong length of %d bytes instead of %d", len(addr), net.IPv6len)
642 func (ip *IPv6) AddressTo16() error {
643 if err := checkIPv6Address(ip.SrcIP); err != nil {
644 return fmt.Errorf("Invalid source IPv6 address (%s)", err)
646 if err := checkIPv6Address(ip.DstIP); err != nil {
647 return fmt.Errorf("Invalid destination IPv6 address (%s)", err)