Cannot trace error in python pcapy wrapper

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:

  • pg_restore in postgres docker container
  • What does Kubernetes actually do? [closed]
  • Setup Mesos-DNS dockerized on a mesos cluster
  • Docker DNS not working
  • Install pylint in Alpine Linux based Docker Image
  • Docker Apache graceful shutdown
  • 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: Docker version 1.5.0, build a8a31ef
    • Docker image is the Docker default Ubuntu
    • Python2.7

  • crontab does not get the log in log file
  • docker-compose up via Windows bat file?
  • How to delete all tagged docker images?
  • “Error: mysqli_connect() No Such File or Directory”. PHP 7 FPM, MariaDB, Nginx, Docker
  • Unable to register docker selenium remote node to selenium hub remote host with docker
  • architecture for multiple nginx/php apps using docker
  • 2 Solutions collect form web for “Cannot trace error in python pcapy wrapper”

    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
    

    the answer is pretty simple:
    p.next() will throw on timeout
    your timeout is 100ms (last parameter of open_live)

    so your except should handle the timeout case and you may want to increase the timeout time or set it to 0 for infinite

    edit:
    you simply expected socket.timeout but PcapError is thrown instead. socket.timeout is the exception thrown by the socket code in the python lib so it is python specific. It is getting wrapped up (maybe just with new versions of pcapy) or it jsut stands for a different kind of timeout (TCP socket related)
    see example pcapy code: example

    Docker will be the best open platform for developers and sysadmins to build, ship, and run distributed applications.