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