home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NET-TOOL.1 / NET-TOOL / net-tools / netstat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-11  |  23.3 KB  |  1,015 lines

  1. /*
  2.  * netstat    This file contains an implementation of the command
  3.  *        that helps in debugging the networking modules.
  4.  *
  5.  * Usage:    netstat [options]
  6.  *            -a also listening sockets
  7.  *            -c continous listing
  8.  *            -i interface statistics
  9.  *            -n show network numbers instead of names
  10.  *            -o show timer states
  11.  *            -r show kernel routing table
  12.  *            -t show active tcp connections
  13.  *            -u show active udp connections
  14.  *            -v show version information
  15.  *            -w show active raw connection
  16.  *            -x show active unix sockets
  17.  *
  18.  * Version:    @(#)netstat.c    0.96    01/20/94
  19.  *
  20.  * Authors:    Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de>
  21.  *        Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  22.  *        Phil Packer, <pep@wicked.demon.co.uk>
  23.  *        Johannes Stille, <johannes@titan.os.open.de>
  24.  * Tuned for NET3 by:
  25.  *        Alan Cox, <A.Cox@swansea.ac.uk>
  26.  *
  27.  *        Copyright (c) 1993  Fred Baumgarten
  28.  *
  29.  */
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <strings.h>
  33. #include <unistd.h>
  34. #include <ctype.h>
  35. #include <fcntl.h>
  36. #include <netdb.h>
  37. #include <paths.h>
  38. #include <pwd.h>
  39. #include <sys/param.h>
  40. #include <sys/socket.h>
  41. #include <linux/route.h>
  42. #include <netinet/in.h>
  43. #include <linux/if_ether.h>
  44. #include <linux/net.h>
  45. #include <linux/tcp.h>
  46. #include <sys/ioctl.h>
  47. #include "support.h"
  48. #include "pathnames.h"
  49. #include "version.h"
  50.  
  51.  
  52. #define E_READ  -1
  53. #define E_PARA  -2
  54. #define E_IOCTL -3
  55.  
  56.  
  57.  
  58. char *Release = RELEASE,
  59.      *Version = "@(#)netstat.c 1.1.79 (09/01/95)";
  60. #define Signature "(c) 1993, Fred Baumgarten <dc6iq@insu1.etec.uni-karlsruhe.de>"
  61.  
  62.  
  63. struct interface {
  64.   char name[IFNAMSIZ];        /* interface name       */
  65.   short flags;                  /* various flags        */
  66.   int metric;            /* routing metric       */
  67.   int mtu;            /* MTU value            */
  68.   struct sockaddr addr;        /* IP address           */
  69.   struct sockaddr dstaddr;    /* P-P IP address       */
  70.   struct sockaddr broadaddr;    /* IP broadcast address */
  71.   struct sockaddr netmask;    /* IP network mask      */
  72.   struct sockaddr hwaddr;    /* HW address           */
  73.   struct enet_statistics stats;    /* statistics           */
  74. };
  75.  
  76. struct service {
  77.   int number;
  78.   char *name;
  79.   struct service *next;
  80. };
  81.  
  82.  
  83. int flag_all = 0;
  84. int flag_cnt = 0;
  85. int flag_deb = 0;
  86. int flag_int = 0;
  87. int flag_not = 0;
  88. int flag_opt = 0;
  89. int flag_raw = 0;
  90. int flag_rou = 0;
  91. int flag_tcp = 0;
  92. int flag_udp = 0;
  93. int flag_unx = 0;
  94. int skfd;
  95. FILE *procinfo;
  96. char *line[2000];
  97. static struct service *tcp_name = NULL,
  98.               *udp_name = NULL,
  99.               *raw_name = NULL;
  100.  
  101.  
  102. static void
  103. add2list(struct service **namebase, struct service *item) 
  104. {
  105.   if (*namebase == NULL) {
  106.     *namebase = item;
  107.     item->next = NULL;
  108.   } else {
  109.     item->next = *namebase;
  110.     *namebase = item;
  111.   } 
  112. }
  113.  
  114.  
  115. struct service *
  116. searchlist(struct service *servicebase, int number)
  117. {
  118.   struct service *item;
  119.  
  120.   for(item = servicebase; item != NULL; item = item->next) {
  121.     if (item->number == number) return(item);
  122.   }
  123.   return(NULL);
  124. }
  125.  
  126.  
  127. static int
  128. read_services(void)
  129. {
  130.   char buffer[2048], name[32];
  131.   char protocol[16], dummy[1024];
  132.   int i, number;
  133.   FILE *serv;
  134.   struct service *item;
  135.  
  136.   if ((serv = fopen(_PATH_SERVICES, "r")) == NULL) {
  137.     perror(_PATH_SERVICES);
  138.     return(E_READ);
  139.   }
  140.   while(! feof(serv)) {
  141.     fgets(buffer, 2047, serv);
  142.     i = sscanf(buffer, "%s%d/%3s%s\n", name, &number, protocol, dummy);
  143.     if (i < 3) continue;
  144.  
  145.     /* Allocate a service entry. */
  146.     item = (struct service *) malloc(sizeof(struct service));
  147.     if (item == NULL) perror("netstat"); 
  148.     item->name = strdup(name);
  149.     item->number = number;
  150.  
  151.     /* Fill it in. */
  152.     if (! strcmp(protocol, "tcp")) {
  153.         add2list(&tcp_name,item);
  154.     } else if (! strcmp(protocol, "udp")) {
  155.         add2list(&udp_name,item);
  156.     } else if (! strcmp(protocol, "raw")) {
  157.         add2list(&raw_name,item);
  158.     }
  159.   }
  160.  
  161.   (void) fclose(serv);
  162.   return(0);
  163. }
  164.  
  165.  
  166. static char *
  167. get_sname(int socknumber, char *proto)
  168. {
  169.   static char buffer[64];
  170.   struct service *item;
  171.  
  172.   if (flag_not) {
  173.     sprintf(buffer, "%d", socknumber);
  174.     return(buffer);
  175.   }
  176.   if (socknumber == 0) return("*");
  177.   if (! strcmp(proto, "tcp")) {
  178.     if ((item = searchlist(tcp_name, socknumber)) != NULL)
  179.         sprintf(buffer, "%s", item->name);
  180.       else 
  181.         sprintf(buffer, "%d", socknumber);
  182.   } else if (! strcmp(proto, "udp")) {
  183.     if ((item = searchlist(udp_name, socknumber)) != NULL)
  184.         sprintf(buffer, "%s", item->name);
  185.       else 
  186.         sprintf(buffer, "%d", socknumber);
  187.   } else if (! strcmp(proto, "raw")) {
  188.     if ((item = searchlist(raw_name, socknumber)) != NULL)
  189.         sprintf(buffer, "%s", item->name);
  190.       else 
  191.         sprintf(buffer, "%d", socknumber);
  192.   }
  193.   return(buffer);
  194. }
  195.  
  196.  
  197. static int
  198. route_info(void)
  199. {
  200.   char buff[4096], iface[16], flags[16];
  201.   char gate_addr[128], net_addr[128];
  202.   char mask_addr[128];
  203.   struct sockaddr snet, sgate, smask;
  204.   struct aftype *ap;
  205.   int num, iflags, metric, refcnt, use;
  206.   FILE *fp;
  207.  
  208.   printf("Kernel routing table\n");
  209.   printf(
  210.     "Destination     Gateway         Genmask         "
  211.     "Flags Metric Ref Use    Iface\n");
  212.   if ((fp = fopen(_PATH_PROCNET_ROUTE, "r")) == NULL) {
  213.     perror(_PATH_PROCNET_ROUTE);
  214.     return(E_READ);
  215.   }
  216.  
  217.   while (fgets(buff, 1023, fp))
  218.   {
  219.     num = sscanf(buff, "%s %s %s %X %d %d %d %s %*s %*s\n",
  220.          iface, net_addr, gate_addr,
  221.          &iflags, &refcnt, &use, &metric, mask_addr);
  222.     if (num != 8) continue;
  223.  
  224.     /* Fetch and resolve the target address. */
  225.     (void) getsock(net_addr, &snet);
  226.     if ((ap = get_afntype(snet.sa_family)) == NULL) {
  227.         fprintf(stderr, "route: unsupported address family %d !\n",
  228.                             snet.sa_family);
  229.         continue;
  230.     }
  231.     strcpy(net_addr, ap->sprint(&snet, (flag_not | 0x8000)));
  232.     net_addr[15] = '\0';
  233.     
  234.     /* Fetch and resolve the gateway address. */
  235.     (void) getsock(gate_addr, &sgate);
  236.     strcpy(gate_addr, ap->sprint(&sgate, flag_not));
  237.     gate_addr[15] = '\0';
  238.  
  239.     /* Fetch and resolve the genmask. */
  240.     (void) getsock(mask_addr, &smask);
  241.     strcpy(mask_addr, ap->sprint(&smask, 1));
  242.     mask_addr[15] = '\0';
  243.  
  244.     /* Decode the flags. */
  245.     flags[0] = '\0';
  246.     if (iflags & RTF_UP) strcat(flags, "U");
  247.     if (iflags & RTF_GATEWAY) strcat(flags, "G");
  248.     if (iflags & RTF_HOST) strcat(flags, "H");
  249.     if (iflags & RTF_REINSTATE) strcat(flags, "R");
  250.     if (iflags & RTF_DYNAMIC) strcat(flags, "D");
  251.     if (iflags & RTF_MODIFIED) strcat(flags, "M");
  252.  
  253.     /* Print the info. */
  254.     printf("%-15s %-15s %-15s %-5s %-6d %-3d %6d %s\n",
  255.         net_addr, gate_addr, mask_addr, flags,
  256.         metric, refcnt, use, iface);
  257.   }
  258.  
  259.   (void) fclose(fp);
  260.   return(0);
  261. }
  262.  
  263.  
  264. static int
  265. tcp_info(void)
  266. {
  267.   char buffer[8192], local_addr[128];
  268.   char rem_addr[128], *tcp_state, timers[64];
  269.   struct sockaddr_in localaddr, remaddr;
  270.   struct aftype *ap;
  271.   unsigned long rxq, txq, time_len, retr;
  272.   int num, local_port, rem_port, d, state;
  273.   int uid, timer_run, lnr = 0;
  274.   struct passwd *pw;
  275.   
  276.   if ((procinfo = fopen(_PATH_PROCNET_TCP, "r")) == NULL) {
  277.     perror(_PATH_PROCNET_TCP);
  278.     return(E_READ);
  279.   }
  280.  
  281.   fgets(buffer, sizeof(buffer), procinfo);
  282.   while (! feof(procinfo)) {
  283.     fgets(buffer, sizeof(buffer), procinfo);
  284.     num = strlen(buffer)+1;
  285.     if ((line[lnr] = (char *)malloc(num)) != NULL) {
  286.         strcpy(line[lnr++], buffer);
  287.         if (flag_deb) fprintf(stderr, "%s", buffer);
  288.     }
  289.   }
  290.   (void) fclose(procinfo);
  291.   lnr--; lnr--;
  292.   while (lnr >= 0) {
  293.     num = sscanf(line[lnr--],
  294.         "%d: %lX:%X %lX:%X %X %lX:%lX %X:%lX %lX %d\n",
  295.         &d, &localaddr.sin_addr.s_addr, &local_port,
  296.         &remaddr.sin_addr.s_addr, &rem_port, &state,
  297.         &txq, &rxq, &timer_run, &time_len, &retr, &uid);
  298.     if (flag_deb) fprintf(stderr, "%s -> %d args", line[lnr+1], num);
  299.     if (num < 11) continue;        /* 13 ? */
  300.     localaddr.sin_family = AF_INET;
  301.     remaddr.sin_family = AF_INET;
  302.     if ((ap = get_afntype(localaddr.sin_family)) == NULL) {
  303.         fprintf(stderr, "netstat: unsupported address family %d !\n",
  304.                         localaddr.sin_family);
  305.         continue;
  306.     }
  307.     switch (state) {
  308.         case TCP_ESTABLISHED:
  309.             tcp_state = "ESTABLISHED";
  310.             rxq--;
  311.             break;
  312.  
  313.         case TCP_SYN_SENT:
  314.             tcp_state = "SYN_SENT";
  315.             break;
  316.  
  317.         case TCP_SYN_RECV:
  318.             tcp_state = "SYN_RECV";
  319.             break;
  320.  
  321.         case TCP_FIN_WAIT1:
  322.             tcp_state = "FIN_WAIT1";
  323.             break;
  324.  
  325.         case TCP_FIN_WAIT2:
  326.             tcp_state = "FIN_WAIT2";
  327.             break;
  328.  
  329.         case TCP_TIME_WAIT:
  330.             tcp_state = "TIME_WAIT";
  331.             break;
  332.  
  333.         case TCP_CLOSE:
  334.             tcp_state = "CLOSE";
  335.             break;
  336. #ifdef TCP_CLOSING
  337.         case TCP_CLOSING:
  338.             tcp_state = "CLOSING";
  339.             break;
  340. #endif
  341.         case TCP_CLOSE_WAIT:
  342.             tcp_state = "CLOSE_WAIT";
  343.             break;
  344.  
  345.         case TCP_LAST_ACK:
  346.             tcp_state = "LAST_ACK";
  347.             break;
  348.  
  349.         case TCP_LISTEN:
  350.             tcp_state = "LISTEN";
  351.             time_len = 0;
  352.             retr = 0L;
  353.             rxq=0L;
  354.             txq=0L;
  355.             break;
  356.  
  357.         default:
  358.             tcp_state = "UNKNOWN";
  359.             break;
  360.     }
  361.     strcpy(local_addr, ap->sprint((struct sockaddr *)&localaddr, flag_not));
  362.     strcpy(rem_addr, ap->sprint((struct sockaddr *)&remaddr, flag_not));
  363.     if (flag_all || rem_port) {
  364.         sprintf(buffer, "%s", get_sname(local_port, "tcp"));
  365.         if ((strlen(local_addr) + strlen(buffer)) > 21) {
  366.             local_addr[21-strlen(buffer)] = '\0';
  367.         }
  368.         strcat(local_addr, ":");
  369.         strcat(local_addr, buffer);
  370.         sprintf(buffer, "%s",get_sname(rem_port, "tcp"));
  371.         if ((strlen(rem_addr) + strlen(buffer)) > 21) {
  372.             rem_addr[21-strlen(buffer)] = '\0';
  373.         }
  374.         strcat(rem_addr, ":");
  375.         strcat(rem_addr, buffer);
  376.         timers[0] = '\0';
  377.         if (flag_opt) switch (timer_run) {
  378.             case 0:
  379.                 sprintf(timers, "off (0.00/%ld)", retr);
  380.                       break;
  381.  
  382.             case 1:
  383.                 sprintf(timers, "on (%2.2f/%ld)",
  384.                     (double)time_len / 100, retr);
  385.                 break;
  386.  
  387.             default:
  388.                 sprintf(timers, "unkn-%d (%2.2f/%ld)",
  389.                     timer_run, (double)time_len / 100, retr);
  390.                 break;
  391.         }
  392.         printf("tcp   %6ld %6ld %-22s %-22s %-14s",
  393.             rxq, txq, local_addr, rem_addr, tcp_state);
  394.  
  395.         if ((pw = getpwuid(uid)) != NULL)
  396.             printf("%-10s ", pw->pw_name);
  397.         else
  398.             printf("%-10d ",uid);
  399.  
  400.         if (flag_opt) printf("      %s", timers);
  401.         printf("\n");
  402.     }
  403.   }
  404.   return(0);
  405. }
  406.  
  407.  
  408. static int
  409. udp_info(void)
  410. {
  411.   char buffer[8192], local_addr[64], rem_addr[64];
  412.   char *udp_state, timer_queued, timers[64], more[512];
  413.   int num, local_port, rem_port, d, state, timer_run, lnr = 0;
  414.   struct sockaddr_in localaddr, remaddr;
  415.   struct aftype *ap;
  416.   unsigned long rxq, txq, time_len, retr;
  417.   
  418.   if ((procinfo = fopen(_PATH_PROCNET_UDP, "r")) == NULL) {
  419.     perror(_PATH_PROCNET_UDP);
  420.     return(E_READ);
  421.   }
  422.  
  423.   fgets(buffer, sizeof(buffer), procinfo);
  424.   while (! feof(procinfo)) {
  425.     fgets(buffer, sizeof(buffer), procinfo);
  426.     if ((line[lnr] = (char *)malloc(strlen(buffer)+1)) != NULL) {
  427.         strcpy(line[lnr++], buffer);
  428.         if (flag_deb) fprintf(stderr, "%s", buffer);
  429.     }
  430.   }
  431.   (void) fclose(procinfo);
  432.   lnr--; lnr--;
  433.  
  434.   while (lnr >= 0) {
  435.     more[0] = '\0';
  436.     timer_queued = '\0';
  437.     num = sscanf(line[lnr--],
  438.         "%d: %lX:%X %lX:%X %X %lX:%lX %X:%lX %lX %c %s\n",
  439.         &d, &localaddr.sin_addr.s_addr, &local_port,
  440.         &remaddr.sin_addr.s_addr, &rem_port, &state,
  441.         &txq, &rxq, &timer_run, &time_len, &retr,
  442.         &timer_queued, more);
  443.     localaddr.sin_family = AF_INET;
  444.     remaddr.sin_family = AF_INET;
  445.     if ((ap = get_afntype(localaddr.sin_family)) == NULL) {
  446.         fprintf(stderr, "netstat: unsupported address family %d !\n",
  447.                         localaddr.sin_family);
  448.         continue;
  449.     }
  450.  
  451.     retr = 0L;
  452.     if (! flag_opt) more[0] = '\0';
  453.     if (flag_deb) fprintf(stderr, "%s -> %d args", line[lnr+1], num);
  454.     if (num < 10) continue;
  455.  
  456.     switch (state) {
  457.         case TCP_ESTABLISHED:
  458.             udp_state = "ESTABLISHED ";
  459.             rxq--;
  460.             break;
  461.  
  462.         default:
  463.             udp_state = "";
  464.             break;
  465.     }
  466.  
  467.     strcpy(local_addr, ap->sprint((struct sockaddr *)&localaddr, flag_not));
  468.     strcpy(rem_addr, ap->sprint((struct sockaddr *)&remaddr, flag_not));
  469.     if (flag_all || localaddr.sin_addr.s_addr) {
  470.         sprintf(buffer, "%s", get_sname(local_port, "udp"));
  471.         if ((strlen(local_addr) + strlen(buffer)) > 21) {
  472.             local_addr[21-strlen(buffer)] = '\0';
  473.         }
  474.         strcat(local_addr, ":");
  475.         strcat(local_addr, buffer);
  476.         sprintf(buffer, "%s", get_sname(rem_port, "udp"));
  477.         if ((strlen(rem_addr) + strlen(buffer)) > 21) {
  478.             rem_addr[21-strlen(buffer)] = '\0';
  479.         }
  480.         strcat(rem_addr, ":");
  481.         strcat(rem_addr, buffer);
  482.  
  483.         timers[0] = '\0';
  484.         if (flag_opt) switch (timer_run) {
  485.             case 0:
  486.                 sprintf(timers, "off (0.00/%ld) %c",
  487.                             retr, timer_queued);
  488.                 break;
  489.  
  490.             case 1:
  491.                 sprintf(timers, "on (%2.2f/%ld) %c",
  492.                     (double)time_len / 100, retr, timer_queued);
  493.                 break;
  494.  
  495.             default:
  496.                 sprintf(timers, "unkn-%d (%2.2f/%ld) %c",
  497.                     timer_run, (double)time_len / 100,
  498.                     retr, timer_queued);
  499.                 break;
  500.         }
  501.         printf("udp   %6ld %6ld %-22s %-22s %s",
  502.             rxq, txq, local_addr, rem_addr, udp_state);
  503.         if (flag_opt) printf("                                %s", timers);
  504.         printf("\n");
  505.     }
  506.   }
  507.   return(0);
  508. }
  509.  
  510.  
  511. static int
  512. raw_info(void)
  513. {
  514.   char buffer[8192], local_addr[64], rem_addr[64];
  515.   char *raw_state, timer_queued, timers[64], more[512];
  516.   int num, local_port, rem_port, d, state, timer_run, lnr = 0;
  517.   struct sockaddr_in localaddr, remaddr;
  518.   struct aftype *ap;
  519.   unsigned long rxq, txq, time_len, retr;
  520.   
  521.   if ((procinfo = fopen(_PATH_PROCNET_RAW, "r")) == NULL) {
  522.     perror(_PATH_PROCNET_RAW);
  523.     return(E_READ);
  524.   }
  525.  
  526.   fgets(buffer, sizeof(buffer), procinfo);
  527.   while (! feof(procinfo)) {
  528.     fgets(buffer, sizeof(buffer), procinfo);
  529.     if ((line[lnr] = (char *)malloc(strlen(buffer)+1)) != NULL) {
  530.         strcpy(line[lnr++], buffer);
  531.         if (flag_deb) fprintf(stderr, "%s", buffer);
  532.     }
  533.   }
  534.   (void) fclose(procinfo);
  535.   lnr--; lnr--;
  536.  
  537.   while (lnr >= 0) {
  538.     more[0] = '\0';
  539.     timer_queued = '\0';
  540.     num = sscanf(line[lnr--],
  541.         "%d: %lX:%X %lX:%X %X %lX:%lX %X:%lX %lX %c %s\n",
  542.         &d, &localaddr.sin_addr.s_addr, &local_port,
  543.         &remaddr.sin_addr.s_addr, &rem_port, &state,
  544.         &txq, &rxq, &timer_run, &time_len, &retr,
  545.         &timer_queued, more);
  546.         retr = 0L;
  547.     localaddr.sin_family = AF_INET;
  548.     remaddr.sin_family = AF_INET;
  549.     if ((ap = get_afntype(localaddr.sin_family)) == NULL) {
  550.         fprintf(stderr, "netstat: unsupported address family %d !\n",
  551.                         localaddr.sin_family);
  552.         continue;
  553.     }
  554.  
  555.     if (! flag_opt) more[0] = '\0';
  556.     if (flag_deb) fprintf(stderr, "%s -> %d args", line[lnr+1], num);
  557.     if (num < 10) continue;
  558.  
  559.     raw_state = "";
  560.     strcpy(local_addr, ap->sprint((struct sockaddr *)&localaddr, flag_not));
  561.     strcpy(rem_addr, ap->sprint((struct sockaddr *)&remaddr, flag_not));
  562.     if (flag_all || localaddr.sin_addr.s_addr) {
  563.         sprintf(buffer, "%s", get_sname(local_port, "raw"));
  564.         if ((strlen(local_addr) + strlen(buffer)) > 21) {
  565.             local_addr[21-strlen(buffer)] = '\0';
  566.         }
  567.         strcat(local_addr, ":");
  568.         strcat(local_addr, buffer);
  569.         sprintf(buffer, "%s", get_sname(rem_port, "raw"));
  570.         if ((strlen(rem_addr) + strlen(buffer)) > 21) {
  571.             rem_addr[21-strlen(buffer)] = '\0';
  572.         }
  573.         strcat(rem_addr, ":");
  574.         strcat(rem_addr, buffer);
  575.  
  576.         timers[0] = '\0';
  577.         if (flag_opt) switch (timer_run) {
  578.             case 0:
  579.                 sprintf(timers, "off (0.00/%ld) %c",
  580.                         retr, timer_queued);
  581.                 break;
  582.  
  583.             case 1:
  584.                 sprintf(timers, "on (%2.2f/%ld) %c",
  585.                     (double)time_len / 100, retr,
  586.                     timer_queued);
  587.                 break;
  588.  
  589.             default:
  590.                 sprintf(timers, "unkn-%d (%2.2f/%ld) %c",
  591.                     timer_run, (double)time_len / 100,
  592.                     retr, timer_queued);
  593.                 break;
  594.         }
  595.         printf("raw   %6ld %6ld %-22s %-22s %s",
  596.             rxq, txq, local_addr, rem_addr, raw_state);
  597.         if (flag_opt) printf("                                %s", timers);
  598.         printf("\n");
  599.     }
  600.   }
  601.   return(0);
  602. }
  603.  
  604.  
  605. static int
  606. unix_info(void)
  607. {
  608.   char buffer[8192], path[MAXPATHLEN], ss_flags[32];
  609.   char *ss_proto, *ss_state, *ss_type;
  610.   int num, d, state, type, lnr = 0;
  611.   unsigned long refcnt, proto, flags;
  612.   
  613.   if ((procinfo = fopen(_PATH_PROCNET_UNIX, "r")) == NULL) {
  614.     perror(_PATH_PROCNET_UNIX);
  615.     return E_READ;
  616.   }
  617.  
  618.   fgets(buffer, sizeof(buffer), procinfo);
  619.   while (! feof(procinfo)) {
  620.     fgets(buffer, sizeof(buffer), procinfo);
  621.     if ((line[lnr] = (char *)malloc(strlen(buffer)+1)) != NULL) {
  622.         strcpy(line[lnr++], buffer);
  623.         if (flag_deb) fprintf(stderr, "%s", buffer);
  624.     }
  625.   }
  626.   (void) fclose(procinfo);
  627.   lnr--; lnr--;
  628.  
  629.   printf("Active UNIX domain sockets\n");
  630.   printf("Proto RefCnt Flags      Type            State           Path\n");
  631.   while (lnr >= 0) {
  632.     path[0] = '\0';
  633.     num = sscanf(line[lnr--], "%d: %lX %lX %lX %X %X %s\n",
  634.         &d, &refcnt, &proto, &flags, &type, &state, path);
  635.     if (flag_deb) fprintf(stderr, "%s -> %d args", line[lnr+1], num);
  636.     if (num < 6) continue;
  637.  
  638.     switch(proto) {
  639.         case 0:
  640.             ss_proto = "unix";
  641.             break;
  642.  
  643.         default:
  644.             ss_proto = "??";
  645.     }
  646.  
  647.     switch(type) {
  648.         case SOCK_STREAM:
  649.             ss_type = "SOCK_STREAM";
  650.             break;
  651.  
  652.         case SOCK_DGRAM:
  653.             ss_type = "SOCK_DGRAM";
  654.             break;
  655.  
  656.         case SOCK_RAW:
  657.             ss_type = "SOCK_RAW";
  658.             break;
  659.  
  660.         case SOCK_RDM:
  661.             ss_type = "SOCK_RDM";
  662.             break;
  663.  
  664.         case SOCK_SEQPACKET:
  665.             ss_type = "SOCK_SEQPACKET";
  666.             break;
  667.  
  668.         default:
  669.             ss_type = "UNKNOWN";
  670.     }
  671.  
  672.     switch(state) {
  673.         case SS_FREE:
  674.             ss_state = "FREE";
  675.             break;
  676.  
  677.         case SS_UNCONNECTED:
  678.             /*
  679.              * Unconnected sockets may be listening
  680.              * for something.
  681.              */
  682.             if (flags & SO_ACCEPTCON) {
  683.                 ss_state = "LISTENING";
  684.             } else {
  685.                 ss_state = "UNCONNECTED";
  686.             }
  687.             break;
  688.  
  689.         case SS_CONNECTING:
  690.             ss_state = "CONNECTING";
  691.             break;
  692.  
  693.         case SS_CONNECTED:
  694.             ss_state = "CONNECTED";
  695.             break;
  696.  
  697.         case SS_DISCONNECTING:
  698.             ss_state = "DISCONNECTING";
  699.             break;
  700.  
  701.         default:
  702.             ss_state = "UNKNOWN";
  703.     }
  704.  
  705.     strcpy(ss_flags, "[");
  706.     if (flags & SO_ACCEPTCON) strcat(ss_flags, " ACC ");
  707.  
  708.     if (ss_flags[strlen(ss_flags)-1] != ' ') strcat(ss_flags, " ");
  709.     strcat(ss_flags, "]");
  710.  
  711.     printf("%-5s %-6ld %-10s %-15s %-15s %s\n",
  712.         ss_proto, refcnt, ss_flags, ss_type, ss_state, path);
  713.   }
  714.   return(0);
  715. }
  716.  
  717.  
  718. static void
  719. ife_print(struct interface *ptr)
  720. {
  721.   printf("%-5.5s ", ptr->name);
  722.   printf("%5d %3d ", ptr->mtu, ptr->metric);
  723.   /* If needed, display the interface statistics. */
  724.   printf("%6u %6u %6u %6u ",
  725.      ptr->stats.rx_packets, ptr->stats.rx_errors,
  726.      ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors);
  727.   printf("%6u %6u %6u %6u ",
  728.      ptr->stats.tx_packets, ptr->stats.tx_errors,
  729.      ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors);
  730.   if (ptr->flags == 0) printf("[NO FLAGS]");
  731.   if (ptr->flags & IFF_ALLMULTI) printf("A");
  732.   if (ptr->flags & IFF_BROADCAST) printf("B");
  733.   if (ptr->flags & IFF_DEBUG) printf("D");
  734.   if (ptr->flags & IFF_LOOPBACK) printf("L");
  735.   if (ptr->flags & IFF_PROMISC) printf("M");
  736.   if (ptr->flags & IFF_NOTRAILERS) printf("N");
  737.   if (ptr->flags & IFF_NOARP) printf("O");
  738.   if (ptr->flags & IFF_POINTOPOINT) printf("P");
  739.   if (ptr->flags & IFF_RUNNING) printf("R");
  740.   if (ptr->flags & IFF_UP) printf("U");
  741.   printf("\n");
  742. }
  743.  
  744. static void if_getstats(char *ifname, struct interface *ife)
  745. {
  746.   FILE *f=fopen("/proc/net/dev","r");
  747.   char buf[256];
  748.   char *bp;
  749.   if(f==NULL)
  750.       return;
  751.   while(fgets(buf,255,f))
  752.   {
  753.       bp=buf;
  754.       while(*bp&&isspace(*bp))
  755.           bp++;
  756.       if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
  757.       {
  758.          bp=strchr(bp,':');
  759.          bp++;
  760.          sscanf(bp,"%d %d %d %d %d %d %d %d %d %d %d",
  761.              &ife->stats.rx_packets,
  762.              &ife->stats.rx_errors,
  763.              &ife->stats.rx_dropped,
  764.              &ife->stats.rx_fifo_errors,
  765.              &ife->stats.rx_frame_errors,
  766.              
  767.              &ife->stats.tx_packets,
  768.              &ife->stats.tx_errors,
  769.              &ife->stats.tx_dropped,
  770.              &ife->stats.tx_fifo_errors,
  771.              &ife->stats.collisions,
  772.              
  773.              &ife->stats.tx_carrier_errors
  774.          );
  775.          fclose(f);
  776.          return;
  777.       }
  778.   }
  779.   fclose(f);
  780. }
  781.   
  782. /* Fetch the inteface configuration from the kernel. */
  783. static int
  784. if_fetch(char *ifname, struct interface *ife)
  785. {
  786.   struct ifreq ifr;
  787.   
  788.   memset((char *) ife, 0, sizeof(struct interface));
  789.   strcpy(ife->name, ifname);
  790.   
  791.   strcpy(ifr.ifr_name, ifname);
  792.   if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
  793.     fprintf(stderr, "SIOCGIFFLAGS: %s\n", strerror(errno));
  794.     return(-1);
  795.   }
  796.   ife->flags = ifr.ifr_flags;
  797.   
  798.   strcpy(ifr.ifr_name, ifname);
  799.   if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0) {
  800.     memset(&ife->addr, 0, sizeof(struct sockaddr));
  801.   } else ife->addr = ifr.ifr_addr;
  802.   
  803.   strcpy(ifr.ifr_name, ifname);
  804.   if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) {
  805.     memset(&ife->hwaddr, 0, sizeof(struct sockaddr));
  806.   } else ife->hwaddr = ifr.ifr_addr;
  807.   
  808.   strcpy(ifr.ifr_name, ifname);
  809.   if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) {
  810.     ife->metric = 0;
  811.   } else ife->metric = ifr.ifr_metric;
  812.   
  813.   strcpy(ifr.ifr_name, ifname);
  814.   if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0) {
  815.     ife->mtu = 0;
  816.   } else ife->mtu = ifr.ifr_mtu;
  817.   
  818.   strcpy(ifr.ifr_name, ifname);
  819.   if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) < 0) {
  820.     memset(&ife->dstaddr, 0, sizeof(struct sockaddr));
  821.   } else ife->dstaddr = ifr.ifr_dstaddr;
  822.   
  823.   strcpy(ifr.ifr_name, ifname);
  824.   if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) < 0) {
  825.     memset(&ife->broadaddr, 0, sizeof(struct sockaddr));
  826.   } else ife->broadaddr = ifr.ifr_broadaddr;
  827.   
  828.   strcpy(ifr.ifr_name, ifname);
  829.   if (ioctl(skfd, SIOCGIFNETMASK, &ifr) < 0) {
  830.     memset(&ife->netmask, 0, sizeof(struct sockaddr));
  831.   } else {
  832.     memcpy(ife->netmask.sa_data, &ifr.ifr_data, sizeof(struct sockaddr));
  833.   }
  834.     
  835.   if_getstats(ifname,ife);
  836. /*  strcpy(ifr.ifr_name, ifname);
  837.   ifr.ifr_data = (caddr_t) &ife->stats;
  838.   if (ioctl(skfd, SIOCGIFSTATS, &ifr) < 0) {
  839.     memset(&ife->stats, 0, sizeof(struct dev_stats));
  840.   }
  841.   */
  842.   return(0);
  843. }
  844.  
  845.  
  846. static int
  847. iface_info(void)
  848. {
  849.   char buff[1024];
  850.   struct interface ife;
  851.   struct ifconf ifc;
  852.   struct ifreq *ifr;
  853.   int i;
  854.   
  855.   /* Create a channel to the NET kernel. */
  856.   if ((skfd = socket(AF_INET,SOCK_DGRAM,0)) < 0) {
  857.     perror("socket");
  858.     return(E_READ);
  859.   }
  860.   
  861.   ifc.ifc_len = sizeof(buff);
  862.   ifc.ifc_buf = buff;
  863.   if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
  864.     perror("SIOCGIFCONF");
  865.     close(skfd);
  866.     return(E_IOCTL);
  867.   }
  868.  
  869.   printf("Kernel Interface table\n");
  870.   printf("Iface   MTU Met  RX-OK RX-ERR RX-DRP RX-OVR  TX-OK TX-ERR TX-DRP TX-OVR Flags\n");
  871.   
  872.   ifr = ifc.ifc_req;
  873.   for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
  874.     if (if_fetch(ifr->ifr_name, &ife) < 0) {
  875.         fprintf(stderr, "%s: unknown interface.\n", ifr->ifr_name);
  876.     }
  877.     
  878.     if (((ife.flags & IFF_UP) == 0) && !flag_all) continue;
  879.     ife_print(&ife);
  880.   }
  881.   close(skfd);
  882.   return(0);
  883. }
  884.  
  885.  
  886. static void
  887. usage(void)
  888. {
  889.   fprintf(stderr, "Usage:\tnetstat [options]\n");
  890.   fprintf(stderr, "\t-a also listening sockets\n");
  891.   fprintf(stderr, "\t-c continous listing\n");
  892.   fprintf(stderr, "\t-i interface statistics\n");
  893.   fprintf(stderr, "\t-n show network numbers instead of names\n");
  894.   fprintf(stderr, "\t-o show timer states\n");
  895.   fprintf(stderr, "\t-r show kernel routing table\n");
  896.   fprintf(stderr, "\t-t show active tcp connections\n");
  897.   fprintf(stderr, "\t-u show active udp connections\n");
  898.   fprintf(stderr, "\t-v show version information\n");
  899.   fprintf(stderr, "\t-w show active raw connections\n");
  900.   fprintf(stderr, "\t-x show active unix sockets\n");
  901. }
  902.  
  903.  
  904. int main
  905. (int argc, char *argv[])
  906. {
  907.   int i;
  908.  
  909.   while ((i = getopt(argc, argv, "acdinortuvwx")) != EOF) switch(i) {
  910.     case 'a':
  911.         flag_all++;
  912.         break;
  913.  
  914.     case 'c':
  915.         flag_cnt++;
  916.         break;
  917.  
  918.     case 'd':
  919.         flag_deb++;
  920.         break;
  921.  
  922.     case 'i':
  923.         flag_int++;
  924.         break;
  925.  
  926.     case 'n':
  927.         flag_not++;
  928.         break;
  929.  
  930.     case 'o':
  931.         flag_opt++;
  932.         break;
  933.  
  934.     case 'r':
  935.         flag_rou++;
  936.         break;
  937.  
  938.     case 't':
  939.         flag_tcp++;
  940.         break;
  941.  
  942.     case 'u':
  943.         flag_udp++;
  944.         break;
  945.  
  946.     case 'v':
  947.         printf("%s\n%s\n%s\n", Release, Version, Signature);
  948.         return(0);
  949.         /*NOTREACHED*/
  950.  
  951.     case 'w':
  952.         flag_raw++;
  953.         break;
  954.  
  955.     case 'x':
  956.         flag_unx++;
  957.         break;
  958.  
  959.     case '?':
  960.         usage();
  961.         return(E_PARA);
  962.   }
  963.   
  964.   if (flag_rou) {
  965.     for (;; ) {
  966.         i = route_info();
  967.         if (!flag_cnt || i) break;
  968.         sleep(1);
  969.     }
  970.     return(i);
  971.   }
  972.   
  973.   if (flag_int) {
  974.     for (;; ) {
  975.         i = iface_info();
  976.         if (!flag_cnt || i) break;
  977.         sleep(1);
  978.       }
  979.     return(i);
  980.   }
  981.   
  982.   if ((i = read_services()) != 0) return(i);
  983.  
  984.   for (;; ) {
  985.     printf("Active Internet connections");
  986.     if (flag_all) printf(" (including servers)");
  987.  
  988.     printf("\nProto Recv-Q Send-Q Local Address          Foreign Address        (State)       User\n");
  989.     if ((!flag_udp && !flag_raw && !flag_unx) || flag_tcp) {
  990.         i = tcp_info();
  991.         if (i) return(i);
  992.     }
  993.  
  994.     if ((!flag_tcp && !flag_raw && !flag_unx) || flag_udp) {
  995.         i = udp_info();
  996.         if (i) return(i);
  997.     }
  998.  
  999.     if ((!flag_tcp && !flag_udp && !flag_unx) || flag_raw) {
  1000.         i = raw_info();
  1001.         if (i) return(i);
  1002.     }
  1003.  
  1004.     if ((!flag_tcp && !flag_udp && !flag_raw) || flag_unx) {
  1005.         i = unix_info();
  1006.         if (i) return(i);
  1007.     }
  1008.  
  1009.     if (!flag_cnt || i) break;
  1010.     sleep(1);
  1011.   }
  1012.  
  1013.   return(i);
  1014. }
  1015.