ITL Lab Manual

timeout examine.c


/*
  examine.c
  written by Richard Gordon
  last modified 3/8/00

  This program displays all packets arriving on a specific interface.
  It is called by

  examine <interface> <timeout>

  where <interface> is "eth0", "eth1", etc.,
  and <timeout> is the time to wait for an arriving packet.
  To quit the program type CONTROL-C (i.e. interrupt).

  It uses non-blocking I/O. It uses the select function to implement
  a timeout so that if no packet arrives within a given time it
  displays a message.
*/

#include <stdio.h>
#include <signal.h>
#include <sys/socket.h>
#include <linux/if_arp.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/time.h>

#define BUFFER_LEN 1600

/* local prototypes */
static void interrupt_handler( int i );
void set_promiscuous_mode( char* interface );
void clear_promiscuous_mode( char* interface );

/* static variables */
static char* interface;

int main( int argc, char** argv )
{
  char buffer[ BUFFER_LEN ];
  int sock;
  int nonblocking;

  /* the call must be of the form examine <interface> <timeout>*/
  if (argc != 3)
  {
    fprintf( stderr, "usage: examine <interface> <timeout>\n" );
    exit(1);
  }

  interface = argv[1];

  /* catch interrupts */
  signal( SIGINT, interrupt_handler );

  /* open a socket for catching raw packets */
  if ((sock = socket( PF_INET, SOCK_PACKET, htons(ETH_P_ALL) ))<0)
  {
    perror( "examine: socket" );
    exit(1);
  }

  /* set socket into non-blocking mode */
  nonblocking = 1;
  ioctl( sock, FIONBIO, &nonblocking );

  /* the following is an alternative way to set nonblocking mode */

  /* put the interface into promiscuous mode */
  set_promiscuous_mode( interface );

  /* loop until interrupted */
  while (1)
  {
    struct sockaddr address;
    socklen_t address_len;
    int packet_len;
    fd_set readfds;
    struct timeval timeout;

    FD_ZERO( &readfds );
    FD_SET( sock, &readfds );
    timeout.tv_sec = atoi( argv[2] );
    timeout.tv_usec = 0;

    /* block until you receive a packet from any interface or timeout */
    select( sock+1, &readfds, 0, 0, &timeout );

    address_len = sizeof( address );
    packet_len = recvfrom( sock, buffer, BUFFER_LEN, 0, &address, &address_len );
    if (packet_len < 0)
      fprintf( stdout, "timeout expired\n" );
    else
    {
      /* check the interface the packet arrived on */
      /* only handle packets on the specified interface */
      if (strcmp( address.sa_data, interface ) == 0)
      {
	int i;

	fprintf( stdout, "\nlength = %d\n\n", packet_len );
	for (i=0; i<packet_len; i++)
        {
	  fprintf( stdout, "%2.2hX ", (unsigned char) buffer[ i ] );
	  if (i%16 == 15)
	    fprintf( stdout, "\n" );
	}
	fprintf( stdout, "\n" );
      }
    }
  }

  return 0;
}

void interrupt_handler( int i )
{
  clear_promiscuous_mode( interface );
  exit(0);
}

void set_promiscuous_mode( char* interface )
{
  int sock;
  struct ifreq flags;

  sock = socket( PF_INET, SOCK_PACKET, htons( ETH_P_ALL ) );
  strcpy( flags.ifr_name, interface );
  ioctl( sock, SIOCGIFFLAGS, &flags );
  flags.ifr_flags |= IFF_PROMISC;
  ioctl( sock, SIOCSIFFLAGS, &flags );
  close( sock );
}

void clear_promiscuous_mode( char* interface )
{
  int sock;
  struct ifreq flags;

  sock = socket( PF_INET, SOCK_PACKET, htons(ETH_P_ALL));
  strcpy( flags.ifr_name, interface );
  ioctl( sock, SIOCGIFFLAGS, &flags );
  flags.ifr_flags &= ~IFF_PROMISC;
  ioctl( sock, SIOCSIFFLAGS, &flags );
  close( sock );
}

all: examine

examine: examine.c
	gcc -o examine examine.c

clean:
	-rm -f *~ examine

| Sonoma State University | CS Department | Computer and Engineering Science | Internet Teaching Laboratory | Lab Manual Table of Contents |