1/* vi: set sw=4 ts=4: */ 2/* 3 * Mini ping implementation for busybox 4 * 5 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org> 6 * 7 * Adapted from the ping in netkit-base 0.10: 8 * Copyright (c) 1989 The Regents of the University of California. 9 * All rights reserved. 10 * 11 * This code is derived from software contributed to Berkeley by 12 * Mike Muuss. 13 * 14 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 15 */ 16/* from ping6.c: 17 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org> 18 * 19 * This version of ping is adapted from the ping in netkit-base 0.10, 20 * which is: 21 * 22 * Original copyright notice is retained at the end of this file. 23 * 24 * This version is an adaptation of ping.c from busybox. 25 * The code was modified by Bart Visscher <magick@linux-fan.com> 26 */ 27 28#include <net/if.h> 29#include <netinet/ip_icmp.h> 30#include "libbb.h" 31 32#if ENABLE_PING6 33#include <netinet/icmp6.h> 34/* I see RENUMBERED constants in bits/in.h - !!? 35 * What a fuck is going on with libc? Is it a glibc joke? */ 36#ifdef IPV6_2292HOPLIMIT 37#undef IPV6_HOPLIMIT 38#define IPV6_HOPLIMIT IPV6_2292HOPLIMIT 39#endif 40#endif 41 42enum { 43 DEFDATALEN = 56, 44 MAXIPLEN = 60, 45 MAXICMPLEN = 76, 46 MAXPACKET = 65468, 47 MAX_DUP_CHK = (8 * 128), 48 MAXWAIT = 5, /* foxconn dennis modified 10/21/2010, from 10 to 5 , for fast check, 2010/10/19*/ 49 PINGINTERVAL = 1, /* 1 second */ 50}; 51 52/* common routines */ 53 54static int in_cksum(unsigned short *buf, int sz) 55{ 56 int nleft = sz; 57 int sum = 0; 58 unsigned short *w = buf; 59 unsigned short ans = 0; 60 61 while (nleft > 1) { 62 sum += *w++; 63 nleft -= 2; 64 } 65 66 if (nleft == 1) { 67 *(unsigned char *) (&ans) = *(unsigned char *) w; 68 sum += ans; 69 } 70 71 sum = (sum >> 16) + (sum & 0xFFFF); 72 sum += (sum >> 16); 73 ans = ~sum; 74 return ans; 75} 76 77#if !ENABLE_FEATURE_FANCY_PING 78 79/* simple version */ 80 81static char *hostname; 82/* foxconn dennis modified start, 10/21/2010 */ 83static int noresp(int ign ATTRIBUTE_UNUSED) 84{ 85 printf("No response from %s\n", hostname); 86 exit(EXIT_FAILURE); 87} 88/* foxconn dennis modified end, 10/21/2010 */ 89 90 91static void ping4(len_and_sockaddr *lsa) 92{ 93 struct sockaddr_in pingaddr; 94 struct icmp *pkt; 95 int pingsock, c; 96 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; 97 98 pingsock = create_icmp_socket(); 99 pingaddr = lsa->sin; 100 101 pkt = (struct icmp *) packet; 102 memset(pkt, 0, sizeof(packet)); 103 pkt->icmp_type = ICMP_ECHO; 104 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); 105 106 c = xsendto(pingsock, packet, DEFDATALEN + ICMP_MINLEN, 107 (struct sockaddr *) &pingaddr, sizeof(pingaddr)); 108 109 /* listen for replies */ 110 while (1) { 111 struct sockaddr_in from; 112 socklen_t fromlen = sizeof(from); 113 114 c = recvfrom(pingsock, packet, sizeof(packet), 0, 115 (struct sockaddr *) &from, &fromlen); 116 if (c < 0) { 117 if (errno != EINTR) 118 bb_perror_msg("recvfrom"); 119 continue; 120 } 121 if (c >= 76) { /* ip + icmp */ 122 struct iphdr *iphdr = (struct iphdr *) packet; 123 124 pkt = (struct icmp *) (packet + (iphdr->ihl << 2)); /* skip ip hdr */ 125 if (pkt->icmp_type == ICMP_ECHOREPLY) 126 break; 127 } 128 } 129 if (ENABLE_FEATURE_CLEAN_UP) 130 close(pingsock); 131} 132 133#if ENABLE_PING6 134static void ping6(len_and_sockaddr *lsa) 135{ 136 struct sockaddr_in6 pingaddr; 137 struct icmp6_hdr *pkt; 138 int pingsock, c; 139 int sockopt; 140 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; 141 142 pingsock = create_icmp6_socket(); 143 pingaddr = lsa->sin6; 144 145 pkt = (struct icmp6_hdr *) packet; 146 memset(pkt, 0, sizeof(packet)); 147 pkt->icmp6_type = ICMP6_ECHO_REQUEST; 148 149 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); 150 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt)); 151 152 c = xsendto(pingsock, packet, DEFDATALEN + sizeof (struct icmp6_hdr), 153 (struct sockaddr *) &pingaddr, sizeof(pingaddr)); 154 155 /* listen for replies */ 156 while (1) { 157 struct sockaddr_in6 from; 158 socklen_t fromlen = sizeof(from); 159 160 c = recvfrom(pingsock, packet, sizeof(packet), 0, 161 (struct sockaddr *) &from, &fromlen); 162 if (c < 0) { 163 if (errno != EINTR) 164 bb_perror_msg("recvfrom"); 165 continue; 166 } 167 if (c >= 8) { /* icmp6_hdr */ 168 pkt = (struct icmp6_hdr *) packet; 169 if (pkt->icmp6_type == ICMP6_ECHO_REPLY) 170 break; 171 } 172 } 173 if (ENABLE_FEATURE_CLEAN_UP) 174 close(pingsock); 175} 176#endif 177 178int ping_main(int argc, char **argv); 179int ping_main(int argc, char **argv) 180{ 181 len_and_sockaddr *lsa; 182#if ENABLE_PING6 183 sa_family_t af = AF_UNSPEC; 184 185 while ((++argv)[0] && argv[0][0] == '-') { 186 if (argv[0][1] == '4') { 187 af = AF_INET; 188 continue; 189 } 190 if (argv[0][1] == '6') { 191 af = AF_INET6; 192 continue; 193 } 194 bb_show_usage(); 195 } 196#else 197 argv++; 198#endif 199 200 hostname = *argv; 201 if (!hostname) 202 bb_show_usage(); 203 204#if ENABLE_PING6 205 lsa = xhost_and_af2sockaddr(hostname, 0, af); 206#else 207 lsa = xhost_and_af2sockaddr(hostname, 0, AF_INET); 208#endif 209 /* Set timer _after_ DNS resolution */ 210 signal(SIGALRM, noresp); 211 alarm(5); /* give the host 5000ms to respond */ 212 213#if ENABLE_PING6 214 if (lsa->sa.sa_family == AF_INET6) 215 ping6(lsa); 216 else 217#endif 218 ping4(lsa); 219 printf("%s is alive!\n", hostname); 220 return EXIT_SUCCESS; 221} 222 223 224#else /* FEATURE_FANCY_PING */ 225 226 227/* full(er) version */ 228 229/* Fxcn modify-S Wins, 0911-09 */ 230//#define OPT_STRING ("qvc:s:I:4" USE_PING6("6")) 231#define OPT_STRING ("qvc:s:I:4" USE_PING6("6")"g:f") 232/* Fxcn modify-E Wins, 0911-09 */ 233enum { 234 OPT_QUIET = 1 << 0, 235 OPT_VERBOSE = 1 << 1, 236 OPT_c = 1 << 2, 237 OPT_s = 1 << 3, 238 OPT_I = 1 << 4, 239 OPT_IPV4 = 1 << 5, 240 OPT_IPV6 = (1 << 6) * ENABLE_PING6, 241 /* foxconn dennis modified start, 10/21/2010 */ 242 OPT_g = 1 << 7, 243 OPT_f = 1 << 8, 244 /* foxconn dennis modified end, 10/21/2010 */ 245}; 246 247 248struct globals { 249 int pingsock; 250 len_and_sockaddr *source_lsa; 251 unsigned datalen; 252 int if_index; 253 unsigned long ntransmitted, nreceived, nrepeats, pingcount; 254 uint16_t myid; 255 unsigned tmin, tmax; /* in us */ 256 unsigned long long tsum; /* in us, sum of all times */ 257 const char *hostname; 258 const char *dotted; 259 union { 260 struct sockaddr sa; 261 struct sockaddr_in sin; 262#if ENABLE_PING6 263 struct sockaddr_in6 sin6; 264#endif 265 } pingaddr; 266 /* foxconn dennis modified start, 10/21/2010 */ 267 long ping_trig; 268 long fast_check; 269 /* foxconn dennis modified end, 10/21/2010 */ 270 char rcvd_tbl[MAX_DUP_CHK / 8]; 271}; 272#define G (*(struct globals*)&bb_common_bufsiz1) 273#define pingsock (G.pingsock ) 274#define source_lsa (G.source_lsa ) 275#define datalen (G.datalen ) 276#define if_index (G.if_index ) 277#define ntransmitted (G.ntransmitted) 278#define nreceived (G.nreceived ) 279#define nrepeats (G.nrepeats ) 280#define pingcount (G.pingcount ) 281#define myid (G.myid ) 282#define tmin (G.tmin ) 283#define tmax (G.tmax ) 284#define tsum (G.tsum ) 285#define hostname (G.hostname ) 286#define dotted (G.dotted ) 287#define pingaddr (G.pingaddr ) 288#define rcvd_tbl (G.rcvd_tbl ) 289/* foxconn dennis modified start, 10/21/2010 */ 290#define ping_trig (G.ping_trig ) 291#define fast_check (G.fast_check ) 292/* foxconn dennis modified end, 10/21/2010 */ 293void BUG_ping_globals_too_big(void); 294#define INIT_G() do { \ 295 if (sizeof(G) > COMMON_BUFSIZE) \ 296 BUG_ping_globals_too_big(); \ 297 pingsock = -1; \ 298 tmin = UINT_MAX; \ 299} while (0) 300 301 302#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ 303#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ 304#define SET(bit) (A(bit) |= B(bit)) 305#define CLR(bit) (A(bit) &= (~B(bit))) 306#define TST(bit) (A(bit) & B(bit)) 307 308/**************************************************************************/ 309 310static void pingstats(int junk ATTRIBUTE_UNUSED) 311{ 312 signal(SIGINT, SIG_IGN); 313 314 printf("\n--- %s ping statistics ---\n", hostname); 315 printf("%lu packets transmitted, ", ntransmitted); 316 printf("%lu packets received, ", nreceived); 317 if (nrepeats) 318 printf("%lu duplicates, ", nrepeats); 319 if (ntransmitted) 320 ntransmitted = (ntransmitted - nreceived) * 100 / ntransmitted; 321 printf("%lu%% packet loss\n", ntransmitted); 322 if (tmin != UINT_MAX) { 323 unsigned tavg = tsum / (nreceived + nrepeats); 324 printf("round-trip min/avg/max = %u.%03u/%u.%03u/%u.%03u ms\n", 325 tmin / 1000, tmin % 1000, 326 tavg / 1000, tavg % 1000, 327 tmax / 1000, tmax % 1000); 328 } 329 exit(nreceived == 0); /* (nreceived == 0) is true (1) -- 'failure' */ 330} 331 332static void sendping_tail(void (*sp)(int), const void *pkt, int size_pkt) 333{ 334 int sz; 335 336 CLR((uint16_t)ntransmitted % MAX_DUP_CHK); 337 ntransmitted++; 338 339 /* sizeof(pingaddr) can be larger than real sa size, but I think 340 * it doesn't matter */ 341 sz = xsendto(pingsock, pkt, size_pkt, &pingaddr.sa, sizeof(pingaddr)); 342 if (sz != size_pkt) 343 bb_error_msg_and_die(bb_msg_write_error); 344 345/* Fxcn port-S Wins, 0716-09 */ 346 /* wklin added sart, 01/12/2007 */ 347 if (ping_trig) { 348 close(pingsock); 349 exit(0); 350 } 351 /* wklin added end, 01/12/2007 */ 352/* Fxcn port-E Wins, 0716-09 */ 353 354 signal(SIGALRM, sp); 355 if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */ 356 alarm(PINGINTERVAL); 357 } else { /* done, wait for the last ping to come back */ 358 /* todo, don't necessarily need to wait so long... */ 359 signal(SIGALRM, pingstats); 360 alarm(MAXWAIT); 361 } 362} 363 364static void sendping4(int junk ATTRIBUTE_UNUSED) 365{ 366 /* +4 reserves a place for timestamp, which may end up sitting 367 * *after* packet. Saves one if() */ 368 struct icmp *pkt = alloca(datalen + ICMP_MINLEN + 4); 369 370 pkt->icmp_type = ICMP_ECHO; 371 pkt->icmp_code = 0; 372 pkt->icmp_cksum = 0; 373 pkt->icmp_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */ 374 pkt->icmp_id = myid; 375 376 /* We don't do hton, because we will read it back on the same machine */ 377 /*if (datalen >= 4)*/ 378 *(uint32_t*)&pkt->icmp_dun = monotonic_us(); 379 380 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, datalen + ICMP_MINLEN); 381 382 sendping_tail(sendping4, pkt, datalen + ICMP_MINLEN); 383} 384#if ENABLE_PING6 385static void sendping6(int junk ATTRIBUTE_UNUSED) 386{ 387 struct icmp6_hdr *pkt = alloca(datalen + sizeof(struct icmp6_hdr) + 4); 388 389 pkt->icmp6_type = ICMP6_ECHO_REQUEST; 390 pkt->icmp6_code = 0; 391 pkt->icmp6_cksum = 0; 392 pkt->icmp6_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */ 393 pkt->icmp6_id = myid; 394 395 /*if (datalen >= 4)*/ 396 *(uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us(); 397 398 sendping_tail(sendping6, pkt, datalen + sizeof(struct icmp6_hdr)); 399} 400#endif 401 402static const char *icmp_type_name(int id) 403{ 404 switch (id) { 405 case ICMP_ECHOREPLY: return "Echo Reply"; 406 case ICMP_DEST_UNREACH: return "Destination Unreachable"; 407 case ICMP_SOURCE_QUENCH: return "Source Quench"; 408 case ICMP_REDIRECT: return "Redirect (change route)"; 409 case ICMP_ECHO: return "Echo Request"; 410 case ICMP_TIME_EXCEEDED: return "Time Exceeded"; 411 case ICMP_PARAMETERPROB: return "Parameter Problem"; 412 case ICMP_TIMESTAMP: return "Timestamp Request"; 413 case ICMP_TIMESTAMPREPLY: return "Timestamp Reply"; 414 case ICMP_INFO_REQUEST: return "Information Request"; 415 case ICMP_INFO_REPLY: return "Information Reply"; 416 case ICMP_ADDRESS: return "Address Mask Request"; 417 case ICMP_ADDRESSREPLY: return "Address Mask Reply"; 418 default: return "unknown ICMP type"; 419 } 420} 421#if ENABLE_PING6 422/* RFC3542 changed some definitions from RFC2292 for no good reason, whee! 423 * the newer 3542 uses a MLD_ prefix where as 2292 uses ICMP6_ prefix */ 424#ifndef MLD_LISTENER_QUERY 425# define MLD_LISTENER_QUERY ICMP6_MEMBERSHIP_QUERY 426#endif 427#ifndef MLD_LISTENER_REPORT 428# define MLD_LISTENER_REPORT ICMP6_MEMBERSHIP_REPORT 429#endif 430#ifndef MLD_LISTENER_REDUCTION 431# define MLD_LISTENER_REDUCTION ICMP6_MEMBERSHIP_REDUCTION 432#endif 433static const char *icmp6_type_name(int id) 434{ 435 switch (id) { 436 case ICMP6_DST_UNREACH: return "Destination Unreachable"; 437 case ICMP6_PACKET_TOO_BIG: return "Packet too big"; 438 case ICMP6_TIME_EXCEEDED: return "Time Exceeded"; 439 case ICMP6_PARAM_PROB: return "Parameter Problem"; 440 case ICMP6_ECHO_REPLY: return "Echo Reply"; 441 case ICMP6_ECHO_REQUEST: return "Echo Request"; 442 case MLD_LISTENER_QUERY: return "Listener Query"; 443 case MLD_LISTENER_REPORT: return "Listener Report"; 444 case MLD_LISTENER_REDUCTION: return "Listener Reduction"; 445 default: return "unknown ICMP type"; 446 } 447} 448#endif 449 450static void unpack_tail(int sz, uint32_t *tp, 451 const char *from_str, 452 uint16_t recv_seq, int ttl) 453{ 454 const char *dupmsg = " (DUP!)"; 455 unsigned triptime = triptime; /* for gcc */ 456 457 ++nreceived; 458 459 if (tp) { 460 /* (int32_t) cast is for hypothetical 64-bit unsigned */ 461 /* (doesn't hurt 32-bit real-world anyway) */ 462 triptime = (int32_t) ((uint32_t)monotonic_us() - *tp); 463 tsum += triptime; 464 if (triptime < tmin) 465 tmin = triptime; 466 if (triptime > tmax) 467 tmax = triptime; 468 } 469 470 if (TST(recv_seq % MAX_DUP_CHK)) { 471 ++nrepeats; 472 --nreceived; 473 } else { 474 SET(recv_seq % MAX_DUP_CHK); 475 dupmsg += 7; 476 } 477 478 if (option_mask32 & OPT_QUIET) 479 return; 480 481 printf("%d bytes from %s: seq=%u ttl=%d", sz, 482 from_str, recv_seq, ttl); 483 if (tp) 484 printf(" time=%u.%03u ms", triptime / 1000, triptime % 1000); 485 puts(dupmsg); 486 fflush(stdout); 487} 488static void unpack4(char *buf, int sz, struct sockaddr_in *from) 489{ 490 struct icmp *icmppkt; 491 struct iphdr *iphdr; 492 int hlen; 493 494 /* discard if too short */ 495 if (sz < (datalen + ICMP_MINLEN)) 496 return; 497 498 /* check IP header */ 499 iphdr = (struct iphdr *) buf; 500 hlen = iphdr->ihl << 2; 501 sz -= hlen; 502 icmppkt = (struct icmp *) (buf + hlen); 503 if (icmppkt->icmp_id != myid) 504 return; /* not our ping */ 505 506 if (icmppkt->icmp_type == ICMP_ECHOREPLY) { 507 uint16_t recv_seq = ntohs(icmppkt->icmp_seq); 508 uint32_t *tp = NULL; 509 510 if (sz >= ICMP_MINLEN + sizeof(uint32_t)) 511 tp = (uint32_t *) icmppkt->icmp_data; 512 unpack_tail(sz, tp, 513 inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr), 514 recv_seq, iphdr->ttl); 515 } else if (icmppkt->icmp_type != ICMP_ECHO) { 516 bb_error_msg("warning: got ICMP %d (%s)", 517 icmppkt->icmp_type, 518 icmp_type_name(icmppkt->icmp_type)); 519 } 520} 521#if ENABLE_PING6 522static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit) 523{ 524 struct icmp6_hdr *icmppkt; 525 char buf[INET6_ADDRSTRLEN]; 526 527 /* discard if too short */ 528 if (sz < (datalen + sizeof(struct icmp6_hdr))) 529 return; 530 531 icmppkt = (struct icmp6_hdr *) packet; 532 if (icmppkt->icmp6_id != myid) 533 return; /* not our ping */ 534 535 if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) { 536 uint16_t recv_seq = ntohs(icmppkt->icmp6_seq); 537 uint32_t *tp = NULL; 538 539 if (sz >= sizeof(struct icmp6_hdr) + sizeof(uint32_t)) 540 tp = (uint32_t *) &icmppkt->icmp6_data8[4]; 541 /* Foxconn modified start pling 09/01/2010 */ 542 /* For IPv6 ReadyLogo IOT test */ 543 /* Show actual address that reply to this ping req. 544 * Useful when the ping destination is a multicast addr. 545 */ 546#if 0 547 unpack_tail(sz, tp, 548 inet_ntop(AF_INET6, &pingaddr.sin6.sin6_addr, 549 buf, sizeof(buf)), 550 recv_seq, hoplimit); 551#endif 552 unpack_tail(sz, tp, 553 inet_ntop(AF_INET6, &from->sin6_addr, 554 buf, sizeof(buf)), 555 recv_seq, hoplimit); 556 /* Foxconn modified end pling 09/01/2010 */ 557 } else if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) { 558 bb_error_msg("warning: got ICMP %d (%s)", 559 icmppkt->icmp6_type, 560 icmp6_type_name(icmppkt->icmp6_type)); 561 } 562} 563#endif 564 565static void ping4(len_and_sockaddr *lsa) 566{ 567 char packet[datalen + MAXIPLEN + MAXICMPLEN]; 568 int sockopt; 569 570 pingsock = create_icmp_socket(); 571 pingaddr.sin = lsa->sin; 572 if (source_lsa) { 573 if (setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_IF, 574 &source_lsa->sa, source_lsa->len)) 575 bb_error_msg_and_die("can't set multicast source interface"); 576 xbind(pingsock, &source_lsa->sa, source_lsa->len); 577 } 578 579 /* enable broadcast pings */ 580 setsockopt_broadcast(pingsock); 581 582 /* set recv buf for broadcast pings */ 583 sockopt = 48 * 1024; /* explain why 48k? */ 584 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); 585 586 signal(SIGINT, pingstats); 587 588 /* start the ping's going ... */ 589 sendping4(0); 590 591 /* listen for replies */ 592 while (1) { 593 struct sockaddr_in from; 594 socklen_t fromlen = (socklen_t) sizeof(from); 595 int c; 596 597 c = recvfrom(pingsock, packet, sizeof(packet), 0, 598 (struct sockaddr *) &from, &fromlen); 599 if (c < 0) { 600 if (errno != EINTR) 601 bb_perror_msg("recvfrom"); 602 continue; 603 } 604 unpack4(packet, c, &from); 605 /* foxconn dennis added start, 10/21/2010 */ 606 if (fast_check && nreceived > 0) 607 break; 608 /* foxconn dennis added end, 09/30/2010 */ 609 if (pingcount > 0 && nreceived >= pingcount) 610 break; 611 } 612} 613#if ENABLE_PING6 614extern int BUG_bad_offsetof_icmp6_cksum(void); 615static void ping6(len_and_sockaddr *lsa) 616{ 617 char packet[datalen + MAXIPLEN + MAXICMPLEN]; 618 int sockopt; 619 struct msghdr msg; 620 struct sockaddr_in6 from; 621 struct iovec iov; 622 char control_buf[CMSG_SPACE(36)]; 623 624 pingsock = create_icmp6_socket(); 625 pingaddr.sin6 = lsa->sin6; 626 /* untested whether "-I addr" really works for IPv6: */ 627 if (source_lsa) 628 xbind(pingsock, &source_lsa->sa, source_lsa->len); 629 630#ifdef ICMP6_FILTER 631 { 632 struct icmp6_filter filt; 633 if (!(option_mask32 & OPT_VERBOSE)) { 634 ICMP6_FILTER_SETBLOCKALL(&filt); 635 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt); 636 } else { 637 ICMP6_FILTER_SETPASSALL(&filt); 638 } 639 if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 640 sizeof(filt)) < 0) 641 bb_error_msg_and_die("setsockopt(ICMP6_FILTER)"); 642 } 643#endif /*ICMP6_FILTER*/ 644 645 /* enable broadcast pings */ 646 setsockopt_broadcast(pingsock); 647 648 /* set recv buf for broadcast pings */ 649 sockopt = 48 * 1024; /* explain why 48k? */ 650 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); 651 652 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); 653 if (offsetof(struct icmp6_hdr, icmp6_cksum) != 2) 654 BUG_bad_offsetof_icmp6_cksum(); 655 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt)); 656 657 /* request ttl info to be returned in ancillary data */ 658 setsockopt(pingsock, SOL_IPV6, IPV6_HOPLIMIT, &const_int_1, sizeof(const_int_1)); 659 660 if (if_index) 661 pingaddr.sin6.sin6_scope_id = if_index; 662 663 signal(SIGINT, pingstats); 664 665 /* start the ping's going ... */ 666 sendping6(0); 667 668 /* listen for replies */ 669 msg.msg_name = &from; 670 msg.msg_namelen = sizeof(from); 671 msg.msg_iov = &iov; 672 msg.msg_iovlen = 1; 673 msg.msg_control = control_buf; 674 iov.iov_base = packet; 675 iov.iov_len = sizeof(packet); 676 while (1) { 677 int c; 678 struct cmsghdr *mp; 679 int hoplimit = -1; 680 msg.msg_controllen = sizeof(control_buf); 681 682 c = recvmsg(pingsock, &msg, 0); 683 if (c < 0) { 684 if (errno != EINTR) 685 bb_perror_msg("recvfrom"); 686 continue; 687 } 688 for (mp = CMSG_FIRSTHDR(&msg); mp; mp = CMSG_NXTHDR(&msg, mp)) { 689 if (mp->cmsg_level == SOL_IPV6 690 && mp->cmsg_type == IPV6_HOPLIMIT 691 /* don't check len - we trust the kernel: */ 692 /* && mp->cmsg_len >= CMSG_LEN(sizeof(int)) */ 693 ) { 694 hoplimit = *(int*)CMSG_DATA(mp); 695 } 696 } 697 unpack6(packet, c, &from, hoplimit); 698 if (pingcount > 0 && nreceived >= pingcount) 699 break; 700 } 701} 702#endif 703 704static void ping(len_and_sockaddr *lsa) 705{ 706 printf("PING %s (%s)", hostname, dotted); 707 if (source_lsa) { 708 printf(" from %s", 709 xmalloc_sockaddr2dotted_noport(&source_lsa->sa)); 710 } 711 printf(": %d data bytes\n", datalen); 712 713#if ENABLE_PING6 714 if (lsa->sa.sa_family == AF_INET6) 715 ping6(lsa); 716 else 717#endif 718 ping4(lsa); 719} 720 721/* foxconn dennis added start, 10/21/2010 */ 722static int noresp(int junk) 723{ 724 printf("No DNS query response, quit ping.\n"); 725 exit(EXIT_FAILURE); 726} 727/* foxconn dennis added end, 10/21/2010 */ 728int ping_main(int argc, char **argv); 729int ping_main(int argc, char **argv) 730{ 731 len_and_sockaddr *lsa; 732 char *opt_c, *opt_s, *opt_I; 733 /* Fxcn port-S Wins, 0716-09 */ 734 char *opt_g; 735 /* Fxcn port-E Wins, 0716-09 */ 736 737 /*added by dennis start, for fast ping check, 2010/10/19*/ 738 char *opt_f; 739 /*added by dennis end, for fast ping check, 2010/10/19*/ 740 USE_PING6(sa_family_t af = AF_UNSPEC;) 741 742 INIT_G(); 743 744 datalen = DEFDATALEN; 745 746 /* exactly one argument needed, -v and -q don't mix */ 747 opt_complementary = "=1:q--v:v--q"; 748 /* foxconn wklin modified start, 10/19/2010 */ 749 getopt32(argv, OPT_STRING, &opt_c, &opt_s, &opt_I, &opt_g); 750 /* foxconn wklin modified end, 10/19/2010 */ 751 if (option_mask32 & OPT_c) pingcount = xatoul(opt_c); // -c 752 if (option_mask32 & OPT_s) datalen = xatou16(opt_s); // -s 753 if (option_mask32 & OPT_I) { // -I 754 if_index = if_nametoindex(opt_I); 755 if (!if_index) { 756 /* TODO: I'm not sure it takes IPv6 unless in [XX:XX..] format */ 757 source_lsa = xdotted2sockaddr(opt_I, 0); 758 } 759 } 760 /* foxconn wklin modified start, 10/19/2010 */ 761 if (option_mask32 & OPT_g) 762 ping_trig = 1; 763 else 764 ping_trig = 0; 765 /* with this I can return as soon as I get the first reply */ 766 if (option_mask32 & OPT_f) 767 fast_check = 1; 768 else 769 fast_check = 0; 770 /* wklin added end, 09/30/2010 */ 771 myid = (uint16_t) getpid(); 772 hostname = argv[optind]; 773 /* foxconn dennis modified start, 2010/10/21 */ 774 signal(SIGALRM, noresp); 775 /* Foxconn Perry modified start, 2011/08/02, for secondary DNS query */ 776 /* 1. change the ping timeout from 10 to 15 to avoid DNS query to secondary DNS server failure issue. */ 777 alarm(15); 778 /* Foxconn Perry modified end, 2011/08/02, for secondary DNS query */ 779 /* foxconn dennis modified end, 2010/10/21 */ 780 781#if ENABLE_PING6 782 if (option_mask32 & OPT_IPV4) 783 af = AF_INET; 784 if (option_mask32 & OPT_IPV6) 785 af = AF_INET6; 786 lsa = xhost_and_af2sockaddr(hostname, 0, af); 787#else 788 lsa = xhost_and_af2sockaddr(hostname, 0, AF_INET); 789#endif 790 791 if (source_lsa && source_lsa->sa.sa_family != lsa->sa.sa_family) 792 /* leaking it here... */ 793 source_lsa = NULL; 794 795 dotted = xmalloc_sockaddr2dotted_noport(&lsa->sa); 796 ping(lsa); 797 pingstats(0); 798 return EXIT_SUCCESS; 799} 800#endif /* FEATURE_FANCY_PING */ 801 802 803#if ENABLE_PING6 804int ping6_main(int argc, char **argv); 805int ping6_main(int argc, char **argv) 806{ 807 argv[0] = (char*)"-6"; 808 return ping_main(argc + 1, argv - 1); 809} 810#endif 811 812/* from ping6.c: 813 * Copyright (c) 1989 The Regents of the University of California. 814 * All rights reserved. 815 * 816 * This code is derived from software contributed to Berkeley by 817 * Mike Muuss. 818 * 819 * Redistribution and use in source and binary forms, with or without 820 * modification, are permitted provided that the following conditions 821 * are met: 822 * 1. Redistributions of source code must retain the above copyright 823 * notice, this list of conditions and the following disclaimer. 824 * 2. Redistributions in binary form must reproduce the above copyright 825 * notice, this list of conditions and the following disclaimer in the 826 * documentation and/or other materials provided with the distribution. 827 * 828 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 829 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 830 * 831 * 4. Neither the name of the University nor the names of its contributors 832 * may be used to endorse or promote products derived from this software 833 * without specific prior written permission. 834 * 835 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 836 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 837 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 838 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 839 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 840 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 841 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 842 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 843 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 844 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 845 * SUCH DAMAGE. 846 */ 847