diff options
-rw-r--r-- | include/usage.h | 1 | ||||
-rw-r--r-- | networking/ping.c | 61 | ||||
-rw-r--r-- | networking/ping6.c | 2 |
3 files changed, 52 insertions, 12 deletions
diff --git a/include/usage.h b/include/usage.h index 3e3e8c8..0f56507 100644 --- a/include/usage.h +++ b/include/usage.h @@ -2272,6 +2272,7 @@ USE_FEATURE_MDEV_CONFIG( \ "Options:\n" \ "\t-c COUNT\tSend only COUNT pings\n" \ "\t-s SIZE\t\tSend SIZE data bytes in packets (default=56)\n" \ + "\t-I IPADDR\tUse IPADDR as source address\n" \ "\t-q\t\tQuiet mode, only displays output at start\n" \ "\t\t\tand when finished" #endif diff --git a/networking/ping.c b/networking/ping.c index 967a3e3..18fb926 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -155,6 +155,7 @@ int ping_main(int argc, char **argv) #else /* ! CONFIG_FEATURE_FANCY_PING */ /* full(er) version */ static struct sockaddr_in pingaddr; +static struct sockaddr_in sourceaddr; static int pingsock = -1; static int datalen; /* intentionally uninitialized to work around gcc bug */ @@ -264,16 +265,15 @@ static void unpack(char *buf, int sz, struct sockaddr_in *from) gettimeofday(&tv, NULL); - /* check IP header */ - iphdr = (struct iphdr *) buf; - hlen = iphdr->ihl << 2; /* discard if too short */ if (sz < (datalen + ICMP_MINLEN)) return; + /* check IP header */ + iphdr = (struct iphdr *) buf; + hlen = iphdr->ihl << 2; sz -= hlen; icmppkt = (struct icmp *) (buf + hlen); - if (icmppkt->icmp_id != myid) return; /* not our ping */ @@ -329,12 +329,17 @@ static void ping(const char *host) pingsock = create_icmp_socket(); + if (sourceaddr.sin_addr.s_addr) { + if (bind(pingsock, (struct sockaddr*)&sourceaddr, sizeof(sourceaddr)) == -1) + bb_error_msg_and_die("could not bind to address"); + } + memset(&pingaddr, 0, sizeof(struct sockaddr_in)); pingaddr.sin_family = AF_INET; hostent = xgethostbyname(host); if (hostent->h_addrtype != AF_INET) - bb_error_msg_and_die("unknown address type; only AF_INET is currently supported."); + bb_error_msg_and_die("unknown address type; only AF_INET is currently supported"); memcpy(&pingaddr.sin_addr, hostent->h_addr, sizeof(pingaddr.sin_addr)); @@ -348,10 +353,14 @@ static void ping(const char *host) setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt, sizeof(sockopt)); - printf("PING %s (%s): %d data bytes\n", - hostent->h_name, - inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr), - datalen); + printf("PING %s (%s)", + hostent->h_name, + inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr)); + 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); @@ -378,6 +387,27 @@ static void ping(const char *host) pingstats(0); } +/* 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) +{ + 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; + } + return 1; /* error */ +} + int ping_main(int argc, char **argv) { char *thisarg; @@ -386,7 +416,6 @@ int ping_main(int argc, char **argv) argc--; argv++; - options = 0; /* Parse any options */ while (argc >= 1 && **argv == '-') { thisarg = *argv; @@ -407,6 +436,18 @@ int ping_main(int argc, char **argv) argv++; datalen = atoi(*argv); break; + case 'I': + if (--argc <= 0) + bb_show_usage(); + argv++; +/* ping6 accepts iface too: + if_index = if_nametoindex(*argv); + if (!if_index) ... + make it true for ping too. TODO. +*/ + if (parse_nipquad(*argv, &sourceaddr)) + bb_show_usage(); + break; default: bb_show_usage(); } diff --git a/networking/ping6.c b/networking/ping6.c index 38d605c..267109c 100644 --- a/networking/ping6.c +++ b/networking/ping6.c @@ -265,7 +265,6 @@ static void unpack(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit return; icmppkt = (struct icmp6_hdr *) packet; - if (icmppkt->icmp6_id != myid) return; /* not our ping */ @@ -423,7 +422,6 @@ int ping6_main(int argc, char **argv) argc--; argv++; - options = 0; /* Parse any options */ while (argc >= 1 && **argv == '-') { thisarg = *argv; |