blob: 09afd11a6096079db302d550a908f6b1be25e1ed [file] [log] [blame]
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -07001// 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
8package layers
9
10import (
11 "encoding/binary"
12 "errors"
13 "fmt"
14 "reflect"
15
16 "github.com/google/gopacket"
17)
18
19const (
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
44const (
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
64type icmpv6TypeCodeInfoStruct struct {
65 typeStr string
66 codeStr *map[uint8]string
67}
68
69var (
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
122type ICMPv6TypeCode uint16
123
124// Type returns the ICMPv6 type field.
125func (a ICMPv6TypeCode) Type() uint8 {
126 return uint8(a >> 8)
127}
128
129// Code returns the ICMPv6 code field.
130func (a ICMPv6TypeCode) Code() uint8 {
131 return uint8(a)
132}
133
134func (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
158func (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.
164func (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.
170func 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
175type 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.
186func (i *ICMPv6) LayerType() gopacket.LayerType { return LayerTypeICMPv6 }
187
188// DecodeFromBytes decodes the given bytes into this layer.
189func (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.
203func (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.
225func (i *ICMPv6) CanDecode() gopacket.LayerClass {
226 return LayerTypeICMPv6
227}
228
229// NextLayerType returns the layer type contained by this DecodingLayer.
230func (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
263func decodeICMPv6(data []byte, p gopacket.PacketBuilder) error {
264 i := &ICMPv6{}
265 return decodingLayerDecoder(i, data, p)
266}