23

我正在尝试使用 scapy 发送先前记录的流量(以 pcap 格式捕获)。目前我被困在剥离原始以太层。流量是在另一台主机上捕获的,我基本上需要更改 IP 和以太层 src 和 dst。我设法更换 IP 层并重新计算校验和,但以太层给我带来了麻烦。

任何人都有从捕获文件重新发送数据包的经验,并对 IP 和以太网层(src 和 dst)进行了更改?此外,捕获量相当大,只有几 Gb,在如此大的流量下,scapy 性能如何?

4

4 回答 4

32

检查这个例子

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 将应用于每个 pkt 嗅探
  • 编写新 ip 或 mac 的正确方法是将其视为字符串 ex:ip="1.1.1.1"等等,如上图所示。
  • 例如:for循环中包含的sendp方法,它比其他循环发送数据包要慢
  • 性能提示:在 python 中使用 for 循环太慢了,如果你想要像 C 中的 for 循环那样的速度,请使用map代替
  • 上面使用的 rdpcap 会立即读取文件,如果在读取 1.5 Gb 时可用的内存并且您正在读取 2,3,.. Gb 文件,它将失败。
  • 如果性能问题对您很重要,您可以使用winpcap,但您必须用 C 编写更复杂的代码;使用 python/scapy 执行相同的任务非常简单,但并不比 c 快
  • 这取决于使用哪一个取决于所需的性能水平
  • 如果我的猜测是正确的,在这种情况下你正在发送一个视频流数据包,如果我发送一个 1 兆像素的视频,我会使用 winpcap,或者在其他情况下使用 scapy(每帧尺寸较小)
  • 在使用 C/winpcap 的情况下,您将在读取 pcap 和更改数据并重新发送方面获得出色的性能,但您必须注意同样的问题(大文件),您必须创建一个大小合适的缓冲区才能使用它以相当的性能读取发送数据包
  • 如果数据包大小是恒定的(我猜这在大多数情况下很少见)你可能有一个优势可以充分利用你的可用内存
  • 如果你想在整个“项目/程序”中使用 python/scapy,你可以在 C/Wincap 中创建高性能函数并编译为 dll,然后你可以将此 dll 导入你的 python 程序,你可以在 python 程序中使用它. 通过这种方式,您可以获得美妙的简​​单 python/Scapy 的好处,并且您只需在 c 中编写特定的函数,这样您就可以更快地完成工作,并且您的代码更加专注和可维护
于 2012-01-12T22:41:00.953 回答
7

如果我是你,我会让 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)
于 2014-01-23T12:10:26.160 回答
5

Well, with scapy I came up with the following (sorry for my Python). Hopefully it will help someone. There was a possible simpler scenario where all packets from pcap file are read into memory, but this could lead to problems with large capture files.

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
于 2012-01-05T14:25:03.770 回答
0

对于正确的校验和,我还需要添加del p[UDP].chksum

于 2015-11-30T14:23:30.670 回答