google / gopacket

Provides packet processing capabilities for Go
BSD 3-Clause "New" or "Revised" License
6.35k stars 1.13k forks source link

Stop pcap? #890

Open herrin opened 3 years ago

herrin commented 3 years ago

Stupid question but how do I stop pcap?

If I set a timeout in pcap.OpenLive, ReadPacketData waits until the timeout (regardless of packets received) and then gives me only the first packet it captured. This seems weird and broken.

If I set pcap.BlockForever, ReadPacketData doesn't return until it receives a packet. If no packet arrives, it doesn't stop. I can empty the BPF in another thread but if there are no packets at all on the NIC, it doesn't stop.

Close() blocks until ReadPacketData returns.

The only thing I've found so far is if I intentionally send a matching packet out the interface, ReadPacketData will return it, subsequently allowing me to shut down pcap. Surely there's a better way?

In C I think I would pcap_breakloop() but that doesn't seem to be exposed in gopacket pcap?

zhangbo1882 commented 3 years ago

I have met the same issue. Are there any solution to bypass such issues ?

zhangbo1882 commented 3 years ago
goroutine profile: total 8
1 @ 0x408a6b 0x81f20d 0x821a6c 0x820b6b 0x81d591 0x81d39b 0x7972b8 0x797515 0x46c171
#   0x81f20c    github.com/google/gopacket/pcap._Cfunc_pcap_next_ex_escaping+0x4c   _cgo_gotypes.go:549
#   0x821a6b    github.com/google/gopacket/pcap.(*Handle).pcapNextPacketEx.func1+0x7b   /home/stack/fetrace/vendor/github.com/google/gopacket/pcap/pcap_unix.go:398
#   0x820b6a    github.com/google/gopacket/pcap.(*Handle).pcapNextPacketEx+0x2a     /home/stack/fetrace/vendor/github.com/google/gopacket/pcap/pcap_unix.go:398
#   0x81d590    github.com/google/gopacket/pcap.(*Handle).getNextBufPtrLocked+0x60  /home/stack/fetrace/vendor/github.com/google/gopacket/pcap/pcap.go:312
#   0x81d39a    github.com/google/gopacket/pcap.(*Handle).ReadPacketData+0x8a       /home/stack/fetrace/vendor/github.com/google/gopacket/pcap/pcap.go:252
#   0x7972b7    github.com/google/gopacket.(*PacketSource).NextPacket+0x47      /home/stack/fetrace/vendor/github.com/google/gopacket/packet.go:801
#   0x797514    github.com/google/gopacket.(*PacketSource).packetsToChannel+0x64    /home/stack/fetrace/vendor/github.com/google/gopacket/packet.go:818

handle.Close()--> p.mu.Lock() But the lock is held by packetsToChannel->p.Nextpacket()->p.source.ReadPacketData()

   func (p *Handle) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
      **p.mu.Lock()**
      err = p.getNextBufPtrLocked(&ci)
      if err == nil {
          data = make([]byte, ci.CaptureLength)
          copy(data, (*(*[1 << 30]byte)(unsafe.Pointer(p.bufptr)))[:])
      }
      p.mu.Unlock()
      if err == NextErrorTimeoutExpired {
          runtime.Gosched()
      }
      return
  }

getNextBufPtrLocked()->p.pcapNextPacketEx()-->C.pcap_next_ex_escaping

The root cause is C.pcap_next_ex_escaping is blocked unless there is a new packet arrives.

zhangbo1882 commented 3 years ago

It have the same issue is #862

prskr commented 2 years ago

From what I can tell this can be solved by calling:

_ = unix.Shutdown(int(handle), unix.SHUT_RDWR)

to close the handle without getting a packet and therefore unlocking the goroutine and the lock. I prepared a PR for this and some other things but didn't get any feedback on it...might be helpful anyway for you :blush:

michaelquigley commented 2 years ago

I prepared a PR for this and some other things but didn't get any feedback on it...might be helpful anyway for you blush

Got a link to the PR for this? Would love to check this out...

prskr commented 2 years ago

The PR is #893 - at some point I assumed that I won't merge it anyway hence I reworked a bit more to tweak memory consumption and support cancellation with context.Context but I'm using this already for months in production :sweat_smile:

michaelquigley commented 2 years ago

Awesome! So, with this patch, you're able to stop packet capture even when no packets show up?

prskr commented 2 years ago

I'm pretty sure this should work, yes, because that was exactly my issue when running in my CI environment :smile: give it a try and let me know if you encounter any issue and I'll see what I can do

michaelquigley commented 2 years ago

Will give it a try today... Very much appreciate the quick response. Will let you know how it works out, either way.

prskr commented 2 years ago

Just out of curiosity: how did it go?

michaelquigley commented 2 years ago

We managed to get things working... thank you!

Archimes commented 4 months ago

https://github.com/google/gopacket/issues/1089#issuecomment-1501148868 try this solution