github.com/gopacket/gopacket@v1.1.0/layers/ip6.go (about)

     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/gopacket/gopacket"
    17  )
    18  
    19  const (
    20  	// IPv6HopByHopOptionJumbogram code as defined in RFC 2675
    21  	IPv6HopByHopOptionJumbogram = 0xC2
    22  )
    23  
    24  const (
    25  	ipv6MaxPayloadLength = 65535
    26  )
    27  
    28  // IPv6 is the layer for the IPv6 header.
    29  type 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
    46  func (ipv6 *IPv6) LayerType() gopacket.LayerType { return LayerTypeIPv6 }
    47  
    48  // NetworkFlow returns this new Flow (EndpointIPv6, SrcIP, DstIP)
    49  func (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
    54  func 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)
    80  func 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)
   105  func 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.
   139  func (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
   221  func (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
   281  func (ipv6 *IPv6) CanDecode() gopacket.LayerClass {
   282  	return LayerTypeIPv6
   283  }
   284  
   285  // NextLayerType implementation according to gopacket.DecodingLayer
   286  func (ipv6 *IPv6) NextLayerType() gopacket.LayerType {
   287  	if ipv6.HopByHop != nil {
   288  		return ipv6.HopByHop.NextHeader.LayerType()
   289  	}
   290  	return ipv6.NextHeader.LayerType()
   291  }
   292  
   293  func 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  
   307  type ipv6HeaderTLVOption struct {
   308  	OptionType, OptionLength uint8
   309  	ActualLength             int
   310  	OptionData               []byte
   311  	OptionAlignment          [2]uint8 // Xn+Y = [2]uint8{X, Y}
   312  }
   313  
   314  func (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  
   327  func 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  
   348  func 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
   368  func 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  
   411  type ipv6ExtensionBase struct {
   412  	BaseLayer
   413  	NextHeader   IPProtocol
   414  	HeaderLength uint8
   415  	ActualLength int
   416  }
   417  
   418  func 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.
   437  type IPv6ExtensionSkipper struct {
   438  	NextHeader IPProtocol
   439  	BaseLayer
   440  }
   441  
   442  // DecodeFromBytes implementation according to gopacket.DecodingLayer
   443  func (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
   454  func (i *IPv6ExtensionSkipper) CanDecode() gopacket.LayerClass {
   455  	return LayerClassIPv6Extension
   456  }
   457  
   458  // NextLayerType implementation according to gopacket.DecodingLayer
   459  func (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.
   464  type IPv6HopByHopOption ipv6HeaderTLVOption
   465  
   466  // IPv6HopByHop is the IPv6 hop-by-hop extension.
   467  type IPv6HopByHop struct {
   468  	ipv6ExtensionBase
   469  	Options []*IPv6HopByHopOption
   470  }
   471  
   472  // LayerType returns LayerTypeIPv6HopByHop.
   473  func (i *IPv6HopByHop) LayerType() gopacket.LayerType { return LayerTypeIPv6HopByHop }
   474  
   475  // SerializeTo implementation according to gopacket.SerializableLayer
   476  func (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
   509  func (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  
   528  func 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
   539  func (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.
   551  type 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.
   564  func (i *IPv6Routing) LayerType() gopacket.LayerType { return LayerTypeIPv6Routing }
   565  
   566  func 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.
   594  type 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.
   607  func (i *IPv6Fragment) LayerType() gopacket.LayerType { return LayerTypeIPv6Fragment }
   608  
   609  func 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.
   628  type IPv6DestinationOption ipv6HeaderTLVOption
   629  
   630  // IPv6Destination is the IPv6 destination options header.
   631  type IPv6Destination struct {
   632  	ipv6ExtensionBase
   633  	Options []*IPv6DestinationOption
   634  }
   635  
   636  // LayerType returns LayerTypeIPv6Destination.
   637  func (i *IPv6Destination) LayerType() gopacket.LayerType { return LayerTypeIPv6Destination }
   638  
   639  // DecodeFromBytes implementation according to gopacket.DecodingLayer
   640  func (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  
   658  func 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.
   671  func (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  
   703  func 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)
   714  func (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  }