DPKT库说它现在支持Python3,但是当我在Python 2.x和3.x中使用它时,它具有不同的行为。虽然,两者都不正确,但它会出现。
例如,在Python 2.x中,示例为here
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'
我没有运气将该字符串转换为人类可读的对象。 decode
,binascii
或我尝试过的其他任何方法均无效。我使用的库不正确吗?
答案 0 :(得分:1)
python2和python3之间的主要区别之一是在python3中,str
和bytes
不再相同。比较:
$ python2 -c 'print(b"foo" == "foo")'
True
$ python3 -c 'print(b"foo" == "foo")'
False
这说明了为什么必须在python3中使用"rb"
打开文件。 (尽管如果您在某些使用python2的平台上不这样做,则很可能会得到虚假结果,因为如果没有b
行尾,那么该文件中恰好存在的行尾可能会不适当地扩展。)
另一个区别:在python3中,print
是一个函数,而不是语句,因此,您上面在python3中显示的代码实际上是语法错误。相反,您需要print(eth)
要回答您的实际问题:仅打印eth
时,您就隐式地要求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)
以获得格式化的表示形式。