home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / HOP.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  11KB  |  421 lines

  1. /*
  2.  *    HOP.C   -- trace route packets take to a remote host
  3.  *
  4.  *    02-90    -- Katie Stevens (dkstevens@ucdavis.edu)
  5.  *           UC Davis, Computing Services
  6.  *           Davis, CA
  7.  *    04-90    -- Modified by Phil Karn to use raw IP sockets to read replies
  8.  *    08-90    -- Modified by Bill Simpson to display domain names
  9.  */
  10.  
  11. /****************************************************************************
  12. *    $Id: hop.c 1.2 93/07/16 11:45:09 ROOT_DOS Exp $
  13. *    08 May 93    1.2        GT    Fix warnings.                                    *
  14. ****************************************************************************/
  15.  
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include "global.h"
  19. #include "mbuf.h"
  20. #include "usock.h"
  21. #include "socket.h"
  22. #include "session.h"
  23. #include "timer.h"
  24. #include "proc.h"
  25. #include "netuser.h"
  26. #include "domain.h"
  27. #include "commands.h"
  28. #include "tty.h"
  29. #include "cmdparse.h"
  30. #include "ip.h"
  31. #include "icmp.h"
  32. #include "udp.h"
  33. #include "hardware.h"
  34.  
  35. #define HOPMAXQUERY    5        /* Max# queries each TTL value */
  36. static int16 Hoprport = (int16) (32768L+666);    /* funny port for udp probes */
  37. #define HOP_HIGHBIT    32768        /* Mask to check ICMP msgs */
  38.  
  39.  
  40. #define HOPTRACE    1        /* Enable HOP tracing */
  41. #ifdef HOPTRACE
  42. static int Hoptrace = 0;
  43. static int hoptrace __ARGS((int argc,char *argv[],void *p));
  44. #endif
  45.  
  46.  
  47. static unsigned  short Hopmaxttl  = 30;        /* max attempts */
  48. static unsigned  short Hopmaxwait = 5;        /* secs timeout each attempt */
  49. static unsigned  short Hopquery   = 3;        /* #probes each attempt */
  50.  
  51. static int hopcheck __ARGS((int argc,char *argv[],void *p));
  52. static int hopttl __ARGS((int argc,char *argv[],void *p));
  53. static int hopwait __ARGS((int argc,char *argv[],void *p));
  54. static int hopnum __ARGS((int argc,char *argv[],void *p));
  55. static int geticmp __ARGS((int s,int16 lport,int16 fport,
  56.     int32 *sender,char *type,char *code));
  57.  
  58. static struct cmds Hopcmds[] = {
  59.     { "check",    hopcheck,    2048,    2,    "check <host>" },
  60.     { "maxttl",    hopttl,        0,    0,    NULLCHAR },
  61.     { "maxwait",    hopwait,    0,    0,    NULLCHAR },
  62.     { "queries",    hopnum,        0,    0,    NULLCHAR },
  63. #ifdef HOPTRACE
  64.     { "trace",    hoptrace,    0,    0,    NULLCHAR },
  65. #endif
  66.     { NULLCHAR },
  67. };
  68.  
  69. /* attempt to trace route to a remote host */
  70. int
  71. dohop(argc,argv,p)
  72. int argc;
  73. char *argv[];
  74. void *p;
  75. {
  76.     return subcmd(Hopcmds,argc,argv,p);
  77. }
  78.  
  79. /* Set/show # queries sent each TTL value */
  80. static int
  81. hopnum(argc,argv,p)
  82. int argc;
  83. char *argv[];
  84. void *p;
  85. {
  86.     int16 r;
  87.     int16 x = Hopquery;
  88.     r = setshort(&x,"# queries each attempt",argc,argv);
  89.     if ((x <= 0)||(x > HOPMAXQUERY)) {
  90.         printf("Must be  0 < x <= %d\n",HOPMAXQUERY);
  91.         return 0;
  92.     } else {
  93.         Hopquery = x;
  94.     }
  95.     return (int)r;
  96. }
  97. #ifdef HOPTRACE
  98. /* Set/show tracelevel */
  99. static int
  100. hoptrace(argc,argv,p)
  101. int argc;
  102. char *argv[];
  103. void *p;
  104. {
  105.     return setbool(&Hoptrace,"HOPCHECK tracing",argc,argv);
  106. }
  107. #endif
  108. /* Set/show maximum TTL value for a traceroute query */
  109. static int
  110. hopttl(argc,argv,p)
  111. int argc;
  112. char *argv[];
  113. void *p;
  114. {
  115.     int16 r;
  116.     int16 x = Hopmaxttl;
  117.     r = setshort(&x,"Max attempts to reach host",argc,argv);
  118.     if ((x <= 0)||(x > 255)) {
  119.         printf("Must be  0 < x <= 255\n");
  120.         return 0;
  121.     } else {
  122.         Hopmaxttl = x;
  123.     }
  124.     return (int)r;
  125. }
  126. /* Set/show #secs until timeout for a traceroute query */
  127. static int
  128. hopwait(argc,argv,p)
  129. int argc;
  130. char *argv[];
  131. void *p;
  132. {
  133.     int16 r;
  134.     int16 x = Hopmaxwait;
  135.     r = setshort(&x,"# secs to wait for reply to query",argc,argv);
  136.     if (x <= 0) {
  137.         printf("Must be >= 0\n");
  138.         return 0;
  139.     } else {
  140.         Hopmaxwait = x;
  141.     }
  142.     return (int)r;
  143. }
  144.  
  145. /* send probes to trace route of a remote host */
  146. static int
  147. hopcheck(argc,argv,p)
  148. int argc;
  149. char *argv[];
  150. void *p;
  151. {
  152.     struct session *sp;        /* Session for trace output */
  153.     int s;                /* Socket for queries */
  154.     int s1;                /* Raw socket for replies */
  155.     struct socket lsocket;        /* Local socket sending queries */
  156.     struct socket rsocket;        /* Final destination of queries */
  157.     int32 cticks;            /* Timer for query replies */
  158.     int32 icsource;            /* Sender of last ICMP reply */
  159.     char ictype;            /* ICMP type last ICMP reply */
  160.     char iccode;            /* ICMP code last ICMP reply */
  161.     int32 lastaddr;            /* Sender of previous ICMP reply */
  162.     struct sockaddr_in sock;
  163.     register struct usock *usp;
  164.     register struct sockaddr_in *sinp;
  165.     unsigned char sndttl, q;
  166.     int tracedone = 0;
  167.     int ilookup = 1;        /* Control of inverse domain lookup */
  168.     int c;
  169.     extern int optind;
  170.     char *hostname;
  171.     int save_trace;
  172.  
  173.     optind = 1;
  174.     while((c = getopt(argc,argv,"n")) != EOF){
  175.         switch(c){
  176.         case 'n':
  177.             ilookup = 0;
  178.             break;
  179.         }
  180.     }
  181.     hostname = argv[optind];
  182.     /* Allocate a session descriptor */
  183.     if((sp = newsession(hostname,HOP)) == NULLSESSION){
  184.         tprintf("Too many sessions\n");
  185.         keywait(NULLCHAR,1);
  186.         return 1;
  187.     }
  188.     sp->s = s = -1;
  189.     sp->flowmode = 1;
  190.  
  191.     /* Setup UDP socket to remote host */
  192.     sock.sin_family = AF_INET;
  193.     sock.sin_port = Hoprport;
  194.     tprintf("Resolving %s... ",hostname);
  195.     if((sock.sin_addr.s_addr = resolve(hostname)) == 0){
  196.         tprintf("Host %s unknown\n",hostname);
  197.         keywait(NULLCHAR,1);
  198.         freesession(sp);
  199.         return 1;
  200.     }
  201.  
  202.     /* Open socket to remote host */
  203.     tprintf("traceroute to %s\n",psocket((struct sockaddr *)&sock));
  204.     if((sp->s = s = socket(AF_INET,SOCK_DGRAM,0)) == -1){
  205.         tprintf("Can't create udp socket\n");
  206.         keywait(NULLCHAR,1);
  207.         freesession(sp);
  208.         return 1;
  209.     }
  210.     if(connect(s,(char *)&sock,sizeof(sock)) == -1){
  211.         tprintf("Connect failed\n");
  212.         keywait(NULLCHAR,1);
  213.         freesession(sp);
  214.         return 1;
  215.     }
  216.     if((s1 = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) == -1){
  217.         tprintf("Can't create raw socket\n");
  218.         keywait(NULLCHAR,1);
  219.         freesession(sp);
  220.         return 1;
  221.     }
  222.     /* turn off icmp tracing while hop-checking */
  223.     save_trace = Icmp_trace;
  224.     Icmp_trace = 0;
  225.  
  226.     /* Setup structures to send queries */
  227.     /* Retrieve socket details for user socket control block */
  228.     usp = itop(s);
  229.     sinp = (struct sockaddr_in *)usp->name;
  230.     lsocket.address = sinp->sin_addr.s_addr;
  231.     lsocket.port = sinp->sin_port;
  232.     sinp = (struct sockaddr_in *)usp->peername;
  233.     rsocket.address = sinp->sin_addr.s_addr;
  234.  
  235.     /* Send queries with increasing TTL; start with TTL=1 */
  236.     if (Hoptrace)
  237.         log(sp->s,"HOPCHECK start trace to %s\n",sp->name);
  238.     for (sndttl=1; (sndttl < Hopmaxttl); ++sndttl, sinp->sin_port++) {
  239.         /* Increment funny UDP port number each round */
  240.         rsocket.port = sinp->sin_port;
  241.         tprintf("%3d:",sndttl);
  242.         lastaddr = (int32)0;
  243.         /* Send a round of queries */
  244.         for (q=0; (q < Hopquery); ++q) {
  245.             send_udp(&lsocket,&rsocket,0,sndttl,NULLBUF,0,0,0);
  246.             cticks = msclock();
  247.             alarm( ((long)Hopmaxwait*1000L) );
  248.  
  249.             /* Wait for a reply to our query */
  250.             if(geticmp(s1,lsocket.port,rsocket.port,
  251.              &icsource,&ictype,&iccode) == -1){
  252.                 if(errno != EALARM)
  253.                     goto done;    /* User reset */
  254.                 /* Alarm rang, give up waiting for replies */
  255.                 tprintf(" ***");
  256.                 continue;
  257.             }
  258.             /* Save #ticks taken for reply */
  259.                         cticks = msclock() - cticks;
  260.             /* Report ICMP reply */
  261.             if (icsource != lastaddr) {
  262.                 struct rr *save_rrlp, *rrlp;
  263.  
  264.                 if(lastaddr != (int32)0)
  265.                     tprintf("\n    ");
  266.                 tprintf(" %-15s",inet_ntoa(icsource));
  267.                 if(ilookup){
  268.                     for(rrlp = save_rrlp = inverse_a(icsource);
  269.                         rrlp != NULLRR;
  270.                         rrlp = rrlp->next){
  271.                         if(rrlp->rdlength > 0){
  272.                             switch(rrlp->type){
  273.                             case TYPE_PTR:
  274.                                 tprintf(" %s", rrlp->rdata.name);
  275.                                 break;
  276.                             case TYPE_A:
  277.                                 tprintf(" %s", rrlp->name);
  278.                                 break;
  279.                             }
  280.                             if(rrlp->next != NULLRR)
  281.                                 tprintf("\n%20s"," ");
  282.                         }
  283.                     }
  284.                     free_rr(save_rrlp);
  285.  
  286.                 }
  287.                 lastaddr = icsource;
  288.             }
  289.                         tprintf(" (%ld ms)",cticks);
  290. #ifdef HOPTRACE
  291.             if (Hoptrace)
  292.                 log(sp->s,
  293.                     "(hopcheck) ICMP from %s (%ldms) %s %s",
  294.                     inet_ntoa(icsource),
  295.                     cticks,
  296.                     Icmptypes[ictype],
  297.                     ((ictype == ICMP_TIME_EXCEED)?Exceed[iccode]:Unreach[iccode]));
  298. #endif
  299.  
  300.             /* Check type of reply */
  301.             if (ictype == ICMP_TIME_EXCEED)
  302.                 continue;
  303.             /* Reply was: destination unreachable */
  304.             switch(iccode) {
  305.             case ICMP_PORT_UNREACH:
  306.                 ++tracedone;
  307.                 break;
  308.             case ICMP_NET_UNREACH:
  309.                 ++tracedone;
  310.                 tprintf(" !N");
  311.                 break;
  312.             case ICMP_HOST_UNREACH:
  313.                 ++tracedone;
  314.                 tprintf(" !H");
  315.                 break;
  316.             case ICMP_PROT_UNREACH:
  317.                 ++tracedone;
  318.                 tprintf(" !P");
  319.                 break;
  320.             case ICMP_FRAG_NEEDED:
  321.                 ++tracedone;
  322.                 tprintf(" !F");
  323.                 break;
  324.             case ICMP_ROUTE_FAIL:
  325.                 ++tracedone;
  326.                 tprintf(" !S");
  327.                 break;
  328.                         case ICMP_ADMIN_PROHIB:
  329.                                 ++tracedone;
  330.                                 tprintf(" !A");
  331.                                 break;
  332.                         default:
  333.                                 tprintf(" !?");
  334.                                 break;
  335.             }
  336.         }
  337.         /* Done with this round of queries */
  338.         alarm((long)0);
  339.         tprintf("\n");
  340.         /* Check if we reached remote host this round */
  341.         if (tracedone != 0)
  342.             break;
  343.     }
  344.  
  345.     /* Done with traceroute */
  346. done:    close_s(s);
  347.     sp->s = -1;
  348.     close_s(s1);
  349.     tprintf("traceroute done: ");
  350.     Icmp_trace = save_trace;
  351.     if (sndttl >= Hopmaxttl) {
  352.         tprintf("!! maximum TTL exceeded\n");
  353.     } else if ((icsource == rsocket.address)
  354.             &&(iccode == ICMP_PORT_UNREACH)) {
  355.         tprintf("normal (%s %s)\n",
  356.             Icmptypes[ictype],Unreach[iccode]);
  357.     } else {
  358.         tprintf("!! %s %s\n",
  359.             Icmptypes[ictype],Unreach[iccode]);
  360.     }
  361. #ifdef HOPTRACE
  362.     if (Hoptrace)
  363.         log(sp->s,"HOPCHECK to %s done",sp->name);
  364. #endif
  365.     keywait(NULLCHAR,1);
  366.     freesession(sp);
  367.     return 0;
  368. }
  369.  
  370. /* Read raw network socket looking for ICMP messages in response to our
  371.  * UDP probes
  372.  */
  373. static int
  374. geticmp(s,lport,fport,sender,type,code)
  375. int s;
  376. int16 lport;
  377. int16 fport;
  378. int32 *sender;
  379. char *type,*code;
  380. {
  381.     int size;
  382.     struct icmp icmphdr;
  383.     struct ip iphdr;
  384.     struct udp udphdr;
  385.     struct mbuf *bp;
  386.     struct sockaddr_in sock;
  387.  
  388.     for(;;){
  389.         size = sizeof(sock);
  390.         if(recv_mbuf(s,&bp,0,(char *)&sock,&size) == -1)
  391.             return -1;
  392.         /* It's an ICMP message, let's see if it's interesting */
  393.         ntohicmp(&icmphdr,&bp);
  394.         if((icmphdr.type != ICMP_TIME_EXCEED ||
  395.          icmphdr.code != ICMP_TTL_EXCEED)
  396.          && icmphdr.type != ICMP_DEST_UNREACH){
  397.             /* We're not interested in these */
  398.             free_p(bp);
  399.             continue;
  400.         }
  401.         ntohip(&iphdr,&bp);
  402.         if(iphdr.protocol != UDP_PTCL){
  403.             /* Not UDP, so can't be interesting */
  404.             free_p(bp);
  405.             continue;
  406.         }
  407.         ntohudp(&udphdr,&bp);
  408.         if(udphdr.dest != fport || udphdr.source != lport){
  409.             /* Not from our hopcheck session */
  410.             free_p(bp);
  411.             continue;
  412.         }
  413.         /* Passed all of our checks, so return it */
  414.         *sender = sock.sin_addr.s_addr;
  415.         *type = icmphdr.type;
  416.         *code = icmphdr.code;
  417.         free_p(bp);
  418.         return 0;
  419.     }
  420. }
  421.