blob: 8e33e562d3c5def5708fd21397b55d894ee52d1e [file] [log] [blame]
Andrea Campanella7167ebb2020-02-24 09:56:38 +01001// 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
7/*
8Package gopacket provides packet decoding for the Go language.
9
10gopacket contains many sub-packages with additional functionality you may find
11useful, including:
12
13 * layers: You'll probably use this every time. This contains of the logic
14 built into gopacket for decoding packet protocols. Note that all example
15 code below assumes that you have imported both gopacket and
16 gopacket/layers.
17 * pcap: C bindings to use libpcap to read packets off the wire.
18 * pfring: C bindings to use PF_RING to read packets off the wire.
19 * afpacket: C bindings for Linux's AF_PACKET to read packets off the wire.
20 * tcpassembly: TCP stream reassembly
21
22Also, if you're looking to dive right into code, see the examples subdirectory
23for numerous simple binaries built using gopacket libraries.
24
25Minimum go version required is 1.5 except for pcapgo/EthernetHandle, afpacket,
26and bsdbpf which need at least 1.7 due to x/sys/unix dependencies.
27
28Basic Usage
29
30gopacket takes in packet data as a []byte and decodes it into a packet with
31a non-zero number of "layers". Each layer corresponds to a protocol
32within the bytes. Once a packet has been decoded, the layers of the packet
33can be requested from the packet.
34
35 // Decode a packet
36 packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Default)
37 // Get the TCP layer from this packet
38 if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
39 fmt.Println("This is a TCP packet!")
40 // Get actual TCP data from this layer
41 tcp, _ := tcpLayer.(*layers.TCP)
42 fmt.Printf("From src port %d to dst port %d\n", tcp.SrcPort, tcp.DstPort)
43 }
44 // Iterate over all layers, printing out each layer type
45 for _, layer := range packet.Layers() {
46 fmt.Println("PACKET LAYER:", layer.LayerType())
47 }
48
49Packets can be decoded from a number of starting points. Many of our base
50types implement Decoder, which allow us to decode packets for which
51we don't have full data.
52
53 // Decode an ethernet packet
54 ethP := gopacket.NewPacket(p1, layers.LayerTypeEthernet, gopacket.Default)
55 // Decode an IPv6 header and everything it contains
56 ipP := gopacket.NewPacket(p2, layers.LayerTypeIPv6, gopacket.Default)
57 // Decode a TCP header and its payload
58 tcpP := gopacket.NewPacket(p3, layers.LayerTypeTCP, gopacket.Default)
59
60
61Reading Packets From A Source
62
63Most of the time, you won't just have a []byte of packet data lying around.
64Instead, you'll want to read packets in from somewhere (file, interface, etc)
65and process them. To do that, you'll want to build a PacketSource.
66
67First, you'll need to construct an object that implements the PacketDataSource
68interface. There are implementations of this interface bundled with gopacket
69in the gopacket/pcap and gopacket/pfring subpackages... see their documentation
70for more information on their usage. Once you have a PacketDataSource, you can
71pass it into NewPacketSource, along with a Decoder of your choice, to create
72a PacketSource.
73
74Once you have a PacketSource, you can read packets from it in multiple ways.
75See the docs for PacketSource for more details. The easiest method is the
76Packets function, which returns a channel, then asynchronously writes new
77packets into that channel, closing the channel if the packetSource hits an
78end-of-file.
79
80 packetSource := ... // construct using pcap or pfring
81 for packet := range packetSource.Packets() {
82 handlePacket(packet) // do something with each packet
83 }
84
85You can change the decoding options of the packetSource by setting fields in
86packetSource.DecodeOptions... see the following sections for more details.
87
88
89Lazy Decoding
90
91gopacket optionally decodes packet data lazily, meaning it
92only decodes a packet layer when it needs to handle a function call.
93
94 // Create a packet, but don't actually decode anything yet
95 packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Lazy)
96 // Now, decode the packet up to the first IPv4 layer found but no further.
97 // If no IPv4 layer was found, the whole packet will be decoded looking for
98 // it.
99 ip4 := packet.Layer(layers.LayerTypeIPv4)
100 // Decode all layers and return them. The layers up to the first IPv4 layer
101 // are already decoded, and will not require decoding a second time.
102 layers := packet.Layers()
103
104Lazily-decoded packets are not concurrency-safe. Since layers have not all been
105decoded, each call to Layer() or Layers() has the potential to mutate the packet
106in order to decode the next layer. If a packet is used
107in multiple goroutines concurrently, don't use gopacket.Lazy. Then gopacket
108will decode the packet fully, and all future function calls won't mutate the
109object.
110
111
112NoCopy Decoding
113
114By default, gopacket will copy the slice passed to NewPacket and store the
115copy within the packet, so future mutations to the bytes underlying the slice
116don't affect the packet and its layers. If you can guarantee that the
117underlying slice bytes won't be changed, you can use NoCopy to tell
118gopacket.NewPacket, and it'll use the passed-in slice itself.
119
120 // This channel returns new byte slices, each of which points to a new
121 // memory location that's guaranteed immutable for the duration of the
122 // packet.
123 for data := range myByteSliceChannel {
124 p := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
125 doSomethingWithPacket(p)
126 }
127
128The fastest method of decoding is to use both Lazy and NoCopy, but note from
129the many caveats above that for some implementations either or both may be
130dangerous.
131
132
133Pointers To Known Layers
134
135During decoding, certain layers are stored in the packet as well-known
136layer types. For example, IPv4 and IPv6 are both considered NetworkLayer
137layers, while TCP and UDP are both TransportLayer layers. We support 4
138layers, corresponding to the 4 layers of the TCP/IP layering scheme (roughly
139anagalous to layers 2, 3, 4, and 7 of the OSI model). To access these,
140you can use the packet.LinkLayer, packet.NetworkLayer,
141packet.TransportLayer, and packet.ApplicationLayer functions. Each of
142these functions returns a corresponding interface
143(gopacket.{Link,Network,Transport,Application}Layer). The first three
144provide methods for getting src/dst addresses for that particular layer,
145while the final layer provides a Payload function to get payload data.
146This is helpful, for example, to get payloads for all packets regardless
147of their underlying data type:
148
149 // Get packets from some source
150 for packet := range someSource {
151 if app := packet.ApplicationLayer(); app != nil {
152 if strings.Contains(string(app.Payload()), "magic string") {
153 fmt.Println("Found magic string in a packet!")
154 }
155 }
156 }
157
158A particularly useful layer is ErrorLayer, which is set whenever there's
159an error parsing part of the packet.
160
161 packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Default)
162 if err := packet.ErrorLayer(); err != nil {
163 fmt.Println("Error decoding some part of the packet:", err)
164 }
165
166Note that we don't return an error from NewPacket because we may have decoded
167a number of layers successfully before running into our erroneous layer. You
168may still be able to get your Ethernet and IPv4 layers correctly, even if
169your TCP layer is malformed.
170
171
172Flow And Endpoint
173
174gopacket has two useful objects, Flow and Endpoint, for communicating in a protocol
175independent manner the fact that a packet is coming from A and going to B.
176The general layer types LinkLayer, NetworkLayer, and TransportLayer all provide
177methods for extracting their flow information, without worrying about the type
178of the underlying Layer.
179
180A Flow is a simple object made up of a set of two Endpoints, one source and one
181destination. It details the sender and receiver of the Layer of the Packet.
182
183An Endpoint is a hashable representation of a source or destination. For
184example, for LayerTypeIPv4, an Endpoint contains the IP address bytes for a v4
185IP packet. A Flow can be broken into Endpoints, and Endpoints can be combined
186into Flows:
187
188 packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Lazy)
189 netFlow := packet.NetworkLayer().NetworkFlow()
190 src, dst := netFlow.Endpoints()
191 reverseFlow := gopacket.NewFlow(dst, src)
192
193Both Endpoint and Flow objects can be used as map keys, and the equality
194operator can compare them, so you can easily group together all packets
195based on endpoint criteria:
196
197 flows := map[gopacket.Endpoint]chan gopacket.Packet
198 packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Lazy)
199 // Send all TCP packets to channels based on their destination port.
200 if tcp := packet.Layer(layers.LayerTypeTCP); tcp != nil {
201 flows[tcp.TransportFlow().Dst()] <- packet
202 }
203 // Look for all packets with the same source and destination network address
204 if net := packet.NetworkLayer(); net != nil {
205 src, dst := net.NetworkFlow().Endpoints()
206 if src == dst {
207 fmt.Println("Fishy packet has same network source and dst: %s", src)
208 }
209 }
210 // Find all packets coming from UDP port 1000 to UDP port 500
211 interestingFlow := gopacket.NewFlow(layers.NewUDPPortEndpoint(1000), layers.NewUDPPortEndpoint(500))
212 if t := packet.NetworkLayer(); t != nil && t.TransportFlow() == interestingFlow {
213 fmt.Println("Found that UDP flow I was looking for!")
214 }
215
216For load-balancing purposes, both Flow and Endpoint have FastHash() functions,
217which provide quick, non-cryptographic hashes of their contents. Of particular
218importance is the fact that Flow FastHash() is symmetric: A->B will have the same
219hash as B->A. An example usage could be:
220
221 channels := [8]chan gopacket.Packet
222 for i := 0; i < 8; i++ {
223 channels[i] = make(chan gopacket.Packet)
224 go packetHandler(channels[i])
225 }
226 for packet := range getPackets() {
227 if net := packet.NetworkLayer(); net != nil {
228 channels[int(net.NetworkFlow().FastHash()) & 0x7] <- packet
229 }
230 }
231
232This allows us to split up a packet stream while still making sure that each
233stream sees all packets for a flow (and its bidirectional opposite).
234
235
236Implementing Your Own Decoder
237
238If your network has some strange encapsulation, you can implement your own
239decoder. In this example, we handle Ethernet packets which are encapsulated
240in a 4-byte header.
241
242 // Create a layer type, should be unique and high, so it doesn't conflict,
243 // giving it a name and a decoder to use.
244 var MyLayerType = gopacket.RegisterLayerType(12345, gopacket.LayerTypeMetadata{Name: "MyLayerType", Decoder: gopacket.DecodeFunc(decodeMyLayer)})
245
246 // Implement my layer
247 type MyLayer struct {
248 StrangeHeader []byte
249 payload []byte
250 }
251 func (m MyLayer) LayerType() gopacket.LayerType { return MyLayerType }
252 func (m MyLayer) LayerContents() []byte { return m.StrangeHeader }
253 func (m MyLayer) LayerPayload() []byte { return m.payload }
254
255 // Now implement a decoder... this one strips off the first 4 bytes of the
256 // packet.
257 func decodeMyLayer(data []byte, p gopacket.PacketBuilder) error {
258 // Create my layer
259 p.AddLayer(&MyLayer{data[:4], data[4:]})
260 // Determine how to handle the rest of the packet
261 return p.NextDecoder(layers.LayerTypeEthernet)
262 }
263
264 // Finally, decode your packets:
265 p := gopacket.NewPacket(data, MyLayerType, gopacket.Lazy)
266
267See the docs for Decoder and PacketBuilder for more details on how coding
268decoders works, or look at RegisterLayerType and RegisterEndpointType to see how
269to add layer/endpoint types to gopacket.
270
271
272Fast Decoding With DecodingLayerParser
273
274TLDR: DecodingLayerParser takes about 10% of the time as NewPacket to decode
275packet data, but only for known packet stacks.
276
277Basic decoding using gopacket.NewPacket or PacketSource.Packets is somewhat slow
278due to its need to allocate a new packet and every respective layer. It's very
279versatile and can handle all known layer types, but sometimes you really only
280care about a specific set of layers regardless, so that versatility is wasted.
281
282DecodingLayerParser avoids memory allocation altogether by decoding packet
283layers directly into preallocated objects, which you can then reference to get
284the packet's information. A quick example:
285
286 func main() {
287 var eth layers.Ethernet
288 var ip4 layers.IPv4
289 var ip6 layers.IPv6
290 var tcp layers.TCP
291 parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, &eth, &ip4, &ip6, &tcp)
292 decoded := []gopacket.LayerType{}
293 for packetData := range somehowGetPacketData() {
294 if err := parser.DecodeLayers(packetData, &decoded); err != nil {
295 fmt.Fprintf(os.Stderr, "Could not decode layers: %v\n", err)
296 continue
297 }
298 for _, layerType := range decoded {
299 switch layerType {
300 case layers.LayerTypeIPv6:
301 fmt.Println(" IP6 ", ip6.SrcIP, ip6.DstIP)
302 case layers.LayerTypeIPv4:
303 fmt.Println(" IP4 ", ip4.SrcIP, ip4.DstIP)
304 }
305 }
306 }
307 }
308
309The important thing to note here is that the parser is modifying the passed in
310layers (eth, ip4, ip6, tcp) instead of allocating new ones, thus greatly
311speeding up the decoding process. It's even branching based on layer type...
312it'll handle an (eth, ip4, tcp) or (eth, ip6, tcp) stack. However, it won't
313handle any other type... since no other decoders were passed in, an (eth, ip4,
314udp) stack will stop decoding after ip4, and only pass back [LayerTypeEthernet,
315LayerTypeIPv4] through the 'decoded' slice (along with an error saying it can't
316decode a UDP packet).
317
318Unfortunately, not all layers can be used by DecodingLayerParser... only those
319implementing the DecodingLayer interface are usable. Also, it's possible to
320create DecodingLayers that are not themselves Layers... see
321layers.IPv6ExtensionSkipper for an example of this.
322
323
324Creating Packet Data
325
326As well as offering the ability to decode packet data, gopacket will allow you
327to create packets from scratch, as well. A number of gopacket layers implement
328the SerializableLayer interface; these layers can be serialized to a []byte in
329the following manner:
330
331 ip := &layers.IPv4{
332 SrcIP: net.IP{1, 2, 3, 4},
333 DstIP: net.IP{5, 6, 7, 8},
334 // etc...
335 }
336 buf := gopacket.NewSerializeBuffer()
337 opts := gopacket.SerializeOptions{} // See SerializeOptions for more details.
338 err := ip.SerializeTo(buf, opts)
339 if err != nil { panic(err) }
340 fmt.Println(buf.Bytes()) // prints out a byte slice containing the serialized IPv4 layer.
341
342SerializeTo PREPENDS the given layer onto the SerializeBuffer, and they treat
343the current buffer's Bytes() slice as the payload of the serializing layer.
344Therefore, you can serialize an entire packet by serializing a set of layers in
345reverse order (Payload, then TCP, then IP, then Ethernet, for example). The
346SerializeBuffer's SerializeLayers function is a helper that does exactly that.
347
348To generate a (empty and useless, because no fields are set)
349Ethernet(IPv4(TCP(Payload))) packet, for example, you can run:
350
351 buf := gopacket.NewSerializeBuffer()
352 opts := gopacket.SerializeOptions{}
353 gopacket.SerializeLayers(buf, opts,
354 &layers.Ethernet{},
355 &layers.IPv4{},
356 &layers.TCP{},
357 gopacket.Payload([]byte{1, 2, 3, 4}))
358 packetData := buf.Bytes()
359
360A Final Note
361
362If you use gopacket, you'll almost definitely want to make sure gopacket/layers
363is imported, since when imported it sets all the LayerType variables and fills
364in a lot of interesting variables/maps (DecodersByLayerName, etc). Therefore,
365it's recommended that even if you don't use any layers functions directly, you still import with:
366
367 import (
368 _ "github.com/google/gopacket/layers"
369 )
370*/
371package gopacket