func tryCapture(iface net.Interface) error { if iface.Name[:2] == "lo" { return fmt.Errorf("skipping loopback") } var h *pcap.Handle var err error switch *mode { case "basic": h, err = pcap.OpenLive(iface.Name, 65536, false, time.Second*3) if err != nil { return fmt.Errorf("openlive: %v", err) } defer h.Close() case "filtered": h, err = pcap.OpenLive(iface.Name, 65536, false, time.Second*3) if err != nil { return fmt.Errorf("openlive: %v", err) } defer h.Close() if err := h.SetBPFFilter("port 80 or port 443"); err != nil { return fmt.Errorf("setbpf: %v", err) } case "timestamp": u, err := pcap.NewInactiveHandle(iface.Name) if err != nil { return err } defer u.CleanUp() if err = u.SetSnapLen(65536); err != nil { return err } else if err = u.SetPromisc(false); err != nil { return err } else if err = u.SetTimeout(time.Second * 3); err != nil { return err } sources := u.SupportedTimestamps() if len(sources) == 0 { return fmt.Errorf("no supported timestamp sources") } else if err := u.SetTimestampSource(sources[0]); err != nil { return fmt.Errorf("settimestampsource(%v): %v", sources[0], err) } else if h, err = u.Activate(); err != nil { return fmt.Errorf("could not activate: %v", err) } defer h.Close() default: panic("Invalid --mode: " + *mode) } go generatePackets() h.ReadPacketData() // Do one dummy read to clear any timeouts. data, ci, err := h.ReadPacketData() if err != nil { return fmt.Errorf("readpacketdata: %v", err) } log.Printf("Read packet, %v bytes, CI: %+v", len(data), ci) return nil }
// startReceivingReplies createa a goroutine to read packets via a pcap sniffer func (o *NFQueueTraceObserver) startReceivingReplies() { log.Print("startReceivingReplies\n") snaplen := 65536 // XXX make this a user specified option! filter := "icmp or tcp" handle, err := pcap.OpenLive(o.options.Iface, int32(snaplen), true, pcap.BlockForever) if err != nil { log.Fatal("error opening pcap handle: ", err) } if err := handle.SetBPFFilter(filter); err != nil { log.Fatal("error setting BPF filter: ", err) } o.startParsingReplies() go func() { Loop: for { select { case <-o.stopReceiveChan: break Loop default: data, _, err := handle.ReadPacketData() if err != nil { continue } o.receiveParseChan <- data } } close(o.receiveParseChan) }() }
func (s *PcapSniffer) Open(config *Config) error { // Capture settings const ( // Max packet length snaplen int32 = 65536 // Set the interface in promiscuous mode promisc bool = true // Timeout duration flushAfter string = "10s" //BPF filter when capturing packets filter string = "ip" ) // Open the interface flushDuration, err := time.ParseDuration(flushAfter) if err != nil { return fmt.Errorf("Invalid flush duration: %s", flushAfter) } handle, err := pcap.OpenLive(*iface, snaplen, promisc, flushDuration/2) if err != nil { return fmt.Errorf("Error opening pcap handle: %s", err) } if err := handle.SetBPFFilter(filter); err != nil { return fmt.Errorf("Error setting BPF filter: %s", err) } s.handle = handle return nil }
// newScanner creates a new scanner for a given destination IP address, using // router to determine how to route packets to that IP. func newScanner(ip net.IP, router routing.Router) (*scanner, error) { s := &scanner{ dst: ip, opts: gopacket.SerializeOptions{ FixLengths: true, ComputeChecksums: true, }, buf: gopacket.NewSerializeBuffer(), } // Figure out the route to the IP. iface, gw, src, err := router.Route(ip) if err != nil { return nil, err } log.Printf("scanning ip %v with interface %v, gateway %v, src %v", ip, iface.Name, gw, src) s.gw, s.src, s.iface = gw, src, iface // Open the handle for reading/writing. // Note we could very easily add some BPF filtering here to greatly // decrease the number of packets we have to look at when getting back // scan results. handle, err := pcap.OpenLive(iface.Name, 65536, true, time.Millisecond) if err != nil { return nil, err } s.handle = handle return s, nil }
func main() { var ( device = flag.String("device", "en0", "device to listen to") timeout = flag.Duration("timeout", pcap.BlockForever, "time intervals to parse captured packets") ) flag.Parse() const ( MTULen = 1500 promiscuousMode = true ) handle, err := pcap.OpenLive(*device, MTULen, promiscuousMode, *timeout) // handle, err := pcap.OpenOffline("./dump_one.pcap") if err != nil { log.Fatalln(err) } packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) go countBytes(goingChan) go func() { for packet := range packetSource.Packets() { go handlePacket(packet, goingChan) } }() http.HandleFunc("/count", showClientMap) http.Handle("/", http.FileServer(http.Dir("./"))) if err := http.ListenAndServe(":8080", nil); err != nil { log.Fatalln(err) } }
func main() { fmt.Println("Hello World!") if handle, err := pcap.OpenLive("eno16777736", 1600, true, 0); err != nil { panic(err) } else if err := handle.SetBPFFilter("tcp and port 8005"); err != nil { // optional panic(err) } else { packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) for packet := range packetSource.Packets() { // Get the TCP layer from this packet if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil { fmt.Println("This is a TCP packet!") // Get actual TCP data from this layer tcp, _ := tcpLayer.(*layers.TCP) fmt.Printf("From src port %d to dst port %d\n", tcp.SrcPort, tcp.DstPort) tcp.SrcPort = 5000 fmt.Printf("New src src port is %d", tcp.SrcPort) } // Iterate over all layers, printing out each layer type for _, layer := range packet.Layers() { fmt.Println("PACKET LAYER:", layer.LayerType()) } } } }
func main() { flag.Parse() var handle *pcap.Handle var err error if *fname != "" { if handle, err = pcap.OpenOffline(*fname); err != nil { log.Fatalln("PCAP OpenOffline error:", err) } } else { if handle, err = pcap.OpenLive(*iface, int32(*snaplen), true, time.Second); err != nil { log.Fatalln("PCAP OpenLive error:", err) } if *tstype != "" { if t, err := pcap.TimestampSourceFromString(*tstype); err != nil { log.Fatalf("Supported timestamp types: %v", handle.SupportedTimestamps()) } else if err := handle.SetTimestampSource(t); err != nil { log.Fatalf("Supported timestamp types: %v", handle.SupportedTimestamps()) } } if len(flag.Args()) > 0 { bpffilter := strings.Join(flag.Args(), " ") fmt.Fprintf(os.Stderr, "Using BPF filter %q\n", bpffilter) if err = handle.SetBPFFilter(bpffilter); err != nil { log.Fatalln("BPF filter error:", err) } } } dumpcommand.Run(handle) }
func (tap *Wiretap) packets() chan gopacket.Packet { channel := make(chan gopacket.Packet, 100) filter := tap.Sources.Filter() n := 0 for _, intf := range tap.Interfaces { handle, err := pcap.OpenLive(intf, tap.BufSize, tap.Sources.RequiresPromisc(), tap.Timeout) if err != nil { fmt.Fprintf(os.Stderr, "Error: %s\n", err) continue } if err := handle.SetBPFFilter(filter); err != nil { fmt.Fprintf(os.Stderr, "Error: %s\n", err) continue } n++ go tap.capture(handle, channel) } if n == 0 { panic("no devices could be wiretapped") } return channel }
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.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(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() { if handle, err := pcap.OpenLive("eth0", 1600, true, 0); err != nil { panic(err) } else if err := handle.SetBPFFilter("tcp and port 80"); err != nil { // optional panic(err) } else { packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) for packet := range packetSource.Packets() { fmt.Println(packet.String()) } } }
// scan scans an individual interface's local network for machines using ARP requests/replies. // // scan loops forever, sending packets out regularly. It returns an error if // it's ever unable to write a packet. func scan(iface *net.Interface) error { // We just look for IPv4 addresses, so try to find if the interface has one. var addr *net.IPNet if addrs, err := iface.Addrs(); err != nil { return err } else { for _, a := range addrs { if ipnet, ok := a.(*net.IPNet); ok { if ip4 := ipnet.IP.To4(); ip4 != nil { addr = &net.IPNet{ IP: ip4, Mask: ipnet.Mask[len(ipnet.Mask)-4:], } break } } } } // Sanity-check that the interface has a good address. if addr == nil { return fmt.Errorf("no good IP network found") } else if addr.IP[0] == 127 { return fmt.Errorf("skipping localhost") } else if addr.Mask[0] != 0xff || addr.Mask[1] != 0xff { return fmt.Errorf("mask means network is too large") } log.Printf("Using network range %v for interface %v", addr, iface.Name) // Open up a pcap handle for packet reads/writes. handle, err := pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever) if err != nil { return err } defer handle.Close() // Start up a goroutine to read in packet data. stop := make(chan struct{}) go readARP(handle, iface, stop) defer close(stop) for { // Write our scan packets out to the handle. if err := writeARP(handle, iface, addr); err != nil { log.Printf("error writing packets on %v: %v", iface.Name, err) return err } // We don't know exactly how long it'll take for packets to be // sent back to us, but 10 seconds should be more than enough // time ;) time.Sleep(10 * time.Second) } }
func openLiveHandle() (handle *pcap.Handle) { var err error if handle, err = pcap.OpenLive(gwiface, MTU, true, 0); err != nil { panic(err) } log.Println("Pcap", gwiface, "opened") if gfilter != "" { log.Println("BPFFilter", gfilter) if err = handle.SetBPFFilter(gfilter); err != nil { panic(err) } } return }
func main() { // open device(s) for reading if handle, err := pcap.OpenLive(InterfaceName, 1600, true, pcap.BlockForever); err != nil { panic(err) // set filter } else if err := handle.SetBPFFilter(FilterExpression); err != nil { panic(err) } else { // start capture packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) // handle packets for packet := range packetSource.Packets() { spew.Dump(packet) } } }
func main() { defer util.Run()() 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 *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 minute. log.Println("---- FLUSHING ----") assembler.FlushOlderThan(time.Now().Add(-timeout)) streamFactory.collectOldStreams() } } }
func main() { flag.Parse() log.Printf("starting capture on interface %q", *iface) // Set up pcap packet capture handle, err := pcap.OpenLive(*iface, int32(*snaplen), true, 0) if err != nil { panic(err) } if err := handle.SetBPFFilter(*filter); err != nil { panic(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: 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.Assemble(packet.NetworkLayer().NetworkFlow(), tcp) 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.Parse() var handle *pcap.Handle var err error if *fname != "" { if handle, err = pcap.OpenOffline(*fname); err != nil { log.Fatalln("PCAP OpenOffline error:", err) } } else { if handle, err = pcap.OpenLive(*iface, int32(*snaplen), true, time.Second); err != nil { log.Fatalln("PCAP OpenLive error:", err) } if len(flag.Args()) > 0 { bpffilter := strings.Join(flag.Args(), " ") fmt.Fprintf(os.Stderr, "Using BPF filter %q\n", bpffilter) if err = handle.SetBPFFilter(bpffilter); err != nil { log.Fatalln("BPF filter error:", err) } } } dumpcommand.Run(handle) }
func main() { handle, err := pcap.OpenLive("lo", 1600, true, 0) if err != nil { panic(err) } if err := handle.SetBPFFilter("tcp port 8080"); err != nil { panic(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: log.Printf("%+v", jkjpacket.Dump()) 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)) } } }
//startCapture captures all packets on any interface for an unlimited duration. //Packets can be filtered by a BPF filter string. (E.g. tcp port 22) func capture(snaplen int32, quit chan bool, captureReady chan bool, pcapFile string) error { var handle *pcap.Handle var err error if pcapFile != "" { log.Println("Reading packet loss data from pcap-file:", pcapFile) handle, err = pcap.OpenOffline(pcapFile) } else { //https://godoc.org/code.google.com/p/gopacket/pcap //This might have been the culprit //Alternative to try: 250*time.Millisecond handle, err = pcap.OpenLive("any", snaplen, true, 250*time.Millisecond) } if err != nil { log.Println("Error while start capturing packets", err) return err } packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) captureReady <- true for { select { case packet := <-packetSource.Packets(): if packet != nil { if packet.Layer(layers.LayerTypeIPSecESP) != nil { putChannel(packet, ipSecChannel) } if packet.Layer(layers.LayerTypeICMPv4) != nil { putChannel(packet, icmpChannel) } } case <-quit: log.Println("Received quit message, stopping Listener.") return nil } } }
// 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) }() }
func main() { flag.Parse() args := flag.Args() if len(args) != 2 { log.Printf("Usage: %s <ip> <port>\n", os.Args[0]) os.Exit(-1) } // parse the destination host and port from the command line args dstip := net.ParseIP(args[0]).To4() dport_, err := strconv.ParseInt(args[1], 10, 16) if err != nil { log.Fatal(err) } dport := layers.TCPPort(dport_) sport := layers.TCPPort(5000) // get our local ip. srcip, err := localIP(dstip) if err != nil { log.Fatal(err) } devs, err := pcap.FindAllDevs() if err != nil { log.Fatal(err) } dev := "" for _, d := range devs { for _, a := range d.Addresses { if bytes.Equal(a.IP, srcip) { dev = d.Name } } // if d.Description == "Realtek PCIe GBE Family Controller" { // fmt.Println(d.Name) // dev = d.Name // } // fmt.Println(dev.Description) } if dev == "" { log.Fatal("Could not find the appropriate adapter device") } srcmac, err := localMac(dev) if err != nil { log.Fatal(err) } dstmac, err := remoteMac(dev, srcmac, srcip, dstip) if err != nil { log.Fatal(err) } eth := &layers.Ethernet{ SrcMAC: srcmac, DstMAC: dstmac, EthernetType: layers.EthernetTypeIPv4, } // Our IPv4 header ip := &layers.IPv4{ Version: 4, IHL: 5, TOS: 0, Length: 20, // FIX Id: 2, Flags: layers.IPv4DontFragment, FragOffset: 0, //16384, TTL: 3, //64, Protocol: layers.IPProtocolTCP, Checksum: 0, SrcIP: srcip, DstIP: dstip, } // Our TCP header tcp := &layers.TCP{ SrcPort: sport, DstPort: dport, Seq: 0, Ack: 0, SYN: true, Window: 64240, Checksum: 0, Urgent: 0, } tcp.DataOffset = 5 // uint8(unsafe.Sizeof(tcp)) tcp.SetNetworkLayerForChecksum(ip) buf := gopacket.NewSerializeBuffer() err = gopacket.SerializeLayers( buf, gopacket.SerializeOptions{ ComputeChecksums: true, // automatically compute checksums FixLengths: true, }, eth, ip, tcp, ) if err != nil { log.Fatal(err) } handle, err := pcap.OpenLive(`rpcap://`+dev, 65535, true, time.Second*1) if err != nil { log.Fatal(err) } defer handle.Close() var wg sync.WaitGroup handle.SetBPFFilter(fmt.Sprintf("tcp and host %s and host %s and port %d and port %d", srcip.String(), dstip.String(), sport, dport)) packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) wg.Add(1) go func() { stop := false go func() { <-time.After(time.Second * 2) stop = true }() for { if stop { break } packet, err := packetSource.NextPacket() if err == io.EOF { break } else if err != nil { //log.Println("Error:", err) continue } if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil { tcp, _ := tcpLayer.(*layers.TCP) if tcp.SrcPort == dport && tcp.DstPort == sport { if tcp.SYN && tcp.ACK { fmt.Printf("Port %d is OPEN\n", dport_) } else { fmt.Printf("Port %d is CLOSED\n", dport_) } break } //fmt.Printf("From src port %d to dst port %d\n", tcp.SrcPort, tcp.DstPort) } } wg.Done() }() err = handle.WritePacketData(buf.Bytes()) if err != nil { log.Fatal(err) } wg.Wait() }
// Sends an ARP request packet to determine the MAC address of an IP func remoteMac(dev string, srcmac net.HardwareAddr, srcip, dstip net.IP) (net.HardwareAddr, error) { var dstmac net.HardwareAddr eth := &layers.Ethernet{ SrcMAC: srcmac, DstMAC: net.HardwareAddr{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, EthernetType: layers.EthernetTypeARP, } arp := &layers.ARP{ AddrType: layers.LinkTypeEthernet, Protocol: layers.EthernetTypeIPv4, HwAddressSize: 6, ProtAddressSize: 4, Operation: 1, //arp request SourceHwAddress: srcmac, SourceProtAddress: srcip, DstHwAddress: net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, DstProtAddress: dstip, } buf := gopacket.NewSerializeBuffer() err := gopacket.SerializeLayers( buf, gopacket.SerializeOptions{ ComputeChecksums: true, // automatically compute checksums FixLengths: true, }, eth, arp, ) if err != nil { return dstmac, err } handle, err := pcap.OpenLive(`rpcap://`+dev, 65535, true, time.Second*1) if err != nil { return dstmac, err } defer handle.Close() var wg sync.WaitGroup handle.SetBPFFilter(fmt.Sprintf("arp and ether host %s", srcmac.String())) packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) macchan := make(chan net.HardwareAddr, 1) wg.Add(1) go func() { stop := false go func() { <-time.After(time.Second * 2) stop = true }() for { if stop { break } packet, err := packetSource.NextPacket() if err == io.EOF { break } else if err != nil { //log.Println("Error:", err) continue } if arpLayer := packet.Layer(layers.LayerTypeARP); arpLayer != nil { arp_, _ := arpLayer.(*layers.ARP) if bytes.Equal(arp_.SourceProtAddress, dstip) && arp_.Operation == 2 { macchan <- arp_.SourceHwAddress break } } } wg.Done() }() err = handle.WritePacketData(buf.Bytes()) if err != nil { return dstmac, err } wg.Wait() dstmac = <-macchan return dstmac, nil }
func main() { flag.Parse() log.Printf("starting capture on interface %q", *iface) // Set up pcap packet capture handle, err := pcap.OpenLive(*iface, int32(*snaplen), true, time.Minute) if err != nil { log.Fatal("error opening pcap handle: ", 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) 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(time.Minute) loop: for { // 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(-time.Minute * 2)) nextFlush = time.Now().Add(time.Minute) } // 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, _, err := handle.ZeroCopyReadPacketData() if err != nil { log.Printf("error getting packet: %v", err) 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) } // 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.Assemble(netFlow, &tcp) } else { log.Println("could not find IPv4 or IPv6 layer, inoring") } continue loop } } log.Println("could not find TCP layer") } }