Example #1
0
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())
}
Example #2
0
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))
}
Example #3
0
/* 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))
		}
	}
}
Example #4
0
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))
		}
	}
}
Example #6
0
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()
		}
	}
}
Example #8
0
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)
}
Example #9
0
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
}
Example #10
0
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,
		&eth, &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))
}
Example #11
0
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))
		}
	}
}
Example #12
0
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()
		}
	}
}
Example #14
0
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,
		&eth, &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))
}