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