We now have all the pieces it’s time to fit them together by creating the click configuration file.

Let’s start with AddressInfo, a simple and very handy element able to fill out addresses for an interface. Using this element you only need to use the interface name to point to MAC or IP addresses without having to care about it. Also, defining some base ports and IPs at the top of the file is a good practice, it makes the file easy to modify according to the situation.

The best thing to do now is to add the FromDevice and ToDevice elements. FromDevice can’t be plugged directly to our elements because there can be a lot of “junk” packets on a network so we need to filter them by:

  • IP packet
  • ARP Replies
  • ARP Queries

We need to take care of ARP manually to make the solution more generic.

Let’s focus on the logic for IP packets for now:

If our packet is an IP packet we need to check if the header is correct and if not, delete the packet. If our IP packet is to the defined port for request submission we send it to DummyRequest (after stripping all headers). In case our IP packet is at the destination of the defined dummy protocol port, we strip its headers and print it. Other packets gets discarded. Once the packet is printed we can classify its type (dummy request or dummy answer), other packets types gets discarded. We send dummy answers to DummyLog and dummy requests to DummyAnswer. The packets generated by DummyAnswer and DummyRequest are encapsulated in the same way so they share the UDP+IP encapsulation element called UDPIPEncap. The output of UDPIPEncap is redirected to ARPQuerier as are the ARP Replies classified at the beginning. ARP Queries must be resolved so they are passed along the ARPResponder element. Because all of our elements are outputting to the same device in a PUSH flow we need to “reverse the vapor” using a Queue before sending packets to ToDevice.

This long explanation is only here to explain the mechanics hidden in the following element graph:

provisional_config

The graph is generated using the pc1.click file and clicky (pc2.click is meant for the other computer but is exactly similar):

Now that we have our configuration files (and Click Modular Router ready on both computers) we can test our whole solution. Note that if you are developing a protocol of your own, you need to test elements beforehand of the final integration test. Due to the connected nature of elements it’s not always feasible to test one element at a time but often you can test groups of elements. Unitary testing is a challenge and, as far as I am aware, nothing has been done for elements. One good option here would be to use specially crafted packets (using scapy) replayed using FromDump and output to ToDump, RandomBitErrors for mutations or InfiniteSource for traffic shaping elements.

Before doing any actual tests we need to compile. To compile nothing simpler, type make at the root of the click directory. Of course it’s recommended that you compile your elements before this step, it’s just a reminder.

So let’s see how we can make this system chat. First off, we need to feed the vector in DummyAnswer. Then we can post a request and watch the messages being passed. All of this is observed using wireshark, because it’s a dummy protocol there isn’t a dissector for it so we will have to read hex/binary. To inject the requests I simply use netcat. Now is the time to modify addresses in ‘pc1.click’ and ‘pc2.click’, also take care of the network interface name (it’s weird on Archlinux).

Demo details:

  • @IP PC1: 192.168.1.47
  • @IP PC2: 192.168.1.89
  • ClickControl handler port for both: 3333
  • Input request port: 1234

Run userlevel Click Modular Router (on PC1 and PC2 respectively):

sudo ~/path_to_click/click -p 3333 ~/path_to_conf/pc1.click
sudo ~/path_to_click/click -p 3333 ~/path_to_conf/pc2.click

Now is the appropriate time to start wireshark. In another terminal, add one answer to PC2 from PC1:

export HOST=192.168.1.89
export PORT=3333
export HANDLER_NAME=h_map
export SHORT_NAME=DummyAnswer

./add_handler_mapping.sh 'OOOO|AAAA'
./read_handler.sh

In another terminal, inject a request from PC2 to PC1:

echo -n OOOO | netcat -vvv -u 192.168.1.47 1234

Then watch the outputs for click executions.

Here is what’s happening for me (on PC1):

Here is a comprehensive schema of what’s going on network-wise when you inject a request:

|Time     | 192.168.1.89            192.168.1.47 |
|         |                                      |
|728.43518|         Source port: 43653           |UDP: Source port: 43653  Destination port: 1234
|         |(43653)  ------------------>  (1234)  |
|729.16630|         Source port: 4444  D         |UDP: Source port: 4444  Destination port: 4321
|         |(4321)   <------------------  (4444)  |
|729.16720|         Source port: 4444  D         |UDP: Source port: 4444  Destination port: 4321
|         |(4444)   ------------------>  (4321)  |

That’s it. Happy coding!


Previous / Outline