aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-01-24 23:53:22 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-01-24 23:53:22 +0000
commitb9a279ba9466d8733261aff1bab0d3ec1031c34c (patch)
tree6a995795abf0322f540585a6c4d28847fbebb773
parent677cb5eea52f2424bef1fd0fcc6ed3c8c8b5f1d5 (diff)
downloadbusybox-w32-b9a279ba9466d8733261aff1bab0d3ec1031c34c.tar.gz
busybox-w32-b9a279ba9466d8733261aff1bab0d3ec1031c34c.tar.bz2
busybox-w32-b9a279ba9466d8733261aff1bab0d3ec1031c34c.zip
Unify ping and ping6. ping has -4 and -6 which force
name resolution into IP or IPv6 only, otherwise we take address family returned by host2sockaddr() in lsa->sa.sa_family. IOW: "ping ::1" with do IPv6 ping, "ping 127.0.0.1" will do IPv4 ping. ping6 is aliased to "ping -6".
-rw-r--r--include/usage.h28
-rw-r--r--libbb/xconnect.c2
-rw-r--r--networking/Config.in18
-rw-r--r--networking/Kbuild2
-rw-r--r--networking/ping.c521
-rw-r--r--networking/ping6.c471
-rw-r--r--scripts/defconfig1
7 files changed, 472 insertions, 571 deletions
diff --git a/include/usage.h b/include/usage.h
index 8ddd1166b..c29c6c898 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -2401,6 +2401,10 @@
2401 "host" 2401 "host"
2402#define ping_full_usage \ 2402#define ping_full_usage \
2403 "Send ICMP ECHO_REQUEST packets to network hosts" 2403 "Send ICMP ECHO_REQUEST packets to network hosts"
2404#define ping6_trivial_usage \
2405 "host"
2406#define ping6_full_usage \
2407 "Send ICMP ECHO_REQUEST packets to network hosts"
2404#else 2408#else
2405#define ping_trivial_usage \ 2409#define ping_trivial_usage \
2406 "[OPTION]... host" 2410 "[OPTION]... host"
@@ -2412,22 +2416,6 @@
2412 " -I IP Use IP as source address\n" \ 2416 " -I IP Use IP as source address\n" \
2413 " -q Quiet mode, only displays output at start\n" \ 2417 " -q Quiet mode, only displays output at start\n" \
2414 " and when finished" 2418 " and when finished"
2415#endif
2416#define ping_example_usage \
2417 "$ ping localhost\n" \
2418 "PING slag (127.0.0.1): 56 data bytes\n" \
2419 "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" \
2420 "\n" \
2421 "--- debian ping statistics ---\n" \
2422 "1 packets transmitted, 1 packets received, 0% packet loss\n" \
2423 "round-trip min/avg/max = 20.1/20.1/20.1 ms\n"
2424
2425#ifndef CONFIG_FEATURE_FANCY_PING6
2426#define ping6_trivial_usage \
2427 "host"
2428#define ping6_full_usage \
2429 "Send ICMP ECHO_REQUEST packets to network hosts"
2430#else
2431#define ping6_trivial_usage \ 2419#define ping6_trivial_usage \
2432 "[OPTION]... host" 2420 "[OPTION]... host"
2433#define ping6_full_usage \ 2421#define ping6_full_usage \
@@ -2438,6 +2426,14 @@
2438 " -q Quiet mode, only displays output at start\n" \ 2426 " -q Quiet mode, only displays output at start\n" \
2439 " and when finished" 2427 " and when finished"
2440#endif 2428#endif
2429#define ping_example_usage \
2430 "$ ping localhost\n" \
2431 "PING slag (127.0.0.1): 56 data bytes\n" \
2432 "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" \
2433 "\n" \
2434 "--- debian ping statistics ---\n" \
2435 "1 packets transmitted, 1 packets received, 0% packet loss\n" \
2436 "round-trip min/avg/max = 20.1/20.1/20.1 ms\n"
2441#define ping6_example_usage \ 2437#define ping6_example_usage \
2442 "$ ping6 ip6-localhost\n" \ 2438 "$ ping6 ip6-localhost\n" \
2443 "PING ip6-localhost (::1): 56 data bytes\n" \ 2439 "PING ip6-localhost (::1): 56 data bytes\n" \
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
index 61fe7fd6c..2b35baab7 100644
--- a/libbb/xconnect.c
+++ b/libbb/xconnect.c
@@ -296,10 +296,12 @@ char* xmalloc_sockaddr2host(const struct sockaddr *sa, socklen_t salen)
296 return sockaddr2str(sa, salen, 0); 296 return sockaddr2str(sa, salen, 0);
297} 297}
298 298
299/* Unused
299char* xmalloc_sockaddr2host_noport(const struct sockaddr *sa, socklen_t salen) 300char* xmalloc_sockaddr2host_noport(const struct sockaddr *sa, socklen_t salen)
300{ 301{
301 return sockaddr2str(sa, salen, IGNORE_PORT); 302 return sockaddr2str(sa, salen, IGNORE_PORT);
302} 303}
304*/
303 305
304char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa, socklen_t salen) 306char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa, socklen_t salen)
305{ 307{
diff --git a/networking/Config.in b/networking/Config.in
index 0251a1401..2235dbe3f 100644
--- a/networking/Config.in
+++ b/networking/Config.in
@@ -501,27 +501,19 @@ config PING
501 ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to 501 ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to
502 elicit an ICMP ECHO_RESPONSE from a host or gateway. 502 elicit an ICMP ECHO_RESPONSE from a host or gateway.
503 503
504config FEATURE_FANCY_PING
505 bool "Enable fancy ping output"
506 default y
507 depends on PING
508 help
509 Make the output from the ping applet include statistics, and at the
510 same time provide full support for ICMP packets.
511
512config PING6 504config PING6
513 bool "ping6" 505 bool "ping6"
514 default n 506 default n
515 depends on FEATURE_IPV6 507 depends on FEATURE_IPV6 && PING
516 help 508 help
517 This will give you a ping that can talk IPv6. 509 This will give you a ping that can talk IPv6.
518 510
519config FEATURE_FANCY_PING6 511config FEATURE_FANCY_PING
520 bool "Enable fancy ping6 output" 512 bool "Enable fancy ping output"
521 default y 513 default y
522 depends on PING6 514 depends on PING
523 help 515 help
524 Make the output from the ping6 applet include statistics, and at the 516 Make the output from the ping applet include statistics, and at the
525 same time provide full support for ICMP packets. 517 same time provide full support for ICMP packets.
526 518
527config ROUTE 519config ROUTE
diff --git a/networking/Kbuild b/networking/Kbuild
index 65ecfbf5f..68d36132d 100644
--- a/networking/Kbuild
+++ b/networking/Kbuild
@@ -29,7 +29,7 @@ lib-$(CONFIG_NC) += nc.o
29lib-$(CONFIG_NETSTAT) += netstat.o 29lib-$(CONFIG_NETSTAT) += netstat.o
30lib-$(CONFIG_NSLOOKUP) += nslookup.o 30lib-$(CONFIG_NSLOOKUP) += nslookup.o
31lib-$(CONFIG_PING) += ping.o 31lib-$(CONFIG_PING) += ping.o
32lib-$(CONFIG_PING6) += ping6.o 32lib-$(CONFIG_PING6) += ping.o
33lib-$(CONFIG_ROUTE) += route.o 33lib-$(CONFIG_ROUTE) += route.o
34lib-$(CONFIG_TELNET) += telnet.o 34lib-$(CONFIG_TELNET) += telnet.o
35lib-$(CONFIG_TELNETD) += telnetd.o 35lib-$(CONFIG_TELNETD) += telnetd.o
diff --git a/networking/ping.c b/networking/ping.c
index fc2de456a..7d36b7455 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -13,9 +13,30 @@
13 * 13 *
14 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 14 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
15 */ 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 */
16 27
28#include <net/if.h>
17#include <netinet/ip_icmp.h> 29#include <netinet/ip_icmp.h>
18#include "busybox.h" 30#include "busybox.h"
31#if ENABLE_PING6
32#include <netinet/icmp6.h>
33/* I see RENUMBERED constants in bits/in.h - !!?
34 * What a fuck is going on with libc? Is it a glibc joke? */
35#ifdef IPV6_2292HOPLIMIT
36#undef IPV6_HOPLIMIT
37#define IPV6_HOPLIMIT IPV6_2292HOPLIMIT
38#endif
39#endif
19 40
20enum { 41enum {
21 DEFDATALEN = 56, 42 DEFDATALEN = 56,
@@ -24,11 +45,9 @@ enum {
24 MAXPACKET = 65468, 45 MAXPACKET = 65468,
25 MAX_DUP_CHK = (8 * 128), 46 MAX_DUP_CHK = (8 * 128),
26 MAXWAIT = 10, 47 MAXWAIT = 10,
27 PINGINTERVAL = 1 /* second */ 48 PINGINTERVAL = 1, /* 1 second */
28}; 49};
29 50
30static void ping(const char *host);
31
32/* common routines */ 51/* common routines */
33 52
34static int in_cksum(unsigned short *buf, int sz) 53static int in_cksum(unsigned short *buf, int sz)
@@ -54,34 +73,27 @@ static int in_cksum(unsigned short *buf, int sz)
54 return ans; 73 return ans;
55} 74}
56 75
57#ifndef CONFIG_FEATURE_FANCY_PING 76#if !ENABLE_FEATURE_FANCY_PING
58 77
59/* simple version */ 78/* simple version */
60 79
61static char *hostname; 80static char *hostname;
62 81
63static void noresp(int ign) 82static void noresp(int ign ATTRIBUTE_UNUSED)
64{ 83{
65 printf("No response from %s\n", hostname); 84 printf("No response from %s\n", hostname);
66 exit(EXIT_FAILURE); 85 exit(EXIT_FAILURE);
67} 86}
68 87
69static void ping(const char *host) 88static void ping(len_and_sockaddr *lsa)
70{ 89{
71 struct hostent *h;
72 struct sockaddr_in pingaddr; 90 struct sockaddr_in pingaddr;
73 struct icmp *pkt; 91 struct icmp *pkt;
74 int pingsock, c; 92 int pingsock, c;
75 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; 93 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
76 94
77 pingsock = create_icmp_socket(); 95 pingsock = create_icmp_socket();
78 96 pingaddr = lsa->sin;
79 memset(&pingaddr, 0, sizeof(pingaddr));
80
81 pingaddr.sin_family = AF_INET;
82 h = xgethostbyname(host);
83 memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr));
84 hostname = h->h_name;
85 97
86 pkt = (struct icmp *) packet; 98 pkt = (struct icmp *) packet;
87 memset(pkt, 0, sizeof(packet)); 99 memset(pkt, 0, sizeof(packet));
@@ -89,15 +101,14 @@ static void ping(const char *host)
89 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); 101 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));
90 102
91 c = sendto(pingsock, packet, DEFDATALEN + ICMP_MINLEN, 0, 103 c = sendto(pingsock, packet, DEFDATALEN + ICMP_MINLEN, 0,
92 (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in)); 104 (struct sockaddr *) &pingaddr, sizeof(pingaddr));
93 105
94 if (c < 0) { 106 if (c < 0) {
95 if (ENABLE_FEATURE_CLEAN_UP) close(pingsock); 107 if (ENABLE_FEATURE_CLEAN_UP)
108 close(pingsock);
96 bb_perror_msg_and_die("sendto"); 109 bb_perror_msg_and_die("sendto");
97 } 110 }
98 111
99 signal(SIGALRM, noresp);
100 alarm(5); /* give the host 5000ms to respond */
101 /* listen for replies */ 112 /* listen for replies */
102 while (1) { 113 while (1) {
103 struct sockaddr_in from; 114 struct sockaddr_in from;
@@ -120,43 +131,140 @@ static void ping(const char *host)
120 } 131 }
121 if (ENABLE_FEATURE_CLEAN_UP) 132 if (ENABLE_FEATURE_CLEAN_UP)
122 close(pingsock); 133 close(pingsock);
123 printf("%s is alive!\n", hostname);
124} 134}
125 135
136#if ENABLE_PING6
137static void ping6(len_and_sockaddr *lsa)
138{
139 struct sockaddr_in6 pingaddr;
140 struct icmp6_hdr *pkt;
141 int pingsock, c;
142 int sockopt;
143 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
144
145 pingsock = create_icmp6_socket();
146 pingaddr = lsa->sin6;
147
148 pkt = (struct icmp6_hdr *) packet;
149 memset(pkt, 0, sizeof(packet));
150 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
151
152 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
153 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt));
154
155 c = sendto(pingsock, packet, DEFDATALEN + sizeof (struct icmp6_hdr), 0,
156 (struct sockaddr *) &pingaddr, sizeof(pingaddr));
157
158 if (c < 0) {
159 if (ENABLE_FEATURE_CLEAN_UP)
160 close(pingsock);
161 bb_perror_msg_and_die("sendto");
162 }
163
164 /* listen for replies */
165 while (1) {
166 struct sockaddr_in6 from;
167 socklen_t fromlen = sizeof(from);
168
169 c = recvfrom(pingsock, packet, sizeof(packet), 0,
170 (struct sockaddr *) &from, &fromlen);
171 if (c < 0) {
172 if (errno != EINTR)
173 bb_perror_msg("recvfrom");
174 continue;
175 }
176 if (c >= 8) { /* icmp6_hdr */
177 pkt = (struct icmp6_hdr *) packet;
178 if (pkt->icmp6_type == ICMP6_ECHO_REPLY)
179 break;
180 }
181 }
182 if (ENABLE_FEATURE_CLEAN_UP)
183 close(pingsock);
184}
185#endif
186
126int ping_main(int argc, char **argv) 187int ping_main(int argc, char **argv)
127{ 188{
128 argc--; 189 len_and_sockaddr *lsa;
190#if ENABLE_PING6
191 sa_family_t af = AF_UNSPEC;
192 while (++argv[0][0]) == '-') {
193 if (argv[0][1] == '4') {
194 af = AF_INET;
195 continue;
196 }
197 if (argv[0][1] == '6') {
198 af = AF_INET6;
199 continue;
200 }
201 bb_show_usage();
202 }
203#else
129 argv++; 204 argv++;
130 if (argc < 1) 205#endif
206
207 hostname = *argv;
208 if (!hostname)
131 bb_show_usage(); 209 bb_show_usage();
132 ping(*argv); 210
211#if ENABLE_PING6
212 lsa = host_and_af2sockaddr(hostname, 0, af);
213#else
214 lsa = host_and_af2sockaddr(hostname, 0, AF_INET);
215#endif
216 /* Set timer _after_ DNS resolution */
217 signal(SIGALRM, noresp);
218 alarm(5); /* give the host 5000ms to respond */
219
220#if ENABLE_PING6
221 if (lsa->sa.sa_family == AF_INET6)
222 ping6(lsa);
223 else
224#endif
225 ping(lsa);
226 printf("%s is alive!\n", hostname);
133 return EXIT_SUCCESS; 227 return EXIT_SUCCESS;
134} 228}
135 229
136#else /* ! CONFIG_FEATURE_FANCY_PING */ 230
231#else /* FEATURE_FANCY_PING */
232
137 233
138/* full(er) version */ 234/* full(er) version */
139 235
140#define OPT_STRING "qc:s:I:" 236#define OPT_STRING ("qvc:s:I:4" USE_PING6("6"))
141enum { 237enum {
142 OPT_QUIET = 1 << 0, 238 OPT_QUIET = 1 << 0,
239 OPT_VERBOSE = 1 << 1,
240 OPT_c = 1 << 2,
241 OPT_s = 1 << 3,
242 OPT_I = 1 << 4,
243 OPT_IPV4 = 1 << 5,
244 OPT_IPV6 = (1 << 6) * ENABLE_PING6,
143}; 245};
144 246
145static struct sockaddr_in pingaddr; 247
248static union {
249 struct sockaddr sa;
250 struct sockaddr_in sin;
251#if ENABLE_PING6
252 struct sockaddr_in sin6;
253#endif
254} pingaddr;
146static struct sockaddr_in sourceaddr; 255static struct sockaddr_in sourceaddr;
147static int pingsock = -1; 256static int pingsock = -1;
148static unsigned datalen; /* intentionally uninitialized to work around gcc bug */ 257static unsigned datalen; /* intentionally uninitialized to work around gcc bug */
149 258
259static int if_index;
260
150static unsigned long ntransmitted, nreceived, nrepeats, pingcount; 261static unsigned long ntransmitted, nreceived, nrepeats, pingcount;
151static int myid; 262static int myid;
152static unsigned long tmin = ULONG_MAX, tmax, tsum; 263static unsigned long tmin = ULONG_MAX, tmax, tsum;
153static char rcvd_tbl[MAX_DUP_CHK / 8]; 264static char rcvd_tbl[MAX_DUP_CHK / 8];
154 265
155static struct hostent *hostent; 266static const char *hostname;
156 267static const char *dotted;
157static void sendping(int);
158static void pingstats(int);
159static void unpack(char *, int, struct sockaddr_in *);
160 268
161#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ 269#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
162#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ 270#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
@@ -166,25 +274,25 @@ static void unpack(char *, int, struct sockaddr_in *);
166 274
167/**************************************************************************/ 275/**************************************************************************/
168 276
169static void pingstats(int junk) 277static void pingstats(void)
170{ 278{
171 int status; 279 int status;
172 280
173 signal(SIGINT, SIG_IGN); 281 signal(SIGINT, SIG_IGN);
174 282
175 printf("\n--- %s ping statistics ---\n", hostent->h_name); 283 printf("\n--- %s ping statistics ---\n", hostname);
176 printf("%lu packets transmitted, ", ntransmitted); 284 printf("%lu packets transmitted, ", ntransmitted);
177 printf("%lu packets received, ", nreceived); 285 printf("%lu packets received, ", nreceived);
178 if (nrepeats) 286 if (nrepeats)
179 printf("%lu duplicates, ", nrepeats); 287 printf("%lu duplicates, ", nrepeats);
180 if (ntransmitted) 288 if (ntransmitted)
181 printf("%lu%% packet loss\n", 289 ntransmitted = (ntransmitted - nreceived) * 100 / ntransmitted);
182 (ntransmitted - nreceived) * 100 / ntransmitted); 290 printf("%lu%% packet loss\n", ntransmitted);
183 if (nreceived) 291 if (nreceived)
184 printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n", 292 printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n",
185 tmin / 10, tmin % 10, 293 tmin / 10, tmin % 10,
186 (tsum / (nreceived + nrepeats)) / 10, 294 (tsum / (nreceived + nrepeats)) / 10,
187 (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10); 295 (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10);
188 if (nreceived != 0) 296 if (nreceived != 0)
189 status = EXIT_SUCCESS; 297 status = EXIT_SUCCESS;
190 else 298 else
@@ -192,7 +300,7 @@ static void pingstats(int junk)
192 exit(status); 300 exit(status);
193} 301}
194 302
195static void sendping(int junk) 303static void sendping(int junk ATTRIBUTE_UNUSED)
196{ 304{
197 struct icmp *pkt; 305 struct icmp *pkt;
198 int i; 306 int i;
@@ -212,7 +320,7 @@ static void sendping(int junk)
212 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); 320 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet));
213 321
214 i = sendto(pingsock, packet, sizeof(packet), 0, 322 i = sendto(pingsock, packet, sizeof(packet), 0,
215 (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in)); 323 &pingaddr.sa, sizeof(pingaddr.sin));
216 324
217 if (i < 0) 325 if (i < 0)
218 bb_perror_msg_and_die("sendto"); 326 bb_perror_msg_and_die("sendto");
@@ -223,12 +331,50 @@ static void sendping(int junk)
223 signal(SIGALRM, sendping); 331 signal(SIGALRM, sendping);
224 if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */ 332 if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */
225 alarm(PINGINTERVAL); 333 alarm(PINGINTERVAL);
226 } else { /* done, wait for the last ping to come back */ 334 } else { /* done, wait for the last ping to come back */
335 /* todo, don't necessarily need to wait so long... */
336 signal(SIGALRM, pingstats);
337 alarm(MAXWAIT);
338 }
339}
340#if ENABLE_PING6
341static void sendping6(int junk ATTRIBUTE_UNUSED)
342{
343 struct icmp6_hdr *pkt;
344 int i;
345 char packet[datalen + sizeof (struct icmp6_hdr)];
346
347 pkt = (struct icmp6_hdr *) packet;
348
349 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
350 pkt->icmp6_code = 0;
351 pkt->icmp6_cksum = 0;
352 pkt->icmp6_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */
353 pkt->icmp6_id = myid;
354 CLR((uint16_t)ntransmitted % MAX_DUP_CHK);
355 ntransmitted++;
356
357 gettimeofday((struct timeval *) &pkt->icmp6_data8[4], NULL);
358
359 i = sendto(pingsock, packet, sizeof(packet), 0,
360 &pingaddr.sa, sizeof(pingaddr.sin6));
361
362 if (i < 0)
363 bb_perror_msg_and_die("sendto");
364 if ((size_t)i != sizeof(packet))
365 bb_error_msg_and_die("ping wrote %d chars; %d expected", i,
366 (int)sizeof(packet));
367
368 signal(SIGALRM, sendping6);
369 if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */
370 alarm(PINGINTERVAL);
371 } else { /* done, wait for the last ping to come back */
227 /* todo, don't necessarily need to wait so long... */ 372 /* todo, don't necessarily need to wait so long... */
228 signal(SIGALRM, pingstats); 373 signal(SIGALRM, pingstats);
229 alarm(MAXWAIT); 374 alarm(MAXWAIT);
230 } 375 }
231} 376}
377#endif
232 378
233static char *icmp_type_name(int id) 379static char *icmp_type_name(int id)
234{ 380{
@@ -249,6 +395,34 @@ static char *icmp_type_name(int id)
249 default: return "unknown ICMP type"; 395 default: return "unknown ICMP type";
250 } 396 }
251} 397}
398#if ENABLE_PING6
399/* RFC3542 changed some definitions from RFC2292 for no good reason, whee!
400 * the newer 3542 uses a MLD_ prefix where as 2292 uses ICMP6_ prefix */
401#ifndef MLD_LISTENER_QUERY
402# define MLD_LISTENER_QUERY ICMP6_MEMBERSHIP_QUERY
403#endif
404#ifndef MLD_LISTENER_REPORT
405# define MLD_LISTENER_REPORT ICMP6_MEMBERSHIP_REPORT
406#endif
407#ifndef MLD_LISTENER_REDUCTION
408# define MLD_LISTENER_REDUCTION ICMP6_MEMBERSHIP_REDUCTION
409#endif
410static char *icmp6_type_name(int id)
411{
412 switch (id) {
413 case ICMP6_DST_UNREACH: return "Destination Unreachable";
414 case ICMP6_PACKET_TOO_BIG: return "Packet too big";
415 case ICMP6_TIME_EXCEEDED: return "Time Exceeded";
416 case ICMP6_PARAM_PROB: return "Parameter Problem";
417 case ICMP6_ECHO_REPLY: return "Echo Reply";
418 case ICMP6_ECHO_REQUEST: return "Echo Request";
419 case MLD_LISTENER_QUERY: return "Listener Query";
420 case MLD_LISTENER_REPORT: return "Listener Report";
421 case MLD_LISTENER_REDUCTION: return "Listener Reduction";
422 default: return "unknown ICMP type";
423 }
424}
425#endif
252 426
253static void unpack(char *buf, int sz, struct sockaddr_in *from) 427static void unpack(char *buf, int sz, struct sockaddr_in *from)
254{ 428{
@@ -318,27 +492,85 @@ static void unpack(char *buf, int sz, struct sockaddr_in *from)
318 } 492 }
319 fflush(stdout); 493 fflush(stdout);
320} 494}
495#if ENABLE_PING6
496static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit)
497{
498 struct icmp6_hdr *icmppkt;
499 struct timeval tv, *tp;
500 int dupflag;
501 unsigned long triptime;
502 char buf[INET6_ADDRSTRLEN];
503
504 gettimeofday(&tv, NULL);
505
506 /* discard if too short */
507 if (sz < (datalen + sizeof(struct icmp6_hdr)))
508 return;
509
510 icmppkt = (struct icmp6_hdr *) packet;
511 if (icmppkt->icmp6_id != myid)
512 return; /* not our ping */
513
514 if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) {
515 uint16_t recv_seq = ntohs(icmppkt->icmp6_seq);
516 ++nreceived;
517 tp = (struct timeval *) &icmppkt->icmp6_data8[4];
518
519 if ((tv.tv_usec -= tp->tv_usec) < 0) {
520 --tv.tv_sec;
521 tv.tv_usec += 1000000;
522 }
523 tv.tv_sec -= tp->tv_sec;
524
525 triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100);
526 tsum += triptime;
527 if (triptime < tmin)
528 tmin = triptime;
529 if (triptime > tmax)
530 tmax = triptime;
531
532 if (TST(recv_seq % MAX_DUP_CHK)) {
533 ++nrepeats;
534 --nreceived;
535 dupflag = 1;
536 } else {
537 SET(recv_seq % MAX_DUP_CHK);
538 dupflag = 0;
539 }
540
541 if (option_mask32 & OPT_QUIET)
542 return;
543
544 printf("%d bytes from %s: icmp6_seq=%u", sz,
545 inet_ntop(AF_INET6, &pingaddr.sin6.sin6_addr,
546 buf, sizeof(buf)),
547 recv_seq);
548 printf(" ttl=%d time=%lu.%lu ms", hoplimit,
549 triptime / 10, triptime % 10);
550 if (dupflag)
551 printf(" (DUP!)");
552 puts("");
553 } else {
554 if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST)
555 bb_error_msg("warning: got ICMP %d (%s)",
556 icmppkt->icmp6_type,
557 icmp6_type_name(icmppkt->icmp6_type));
558 }
559 fflush(stdout);
560}
561#endif
321 562
322static void ping(const char *host) 563static void ping(len_and_sockaddr *lsa)
323{ 564{
324 char packet[datalen + MAXIPLEN + MAXICMPLEN]; 565 char packet[datalen + MAXIPLEN + MAXICMPLEN];
325 int sockopt; 566 int sockopt;
326 567
327 pingsock = create_icmp_socket(); 568 pingsock = create_icmp_socket();
328 569 pingaddr.sin = lsa->sin;
329 if (sourceaddr.sin_addr.s_addr) { 570 if (sourceaddr.sin_addr.s_addr) {
330 xbind(pingsock, (struct sockaddr*)&sourceaddr, sizeof(sourceaddr)); 571 xbind(pingsock, (struct sockaddr*)&sourceaddr, sizeof(sourceaddr));
331 } 572 }
332 573
333 memset(&pingaddr, 0, sizeof(pingaddr));
334
335 pingaddr.sin_family = AF_INET;
336 hostent = xgethostbyname(host);
337 if (hostent->h_addrtype != AF_INET)
338 bb_error_msg_and_die("unknown address type; only AF_INET is currently supported");
339
340 memcpy(&pingaddr.sin_addr, hostent->h_addr, sizeof(pingaddr.sin_addr));
341
342 /* enable broadcast pings */ 574 /* enable broadcast pings */
343 setsockopt_broadcast(pingsock); 575 setsockopt_broadcast(pingsock);
344 576
@@ -346,9 +578,7 @@ static void ping(const char *host)
346 sockopt = 48 * 1024; /* explain why 48k? */ 578 sockopt = 48 * 1024; /* explain why 48k? */
347 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); 579 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt));
348 580
349 printf("PING %s (%s)", 581 printf("PING %s (%s)", hostname, dotted);
350 hostent->h_name,
351 inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr));
352 if (sourceaddr.sin_addr.s_addr) { 582 if (sourceaddr.sin_addr.s_addr) {
353 printf(" from %s", 583 printf(" from %s",
354 inet_ntoa(*(struct in_addr *) &sourceaddr.sin_addr.s_addr)); 584 inet_ntoa(*(struct in_addr *) &sourceaddr.sin_addr.s_addr));
@@ -377,8 +607,100 @@ static void ping(const char *host)
377 if (pingcount > 0 && nreceived >= pingcount) 607 if (pingcount > 0 && nreceived >= pingcount)
378 break; 608 break;
379 } 609 }
380 pingstats(0);
381} 610}
611#if ENABLE_PING6
612extern int BUG_bad_offsetof_icmp6_cksum(void);
613static void ping6(len_and_sockaddr *lsa)
614{
615 char packet[datalen + MAXIPLEN + MAXICMPLEN];
616 char buf[INET6_ADDRSTRLEN];
617 int sockopt;
618 struct msghdr msg;
619 struct sockaddr_in6 from;
620 struct iovec iov;
621 char control_buf[CMSG_SPACE(36)];
622
623 pingsock = create_icmp6_socket();
624 pingaddr.sin6 = lsa->sin6;
625 //if (sourceaddr.sin_addr.s_addr) {
626 // xbind(pingsock, (struct sockaddr*)&sourceaddr, sizeof(sourceaddr));
627 //}
628
629#ifdef ICMP6_FILTER
630 {
631 struct icmp6_filter filt;
632 if (!(option_mask32 & OPT_VERBOSE)) {
633 ICMP6_FILTER_SETBLOCKALL(&filt);
634 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);
635 } else {
636 ICMP6_FILTER_SETPASSALL(&filt);
637 }
638 if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
639 sizeof(filt)) < 0)
640 bb_error_msg_and_die("setsockopt(ICMP6_FILTER)");
641 }
642#endif /*ICMP6_FILTER*/
643
644 /* enable broadcast pings */
645 setsockopt_broadcast(pingsock);
646
647 /* set recv buf for broadcast pings */
648 sockopt = 48 * 1024; /* explain why 48k? */
649 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt));
650
651 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
652 if (offsetof(struct icmp6_hdr, icmp6_cksum) != 2)
653 BUG_bad_offsetof_icmp6_cksum();
654 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt));
655
656 /* request ttl info to be returned in ancillary data */
657 setsockopt(pingsock, SOL_IPV6, IPV6_HOPLIMIT, &const_int_1, sizeof(const_int_1));
658
659 if (if_index)
660 pingaddr.sin6_scope_id = if_index;
661
662 printf("PING %s (%s): %d data bytes\n", hostname, dotted, datalen);
663
664 signal(SIGINT, pingstats);
665
666 /* start the ping's going ... */
667 sendping6(0);
668
669 /* listen for replies */
670 msg.msg_name = &from;
671 msg.msg_namelen = sizeof(from);
672 msg.msg_iov = &iov;
673 msg.msg_iovlen = 1;
674 msg.msg_control = control_buf;
675 iov.iov_base = packet;
676 iov.iov_len = sizeof(packet);
677 while (1) {
678 int c;
679 struct cmsghdr *mp;
680 int hoplimit = -1;
681 msg.msg_controllen = sizeof(control_buf);
682
683 c = recvmsg(pingsock, &msg, 0);
684 if (c < 0) {
685 if (errno != EINTR)
686 bb_perror_msg("recvfrom");
687 continue;
688 }
689 for (mp = CMSG_FIRSTHDR(&msg); mp; mp = CMSG_NXTHDR(&msg, mp)) {
690 if (mp->cmsg_level == SOL_IPV6
691 && mp->cmsg_type == IPV6_HOPLIMIT
692 /* don't check len - we trust the kernel: */
693 /* && mp->cmsg_len >= CMSG_LEN(sizeof(int)) */
694 ) {
695 hoplimit = *(int*)CMSG_DATA(mp);
696 }
697 }
698 unpack6(packet, c, &from, hoplimit);
699 if (pingcount > 0 && nreceived >= pingcount)
700 break;
701 }
702}
703#endif
382 704
383/* TODO: consolidate ether-wake.c, dnsd.c, ifupdown.c, nslookup.c 705/* TODO: consolidate ether-wake.c, dnsd.c, ifupdown.c, nslookup.c
384 * versions of below thing. BTW we have far too many "%u.%u.%u.%u" too... 706 * versions of below thing. BTW we have far too many "%u.%u.%u.%u" too...
@@ -403,26 +725,87 @@ static int parse_nipquad(const char *str, struct sockaddr_in* addr)
403 725
404int ping_main(int argc, char **argv) 726int ping_main(int argc, char **argv)
405{ 727{
728 const char *hostname;
406 char *opt_c, *opt_s, *opt_I; 729 char *opt_c, *opt_s, *opt_I;
730 USE_PING6(sa_family_t af = AF_UNSPEC;)
407 731
408 datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */ 732 datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */
409 733
410 /* exactly one argument needed */ 734 /* exactly one argument needed, -v and -q don't mix. So do 4, 6 */
411 opt_complementary = "=1"; 735 opt_complementary = "=1:q--v:v--q" USE_PING6(":4--6:6--4");
412 getopt32(argc, argv, OPT_STRING, &opt_c, &opt_s, &opt_I); 736 getopt32(argc, argv, OPT_STRING, &opt_c, &opt_s, &opt_I);
413 if (option_mask32 & 2) pingcount = xatoul(opt_c); // -c 737 if (option_mask32 & OPT_c) pingcount = xatoul(opt_c); // -c
414 if (option_mask32 & 4) datalen = xatou16(opt_s); // -s 738 if (option_mask32 & OPT_s) datalen = xatou16(opt_s); // -s
415 if (option_mask32 & 8) { // -I 739 if (option_mask32 & OPT_I) { // -I
416/* TODO: ping6 accepts iface too: 740 if_index = if_nametoindex(opt_I);
417 if_index = if_nametoindex(*argv); 741 if (!if_index)
418 if (!if_index) ... 742 if (parse_nipquad(opt_I, &sourceaddr))
419make it true for ping. */ 743 bb_show_usage();
420 if (parse_nipquad(opt_I, &sourceaddr))
421 bb_show_usage();
422 } 744 }
423
424 myid = (int16_t) getpid(); 745 myid = (int16_t) getpid();
425 ping(argv[optind]); 746 hostname = argv[optind];
747#if ENABLE_PING6
748 if (option_mask32 & OPT_IPV4)
749 af = AF_INET;
750 if (option_mask32 & OPT_IPV6)
751 af = AF_INET6;
752 lsa = host_and_af2sockaddr(hostname, 0, af);
753#else
754 lsa = host_and_af2sockaddr(hostname, 0, AF_INET);
755#endif
756 dotted = xmalloc_sockaddr2dotted_noport(lsa->sa, lsa->len);
757#if ENABLE_PING6
758 if (lsa->sa.sa_family == AF_INET6)
759 ping6(lsa);
760 else
761#endif
762 ping(lsa);
763 pingstats();
426 return EXIT_SUCCESS; 764 return EXIT_SUCCESS;
427} 765}
428#endif /* ! CONFIG_FEATURE_FANCY_PING */ 766#endif /* FEATURE_FANCY_PING */
767
768
769#if ENABLE_PING6
770int ping6_main(int argc, char **argv)
771{
772 argv[0] = "-6";
773 return ping_main(argc + 1, argv - 1);
774}
775#endif
776
777/* from ping6.c:
778 * Copyright (c) 1989 The Regents of the University of California.
779 * All rights reserved.
780 *
781 * This code is derived from software contributed to Berkeley by
782 * Mike Muuss.
783 *
784 * Redistribution and use in source and binary forms, with or without
785 * modification, are permitted provided that the following conditions
786 * are met:
787 * 1. Redistributions of source code must retain the above copyright
788 * notice, this list of conditions and the following disclaimer.
789 * 2. Redistributions in binary form must reproduce the above copyright
790 * notice, this list of conditions and the following disclaimer in the
791 * documentation and/or other materials provided with the distribution.
792 *
793 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
794 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
795 *
796 * 4. Neither the name of the University nor the names of its contributors
797 * may be used to endorse or promote products derived from this software
798 * without specific prior written permission.
799 *
800 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
801 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
802 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
803 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
804 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
805 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
806 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
807 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
808 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
809 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
810 * SUCH DAMAGE.
811 */
diff --git a/networking/ping6.c b/networking/ping6.c
deleted file mode 100644
index b67fab5b3..000000000
--- a/networking/ping6.c
+++ /dev/null
@@ -1,471 +0,0 @@
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 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 *
9 * This version of ping is adapted from the ping in netkit-base 0.10,
10 * which is:
11 *
12 * Copyright (c) 1989 The Regents of the University of California.
13 * All rights reserved.
14 *
15 * This code is derived from software contributed to Berkeley by
16 * Mike Muuss.
17 *
18 * Original copyright notice is retained at the end of this file.
19 *
20 * This version is an adaptation of ping.c from busybox.
21 * The code was modified by Bart Visscher <magick@linux-fan.com>
22 */
23
24#include <netinet/icmp6.h>
25#include <net/if.h>
26#include "busybox.h"
27
28/* I see RENUMBERED constants in bits/in.h - !!?
29 * What a fuck is going on with libc? Is it a glibc joke? */
30#ifdef IPV6_2292HOPLIMIT
31#undef IPV6_HOPLIMIT
32#define IPV6_HOPLIMIT IPV6_2292HOPLIMIT
33#endif
34
35enum {
36 DEFDATALEN = 56,
37 MAXIPLEN = 60,
38 MAXICMPLEN = 76,
39 MAXPACKET = 65468,
40 MAX_DUP_CHK = (8 * 128),
41 MAXWAIT = 10,
42 PINGINTERVAL = 1 /* second */
43};
44
45static void ping(const char *host);
46
47#ifndef CONFIG_FEATURE_FANCY_PING6
48
49/* simple version */
50
51static const char *hostname;
52
53static void noresp(int ign)
54{
55 printf("No response from %s\n", hostname);
56 exit(EXIT_FAILURE);
57}
58
59static void ping(const char *host)
60{
61 len_and_sockaddr *lsa;
62 struct sockaddr_in6 pingaddr;
63 struct icmp6_hdr *pkt;
64 int pingsock, c;
65 int sockopt;
66 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
67
68 hostname = host;
69
70 pingsock = create_icmp6_socket();
71
72 lsa = host_and_af2sockaddr(host, 0, AF_INET6);
73 pingaddr = lsa->sin6;
74
75 pkt = (struct icmp6_hdr *) packet;
76 memset(pkt, 0, sizeof(packet));
77 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
78
79 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
80 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt));
81
82 c = sendto(pingsock, packet, DEFDATALEN + sizeof (struct icmp6_hdr), 0,
83 (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in6));
84
85 if (c < 0) {
86 if (ENABLE_FEATURE_CLEAN_UP) close(pingsock);
87 bb_perror_msg_and_die("sendto");
88 }
89
90 signal(SIGALRM, noresp);
91 alarm(5); /* give the host 5000ms to respond */
92 /* listen for replies */
93 while (1) {
94 struct sockaddr_in6 from;
95 socklen_t fromlen = sizeof(from);
96
97 c = recvfrom(pingsock, packet, sizeof(packet), 0,
98 (struct sockaddr *) &from, &fromlen);
99 if (c < 0) {
100 if (errno != EINTR)
101 bb_perror_msg("recvfrom");
102 continue;
103 }
104 if (c >= 8) { /* icmp6_hdr */
105 pkt = (struct icmp6_hdr *) packet;
106 if (pkt->icmp6_type == ICMP6_ECHO_REPLY)
107 break;
108 }
109 }
110 if (ENABLE_FEATURE_CLEAN_UP)
111 close(pingsock);
112 printf("%s is alive!\n", hostname);
113}
114
115int ping6_main(int argc, char **argv)
116{
117 argc--;
118 argv++;
119 if (argc < 1)
120 bb_show_usage();
121 ping(*argv);
122 return EXIT_SUCCESS;
123}
124
125#else /* ! CONFIG_FEATURE_FANCY_PING6 */
126
127/* full(er) version */
128
129#define OPT_STRING "qvc:s:I:"
130enum {
131 OPT_QUIET = 1 << 0,
132 OPT_VERBOSE = 1 << 1,
133};
134
135static struct sockaddr_in6 pingaddr;
136static int pingsock = -1;
137static unsigned datalen; /* intentionally uninitialized to work around gcc bug */
138static int if_index;
139
140static unsigned long ntransmitted, nreceived, nrepeats, pingcount;
141static int myid;
142static unsigned long tmin = ULONG_MAX, tmax, tsum;
143static char rcvd_tbl[MAX_DUP_CHK / 8];
144
145static char *hostname;
146
147static void sendping(int);
148static void pingstats(int);
149static void unpack(char *, int, struct sockaddr_in6 *, int);
150
151#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
152#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
153#define SET(bit) (A(bit) |= B(bit))
154#define CLR(bit) (A(bit) &= (~B(bit)))
155#define TST(bit) (A(bit) & B(bit))
156
157/**************************************************************************/
158
159static void pingstats(int junk)
160{
161 int status;
162
163 signal(SIGINT, SIG_IGN);
164
165 printf("\n--- %s ping statistics ---\n", hostname);
166 printf("%lu packets transmitted, ", ntransmitted);
167 printf("%lu packets received, ", nreceived);
168 if (nrepeats)
169 printf("%lu duplicates, ", nrepeats);
170 if (ntransmitted)
171 printf("%lu%% packet loss\n",
172 (ntransmitted - nreceived) * 100 / ntransmitted);
173 if (nreceived)
174 printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n",
175 tmin / 10, tmin % 10,
176 (tsum / (nreceived + nrepeats)) / 10,
177 (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10);
178 if (nreceived != 0)
179 status = EXIT_SUCCESS;
180 else
181 status = EXIT_FAILURE;
182 exit(status);
183}
184
185static void sendping(int junk)
186{
187 struct icmp6_hdr *pkt;
188 int i;
189 char packet[datalen + sizeof (struct icmp6_hdr)];
190
191 pkt = (struct icmp6_hdr *) packet;
192
193 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
194 pkt->icmp6_code = 0;
195 pkt->icmp6_cksum = 0;
196 pkt->icmp6_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */
197 pkt->icmp6_id = myid;
198 CLR((uint16_t)ntransmitted % MAX_DUP_CHK);
199 ntransmitted++;
200
201 gettimeofday((struct timeval *) &pkt->icmp6_data8[4], NULL);
202
203 i = sendto(pingsock, packet, sizeof(packet), 0,
204 (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in6));
205
206 if (i < 0)
207 bb_perror_msg_and_die("sendto");
208 if ((size_t)i != sizeof(packet))
209 bb_error_msg_and_die("ping wrote %d chars; %d expected", i,
210 (int)sizeof(packet));
211
212 signal(SIGALRM, sendping);
213 if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */
214 alarm(PINGINTERVAL);
215 } else { /* done, wait for the last ping to come back */
216 /* todo, don't necessarily need to wait so long... */
217 signal(SIGALRM, pingstats);
218 alarm(MAXWAIT);
219 }
220}
221
222/* RFC3542 changed some definitions from RFC2292 for no good reason, whee!
223 * the newer 3542 uses a MLD_ prefix where as 2292 uses ICMP6_ prefix */
224#ifndef MLD_LISTENER_QUERY
225# define MLD_LISTENER_QUERY ICMP6_MEMBERSHIP_QUERY
226#endif
227#ifndef MLD_LISTENER_REPORT
228# define MLD_LISTENER_REPORT ICMP6_MEMBERSHIP_REPORT
229#endif
230#ifndef MLD_LISTENER_REDUCTION
231# define MLD_LISTENER_REDUCTION ICMP6_MEMBERSHIP_REDUCTION
232#endif
233static char *icmp6_type_name(int id)
234{
235 switch (id) {
236 case ICMP6_DST_UNREACH: return "Destination Unreachable";
237 case ICMP6_PACKET_TOO_BIG: return "Packet too big";
238 case ICMP6_TIME_EXCEEDED: return "Time Exceeded";
239 case ICMP6_PARAM_PROB: return "Parameter Problem";
240 case ICMP6_ECHO_REPLY: return "Echo Reply";
241 case ICMP6_ECHO_REQUEST: return "Echo Request";
242 case MLD_LISTENER_QUERY: return "Listener Query";
243 case MLD_LISTENER_REPORT: return "Listener Report";
244 case MLD_LISTENER_REDUCTION: return "Listener Reduction";
245 default: return "unknown ICMP type";
246 }
247}
248
249static void unpack(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit)
250{
251 struct icmp6_hdr *icmppkt;
252 struct timeval tv, *tp;
253 int dupflag;
254 unsigned long triptime;
255 char buf[INET6_ADDRSTRLEN];
256
257 gettimeofday(&tv, NULL);
258
259 /* discard if too short */
260 if (sz < (datalen + sizeof(struct icmp6_hdr)))
261 return;
262
263 icmppkt = (struct icmp6_hdr *) packet;
264 if (icmppkt->icmp6_id != myid)
265 return; /* not our ping */
266
267 if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) {
268 uint16_t recv_seq = ntohs(icmppkt->icmp6_seq);
269 ++nreceived;
270 tp = (struct timeval *) &icmppkt->icmp6_data8[4];
271
272 if ((tv.tv_usec -= tp->tv_usec) < 0) {
273 --tv.tv_sec;
274 tv.tv_usec += 1000000;
275 }
276 tv.tv_sec -= tp->tv_sec;
277
278 triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100);
279 tsum += triptime;
280 if (triptime < tmin)
281 tmin = triptime;
282 if (triptime > tmax)
283 tmax = triptime;
284
285 if (TST(recv_seq % MAX_DUP_CHK)) {
286 ++nrepeats;
287 --nreceived;
288 dupflag = 1;
289 } else {
290 SET(recv_seq % MAX_DUP_CHK);
291 dupflag = 0;
292 }
293
294 if (option_mask32 & OPT_QUIET)
295 return;
296
297 printf("%d bytes from %s: icmp6_seq=%u", sz,
298 inet_ntop(AF_INET6, &pingaddr.sin6_addr,
299 buf, sizeof(buf)),
300 recv_seq);
301 printf(" ttl=%d time=%lu.%lu ms", hoplimit,
302 triptime / 10, triptime % 10);
303 if (dupflag)
304 printf(" (DUP!)");
305 puts("");
306 } else {
307 if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST)
308 bb_error_msg("warning: got ICMP %d (%s)",
309 icmppkt->icmp6_type,
310 icmp6_type_name(icmppkt->icmp6_type));
311 }
312 fflush(stdout);
313}
314
315extern int BUG_bad_offsetof_icmp6_cksum(void);
316static void ping(const char *host)
317{
318 len_and_sockaddr *lsa;
319 char packet[datalen + MAXIPLEN + MAXICMPLEN];
320 char buf[INET6_ADDRSTRLEN];
321 int sockopt;
322 struct msghdr msg;
323 struct sockaddr_in6 from;
324 struct iovec iov;
325 char control_buf[CMSG_SPACE(36)];
326
327 pingsock = create_icmp6_socket();
328
329 lsa = host_and_af2sockaddr(host, 0, AF_INET6);
330 hostname = xmalloc_sockaddr2host_noport(&lsa->sa, lsa->len);
331 pingaddr = lsa->sin6;
332
333#ifdef ICMP6_FILTER
334 {
335 struct icmp6_filter filt;
336 if (!(option_mask32 & OPT_VERBOSE)) {
337 ICMP6_FILTER_SETBLOCKALL(&filt);
338 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);
339 } else {
340 ICMP6_FILTER_SETPASSALL(&filt);
341 }
342 if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
343 sizeof(filt)) < 0)
344 bb_error_msg_and_die("setsockopt(ICMP6_FILTER)");
345 }
346#endif /*ICMP6_FILTER*/
347
348 /* enable broadcast pings */
349 setsockopt_broadcast(pingsock);
350
351 /* set recv buf for broadcast pings */
352 sockopt = 48 * 1024; /* explain why 48k? */
353 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt));
354
355 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
356 if (offsetof(struct icmp6_hdr, icmp6_cksum) != 2)
357 BUG_bad_offsetof_icmp6_cksum();
358 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt));
359
360 /* request ttl info to be returned in ancillary data */
361 setsockopt(pingsock, SOL_IPV6, IPV6_HOPLIMIT, &const_int_1, sizeof(const_int_1));
362
363 if (if_index)
364 pingaddr.sin6_scope_id = if_index;
365
366 printf("PING %s (%s): %d data bytes\n",
367 hostname,
368 inet_ntop(AF_INET6, &pingaddr.sin6_addr,
369 buf, sizeof(buf)),
370 datalen);
371
372 signal(SIGINT, pingstats);
373
374 /* start the ping's going ... */
375 sendping(0);
376
377 /* listen for replies */
378 msg.msg_name = &from;
379 msg.msg_namelen = sizeof(from);
380 msg.msg_iov = &iov;
381 msg.msg_iovlen = 1;
382 msg.msg_control = control_buf;
383 iov.iov_base = packet;
384 iov.iov_len = sizeof(packet);
385 while (1) {
386 int c;
387 struct cmsghdr *mp;
388 int hoplimit = -1;
389 msg.msg_controllen = sizeof(control_buf);
390
391 c = recvmsg(pingsock, &msg, 0);
392 if (c < 0) {
393 if (errno != EINTR)
394 bb_perror_msg("recvfrom");
395 continue;
396 }
397 for (mp = CMSG_FIRSTHDR(&msg); mp; mp = CMSG_NXTHDR(&msg, mp)) {
398 if (mp->cmsg_level == SOL_IPV6
399 && mp->cmsg_type == IPV6_HOPLIMIT
400 /* don't check len - we trust the kernel: */
401 /* && mp->cmsg_len >= CMSG_LEN(sizeof(int)) */
402 ) {
403 hoplimit = *(int*)CMSG_DATA(mp);
404 }
405 }
406 unpack(packet, c, &from, hoplimit);
407 if (pingcount > 0 && nreceived >= pingcount)
408 break;
409 }
410 pingstats(0);
411}
412
413int ping6_main(int argc, char **argv)
414{
415 char *opt_c, *opt_s, *opt_I;
416
417 datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */
418
419 /* exactly one argument needed, -v and -q don't mix */
420 opt_complementary = "=1:q--v:v--q";
421 getopt32(argc, argv, OPT_STRING, &opt_c, &opt_s, &opt_I);
422 if (option_mask32 & 4) pingcount = xatoul(opt_c); // -c
423 if (option_mask32 & 8) datalen = xatou16(opt_s); // -s
424 if (option_mask32 & 0x10) { // -I
425 if_index = if_nametoindex(opt_I);
426 if (!if_index)
427 bb_error_msg_and_die(
428 "%s: invalid interface name", opt_I);
429 }
430
431 myid = (int16_t) getpid();
432 ping(argv[optind]);
433 return EXIT_SUCCESS;
434}
435#endif /* ! CONFIG_FEATURE_FANCY_PING6 */
436
437/*
438 * Copyright (c) 1989 The Regents of the University of California.
439 * All rights reserved.
440 *
441 * This code is derived from software contributed to Berkeley by
442 * Mike Muuss.
443 *
444 * Redistribution and use in source and binary forms, with or without
445 * modification, are permitted provided that the following conditions
446 * are met:
447 * 1. Redistributions of source code must retain the above copyright
448 * notice, this list of conditions and the following disclaimer.
449 * 2. Redistributions in binary form must reproduce the above copyright
450 * notice, this list of conditions and the following disclaimer in the
451 * documentation and/or other materials provided with the distribution.
452 *
453 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
454 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
455 *
456 * 4. Neither the name of the University nor the names of its contributors
457 * may be used to endorse or promote products derived from this software
458 * without specific prior written permission.
459 *
460 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
461 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
462 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
463 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
464 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
465 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
466 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
467 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
468 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
469 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
470 * SUCH DAMAGE.
471 */
diff --git a/scripts/defconfig b/scripts/defconfig
index 6a1c57bc8..ed9959985 100644
--- a/scripts/defconfig
+++ b/scripts/defconfig
@@ -566,7 +566,6 @@ CONFIG_NSLOOKUP=y
566CONFIG_PING=y 566CONFIG_PING=y
567CONFIG_FEATURE_FANCY_PING=y 567CONFIG_FEATURE_FANCY_PING=y
568CONFIG_PING6=y 568CONFIG_PING6=y
569CONFIG_FEATURE_FANCY_PING6=y
570CONFIG_ROUTE=y 569CONFIG_ROUTE=y
571CONFIG_TELNET=y 570CONFIG_TELNET=y
572CONFIG_FEATURE_TELNET_TTYPE=y 571CONFIG_FEATURE_TELNET_TTYPE=y