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

Defined functions

catcher defined in line 379; used 4 times
fill defined in line 946; used 1 times
finish defined in line 689; used 4 times
in_cksum defined in line 638; used 1 times
main defined in line 140; never used
pinger defined in line 408; used 3 times
pr_addr defined in line 908; used 4 times
pr_icmph defined in line 739; used 1 times
pr_iph defined in line 879; used 1 times
pr_pack defined in line 452; used 1 times
pr_retip defined in line 928; used 10 times
tvsub defined in line 675; used 1 times
usage defined in line 979; used 2 times

Defined variables

BSPACE defined in line 119; used 1 times
DOT defined in line 120; used 1 times
copyright defined in line 38; never used
datalen defined in line 116; used 11 times
hostname defined in line 121; used 6 times
ident defined in line 122; used 3 times
interval defined in line 129; used 3 times
mx_dup_ck defined in line 112; used 3 times
npackets defined in line 125; used 6 times
nreceived defined in line 126; used 9 times
nrepeats defined in line 127; used 4 times
ntransmitted defined in line 128; used 7 times
options defined in line 95; used 27 times
outpack defined in line 118; used 5 times
rcvd_tbl defined in line 113; used 1 times
  • in line 88
s defined in line 117; used 9 times
sccsid defined in line 42; never used
timing defined in line 132; used 5 times
tmax defined in line 134; used 4 times
tmin defined in line 133; used 3 times
tsum defined in line 135; used 2 times
ttab defined in line 720; never used
whereto defined in line 115; used 3 times

Defined macros

A defined in line 88; used 3 times
B defined in line 89; used 3 times
CLR defined in line 91; used 1 times
DEFDATALEN defined in line 81; used 1 times
F_FLOOD defined in line 96; used 8 times
F_INTERVAL defined in line 97; used 2 times
F_NUMERIC defined in line 98; used 2 times
F_PINGFILLED defined in line 99; used 2 times
F_QUIET defined in line 100; used 4 times
F_RROUTE defined in line 101; used 2 times
F_SO_DEBUG defined in line 102; used 2 times
F_SO_DONTROUTE defined in line 103; used 2 times
F_VERBOSE defined in line 104; used 3 times
MAXICMPLEN defined in line 83; used 1 times
MAXIPLEN defined in line 82; used 1 times
MAXPACKET defined in line 84; used 3 times
MAXWAIT defined in line 85; used 1 times
MAX_DUP_CHK defined in line 111; used 2 times
NROUTES defined in line 86; used 1 times
SET defined in line 90; used 1 times
TST defined in line 92; used 1 times
Last modified: 1996-01-19
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 6583
Valid CSS Valid XHTML 1.0 Strict