blob: e5dc0e45d8dc467104b33c7dbc43b099cd352a04 [file] [log] [blame]
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -07001// Copyright 2012 Google, Inc. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style license
4// that can be found in the LICENSE file in the root of the source
5// tree.
6
7package gopacket
8
9import (
10 "fmt"
11)
12
13// DecodingLayer is an interface for packet layers that can decode themselves.
14//
15// The important part of DecodingLayer is that they decode themselves in-place.
16// Calling DecodeFromBytes on a DecodingLayer totally resets the entire layer to
17// the new state defined by the data passed in. A returned error leaves the
18// DecodingLayer in an unknown intermediate state, thus its fields should not be
19// trusted.
20//
21// Because the DecodingLayer is resetting its own fields, a call to
22// DecodeFromBytes should normally not require any memory allocation.
23type DecodingLayer interface {
24 // DecodeFromBytes resets the internal state of this layer to the state
25 // defined by the passed-in bytes. Slices in the DecodingLayer may
26 // reference the passed-in data, so care should be taken to copy it
27 // first should later modification of data be required before the
28 // DecodingLayer is discarded.
29 DecodeFromBytes(data []byte, df DecodeFeedback) error
30 // CanDecode returns the set of LayerTypes this DecodingLayer can
31 // decode. For Layers that are also DecodingLayers, this will most
32 // often be that Layer's LayerType().
33 CanDecode() LayerClass
34 // NextLayerType returns the LayerType which should be used to decode
35 // the LayerPayload.
36 NextLayerType() LayerType
37 // LayerPayload is the set of bytes remaining to decode after a call to
38 // DecodeFromBytes.
39 LayerPayload() []byte
40}
41
42// DecodingLayerParser parses a given set of layer types. See DecodeLayers for
43// more information on how DecodingLayerParser should be used.
44type DecodingLayerParser struct {
45 // DecodingLayerParserOptions is the set of options available to the
46 // user to define the parser's behavior.
47 DecodingLayerParserOptions
48 first LayerType
49 decoders map[LayerType]DecodingLayer
50 df DecodeFeedback
51 // Truncated is set when a decode layer detects that the packet has been
52 // truncated.
53 Truncated bool
54}
55
56// AddDecodingLayer adds a decoding layer to the parser. This adds support for
57// the decoding layer's CanDecode layers to the parser... should they be
58// encountered, they'll be parsed.
59func (l *DecodingLayerParser) AddDecodingLayer(d DecodingLayer) {
60 for _, typ := range d.CanDecode().LayerTypes() {
61 l.decoders[typ] = d
62 }
63}
64
65// SetTruncated is used by DecodingLayers to set the Truncated boolean in the
66// DecodingLayerParser. Users should simply read Truncated after calling
67// DecodeLayers.
68func (l *DecodingLayerParser) SetTruncated() {
69 l.Truncated = true
70}
71
72// NewDecodingLayerParser creates a new DecodingLayerParser and adds in all
73// of the given DecodingLayers with AddDecodingLayer.
74//
75// Each call to DecodeLayers will attempt to decode the given bytes first by
76// treating them as a 'first'-type layer, then by using NextLayerType on
77// subsequently decoded layers to find the next relevant decoder. Should a
78// deoder not be available for the layer type returned by NextLayerType,
79// decoding will stop.
80func NewDecodingLayerParser(first LayerType, decoders ...DecodingLayer) *DecodingLayerParser {
81 dlp := &DecodingLayerParser{
82 decoders: make(map[LayerType]DecodingLayer),
83 first: first,
84 }
85 dlp.df = dlp // Cast this once to the interface
86 for _, d := range decoders {
87 dlp.AddDecodingLayer(d)
88 }
89 return dlp
90}
91
92// DecodeLayers decodes as many layers as possible from the given data. It
93// initially treats the data as layer type 'typ', then uses NextLayerType on
94// each subsequent decoded layer until it gets to a layer type it doesn't know
95// how to parse.
96//
97// For each layer successfully decoded, DecodeLayers appends the layer type to
98// the decoded slice. DecodeLayers truncates the 'decoded' slice initially, so
99// there's no need to empty it yourself.
100//
101// This decoding method is about an order of magnitude faster than packet
102// decoding, because it only decodes known layers that have already been
103// allocated. This means it doesn't need to allocate each layer it returns...
104// instead it overwrites the layers that already exist.
105//
106// Example usage:
107// func main() {
108// var eth layers.Ethernet
109// var ip4 layers.IPv4
110// var ip6 layers.IPv6
111// var tcp layers.TCP
112// var udp layers.UDP
113// var payload gopacket.Payload
114// parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, &eth, &ip4, &ip6, &tcp, &udp, &payload)
115// var source gopacket.PacketDataSource = getMyDataSource()
116// decodedLayers := make([]gopacket.LayerType, 0, 10)
117// for {
118// data, _, err := source.ReadPacketData()
119// if err != nil {
120// fmt.Println("Error reading packet data: ", err)
121// continue
122// }
123// fmt.Println("Decoding packet")
124// err = parser.DecodeLayers(data, &decodedLayers)
125// for _, typ := range decodedLayers {
126// fmt.Println(" Successfully decoded layer type", typ)
127// switch typ {
128// case layers.LayerTypeEthernet:
129// fmt.Println(" Eth ", eth.SrcMAC, eth.DstMAC)
130// case layers.LayerTypeIPv4:
131// fmt.Println(" IP4 ", ip4.SrcIP, ip4.DstIP)
132// case layers.LayerTypeIPv6:
133// fmt.Println(" IP6 ", ip6.SrcIP, ip6.DstIP)
134// case layers.LayerTypeTCP:
135// fmt.Println(" TCP ", tcp.SrcPort, tcp.DstPort)
136// case layers.LayerTypeUDP:
137// fmt.Println(" UDP ", udp.SrcPort, udp.DstPort)
138// }
139// }
140// if decodedLayers.Truncated {
141// fmt.Println(" Packet has been truncated")
142// }
143// if err != nil {
144// fmt.Println(" Error encountered:", err)
145// }
146// }
147// }
148//
149// If DecodeLayers is unable to decode the next layer type, it will return the
150// error UnsupportedLayerType.
151func (l *DecodingLayerParser) DecodeLayers(data []byte, decoded *[]LayerType) (err error) {
152 l.Truncated = false
153 if !l.IgnorePanic {
154 defer panicToError(&err)
155 }
156 typ := l.first
157 *decoded = (*decoded)[:0] // Truncated decoded layers.
158 for len(data) > 0 {
159 decoder, ok := l.decoders[typ]
160 if !ok {
161 if l.IgnoreUnsupported {
162 return nil
163 }
164 return UnsupportedLayerType(typ)
165 } else if err = decoder.DecodeFromBytes(data, l.df); err != nil {
166 return err
167 }
168 *decoded = append(*decoded, typ)
169 typ = decoder.NextLayerType()
170 data = decoder.LayerPayload()
171 }
172 return nil
173}
174
175// UnsupportedLayerType is returned by DecodingLayerParser if DecodeLayers
176// encounters a layer type that the DecodingLayerParser has no decoder for.
177type UnsupportedLayerType LayerType
178
179// Error implements the error interface, returning a string to say that the
180// given layer type is unsupported.
181func (e UnsupportedLayerType) Error() string {
182 return fmt.Sprintf("No decoder for layer type %v", LayerType(e))
183}
184
185func panicToError(e *error) {
186 if r := recover(); r != nil {
187 *e = fmt.Errorf("panic: %v", r)
188 }
189}
190
191// DecodingLayerParserOptions provides options to affect the behavior of a given
192// DecodingLayerParser.
193type DecodingLayerParserOptions struct {
194 // IgnorePanic determines whether a DecodingLayerParser should stop
195 // panics on its own (by returning them as an error from DecodeLayers)
196 // or should allow them to raise up the stack. Handling errors does add
197 // latency to the process of decoding layers, but is much safer for
198 // callers. IgnorePanic defaults to false, thus if the caller does
199 // nothing decode panics will be returned as errors.
200 IgnorePanic bool
201 // IgnoreUnsupported will stop parsing and return a nil error when it
202 // encounters a layer it doesn't have a parser for, instead of returning an
203 // UnsupportedLayerType error. If this is true, it's up to the caller to make
204 // sure that all expected layers have been parsed (by checking the decoded
205 // slice).
206 IgnoreUnsupported bool
207}