ping: implement -I option
authorDenis Vlasenko <vda.linux@googlemail.com>
Sat, 2 Sep 2006 16:17:30 +0000 (16:17 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sat, 2 Sep 2006 16:17:30 +0000 (16:17 -0000)
include/usage.h
networking/ping.c
networking/ping6.c

index 3e3e8c84aecce28a4179675237327b37d609363f..0f56507ce3bac9c8d40f2ace21391b76c1ea9b64 100644 (file)
@@ -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
index 967a3e3788e5e34f2785c19f67b4e2ce74a6b199..18fb926ad28ad8202a9c7ef1e6b89c6e059ea35d 100644 (file)
@@ -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();
                }
index 38d605c6d162448b93317afdcebf8a8fcef6ba21..267109c9f0e486815f87376e4ed24ba7c2f72f25 100644 (file)
@@ -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;