1 // Copyright 2012 Google, Inc. All rights reserved.
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
7 // This binary provides sample code for using the gopacket TCP assembler and TCP
8 // stream reader. It reads packets off the wire and reconstructs HTTP requests
9 // it sees, logging them.
20 "github.com/google/gopacket"
21 "github.com/google/gopacket/examples/util"
22 "github.com/google/gopacket/layers"
23 "github.com/google/gopacket/pcap"
24 "github.com/google/gopacket/tcpassembly"
25 "github.com/google/gopacket/tcpassembly/tcpreader"
28 var iface = flag.String("i", "eth0", "Interface to get packets from")
29 var fname = flag.String("r", "", "Filename to read from, overrides -i")
30 var snaplen = flag.Int("s", 1600, "SnapLen for pcap packet capture")
31 var filter = flag.String("f", "tcp and dst port 80", "BPF filter for pcap")
32 var logAllPackets = flag.Bool("v", false, "Logs every packet in great detail")
34 // Build a simple HTTP request parser using tcpassembly.StreamFactory and tcpassembly.Stream interfaces
36 // httpStreamFactory implements tcpassembly.StreamFactory
37 type httpStreamFactory struct{}
39 // httpStream will handle the actual decoding of http requests.
40 type httpStream struct {
41 net, transport gopacket.Flow
42 r tcpreader.ReaderStream
45 func (h *httpStreamFactory) New(net, transport gopacket.Flow) tcpassembly.Stream {
46 hstream := &httpStream{
49 r: tcpreader.NewReaderStream(),
51 go hstream.run() // Important... we must guarantee that data from the reader stream is read.
53 // ReaderStream implements tcpassembly.Stream, so we can return a pointer to it.
57 func (h *httpStream) run() {
58 buf := bufio.NewReader(&h.r)
60 req, err := http.ReadRequest(buf)
62 // We must read until we see an EOF... very important!
64 } else if err != nil {
65 log.Println("Error reading stream", h.net, h.transport, ":", err)
67 bodyBytes := tcpreader.DiscardBytesToEOF(req.Body)
69 log.Println("Received request from stream", h.net, h.transport, ":", req, "with", bodyBytes, "bytes in request body")
76 var handle *pcap.Handle
79 // Set up pcap packet capture
81 log.Printf("Reading from pcap dump %q", *fname)
82 handle, err = pcap.OpenOffline(*fname)
84 log.Printf("Starting capture on interface %q", *iface)
85 handle, err = pcap.OpenLive(*iface, int32(*snaplen), true, pcap.BlockForever)
91 if err := handle.SetBPFFilter(*filter); err != nil {
96 streamFactory := &httpStreamFactory{}
97 streamPool := tcpassembly.NewStreamPool(streamFactory)
98 assembler := tcpassembly.NewAssembler(streamPool)
100 log.Println("reading in packets")
101 // Read in packets, pass to assembler.
102 packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
103 packets := packetSource.Packets()
104 ticker := time.Tick(time.Minute)
107 case packet := <-packets:
108 // A nil packet indicates the end of a pcap file.
115 if packet.NetworkLayer() == nil || packet.TransportLayer() == nil || packet.TransportLayer().LayerType() != layers.LayerTypeTCP {
116 log.Println("Unusable packet")
119 tcp := packet.TransportLayer().(*layers.TCP)
120 assembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp)
123 // Every minute, flush connections that haven't seen activity in the past 2 minutes.
124 assembler.FlushOlderThan(time.Now().Add(time.Minute * -2))