I'm using python pcapy
in a docker
container using this piece of code:
from pcapy import open_live, findalldevs
import sys
import traceback
p = open_live("eth0", 1024, False, 100)
dumper = p.dump_open("test.pcap")
devices = findalldevs()
print dumper, devices
while True:
try:
print p.next()
except Exception as e:
print dir(e), e.message, e.args[0]
traceback.print_exc(file=sys.stdout)
break
When I run it I get the following exception:
Traceback (most recent call last):
File "test_pcap.py", line 12, in
print p.next()
PcapError
I've tried to play with the arguments by changing to different maximum packet sizes and setting promiscuous to True
.
I've tried to get any message from the exception, but it seems the message is empty. I also skimmed through pcapy source code: since the exception in the PcapyError object is empty and the other PcapErrors in the next
function are explicit strings, it implies we are falling into the condition in which buf
is empty. It seems pcap_geterr
returns an empty string because pp->pcap
has been closed and the pointer to the pcap exception no longer exists (take a look into the doc).
When I run using the loop()
method, everything works fine:
# Modified from: http://snipplr.com/view/3579/
import pcapy
from impacket.ImpactDecoder import *
# list all the network devices
pcapy.findalldevs()
max_bytes = 1024
promiscuous = False
read_timeout = 100 # in milliseconds
pc = pcapy.open_live("eth0", max_bytes,
promiscuous, read_timeout)
# callback for received packets
def recv_pkts(hdr, data):
packet = EthDecoder().decode(data)
print packet
packet_limit = -1 # infinite
pc.loop(packet_limit, recv_pkts) # capture packets
I really don't know the source of the problem or what else to do for debugging it.
EDIT
I cannot find any error using strace
. This is the grep for error in strace
output:
strace python test_pcap.py 2>&1 1>/dev/null | grep -i error
read(6, "\0\0\0t\3\0\0\0intt\n\0\0\0ValueErrort\23\0\0\0_"..., 4096) = 995
getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
getsockopt(5, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
getsockopt(5, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
EDIT2
I also tested pcap.h
by calling to pcap_next
myself:
// Modified from: http://www.tcpdump.org/pcap.html
#include <pcap.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
pcap_t *handle; /* Session handle */
char *dev; /* The device to sniff on */
char errbuf[PCAP_ERRBUF_SIZE]; /* Error string */
bpf_u_int32 mask; /* Our netmask */
bpf_u_int32 net; /* Our IP */
struct pcap_pkthdr header; /* The header that pcap gives us */
const u_char *packet; /* The actual packet */
/* Define the device */
dev = pcap_lookupdev(errbuf);
if (dev == NULL) {
fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
return(2);
}
/* Find the properties for the device */
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
net = 0;
mask = 0;
}
/* Open the session in promiscuous mode */
handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
if (handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s\n", "eth0", errbuf);
return(2);
}
while (1) {
/* Grab a packet */
packet = pcap_next(handle, &header);
/* Print its length */
printf("Jacked a packet with length of [%d]\n", header.len);
/* Print contents */
printf("\tPacket: %s\n", packet);
/* And close the session */
}
pcap_close(handle);
return(0);
}
To compile, write it to test_sniff.c
and run:
gcc test_sniff.c -o test_sniff -lpcap
And I was able to capture packets successfully. So I don't really know where the problem is...
Other info to reproduce behaviour
Docker version 1.5.0, build a8a31ef
Ubuntu
pcapy
doesn't use Python socket
module. It won't raise socket.timeout
which is raised if timeout has been enabled by previous socket.settimeout
call. socket.settimeout
is used to set a socket
into blocking, non-blocking or timeout state.
In pcapy
, the timeout argument of open_live
is passed to poll
syscall at least in Linux, should differ by OS where poll
is not available.
Reader.next
call raises PcapError
if there's no packet to return because it hasn't captured any packets yet. It's not an error, just an indication like StopIteration
. It can be ignored and Reader.next
has to be called again.
Reader.loop
won't return until it has at least one packet to return or an error occurs.
The following code captures 10 packets and exits.
from pcapy import open_live, findalldevs, PcapError
p = open_live("eth0", 1024, False, 100)
dumper = p.dump_open("test.pcap")
devices = findalldevs()
print dumper, devices
count=0
while True:
try:
packet = p.next()
except PcapError:
continue
else:
print packet
count += 1
if count == 10:
break