Sunday, August 16, 2015

Part II: Send packets on the same computer running tcpreplay

Send packets on the same computer running tcpreplay

Q: Can I send packets on the same computer running tcpreplay?
Generally speaking no. When tcpreplay sends packets, it injects them between the TCP/IP stack of the system and the device driver of the network card. The result is the TCP/IP stack system running tcpreplay never sees the packets.
One suggestion that has been made is using something like VMWare, Parallels or Xen. Running tcpreplay in the virtual machine (guest) would allow packets to be seen by the host operating system.
That's what official documentation says ... In my opinion answer "generally speaking yes" is more optimistic :).

I would like to appreciate help of Denis Pynkin who was able to find practical solution how to resolve the issue and use only one machine to send and receive traffic. Denis thank you!

Prepare environment


In this part we are going to deal with feature called namespaces.
A namespace wraps a global system resource in an abstraction that
       makes it appear to the processes within the namespace that they have
       their own isolated instance of the global resource.  Changes to the
       global resource are visible to other processes that are members of
       the namespace, but are invisible to other processes.  One use of
       namespaces is to implement containers.
You can learn more about namespaces from man page or from serie of articels at lwn: Namespaces in operation, part 1: namespaces overview.

We are going to work with unshare utility. Our goal is to create process with isolated network namespace, to have two "honest" network interfaces to send from and to accept on.

We start with screen shot of my environment with some explanation and than we'll see the steps how to create your own one. First of all there is a tmux session. So left pane is our host environment. Right is "container" environment. Pay attention to the first command in both panes: echo $$: it shows two different PID ( proccess ID ). In right pane I executed the following command : unshare --net bash. (After that we have different bash process with network namespace unshared). Network interfaces ceth1 and ceth0 are manually created with IP addresses assigned. And we can send and receiver ping requests.













If you carefully follow the commands below, you should have similiar environment.
Here is H == host, C == container:
H: ip link add name ceth0  type veth peer name ceth1
H: ip a add 172.18.0.1/24 dev ceth0
H: unshare --net bash
C: echo $$ = PID
H: ip link set ceth1 netns <PID>
C: ip a add 172.18.0.2/24 dev ceth1
C: ip link set dev ceth1 up

At this step we have environment configured and ready to move next ...

 Prepare traffic with tcprewrite


download template.pcap

Before we can play multicast UDP traffic we have to make some preparation of our pcap file.
That's can be done by one command:

tcprewrite --enet-dmac=4e:ae:72:a4:2a:96 --srcipmap=127.0.0.1:172.18.0.5 --fixcsum --infile=template.pcap --outfile=dump.pcap

Let’s examine parameters:

--enet-dmac=4e:ae:72:a4:2a:96      
Says to replace L2 destination mac address into input file to specified in command line.
In our case we want destination mac address was equal host’s mac address.
--srcipmap=127.0.0.1:172.18.0.5
Says to replace L3 source ip address from 127.0.01 to 172.18.0.5
Since our container’s ip address is equal to 172.18.0.5 we put it in IP packets.

--fixcsum
Documentation says that IP checksum will be re-calculated automatically (but when I did commands separatelly, step by step, somehow checksum was not recalculated, that's why I prefer to pass it manually now)

--infile=part.pcap
Name of the input pcap file

--outfile=prep.pcap
Name of the output pcap file
Now we have changed destanation mac address and source IP address, moreover we pass --fixcsum parameter to recalculate IP check sum field.

Output file is ready to be replayed.

Let's check


Now we are goingn to check that trafic we send from eth1 is can be captured on eth0.
I will use socat tool for that.
In left pane of our tmux application run the following command:

socat UDP4-RECVFROM:11000,ip-add-membership=239.10.5.2:172.18.0.1, STDOUT

In the right pane (child container) run:
tcpreplay -i ceth1 dump.pcap

If everything goes smoothly you should see some printed bytes on left pane and then socat would exit.











It measn that socat was able to receive the traffic and everything works fine!
Now you can run your application in left pane instead of socat and run tcpreplay on the right pane.

Enjoy!

2 comments:

  1. Hi, Works great, Thanks!

    1 minor change: "H: unshare --net bash" should be "C: unshare --net bash"

    ReplyDelete
  2. and there should be an "H: ip link set dev ceth0 up"

    ReplyDelete