web-dev-qa-db-ja.com

scapyのsrc / dstが変更されたpcapからパケットを送信する

以前に記録されたトラフィック(pcap形式でキャプチャされた)をscapyで送信しようとしています。現在、元のEtherレイヤーのストライピングに行き詰まっています。トラフィックは別のホストでキャプチャされたので、基本的にIPレイヤーとEtherレイヤーのsrcとdstの両方を変更する必要があります。 IPレイヤーを置き換えてチェックサムを再計算できましたが、イーサーレイヤーで問題が発生しました。

誰でも、IPおよびEtherレイヤー(srcおよびdst)に変更を適用したキャプチャファイルからパケットを再送信した経験がありますか?また、キャプチャはGbのかなり大きなカップルですが、そのようなトラフィック量でのscapyパフォーマンスはどうですか?

20
Jason Bart

この例を確認してください

_from scapy.all import *
from scapy.utils import rdpcap

pkts=rdpcap("FileName.pcap")  # could be used like this rdpcap("filename",500) fetches first 500 pkts
for pkt in pkts:
     pkt[Ether].src= new_src_mac  # i.e new_src_mac="00:11:22:33:44:55"
     pkt[Ether].dst= new_dst_mac
     pkt[IP].src= new_src_ip # i.e new_src_ip="255.255.255.255"
     pkt[IP].dst= new_dst_ip
     sendp(pkt) #sending packet at layer 2
_

コメント:

  • rdpcap、wrpcap scapyメソッドを使用して、pcap形式のファイルから読み書きします
  • sniff(offline="filename")を使用してパケットを読み取ることができ、このsniff(offline="filename",prn=My_Function)のようなprnパラメータを使用できます。この場合、My_Functionsがスニッフィングされたすべてのパケットに適用されます
  • 新しいIPまたはMACを記述する正しい方法は、上記のように_ip="1.1.1.1"_などの文字列と見なすことです。
  • 例:他のループでパケットを送信するよりも遅いforループに含まれるsendpメソッド
  • パフォーマンスのヒント:in python forループの使用は遅すぎる-Cのforループのような速度が必要な場合は、代わりに map を使用してください--- Ref =
  • 上記で使用されているrdpcapはファイルを一度に読み取りますが、読み取り中に使用可能なメモリが1.5 Gbであり、2,3、.. Gbファイルを読み取っている場合は失敗します。
  • パフォーマンスの問題が重要な場合は winpcap を使用できますが、Cでより複雑なコードを記述する必要があります。python/ scapyを使用して同じタスクを実行するのは簡単ですが、cよりも高速ではありません。
  • どれを使用するかは、必要なパフォーマンスのレベルによって異なります
  • 私の推測が正しい場合、この場合はビデオストリームパケットを送信します。他の場合に1メガピクセルのビデオまたはscapyを送信する場合は、winpcapを使用します(フレームあたりのサイズが小さい)。
  • c/winpcapを使用する場合、pcapsの読み取りで優れたパフォーマンスが得られ、データを変更して再送信しますが、同じ問題(大きなファイル)に注意して、適切なサイズのバッファーを作成して使用する必要があります。かなりのパフォーマンスでパケットを送信して読む
  • パケットサイズが一定である場合(ほとんどの場合はまれですが、私は推測します)、利用可能なメモリを最大限に利用するという利点があるかもしれません
  • 「プロジェクト/プログラム」全体にpython/scapyを使用する場合は、C/Wincapで高性能関数を作成し、dllとしてコンパイルすることができます。このdllをpythonプログラムにインポートできます。 pythonプログラム内で使用できます。これにより、すばらしい簡単なpython/Scapyの利点が得られ、cで特定の関数のみを記述できるので、仕事をより速く、コードを実行できます。集中して保守できる
25
Abdurahman

私があなたなら、ScapyにEtherレイヤーを処理させ、send()関数を使用します。例えば:

ip_map = {"1.2.3.4": "10.0.0.1", "1.2.3.5": "10.0.0.2"}
for p in PcapReader("filename.cap"):
    if IP not in p:
        continue
    p = p[IP]
    # if you want to use a constant map, only let the following line
    p.src = "10.0.0.1"
    p.dst = "10.0.0.2"
    # if you want to use the original src/dst if you don't find it in ip_map
    p.src = ip_map.get(p.src, p.src)
    p.dst = ip_map.get(p.dst, p.dst)
    # if you want to drop the packet if you don't find both src and dst in ip_map
    if p.src not in ip_map or p.dst not in ip_map:
        continue
    p.src = ip_map[p.src]
    p.dst = ip_map[p.dst]
    # as suggested by @AliA, we need to let Scapy compute the correct checksum
    del(p.chksum)
    # then send the packet
    send(p)
6
Pierre

さて、scapyで私は次のことを思いつきました(私のPythonで申し訳ありません)。うまくいけば、それは誰かを助けるでしょう。 pcapファイルからのすべてのパケットがメモリに読み込まれる可能性のあるより単純なシナリオがありましたが、これは大きなキャプチャファイルで問題を引き起こす可能性があります。

from scapy.all import *
global src_ip, dst_ip
src_ip = 1.1.1.1
dst_ip = 2.2.2.2
infile = "dump.pcap"

try:
    my_reader = PcapReader(infile)
    my_send(my_reader)
except IOError:
    print "Failed reading file %s contents" % infile
    sys.exit(1)

def my_send(rd, count=100):
    pkt_cnt = 0
    p_out = []

    for p in rd:
        pkt_cnt += 1
        np = p.payload
        np[IP].dst = dst_ip
        np[IP].src = src_ip
        del np[IP].chksum
        p_out.append(np)
        if pkt_cnt % count == 0:
            send(PacketList(p_out))
            p_out = []

    # Send remaining in final batch
    send(PacketList(p_out))
    print "Total packets sent %d" % pkt_cn
5
Jason Bart

チェックサムを正しくするには、del p[UDP].chksumも追加する必要がありました

0
Catalina