Network Packet Sniffing for CSE461

1. Overview
2. Method
3. Programming Considerations
Appendix A

1. Overview

Due to security and privacy concerns, the ability to watch packets travel across the network (sniffing) is restricted in the CSE environment. However, special provisions have been made to allow CSE461 students to observe packets generated by their class projects. This note details the methodology that must be used and explains the restrictions imposed.

2. Method

Packet sniffing can be done only from a limited number of machines and will only detect packets set between a specific set of IP addresses.

Sniffing can be initiated by using the command tcpdump461 which is installed only on the machines attu1, attu2, attu3 and attu4. Tcpdump461 is a modififed version of the standard tcpdump(8) utility. It listens for packets on a specific network interface, ignores certain options dealing with file manipulation and will run for at most 5 minutes, at which time it must be restarted. In all other respects (particularly the ability to filter packets based on user-specified criteria) it is the same as tcpdump(8); see the man page for details.

Packets are sniffable only if they are well-formed IP packets with source and destination addresses within a certain range. These addresses are available only on attu[1-4] and the Linux machines in the CSE002, CSE006 and CSE022 labs. Specifically these machines are:

     shraw CSE-002
     deare CSE-002
     rudum CSE-002
     taisk CSE-002
     dearf CSE-002
     exife CSE-002
     caves CSE-006
     ibsen CSE-006
     allan CSE-006
     asman CSE-006
     integ CSE-022
     nutch CSE-022
     reune CSE-022
     prufe CSE-022
     spang CSE-022
     yotch CSE-022

Thus, to observe the packets exchanged between a typical network client-server application, one "end" of the application must be run on attu[1-4] and the other "end" on attu[1-4] or one of the lab machines listed above.

3. Programming Considerations

As mentioned above, sniffable applications must use a specific set of IP addresses. These addresses are not the "default" address associated with any of the machines on which applications must be run. Thus special steps must be taken when binding network end points to addresses.

The following example code shows how to create a socket bound to the sniffable address of the machine on which the program is run (error checking elided).


     #include .....

    extern int GetSniffableIPAddr(int);
     int s;
     struct sockaddr_in myAddr;

       ...

    s = socket(AF_INET, SOCK_STREAM, 0);
     myAddr.sin_family = AF_INET;
     myAddr.sin_port = 0;
     myAddr.sin_addr.s_addr = GetSniffableIPAddr(0);
     bind(s, (struct sockaddr *)&myAddr, sizeof(myAddr));

       ...


The C code for the routine GetSniffableIPAddr is contain in Appendix A of this document.

The example above is suitable for establishing the local end of a network communication path. In order to connect the local end to the remote end, it is necessary to determine the address of the remote machine. This is easy if the remote end is running on one of the attu machines (which it must be in order to sniff packets). The attu machines have symbolic names of the form attu?-461.pvt.cs.washington.edu attached to their sniffable addresses. If the example above represents a client, the next step would be to connect to the server running on e.g. attu1 by doing the following:


        ...

       #include <netdb.h>

       struct sockaddr_in srvAddr;
        struct hostent *hp;

       srvAddr.sin_family = AF_INET;
        srvAddr.sin_port = htons(<serverport>);
        hp = gethostbyname("attu1-461.pvt.cs.washington.edu");
        srvAddr.sin_addr.s_addr = *(int *)hp->h_addr_list[0];
        connect(s, (struct sockaddr *)&srvAddr, sizeof(srvAddr));

       ...


The lab machines do not have symbolic names for their sniffable IP addresses. However the address for each machine can be determine by replacing its default address, 128.208.1.N, with 192.168.21.N.

Appendix A

What follows is the code for the routine GetSniffableIPAddr. It merely looks through the list of availabe network interfaces until it finds one with an address on the 192.168.21 private network.


     #include <unistd.h>
     #include <stdlib.h>
     #include <stdio.h>
     #include <sys/types.h>
     #include <sys/socket.h>
     #include <sys/ioctl.h>
     #include <netinet/in.h>
     #include <linux/if.h>
     #include <string.h>
     #include <netdb.h>
     #include <errno.h>

    extern int errno;

    int GetSniffableIPAddr(int debug)
     {
         int sock;
         struct ifconf ifc;
         struct ifreq *ifr;
         int n, a;
         int magic = 0x0015a8c0;

        sock = socket(AF_INET, SOCK_DGRAM, 0);
         if ( sock < 0 ) {
             fprintf(stderr, "Can’t open address probe socket: %s0,
                     strerror(errno));
             exit(1);
         }
         ifc.ifc_len = 5 * sizeof(struct ifreq); /* five should be plenty */
         ifc.ifc_buf = malloc(ifc.ifc_len);
         if (ioctl(sock, SIOCGIFCONF, &ifc) < 0 ) {
             perror("SIOCGIFCONF");
             exit(1);
         }
         ifr = ifc.ifc_req;
         for ( n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
             ioctl(sock, SIOCGIFADDR, &ifr);
             a = *(int *)&ifr->ifr_addr.sa_data[2];
             if ( debug) printf("interface %s address: %0x0,ifr->ifr_name,a);
             if ( (a & magic) == magic ) {
                 close(sock);
                 return a;
             }
             ifr++;
         }
         close(sock);
         fprintf(stderr,"Can’t find sniffable IP address0);
         exit(1);
     }

    #ifdef DEBUG
     main(int argc, char *argv[])
     {
         GetSniffableIPAddr(1);
     }
     #endif