Click Lab

In this lab you'll experiment with the Click router toolkit. You'll learn how to send and receive packets, how to classify packets, and finally how to build a transparent TCP proxy. We will give you Click configurations to run as well as asking you to modify our configurations.

Getting Started

We have pre-installed Click on one of our hosts, frenulum.lcs.mit.edu. We've given you an account name on frenulum called oxyX, where X is a number. You can log into frenulum from a Windows laptop using putty.exe. Type frenulum.lcs.mit.edu into the Host Name field and press return. Click on Yes on the PuTTY Security Alert.

If you have a Linux laptop, try

% ssh -l oxyX frenulum.lcs.mit.edu

You may wish to consult the Click documenation while working on this lab. You can also find the Click source code on the Click web site http://pdos.lcs.mit.edu/click/.

Example One: Printing All Packets

Run Click in your putty window:
% click
Copy the following Click configuration (with control-C in your browser), then paste it into your putty window (with Shift-Insert or right-click):
FromDevice(de0, PROMISC true) -> Print("hi") -> Discard;
Then type return and control-D. You should see lots of hex output from Click, one packet per line, perhaps like this:
hi:   84 | 0800460d 3fd00007 b3d44300 08004500 0034f69b 4000fb2f 
hi:   60 | ffffffff ffff0030 65b83cee 08060001 08000604 00010030 
hi:   66 | 00e02905 d6230007 b3d44300 08004500 00348be7 40003906 
You can type control-C to stop Click.

The Click configuration reads all packets from the local Ethernet (with FromDevice) and prints the first 24 bytes of each packet (with Print). The "PROMISC true" argument to FromDevice puts it in promiscuous mode, so that it sees all packets on the local Ethernet, not just the ones addressed to the host you're using. Each packet starts with the 14-byte Ethernet header. For example, the first line in the example above is a packet to Ethernet host 08:00:46:0d:3f:d0, from host 00:07:b3:d4:43:00, and of type IP (0x0800). This page contains descriptions of header formats.

You will find Print useful for debugging. You can add it almost anywhere in a Click configuration to see what packets flow through that part of the configuration.

Exercise A

Modify the above configuration to print every packet twice. You should copy the configuration into an editor such as Notepad, make your changes, then copy and paste into the PuTTY window after running Click. Don't forget to type return and control-D after you paste the configuration. Here's an example of what your output might look like:
hi:  106 | 00e02905 d6230007 b3d44300 08004500 005cffa0 40007f06
xx:  106 | 00e02905 d6230007 b3d44300 08004500 005cffa0 40007f06
hi:   60 | ffffffff ffff0007 b3d44300 08060001 08000604 00010007
xx:   60 | ffffffff ffff0007 b3d44300 08060001 08000604 00010007

Example Two: Printing IP and ARP Packets

Click can separate different types of packets for different processing using the Classifier element. The Classifier in the following configuration selects IP and ARP packets by looking at the Ethernet header's type field; it discards other kinds of packets. Each argument to Classifier is a pattern specifying an offset and a value to look for at the output. Classifier has one output per pattern.

Run this configuration:

FromDevice(de0, PROMISC true) -> cl :: Classifier(12/0800, 12/0806);
cl[0] -> Strip(14) -> CheckIPHeader -> IPPrint("IP") -> Discard;
cl[1] -> Print("ARP") -> Discard;

You might see output like this from Click:

ARP:   60 | ffffffff ffff00e0 8103ad99 08060001 08000604 000100e0 
IP: 1106485059.379213: 24.61.43.128.49435 > 18.26.4.123.22: . 3382018920:3382018920(0,52,52) ack 579108457 win 33304
ARP:   60 | ffffffff ffff0007 b3d44300 08060001 08000604 00010007
This configuration uses IPPrint for the IP packets; IPPrint knows how to parse the IP headers, much like tcpdump. IPPrint expects packets to start with the IP header, so the configuration uses Strip(14) to remove the Ethernet header. IPPrint also requires that packets first be processed by CheckIPHeader to ensure that they are valid IP packets.

Exercise B

Modify the above configuration so that it prints "TCP" for TCP packets, "UDP" for UDP packets, "IP" for other kinds of IP packets, and "ARP" for ARP packets. You may wish to look at the Click documentation for IPClassifier or Classifier. Hint: the element IPClassifier(ip proto tcp, ip proto udp, -) could come in handy. Packets sent to IPClassifier() must start with the IP header, and they must have been processed by CheckIPHeader.

The output of your new configuration should look something like this:

IP: 1106484913.008497: 18.18.0.3 > 18.26.4.133: ip-proto-47
UDP: 1106484913.008853: 18.26.4.127.2049 > 18.26.4.123.989: udp 244
TCP: 1106484913.022493: 24.61.43.128.49435 > 18.26.4.123.22: . 3382017972:3382017972(0,52,52) ack 579105741 win 33158
ARP:   60 | ffffffff ffff0002 b315b7bb 08060001 08000604 00010002

Example Three: Responding to ARP Packets

We've allocated you an IP address on the local network that looks like 18.26.4.X. From now on you should replace the X with the host number we've given you. Try pinging that address from your laptop -- you should get no response, because there is no host with that address. To use the Windows ping command: select Run... from the Start menu, type cmd in the Open field, and when you see a command prompt type ping 18.26.4.X. The next few configurations will build simple routers that do respond to your IP address.

When host H1 first tries to send an IP packet to host H2, H1 must find H2's ethernet address using ARP. Host H1 sends out an ARP broadcast containing H2's IP address, and H2 sends back an ARP response containing H2's ethernet address. Here is a configuration that will respond to ARP queries for your IP address. You should replace 18.26.4.X with your IP address.

in :: FromDevice(de0, PROMISC true);
out :: Queue -> ToDevice(de0);
in -> cl :: Classifier(12/0800, 12/0806 20/0001);
cl[0] ->
  Strip(14) ->
  CheckIPHeader ->
  IPClassifier(dst host 18.26.4.X) ->
  IPPrint("IP") ->
  Discard;
cl[1] -> 
  ARPResponder(18.26.4.X 00:e0:29:05:d6:23) ->
  Print("ARP resp") ->
  out;
Here's a diagram. The ARPResponder element looks for queries with the indicated IP address, and sends out responses with the indicated Ethernet address. The Classifier sends only ARP queries to the ARP responder (Ethernet type 0x0806 and ARP operation 0001).

Now ping your IP address from you laptop. After a few seconds you should see output like this:

ARP resp:   42 | 0007b3d4 430000e0 2905d623 08060001 08000604 000200e0
IP: 1106752295.767113: 128.30.5.187 > 18.26.4.X: icmp: echo request (2, 15)
IP: 1106752301.266950: 128.30.5.187 > 18.26.4.X: icmp: echo request (2, 16)
The "ARP resp" line indicates that your Click configuration has sent an ARP response. You will only see one "ARP resp" line, because once the router between your laptop and frenulum sees your ARP response, it stops sending ARP queries. The "IP...icmp: echo request" lines are the ping packets from your laptop. Your laptop will complain "Request timed out" because this Click configuration does not send ping responses.

Example Four: Sending Pings

The following configuration sends one ICMP echo request (ping) per second to 128.2.222.173 (cs.cmu.edu), as well as printing any arriving echo replies.
in :: FromDevice(de0, PROMISC true);
out :: Queue -> ToDevice(de0);
in -> cl :: Classifier(12/0800, 12/0806 20/0002);
aout :: ARPQuerier(18.26.4.X, 00:e0:29:05:d6:23);
cl[1] -> [1]aout;
aout[0] -> out;
cl[0] ->
  Strip(14) ->
  CheckIPHeader ->
  IPClassifier(dst host 18.26.4.X and ip proto icmp) ->
  IPPrint("in") ->
  Discard;
ICMPPingSource(18.26.4.X, 128.2.222.173) ->
  SetIPAddress(18.26.4.1) ->
  IPPrint("out") ->
  aout;
Here's a diagram. When you run this configuration, the output should look like this:
out: 1106498717.503013: 18.26.4.X > 128.2.222.173: icmp: echo request (0, 256)
in: 1106498717.523577: 128.2.222.173 > 18.26.4.X: icmp: echo reply (0, 256)
out: 1106498718.503018: 18.26.4.X > 128.2.222.173: icmp: echo request (0, 512)
in: 1106498718.522998: 128.2.222.173 > 18.26.4.X: icmp: echo reply (0, 512)
The configuration uses three new elements. ICMPPingSource generates an ICMP packet once per second. ARPQuerier accepts an IP packet as input, sends ARP queries to resolve the IP address to an ethernet address, and then sends the IP packet. Finally, SetIPAddress sets an IP packet's "address annotation". Every Click packet has an address annotation, which contains the IP address of the host to which a packet should be forwarded. This differs from the packet's destination IP address (in the IP header) when the packet must be forwarded through a router, in this case 18.26.4.1. ARPQuerier queries for the IP address in the address annotation, not the address in the IP header's destination field. Note that the Classifier sends ARP responses to the ARPQuerier (Ethernet type 0x0806 and ARP operation 0002).

Exercise C

Create a new configuration that listens for ICMP echo request packets and sends ICMP echo reply packets in response. Use the ICMPPingResponder element. You will also need to use both ARPResponder and ARPQuerier. Don't forget the SetIPAddress(18.26.4.1). It may be easiest to start from the configuration in Example Three above, and copy parts of Example Four (such as the SetIPAddress and ARPQuerier).

You should be able to ping your new configuration from your laptop, and your laptop should receive the replies. Ping should produce output that looks like this:

C:\>ping 18.26.4.X
Pinging 18.26.4.X with 32 bytes of data:
Reply from 18.26.4.X: bytes=32 time=2ms TTL=254
Reply from 18.26.4.X: bytes=32 time=2ms TTL=254
Reply from 18.26.4.X: bytes=32 time=2ms TTL=254
Reply from 18.26.4.X: bytes=32 time=2ms TTL=254

Example Five: Transparent TCP Redirector

The following configuration is a transparent TCP redirector. Run it:
in :: FromDevice(de0, PROMISC true);
out :: Queue -> ToDevice(de0);
in -> cl :: Classifier(12/0800, 12/0806 20/0001, 12/0806 20/0002);
aout :: ARPQuerier(18.26.4.X, 00:e0:29:05:d6:23);
cl[2] -> [1]aout;
aout[0] -> out;
cl[1] -> 
  ARPResponder(18.26.4.X 00:e0:29:05:d6:23) ->
  out;
cl[0] ->
  Strip(14) ->
  CheckIPHeader ->
  IPClassifier(dst host 18.26.4.X and ip proto tcp and port 80) ->
  IPPrint("in") ->
  rw1 :: IPRewriter(pattern 18.26.4.X 50000-60000 68.142.226.37 - 0 1);
rw1[0] ->
  SetIPAddress(18.26.4.1) ->
  IPPrint("out0") ->
  aout;
rw1[1] ->
  SetIPAddress(18.26.4.1) ->
  IPPrint("out1") ->
  aout;
Now go to the URL http://18.26.4.X in your laptop's browser. You should see a familiar website!

Here's a diagram of the redirector configuration. The IPRewriter element modifies incoming TCP HTTP (port 80) packets so that they have destination 68.142.226.37, and sends them back out on the Ethernet. The IPRewriter keeps track of the original packet sources in an internal table, and changes reply packets from 68.142.226.37 so that they are addressed to the original source.

For example, if the original packet had src=10.0.0.1 and dst=18.26.4.X, the IPRewriter changes it to be src=18.26.4.X and dst=68.142.226.37. When a reply packet arrives with src=68.142.226.37 and dst=18.26.4.X, IPRewriter modifies it with src=18.26.4.X and dst 10.0.0.1.

A redirector like this might be useful as a load-balancing front end to a cluster of Web servers. IPRewriter can also be used to implement a network address translator (NAT).

You should also see output like this from Click:

in: 1106504619.659793: 24.61.43.128.62800 > 18.26.4.X.80: S 631525024:631525025(1,64,64) win 65535
out0: 1106504619.659793: 18.26.4.X.51383 > 68.142.226.37.80: S 631525024:631525025(1,64,64) win 65535
in: 1106504619.672205: 68.142.226.37.80 > 18.26.4.X.51383: S 1707715834:1707715835(1,60,60) ack 631525025 win 65535
out1: 1106504619.672205: 18.26.4.X.80 > 24.61.43.128.62800: S 1707715834:1707715835(1,60,60) ack 631525025 win 65535

Exercise D

Modify the redirector configuration so that it sends SMTP connections (port 25) to host 128.2.222.173 (cs.cmu.edu), in addition to sending http connections to 68.142.226.37. You can test the result using the telnet program on your Windows or Linux laptop. You should see something like the following:
C:\> telnet 18.26.4.X 25
Trying 18.26.4.X...
Connected to nephron.lcs.mit.edu.
Escape character is '^]'.
220 cs.cmu.edu SMTP, Problems to: Help@FAC.CS.CMU.EDU