Logo Search packages:      
Sourcecode: netdiag version File versions  Download package

trafshow.c

/*
 * $Id: trafshow.c,v 1.3 1997/08/13 21:55:21 begemot Exp begemot $
 * $Log: trafshow.c,v $
 * Revision 1.3  1997/08/13 21:55:21  begemot
 * debug messages removed.
 *
 * Revision 1.2  1997/08/12 19:17:13  begemot
 * New modes, new options (show speed, sort).
 *
 * Revision 1.1  1997/08/12 16:37:50  begemot
 * Initial revision
 *
 * Revision 1.30  1995/11/09  15:30:00  begemot
 * Strict option checking.
 *
 * Revision 1.29  1995/02/26  19:55:45  begemot
 * ICMP reqest-reply packets now displayed as single line.
 *
 * Revision 1.28  1995/02/26  18:59:25  begemot
 * Added RCS Id & Log entries into the all source files.
 *
*/

/*
 * Copyright (C) 1994-1996 D.Gorodchanin. See COPYING for more info.
 */

#include "trafshow.h"

int update_interval = SCREEN_UPDATE;
int remove_interval = CHANNEL_REMOVE;
int forget_interval = CHANNEL_FORGET;
int show_speed      = 0;
int sort_mode       = 0;
unsigned char iface[MAX_IF_NAME+1] = "";
int force_mono = 0;
int dont_resolve = 0;

struct timeval start;
struct timeval now;
struct timeval next;

double stats[MAX_STATS][SPEED_COUNT + 1];

static void update_stats(int type, int size)
{
      int i, n;
      static struct timeval update;

      for (i = 0; i < MAX_STATS; i++) {
            n = (i == type || i == 0) ? size : 0;
            calc_speed(stats[i], n, &update);
      }
      update = now;
}

static void quit (int const signal)
{
      screen_close();
      exit(0);
}

static void error (char const * const where)
{
      int err = errno;
      
      screen_close();
      if ((errno = err) != 0) {
            perror(where);
      } else  {
            fprintf(stderr, where);
      }
      exit(1);
}

static int open_packet_socket()
{
      int fd;

      fd = socket (AF_INET, SOCK_PACKET, htons(ETH_P_ALL));
      if (fd < 0) {
            error("open");
      }
      return fd;
}

static int read_packet(const int fd, unsigned char * const buffer, 
                   unsigned char * * const packet,
                   unsigned char * const ifname)
{
      int len;
      int fromlen; 
      struct sockaddr_pkt fromaddr;

      do {
            fromlen = sizeof(fromaddr);
            len = recvfrom(fd, buffer, MAX_PACKET_LEN , 0,
                         (struct sockaddr *)&fromaddr, &fromlen);
      } while (len < 0 && errno == EINTR);
      
      if (len < 0)  {
            error("recvfrom");
      }
      
      if (fromaddr.spkt_protocol != ntohs(ETH_P_IP)) {
            update_stats(NONIP, len);
            return 0;
      }
      if ((*iface && strcmp(iface, fromaddr.spkt_device))) 
            return 0;

      switch (fromaddr.spkt_family) {
            case ARPHRD_ETHER:
            case ARPHRD_LOOPBACK:
                  *packet = buffer + ETH_HLEN;
                  len -= ETH_HLEN;
                  break;
            default:
                  fprintf(stderr, "Unknown family %d (if %s)\n", 
                        fromaddr.spkt_family, fromaddr.spkt_device);
            case ARPHRD_AX25:
            case ARPHRD_SLIP:
            case ARPHRD_CSLIP:
            case ARPHRD_SLIP6:
            case ARPHRD_CSLIP6:
            case ARPHRD_ADAPT:
            case ARPHRD_IEEE80211:
            case ARPHRD_PPP:
                  *packet = buffer;
                  break;
      }

      strcpy(ifname, fromaddr.spkt_device);

      return len;
}

static void update_packets(unsigned char * packet, int len,
                     unsigned char const * const ifname)
{
      
      struct iphdr * iph = (struct iphdr *) packet;
      
      if (!strcmp(ifname, "lo"))
            len >>= 1;

      if (len < sizeof(iph) || (iph->ihl * 4 > len) ||
          (in_cksum((unsigned short *)&packet, iph->ihl) == ntohs(iph->check)))  {
            update_stats(ILL, len);
            return;
      }

      if ((ntohs(iph->frag_off) & 0x3fff) && !(len = handle_fragment(iph, len)))
            return;

      
      switch (iph->protocol)  {
            
       case IPPROTO_TCP :
            {
                  unsigned short *p =
                  (unsigned short *)(((int32_t *)iph) + iph->ihl);

                  update_stats(TCP, len);
                  update_channels(iph->saddr, iph->daddr,
#ifdef __LITTLE_ENDIAN
                              p[0], p[1],
#else
                              p[1], p[0],
#endif
                              iph->protocol,
                              len, ifname);
            }
            break;
            
       case IPPROTO_UDP :
            {
                  unsigned short *p = 
                  (unsigned short *)(((int32_t *)iph) + iph->ihl);
                  
                  update_stats(UDP, len);
                  update_channels(iph->saddr, iph->daddr,
#ifdef __LITTLE_ENDIAN
                              p[0], p[1],
#else
                              p[1], p[0],
#endif
                              iph->protocol,
                              len, ifname);
            }
            break;
            
       case IPPROTO_ICMP:
            {
                  static int icmp_complement[19] =  { 
                        8,    /*  0: echo    - echorq        */
                        0xffff, /*  1: unknown - unknown       */
                        0xffff, /*  2: unknown - unknown       */
                        0xffff, /*  3: destun  - unknown       */
                        0xffff, /*  4: sqnch   - unknown       */
                        0xffff, /*  5: redir   - unknown       */
                        0xffff, /*  6: unknown - unknown       */
                        0xffff, /*  7: unknown - unknown       */
                        0,    /*  8: echorq  - echo          */
                        0xffff, /*  9: unknown - unknown       */
                        0xffff, /* 10: unknown - unknown       */
                        0xffff, /* 11: timexd  - unknown       */
                        0xffff, /* 12: parmpb  - unknown       */
                        0x14,   /* 13: timerq  - time          */
                        0x13,   /* 14: time    - timerq        */
                        0x16,   /* 15: inforq  - info          */
                        0x15,   /* 16: info    - inforq        */
                        0x18,   /* 17: addrrq  - addr          */
                        0x17,   /* 18: addr    - addrrq        */
                  };
                  int type = 
                  *((unsigned char *)(((int32_t *)iph) + iph->ihl));
                        
                  update_stats(ICMP, len);
                  update_channels(iph->saddr, iph->daddr,
                              type, type > 18 ? 0xffff : icmp_complement[type],
                              iph->protocol,
                              len, ifname);
            }
            break;
            
       default:
            update_stats(UNKN, len);
            update_channels(iph->saddr, iph->daddr,
                        0, 0, iph->protocol, 
                        len, ifname);
            break;
      }
      
}

static void usage(const char * name)
{
      printf( "\nUsage: %s <options>\n\n"
            "Options:\n"
            "\t-m\t\tforce monochrome mode\n"
            "\t-n\t\tdon't resolve hostnames\n"
            "\t-i <iface>\tshow traffic only for specified interface\n"
            "\t-f <seconds>\tbefore remove inactive connection from internal tables\n"
            "\t-r <seconds>\tbefore remove inactive connection from screen\n"
            "\t-s <number>\tshow estimated speed for specified interval\n"
            "\t\t\t(1 - 5 sec, 2 - 10 sec, 3 - 30 sec, 4 - 120 sec)\n"
            "\t-S\t\toutput sorted by traffic/speed\n"
            "\t-u <seconds>\tscreen update interval\n\n"
            "Version 1.3, Copyright (C) D.Gorodchanin 1994-1997.\n"
            , name);
}

int main (int const argc, char * const argv[])
{
      unsigned char buffer[MAX_PACKET_LEN];
      unsigned char *packet;
      unsigned char ifname[MAX_IF_NAME + 1];
      int  pfd;
      int  size;
      fd_set set;
      struct timeval timeout;
      int nfd;
      int c;

      while ((c = getopt(argc, argv, "?hf:i:mnr:u:s:S")) > 0)  {
            switch (c)  {
            case 'f':
                  forget_interval = atoi(optarg);
                  break;
            case 'i':
                  strncpy(iface, optarg, MAX_IF_NAME);
                  iface[MAX_IF_NAME] = 0;
                  break;
            case 'm':
                  force_mono = 1;
                  break;
            case 'n':
                  dont_resolve = 1;
                  break;
            case 'r':
                  remove_interval = atoi(optarg);
                  break;
            case 's':
                  show_speed = atoi(optarg);
                  if (show_speed > SPEED_COUNT)
                        show_speed = SPEED_COUNT;
                  else if (show_speed < 0)
                        show_speed = 0;
                  break;
            case 'S':
                  sort_mode = 1;
                  break;
            case 'u':
                  update_interval = atoi(optarg);
                  break;
            case 'h':
            case '?':
                    usage(argv[0]);
                  exit(1);
            }
      }
      
      if (optind < argc)  {
            fprintf(stderr, "Invalid argument `%s', try `%s -h' for help \n", argv[optind], argv[0]);
            exit(1);
      }
      
      
      gettimeofday(&start, NULL);
      
      screen_open();
      
      pfd = open_packet_socket();
      init_channels_table();
      
      signal(SIGINT, quit);
      signal(SIGTERM, quit);

      gettimeofday(&next, NULL);

      for (;;)  {
            
            gettimeofday(&now, NULL);
            FD_ZERO(&set);
            
            timeout.tv_sec = timeout.tv_usec = 0;

            if (next.tv_sec > now.tv_sec 
                || (next.tv_sec == now.tv_sec
                  && next.tv_usec > now.tv_usec)) {
                  /* Select now */
                  timeout.tv_sec = next.tv_sec - now.tv_sec;
                  timeout.tv_usec = next.tv_usec - now.tv_usec;
                  if (timeout.tv_sec > update_interval) {
                        /* Someone changed system clock */ 
                        timeout.tv_sec = update_interval;
                        timeout.tv_usec = 0;
                  }
                  if (timeout.tv_usec < 0) {
                        timeout.tv_sec--;
                        timeout.tv_usec = 1000000 + timeout.tv_usec;
                  }
                  FD_SET(pfd, &set);
                  FD_SET(fileno(stdin), &set);
                  do  {
                        nfd = select(pfd + 1, &set, 
                                   NULL, NULL, &timeout);
                  } while (nfd < 0 && errno == EINTR);
                  if (nfd < 0)  {
                        error("select");
                  }
                        
            }
            
            if (timeout.tv_sec == 0 && timeout.tv_usec == 0)  {
                  next.tv_sec += update_interval;
                  screen_update();
            }
            
            if (FD_ISSET(pfd, &set))  {
                  if ((size = read_packet(pfd, buffer,
                                    &packet, ifname)))  {
                        update_packets(packet, size, ifname);
                  }
            }
            
            if (FD_ISSET(fileno(stdin), &set))  {
                  int i,n;
                  n = read(fileno(stdin), buffer, sizeof(buffer));
                    for (i = 0; i < n; i++) {
                        switch (buffer[i]) {
                        case 's':
                              show_speed %= SPEED_COUNT;
                              show_speed++;
                              break;
                        case 't':
                              show_speed = 0;
                              break;
                        case 'S':
                              sort_mode = 1 - sort_mode;
                              break;
                        case 'n':
                              dont_resolve = 1 - dont_resolve;
                              break;
                        default:
                              break;
                        }
                  }
                  screen_close();
                  screen_open();
            }
            
      }
}

Generated by  Doxygen 1.6.0   Back to index