aboutsummaryrefslogtreecommitdiff
path: root/networking
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2016-07-07 14:28:08 +0100
committerRon Yorston <rmy@pobox.com>2016-07-07 14:58:55 +0100
commit613f46218c53c8cabdbf0435653e74e0e0e91e1c (patch)
treeca06a7e7a3e4c861441acb4ea20648d7827fa6ae /networking
parenta0c61c9492723dd31681f878f9c68c92817a476d (diff)
parent237bedd499c58034a1355484d6d4d906f0180308 (diff)
downloadbusybox-w32-613f46218c53c8cabdbf0435653e74e0e0e91e1c.tar.gz
busybox-w32-613f46218c53c8cabdbf0435653e74e0e0e91e1c.tar.bz2
busybox-w32-613f46218c53c8cabdbf0435653e74e0e0e91e1c.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'networking')
-rw-r--r--networking/arp.c6
-rw-r--r--networking/arping.c15
-rw-r--r--networking/ftpd.c6
-rw-r--r--networking/ifplugd.c5
-rw-r--r--networking/inetd.c4
-rw-r--r--networking/nc_bloaty.c4
-rw-r--r--networking/ntpd.c96
-rw-r--r--networking/ping.c12
-rw-r--r--networking/tcpudp.c4
-rw-r--r--networking/telnetd.c4
-rw-r--r--networking/traceroute.c4
-rw-r--r--networking/udhcp/d6_dhcpc.c10
-rw-r--r--networking/udhcp/dhcpc.c10
-rw-r--r--networking/wget.c3
-rw-r--r--networking/whois.c147
15 files changed, 240 insertions, 90 deletions
diff --git a/networking/arp.c b/networking/arp.c
index 9381eb53a..69a5816eb 100644
--- a/networking/arp.c
+++ b/networking/arp.c
@@ -178,7 +178,7 @@ static int arp_del(char **args)
178 if (flags == 0) 178 if (flags == 0)
179 flags = 3; 179 flags = 3;
180 180
181 strncpy(req.arp_dev, device, sizeof(req.arp_dev)); 181 strncpy_IFNAMSIZ(req.arp_dev, device);
182 182
183 err = -1; 183 err = -1;
184 184
@@ -219,7 +219,7 @@ static void arp_getdevhw(char *ifname, struct sockaddr *sa)
219 struct ifreq ifr; 219 struct ifreq ifr;
220 const struct hwtype *xhw; 220 const struct hwtype *xhw;
221 221
222 strcpy(ifr.ifr_name, ifname); 222 strncpy_IFNAMSIZ(ifr.ifr_name, ifname);
223 ioctl_or_perror_and_die(sockfd, SIOCGIFHWADDR, &ifr, 223 ioctl_or_perror_and_die(sockfd, SIOCGIFHWADDR, &ifr,
224 "can't get HW-Address for '%s'", ifname); 224 "can't get HW-Address for '%s'", ifname);
225 if (hw_set && (ifr.ifr_hwaddr.sa_family != hw->type)) { 225 if (hw_set && (ifr.ifr_hwaddr.sa_family != hw->type)) {
@@ -332,7 +332,7 @@ static int arp_set(char **args)
332 /* Fill in the remainder of the request. */ 332 /* Fill in the remainder of the request. */
333 req.arp_flags = flags; 333 req.arp_flags = flags;
334 334
335 strncpy(req.arp_dev, device, sizeof(req.arp_dev)); 335 strncpy_IFNAMSIZ(req.arp_dev, device);
336 336
337 /* Call the kernel. */ 337 /* Call the kernel. */
338 if (option_mask32 & ARP_OPT_v) 338 if (option_mask32 & ARP_OPT_v)
diff --git a/networking/arping.c b/networking/arping.c
index 6b0de4de2..46bd65e36 100644
--- a/networking/arping.c
+++ b/networking/arping.c
@@ -231,20 +231,23 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
231 if (!(option_mask32 & QUIET)) { 231 if (!(option_mask32 & QUIET)) {
232 int s_printed = 0; 232 int s_printed = 0;
233 233
234 printf("%scast re%s from %s [%s]", 234 printf("%scast re%s from %s [%02x:%02x:%02x:%02x:%02x:%02x]",
235 FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad", 235 FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad",
236 ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest", 236 ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest",
237 inet_ntoa(src_ip), 237 inet_ntoa(src_ip),
238 ether_ntoa((struct ether_addr *) p)); 238 p[0], p[1], p[2], p[3], p[4], p[5]
239 );
239 if (dst_ip.s_addr != src.s_addr) { 240 if (dst_ip.s_addr != src.s_addr) {
240 printf("for %s ", inet_ntoa(dst_ip)); 241 printf("for %s ", inet_ntoa(dst_ip));
241 s_printed = 1; 242 s_printed = 1;
242 } 243 }
243 if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) { 244 if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) {
245 unsigned char *pp = p + ah->ar_hln + 4;
244 if (!s_printed) 246 if (!s_printed)
245 printf("for "); 247 printf("for ");
246 printf("[%s]", 248 printf("[%02x:%02x:%02x:%02x:%02x:%02x]",
247 ether_ntoa((struct ether_addr *) p + ah->ar_hln + 4)); 249 pp[0], pp[1], pp[2], pp[3], pp[4], pp[5]
250 );
248 } 251 }
249 252
250 if (last) { 253 if (last) {
@@ -292,8 +295,8 @@ int arping_main(int argc UNUSED_PARAM, char **argv)
292 /* Dad also sets quit_on_reply. 295 /* Dad also sets quit_on_reply.
293 * Advert also sets unsolicited. 296 * Advert also sets unsolicited.
294 */ 297 */
295 opt_complementary = "=1:Df:AU:c+"; 298 opt_complementary = "=1:Df:AU";
296 opt = getopt32(argv, "DUAqfbc:w:I:s:", 299 opt = getopt32(argv, "DUAqfbc:+w:I:s:",
297 &count, &str_timeout, &device, &source); 300 &count, &str_timeout, &device, &source);
298 if (opt & 0x80) /* -w: timeout */ 301 if (opt & 0x80) /* -w: timeout */
299 timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000; 302 timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000;
diff --git a/networking/ftpd.c b/networking/ftpd.c
index 360d1e6be..4cbb9b6fe 100644
--- a/networking/ftpd.c
+++ b/networking/ftpd.c
@@ -1130,11 +1130,11 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
1130 abs_timeout = 1 * 60 * 60; 1130 abs_timeout = 1 * 60 * 60;
1131 verbose_S = 0; 1131 verbose_S = 0;
1132 G.timeout = 2 * 60; 1132 G.timeout = 2 * 60;
1133 opt_complementary = "t+:T+:vv:SS"; 1133 opt_complementary = "vv:SS";
1134#if BB_MMU 1134#if BB_MMU
1135 opts = getopt32(argv, "vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S); 1135 opts = getopt32(argv, "vS" IF_FEATURE_FTP_WRITE("w") "t:+T:+", &G.timeout, &abs_timeout, &G.verbose, &verbose_S);
1136#else 1136#else
1137 opts = getopt32(argv, "l1AvS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S); 1137 opts = getopt32(argv, "l1AvS" IF_FEATURE_FTP_WRITE("w") "t:+T:+", &G.timeout, &abs_timeout, &G.verbose, &verbose_S);
1138 if (opts & (OPT_l|OPT_1)) { 1138 if (opts & (OPT_l|OPT_1)) {
1139 /* Our secret backdoor to ls */ 1139 /* Our secret backdoor to ls */
1140/* TODO: pass --group-directories-first? would be nice, but ls doesn't do that yet */ 1140/* TODO: pass --group-directories-first? would be nice, but ls doesn't do that yet */
diff --git a/networking/ifplugd.c b/networking/ifplugd.c
index f0defb5c8..28c49e218 100644
--- a/networking/ifplugd.c
+++ b/networking/ifplugd.c
@@ -107,9 +107,9 @@ enum {
107#endif 107#endif
108}; 108};
109#if ENABLE_FEATURE_PIDFILE 109#if ENABLE_FEATURE_PIDFILE
110# define OPTION_STR "+ansfFi:r:It:u:d:m:pqlx:Mk" 110# define OPTION_STR "+ansfFi:r:It:+u:+d:+m:pqlx:Mk"
111#else 111#else
112# define OPTION_STR "+ansfFi:r:It:u:d:m:pqlx:M" 112# define OPTION_STR "+ansfFi:r:It:+u:+d:+m:pqlx:M"
113#endif 113#endif
114 114
115enum { // interface status 115enum { // interface status
@@ -560,7 +560,6 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv)
560 560
561 INIT_G(); 561 INIT_G();
562 562
563 opt_complementary = "t+:u+:d+";
564 opts = getopt32(argv, OPTION_STR, 563 opts = getopt32(argv, OPTION_STR,
565 &G.iface, &G.script_name, &G.poll_time, &G.delay_up, 564 &G.iface, &G.script_name, &G.poll_time, &G.delay_up,
566 &G.delay_down, &G.api_mode, &G.extra_arg); 565 &G.delay_down, &G.api_mode, &G.extra_arg);
diff --git a/networking/inetd.c b/networking/inetd.c
index 8d44b5198..f9295e38b 100644
--- a/networking/inetd.c
+++ b/networking/inetd.c
@@ -1153,8 +1153,8 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
1153 if (real_uid != 0) /* run by non-root user */ 1153 if (real_uid != 0) /* run by non-root user */
1154 config_filename = NULL; 1154 config_filename = NULL;
1155 1155
1156 opt_complementary = "R+:q+"; /* -q N, -R N */ 1156 /* -q N, -R N */
1157 opt = getopt32(argv, "R:feq:", &max_concurrency, &global_queuelen); 1157 opt = getopt32(argv, "R:+feq:+", &max_concurrency, &global_queuelen);
1158 argv += optind; 1158 argv += optind;
1159 //argc -= optind; 1159 //argc -= optind;
1160 if (argv[0]) 1160 if (argv[0])
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c
index 471ae1a12..192e42fe5 100644
--- a/networking/nc_bloaty.c
+++ b/networking/nc_bloaty.c
@@ -794,8 +794,8 @@ int nc_main(int argc UNUSED_PARAM, char **argv)
794 e_found: 794 e_found:
795 795
796 // -g -G -t -r deleted, unimplemented -a deleted too 796 // -g -G -t -r deleted, unimplemented -a deleted too
797 opt_complementary = "?2:vv:ll:w+"; /* max 2 params; -v and -l are counters; -w N */ 797 opt_complementary = "?2:vv:ll"; /* max 2 params; -v and -l are counters; -w N */
798 getopt32(argv, "np:s:uvw:" IF_NC_SERVER("lk") 798 getopt32(argv, "np:s:uvw:+" IF_NC_SERVER("lk")
799 IF_NC_EXTRA("i:o:z"), 799 IF_NC_EXTRA("i:o:z"),
800 &str_p, &str_s, &o_wait 800 &str_p, &str_s, &o_wait
801 IF_NC_EXTRA(, &str_i, &str_o), &o_verbose IF_NC_SERVER(, &cnt_l)); 801 IF_NC_EXTRA(, &str_i, &str_o), &o_verbose IF_NC_SERVER(, &cnt_l));
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 410318979..130cef0af 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -267,7 +267,6 @@ typedef struct {
267 267
268typedef struct { 268typedef struct {
269 len_and_sockaddr *p_lsa; 269 len_and_sockaddr *p_lsa;
270 char *p_hostname;
271 char *p_dotted; 270 char *p_dotted;
272 int p_fd; 271 int p_fd;
273 int datapoint_idx; 272 int datapoint_idx;
@@ -293,6 +292,7 @@ typedef struct {
293 datapoint_t filter_datapoint[NUM_DATAPOINTS]; 292 datapoint_t filter_datapoint[NUM_DATAPOINTS];
294 /* last sent packet: */ 293 /* last sent packet: */
295 msg_t p_xmt_msg; 294 msg_t p_xmt_msg;
295 char p_hostname[1];
296} peer_t; 296} peer_t;
297 297
298 298
@@ -765,14 +765,38 @@ reset_peer_stats(peer_t *p, double offset)
765} 765}
766 766
767static void 767static void
768resolve_peer_hostname(peer_t *p, int loop_on_fail)
769{
770 len_and_sockaddr *lsa;
771
772 again:
773 lsa = host2sockaddr(p->p_hostname, 123);
774 if (!lsa) {
775 /* error message already emitted by host2sockaddr() */
776 if (!loop_on_fail)
777 return;
778//FIXME: do this to avoid infinite looping on typo in a hostname?
779//well... in which case, what is a good value for loop_on_fail?
780 //if (--loop_on_fail == 0)
781 // xfunc_die();
782 sleep(5);
783 goto again;
784 }
785 free(p->p_lsa);
786 free(p->p_dotted);
787 p->p_lsa = lsa;
788 p->p_dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
789}
790
791static void
768add_peers(const char *s) 792add_peers(const char *s)
769{ 793{
770 llist_t *item; 794 llist_t *item;
771 peer_t *p; 795 peer_t *p;
772 796
773 p = xzalloc(sizeof(*p)); 797 p = xzalloc(sizeof(*p) + strlen(s));
774 p->p_lsa = xhost2sockaddr(s, 123); 798 strcpy(p->p_hostname, s);
775 p->p_dotted = xmalloc_sockaddr2dotted_noport(&p->p_lsa->u.sa); 799 resolve_peer_hostname(p, /*loop_on_fail=*/ 1);
776 800
777 /* Names like N.<country2chars>.pool.ntp.org are randomly resolved 801 /* Names like N.<country2chars>.pool.ntp.org are randomly resolved
778 * to a pool of machines. Sometimes different N's resolve to the same IP. 802 * to a pool of machines. Sometimes different N's resolve to the same IP.
@@ -789,7 +813,6 @@ add_peers(const char *s)
789 } 813 }
790 } 814 }
791 815
792 p->p_hostname = xstrdup(s);
793 p->p_fd = -1; 816 p->p_fd = -1;
794 p->p_xmt_msg.m_status = MODE_CLIENT | (NTP_VERSION << 3); 817 p->p_xmt_msg.m_status = MODE_CLIENT | (NTP_VERSION << 3);
795 p->next_action_time = G.cur_time; /* = set_next(p, 0); */ 818 p->next_action_time = G.cur_time; /* = set_next(p, 0); */
@@ -2174,11 +2197,11 @@ static NOINLINE void ntp_init(char **argv)
2174 2197
2175 /* Parse options */ 2198 /* Parse options */
2176 peers = NULL; 2199 peers = NULL;
2177 opt_complementary = "dd:p::wn" /* -d: counter; -p: list; -w implies -n */ 2200 opt_complementary = "dd:wn" /* -d: counter; -p: list; -w implies -n */
2178 IF_FEATURE_NTPD_SERVER(":Il"); /* -I implies -l */ 2201 IF_FEATURE_NTPD_SERVER(":Il"); /* -I implies -l */
2179 opts = getopt32(argv, 2202 opts = getopt32(argv,
2180 "nqNx" /* compat */ 2203 "nqNx" /* compat */
2181 "wp:S:"IF_FEATURE_NTPD_SERVER("l") /* NOT compat */ 2204 "wp:*S:"IF_FEATURE_NTPD_SERVER("l") /* NOT compat */
2182 IF_FEATURE_NTPD_SERVER("I:") /* compat */ 2205 IF_FEATURE_NTPD_SERVER("I:") /* compat */
2183 "d" /* compat */ 2206 "d" /* compat */
2184 "46aAbgL", /* compat, ignored */ 2207 "46aAbgL", /* compat, ignored */
@@ -2190,6 +2213,31 @@ static NOINLINE void ntp_init(char **argv)
2190 2213
2191// if (opts & OPT_x) /* disable stepping, only slew is allowed */ 2214// if (opts & OPT_x) /* disable stepping, only slew is allowed */
2192// G.time_was_stepped = 1; 2215// G.time_was_stepped = 1;
2216
2217#if ENABLE_FEATURE_NTPD_SERVER
2218 G_listen_fd = -1;
2219 if (opts & OPT_l) {
2220 G_listen_fd = create_and_bind_dgram_or_die(NULL, 123);
2221 if (G.if_name) {
2222 if (setsockopt_bindtodevice(G_listen_fd, G.if_name))
2223 xfunc_die();
2224 }
2225 socket_want_pktinfo(G_listen_fd);
2226 setsockopt_int(G_listen_fd, IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY);
2227 }
2228#endif
2229 /* I hesitate to set -20 prio. -15 should be high enough for timekeeping */
2230 if (opts & OPT_N)
2231 setpriority(PRIO_PROCESS, 0, -15);
2232
2233 /* add_peers() calls can retry DNS resolution (possibly forever).
2234 * Daemonize before them, or else boot can stall forever.
2235 */
2236 if (!(opts & OPT_n)) {
2237 bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO, argv);
2238 logmode = LOGMODE_NONE;
2239 }
2240
2193 if (peers) { 2241 if (peers) {
2194 while (peers) 2242 while (peers)
2195 add_peers(llist_pop(&peers)); 2243 add_peers(llist_pop(&peers));
@@ -2218,26 +2266,6 @@ static NOINLINE void ntp_init(char **argv)
2218 /* -l but no peers: "stratum 1 server" mode */ 2266 /* -l but no peers: "stratum 1 server" mode */
2219 G.stratum = 1; 2267 G.stratum = 1;
2220 } 2268 }
2221#if ENABLE_FEATURE_NTPD_SERVER
2222 G_listen_fd = -1;
2223 if (opts & OPT_l) {
2224 G_listen_fd = create_and_bind_dgram_or_die(NULL, 123);
2225 if (opts & OPT_I) {
2226 if (setsockopt_bindtodevice(G_listen_fd, G.if_name))
2227 xfunc_die();
2228 }
2229 socket_want_pktinfo(G_listen_fd);
2230 setsockopt_int(G_listen_fd, IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY);
2231 }
2232#endif
2233 if (!(opts & OPT_n)) {
2234 bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO, argv);
2235 logmode = LOGMODE_NONE;
2236 }
2237 /* I hesitate to set -20 prio. -15 should be high enough for timekeeping */
2238 if (opts & OPT_N)
2239 setpriority(PRIO_PROCESS, 0, -15);
2240
2241 /* If network is up, syncronization occurs in ~10 seconds. 2269 /* If network is up, syncronization occurs in ~10 seconds.
2242 * We give "ntpd -q" 10 seconds to get first reply, 2270 * We give "ntpd -q" 10 seconds to get first reply,
2243 * then another 50 seconds to finish syncing. 2271 * then another 50 seconds to finish syncing.
@@ -2338,18 +2366,8 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
2338 p->p_dotted, p->reachable_bits, timeout); 2366 p->p_dotted, p->reachable_bits, timeout);
2339 2367
2340 /* What if don't see it because it changed its IP? */ 2368 /* What if don't see it because it changed its IP? */
2341 if (p->reachable_bits == 0) { 2369 if (p->reachable_bits == 0)
2342 len_and_sockaddr *lsa = host2sockaddr(p->p_hostname, 123); 2370 resolve_peer_hostname(p, /*loop_on_fail=*/ 0);
2343 if (lsa) {
2344 char *dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
2345 //if (strcmp(dotted, p->p_dotted) != 0)
2346 // bb_error_msg("peer IP changed");
2347 free(p->p_lsa);
2348 free(p->p_dotted);
2349 p->p_lsa = lsa;
2350 p->p_dotted = dotted;
2351 }
2352 }
2353 2371
2354 set_next(p, timeout); 2372 set_next(p, timeout);
2355 } 2373 }
diff --git a/networking/ping.c b/networking/ping.c
index cfe682646..82d5b7a85 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -186,6 +186,7 @@ create_icmp_socket(void)
186struct globals { 186struct globals {
187 char *hostname; 187 char *hostname;
188 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; 188 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
189 uint16_t myid;
189} FIX_ALIASING; 190} FIX_ALIASING;
190#define G (*(struct globals*)bb_common_bufsiz1) 191#define G (*(struct globals*)bb_common_bufsiz1)
191#define INIT_G() do { setup_common_bufsiz(); } while (0) 192#define INIT_G() do { setup_common_bufsiz(); } while (0)
@@ -204,6 +205,7 @@ static void ping4(len_and_sockaddr *lsa)
204 pkt = (struct icmp *) G.packet; 205 pkt = (struct icmp *) G.packet;
205 /*memset(pkt, 0, sizeof(G.packet)); already is */ 206 /*memset(pkt, 0, sizeof(G.packet)); already is */
206 pkt->icmp_type = ICMP_ECHO; 207 pkt->icmp_type = ICMP_ECHO;
208 pkt->icmp_id = G.myid;
207 pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, sizeof(G.packet)); 209 pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, sizeof(G.packet));
208 210
209 xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len); 211 xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len);
@@ -228,6 +230,8 @@ static void ping4(len_and_sockaddr *lsa)
228 struct iphdr *iphdr = (struct iphdr *) G.packet; 230 struct iphdr *iphdr = (struct iphdr *) G.packet;
229 231
230 pkt = (struct icmp *) (G.packet + (iphdr->ihl << 2)); /* skip ip hdr */ 232 pkt = (struct icmp *) (G.packet + (iphdr->ihl << 2)); /* skip ip hdr */
233 if (pkt->icmp_id != G.myid)
234 continue; /* not our ping */
231 if (pkt->icmp_type == ICMP_ECHOREPLY) 235 if (pkt->icmp_type == ICMP_ECHOREPLY)
232 break; 236 break;
233 } 237 }
@@ -246,6 +250,7 @@ static void ping6(len_and_sockaddr *lsa)
246 pkt = (struct icmp6_hdr *) G.packet; 250 pkt = (struct icmp6_hdr *) G.packet;
247 /*memset(pkt, 0, sizeof(G.packet)); already is */ 251 /*memset(pkt, 0, sizeof(G.packet)); already is */
248 pkt->icmp6_type = ICMP6_ECHO_REQUEST; 252 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
253 pkt->icmp6_id = G.myid;
249 254
250 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); 255 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
251 setsockopt_int(pingsock, SOL_RAW, IPV6_CHECKSUM, sockopt); 256 setsockopt_int(pingsock, SOL_RAW, IPV6_CHECKSUM, sockopt);
@@ -269,6 +274,8 @@ static void ping6(len_and_sockaddr *lsa)
269 continue; 274 continue;
270 } 275 }
271 if (c >= ICMP_MINLEN) { /* icmp6_hdr */ 276 if (c >= ICMP_MINLEN) { /* icmp6_hdr */
277 if (pkt->icmp6_id != G.myid)
278 continue; /* not our ping */
272 if (pkt->icmp6_type == ICMP6_ECHO_REPLY) 279 if (pkt->icmp6_type == ICMP6_ECHO_REPLY)
273 break; 280 break;
274 } 281 }
@@ -317,6 +324,7 @@ static int common_ping_main(sa_family_t af, char **argv)
317 alarm(5); /* give the host 5000ms to respond */ 324 alarm(5); /* give the host 5000ms to respond */
318 325
319 create_icmp_socket(lsa); 326 create_icmp_socket(lsa);
327 G.myid = (uint16_t) getpid();
320#if ENABLE_PING6 328#if ENABLE_PING6
321 if (lsa->u.sa.sa_family == AF_INET6) 329 if (lsa->u.sa.sa_family == AF_INET6)
322 ping6(lsa); 330 ping6(lsa);
@@ -333,7 +341,7 @@ static int common_ping_main(sa_family_t af, char **argv)
333 341
334/* Full(er) version */ 342/* Full(er) version */
335 343
336#define OPT_STRING ("qvc:s:t:w:W:I:np:4" IF_PING6("6")) 344#define OPT_STRING ("qvc:+s:t:+w:+W:+I:np:4" IF_PING6("6"))
337enum { 345enum {
338 OPT_QUIET = 1 << 0, 346 OPT_QUIET = 1 << 0,
339 OPT_VERBOSE = 1 << 1, 347 OPT_VERBOSE = 1 << 1,
@@ -857,7 +865,7 @@ static int common_ping_main(int opt, char **argv)
857 INIT_G(); 865 INIT_G();
858 866
859 /* exactly one argument needed; -v and -q don't mix; -c NUM, -t NUM, -w NUM, -W NUM */ 867 /* exactly one argument needed; -v and -q don't mix; -c NUM, -t NUM, -w NUM, -W NUM */
860 opt_complementary = "=1:q--v:v--q:c+:t+:w+:W+"; 868 opt_complementary = "=1:q--v:v--q";
861 opt |= getopt32(argv, OPT_STRING, &pingcount, &str_s, &opt_ttl, &deadline, &timeout, &str_I, &str_p); 869 opt |= getopt32(argv, OPT_STRING, &pingcount, &str_s, &opt_ttl, &deadline, &timeout, &str_I, &str_p);
862 if (opt & OPT_s) 870 if (opt & OPT_s)
863 datalen = xatou16(str_s); // -s 871 datalen = xatou16(str_s); // -s
diff --git a/networking/tcpudp.c b/networking/tcpudp.c
index 31bc70459..fbd1f1c45 100644
--- a/networking/tcpudp.c
+++ b/networking/tcpudp.c
@@ -232,9 +232,9 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv)
232 tcp = (applet_name[0] == 't'); 232 tcp = (applet_name[0] == 't');
233 233
234 /* 3+ args, -i at most once, -p implies -h, -v is counter, -b N, -c N */ 234 /* 3+ args, -i at most once, -p implies -h, -v is counter, -b N, -c N */
235 opt_complementary = "-3:i--i:ph:vv:b+:c+"; 235 opt_complementary = "-3:i--i:ph:vv";
236#ifdef SSLSVD 236#ifdef SSLSVD
237 opts = getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:", 237 opts = getopt32(argv, "+c:+C:i:x:u:l:Eb:+hpt:vU:/:Z:K:",
238 &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname, 238 &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname,
239 &backlog, &str_t, &ssluser, &root, &cert, &key, &verbose 239 &backlog, &str_t, &ssluser, &root, &cert, &key, &verbose
240 ); 240 );
diff --git a/networking/telnetd.c b/networking/telnetd.c
index 13c36aa46..2fbdc3bb3 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -496,12 +496,12 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
496 INIT_G(); 496 INIT_G();
497 497
498 /* -w NUM, and implies -F. -w and -i don't mix */ 498 /* -w NUM, and implies -F. -w and -i don't mix */
499 IF_FEATURE_TELNETD_INETD_WAIT(opt_complementary = "wF:w+:i--w:w--i";) 499 IF_FEATURE_TELNETD_INETD_WAIT(opt_complementary = "wF:i--w:w--i";)
500 /* Even if !STANDALONE, we accept (and ignore) -i, thus people 500 /* Even if !STANDALONE, we accept (and ignore) -i, thus people
501 * don't need to guess whether it's ok to pass -i to us */ 501 * don't need to guess whether it's ok to pass -i to us */
502 opt = getopt32(argv, "f:l:Ki" 502 opt = getopt32(argv, "f:l:Ki"
503 IF_FEATURE_TELNETD_STANDALONE("p:b:F") 503 IF_FEATURE_TELNETD_STANDALONE("p:b:F")
504 IF_FEATURE_TELNETD_INETD_WAIT("Sw:"), 504 IF_FEATURE_TELNETD_INETD_WAIT("Sw:+"),
505 &G.issuefile, &G.loginpath 505 &G.issuefile, &G.loginpath
506 IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr) 506 IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr)
507 IF_FEATURE_TELNETD_INETD_WAIT(, &sec_linger) 507 IF_FEATURE_TELNETD_INETD_WAIT(, &sec_linger)
diff --git a/networking/traceroute.c b/networking/traceroute.c
index eee4f8873..e43a36dc7 100644
--- a/networking/traceroute.c
+++ b/networking/traceroute.c
@@ -294,7 +294,7 @@
294 294
295#define OPT_STRING \ 295#define OPT_STRING \
296 "FIlnrdvxt:i:m:p:q:s:w:z:f:" \ 296 "FIlnrdvxt:i:m:p:q:s:w:z:f:" \
297 IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:") \ 297 IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:*") \
298 "4" IF_TRACEROUTE6("6") 298 "4" IF_TRACEROUTE6("6")
299enum { 299enum {
300 OPT_DONT_FRAGMNT = (1 << 0), /* F */ 300 OPT_DONT_FRAGMNT = (1 << 0), /* F */
@@ -819,7 +819,7 @@ common_traceroute_main(int op, char **argv)
819 INIT_G(); 819 INIT_G();
820 820
821 /* minimum 1 arg */ 821 /* minimum 1 arg */
822 opt_complementary = "-1:x-x" IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(":g::"); 822 opt_complementary = "-1:x-x";
823 op |= getopt32(argv, OPT_STRING 823 op |= getopt32(argv, OPT_STRING
824 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str 824 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str
825 , &source, &waittime_str, &pausemsecs_str, &first_ttl_str 825 , &source, &waittime_str, &pausemsecs_str, &first_ttl_str
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index c77669a31..6ff040d9e 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -793,7 +793,11 @@ static void perform_renew(void)
793static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) 793static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
794{ 794{
795 /* send release packet */ 795 /* send release packet */
796 if (state == BOUND || state == RENEWING || state == REBINDING) { 796 if (state == BOUND
797 || state == RENEWING
798 || state == REBINDING
799 || state == RENEW_REQUESTED
800 ) {
797 bb_error_msg("unicasting a release"); 801 bb_error_msg("unicasting a release");
798 send_d6_release(server_ipv6, our_cur_ipv6); /* unicast */ 802 send_d6_release(server_ipv6, our_cur_ipv6); /* unicast */
799 d6_run_script(NULL, "deconfig"); 803 d6_run_script(NULL, "deconfig");
@@ -940,9 +944,9 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
940 944
941 /* Parse command line */ 945 /* Parse command line */
942 /* O,x: list; -T,-t,-A take numeric param */ 946 /* O,x: list; -T,-t,-A take numeric param */
943 opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ; 947 IF_UDHCP_VERBOSE(opt_complementary = "vv";)
944 IF_LONG_OPTS(applet_long_options = udhcpc6_longopts;) 948 IF_LONG_OPTS(applet_long_options = udhcpc6_longopts;)
945 opt = getopt32(argv, "i:np:qRr:s:T:t:SA:O:ox:f" 949 opt = getopt32(argv, "i:np:qRr:s:T:+t:+SA:+O:*ox:*f"
946 USE_FOR_MMU("b") 950 USE_FOR_MMU("b")
947 ///IF_FEATURE_UDHCPC_ARPING("a") 951 ///IF_FEATURE_UDHCPC_ARPING("a")
948 IF_FEATURE_UDHCP_PORT("P:") 952 IF_FEATURE_UDHCP_PORT("P:")
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index fc7b6216d..8a16e987d 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -1118,7 +1118,11 @@ static void perform_release(uint32_t server_addr, uint32_t requested_ip)
1118 struct in_addr temp_addr; 1118 struct in_addr temp_addr;
1119 1119
1120 /* send release packet */ 1120 /* send release packet */
1121 if (state == BOUND || state == RENEWING || state == REBINDING) { 1121 if (state == BOUND
1122 || state == RENEWING
1123 || state == REBINDING
1124 || state == RENEW_REQUESTED
1125 ) {
1122 temp_addr.s_addr = server_addr; 1126 temp_addr.s_addr = server_addr;
1123 strcpy(buffer, inet_ntoa(temp_addr)); 1127 strcpy(buffer, inet_ntoa(temp_addr));
1124 temp_addr.s_addr = requested_ip; 1128 temp_addr.s_addr = requested_ip;
@@ -1279,9 +1283,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1279 1283
1280 /* Parse command line */ 1284 /* Parse command line */
1281 /* O,x: list; -T,-t,-A take numeric param */ 1285 /* O,x: list; -T,-t,-A take numeric param */
1282 opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ; 1286 IF_UDHCP_VERBOSE(opt_complementary = "vv";)
1283 IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) 1287 IF_LONG_OPTS(applet_long_options = udhcpc_longopts;)
1284 opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB" 1288 opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:+t:+SA:+O:*ox:*fB"
1285 USE_FOR_MMU("b") 1289 USE_FOR_MMU("b")
1286 IF_FEATURE_UDHCPC_ARPING("a::") 1290 IF_FEATURE_UDHCPC_ARPING("a::")
1287 IF_FEATURE_UDHCP_PORT("P:") 1291 IF_FEATURE_UDHCP_PORT("P:")
diff --git a/networking/wget.c b/networking/wget.c
index c725edb5b..c886dd391 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -1274,9 +1274,8 @@ IF_DESKTOP( "no-parent\0" No_argument "\xf0")
1274 applet_long_options = wget_longopts; 1274 applet_long_options = wget_longopts;
1275#endif 1275#endif
1276 opt_complementary = "-1" /* at least one URL */ 1276 opt_complementary = "-1" /* at least one URL */
1277 IF_FEATURE_WGET_TIMEOUT(":T+") /* -T NUM */
1278 IF_FEATURE_WGET_LONG_OPTIONS(":\xff::"); /* --header is a list */ 1277 IF_FEATURE_WGET_LONG_OPTIONS(":\xff::"); /* --header is a list */
1279 getopt32(argv, "csqO:P:Y:U:T:" 1278 getopt32(argv, "csqO:P:Y:U:T:+"
1280 /*ignored:*/ "t:" 1279 /*ignored:*/ "t:"
1281 /*ignored:*/ "n::" 1280 /*ignored:*/ "n::"
1282 /* wget has exactly four -n<letter> opts, all of which we can ignore: 1281 /* wget has exactly four -n<letter> opts, all of which we can ignore:
diff --git a/networking/whois.c b/networking/whois.c
index bf330334a..c9dfcf5ee 100644
--- a/networking/whois.c
+++ b/networking/whois.c
@@ -21,43 +21,158 @@
21//kbuild:lib-$(CONFIG_WHOIS) += whois.o 21//kbuild:lib-$(CONFIG_WHOIS) += whois.o
22 22
23//usage:#define whois_trivial_usage 23//usage:#define whois_trivial_usage
24//usage: "[-h SERVER] [-p PORT] NAME..." 24//usage: "[-i] [-h SERVER] [-p PORT] NAME..."
25//usage:#define whois_full_usage "\n\n" 25//usage:#define whois_full_usage "\n\n"
26//usage: "Query WHOIS info about NAME\n" 26//usage: "Query WHOIS info about NAME\n"
27//usage: "\n -i Show redirect results too"
27//usage: "\n -h,-p Server to query" 28//usage: "\n -h,-p Server to query"
28 29
29#include "libbb.h" 30#include "libbb.h"
30 31
31static void pipe_out(int fd) 32enum {
33 OPT_i = (1 << 0),
34};
35
36static char *query(const char *host, int port, const char *domain)
32{ 37{
38 int fd;
33 FILE *fp; 39 FILE *fp;
34 char buf[1024]; 40 bool success;
41 char *redir = NULL;
42 const char *pfx = "";
43 char linebuf[1024];
44 char *buf = NULL;
45 unsigned bufpos = 0;
35 46
47 again:
48 printf("[Querying %s:%d '%s%s']\n", host, port, pfx, domain);
49 fd = create_and_connect_stream_or_die(host, port);
50 success = 0;
51 fdprintf(fd, "%s%s\r\n", pfx, domain);
36 fp = xfdopen_for_read(fd); 52 fp = xfdopen_for_read(fd);
37 while (fgets(buf, sizeof(buf), fp)) {
38 char *p = strpbrk(buf, "\r\n");
39 if (p)
40 *p = '\0';
41 puts(buf);
42 }
43 53
54 while (fgets(linebuf, sizeof(linebuf), fp)) {
55 unsigned len = strcspn(linebuf, "\r\n");
56 linebuf[len++] = '\n';
57
58 buf = xrealloc(buf, bufpos + len + 1);
59 memcpy(buf + bufpos, linebuf, len);
60 bufpos += len;
61 buf[bufpos] = '\0';
62
63 if (!redir || !success) {
64 trim(linebuf);
65 str_tolower(linebuf);
66 if (!success) {
67 success = is_prefixed_with(linebuf, "domain:")
68 || is_prefixed_with(linebuf, "domain name:");
69 }
70 else if (!redir) {
71 char *p = is_prefixed_with(linebuf, "whois server:");
72 if (!p)
73 p = is_prefixed_with(linebuf, "whois:");
74 if (p)
75 redir = xstrdup(skip_whitespace(p));
76 }
77 }
78 }
44 fclose(fp); /* closes fd too */ 79 fclose(fp); /* closes fd too */
80 if (!success && !pfx[0]) {
81 /*
82 * Looking at /etc/jwhois.conf, some whois servers use
83 * "domain = DOMAIN", "DOMAIN ID <DOMAIN>"
84 * and "domain=DOMAIN_WITHOUT_LAST_COMPONENT"
85 * formats, but those are rare.
86 * (There are a few even more contrived ones.)
87 * We are trying only "domain DOMAIN", the typical one.
88 */
89 pfx = "domain ";
90 bufpos = 0;
91 goto again;
92 }
93
94 /* Success */
95 if (redir && strcmp(redir, host) == 0) {
96 /* Redirect to self does not count */
97 free(redir);
98 redir = NULL;
99 }
100 if (!redir || (option_mask32 & OPT_i)) {
101 /* Output saved text */
102 printf("[%s]\n%s", host, buf ? buf : "");
103 }
104 free(buf);
105 return redir;
106}
107
108static void recursive_query(const char *host, int port, const char *domain)
109{
110 char *free_me = NULL;
111 char *redir;
112 again:
113 redir = query(host, port, domain);
114 free(free_me);
115 if (redir) {
116 printf("[Redirected to %s]\n", redir);
117 host = free_me = redir;
118 port = 43;
119 goto again;
120 }
45} 121}
46 122
123/* One of "big" whois implementations has these options:
124 *
125 * $ whois --help
126 * jwhois version 4.0, Copyright (C) 1999-2007 Free Software Foundation, Inc.
127 * -v, --verbose verbose debug output
128 * -c FILE, --config=FILE use FILE as configuration file
129 * -h HOST, --host=HOST explicitly query HOST
130 * -n, --no-redirect disable content redirection
131 * -s, --no-whoisservers disable whois-servers.net service support
132 * -a, --raw disable reformatting of the query
133 * -i, --display-redirections display all redirects instead of hiding them
134 * -p PORT, --port=PORT use port number PORT (in conjunction with HOST)
135 * -r, --rwhois force an rwhois query to be made
136 * --rwhois-display=DISPLAY sets the display option in rwhois queries
137 * --rwhois-limit=LIMIT sets the maximum number of matches to return
138 *
139 * Example of its output:
140 * $ whois cnn.com
141 * [Querying whois.verisign-grs.com]
142 * [Redirected to whois.corporatedomains.com]
143 * [Querying whois.corporatedomains.com]
144 * [whois.corporatedomains.com]
145 * ...text of the reply...
146 *
147 * With -i, reply from each server is printed, after all redirects are done:
148 * [Querying whois.verisign-grs.com]
149 * [Redirected to whois.corporatedomains.com]
150 * [Querying whois.corporatedomains.com]
151 * [whois.verisign-grs.com]
152 * ...text of the reply...
153 * [whois.corporatedomains.com]
154 * ...text of the reply...
155 *
156 * With -a, no "DOMAIN" -> "domain DOMAIN" transformation is attempted.
157
158 * With -n, the first reply is shown, redirects are not followed:
159 * [Querying whois.verisign-grs.com]
160 * [whois.verisign-grs.com]
161 * ...text of the reply...
162 */
163
47int whois_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 164int whois_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
48int whois_main(int argc UNUSED_PARAM, char **argv) 165int whois_main(int argc UNUSED_PARAM, char **argv)
49{ 166{
50 int port = 43; 167 int port = 43;
51 const char *host = "whois-servers.net"; 168 const char *host = "whois.iana.org";
52
53 opt_complementary = "-1:p+";
54 getopt32(argv, "h:p:", &host, &port);
55 169
170 opt_complementary = "-1";
171 getopt32(argv, "ih:p:+", &host, &port);
56 argv += optind; 172 argv += optind;
173
57 do { 174 do {
58 int fd = create_and_connect_stream_or_die(host, port); 175 recursive_query(host, port, *argv);
59 fdprintf(fd, "%s\r\n", *argv);
60 pipe_out(fd);
61 } 176 }
62 while (*++argv); 177 while (*++argv);
63 178