Project #3: Part 2, TCP Injection

Overvew

In this part of the assignment, you will be implementing a router that can inject arbitrary data into live TCP streams. You will be implementing your router within the Virtual Network System (VNS) which provides live access to traffic traversing the network.

The goal is to add an arbitrary string to an HTTP session passing through the router. In fact, you will doing the injection to MIT's homepage during an HTTP GET by a local client. The modification must be completely transparent to both the receiver's and sender's TCP stacks as well as the web-server and browser. We have an example running which you can reach by pointing your browser to: http://171.67.71.27:8080/ The example router is injecting Stanford's logo in real time as the page passes. You can view the original page here.

Project Overview:

For this assignment you will use the VNS infrastructure. Start by downloading this stub code. You should have received a topology number from your TA already. After downloading the code, compile it (type 'make') then run the program 'evil_router' with your topology number (for example, if your topology number is 3, run './evil_router -t 3'). Once your router is connected, you should be able to point a web-browser at the IP of the application server on port 8080 and view the target page. As packets traverse the router it should print the source interface. For example, if a packet arrived on interface eth0, it will print:

 ** Incoming packet from eth0 .. muahahaha!!
If you are unable to view the web-page, send your TAs an email. Note that your topology file should have come with an rtable file which you need to place in the same directory as your evil router.

The stub code consists of 5 files which you shouldn't edit:

The only file you need to edit is evil_router.c. It contains one method, do_evil_stuff() which is called each time a packet is received. The parameters passed to the method are:

Getting Started

The method do_evil_stuff(..) accepts an IP packet (including the IP header). The packet, as it comes in, is essentially a big blob of bits. The first thing you might want to do, is to cast it into a usable structure. You can do this by casting the appropriate parts to structs representing TCP and IP headers. Doing this is demonstrated below:
struct ip* ip_hdr = (struct ip*) packet;
struct tcp* tcp_hdr = (struct tcp*) (packet + ip_hdr->ip_hl * 4);
The struct pointers can then be used to edit the packet. For example, to fix the TCP checksum you can:
tcp_hdr->th_sum = tcp_checksum(ip_hdr->ip_src.s_addr, ip_hdr->ip_dst.s_a ddr, tcp_hdr, ntohs(ip_hdr->ip_len) - ip_hdr->ip_hl * 4);
Your job is to modify the correct packets so as to inject data into passing TCP streams without having the connection be dropped by either end.

Assignment Details

As mentioned above, your goal is to inject html into a passing web-page. We will only be testing against the MIT page (mapped to port 8080 on your application server) during grading, however may also visit www.cnn.com which is mapped to port 5252 or the standard web-page (on port 80).

Please copy the reference solution when injecting data into the stream. Your final webpage should be identical to this page. A grading script will be used, so please make sure you match exactly.

Your code must be able to inject data into multiple streams, however you can assume the streams are issued sequentially, so you don't have to maintain parallel state for streams (though you can if you'd like).

Some (potentially helpful) Background

TCP Sequence Numbers

Each byte in a TCP stream has a unique sequence number associated with it. The starting values for sequence numbers are negotiated during the three way handshake. All subsequent packets carry the sequence number of the first byte of data in the packet, and ACKnowledgement sequence which denotes the sequence value of the last contiguous byte. As a grossly oversimplified example:

Sender: Seq num: 123 (length 10 bytes)
Receiver: Ack num: 133

If you modify the size of data (which you must for this assignment) you must be sure to patch the sequence numbers correctly.

For this assignment you can assume all packets are received in order, IP packets will never be fragmented. However, you do have to deal with loss and retransmission if necessary.

Testing

Fortunately, your evil_router sub code is able to dump packets out to pcap format which you can read using tcpdump or Ethereal. Using this functionality is essential to aiding in development and debugging. To turn on logging, used the -l option on the command line:

./evil_router -t 3 -l my_trave_file.tr
You may then read the tracefile as you did in part1.

You may also print out certain fields of the packets at runtime. Below are two methods that demonstrate how to print out both IP and TCP header values:

void print_ip(struct ip* ip_hdr) {
        printf("------------------------------\n");
        printf("header length: %d\nversion: %d\nTOS: %d\nlen: %d\nID: %d\nflags:  %02x\noffset: %d\nTTL: %d\nProtocol: %d\nChecksum: %x\n",
               ip_hdr->ip_hl,
               ip_hdr->ip_v,
               ip_hdr->ip_tos,
               ntohs(ip_hdr->ip_len),
               ntohs(ip_hdr->ip_id),
               ntohs(ip_hdr->ip_off) & (IP_RF | IP_DF | IP_MF),
               ntohs(ip_hdr->ip_off) & IP_OFFMASK,
               ip_hdr->ip_ttl,
               ip_hdr->ip_p,
               ntohs(ip_hdr->ip_sum));
        printf("sender: %s\n", inet_ntoa(ip_hdr->ip_src));
        printf("destination: %s\n", inet_ntoa(ip_hdr->ip_dst));
        printf("------------------------------\n");

}

void print_tcp(struct tcp* tcp_hdr) {
        printf("------------------------------\n");
        printf("source port: %d\ndestination port: %d\nsequence num: %u\nacknowl edgement num: %u\noffset: %d\nflags: %d\nwindow: %d\nchecksum: %x\nurgent pointe r: %d\n",
               ntohs(tcp_hdr->th_sport),
               ntohs(tcp_hdr->th_dport),
               ntohl(tcp_hdr->th_seq),
               ntohl(tcp_hdr->th_ack),
               tcp_hdr->th_off,
               tcp_hdr->th_flags,
               ntohs(tcp_hdr->th_win),
               ntohs(tcp_hdr->th_sum),
               ntohs(tcp_hdr->th_urp));
        printf("------------------------------\n");
}

Deliverables

You are expected to submit your router code (evil_router.c) along with a file (README.2) that describes your implementation. Your router should inject data into multiple, non-overlapping, HTTP streams. It shouldn't drop any TCP streams nor should it corrupt non HTTP transmissions.