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