=================================================== Experiment 1: The IPv4 Header and Internet Checksum =================================================== Objectives ---------- #. Become familiar with some fields of the IPv4 header and IP addresses. #. Develop a program to check the integrity of data using the Internet Checksum. #. Become familiar with C programming, some bit- wise operations, compilation and testing a program. Background ---------- In this experiment we'll analyze IPv4 header data, extract some of the fields and check the integrity using the Internet Checksum. The IPv4 headers are read from a file. The file format is groups of two octets in hex format, separated by commas, one header per line. To simplify program, headers length is fixed to 20 octets (10 groups). Example: .. code-block:: text 4500, 0034, 3e01, 4000, 3606, f60c, 4127, 0e81, c0a8, 0066 4500, 015a, 1a02, 0000, ff17, 9377, c0a8, 6c03, e000, 0324 4500, 015a, 1a02, 0000, ff17, 9377, c0a8, 6c03, e000, 0067 The format of the IPv4 header is the following (from RFC 791): .. code-block:: text .0 1 2 3 .0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Version| IHL |Type of Service| Total Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identification |Flags| Fragment Offset | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time to Live | Protocol | Header Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ The checksum field is the sixth group of two octets (`f60c` in the first line). It is practical to work with hexadecimal notation rather than decimal. Each hexadecimal digit corresponds to 4 bits. In C we can denote hexadecimal constants by adding the prefix `0x` to the hexadecimal number, for example `0xf60c`. The first step in analyzing the header is to check the integrity of the data using the checksum. If the checksum fails, the header is discarded because none of the information in the other fields can be trusted. Checksum Calculation ******************** To calculate the checksum of each header, all groups of two octets are summed and if the result has more than 16 bits, the lower 16 bits are summed to the upper bits shifted down by 16 positions (that is, bit 17 becomes bit 1). The checksum is one's complement of this sum, truncated to 16 bits. Note that we can not get more than 20 bits by adding 10 numbers with 16 bits:: 0xffff * 0xA = 0x9fff6 This means we have enough bits to calculate the checksum using 32-bit unsigned integer variables in C. To do the calculation in C, we'll need to use the `>>` operator to shift bits down, the `&` operator for bit-wise `and` (to select bits in a variable), and the `~` operator to perform bit-wise one's complement. The ``printf`` format string that we'll use is "%x" to print unsigned integers in hexadecimal format. The steps to calculate the checksum are listed below: .. highlight:: c 1. Read header data from file. For convenience the data can be stored in an `unsigned int` array 2. Add all values in the array on an accumulator 3. If the result has more than 16 bits (what happens if not?), add the lower 16 bits and the upper bits, shifted down 16 positions:: low16 = accum & 0xffff; // store the 16 least significant bits high16 = accum >> 16; // store upper bits shifted down 16 positions 4. Calculate checksum:: checksum = ~(low16 + high16); 5. Print checksum in hex format:: printf("Checksum = 0x%x\n", checksum); Extraction of Header Data ************************* If the checksum result is zero, the header is validated and we can proceed to extract the data. Otherwise, the program discards the header. The data to be extracted for each valid header is listed below: 1. Packet length in bytes, in decimal format 2. Source and destination addresses in dot-decimal format To extract this information, you will need to use some bit-wise operations as described in the checksum calculation. To print `unsigned int` variables in decimal format, use the `%u` format string (use `%d` for regular `int`). For example, assuming the dot-decimal bytes of an address are stored in `b3`, `b2`, `b1`, `b0`, the corresponding statement would look similar the following:: printf("Source address: %u.%u.%u.%u\n", b3, b2, b1, b0); Sample program output: .. code-block:: text /--- Header number in file | /-------- Packet length in bytes | | /--------- Source Address | | | /---- Destination Address | | | | V V V V 1: 52, 65.39.14.129, 192.168.0.102 2: Checksum failed = 0xfd42 3: 346, 192.168.108.3, 224.0.0.103 Your program does not need to exactly produce this output, but all requested fields should be present. A template code with an outline of the program flow to get you started is included in the :ref:`appendix_1` Section. Note that `checksum` is not calculated and initialized to `1`, so the `if` statement in the main program is always false (`!checksum` could be replaced with `checksum == 0`). References ---------- * Class notes * RFC 791, Internet Protocol: http://www.rfc-editor.org/info/rfc791 * MinGW-w64 (gcc compiler and utilities on Windows): https://www.mingw-w64.org Procedure --------- #. **Read the background section before starting.** #. Open a command window (cmd.exe). The current directory should be set to ``c:\users\engineer``. Run ``experiment1`` in that window as shown below. That script sets up the working directory and the environment variables to use the compiler. **Do not close this window**: you need it to compile and run the program. #. We'll assume in the following that the work directory is ``c:\users\engineering\exp1`` and the source code file is saved as ``ipv4check.c``. Your directory name may not be exactly the same but that should not be a problem. Type ``notepad++ ipv4check.c`` to simultaneously open the notepad++ editor and create the source code file (answer ``yes`` to create new file). Paste the code from the :ref:`appendix_1` into the editor and save into the work directory. Also set language to ``C`` in Notepad++ editor. Save your file. #. Return to the command line window. Typing ``dir`` should list your saved C source file. Compile the program as shown below. The ``-Wall`` option tells the compiler to print all warnings. This is useful to detect problems with the source code. The executable file is called ``a.exe`` by default. You can change this name by using the ``-o`` flag when compiling. For example:: gcc -Wall -o ipv4check.exe ipv4check.c The program should compile with no errors/warnings. Every time you make changes to the source code **you must re-compile.** #. Typing the data into the program every time you want to test is too time consuming. The code can be run more conveniently by redirecting the standard input to a file with numbers. This means that the program reads the input from a file instead of the keyboard. Open a new file in notepad++, type the numbers shown below and save the file as ``data.hex`` in the working directory: .. code-block:: text 4500, 0034, 3e01, 4000, 3606, f60c, 4127, 0e81, c0a8, 0066 4500, 015a, 1a02, 0000, ff17, 9377, c0a8, 6c03, e000, 0324 4500, 015a, 1a02, 0000, ff17, 9377, c0a8, 6c03, e000, 0067 Run the program as follows:: ipv4check.exe < data.hex The program should run, but of course checksums are not calculated and the output of the program should look as shown below: .. image:: initial_checksum.png :scale: 70 % :alt: Environment setup, compilation of source code using MinGW-w64 and program running. #. Now implement the checksum calculation inside the body of the `testChecksum()` function. After this is done, you should be able to compile the program and detect all headers with correct checksums (result should match example given in Background section). #. Now implement in the main function the instructions to print the packet length and the source and destination addresses. (result should match example given in Background section). #. The lab instructor will provide a different file to each group. If everything is correct, your program should be able to process the header data in the supplied file. Report preparation and questions -------------------------------- #. Prepare a formal report summarizing this experiment in pdf format and submit it to the lab instructor. Report writing rules: * One report per group * All students are responsible for the contents of the report, but one student in the group must coordinate, write and submit the report for the experiment. Each student in a group must prepare at least one of the five reports in the term. * Clearly state in the report cover the name of all students in the group and indicate who prepared the report #. Include a copy of your source code in your report. Your source code should be properly indented, with updated comments and consistent variables and function names. #. Show the output generated by your program. #. Answer why all (valid) headers start with 0x45 #. Comment difficulties (if any) and conclusions about this experiment. .. _appendix_1: Appendix -------- Program template:: /* Test checksum of packet headers stored in file and print some fields if checksum is valid. */ #include unsigned int testChecksum(unsigned int header[]) { unsigned int checksum = 1; // do some calculation ... return checksum; } int main() { // Array to store header bytes (in groups of 16 bits) unsigned int header[10]; // header number counter int hnumber = 0; while(scanf("%x, %x, %x, %x, %x, %x, %x, %x, %x, %x", header, header+1, header+2, header+3, header+4, header+5, header+6, header+7, header+8, header+9) == 10) { hnumber++; unsigned int checksum = testChecksum(header); if (!checksum) { // Extract and print header information printf("%d:\t something\n", hnumber); } else { // Checksum failed, discard header and print message printf("%d:\tChecksum failed = 0x%x\n", hnumber, checksum); } } return 0; }