// 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" ) // A container for single LayerType->DecodingLayer mapping. type decodingLayerElem struct { typ LayerType dec DecodingLayer } // 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 } // DecodingLayerFunc decodes given packet and stores decoded LayerType // values into specified slice. Returns either first encountered // unsupported LayerType value or decoding error. In case of success, // returns (LayerTypeZero, nil). type DecodingLayerFunc func([]byte, *[]LayerType) (LayerType, error) // DecodingLayerContainer stores all DecodingLayer-s and serves as a // searching tool for DecodingLayerParser. type DecodingLayerContainer interface { // Put adds new DecodingLayer to container. The new instance of // the same DecodingLayerContainer is returned so it may be // implemented as a value receiver. Put(DecodingLayer) DecodingLayerContainer // Decoder returns DecodingLayer to decode given LayerType and // true if it was found. If no decoder found, return false. Decoder(LayerType) (DecodingLayer, bool) // LayersDecoder returns DecodingLayerFunc which decodes given // packet, starting with specified LayerType and DecodeFeedback. LayersDecoder(first LayerType, df DecodeFeedback) DecodingLayerFunc } // DecodingLayerSparse is a sparse array-based implementation of // DecodingLayerContainer. Each DecodingLayer is addressed in an // allocated slice by LayerType value itself. Though this is the // fastest container it may be memory-consuming if used with big // LayerType values. type DecodingLayerSparse []DecodingLayer // Put implements DecodingLayerContainer interface. func (dl DecodingLayerSparse) Put(d DecodingLayer) DecodingLayerContainer { maxLayerType := LayerType(len(dl) - 1) for _, typ := range d.CanDecode().LayerTypes() { if typ > maxLayerType { maxLayerType = typ } } if extra := maxLayerType - LayerType(len(dl)) + 1; extra > 0 { dl = append(dl, make([]DecodingLayer, extra)...) } for _, typ := range d.CanDecode().LayerTypes() { dl[typ] = d } return dl } // LayersDecoder implements DecodingLayerContainer interface. func (dl DecodingLayerSparse) LayersDecoder(first LayerType, df DecodeFeedback) DecodingLayerFunc { return LayersDecoder(dl, first, df) } // Decoder implements DecodingLayerContainer interface. func (dl DecodingLayerSparse) Decoder(typ LayerType) (DecodingLayer, bool) { if int64(typ) < int64(len(dl)) { decoder := dl[typ] return decoder, decoder != nil } return nil, false } // DecodingLayerArray is an array-based implementation of // DecodingLayerContainer. Each DecodingLayer is searched linearly in // an allocated slice in one-by-one fashion. type DecodingLayerArray []decodingLayerElem // Put implements DecodingLayerContainer interface. func (dl DecodingLayerArray) Put(d DecodingLayer) DecodingLayerContainer { TYPES: for _, typ := range d.CanDecode().LayerTypes() { for i := range dl { if dl[i].typ == typ { dl[i].dec = d continue TYPES } } dl = append(dl, decodingLayerElem{typ, d}) } return dl } // Decoder implements DecodingLayerContainer interface. func (dl DecodingLayerArray) Decoder(typ LayerType) (DecodingLayer, bool) { for i := range dl { if dl[i].typ == typ { return dl[i].dec, true } } return nil, false } // LayersDecoder implements DecodingLayerContainer interface. func (dl DecodingLayerArray) LayersDecoder(first LayerType, df DecodeFeedback) DecodingLayerFunc { return LayersDecoder(dl, first, df) } // DecodingLayerMap is an map-based implementation of // DecodingLayerContainer. Each DecodingLayer is searched in a map // hashed by LayerType value. type DecodingLayerMap map[LayerType]DecodingLayer // Put implements DecodingLayerContainer interface. func (dl DecodingLayerMap) Put(d DecodingLayer) DecodingLayerContainer { for _, typ := range d.CanDecode().LayerTypes() { if dl == nil { dl = make(map[LayerType]DecodingLayer) } dl[typ] = d } return dl } // Decoder implements DecodingLayerContainer interface. func (dl DecodingLayerMap) Decoder(typ LayerType) (DecodingLayer, bool) { d, ok := dl[typ] return d, ok } // LayersDecoder implements DecodingLayerContainer interface. func (dl DecodingLayerMap) LayersDecoder(first LayerType, df DecodeFeedback) DecodingLayerFunc { return LayersDecoder(dl, first, df) } // Static code check. var ( _ = []DecodingLayerContainer{ DecodingLayerSparse(nil), DecodingLayerMap(nil), DecodingLayerArray(nil), } ) // 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 dlc DecodingLayerContainer first LayerType df DecodeFeedback decodeFunc DecodingLayerFunc // 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) { l.SetDecodingLayerContainer(l.dlc.Put(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. // // NewDecodingLayerParser uses DecodingLayerMap container by // default. func NewDecodingLayerParser(first LayerType, decoders ...DecodingLayer) *DecodingLayerParser { dlp := &DecodingLayerParser{first: first} dlp.df = dlp // Cast this once to the interface // default container dlc := DecodingLayerContainer(DecodingLayerMap(make(map[LayerType]DecodingLayer))) for _, d := range decoders { dlc = dlc.Put(d) } dlp.SetDecodingLayerContainer(dlc) return dlp } // SetDecodingLayerContainer specifies container with decoders. This // call replaces all decoders already registered in given instance of // DecodingLayerParser. func (l *DecodingLayerParser) SetDecodingLayerContainer(dlc DecodingLayerContainer) { l.dlc = dlc l.decodeFunc = l.dlc.LayersDecoder(l.first, l.df) } // 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, err := l.decodeFunc(data, decoded) if typ != LayerTypeZero { // no decoder if l.IgnoreUnsupported { return nil } return UnsupportedLayerType(typ) } return err } // 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 }