1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119#include <net/if.h>
120#include <netinet/ip_icmp.h>
121#include "libbb.h"
122#include "common_bufsiz.h"
123
124#ifdef __BIONIC__
125
126# define ICMP_DEST_UNREACH 3
127# define ICMP_SOURCE_QUENCH 4
128# define ICMP_REDIRECT 5
129# define ICMP_ECHO 8
130# define ICMP_TIME_EXCEEDED 11
131# define ICMP_PARAMETERPROB 12
132# define ICMP_TIMESTAMP 13
133# define ICMP_TIMESTAMPREPLY 14
134# define ICMP_INFO_REQUEST 15
135# define ICMP_INFO_REPLY 16
136# define ICMP_ADDRESS 17
137# define ICMP_ADDRESSREPLY 18
138#endif
139
140
141
142
143
144#ifndef SOL_RAW
145# define SOL_RAW IPPROTO_RAW
146#endif
147
148#if ENABLE_PING6
149# include <netinet/icmp6.h>
150
151
152# ifdef IPV6_2292HOPLIMIT
153# undef IPV6_HOPLIMIT
154# define IPV6_HOPLIMIT IPV6_2292HOPLIMIT
155# endif
156#endif
157
158enum {
159 DEFDATALEN = 56,
160 MAXIPLEN = 60,
161 MAXICMPLEN = 76,
162 MAX_DUP_CHK = (8 * 128),
163 MAXWAIT = 10,
164 PINGINTERVAL = 1,
165 pingsock = 0,
166};
167
168static void
169#if ENABLE_PING6
170create_icmp_socket(len_and_sockaddr *lsa)
171#else
172create_icmp_socket(void)
173#define create_icmp_socket(lsa) create_icmp_socket()
174#endif
175{
176 int sock;
177#if ENABLE_PING6
178 if (lsa->u.sa.sa_family == AF_INET6)
179 sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
180 else
181#endif
182 sock = socket(AF_INET, SOCK_RAW, 1);
183 if (sock < 0) {
184 if (errno == EPERM)
185 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
186 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
187 }
188
189 xmove_fd(sock, pingsock);
190}
191
192#if !ENABLE_FEATURE_FANCY_PING
193
194
195
196struct globals {
197 char *hostname;
198 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
199 uint16_t myid;
200} FIX_ALIASING;
201#define G (*(struct globals*)bb_common_bufsiz1)
202#define INIT_G() do { setup_common_bufsiz(); } while (0)
203
204static void noresp(int ign UNUSED_PARAM)
205{
206 printf("No response from %s\n", G.hostname);
207 exit(EXIT_FAILURE);
208}
209
210static void ping4(len_and_sockaddr *lsa)
211{
212 struct icmp *pkt;
213 int c;
214
215 pkt = (struct icmp *) G.packet;
216
217 pkt->icmp_type = ICMP_ECHO;
218 pkt->icmp_id = G.myid;
219 pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, sizeof(G.packet));
220
221 xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len);
222
223
224 while (1) {
225#if 0
226 struct sockaddr_in from;
227 socklen_t fromlen = sizeof(from);
228
229 c = recvfrom(pingsock, G.packet, sizeof(G.packet), 0,
230 (struct sockaddr *) &from, &fromlen);
231#else
232 c = recv(pingsock, G.packet, sizeof(G.packet), 0);
233#endif
234 if (c < 0) {
235 if (errno != EINTR)
236 bb_perror_msg("recvfrom");
237 continue;
238 }
239 if (c >= 76) {
240 struct iphdr *iphdr = (struct iphdr *) G.packet;
241
242 pkt = (struct icmp *) (G.packet + (iphdr->ihl << 2));
243 if (pkt->icmp_id != G.myid)
244 continue;
245 if (pkt->icmp_type == ICMP_ECHOREPLY)
246 break;
247 }
248 }
249}
250
251#if ENABLE_PING6
252static void ping6(len_and_sockaddr *lsa)
253{
254 struct icmp6_hdr *pkt;
255 int c;
256 int sockopt;
257
258 pkt = (struct icmp6_hdr *) G.packet;
259
260 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
261 pkt->icmp6_id = G.myid;
262
263 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
264 setsockopt_int(pingsock, SOL_RAW, IPV6_CHECKSUM, sockopt);
265
266 xsendto(pingsock, G.packet, DEFDATALEN + sizeof(struct icmp6_hdr), &lsa->u.sa, lsa->len);
267
268
269 while (1) {
270#if 0
271 struct sockaddr_in6 from;
272 socklen_t fromlen = sizeof(from);
273
274 c = recvfrom(pingsock, G.packet, sizeof(G.packet), 0,
275 (struct sockaddr *) &from, &fromlen);
276#else
277 c = recv(pingsock, G.packet, sizeof(G.packet), 0);
278#endif
279 if (c < 0) {
280 if (errno != EINTR)
281 bb_perror_msg("recvfrom");
282 continue;
283 }
284 if (c >= ICMP_MINLEN) {
285 if (pkt->icmp6_id != G.myid)
286 continue;
287 if (pkt->icmp6_type == ICMP6_ECHO_REPLY)
288 break;
289 }
290 }
291}
292#endif
293
294#if !ENABLE_PING6
295# define common_ping_main(af, argv) common_ping_main(argv)
296#endif
297static int common_ping_main(sa_family_t af, char **argv)
298{
299 len_and_sockaddr *lsa;
300
301 INIT_G();
302
303#if ENABLE_PING6
304 while ((++argv)[0] && argv[0][0] == '-') {
305 if (argv[0][1] == '4') {
306 af = AF_INET;
307 continue;
308 }
309 if (argv[0][1] == '6') {
310 af = AF_INET6;
311 continue;
312 }
313 bb_show_usage();
314 }
315#else
316 argv++;
317#endif
318
319 G.hostname = *argv;
320 if (!G.hostname)
321 bb_show_usage();
322
323#if ENABLE_PING6
324 lsa = xhost_and_af2sockaddr(G.hostname, 0, af);
325#else
326 lsa = xhost_and_af2sockaddr(G.hostname, 0, AF_INET);
327#endif
328
329 signal(SIGALRM, noresp);
330 alarm(5);
331
332 create_icmp_socket(lsa);
333 G.myid = (uint16_t) getpid();
334#if ENABLE_PING6
335 if (lsa->u.sa.sa_family == AF_INET6)
336 ping6(lsa);
337 else
338#endif
339 ping4(lsa);
340 if (ENABLE_FEATURE_CLEAN_UP)
341 close(pingsock);
342 printf("%s is alive!\n", G.hostname);
343 return EXIT_SUCCESS;
344}
345
346
347#else
348
349
350
351
352
353#define OPT_STRING "qvAc:+s:t:+w:+W:+I:np:4"IF_PING6("6")
354enum {
355 OPT_QUIET = 1 << 0,
356 OPT_VERBOSE = 1 << 1,
357 OPT_A = 1 << 2,
358 OPT_c = 1 << 3,
359 OPT_s = 1 << 4,
360 OPT_t = 1 << 5,
361 OPT_w = 1 << 6,
362 OPT_W = 1 << 7,
363 OPT_I = 1 << 8,
364
365 OPT_p = 1 << 10,
366 OPT_IPV4 = 1 << 11,
367 OPT_IPV6 = (1 << 12) * ENABLE_PING6,
368};
369
370
371struct globals {
372 int if_index;
373 char *str_I;
374 len_and_sockaddr *source_lsa;
375 unsigned datalen;
376 unsigned pingcount;
377 unsigned opt_ttl;
378 unsigned long ntransmitted, nreceived, nrepeats;
379 uint16_t myid;
380 uint8_t pattern;
381 unsigned tmin, tmax;
382 unsigned long long tsum;
383 unsigned cur_us;
384 unsigned deadline_us;
385 unsigned timeout;
386 unsigned sizeof_rcv_packet;
387 char *rcv_packet;
388 void *snd_packet;
389 const char *hostname;
390 const char *dotted;
391 union {
392 struct sockaddr sa;
393 struct sockaddr_in sin;
394#if ENABLE_PING6
395 struct sockaddr_in6 sin6;
396#endif
397 } pingaddr;
398 unsigned char rcvd_tbl[MAX_DUP_CHK / 8];
399} FIX_ALIASING;
400#define G (*(struct globals*)bb_common_bufsiz1)
401#define if_index (G.if_index )
402#define source_lsa (G.source_lsa )
403#define str_I (G.str_I )
404#define datalen (G.datalen )
405#define pingcount (G.pingcount )
406#define opt_ttl (G.opt_ttl )
407#define myid (G.myid )
408#define tmin (G.tmin )
409#define tmax (G.tmax )
410#define tsum (G.tsum )
411#define timeout (G.timeout )
412#define hostname (G.hostname )
413#define dotted (G.dotted )
414#define pingaddr (G.pingaddr )
415#define rcvd_tbl (G.rcvd_tbl )
416#define INIT_G() do { \
417 setup_common_bufsiz(); \
418 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
419 datalen = DEFDATALEN; \
420 timeout = MAXWAIT; \
421 tmin = UINT_MAX; \
422} while (0)
423
424
425#define BYTE(bit) rcvd_tbl[(bit)>>3]
426#define MASK(bit) (1 << ((bit) & 7))
427#define SET(bit) (BYTE(bit) |= MASK(bit))
428#define CLR(bit) (BYTE(bit) &= (~MASK(bit)))
429#define TST(bit) (BYTE(bit) & MASK(bit))
430
431static void print_stats_and_exit(int junk) NORETURN;
432static void print_stats_and_exit(int junk UNUSED_PARAM)
433{
434 unsigned long ul;
435 unsigned long nrecv;
436
437 signal(SIGINT, SIG_IGN);
438
439 nrecv = G.nreceived;
440 printf("\n--- %s ping statistics ---\n"
441 "%lu packets transmitted, "
442 "%lu packets received, ",
443 hostname, G.ntransmitted, nrecv
444 );
445 if (G.nrepeats)
446 printf("%lu duplicates, ", G.nrepeats);
447 ul = G.ntransmitted;
448 if (ul != 0)
449 ul = (ul - nrecv) * 100 / ul;
450 printf("%lu%% packet loss\n", ul);
451 if (tmin != UINT_MAX) {
452 unsigned tavg = tsum / (nrecv + G.nrepeats);
453 printf("round-trip min/avg/max = %u.%03u/%u.%03u/%u.%03u ms\n",
454 tmin / 1000, tmin % 1000,
455 tavg / 1000, tavg % 1000,
456 tmax / 1000, tmax % 1000);
457 }
458
459 exit(nrecv == 0 || (G.deadline_us && nrecv < pingcount));
460}
461
462static void sendping_tail(void (*sp)(int), int size_pkt)
463{
464 int sz;
465
466 CLR((uint16_t)G.ntransmitted % MAX_DUP_CHK);
467 G.ntransmitted++;
468
469 size_pkt += datalen;
470
471 if (G.deadline_us) {
472 unsigned n = G.cur_us - G.deadline_us;
473 if ((int)n >= 0)
474 print_stats_and_exit(0);
475 }
476
477
478
479 sz = xsendto(pingsock, G.snd_packet, size_pkt, &pingaddr.sa, sizeof(pingaddr));
480 if (sz != size_pkt)
481 bb_error_msg_and_die(bb_msg_write_error);
482
483 if (pingcount == 0 || G.ntransmitted < pingcount) {
484
485 signal(SIGALRM, sp);
486 alarm(PINGINTERVAL);
487 } else {
488
489
490
491
492 unsigned expire = timeout;
493
494 if (G.nreceived) {
495
496 expire = tmax / (512*1024);
497 if (expire == 0)
498 expire = 1;
499 }
500 signal(SIGALRM, print_stats_and_exit);
501 alarm(expire);
502 }
503}
504
505static void sendping4(int junk UNUSED_PARAM)
506{
507 struct icmp *pkt = G.snd_packet;
508
509 memset(pkt, G.pattern, datalen + ICMP_MINLEN + 4);
510 pkt->icmp_type = ICMP_ECHO;
511
512 pkt->icmp_cksum = 0;
513 pkt->icmp_seq = htons(G.ntransmitted);
514 pkt->icmp_id = myid;
515
516
517
518
519
520
521 *(uint32_t*)&pkt->icmp_dun = G.cur_us = monotonic_us();
522
523 pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, datalen + ICMP_MINLEN);
524
525 sendping_tail(sendping4, ICMP_MINLEN);
526}
527#if ENABLE_PING6
528static void sendping6(int junk UNUSED_PARAM)
529{
530 struct icmp6_hdr *pkt = G.snd_packet;
531
532 memset(pkt, G.pattern, datalen + sizeof(struct icmp6_hdr) + 4);
533 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
534
535
536 pkt->icmp6_seq = htons(G.ntransmitted);
537 pkt->icmp6_id = myid;
538
539
540 *(bb__aliased_uint32_t*)(&pkt->icmp6_data8[4]) = G.cur_us = monotonic_us();
541
542
543
544 sendping_tail(sendping6, sizeof(struct icmp6_hdr));
545}
546#endif
547
548static const char *icmp_type_name(int id)
549{
550 switch (id) {
551 case ICMP_ECHOREPLY: return "Echo Reply";
552 case ICMP_DEST_UNREACH: return "Destination Unreachable";
553 case ICMP_SOURCE_QUENCH: return "Source Quench";
554 case ICMP_REDIRECT: return "Redirect (change route)";
555 case ICMP_ECHO: return "Echo Request";
556 case ICMP_TIME_EXCEEDED: return "Time Exceeded";
557 case ICMP_PARAMETERPROB: return "Parameter Problem";
558 case ICMP_TIMESTAMP: return "Timestamp Request";
559 case ICMP_TIMESTAMPREPLY: return "Timestamp Reply";
560 case ICMP_INFO_REQUEST: return "Information Request";
561 case ICMP_INFO_REPLY: return "Information Reply";
562 case ICMP_ADDRESS: return "Address Mask Request";
563 case ICMP_ADDRESSREPLY: return "Address Mask Reply";
564 default: return "unknown ICMP type";
565 }
566}
567#if ENABLE_PING6
568
569
570#ifndef MLD_LISTENER_QUERY
571# define MLD_LISTENER_QUERY ICMP6_MEMBERSHIP_QUERY
572#endif
573#ifndef MLD_LISTENER_REPORT
574# define MLD_LISTENER_REPORT ICMP6_MEMBERSHIP_REPORT
575#endif
576#ifndef MLD_LISTENER_REDUCTION
577# define MLD_LISTENER_REDUCTION ICMP6_MEMBERSHIP_REDUCTION
578#endif
579static const char *icmp6_type_name(int id)
580{
581 switch (id) {
582 case ICMP6_DST_UNREACH: return "Destination Unreachable";
583 case ICMP6_PACKET_TOO_BIG: return "Packet too big";
584 case ICMP6_TIME_EXCEEDED: return "Time Exceeded";
585 case ICMP6_PARAM_PROB: return "Parameter Problem";
586 case ICMP6_ECHO_REPLY: return "Echo Reply";
587 case ICMP6_ECHO_REQUEST: return "Echo Request";
588 case MLD_LISTENER_QUERY: return "Listener Query";
589 case MLD_LISTENER_REPORT: return "Listener Report";
590 case MLD_LISTENER_REDUCTION: return "Listener Reduction";
591 default: return "unknown ICMP type";
592 }
593}
594#endif
595
596static void unpack_tail(int sz, uint32_t *tp,
597 const char *from_str,
598 uint16_t recv_seq, int ttl)
599{
600 unsigned char *b, m;
601 const char *dupmsg = " (DUP!)";
602 unsigned triptime = triptime;
603
604 if (tp) {
605
606
607 triptime = (int32_t) ((uint32_t)monotonic_us() - *tp);
608 tsum += triptime;
609 if (triptime < tmin)
610 tmin = triptime;
611 if (triptime > tmax)
612 tmax = triptime;
613 }
614
615 b = &BYTE(recv_seq % MAX_DUP_CHK);
616 m = MASK(recv_seq % MAX_DUP_CHK);
617
618 if (*b & m) {
619 ++G.nrepeats;
620 } else {
621
622 *b |= m;
623 ++G.nreceived;
624 dupmsg += 7;
625 }
626
627 if (option_mask32 & OPT_QUIET)
628 return;
629
630 printf("%d bytes from %s: seq=%u ttl=%d", sz,
631 from_str, recv_seq, ttl);
632 if (tp)
633 printf(" time=%u.%03u ms", triptime / 1000, triptime % 1000);
634 puts(dupmsg);
635 fflush_all();
636}
637static int unpack4(char *buf, int sz, struct sockaddr_in *from)
638{
639 struct icmp *icmppkt;
640 struct iphdr *iphdr;
641 int hlen;
642
643
644 if (sz < (datalen + ICMP_MINLEN))
645 return 0;
646
647
648 iphdr = (struct iphdr *) buf;
649 hlen = iphdr->ihl << 2;
650 sz -= hlen;
651 icmppkt = (struct icmp *) (buf + hlen);
652 if (icmppkt->icmp_id != myid)
653 return 0;
654
655 if (icmppkt->icmp_type == ICMP_ECHOREPLY) {
656 uint16_t recv_seq = ntohs(icmppkt->icmp_seq);
657 uint32_t *tp = NULL;
658
659 if (sz >= ICMP_MINLEN + sizeof(uint32_t))
660 tp = (uint32_t *) icmppkt->icmp_data;
661 unpack_tail(sz, tp,
662 inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr),
663 recv_seq, iphdr->ttl);
664 return 1;
665 }
666 if (icmppkt->icmp_type != ICMP_ECHO) {
667 bb_error_msg("warning: got ICMP %d (%s)",
668 icmppkt->icmp_type,
669 icmp_type_name(icmppkt->icmp_type));
670 }
671 return 0;
672}
673#if ENABLE_PING6
674static int unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit)
675{
676 struct icmp6_hdr *icmppkt;
677 char buf[INET6_ADDRSTRLEN];
678
679
680 if (sz < (datalen + sizeof(struct icmp6_hdr)))
681 return 0;
682
683 icmppkt = (struct icmp6_hdr *) packet;
684 if (icmppkt->icmp6_id != myid)
685 return 0;
686
687 if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) {
688 uint16_t recv_seq = ntohs(icmppkt->icmp6_seq);
689 uint32_t *tp = NULL;
690
691 if (sz >= sizeof(struct icmp6_hdr) + sizeof(uint32_t))
692 tp = (uint32_t *) &icmppkt->icmp6_data8[4];
693 unpack_tail(sz, tp,
694 inet_ntop(AF_INET6, &from->sin6_addr,
695 buf, sizeof(buf)),
696 recv_seq, hoplimit);
697 return 1;
698 }
699 if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) {
700 bb_error_msg("warning: got ICMP %d (%s)",
701 icmppkt->icmp6_type,
702 icmp6_type_name(icmppkt->icmp6_type));
703 }
704 return 0;
705}
706#endif
707
708static void ping4(len_and_sockaddr *lsa)
709{
710 int sockopt;
711
712 pingaddr.sin = lsa->u.sin;
713 if (source_lsa) {
714 if (setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_IF,
715 &source_lsa->u.sa, source_lsa->len))
716 bb_error_msg_and_die("can't set multicast source interface");
717 xbind(pingsock, &source_lsa->u.sa, source_lsa->len);
718 }
719
720
721 setsockopt_broadcast(pingsock);
722
723
724
725 sockopt = (datalen * 2) + 7 * 1024;
726 setsockopt_SOL_SOCKET_int(pingsock, SO_RCVBUF, sockopt);
727
728 if (opt_ttl != 0) {
729 setsockopt_int(pingsock, IPPROTO_IP, IP_TTL, opt_ttl);
730
731 setsockopt_int(pingsock, IPPROTO_IP, IP_MULTICAST_TTL, opt_ttl);
732 }
733
734 signal(SIGINT, print_stats_and_exit);
735
736
737 send_ping:
738 sendping4(0);
739
740
741 while (1) {
742 struct sockaddr_in from;
743 socklen_t fromlen = (socklen_t) sizeof(from);
744 int c;
745
746 c = recvfrom(pingsock, G.rcv_packet, G.sizeof_rcv_packet, 0,
747 (struct sockaddr *) &from, &fromlen);
748 if (c < 0) {
749 if (errno != EINTR)
750 bb_perror_msg("recvfrom");
751 continue;
752 }
753 c = unpack4(G.rcv_packet, c, &from);
754 if (pingcount && G.nreceived >= pingcount)
755 break;
756 if (c && (option_mask32 & OPT_A)) {
757 goto send_ping;
758 }
759 }
760}
761#if ENABLE_PING6
762static void ping6(len_and_sockaddr *lsa)
763{
764 int sockopt;
765 struct msghdr msg;
766 struct sockaddr_in6 from;
767 struct iovec iov;
768 char control_buf[CMSG_SPACE(36)];
769
770 pingaddr.sin6 = lsa->u.sin6;
771 if (source_lsa)
772 xbind(pingsock, &source_lsa->u.sa, source_lsa->len);
773
774#ifdef ICMP6_FILTER
775 {
776 struct icmp6_filter filt;
777 if (!(option_mask32 & OPT_VERBOSE)) {
778 ICMP6_FILTER_SETBLOCKALL(&filt);
779 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);
780 } else {
781 ICMP6_FILTER_SETPASSALL(&filt);
782 }
783 if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
784 sizeof(filt)) < 0)
785 bb_error_msg_and_die("setsockopt(%s)", "ICMP6_FILTER");
786 }
787#endif
788
789
790 setsockopt_broadcast(pingsock);
791
792
793
794 sockopt = (datalen * 2) + 7 * 1024;
795 setsockopt_SOL_SOCKET_int(pingsock, SO_RCVBUF, sockopt);
796
797 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
798 BUILD_BUG_ON(offsetof(struct icmp6_hdr, icmp6_cksum) != 2);
799 setsockopt_int(pingsock, SOL_RAW, IPV6_CHECKSUM, sockopt);
800
801
802 setsockopt_1(pingsock, SOL_IPV6, IPV6_HOPLIMIT);
803
804 if (if_index)
805 pingaddr.sin6.sin6_scope_id = if_index;
806
807 signal(SIGINT, print_stats_and_exit);
808
809 msg.msg_name = &from;
810 msg.msg_namelen = sizeof(from);
811 msg.msg_iov = &iov;
812 msg.msg_iovlen = 1;
813 msg.msg_control = control_buf;
814 iov.iov_base = G.rcv_packet;
815 iov.iov_len = G.sizeof_rcv_packet;
816
817
818 send_ping:
819 sendping6(0);
820
821
822 while (1) {
823 int c;
824 struct cmsghdr *mp;
825 int hoplimit = -1;
826
827 msg.msg_controllen = sizeof(control_buf);
828 c = recvmsg(pingsock, &msg, 0);
829 if (c < 0) {
830 if (errno != EINTR)
831 bb_perror_msg("recvfrom");
832 continue;
833 }
834 for (mp = CMSG_FIRSTHDR(&msg); mp; mp = CMSG_NXTHDR(&msg, mp)) {
835 if (mp->cmsg_level == SOL_IPV6
836 && mp->cmsg_type == IPV6_HOPLIMIT
837
838
839 ) {
840
841 move_from_unaligned_int(hoplimit, CMSG_DATA(mp));
842 }
843 }
844 c = unpack6(G.rcv_packet, c, &from, hoplimit);
845 if (pingcount && G.nreceived >= pingcount)
846 break;
847 if (c && (option_mask32 & OPT_A)) {
848 goto send_ping;
849 }
850 }
851}
852#endif
853
854static void ping(len_and_sockaddr *lsa)
855{
856 printf("PING %s (%s)", hostname, dotted);
857 if (source_lsa) {
858 printf(" from %s",
859 xmalloc_sockaddr2dotted_noport(&source_lsa->u.sa));
860 }
861 printf(": %d data bytes\n", datalen);
862
863 create_icmp_socket(lsa);
864
865 if (str_I)
866 setsockopt_bindtodevice(pingsock, str_I);
867
868 G.sizeof_rcv_packet = datalen + MAXIPLEN + MAXICMPLEN;
869 G.rcv_packet = xzalloc(G.sizeof_rcv_packet);
870#if ENABLE_PING6
871 if (lsa->u.sa.sa_family == AF_INET6) {
872
873
874 G.snd_packet = xzalloc(datalen + sizeof(struct icmp6_hdr) + 4);
875 ping6(lsa);
876 } else
877#endif
878 {
879 G.snd_packet = xzalloc(datalen + ICMP_MINLEN + 4);
880 ping4(lsa);
881 }
882}
883
884static int common_ping_main(int opt, char **argv)
885{
886 len_and_sockaddr *lsa;
887 char *str_s, *str_p;
888
889 INIT_G();
890
891 opt |= getopt32(argv, "^"
892 OPT_STRING
893
894 "\0" "=1:q--v:v--q",
895 &pingcount, &str_s, &opt_ttl, &G.deadline_us, &timeout, &str_I, &str_p
896 );
897 if (opt & OPT_s)
898 datalen = xatou16(str_s);
899 if (opt & OPT_I) {
900 if_index = if_nametoindex(str_I);
901 if (!if_index) {
902
903 source_lsa = xdotted2sockaddr(str_I, 0);
904 str_I = NULL;
905 }
906 }
907 if (opt & OPT_p)
908 G.pattern = xstrtou_range(str_p, 16, 0, 255);
909 if (G.deadline_us) {
910 unsigned d = G.deadline_us < INT_MAX/1000000 ? G.deadline_us : INT_MAX/1000000;
911 G.deadline_us = 1 | ((d * 1000000) + monotonic_us());
912 }
913
914 myid = (uint16_t) getpid();
915 hostname = argv[optind];
916#if ENABLE_PING6
917 {
918 sa_family_t af = AF_UNSPEC;
919 if (opt & OPT_IPV4)
920 af = AF_INET;
921 if (opt & OPT_IPV6)
922 af = AF_INET6;
923 lsa = xhost_and_af2sockaddr(hostname, 0, af);
924 }
925#else
926 lsa = xhost_and_af2sockaddr(hostname, 0, AF_INET);
927#endif
928
929 if (source_lsa && source_lsa->u.sa.sa_family != lsa->u.sa.sa_family)
930
931 source_lsa = NULL;
932
933 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
934 ping(lsa);
935 print_stats_and_exit(0);
936
937}
938#endif
939
940
941#if ENABLE_PING
942int ping_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
943int ping_main(int argc UNUSED_PARAM, char **argv)
944{
945# if !ENABLE_FEATURE_FANCY_PING
946 return common_ping_main(AF_UNSPEC, argv);
947# else
948 return common_ping_main(0, argv);
949# endif
950}
951#endif
952
953#if ENABLE_PING6
954int ping6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
955int ping6_main(int argc UNUSED_PARAM, char **argv)
956{
957# if !ENABLE_FEATURE_FANCY_PING
958 return common_ping_main(AF_INET6, argv);
959# else
960 return common_ping_main(OPT_IPV6, argv);
961# endif
962}
963#endif
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000