home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-B.05 / NETKIT-B / NetKit-B-0.05 / ping / ping.c < prev   
Encoding:
C/C++ Source or Header  |  1994-05-23  |  25.8 KB  |  1,064 lines

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