使用 Python 修改 PCAP

waz*_*ari 1 python pcap

我需要读取 PCAP 文件,修改一些字段(实际上是 IPv4 源和目标以及以太网源和目标)。PCAP 经过预过滤,仅包含以太网上的 IPv4 数据包。

到目前为止,我尝试使用 scapy 来执行此操作,但它存在严重的内存问题。当读取 ~350MB PCAP 文件时,我的 16GB RAM 已完全填满。其实只是读书而已。我还没有对该文件执行任何其他操作。我也找到了这个答案,并且通过这些更改,阅读速度非常快。一旦我开始修改数据包,内存就会再次膨胀。Scapy 实际上在这种情况下不可用

我也考虑过使用其他工具,例如 tcprewrite,但它不能满足我的目的。每个数据包的源 MAC 始终相同,这也可以使用 tcprewrite 来完成。源IP在给定的子网范围内应该是随机的,例如均匀分布在10.0.0.0/16中。不太容易。更复杂的是目标IP,需要根据给定的流量矩阵计算出来。

所以问题是:如何读取 PCAP 文件,使用自定义函数修改四个基本字段(以太网 src+dst、IP src+dst),并将其写回(另一个)PCAP 文件?

实际上,我的框架的其余部分是用Python编写的,所以我更喜欢基于Python的解决方案。但是,由于我可以简单地调用其他脚本,因此这不是强制性的。谢谢你!

Pie*_*rre 5

正如您所说,Scapy 似乎有“严重的内存问题”,可能是因为您在内存中读取整个 PCAP 文件,rdpcap()然后修改它(仍在内存中),然后将其一次性写回另一个文件,从你的记忆,与wrpcap().

但做这样的事情最“Pythonic”和“Scapyist”的方法是使用生成器(PcapReaderPcapWriter)。这是一个例子:

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()
Run Code Online (Sandbox Code Playgroud)