Sending packets from pcap with changed src/dst in scapy
Asked Answered
J

4

27

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?

Jonijonie answered 4/1, 2012 at 12:29 Comment(5)
scapy is a nice tool, but do you have to do this with scapy? There are other solutions that may be optimized for this...Daleth
Mike, what "other tools" you could recommend? It seemed to me that Scapy was a natural choice for this task.Jonijonie
look at tcpreplayDaleth
@MikePennington Can tcpreplay handle the requested capabilities of changing the source and destination addresses? I looked and was unable to find this feature, which is why I got to this page.Smedley
Never mind; you'd use tcprewrite with the Pseudo-NAT option (-S for example) with 0.0.0.0/0:<ip>/32 (if you wanted, say, to change all source addresses to <ip>) to first convert the file, then use tcpreplay to replay it.Smedley
E
33

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
Entertaining answered 12/1, 2012 at 22:41 Comment(3)
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").Jonijonie
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.Hubby
Quoting the OP - "the capture is rather big couple of Gb, how about scapy performance with such amounts of traffic". Sadly giving your first downvote because if you have a pcap, scapy is about the slowest possible thing you can use. At low packet rates, who cares? At high packet rates, scapy is a pig. tcpreplay is a better option at high packet rates. Best of both worlds? Rewrite your pcap values once with scapy and then replay over and over with tcpreplay. I don't know if that fits the OP's use-case.Daleth
W
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)
Wolffish answered 23/1, 2014 at 12:10 Comment(1)
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)Hardiness
J
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
Jonijonie answered 5/1, 2012 at 14:25 Comment(0)
W
0

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

Wharve answered 30/11, 2015 at 14:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.