scapy 导出的 linux 熟模式捕获不会在 wireshark 中打开
scapy's exported linux cooked-mode capture doesn't open in wireshark
这是一个简单的例子:
from scapy.all import *
pkts = rdpcap('/tmp/sample.pcap')
wireshark(pkts)
然后wireshark报错:
The capture file appears to be damaged or corrupt.
(libpcap: IrDA capture has a packet with an invalid sll_protocol field)
我正在使用 wireshark 1.8、python 2.7.3 和 scapy 2.2.0。
注意:我可以直接使用 wireshark 打开 smaple.pcap 文件。
如何使 scapy 生成的 pcap 文件在 wireshark 中打开?
编辑:
我尝试了其他 pcap 文件(来自 wireshark 捕获样本)并且它有效。看来问题出在我的数据包中。这是第一个数据包(也不起作用):
###[ cooked linux ]###
pkttype = unicast
lladdrtype= 0x1
lladdrlen = 6
src = '\x00\x04\xed\xcb\x9b0'
proto = 0x800
###[ IP ]###
version = 4L
ihl = 5L
tos = 0xb8
len = 165
id = 47433
flags =
frag = 0L
ttl = 49
proto = udp
chksum = 0x50c9
src = 22.31.32.55
dst = 192.168.1.102
\options \
###[ UDP ]###
sport = 4566
dport = 4566
len = 145
chksum = 0x0
###[ Raw ]###
load = 'H\x84\x80\x80\x80\x80\x80\x8c\x80\x80\x86\x81\x8b\x82\x80\x82\x81\x98\xb1\xb9\xb2\xae\xb1\xb6\xb8\xae\xb1\xae\xb2\xb5\xad\xb0\xb1\xb2\xb2\xb6\xb6\xb5\xb7\xb4\xb9\xb4\xad\x81\xca\x82\x89\xb9\xb9\xb5\xb0\xb6\xb1\xb0\xb3\xb3\xa6\x81\x80\xa7\x81\x80\xa8\x82\x80\x80\x84\x89\xb9\xb9\xb5\xb0\xb6\xb1\xb0\xb3\xb3\x8a\x82\xe5\xee\x86\x88\xe3\xe3\xec\xe9\xe5\xee\xf4\xb2\x89\x84\x80\x80\x81\x80\xb8\x89\x80\x80\x80\x80\x80\x80\x80\x81\x80\x88\x84\x80\x80\x81\x80\xb7\x89\x80\x80\x80\x80\x80\x80\x80\x81\x80\x8c\x82\x80\x82\x9f\x84\x9e\xa7 \xe2\xb6\x80'
注意:更改了 IP 地址,因此校验和可能不正确。
我不知道问题出在哪里,但可以通过以下方式解决:
wireshark(pkt for pkt in pkts) # don't supply a list but rather a generator
这还会输出以下消息:
WARNING: PcapWriter: unknown LL type for generator. Using type 1 (Ethernet)
显然,wireshark
函数不处理 Linux cooked-mode capture that well. This odd situation might have something to do with the following excerpt from scapy
's wiki:
Please remember that Wireshark works with Layer 2 packets (usually called "frames"). So we had to add an Ether()
header to our ICMP packets. Passing just IP packets (layer 3) to Wireshark will give strange results.
如果我们真的不关心第 2 层帧,我们也可以通过创建一个虚拟以太网层来规避这个问题:
pkts = [Ether(src=pkt[0].src)/pkt[1:] for pkt in pkts]
编辑 - 经过进一步研究和分析 scapy 的源代码,我明白了为什么传递一个生成器 object 似乎可以解决这个问题。
wireshark
函数创建一个包含数据包的临时文件,并使用该文件启动 Wireshark。在该文件的 header 中指定的 link 类型按以下方式提取:
if self.linktype == None:
if type(pkt) is list or type(pkt) is tuple or isinstance(pkt,BasePacketList):
pkt = pkt[0]
try:
self.linktype = conf.l2types[pkt.__class__]
except KeyError:
warning("PcapWriter: unknown LL type for %s. Using type 1 (Ethernet)" % pkt.__class__.__name__)
self.linktype = 1
当传递生成器 object 时,第一个 if
语句的计算结果为 False
(这显然是一个错误)并且在尝试访问 [=21= 时引发异常] 因为 pkt.__class__
是 <type 'generator'>
。因此执行try-except
代码块的except子句,指定link类型为1.
然而,当传递真实列表时,第一个 if
语句计算为 True
并且列表的第一个数据包被提取并用于访问 conf.l2types
,即:
In [2]: conf.l2types
Out[2]:
0x1 <- Dot3 (802.3)
0x1 <-> Ether (Ethernet)
0xc -> IP (IP)
0x17 -> Ether (Ethernet)
0x1f <-> IPv6 (IPv6)
0x65 <-> IP (IP)
0x69 <-> Dot11 (802.11)
0x71 -> CookedLinux (cooked linux)
0x77 <-> PrismHeader (Prism header)
0x7f <-> RadioTap (RadioTap dummy)
0x90 <-> CookedLinux (cooked linux)
0xc0 <-> PPI (Per-Packet Information header (partial))
0x304 -> Ether (Ethernet)
0x321 -> Dot11 (802.11)
0x322 -> PrismHeader (Prism header)
0x323 -> RadioTap (RadioTap dummy)
因为 pkts[0].__class__
是 scapy.layers.l2.CookedLinux
,link 类型被设置为 0x90
而不是 0x71
(似乎又是一个错误),这导致 Wireshark 无法解析文件。
因此,我认为最好的方法是模仿 scapy 的 wireshark
函数,并允许用户明确指定 link 类型:
def wireshark(*args, **kwargs):
"""Run wireshark on a list of packets"""
f = scapy.all.get_temp_file()
scapy.all.wrpcap(f, *args, **kwargs)
subprocess.Popen([scapy.all.conf.prog.wireshark, "-r", f])
wireshark(pkts, linktype=0x71)
编辑 - 我现在注意到 link 类型映射问题已经 reported and fixed by secdev. However, it hasn't reached python-scapy
just yet. I've also created a new issue 关于生成器的无效处理 object 在 PcapWriter
.
(libpcap: IrDA capture has a packet with an invalid sll_protocol field)
Linux IrDA 使用了一些东西 像 和 Linux cooked-mode header,但它不一样:
- Linux cooked-mode header,link-layer header 类型为 113;
- Linux IrDA header,link-layer header 类型为 144。
不知道是什么原因导致你的程序选择了144而不是113;您的 输入 文件是 Linux IrDA 文件而不是 Linux 熟捕获文件吗?
这是一个简单的例子:
from scapy.all import *
pkts = rdpcap('/tmp/sample.pcap')
wireshark(pkts)
然后wireshark报错:
The capture file appears to be damaged or corrupt.
(libpcap: IrDA capture has a packet with an invalid sll_protocol field)
我正在使用 wireshark 1.8、python 2.7.3 和 scapy 2.2.0。
注意:我可以直接使用 wireshark 打开 smaple.pcap 文件。
如何使 scapy 生成的 pcap 文件在 wireshark 中打开?
编辑: 我尝试了其他 pcap 文件(来自 wireshark 捕获样本)并且它有效。看来问题出在我的数据包中。这是第一个数据包(也不起作用):
###[ cooked linux ]###
pkttype = unicast
lladdrtype= 0x1
lladdrlen = 6
src = '\x00\x04\xed\xcb\x9b0'
proto = 0x800
###[ IP ]###
version = 4L
ihl = 5L
tos = 0xb8
len = 165
id = 47433
flags =
frag = 0L
ttl = 49
proto = udp
chksum = 0x50c9
src = 22.31.32.55
dst = 192.168.1.102
\options \
###[ UDP ]###
sport = 4566
dport = 4566
len = 145
chksum = 0x0
###[ Raw ]###
load = 'H\x84\x80\x80\x80\x80\x80\x8c\x80\x80\x86\x81\x8b\x82\x80\x82\x81\x98\xb1\xb9\xb2\xae\xb1\xb6\xb8\xae\xb1\xae\xb2\xb5\xad\xb0\xb1\xb2\xb2\xb6\xb6\xb5\xb7\xb4\xb9\xb4\xad\x81\xca\x82\x89\xb9\xb9\xb5\xb0\xb6\xb1\xb0\xb3\xb3\xa6\x81\x80\xa7\x81\x80\xa8\x82\x80\x80\x84\x89\xb9\xb9\xb5\xb0\xb6\xb1\xb0\xb3\xb3\x8a\x82\xe5\xee\x86\x88\xe3\xe3\xec\xe9\xe5\xee\xf4\xb2\x89\x84\x80\x80\x81\x80\xb8\x89\x80\x80\x80\x80\x80\x80\x80\x81\x80\x88\x84\x80\x80\x81\x80\xb7\x89\x80\x80\x80\x80\x80\x80\x80\x81\x80\x8c\x82\x80\x82\x9f\x84\x9e\xa7 \xe2\xb6\x80'
注意:更改了 IP 地址,因此校验和可能不正确。
我不知道问题出在哪里,但可以通过以下方式解决:
wireshark(pkt for pkt in pkts) # don't supply a list but rather a generator
这还会输出以下消息:
WARNING: PcapWriter: unknown LL type for generator. Using type 1 (Ethernet)
显然,wireshark
函数不处理 Linux cooked-mode capture that well. This odd situation might have something to do with the following excerpt from scapy
's wiki:
Please remember that Wireshark works with Layer 2 packets (usually called "frames"). So we had to add an
Ether()
header to our ICMP packets. Passing just IP packets (layer 3) to Wireshark will give strange results.
如果我们真的不关心第 2 层帧,我们也可以通过创建一个虚拟以太网层来规避这个问题:
pkts = [Ether(src=pkt[0].src)/pkt[1:] for pkt in pkts]
编辑 - 经过进一步研究和分析 scapy 的源代码,我明白了为什么传递一个生成器 object 似乎可以解决这个问题。
wireshark
函数创建一个包含数据包的临时文件,并使用该文件启动 Wireshark。在该文件的 header 中指定的 link 类型按以下方式提取:
if self.linktype == None:
if type(pkt) is list or type(pkt) is tuple or isinstance(pkt,BasePacketList):
pkt = pkt[0]
try:
self.linktype = conf.l2types[pkt.__class__]
except KeyError:
warning("PcapWriter: unknown LL type for %s. Using type 1 (Ethernet)" % pkt.__class__.__name__)
self.linktype = 1
当传递生成器 object 时,第一个 if
语句的计算结果为 False
(这显然是一个错误)并且在尝试访问 [=21= 时引发异常] 因为 pkt.__class__
是 <type 'generator'>
。因此执行try-except
代码块的except子句,指定link类型为1.
然而,当传递真实列表时,第一个 if
语句计算为 True
并且列表的第一个数据包被提取并用于访问 conf.l2types
,即:
In [2]: conf.l2types
Out[2]:
0x1 <- Dot3 (802.3)
0x1 <-> Ether (Ethernet)
0xc -> IP (IP)
0x17 -> Ether (Ethernet)
0x1f <-> IPv6 (IPv6)
0x65 <-> IP (IP)
0x69 <-> Dot11 (802.11)
0x71 -> CookedLinux (cooked linux)
0x77 <-> PrismHeader (Prism header)
0x7f <-> RadioTap (RadioTap dummy)
0x90 <-> CookedLinux (cooked linux)
0xc0 <-> PPI (Per-Packet Information header (partial))
0x304 -> Ether (Ethernet)
0x321 -> Dot11 (802.11)
0x322 -> PrismHeader (Prism header)
0x323 -> RadioTap (RadioTap dummy)
因为 pkts[0].__class__
是 scapy.layers.l2.CookedLinux
,link 类型被设置为 0x90
而不是 0x71
(似乎又是一个错误),这导致 Wireshark 无法解析文件。
因此,我认为最好的方法是模仿 scapy 的 wireshark
函数,并允许用户明确指定 link 类型:
def wireshark(*args, **kwargs):
"""Run wireshark on a list of packets"""
f = scapy.all.get_temp_file()
scapy.all.wrpcap(f, *args, **kwargs)
subprocess.Popen([scapy.all.conf.prog.wireshark, "-r", f])
wireshark(pkts, linktype=0x71)
编辑 - 我现在注意到 link 类型映射问题已经 reported and fixed by secdev. However, it hasn't reached python-scapy
just yet. I've also created a new issue 关于生成器的无效处理 object 在 PcapWriter
.
(libpcap: IrDA capture has a packet with an invalid sll_protocol field)
Linux IrDA 使用了一些东西 像 和 Linux cooked-mode header,但它不一样:
- Linux cooked-mode header,link-layer header 类型为 113;
- Linux IrDA header,link-layer header 类型为 144。
不知道是什么原因导致你的程序选择了144而不是113;您的 输入 文件是 Linux IrDA 文件而不是 Linux 熟捕获文件吗?