func benchmarkPacketDecode(packetSource *gopacket.PacketSource) { count, errors := 0, 0 start := time.Now() for packet, err := packetSource.NextPacket(); err != io.EOF; packet, err = packetSource.NextPacket() { if err != nil { fmt.Println("Error reading in packet:", err) continue } count++ var hasError bool if *printErrors && packet.ErrorLayer() != nil { fmt.Println("\n\n\nError decoding packet:", packet.ErrorLayer().Error()) fmt.Println(hex.Dump(packet.Data())) fmt.Printf("%#v\n", packet.Data()) errors++ hasError = true } if *printLayers || hasError { fmt.Printf("\n=== PACKET %d ===\n", count) for _, l := range packet.Layers() { fmt.Printf("--- LAYER %v ---\n%#v\n\n", l.LayerType(), l) } fmt.Println() } } duration := time.Since(start) fmt.Printf("\tRead in %v packets in %v, %v per packet\n", count, duration, duration/time.Duration(count)) if *printErrors { fmt.Printf("%v errors, successfully decoded %.02f%%\n", errors, float64(count-errors)*100.0/float64(count)) } }
// Packet reading -------------------------------------------------------------------- func(g *GPCapture) ReadPackets(packetSource *gopacket.PacketSource) { var numConsecDecodingFailures int SysLog.Debug("Entered Read packets") for { select { case <-g.quitCaptureChan: return default: // repeatedly read the packets from the packet source, return an error string // if the packet could not be decoded if packet, packerr := packetSource.NextPacket(); packerr == nil { // safely increment packet counter atomic.AddUint64(&g.pktsRead, 1) // OSAG gopacket addition: make sure that non-standard encapsulated packets // are sliced up correctly. The original gopacket does not support GRE-en- // capsulated packets for example packet.StripHeaders(g.linkType) // pull out the flow-relevant information and write it to the flow matrix. // Block the write out thread for the time of the insertion if p, perr := g.handlePacket(packet); perr == nil { // protect critical section g.flowTab.Lock() g.flowTab.flows.addToFlow(p) g.flowTab.Unlock() numConsecDecodingFailures = 0 } else { numConsecDecodingFailures++ // shut down the interface thread if too many consecutive decoding failures // have been encountered if numConsecDecodingFailures > 10000 { SysLog.Err(g.iface+": the last 10 000 packets could not be decoded") return } } } else if packerr == pcap.NextErrorTimeoutExpired { continue } else { SysLog.Warning(g.iface+": interface capture error: " + packerr.Error()) return } } } }
func main() { flag.Parse() filename := os.TempDir() + string(os.PathSeparator) + "gopacket_benchmark.pcap" if _, err := os.Stat(filename); err != nil { // This URL points to a publicly available packet data set from a DARPA // intrusion detection evaluation. See // http://www.ll.mit.edu/mission/communications/cyber/CSTcorpora/ideval/data/1999/training/week1/index.html // for more details. fmt.Println("Local pcap file", filename, "doesn't exist, reading from", *url) if resp, err := http.Get(*url); err != nil { panic(err) } else if out, err := os.Create(filename); err != nil { panic(err) } else if gz, err := gzip.NewReader(resp.Body); err != nil { panic(err) } else if n, err := io.Copy(out, gz); err != nil { panic(err) } else if err := gz.Close(); err != nil { panic(err) } else if err := out.Close(); err != nil { panic(err) } else { fmt.Println("Successfully read", n, "bytes from url, unzipped to local storage") } } fmt.Println("Reading file once through to hopefully cache most of it") if f, err := os.Open(filename); err != nil { panic(err) } else if n, err := io.Copy(ioutil.Discard, f); err != nil { panic(err) } else if err := f.Close(); err != nil { panic(err) } else { fmt.Println("Read in file", filename, ", total of", n, "bytes") } if *cpuProfile != "" { if cpu, err := os.Create(*cpuProfile); err != nil { panic(err) } else if err := pprof.StartCPUProfile(cpu); err != nil { panic(err) } else { defer func() { pprof.StopCPUProfile() cpu.Close() }() } } var packetDataSource *BufferPacketSource var packetSource *gopacket.PacketSource fmt.Printf("Opening file %q for read\n", filename) if h, err := pcap.OpenOffline(filename); err != nil { panic(err) } else { fmt.Println("Reading all packets into memory with BufferPacketSource.") start := time.Now() packetDataSource = NewBufferPacketSource(h) duration := time.Since(start) fmt.Printf("Time to read packet data into memory from file: %v\n", duration) packetSource = gopacket.NewPacketSource(packetDataSource, h.LinkType()) packetSource.DecodeOptions.Lazy = *decodeLazy packetSource.DecodeOptions.NoCopy = *decodeNoCopy } for i := 0; i < *repeat; i++ { packetDataSource.Reset() count, errors := 0, 0 runtime.GC() fmt.Printf("Benchmarking decode %d/%d\n", i+1, *repeat) start := time.Now() for packet, err := packetSource.NextPacket(); err != io.EOF; packet, err = packetSource.NextPacket() { if err != nil { fmt.Println("Error reading in packet:", err) } count++ var hasError bool if *printErrors && packet.ErrorLayer() != nil { fmt.Println("\n\n\nError decoding packet:", packet.ErrorLayer().Error()) fmt.Println(hex.Dump(packet.Data())) fmt.Printf("%#v\n", packet.Data()) errors++ hasError = true } if *printLayers || hasError { fmt.Printf("\n=== PACKET %d ===\n", count) for _, l := range packet.Layers() { fmt.Printf("--- LAYER %v ---\n%#v\n\n", l.LayerType(), l) } fmt.Println() } } duration := time.Since(start) fmt.Printf("\tRead in %v packets in %v, %v per packet\n", count, duration, duration/time.Duration(count)) if *printErrors { fmt.Printf("%v errors, successfully decoded %.02f%%\n", errors, float64(count-errors)*100.0/float64(count)) } } }
// This function gets the interface and configuration parameters from the core process // and starts handling packets that are captured with gopacket.pcap func (g *GPCapture) CaptureInterface(snapLen int32, promiscMode bool, bpfFilterString string, threadTerminationChan chan string, iwg *sync.WaitGroup) { go func() { defer g.CaptureDefer(threadTerminationChan) var ( err error packetSource *gopacket.PacketSource ) SysLog.Info(g.iface+": setting up capture") // loopback does not support in/out-bound filters, thus ignore it if g.iface == "lo" { SysLog.Err(g.iface+": interface not supported") iwg.Done() return } // open packet stream from an interface if g.pcapHandle, err = pcap.OpenLive(g.iface, snapLen, promiscMode, 250*time.Millisecond); err != nil { SysLog.Err(g.iface+": could not open capture: "+err.Error()) iwg.Done() return } // set the BPF filter. This has to be done in order to ensure that the link // type is identified correctly if e := g.pcapHandle.SetBPFFilter(bpfFilterString); e != nil { SysLog.Err(g.iface+": error setting BPF filter: " + e.Error()) iwg.Done() return } SysLog.Debug(g.iface+": bpf set") // return from function in case the link type is zero (which can happen if the // specified interface does not exist (anymore)) if g.pcapHandle.LinkType() == layers.LinkTypeNull { SysLog.Err(g.iface+": link type is null") iwg.Done() return } SysLog.Debug(g.iface+": link type: "+g.pcapHandle.LinkType().String()) // specify the pcap as the source from which the packets will be read packetSource = gopacket.NewPacketSource(g.pcapHandle, g.pcapHandle.LinkType()) // set the decoding options to lazy decoding in order to ensure that the packet // layers are only decoded once they are needed. Additionally, this is imperative // when GRE-encapsulated packets are decoded because otherwise the layers cannot // be detected correctly. Additionally set the link type for this interface packetSource.DecodeOptions = gopacket.Lazy g.linkType = int(g.pcapHandle.LinkType()) SysLog.Debug(g.iface+": set packet source") iwg.Done() // perform the actual packet capturing: g.ReadPackets(packetSource) }() }