1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
|
// 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/gopacket/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
// The following are from RFC 2710
ICMPv6TypeMLDv1MulticastListenerQueryMessage = 130
ICMPv6TypeMLDv1MulticastListenerReportMessage = 131
ICMPv6TypeMLDv1MulticastListenerDoneMessage = 132
// The following are from RFC 3810
ICMPv6TypeMLDv2MulticastListenerReportMessageV2 = 143
)
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 = gopacket.FoldChecksum(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 ICMPv6TypeEchoRequest:
return LayerTypeICMPv6Echo
case ICMPv6TypeEchoReply:
return LayerTypeICMPv6Echo
case ICMPv6TypeRouterSolicitation:
return LayerTypeICMPv6RouterSolicitation
case ICMPv6TypeRouterAdvertisement:
return LayerTypeICMPv6RouterAdvertisement
case ICMPv6TypeNeighborSolicitation:
return LayerTypeICMPv6NeighborSolicitation
case ICMPv6TypeNeighborAdvertisement:
return LayerTypeICMPv6NeighborAdvertisement
case ICMPv6TypeRedirect:
return LayerTypeICMPv6Redirect
case ICMPv6TypeMLDv1MulticastListenerQueryMessage: // Same Code for MLDv1 Query and MLDv2 Query
if len(i.Payload) > 20 { // Only payload size differs
return LayerTypeMLDv2MulticastListenerQuery
} else {
return LayerTypeMLDv1MulticastListenerQuery
}
case ICMPv6TypeMLDv1MulticastListenerDoneMessage:
return LayerTypeMLDv1MulticastListenerDone
case ICMPv6TypeMLDv1MulticastListenerReportMessage:
return LayerTypeMLDv1MulticastListenerReport
case ICMPv6TypeMLDv2MulticastListenerReportMessageV2:
return LayerTypeMLDv2MulticastListenerReport
}
return gopacket.LayerTypePayload
}
func (i *ICMPv6) VerifyChecksum() (error, gopacket.ChecksumVerificationResult) {
bytes := append(i.Contents, i.Payload...)
existing := i.Checksum
verification, err := i.computeChecksum(bytes, IPProtocolICMPv6)
if err != nil {
return err, gopacket.ChecksumVerificationResult{}
}
correct := gopacket.FoldChecksum(verification - uint32(existing))
return nil, gopacket.ChecksumVerificationResult{
Valid: correct == existing,
Correct: uint32(correct),
Actual: uint32(existing),
}
}
func decodeICMPv6(data []byte, p gopacket.PacketBuilder) error {
i := &ICMPv6{}
return decodingLayerDecoder(i, data, p)
}
|