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