blob: b46e43dfa531a917e5c6b665d16b954fda4d257c [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301// 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.FlowFromEndpoints(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
323Faster And Customized Decoding with DecodingLayerContainer
324
325By default, DecodingLayerParser uses native map to store and search for a layer
326to decode. Though being versatile, in some cases this solution may be not so
327optimal. For example, if you have only few layers faster operations may be
328provided by sparse array indexing or linear array scan.
329
330To accomodate these scenarios, DecodingLayerContainer interface is introduced
331along with its implementations: DecodingLayerSparse, DecodingLayerArray and
332DecodingLayerMap. You can specify a container implementation to
333DecodingLayerParser with SetDecodingLayerContainer method. Example:
334
335 dlp := gopacket.NewDecodingLayerParser(LayerTypeEthernet)
336 dlp.SetDecodingLayerContainer(gopacket.DecodingLayerSparse(nil))
337 var eth layers.Ethernet
338 dlp.AddDecodingLayer(&eth)
339 // ... add layers and use DecodingLayerParser as usual...
340
341To skip one level of indirection (though sacrificing some capabilities) you may
342also use DecodingLayerContainer as a decoding tool as it is. In this case you have to
343handle unknown layer types and layer panics by yourself. Example:
344
345 func main() {
346 var eth layers.Ethernet
347 var ip4 layers.IPv4
348 var ip6 layers.IPv6
349 var tcp layers.TCP
350 dlc := gopacket.DecodingLayerContainer(gopacket.DecodingLayerArray(nil))
351 dlc = dlc.Put(&eth)
352 dlc = dlc.Put(&ip4)
353 dlc = dlc.Put(&ip6)
354 dlc = dlc.Put(&tcp)
355 // you may specify some meaningful DecodeFeedback
356 decoder := dlc.LayersDecoder(LayerTypeEthernet, gopacket.NilDecodeFeedback)
357 decoded := make([]gopacket.LayerType, 0, 20)
358 for packetData := range somehowGetPacketData() {
359 lt, err := decoder(packetData, &decoded)
360 if err != nil {
361 fmt.Fprintf(os.Stderr, "Could not decode layers: %v\n", err)
362 continue
363 }
364 if lt != gopacket.LayerTypeZero {
365 fmt.Fprintf(os.Stderr, "unknown layer type: %v\n", lt)
366 continue
367 }
368 for _, layerType := range decoded {
369 // examine decoded layertypes just as already shown above
370 }
371 }
372 }
373
374DecodingLayerSparse is the fastest but most effective when LayerType values
375that layers in use can decode are not large because otherwise that would lead
376to bigger memory footprint. DecodingLayerArray is very compact and primarily
377usable if the number of decoding layers is not big (up to ~10-15, but please do
378your own benchmarks). DecodingLayerMap is the most versatile one and used by
379DecodingLayerParser by default. Please refer to tests and benchmarks in layers
380subpackage to further examine usage examples and performance measurements.
381
382You may also choose to implement your own DecodingLayerContainer if you want to
383make use of your own internal packet decoding logic.
384
385Creating Packet Data
386
387As well as offering the ability to decode packet data, gopacket will allow you
388to create packets from scratch, as well. A number of gopacket layers implement
389the SerializableLayer interface; these layers can be serialized to a []byte in
390the following manner:
391
392 ip := &layers.IPv4{
393 SrcIP: net.IP{1, 2, 3, 4},
394 DstIP: net.IP{5, 6, 7, 8},
395 // etc...
396 }
397 buf := gopacket.NewSerializeBuffer()
398 opts := gopacket.SerializeOptions{} // See SerializeOptions for more details.
399 err := ip.SerializeTo(buf, opts)
400 if err != nil { panic(err) }
401 fmt.Println(buf.Bytes()) // prints out a byte slice containing the serialized IPv4 layer.
402
403SerializeTo PREPENDS the given layer onto the SerializeBuffer, and they treat
404the current buffer's Bytes() slice as the payload of the serializing layer.
405Therefore, you can serialize an entire packet by serializing a set of layers in
406reverse order (Payload, then TCP, then IP, then Ethernet, for example). The
407SerializeBuffer's SerializeLayers function is a helper that does exactly that.
408
409To generate a (empty and useless, because no fields are set)
410Ethernet(IPv4(TCP(Payload))) packet, for example, you can run:
411
412 buf := gopacket.NewSerializeBuffer()
413 opts := gopacket.SerializeOptions{}
414 gopacket.SerializeLayers(buf, opts,
415 &layers.Ethernet{},
416 &layers.IPv4{},
417 &layers.TCP{},
418 gopacket.Payload([]byte{1, 2, 3, 4}))
419 packetData := buf.Bytes()
420
421A Final Note
422
423If you use gopacket, you'll almost definitely want to make sure gopacket/layers
424is imported, since when imported it sets all the LayerType variables and fills
425in a lot of interesting variables/maps (DecodersByLayerName, etc). Therefore,
426it's recommended that even if you don't use any layers functions directly, you still import with:
427
428 import (
429 _ "github.com/google/gopacket/layers"
430 )
431*/
432package gopacket