home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 3 / PDCD_3.iso / internet / tcpipsrc / h / if / ICMP / c / icmpcmd < prev    next >
Encoding:
Text File  |  1994-09-04  |  10.9 KB  |  505 lines

  1. /* ICMP-related user commands */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <time.h>
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "cmdparse.h"
  9. #include "domain.h"
  10. #include "netuser.h"
  11. #include "internet.h"
  12. #include "timer.h"
  13. #include "ping.h"
  14. #include "misc.h"
  15. #include "Terminal.h"
  16. #include "udp.h"
  17. #include "icmp.h"
  18. #include "vterm.h"
  19.  
  20. #define HOPMAXQUERY    5        /* Max# queries each TTL value */
  21.  
  22. extern int16 lport;                     /* local port placeholder */
  23.  
  24. static int pingem(int32, int16, int16);
  25. static int16 hash_ping(int32);
  26. static struct ping *add_ping(int32);
  27. static void del_ping(struct ping *);
  28.  
  29. static void send_hop(void);
  30. static int docheck (int argc,char *argv[]);
  31. static int dottl (int argc,char *argv[]);
  32. static int dowait (int argc,char *argv[]);
  33. static int donum (int argc,char *argv[]);
  34.  
  35. struct cmds Hopcmds[] = {
  36.     "check",    docheck,    2,    "hop check <host>", NULLCHAR,
  37.     "maxttl",    dottl,        0,    0,    NULLCHAR,
  38.     "maxwait",    dowait,      0,    0,    NULLCHAR,
  39.     "queries",    donum,        0,    0,    NULLCHAR,
  40.     NULLCHAR,
  41. };
  42.  
  43. /* ICMP message types */
  44. extern char *icmptypes[];
  45.  
  46. /* ICMP unreachable messages */
  47. extern char *unreach[];
  48.  
  49. int dohop(int argc, char *argv[])
  50. {
  51.   return subcmd(Hopcmds, argc, argv);
  52. }
  53.  
  54. int doicmpstat(void)
  55. {
  56.   extern struct icmp_errors icmp_errors;
  57.   extern struct icmp_stats icmp_stats;
  58.   extern char *icmptypes[];
  59.   register int i;
  60.  
  61.   cwprintf(NULL, "ICMP: chksum err %u no space %u icmp %u bdcsts %u\r\n",
  62.   icmp_errors.checksum,icmp_errors.nospace,icmp_errors.noloop,
  63.   icmp_errors.bdcsts);
  64.   cwprintf(NULL, "type  rcvd  sent\r\n");
  65.   for(i=0;i<ICMP_TYPES;i++)
  66.   {
  67.     if(icmp_stats.input[i] == 0 && icmp_stats.output[i] == 0)
  68.       continue;
  69.     cwprintf(NULL, "%-6u%-6u%-6u",i,icmp_stats.input[i],
  70.     icmp_stats.output[i]);
  71.     if(icmptypes[i] != NULLCHAR)
  72.       cwprintf(NULL, "  %s",icmptypes[i]);
  73.     cwprintf(NULL, "\r\n");
  74.   }
  75.   return 0;
  76. }
  77.  
  78. /* Hash table list heads */
  79. struct ping *ping[PMOD];
  80.  
  81. /* Counter for generating seq numbers */
  82. static int16 iclk;
  83.  
  84. /* Increment counter -- called by low level clock tick */
  85. void icmpclk(void)
  86. {
  87.   iclk++;
  88. }
  89.  
  90. static int32 cticks;
  91. static int16 hopttl;
  92. static int16 hopquery;
  93. static struct socket lsocket, fsocket;    /* socket address */
  94. static int32 lastsource;
  95. static int32 hopmean;
  96. static struct timer hop_time_t;
  97. static Terminal *window;
  98.  
  99. static int16 Hopmaxttl   = 30;        /* max attempts */
  100. static int16 Hopmaxwait  = 5;        /* secs timeout each attempt */
  101. static int16 Hopmaxquery = 3;        /* #probes each attempt */
  102.  
  103. /* Set/show # queries sent each TTL value */
  104. static int donum(int argc, char *argv[])
  105. {
  106.   int n = atoi(argv[1]);
  107.  
  108.   if (argc < 2)
  109.   {
  110.     cwprintf(NULL, "%d checks for each host\n", Hopmaxquery);
  111.   }
  112.   else if (n < 1 || n > HOPMAXQUERY)
  113.   {
  114.     cwprintf(NULL, "Checks for each host must be > 0 and <= %d\n", HOPMAXQUERY);
  115.     return (1);
  116.   }
  117.   else
  118.   {
  119.     Hopmaxquery = n;
  120.   }
  121.   return (0);
  122. }
  123.  
  124. /* Set/show maximum TTL value for a traceroute query */
  125. static int dottl(int argc, char *argv[])
  126. {
  127.   int n = atoi(argv[1]);
  128.  
  129.   if (argc < 2)
  130.   {
  131.     cwprintf(NULL, "Maximum ttl %d\n", Hopmaxttl);
  132.   }
  133.   else if (n < 2 || n > 255)
  134.   {
  135.     cwprintf(NULL, "Maximum ttl must be > 0 and <= 255\n");
  136.     return (1);
  137.   }
  138.   else
  139.   {
  140.     Hopmaxttl = n;
  141.   }
  142.   return (0);
  143. }
  144.  
  145. static void hop_timeout(void *vp)
  146. {
  147.   if (hopquery == 1)
  148.   {
  149.     if (lastsource != 0)
  150.     {
  151.       cwprintf(window, " (mean %ld)", 10 * hopmean / Hopmaxquery);
  152.       hopmean = 0;
  153.     }
  154.     cwprintf(window, "\n%3d %-40s", hopttl, inet_ntoa(0));
  155.   }
  156.   cticks = clock() - cticks;
  157.   cwprintf(window, "  ***  ");
  158.   hopmean += cticks;
  159.   send_hop();
  160. }
  161.  
  162. /* Set/show #secs until timeout for a traceroute query */
  163. static int dowait(int argc, char *argv[])
  164. {
  165.   int n = atoi(argv[1]);
  166.  
  167.   if (argc < 2)
  168.   {
  169.     cwprintf(NULL, "Maximum wait for reply %d\n", Hopmaxwait);
  170.   }
  171.   else if (n < 1)
  172.   {
  173.     cwprintf(NULL, "Maximum wait for reply must be > 0\n");
  174.     return (1);
  175.   }
  176.   else
  177.   {
  178.     Hopmaxwait = n;
  179.   }
  180.   return (0);
  181. }
  182.  
  183. static void send_hop(void)
  184. {
  185.   if (hopquery >= Hopmaxquery)
  186.   {
  187.     hopquery = 0;
  188.     hopttl++;
  189.   }
  190.   if (hopttl < Hopmaxttl)
  191.   {
  192.     send_udp(&lsocket, &fsocket, 0, hopttl, 0, 0, 0, 0);
  193.     cticks = clock();
  194.     hopquery++;
  195.     hop_time_t.func = hop_timeout;  /* what to call on timeout */
  196.     hop_time_t.arg  = NULL;
  197.     set_timer(&hop_time_t, Hopmaxwait * 1000L);
  198.     start_timer(&hop_time_t);
  199.   }
  200. }
  201.  
  202. void hop_rec(struct icmp *icmphdr, struct udp *udphdr, int32 source, int16 type)
  203. {
  204.   BOOL tracedone = FALSE;
  205.   struct socket fsocket;    /* socket address    */
  206.  
  207.   if (udphdr->source != lsocket.port)
  208.     return;
  209.  
  210.   stop_timer(&hop_time_t);
  211.   if (lastsource != source)
  212.   {
  213.     if (lastsource != 0)
  214.     {
  215.       cwprintf(window, " (mean %ldms)", 10 * hopmean / Hopmaxquery);
  216.       hopmean = 0;
  217.     }
  218.     cwprintf(window, "\n%3d %-40s", hopttl, inet_ntoa(source));
  219.   }
  220.   lastsource = source;
  221.   cticks = clock() - cticks;
  222.   cwprintf(window, " %4ldms", 10 * cticks);
  223.   hopmean += cticks;
  224.  
  225.   if (icmphdr->type == DEST_UNREACH)
  226.   {
  227.     switch(icmphdr->code)
  228.     {
  229.     case PORT_UNREACH:
  230.       ++tracedone;
  231.       break;
  232.     case NET_UNREACH:
  233.       ++tracedone;
  234.       cwprintf(window, " !N");
  235.       break;
  236.     case HOST_UNREACH:
  237.       ++tracedone;
  238.       cwprintf(window, " !H");
  239.       break;
  240.     case PROT_UNREACH:
  241.       ++tracedone;
  242.       cwprintf(window, " !P");
  243.       break;
  244.     case FRAG_NEEDED:
  245.       ++tracedone;
  246.       cwprintf(window, " !F");
  247.       break;
  248.     case ROUTE_FAIL:
  249.       ++tracedone;
  250.       cwprintf(window, " !S");
  251.       break;
  252.     case ADMIN_PROHIB:
  253.       ++tracedone;
  254.       cwprintf(window, " !A");
  255.       break;
  256.     default:
  257.       cwprintf(window, " !?");
  258.       break;
  259.     }
  260.   }
  261.   if (!tracedone)
  262.     send_hop();
  263.  
  264.   if (tracedone || hopttl >= Hopmaxttl)
  265.   {
  266.     cwprintf(window, "\n\ntraceroute done: ");
  267.     if (hopttl >= Hopmaxttl)
  268.     {
  269.       cwprintf(window, "!! maximum TTL exceeded\n");
  270.     }
  271.     else if (source == fsocket.address && icmphdr->code == DEST_UNREACH)
  272.     {
  273.       cwprintf(window, "normal (%s %s)\n", icmptypes[type], unreach[icmphdr->code]);
  274.     }
  275.     else
  276.     {
  277.       cwprintf(window, "!! %s %s\n", icmptypes[type], unreach[icmphdr->code]);
  278.     }
  279.     window->Attr = ATTR_REVERSE;
  280.     window->Flags.flags.dont_destroy = FALSE;
  281.     Window_CloseDown(window);
  282.     window = NULL;
  283.   }
  284. }
  285.  
  286. static int docheck(int argc, char *argv[])
  287. {
  288.   char title[80];
  289.  
  290.   /* Set up the connection. */
  291.   fsocket.address = resolve(argv[1]);
  292.   if (fsocket.address != 0)
  293.   {
  294.     fsocket.port    = (int16) (32768L+666);
  295.     lsocket.address = ip_addr;      /* our ip address */
  296.     lsocket.port    = lport++;      /* next unused port */
  297.  
  298.     hopttl     = 0;
  299.     hopquery   = Hopmaxquery;
  300.     lastsource = 0;
  301.     hopmean    = 0;
  302.  
  303.     sprintf(title, "Hop check to %s", argv[1]);
  304.     window = Window_Open(NULL, title, term_NO_INPUT);
  305.     vterm_parse(window->vt, argc-2, &argv[2]);
  306.     send_hop();
  307.   }
  308.   else
  309.   {
  310.     cwprintf(NULL, "Hop - Can't resolve %s\n", argv[1]);
  311.   }
  312.   return(0);
  313. }
  314.  
  315. /* Send ICMP Echo Request packets */
  316. int doping(int argc, char **argv)
  317. {
  318.   int32 dest;
  319.   struct ping *pp1;
  320.   register struct ping *pp;
  321.   int16 hval;
  322.   int i;
  323.  
  324.   if(argc < 2)
  325.   {
  326.     cwprintf(NULL, "Host                Sent    Rcvd   %%   Avg RTT  Interval\r\n");
  327.     for (i = 0; i < PMOD; i++)
  328.     {
  329.       for (pp = ping[i]; pp != NULLPING; pp = pp->next)
  330.       {
  331.         cwprintf(NULL, "%-40s",inet_ntoa(pp->remote));
  332.         cwprintf(NULL, "%8lu%8lu", pp->count, pp->echoes);
  333.         cwprintf(NULL, "%4lu%10lu%10lu\r\n",
  334.         (long)pp->echoes * 100 / pp->count,
  335.         pp->echoes != 0 ?
  336.         (long)pp->ttotal * MSPTICK / pp->echoes : 0,
  337.         ((long)pp->timer.start * MSPTICK + 500) / 1000);
  338.       }
  339.     }
  340.     return 0;
  341.   }
  342.   if (strcmp(argv[1],"clear") == 0)
  343.   {
  344.     for(i = 0; i < PMOD; i++)
  345.     {
  346.       for (pp = ping[i]; pp != NULLPING; pp = pp1)
  347.       {
  348.         pp1 = pp->next;
  349.         del_ping(pp);
  350.       }
  351.     }
  352.     return 0;
  353.   }
  354.   if ((dest = resolve(argv[1])) == 0)
  355.   {
  356.     cwprintf(NULL, "Host %s unknown\r\n",argv[1]);
  357.     return 1;
  358.   }
  359.   /* See if dest is already in table */
  360.   hval = hash_ping(dest);
  361.   for (pp = ping[hval]; pp != NULLPING; pp = pp->next)
  362.   {
  363.     if(pp->remote == dest)
  364.     {
  365.       break;
  366.     }
  367.   }
  368.   if(argc > 2)
  369.   {
  370.     /* Inter-ping time is specified; set up timer structure */
  371.     if(pp == NULLPING)
  372.       pp = add_ping(dest);
  373.     if (pp->window != NULL)
  374.       cwtitle(pp->window, "Ping - %s", argv[1]);
  375.     pp->timer.start = atoi(argv[2]) * (int32)(1000 / MSPTICK);
  376.     pp->timer.func = ptimeout;
  377.     pp->timer.arg = (char *)pp;
  378.     pp->remote = dest;
  379.     start_timer(&pp->timer);
  380.     pp->count++;
  381.     pingem(dest, iclk, REPEAT);
  382.   }
  383.   else
  384.     pingem(dest, iclk, ONESHOT);
  385.  
  386.   return 0;
  387. }
  388.  
  389. /* Called by ping timeout */
  390. void ptimeout(char *p)
  391. {
  392.   register struct ping *pp;
  393.  
  394.   /* Send another ping */
  395.   pp = (struct ping *)p;
  396.   pp->count++;
  397.   pingem(pp->remote,iclk,REPEAT);
  398.   start_timer(&pp->timer);
  399. }
  400. /* Send ICMP Echo Request packet */
  401. static int pingem(int32 dest, int16 seq, int16 id)
  402. {
  403.   struct mbuf *bp;
  404.   struct icmp icmp;
  405.   extern struct icmp_stats icmp_stats;
  406.  
  407.   icmp_stats.output[ECHO]++;
  408.   icmp.type = ECHO;
  409.   icmp.code = 0;
  410.   icmp.args.echo.seq = seq;
  411.   icmp.args.echo.id = id;
  412.   if((bp = htonicmp(&icmp,NULLBUF)) == NULLBUF)
  413.     return 0;
  414.   return ip_send(ip_addr,dest,ICMP_PTCL,0,0,bp,len_mbuf(bp),0,0);
  415. }
  416.  
  417. /* Called with incoming Echo Reply packet */
  418. void echo_proc(int32 source, int32 dest, struct icmp *icmp)
  419. {
  420.   register struct ping *pp;
  421.   int16 hval;
  422.   int16 rtt;
  423.  
  424.   dest = dest;
  425.  
  426.   rtt = iclk - icmp->args.echo.seq;
  427.   hval = hash_ping(source);
  428.   for(pp = ping[hval]; pp != NULLPING; pp = pp->next)
  429.     if(pp->remote == source)
  430.       break;
  431.   if (pp == NULLPING || icmp->args.echo.id != 1)
  432.   {
  433.     cwprintf(NULL, "%s: echo reply id %u seq %u, %lu ms\r\n",
  434.     inet_ntoa(source),
  435.     icmp->args.echo.id,icmp->args.echo.seq,
  436.     (long)rtt * MSPTICK);
  437.   }
  438.   else if (pp->window != NULL)
  439.   {
  440.     cwprintf(pp->window, "echo reply id %u seq %u, %lu ms\r\n",
  441.     icmp->args.echo.id,icmp->args.echo.seq,
  442.     (long)rtt * MSPTICK);
  443.   }
  444.   else
  445.   {
  446.     /* Repeated poll, just keep stats */
  447.     pp->ttotal += rtt;
  448.     pp->echoes++;
  449.   }
  450. }
  451.  
  452. static int16 hash_ping(int32 dest)
  453. {
  454.   int16 hval;
  455.  
  456.   hval = (hiword(dest) ^ loword(dest)) % PMOD;
  457.   return hval;
  458. }
  459.  
  460. /* Add entry to ping table */
  461. static struct ping * add_ping(int32 dest)
  462. {
  463.   struct ping *pp;
  464.   int16 hval;
  465.  
  466.   pp = (struct ping *)calloc(1,sizeof(struct ping));
  467.   if(pp == NULLPING)
  468.     return NULLPING;
  469.  
  470.   hval = hash_ping(dest);
  471.   pp->prev = NULLPING;
  472.   pp->next = ping[hval];
  473.   if(pp->next != NULLPING)
  474.     pp->next->prev = pp;
  475.   ping[hval] = pp;
  476.   pp->window = Window_Open(NULL, "Ping", term_NO_INPUT);
  477.   return pp;
  478. }
  479. /* Delete entry from ping table */
  480. static void del_ping(struct ping *pp)
  481. {
  482.   int16 hval;
  483.  
  484.   stop_timer(&pp->timer);
  485.  
  486.   if(pp->next != NULLPING)
  487.     pp->next->prev = pp->prev;
  488.   if(pp->prev != NULLPING)
  489.   {
  490.     pp->prev->next = pp->next;
  491.   }
  492.   else
  493.   {
  494.     hval = hash_ping(pp->remote);
  495.     ping[hval] = pp->next;
  496.   }
  497.   if (pp->window)
  498.   {
  499.     pp->window->Attr = ATTR_REVERSE;
  500.     pp->window->Flags.flags.dont_destroy = FALSE;
  501.     Window_CloseDown(pp->window);
  502.   }
  503.   free((char *)pp);
  504. }
  505.