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