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