aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-02-09 17:32:16 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-02-09 17:32:16 +0000
commit9ca26d38c513c918cf88db8fef057b7ae5c133f0 (patch)
tree59a8c81de0d3631aca6303adc506363e2807f270
parentd244c5eaf80677bc785ada68d4bb805cdf2d4505 (diff)
downloadbusybox-w32-9ca26d38c513c918cf88db8fef057b7ae5c133f0.tar.gz
busybox-w32-9ca26d38c513c918cf88db8fef057b7ae5c133f0.tar.bz2
busybox-w32-9ca26d38c513c918cf88db8fef057b7ae5c133f0.zip
ping: support -I addr in family neutral manner; reuse a bit of common code
-rw-r--r--include/libbb.h1
-rw-r--r--include/usage.h20
-rw-r--r--libbb/xconnect.c2
-rw-r--r--networking/ping.c72
4 files changed, 43 insertions, 52 deletions
diff --git a/include/libbb.h b/include/libbb.h
index bb4a68741..218a1935c 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -321,6 +321,7 @@ int xconnect_stream(const len_and_sockaddr *lsa);
321len_and_sockaddr* host2sockaddr(const char *host, int port); 321len_and_sockaddr* host2sockaddr(const char *host, int port);
322/* Version which dies on error */ 322/* Version which dies on error */
323len_and_sockaddr* xhost2sockaddr(const char *host, int port); 323len_and_sockaddr* xhost2sockaddr(const char *host, int port);
324len_and_sockaddr* xdotted2sockaddr(const char *host, int port);
324#if ENABLE_FEATURE_IPV6 325#if ENABLE_FEATURE_IPV6
325/* Same, useful if you want to force family (e.g. IPv6) */ 326/* Same, useful if you want to force family (e.g. IPv6) */
326len_and_sockaddr* host_and_af2sockaddr(const char *host, int port, sa_family_t af); 327len_and_sockaddr* host_and_af2sockaddr(const char *host, int port, sa_family_t af);
diff --git a/include/usage.h b/include/usage.h
index 17dcf9be9..fb1617a7c 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -2428,20 +2428,22 @@
2428#define ping_full_usage \ 2428#define ping_full_usage \
2429 "Send ICMP ECHO_REQUEST packets to network hosts" \ 2429 "Send ICMP ECHO_REQUEST packets to network hosts" \
2430 "\n\nOptions:\n" \ 2430 "\n\nOptions:\n" \
2431 " -c CNT Send only CNT pings\n" \ 2431 " -4, -6 Force IPv4 or IPv6 hostname resolution\n" \
2432 " -s SIZE Send SIZE data bytes in packets (default=56)\n" \ 2432 " -c CNT Send only CNT pings\n" \
2433 " -I IP Use IP as source address\n" \ 2433 " -s SIZE Send SIZE data bytes in packets (default=56)\n" \
2434 " -q Quiet mode, only displays output at start\n" \ 2434 " -I iface/IP Use interface or IP address as source\n" \
2435 " and when finished" 2435 " -q Quiet mode, only displays output at start\n" \
2436 " and when finished"
2436#define ping6_trivial_usage \ 2437#define ping6_trivial_usage \
2437 "[OPTION]... host" 2438 "[OPTION]... host"
2438#define ping6_full_usage \ 2439#define ping6_full_usage \
2439 "Send ICMP ECHO_REQUEST packets to network hosts" \ 2440 "Send ICMP ECHO_REQUEST packets to network hosts" \
2440 "\n\nOptions:\n" \ 2441 "\n\nOptions:\n" \
2441 " -c CNT Send only CNT pings\n" \ 2442 " -c CNT Send only CNT pings\n" \
2442 " -s SIZE Send SIZE data bytes in packets (default=56)\n" \ 2443 " -s SIZE Send SIZE data bytes in packets (default=56)\n" \
2443 " -q Quiet mode, only displays output at start\n" \ 2444 " -I iface/IP Use interface or IP address as source\n" \
2444 " and when finished" 2445 " -q Quiet mode, only displays output at start\n" \
2446 " and when finished"
2445#endif 2447#endif
2446#define ping_example_usage \ 2448#define ping_example_usage \
2447 "$ ping localhost\n" \ 2449 "$ ping localhost\n" \
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
index 66b136615..118fe3e75 100644
--- a/libbb/xconnect.c
+++ b/libbb/xconnect.c
@@ -203,7 +203,7 @@ len_and_sockaddr* xhost2sockaddr(const char *host, int port)
203 return str2sockaddr(host, port, AF_UNSPEC, DIE_ON_ERROR); 203 return str2sockaddr(host, port, AF_UNSPEC, DIE_ON_ERROR);
204} 204}
205 205
206static len_and_sockaddr* xdotted2sockaddr(const char *host, int port) 206len_and_sockaddr* xdotted2sockaddr(const char *host, int port)
207{ 207{
208 return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR); 208 return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR);
209} 209}
diff --git a/networking/ping.c b/networking/ping.c
index e76584341..9bf38130e 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -254,7 +254,7 @@ static union {
254 struct sockaddr_in6 sin6; 254 struct sockaddr_in6 sin6;
255#endif 255#endif
256} pingaddr; 256} pingaddr;
257static struct sockaddr_in sourceaddr; 257static len_and_sockaddr *source_lsa;
258static int pingsock = -1; 258static int pingsock = -1;
259static unsigned datalen; /* intentionally uninitialized to work around gcc bug */ 259static unsigned datalen; /* intentionally uninitialized to work around gcc bug */
260 260
@@ -561,9 +561,8 @@ static void ping4(len_and_sockaddr *lsa)
561 561
562 pingsock = create_icmp_socket(); 562 pingsock = create_icmp_socket();
563 pingaddr.sin = lsa->sin; 563 pingaddr.sin = lsa->sin;
564 if (sourceaddr.sin_addr.s_addr) { 564 if (source_lsa)
565 xbind(pingsock, (struct sockaddr*)&sourceaddr, sizeof(sourceaddr)); 565 xbind(pingsock, &lsa->sa, lsa->len);
566 }
567 566
568 /* enable broadcast pings */ 567 /* enable broadcast pings */
569 setsockopt_broadcast(pingsock); 568 setsockopt_broadcast(pingsock);
@@ -572,13 +571,6 @@ static void ping4(len_and_sockaddr *lsa)
572 sockopt = 48 * 1024; /* explain why 48k? */ 571 sockopt = 48 * 1024; /* explain why 48k? */
573 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); 572 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt));
574 573
575 printf("PING %s (%s)", hostname, dotted);
576 if (sourceaddr.sin_addr.s_addr) {
577 printf(" from %s",
578 inet_ntoa(*(struct in_addr *) &sourceaddr.sin_addr.s_addr));
579 }
580 printf(": %d data bytes\n", datalen);
581
582 signal(SIGINT, pingstats); 574 signal(SIGINT, pingstats);
583 575
584 /* start the ping's going ... */ 576 /* start the ping's going ... */
@@ -615,9 +607,9 @@ static void ping6(len_and_sockaddr *lsa)
615 607
616 pingsock = create_icmp6_socket(); 608 pingsock = create_icmp6_socket();
617 pingaddr.sin6 = lsa->sin6; 609 pingaddr.sin6 = lsa->sin6;
618 //if (sourceaddr.sin_addr.s_addr) { 610 /* untested whether "-I addr" really works for IPv6: */
619 // xbind(pingsock, (struct sockaddr*)&sourceaddr, sizeof(sourceaddr)); 611 if (source_lsa)
620 //} 612 xbind(pingsock, &lsa->sa, lsa->len);
621 613
622#ifdef ICMP6_FILTER 614#ifdef ICMP6_FILTER
623 { 615 {
@@ -652,8 +644,6 @@ static void ping6(len_and_sockaddr *lsa)
652 if (if_index) 644 if (if_index)
653 pingaddr.sin6.sin6_scope_id = if_index; 645 pingaddr.sin6.sin6_scope_id = if_index;
654 646
655 printf("PING %s (%s): %d data bytes\n", hostname, dotted, datalen);
656
657 signal(SIGINT, pingstats); 647 signal(SIGINT, pingstats);
658 648
659 /* start the ping's going ... */ 649 /* start the ping's going ... */
@@ -695,25 +685,21 @@ static void ping6(len_and_sockaddr *lsa)
695} 685}
696#endif 686#endif
697 687
698/* TODO: consolidate ether-wake.c, dnsd.c, ifupdown.c, nslookup.c 688static void ping(len_and_sockaddr *lsa)
699 * versions of below thing. BTW we have far too many "%u.%u.%u.%u" too...
700*/
701static int parse_nipquad(const char *str, struct sockaddr_in* addr)
702{ 689{
703 char dummy; 690 printf("PING %s (%s)", hostname, dotted);
704 unsigned i1, i2, i3, i4; 691 if (source_lsa) {
705 if (sscanf(str, "%u.%u.%u.%u%c", 692 printf(" from %s",
706 &i1, &i2, &i3, &i4, &dummy) == 4 693 xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len));
707 && ( (i1|i2|i3|i4) <= 0xff )
708 ) {
709 uint8_t* ptr = (uint8_t*)&addr->sin_addr;
710 ptr[0] = i1;
711 ptr[1] = i2;
712 ptr[2] = i3;
713 ptr[3] = i4;
714 return 0;
715 } 694 }
716 return 1; /* error */ 695 printf(": %d data bytes\n", datalen);
696
697#if ENABLE_PING6
698 if (lsa->sa.sa_family == AF_INET6)
699 ping6(lsa);
700 else
701#endif
702 ping4(lsa);
717} 703}
718 704
719int ping_main(int argc, char **argv); 705int ping_main(int argc, char **argv);
@@ -732,9 +718,11 @@ int ping_main(int argc, char **argv)
732 if (option_mask32 & OPT_s) datalen = xatou16(opt_s); // -s 718 if (option_mask32 & OPT_s) datalen = xatou16(opt_s); // -s
733 if (option_mask32 & OPT_I) { // -I 719 if (option_mask32 & OPT_I) { // -I
734 if_index = if_nametoindex(opt_I); 720 if_index = if_nametoindex(opt_I);
735 if (!if_index) 721 if (!if_index) {
736 if (parse_nipquad(opt_I, &sourceaddr)) 722 /* TODO: I'm not sure it takes IPv6 unless in [XX:XX..] format */
737 bb_show_usage(); 723 /* (ping doesn't support source IPv6 addresses yet anyway) */
724 source_lsa = xdotted2sockaddr(opt_I, 0);
725 }
738 } 726 }
739 myid = (int16_t) getpid(); 727 myid = (int16_t) getpid();
740 hostname = argv[optind]; 728 hostname = argv[optind];
@@ -747,13 +735,13 @@ int ping_main(int argc, char **argv)
747#else 735#else
748 lsa = xhost_and_af2sockaddr(hostname, 0, AF_INET); 736 lsa = xhost_and_af2sockaddr(hostname, 0, AF_INET);
749#endif 737#endif
738
739 if (source_lsa && source_lsa->sa.sa_family != lsa->sa.sa_family)
740 /* leaking it here... */
741 source_lsa = NULL;
742
750 dotted = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len); 743 dotted = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
751#if ENABLE_PING6 744 ping(lsa);
752 if (lsa->sa.sa_family == AF_INET6)
753 ping6(lsa);
754 else
755#endif
756 ping4(lsa);
757 pingstats(0); 745 pingstats(0);
758 return EXIT_SUCCESS; 746 return EXIT_SUCCESS;
759} 747}