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