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 /* 38 * P I N G . C 39 * 40 * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, 41 * measure round-trip-delays and packet loss across network paths. 42 * 43 * Author - 44 * Mike Muuss 45 * U. S. Army Ballistic Research Laboratory 46 * December, 1983 47 * 48 * Status - 49 * Public Domain. Distribution Unlimited. 50 * Bugs - 51 * More statistics could always be gathered. 52 * This program has to run SUID to ROOT to access the ICMP socket. 53 */ 54 55 #include <OS.h> 56 57 #include <sys/param.h> 58 #include <sys/socket.h> 59 #include <sys/time.h> 60 61 #include <netinet/in.h> 62 #include "netinet/ip.h" 63 #include "netinet/ip_icmp.h" 64 #include <netinet/ip_var.h> 65 #include <arpa/inet.h> 66 #include <netdb.h> 67 #include <signal.h> 68 #include <unistd.h> 69 #include <stdio.h> 70 #include <ctype.h> 71 #include <errno.h> 72 #include <string.h> 73 #include <stdlib.h> 74 #include <sys/select.h> 75 76 #define DEFDATALEN (64 - 8) /* default data length */ 77 #define MAXIPLEN 60 78 #define MAXICMPLEN 76 79 #define MAXPAYLOAD (IP_MAXPACKET - MAXIPLEN - 8) /* max ICMP payload size */ 80 #define MAXWAIT_DEFAULT 10 /* secs to wait for response */ 81 #define NROUTES 9 /* number of record route slots */ 82 83 #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ 84 #define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ 85 #define SET(bit) (A(bit) |= B(bit)) 86 #define CLR(bit) (A(bit) &= (~B(bit))) 87 #define TST(bit) (A(bit) & B(bit)) 88 89 /* various options */ 90 int options; 91 #define F_FLOOD 0x001 92 #define F_INTERVAL 0x002 93 #define F_NUMERIC 0x004 94 #define F_PINGFILLED 0x008 95 #define F_QUIET 0x010 96 #define F_RROUTE 0x020 97 #define F_SO_DEBUG 0x040 98 #define F_SO_DONTROUTE 0x080 99 #define F_VERBOSE 0x100 100 #define F_SADDR 0x200 101 #define F_HDRINCL 0x400 102 #define F_TTL 0x800 103 104 /* multicast options */ 105 int moptions; 106 #define MULTICAST_NOLOOP 0x001 107 #define MULTICAST_TTL 0x002 108 #define MULTICAST_IF 0x004 109 110 /* 111 * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum 112 * number of received sequence numbers we can keep track of. Change 128 113 * to 8192 for complete accuracy... 114 */ 115 #define MAX_DUP_CHK (8 * 128) 116 int mx_dup_ck = MAX_DUP_CHK; 117 char rcvd_tbl[MAX_DUP_CHK / 8]; 118 119 struct sockaddr whereto; /* who to ping */ 120 struct sockaddr_in whence; /* Which interface we come from */ 121 int datalen = DEFDATALEN; 122 int s; /* socket file descriptor */ 123 u_char outpackhdr[IP_MAXPACKET]; /* Max packet size = 65535 */ 124 u_char *outpack = outpackhdr+sizeof(struct ip); 125 char BSPACE = '\b'; /* characters written for flood */ 126 char DOT = '.'; 127 char *hostname; 128 int ident; /* process id to identify our packets */ 129 130 /* counters */ 131 long npackets; /* max packets to transmit */ 132 long nreceived; /* # of packets we got back */ 133 long nrepeats; /* number of duplicates */ 134 long ntransmitted; /* sequence # for outbound packets = #sent */ 135 double interval = 1; /* interval between packets */ 136 137 /* timing */ 138 int timing; /* flag to do timing */ 139 int maxwait = MAXWAIT_DEFAULT; /* max seconds to wait for response */ 140 uint64 tmin = 999999999; /* minimum round trip time in millisec */ 141 uint64 tmax = 0; /* maximum round trip time in millisec */ 142 uint64 tsum = 0; /* sum of all times in millisec, for doing average */ 143 uint64 tsumsq = 0; /* sum of all times squared, for std. dev. */ 144 145 #ifdef SIGINFO 146 int reset_kerninfo; 147 #endif 148 149 #define DEFAULT_BUFSPACE 60*1024 /* default read buffer size */ 150 int bufspace = DEFAULT_BUFSPACE; 151 152 void fill(char *, char *); 153 void catcher(int); 154 void prtsig(int); 155 void finish(int); 156 void summary(int); 157 int compute_in_cksum (u_short *, int); 158 void pinger(void); 159 char *pr_addr (in_addr_t); 160 int check_icmph (struct ip *); 161 void pr_icmph (struct icmp *); 162 void pr_pack (char *, int, struct sockaddr_in *); 163 void pr_retip (struct ip *); 164 void pr_iph(struct ip *ip); 165 uint64 qsqrt (uint64); 166 void usage(void); 167 168 169 static void err(int exitval, char *where) 170 { 171 printf("error: %s: error %d [%s]\n", where, errno, strerror(errno)); 172 exit(exitval); 173 } 174 175 static void errx(int exitval, char *fmt_string, char *value) 176 { 177 printf("error: "); 178 printf(fmt_string, value); 179 printf("\n"); 180 exit(exitval); 181 } 182 183 int main(int argc, char **argv) 184 { 185 struct timeval timeout; 186 struct hostent *hp; 187 struct sockaddr_in *to; 188 struct protoent *proto; 189 struct in_addr saddr; 190 int i; 191 int ch, hold = 1, packlen, preload; 192 int maxsize, fdmasks; 193 socklen_t maxsizelen; 194 u_char *datap, *packet; 195 char *target, hnamebuf[MAXHOSTNAMELEN]; 196 u_char ttl = MAXTTL, loop = 1, df = 0; 197 int tos = 0; 198 #ifdef IP_OPTIONS 199 char rspace[3 + 4 * NROUTES + 1]; /* record route space */ 200 #endif 201 fd_set *fdmaskp; 202 203 if (!(proto = getprotobyname("icmp"))) 204 err(1, "unknown protocol icmp"); 205 if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) 206 err(1, "socket"); 207 208 /* revoke privs */ 209 // seteuid(getuid()); 210 // setuid(getuid()); 211 212 preload = 0; 213 datap = &outpack[8 + sizeof(uint64)]; 214 while ((ch = getopt(argc, argv, "DI:LRS:c:dfh:i:l:np:qrs:T:t:vw:")) != -1) 215 switch(ch) { 216 case 'c': 217 npackets = strtol(optarg, NULL, 0); 218 if (npackets <= 0) 219 errx(1, "bad number of packets to transmit: %s", 220 optarg); 221 break; 222 case 'D': 223 options |= F_HDRINCL; 224 df = -1; 225 break; 226 case 'd': 227 options |= F_SO_DEBUG; 228 break; 229 case 'f': 230 if (getuid()) 231 errx(1, "%s", strerror(EPERM)); 232 options |= F_FLOOD; 233 setbuf(stdout, (char *)NULL); 234 break; 235 case 'I': 236 case 'S': /* deprecated */ 237 if (inet_aton(optarg, &saddr) == 0) { 238 if ((hp = gethostbyname(optarg)) == NULL) 239 errx(1, "bad interface address: %s", 240 optarg); 241 memcpy(&saddr, hp->h_addr, sizeof(saddr)); 242 } 243 options |= F_SADDR; 244 break; 245 case 'i': /* wait between sending packets */ 246 interval = strtod(optarg, NULL); 247 248 if (interval <= 0 || interval >= INT_MAX) 249 errx(1, "bad timing interval: %s", optarg); 250 251 if (interval < 1) 252 if (getuid()) 253 errx(1, "%s: only root may use interval < 1s", strerror(EPERM)); 254 255 if (interval < 0.01) 256 interval = 0.01; 257 258 options |= F_INTERVAL; 259 break; 260 case 'L': 261 moptions |= MULTICAST_NOLOOP; 262 loop = 0; 263 break; 264 case 'l': 265 if (getuid()) 266 errx(1, "%s", strerror(EPERM)); 267 preload = strtol(optarg, NULL, 0); 268 if (preload < 0) 269 errx(1, "bad preload value: %s", optarg); 270 break; 271 case 'n': 272 options |= F_NUMERIC; 273 break; 274 case 'p': /* fill buffer with user pattern */ 275 options |= F_PINGFILLED; 276 fill((char *)datap, optarg); 277 break; 278 case 'q': 279 options |= F_QUIET; 280 break; 281 case 'R': 282 options |= F_RROUTE; 283 break; 284 case 'r': 285 options |= F_SO_DONTROUTE; 286 break; 287 case 's': /* size of packet to send */ 288 datalen = strtol(optarg, NULL, 0); 289 if (datalen <= 0) 290 errx(1, "bad packet size: %s", optarg); 291 if (datalen > MAXPAYLOAD) 292 errx(1, "packet size too large: %s", optarg); 293 break; 294 case 'T': 295 options |= F_HDRINCL; 296 tos = strtoul(optarg, NULL, 0); 297 if (tos > 0xFF) 298 errx(1, "bad tos value: %s", optarg); 299 break; 300 case 't': 301 options |= F_TTL; 302 ttl = strtol(optarg, NULL, 0); 303 if (ttl <= 0) 304 errx(1, "bad ttl value: %s", optarg); 305 if (ttl > 255) 306 errx(1, "ttl value too large: %s", optarg); 307 break; 308 case 'v': 309 options |= F_VERBOSE; 310 break; 311 case 'w': 312 maxwait = strtol(optarg, NULL, 0); 313 if (maxwait <= 0) 314 errx(1, "bad maxwait value: %s", optarg); 315 break; 316 default: 317 usage(); 318 } 319 argc -= optind; 320 argv += optind; 321 322 if (argc != 1) 323 usage(); 324 325 target = *argv; 326 327 memset(&whereto, 0, sizeof(struct sockaddr)); 328 to = (struct sockaddr_in *)&whereto; 329 to->sin_len = sizeof(struct sockaddr_in); 330 to->sin_family = AF_INET; 331 if (inet_aton(target, &to->sin_addr) != 0) 332 hostname = target; 333 else { 334 hp = gethostbyname(target); 335 if (!hp) 336 errx(1, "unknown host: %s", target); 337 to->sin_family = hp->h_addrtype; 338 memcpy(&to->sin_addr, hp->h_addr, hp->h_length); 339 (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf)); 340 hostname = hnamebuf; 341 } 342 343 if (options & F_FLOOD && options & F_INTERVAL) 344 err(1, "-f and -i options are incompatible"); 345 346 if (datalen >= (int) sizeof(uint64)) /* can we time transfer */ 347 timing = 1; 348 packlen = datalen + MAXIPLEN + MAXICMPLEN; 349 if (!(packet = (u_char *)malloc((u_int)packlen))) 350 err(1, "malloc"); 351 if (!(options & F_PINGFILLED)) 352 for (i = sizeof(bigtime_t); i < datalen; ++i) 353 *datap++ = i; 354 355 ident = getpid() & 0xFFFF; 356 357 if (options & F_SADDR) { 358 if (IN_MULTICAST(ntohl(to->sin_addr.s_addr))) 359 moptions |= MULTICAST_IF; 360 else { 361 memset(&whence, 0, sizeof(whence)); 362 whence.sin_len = sizeof(whence); 363 whence.sin_family = AF_INET; 364 memcpy(&whence.sin_addr.s_addr, &saddr, sizeof(saddr)); 365 if (bind(s, (struct sockaddr*)&whence, 366 sizeof(whence)) < 0) 367 err(1, "bind"); 368 } 369 } 370 371 if (options & F_SO_DEBUG) 372 (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold, 373 sizeof(hold)); 374 if (options & F_SO_DONTROUTE) 375 (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, 376 sizeof(hold)); 377 378 if (options & F_TTL) { 379 if (IN_MULTICAST(ntohl(to->sin_addr.s_addr))) 380 moptions |= MULTICAST_TTL; 381 else 382 options |= F_HDRINCL; 383 } 384 385 if (options & F_RROUTE && options & F_HDRINCL) 386 err(1, "-R option and -D or -T, or -t to unicast destinations" 387 " are incompatible"); 388 389 if (options & F_HDRINCL) { 390 struct ip *ip = (struct ip*)outpackhdr; 391 392 setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold)); 393 ip->ip_v = IPVERSION; 394 ip->ip_hl = sizeof(struct ip) >> 2; 395 ip->ip_tos = tos; 396 ip->ip_id = 0; 397 ip->ip_off = htons(df?IP_DF:0); 398 ip->ip_ttl = ttl; 399 ip->ip_p = proto->p_proto; 400 ip->ip_src.s_addr = INADDR_ANY; 401 ip->ip_dst = to->sin_addr; 402 } 403 404 /* record route option */ 405 if (options & F_RROUTE) { 406 if (IN_MULTICAST(ntohl(to->sin_addr.s_addr))) 407 err(1, "record route not valid to multicast destinations"); 408 #ifdef IP_OPTIONS 409 rspace[IPOPT_OPTVAL] = IPOPT_RR; 410 rspace[IPOPT_OLEN] = sizeof(rspace)-1; 411 rspace[IPOPT_OFFSET] = IPOPT_MINOFF; 412 if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace, 413 sizeof(rspace)) < 0) { 414 perror("ping: record route"); 415 exit(1); 416 } 417 #else 418 err(1, "record route not available in this implementation"); 419 #endif /* IP_OPTIONS */ 420 } 421 422 if ((moptions & MULTICAST_NOLOOP) && 423 setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, 424 sizeof(loop)) < 0) 425 err(1, "setsockopt IP_MULTICAST_LOOP"); 426 if ((moptions & MULTICAST_TTL) && 427 setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, 428 sizeof(ttl)) < 0) 429 err(1, "setsockopt IP_MULTICAST_TTL"); 430 if ((moptions & MULTICAST_IF) && 431 setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &saddr, 432 sizeof(saddr)) < 0) 433 err(1, "setsockopt IP_MULTICAST_IF"); 434 435 /* 436 * When trying to send large packets, you must increase the 437 * size of both the send and receive buffers... 438 */ 439 maxsizelen = sizeof maxsize; 440 if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &maxsize, &maxsizelen) < 0) 441 err(1, "getsockopt"); 442 if (maxsize < packlen && 443 setsockopt(s, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(maxsize)) < 0) 444 err(1, "setsockopt"); 445 /* 446 * When pinging the broadcast address, you can get a lot of answers. 447 * Doing something so evil is useful if you are trying to stress the 448 * ethernet, or just want to fill the arp cache to get some stuff for 449 * /etc/ethers. 450 */ 451 while (setsockopt(s, SOL_SOCKET, SO_RCVBUF, 452 (void*)&bufspace, sizeof(bufspace)) < 0) { 453 if ((bufspace -= 1024) <= 0) 454 err(1, "Cannot set the receive buffer size"); 455 } 456 if (bufspace < DEFAULT_BUFSPACE) 457 printf("Could only allocate a receive buffer of %i bytes (default %i)\n", 458 bufspace, DEFAULT_BUFSPACE); 459 460 if (to->sin_family == AF_INET) 461 (void)printf("PING %s (%s): %d data bytes\n", hostname, 462 inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr), 463 datalen); 464 else 465 (void)printf("PING %s: %d data bytes\n", hostname, datalen); 466 467 (void)signal(SIGINT, finish); 468 (void)signal(SIGALRM, catcher); 469 #ifdef SIGINFO 470 (void)signal(SIGINFO, prtsig); 471 #endif 472 473 while (preload--) /* fire off them quickies */ 474 pinger(); 475 476 if ((options & F_FLOOD) == 0) 477 catcher(0); /* start things going */ 478 479 fdmasks = _howmany(s+1, NFDBITS) * sizeof(fd_mask); 480 if ((fdmaskp = (fd_set *)malloc(fdmasks)) == NULL) 481 err(1, "malloc"); 482 483 for (;;) { 484 struct sockaddr_in from; 485 int cc; 486 socklen_t fromlen; 487 sigset_t omask, nmask; 488 489 if (options & F_FLOOD) { 490 pinger(); 491 timeout.tv_sec = 0; 492 timeout.tv_usec = 10000; 493 memset(fdmaskp, 0, fdmasks); 494 FD_SET(s, fdmaskp); 495 if (select(s + 1, (fd_set *)fdmaskp, (fd_set *)NULL, 496 (fd_set *)NULL, &timeout) < 1) 497 continue; 498 } 499 fromlen = sizeof(from); 500 if ((cc = recvfrom(s, (char *)packet, packlen, 0, 501 (struct sockaddr *)&from, &fromlen)) < 0) { 502 if (errno == EINTR) 503 continue; 504 perror("ping: recvfrom"); 505 continue; 506 } 507 sigemptyset(&nmask); 508 sigaddset(&nmask, SIGALRM); 509 sigprocmask(SIG_BLOCK, &nmask, &omask); 510 pr_pack((char *)packet, cc, &from); 511 sigprocmask(SIG_SETMASK, &omask, NULL); 512 if (npackets && nreceived >= npackets) 513 break; 514 } 515 free(fdmaskp); 516 finish(0); 517 /* NOTREACHED */ 518 exit(0); /* Make the compiler happy */ 519 } 520 521 /* 522 * catcher -- 523 * This routine causes another PING to be transmitted, and then 524 * schedules another SIGALRM for 1 second from now. 525 * 526 * bug -- 527 * Our sense of time will slowly skew (i.e., packets will not be 528 * launched exactly at 1-second intervals). This does not affect the 529 * quality of the delay and loss statistics. 530 */ 531 void catcher(int sig) 532 { 533 int waittime; 534 int save_errno = errno; 535 536 pinger(); 537 (void)signal(SIGALRM, catcher); 538 539 if (!npackets || ntransmitted < npackets) 540 (void)alarm((uint)interval); 541 else { 542 if (nreceived) { 543 waittime = 2 * tmax / 1000000; 544 if (!waittime) 545 waittime = 1; 546 } else 547 waittime = maxwait; 548 (void)signal(SIGALRM, finish); 549 (void)alarm((uint)waittime); 550 } 551 errno = save_errno; 552 } 553 554 /* 555 * Print statistics when SIGINFO is received. 556 * XXX not race safe 557 */ 558 void prtsig(int sig) 559 { 560 int save_errno = errno; 561 562 summary(0); 563 errno = save_errno; 564 } 565 566 /* 567 * pinger -- 568 * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet 569 * will be added on by the kernel. The ID field is our UNIX process ID, 570 * and the sequence number is an ascending integer. The first 8 bytes 571 * of the data portion are used to hold a UNIX "timeval" struct in VAX 572 * byte-order, to compute the round-trip time. 573 */ 574 void pinger(void) 575 { 576 struct icmp *icp; 577 int cc; 578 int i; 579 char *packet = outpack; 580 581 icp = (struct icmp *)outpack; 582 icp->icmp_type = ICMP_ECHO; 583 icp->icmp_code = 0; 584 icp->icmp_cksum = 0; 585 icp->icmp_seq = htons(ntransmitted++); 586 icp->icmp_id = ident; /* ID */ 587 588 CLR(ntohs(icp->icmp_seq) % mx_dup_ck); 589 590 if (timing) { 591 bigtime_t tm = real_time_clock_usecs(); 592 memcpy(&outpack[8], &tm, sizeof(tm)); 593 } 594 595 cc = datalen + 8; /* skips ICMP portion */ 596 597 /* compute ICMP checksum here */ 598 icp->icmp_cksum = compute_in_cksum((u_short *)icp, cc); 599 600 if (options & F_HDRINCL) { 601 struct ip *ip = (struct ip*)outpackhdr; 602 603 packet = (char*)ip; 604 cc += sizeof(struct ip); 605 ip->ip_len = htons(cc); 606 ip->ip_sum = compute_in_cksum((u_short *)outpackhdr, cc); 607 } 608 609 i = sendto(s, (char *)packet, cc, 0, &whereto, 610 sizeof(struct sockaddr)); 611 612 if (i < 0 || i != cc) { 613 if (i < 0) 614 perror("ping: sendto"); 615 (void)printf("ping: wrote %s %d chars, ret=%d\n", 616 hostname, cc, i); 617 } 618 if (!(options & F_QUIET) && options & F_FLOOD) 619 (void)write(STDOUT_FILENO, &DOT, 1); 620 } 621 622 /* 623 * pr_pack -- 624 * Print out the packet, if it came from us. This logic is necessary 625 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets 626 * which arrive ('tis only fair). This permits multiple copies of this 627 * program to be run without having intermingled output (or statistics!). 628 */ 629 void pr_pack(char *buf, int cc, struct sockaddr_in *from) 630 { 631 struct icmp *icp; 632 in_addr_t l; 633 u_int i, j; 634 u_char *cp, *dp; 635 static int old_rrlen; 636 static char old_rr[MAX_IPOPTLEN]; 637 struct ip *ip, *ip2; 638 // struct timeval tv, tp; 639 char *pkttime; 640 uint64 triptime = 0; 641 int hlen, hlen2, dupflag; 642 643 // (void)gettimeofday(&tv, (struct timezone *)NULL); 644 645 /* Check the IP header */ 646 ip = (struct ip *)buf; 647 hlen = ip->ip_hl << 2; 648 if (cc < hlen + ICMP_MINLEN) { 649 if (options & F_VERBOSE) 650 printf("packet too short (%d bytes) from %s\n", cc, 651 inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr)); 652 return; 653 } 654 655 /* Now the ICMP part */ 656 cc -= hlen; 657 icp = (struct icmp *)(buf + hlen); 658 if (icp->icmp_type == ICMP_ECHOREPLY) { 659 if (icp->icmp_id != ident) 660 return; /* 'Twas not our ECHO */ 661 ++nreceived; 662 if (timing) { 663 bigtime_t tvi; 664 665 #ifndef icmp_data 666 pkttime = (char *)&icp->icmp_ip; 667 #else 668 pkttime = (char *)icp->icmp_data; 669 #endif 670 memcpy(&tvi, pkttime, sizeof tvi); 671 triptime = real_time_clock_usecs() - tvi; 672 tsum += triptime; 673 tsumsq += triptime * triptime; 674 if (triptime < tmin) 675 tmin = triptime; 676 if (triptime > tmax) 677 tmax = triptime; 678 } 679 680 if (TST(ntohs(icp->icmp_seq) % mx_dup_ck)) { 681 ++nrepeats; 682 --nreceived; 683 dupflag = 1; 684 } else { 685 SET(ntohs(icp->icmp_seq) % mx_dup_ck); 686 dupflag = 0; 687 } 688 689 if (options & F_QUIET) 690 return; 691 692 if (options & F_FLOOD) 693 (void)write(STDOUT_FILENO, &BSPACE, 1); 694 else { 695 (void)printf("%d bytes from %s: icmp_seq=%u", cc, 696 inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr), 697 ntohs(icp->icmp_seq)); 698 (void)printf(" ttl=%d", ip->ip_ttl); 699 if (timing) 700 (void)printf(" time=%d.%03d ms", 701 (int)(triptime / 1000), 702 (int)(triptime % 1000)); 703 if (dupflag) 704 (void)printf(" (DUP!)"); 705 /* check the data */ 706 cp = (u_char*)&icp->icmp_data[sizeof(bigtime_t)]; 707 dp = &outpack[8 + sizeof(bigtime_t)]; 708 for (i = 8 + sizeof(bigtime_t); (int) i < datalen; 709 ++i, ++cp, ++dp) { 710 if (*cp != *dp) { 711 (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", 712 i, *dp, *cp); 713 cp = (u_char*)&icp->icmp_data[0]; 714 for (i = 8; (int) i < datalen; ++i, ++cp) { 715 if ((i % 32) == 8) 716 (void)printf("\n\t"); 717 (void)printf("%x ", *cp); 718 } 719 break; 720 } 721 } 722 } 723 } else { 724 /* We've got something other than an ECHOREPLY */ 725 if (!(options & F_VERBOSE)) 726 return; 727 ip2 = (struct ip *) (buf + hlen + sizeof (struct icmp)); 728 hlen2 = ip2->ip_hl << 2; 729 if (cc >= hlen2 + 8 && check_icmph((struct ip *)(icp + 730 sizeof (struct icmp))) != 1) 731 return; 732 (void)printf("%d bytes from %s: ", cc, 733 pr_addr(from->sin_addr.s_addr)); 734 pr_icmph(icp); 735 } 736 737 /* Display any IP options */ 738 cp = (u_char *)buf + sizeof(struct ip); 739 740 for (; hlen > (int)sizeof(struct ip); --hlen, ++cp) 741 switch (*cp) { 742 case IPOPT_EOL: 743 hlen = 0; 744 break; 745 case IPOPT_LSRR: 746 (void)printf("\nLSRR: "); 747 hlen -= 2; 748 j = *++cp; 749 ++cp; 750 i = 0; 751 if (j > IPOPT_MINOFF) { 752 for (;;) { 753 l = *++cp; 754 l = (l<<8) + *++cp; 755 l = (l<<8) + *++cp; 756 l = (l<<8) + *++cp; 757 if (l == 0) 758 (void)printf("\t0.0.0.0"); 759 else 760 (void)printf("\t%s", 761 pr_addr(ntohl(l))); 762 hlen -= 4; 763 j -= 4; 764 i += 4; 765 if (j <= IPOPT_MINOFF) 766 break; 767 if (i >= MAX_IPOPTLEN) { 768 (void)printf("\t(truncated route)"); 769 break; 770 } 771 (void)putchar('\n'); 772 } 773 } 774 break; 775 case IPOPT_RR: 776 j = *++cp; /* get length */ 777 i = *++cp; /* and pointer */ 778 hlen -= 2; 779 if (i > j) 780 i = j; 781 i -= IPOPT_MINOFF; 782 if (i <= 0) 783 continue; 784 if ((int) i == old_rrlen 785 && cp == (u_char *) buf + sizeof(struct ip) + 2 786 && !memcmp(cp, old_rr, i) 787 && !(options & F_FLOOD)) { 788 (void)printf("\t(same route)"); 789 i = ((i + 3) / 4) * 4; 790 hlen -= i; 791 cp += i; 792 break; 793 } 794 if (i < MAX_IPOPTLEN) { 795 old_rrlen = i; 796 memcpy(old_rr, cp, i); 797 } else 798 old_rrlen = 0; 799 800 (void)printf("\nRR: "); 801 j = 0; 802 for (;;) { 803 l = *++cp; 804 l = (l<<8) + *++cp; 805 l = (l<<8) + *++cp; 806 l = (l<<8) + *++cp; 807 if (l == 0) 808 (void)printf("\t0.0.0.0"); 809 else 810 (void)printf("\t%s", pr_addr(ntohl(l))); 811 hlen -= 4; 812 i -= 4; 813 j += 4; 814 if (i <= 0) 815 break; 816 if (j >= MAX_IPOPTLEN) { 817 (void)printf("\t(truncated route)"); 818 break; 819 } 820 (void)putchar('\n'); 821 } 822 break; 823 case IPOPT_NOP: 824 (void)printf("\nNOP"); 825 break; 826 default: 827 (void)printf("\nunknown option %x", *cp); 828 hlen = hlen + cp[1] - 1; 829 cp = cp + cp[1] - 1; 830 break; 831 } 832 if (!(options & F_FLOOD)) { 833 (void)putchar('\n'); 834 (void)fflush(stdout); 835 } 836 } 837 838 /* 839 * compute_in_cksum -- 840 * Checksum routine for Internet Protocol family headers (C Version) 841 */ 842 int 843 compute_in_cksum(addr, len) 844 u_short *addr; 845 int len; 846 { 847 int nleft = len; 848 u_short *w = addr; 849 int sum = 0; 850 u_short answer = 0; 851 852 /* 853 * Our algorithm is simple, using a 32 bit accumulator (sum), we add 854 * sequential 16 bit words to it, and at the end, fold back all the 855 * carry bits from the top 16 bits into the lower 16 bits. 856 */ 857 while (nleft > 1) { 858 sum += *w++; 859 nleft -= 2; 860 } 861 862 /* mop up an odd byte, if necessary */ 863 if (nleft == 1) { 864 *(u_char *)(&answer) = *(u_char *)w ; 865 sum += answer; 866 } 867 868 /* add back carry outs from top 16 bits to low 16 bits */ 869 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 870 sum += (sum >> 16); /* add carry */ 871 answer = ~sum; /* truncate to 16 bits */ 872 return(answer); 873 } 874 875 void summary(int header) 876 { 877 (void)putchar('\r'); 878 (void)fflush(stdout); 879 880 if (header) 881 (void)printf("--- %s ping statistics ---\n", hostname); 882 883 (void)printf("%ld packets transmitted, ", ntransmitted); 884 (void)printf("%ld packets received, ", nreceived); 885 if (nrepeats) 886 (void)printf("%ld duplicates, ", nrepeats); 887 if (ntransmitted) { 888 if (nreceived > ntransmitted) 889 (void)printf("-- somebody's printing up packets!"); 890 else 891 (void)printf("%d%% packet loss", 892 (int) (((ntransmitted - nreceived) * 100) / 893 ntransmitted)); 894 } 895 (void)putchar('\n'); 896 if (nreceived && timing) { 897 uint64 num = nreceived + nrepeats; 898 uint64 avg = tsum / num; 899 uint64 dev = qsqrt(tsumsq / num - avg * avg); 900 (void)printf("round-trip min/avg/max/std-dev = " 901 "%d.%03d/%d.%03d/%d.%03d/%d.%03d ms\n", 902 (int)(tmin / 1000), (int)(tmin % 1000), 903 (int)(avg / 1000), (int)(avg % 1000), 904 (int)(tmax / 1000), (int)(tmax % 1000), 905 (int)(dev / 1000), (int)(dev % 1000)); 906 } 907 } 908 909 uint64 qsqrt(uint64 qdev) 910 { 911 int64 y, x = 1; 912 913 if (!qdev) 914 return(0); 915 916 do { /* newton was a stinker */ 917 y = x; 918 x = qdev / x; 919 x += y; 920 x /= 2; 921 } while ((x - y) > 1 || (x - y) < -1); 922 923 return (uint64) x; 924 } 925 926 /* 927 * finish -- 928 * Print out statistics, and give up. 929 */ 930 void finish(int sig) 931 { 932 (void)signal(SIGINT, SIG_IGN); 933 (void)signal(SIGALRM, SIG_IGN); 934 935 summary(1); 936 exit(nreceived ? 0 : 1); 937 } 938 939 #ifdef notdef 940 static char *ttab[] = { 941 "Echo Reply", /* ip + seq + udata */ 942 "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */ 943 "Source Quench", /* IP */ 944 "Redirect", /* redirect type, gateway, + IP */ 945 "Echo", 946 "Time Exceeded", /* transit, frag reassem + IP */ 947 "Parameter Problem", /* pointer + IP */ 948 "Timestamp", /* id + seq + three timestamps */ 949 "Timestamp Reply", /* " */ 950 "Info Request", /* id + sq */ 951 "Info Reply" /* " */ 952 }; 953 #endif 954 955 /* 956 * pr_icmph -- 957 * Print a descriptive string about an ICMP header. 958 */ 959 void 960 pr_icmph(icp) 961 struct icmp *icp; 962 { 963 switch(icp->icmp_type) { 964 case ICMP_ECHOREPLY: 965 (void)printf("Echo Reply\n"); 966 /* XXX ID + Seq + Data */ 967 break; 968 case ICMP_UNREACH: 969 switch(icp->icmp_code) { 970 case ICMP_UNREACH_NET: 971 (void)printf("Destination Net Unreachable\n"); 972 break; 973 case ICMP_UNREACH_HOST: 974 (void)printf("Destination Host Unreachable\n"); 975 break; 976 case ICMP_UNREACH_PROTOCOL: 977 (void)printf("Destination Protocol Unreachable\n"); 978 break; 979 case ICMP_UNREACH_PORT: 980 (void)printf("Destination Port Unreachable\n"); 981 break; 982 case ICMP_UNREACH_NEEDFRAG: 983 if (icp->icmp_nextmtu != 0) 984 (void)printf("frag needed and DF set (MTU %d)\n", 985 ntohs(icp->icmp_nextmtu)); 986 else 987 (void)printf("frag needed and DF set\n"); 988 break; 989 case ICMP_UNREACH_SRCFAIL: 990 (void)printf("Source Route Failed\n"); 991 break; 992 case ICMP_UNREACH_NET_UNKNOWN: 993 (void)printf("Network Unknown\n"); 994 break; 995 case ICMP_UNREACH_HOST_UNKNOWN: 996 (void)printf("Host Unknown\n"); 997 break; 998 case ICMP_UNREACH_ISOLATED: 999 (void)printf("Source Isolated\n"); 1000 break; 1001 case ICMP_UNREACH_NET_PROHIB: 1002 (void)printf("Dest. Net Administratively Prohibited\n"); 1003 break; 1004 case ICMP_UNREACH_HOST_PROHIB: 1005 (void)printf("Dest. Host Administratively Prohibited\n"); 1006 break; 1007 case ICMP_UNREACH_TOSNET: 1008 (void)printf("Destination Net Unreachable for TOS\n"); 1009 break; 1010 case ICMP_UNREACH_TOSHOST: 1011 (void)printf("Desination Host Unreachable for TOS\n"); 1012 break; 1013 case ICMP_UNREACH_FILTER_PROHIB: 1014 (void)printf("Route administratively prohibited\n"); 1015 break; 1016 case ICMP_UNREACH_HOST_PRECEDENCE: 1017 (void)printf("Host Precedence Violation\n"); 1018 break; 1019 case ICMP_UNREACH_PRECEDENCE_CUTOFF: 1020 (void)printf("Precedence Cutoff\n"); 1021 break; 1022 default: 1023 (void)printf("Dest Unreachable, Unknown Code: %d\n", 1024 icp->icmp_code); 1025 break; 1026 } 1027 /* Print returned IP header information */ 1028 #ifndef icmp_data 1029 pr_retip(&icp->icmp_ip); 1030 #else 1031 pr_retip((struct ip *)icp->icmp_data); 1032 #endif 1033 break; 1034 case ICMP_SOURCEQUENCH: 1035 (void)printf("Source Quench\n"); 1036 #ifndef icmp_data 1037 pr_retip(&icp->icmp_ip); 1038 #else 1039 pr_retip((struct ip *)icp->icmp_data); 1040 #endif 1041 break; 1042 case ICMP_REDIRECT: 1043 switch(icp->icmp_code) { 1044 case ICMP_REDIRECT_NET: 1045 (void)printf("Redirect Network"); 1046 break; 1047 case ICMP_REDIRECT_HOST: 1048 (void)printf("Redirect Host"); 1049 break; 1050 case ICMP_REDIRECT_TOSNET: 1051 (void)printf("Redirect Type of Service and Network"); 1052 break; 1053 case ICMP_REDIRECT_TOSHOST: 1054 (void)printf("Redirect Type of Service and Host"); 1055 break; 1056 default: 1057 (void)printf("Redirect, Unknown Code: %d", icp->icmp_code); 1058 break; 1059 } 1060 (void)printf("(New addr: %s)\n", 1061 inet_ntoa(icp->icmp_gwaddr)); 1062 #ifndef icmp_data 1063 pr_retip(&icp->icmp_ip); 1064 #else 1065 pr_retip((struct ip *)icp->icmp_data); 1066 #endif 1067 break; 1068 case ICMP_ECHO: 1069 (void)printf("Echo Request\n"); 1070 /* XXX ID + Seq + Data */ 1071 break; 1072 // case ICMP_ROUTERADVERT: 1073 /* RFC1256 */ 1074 /* 1075 (void)printf("Router Discovery Advertisement\n"); 1076 (void)printf("(%d entries, lifetime %d seconds)\n", 1077 icp->icmp_num_addrs, ntohs(icp->icmp_lifetime)); 1078 break; 1079 */ 1080 // case ICMP_ROUTERSOLICIT: 1081 /* RFC1256 */ 1082 /* (void)printf("Router Discovery Solicitation\n"); 1083 break; 1084 */ 1085 case ICMP_TIMXCEED: 1086 switch(icp->icmp_code) { 1087 case ICMP_TIMXCEED_INTRANS: 1088 (void)printf("Time to live exceeded\n"); 1089 break; 1090 case ICMP_TIMXCEED_REASS: 1091 (void)printf("Frag reassembly time exceeded\n"); 1092 break; 1093 default: 1094 (void)printf("Time exceeded, Unknown Code: %d\n", 1095 icp->icmp_code); 1096 break; 1097 } 1098 #ifndef icmp_data 1099 pr_retip(&icp->icmp_ip); 1100 #else 1101 pr_retip((struct ip *)icp->icmp_data); 1102 #endif 1103 break; 1104 case ICMP_PARAMPROB: 1105 switch(icp->icmp_code) { 1106 case ICMP_PARAMPROB_OPTABSENT: 1107 (void)printf( 1108 "Parameter problem, required option absent: pointer = 0x%02x\n", 1109 ntohs(icp->icmp_hun.ih_pptr)); 1110 break; 1111 default: 1112 (void)printf("Parameter problem: pointer = 0x%02x\n", 1113 ntohs(icp->icmp_hun.ih_pptr)); 1114 break; 1115 } 1116 #ifndef icmp_data 1117 pr_retip(&icp->icmp_ip); 1118 #else 1119 pr_retip((struct ip *)icp->icmp_data); 1120 #endif 1121 break; 1122 case ICMP_TSTAMP: 1123 (void)printf("Timestamp\n"); 1124 /* XXX ID + Seq + 3 timestamps */ 1125 break; 1126 case ICMP_TSTAMPREPLY: 1127 (void)printf("Timestamp Reply\n"); 1128 /* XXX ID + Seq + 3 timestamps */ 1129 break; 1130 case ICMP_IREQ: 1131 (void)printf("Information Request\n"); 1132 /* XXX ID + Seq */ 1133 break; 1134 case ICMP_IREQREPLY: 1135 (void)printf("Information Reply\n"); 1136 /* XXX ID + Seq */ 1137 break; 1138 #ifdef ICMP_MASKREQ 1139 case ICMP_MASKREQ: 1140 (void)printf("Address Mask Request\n"); 1141 break; 1142 #endif 1143 #ifdef ICMP_MASKREPLY 1144 case ICMP_MASKREPLY: 1145 (void)printf("Address Mask Reply (Mask 0x%08ld)\n", 1146 (long)ntohl(icp->icmp_mask)); 1147 break; 1148 #endif 1149 default: 1150 (void)printf("Unknown ICMP type: %u\n", icp->icmp_type); 1151 } 1152 } 1153 1154 /* 1155 * pr_iph -- 1156 * Print an IP header with options. 1157 */ 1158 void pr_iph(struct ip *ip) 1159 { 1160 int hlen; 1161 u_char *cp; 1162 1163 hlen = ip->ip_hl << 2; 1164 cp = (u_char *)ip + 20; /* point to options */ 1165 1166 (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n"); 1167 (void)printf(" %1x %1x %02x %04x %04x", 1168 ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id); 1169 (void)printf(" %1x %04x", ((ip->ip_off) & 0xe000) >> 13, 1170 (ip->ip_off) & 0x1fff); 1171 (void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum); 1172 (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr)); 1173 (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr)); 1174 /* dump and option bytes */ 1175 while (hlen-- > 20) { 1176 (void)printf("%02x", *cp++); 1177 } 1178 (void)putchar('\n'); 1179 } 1180 1181 /* 1182 * pr_addr -- 1183 * Return an ascii host address as a dotted quad and optionally with 1184 * a hostname. 1185 */ 1186 char * 1187 pr_addr(a) 1188 in_addr_t a; 1189 { 1190 struct hostent *hp; 1191 struct in_addr in; 1192 static char buf[16+3+MAXHOSTNAMELEN]; 1193 1194 in.s_addr = a; 1195 if ((options & F_NUMERIC) || 1196 !(hp = gethostbyaddr((char *)&in.s_addr, sizeof(in.s_addr), AF_INET))) 1197 (void)snprintf(buf, sizeof buf, "%s", inet_ntoa(in)); 1198 else 1199 (void)snprintf(buf, sizeof buf, "%s (%s)", hp->h_name, 1200 inet_ntoa(in)); 1201 return(buf); 1202 } 1203 1204 /* 1205 * pr_retip -- 1206 * Dump some info on a returned (via ICMP) IP packet. 1207 */ 1208 void pr_retip(struct ip *ip) 1209 { 1210 int hlen; 1211 u_char *cp; 1212 1213 pr_iph(ip); 1214 hlen = ip->ip_hl << 2; 1215 cp = (u_char *)ip + hlen; 1216 1217 if (ip->ip_p == 6) 1218 (void)printf("TCP: from port %u, to port %u (decimal)\n", 1219 (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); 1220 else if (ip->ip_p == 17) 1221 (void)printf("UDP: from port %u, to port %u (decimal)\n", 1222 (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); 1223 } 1224 1225 void 1226 fill(bp, patp) 1227 char *bp, *patp; 1228 { 1229 int ii, jj, kk; 1230 int pat[16]; 1231 char *cp; 1232 1233 for (cp = patp; *cp; cp++) 1234 if (!isxdigit(*cp)) 1235 err(1, "patterns must be specified as hex digits"); 1236 ii = sscanf(patp, 1237 "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", 1238 &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], 1239 &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], 1240 &pat[13], &pat[14], &pat[15]); 1241 1242 if (ii > 0) 1243 for (kk = 0; 1244 kk <= (int) (MAXPAYLOAD - (8 + sizeof(uint64) + ii)); 1245 kk += ii) 1246 for (jj = 0; jj < ii; ++jj) 1247 bp[jj + kk] = pat[jj]; 1248 if (!(options & F_QUIET)) { 1249 (void)printf("PATTERN: 0x"); 1250 for (jj = 0; jj < ii; ++jj) 1251 (void)printf("%02x", bp[jj] & 0xFF); 1252 (void)printf("\n"); 1253 } 1254 } 1255 1256 /* 1257 * when we get types of ICMP message with parts of the orig. datagram 1258 * we want to try to assure ourselves that it is from this instance 1259 * of ping, and not say, a refused finger connection or something 1260 */ 1261 int 1262 check_icmph(iph) 1263 struct ip *iph; 1264 { 1265 struct icmp *icmph; 1266 1267 /* only allow IP version 4 */ 1268 if (iph->ip_v != 4) 1269 return 0; 1270 1271 /* Only allow ICMP */ 1272 if (iph->ip_p != IPPROTO_ICMP) 1273 return 0; 1274 1275 icmph = (struct icmp *) (iph + (4 * iph->ip_hl)); 1276 1277 /* make sure it is in response to an ECHO request */ 1278 if (icmph->icmp_type != 8) 1279 return 0; 1280 1281 /* ok, make sure it has the right id on it */ 1282 if (icmph->icmp_hun.ih_idseq.icd_id != ident) 1283 return 0; 1284 1285 return 1; 1286 } 1287 1288 void 1289 usage() 1290 { 1291 extern const char *__progname; 1292 1293 (void)fprintf(stderr, 1294 "usage: %s [-DdfLnqRrv] [-c count] [-I ifaddr] [-i wait]\n" 1295 "\t[-l preload] [-p pattern] [-s packetsize] [-t ttl]" 1296 " [-w maxwait] host\n", __progname); 1297 exit(1); 1298 } 1299