// Copyright 2012 Google, Inc. 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 gopacket import ( "fmt" ) // DecodingLayer is an interface for packet layers that can decode themselves. // // The important part of DecodingLayer is that they decode themselves in-place. // Calling DecodeFromBytes on a DecodingLayer totally resets the entire layer to // the new state defined by the data passed in. A returned error leaves the // DecodingLayer in an unknown intermediate state, thus its fields should not be // trusted. // // Because the DecodingLayer is resetting its own fields, a call to // DecodeFromBytes should normally not require any memory allocation. type DecodingLayer interface { // DecodeFromBytes resets the internal state of this layer to the state // defined by the passed-in bytes. Slices in the DecodingLayer may // reference the passed-in data, so care should be taken to copy it // first should later modification of data be required before the // DecodingLayer is discarded. DecodeFromBytes(data []byte, df DecodeFeedback) error // CanDecode returns the set of LayerTypes this DecodingLayer can // decode. For Layers that are also DecodingLayers, this will most // often be that Layer's LayerType(). CanDecode() LayerClass // NextLayerType returns the LayerType which should be used to decode // the LayerPayload. NextLayerType() LayerType // LayerPayload is the set of bytes remaining to decode after a call to // DecodeFromBytes. LayerPayload() []byte } // DecodingLayerParser parses a given set of layer types. See DecodeLayers for // more information on how DecodingLayerParser should be used. type DecodingLayerParser struct { // DecodingLayerParserOptions is the set of options available to the // user to define the parser's behavior. DecodingLayerParserOptions first LayerType decoders map[LayerType]DecodingLayer df DecodeFeedback // Truncated is set when a decode layer detects that the packet has been // truncated. Truncated bool } // AddDecodingLayer adds a decoding layer to the parser. This adds support for // the decoding layer's CanDecode layers to the parser... should they be // encountered, they'll be parsed. func (l *DecodingLayerParser) AddDecodingLayer(d DecodingLayer) { for _, typ := range d.CanDecode().LayerTypes() { l.decoders[typ] = d } } // SetTruncated is used by DecodingLayers to set the Truncated boolean in the // DecodingLayerParser. Users should simply read Truncated after calling // DecodeLayers. func (l *DecodingLayerParser) SetTruncated() { l.Truncated = true } // NewDecodingLayerParser creates a new DecodingLayerParser and adds in all // of the given DecodingLayers with AddDecodingLayer. // // Each call to DecodeLayers will attempt to decode the given bytes first by // treating them as a 'first'-type layer, then by using NextLayerType on // subsequently decoded layers to find the next relevant decoder. Should a // deoder not be available for the layer type returned by NextLayerType, // decoding will stop. func NewDecodingLayerParser(first LayerType, decoders ...DecodingLayer) *DecodingLayerParser { dlp := &DecodingLayerParser{ decoders: make(map[LayerType]DecodingLayer), first: first, } dlp.df = dlp // Cast this once to the interface for _, d := range decoders { dlp.AddDecodingLayer(d) } return dlp } // DecodeLayers decodes as many layers as possible from the given data. It // initially treats the data as layer type 'typ', then uses NextLayerType on // each subsequent decoded layer until it gets to a layer type it doesn't know // how to parse. // // For each layer successfully decoded, DecodeLayers appends the layer type to // the decoded slice. DecodeLayers truncates the 'decoded' slice initially, so // there's no need to empty it yourself. // // This decoding method is about an order of magnitude faster than packet // decoding, because it only decodes known layers that have already been // allocated. This means it doesn't need to allocate each layer it returns... // instead it overwrites the layers that already exist. // // Example usage: // func main() { // var eth layers.Ethernet // var ip4 layers.IPv4 // var ip6 layers.IPv6 // var tcp layers.TCP // var udp layers.UDP // var payload gopacket.Payload // parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, ð, &ip4, &ip6, &tcp, &udp, &payload) // var source gopacket.PacketDataSource = getMyDataSource() // decodedLayers := make([]gopacket.LayerType, 0, 10) // for { // data, _, err := source.ReadPacketData() // if err == nil { // fmt.Println("Error reading packet data: ", err) // continue // } // fmt.Println("Decoding packet") // err = parser.DecodeLayers(data, &decodedLayers) // for _, typ := range decodedLayers { // fmt.Println(" Successfully decoded layer type", typ) // switch typ { // case layers.LayerTypeEthernet: // fmt.Println(" Eth ", eth.SrcMAC, eth.DstMAC) // case layers.LayerTypeIPv4: // fmt.Println(" IP4 ", ip4.SrcIP, ip4.DstIP) // case layers.LayerTypeIPv6: // fmt.Println(" IP6 ", ip6.SrcIP, ip6.DstIP) // case layers.LayerTypeTCP: // fmt.Println(" TCP ", tcp.SrcPort, tcp.DstPort) // case layers.LayerTypeUDP: // fmt.Println(" UDP ", udp.SrcPort, udp.DstPort) // } // } // if decodedLayers.Truncated { // fmt.Println(" Packet has been truncated") // } // if err != nil { // fmt.Println(" Error encountered:", err) // } // } // } // // If DecodeLayers is unable to decode the next layer type, it will return the // error UnsupportedLayerType. func (l *DecodingLayerParser) DecodeLayers(data []byte, decoded *[]LayerType) (err error) { l.Truncated = false if !l.IgnorePanic { defer panicToError(&err) } typ := l.first *decoded = (*decoded)[:0] // Truncated decoded layers. for len(data) > 0 { decoder, ok := l.decoders[typ] if !ok { if l.IgnoreUnsupported { return nil } return UnsupportedLayerType(typ) } else if err = decoder.DecodeFromBytes(data, l.df); err != nil { return err } *decoded = append(*decoded, typ) typ = decoder.NextLayerType() data = decoder.LayerPayload() } return nil } // UnsupportedLayerType is returned by DecodingLayerParser if DecodeLayers // encounters a layer type that the DecodingLayerParser has no decoder for. type UnsupportedLayerType LayerType // Error implements the error interface, returning a string to say that the // given layer type is unsupported. func (e UnsupportedLayerType) Error() string { return fmt.Sprintf("No decoder for layer type %v", LayerType(e)) } func panicToError(e *error) { if r := recover(); r != nil { *e = fmt.Errorf("panic: %v", r) } } // DecodingLayerParserOptions provides options to affect the behavior of a given // DecodingLayerParser. type DecodingLayerParserOptions struct { // IgnorePanic determines whether a DecodingLayerParser should stop // panics on its own (by returning them as an error from DecodeLayers) // or should allow them to raise up the stack. Handling errors does add // latency to the process of decoding layers, but is much safer for // callers. IgnorePanic defaults to false, thus if the caller does // nothing decode panics will be returned as errors. IgnorePanic bool // IgnoreUnsupported will stop parsing and return a nil error when it // encounters a layer it doesn't have a parser for, instead of returning an // UnsupportedLayerType error. If this is true, it's up to the caller to make // sure that all expected layers have been parsed (by checking the decoded // slice). IgnoreUnsupported bool }