home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / ping11.zip / ping.org < prev    next >
Text File  |  1989-06-30  |  23KB  |  930 lines

  1. /*
  2.  *            P I N G . C
  3.  *
  4.  * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
  5.  * measure round-trip-delays and packet loss across network paths.
  6.  *
  7.  * Author -
  8.  *    Mike Muuss
  9.  *    U. S. Army Ballistic Research Laboratory
  10.  *    December, 1983
  11.  * Modified at Uc Berkeley
  12.  * Record Route and verbose headers - Phil Dykstra, BRL, March 1988.
  13.  * ttl, duplicate detection - Cliff Frost, UCB, April 1989
  14.  * Pad pattern - Cliff Frost (from Tom Ferrin, UCSF), April 1989
  15.  * Wait for dribbles, option decoding, pkt compare - vjs@sgi.com, May 1989
  16.  *
  17.  * Status -
  18.  *    Public Domain.  Distribution Unlimited.
  19.  *
  20.  * Bugs -
  21.  *    More statistics could always be gathered.
  22.  *    This program has to run SUID to ROOT to access the ICMP socket.
  23.  */
  24.  
  25. #include <stdio.h>
  26. #include <errno.h>
  27. #include <sys/time.h>
  28. #include <sys/signal.h>
  29.  
  30. #include <sys/param.h>
  31. #include <sys/socket.h>
  32. #include <sys/file.h>
  33.  
  34. #include <netinet/in_systm.h>
  35. #include <netinet/in.h>
  36. #include <netinet/ip.h>
  37. #include <netinet/ip_icmp.h>
  38. #include <netinet/ip_var.h>
  39. #include <ctype.h>
  40. #include <netdb.h>
  41.  
  42. #define    MAXWAIT        10    /* max time to wait for response, sec. */
  43. #define    MAXPACKET    (65536-60-8)    /* max packet size */
  44. #define VERBOSE        1    /* verbose flag */
  45. #define QUIET        2    /* quiet flag */
  46. #define FLOOD        4    /* floodping flag */
  47. #define    RROUTE        8    /* record route flag */
  48. #define PING_FILLED     16      /* is buffer filled? */
  49. #define    NUMERIC        32    /* don't do gethostbyaddr() calls */
  50. #define    INTERVAL    64    /* did user specify interval? */
  51. #define    NROUTES        9    /* number of record route slots */
  52. #ifndef MAXHOSTNAMELEN
  53. #define MAXHOSTNAMELEN    64
  54. #endif
  55.  
  56. /* MAX_DUP_CHK is the number of bits in received table, ie the */
  57. /*      maximum number of received sequence numbers we can keep track of. */
  58. /*      Change 128 to 8192 for complete accuracy... */
  59.  
  60. #define MAX_DUP_CHK     8 * 128
  61. int     mx_dup_ck = MAX_DUP_CHK;
  62. char    rcvd_tbl[ MAX_DUP_CHK / 8 ];
  63. int     nrepeats = 0;
  64.  
  65. #define A(bit)          rcvd_tbl[ (bit>>3) ]    /* identify byte in array */
  66. #define B(bit)          ( 1 << (bit & 0x07) )   /* identify bit in byte */
  67. #define SET(bit)        A(bit) |= B(bit)
  68. #define CLR(bit)        A(bit) &= (~B(bit))
  69. #define TST(bit)        (A(bit) & B(bit))
  70.  
  71.  
  72. char    *malloc();
  73.  
  74. u_char    *packet;
  75. int    packlen;
  76. int    i, pingflags = 0, options;
  77. extern    int errno;
  78.  
  79. int s;            /* Socket file descriptor */
  80. struct hostent *hp;    /* Pointer to host info */
  81. struct timezone tz;    /* leftover */
  82.  
  83. struct sockaddr whereto;    /* Who to ping */
  84. int datalen = 64-8;        /* How much data */
  85.  
  86. char usage[] =
  87. "Usage:  ping [-dfnqrvR][-c count][-i wait][-l preload][-p pattern][-s packetsize][-h] host \n";
  88.  
  89. char *hostname;
  90. char hnamebuf[MAXHOSTNAMELEN];
  91.  
  92. static u_char outpack[MAXPACKET];
  93.  
  94. int npackets=0;
  95. int preload = 0;        /* number of packets to "preload" */
  96. int ntransmitted = 0;        /* sequence # for outbound packets = #sent */
  97. int ident;
  98. unsigned interval=1;        /* interval between packets */
  99.  
  100. int nreceived = 0;        /* # of packets we got back */
  101. int timing = 0;
  102. int tmin = 999999999;
  103. int tmax = 0;
  104. int tsum = 0;            /* sum of all times, for doing average */
  105. int finish(), catcher();
  106. int bufspace = 48*1024;
  107. int prefinish();
  108. char *inet_ntoa(),*strcpy(),*strncpy(),*sprintf();
  109. char *pr_addr();
  110. u_long inet_addr();
  111. char rspace[3+4*NROUTES+1];    /* record route space */
  112.  
  113. /*
  114.  *             M A I N
  115.  */
  116. main(argc, argv)
  117. char *argv[];
  118. {
  119.     struct sockaddr_in from;
  120. /*    char **av = argv; */
  121.     struct sockaddr_in *to = (struct sockaddr_in *) &whereto;
  122.     int c, k, on = 1, hostind = 0;
  123.     struct protoent *proto;
  124.     static u_char *datap = &outpack[8+sizeof(struct timeval)];
  125.     extern int optind;
  126.     extern char *optarg;
  127.  
  128.     while ((c = getopt(argc, argv, "c:dfh:i:l:np:qrs:vR")) != EOF)
  129.         switch(c) {
  130.             case 'c':
  131.                 npackets = atoi(optarg);
  132.                 break;
  133.             case 'd':
  134.                 options |= SO_DEBUG;
  135.                 break;
  136.             case 'f':
  137.                 pingflags |= FLOOD;
  138.                 break;
  139.             case 'h':
  140.                 hostind = optind-1;
  141.                 break;
  142.                         case 'i':       /* wait between sending packets */
  143.                 interval = atoi(optarg);
  144.                 if (interval == 0) 
  145.                     interval = 1;
  146.                 pingflags |= INTERVAL;
  147.                                 break;
  148.             case 'l':
  149.                 preload = atoi(optarg);
  150.                 break;
  151.             case 'n':
  152.                 pingflags |= NUMERIC;
  153.                 break;
  154.                         case 'p':       /* fill buffer with user pattern */
  155.                                 pingflags |= PING_FILLED;
  156.                 fill((char *)datap, optarg);
  157.                                 break;
  158.             case 'q':
  159.                 pingflags |= QUIET;
  160.                 break;
  161.             case 'r':
  162.                 options |= SO_DONTROUTE;
  163.                 break;
  164.                         case 's':       /* size of packet to send */
  165.                 datalen = atoi(optarg);
  166.                                 break;
  167.             case 'v':
  168.                 pingflags |= VERBOSE;
  169.                 break;
  170.             case 'R':
  171.                 pingflags |= RROUTE;
  172.                 break;
  173.             default:
  174.                 printf(usage);
  175.                 exit(1);
  176.         }
  177.  
  178.     if (hostind == 0) {
  179.         if (optind != argc-1) {
  180.             fprintf(stderr, usage);
  181.             exit(1);
  182.         } else hostind = optind;
  183.     }
  184.  
  185.     bzero((char *)&whereto, sizeof(struct sockaddr) );
  186.     to->sin_family = AF_INET;
  187.     to->sin_addr.s_addr = inet_addr(argv[hostind]);
  188.     if(to->sin_addr.s_addr != (unsigned)-1) {
  189.         strcpy(hnamebuf, argv[hostind]);
  190.         hostname = hnamebuf;
  191.     } else {
  192.         hp = gethostbyname(argv[hostind]);
  193.         if (hp) {
  194.             to->sin_family = hp->h_addrtype;
  195.             bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
  196.             strncpy( hnamebuf, hp->h_name, sizeof(hnamebuf)-1 );
  197.             hostname = hnamebuf;
  198.         } else {
  199.             printf("%s: unknown host %s\n", argv[0], argv[hostind]);
  200.             exit(1);
  201.         }
  202.     }
  203.  
  204.     if ( (pingflags & FLOOD) && (pingflags & INTERVAL) ) {
  205.         fprintf(stderr, "ping: -f and -i incompatible options\n");
  206.         exit(1);
  207.     }
  208.  
  209.     if (datalen > MAXPACKET) {
  210.         fprintf(stderr, "ping: packet size too large\n");
  211.         exit(1);
  212.     }
  213.     if (datalen >= sizeof(struct timeval))    /* can we time 'em? */
  214.         timing = 1;
  215.     packlen = datalen + 60 + 76;    /* MAXIP + MAXICMP */
  216.     if( (packet = (u_char *)malloc((unsigned)packlen)) == NULL ) {
  217.         fprintf( stderr, "ping: malloc failed\n" );
  218.         exit(1);
  219.     }
  220.  
  221.     if (!(pingflags & PING_FILLED)) {
  222.                 for( k=8; k<datalen; k++) *datap++ = k;
  223.         }
  224.  
  225.     ident = getpid() & 0xFFFF;
  226.  
  227.     if ((proto = getprotobyname("icmp")) == NULL) {
  228.         fprintf(stderr, "icmp: unknown protocol\n");
  229.         exit(10);
  230.     }
  231.     if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
  232.         perror("ping: socket");
  233.         exit(5);
  234.     }
  235.     if (options & SO_DEBUG) {
  236.         (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, &on, sizeof(on));
  237.     }
  238.     if (options & SO_DONTROUTE) {
  239.         (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, &on, sizeof(on));
  240.     }
  241.     /* Record Route option */
  242.     if( pingflags & RROUTE ) {
  243. #ifdef IP_OPTIONS
  244.         rspace[IPOPT_OPTVAL] = IPOPT_RR;
  245.         rspace[IPOPT_OLEN] = sizeof(rspace)-1;
  246.         rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
  247.         if( setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace, sizeof(rspace)) < 0 ) {
  248.             perror( "Record route" );
  249.             exit( 42 );
  250.         }
  251. #else
  252.         fprintf( stderr, "ping: record route not available on this machine.\n" );
  253.         exit( 42 );
  254. #endif IP_OPTIONS
  255.     }
  256.  
  257.     if(to->sin_family == AF_INET) {
  258.         printf("PING %s (%s): %d data bytes\n", hostname,
  259.           inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr), datalen);
  260.     } else {
  261.         printf("PING %s: %d data bytes\n", hostname, datalen );
  262.     }
  263.     /* When pinging the broadcast address, you can get a lot
  264.      * of answers.  Doing something so evil is useful if you
  265.      * are trying to stress the ethernet, or just want to
  266.      * fill the arp cache to get some stuff for /etc/ethers.
  267.      */
  268.     (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&bufspace,
  269.              sizeof(bufspace));
  270.  
  271.     signal( SIGINT, prefinish );
  272.     signal(SIGALRM, catcher);
  273.  
  274.     /* fire off them quickies */
  275.     for(i=0; i < preload; i++)
  276.         pinger();
  277.  
  278.     if(!(pingflags & FLOOD))
  279.         catcher();    /* start things going */
  280.  
  281.     for (;;) {
  282.         int fromlen = sizeof (from);
  283.         int cc;
  284.         struct timeval timeout;
  285.         int fdmask = 1 << s;
  286.  
  287.         timeout.tv_sec = 0;
  288.         timeout.tv_usec = 10000;
  289.  
  290.         if(pingflags & FLOOD) {
  291.             pinger();
  292.             if( select(32, (fd_set *)&fdmask, (fd_set *)0, (fd_set *)0, &timeout) == 0)
  293.                 continue;
  294.         }
  295.         if ( (cc=recvfrom(s, (char *)packet, packlen, 0, (struct sockaddr *)&from, &fromlen)) < 0) {
  296.             if( errno == EINTR )
  297.                 continue;
  298.             perror("ping: recvfrom");
  299.             continue;
  300.         }
  301.         pr_pack( (char *)packet, cc, &from );
  302.         if (npackets && nreceived >= npackets)
  303.             finish();
  304.     }
  305.     /*NOTREACHED*/
  306. }
  307.  
  308. /*
  309.  *             C A T C H E R
  310.  * 
  311.  * This routine causes another PING to be transmitted, and then
  312.  * schedules another SIGALRM for 1 second from now.
  313.  * 
  314.  * Bug -
  315.  *     Our sense of time will slowly skew (ie, packets will not be launched
  316.  *     exactly at 1-second intervals).  This does not affect the quality
  317.  *    of the delay and loss statistics.
  318.  */
  319. catcher()
  320. {
  321.     int waittime;
  322.  
  323.     pinger();
  324.     signal(SIGALRM, catcher);
  325.     if (npackets == 0 || ntransmitted < npackets)
  326.         alarm(interval);
  327.     else {
  328.         if (nreceived) {
  329.             waittime = 2 * tmax / 1000;
  330.             if (waittime == 0)
  331.                 waittime = 1;
  332.         } else
  333.             waittime = MAXWAIT;
  334.         signal(SIGALRM, finish);
  335.         alarm((unsigned)waittime);
  336.     }
  337. }
  338.  
  339. /*
  340.  *             P I N G E R
  341.  * 
  342.  * Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
  343.  * will be added on by the kernel.  The ID field is our UNIX process ID,
  344.  * and the sequence number is an ascending integer.  The first 8 bytes
  345.  * of the data portion are used to hold a UNIX "timeval" struct in VAX
  346.  * byte-order, to compute the round-trip time.
  347.  */
  348. pinger()
  349. {
  350.     register struct icmp *icp = (struct icmp *) outpack;
  351.     int i, cc;
  352.     register struct timeval *tp = (struct timeval *) &outpack[8];
  353.  
  354.     icp->icmp_type = ICMP_ECHO;
  355.     icp->icmp_code = 0;
  356.     icp->icmp_cksum = 0;
  357.     icp->icmp_seq = ntransmitted++;
  358.     icp->icmp_id = ident;        /* ID */
  359.  
  360.         CLR( icp->icmp_seq % mx_dup_ck );
  361.  
  362.     cc = datalen+8;            /* skips ICMP portion */
  363.  
  364.     if (timing)
  365.         gettimeofday( tp, &tz );
  366.  
  367.     /* Compute ICMP checksum here */
  368.     icp->icmp_cksum = in_cksum( (u_short *)icp, cc );
  369.  
  370.     /* cc = sendto(s, msg, len, flags, to, tolen) */
  371.     i = sendto( s, (char *)outpack, cc, 0, &whereto, sizeof(struct sockaddr) );
  372.  
  373.     if( i < 0 || i != cc )  {
  374.         if( i<0 )  perror("sendto");
  375.         printf("ping: wrote %s %d chars, ret=%d\n",
  376.             hostname, cc, i );
  377.         fflush(stdout);
  378.     }
  379.     if( pingflags & FLOOD ) {
  380.         putchar('.');
  381.         fflush(stdout);
  382.     }
  383. }
  384.  
  385. /*
  386.  *            P R _ P A C K
  387.  *
  388.  * Print out the packet, if it came from us.  This logic is necessary
  389.  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
  390.  * which arrive ('tis only fair).  This permits multiple copies of this
  391.  * program to be run without having intermingled output (or statistics!).
  392.  */
  393. pr_pack( buf, cc, from )
  394. char *buf;
  395. int cc;
  396. struct sockaddr_in *from;
  397. {
  398.     struct ip *ip;
  399.     register struct icmp *icp;
  400.     register int i, j;
  401.     register u_char *cp,*dp;
  402.     static int old_rrlen;
  403.     static char old_rr[MAX_IPOPTLEN];
  404.     struct timeval tv;
  405.     struct timeval *tp;
  406.     int hlen, triptime, dupflag;
  407.  
  408.     gettimeofday( &tv, &tz );
  409.  
  410.     /* Check the IP header */
  411.     ip = (struct ip *) buf;
  412.     hlen = ip->ip_hl << 2;
  413.     if( cc < hlen + ICMP_MINLEN ) {
  414.         if( pingflags & VERBOSE )
  415.             printf("packet too short (%d bytes) from %s\n", cc,
  416.                 inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr));
  417.             fflush(stdout);
  418.         return;
  419.     }
  420.  
  421.     /* Now the ICMP part */
  422.     cc -= hlen;
  423.     icp = (struct icmp *)(buf + hlen);
  424.     if( icp->icmp_type == ICMP_ECHOREPLY ) {
  425.         if( icp->icmp_id != ident )
  426.             return;            /* 'Twas not our ECHO */
  427.  
  428.         nreceived++;
  429.         if (timing) {
  430. #ifndef icmp_data
  431.             tp = (struct timeval *)&icp->icmp_ip;
  432. #else
  433.             tp = (struct timeval *)&icp->icmp_data[0];
  434. #endif
  435.             tvsub( &tv, tp );
  436.             triptime = tv.tv_sec*1000+(tv.tv_usec/1000);
  437.             tsum += triptime;
  438.             if( triptime < tmin )
  439.                 tmin = triptime;
  440.             if( triptime > tmax )
  441.                 tmax = triptime;
  442.         }
  443.  
  444.                 if ( TST(icp->icmp_seq%mx_dup_ck) ) {
  445.                            nrepeats++, nreceived--;
  446.             dupflag=1;
  447.                 } else {
  448.             SET(icp->icmp_seq%mx_dup_ck);
  449.             dupflag=0;
  450.         }
  451.  
  452.         if( pingflags & QUIET )
  453.             return;
  454.  
  455.         if( pingflags & FLOOD ) {
  456.             putchar('\b');
  457.             fflush(stdout);
  458.         } else {
  459.             printf("%d bytes from %s: icmp_seq=%d", cc,
  460.               inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
  461.               icp->icmp_seq );
  462.             if ( dupflag ) printf(" DUP!");
  463.             printf(" ttl=%d", ip->ip_ttl);
  464.             if (timing)
  465.                 printf(" time=%d ms", triptime );
  466.             /* check the data */
  467.             cp = (u_char*)&icp->icmp_data[8];
  468.             dp = &outpack[8+sizeof(struct timeval)];
  469.             for (i=8; i<datalen; i++, cp++, dp++) {
  470.                 if (*cp != *dp) {
  471.             printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
  472.                         i, *dp, *cp);
  473.                     cp = (u_char*)&icp->icmp_data[0];
  474.                     for (i=8; i<datalen; i++, cp++) {
  475.                         if ((i%32) == 8)
  476.                             printf("\n\t");
  477.                         printf("%x ", *cp);
  478.                     }
  479.                     break;
  480.                 }
  481.             }
  482.  
  483.         }
  484.     } else {
  485.         /* We've got something other than an ECHOREPLY */
  486.         if( !(pingflags & VERBOSE) )
  487.             return;
  488.  
  489.         printf("%d bytes from %s: ",
  490.           cc, pr_addr(from->sin_addr.s_addr) );
  491.         pr_icmph( icp );
  492.     }
  493.  
  494.     /* Display any IP options */
  495.     cp = (u_char *)buf + sizeof(struct ip);
  496.     while (hlen > sizeof(struct ip) & (hlen >= 0)) { /* !ANSI C will  */
  497.         register unsigned long l;         /* force hlen to */
  498.         switch (*cp) {                 /* unsigned!     */
  499.         case IPOPT_EOL:
  500.             hlen = 0;
  501.             break;
  502.         case IPOPT_LSRR:
  503.             printf("\nLSRR: ");
  504.             hlen -= 2;
  505.             j = *++cp;
  506.             ++cp;
  507.             if (j > IPOPT_MINOFF) for (;;) {
  508.                 l = *++cp;
  509.                 l = (l<<8) + *++cp;
  510.                 l = (l<<8) + *++cp;
  511.                 l = (l<<8) + *++cp;
  512.                 if (l == 0)
  513.                     printf("\t0.0.0.0");
  514.                 else
  515.                     printf("\t%s", pr_addr(ntohl(l)));
  516.                 hlen -= 4;
  517.                 j -= 4;
  518.                 if (j <= IPOPT_MINOFF)
  519.                     break;
  520.                 putchar('\n');
  521.             }
  522.             break;
  523.         case IPOPT_RR:
  524.             j = *++cp;    /* get length */
  525.             i = *++cp;    /* and pointer */
  526.             hlen -= 2;
  527.             if (i > j) i = j;
  528.             i -= IPOPT_MINOFF;
  529.             if (i <= 0)
  530.                 continue;
  531.             if (i == old_rrlen
  532.                 && cp == (u_char *)buf + sizeof(struct ip) + 2
  533.                 && !bcmp((char *)cp, old_rr, i)
  534.                 && !(pingflags & FLOOD)) {
  535.                 printf("\t(same route)");
  536.                 i = ((i+3)/4)*4;
  537.                 hlen -= i;
  538.                 cp += i;
  539.                 break;
  540.             }
  541.             old_rrlen = i;
  542.             bcopy((char *)cp, old_rr, i);
  543.             printf("\nRR: ");
  544.             for (;;) {
  545.                 l = *++cp;
  546.                 l = (l<<8) + *++cp;
  547.                 l = (l<<8) + *++cp;
  548.                 l = (l<<8) + *++cp;
  549.                 if (l == 0)
  550.                     printf("\t0.0.0.0");
  551.                 else
  552.                     printf("\t%s", pr_addr(ntohl(l)));
  553.                 hlen -= 4;
  554.                 i -= 4;
  555.                 if (i <= 0)
  556.                     break;
  557.                 putchar('\n');
  558.             }
  559.             break;
  560.         case IPOPT_NOP:
  561.             printf("\nNOP");
  562.             break;
  563.         default:
  564.             printf("\nunknown option %x", *cp);
  565.             break;
  566.         }
  567.         hlen--;
  568.         cp++;
  569.     }
  570.     if (!(pingflags & FLOOD))
  571.         putchar('\n');
  572.     fflush(stdout);
  573. }
  574.  
  575. /*
  576.  *            I N _ C K S U M
  577.  *
  578.  * Checksum routine for Internet Protocol family headers (C Version)
  579.  *
  580.  */
  581. in_cksum(addr, len)
  582. u_short *addr;
  583. int len;
  584. {
  585.     register int nleft = len;
  586.     register u_short *w = addr;
  587.     register int sum = 0;
  588.     u_short answer = 0;
  589.  
  590.     /*
  591.      *  Our algorithm is simple, using a 32 bit accumulator (sum),
  592.      *  we add sequential 16 bit words to it, and at the end, fold
  593.      *  back all the carry bits from the top 16 bits into the lower
  594.      *  16 bits.
  595.      */
  596.     while( nleft > 1 )  {
  597.         sum += *w++;
  598.         nleft -= 2;
  599.     }
  600.  
  601.     /* mop up an odd byte, if necessary */
  602.     if( nleft == 1 ) {
  603.         *(u_char *)(&answer) = *(u_char *)w ;
  604.         sum += answer;
  605.     }
  606.  
  607.     /*
  608.      * add back carry outs from top 16 bits to low 16 bits
  609.      */
  610.     sum = (sum >> 16) + (sum & 0xffff);    /* add hi 16 to low 16 */
  611.     sum += (sum >> 16);            /* add carry */
  612.     answer = ~sum;                /* truncate to 16 bits */
  613.     return (answer);
  614. }
  615.  
  616. /*
  617.  *             T V S U B
  618.  * 
  619.  * Subtract 2 timeval structs:  out = out - in.
  620.  * 
  621.  * Out is assumed to be >= in.
  622.  */
  623. tvsub( out, in )
  624. register struct timeval *out, *in;
  625. {
  626.     if( (out->tv_usec -= in->tv_usec) < 0 )   {
  627.         out->tv_sec--;
  628.         out->tv_usec += 1000000;
  629.     }
  630.     out->tv_sec -= in->tv_sec;
  631. }
  632.  
  633. /* On the first SIGINT, allow any outstanding packets to dribble in */
  634. prefinish()
  635. {
  636.     if (nreceived >= ntransmitted    /* quit now if caught up */
  637.         || nreceived == 0)        /* or if remote is dead */
  638.         finish();
  639.     signal(SIGINT, finish);        /* do this only the 1st time */
  640.     npackets = ntransmitted+1;    /* let the normal limit work */
  641. }
  642. /*
  643.  *            F I N I S H
  644.  *
  645.  * Print out statistics, and give up.
  646.  * Heavily buffered STDIO is used here, so that all the statistics
  647.  * will be written with 1 sys-write call.  This is nice when more
  648.  * than one copy of the program is running on a terminal;  it prevents
  649.  * the statistics output from becomming intermingled.
  650.  */
  651. finish()
  652. {
  653.     putchar('\n');
  654.     fflush(stdout);
  655.     printf("\n----%s PING Statistics----\n", hostname );
  656.     printf("%d packets transmitted, ", ntransmitted );
  657.     printf("%d packets received, ", nreceived );
  658.         if (nrepeats) printf("+%d duplicates, ", nrepeats );
  659.     if (ntransmitted)
  660.         if( nreceived > ntransmitted)
  661.             printf("-- somebody's printing up packets!");
  662.         else
  663.             printf("%d%% packet loss", 
  664.               (int) (((ntransmitted-nreceived)*100) /
  665.               ntransmitted));
  666.     printf("\n");
  667.     if (nreceived && timing)
  668.         printf("round-trip (ms)  min/avg/max = %d/%d/%d\n",
  669.         tmin,
  670.         tsum / (nreceived + nrepeats),
  671.         tmax );
  672.     fflush(stdout);
  673.     exit(0);
  674. }
  675.  
  676. #if 0
  677. static char *ttab[] = {
  678.     "Echo Reply",        /* ip + seq + udata */
  679.     "Dest Unreachable",    /* net, host, proto, port, frag, sr + IP */
  680.     "Source Quench",    /* IP */
  681.     "Redirect",        /* redirect type, gateway, + IP  */
  682.     "Echo",
  683.     "Time Exceeded",    /* transit, frag reassem + IP */
  684.     "Parameter Problem",    /* pointer + IP */
  685.     "Timestamp",        /* id + seq + three timestamps */
  686.     "Timestamp Reply",    /* " */
  687.     "Info Request",        /* id + sq */
  688.     "Info Reply"        /* " */
  689. };
  690. #endif    /* 0 */
  691.  
  692. /*
  693.  *  Print a descriptive string about an ICMP header.
  694.  */
  695. pr_icmph( icp )
  696. struct icmp *icp;
  697. {
  698.     switch( icp->icmp_type ) {
  699.     case ICMP_ECHOREPLY:
  700.         printf("Echo Reply\n");
  701.         /* XXX ID + Seq + Data */
  702.         break;
  703.     case ICMP_UNREACH:
  704.         switch( icp->icmp_code ) {
  705.         case ICMP_UNREACH_NET:
  706.             printf("Destination Net Unreachable\n");
  707.             break;
  708.         case ICMP_UNREACH_HOST:
  709.             printf("Destination Host Unreachable\n");
  710.             break;
  711.         case ICMP_UNREACH_PROTOCOL:
  712.             printf("Destination Protocol Unreachable\n");
  713.             break;
  714.         case ICMP_UNREACH_PORT:
  715.             printf("Destination Port Unreachable\n");
  716.             break;
  717.         case ICMP_UNREACH_NEEDFRAG:
  718.             printf("frag needed and DF set\n");
  719.             break;
  720.         case ICMP_UNREACH_SRCFAIL:
  721.             printf("Source Route Failed\n");
  722.             break;
  723.         default:
  724.             printf("Dest Unreachable, Bad Code: %d\n", icp->icmp_code );
  725.             break;
  726.         }
  727.         /* Print returned IP header information */
  728. #ifndef icmp_data
  729.         pr_retip( &icp->icmp_ip );
  730. #else
  731.         pr_retip( (struct ip *)icp->icmp_data );
  732. #endif
  733.         break;
  734.     case ICMP_SOURCEQUENCH:
  735.         printf("Source Quench\n");
  736. #ifndef icmp_data
  737.         pr_retip( &icp->icmp_ip );
  738. #else
  739.         pr_retip( (struct ip *)icp->icmp_data );
  740. #endif
  741.         break;
  742.     case ICMP_REDIRECT:
  743.         switch( icp->icmp_code ) {
  744.         case ICMP_REDIRECT_NET:
  745.             printf("Redirect Network");
  746.             break;
  747.         case ICMP_REDIRECT_HOST:
  748.             printf("Redirect Host");
  749.             break;
  750.         case ICMP_REDIRECT_TOSNET:
  751.             printf("Redirect Type of Service and Network");
  752.             break;
  753.         case ICMP_REDIRECT_TOSHOST:
  754.             printf("Redirect Type of Service and Host");
  755.             break;
  756.         default:
  757.             printf("Redirect, Bad Code: %d", icp->icmp_code );
  758.             break;
  759.         }
  760.         printf(" (New addr: 0x%08x)\n", icp->icmp_hun.ih_gwaddr );
  761. #ifndef icmp_data
  762.         pr_retip( &icp->icmp_ip );
  763. #else
  764.         pr_retip( (struct ip *)icp->icmp_data );
  765. #endif
  766.         break;
  767.     case ICMP_ECHO:
  768.         printf("Echo Request\n");
  769.         /* XXX ID + Seq + Data */
  770.         break;
  771.     case ICMP_TIMXCEED:
  772.         switch( icp->icmp_code ) {
  773.         case ICMP_TIMXCEED_INTRANS:
  774.             printf("Time to live exceeded\n");
  775.             break;
  776.         case ICMP_TIMXCEED_REASS:
  777.             printf("Frag reassembly time exceeded\n");
  778.             break;
  779.         default:
  780.             printf("Time exceeded, Bad Code: %d\n", icp->icmp_code );
  781.             break;
  782.         }
  783. #ifndef icmp_data
  784.         pr_retip( &icp->icmp_ip );
  785. #else
  786.         pr_retip( (struct ip *)icp->icmp_data );
  787. #endif
  788.         break;
  789.     case ICMP_PARAMPROB:
  790.         printf("Parameter problem: pointer = 0x%02x\n",
  791.             icp->icmp_hun.ih_pptr );
  792. #ifndef icmp_data
  793.         pr_retip( &icp->icmp_ip );
  794. #else
  795.         pr_retip( (struct ip *)icp->icmp_data );
  796. #endif
  797.         break;
  798.     case ICMP_TSTAMP:
  799.         printf("Timestamp\n");
  800.         /* XXX ID + Seq + 3 timestamps */
  801.         break;
  802.     case ICMP_TSTAMPREPLY:
  803.         printf("Timestamp Reply\n");
  804.         /* XXX ID + Seq + 3 timestamps */
  805.         break;
  806.     case ICMP_IREQ:
  807.         printf("Information Request\n");
  808.         /* XXX ID + Seq */
  809.         break;
  810.     case ICMP_IREQREPLY:
  811.         printf("Information Reply\n");
  812.         /* XXX ID + Seq */
  813.         break;
  814. #ifdef ICMP_MASKREQ
  815.     case ICMP_MASKREQ:
  816.         printf("Address Mask Request\n");
  817.         break;
  818. #endif
  819. #ifdef ICMP_MASKREPLY
  820.     case ICMP_MASKREPLY:
  821.         printf("Address Mask Reply\n");
  822.         break;
  823. #endif
  824.     default:
  825.         printf("Bad ICMP type: %d\n", icp->icmp_type);
  826.     }
  827. }
  828.  
  829. /*
  830.  *  Print an IP header with options.
  831.  */
  832. pr_iph( ip )
  833. struct ip *ip;
  834. {
  835.     int    hlen;
  836.     unsigned char *cp;
  837.  
  838.     hlen = ip->ip_hl << 2;
  839.     cp = (unsigned char *)ip + 20;    /* point to options */
  840.  
  841.     printf("Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst Data\n");
  842.     printf(" %1x  %1x  %02x %04x %04x",
  843.         ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id );
  844.     printf("   %1x %04x", ((ip->ip_off)&0xe000)>>13, (ip->ip_off)&0x1fff );
  845.     printf("  %02x  %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum );
  846.     printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
  847.     printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
  848.     /* dump and option bytes */
  849.     while( hlen-- > 20 ) {
  850.         printf( "%02x", *cp++ );
  851.     }
  852.     printf("\n");
  853. }
  854.  
  855. /*
  856.  *  Return an ascii host address
  857.  *  as a dotted quad and optionally with a hostname
  858.  */
  859. char *
  860. pr_addr( l )
  861. unsigned long l;
  862. {
  863.     struct    hostent    *hp;
  864.     static    char    buf[80];
  865.  
  866.     if( (pingflags & NUMERIC) || (hp = gethostbyaddr((char *)&l, 4, AF_INET)) == NULL )
  867.         sprintf( buf, "%s", inet_ntoa(*(struct in_addr *)&l) );
  868.     else
  869.         sprintf( buf, "%s (%s)", hp->h_name, inet_ntoa(*(struct in_addr *)&l) );
  870.  
  871.     return( buf );
  872. }
  873.  
  874. /*
  875.  *  Dump some info on a returned (via ICMP) IP packet.
  876.  */
  877. pr_retip( ip )
  878. struct ip *ip;
  879. {
  880.     int    hlen;
  881.     unsigned char    *cp;
  882.  
  883.     pr_iph( ip );
  884.     hlen = ip->ip_hl << 2;
  885.     cp = (unsigned char *)ip + hlen;
  886.  
  887.     if( ip->ip_p == 6 ) {
  888.         printf( "TCP: from port %d, to port %d (decimal)\n",
  889.             (*cp*256+*(cp+1)), (*(cp+2)*256+*(cp+3)) );
  890.     } else if( ip->ip_p == 17 ) {
  891.         printf( "UDP: from port %d, to port %d (decimal)\n",
  892.             (*cp*256+*(cp+1)), (*(cp+2)*256+*(cp+3)) );
  893.     }
  894. }
  895.  
  896. fill(bp, patp)
  897. char *bp, *patp;
  898. {
  899.         register int ii,jj,kk;
  900.         char *cp;
  901.         int pat[16];
  902.  
  903.         for (cp=patp; *cp; cp++)
  904.                 if (!isxdigit(*cp)) {
  905.                         printf("\"-p %s\" ???: ", patp);
  906.                         printf("patterns must be specified as hex digits\n");
  907.                         exit(1);
  908.                 }
  909.  
  910.         ii = sscanf(patp,
  911.                 "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
  912.                 &pat[0], &pat[1], &pat[2], &pat[3],
  913.                 &pat[4], &pat[5], &pat[6], &pat[7],
  914.                 &pat[8], &pat[9], &pat[10], &pat[11],
  915.                 &pat[12], &pat[13], &pat[14], &pat[15]);
  916.  
  917.         if (ii > 0)
  918.                 for (kk=0; kk<=MAXPACKET-(8+ii); kk+=ii)
  919.                 for (jj=0; jj<ii; jj++)
  920.                         bp[jj+kk] = pat[jj];
  921.  
  922.         if (!(pingflags & QUIET)) {
  923.                 printf("PATTERN: 0x");
  924.                 for (jj=0; jj<ii; jj++)
  925.                         printf("%02x", bp[jj]&0xFF);
  926.                 printf("\n");
  927.         }
  928.  
  929. }
  930.