123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- // Copyright 2012 Google, Inc. All rights reserved.
- // Copyright 2009-2011 Andreas Krennmair. All rights reserved.
- //
- // Use of this source code is governed by a BSD-style license
- // that can be found in the LICENSE file in the root of the source
- // tree.
- package layers
- import (
- "encoding/binary"
- "encoding/hex"
- "errors"
- "fmt"
- "net"
- "time"
- "github.com/google/gopacket"
- )
- // Based on RFC 4861
- // ICMPv6Opt indicate how to decode the data associated with each ICMPv6Option.
- type ICMPv6Opt uint8
- const (
- _ ICMPv6Opt = iota
- // ICMPv6OptSourceAddress contains the link-layer address of the sender of
- // the packet. It is used in the Neighbor Solicitation, Router
- // Solicitation, and Router Advertisement packets. Must be ignored for other
- // Neighbor discovery messages.
- ICMPv6OptSourceAddress
- // ICMPv6OptTargetAddress contains the link-layer address of the target. It
- // is used in Neighbor Advertisement and Redirect packets. Must be ignored
- // for other Neighbor discovery messages.
- ICMPv6OptTargetAddress
- // ICMPv6OptPrefixInfo provides hosts with on-link prefixes and prefixes
- // for Address Autoconfiguration. The Prefix Information option appears in
- // Router Advertisement packets and MUST be silently ignored for other
- // messages.
- ICMPv6OptPrefixInfo
- // ICMPv6OptRedirectedHeader is used in Redirect messages and contains all
- // or part of the packet that is being redirected.
- ICMPv6OptRedirectedHeader
- // ICMPv6OptMTU is used in Router Advertisement messages to ensure that all
- // nodes on a link use the same MTU value in those cases where the link MTU
- // is not well known. This option MUST be silently ignored for other
- // Neighbor Discovery messages.
- ICMPv6OptMTU
- )
- // ICMPv6RouterSolicitation is sent by hosts to find routers.
- type ICMPv6RouterSolicitation struct {
- BaseLayer
- Options ICMPv6Options
- }
- // ICMPv6RouterAdvertisement is sent by routers in response to Solicitation.
- type ICMPv6RouterAdvertisement struct {
- BaseLayer
- HopLimit uint8
- Flags uint8
- RouterLifetime uint16
- ReachableTime uint32
- RetransTimer uint32
- Options ICMPv6Options
- }
- // ICMPv6NeighborSolicitation is sent to request the link-layer address of a
- // target node.
- type ICMPv6NeighborSolicitation struct {
- BaseLayer
- TargetAddress net.IP
- Options ICMPv6Options
- }
- // ICMPv6NeighborAdvertisement is sent by nodes in response to Solicitation.
- type ICMPv6NeighborAdvertisement struct {
- BaseLayer
- Flags uint8
- TargetAddress net.IP
- Options ICMPv6Options
- }
- // ICMPv6Redirect is sent by routers to inform hosts of a better first-hop node
- // on the path to a destination.
- type ICMPv6Redirect struct {
- BaseLayer
- TargetAddress net.IP
- DestinationAddress net.IP
- Options ICMPv6Options
- }
- // ICMPv6Option contains the type and data for a single option.
- type ICMPv6Option struct {
- Type ICMPv6Opt
- Data []byte
- }
- // ICMPv6Options is a slice of ICMPv6Option.
- type ICMPv6Options []ICMPv6Option
- func (i ICMPv6Opt) String() string {
- switch i {
- case ICMPv6OptSourceAddress:
- return "SourceAddress"
- case ICMPv6OptTargetAddress:
- return "TargetAddress"
- case ICMPv6OptPrefixInfo:
- return "PrefixInfo"
- case ICMPv6OptRedirectedHeader:
- return "RedirectedHeader"
- case ICMPv6OptMTU:
- return "MTU"
- default:
- return fmt.Sprintf("Unknown(%d)", i)
- }
- }
- // LayerType returns LayerTypeICMPv6.
- func (i *ICMPv6RouterSolicitation) LayerType() gopacket.LayerType {
- return LayerTypeICMPv6RouterSolicitation
- }
- // NextLayerType returns the layer type contained by this DecodingLayer.
- func (i *ICMPv6RouterSolicitation) NextLayerType() gopacket.LayerType {
- return gopacket.LayerTypePayload
- }
- // DecodeFromBytes decodes the given bytes into this layer.
- func (i *ICMPv6RouterSolicitation) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
- // first 4 bytes are reserved followed by options
- if len(data) < 4 {
- df.SetTruncated()
- return errors.New("ICMP layer less then 4 bytes for ICMPv6 router solicitation")
- }
- // truncate old options
- i.Options = i.Options[:0]
- return i.Options.DecodeFromBytes(data[4:], df)
- }
- // SerializeTo writes the serialized form of this layer into the
- // SerializationBuffer, implementing gopacket.SerializableLayer.
- // See the docs for gopacket.SerializableLayer for more info.
- func (i *ICMPv6RouterSolicitation) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
- if err := i.Options.SerializeTo(b, opts); err != nil {
- return err
- }
- buf, err := b.PrependBytes(4)
- if err != nil {
- return err
- }
- copy(buf, lotsOfZeros[:4])
- return nil
- }
- // LayerType returns LayerTypeICMPv6RouterAdvertisement.
- func (i *ICMPv6RouterAdvertisement) LayerType() gopacket.LayerType {
- return LayerTypeICMPv6RouterAdvertisement
- }
- // NextLayerType returns the layer type contained by this DecodingLayer.
- func (i *ICMPv6RouterAdvertisement) NextLayerType() gopacket.LayerType {
- return gopacket.LayerTypePayload
- }
- // DecodeFromBytes decodes the given bytes into this layer.
- func (i *ICMPv6RouterAdvertisement) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
- if len(data) < 12 {
- df.SetTruncated()
- return errors.New("ICMP layer less then 12 bytes for ICMPv6 router advertisement")
- }
- i.HopLimit = uint8(data[0])
- // M, O bit followed by 6 reserved bits
- i.Flags = uint8(data[1])
- i.RouterLifetime = binary.BigEndian.Uint16(data[2:4])
- i.ReachableTime = binary.BigEndian.Uint32(data[4:8])
- i.RetransTimer = binary.BigEndian.Uint32(data[8:12])
- i.BaseLayer = BaseLayer{data, nil} // assume no payload
- // truncate old options
- i.Options = i.Options[:0]
- return i.Options.DecodeFromBytes(data[12:], df)
- }
- // SerializeTo writes the serialized form of this layer into the
- // SerializationBuffer, implementing gopacket.SerializableLayer.
- // See the docs for gopacket.SerializableLayer for more info.
- func (i *ICMPv6RouterAdvertisement) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
- if err := i.Options.SerializeTo(b, opts); err != nil {
- return err
- }
- buf, err := b.PrependBytes(12)
- if err != nil {
- return err
- }
- buf[0] = byte(i.HopLimit)
- buf[1] = byte(i.Flags)
- binary.BigEndian.PutUint16(buf[2:], i.RouterLifetime)
- binary.BigEndian.PutUint32(buf[4:], i.ReachableTime)
- binary.BigEndian.PutUint32(buf[8:], i.RetransTimer)
- return nil
- }
- // ManagedAddressConfig is true when addresses are available via DHCPv6. If
- // set, the OtherConfig flag is redundant.
- func (i *ICMPv6RouterAdvertisement) ManagedAddressConfig() bool {
- return i.Flags&0x80 != 1
- }
- // OtherConfig is true when there is other configuration information available
- // via DHCPv6. For example, DNS-related information.
- func (i *ICMPv6RouterAdvertisement) OtherConfig() bool {
- return i.Flags&0x40 != 1
- }
- // LayerType returns LayerTypeICMPv6NeighborSolicitation.
- func (i *ICMPv6NeighborSolicitation) LayerType() gopacket.LayerType {
- return LayerTypeICMPv6NeighborSolicitation
- }
- // NextLayerType returns the layer type contained by this DecodingLayer.
- func (i *ICMPv6NeighborSolicitation) NextLayerType() gopacket.LayerType {
- return gopacket.LayerTypePayload
- }
- // DecodeFromBytes decodes the given bytes into this layer.
- func (i *ICMPv6NeighborSolicitation) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
- if len(data) < 20 {
- df.SetTruncated()
- return errors.New("ICMP layer less then 20 bytes for ICMPv6 neighbor solicitation")
- }
- i.TargetAddress = net.IP(data[4:20])
- i.BaseLayer = BaseLayer{data, nil} // assume no payload
- // truncate old options
- i.Options = i.Options[:0]
- return i.Options.DecodeFromBytes(data[20:], df)
- }
- // SerializeTo writes the serialized form of this layer into the
- // SerializationBuffer, implementing gopacket.SerializableLayer.
- // See the docs for gopacket.SerializableLayer for more info.
- func (i *ICMPv6NeighborSolicitation) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
- if err := i.Options.SerializeTo(b, opts); err != nil {
- return err
- }
- buf, err := b.PrependBytes(20)
- if err != nil {
- return err
- }
- copy(buf, lotsOfZeros[:4])
- copy(buf[4:], i.TargetAddress)
- return nil
- }
- // LayerType returns LayerTypeICMPv6NeighborAdvertisement.
- func (i *ICMPv6NeighborAdvertisement) LayerType() gopacket.LayerType {
- return LayerTypeICMPv6NeighborAdvertisement
- }
- // NextLayerType returns the layer type contained by this DecodingLayer.
- func (i *ICMPv6NeighborAdvertisement) NextLayerType() gopacket.LayerType {
- return gopacket.LayerTypePayload
- }
- // DecodeFromBytes decodes the given bytes into this layer.
- func (i *ICMPv6NeighborAdvertisement) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
- if len(data) < 20 {
- df.SetTruncated()
- return errors.New("ICMP layer less then 20 bytes for ICMPv6 neighbor advertisement")
- }
- i.Flags = uint8(data[0])
- i.TargetAddress = net.IP(data[4:20])
- i.BaseLayer = BaseLayer{data, nil} // assume no payload
- // truncate old options
- i.Options = i.Options[:0]
- return i.Options.DecodeFromBytes(data[20:], df)
- }
- // SerializeTo writes the serialized form of this layer into the
- // SerializationBuffer, implementing gopacket.SerializableLayer.
- // See the docs for gopacket.SerializableLayer for more info.
- func (i *ICMPv6NeighborAdvertisement) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
- if err := i.Options.SerializeTo(b, opts); err != nil {
- return err
- }
- buf, err := b.PrependBytes(20)
- if err != nil {
- return err
- }
- buf[0] = byte(i.Flags)
- copy(buf[1:], lotsOfZeros[:3])
- copy(buf[4:], i.TargetAddress)
- return nil
- }
- // Router indicates whether the sender is a router or not.
- func (i *ICMPv6NeighborAdvertisement) Router() bool {
- return i.Flags&0x80 != 0
- }
- // Solicited indicates whether the advertisement was solicited or not.
- func (i *ICMPv6NeighborAdvertisement) Solicited() bool {
- return i.Flags&0x40 != 0
- }
- // Override indicates whether the advertisement should Override an existing
- // cache entry.
- func (i *ICMPv6NeighborAdvertisement) Override() bool {
- return i.Flags&0x20 != 0
- }
- // LayerType returns LayerTypeICMPv6Redirect.
- func (i *ICMPv6Redirect) LayerType() gopacket.LayerType {
- return LayerTypeICMPv6Redirect
- }
- // NextLayerType returns the layer type contained by this DecodingLayer.
- func (i *ICMPv6Redirect) NextLayerType() gopacket.LayerType {
- return gopacket.LayerTypePayload
- }
- // DecodeFromBytes decodes the given bytes into this layer.
- func (i *ICMPv6Redirect) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
- if len(data) < 36 {
- df.SetTruncated()
- return errors.New("ICMP layer less then 36 bytes for ICMPv6 redirect")
- }
- i.TargetAddress = net.IP(data[4:20])
- i.DestinationAddress = net.IP(data[20:36])
- i.BaseLayer = BaseLayer{data, nil} // assume no payload
- // truncate old options
- i.Options = i.Options[:0]
- return i.Options.DecodeFromBytes(data[36:], df)
- }
- // SerializeTo writes the serialized form of this layer into the
- // SerializationBuffer, implementing gopacket.SerializableLayer.
- // See the docs for gopacket.SerializableLayer for more info.
- func (i *ICMPv6Redirect) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
- if err := i.Options.SerializeTo(b, opts); err != nil {
- return err
- }
- buf, err := b.PrependBytes(36)
- if err != nil {
- return err
- }
- copy(buf, lotsOfZeros[:4])
- copy(buf[4:], i.TargetAddress)
- copy(buf[20:], i.DestinationAddress)
- return nil
- }
- func (i ICMPv6Option) String() string {
- hd := hex.EncodeToString(i.Data)
- if len(hd) > 0 {
- hd = " 0x" + hd
- }
- switch i.Type {
- case ICMPv6OptSourceAddress, ICMPv6OptTargetAddress:
- return fmt.Sprintf("ICMPv6Option(%s:%v)",
- i.Type,
- net.HardwareAddr(i.Data))
- case ICMPv6OptPrefixInfo:
- if len(i.Data) == 30 {
- prefixLen := uint8(i.Data[0])
- onLink := (i.Data[1]&0x80 != 0)
- autonomous := (i.Data[1]&0x40 != 0)
- validLifetime := time.Duration(binary.BigEndian.Uint32(i.Data[2:6])) * time.Second
- preferredLifetime := time.Duration(binary.BigEndian.Uint32(i.Data[6:10])) * time.Second
- prefix := net.IP(i.Data[14:])
- return fmt.Sprintf("ICMPv6Option(%s:%v/%v:%t:%t:%v:%v)",
- i.Type,
- prefix, prefixLen,
- onLink, autonomous,
- validLifetime, preferredLifetime)
- }
- case ICMPv6OptRedirectedHeader:
- // could invoke IP decoder on data... probably best not to
- break
- case ICMPv6OptMTU:
- if len(i.Data) == 6 {
- return fmt.Sprintf("ICMPv6Option(%s:%v)",
- i.Type,
- binary.BigEndian.Uint32(i.Data[2:]))
- }
- }
- return fmt.Sprintf("ICMPv6Option(%s:%s)", i.Type, hd)
- }
- // DecodeFromBytes decodes the given bytes into this layer.
- func (i *ICMPv6Options) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
- for len(data) > 0 {
- if len(data) < 2 {
- df.SetTruncated()
- return errors.New("ICMP layer less then 2 bytes for ICMPv6 message option")
- }
- // unit is 8 octets, convert to bytes
- length := int(data[1]) * 8
- if len(data) < length {
- df.SetTruncated()
- return fmt.Errorf("ICMP layer only %v bytes for ICMPv6 message option with length %v", len(data), length)
- }
- o := ICMPv6Option{
- Type: ICMPv6Opt(data[0]),
- Data: data[2:length],
- }
- // chop off option we just consumed
- data = data[length:]
- *i = append(*i, o)
- }
- return nil
- }
- // SerializeTo writes the serialized form of this layer into the
- // SerializationBuffer, implementing gopacket.SerializableLayer.
- // See the docs for gopacket.SerializableLayer for more info.
- func (i *ICMPv6Options) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
- for _, opt := range []ICMPv6Option(*i) {
- length := len(opt.Data) + 2
- buf, err := b.PrependBytes(length)
- if err != nil {
- return err
- }
- buf[0] = byte(opt.Type)
- buf[1] = byte(length / 8)
- copy(buf[2:], opt.Data)
- }
- return nil
- }
- func decodeICMPv6RouterSolicitation(data []byte, p gopacket.PacketBuilder) error {
- i := &ICMPv6RouterSolicitation{}
- return decodingLayerDecoder(i, data, p)
- }
- func decodeICMPv6RouterAdvertisement(data []byte, p gopacket.PacketBuilder) error {
- i := &ICMPv6RouterAdvertisement{}
- return decodingLayerDecoder(i, data, p)
- }
- func decodeICMPv6NeighborSolicitation(data []byte, p gopacket.PacketBuilder) error {
- i := &ICMPv6NeighborSolicitation{}
- return decodingLayerDecoder(i, data, p)
- }
- func decodeICMPv6NeighborAdvertisement(data []byte, p gopacket.PacketBuilder) error {
- i := &ICMPv6NeighborAdvertisement{}
- return decodingLayerDecoder(i, data, p)
- }
- func decodeICMPv6Redirect(data []byte, p gopacket.PacketBuilder) error {
- i := &ICMPv6Redirect{}
- return decodingLayerDecoder(i, data, p)
- }
|