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.
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.
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 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.
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