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