github.com/gopacket/gopacket@v1.1.0/layers/icmp6.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  	"reflect"
    15  
    16  	"github.com/gopacket/gopacket"
    17  )
    18  
    19  const (
    20  	// The following are from RFC 4443
    21  	ICMPv6TypeDestinationUnreachable = 1
    22  	ICMPv6TypePacketTooBig           = 2
    23  	ICMPv6TypeTimeExceeded           = 3
    24  	ICMPv6TypeParameterProblem       = 4
    25  	ICMPv6TypeEchoRequest            = 128
    26  	ICMPv6TypeEchoReply              = 129
    27  
    28  	// The following are from RFC 4861
    29  	ICMPv6TypeRouterSolicitation    = 133
    30  	ICMPv6TypeRouterAdvertisement   = 134
    31  	ICMPv6TypeNeighborSolicitation  = 135
    32  	ICMPv6TypeNeighborAdvertisement = 136
    33  	ICMPv6TypeRedirect              = 137
    34  
    35  	// The following are from RFC 2710
    36  	ICMPv6TypeMLDv1MulticastListenerQueryMessage  = 130
    37  	ICMPv6TypeMLDv1MulticastListenerReportMessage = 131
    38  	ICMPv6TypeMLDv1MulticastListenerDoneMessage   = 132
    39  
    40  	// The following are from RFC 3810
    41  	ICMPv6TypeMLDv2MulticastListenerReportMessageV2 = 143
    42  )
    43  
    44  const (
    45  	// DestinationUnreachable
    46  	ICMPv6CodeNoRouteToDst           = 0
    47  	ICMPv6CodeAdminProhibited        = 1
    48  	ICMPv6CodeBeyondScopeOfSrc       = 2
    49  	ICMPv6CodeAddressUnreachable     = 3
    50  	ICMPv6CodePortUnreachable        = 4
    51  	ICMPv6CodeSrcAddressFailedPolicy = 5
    52  	ICMPv6CodeRejectRouteToDst       = 6
    53  
    54  	// TimeExceeded
    55  	ICMPv6CodeHopLimitExceeded               = 0
    56  	ICMPv6CodeFragmentReassemblyTimeExceeded = 1
    57  
    58  	// ParameterProblem
    59  	ICMPv6CodeErroneousHeaderField   = 0
    60  	ICMPv6CodeUnrecognizedNextHeader = 1
    61  	ICMPv6CodeUnrecognizedIPv6Option = 2
    62  )
    63  
    64  type icmpv6TypeCodeInfoStruct struct {
    65  	typeStr string
    66  	codeStr *map[uint8]string
    67  }
    68  
    69  var (
    70  	icmpv6TypeCodeInfo = map[uint8]icmpv6TypeCodeInfoStruct{
    71  		ICMPv6TypeDestinationUnreachable: icmpv6TypeCodeInfoStruct{
    72  			"DestinationUnreachable", &map[uint8]string{
    73  				ICMPv6CodeNoRouteToDst:           "NoRouteToDst",
    74  				ICMPv6CodeAdminProhibited:        "AdminProhibited",
    75  				ICMPv6CodeBeyondScopeOfSrc:       "BeyondScopeOfSrc",
    76  				ICMPv6CodeAddressUnreachable:     "AddressUnreachable",
    77  				ICMPv6CodePortUnreachable:        "PortUnreachable",
    78  				ICMPv6CodeSrcAddressFailedPolicy: "SrcAddressFailedPolicy",
    79  				ICMPv6CodeRejectRouteToDst:       "RejectRouteToDst",
    80  			},
    81  		},
    82  		ICMPv6TypePacketTooBig: icmpv6TypeCodeInfoStruct{
    83  			"PacketTooBig", nil,
    84  		},
    85  		ICMPv6TypeTimeExceeded: icmpv6TypeCodeInfoStruct{
    86  			"TimeExceeded", &map[uint8]string{
    87  				ICMPv6CodeHopLimitExceeded:               "HopLimitExceeded",
    88  				ICMPv6CodeFragmentReassemblyTimeExceeded: "FragmentReassemblyTimeExceeded",
    89  			},
    90  		},
    91  		ICMPv6TypeParameterProblem: icmpv6TypeCodeInfoStruct{
    92  			"ParameterProblem", &map[uint8]string{
    93  				ICMPv6CodeErroneousHeaderField:   "ErroneousHeaderField",
    94  				ICMPv6CodeUnrecognizedNextHeader: "UnrecognizedNextHeader",
    95  				ICMPv6CodeUnrecognizedIPv6Option: "UnrecognizedIPv6Option",
    96  			},
    97  		},
    98  		ICMPv6TypeEchoRequest: icmpv6TypeCodeInfoStruct{
    99  			"EchoRequest", nil,
   100  		},
   101  		ICMPv6TypeEchoReply: icmpv6TypeCodeInfoStruct{
   102  			"EchoReply", nil,
   103  		},
   104  		ICMPv6TypeRouterSolicitation: icmpv6TypeCodeInfoStruct{
   105  			"RouterSolicitation", nil,
   106  		},
   107  		ICMPv6TypeRouterAdvertisement: icmpv6TypeCodeInfoStruct{
   108  			"RouterAdvertisement", nil,
   109  		},
   110  		ICMPv6TypeNeighborSolicitation: icmpv6TypeCodeInfoStruct{
   111  			"NeighborSolicitation", nil,
   112  		},
   113  		ICMPv6TypeNeighborAdvertisement: icmpv6TypeCodeInfoStruct{
   114  			"NeighborAdvertisement", nil,
   115  		},
   116  		ICMPv6TypeRedirect: icmpv6TypeCodeInfoStruct{
   117  			"Redirect", nil,
   118  		},
   119  	}
   120  )
   121  
   122  type ICMPv6TypeCode uint16
   123  
   124  // Type returns the ICMPv6 type field.
   125  func (a ICMPv6TypeCode) Type() uint8 {
   126  	return uint8(a >> 8)
   127  }
   128  
   129  // Code returns the ICMPv6 code field.
   130  func (a ICMPv6TypeCode) Code() uint8 {
   131  	return uint8(a)
   132  }
   133  
   134  func (a ICMPv6TypeCode) String() string {
   135  	t, c := a.Type(), a.Code()
   136  	strInfo, ok := icmpv6TypeCodeInfo[t]
   137  	if !ok {
   138  		// Unknown ICMPv6 type field
   139  		return fmt.Sprintf("%d(%d)", t, c)
   140  	}
   141  	typeStr := strInfo.typeStr
   142  	if strInfo.codeStr == nil && c == 0 {
   143  		// The ICMPv6 type does not make use of the code field
   144  		return fmt.Sprintf("%s", strInfo.typeStr)
   145  	}
   146  	if strInfo.codeStr == nil && c != 0 {
   147  		// The ICMPv6 type does not make use of the code field, but it is present anyway
   148  		return fmt.Sprintf("%s(Code: %d)", typeStr, c)
   149  	}
   150  	codeStr, ok := (*strInfo.codeStr)[c]
   151  	if !ok {
   152  		// We don't know this ICMPv6 code; print the numerical value
   153  		return fmt.Sprintf("%s(Code: %d)", typeStr, c)
   154  	}
   155  	return fmt.Sprintf("%s(%s)", typeStr, codeStr)
   156  }
   157  
   158  func (a ICMPv6TypeCode) GoString() string {
   159  	t := reflect.TypeOf(a)
   160  	return fmt.Sprintf("%s(%d, %d)", t.String(), a.Type(), a.Code())
   161  }
   162  
   163  // SerializeTo writes the ICMPv6TypeCode value to the 'bytes' buffer.
   164  func (a ICMPv6TypeCode) SerializeTo(bytes []byte) {
   165  	binary.BigEndian.PutUint16(bytes, uint16(a))
   166  }
   167  
   168  // CreateICMPv6TypeCode is a convenience function to create an ICMPv6TypeCode
   169  // gopacket type from the ICMPv6 type and code values.
   170  func CreateICMPv6TypeCode(typ uint8, code uint8) ICMPv6TypeCode {
   171  	return ICMPv6TypeCode(binary.BigEndian.Uint16([]byte{typ, code}))
   172  }
   173  
   174  // ICMPv6 is the layer for IPv6 ICMP packet data
   175  type ICMPv6 struct {
   176  	BaseLayer
   177  	TypeCode ICMPv6TypeCode
   178  	Checksum uint16
   179  	// TypeBytes is deprecated and always nil. See the different ICMPv6 message types
   180  	// instead (e.g. ICMPv6TypeRouterSolicitation).
   181  	TypeBytes []byte
   182  	tcpipchecksum
   183  }
   184  
   185  // LayerType returns LayerTypeICMPv6.
   186  func (i *ICMPv6) LayerType() gopacket.LayerType { return LayerTypeICMPv6 }
   187  
   188  // DecodeFromBytes decodes the given bytes into this layer.
   189  func (i *ICMPv6) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
   190  	if len(data) < 4 {
   191  		df.SetTruncated()
   192  		return errors.New("ICMP layer less then 4 bytes for ICMPv6 packet")
   193  	}
   194  	i.TypeCode = CreateICMPv6TypeCode(data[0], data[1])
   195  	i.Checksum = binary.BigEndian.Uint16(data[2:4])
   196  	i.BaseLayer = BaseLayer{data[:4], data[4:]}
   197  	return nil
   198  }
   199  
   200  // SerializeTo writes the serialized form of this layer into the
   201  // SerializationBuffer, implementing gopacket.SerializableLayer.
   202  // See the docs for gopacket.SerializableLayer for more info.
   203  func (i *ICMPv6) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
   204  	bytes, err := b.PrependBytes(4)
   205  	if err != nil {
   206  		return err
   207  	}
   208  	i.TypeCode.SerializeTo(bytes)
   209  
   210  	if opts.ComputeChecksums {
   211  		bytes[2] = 0
   212  		bytes[3] = 0
   213  		csum, err := i.computeChecksum(b.Bytes(), IPProtocolICMPv6)
   214  		if err != nil {
   215  			return err
   216  		}
   217  		i.Checksum = csum
   218  	}
   219  	binary.BigEndian.PutUint16(bytes[2:], i.Checksum)
   220  
   221  	return nil
   222  }
   223  
   224  // CanDecode returns the set of layer types that this DecodingLayer can decode.
   225  func (i *ICMPv6) CanDecode() gopacket.LayerClass {
   226  	return LayerTypeICMPv6
   227  }
   228  
   229  // NextLayerType returns the layer type contained by this DecodingLayer.
   230  func (i *ICMPv6) NextLayerType() gopacket.LayerType {
   231  	switch i.TypeCode.Type() {
   232  	case ICMPv6TypeEchoRequest:
   233  		return LayerTypeICMPv6Echo
   234  	case ICMPv6TypeEchoReply:
   235  		return LayerTypeICMPv6Echo
   236  	case ICMPv6TypeRouterSolicitation:
   237  		return LayerTypeICMPv6RouterSolicitation
   238  	case ICMPv6TypeRouterAdvertisement:
   239  		return LayerTypeICMPv6RouterAdvertisement
   240  	case ICMPv6TypeNeighborSolicitation:
   241  		return LayerTypeICMPv6NeighborSolicitation
   242  	case ICMPv6TypeNeighborAdvertisement:
   243  		return LayerTypeICMPv6NeighborAdvertisement
   244  	case ICMPv6TypeRedirect:
   245  		return LayerTypeICMPv6Redirect
   246  	case ICMPv6TypeMLDv1MulticastListenerQueryMessage: // Same Code for MLDv1 Query and MLDv2 Query
   247  		if len(i.Payload) > 20 { // Only payload size differs
   248  			return LayerTypeMLDv2MulticastListenerQuery
   249  		} else {
   250  			return LayerTypeMLDv1MulticastListenerQuery
   251  		}
   252  	case ICMPv6TypeMLDv1MulticastListenerDoneMessage:
   253  		return LayerTypeMLDv1MulticastListenerDone
   254  	case ICMPv6TypeMLDv1MulticastListenerReportMessage:
   255  		return LayerTypeMLDv1MulticastListenerReport
   256  	case ICMPv6TypeMLDv2MulticastListenerReportMessageV2:
   257  		return LayerTypeMLDv2MulticastListenerReport
   258  	}
   259  
   260  	return gopacket.LayerTypePayload
   261  }
   262  
   263  func decodeICMPv6(data []byte, p gopacket.PacketBuilder) error {
   264  	i := &ICMPv6{}
   265  	return decodingLayerDecoder(i, data, p)
   266  }