helpsystems / pcapy

Pcapy is a Python extension module that interfaces with the libpcap packet capture library.
Other
381 stars 104 forks source link

Support for immediate mode #23

Open brifordwylie opened 7 years ago

brifordwylie commented 7 years ago

Great python module, thanks for making it available to the public. Wondering if you could add an option (defaulted to False) to set immediate mode (no buffering of packets). Several of the other python wrappers for libpcap have an immediate flag.

csavoie commented 7 years ago

The need for be able to set the immediate flag has become more urgent when using the latest libpacp library in linux. In the latest version of libpcap(1.8.1 and above... see https://github.com/the-tcpdump-group/libpcap/issues/572), the timeout parameter for pcapy_open_live doesn't cause the next function to return after waiting until timeout like in earlier version. In 1.8.1, the next function will wait until it receives a packet and the timeout is the amount of time to buffer a packet.
The solution to the problem is to set immediate mode so it will return when no packets have been received.

brifordwylie commented 7 years ago

@csavoie You're saying this is possible now with the current code base or you're just elaborating on how it should be done?

csavoie commented 7 years ago

@brifordwylie I have reproduced this problem in sles12 sp2 which has updated the libpcap package to 1.8.1. I have a python script that snoops for vrrp packets in a closed network. If it is first system online, it will wait forever for a packet even though I set a timeout 60 seconds. I traced it down to the change in behavior of the timeout parameter for pcap_open_live().

brifordwylie commented 7 years ago

@csavoie just to be explicit. Let me restate the feature request with example code :)

With the pypcap module (for instance) you can set the immediate flag to true and this code will immediately begin printing packets as they arrive:

import pcap
sniffer = pcap.pcap(name=None, promisc=True, immediate=True)
for ts, pkt in sniffer:
    print ts, repr(pkt)

The equivalent code with pcapy will often wait a couple minutes (based on traffic volume) to start printing out packets.

import pcapy

sniffer = pcapy.open_live('en0', 65536 , 1 , 0)
while True:
    # Grab the next header and packet buffer
    header, raw_buf = sniffer.next()
    print header

So the feature request is to return as soon as you get a packet (not wait for some pcap buffer to fill up.. or whatever is causing the long delay before starting...).

Version info:

csavoie commented 7 years ago

On further inspection of the code and issue#572, it looks like pcapy is unable to implement the changes that I'm looking for. In Linux, the libpcap library in 1.8.1 has a slightly different behavior when it comes to the use of the timeout parameter in open_live() function. In the older version, the timeout would force the next() function to wait until it received a packet for the timeout value from open_live().
What I did realize was that the open_live() function create cap object and activates it. You can't set the immmediate flag once a cap object is active so the solution to my problem can't be solved with pcapy.

brifordwylie commented 7 years ago

@csavoie it's clear at this point that you have a different issue/feature request, so perhaps open another issue for that. I'd like to keep this feature request focused on this particular requested feature, basically an immediate return when a packet arrives.

guyharris commented 7 years ago

If you want libpcap to deliver packets as soon as they arrive, you have to turn on immediate mode, and, in the general case, that means using pcap_create() and pcap_activate() to open a device on which to capture, with a call to pcap_set_immediate_mode() between those two calls. It can't be done if you're using pcap_open_live() to open the device - on Linux, you can't do immediate mode with TPACKET_V3, and changing from TPACKET_V3 to TPACKET_V2 involves almost as much work as closing a device and re-opening it, so we require that immediate mode be specified before we set up the TPACKET ring buffer, and there are no arguments to pcap_open_live() available to indicate that.

So, if you want an immediate return when a packet arrives, and want to support that in a portable fashion, you'll either need to export pcap_create(), pcap_activate(), and the routines called between those two calls to Python callers or you'll need to export APIs that use them.

(As for the timeout, libpcap has never guaranteed, in its API contract, that the timeout is guaranteed to trigger before any packets have arrived; whether it triggers before any packets have arrived depends on the OS (libpcap being a wrapper around the very-different capture mechanisms on different OSes) and, in the case of Linux, it also depends on the kernel version.)