// 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" "errors" "fmt" "reflect" "github.com/google/gopacket" ) const ( // The following are from RFC 4443 ICMPv6TypeDestinationUnreachable = 1 ICMPv6TypePacketTooBig = 2 ICMPv6TypeTimeExceeded = 3 ICMPv6TypeParameterProblem = 4 ICMPv6TypeEchoRequest = 128 ICMPv6TypeEchoReply = 129 // The following are from RFC 4861 ICMPv6TypeRouterSolicitation = 133 ICMPv6TypeRouterAdvertisement = 134 ICMPv6TypeNeighborSolicitation = 135 ICMPv6TypeNeighborAdvertisement = 136 ICMPv6TypeRedirect = 137 ) const ( // DestinationUnreachable ICMPv6CodeNoRouteToDst = 0 ICMPv6CodeAdminProhibited = 1 ICMPv6CodeBeyondScopeOfSrc = 2 ICMPv6CodeAddressUnreachable = 3 ICMPv6CodePortUnreachable = 4 ICMPv6CodeSrcAddressFailedPolicy = 5 ICMPv6CodeRejectRouteToDst = 6 // TimeExceeded ICMPv6CodeHopLimitExceeded = 0 ICMPv6CodeFragmentReassemblyTimeExceeded = 1 // ParameterProblem ICMPv6CodeErroneousHeaderField = 0 ICMPv6CodeUnrecognizedNextHeader = 1 ICMPv6CodeUnrecognizedIPv6Option = 2 ) type icmpv6TypeCodeInfoStruct struct { typeStr string codeStr *map[uint8]string } var ( icmpv6TypeCodeInfo = map[uint8]icmpv6TypeCodeInfoStruct{ ICMPv6TypeDestinationUnreachable: icmpv6TypeCodeInfoStruct{ "DestinationUnreachable", &map[uint8]string{ ICMPv6CodeNoRouteToDst: "NoRouteToDst", ICMPv6CodeAdminProhibited: "AdminProhibited", ICMPv6CodeBeyondScopeOfSrc: "BeyondScopeOfSrc", ICMPv6CodeAddressUnreachable: "AddressUnreachable", ICMPv6CodePortUnreachable: "PortUnreachable", ICMPv6CodeSrcAddressFailedPolicy: "SrcAddressFailedPolicy", ICMPv6CodeRejectRouteToDst: "RejectRouteToDst", }, }, ICMPv6TypePacketTooBig: icmpv6TypeCodeInfoStruct{ "PacketTooBig", nil, }, ICMPv6TypeTimeExceeded: icmpv6TypeCodeInfoStruct{ "TimeExceeded", &map[uint8]string{ ICMPv6CodeHopLimitExceeded: "HopLimitExceeded", ICMPv6CodeFragmentReassemblyTimeExceeded: "FragmentReassemblyTimeExceeded", }, }, ICMPv6TypeParameterProblem: icmpv6TypeCodeInfoStruct{ "ParameterProblem", &map[uint8]string{ ICMPv6CodeErroneousHeaderField: "ErroneousHeaderField", ICMPv6CodeUnrecognizedNextHeader: "UnrecognizedNextHeader", ICMPv6CodeUnrecognizedIPv6Option: "UnrecognizedIPv6Option", }, }, ICMPv6TypeEchoRequest: icmpv6TypeCodeInfoStruct{ "EchoRequest", nil, }, ICMPv6TypeEchoReply: icmpv6TypeCodeInfoStruct{ "EchoReply", nil, }, ICMPv6TypeRouterSolicitation: icmpv6TypeCodeInfoStruct{ "RouterSolicitation", nil, }, ICMPv6TypeRouterAdvertisement: icmpv6TypeCodeInfoStruct{ "RouterAdvertisement", nil, }, ICMPv6TypeNeighborSolicitation: icmpv6TypeCodeInfoStruct{ "NeighborSolicitation", nil, }, ICMPv6TypeNeighborAdvertisement: icmpv6TypeCodeInfoStruct{ "NeighborAdvertisement", nil, }, ICMPv6TypeRedirect: icmpv6TypeCodeInfoStruct{ "Redirect", nil, }, } ) type ICMPv6TypeCode uint16 // Type returns the ICMPv6 type field. func (a ICMPv6TypeCode) Type() uint8 { return uint8(a >> 8) } // Code returns the ICMPv6 code field. func (a ICMPv6TypeCode) Code() uint8 { return uint8(a) } func (a ICMPv6TypeCode) String() string { t, c := a.Type(), a.Code() strInfo, ok := icmpv6TypeCodeInfo[t] if !ok { // Unknown ICMPv6 type field return fmt.Sprintf("%d(%d)", t, c) } typeStr := strInfo.typeStr if strInfo.codeStr == nil && c == 0 { // The ICMPv6 type does not make use of the code field return fmt.Sprintf("%s", strInfo.typeStr) } if strInfo.codeStr == nil && c != 0 { // The ICMPv6 type does not make use of the code field, but it is present anyway return fmt.Sprintf("%s(Code: %d)", typeStr, c) } codeStr, ok := (*strInfo.codeStr)[c] if !ok { // We don't know this ICMPv6 code; print the numerical value return fmt.Sprintf("%s(Code: %d)", typeStr, c) } return fmt.Sprintf("%s(%s)", typeStr, codeStr) } func (a ICMPv6TypeCode) GoString() string { t := reflect.TypeOf(a) return fmt.Sprintf("%s(%d, %d)", t.String(), a.Type(), a.Code()) } // SerializeTo writes the ICMPv6TypeCode value to the 'bytes' buffer. func (a ICMPv6TypeCode) SerializeTo(bytes []byte) { binary.BigEndian.PutUint16(bytes, uint16(a)) } // CreateICMPv6TypeCode is a convenience function to create an ICMPv6TypeCode // gopacket type from the ICMPv6 type and code values. func CreateICMPv6TypeCode(typ uint8, code uint8) ICMPv6TypeCode { return ICMPv6TypeCode(binary.BigEndian.Uint16([]byte{typ, code})) } // ICMPv6 is the layer for IPv6 ICMP packet data type ICMPv6 struct { BaseLayer TypeCode ICMPv6TypeCode Checksum uint16 // TypeBytes is deprecated and always nil. See the different ICMPv6 message types // instead (e.g. ICMPv6TypeRouterSolicitation). TypeBytes []byte tcpipchecksum } // LayerType returns LayerTypeICMPv6. func (i *ICMPv6) LayerType() gopacket.LayerType { return LayerTypeICMPv6 } // DecodeFromBytes decodes the given bytes into this layer. func (i *ICMPv6) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { if len(data) < 4 { df.SetTruncated() return errors.New("ICMP layer less then 4 bytes for ICMPv6 packet") } i.TypeCode = CreateICMPv6TypeCode(data[0], data[1]) i.Checksum = binary.BigEndian.Uint16(data[2:4]) i.BaseLayer = BaseLayer{data[:4], data[4:]} 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 *ICMPv6) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { bytes, err := b.PrependBytes(4) if err != nil { return err } i.TypeCode.SerializeTo(bytes) if opts.ComputeChecksums { bytes[2] = 0 bytes[3] = 0 csum, err := i.computeChecksum(b.Bytes(), IPProtocolICMPv6) if err != nil { return err } i.Checksum = csum } binary.BigEndian.PutUint16(bytes[2:], i.Checksum) return nil } // CanDecode returns the set of layer types that this DecodingLayer can decode. func (i *ICMPv6) CanDecode() gopacket.LayerClass { return LayerTypeICMPv6 } // NextLayerType returns the layer type contained by this DecodingLayer. func (i *ICMPv6) NextLayerType() gopacket.LayerType { switch i.TypeCode.Type() { case ICMPv6TypeRouterSolicitation: return LayerTypeICMPv6RouterSolicitation case ICMPv6TypeRouterAdvertisement: return LayerTypeICMPv6RouterAdvertisement case ICMPv6TypeNeighborSolicitation: return LayerTypeICMPv6NeighborSolicitation case ICMPv6TypeNeighborAdvertisement: return LayerTypeICMPv6NeighborAdvertisement case ICMPv6TypeRedirect: return LayerTypeICMPv6Redirect } return gopacket.LayerTypePayload } func decodeICMPv6(data []byte, p gopacket.PacketBuilder) error { i := &ICMPv6{} return decodingLayerDecoder(i, data, p) }