123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- // 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
- }
|