2015-08-27 4 views
1

Мне нужно прочитать файл PCAP, изменить некоторые поля (на самом деле источник и адреса IPv4 и источник и место назначения Ethernet). PCAP предварительно фильтруется, чтобы включать только IPv4 через Ethernet-пакеты.Изменение PCAP с помощью Python

До сих пор я пытался сделать это с помощью scapy, который, однако, имеет серьезную проблему с памятью. Моя память объемом 16 ГБ полностью заполняется при чтении файла PCAP емкостью 350 МБ. Собственно, просто чтение. Я еще ничего не делал с этим файлом. У меня также есть found this answer, и с этими изменениями чтение происходит очень быстро. Как только я начну изменять пакет, память снова раздувается. Scapy на самом деле не используется в этом контексте.

Я также подумал об использовании других инструментов, таких как tcprewrite, но это не может служить моим целям. MAC-адрес источника всегда одинаковый для каждого пакета, это также можно сделать с помощью tcprewrite. Исходный IP-адрес должен быть случайным в заданном диапазоне подсети, например, равномерно распределенном в 10.0.0.0/16. Не слишком легко. Еще более сложным является IP-адрес назначения, который необходимо вычислить из заданной матрицы трафика.

Вопрос: как я могу прочитать в файле PCAP, изменить четыре основных поля (Ethernet src + dst, IP src + dst) с помощью специальной функции и записать их обратно в (другой) файл PCAP?

На самом деле, остальная часть моей структуры написана на Python, поэтому я бы предпочел решение на основе python. Однако, поскольку я мог просто вызвать другие скрипты, это не обязательно. Спасибо!

ответ

0

Я не знаю, есть ли способ сделать это с помощью scapy, но вы также можете использовать очень простую библиотеку PcapFile.py, которая позволяет вам читать/записывать пакет файлов pcap по пакетам (отказ от ответственности: я являюсь одним из авторы). Если ваши потребности не слишком сложны (например, вам не нужно повторно генерировать контрольные суммы), вы можете просто изменить байтовую строку фрейма с помощью Python slicing и структурного модуля Python.

Но я думаю, что также должно быть возможно получить scapy для анализа кадра с использованием p = Ether(packet_bytes) и конвертировать обратно в байтовый поток для PcapFile.py с использованием str(p). Таким образом, вы можете позволить scapy пересчитать действительную контрольную сумму для вас.

+1

Спасибо! Я смог выполнить требуемую операцию вручную по байтовым данным. После изменения файла я использую [один проход с tcprewrite] (http://tcpreplay.synfin.net/wiki/tcprewrite) для исправления контрольных сумм снова, это намного быстрее, чем использование Scapy для этого. –

1

Scapy, кажется, есть «серьезные проблемы с памятью», как вы утверждаете, вероятно, потому, что вы прочитали весь файл PCAP в памяти с rdpcap(), а затем изменить его (до сих пор в памяти), а затем записать его обратно в другой файл , все сразу, из вашей памяти, с wrpcap().

Но самым «путинским» и «скапистским» способом сделать это было бы использование генераторов (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() 
Смежные вопросы