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