用Python修改PCAP

用Python修改PCAP,python,pcap,Python,Pcap,我需要读取PCAP文件,修改一些字段(实际上是IPv4源和目标以及以太网源和目标)。PCAP经过预筛选,仅包括以太网上的IPv4数据包 到目前为止,我试着用scapy做这件事,但是它有一个严重的记忆问题。读取~350MB PCAP文件时,我的16GB RAM已完全填满。实际上,只是读书。我还没有对这个文件做任何其他事情。我也有,随着这些变化,阅读速度非常快。一旦我开始修改数据包,内存就会再次膨胀。在这种情况下,Scapy实际上是不可用的 我还考虑过使用其他工具,如tcprewrite,但它不能满

我需要读取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编写的,因此我更喜欢基于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快得多。