使用Python捕获TCP数据包

3 投票
2 回答
13040 浏览
提问于 2025-04-17 00:09

我尝试用Python的dpkt和pcap来捕获HTTP下载。我的代码大概是这样的:

...
pc = pcap.pcap(iface)
for ts, pkt in pc:
    handle_packet(pkt)

def handle_packet(pkt):
    eth = dpkt.ethernet.Ethernet(pkt)

    # Ignore non-IP and non-TCP packets
    if eth.type != dpkt.ethernet.ETH_TYPE_IP:
        return
    ip = eth.data
    if ip.p != dpkt.ip.IP_PROTO_TCP:
        return

    tcp = ip.data
    data = tcp.data

    # current connection
    c = (ip.src, ip.dst, tcp.sport, tcp.dport)

    # Handle only new HTTP-responses and TCP-packets
    # of existing connections.
    if c in conn:
        handle_tcp_packet(c, tcp)
    elif data[:4] == 'HTTP':
        handle_http_response(c, tcp)
...

handle_http_response()handle_tcp_packet()这两个函数里,我读取TCP数据包里的数据(tcp.data),然后把它们写到一个文件里。不过我注意到,我经常会收到一些TCP序列号(tcp.seq)相同的数据包(在同一个连接上),但它们似乎包含的是相同的数据。此外,似乎并不是所有的数据包都被捕获到。例如,如果我把所有数据包的大小加起来,结果的值会比HTTP头里的content-length小。但是在Wireshark里我能看到所有的数据包。

有没有人知道为什么我会收到这些重复的数据包,以及我该如何捕获到所有属于HTTP响应的数据包?

编辑:
这里是完整的代码:pastebin.com。运行时,它会在标准输出上打印类似这样的内容:

Waiting for HTTP-Audio-responses ...
...
New TCP-Packet, len=1440, tcp-payload=5107680, con-len=5197150 , dups=57 , dup-bytes=82080
New TCP-Packet, len=1440, tcp-payload=5109120, con-len=5197150 , dups=57 , dup-bytes=82080
New TCP-Packet, len=1440, tcp-payload=5110560, con-len=5197150 , dups=57 , dup-bytes=82080
----------> FIN <----------
New TCP-Packet, len=1937, tcp-payload=5112497, con-len=5197150 , dups=57 , dup-bytes=82080
New TCP-Packet, len=0, tcp-payload=5112497, con-len=5197150 , dups=57 , dup-bytes=82080

如你所见,TCP负载加上重复接收到的字节(5112497+82080=5194577)小于下载的文件大小(5197150)。而且你可以看到我收到了57个重复的数据包(相同的SEQ和相同的TCP数据),并且在带有FIN标志的数据包之后仍然有数据包被接收。

那么,有人知道我该如何捕获所有属于这个连接的数据包吗?Wireshark能看到所有的数据包,我想它也使用libpcap。

我甚至不知道我是不是做错了什么,或者是pcap库出了问题。

编辑2:
好的,看来我的代码是正确的:在Wireshark里我保存了捕获到的数据包,并在我的代码中使用了这个捕获文件(pcap.pcap('/home/path/filename'),而不是pcap.pcap('eth0'))。我的代码完美地读取了所有的数据包(经过多次测试)!因为Wireshark也使用libpcap(据我所知),所以我认为问题出在pypcap库上,它没有提供我所有的数据包。

有没有什么办法可以测试这个问题?

我已经自己编译了pypcap(trunk),但这并没有改变什么 -.-

编辑3:
好的,我把我的代码改成用pcapy而不是pypcap,结果还是同样的问题:
当我从之前用Wireshark捕获的文件中读取数据包时,一切都很好,但当我直接从eth0捕获数据包时,有些数据包就丢失了。

有趣的是:当我同时运行两个程序(一个用pypcap,另一个用pcapy)时,它们捕获到的数据包是不同的。例如,一个程序多接收到一个数据包。

但我还是不知道为什么 -.-
我以为Wireshark使用的是相同的基础库(libpcap)。

请帮帮我 :)

2 个回答

0

把抓包的长度设置为65535。显然,这个值是Wireshark的默认设置:

http://www.wireshark.org/docs/wsug_html_chunked/ChCustCommandLine.html

1

这里有几个需要注意的事项:

  • 确保你的快照长度(snaplen)设置得足够大——在使用pcapy时,可以在open_live的第二个参数中设置这个值。
  • 要处理好分片的数据包——这不会自动完成,你需要自己检查具体的细节。
  • 查看统计信息——遗憾的是,我觉得pcapy的接口没有提供这个功能,但有可能你没有处理所有的数据包;如果你处理得太晚,就不知道自己漏掉了什么(不过你可以通过跟踪TCP流的长度和位置来获取相同的信息)。libpcap本身是有这些统计信息的,所以你可能可以为它添加这个功能。

撰写回答