1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Portions of this source code were derived from Berkeley 4.3 BSD 32 * under license from the Regents of the University of California. 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 #include <stdio.h> 38 #include <string.h> 39 #include <strings.h> 40 #include <errno.h> 41 #include <fcntl.h> 42 #include <unistd.h> 43 #include <signal.h> 44 45 #include <sys/time.h> 46 #include <sys/param.h> 47 #include <sys/socket.h> 48 #include <sys/sockio.h> 49 #include <sys/stropts.h> 50 #include <sys/file.h> 51 #include <arpa/inet.h> 52 #include <net/if.h> 53 #include <netinet/in_systm.h> 54 #include <netinet/in.h> 55 #include <netinet/ip.h> 56 #include <netinet/ip_icmp.h> 57 #include <netinet/udp.h> 58 #include <netdb.h> 59 #include <stdlib.h> 60 61 #include <libinetutil.h> 62 #include "ping.h" 63 64 65 /* 66 * IPv4 source routing option. 67 * In order to avoid padding for the alignment of IPv4 addresses, ipsr_addrs 68 * is defined as a 2-D array of uint8_t, instead of 1-D array of struct in_addr. 69 */ 70 struct ip_sourceroute { 71 uint8_t ipsr_code; 72 uint8_t ipsr_len; 73 uint8_t ipsr_ptr; 74 /* up to 9 IPv4 addresses */ 75 uint8_t ipsr_addrs[1][sizeof (struct in_addr)]; 76 }; 77 78 void check_reply(struct addrinfo *, struct msghdr *, int, ushort_t); 79 extern void find_dstaddr(ushort_t, union any_in_addr *); 80 extern boolean_t is_a_target(struct addrinfo *, union any_in_addr *); 81 extern char *pr_name(char *, int); 82 static void pr_options(uchar_t *, int); 83 extern char *pr_protocol(int); 84 static void pr_rropt(uchar_t *, int, boolean_t); 85 static void pr_tsopt(uchar_t *, int); 86 static char *pr_type(int); 87 extern void schedule_sigalrm(); 88 extern void send_scheduled_probe(); 89 extern boolean_t seq_match(ushort_t, int, ushort_t); 90 extern void sigalrm_handler(); 91 void set_IPv4_options(int, union any_in_addr *, int, struct in_addr *, 92 struct in_addr *); 93 extern void tvsub(struct timeval *, struct timeval *); 94 95 /* 96 * Set IPv4 options 97 */ 98 void 99 set_IPv4_options(int sock, union any_in_addr *gw_IP_list, int gw_count, 100 struct in_addr *src, struct in_addr *dst) 101 { 102 int req_size; 103 char srr[ROUTE_SIZE + 1]; 104 char *bufp; 105 int optsize = ROUTE_SIZE; 106 struct ip_sourceroute *srp; 107 struct ip_timestamp *tsp; 108 int i; 109 110 if (rr_option || ts_option || gw_count > 0) { 111 bzero(srr, sizeof (srr)); 112 bufp = srr; 113 114 if (gw_count > 0) { 115 /* 3 = 1 (code) + 1 (len) + 1 (ptr) of src route opt. */ 116 req_size = 3 + (sizeof (struct in_addr)) * gw_count; 117 118 if (optsize < req_size) { 119 Fprintf(stderr, "%s: too many IPv4 gateways\n", 120 progname); 121 exit(EXIT_FAILURE); 122 } 123 124 srp = (struct ip_sourceroute *)bufp; 125 srp->ipsr_code = strict ? IPOPT_SSRR : IPOPT_LSRR; 126 srp->ipsr_len = req_size; 127 srp->ipsr_ptr = IPOPT_MINOFF; 128 129 for (i = 0; i < gw_count; i++) { 130 bcopy((char *)&gw_IP_list[i].addr, 131 &srp->ipsr_addrs[i], 132 sizeof (struct in_addr)); 133 } 134 optsize -= srp->ipsr_len; 135 bufp += srp->ipsr_len; 136 } 137 /* do we send a timestamp option? */ 138 if (ts_option) { 139 if (optsize < IPOPT_MINOFF) { 140 Fprintf(stderr, 141 "%s: no room for timestamp option\n", 142 progname); 143 exit(EXIT_FAILURE); 144 } 145 /* LINTED */ 146 tsp = (struct ip_timestamp *)bufp; 147 tsp->ipt_code = IPOPT_TS; 148 tsp->ipt_len = optsize; 149 tsp->ipt_ptr = IPOPT_MINOFF + 1; 150 tsp->ipt_flg = ts_flag & 0x0f; 151 152 if (tsp->ipt_flg > IPOPT_TS_TSANDADDR) { 153 req_size = IPOPT_MINOFF + 154 2 * sizeof (struct ipt_ta); 155 /* 156 * Note: BSD/4.X is broken in their check so we 157 * have to bump up this number by at least one. 158 */ 159 req_size++; 160 161 if (optsize < req_size) { 162 Fprintf(stderr, "%s: no room for " 163 "timestamp option\n", progname); 164 exit(EXIT_FAILURE); 165 } 166 167 bcopy((char *)dst, 168 &tsp->ipt_timestamp.ipt_ta[0].ipt_addr, 169 sizeof (struct in_addr)); 170 171 bcopy((char *)src, 172 &tsp->ipt_timestamp.ipt_ta[1].ipt_addr, 173 sizeof (struct in_addr)); 174 tsp->ipt_len = req_size; 175 176 } 177 optsize -= tsp->ipt_len; 178 bufp += tsp->ipt_len; 179 } 180 /* do we send a record route option? */ 181 if (rr_option) { 182 if (optsize < IPOPT_MINOFF) { 183 Fprintf(stderr, 184 "%s: no room for record route option\n", 185 progname); 186 exit(EXIT_FAILURE); 187 188 } 189 /* 190 * Format of record route option is same as source 191 * route option. 192 */ 193 srp = (struct ip_sourceroute *)bufp; 194 srp->ipsr_code = IPOPT_RR; 195 srp->ipsr_len = optsize; 196 srp->ipsr_ptr = IPOPT_MINOFF; 197 198 optsize -= srp->ipsr_len; 199 bufp += srp->ipsr_len; 200 } 201 optsize = bufp - srr; 202 /* Round up to 4 byte boundary */ 203 if (optsize & 0x3) 204 optsize = (optsize & ~0x3) + 4; 205 if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, srr, optsize) < 206 0) { 207 Fprintf(stderr, "%s: setsockopt IP_OPTIONS %s\n", 208 progname, strerror(errno)); 209 exit(EXIT_FAILURE); 210 } 211 } 212 } 213 214 /* 215 * Check out the packet to see if it came from us. This logic is necessary 216 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets 217 * which arrive ('tis only fair). This permits multiple copies of this 218 * program to be run without having intermingled output (or statistics!). 219 */ 220 void 221 check_reply(struct addrinfo *ai_dst, struct msghdr *msg, int cc, 222 ushort_t udp_src_port) 223 { 224 struct ip *ip; 225 struct icmp *icp; 226 struct udphdr *up; 227 union any_in_addr dst_addr; 228 uchar_t *buf; 229 int32_t *intp; 230 struct sockaddr_in *from; 231 struct timeval *tp; 232 struct timeval tv; 233 int hlen, hlen1; 234 int64_t triptime; 235 boolean_t valid_reply = _B_FALSE; 236 boolean_t reply_matched_current_target; /* Is the source address of */ 237 /* this reply same as where */ 238 /* we're sending currently? */ 239 boolean_t last_reply_from_targetaddr = _B_FALSE; /* Is this stats, */ 240 /* probe all with npackets>0 */ 241 /* and we received reply for */ 242 /* the last probe sent to */ 243 /* targetaddr */ 244 int cc_left; 245 char tmp_buf[INET6_ADDRSTRLEN]; 246 static char *unreach[] = { 247 "Net Unreachable", 248 "Host Unreachable", 249 "Protocol Unreachable", 250 "Port Unreachable", 251 "Fragmentation needed and DF set", 252 "Source Route Failed", 253 /* The following are from RFC1700 */ 254 "Net Unknown", 255 "Host Unknown", 256 "Source Host Isolated", 257 "Dest Net Prohibited", 258 "Dest Host Prohibited", 259 "Net Unreachable for TOS", 260 "Host Unreachable for TOS", 261 "Communication Administratively Prohibited", 262 "Host Precedence Violation", 263 "Precedence Cutoff in Effect" 264 }; 265 static char *redirect[] = { 266 "Net", 267 "Host", 268 "TOS Net", 269 "TOS Host" 270 }; 271 static char *timexceed[] = { 272 "Time exceeded in transit", 273 "Time exceeded during reassembly" 274 }; 275 boolean_t print_newline = _B_FALSE; 276 int i; 277 278 /* decompose msghdr into useful pieces */ 279 buf = (uchar_t *)msg->msg_iov->iov_base; 280 from = (struct sockaddr_in *)msg->msg_name; 281 282 /* LINTED */ 283 intp = (int32_t *)buf; 284 285 (void) gettimeofday(&tv, (struct timezone *)NULL); 286 287 /* LINTED */ 288 ip = (struct ip *)buf; 289 hlen = ip->ip_hl << 2; 290 291 if ((cc < sizeof (struct ip)) || (cc < hlen + ICMP_MINLEN)) { 292 if (verbose) { 293 Printf("packet too short (%d bytes) from %s\n", cc, 294 pr_name((char *)&from->sin_addr, AF_INET)); 295 } 296 return; 297 } 298 299 cc -= hlen; 300 /* LINTED */ 301 icp = (struct icmp *)(buf + hlen); 302 303 if (ip->ip_p == 0) { 304 /* 305 * Assume that we are running on a pre-4.3BSD system 306 * such as SunOS before 4.0 307 */ 308 /* LINTED */ 309 icp = (struct icmp *)buf; 310 } 311 cc_left = cc - ICMP_MINLEN; 312 313 switch (icp->icmp_type) { 314 case ICMP_UNREACH: 315 ip = &icp->icmp_ip; 316 hlen1 = ip->ip_hl << 2; 317 318 /* check if we have enough of the packet to work on */ 319 if ((cc_left < sizeof (struct ip)) || 320 (cc_left < hlen1 + sizeof (struct udphdr))) { 321 if (verbose) { 322 Printf("packet too short (%d bytes) from %s\n", 323 cc, pr_name((char *)&from->sin_addr, 324 AF_INET)); 325 } 326 return; 327 } 328 329 /* get the UDP packet */ 330 cc_left -= hlen1 + sizeof (struct udphdr); 331 /* LINTED */ 332 up = (struct udphdr *)((uchar_t *)ip + hlen1); 333 334 /* check to see if this is what we sent */ 335 if (icp->icmp_code == ICMP_UNREACH_PORT && 336 ip->ip_p == IPPROTO_UDP && 337 udp_src_port == up->uh_sport && 338 use_udp) { 339 valid_reply = _B_TRUE; 340 } else { 341 valid_reply = _B_FALSE; 342 } 343 344 if (valid_reply) { 345 /* 346 * For this valid reply, if we are still sending to 347 * this target IP address, we'd like to do some 348 * updates to targetaddr, so hold SIGALRMs. 349 */ 350 (void) sighold(SIGALRM); 351 is_alive = _B_TRUE; 352 nreceived++; 353 reply_matched_current_target = 354 seq_match(current_targetaddr->starting_seq_num, 355 current_targetaddr->num_sent, 356 ntohs(up->uh_dport)); 357 if (reply_matched_current_target) { 358 current_targetaddr->got_reply = _B_TRUE; 359 nreceived_last_target++; 360 /* 361 * Determine if stats, probe-all, and 362 * npackets != 0, and this is the reply for 363 * the last probe we sent to current target 364 * address. 365 */ 366 if (stats && probe_all && npackets > 0 && 367 ((current_targetaddr->starting_seq_num + 368 current_targetaddr->num_probes - 1) % 369 (MAX_PORT + 1) == ntohs(up->uh_dport)) && 370 (current_targetaddr->num_probes == 371 current_targetaddr->num_sent)) 372 last_reply_from_targetaddr = _B_TRUE; 373 } else { 374 /* 375 * If it's just probe_all and we just received 376 * a reply from a target address we were 377 * probing and had timed out (now we are probing 378 * some other target address), we ignore 379 * this reply. 380 */ 381 if (probe_all && !stats) { 382 valid_reply = _B_FALSE; 383 /* 384 * Only if it's verbose, we get a 385 * message regarding this reply, 386 * otherwise we are done here. 387 */ 388 if (!verbose) { 389 (void) sigrelse(SIGALRM); 390 return; 391 } 392 } 393 } 394 } 395 396 /* stats mode doesn't print 'alive' messages */ 397 if (valid_reply && !stats) { 398 /* 399 * if we are still sending to the same target address, 400 * then stop it, because we know it's alive. 401 */ 402 if (reply_matched_current_target) { 403 (void) alarm(0); /* cancel alarm */ 404 (void) sigset(SIGALRM, SIG_IGN); 405 current_targetaddr->probing_done = _B_TRUE; 406 } 407 (void) sigrelse(SIGALRM); 408 409 if (!probe_all) { 410 Printf("%s is alive\n", targethost); 411 } else { 412 (void) inet_ntop(AF_INET, (void *)&ip->ip_dst, 413 tmp_buf, sizeof (tmp_buf)); 414 415 if (nflag) { 416 Printf("%s is alive\n", tmp_buf); 417 } else { 418 Printf("%s (%s) is alive\n", 419 targethost, tmp_buf); 420 } 421 } 422 if (reply_matched_current_target) { 423 /* 424 * Let's get things going again, but now 425 * ping will start sending to next target IP 426 * address. 427 */ 428 send_scheduled_probe(); 429 (void) sigset(SIGALRM, sigalrm_handler); 430 schedule_sigalrm(); 431 } 432 return; 433 } else { 434 /* 435 * If we are not moving to next targetaddr, let's 436 * release the SIGALRM now. We don't want to stall in 437 * the middle of probing a targetaddr if the pr_name() 438 * call (see below) takes longer. 439 */ 440 if (!last_reply_from_targetaddr) 441 (void) sigrelse(SIGALRM); 442 /* else, we'll release it later */ 443 } 444 445 dst_addr.addr = ip->ip_dst; 446 if (valid_reply) { 447 Printf("%d bytes from %s: ", cc, 448 pr_name((char *)&from->sin_addr, AF_INET)); 449 Printf("udp_port=%d. ", ntohs(up->uh_dport)); 450 print_newline = _B_TRUE; 451 } else if (is_a_target(ai_dst, &dst_addr) || verbose) { 452 if (icp->icmp_code >= A_CNT(unreach)) { 453 Printf("ICMP %d Unreachable from gateway %s\n", 454 icp->icmp_code, 455 pr_name((char *)&from->sin_addr, AF_INET)); 456 } else { 457 Printf("ICMP %s from gateway %s\n", 458 unreach[icp->icmp_code], 459 pr_name((char *)&from->sin_addr, AF_INET)); 460 } 461 Printf(" for %s from %s", pr_protocol(ip->ip_p), 462 pr_name((char *)&ip->ip_src, AF_INET)); 463 Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET)); 464 if (ip->ip_p == IPPROTO_TCP || 465 ip->ip_p == IPPROTO_UDP) { 466 Printf(" port %d ", ntohs(up->uh_dport)); 467 } 468 print_newline = _B_TRUE; 469 } 470 471 /* if we are timing and the reply has a timeval */ 472 if (valid_reply && datalen >= sizeof (struct timeval) && 473 cc_left >= sizeof (struct timeval)) { 474 /* LINTED */ 475 tp = (struct timeval *)((char *)up + 476 sizeof (struct udphdr)); 477 (void) tvsub(&tv, tp); 478 triptime = (int64_t)tv.tv_sec * MICROSEC + tv.tv_usec; 479 Printf("time=" TIMEFORMAT " ms", triptime/1000.0); 480 tsum += triptime; 481 tsum2 += triptime*triptime; 482 if (triptime < tmin) 483 tmin = triptime; 484 if (triptime > tmax) 485 tmax = triptime; 486 print_newline = _B_TRUE; 487 } 488 if (print_newline) 489 (void) putchar('\n'); 490 /* 491 * If it's stats, probe-all, npackets > 0, and we received reply 492 * for the last probe sent to this target address, then we 493 * don't need to wait anymore, let's move on to next target 494 * address, now! 495 */ 496 if (last_reply_from_targetaddr) { 497 (void) alarm(0); /* cancel alarm */ 498 current_targetaddr->probing_done = _B_TRUE; 499 (void) sigrelse(SIGALRM); 500 send_scheduled_probe(); 501 schedule_sigalrm(); 502 } 503 break; 504 505 case ICMP_REDIRECT: 506 if (cc_left < sizeof (struct ip)) { 507 if (verbose) { 508 Printf("packet too short (%d bytes) from %s\n", 509 cc, pr_name((char *)&from->sin_addr, 510 AF_INET)); 511 } 512 return; 513 } 514 515 ip = &icp->icmp_ip; 516 dst_addr.addr = ip->ip_dst; 517 if (is_a_target(ai_dst, &dst_addr) || verbose) { 518 if (icp->icmp_code >= A_CNT(redirect)) { 519 Printf("ICMP %d redirect from gateway %s\n", 520 icp->icmp_code, 521 pr_name((char *)&from->sin_addr, AF_INET)); 522 } else { 523 Printf("ICMP %s redirect from gateway %s\n", 524 redirect[icp->icmp_code], 525 pr_name((char *)&from->sin_addr, AF_INET)); 526 } 527 Printf(" to %s", 528 pr_name((char *)&icp->icmp_gwaddr, AF_INET)); 529 Printf(" for %s\n", 530 pr_name((char *)&ip->ip_dst, AF_INET)); 531 } 532 break; 533 534 case ICMP_ECHOREPLY: 535 if (ntohs(icp->icmp_id) == ident) { 536 if (!use_udp && !use_icmp_ts) 537 valid_reply = _B_TRUE; 538 else 539 valid_reply = _B_FALSE; 540 } else { 541 return; 542 } 543 544 if (valid_reply) { 545 /* 546 * For this valid reply, if we are still sending to 547 * this target IP address, we'd like to do some 548 * updates to targetaddr, so hold SIGALRMs. 549 */ 550 (void) sighold(SIGALRM); 551 is_alive = _B_TRUE; 552 nreceived++; 553 reply_matched_current_target = 554 seq_match(current_targetaddr->starting_seq_num, 555 current_targetaddr->num_sent, 556 ntohs(icp->icmp_seq)); 557 if (reply_matched_current_target) { 558 current_targetaddr->got_reply = _B_TRUE; 559 nreceived_last_target++; 560 /* 561 * Determine if stats, probe-all, and 562 * npackets != 0, and this is the reply for 563 * the last probe we sent to current target 564 * address. 565 */ 566 if (stats && probe_all && npackets > 0 && 567 ((current_targetaddr->starting_seq_num + 568 current_targetaddr->num_probes - 1) % 569 (MAX_ICMP_SEQ + 1) == 570 ntohs(icp->icmp_seq)) && 571 (current_targetaddr->num_probes == 572 current_targetaddr->num_sent)) 573 last_reply_from_targetaddr = _B_TRUE; 574 } else { 575 /* 576 * If it's just probe_all and we just received 577 * a reply from a target address we were 578 * probing and had timed out (now we are probing 579 * some other target address), we ignore 580 * this reply. 581 */ 582 if (probe_all && !stats) { 583 valid_reply = _B_FALSE; 584 /* 585 * Only if it's verbose, we get a 586 * message regarding this reply, 587 * otherwise we are done here. 588 */ 589 if (!verbose) { 590 (void) sigrelse(SIGALRM); 591 return; 592 } 593 } 594 } 595 } 596 597 if (!stats && valid_reply) { 598 /* 599 * if we are still sending to the same target address, 600 * then stop it, because we know it's alive. 601 */ 602 if (reply_matched_current_target) { 603 (void) alarm(0); /* cancel alarm */ 604 (void) sigset(SIGALRM, SIG_IGN); 605 current_targetaddr->probing_done = _B_TRUE; 606 } 607 (void) sigrelse(SIGALRM); 608 609 if (!probe_all) { 610 Printf("%s is alive\n", targethost); 611 } else { 612 /* 613 * If we are using send_reply, the real 614 * target address is not the src address of the 615 * replies. Use icmp_seq to find out where this 616 * probe was sent to. 617 */ 618 if (send_reply) { 619 (void) find_dstaddr( 620 ntohs(icp->icmp_seq), &dst_addr); 621 (void) inet_ntop(AF_INET, 622 (void *)&dst_addr.addr, 623 tmp_buf, sizeof (tmp_buf)); 624 } else { 625 (void) inet_ntop(AF_INET, 626 (void *)&from->sin_addr, 627 tmp_buf, sizeof (tmp_buf)); 628 } 629 if (nflag) { 630 Printf("%s is alive\n", tmp_buf); 631 } else { 632 Printf("%s (%s) is alive\n", 633 targethost, tmp_buf); 634 } 635 } 636 if (reply_matched_current_target) { 637 /* 638 * Let's get things going again, but now 639 * ping will start sending to next target IP 640 * address. 641 */ 642 send_scheduled_probe(); 643 (void) sigset(SIGALRM, sigalrm_handler); 644 schedule_sigalrm(); 645 } 646 return; 647 } else { 648 /* 649 * If we are not moving to next targetaddr, let's 650 * release the SIGALRM now. We don't want to stall in 651 * the middle of probing a targetaddr if the pr_name() 652 * call (see below) takes longer. 653 */ 654 if (!last_reply_from_targetaddr) 655 (void) sigrelse(SIGALRM); 656 /* else, we'll release it later */ 657 } 658 /* 659 * If we are using send_reply, the real target address is 660 * not the src address of the replies. Use icmp_seq to find out 661 * where this probe was sent to. 662 */ 663 if (send_reply) { 664 (void) find_dstaddr(ntohs(icp->icmp_seq), &dst_addr); 665 Printf("%d bytes from %s: ", cc, 666 pr_name((char *)&dst_addr.addr, AF_INET)); 667 } else { 668 Printf("%d bytes from %s: ", cc, 669 pr_name((char *)&from->sin_addr, AF_INET)); 670 } 671 Printf("icmp_seq=%d. ", ntohs(icp->icmp_seq)); 672 673 if (valid_reply && datalen >= sizeof (struct timeval) && 674 cc_left >= sizeof (struct timeval)) { 675 /* LINTED */ 676 tp = (struct timeval *)&icp->icmp_data[0]; 677 (void) tvsub(&tv, tp); 678 triptime = (int64_t)tv.tv_sec * MICROSEC + tv.tv_usec; 679 Printf("time=" TIMEFORMAT " ms", triptime/1000.0); 680 tsum += triptime; 681 tsum2 += triptime*triptime; 682 if (triptime < tmin) 683 tmin = triptime; 684 if (triptime > tmax) 685 tmax = triptime; 686 } 687 (void) putchar('\n'); 688 689 /* 690 * If it's stats, probe-all, npackets > 0, and we received reply 691 * for the last probe sent to this target address, then we 692 * don't need to wait anymore, let's move on to next target 693 * address, now! 694 */ 695 if (last_reply_from_targetaddr) { 696 (void) alarm(0); /* cancel alarm */ 697 current_targetaddr->probing_done = _B_TRUE; 698 (void) sigrelse(SIGALRM); 699 send_scheduled_probe(); 700 schedule_sigalrm(); 701 } 702 break; 703 704 case ICMP_SOURCEQUENCH: 705 if (cc_left < sizeof (struct ip)) { 706 if (verbose) { 707 Printf("packet too short (%d bytes) from %s\n", 708 cc, pr_name((char *)&from->sin_addr, 709 AF_INET)); 710 } 711 return; 712 } 713 ip = &icp->icmp_ip; 714 hlen1 = ip->ip_hl << 2; 715 dst_addr.addr = ip->ip_dst; 716 if (is_a_target(ai_dst, &dst_addr) || verbose) { 717 Printf("ICMP Source Quench from %s\n", 718 pr_name((char *)&from->sin_addr, AF_INET)); 719 Printf(" for %s from %s", pr_protocol(ip->ip_p), 720 pr_name((char *)&ip->ip_src, AF_INET)); 721 Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET)); 722 723 /* 724 * if it's a UDP or TCP packet, we need at least first 725 * 4 bytes of it to see the src/dst ports 726 */ 727 if ((ip->ip_p == IPPROTO_TCP || 728 ip->ip_p == IPPROTO_UDP) && 729 (cc_left >= hlen1 + 4)) { 730 /* LINTED */ 731 up = (struct udphdr *)((uchar_t *)ip + hlen1); 732 Printf(" port %d", ntohs(up->uh_dport)); 733 } 734 (void) putchar('\n'); 735 } 736 break; 737 738 case ICMP_PARAMPROB: 739 if (cc_left < sizeof (struct ip)) { 740 if (verbose) { 741 Printf("packet too short (%d bytes) from %s\n", 742 cc, pr_name((char *)&from->sin_addr, 743 AF_INET)); 744 } 745 return; 746 } 747 ip = &icp->icmp_ip; 748 hlen1 = ip->ip_hl << 2; 749 dst_addr.addr = ip->ip_dst; 750 if (is_a_target(ai_dst, &dst_addr) || verbose) { 751 switch (icp->icmp_code) { 752 case ICMP_PARAMPROB_OPTABSENT: 753 Printf("ICMP Missing a Required Option " 754 "parameter problem from %s\n", 755 pr_name((char *)&from->sin_addr, AF_INET)); 756 Printf(" option type = %d", icp->icmp_pptr); 757 break; 758 case ICMP_PARAMPROB_BADLENGTH: 759 Printf("ICMP Bad Length parameter problem " 760 "from %s\n", 761 pr_name((char *)&from->sin_addr, AF_INET)); 762 Printf(" in byte %d", icp->icmp_pptr); 763 if (icp->icmp_pptr <= hlen1) { 764 Printf(" (value 0x%x)", 765 *((char *)ip + icp->icmp_pptr)); 766 } 767 break; 768 case 0: 769 default: 770 Printf("ICMP Parameter Problem from %s\n", 771 pr_name((char *)&from->sin_addr, AF_INET)); 772 Printf(" in byte %d", icp->icmp_pptr); 773 if (icp->icmp_pptr <= hlen1) { 774 Printf(" (value 0x%x)", 775 *((char *)ip + icp->icmp_pptr)); 776 } 777 break; 778 } 779 780 Printf(" for %s from %s", pr_protocol(ip->ip_p), 781 pr_name((char *)&ip->ip_src, AF_INET)); 782 Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET)); 783 784 /* 785 * if it's a UDP or TCP packet, we need at least first 786 * 4 bytes of it to see the src/dst ports 787 */ 788 if ((ip->ip_p == IPPROTO_TCP || 789 ip->ip_p == IPPROTO_UDP) && 790 (cc_left >= hlen1 + 4)) { 791 /* LINTED */ 792 up = (struct udphdr *)((uchar_t *)ip + hlen1); 793 Printf(" port %d", ntohs(up->uh_dport)); 794 } 795 (void) putchar('\n'); 796 } 797 break; 798 799 case ICMP_TIMXCEED: 800 if (cc_left < sizeof (struct ip)) { 801 if (verbose) { 802 Printf("packet too short (%d bytes) from %s\n", 803 cc, pr_name((char *)&from->sin_addr, 804 AF_INET)); 805 } 806 return; 807 } 808 ip = &icp->icmp_ip; 809 hlen1 = ip->ip_hl << 2; 810 dst_addr.addr = ip->ip_dst; 811 if (is_a_target(ai_dst, &dst_addr) || verbose) { 812 if (icp->icmp_code >= A_CNT(timexceed)) { 813 Printf("ICMP %d time exceeded from %s\n", 814 icp->icmp_code, 815 pr_name((char *)&from->sin_addr, AF_INET)); 816 } else { 817 Printf("ICMP %s from %s\n", 818 timexceed[icp->icmp_code], 819 pr_name((char *)&from->sin_addr, AF_INET)); 820 } 821 Printf(" for %s from %s", pr_protocol(ip->ip_p), 822 pr_name((char *)&ip->ip_src, AF_INET)); 823 Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET)); 824 if ((ip->ip_p == IPPROTO_TCP || 825 ip->ip_p == IPPROTO_UDP) && 826 (cc_left >= hlen1 + 4)) { 827 /* LINTED */ 828 up = (struct udphdr *)((uchar_t *)ip + hlen1); 829 Printf(" port %d", ntohs(up->uh_dport)); 830 } 831 (void) putchar('\n'); 832 } 833 break; 834 835 case ICMP_TSTAMPREPLY: 836 /* the packet should have enough space to store timestamps */ 837 if (cc_left < sizeof (struct id_ts)) { 838 if (verbose) { 839 Printf("packet too short (%d bytes) from %s\n", 840 cc, pr_name((char *)&from->sin_addr, 841 AF_INET)); 842 } 843 return; 844 } 845 846 if (ntohs(icp->icmp_id) == ident) { 847 if (use_icmp_ts) 848 valid_reply = _B_TRUE; 849 else 850 valid_reply = _B_FALSE; 851 } else { 852 return; 853 } 854 855 if (valid_reply) { 856 /* 857 * For this valid reply, if we are still sending to 858 * this target IP address, we'd like to do some 859 * updates to targetaddr, so hold SIGALRMs. 860 */ 861 (void) sighold(SIGALRM); 862 is_alive = _B_TRUE; 863 nreceived++; 864 reply_matched_current_target = 865 seq_match(current_targetaddr->starting_seq_num, 866 current_targetaddr->num_sent, 867 ntohs(icp->icmp_seq)); 868 if (reply_matched_current_target) { 869 current_targetaddr->got_reply = _B_TRUE; 870 nreceived_last_target++; 871 /* 872 * Determine if stats, probe-all, and 873 * npackets != 0, and this is the reply for 874 * the last probe we sent to current target 875 * address. 876 */ 877 if (stats && probe_all && npackets > 0 && 878 ((current_targetaddr->starting_seq_num + 879 current_targetaddr->num_probes - 1) % 880 (MAX_ICMP_SEQ + 1) == 881 ntohs(icp->icmp_seq)) && 882 (current_targetaddr->num_probes == 883 current_targetaddr->num_sent)) 884 last_reply_from_targetaddr = _B_TRUE; 885 } else { 886 /* 887 * If it's just probe_all and we just received 888 * a reply from a target address we were 889 * probing and had timed out (now we are probing 890 * some other target address), we ignore 891 * this reply. 892 */ 893 if (probe_all && !stats) { 894 valid_reply = _B_FALSE; 895 /* 896 * Only if it's verbose, we get a 897 * message regarding this reply, 898 * otherwise we are done here. 899 */ 900 if (!verbose) { 901 (void) sigrelse(SIGALRM); 902 return; 903 } 904 } 905 } 906 } 907 908 if (!stats && valid_reply) { 909 /* 910 * if we are still sending to the same target address, 911 * then stop it, because we know it's alive. 912 */ 913 if (reply_matched_current_target) { 914 (void) alarm(0); /* cancel alarm */ 915 (void) sigset(SIGALRM, SIG_IGN); 916 current_targetaddr->probing_done = _B_TRUE; 917 } 918 (void) sigrelse(SIGALRM); 919 920 if (!probe_all) { 921 Printf("%s is alive\n", targethost); 922 } else { 923 /* 924 * If we are using send_reply, the real 925 * target address is not the src address of the 926 * replies. Use icmp_seq to find out where this 927 * probe was sent to. 928 */ 929 if (send_reply) { 930 (void) find_dstaddr( 931 ntohs(icp->icmp_seq), &dst_addr); 932 (void) inet_ntop(AF_INET, 933 (void *)&dst_addr.addr, 934 tmp_buf, sizeof (tmp_buf)); 935 } else { 936 (void) inet_ntop(AF_INET, 937 (void *)&from->sin_addr, 938 tmp_buf, sizeof (tmp_buf)); 939 } 940 if (nflag) { 941 Printf("%s is alive\n", tmp_buf); 942 } else { 943 Printf("%s (%s) is alive\n", 944 targethost, tmp_buf); 945 } 946 } 947 if (reply_matched_current_target) { 948 /* 949 * Let's get things going again, but now 950 * ping will start sending to next target IP 951 * address. 952 */ 953 send_scheduled_probe(); 954 (void) sigset(SIGALRM, sigalrm_handler); 955 schedule_sigalrm(); 956 } 957 return; 958 } else { 959 /* 960 * If we are not moving to next targetaddr, let's 961 * release the SIGALRM now. We don't want to stall in 962 * the middle of probing a targetaddr if the pr_name() 963 * call (see below) takes longer. 964 */ 965 if (!last_reply_from_targetaddr) 966 (void) sigrelse(SIGALRM); 967 /* else, we'll release it later */ 968 } 969 970 /* 971 * If we are using send_reply, the real target address is 972 * not the src address of the replies. Use icmp_seq to find out 973 * where this probe was sent to. 974 */ 975 if (send_reply) { 976 (void) find_dstaddr(ntohs(icp->icmp_seq), &dst_addr); 977 Printf("%d bytes from %s: ", cc, 978 pr_name((char *)&dst_addr.addr, AF_INET)); 979 } else { 980 Printf("%d bytes from %s: ", cc, 981 pr_name((char *)&from->sin_addr, AF_INET)); 982 } 983 Printf("icmp_seq=%d. ", ntohs(icp->icmp_seq)); 984 Printf("orig = %lu, recv = %lu, xmit = %lu ", 985 (ulong_t)ntohl(icp->icmp_otime), 986 (ulong_t)ntohl(icp->icmp_rtime), 987 (ulong_t)ntohl(icp->icmp_ttime)); 988 989 if (valid_reply) { 990 /* 991 * icp->icmp_otime is the time passed since midnight. 992 * Therefore we need to adjust tv value, which is 993 * the time passed since Jan 1, 1970. 994 */ 995 triptime = (tv.tv_sec % (24LL * 60 * 60)) * MILLISEC + 996 (tv.tv_usec / (MICROSEC/MILLISEC)); 997 triptime -= ntohl(icp->icmp_otime); 998 if (triptime < 0) 999 triptime += 24LL * 60 * 60 * MILLISEC; 1000 1001 Printf("time=%d. ms", (int)triptime); 1002 triptime *= (MICROSEC/MILLISEC); 1003 tsum += triptime; 1004 tsum2 += triptime*triptime; 1005 if (triptime < tmin) 1006 tmin = triptime; 1007 if (triptime > tmax) 1008 tmax = triptime; 1009 } 1010 (void) putchar('\n'); 1011 /* 1012 * If it's stats, probe-all, npackets > 0, and we received reply 1013 * for the last probe sent to this target address, then we 1014 * don't need to wait anymore, let's move on to next target 1015 * address, now! 1016 */ 1017 if (last_reply_from_targetaddr) { 1018 (void) alarm(0); /* cancel alarm */ 1019 current_targetaddr->probing_done = _B_TRUE; 1020 (void) sigrelse(SIGALRM); 1021 send_scheduled_probe(); 1022 schedule_sigalrm(); 1023 } 1024 break; 1025 case ICMP_ROUTERADVERT: 1026 case ICMP_ROUTERSOLICIT: 1027 /* Router discovery messages */ 1028 return; 1029 1030 case ICMP_ECHO: 1031 case ICMP_TSTAMP: 1032 case ICMP_IREQ: 1033 case ICMP_MASKREQ: 1034 /* These were never passed out from the SunOS 4.X kernel. */ 1035 return; 1036 1037 case ICMP_IREQREPLY: 1038 case ICMP_MASKREPLY: 1039 /* Replies for information and address mask requests */ 1040 return; 1041 1042 default: 1043 if (verbose) { 1044 Printf("%d bytes from %s:\n", cc, 1045 pr_name((char *)&from->sin_addr, AF_INET)); 1046 Printf("icmp_type=%d (%s) ", 1047 icp->icmp_type, pr_type(icp->icmp_type)); 1048 Printf("icmp_code=%d\n", icp->icmp_code); 1049 for (i = 0; i < 12; i++) { 1050 Printf("x%2.2x: x%8.8x\n", 1051 i * sizeof (int32_t), *intp++); 1052 } 1053 } 1054 break; 1055 } 1056 1057 buf += sizeof (struct ip); 1058 hlen -= sizeof (struct ip); 1059 1060 /* if verbose and there exists IP options */ 1061 if (verbose && hlen > 0) 1062 pr_options((uchar_t *)buf, hlen); 1063 } 1064 1065 /* 1066 * Print out the ip options. 1067 */ 1068 static void 1069 pr_options(uchar_t *opt, int optlength) 1070 { 1071 int curlength; 1072 1073 Printf(" IP options: "); 1074 while (optlength > 0) { 1075 curlength = opt[1]; 1076 switch (*opt) { 1077 case IPOPT_EOL: 1078 optlength = 0; 1079 break; 1080 1081 case IPOPT_NOP: 1082 opt++; 1083 optlength--; 1084 continue; 1085 1086 case IPOPT_RR: 1087 Printf(" <record route> "); 1088 pr_rropt(opt, curlength, _B_TRUE); 1089 break; 1090 1091 case IPOPT_TS: 1092 Printf(" <time stamp> "); 1093 pr_tsopt(opt, curlength); 1094 break; 1095 1096 case IPOPT_SECURITY: 1097 Printf(" <security>"); 1098 break; 1099 1100 case IPOPT_LSRR: 1101 Printf(" <loose source route> "); 1102 pr_rropt(opt, curlength, _B_FALSE); 1103 break; 1104 1105 case IPOPT_SATID: 1106 Printf(" <stream id>"); 1107 break; 1108 1109 case IPOPT_SSRR: 1110 Printf(" <strict source route> "); 1111 pr_rropt(opt, curlength, _B_FALSE); 1112 break; 1113 1114 default: 1115 Printf(" <option %d, len %d>", *opt, curlength); 1116 break; 1117 } 1118 /* 1119 * Following most options comes a length field 1120 */ 1121 opt += curlength; 1122 optlength -= curlength; 1123 } 1124 (void) putchar('\n'); 1125 } 1126 1127 /* 1128 * Print out a recorded route option. If rrflag is _B_TRUE, it prints record 1129 * route option, otherwise LSRR/SSRR. 1130 */ 1131 static void 1132 pr_rropt(uchar_t *opt, int length, boolean_t rrflag) 1133 { 1134 struct ip_sourceroute *rrp; 1135 int sr_index = 0; 1136 struct in_addr addr; 1137 1138 rrp = (struct ip_sourceroute *)opt; 1139 1140 /* data starts at offset 3 */ 1141 length -= 3; 1142 while (length > 0) { 1143 /* 1144 * Let's see if we are examining the addr pointed by ipsr_ptr 1145 */ 1146 if ((rrp->ipsr_ptr == (sr_index + 1) * sizeof (addr)) && 1147 rrflag) { 1148 Printf(" (End of record)"); 1149 break; 1150 } 1151 1152 bcopy(&rrp->ipsr_addrs[sr_index], &addr, sizeof (addr)); 1153 Printf("%s", pr_name((char *)&addr, AF_INET)); 1154 1155 if (rrp->ipsr_ptr == (sr_index + 1) * sizeof (addr)) { 1156 Printf("(Current)"); 1157 } 1158 1159 sr_index++; 1160 1161 length -= sizeof (addr); 1162 if (length > 0) 1163 Printf(", "); 1164 } 1165 } 1166 1167 /* 1168 * Print out a timestamp option. 1169 */ 1170 static void 1171 pr_tsopt(uchar_t *opt, int length) 1172 { 1173 boolean_t address_present; 1174 boolean_t rrflag; /* End at current entry? */ 1175 struct ip_timestamp *tsp; 1176 int ts_index = 0; 1177 struct in_addr addr; 1178 size_t data_len; 1179 int32_t time; 1180 1181 /* LINTED */ 1182 tsp = (struct ip_timestamp *)opt; 1183 1184 switch (tsp->ipt_flg) { 1185 case IPOPT_TS_TSONLY: 1186 address_present = _B_FALSE; 1187 data_len = sizeof (tsp->ipt_timestamp.ipt_time[0]); 1188 rrflag = _B_TRUE; 1189 break; 1190 case IPOPT_TS_TSANDADDR: 1191 address_present = _B_TRUE; 1192 data_len = sizeof (tsp->ipt_timestamp.ipt_ta[0]); 1193 rrflag = _B_TRUE; 1194 break; 1195 case IPOPT_TS_PRESPEC: 1196 case 3: 1197 address_present = _B_TRUE; 1198 data_len = sizeof (tsp->ipt_timestamp.ipt_ta[0]); 1199 rrflag = _B_FALSE; 1200 break; 1201 default: 1202 Printf("(Bad flag value: 0x%x)", tsp->ipt_flg); 1203 return; 1204 } 1205 if (tsp->ipt_oflw > 0) 1206 Printf("(Overflow: %d) ", tsp->ipt_oflw); 1207 1208 /* data starts at offset 4 */ 1209 length -= 4; 1210 1211 while (length > 0) { 1212 if (length < data_len) 1213 break; 1214 1215 /* the minimum value of ipt_ptr is 5 */ 1216 if ((tsp->ipt_ptr == ts_index * data_len + 5) && rrflag) { 1217 Printf(" (End of record)"); 1218 break; 1219 } 1220 if (address_present) { 1221 bcopy(&tsp->ipt_timestamp.ipt_ta[ts_index].ipt_addr, 1222 &addr, sizeof (addr)); 1223 Printf("%s: ", pr_name((char *)&addr, AF_INET)); 1224 bcopy(&tsp->ipt_timestamp.ipt_ta[ts_index].ipt_time, 1225 &time, sizeof (time)); 1226 } else { 1227 bcopy(&tsp->ipt_timestamp.ipt_time[ts_index], 1228 &time, sizeof (time)); 1229 } 1230 Printf("%d", ntohl(time)); 1231 1232 if (tsp->ipt_ptr == ts_index * data_len + 5) 1233 Printf("(Current)"); 1234 1235 ts_index++; 1236 length -= data_len; 1237 if (length > 0) 1238 Printf(", "); 1239 } 1240 } 1241 1242 /* 1243 * Convert an ICMP "type" field to a printable string. 1244 */ 1245 static char * 1246 pr_type(int icmp_type) 1247 { 1248 static struct icmptype_table ttab[] = { 1249 {ICMP_ECHOREPLY, "Echo Reply"}, 1250 {1, "ICMP 1"}, 1251 {2, "ICMP 2"}, 1252 {ICMP_UNREACH, "Dest Unreachable"}, 1253 {ICMP_SOURCEQUENCH, "Source Quench"}, 1254 {ICMP_REDIRECT, "Redirect"}, 1255 {6, "ICMP 6"}, 1256 {7, "ICMP 7"}, 1257 {ICMP_ECHO, "Echo"}, 1258 {ICMP_ROUTERADVERT, "Router Advertisement"}, 1259 {ICMP_ROUTERSOLICIT, "Router Solicitation"}, 1260 {ICMP_TIMXCEED, "Time Exceeded"}, 1261 {ICMP_PARAMPROB, "Parameter Problem"}, 1262 {ICMP_TSTAMP, "Timestamp"}, 1263 {ICMP_TSTAMPREPLY, "Timestamp Reply"}, 1264 {ICMP_IREQ, "Info Request"}, 1265 {ICMP_IREQREPLY, "Info Reply"}, 1266 {ICMP_MASKREQ, "Netmask Request"}, 1267 {ICMP_MASKREPLY, "Netmask Reply"} 1268 }; 1269 int i; 1270 1271 for (i = 0; i < A_CNT(ttab); i++) { 1272 if (ttab[i].type == icmp_type) 1273 return (ttab[i].message); 1274 } 1275 1276 return ("OUT-OF-RANGE"); 1277 } 1278