home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / ping-w4.zip / ping.c next >
C/C++ Source or Header  |  1997-03-01  |  29KB  |  1,140 lines

  1. /*
  2.  * Copyright (c) 1989, 1993
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Mike Muuss.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char copyright[] =
  39. "@(#) Copyright (c) 1989, 1993\n\
  40.     The Regents of the University of California.  All rights reserved.\n";
  41. #endif /* not lint */
  42.  
  43. #ifndef lint
  44. static char sccsid[] = "@(#)ping.c    8.1 (Berkeley) 6/5/93";
  45. #endif /* not lint */
  46.  
  47. /*
  48.  *            P I N G . C
  49.  *
  50.  * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
  51.  * measure round-trip-delays and packet loss across network paths.
  52.  *
  53.  * Author -
  54.  *    Mike Muuss
  55.  *    U. S. Army Ballistic Research Laboratory
  56.  *    December, 1983
  57.  *
  58.  * Status -
  59.  *    Public Domain.  Distribution Unlimited.
  60.  * Bugs -
  61.  *    More statistics could always be gathered.
  62.  *    This program has to run SUID to ROOT to access the ICMP socket.
  63.  */
  64.  
  65. #include <sys/param.h>
  66. #include <sys/socket.h>
  67. #include <sys/file.h>
  68. #include <sys/time.h>
  69. #include <signal.h>
  70. #include <termios.h>
  71.  
  72. #include <netinet/in_systm.h>
  73. #include <netinet/in.h>
  74. #include <netinet/ip.h>
  75. #include <netinet/ip_icmp.h>
  76. #include <netinet/ip_var.h>
  77. #include <netdb.h>
  78. #include <unistd.h>
  79. #include <stdio.h>
  80. #include <ctype.h>
  81. #include <errno.h>
  82. #include <string.h>
  83.  
  84. #define    DEFDATALEN    (64 - 8)    /* default data length */
  85. #define    MAXIPLEN    60
  86. #define    MAXICMPLEN    76
  87. #define    MAXPACKET    (65536 - 60 - 8)/* max packet size */
  88. #define    MAXWAIT        10        /* max seconds to wait for response */
  89. #define    NROUTES        9        /* number of record route slots */
  90.  
  91. #define    A(bit)        rcvd_tbl[(bit)>>3]    /* identify byte in array */
  92. #define    B(bit)        (1 << ((bit) & 0x07))    /* identify bit in byte */
  93. #define    SET(bit)    (A(bit) |= B(bit))
  94. #define    CLR(bit)    (A(bit) &= (~B(bit)))
  95. #define    TST(bit)    (A(bit) & B(bit))
  96.  
  97. /* various options */
  98. int options;
  99. #define    F_FLOOD        0x0001
  100. #define    F_INTERVAL    0x0002
  101. #define    F_NUMERIC    0x0004
  102. #define    F_PINGFILLED    0x0008
  103. #define    F_QUIET        0x0010
  104. #define    F_RROUTE    0x0020
  105. #define    F_SO_DEBUG    0x0040
  106. #define    F_SO_DONTROUTE    0x0080
  107. #define    F_VERBOSE    0x0100
  108. #define    F_QUIET2    0x0200
  109. #define    F_NOLOOP    0x0400
  110. #define    F_MTTL        0x0800
  111. #define    F_MIF        0x1000
  112.  
  113. /*
  114.  * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
  115.  * number of received sequence numbers we can keep track of.  Change 128
  116.  * to 8192 for complete accuracy...
  117.  */
  118. #define    MAX_DUP_CHK    (8 * 128)
  119. int mx_dup_ck = MAX_DUP_CHK;
  120. char rcvd_tbl[MAX_DUP_CHK / 8];
  121.  
  122. struct sockaddr whereto;    /* who to ping */
  123. int datalen = DEFDATALEN;
  124. int s;                /* socket file descriptor */
  125. u_char outpack[MAXPACKET];
  126. char BSPACE = '\b';        /* characters written for flood */
  127. char DOT = '.';
  128. char *hostname;
  129. int ident;            /* process id to identify our packets */
  130.  
  131. /* counters */
  132. long npackets;            /* max packets to transmit */
  133. long nreceived;            /* # of packets we got back */
  134. long nrepeats;            /* number of duplicates */
  135. long ntransmitted;        /* sequence # for outbound packets = #sent */
  136. int interval = 1;        /* interval between packets */
  137.  
  138. /* timing */
  139. int timing;            /* flag to do timing */
  140. double tmin = 999999999.0;    /* minimum round trip time */
  141. double tmax = 0.0;        /* maximum round trip time */
  142. double tsum = 0.0;        /* sum of all times, for doing average */
  143.  
  144. int reset_kerninfo;
  145. sig_atomic_t siginfo_p;
  146.  
  147. char *pr_addr();
  148. void catcher(), finish(), status(), check_status();
  149.  
  150. main(argc, argv)
  151.     int argc;
  152.     char **argv;
  153. {
  154.     extern int errno, optind;
  155.     extern char *optarg;
  156.     struct timeval timeout;
  157.     struct hostent *hp;
  158.     struct sockaddr_in *to;
  159.     struct protoent *proto;
  160.     struct termios ts;
  161.     register int i;
  162.     int ch, fdmask, hold, packlen, preload, sockerrno;
  163.     struct in_addr ifaddr;
  164.     unsigned char ttl, loop;
  165.     u_char *datap, *packet;
  166.     char *target, hnamebuf[MAXHOSTNAMELEN], *malloc();
  167. #ifdef IP_OPTIONS
  168.     char rspace[3 + 4 * NROUTES + 1];    /* record route space */
  169. #endif
  170.     struct sigaction si_sa;
  171.  
  172.     /*
  173.      * Do the stuff that we need root priv's for *first*, and
  174.      * then drop our setuid bit.  Save error reporting for
  175.      * after arg parsing.
  176.      */
  177.     proto = getprotobyname("icmp");
  178.     if (proto) {
  179.         s = socket(AF_INET, SOCK_RAW, proto->p_proto);
  180.         sockerrno = errno;
  181.     }
  182.  
  183.     setuid(getuid());
  184.  
  185.     preload = 0;
  186.  
  187.     datap = &outpack[8 + sizeof(struct timeval)];
  188.     while ((ch = getopt(argc, argv, "I:LQRT:c:dfh:i:l:np:qrs:v")) != EOF)
  189.         switch(ch) {
  190.         case 'c':
  191.             npackets = atoi(optarg);
  192.             if (npackets <= 0) {
  193.                 (void)fprintf(stderr,
  194.                     "ping: bad number of packets to transmit.\n");
  195.                 exit(1);
  196.             }
  197.             break;
  198.         case 'd':
  199.             options |= F_SO_DEBUG;
  200.             break;
  201.         case 'f':
  202.             if (getuid()) {
  203.                 (void)fprintf(stderr,
  204.                     "ping: %s\n", strerror(EPERM));
  205.                 exit(1);
  206.             }
  207.             options |= F_FLOOD;
  208.             setbuf(stdout, (char *)NULL);
  209.             break;
  210.         case 'i':        /* wait between sending packets */
  211.             interval = atoi(optarg);
  212.             if (interval <= 0) {
  213.                 (void)fprintf(stderr,
  214.                     "ping: bad timing interval.\n");
  215.                 exit(1);
  216.             }
  217.             options |= F_INTERVAL;
  218.             break;
  219.         case 'I':        /* multicast interface */
  220.             if (inet_aton(optarg, &ifaddr) == 0) {
  221.                 (void)fprintf(stderr,
  222.                     "ping: bad multicast interface.\n");
  223.                 exit(1);
  224.             }
  225.             options |= F_MIF;
  226.             break;
  227.         case 'l':
  228.             preload = atoi(optarg);
  229.             if (preload < 0) {
  230.                 (void)fprintf(stderr,
  231.                     "ping: bad preload value.\n");
  232.                 exit(1);
  233.             }
  234.             break;
  235.         case 'L':
  236.             options |= F_NOLOOP;
  237.             loop = 0;
  238.             break;
  239.         case 'n':
  240.             options |= F_NUMERIC;
  241.             break;
  242.         case 'p':        /* fill buffer with user pattern */
  243.             options |= F_PINGFILLED;
  244.             fill((char *)datap, optarg);
  245.                 break;
  246.         case 'Q':
  247.             options |= F_QUIET2;
  248.             break;
  249.         case 'q':
  250.             options |= F_QUIET;
  251.             break;
  252.         case 'R':
  253.             options |= F_RROUTE;
  254.             break;
  255.         case 'r':
  256.             options |= F_SO_DONTROUTE;
  257.             break;
  258.         case 's':        /* size of packet to send */
  259.             datalen = atoi(optarg);
  260.             if (datalen > MAXPACKET) {
  261.                 (void)fprintf(stderr,
  262.                     "ping: packet size too large.\n");
  263.                 exit(1);
  264.             }
  265.             if (datalen <= 0) {
  266.                 (void)fprintf(stderr,
  267.                     "ping: illegal packet size.\n");
  268.                 exit(1);
  269.             }
  270.             break;
  271.         case 'T':        /* multicast TTL */
  272.             i = atoi(optarg);
  273.             if (i < 0 || i > 255) {
  274.                 (void)fprintf(stderr,
  275.                     "ping: illegal multicast TTL.\n");
  276.                 exit(1);
  277.             }
  278.             ttl = i;
  279.             options |= F_MTTL;
  280.             break;
  281.         case 'v':
  282.             options |= F_VERBOSE;
  283.             break;
  284.         default:
  285.             usage();
  286.         }
  287.     argc -= optind;
  288.     argv += optind;
  289.  
  290.     if (argc != 1)
  291.         usage();
  292.     target = *argv;
  293.  
  294.     bzero((char *)&whereto, sizeof(struct sockaddr));
  295.     to = (struct sockaddr_in *)&whereto;
  296.     to->sin_family = AF_INET;
  297.     to->sin_addr.s_addr = inet_addr(target);
  298.     if (to->sin_addr.s_addr != (u_int)-1)
  299.         hostname = target;
  300.     else {
  301.         hp = gethostbyname(target);
  302.         if (!hp) {
  303.             (void)fprintf(stderr,
  304.                 "ping: unknown host %s\n", target);
  305.             exit(1);
  306.         }
  307.         to->sin_family = hp->h_addrtype;
  308.         bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
  309.         (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
  310.         hostname = hnamebuf;
  311.     }
  312.  
  313.     if (options & F_FLOOD && options & F_INTERVAL) {
  314.         (void)fprintf(stderr,
  315.             "ping: -f and -i incompatible options.\n");
  316.         exit(1);
  317.     }
  318.  
  319.     if (datalen >= sizeof(struct timeval))    /* can we time transfer */
  320.         timing = 1;
  321.     packlen = datalen + MAXIPLEN + MAXICMPLEN;
  322.     if (!(packet = (u_char *)malloc((u_int)packlen))) {
  323.         (void)fprintf(stderr, "ping: out of memory.\n");
  324.         exit(1);
  325.     }
  326.     if (!(options & F_PINGFILLED))
  327.         for (i = 8; i < datalen; ++i)
  328.             *datap++ = i;
  329.  
  330.     ident = getpid() & 0xFFFF;
  331.  
  332.     if (!proto) {
  333.         (void)fprintf(stderr, "ping: unknown protocol icmp.\n");
  334.         exit(1);
  335.     }
  336.     if (s < 0) {
  337.         errno = sockerrno;
  338.         perror("ping: socket");
  339.         exit(1);
  340.     }
  341.     hold = 1;
  342.     if (options & F_SO_DEBUG)
  343.         (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
  344.             sizeof(hold));
  345.     if (options & F_SO_DONTROUTE)
  346.         (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
  347.             sizeof(hold));
  348.  
  349.     /* record route option */
  350.     if (options & F_RROUTE) {
  351. #ifdef IP_OPTIONS
  352.         rspace[IPOPT_OPTVAL] = IPOPT_RR;
  353.         rspace[IPOPT_OLEN] = sizeof(rspace)-1;
  354.         rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
  355.         if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
  356.             sizeof(rspace)) < 0) {
  357.             perror("ping: record route");
  358.             exit(1);
  359.         }
  360. #else
  361.         (void)fprintf(stderr,
  362.           "ping: record route not available in this implementation.\n");
  363.         exit(1);
  364. #endif /* IP_OPTIONS */
  365.     }
  366.  
  367.     if (options & F_NOLOOP) {
  368.         if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop,
  369.             sizeof(loop)) < 0) {
  370.             perror("ping: IP_MULTICAST_LOOP");
  371.             exit(1);
  372.         }
  373.     }
  374.     if (options & F_MTTL) {
  375.         if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
  376.             sizeof(ttl)) < 0) {
  377.             perror("ping: IP_MULTICAST_TTL");
  378.             exit(1);
  379.         }
  380.     }
  381.     if (options & F_MIF) {
  382.         if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr,
  383.             sizeof(ifaddr)) < 0) {
  384.             perror("ping: IP_MULTICAST_IF");
  385.             exit(1);
  386.         }
  387.     }
  388.  
  389.     /*
  390.      * When pinging the broadcast address, you can get a lot of answers.
  391.      * Doing something so evil is useful if you are trying to stress the
  392.      * ethernet, or just want to fill the arp cache to get some stuff for
  393.      * /etc/ethers.
  394.      */
  395.     hold = 48 * 1024;
  396.     (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
  397.         sizeof(hold));
  398.  
  399.     if (to->sin_family == AF_INET)
  400.         (void)printf("PING %s (%s): %d data bytes\n", hostname,
  401.             inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr),
  402.             datalen);
  403.     else
  404.         (void)printf("PING %s: %d data bytes\n", hostname, datalen);
  405.  
  406.     (void)signal(SIGINT, finish);
  407.     (void)signal(SIGALRM, catcher);
  408.  
  409.     /*
  410.      * Use sigaction instead of signal() to get unambiguous semantics
  411.      * for SIGINFO, in particular with SA_RESTART not set.
  412.      */
  413.     si_sa.sa_handler = status;
  414.     sigemptyset(&si_sa.sa_mask);
  415.     si_sa.sa_flags = 0;
  416.     if (sigaction(SIGINFO, &si_sa, 0) == -1) {
  417.         perror("sigaction");
  418.         exit(1);
  419.     }
  420.  
  421.     if (tcgetattr(STDOUT_FILENO, &ts) != -1) {
  422.         reset_kerninfo = !(ts.c_lflag & NOKERNINFO);
  423.         ts.c_lflag |= NOKERNINFO;
  424.         tcsetattr(STDOUT_FILENO, TCSANOW, &ts);
  425.     }
  426.  
  427.     while (preload--)        /* fire off them quickies */
  428.         pinger();
  429.  
  430.     if ((options & F_FLOOD) == 0)
  431.         catcher();        /* start things going */
  432.  
  433.     for (;;) {
  434.         struct sockaddr_in from;
  435.         register int cc;
  436.         int fromlen;
  437.  
  438.         check_status();
  439.         if (options & F_FLOOD) {
  440.             pinger();
  441.             timeout.tv_sec = 0;
  442.             timeout.tv_usec = 10000;
  443.             fdmask = 1 << s;
  444.             if (select(s + 1, (fd_set *)&fdmask, (fd_set *)NULL,
  445.                 (fd_set *)NULL, &timeout) < 1)
  446.                 continue;
  447.         }
  448.         fromlen = sizeof(from);
  449.         if ((cc = recvfrom(s, (char *)packet, packlen, 0,
  450.             (struct sockaddr *)&from, &fromlen)) < 0) {
  451.             if (errno == EINTR)
  452.                 continue;
  453.             perror("ping: recvfrom");
  454.             continue;
  455.         }
  456.         pr_pack((char *)packet, cc, &from);
  457.         if (npackets && nreceived >= npackets)
  458.             break;
  459.     }
  460.     finish();
  461.     /* NOTREACHED */
  462. }
  463.  
  464. /*
  465.  * catcher --
  466.  *    This routine causes another PING to be transmitted, and then
  467.  * schedules another SIGALRM for 1 second from now.
  468.  *
  469.  * bug --
  470.  *    Our sense of time will slowly skew (i.e., packets will not be
  471.  * launched exactly at 1-second intervals).  This does not affect the
  472.  * quality of the delay and loss statistics.
  473.  */
  474. void
  475. catcher()
  476. {
  477.     int waittime;
  478.  
  479.     pinger();
  480.     (void)signal(SIGALRM, catcher);
  481.     if (!npackets || ntransmitted < npackets)
  482.         alarm((u_int)interval);
  483.     else {
  484.         if (nreceived) {
  485.             waittime = 2 * tmax / 1000;
  486.             if (!waittime)
  487.                 waittime = 1;
  488.         } else
  489.             waittime = MAXWAIT;
  490.         (void)signal(SIGALRM, finish);
  491.         (void)alarm((u_int)waittime);
  492.     }
  493. }
  494.  
  495. /*
  496.  * pinger --
  497.  *    Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
  498.  * will be added on by the kernel.  The ID field is our UNIX process ID,
  499.  * and the sequence number is an ascending integer.  The first 8 bytes
  500.  * of the data portion are used to hold a UNIX "timeval" struct in host
  501.  * byte-order, to compute the round-trip time.
  502.  */
  503. pinger()
  504. {
  505.     register struct icmp *icp;
  506.     register int cc;
  507.     int i;
  508.  
  509.     icp = (struct icmp *)outpack;
  510.     icp->icmp_type = ICMP_ECHO;
  511.     icp->icmp_code = 0;
  512.     icp->icmp_cksum = 0;
  513.     icp->icmp_seq = ntransmitted++;
  514.     icp->icmp_id = ident;            /* ID */
  515.  
  516.     CLR(icp->icmp_seq % mx_dup_ck);
  517.  
  518.     if (timing)
  519.         (void)gettimeofday((struct timeval *)&outpack[8],
  520.             (struct timezone *)NULL);
  521.  
  522.     cc = datalen + 8;            /* skips ICMP portion */
  523.  
  524.     /* compute ICMP checksum here */
  525.     icp->icmp_cksum = in_cksum((u_short *)icp, cc);
  526.  
  527.     i = sendto(s, (char *)outpack, cc, 0, &whereto,
  528.         sizeof(struct sockaddr));
  529.  
  530.     if (i < 0 || i != cc)  {
  531.         if (i < 0)
  532.             perror("ping: sendto");
  533.         (void)printf("ping: wrote %s %d chars, ret=%d\n",
  534.             hostname, cc, i);
  535.     }
  536.     if (!(options & F_QUIET) && options & F_FLOOD)
  537.         (void)write(STDOUT_FILENO, &DOT, 1);
  538. }
  539.  
  540. /*
  541.  * pr_pack --
  542.  *    Print out the packet, if it came from us.  This logic is necessary
  543.  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
  544.  * which arrive ('tis only fair).  This permits multiple copies of this
  545.  * program to be run without having intermingled output (or statistics!).
  546.  */
  547. pr_pack(buf, cc, from)
  548.     char *buf;
  549.     int cc;
  550.     struct sockaddr_in *from;
  551. {
  552.     register struct icmp *icp;
  553.     register u_long l;
  554.     register int i, j;
  555.     register u_char *cp,*dp;
  556.     static int old_rrlen;
  557.     static char old_rr[MAX_IPOPTLEN];
  558.     struct ip *ip;
  559.     struct timeval tv, *tp;
  560.     double triptime;
  561.     int hlen, dupflag;
  562.  
  563.     (void)gettimeofday(&tv, (struct timezone *)NULL);
  564.  
  565.     /* Check the IP header */
  566.     ip = (struct ip *)buf;
  567.     hlen = ip->ip_hl << 2;
  568.     if (cc < hlen + ICMP_MINLEN) {
  569.         if (options & F_VERBOSE)
  570.             (void)fprintf(stderr,
  571.               "ping: packet too short (%d bytes) from %s\n", cc,
  572.               inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr));
  573.         return;
  574.     }
  575.  
  576.     /* Now the ICMP part */
  577.     cc -= hlen;
  578.     icp = (struct icmp *)(buf + hlen);
  579.     if (icp->icmp_type == ICMP_ECHOREPLY) {
  580.         if (icp->icmp_id != ident)
  581.             return;            /* 'Twas not our ECHO */
  582.         ++nreceived;
  583.         if (timing) {
  584. #ifndef icmp_data
  585.             tp = (struct timeval *)&icp->icmp_ip;
  586. #else
  587.             tp = (struct timeval *)icp->icmp_data;
  588. #endif
  589.             tvsub(&tv, tp);
  590.             triptime = ((double)tv.tv_sec) * 1000.0 +
  591.                 ((double)tv.tv_usec) / 1000.0;
  592.             tsum += triptime;
  593.             if (triptime < tmin)
  594.                 tmin = triptime;
  595.             if (triptime > tmax)
  596.                 tmax = triptime;
  597.         }
  598.  
  599.         if (TST(icp->icmp_seq % mx_dup_ck)) {
  600.             ++nrepeats;
  601.             --nreceived;
  602.             dupflag = 1;
  603.         } else {
  604.             SET(icp->icmp_seq % mx_dup_ck);
  605.             dupflag = 0;
  606.         }
  607.  
  608.         if (options & F_QUIET)
  609.             return;
  610.  
  611.         if (options & F_FLOOD)
  612.             (void)write(STDOUT_FILENO, &BSPACE, 1);
  613.         else {
  614.             (void)printf("%d bytes from %s: icmp_seq=%u", cc,
  615.                inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
  616.                icp->icmp_seq);
  617.             (void)printf(" ttl=%d", ip->ip_ttl);
  618.             if (timing)
  619.                 (void)printf(" time=%.3f ms", triptime);
  620.             if (dupflag)
  621.                 (void)printf(" (DUP!)");
  622.             /* check the data */
  623.             cp = (u_char*)&icp->icmp_data[8];
  624.             dp = &outpack[8 + sizeof(struct timeval)];
  625.             for (i = 8; i < datalen; ++i, ++cp, ++dp) {
  626.                 if (*cp != *dp) {
  627.     (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
  628.         i, *dp, *cp);
  629.                     cp = (u_char*)&icp->icmp_data[0];
  630.                     for (i = 8; i < datalen; ++i, ++cp) {
  631.                         if ((i % 32) == 8)
  632.                             (void)printf("\n\t");
  633.                         (void)printf("%x ", *cp);
  634.                     }
  635.                     break;
  636.                 }
  637.             }
  638.         }
  639.     } else {
  640.         /*
  641.          * We've got something other than an ECHOREPLY.
  642.          * See if it's a reply to something that we sent.
  643.          * We can compare IP destination, protocol,
  644.          * and ICMP type and ID.
  645.          */
  646. #ifndef icmp_data
  647.         struct ip *oip = &icp->icmp_ip;
  648. #else
  649.         struct ip *oip = (struct ip *)icp->icmp_data;
  650. #endif
  651.         struct icmp *oicmp = (struct icmp *)(oip + 1);
  652.  
  653.         if ((options & F_VERBOSE) ||
  654.             (!(options & F_QUIET2) &&
  655.              (oip->ip_dst.s_addr ==
  656.              ((struct sockaddr_in *)&whereto)->sin_addr.s_addr) &&
  657.              (oip->ip_p == IPPROTO_ICMP) &&
  658.              (oicmp->icmp_type == ICMP_ECHO) &&
  659.              (oicmp->icmp_id == ident))) {
  660.             (void)printf("%d bytes from %s: ", cc,
  661.             pr_addr(from->sin_addr.s_addr));
  662.             pr_icmph(icp);
  663.         } else
  664.             return;
  665.     }
  666.  
  667.     /* Display any IP options */
  668.     cp = (u_char *)buf + sizeof(struct ip);
  669.  
  670.     for (; hlen > (int)sizeof(struct ip); --hlen, ++cp)
  671.         switch (*cp) {
  672.         case IPOPT_EOL:
  673.             hlen = 0;
  674.             break;
  675.         case IPOPT_LSRR:
  676.             (void)printf("\nLSRR: ");
  677.             hlen -= 2;
  678.             j = *++cp;
  679.             ++cp;
  680.             if (j > IPOPT_MINOFF)
  681.                 for (;;) {
  682.                     l = *++cp;
  683.                     l = (l<<8) + *++cp;
  684.                     l = (l<<8) + *++cp;
  685.                     l = (l<<8) + *++cp;
  686.                     if (l == 0)
  687.                         (void)printf("\t0.0.0.0");
  688.                 else
  689.                     (void)printf("\t%s", pr_addr(ntohl(l)));
  690.                 hlen -= 4;
  691.                 j -= 4;
  692.                 if (j <= IPOPT_MINOFF)
  693.                     break;
  694.                 (void)putchar('\n');
  695.             }
  696.             break;
  697.         case IPOPT_RR:
  698.             j = *++cp;        /* get length */
  699.             i = *++cp;        /* and pointer */
  700.             hlen -= 2;
  701.             if (i > j)
  702.                 i = j;
  703.             i -= IPOPT_MINOFF;
  704.             if (i <= 0)
  705.                 continue;
  706.             if (i == old_rrlen
  707.                 && cp == (u_char *)buf + sizeof(struct ip) + 2
  708.                 && !bcmp((char *)cp, old_rr, i)
  709.                 && !(options & F_FLOOD)) {
  710.                 (void)printf("\t(same route)");
  711.                 i = ((i + 3) / 4) * 4;
  712.                 hlen -= i;
  713.                 cp += i;
  714.                 break;
  715.             }
  716.             old_rrlen = i;
  717.             bcopy((char *)cp, old_rr, i);
  718.             (void)printf("\nRR: ");
  719.             for (;;) {
  720.                 l = *++cp;
  721.                 l = (l<<8) + *++cp;
  722.                 l = (l<<8) + *++cp;
  723.                 l = (l<<8) + *++cp;
  724.                 if (l == 0)
  725.                     (void)printf("\t0.0.0.0");
  726.                 else
  727.                     (void)printf("\t%s", pr_addr(ntohl(l)));
  728.                 hlen -= 4;
  729.                 i -= 4;
  730.                 if (i <= 0)
  731.                     break;
  732.                 (void)putchar('\n');
  733.             }
  734.             break;
  735.         case IPOPT_NOP:
  736.             (void)printf("\nNOP");
  737.             break;
  738.         default:
  739.             (void)printf("\nunknown option %x", *cp);
  740.             break;
  741.         }
  742.     if (!(options & F_FLOOD)) {
  743.         (void)putchar('\n');
  744.         (void)fflush(stdout);
  745.     }
  746. }
  747.  
  748. /*
  749.  * in_cksum --
  750.  *    Checksum routine for Internet Protocol family headers (C Version)
  751.  */
  752. in_cksum(addr, len)
  753.     u_short *addr;
  754.     int len;
  755. {
  756.     register int nleft = len;
  757.     register u_short *w = addr;
  758.     register int sum = 0;
  759.     u_short answer = 0;
  760.  
  761.     /*
  762.      * Our algorithm is simple, using a 32 bit accumulator (sum), we add
  763.      * sequential 16 bit words to it, and at the end, fold back all the
  764.      * carry bits from the top 16 bits into the lower 16 bits.
  765.      */
  766.     while (nleft > 1)  {
  767.         sum += *w++;
  768.         nleft -= 2;
  769.     }
  770.  
  771.     /* mop up an odd byte, if necessary */
  772.     if (nleft == 1) {
  773.         *(u_char *)(&answer) = *(u_char *)w ;
  774.         sum += answer;
  775.     }
  776.  
  777.     /* add back carry outs from top 16 bits to low 16 bits */
  778.     sum = (sum >> 16) + (sum & 0xffff);    /* add hi 16 to low 16 */
  779.     sum += (sum >> 16);            /* add carry */
  780.     answer = ~sum;                /* truncate to 16 bits */
  781.     return(answer);
  782. }
  783.  
  784. /*
  785.  * tvsub --
  786.  *    Subtract 2 timeval structs:  out = out - in.  Out is assumed to
  787.  * be >= in.
  788.  */
  789. tvsub(out, in)
  790.     register struct timeval *out, *in;
  791. {
  792.     if ((out->tv_usec -= in->tv_usec) < 0) {
  793.         --out->tv_sec;
  794.         out->tv_usec += 1000000;
  795.     }
  796.     out->tv_sec -= in->tv_sec;
  797. }
  798.  
  799. /*
  800.  * status --
  801.  *    Print out statistics when SIGINFO is received.
  802.  */
  803.  
  804. void
  805. status(sig)
  806.     int sig;
  807. {
  808.     siginfo_p = 1;
  809. }
  810.  
  811. void
  812. check_status()
  813. {
  814.     if (siginfo_p) {
  815.         siginfo_p = 0;
  816.         (void)fprintf(stderr,
  817.     "\r%ld/%ld packets received (%.0f%%) %.3f min / %.3f avg / %.3f max\n",
  818.             nreceived, ntransmitted,
  819.             ntransmitted ? nreceived * 100.0 / ntransmitted : 0.0,
  820.             nreceived ? tmin : 0.0,
  821.             nreceived + nrepeats ? tsum / (nreceived + nrepeats) : tsum,
  822.             tmax);
  823.     }
  824. }
  825.  
  826. /*
  827.  * finish --
  828.  *    Print out statistics, and give up.
  829.  */
  830. void
  831. finish()
  832. {
  833.     struct termios ts;
  834.  
  835.     (void)signal(SIGINT, SIG_IGN);
  836.     (void)putchar('\n');
  837.     (void)fflush(stdout);
  838.     (void)printf("--- %s ping statistics ---\n", hostname);
  839.     (void)printf("%ld packets transmitted, ", ntransmitted);
  840.     (void)printf("%ld packets received, ", nreceived);
  841.     if (nrepeats)
  842.         (void)printf("+%ld duplicates, ", nrepeats);
  843.     if (ntransmitted)
  844.         if (nreceived > ntransmitted)
  845.             (void)printf("-- somebody's printing up packets!");
  846.         else
  847.             (void)printf("%d%% packet loss",
  848.                 (int) (((ntransmitted - nreceived) * 100) /
  849.                 ntransmitted));
  850.     (void)putchar('\n');
  851.     if (nreceived && timing)
  852.         (void)printf("round-trip min/avg/max = %.3f/%.3f/%.3f ms\n",
  853.             tmin, tsum / (nreceived + nrepeats), tmax);
  854.     if (reset_kerninfo && tcgetattr(STDOUT_FILENO, &ts) != -1) {
  855.         ts.c_lflag &= ~NOKERNINFO;
  856.         tcsetattr(STDOUT_FILENO, TCSANOW, &ts);
  857.     }
  858.  
  859.     if (nreceived)
  860.         exit(0);
  861.     else
  862.         exit(2);
  863. }
  864.  
  865. #ifdef notdef
  866. static char *ttab[] = {
  867.     "Echo Reply",        /* ip + seq + udata */
  868.     "Dest Unreachable",    /* net, host, proto, port, frag, sr + IP */
  869.     "Source Quench",    /* IP */
  870.     "Redirect",        /* redirect type, gateway, + IP  */
  871.     "Echo",
  872.     "Time Exceeded",    /* transit, frag reassem + IP */
  873.     "Parameter Problem",    /* pointer + IP */
  874.     "Timestamp",        /* id + seq + three timestamps */
  875.     "Timestamp Reply",    /* " */
  876.     "Info Request",        /* id + sq */
  877.     "Info Reply"        /* " */
  878. };
  879. #endif
  880.  
  881. /*
  882.  * pr_icmph --
  883.  *    Print a descriptive string about an ICMP header.
  884.  */
  885. pr_icmph(icp)
  886.     struct icmp *icp;
  887. {
  888.     switch(icp->icmp_type) {
  889.     case ICMP_ECHOREPLY:
  890.         (void)printf("Echo Reply\n");
  891.         /* XXX ID + Seq + Data */
  892.         break;
  893.     case ICMP_UNREACH:
  894.         switch(icp->icmp_code) {
  895.         case ICMP_UNREACH_NET:
  896.             (void)printf("Destination Net Unreachable\n");
  897.             break;
  898.         case ICMP_UNREACH_HOST:
  899.             (void)printf("Destination Host Unreachable\n");
  900.             break;
  901.         case ICMP_UNREACH_PROTOCOL:
  902.             (void)printf("Destination Protocol Unreachable\n");
  903.             break;
  904.         case ICMP_UNREACH_PORT:
  905.             (void)printf("Destination Port Unreachable\n");
  906.             break;
  907.         case ICMP_UNREACH_NEEDFRAG:
  908.             (void)printf("frag needed and DF set (MTU %d)\n",
  909.                     icp->icmp_nextmtu);
  910.             break;
  911.         case ICMP_UNREACH_SRCFAIL:
  912.             (void)printf("Source Route Failed\n");
  913.             break;
  914.         case ICMP_UNREACH_FILTER_PROHIB:
  915.             (void)printf("Communication prohibited by filter\n");
  916.             break;
  917.         default:
  918.             (void)printf("Dest Unreachable, Bad Code: %d\n",
  919.                 icp->icmp_code);
  920.             break;
  921.         }
  922.         /* Print returned IP header information */
  923. #ifndef icmp_data
  924.         pr_retip(&icp->icmp_ip);
  925. #else
  926.         pr_retip((struct ip *)icp->icmp_data);
  927. #endif
  928.         break;
  929.     case ICMP_SOURCEQUENCH:
  930.         (void)printf("Source Quench\n");
  931. #ifndef icmp_data
  932.         pr_retip(&icp->icmp_ip);
  933. #else
  934.         pr_retip((struct ip *)icp->icmp_data);
  935. #endif
  936.         break;
  937.     case ICMP_REDIRECT:
  938.         switch(icp->icmp_code) {
  939.         case ICMP_REDIRECT_NET:
  940.             (void)printf("Redirect Network");
  941.             break;
  942.         case ICMP_REDIRECT_HOST:
  943.             (void)printf("Redirect Host");
  944.             break;
  945.         case ICMP_REDIRECT_TOSNET:
  946.             (void)printf("Redirect Type of Service and Network");
  947.             break;
  948.         case ICMP_REDIRECT_TOSHOST:
  949.             (void)printf("Redirect Type of Service and Host");
  950.             break;
  951.         default:
  952.             (void)printf("Redirect, Bad Code: %d", icp->icmp_code);
  953.             break;
  954.         }
  955.         (void)printf("(New addr: 0x%08lx)\n", icp->icmp_gwaddr.s_addr);
  956. #ifndef icmp_data
  957.         pr_retip(&icp->icmp_ip);
  958. #else
  959.         pr_retip((struct ip *)icp->icmp_data);
  960. #endif
  961.         break;
  962.     case ICMP_ECHO:
  963.         (void)printf("Echo Request\n");
  964.         /* XXX ID + Seq + Data */
  965.         break;
  966.     case ICMP_TIMXCEED:
  967.         switch(icp->icmp_code) {
  968.         case ICMP_TIMXCEED_INTRANS:
  969.             (void)printf("Time to live exceeded\n");
  970.             break;
  971.         case ICMP_TIMXCEED_REASS:
  972.             (void)printf("Frag reassembly time exceeded\n");
  973.             break;
  974.         default:
  975.             (void)printf("Time exceeded, Bad Code: %d\n",
  976.                 icp->icmp_code);
  977.             break;
  978.         }
  979. #ifndef icmp_data
  980.         pr_retip(&icp->icmp_ip);
  981. #else
  982.         pr_retip((struct ip *)icp->icmp_data);
  983. #endif
  984.         break;
  985.     case ICMP_PARAMPROB:
  986.         (void)printf("Parameter problem: pointer = 0x%02x\n",
  987.             icp->icmp_hun.ih_pptr);
  988. #ifndef icmp_data
  989.         pr_retip(&icp->icmp_ip);
  990. #else
  991.         pr_retip((struct ip *)icp->icmp_data);
  992. #endif
  993.         break;
  994.     case ICMP_TSTAMP:
  995.         (void)printf("Timestamp\n");
  996.         /* XXX ID + Seq + 3 timestamps */
  997.         break;
  998.     case ICMP_TSTAMPREPLY:
  999.         (void)printf("Timestamp Reply\n");
  1000.         /* XXX ID + Seq + 3 timestamps */
  1001.         break;
  1002.     case ICMP_IREQ:
  1003.         (void)printf("Information Request\n");
  1004.         /* XXX ID + Seq */
  1005.         break;
  1006.     case ICMP_IREQREPLY:
  1007.         (void)printf("Information Reply\n");
  1008.         /* XXX ID + Seq */
  1009.         break;
  1010.     case ICMP_MASKREQ:
  1011.         (void)printf("Address Mask Request\n");
  1012.         break;
  1013.     case ICMP_MASKREPLY:
  1014.         (void)printf("Address Mask Reply\n");
  1015.         break;
  1016.     case ICMP_ROUTERADVERT:
  1017.         (void)printf("Router Advertisement\n");
  1018.         break;
  1019.     case ICMP_ROUTERSOLICIT:
  1020.         (void)printf("Router Solicitation\n");
  1021.         break;
  1022.     default:
  1023.         (void)printf("Bad ICMP type: %d\n", icp->icmp_type);
  1024.     }
  1025. }
  1026.  
  1027. /*
  1028.  * pr_iph --
  1029.  *    Print an IP header with options.
  1030.  */
  1031. pr_iph(ip)
  1032.     struct ip *ip;
  1033. {
  1034.     int hlen;
  1035.     u_char *cp;
  1036.  
  1037.     hlen = ip->ip_hl << 2;
  1038.     cp = (u_char *)ip + 20;        /* point to options */
  1039.  
  1040.     (void)printf("Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst\n");
  1041.     (void)printf(" %1x  %1x  %02x %04x %04x",
  1042.         ip->ip_v, ip->ip_hl, ip->ip_tos, ntohs(ip->ip_len),
  1043.         ntohs(ip->ip_id));
  1044.     (void)printf("   %1x %04x", (ntohl(ip->ip_off) & 0xe000) >> 13,
  1045.         ntohl(ip->ip_off) & 0x1fff);
  1046.     (void)printf("  %02x  %02x %04x", ip->ip_ttl, ip->ip_p,
  1047.                                 ntohs(ip->ip_sum));
  1048.     (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
  1049.     (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
  1050.     /* dump any option bytes */
  1051.     while (hlen-- > 20) {
  1052.         (void)printf("%02x", *cp++);
  1053.     }
  1054.     (void)putchar('\n');
  1055. }
  1056.  
  1057. /*
  1058.  * pr_addr --
  1059.  *    Return an ascii host address as a dotted quad and optionally with
  1060.  * a hostname.
  1061.  */
  1062. char *
  1063. pr_addr(l)
  1064.     u_long l;
  1065. {
  1066.     struct hostent *hp;
  1067.     static char buf[80];
  1068.  
  1069.     if ((options & F_NUMERIC) ||
  1070.         !(hp = gethostbyaddr((char *)&l, 4, AF_INET)))
  1071.         (void)snprintf(buf, sizeof(buf), "%s",
  1072.             inet_ntoa(*(struct in_addr *)&l));
  1073.     else
  1074.         (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name,
  1075.             inet_ntoa(*(struct in_addr *)&l));
  1076.     return(buf);
  1077. }
  1078.  
  1079. /*
  1080.  * pr_retip --
  1081.  *    Dump some info on a returned (via ICMP) IP packet.
  1082.  */
  1083. pr_retip(ip)
  1084.     struct ip *ip;
  1085. {
  1086.     int hlen;
  1087.     u_char *cp;
  1088.  
  1089.     pr_iph(ip);
  1090.     hlen = ip->ip_hl << 2;
  1091.     cp = (u_char *)ip + hlen;
  1092.  
  1093.     if (ip->ip_p == 6)
  1094.         (void)printf("TCP: from port %u, to port %u (decimal)\n",
  1095.             (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
  1096.     else if (ip->ip_p == 17)
  1097.         (void)printf("UDP: from port %u, to port %u (decimal)\n",
  1098.             (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
  1099. }
  1100.  
  1101. fill(bp, patp)
  1102.     char *bp, *patp;
  1103. {
  1104.     register int ii, jj, kk;
  1105.     int pat[16];
  1106.     char *cp;
  1107.  
  1108.     for (cp = patp; *cp; cp++)
  1109.         if (!isxdigit(*cp)) {
  1110.             (void)fprintf(stderr,
  1111.                 "ping: patterns must be specified as hex digits.\n");
  1112.             exit(1);
  1113.         }
  1114.     ii = sscanf(patp,
  1115.         "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
  1116.         &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
  1117.         &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
  1118.         &pat[13], &pat[14], &pat[15]);
  1119.  
  1120.     if (ii > 0)
  1121.         for (kk = 0;
  1122.             kk <= MAXPACKET - (8 + sizeof(struct timeval) + ii);
  1123.             kk += ii)
  1124.             for (jj = 0; jj < ii; ++jj)
  1125.                 bp[jj + kk] = pat[jj];
  1126.     if (!(options & F_QUIET)) {
  1127.         (void)printf("PATTERN: 0x");
  1128.         for (jj = 0; jj < ii; ++jj)
  1129.             (void)printf("%02x", bp[jj] & 0xFF);
  1130.         (void)printf("\n");
  1131.     }
  1132. }
  1133.  
  1134. usage()
  1135. {
  1136.     (void)fprintf(stderr,
  1137.         "usage: ping [-LQRdfnqrv] [-c count] [-i wait] [-I interface]\n\t[-l preload] [-p pattern] [-s packetsize] [-T ttl] host\n");
  1138.     exit(1);
  1139. }
  1140.