diff --git a/include/libbb.h b/include/libbb.h index bb4a68741..218a1935c 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -321,6 +321,7 @@ int xconnect_stream(const len_and_sockaddr *lsa); len_and_sockaddr* host2sockaddr(const char *host, int port); /* Version which dies on error */ len_and_sockaddr* xhost2sockaddr(const char *host, int port); +len_and_sockaddr* xdotted2sockaddr(const char *host, int port); #if ENABLE_FEATURE_IPV6 /* Same, useful if you want to force family (e.g. IPv6) */ len_and_sockaddr* host_and_af2sockaddr(const char *host, int port, sa_family_t af); diff --git a/include/usage.h b/include/usage.h index 17dcf9be9..fb1617a7c 100644 --- a/include/usage.h +++ b/include/usage.h @@ -2428,20 +2428,22 @@ #define ping_full_usage \ "Send ICMP ECHO_REQUEST packets to network hosts" \ "\n\nOptions:\n" \ - " -c CNT Send only CNT pings\n" \ - " -s SIZE Send SIZE data bytes in packets (default=56)\n" \ - " -I IP Use IP as source address\n" \ - " -q Quiet mode, only displays output at start\n" \ - " and when finished" + " -4, -6 Force IPv4 or IPv6 hostname resolution\n" \ + " -c CNT Send only CNT pings\n" \ + " -s SIZE Send SIZE data bytes in packets (default=56)\n" \ + " -I iface/IP Use interface or IP address as source\n" \ + " -q Quiet mode, only displays output at start\n" \ + " and when finished" #define ping6_trivial_usage \ "[OPTION]... host" #define ping6_full_usage \ "Send ICMP ECHO_REQUEST packets to network hosts" \ "\n\nOptions:\n" \ - " -c CNT Send only CNT pings\n" \ - " -s SIZE Send SIZE data bytes in packets (default=56)\n" \ - " -q Quiet mode, only displays output at start\n" \ - " and when finished" + " -c CNT Send only CNT pings\n" \ + " -s SIZE Send SIZE data bytes in packets (default=56)\n" \ + " -I iface/IP Use interface or IP address as source\n" \ + " -q Quiet mode, only displays output at start\n" \ + " and when finished" #endif #define ping_example_usage \ "$ ping localhost\n" \ diff --git a/libbb/xconnect.c b/libbb/xconnect.c index 66b136615..118fe3e75 100644 --- a/libbb/xconnect.c +++ b/libbb/xconnect.c @@ -203,7 +203,7 @@ len_and_sockaddr* xhost2sockaddr(const char *host, int port) return str2sockaddr(host, port, AF_UNSPEC, DIE_ON_ERROR); } -static len_and_sockaddr* xdotted2sockaddr(const char *host, int port) +len_and_sockaddr* xdotted2sockaddr(const char *host, int port) { return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR); } diff --git a/networking/ping.c b/networking/ping.c index e76584341..9bf38130e 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -254,7 +254,7 @@ static union { struct sockaddr_in6 sin6; #endif } pingaddr; -static struct sockaddr_in sourceaddr; +static len_and_sockaddr *source_lsa; static int pingsock = -1; static unsigned datalen; /* intentionally uninitialized to work around gcc bug */ @@ -561,9 +561,8 @@ static void ping4(len_and_sockaddr *lsa) pingsock = create_icmp_socket(); pingaddr.sin = lsa->sin; - if (sourceaddr.sin_addr.s_addr) { - xbind(pingsock, (struct sockaddr*)&sourceaddr, sizeof(sourceaddr)); - } + if (source_lsa) + xbind(pingsock, &lsa->sa, lsa->len); /* enable broadcast pings */ setsockopt_broadcast(pingsock); @@ -572,13 +571,6 @@ static void ping4(len_and_sockaddr *lsa) sockopt = 48 * 1024; /* explain why 48k? */ setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); - printf("PING %s (%s)", hostname, dotted); - if (sourceaddr.sin_addr.s_addr) { - printf(" from %s", - inet_ntoa(*(struct in_addr *) &sourceaddr.sin_addr.s_addr)); - } - printf(": %d data bytes\n", datalen); - signal(SIGINT, pingstats); /* start the ping's going ... */ @@ -615,9 +607,9 @@ static void ping6(len_and_sockaddr *lsa) pingsock = create_icmp6_socket(); pingaddr.sin6 = lsa->sin6; - //if (sourceaddr.sin_addr.s_addr) { - // xbind(pingsock, (struct sockaddr*)&sourceaddr, sizeof(sourceaddr)); - //} + /* untested whether "-I addr" really works for IPv6: */ + if (source_lsa) + xbind(pingsock, &lsa->sa, lsa->len); #ifdef ICMP6_FILTER { @@ -652,8 +644,6 @@ static void ping6(len_and_sockaddr *lsa) if (if_index) pingaddr.sin6.sin6_scope_id = if_index; - printf("PING %s (%s): %d data bytes\n", hostname, dotted, datalen); - signal(SIGINT, pingstats); /* start the ping's going ... */ @@ -695,25 +685,21 @@ static void ping6(len_and_sockaddr *lsa) } #endif -/* TODO: consolidate ether-wake.c, dnsd.c, ifupdown.c, nslookup.c - * versions of below thing. BTW we have far too many "%u.%u.%u.%u" too... -*/ -static int parse_nipquad(const char *str, struct sockaddr_in* addr) +static void ping(len_and_sockaddr *lsa) { - char dummy; - unsigned i1, i2, i3, i4; - if (sscanf(str, "%u.%u.%u.%u%c", - &i1, &i2, &i3, &i4, &dummy) == 4 - && ( (i1|i2|i3|i4) <= 0xff ) - ) { - uint8_t* ptr = (uint8_t*)&addr->sin_addr; - ptr[0] = i1; - ptr[1] = i2; - ptr[2] = i3; - ptr[3] = i4; - return 0; + printf("PING %s (%s)", hostname, dotted); + if (source_lsa) { + printf(" from %s", + xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len)); } - return 1; /* error */ + printf(": %d data bytes\n", datalen); + +#if ENABLE_PING6 + if (lsa->sa.sa_family == AF_INET6) + ping6(lsa); + else +#endif + ping4(lsa); } int ping_main(int argc, char **argv); @@ -732,9 +718,11 @@ int ping_main(int argc, char **argv) if (option_mask32 & OPT_s) datalen = xatou16(opt_s); // -s if (option_mask32 & OPT_I) { // -I if_index = if_nametoindex(opt_I); - if (!if_index) - if (parse_nipquad(opt_I, &sourceaddr)) - bb_show_usage(); + if (!if_index) { + /* TODO: I'm not sure it takes IPv6 unless in [XX:XX..] format */ + /* (ping doesn't support source IPv6 addresses yet anyway) */ + source_lsa = xdotted2sockaddr(opt_I, 0); + } } myid = (int16_t) getpid(); hostname = argv[optind]; @@ -747,13 +735,13 @@ int ping_main(int argc, char **argv) #else lsa = xhost_and_af2sockaddr(hostname, 0, AF_INET); #endif + + if (source_lsa && source_lsa->sa.sa_family != lsa->sa.sa_family) + /* leaking it here... */ + source_lsa = NULL; + dotted = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len); -#if ENABLE_PING6 - if (lsa->sa.sa_family == AF_INET6) - ping6(lsa); - else -#endif - ping4(lsa); + ping(lsa); pingstats(0); return EXIT_SUCCESS; }