用Python修改PCAP
我需要读取PCAP文件,修改一些字段(实际上是IPv4源和目标以及以太网源和目标)。PCAP经过预筛选,仅包括以太网上的IPv4数据包 到目前为止,我试着用scapy做这件事,但是它有一个严重的记忆问题。读取~350MB PCAP文件时,我的16GB RAM已完全填满。实际上,只是读书。我还没有对这个文件做任何其他事情。我也有,随着这些变化,阅读速度非常快。一旦我开始修改数据包,内存就会再次膨胀。在这种情况下,Scapy实际上是不可用的 我还考虑过使用其他工具,如tcprewrite,但它不能满足我的目的。每个数据包的源MAC总是相同的,这也可以通过tcprewrite实现。源IP在给定的子网范围内应该是随机的,例如在10.0.0.0/16中均匀分布。不太容易。更复杂的是目标IP,它需要根据给定的流量矩阵进行计算 所以问题是:我如何读取PCAP文件,用自定义函数修改四个基本字段(Ethernet src+dst、IP src+dst),然后将其写回(另一个)PCAP文件用Python修改PCAP,python,pcap,Python,Pcap,我需要读取PCAP文件,修改一些字段(实际上是IPv4源和目标以及以太网源和目标)。PCAP经过预筛选,仅包括以太网上的IPv4数据包 到目前为止,我试着用scapy做这件事,但是它有一个严重的记忆问题。读取~350MB PCAP文件时,我的16GB RAM已完全填满。实际上,只是读书。我还没有对这个文件做任何其他事情。我也有,随着这些变化,阅读速度非常快。一旦我开始修改数据包,内存就会再次膨胀。在这种情况下,Scapy实际上是不可用的 我还考虑过使用其他工具,如tcprewrite,但它不能满
实际上,我的框架的其余部分是用Python编写的,因此我更喜欢基于Python的解决方案。然而,正如我可以简单地调用其他脚本一样,这不是强制性的。谢谢大家! 我不知道是否有办法用scapy做到这一点,但您也可以使用非常简单的库,让您可以逐包读/写pcap文件(免责声明:我是作者之一)。如果您的需求不太复杂(例如,您不需要重新生成校验和),您可以使用Python切片和Python的struct模块简单地修改框架的bytestring
但我认为也可以让scapy使用
p=Ether(packet\u bytes)
分析帧,并使用str(p)
将PcapFile.py转换回bytestream。通过这种方式,您可以让scapy为您重新计算有效的校验和。我不知道是否有办法使用scapy实现这一点,但您也可以使用非常简单的库,让您可以逐包读取/写入pcap文件(免责声明:我是作者之一)。如果您的需求不太复杂(例如,您不需要重新生成校验和),您可以使用Python切片和Python的struct模块简单地修改框架的bytestring
但我认为也可以让scapy使用p=Ether(packet\u bytes)
分析帧,并使用str(p)
将PcapFile.py转换回bytestream。这样,您就可以让scapy为您重新计算有效的校验和。
正如您所说,Scapy似乎有“严重的内存问题”,可能是因为您使用rdpcap()
读取内存中的整个PCAP文件,然后修改它(仍在内存中),然后使用wrpcap()
从内存中一次性将其写回另一个文件
但最“Pythonic”和“Scapyist”的方法是使用生成器(PcapReader
和PcapWriter
)。以下是一个例子:
from scapy.all import *
ETHER_ADDR_TRANSLATION = {
"orig_mac_1": "new_mac_1",
# [...]
}
IP_ADDR_TRANSLATION = {
"orig_ip_1": "new_ip_1",
# [...]
}
def addr_translation_pcap(source, destination):
out = PcapWriter(destination)
for pkt in PcapReader(source):
# In case we have complex encapsulations, like IP-in-IP, etc.,
# we have to do something like this. If we know for sure that's
# not the case, there's no need for such a (time-consuming) code.
layer = pkt
while not isinstance(layer, NoPayload):
if isinstance(layer, Ether):
for field in ['src', 'dst']:
fval = getattr(layer, field)
if fval in ETHER_ADDR_TRANSLATION:
setattr(layer, field, ETHER_ADDR_TRANSLATION[fval])
# Let's not forget IP-in-ICMP-error
elif isinstance(layer, (IP, IPerror)):
for field in ['src', 'dst']:
fval = getattr(layer, field)
if fval in IP_ADDR_TRANSLATION:
setattr(layer, field, IP_ADDR_TRANSLATION[fval])
elif isinstance(layer, ARP):
fields = {}
if layer.hwtype == 1:
fields.update({'hwsrc': ETHER_ADDR_TRANSLATION,
'hwdst': ETHER_ADDR_TRANSLATION})
if layer.ptype == 2048:
fields.update({'psrc': IP_ADDR_TRANSLATION,
'pdst': IP_ADDR_TRANSLATION})
for field, translator in fields.iteritems():
fval = getattr(layer, field)
if fval in translator:
setattr(layer, field, translator[fval])
layer = layer.payload
out.write(pkt)
out.close()
正如您所说,Scapy似乎有“严重的内存问题”,可能是因为您使用rdpcap()
读取内存中的整个PCAP文件,然后修改它(仍在内存中),然后使用wrpcap()
从内存中一次性将其写回另一个文件
但最“Pythonic”和“Scapyist”的方法是使用生成器(PcapReader
和PcapWriter
)。以下是一个例子:
from scapy.all import *
ETHER_ADDR_TRANSLATION = {
"orig_mac_1": "new_mac_1",
# [...]
}
IP_ADDR_TRANSLATION = {
"orig_ip_1": "new_ip_1",
# [...]
}
def addr_translation_pcap(source, destination):
out = PcapWriter(destination)
for pkt in PcapReader(source):
# In case we have complex encapsulations, like IP-in-IP, etc.,
# we have to do something like this. If we know for sure that's
# not the case, there's no need for such a (time-consuming) code.
layer = pkt
while not isinstance(layer, NoPayload):
if isinstance(layer, Ether):
for field in ['src', 'dst']:
fval = getattr(layer, field)
if fval in ETHER_ADDR_TRANSLATION:
setattr(layer, field, ETHER_ADDR_TRANSLATION[fval])
# Let's not forget IP-in-ICMP-error
elif isinstance(layer, (IP, IPerror)):
for field in ['src', 'dst']:
fval = getattr(layer, field)
if fval in IP_ADDR_TRANSLATION:
setattr(layer, field, IP_ADDR_TRANSLATION[fval])
elif isinstance(layer, ARP):
fields = {}
if layer.hwtype == 1:
fields.update({'hwsrc': ETHER_ADDR_TRANSLATION,
'hwdst': ETHER_ADDR_TRANSLATION})
if layer.ptype == 2048:
fields.update({'psrc': IP_ADDR_TRANSLATION,
'pdst': IP_ADDR_TRANSLATION})
for field, translator in fields.iteritems():
fval = getattr(layer, field)
if fval in translator:
setattr(layer, field, translator[fval])
layer = layer.payload
out.write(pkt)
out.close()
非常感谢。我能够对字节数据手动执行所需的操作。修改文件后,我再次使用来修复校验和,这比使用Scapy快得多。谢谢!我能够对字节数据手动执行所需的操作。修改文件后,我再次使用修复校验和,这比使用Scapy快得多。