source: MondoRescue/branches/stable/mindi-busybox/networking/ping.c@ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

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