23

I am trying to send a previously recorded traffic (captured in pcap format) with scapy. Currently I am stuck at striping original Ether layer. The traffic was captured on another host and I basically need to change both IP and Ether layer src and dst. I managed to replace IP layer and recalculate checksums, but Ether layer gives me trouble.

Anyone has experience resending packets from capture file with applied changes to IP and Ether layer(src and dst)? Also, the capture is rather big couple of Gb, how about scapy performance with such amounts of traffic?

Jason Bart
  • 281
  • 1
  • 2
  • 6

4 Answers4

31

check this example

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

comments:

  • use rdpcap,wrpcap scapy methods to read and write from pcap formatted file
  • you can use sniff(offline="filename") to read packets and you may use prn parameter like this sniff(offline="filename",prn=My_Function) in this case My_Functions will be applied to every pkt sniffed
  • the correct way to write your new ip or mac is to consider it as a string ex: ip="1.1.1.1" and so on as illustrated above.
  • in example: sendp method included in for loop which is slower than making other loop to send packets
  • performance tip: in python using for loops is too slow use map instead if you would like a speed like a for loop in C ,Ref
  • the rdpcap as used above reads the file at once, if the memory available while reading say 1.5 Gb and you are reading a 2,3,.. Gb file it will fail.
  • if the performance issue is critical for you may use winpcap but you have to write more complex code in C;doing the same task using python/scapy is pretty easy an simple but it is not faster than c
  • it depends which one to use on the level of performance needed
  • if my guess is right you are sending a video stream packets in this case i would use a winpcap if i am sending an 1 mega pixel video or scapy in other cases(lower size per frame)
  • in case of using C/winpcap you will get a great performance in reading pcaps and change the data and resend but you have to be aware of the same problem (large files) you have to create a buffer with a proper size to use it for reading sending the packets in a quite performance
  • if the packet size is constant(which is rare in most cases, i guess) you may have an advantage get the most of your available memory
  • if you want to use python/scapy for the whole "project/program" you may create the high performance functions in C/Wincap and compile as dll then you can import this dll to your python program and you can use it inside a python program. This way you get benefits of wonderful easy python/Scapy and you only write a specific functions in c so you can get your job done faster and your code to be focused and maintainable
Abdurahman
  • 620
  • 8
  • 16
  • 1
    Thanks for tips, Abdurahman, especially those regarding performance issues! Scapy is a nice tool, but may not be suited for heavy traffic simulation (at least "out of the box"). – Jason Bart Jan 24 '12 at 08:43
  • About your suggestions for using built-in `map`, I wouldn't be sure if that would improve performance, given that the scapy send/sendp methods receive a list of packets as a parameter and inside the functions themselves they have a `for` loop (`__gen_send` function). So maybe what you gain by calling `map` packet-by-packet instead of passing the list of packets directly to send/sendp is lost with the inner `for` loops. – newlog Mar 09 '15 at 10:35
7

If I were you, I would let Scapy deal with the Ether layer, and use the send() function. For example:

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)
Pierre
  • 5,457
  • 1
  • 29
  • 46
  • 3
    Worked for me, the only problem I got was the wrong IP checksum which was easily fixed by adding del p.chksum before send(p) – AliA Mar 26 '14 at 00:09
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
Jason Bart
  • 281
  • 1
  • 2
  • 6
0

For correct checksum, I also needed to add del p[UDP].chksum

Sterling Archer
  • 20,452
  • 15
  • 77
  • 107