ITL Lab Manual

non-blocking examine.c


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

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

  examine <interface>

  where <interface> is "eth0", "eth1", etc.  To quit the program
  type CONTROL-C (i.e. interrupt).

  It uses non-blocking I/O. In the display, between the actual
  arriving packets, it displays the number of calls that revealed
  nothing was read.
*/

#include <stdio.h>
#include <signal.h>
#include <sys/socket.h>
#include <linux/if_arp.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <unistd.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;
  long nothing_read_count;
  int nonblocking;

  /* the call must be of the form examine <interface> */
  if (argc != 2)
  {
    fprintf( stderr, "usage: examine <interface>\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 */
  //  fcntl( sock, F_SETFL, O_NONBLOCK );

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

  /* loop until interrupted */
  nothing_read_count = 0;
  while (1)
  {
    struct sockaddr address;
    socklen_t address_len;
    int packet_len;

    /* block until you receive a packet from any interface */
    address_len = sizeof( address );
    packet_len = recvfrom( sock, buffer, BUFFER_LEN, 0, &address, &address_len );
    if (packet_len < 0)
      nothing_read_count++;
    else
    {
      fprintf( stdout, "\n%d reads of socket with no packet\n", nothing_read_count );
      nothing_read_count = 0;

      /* 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 |