无法跟踪 python pcapy 包装器中的错误

Cannot trace error in python pcapy wrapper

我在 docker 容器中使用 python pcapy 使用这段代码:

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

当我 运行 它时,我得到以下异常:

Traceback (most recent call last):

File "test_pcap.py", line 12, in

print p.next()

PcapError

我尝试通过更改为不同的最大数据包大小并将混杂设置为 True

我试图从异常中获取任何消息,但消息似乎是空的。我还浏览了 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).

当我运行使用loop()方法时,一切正常:

# 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

我真的不知道问题的根源或调试它的其他方法。

编辑

我使用 strace 找不到任何错误。这是 strace 输出中错误的 grep:

strace python test_pcap.py 2>&1 1>/dev/null | grep -i error

read(6, "[=33=][=33=][=33=]t[=33=][=33=][=33=]intt\n[=33=][=33=][=33=]ValueErrort[=33=][=33=][=33=]_"..., 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

我也通过自己打电话给 pcap_next 测试了 pcap.h

 // 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);
 }

要编译,写入test_sniff.c和运行:

gcc test_sniff.c -o test_sniff -lpcap

并且我能够成功捕获数据包。所以我真的不知道问题出在哪里...

重现行为的其他信息

答案很简单:
p.next() 将在 timeout
throw 您的超时是 100msopen_live 的最后一个参数)

所以你的 except 应该处理超时情况,你可能想增加 timeout 时间或将它设置为 0 for infinite

编辑:
你只是期望 socket.timeoutPcapError 被抛出。 socket.timeout 是 python 库中的套接字代码抛出的异常,因此它是 python 特定的。它正在结束(可能只是使用新版本的 pcapy)或者它只是代表一种不同类型的超时(与 TCP 套接字相关)
请参阅示例 pcapy 代码:example

pcapy 不使用 Python socket 模块。如果先前的 socket.settimeout 调用启用了超时,它不会引发 socket.timeoutsocket.settimeout用于将socket设置为阻塞、非阻塞或超时状态。

pcapy 中,open_live 的超时参数至少在 Linux 中传递给 poll 系统调用,应该与 OS 不同,其中 poll 不可用。

Reader.next 如果没有数据包到 return,调用会引发 PcapError,因为它还没有捕获任何数据包。这不是错误,只是像 StopIteration 这样的指示。可以忽略,需要重新调用Reader.next

Reader.loop 不会 return 直到它至少有一个数据包到 return 或发生错误。

以下代码捕获 10 个数据包并退出。

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