func TestTCP(t *testing.T) { handle, err := pcap.OpenOffline("tcptest.pcap") if err != nil { panic(err) } packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) defer handle.Close() tcpPack := make(chan gopacket.Packet, 10) nomalPack := make(chan gopacket.Packet, 5) for input_pack := range packetSource.Packets() { // send tcp package for channel tcpLayer := input_pack.Layer(layers.LayerTypeTCP) if tcpLayer != nil { tcpPack <- input_pack // send packet to tcp ASSEMBLER } } streamFactory := &DNSStreamFactory{normal: nomalPack} streamPool := tcpassembly.NewStreamPool(streamFactory) assembler := tcpassembly.NewAssembler(streamPool) go tcpAssemble(tcpPack, assembler) pack := <-nomalPack udpLayer := pack.Layer(layers.LayerTypeUDP) if udpLayer == nil { t.Errorf("can not fine udp Layer in result") } dns_message := new(dns.Msg) err = dns_message.Unpack(udpLayer.LayerPayload()) if err != nil { t.Errorf("can not parse dns message") } fmt.Printf(dns_message.String()) }
func TestNgnet(t *testing.T) { eventChan := make(chan interface{}, 1024) f := NewHttpStreamFactory(eventChan) pool := tcpassembly.NewStreamPool(f) assembler := tcpassembly.NewAssembler(pool) packetCount := 0 fmt.Println("Run") if handle, err := pcap.OpenOffline("dump.pcapng"); err != nil { panic(err) } else { packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) for packet := range packetSource.Packets() { net_layer := packet.NetworkLayer() trans_layer := packet.TransportLayer() if net_layer == nil { continue } if trans_layer == nil { continue } packetCount++ tcp, _ := trans_layer.(*layers.TCP) assembler.AssembleWithTimestamp(net_layer.NetworkFlow(), tcp, packet.Metadata().CaptureInfo.Timestamp) } } assembler.FlushAll() f.Wait() fmt.Println("packet:", packetCount, "http:", len(eventChan)) }
/* validate if DNS packet, make conntable entry and output to log channel if there is a match we pass packet by value here because we turned on ZeroCopy for the capture, which reuses the capture buffer */ func handlePacket(packets chan *packetData, logC chan dnsLogEntry, gcInterval time.Duration, gcAge time.Duration, threadNum int, stats *statsd.StatsdBuffer) { //DNS IDs are stored as uint16s by the gopacket DNS layer var conntable = make(map[uint16]dnsMapEntry) //setup garbage collection for this map go cleanDnsCache(&conntable, gcAge, gcInterval, threadNum, stats) //TCP reassembly init streamFactory := &dnsStreamFactory{} streamPool := tcpassembly.NewStreamPool(streamFactory) assembler := tcpassembly.NewAssembler(streamPool) ticker := time.Tick(time.Minute) for { select { case packet, more := <-packets: //used for clean shutdowns if !more { return } err := packet.Parse() if err != nil { log.Debugf("Error parsing packet: %s", err) continue } srcIP := packet.GetSrcIP() dstIP := packet.GetDstIP() //All TCP goes to reassemble. This is first because a single packet DNS request will parse as DNS //But that will leave the connection hanging around in memory, because the inital handshake won't //parse as DNS, nor will the connection closing. if packet.IsTCPStream() { handleDns(&conntable, packet.GetDNSLayer(), logC, srcIP, dstIP) } else if packet.HasTCPLayer() { assembler.AssembleWithTimestamp(packet.GetIPLayer().NetworkFlow(), packet.GetTCPLayer(), *packet.GetTimestamp()) continue } else if packet.HasDNSLayer() { handleDns(&conntable, packet.GetDNSLayer(), logC, srcIP, dstIP) if stats != nil { stats.Incr(strconv.Itoa(threadNum)+".dns_lookups", 1) } } else { //UDP and doesn't parse as DNS? log.Debug("Missing a DNS layer?") } case <-ticker: // Every minute, flush connections that haven't seen activity in the past 2 minutes. assembler.FlushOlderThan(time.Now().Add(time.Minute * -2)) } } }
func testReadSequence(t *testing.T, lossErrors bool, readSize int, seq readSequence) { f := &testReaderFactory{ReaderStream: NewReaderStream()} f.ReaderStream.LossErrors = lossErrors p := tcpassembly.NewStreamPool(f) a := tcpassembly.NewAssembler(p) buf := make([]byte, readSize) go func() { for i, test := range seq.in { fmt.Println("Assembling", i) a.Assemble(netFlow, &test) fmt.Println("Assembly done") } }() for i, test := range seq.want { fmt.Println("Waiting for read", i) n, err := f.Read(buf[:]) fmt.Println("Got read") if n != len(test.data) { t.Errorf("test %d want %d bytes, got %d bytes", i, len(test.data), n) } else if err != test.err { t.Errorf("test %d want err %v, got err %v", i, test.err, err) } else if !bytes.Equal(buf[:n], test.data) { t.Errorf("test %d\nwant: %v\n got: %v\n", i, test.data, buf[:n]) } } fmt.Println("All done reads") }
func main() { defer util.Run()() var handle *pcap.Handle var err error // Set up pcap packet capture if *fname != "" { log.Printf("Reading from pcap dump %q", *fname) handle, err = pcap.OpenOffline(*fname) } else { log.Fatalln("Error: pcap file name is required!") // log.Printf("Starting capture on interface %q", *iface) // handle, err = pcap.OpenLive(*iface, int32(*snaplen), true, pcap.BlockForever) } if err != nil { log.Fatal(err) } if err := handle.SetBPFFilter(*filter); err != nil { log.Fatal(err) } // Set up assembly streamFactory := &httpStreamFactory{} streamPool := tcpassembly.NewStreamPool(streamFactory) assembler := tcpassembly.NewAssembler(streamPool) log.Println("reading in packets") // Read in packets, pass to assembler. packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) packets := packetSource.Packets() ticker := time.Tick(time.Minute) for { select { case packet := <-packets: // A nil packet indicates the end of a pcap file. if packet == nil { return } if *logAllPackets { log.Println("\npacket:") // log.Println(packet) } if packet.NetworkLayer() == nil || packet.TransportLayer() == nil || packet.TransportLayer().LayerType() != layers.LayerTypeTCP { log.Println("Unusable packet") continue } tcp := packet.TransportLayer().(*layers.TCP) log.Printf("\n.......................................................\n") log.Printf("packet:\n") log.Printf("packet.Metadata().Timestamp=%T=%v=%v:\n%#v\n", packet.Metadata().Timestamp, packet.Metadata().Timestamp, packet.Metadata().Timestamp.UTC(), packet.Metadata().Timestamp) assembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp) case <-ticker: // Every minute, flush connections that haven't seen activity in the past 2 minutes. assembler.FlushOlderThan(time.Now().Add(time.Minute * -2)) } } }
func main() { flag.Usage = usage flag.Parse() pcapfile, err := openPcap() if err != nil { glog.Fatalf("%v", err) } bpf := strings.Join(flag.Args(), " ") if err = pcapfile.SetBPFFilter(bpf); err != nil { glog.Fatalf("unable to set BPF: %v", err) } // "Pass this stream factory to an tcpassembly.StreamPool , // start up an tcpassembly.Assembler, and you're good to go!" done := make(chan struct{}) results := make(chan string) go printResults(done, results) wg := &sync.WaitGroup{} rtmp := &rtmpStreamWrapper{wg, results} pool := tcpassembly.NewStreamPool(rtmp) asm := tcpassembly.NewAssembler(pool) asm.MaxBufferedPagesTotal = 4096 // limit gopacket memory allocation source := gopacket.NewPacketSource(pcapfile, pcapfile.LinkType()) var pkt gopacket.Packet for { pkt, err = source.NextPacket() if pkt == nil || err != nil { break } if tcp := pkt.Layer(layers.LayerTypeTCP); tcp != nil { asm.AssembleWithTimestamp( pkt.TransportLayer().TransportFlow(), tcp.(*layers.TCP), pkt.Metadata().Timestamp) } } if err != nil && !errIsEOF(err) { glog.Errorf("packet: %v", err) if err = pcapfile.Error(); err != nil { glog.Errorf("pcap: %v", err) } } asm.FlushAll() // abort any in progress tcp connections wg.Wait() // tcp streams have finished processing close(results) // no more results will be generated by tcp streams <-done // printResults has finished }
func main() { defer util.Run()() var err error f_config := fluent.Config{FluentSocketPath: *fluent_socket, FluentNetwork: "unix"} logger, err = fluent.New(f_config) defer logger.Close() // log.Printf("starting capture on interface %q", *iface) // Set up pcap packet capture handle, err := pcap.OpenLive(*iface, int32(*snaplen), true, pcap.BlockForever) if err != nil { panic(err) } if err := handle.SetBPFFilter(*filter); err != nil { panic(err) } // Set up assembly streamFactory := &myFactory{bidiMap: make(map[key]*bidi)} streamPool := tcpassembly.NewStreamPool(streamFactory) assembler := tcpassembly.NewAssembler(streamPool) // log.Println("reading in packets") // Read in packets, pass to assembler. packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) packets := packetSource.Packets() ticker := time.Tick(timeout / 4) for { select { case packet := <-packets: if packet.NetworkLayer() == nil || packet.TransportLayer() == nil || packet.TransportLayer().LayerType() != layers.LayerTypeTCP { //log.Println("Unusable packet") continue } tcp := packet.TransportLayer().(*layers.TCP) assembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp) case <-ticker: // Every minute, flush connections that haven't seen activity in the past minute. // log.Println("---- FLUSHING ----") assembler.FlushOlderThan(time.Now().Add(-timeout)) streamFactory.collectOldStreams() } } }
func runNGNet(packetSource *gopacket.PacketSource) { streamFactory := ngnet.NewHttpStreamFactory(eventChan) pool := tcpassembly.NewStreamPool(streamFactory) assembler := tcpassembly.NewAssembler(pool) var pcapWriter *pcapgo.Writer if *outputPcap != "" { outPcapFile, err := os.Create(*outputPcap) if err != nil { log.Fatalln(err) } defer outPcapFile.Close() pcapWriter = pcapgo.NewWriter(outPcapFile) pcapWriter.WriteFileHeader(65536, layers.LinkTypeEthernet) } var count int = 0 for packet := range packetSource.Packets() { count++ net_layer := packet.NetworkLayer() if net_layer == nil { continue } trans_layer := packet.TransportLayer() if trans_layer == nil { continue } tcp, _ := trans_layer.(*layers.TCP) if tcp == nil { continue } if pcapWriter != nil { pcapWriter.WritePacket(packet.Metadata().CaptureInfo, packet.Data()) } assembler.AssembleWithTimestamp( net_layer.NetworkFlow(), tcp, packet.Metadata().CaptureInfo.Timestamp) } assembler.FlushAll() streamFactory.Wait() log.Println("Packet count: ", count) }
func main() { var FilePathInput string var FilePathOutput string flag.StringVar(&FilePathInput, "in", "", "the path of PCAP file") flag.StringVar(&FilePathOutput, "out", "", "the output file") flag.Parse() // in mind if we need to do search in file. if FilePathInput == "" || FilePathOutput == "" { fmt.Print("lack of parameters!") return } handle, err := pcap.OpenOffline(FilePathInput) if err != nil { panic(err) } defer handle.Close() packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) //need to add tcp assemble and udp defrag here. Output, err := os.Create(FilePathOutput) w := pcapgo.NewWriter(Output) w.WriteFileHeader(65536, layers.LinkTypeRaw) defer Output.Close() // need add function call here tcpPack := make(chan gopacket.Packet, 5) // maybe need change buffersize for chan nomalPack := make(chan gopacket.Packet, 5) fragV4Pack := make(chan gopacket.Packet, 5) fragV6Pack := make(chan gopacket.Packet, 5) endNotification := make(chan bool) go readSource(packetSource, tcpPack, nomalPack, fragV4Pack, fragV6Pack, endNotification) go v6Defrag(fragV6Pack, nomalPack) go v4Defrag(fragV4Pack, nomalPack) go pcapWrite(w, nomalPack) streamFactory := &DNSStreamFactory{normal: nomalPack} streamPool := tcpassembly.NewStreamPool(streamFactory) assembler := tcpassembly.NewAssembler(streamPool) go tcpAssemble(tcpPack, assembler) // wait for the reading to finish <-endNotification }
func benchmarkLayerDecode(source *BufferPacketSource, assemble bool) { var tcp layers.TCP var ip layers.IPv4 var eth layers.Ethernet var udp layers.UDP var icmp layers.ICMPv4 var payload gopacket.Payload parser := gopacket.NewDecodingLayerParser( layers.LayerTypeEthernet, ð, &ip, &icmp, &tcp, &udp, &payload) pool := tcpassembly.NewStreamPool(&streamFactory{}) assembler := tcpassembly.NewAssembler(pool) var decoded []gopacket.LayerType start := time.Now() packets, decodedlayers, assembled := 0, 0, 0 for { packets++ data, ci, err := source.ReadPacketData() if err == io.EOF { break } else if err != nil { fmt.Println("Error reading packet: ", err) continue } err = parser.DecodeLayers(data, &decoded) for _, typ := range decoded { decodedlayers++ if typ == layers.LayerTypeTCP && assemble { assembled++ assembler.AssembleWithTimestamp(ip.NetworkFlow(), &tcp, ci.Timestamp) } } } if assemble { assembler.FlushAll() } duration := time.Since(start) fmt.Printf("\tRead in %d packets in %v, decoded %v layers, assembled %v packets: %v per packet\n", packets, duration, decodedlayers, assembled, duration/time.Duration(packets)) }
func doCaptureLoop(packageSource *gopacket.PacketSource) { // dataStream := datastream.TcpDataStreamFactory{ps[:len(ps)]} streamPool := tcpassembly.NewStreamPool(dataStream) assembler := tcpassembly.NewAssembler(streamPool) log.Debug("构建tcp分析者完成") // packets := packageSource.Packets() ticker := time.Tick(time.Minute) // for { select { case packet := <-packets: { if packet == nil { return } if packet.NetworkLayer() == nil || packet.TransportLayer() == nil { continue } //tcp if packet.TransportLayer().LayerType() == layers.LayerTypeTCP { tcp, _ := packet.TransportLayer().(*layers.TCP) assembler.AssembleWithTimestamp( packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp) } } case <-ticker: assembler.FlushOlderThan(time.Now().Add(time.Minute * -2)) } } }
func main() { defer util.Run()() //var handle *pcap.Handle var handle *bsdbpf.BPFSniffer var err error var options = bsdbpf.Options{ BPFDeviceName: "", //ReadBufLen: 32767, ReadBufLen: 0, // asks BPF for buffer size (32768 with OpenBSD 5.7) //Timeout: nil, Timeout: &syscall.Timeval{Sec: 1, Usec: 0}, Promisc: true, //Immediate: true, Immediate: false, PreserveLinkAddr: true, } // Set up pcap packet capture if *fname != "" { log.Printf("Reading from pcap dump %q", *fname) //handle, err = pcap.OpenOffline(*fname) log.Fatal("Reading from pcap dump %q not yet implemented on BSD", *fname) } else { log.Printf("Starting capture on interface %q", *iface) //handle, err = pcap.OpenLive(*iface, int32(*snaplen), true, pcap.BlockForever) //handle, err = bsdbpf.NewBPFSniffer(*iface, nil) handle, err = bsdbpf.NewBPFSniffer(*iface, &options) } if err != nil { log.Fatal(err) } if err := handle.SetBpfReadFilterProgram(bpfHTTPFilterProg); err != nil { log.Fatal(err) } if err := handle.FlushBpf(); err != nil { log.Fatal(err) } // Set up assembly streamFactory := &httpStreamFactory{} streamPool := tcpassembly.NewStreamPool(streamFactory) assembler := tcpassembly.NewAssembler(streamPool) log.Println("reading in packets") // Read in packets, pass to assembler. //packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) packetSource := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet) packets := packetSource.Packets() ticker := time.Tick(time.Minute) for { select { case packet := <-packets: // A nil packet indicates the end of a pcap file. if packet == nil { return } if *logAllPackets { log.Println(packet) } if packet.NetworkLayer() == nil || packet.TransportLayer() == nil || packet.TransportLayer().LayerType() != layers.LayerTypeTCP { log.Println("Unusable packet") continue } tcp := packet.TransportLayer().(*layers.TCP) assembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp) case <-ticker: // Every minute, flush connections that haven't seen activity in the past 2 minutes. assembler.FlushOlderThan(time.Now().Add(time.Minute * -2)) } } }
func main() { defer util.Run()() var handle *pcap.Handle var err error // Set up pcap packet capture if *fname != "" { log.Printf("Reading from pcap dump %q", *fname) handle, err = pcap.OpenOffline(*fname) } else { log.Fatalln("Error: pcap file name is required!") // log.Printf("Starting capture on interface %q", *iface) // handle, err = pcap.OpenLive(*iface, int32(*snaplen), true, pcap.BlockForever) } // log.Printf("starting capture on interface %q", *iface) // // Set up pcap packet capture // handle, err := pcap.OpenLive(*iface, int32(*snaplen), true, pcap.BlockForever) if err != nil { panic(err) } if err := handle.SetBPFFilter(*filter); err != nil { panic(err) } // Set up assembly streamFactory := &myFactory{bidiMap: make(map[key]*bidi)} streamPool := tcpassembly.NewStreamPool(streamFactory) assembler := tcpassembly.NewAssembler(streamPool) log.Println("reading in packets") // Read in packets, pass to assembler. packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) packets := packetSource.Packets() ticker := time.Tick(timeout / 4) ReadingPackets: for { select { case packet := <-packets: if *logAllPackets { log.Println(packet) } if packet == nil { log.Println("Unusable packet: if packet == nil") break ReadingPackets } if packet.NetworkLayer() == nil { log.Println("Unusable packet: if packet.NetworkLayer() == nil") break ReadingPackets } if packet.TransportLayer() == nil { log.Println("Unusable packet: if packet.TransportLayer() == nil") break ReadingPackets } if packet.TransportLayer().LayerType() != layers.LayerTypeTCP { log.Println("Unusable packet: if packet.TransportLayer().LayerType() != layers.LayerTypeTCP") break ReadingPackets } tcp := packet.TransportLayer().(*layers.TCP) assembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp) case <-ticker: // Every minute, flush connections that haven't seen activity in the past minute. log.Println("---- FLUSHING ----") assembler.FlushOlderThan(time.Now().Add(-timeout)) streamFactory.collectOldStreams() } } }
func main() { var handle *pcap.Handle var err error flag.Parse() if *fname != "" { log.Printf("Reading from pcap file %q", *fname) handle, err = pcap.OpenOffline(*fname) } else { log.Printf("Starting capture on interface %q", *iface) handle, err = pcap.OpenLive(*iface, int32(*snaplen), false, pcap.BlockForever) } if err != nil { log.Fatal(err) } if *filter == "" { // from kcs_const.js *filter = "tcp port 80 and host" *filter += " (125.6.184.15 or 125.6.184.16 or 125.6.187.205 or" *filter += " 125.6.187.229 or 125.6.187.253 or 125.6.188.25 or" *filter += " 125.6.189.7 or 125.6.189.39 or 125.6.189.71 or" *filter += " 125.6.189.103 or 125.6.189.135 or 125.6.189.167 or" *filter += " 125.6.189.215 or 125.6.189.247 or 203.104.209.7 or" *filter += " 203.104.209.23 or 203.104.209.39 or 203.104.209.55 or" *filter += " 203.104.209.71 or 203.104.209.102 or 203.104.248.135)" } if err := handle.SetBPFFilter(*filter); err != nil { log.Fatal(err) } // Set up assembly streamFactory := &httpStreamFactory{} streamPool := tcpassembly.NewStreamPool(streamFactory) assembler := tcpassembly.NewAssembler(streamPool) // Set up paser goroutine cpus := runtime.NumCPU() runtime.GOMAXPROCS(cpus) wait := new(sync.WaitGroup) go parse(wait) // Read in packets, pass to assembler. packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) packets := packetSource.Packets() ticker := time.Tick(time.Minute) for { select { case packet := <-packets: // A nil packet indicates the end of a pcap file. if packet == nil { return } if packet.NetworkLayer() == nil || packet.TransportLayer() == nil { continue } if packet.TransportLayer().LayerType() != layers.LayerTypeTCP { continue } tcp := packet.TransportLayer().(*layers.TCP) assembler.AssembleWithTimestamp(packet.NetworkLayer().NetworkFlow(), tcp, packet.Metadata().Timestamp) case <-ticker: // Every minute, flush connections that haven't seen activity in the past 2 minutes. assembler.FlushOlderThan(time.Now().Add(time.Minute * -2)) } } parserCh <- Res{port: 0} wait.Wait() }
func (p *PacketHandler) Handle(streamHandler StreamHandler, numToHandle int) error { count := int64(0) start := time.Now() if p.Verbose && numToHandle > 0 { log.Println("Processing", numToHandle, "packets") } source := gopacket.NewPacketSource(p.pcap, p.pcap.LinkType()) streamPool := tcpassembly.NewStreamPool(streamHandler) assembler := tcpassembly.NewAssembler(streamPool) defer func() { if p.Verbose { log.Println("flushing assembler.") log.Println("num flushed/closed:", assembler.FlushAll()) log.Println("closing stream handler.") } else { assembler.FlushAll() } streamHandler.Close() }() defer func() { if p.Verbose { log.Println("Dropped", p.numDropped, "packets out of", count) runTime := float64(time.Now().Sub(start)) / float64(time.Second) log.Println("Processed", float64(count-p.numDropped)/runTime, "packets per second") } }() ticker := time.Tick(time.Second * 1) for { select { case pkt := <-source.Packets(): if pkt == nil { // end of pcap file if p.Verbose { log.Println("end of stream") } return nil } if tcpLayer := pkt.Layer(layers.LayerTypeTCP); tcpLayer != nil { assembler.AssembleWithTimestamp( pkt.TransportLayer().TransportFlow(), tcpLayer.(*layers.TCP), pkt.Metadata().Timestamp) } if count == 0 { if firstSeener, ok := streamHandler.(SetFirstSeener); ok { firstSeener.SetFirstSeen(pkt.Metadata().Timestamp) } } count++ if numToHandle > 0 && count >= int64(numToHandle) { if p.Verbose { log.Println("Count exceeds requested packets, returning.") } break } case <-ticker: if p.Verbose { log.Println("flushing old streams") } assembler.FlushOlderThan(time.Now().Add(time.Second * -5)) } } return nil }
func main() { defer util.Run()() var handle *pcap.Handle var err error flushDuration, err := time.ParseDuration(*flushAfter) if err != nil { log.Fatal("invalid flush duration: ", *flushAfter) } // log.Printf("starting capture on interface %q", *iface) // // Set up pcap packet capture // handle, err := pcap.OpenLive(*iface, int32(*snaplen), true, flushDuration/2) // if err != nil { // log.Fatal("error opening pcap handle: ", err) // } // Set up pcap packet capture if *fname != "" { log.Printf("Reading from pcap dump %q", *fname) handle, err = pcap.OpenOffline(*fname) } else { log.Fatalln("Error: pcap file name is required!") // log.Printf("Starting capture on interface %q", *iface) // handle, err = pcap.OpenLive(*iface, int32(*snaplen), true, pcap.BlockForever) } if err != nil { log.Fatal(err) } if err := handle.SetBPFFilter(*filter); err != nil { log.Fatal("error setting BPF filter: ", err) } // Set up assembly streamFactory := &statsStreamFactory{} streamPool := tcpassembly.NewStreamPool(streamFactory) assembler := tcpassembly.NewAssembler(streamPool) assembler.MaxBufferedPagesPerConnection = *bufferedPerConnection assembler.MaxBufferedPagesTotal = *bufferedTotal log.Println("reading in packets") // We use a DecodingLayerParser here instead of a simpler PacketSource. // This approach should be measurably faster, but is also more rigid. // PacketSource will handle any known type of packet safely and easily, // but DecodingLayerParser will only handle those packet types we // specifically pass in. This trade-off can be quite useful, though, in // high-throughput situations. var eth layers.Ethernet var dot1q layers.Dot1Q var ip4 layers.IPv4 var ip6 layers.IPv6 var ip6extensions layers.IPv6ExtensionSkipper var tcp layers.TCP var payload gopacket.Payload parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, ð, &dot1q, &ip4, &ip6, &ip6extensions, &tcp, &payload) decoded := make([]gopacket.LayerType, 0, 4) nextFlush := time.Now().Add(flushDuration / 2) var byteCount int64 start := time.Now() loop: for ; *packetCount != 0; *packetCount-- { // Check to see if we should flush the streams we have // that haven't seen any new data in a while. Note we set a // timeout on our PCAP handle, so this should happen even if we // never see packet data. if time.Now().After(nextFlush) { stats, _ := handle.Stats() log.Printf("flushing all streams that haven't seen packets in the last 2 minutes, pcap stats: %+v", stats) assembler.FlushOlderThan(time.Now().Add(flushDuration)) nextFlush = time.Now().Add(flushDuration / 2) } // To speed things up, we're also using the ZeroCopy method for // reading packet data. This method is faster than the normal // ReadPacketData, but the returned bytes in 'data' are // invalidated by any subsequent ZeroCopyReadPacketData call. // Note that tcpassembly is entirely compatible with this packet // reading method. This is another trade-off which might be // appropriate for high-throughput sniffing: it avoids a packet // copy, but its cost is much more careful handling of the // resulting byte slice. data, ci, err := handle.ZeroCopyReadPacketData() if err != nil { log.Printf("error getting packet: %v", err) break loop // continue } err = parser.DecodeLayers(data, &decoded) if err != nil { log.Printf("error decoding packet: %v", err) continue } if *logAllPackets { log.Printf("decoded the following layers: %v", decoded) } byteCount += int64(len(data)) // Find either the IPv4 or IPv6 address to use as our network // layer. foundNetLayer := false var netFlow gopacket.Flow for _, typ := range decoded { switch typ { case layers.LayerTypeIPv4: netFlow = ip4.NetworkFlow() foundNetLayer = true case layers.LayerTypeIPv6: netFlow = ip6.NetworkFlow() foundNetLayer = true case layers.LayerTypeTCP: if foundNetLayer { assembler.AssembleWithTimestamp(netFlow, &tcp, ci.Timestamp) } else { log.Println("could not find IPv4 or IPv6 layer, inoring") } continue loop } } log.Println("could not find TCP layer") } assembler.FlushAll() log.Printf("processed %d bytes in %v", byteCount, time.Since(start)) }