0

DPKT 库说它现在支持 Python3,但是当我在 Python 2.x 和 3.x 中使用它时,它的行为有所不同。虽然,两者都不正确,但它似乎出现了。

例如,在 Python 2.x 中,此处给出的示例

with open('test.pcap') as f:
    pcap = dpkt.pcap.Reader(f)
    for ts, buf in pcap:
       eth = dpkt.ethernet.Ethernet(buf)
       print eth

返回一个我不期望的格式,一个类似于:

   ^����6#���l�m�
Q!6�(�����k����~�pO���o���N�l   �k4�'���8�9�j��@mf���5��pB�6bٌ�~p��Jf.Jܼ3H�:�ݭ�k-O7+�O��
4�(�9��^F�fb��V��t˜������\�X1��#�.�ج<�Q�!����>�^ɹDĀ�orC=bC���S�6;��SR�`�� �

ZD����j2Q���m����h��)1@��1���aw}�d�ڧn�                                          ��
0Z:�`8ຄE(�@4���}������Mu��63fP�/�
������h'7�h'7�;������

但是,在 Python 3 中,我被迫以“rb”模式打开 pcap 文件,这很好,除了输出问题(我不确定“rb”现在与这些问题有什么关系):

with open('test.pcap', 'rb') as f:
    pcap = dpkt.pcap.Reader(f)
    for ts, buf in pcap:
       eth = dpkt.ethernet.Ethernet(buf)
       print eth

这现在返回我认为是字节串的内容,但我还没有找到一种方法来从中获取我需要的数据。例如,如果我需要标志的数量,我可以从他们网站的上述示例中轻松获得 17 个,但我似乎根本无法让他们的示例工作:

b'\x00\x0f\x1f\x16\xd1\xcd\x00\xc0\xf0y\x9a\xfd\x08\x00E\x00\x00\x1c\xb1\xce\x00\x006\x01N\xf7\xc0\xa8\x01d\xc0\xa8\x01g\x08\x00\xd9\xd7\xb7\xc4fc'

我没有任何运气将此字符串转换为人类可读的对象。没有任何组合decodebinascii或者我尝试过的任何其他方法都有效。我是否错误地使用了这个库?

4

1 回答 1

3

python2和python3之间的主要区别之一是在python3中,str不再bytes相同。相比:

$ python2 -c 'print(b"foo" == "foo")'
True

$ python3 -c 'print(b"foo" == "foo")'
False

"rb"这解释了为什么你必须在 python3 中打开文件。(尽管如果您在某些使用 python2 的平台上不这样做,您很可能会得到虚假的结果,因为如果b文件中不存在恰好存在的行结尾可能会被不适当地扩展。)

另一个区别:在 python3 中,print是一个函数,而不是一个语句,所以上面显示的 python3 代码实际上是一个语法错误。相反,你需要print(eth)

回答您的实际问题:当您简单地 printeth时,您隐含地要求eth对象使其自身可打印。这与调用相同print(str(eth)),因此它为您提供了包含以太网帧的二进制数据缓冲区的可打印字符串版本。

您需要使用 的工具dpkt来发现,然后剖析您关心的框架部分。

这是一个解码包含 DNS 数据包的 pcap 的简短示例:

import dpkt
with open("/tmp/dns.pcap", "rb") as f:
    pcap = dpkt.pcap.Reader(f)
    for ts, buf in pcap:
        l2 = dpkt.ethernet.Ethernet(buf)
        print("Ethernet (L2) frame:", repr(l2))

        if l2.type not in (dpkt.ethernet.ETH_TYPE_IP, dpkt.ethernet.ETH_TYPE_IP6):
            print("Not an IP packet")
            continue
        l3 = l2.data
        print("IP packet:", repr(l3))

        if l3.p not in (dpkt.ip.IP_PROTO_TCP, dpkt.ip.IP_PROTO_UDP):
            print("Not TCP or UDP")
            continue

        l4 = l3.data
        print("Layer 4:", repr(l4))

        if l4.dport in (53, 5353) or l4.sport in (53, 5353):
            dns = l4.data
            if not isinstance(dns, dpkt.dns.DNS):
                dns = dpkt.dns.DNS(dns)
            print("DNS packet:", repr(dns))

至于为什么您的输出看起来与教程不同。该教程已过时。显然在某些时候,对象__str__上的魔术方法的实现发生了dpkt变化(当您只是print一个对象时,您会得到其__str__方法的结果)。

最初,__str__返回对象的格式化表示。稍后它只返回对象原始字节的字符串表示形式。所以现在你需要调用repr(obj)以获得格式化的表示。

于 2019-12-07T00:12:05.477 回答