aboutsummaryrefslogtreecommitdiff
path: root/networking
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2018-02-13 09:44:44 +0000
committerRon Yorston <rmy@pobox.com>2018-02-13 09:44:44 +0000
commitdc19a361bd6c6df30338371532691bbc7f7126bb (patch)
tree1fb2cd646d54b5f8e425c4f11f3e09fc21d1966b /networking
parent096aee2bb468d1ab044de36e176ed1f6c7e3674d (diff)
parent3459024bf404af814cacfe90a0deb719e282ae62 (diff)
downloadbusybox-w32-dc19a361bd6c6df30338371532691bbc7f7126bb.tar.gz
busybox-w32-dc19a361bd6c6df30338371532691bbc7f7126bb.tar.bz2
busybox-w32-dc19a361bd6c6df30338371532691bbc7f7126bb.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'networking')
-rw-r--r--networking/arping.c193
-rw-r--r--networking/ftpd.c14
-rw-r--r--networking/ftpgetput.c44
-rw-r--r--networking/inetd.c5
-rw-r--r--networking/libiproute/Kbuild.src6
-rw-r--r--networking/libiproute/ipaddress.c6
-rw-r--r--networking/libiproute/iplink.c4
-rw-r--r--networking/libiproute/ipneigh.c10
-rw-r--r--networking/libiproute/iproute.c4
-rw-r--r--networking/libiproute/iprule.c2
-rw-r--r--networking/libiproute/libnetlink.c7
-rw-r--r--networking/libiproute/ll_map.c2
-rw-r--r--networking/ntpd.c4
-rw-r--r--networking/parse_pasv_epsv.c66
-rw-r--r--networking/ssl_client.c14
-rw-r--r--networking/tc.c128
-rw-r--r--networking/tftp.c3
-rw-r--r--networking/tls.c98
-rw-r--r--networking/udhcp/Config.src2
-rw-r--r--networking/udhcp/d6_common.h1
-rw-r--r--networking/udhcp/d6_dhcpc.c246
-rw-r--r--networking/udhcp/d6_socket.c31
-rw-r--r--networking/udhcp/dhcpc.c8
-rw-r--r--networking/udhcp/dhcpd.c8
-rw-r--r--networking/udhcp/dhcprelay.c8
-rw-r--r--networking/wget.c278
26 files changed, 708 insertions, 484 deletions
diff --git a/networking/arping.c b/networking/arping.c
index f9967d81e..788fded3c 100644
--- a/networking/arping.c
+++ b/networking/arping.c
@@ -11,7 +11,6 @@
11//config: select PLATFORM_LINUX 11//config: select PLATFORM_LINUX
12//config: help 12//config: help
13//config: Ping hosts by ARP packets. 13//config: Ping hosts by ARP packets.
14//config:
15 14
16//applet:IF_ARPING(APPLET(arping, BB_DIR_USR_SBIN, BB_SUID_DROP)) 15//applet:IF_ARPING(APPLET(arping, BB_DIR_USR_SBIN, BB_SUID_DROP))
17 16
@@ -29,6 +28,7 @@
29//usage: "\n -A ARP answer mode, update your neighbors" 28//usage: "\n -A ARP answer mode, update your neighbors"
30//usage: "\n -c N Stop after sending N ARP requests" 29//usage: "\n -c N Stop after sending N ARP requests"
31//usage: "\n -w TIMEOUT Seconds to wait for ARP reply" 30//usage: "\n -w TIMEOUT Seconds to wait for ARP reply"
31//NB: in iputils-s20160308, iface is mandatory, no default
32//usage: "\n -I IFACE Interface to use (default eth0)" 32//usage: "\n -I IFACE Interface to use (default eth0)"
33//usage: "\n -s SRC_IP Sender IP address" 33//usage: "\n -s SRC_IP Sender IP address"
34//usage: "\n DST_IP Target IP address" 34//usage: "\n DST_IP Target IP address"
@@ -45,21 +45,29 @@
45#define MONOTONIC_US() ((unsigned)monotonic_us()) 45#define MONOTONIC_US() ((unsigned)monotonic_us())
46 46
47enum { 47enum {
48 DAD = 1, 48 UNSOLICITED = 1 << 0,
49 UNSOLICITED = 2, 49 DAD = 1 << 1,
50 ADVERT = 4, 50 ADVERT = 1 << 2,
51 QUIET = 8, 51 QUIET = 1 << 3,
52 QUIT_ON_REPLY = 16, 52 QUIT_ON_REPLY = 1 << 4,
53 BCAST_ONLY = 32, 53 BCAST_ONLY = 1 << 5,
54 UNICASTING = 64 54 UNICASTING = 1 << 6,
55 TIMEOUT = 1 << 7,
55}; 56};
57#define GETOPT32(str_timeout, device, source) \
58 getopt32(argv, "^" \
59 "UDAqfbc:+w:I:s:" \
60 /* DAD also sets quit_on_reply, */ \
61 /* advert also sets unsolicited: */ \
62 "\0" "=1:Df:AU", \
63 &count, &str_timeout, &device, &source \
64 );
56 65
57struct globals { 66struct globals {
58 struct in_addr src; 67 struct in_addr src;
59 struct in_addr dst; 68 struct in_addr dst;
60 struct sockaddr_ll me; 69 struct sockaddr_ll me;
61 struct sockaddr_ll he; 70 struct sockaddr_ll he;
62 int sock_fd;
63 71
64 int count; // = -1; 72 int count; // = -1;
65 unsigned last; 73 unsigned last;
@@ -71,13 +79,17 @@ struct globals {
71 unsigned received; 79 unsigned received;
72 unsigned brd_recv; 80 unsigned brd_recv;
73 unsigned req_recv; 81 unsigned req_recv;
82
83 /* should be in main(), but are here to reduce stack use: */
84 struct ifreq ifr;
85 struct sockaddr_in probe_saddr;
86 sigset_t sset;
87 unsigned char packet[4096];
74} FIX_ALIASING; 88} FIX_ALIASING;
75#define G (*(struct globals*)bb_common_bufsiz1)
76#define src (G.src ) 89#define src (G.src )
77#define dst (G.dst ) 90#define dst (G.dst )
78#define me (G.me ) 91#define me (G.me )
79#define he (G.he ) 92#define he (G.he )
80#define sock_fd (G.sock_fd )
81#define count (G.count ) 93#define count (G.count )
82#define last (G.last ) 94#define last (G.last )
83#define timeout_us (G.timeout_us) 95#define timeout_us (G.timeout_us)
@@ -87,26 +99,25 @@ struct globals {
87#define received (G.received ) 99#define received (G.received )
88#define brd_recv (G.brd_recv ) 100#define brd_recv (G.brd_recv )
89#define req_recv (G.req_recv ) 101#define req_recv (G.req_recv )
102//#define G (*(struct globals*)bb_common_bufsiz1)
103#define G (*ptr_to_globals)
90#define INIT_G() do { \ 104#define INIT_G() do { \
91 setup_common_bufsiz(); \ 105 /*setup_common_bufsiz();*/ \
106 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
92 count = -1; \ 107 count = -1; \
93} while (0) 108} while (0)
94 109
95// If GNUisms are not available... 110#define sock_fd 3
96//static void *mempcpy(void *_dst, const void *_src, int n)
97//{
98// memcpy(_dst, _src, n);
99// return (char*)_dst + n;
100//}
101 111
102static int send_pack(struct in_addr *src_addr, 112static int send_pack(struct in_addr *src_addr,
103 struct in_addr *dst_addr, struct sockaddr_ll *ME, 113 struct in_addr *dst_addr,
114 struct sockaddr_ll *ME,
104 struct sockaddr_ll *HE) 115 struct sockaddr_ll *HE)
105{ 116{
106 int err; 117 int err;
107 unsigned char buf[256]; 118 unsigned char buf[256];
108 struct arphdr *ah = (struct arphdr *) buf; 119 struct arphdr *ah = (struct arphdr *) buf;
109 unsigned char *p = (unsigned char *) (ah + 1); 120 unsigned char *p;
110 121
111 ah->ar_hrd = htons(ARPHRD_ETHER); 122 ah->ar_hrd = htons(ARPHRD_ETHER);
112 ah->ar_pro = htons(ETH_P_IP); 123 ah->ar_pro = htons(ETH_P_IP);
@@ -114,6 +125,7 @@ static int send_pack(struct in_addr *src_addr,
114 ah->ar_pln = 4; 125 ah->ar_pln = 4;
115 ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST); 126 ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
116 127
128 p = (unsigned char *) (ah + 1);
117 p = mempcpy(p, &ME->sll_addr, ah->ar_hln); 129 p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
118 p = mempcpy(p, src_addr, 4); 130 p = mempcpy(p, src_addr, 4);
119 131
@@ -139,10 +151,10 @@ static void finish(void)
139{ 151{
140 if (!(option_mask32 & QUIET)) { 152 if (!(option_mask32 & QUIET)) {
141 printf("Sent %u probe(s) (%u broadcast(s))\n" 153 printf("Sent %u probe(s) (%u broadcast(s))\n"
142 "Received %u repl%s" 154 "Received %u response(s)"
143 " (%u request(s), %u broadcast(s))\n", 155 " (%u request(s), %u broadcast(s))\n",
144 sent, brd_sent, 156 sent, brd_sent,
145 received, (received == 1) ? "ies" : "y", 157 received,
146 req_recv, brd_recv); 158 req_recv, brd_recv);
147 } 159 }
148 if (option_mask32 & DAD) 160 if (option_mask32 & DAD)
@@ -180,15 +192,10 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
180 struct arphdr *ah = (struct arphdr *) buf; 192 struct arphdr *ah = (struct arphdr *) buf;
181 unsigned char *p = (unsigned char *) (ah + 1); 193 unsigned char *p = (unsigned char *) (ah + 1);
182 struct in_addr src_ip, dst_ip; 194 struct in_addr src_ip, dst_ip;
195
183 /* moves below assume in_addr is 4 bytes big, ensure that */ 196 /* moves below assume in_addr is 4 bytes big, ensure that */
184 struct BUG_in_addr_must_be_4 { 197 BUILD_BUG_ON(sizeof(struct in_addr) != 4);
185 char BUG_in_addr_must_be_4[ 198 BUILD_BUG_ON(sizeof(src_ip.s_addr) != 4);
186 sizeof(struct in_addr) == 4 ? 1 : -1
187 ];
188 char BUG_s_addr_must_be_4[
189 sizeof(src_ip.s_addr) == 4 ? 1 : -1
190 ];
191 };
192 199
193 /* Filter out wild packets */ 200 /* Filter out wild packets */
194 if (FROM->sll_pkttype != PACKET_HOST 201 if (FROM->sll_pkttype != PACKET_HOST
@@ -209,8 +216,10 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
209 if (ah->ar_pro != htons(ETH_P_IP) 216 if (ah->ar_pro != htons(ETH_P_IP)
210 || (ah->ar_pln != 4) 217 || (ah->ar_pln != 4)
211 || (ah->ar_hln != me.sll_halen) 218 || (ah->ar_hln != me.sll_halen)
212 || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln)))) 219 || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln)))
220 ) {
213 return; 221 return;
222 }
214 223
215 move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln); 224 move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln);
216 move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln); 225 move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln);
@@ -242,6 +251,7 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
242 if (!(option_mask32 & QUIET)) { 251 if (!(option_mask32 & QUIET)) {
243 int s_printed = 0; 252 int s_printed = 0;
244 253
254//TODO: arping from iputils-s20160308 print upprcase hex in MAC, follow them?
245 printf("%scast re%s from %s [%02x:%02x:%02x:%02x:%02x:%02x]", 255 printf("%scast re%s from %s [%02x:%02x:%02x:%02x:%02x:%02x]",
246 FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad", 256 FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad",
247 ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest", 257 ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest",
@@ -249,14 +259,14 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
249 p[0], p[1], p[2], p[3], p[4], p[5] 259 p[0], p[1], p[2], p[3], p[4], p[5]
250 ); 260 );
251 if (dst_ip.s_addr != src.s_addr) { 261 if (dst_ip.s_addr != src.s_addr) {
252 printf("for %s ", inet_ntoa(dst_ip)); 262 printf("for %s", inet_ntoa(dst_ip));
253 s_printed = 1; 263 s_printed = 1;
254 } 264 }
255 if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) { 265 if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) {
256 unsigned char *pp = p + ah->ar_hln + 4; 266 unsigned char *pp = p + ah->ar_hln + 4;
257 if (!s_printed) 267 if (!s_printed)
258 printf("for "); 268 printf(" for");
259 printf("[%02x:%02x:%02x:%02x:%02x:%02x]", 269 printf(" [%02x:%02x:%02x:%02x:%02x:%02x]",
260 pp[0], pp[1], pp[2], pp[3], pp[4], pp[5] 270 pp[0], pp[1], pp[2], pp[3], pp[4], pp[5]
261 ); 271 );
262 } 272 }
@@ -288,12 +298,11 @@ int arping_main(int argc UNUSED_PARAM, char **argv)
288 const char *device = "eth0"; 298 const char *device = "eth0";
289 char *source = NULL; 299 char *source = NULL;
290 char *target; 300 char *target;
291 unsigned char *packet;
292 char *err_str; 301 char *err_str;
293 302
294 INIT_G(); 303 INIT_G();
295 304
296 sock_fd = xsocket(AF_PACKET, SOCK_DGRAM, 0); 305 xmove_fd(xsocket(AF_PACKET, SOCK_DGRAM, 0), sock_fd);
297 306
298 // If you ever change BB_SUID_DROP to BB_SUID_REQUIRE, 307 // If you ever change BB_SUID_DROP to BB_SUID_REQUIRE,
299 // drop suid root privileges here: 308 // drop suid root privileges here:
@@ -303,41 +312,30 @@ int arping_main(int argc UNUSED_PARAM, char **argv)
303 unsigned opt; 312 unsigned opt;
304 char *str_timeout; 313 char *str_timeout;
305 314
306 /* Dad also sets quit_on_reply. 315 opt = GETOPT32(str_timeout, device, source);
307 * Advert also sets unsolicited. 316 if (opt & TIMEOUT)
308 */
309 opt = getopt32(argv, "^" "DUAqfbc:+w:I:s:" "\0" "=1:Df:AU",
310 &count, &str_timeout, &device, &source
311 );
312 if (opt & 0x80) /* -w: timeout */
313 timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000; 317 timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000;
314 //if (opt & 0x200) /* -s: source */
315 option_mask32 &= 0x3f; /* set respective flags */
316 } 318 }
317 319
318 target = argv[optind]; 320 target = argv[optind];
319 err_str = xasprintf("interface %s %%s", device); 321 err_str = xasprintf("interface %s %%s", device);
320 xfunc_error_retval = 2; 322 xfunc_error_retval = 2;
321 323
322 { 324 /*memset(&G.ifr, 0, sizeof(G.ifr)); - zeroed by INIT_G */
323 struct ifreq ifr; 325 strncpy_IFNAMSIZ(G.ifr.ifr_name, device);
324 326 ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &G.ifr, err_str, "not found");
325 memset(&ifr, 0, sizeof(ifr)); 327 me.sll_ifindex = G.ifr.ifr_ifindex;
326 strncpy_IFNAMSIZ(ifr.ifr_name, device);
327 /* We use ifr.ifr_name in error msg so that problem
328 * with truncated name will be visible */
329 ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &ifr, err_str, "not found");
330 me.sll_ifindex = ifr.ifr_ifindex;
331 328
332 xioctl(sock_fd, SIOCGIFFLAGS, (char *) &ifr); 329 xioctl(sock_fd, SIOCGIFFLAGS, (char *) &G.ifr);
333 330
334 if (!(ifr.ifr_flags & IFF_UP)) { 331 if (!(G.ifr.ifr_flags & IFF_UP)) {
335 bb_error_msg_and_die(err_str, "is down"); 332 bb_error_msg_and_die(err_str, "is down");
336 } 333 }
337 if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) { 334 if (G.ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) {
338 bb_error_msg(err_str, "is not ARPable"); 335 bb_error_msg(err_str, "is not ARPable");
339 return (option_mask32 & DAD ? 0 : 2); 336 BUILD_BUG_ON(DAD != 2);
340 } 337 /* exit 0 if DAD, else exit 2 */
338 return (~option_mask32 & DAD);
341 } 339 }
342 340
343 /* if (!inet_aton(target, &dst)) - not needed */ { 341 /* if (!inet_aton(target, &dst)) - not needed */ {
@@ -356,33 +354,29 @@ int arping_main(int argc UNUSED_PARAM, char **argv)
356 src = dst; 354 src = dst;
357 355
358 if (!(option_mask32 & DAD) || src.s_addr) { 356 if (!(option_mask32 & DAD) || src.s_addr) {
359 struct sockaddr_in saddr; 357 /*struct sockaddr_in probe_saddr;*/
360 int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); 358 int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0);
361 359
362 setsockopt_bindtodevice(probe_fd, device); 360 setsockopt_bindtodevice(probe_fd, device);
363 memset(&saddr, 0, sizeof(saddr)); 361
364 saddr.sin_family = AF_INET; 362 /*memset(&G.probe_saddr, 0, sizeof(G.probe_saddr)); - zeroed by INIT_G */
363 G.probe_saddr.sin_family = AF_INET;
365 if (src.s_addr) { 364 if (src.s_addr) {
366 /* Check that this is indeed our IP */ 365 /* Check that this is indeed our IP */
367 saddr.sin_addr = src; 366 G.probe_saddr.sin_addr = src;
368 xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); 367 xbind(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr));
369 } else { /* !(option_mask32 & DAD) case */ 368 } else { /* !(option_mask32 & DAD) case */
370 /* Find IP address on this iface */ 369 /* Find IP address on this iface */
371 socklen_t alen = sizeof(saddr); 370 G.probe_saddr.sin_port = htons(1025);
372 371 G.probe_saddr.sin_addr = dst;
373 saddr.sin_port = htons(1025);
374 saddr.sin_addr = dst;
375 372
376 if (setsockopt_SOL_SOCKET_1(probe_fd, SO_DONTROUTE) != 0) 373 if (setsockopt_SOL_SOCKET_1(probe_fd, SO_DONTROUTE) != 0)
377 bb_perror_msg("setsockopt(%s)", "SO_DONTROUTE"); 374 bb_perror_msg("setsockopt(%s)", "SO_DONTROUTE");
378 xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); 375 xconnect(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr));
379 getsockname(probe_fd, (struct sockaddr *) &saddr, &alen); 376 bb_getsockname(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr));
380 //never happens: 377 if (G.probe_saddr.sin_family != AF_INET)
381 //if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1)
382 // bb_perror_msg_and_die("getsockname");
383 if (saddr.sin_family != AF_INET)
384 bb_error_msg_and_die("no IP address configured"); 378 bb_error_msg_and_die("no IP address configured");
385 src = saddr.sin_addr; 379 src = G.probe_saddr.sin_addr;
386 } 380 }
387 close(probe_fd); 381 close(probe_fd);
388 } 382 }
@@ -392,48 +386,53 @@ int arping_main(int argc UNUSED_PARAM, char **argv)
392 me.sll_protocol = htons(ETH_P_ARP); 386 me.sll_protocol = htons(ETH_P_ARP);
393 xbind(sock_fd, (struct sockaddr *) &me, sizeof(me)); 387 xbind(sock_fd, (struct sockaddr *) &me, sizeof(me));
394 388
395 { 389 bb_getsockname(sock_fd, (struct sockaddr *) &me, sizeof(me));
396 socklen_t alen = sizeof(me); 390 //never happens:
397 getsockname(sock_fd, (struct sockaddr *) &me, &alen); 391 //if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1)
398 //never happens: 392 // bb_perror_msg_and_die("getsockname");
399 //if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1)
400 // bb_perror_msg_and_die("getsockname");
401 }
402 if (me.sll_halen == 0) { 393 if (me.sll_halen == 0) {
403 bb_error_msg(err_str, "is not ARPable (no ll address)"); 394 bb_error_msg(err_str, "is not ARPable (no ll address)");
404 return (option_mask32 & DAD ? 0 : 2); 395 BUILD_BUG_ON(DAD != 2);
396 /* exit 0 if DAD, else exit 2 */
397 return (~option_mask32 & DAD);
405 } 398 }
406 he = me; 399 he = me;
407 memset(he.sll_addr, -1, he.sll_halen); 400 memset(he.sll_addr, -1, he.sll_halen);
408 401
409 if (!(option_mask32 & QUIET)) { 402 if (!(option_mask32 & QUIET)) {
410 /* inet_ntoa uses static storage, can't use in same printf */ 403 /* inet_ntoa uses static storage, can't use in same printf */
411 printf("ARPING to %s", inet_ntoa(dst)); 404 printf("ARPING %s", inet_ntoa(dst));
412 printf(" from %s via %s\n", inet_ntoa(src), device); 405 printf(" from %s %s\n", inet_ntoa(src), device);
413 } 406 }
414 407
408 /*sigemptyset(&G.sset); - zeroed by INIT_G */
409 sigaddset(&G.sset, SIGALRM);
410 sigaddset(&G.sset, SIGINT);
415 signal_SA_RESTART_empty_mask(SIGINT, (void (*)(int))finish); 411 signal_SA_RESTART_empty_mask(SIGINT, (void (*)(int))finish);
416 signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher); 412 signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher);
417 413
414 /* Send the first packet, arm ALRM */
418 catcher(); 415 catcher();
419 416
420 packet = xmalloc(4096);
421 while (1) { 417 while (1) {
422 sigset_t sset, osset;
423 struct sockaddr_ll from; 418 struct sockaddr_ll from;
424 socklen_t alen = sizeof(from); 419 socklen_t alen = sizeof(from);
425 int cc; 420 int cc;
426 421
427 cc = recvfrom(sock_fd, packet, 4096, 0, (struct sockaddr *) &from, &alen); 422 /* Unblock SIGALRM so that the previously called alarm()
423 * can prevent recvfrom from blocking forever in case the
424 * inherited procmask is blocking SIGALRM.
425 */
426 sigprocmask(SIG_UNBLOCK, &G.sset, NULL);
427
428 cc = recvfrom(sock_fd, G.packet, sizeof(G.packet), 0, (struct sockaddr *) &from, &alen);
429
430 /* Don't allow SIGALRMs while we process the reply */
431 sigprocmask(SIG_BLOCK, &G.sset, NULL);
428 if (cc < 0) { 432 if (cc < 0) {
429 bb_perror_msg("recvfrom"); 433 bb_perror_msg("recvfrom");
430 continue; 434 continue;
431 } 435 }
432 sigemptyset(&sset); 436 recv_pack(G.packet, cc, &from);
433 sigaddset(&sset, SIGALRM);
434 sigaddset(&sset, SIGINT);
435 sigprocmask(SIG_BLOCK, &sset, &osset);
436 recv_pack(packet, cc, &from);
437 sigprocmask(SIG_SETMASK, &osset, NULL);
438 } 437 }
439} 438}
diff --git a/networking/ftpd.c b/networking/ftpd.c
index 8af5acac2..8abbf7f57 100644
--- a/networking/ftpd.c
+++ b/networking/ftpd.c
@@ -171,9 +171,13 @@ struct globals {
171 char msg_ok [(sizeof("NNN " MSG_OK ) + 3) & 0xfffc]; 171 char msg_ok [(sizeof("NNN " MSG_OK ) + 3) & 0xfffc];
172 char msg_err[(sizeof("NNN " MSG_ERR) + 3) & 0xfffc]; 172 char msg_err[(sizeof("NNN " MSG_ERR) + 3) & 0xfffc];
173} FIX_ALIASING; 173} FIX_ALIASING;
174#define G (*(struct globals*)bb_common_bufsiz1) 174#define G (*ptr_to_globals)
175/* ^^^ about 75 bytes smaller code than this: */
176//#define G (*(struct globals*)bb_common_bufsiz1)
175#define INIT_G() do { \ 177#define INIT_G() do { \
176 setup_common_bufsiz(); \ 178 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
179 /*setup_common_bufsiz();*/ \
180 \
177 /* Moved to main */ \ 181 /* Moved to main */ \
178 /*strcpy(G.msg_ok + 4, MSG_OK );*/ \ 182 /*strcpy(G.msg_ok + 4, MSG_OK );*/ \
179 /*strcpy(G.msg_err + 4, MSG_ERR);*/ \ 183 /*strcpy(G.msg_err + 4, MSG_ERR);*/ \
@@ -258,7 +262,7 @@ cmdio_write(uint32_t status_str, const char *str)
258static void 262static void
259cmdio_write_ok(unsigned status) 263cmdio_write_ok(unsigned status)
260{ 264{
261 *(uint32_t *) G.msg_ok = status; 265 *(bb__aliased_uint32_t *) G.msg_ok = status;
262 xwrite(STDOUT_FILENO, G.msg_ok, sizeof("NNN " MSG_OK) - 1); 266 xwrite(STDOUT_FILENO, G.msg_ok, sizeof("NNN " MSG_OK) - 1);
263 if (G.verbose > 1) 267 if (G.verbose > 1)
264 verbose_log(G.msg_ok); 268 verbose_log(G.msg_ok);
@@ -269,7 +273,7 @@ cmdio_write_ok(unsigned status)
269static void 273static void
270cmdio_write_error(unsigned status) 274cmdio_write_error(unsigned status)
271{ 275{
272 *(uint32_t *) G.msg_err = status; 276 *(bb__aliased_uint32_t *) G.msg_err = status;
273 xwrite(STDOUT_FILENO, G.msg_err, sizeof("NNN " MSG_ERR) - 1); 277 xwrite(STDOUT_FILENO, G.msg_err, sizeof("NNN " MSG_ERR) - 1);
274 if (G.verbose > 0) 278 if (G.verbose > 0)
275 verbose_log(G.msg_err); 279 verbose_log(G.msg_err);
@@ -599,7 +603,7 @@ static void
599handle_rest(void) 603handle_rest(void)
600{ 604{
601 /* When ftp_arg == NULL simply restart from beginning */ 605 /* When ftp_arg == NULL simply restart from beginning */
602 G.restart_pos = G.ftp_arg ? xatoi_positive(G.ftp_arg) : 0; 606 G.restart_pos = G.ftp_arg ? XATOOFF(G.ftp_arg) : 0;
603 WRITE_OK(FTP_RESTOK); 607 WRITE_OK(FTP_RESTOK);
604} 608}
605 609
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c
index 029587aa2..ffc4cd5f1 100644
--- a/networking/ftpgetput.c
+++ b/networking/ftpgetput.c
@@ -158,46 +158,16 @@ static void ftp_login(void)
158 158
159static int xconnect_ftpdata(void) 159static int xconnect_ftpdata(void)
160{ 160{
161 char *buf_ptr; 161 int port_num;
162 unsigned port_num;
163 162
164/* 163 if (ENABLE_FEATURE_IPV6 && ftpcmd("EPSV", NULL) == 229) {
165TODO: PASV command will not work for IPv6. RFC2428 describes 164 /* good */
166IPv6-capable "extended PASV" - EPSV. 165 } else if (ftpcmd("PASV", NULL) != 227) {
167
168"EPSV [protocol]" asks server to bind to and listen on a data port
169in specified protocol. Protocol is 1 for IPv4, 2 for IPv6.
170If not specified, defaults to "same as used for control connection".
171If server understood you, it should answer "229 <some text>(|||port|)"
172where "|" are literal pipe chars and "port" is ASCII decimal port#.
173
174There is also an IPv6-capable replacement for PORT (EPRT),
175but we don't need that.
176
177NB: PASV may still work for some servers even over IPv6.
178For example, vsftp happily answers
179"227 Entering Passive Mode (0,0,0,0,n,n)" and proceeds as usual.
180
181TODO2: need to stop ignoring IP address in PASV response.
182*/
183
184 if (ftpcmd("PASV", NULL) != 227) {
185 ftp_die("PASV"); 166 ftp_die("PASV");
186 } 167 }
187 168 port_num = parse_pasv_epsv(buf);
188 /* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage] 169 if (port_num < 0)
189 * Server's IP is N1.N2.N3.N4 (we ignore it) 170 ftp_die("PASV");
190 * Server's port for data connection is P1*256+P2 */
191 buf_ptr = strrchr(buf, ')');
192 if (buf_ptr) *buf_ptr = '\0';
193
194 buf_ptr = strrchr(buf, ',');
195 *buf_ptr = '\0';
196 port_num = xatoul_range(buf_ptr + 1, 0, 255);
197
198 buf_ptr = strrchr(buf, ',');
199 *buf_ptr = '\0';
200 port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256;
201 171
202 set_nport(&lsa->u.sa, htons(port_num)); 172 set_nport(&lsa->u.sa, htons(port_num));
203 return xconnect_stream(lsa); 173 return xconnect_stream(lsa);
diff --git a/networking/inetd.c b/networking/inetd.c
index 4dfa0089a..6843845fb 100644
--- a/networking/inetd.c
+++ b/networking/inetd.c
@@ -497,10 +497,9 @@ static void register_rpc(servtab_t *sep)
497{ 497{
498 int n; 498 int n;
499 struct sockaddr_in ir_sin; 499 struct sockaddr_in ir_sin;
500 socklen_t size;
501 500
502 size = sizeof(ir_sin); 501 if (bb_getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, sizeof(ir_sin)) < 0) {
503 if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) { 502//TODO: verify that such failure is even possible in Linux kernel
504 bb_perror_msg("getsockname"); 503 bb_perror_msg("getsockname");
505 return; 504 return;
506 } 505 }
diff --git a/networking/libiproute/Kbuild.src b/networking/libiproute/Kbuild.src
index 056a58540..d94e4c6e5 100644
--- a/networking/libiproute/Kbuild.src
+++ b/networking/libiproute/Kbuild.src
@@ -12,6 +12,12 @@ INSERT
12lib-$(CONFIG_SLATTACH) += \ 12lib-$(CONFIG_SLATTACH) += \
13 utils.o 13 utils.o
14 14
15lib-$(CONFIG_TC) += \
16 libnetlink.o \
17 ll_map.o \
18 ll_proto.o \
19 utils.o
20
15lib-$(CONFIG_IP) += \ 21lib-$(CONFIG_IP) += \
16 ip_parse_common_args.o \ 22 ip_parse_common_args.o \
17 libnetlink.o \ 23 libnetlink.o \
diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c
index 921ecf0d9..d7f888176 100644
--- a/networking/libiproute/ipaddress.c
+++ b/networking/libiproute/ipaddress.c
@@ -113,7 +113,7 @@ static NOINLINE int print_linkinfo(const struct nlmsghdr *n)
113 if (G_filter.up && !(ifi->ifi_flags & IFF_UP)) 113 if (G_filter.up && !(ifi->ifi_flags & IFF_UP))
114 return 0; 114 return 0;
115 115
116 memset(tb, 0, sizeof(tb)); 116 //memset(tb, 0, sizeof(tb)); - parse_rtattr does this
117 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); 117 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
118 if (tb[IFLA_IFNAME] == NULL) { 118 if (tb[IFLA_IFNAME] == NULL) {
119 bb_error_msg("nil ifname"); 119 bb_error_msg("nil ifname");
@@ -227,7 +227,7 @@ static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM,
227 if (G_filter.flushb && n->nlmsg_type != RTM_NEWADDR) 227 if (G_filter.flushb && n->nlmsg_type != RTM_NEWADDR)
228 return 0; 228 return 0;
229 229
230 memset(rta_tb, 0, sizeof(rta_tb)); 230 //memset(rta_tb, 0, sizeof(rta_tb)); - parse_rtattr does this
231 parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); 231 parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
232 232
233 if (!rta_tb[IFA_LOCAL]) 233 if (!rta_tb[IFA_LOCAL])
@@ -535,7 +535,7 @@ int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush)
535 continue; 535 continue;
536 if (G_filter.pfx.family || G_filter.label) { 536 if (G_filter.pfx.family || G_filter.label) {
537 struct rtattr *tb[IFA_MAX+1]; 537 struct rtattr *tb[IFA_MAX+1];
538 memset(tb, 0, sizeof(tb)); 538 //memset(tb, 0, sizeof(tb)); - parse_rtattr does this
539 parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n)); 539 parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n));
540 if (!tb[IFA_LOCAL]) 540 if (!tb[IFA_LOCAL])
541 tb[IFA_LOCAL] = tb[IFA_ADDRESS]; 541 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c
index aef5f6490..f38fba055 100644
--- a/networking/libiproute/iplink.c
+++ b/networking/libiproute/iplink.c
@@ -132,7 +132,6 @@ static int get_address(char *dev, int *htype)
132{ 132{
133 struct ifreq ifr; 133 struct ifreq ifr;
134 struct sockaddr_ll me; 134 struct sockaddr_ll me;
135 socklen_t alen;
136 int s; 135 int s;
137 136
138 s = xsocket(PF_PACKET, SOCK_DGRAM, 0); 137 s = xsocket(PF_PACKET, SOCK_DGRAM, 0);
@@ -146,8 +145,7 @@ static int get_address(char *dev, int *htype)
146 me.sll_ifindex = ifr.ifr_ifindex; 145 me.sll_ifindex = ifr.ifr_ifindex;
147 me.sll_protocol = htons(ETH_P_LOOP); 146 me.sll_protocol = htons(ETH_P_LOOP);
148 xbind(s, (struct sockaddr*)&me, sizeof(me)); 147 xbind(s, (struct sockaddr*)&me, sizeof(me));
149 alen = sizeof(me); 148 bb_getsockname(s, (struct sockaddr*)&me, sizeof(me));
150 getsockname(s, (struct sockaddr*)&me, &alen);
151 //never happens: 149 //never happens:
152 //if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) 150 //if (getsockname(s, (struct sockaddr*)&me, &alen) == -1)
153 // bb_perror_msg_and_die("getsockname"); 151 // bb_perror_msg_and_die("getsockname");
diff --git a/networking/libiproute/ipneigh.c b/networking/libiproute/ipneigh.c
index 1cd90d707..f572414e9 100644
--- a/networking/libiproute/ipneigh.c
+++ b/networking/libiproute/ipneigh.c
@@ -110,11 +110,13 @@ static int FAST_FUNC print_neigh(const struct sockaddr_nl *who UNUSED_PARAM,
110 return 0; 110 return 0;
111 if (G_filter.index && G_filter.index != r->ndm_ifindex) 111 if (G_filter.index && G_filter.index != r->ndm_ifindex)
112 return 0; 112 return 0;
113 if (!(G_filter.state&r->ndm_state) && 113 if (!(G_filter.state&r->ndm_state)
114 !(r->ndm_flags & NTF_PROXY) && 114 && !(r->ndm_flags & NTF_PROXY)
115 (r->ndm_state || !(G_filter.state & 0x100)) && 115 && (r->ndm_state || !(G_filter.state & 0x100))
116 (r->ndm_family != AF_DECnet)) 116 && (r->ndm_family != AF_DECnet)
117 ) {
117 return 0; 118 return 0;
119 }
118 120
119 parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); 121 parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
120 122
diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c
index 95dafe183..2a8610ea6 100644
--- a/networking/libiproute/iproute.c
+++ b/networking/libiproute/iproute.c
@@ -83,7 +83,7 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
83 if (len < 0) 83 if (len < 0)
84 bb_error_msg_and_die("wrong nlmsg len %d", len); 84 bb_error_msg_and_die("wrong nlmsg len %d", len);
85 85
86 memset(tb, 0, sizeof(tb)); 86 //memset(tb, 0, sizeof(tb)); - parse_rtattr does this
87 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); 87 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
88 88
89#if HAVE_RTA_TABLE 89#if HAVE_RTA_TABLE
@@ -1081,7 +1081,7 @@ static int iproute_get(char **argv)
1081 bb_error_msg_and_die("wrong len %d", len); 1081 bb_error_msg_and_die("wrong len %d", len);
1082 } 1082 }
1083 1083
1084 memset(tb, 0, sizeof(tb)); 1084 //memset(tb, 0, sizeof(tb)); - parse_rtattr does this
1085 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); 1085 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
1086 1086
1087 if (tb[RTA_PREFSRC]) { 1087 if (tb[RTA_PREFSRC]) {
diff --git a/networking/libiproute/iprule.c b/networking/libiproute/iprule.c
index 53b11e16c..0ce0dfeef 100644
--- a/networking/libiproute/iprule.c
+++ b/networking/libiproute/iprule.c
@@ -63,7 +63,7 @@ static int FAST_FUNC print_rule(const struct sockaddr_nl *who UNUSED_PARAM,
63 if (len < 0) 63 if (len < 0)
64 return -1; 64 return -1;
65 65
66 memset(tb, 0, sizeof(tb)); 66 //memset(tb, 0, sizeof(tb)); - parse_rtattr does this
67 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); 67 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
68 68
69 if (r->rtm_family == AF_INET) 69 if (r->rtm_family == AF_INET)
diff --git a/networking/libiproute/libnetlink.c b/networking/libiproute/libnetlink.c
index 3f0f70326..40955fcae 100644
--- a/networking/libiproute/libnetlink.c
+++ b/networking/libiproute/libnetlink.c
@@ -15,16 +15,13 @@
15 15
16void FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/) 16void FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/)
17{ 17{
18 socklen_t addr_len;
19
20 memset(rth, 0, sizeof(*rth)); 18 memset(rth, 0, sizeof(*rth));
21 rth->fd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 19 rth->fd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
22 rth->local.nl_family = AF_NETLINK; 20 rth->local.nl_family = AF_NETLINK;
23 /*rth->local.nl_groups = subscriptions;*/ 21 /*rth->local.nl_groups = subscriptions;*/
24 22
25 xbind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)); 23 xbind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local));
26 addr_len = sizeof(rth->local); 24 bb_getsockname(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local));
27 getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len);
28 25
29/* too much paranoia 26/* too much paranoia
30 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) 27 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0)
@@ -401,6 +398,8 @@ int FAST_FUNC rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data
401 398
402void FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) 399void FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
403{ 400{
401 memset(tb, 0, (max + 1) * sizeof(tb[0]));
402
404 while (RTA_OK(rta, len)) { 403 while (RTA_OK(rta, len)) {
405 if (rta->rta_type <= max) { 404 if (rta->rta_type <= max) {
406 tb[rta->rta_type] = rta; 405 tb[rta->rta_type] = rta;
diff --git a/networking/libiproute/ll_map.c b/networking/libiproute/ll_map.c
index be88a04e8..66401da77 100644
--- a/networking/libiproute/ll_map.c
+++ b/networking/libiproute/ll_map.c
@@ -51,7 +51,7 @@ int FAST_FUNC ll_remember_index(const struct sockaddr_nl *who UNUSED_PARAM,
51 if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) 51 if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi)))
52 return -1; 52 return -1;
53 53
54 memset(tb, 0, sizeof(tb)); 54 //memset(tb, 0, sizeof(tb)); - parse_rtattr does this
55 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); 55 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
56 if (tb[IFLA_IFNAME] == NULL) 56 if (tb[IFLA_IFNAME] == NULL)
57 return 0; 57 return 0;
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 0b60d003b..17e5c7da6 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -2362,7 +2362,9 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
2362 2362
2363 /* Nothing between here and poll() blocks for any significant time */ 2363 /* Nothing between here and poll() blocks for any significant time */
2364 2364
2365 nextaction = G.cur_time + 3600; 2365 nextaction = G.last_script_run + (11*60);
2366 if (nextaction < G.cur_time + 1)
2367 nextaction = G.cur_time + 1;
2366 2368
2367 i = 0; 2369 i = 0;
2368#if ENABLE_FEATURE_NTPD_SERVER 2370#if ENABLE_FEATURE_NTPD_SERVER
diff --git a/networking/parse_pasv_epsv.c b/networking/parse_pasv_epsv.c
new file mode 100644
index 000000000..14f4d4258
--- /dev/null
+++ b/networking/parse_pasv_epsv.c
@@ -0,0 +1,66 @@
1/*
2 * Utility routines.
3 *
4 * Copyright (C) 2018 Denys Vlasenko
5 *
6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
7 */
8//kbuild:lib-$(CONFIG_FTPGET) += parse_pasv_epsv.o
9//kbuild:lib-$(CONFIG_FTPPUT) += parse_pasv_epsv.o
10//kbuild:lib-$(CONFIG_WGET) += parse_pasv_epsv.o
11
12#include "libbb.h"
13
14int FAST_FUNC parse_pasv_epsv(char *buf)
15{
16/*
17 * PASV command will not work for IPv6. RFC2428 describes
18 * IPv6-capable "extended PASV" - EPSV.
19 *
20 * "EPSV [protocol]" asks server to bind to and listen on a data port
21 * in specified protocol. Protocol is 1 for IPv4, 2 for IPv6.
22 * If not specified, defaults to "same as used for control connection".
23 * If server understood you, it should answer "229 <some text>(|||port|)"
24 * where "|" are literal pipe chars and "port" is ASCII decimal port#.
25 *
26 * There is also an IPv6-capable replacement for PORT (EPRT),
27 * but we don't need that.
28 *
29 * NB: PASV may still work for some servers even over IPv6.
30 * For example, vsftp happily answers
31 * "227 Entering Passive Mode (0,0,0,0,n,n)" and proceeds as usual.
32 */
33 char *ptr;
34 int port;
35
36 if (!ENABLE_FEATURE_IPV6 || buf[2] == '7' /* "227" */) {
37 /* Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage]"
38 * Server's IP is N1.N2.N3.N4 (we ignore it)
39 * Server's port for data connection is P1*256+P2 */
40 ptr = strrchr(buf, ')');
41 if (ptr) *ptr = '\0';
42
43 ptr = strrchr(buf, ',');
44 if (!ptr) return -1;
45 *ptr = '\0';
46 port = xatou_range(ptr + 1, 0, 255);
47
48 ptr = strrchr(buf, ',');
49 if (!ptr) return -1;
50 *ptr = '\0';
51 port += xatou_range(ptr + 1, 0, 255) * 256;
52 } else {
53 /* Response is "229 garbage(|||P1|)"
54 * Server's port for data connection is P1 */
55 ptr = strrchr(buf, '|');
56 if (!ptr) return -1;
57 *ptr = '\0';
58
59 ptr = strrchr(buf, '|');
60 if (!ptr) return -1;
61 *ptr = '\0';
62 port = xatou_range(ptr + 1, 0, 65535);
63 }
64
65 return port;
66}
diff --git a/networking/ssl_client.c b/networking/ssl_client.c
index d479846d7..eb84e7726 100644
--- a/networking/ssl_client.c
+++ b/networking/ssl_client.c
@@ -15,7 +15,7 @@
15//kbuild:lib-$(CONFIG_SSL_CLIENT) += ssl_client.o 15//kbuild:lib-$(CONFIG_SSL_CLIENT) += ssl_client.o
16 16
17//usage:#define ssl_client_trivial_usage 17//usage:#define ssl_client_trivial_usage
18//usage: "-s FD [-r FD] [-n SNI]" 18//usage: "[-e] -s FD [-r FD] [-n SNI]"
19//usage:#define ssl_client_full_usage "" 19//usage:#define ssl_client_full_usage ""
20 20
21#include "libbb.h" 21#include "libbb.h"
@@ -30,26 +30,28 @@ int ssl_client_main(int argc UNUSED_PARAM, char **argv)
30 // INIT_G(); 30 // INIT_G();
31 31
32 tls = new_tls_state(); 32 tls = new_tls_state();
33 opt = getopt32(argv, "s:#r:#n:", &tls->ofd, &tls->ifd, &sni); 33 opt = getopt32(argv, "es:#r:#n:", &tls->ofd, &tls->ifd, &sni);
34 if (!(opt & 2)) { 34 if (!(opt & (1<<2))) {
35 /* -r N defaults to -s N */ 35 /* -r N defaults to -s N */
36 tls->ifd = tls->ofd; 36 tls->ifd = tls->ofd;
37 } 37 }
38 38
39 if (!(opt & 3)) { 39 if (!(opt & (3<<1))) {
40 if (!argv[1]) 40 if (!argv[1])
41 bb_show_usage(); 41 bb_show_usage();
42 /* Undocumented debug feature: without -s and -r, takes HOST arg and connects to it */ 42 /* Undocumented debug feature: without -s and -r, takes HOST arg and connects to it */
43 // 43 //
44 // Talk to kernel.org: 44 // Talk to kernel.org:
45 // printf "GET / HTTP/1.1\r\nHost: kernel.org\r\n\r\n" | ./busybox ssl_client kernel.org 45 // printf "GET / HTTP/1.1\r\nHost: kernel.org\r\n\r\n" | busybox ssl_client kernel.org
46 if (!sni) 46 if (!sni)
47 sni = argv[1]; 47 sni = argv[1];
48 tls->ifd = tls->ofd = create_and_connect_stream_or_die(argv[1], 443); 48 tls->ifd = tls->ofd = create_and_connect_stream_or_die(argv[1], 443);
49 } 49 }
50 50
51 tls_handshake(tls, sni); 51 tls_handshake(tls, sni);
52 tls_run_copy_loop(tls); 52
53 BUILD_BUG_ON(TLSLOOP_EXIT_ON_LOCAL_EOF != 1);
54 tls_run_copy_loop(tls, /*flags*/ opt & 1);
53 55
54 return EXIT_SUCCESS; 56 return EXIT_SUCCESS;
55} 57}
diff --git a/networking/tc.c b/networking/tc.c
index 23abf636c..4fa3e47bf 100644
--- a/networking/tc.c
+++ b/networking/tc.c
@@ -6,22 +6,20 @@
6 * 6 *
7 * Bernhard Reutner-Fischer adjusted for busybox 7 * Bernhard Reutner-Fischer adjusted for busybox
8 */ 8 */
9//config:config TC
10//config: bool "tc (3.1 kb)"
11//config: default y
12//config: help
13//config: Show / manipulate traffic control settings
14//config:
15//config:config FEATURE_TC_INGRESS
16//config: bool "Enable ingress"
17//config: default y
18//config: depends on TC
9 19
10/* Was disabled in 2008 by Bernhard, not known why. 20//applet:IF_TC(APPLET(tc, BB_DIR_SBIN, BB_SUID_DROP))
11--//config:#config TC 21
12--//config:# bool "tc" 22//kbuild:lib-$(CONFIG_TC) += tc.o
13--//config:# default y
14--//config:# help
15--//config:# Show / manipulate traffic control settings
16--//config:#
17--//config:#config FEATURE_TC_INGRESS
18--//config:# default y
19--//config:# depends on TC
20--
21--//applet:IF_TC(APPLET(tc, BB_DIR_SBIN, BB_SUID_DROP))
22--
23--//kbuild:lib-$(CONFIG_TC) += tc.o
24*/
25 23
26//usage:#define tc_trivial_usage 24//usage:#define tc_trivial_usage
27/* //usage: "[OPTIONS] OBJECT CMD [dev STRING]" */ 25/* //usage: "[OPTIONS] OBJECT CMD [dev STRING]" */
@@ -52,22 +50,37 @@
52#include "libiproute/rt_names.h" 50#include "libiproute/rt_names.h"
53#include <linux/pkt_sched.h> /* for the TC_H_* macros */ 51#include <linux/pkt_sched.h> /* for the TC_H_* macros */
54 52
53/* This is the deprecated multiqueue interface */
54#ifndef TCA_PRIO_MAX
55enum
56{
57 TCA_PRIO_UNSPEC,
58 TCA_PRIO_MQ,
59 __TCA_PRIO_MAX
60};
61#define TCA_PRIO_MAX (__TCA_PRIO_MAX - 1)
62#endif
63
55#define parse_rtattr_nested(tb, max, rta) \ 64#define parse_rtattr_nested(tb, max, rta) \
56 (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))) 65 (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta)))
57 66
58/* nullifies tb on error */ 67/* nullifies tb on error */
59#define __parse_rtattr_nested_compat(tb, max, rta, len) \ 68#define __parse_rtattr_nested_compat(tb, max, rta, len) \
60 ({if ((RTA_PAYLOAD(rta) >= len) && \ 69({ \
61 (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr))) { \ 70 if ((RTA_PAYLOAD(rta) >= len) \
62 rta = RTA_DATA(rta) + RTA_ALIGN(len); \ 71 && (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) \
63 parse_rtattr_nested(tb, max, rta); \ 72 ) { \
64 } else \ 73 rta = RTA_DATA(rta) + RTA_ALIGN(len); \
65 memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); \ 74 parse_rtattr_nested(tb, max, rta); \
66 }) 75 } else \
76 memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); \
77})
67 78
68#define parse_rtattr_nested_compat(tb, max, rta, data, len) \ 79#define parse_rtattr_nested_compat(tb, max, rta, data, len) \
69 ({data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \ 80({ \
70 __parse_rtattr_nested_compat(tb, max, rta, len); }) 81 data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \
82 __parse_rtattr_nested_compat(tb, max, rta, len); \
83})
71 84
72#define show_details (0) /* not implemented. Does anyone need it? */ 85#define show_details (0) /* not implemented. Does anyone need it? */
73#define use_iec (0) /* not currently documented in the upstream manpage */ 86#define use_iec (0) /* not currently documented in the upstream manpage */
@@ -184,11 +197,13 @@ static void print_rate(char *buf, int len, uint32_t rate)
184 } 197 }
185} 198}
186 199
200#if 0
187/* This is "pfifo_fast". */ 201/* This is "pfifo_fast". */
188static int prio_parse_opt(int argc, char **argv, struct nlmsghdr *n) 202static int prio_parse_opt(int argc, char **argv, struct nlmsghdr *n)
189{ 203{
190 return 0; 204 return 0;
191} 205}
206#endif
192static int prio_print_opt(struct rtattr *opt) 207static int prio_print_opt(struct rtattr *opt)
193{ 208{
194 int i; 209 int i;
@@ -211,11 +226,13 @@ static int prio_print_opt(struct rtattr *opt)
211 return 0; 226 return 0;
212} 227}
213 228
229#if 0
214/* Class Based Queue */ 230/* Class Based Queue */
215static int cbq_parse_opt(int argc, char **argv, struct nlmsghdr *n) 231static int cbq_parse_opt(int argc, char **argv, struct nlmsghdr *n)
216{ 232{
217 return 0; 233 return 0;
218} 234}
235#endif
219static int cbq_print_opt(struct rtattr *opt) 236static int cbq_print_opt(struct rtattr *opt)
220{ 237{
221 struct rtattr *tb[TCA_CBQ_MAX+1]; 238 struct rtattr *tb[TCA_CBQ_MAX+1];
@@ -308,8 +325,10 @@ static int cbq_print_opt(struct rtattr *opt)
308 return 0; 325 return 0;
309} 326}
310 327
311static int print_qdisc(const struct sockaddr_nl *who UNUSED_PARAM, 328static FAST_FUNC int print_qdisc(
312 struct nlmsghdr *hdr, void *arg UNUSED_PARAM) 329 const struct sockaddr_nl *who UNUSED_PARAM,
330 struct nlmsghdr *hdr,
331 void *arg UNUSED_PARAM)
313{ 332{
314 struct tcmsg *msg = NLMSG_DATA(hdr); 333 struct tcmsg *msg = NLMSG_DATA(hdr);
315 int len = hdr->nlmsg_len; 334 int len = hdr->nlmsg_len;
@@ -364,8 +383,10 @@ static int print_qdisc(const struct sockaddr_nl *who UNUSED_PARAM,
364 return 0; 383 return 0;
365} 384}
366 385
367static int print_class(const struct sockaddr_nl *who UNUSED_PARAM, 386static FAST_FUNC int print_class(
368 struct nlmsghdr *hdr, void *arg UNUSED_PARAM) 387 const struct sockaddr_nl *who UNUSED_PARAM,
388 struct nlmsghdr *hdr,
389 void *arg UNUSED_PARAM)
369{ 390{
370 struct tcmsg *msg = NLMSG_DATA(hdr); 391 struct tcmsg *msg = NLMSG_DATA(hdr);
371 int len = hdr->nlmsg_len; 392 int len = hdr->nlmsg_len;
@@ -432,8 +453,10 @@ static int print_class(const struct sockaddr_nl *who UNUSED_PARAM,
432 return 0; 453 return 0;
433} 454}
434 455
435static int print_filter(const struct sockaddr_nl *who UNUSED_PARAM, 456static FAST_FUNC int print_filter(
436 struct nlmsghdr *hdr, void *arg UNUSED_PARAM) 457 const struct sockaddr_nl *who UNUSED_PARAM,
458 struct nlmsghdr *hdr UNUSED_PARAM,
459 void *arg UNUSED_PARAM)
437{ 460{
438 return 0; 461 return 0;
439} 462}
@@ -451,6 +474,12 @@ int tc_main(int argc UNUSED_PARAM, char **argv)
451 "replace\0" 474 "replace\0"
452 "show\0""list\0" 475 "show\0""list\0"
453 ; 476 ;
477 enum {
478 CMD_add = 0, CMD_del, CMD_change,
479 CMD_link,
480 CMD_replace,
481 CMD_show
482 };
454 static const char args[] ALIGN1 = 483 static const char args[] ALIGN1 =
455 "dev\0" /* qdisc, class, filter */ 484 "dev\0" /* qdisc, class, filter */
456 "root\0" /* class, filter */ 485 "root\0" /* class, filter */
@@ -460,9 +489,15 @@ int tc_main(int argc UNUSED_PARAM, char **argv)
460 "classid\0" /* change: for class use "handle" */ 489 "classid\0" /* change: for class use "handle" */
461 "preference\0""priority\0""protocol\0" /* filter */ 490 "preference\0""priority\0""protocol\0" /* filter */
462 ; 491 ;
463 enum { CMD_add = 0, CMD_del, CMD_change, CMD_link, CMD_replace, CMD_show }; 492 enum {
464 enum { ARG_dev = 0, ARG_root, ARG_parent, ARG_qdisc, 493 ARG_dev = 0,
465 ARG_handle, ARG_classid, ARG_pref, ARG_prio, ARG_proto}; 494 ARG_root,
495 ARG_parent,
496 ARG_qdisc,
497 ARG_handle,
498 ARG_classid,
499 ARG_pref, ARG_prio, ARG_proto
500 };
466 struct rtnl_handle rth; 501 struct rtnl_handle rth;
467 struct tcmsg msg; 502 struct tcmsg msg;
468 int ret, obj, cmd, arg; 503 int ret, obj, cmd, arg;
@@ -487,9 +522,12 @@ int tc_main(int argc UNUSED_PARAM, char **argv)
487 invarg_1_to_2(*argv, argv[-1]); 522 invarg_1_to_2(*argv, argv[-1]);
488 argv++; 523 argv++;
489 } 524 }
525
490 memset(&msg, 0, sizeof(msg)); 526 memset(&msg, 0, sizeof(msg));
491 msg.tcm_family = AF_UNSPEC; 527 if (AF_UNSPEC != 0)
528 msg.tcm_family = AF_UNSPEC;
492 ll_init_map(&rth); 529 ll_init_map(&rth);
530
493 while (*argv) { 531 while (*argv) {
494 arg = index_in_substrings(args, *argv); 532 arg = index_in_substrings(args, *argv);
495 if (arg == ARG_dev) { 533 if (arg == ARG_dev) {
@@ -526,7 +564,8 @@ int tc_main(int argc UNUSED_PARAM, char **argv)
526 msg.tcm_parent = TC_H_ROOT; 564 msg.tcm_parent = TC_H_ROOT;
527 if (obj == OBJ_filter) 565 if (obj == OBJ_filter)
528 filter_parent = TC_H_ROOT; 566 filter_parent = TC_H_ROOT;
529 } else if (arg == ARG_parent) { 567 } else
568 if (arg == ARG_parent) {
530 uint32_t handle; 569 uint32_t handle;
531 if (msg.tcm_parent) 570 if (msg.tcm_parent)
532 duparg(*argv, "parent"); 571 duparg(*argv, "parent");
@@ -535,23 +574,31 @@ int tc_main(int argc UNUSED_PARAM, char **argv)
535 msg.tcm_parent = handle; 574 msg.tcm_parent = handle;
536 if (obj == OBJ_filter) 575 if (obj == OBJ_filter)
537 filter_parent = handle; 576 filter_parent = handle;
538 } else if (arg == ARG_handle) { /* filter::list */ 577 } else
578 if (arg == ARG_handle) { /* filter::list */
539 if (msg.tcm_handle) 579 if (msg.tcm_handle)
540 duparg(*argv, "handle"); 580 duparg(*argv, "handle");
541 /* reject LONG_MIN || LONG_MAX */ 581 /* reject LONG_MIN || LONG_MAX */
542 /* TODO: for fw 582 /* TODO: for fw
543 slash = strchr(handle, '/'); 583 slash = strchr(handle, '/');
544 if (slash != NULL) 584 if (slash != NULL)
545 *slash = '\0'; 585 *slash = '\0';
546 */ 586 */
547 msg.tcm_handle = get_u32(*argv, "handle"); 587 msg.tcm_handle = get_u32(*argv, "handle");
548 /* if (slash) {if (get_u32(uint32_t &mask, slash+1, NULL)) inv mask; addattr32(n, MAX_MSG, TCA_FW_MASK, mask); */ 588 /* if (slash) {if (get_u32(uint32_t &mask, slash+1, NULL)) inv mask; addattr32(n, MAX_MSG, TCA_FW_MASK, mask); */
549 } else if (arg == ARG_classid && obj == OBJ_class && cmd == CMD_change){ 589 } else
550 } else if (arg == ARG_pref || arg == ARG_prio) { /* filter::list */ 590 if (arg == ARG_classid
591 && obj == OBJ_class
592 && cmd == CMD_change
593 ) {
594 /* TODO */
595 } else
596 if (arg == ARG_pref || arg == ARG_prio) { /* filter::list */
551 if (filter_prio) 597 if (filter_prio)
552 duparg(*argv, "priority"); 598 duparg(*argv, "priority");
553 filter_prio = get_u32(*argv, "priority"); 599 filter_prio = get_u32(*argv, "priority");
554 } else if (arg == ARG_proto) { /* filter::list */ 600 } else
601 if (arg == ARG_proto) { /* filter::list */
555 uint16_t tmp; 602 uint16_t tmp;
556 if (filter_proto) 603 if (filter_proto)
557 duparg(*argv, "protocol"); 604 duparg(*argv, "protocol");
@@ -560,6 +607,7 @@ int tc_main(int argc UNUSED_PARAM, char **argv)
560 filter_proto = tmp; 607 filter_proto = tmp;
561 } 608 }
562 } 609 }
610
563 if (cmd >= CMD_show) { /* show or list */ 611 if (cmd >= CMD_show) { /* show or list */
564 if (obj == OBJ_filter) 612 if (obj == OBJ_filter)
565 msg.tcm_info = TC_H_MAKE(filter_prio<<16, filter_proto); 613 msg.tcm_info = TC_H_MAKE(filter_prio<<16, filter_proto);
diff --git a/networking/tftp.c b/networking/tftp.c
index 73a9829aa..4cd39186a 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -208,7 +208,7 @@ struct globals {
208#define G_error_pkt_reason (G.error_pkt[3]) 208#define G_error_pkt_reason (G.error_pkt[3])
209#define G_error_pkt_str ((char*)(G.error_pkt + 4)) 209#define G_error_pkt_str ((char*)(G.error_pkt + 4))
210 210
211#if ENABLE_FEATURE_TFTP_PROGRESS_BAR 211#if ENABLE_FEATURE_TFTP_PROGRESS_BAR && ENABLE_FEATURE_TFTP_BLOCKSIZE
212static void tftp_progress_update(void) 212static void tftp_progress_update(void)
213{ 213{
214 bb_progress_update(&G.pmt, 0, G.pos, G.size); 214 bb_progress_update(&G.pmt, 0, G.pos, G.size);
@@ -227,6 +227,7 @@ static void tftp_progress_done(void)
227 } 227 }
228} 228}
229#else 229#else
230# define tftp_progress_update() ((void)0)
230# define tftp_progress_init() ((void)0) 231# define tftp_progress_init() ((void)0)
231# define tftp_progress_done() ((void)0) 232# define tftp_progress_done() ((void)0)
232#endif 233#endif
diff --git a/networking/tls.c b/networking/tls.c
index fd3cb0dba..da7b6058f 100644
--- a/networking/tls.c
+++ b/networking/tls.c
@@ -84,23 +84,23 @@
84# define dbg_der(...) ((void)0) 84# define dbg_der(...) ((void)0)
85#endif 85#endif
86 86
87#define RECORD_TYPE_CHANGE_CIPHER_SPEC 20 87#define RECORD_TYPE_CHANGE_CIPHER_SPEC 20 /* 0x14 */
88#define RECORD_TYPE_ALERT 21 88#define RECORD_TYPE_ALERT 21 /* 0x15 */
89#define RECORD_TYPE_HANDSHAKE 22 89#define RECORD_TYPE_HANDSHAKE 22 /* 0x16 */
90#define RECORD_TYPE_APPLICATION_DATA 23 90#define RECORD_TYPE_APPLICATION_DATA 23 /* 0x17 */
91 91
92#define HANDSHAKE_HELLO_REQUEST 0 92#define HANDSHAKE_HELLO_REQUEST 0 /* 0x00 */
93#define HANDSHAKE_CLIENT_HELLO 1 93#define HANDSHAKE_CLIENT_HELLO 1 /* 0x01 */
94#define HANDSHAKE_SERVER_HELLO 2 94#define HANDSHAKE_SERVER_HELLO 2 /* 0x02 */
95#define HANDSHAKE_HELLO_VERIFY_REQUEST 3 95#define HANDSHAKE_HELLO_VERIFY_REQUEST 3 /* 0x03 */
96#define HANDSHAKE_NEW_SESSION_TICKET 4 96#define HANDSHAKE_NEW_SESSION_TICKET 4 /* 0x04 */
97#define HANDSHAKE_CERTIFICATE 11 97#define HANDSHAKE_CERTIFICATE 11 /* 0x0b */
98#define HANDSHAKE_SERVER_KEY_EXCHANGE 12 98#define HANDSHAKE_SERVER_KEY_EXCHANGE 12 /* 0x0c */
99#define HANDSHAKE_CERTIFICATE_REQUEST 13 99#define HANDSHAKE_CERTIFICATE_REQUEST 13 /* 0x0d */
100#define HANDSHAKE_SERVER_HELLO_DONE 14 100#define HANDSHAKE_SERVER_HELLO_DONE 14 /* 0x0e */
101#define HANDSHAKE_CERTIFICATE_VERIFY 15 101#define HANDSHAKE_CERTIFICATE_VERIFY 15 /* 0x0f */
102#define HANDSHAKE_CLIENT_KEY_EXCHANGE 16 102#define HANDSHAKE_CLIENT_KEY_EXCHANGE 16 /* 0x10 */
103#define HANDSHAKE_FINISHED 20 103#define HANDSHAKE_FINISHED 20 /* 0x14 */
104 104
105#define SSL_NULL_WITH_NULL_NULL 0x0000 105#define SSL_NULL_WITH_NULL_NULL 0x0000
106#define SSL_RSA_WITH_NULL_MD5 0x0001 106#define SSL_RSA_WITH_NULL_MD5 0x0001
@@ -512,10 +512,12 @@ static void bad_record_die(tls_state_t *tls, const char *expected, int len)
512 bb_error_msg("got bad TLS record (len:%d) while expecting %s", len, expected); 512 bb_error_msg("got bad TLS record (len:%d) while expecting %s", len, expected);
513 if (len > 0) { 513 if (len > 0) {
514 uint8_t *p = tls->inbuf; 514 uint8_t *p = tls->inbuf;
515 while (len > 0) { 515 if (len > 99)
516 len = 99; /* don't flood, a few lines should be enough */
517 do {
516 fprintf(stderr, " %02x", *p++); 518 fprintf(stderr, " %02x", *p++);
517 len--; 519 len--;
518 } 520 } while (len != 0);
519 fputc('\n', stderr); 521 fputc('\n', stderr);
520 } 522 }
521 xfunc_die(); 523 xfunc_die();
@@ -671,9 +673,11 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
671 // AES_128_CBC Block 16 16 16 673 // AES_128_CBC Block 16 16 16
672 // AES_256_CBC Block 32 16 16 674 // AES_256_CBC Block 32 16 16
673 675
674 /* Fill IV and padding in outbuf */
675 tls_get_random(buf - AES_BLOCKSIZE, AES_BLOCKSIZE); /* IV */ 676 tls_get_random(buf - AES_BLOCKSIZE, AES_BLOCKSIZE); /* IV */
676 dbg("before crypt: 5 hdr + %u data + %u hash bytes\n", size, tls->MAC_size); 677 dbg("before crypt: 5 hdr + %u data + %u hash bytes\n",
678 size - tls->MAC_size, tls->MAC_size);
679
680 /* Fill IV and padding in outbuf */
677 // RFC is talking nonsense: 681 // RFC is talking nonsense:
678 // "Padding that is added to force the length of the plaintext to be 682 // "Padding that is added to force the length of the plaintext to be
679 // an integral multiple of the block cipher's block length." 683 // an integral multiple of the block cipher's block length."
@@ -773,7 +777,7 @@ static const char *alert_text(int code)
773 return itoa(code); 777 return itoa(code);
774} 778}
775 779
776static int tls_xread_record(tls_state_t *tls) 780static int tls_xread_record(tls_state_t *tls, const char *expected)
777{ 781{
778 struct record_hdr *xhdr; 782 struct record_hdr *xhdr;
779 int sz; 783 int sz;
@@ -796,13 +800,16 @@ static int tls_xread_record(tls_state_t *tls)
796 if (total >= RECHDR_LEN && target == MAX_INBUF) { 800 if (total >= RECHDR_LEN && target == MAX_INBUF) {
797 xhdr = (void*)tls->inbuf; 801 xhdr = (void*)tls->inbuf;
798 target = RECHDR_LEN + (0x100 * xhdr->len16_hi + xhdr->len16_lo); 802 target = RECHDR_LEN + (0x100 * xhdr->len16_hi + xhdr->len16_lo);
799 if (target > MAX_INBUF) { 803
800 /* malformed input (too long): yell and die */ 804 if (target > MAX_INBUF /* malformed input (too long) */
801 tls->buffered_size = 0; 805 || xhdr->proto_maj != TLS_MAJ
802 tls->ofs_to_buffered = total; 806 || xhdr->proto_min != TLS_MIN
803 tls_error_die(tls); 807 ) {
808 sz = total < target ? total : target;
809 if (sz > 24)
810 sz = 24; /* don't flood */
811 bad_record_die(tls, expected, sz);
804 } 812 }
805 /* can also check type/proto_maj/proto_min here */
806 dbg("xhdr type:%d ver:%d.%d len:%d\n", 813 dbg("xhdr type:%d ver:%d.%d len:%d\n",
807 xhdr->type, xhdr->proto_maj, xhdr->proto_min, 814 xhdr->type, xhdr->proto_maj, xhdr->proto_min,
808 0x100 * xhdr->len16_hi + xhdr->len16_lo 815 0x100 * xhdr->len16_hi + xhdr->len16_lo
@@ -1137,13 +1144,11 @@ static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len)
1137static int tls_xread_handshake_block(tls_state_t *tls, int min_len) 1144static int tls_xread_handshake_block(tls_state_t *tls, int min_len)
1138{ 1145{
1139 struct record_hdr *xhdr; 1146 struct record_hdr *xhdr;
1140 int len = tls_xread_record(tls); 1147 int len = tls_xread_record(tls, "handshake record");
1141 1148
1142 xhdr = (void*)tls->inbuf; 1149 xhdr = (void*)tls->inbuf;
1143 if (len < min_len 1150 if (len < min_len
1144 || xhdr->type != RECORD_TYPE_HANDSHAKE 1151 || xhdr->type != RECORD_TYPE_HANDSHAKE
1145 || xhdr->proto_maj != TLS_MAJ
1146 || xhdr->proto_min != TLS_MIN
1147 ) { 1152 ) {
1148 bad_record_die(tls, "handshake record", len); 1153 bad_record_die(tls, "handshake record", len);
1149 } 1154 }
@@ -1195,7 +1200,9 @@ static void send_client_hello_and_alloc_hsd(tls_state_t *tls, const char *sni)
1195// 0023 0000 - session_ticket 1200// 0023 0000 - session_ticket
1196// 000a 0008 0006001700180019 - supported_groups 1201// 000a 0008 0006001700180019 - supported_groups
1197// 000b 0002 0100 - ec_point_formats 1202// 000b 0002 0100 - ec_point_formats
1198// 000d 0016 00140401040305010503060106030301030302010203 - signature_algorithms 1203// 000d 0016 0014 0401 0403 0501 0503 0601 0603 0301 0303 0201 0203 - signature_algorithms
1204// wolfssl library sends this option, RFC 7627 (closes a security weakness, some servers may require it. TODO?):
1205// 0017 0000 - extended master secret
1199 }; 1206 };
1200 struct client_hello *record; 1207 struct client_hello *record;
1201 int len; 1208 int len;
@@ -1354,7 +1361,7 @@ static void get_server_cert(tls_state_t *tls)
1354 xhdr = (void*)tls->inbuf; 1361 xhdr = (void*)tls->inbuf;
1355 certbuf = (void*)(xhdr + 1); 1362 certbuf = (void*)(xhdr + 1);
1356 if (certbuf[0] != HANDSHAKE_CERTIFICATE) 1363 if (certbuf[0] != HANDSHAKE_CERTIFICATE)
1357 tls_error_die(tls); 1364 bad_record_die(tls, "certificate", len);
1358 dbg("<< CERTIFICATE\n"); 1365 dbg("<< CERTIFICATE\n");
1359 // 4392 bytes: 1366 // 4392 bytes:
1360 // 0b 00|11|24 00|11|21 00|05|b0 30|82|05|ac|30|82|04|94|a0|03|02|01|02|02|11|00|9f|85|bf|66|4b|0c|dd|af|ca|50|86|79|50|1b|2b|e4|30|0d... 1367 // 0b 00|11|24 00|11|21 00|05|b0 30|82|05|ac|30|82|04|94|a0|03|02|01|02|02|11|00|9f|85|bf|66|4b|0c|dd|af|ca|50|86|79|50|1b|2b|e4|30|0d...
@@ -1611,6 +1618,7 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
1611 // <------- Finished 1618 // <------- Finished
1612 // Application Data <------> Application Data 1619 // Application Data <------> Application Data
1613 int len; 1620 int len;
1621 int got_cert_req;
1614 1622
1615 send_client_hello_and_alloc_hsd(tls, sni); 1623 send_client_hello_and_alloc_hsd(tls, sni);
1616 get_server_hello(tls); 1624 get_server_hello(tls);
@@ -1638,7 +1646,8 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
1638 len = tls_xread_handshake_block(tls, 4); 1646 len = tls_xread_handshake_block(tls, 4);
1639 } 1647 }
1640 1648
1641 if (tls->inbuf[RECHDR_LEN] == HANDSHAKE_CERTIFICATE_REQUEST) { 1649 got_cert_req = (tls->inbuf[RECHDR_LEN] == HANDSHAKE_CERTIFICATE_REQUEST);
1650 if (got_cert_req) {
1642 dbg("<< CERTIFICATE_REQUEST\n"); 1651 dbg("<< CERTIFICATE_REQUEST\n");
1643 // RFC 5246: "If no suitable certificate is available, 1652 // RFC 5246: "If no suitable certificate is available,
1644 // the client MUST send a certificate message containing no 1653 // the client MUST send a certificate message containing no
@@ -1647,7 +1656,9 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
1647 // Client certificates are sent using the Certificate structure 1656 // Client certificates are sent using the Certificate structure
1648 // defined in Section 7.4.2." 1657 // defined in Section 7.4.2."
1649 // (i.e. the same format as server certs) 1658 // (i.e. the same format as server certs)
1650 send_empty_client_cert(tls); 1659
1660 /*send_empty_client_cert(tls); - WRONG (breaks handshake hash calc) */
1661 /* need to hash _all_ server replies first, up to ServerHelloDone */
1651 len = tls_xread_handshake_block(tls, 4); 1662 len = tls_xread_handshake_block(tls, 4);
1652 } 1663 }
1653 1664
@@ -1657,6 +1668,9 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
1657 // 0e 000000 (len:0) 1668 // 0e 000000 (len:0)
1658 dbg("<< SERVER_HELLO_DONE\n"); 1669 dbg("<< SERVER_HELLO_DONE\n");
1659 1670
1671 if (got_cert_req)
1672 send_empty_client_cert(tls);
1673
1660 send_client_key_exchange(tls); 1674 send_client_key_exchange(tls);
1661 1675
1662 send_change_cipher_spec(tls); 1676 send_change_cipher_spec(tls);
@@ -1667,7 +1681,7 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
1667 send_client_finished(tls); 1681 send_client_finished(tls);
1668 1682
1669 /* Get CHANGE_CIPHER_SPEC */ 1683 /* Get CHANGE_CIPHER_SPEC */
1670 len = tls_xread_record(tls); 1684 len = tls_xread_record(tls, "switch to encrypted traffic");
1671 if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0) 1685 if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0)
1672 bad_record_die(tls, "switch to encrypted traffic", len); 1686 bad_record_die(tls, "switch to encrypted traffic", len);
1673 dbg("<< CHANGE_CIPHER_SPEC\n"); 1687 dbg("<< CHANGE_CIPHER_SPEC\n");
@@ -1685,9 +1699,9 @@ void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
1685 } 1699 }
1686 1700
1687 /* Get (encrypted) FINISHED from the server */ 1701 /* Get (encrypted) FINISHED from the server */
1688 len = tls_xread_record(tls); 1702 len = tls_xread_record(tls, "'server finished'");
1689 if (len < 4 || tls->inbuf[RECHDR_LEN] != HANDSHAKE_FINISHED) 1703 if (len < 4 || tls->inbuf[RECHDR_LEN] != HANDSHAKE_FINISHED)
1690 tls_error_die(tls); 1704 bad_record_die(tls, "'server finished'", len);
1691 dbg("<< FINISHED\n"); 1705 dbg("<< FINISHED\n");
1692 /* application data can be sent/received */ 1706 /* application data can be sent/received */
1693 1707
@@ -1713,7 +1727,7 @@ static void tls_xwrite(tls_state_t *tls, int len)
1713// openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL 1727// openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL
1714// openssl s_client -connect 127.0.0.1:4433 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL-SHA256 1728// openssl s_client -connect 127.0.0.1:4433 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL-SHA256
1715 1729
1716void FAST_FUNC tls_run_copy_loop(tls_state_t *tls) 1730void FAST_FUNC tls_run_copy_loop(tls_state_t *tls, unsigned flags)
1717{ 1731{
1718 int inbuf_size; 1732 int inbuf_size;
1719 const int INBUF_STEP = 4 * 1024; 1733 const int INBUF_STEP = 4 * 1024;
@@ -1748,6 +1762,8 @@ void FAST_FUNC tls_run_copy_loop(tls_state_t *tls)
1748 */ 1762 */
1749 pfds[0].fd = -1; 1763 pfds[0].fd = -1;
1750 tls_free_outbuf(tls); /* mem usage optimization */ 1764 tls_free_outbuf(tls); /* mem usage optimization */
1765 if (flags & TLSLOOP_EXIT_ON_LOCAL_EOF)
1766 break;
1751 } else { 1767 } else {
1752 if (nread == inbuf_size) { 1768 if (nread == inbuf_size) {
1753 /* TLS has per record overhead, if input comes fast, 1769 /* TLS has per record overhead, if input comes fast,
@@ -1763,7 +1779,7 @@ void FAST_FUNC tls_run_copy_loop(tls_state_t *tls)
1763 if (pfds[1].revents) { 1779 if (pfds[1].revents) {
1764 dbg("NETWORK HAS DATA\n"); 1780 dbg("NETWORK HAS DATA\n");
1765 read_record: 1781 read_record:
1766 nread = tls_xread_record(tls); 1782 nread = tls_xread_record(tls, "encrypted data");
1767 if (nread < 1) { 1783 if (nread < 1) {
1768 /* TLS protocol has no real concept of one-sided shutdowns: 1784 /* TLS protocol has no real concept of one-sided shutdowns:
1769 * if we get "TLS EOF" from the peer, writes will fail too 1785 * if we get "TLS EOF" from the peer, writes will fail too
@@ -1775,7 +1791,7 @@ void FAST_FUNC tls_run_copy_loop(tls_state_t *tls)
1775 break; 1791 break;
1776 } 1792 }
1777 if (tls->inbuf[0] != RECORD_TYPE_APPLICATION_DATA) 1793 if (tls->inbuf[0] != RECORD_TYPE_APPLICATION_DATA)
1778 bb_error_msg_and_die("unexpected record type %d", tls->inbuf[0]); 1794 bad_record_die(tls, "encrypted data", nread);
1779 xwrite(STDOUT_FILENO, tls->inbuf + RECHDR_LEN, nread); 1795 xwrite(STDOUT_FILENO, tls->inbuf + RECHDR_LEN, nread);
1780 /* We may already have a complete next record buffered, 1796 /* We may already have a complete next record buffered,
1781 * can process it without network reads (and possible blocking) 1797 * can process it without network reads (and possible blocking)
diff --git a/networking/udhcp/Config.src b/networking/udhcp/Config.src
index 8ab8d30ce..50bff2e8c 100644
--- a/networking/udhcp/Config.src
+++ b/networking/udhcp/Config.src
@@ -94,7 +94,7 @@ config FEATURE_UDHCPC_SANITIZEOPT
94config UDHCPC_DEFAULT_SCRIPT 94config UDHCPC_DEFAULT_SCRIPT
95 string "Absolute path to config script" 95 string "Absolute path to config script"
96 default "/usr/share/udhcpc/default.script" 96 default "/usr/share/udhcpc/default.script"
97 depends on UDHCPC 97 depends on UDHCPC || UDHCPC6
98 help 98 help
99 This script is called after udhcpc receives an answer. See 99 This script is called after udhcpc receives an answer. See
100 examples/udhcp for a working example. Normally it is safe 100 examples/udhcp for a working example. Normally it is safe
diff --git a/networking/udhcp/d6_common.h b/networking/udhcp/d6_common.h
index 310550371..e9c0397ae 100644
--- a/networking/udhcp/d6_common.h
+++ b/networking/udhcp/d6_common.h
@@ -133,6 +133,7 @@ struct d6_option {
133struct client6_data_t { 133struct client6_data_t {
134 struct d6_option *server_id; 134 struct d6_option *server_id;
135 struct d6_option *ia_na; 135 struct d6_option *ia_na;
136 struct d6_option *ia_pd;
136 char **env_ptr; 137 char **env_ptr;
137 unsigned env_idx; 138 unsigned env_idx;
138 /* link-local IPv6 address */ 139 /* link-local IPv6 address */
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 37ffd064d..35c99e89c 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -96,6 +96,7 @@ static const char udhcpc6_longopts[] ALIGN1 =
96 "quit\0" No_argument "q" 96 "quit\0" No_argument "q"
97 "release\0" No_argument "R" 97 "release\0" No_argument "R"
98 "request\0" Required_argument "r" 98 "request\0" Required_argument "r"
99 "requestprefix\0" No_argument "d"
99 "script\0" Required_argument "s" 100 "script\0" Required_argument "s"
100 "timeout\0" Required_argument "T" 101 "timeout\0" Required_argument "T"
101 "retries\0" Required_argument "t" 102 "retries\0" Required_argument "t"
@@ -128,8 +129,9 @@ enum {
128 OPT_o = 1 << 12, 129 OPT_o = 1 << 12,
129 OPT_x = 1 << 13, 130 OPT_x = 1 << 13,
130 OPT_f = 1 << 14, 131 OPT_f = 1 << 14,
132 OPT_d = 1 << 15,
131/* The rest has variable bit positions, need to be clever */ 133/* The rest has variable bit positions, need to be clever */
132 OPTBIT_f = 14, 134 OPTBIT_d = 15,
133 USE_FOR_MMU( OPTBIT_b,) 135 USE_FOR_MMU( OPTBIT_b,)
134 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) 136 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
135 IF_FEATURE_UDHCP_PORT( OPTBIT_P,) 137 IF_FEATURE_UDHCP_PORT( OPTBIT_P,)
@@ -277,11 +279,11 @@ static void option_to_env(uint8_t *option, uint8_t *option_end)
277 * | | 279 * | |
278 * +-+-+-+-+-+-+-+-+ 280 * +-+-+-+-+-+-+-+-+
279 */ 281 */
280 //move_from_unaligned32(v32, option + 4 + 4); 282 move_from_unaligned32(v32, option + 4 + 4);
281 //*new_env() = xasprintf("lease=%u", (unsigned)v32); 283 *new_env() = xasprintf("ipv6prefix_lease=%u", (unsigned)v32);
282 284
283 sprint_nip6(ipv6str, option + 4 + 4 + 1); 285 sprint_nip6(ipv6str, option + 4 + 4 + 4 + 1);
284 *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4])); 286 *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4 + 4]));
285 break; 287 break;
286#if ENABLE_FEATURE_UDHCPC6_RFC3646 288#if ENABLE_FEATURE_UDHCPC6_RFC3646
287 case D6_OPT_DNS_SERVERS: { 289 case D6_OPT_DNS_SERVERS: {
@@ -561,18 +563,33 @@ static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ip
561 563
562 /* Create new IA_NA, optionally with included IAADDR with requested IP */ 564 /* Create new IA_NA, optionally with included IAADDR with requested IP */
563 free(client6_data.ia_na); 565 free(client6_data.ia_na);
564 len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4; 566 client6_data.ia_na = NULL;
565 client6_data.ia_na = xzalloc(len); 567 if (option_mask32 & OPT_r) {
566 client6_data.ia_na->code = D6_OPT_IA_NA; 568 len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4;
567 client6_data.ia_na->len = len - 4; 569 client6_data.ia_na = xzalloc(len);
568 *(uint32_t*)client6_data.ia_na->data = rand(); /* IAID */ 570 client6_data.ia_na->code = D6_OPT_IA_NA;
569 if (requested_ipv6) { 571 client6_data.ia_na->len = len - 4;
570 struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4); 572 *(uint32_t*)client6_data.ia_na->data = rand(); /* IAID */
571 iaaddr->code = D6_OPT_IAADDR; 573 if (requested_ipv6) {
572 iaaddr->len = 16+4+4; 574 struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4);
573 memcpy(iaaddr->data, requested_ipv6, 16); 575 iaaddr->code = D6_OPT_IAADDR;
576 iaaddr->len = 16+4+4;
577 memcpy(iaaddr->data, requested_ipv6, 16);
578 }
579 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, len);
580 }
581
582 /* IA_PD */
583 free(client6_data.ia_pd);
584 client6_data.ia_pd = NULL;
585 if (option_mask32 & OPT_d) {
586 len = 2+2+4+4+4;
587 client6_data.ia_pd = xzalloc(len);
588 client6_data.ia_pd->code = D6_OPT_IA_PD;
589 client6_data.ia_pd->len = len - 4;
590 *(uint32_t*)client6_data.ia_pd->data = rand(); /* IAID */
591 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len);
574 } 592 }
575 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, len);
576 593
577 /* Add options: 594 /* Add options:
578 * "param req" option according to -O, options specified with -x 595 * "param req" option according to -O, options specified with -x
@@ -625,7 +642,11 @@ static NOINLINE int send_d6_select(uint32_t xid)
625 /* server id */ 642 /* server id */
626 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); 643 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
627 /* IA NA (contains requested IP) */ 644 /* IA NA (contains requested IP) */
628 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); 645 if (client6_data.ia_na)
646 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
647 /* IA PD */
648 if (client6_data.ia_pd)
649 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
629 650
630 /* Add options: 651 /* Add options:
631 * "param req" option according to -O, options specified with -x 652 * "param req" option according to -O, options specified with -x
@@ -694,7 +715,11 @@ static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, st
694 /* server id */ 715 /* server id */
695 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); 716 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
696 /* IA NA (contains requested IP) */ 717 /* IA NA (contains requested IP) */
697 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); 718 if (client6_data.ia_na)
719 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
720 /* IA PD */
721 if (client6_data.ia_pd)
722 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
698 723
699 /* Add options: 724 /* Add options:
700 * "param req" option according to -O, options specified with -x 725 * "param req" option according to -O, options specified with -x
@@ -725,7 +750,11 @@ static int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cu
725 /* server id */ 750 /* server id */
726 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); 751 opt_ptr = mempcpy(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
727 /* IA NA (contains our current IP) */ 752 /* IA NA (contains our current IP) */
728 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); 753 if (client6_data.ia_na)
754 opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
755 /* IA PD */
756 if (client6_data.ia_pd)
757 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
729 758
730 bb_error_msg("sending %s", "release"); 759 bb_error_msg("sending %s", "release");
731 return d6_send_kernel_packet( 760 return d6_send_kernel_packet(
@@ -1001,44 +1030,9 @@ static void client_background(void)
1001//usage:# define IF_UDHCP_VERBOSE(...) 1030//usage:# define IF_UDHCP_VERBOSE(...)
1002//usage:#endif 1031//usage:#endif
1003//usage:#define udhcpc6_trivial_usage 1032//usage:#define udhcpc6_trivial_usage
1004//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" 1033//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"odR] [-i IFACE] [-r IPv6] [-s PROG] [-p PIDFILE]\n"
1005//usage: " [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") 1034//usage: " [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]")
1006//usage:#define udhcpc6_full_usage "\n" 1035//usage:#define udhcpc6_full_usage "\n"
1007//usage: IF_LONG_OPTS(
1008//usage: "\n -i,--interface IFACE Interface to use (default eth0)"
1009//usage: "\n -p,--pidfile FILE Create pidfile"
1010//usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
1011//usage: "\n -B,--broadcast Request broadcast replies"
1012//usage: "\n -t,--retries N Send up to N discover packets"
1013//usage: "\n -T,--timeout N Pause between packets (default 3 seconds)"
1014//usage: "\n -A,--tryagain N Wait N seconds after failure (default 20)"
1015//usage: "\n -f,--foreground Run in foreground"
1016//usage: USE_FOR_MMU(
1017//usage: "\n -b,--background Background if lease is not obtained"
1018//usage: )
1019//usage: "\n -n,--now Exit if lease is not obtained"
1020//usage: "\n -q,--quit Exit after obtaining lease"
1021//usage: "\n -R,--release Release IP on exit"
1022//usage: "\n -S,--syslog Log to syslog too"
1023//usage: IF_FEATURE_UDHCP_PORT(
1024//usage: "\n -P,--client-port N Use port N (default 546)"
1025//usage: )
1026////usage: IF_FEATURE_UDHCPC_ARPING(
1027////usage: "\n -a,--arping Use arping to validate offered address"
1028////usage: )
1029//usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)"
1030//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)"
1031//usage: "\n -r,--request IP Request this IP address"
1032//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)"
1033//usage: "\n Examples of string, numeric, and hex byte opts:"
1034//usage: "\n -x hostname:bbox - option 12"
1035//usage: "\n -x lease:3600 - option 51 (lease time)"
1036//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
1037//usage: IF_UDHCP_VERBOSE(
1038//usage: "\n -v Verbose"
1039//usage: )
1040//usage: )
1041//usage: IF_NOT_LONG_OPTS(
1042//usage: "\n -i IFACE Interface to use (default eth0)" 1036//usage: "\n -i IFACE Interface to use (default eth0)"
1043//usage: "\n -p FILE Create pidfile" 1037//usage: "\n -p FILE Create pidfile"
1044//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" 1038//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
@@ -1062,7 +1056,8 @@ static void client_background(void)
1062////usage: ) 1056////usage: )
1063//usage: "\n -O OPT Request option OPT from server (cumulative)" 1057//usage: "\n -O OPT Request option OPT from server (cumulative)"
1064//usage: "\n -o Don't request any options (unless -O is given)" 1058//usage: "\n -o Don't request any options (unless -O is given)"
1065//usage: "\n -r IP Request this IP address" 1059//usage: "\n -r IPv6 Request this address ('no' to not request any IP)"
1060//usage: "\n -d Request prefix"
1066//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" 1061//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)"
1067//usage: "\n Examples of string, numeric, and hex byte opts:" 1062//usage: "\n Examples of string, numeric, and hex byte opts:"
1068//usage: "\n -x hostname:bbox - option 12" 1063//usage: "\n -x hostname:bbox - option 12"
@@ -1071,7 +1066,6 @@ static void client_background(void)
1071//usage: IF_UDHCP_VERBOSE( 1066//usage: IF_UDHCP_VERBOSE(
1072//usage: "\n -v Verbose" 1067//usage: "\n -v Verbose"
1073//usage: ) 1068//usage: )
1074//usage: )
1075//usage: "\nSignals:" 1069//usage: "\nSignals:"
1076//usage: "\n USR1 Renew lease" 1070//usage: "\n USR1 Renew lease"
1077//usage: "\n USR2 Release lease" 1071//usage: "\n USR2 Release lease"
@@ -1099,6 +1093,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1099 int retval; 1093 int retval;
1100 1094
1101 setup_common_bufsiz(); 1095 setup_common_bufsiz();
1096 /* We want random_xid to be random */
1097 srand(monotonic_us());
1102 1098
1103 /* Default options */ 1099 /* Default options */
1104 IF_FEATURE_UDHCP_PORT(SERVER_PORT6 = 547;) 1100 IF_FEATURE_UDHCP_PORT(SERVER_PORT6 = 547;)
@@ -1109,7 +1105,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1109 /* Parse command line */ 1105 /* Parse command line */
1110 opt = getopt32long(argv, "^" 1106 opt = getopt32long(argv, "^"
1111 /* O,x: list; -T,-t,-A take numeric param */ 1107 /* O,x: list; -T,-t,-A take numeric param */
1112 "i:np:qRr:s:T:+t:+SA:+O:*ox:*f" 1108 "i:np:qRr:s:T:+t:+SA:+O:*ox:*fd"
1113 USE_FOR_MMU("b") 1109 USE_FOR_MMU("b")
1114 ///IF_FEATURE_UDHCPC_ARPING("a") 1110 ///IF_FEATURE_UDHCPC_ARPING("a")
1115 IF_FEATURE_UDHCP_PORT("P:") 1111 IF_FEATURE_UDHCP_PORT("P:")
@@ -1125,10 +1121,15 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1125 IF_UDHCP_VERBOSE(, &dhcp_verbose) 1121 IF_UDHCP_VERBOSE(, &dhcp_verbose)
1126 ); 1122 );
1127 requested_ipv6 = NULL; 1123 requested_ipv6 = NULL;
1124 option_mask32 |= OPT_r;
1128 if (opt & OPT_r) { 1125 if (opt & OPT_r) {
1129 if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0) 1126 if (strcmp(str_r, "no") == 0) {
1130 bb_error_msg_and_die("bad IPv6 address '%s'", str_r); 1127 option_mask32 -= OPT_r;
1131 requested_ipv6 = &ipv6_buf; 1128 } else {
1129 if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0)
1130 bb_error_msg_and_die("bad IPv6 address '%s'", str_r);
1131 requested_ipv6 = &ipv6_buf;
1132 }
1132 } 1133 }
1133#if ENABLE_FEATURE_UDHCP_PORT 1134#if ENABLE_FEATURE_UDHCP_PORT
1134 if (opt & OPT_P) { 1135 if (opt & OPT_P) {
@@ -1200,16 +1201,12 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1200 1201
1201 /* Make sure fd 0,1,2 are open */ 1202 /* Make sure fd 0,1,2 are open */
1202 bb_sanitize_stdio(); 1203 bb_sanitize_stdio();
1203 /* Equivalent of doing a fflush after every \n */
1204 setlinebuf(stdout);
1205 /* Create pidfile */ 1204 /* Create pidfile */
1206 write_pidfile(client_config.pidfile); 1205 write_pidfile(client_config.pidfile);
1207 /* Goes to stdout (unless NOMMU) and possibly syslog */ 1206 /* Goes to stdout (unless NOMMU) and possibly syslog */
1208 bb_error_msg("started, v"BB_VER); 1207 bb_error_msg("started, v"BB_VER);
1209 /* Set up the signal pipe */ 1208 /* Set up the signal pipe */
1210 udhcp_sp_setup(); 1209 udhcp_sp_setup();
1211 /* We want random_xid to be random... */
1212 srand(monotonic_us());
1213 1210
1214 state = INIT_SELECTING; 1211 state = INIT_SELECTING;
1215 d6_run_script(NULL, "deconfig"); 1212 d6_run_script(NULL, "deconfig");
@@ -1465,8 +1462,12 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1465 case REBINDING: 1462 case REBINDING:
1466 if (packet.d6_msg_type == D6_MSG_REPLY) { 1463 if (packet.d6_msg_type == D6_MSG_REPLY) {
1467 uint32_t lease_seconds; 1464 uint32_t lease_seconds;
1468 struct d6_option *option, *iaaddr; 1465 struct d6_option *option;
1466 unsigned address_timeout;
1467 unsigned prefix_timeout;
1469 type_is_ok: 1468 type_is_ok:
1469 address_timeout = 0;
1470 prefix_timeout = 0;
1470 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); 1471 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
1471 if (option && (option->data[0] | option->data[1]) != 0) { 1472 if (option && (option->data[0] | option->data[1]) != 0) {
1472 /* return to init state */ 1473 /* return to init state */
@@ -1589,44 +1590,87 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1589 * . . 1590 * . .
1590 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1591 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1591 */ 1592 */
1592 free(client6_data.ia_na); 1593 if (option_mask32 & OPT_r) {
1593 client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA); 1594 struct d6_option *iaaddr;
1594 if (!client6_data.ia_na) { 1595
1595 bb_error_msg("no %s option, ignoring packet", "IA_NA"); 1596 free(client6_data.ia_na);
1596 continue; 1597 client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA);
1597 } 1598 if (!client6_data.ia_na) {
1598 if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) { 1599 bb_error_msg("no %s option, ignoring packet", "IA_NA");
1599 bb_error_msg("IA_NA option is too short:%d bytes", client6_data.ia_na->len); 1600 continue;
1600 continue; 1601 }
1601 } 1602 if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) {
1602 iaaddr = d6_find_option(client6_data.ia_na->data + 4 + 4 + 4, 1603 bb_error_msg("%s option is too short:%d bytes",
1603 client6_data.ia_na->data + client6_data.ia_na->len, 1604 "IA_NA", client6_data.ia_na->len);
1604 D6_OPT_IAADDR 1605 continue;
1605 ); 1606 }
1606 if (!iaaddr) { 1607 iaaddr = d6_find_option(client6_data.ia_na->data + 4 + 4 + 4,
1607 bb_error_msg("no %s option, ignoring packet", "IAADDR"); 1608 client6_data.ia_na->data + client6_data.ia_na->len,
1608 continue; 1609 D6_OPT_IAADDR
1610 );
1611 if (!iaaddr) {
1612 bb_error_msg("no %s option, ignoring packet", "IAADDR");
1613 continue;
1614 }
1615 if (iaaddr->len < (16 + 4 + 4)) {
1616 bb_error_msg("%s option is too short:%d bytes",
1617 "IAADDR", iaaddr->len);
1618 continue;
1619 }
1620 /* Note: the address is sufficiently aligned for cast:
1621 * we _copied_ IA-NA, and copy is always well-aligned.
1622 */
1623 requested_ipv6 = (struct in6_addr*) iaaddr->data;
1624 move_from_unaligned32(lease_seconds, iaaddr->data + 16 + 4);
1625 lease_seconds = ntohl(lease_seconds);
1626/// TODO: check for 0 lease time?
1627 bb_error_msg("%s obtained, lease time %u",
1628 "IPv6", /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1629 address_timeout = lease_seconds;
1609 } 1630 }
1610 if (iaaddr->len < (16 + 4 + 4)) { 1631 if (option_mask32 & OPT_d) {
1611 bb_error_msg("IAADDR option is too short:%d bytes", iaaddr->len); 1632 struct d6_option *iaprefix;
1612 continue; 1633
1634 free(client6_data.ia_pd);
1635 client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD);
1636 if (!client6_data.ia_pd) {
1637 bb_error_msg("no %s option, ignoring packet", "IA_PD");
1638 continue;
1639 }
1640 if (client6_data.ia_pd->len < (4 + 4 + 4) + (2 + 2 + 4 + 4 + 1 + 16)) {
1641 bb_error_msg("%s option is too short:%d bytes",
1642 "IA_PD", client6_data.ia_pd->len);
1643 continue;
1644 }
1645 iaprefix = d6_find_option(client6_data.ia_pd->data + 4 + 4 + 4,
1646 client6_data.ia_pd->data + client6_data.ia_pd->len,
1647 D6_OPT_IAPREFIX
1648 );
1649 if (!iaprefix) {
1650 bb_error_msg("no %s option, ignoring packet", "IAPREFIX");
1651 continue;
1652 }
1653 if (iaprefix->len < (4 + 4 + 1 + 16)) {
1654 bb_error_msg("%s option is too short:%d bytes",
1655 "IAPREFIX", iaprefix->len);
1656 continue;
1657 }
1658 move_from_unaligned32(lease_seconds, iaprefix->data + 4);
1659 lease_seconds = ntohl(lease_seconds);
1660 bb_error_msg("%s obtained, lease time %u",
1661 "prefix", /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1662 prefix_timeout = lease_seconds;
1613 } 1663 }
1614 /* Note: the address is sufficiently aligned for cast: 1664 if (!address_timeout)
1615 * we _copied_ IA-NA, and copy is always well-aligned. 1665 address_timeout = prefix_timeout;
1616 */ 1666 if (!prefix_timeout)
1617 requested_ipv6 = (struct in6_addr*) iaaddr->data; 1667 prefix_timeout = address_timeout;
1618 move_from_unaligned32(lease_seconds, iaaddr->data + 16 + 4); 1668 /* note: "int timeout" will not overflow even with 0xffffffff inputs here: */
1619 lease_seconds = ntohl(lease_seconds); 1669 timeout = (prefix_timeout < address_timeout ? prefix_timeout : address_timeout) / 2;
1620 /* paranoia: must not be too small and not prone to overflows */ 1670 /* paranoia: must not be too small */
1621 if (lease_seconds < 0x10) 1671 if (timeout < 0x10)
1622 lease_seconds = 0x10; 1672 timeout = 0x10;
1623/// TODO: check for 0 lease time?
1624 if (lease_seconds > 0x7fffffff / 1000)
1625 lease_seconds = 0x7fffffff / 1000;
1626 /* enter bound state */ 1673 /* enter bound state */
1627 timeout = lease_seconds / 2;
1628 bb_error_msg("lease obtained, lease time %u",
1629 /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1630 d6_run_script(&packet, state == REQUESTING ? "bound" : "renew"); 1674 d6_run_script(&packet, state == REQUESTING ? "bound" : "renew");
1631 1675
1632 state = BOUND; 1676 state = BOUND;
diff --git a/networking/udhcp/d6_socket.c b/networking/udhcp/d6_socket.c
index d00c217d6..315c8d98a 100644
--- a/networking/udhcp/d6_socket.c
+++ b/networking/udhcp/d6_socket.c
@@ -16,7 +16,6 @@ int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_
16 struct ifaddrs *ifap, *ifa; 16 struct ifaddrs *ifap, *ifa;
17 17
18 getifaddrs(&ifap); 18 getifaddrs(&ifap);
19
20 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 19 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
21 struct sockaddr_in6 *sip6; 20 struct sockaddr_in6 *sip6;
22 21
@@ -29,9 +28,9 @@ int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_
29 struct sockaddr_ll *sll = (struct sockaddr_ll*)(ifa->ifa_addr); 28 struct sockaddr_ll *sll = (struct sockaddr_ll*)(ifa->ifa_addr);
30 memcpy(mac, sll->sll_addr, 6); 29 memcpy(mac, sll->sll_addr, 6);
31 log2("MAC %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 30 log2("MAC %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
32 log2("ifindex %d", sll->sll_ifindex);
33 *ifindex = sll->sll_ifindex; 31 *ifindex = sll->sll_ifindex;
34 retval &= (0xf - (1<<0)); 32 log2("ifindex %d", *ifindex);
33 retval &= (3 - (1<<0));
35 } 34 }
36#if 0 35#if 0
37 if (ifa->ifa_addr->sa_family == AF_INET) { 36 if (ifa->ifa_addr->sa_family == AF_INET) {
@@ -54,11 +53,33 @@ int FAST_FUNC d6_read_interface(const char *interface, int *ifindex, struct in6_
54 nip6->s6_addr[12], nip6->s6_addr[13], 53 nip6->s6_addr[12], nip6->s6_addr[13],
55 nip6->s6_addr[14], nip6->s6_addr[15] 54 nip6->s6_addr[14], nip6->s6_addr[15]
56 ); 55 );
57 retval &= (0xf - (1<<1)); 56 retval &= (3 - (1<<1));
58 } 57 }
59 } 58 }
60
61 freeifaddrs(ifap); 59 freeifaddrs(ifap);
60
61 if (retval & (1<<0)) {
62 /* This iface has no MAC (e.g. ppp), generate a random one */
63 struct ifreq ifr;
64 int fd;
65
66 memset(&ifr, 0, sizeof(ifr));
67 strncpy_IFNAMSIZ(ifr.ifr_name, interface);
68 fd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
69 if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
70 *ifindex = ifr.ifr_ifindex;
71 log2("ifindex %d", *ifindex);
72 if (((uint32_t*)mac)[0] == 0) {
73 /* invent a fictitious MAC (once) */
74 ((uint32_t*)mac)[0] = rand();
75 ((uint16_t*)mac)[2] = rand();
76 mac[0] &= 0xfc; /* make sure it's not bcast */
77 }
78 retval &= (3 - (1<<0));
79 }
80 close(fd);
81 }
82
62 if (retval == 0) 83 if (retval == 0)
63 return retval; 84 return retval;
64 85
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 55f21c187..35694fbe3 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -1386,8 +1386,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1386 1386
1387 /* Make sure fd 0,1,2 are open */ 1387 /* Make sure fd 0,1,2 are open */
1388 bb_sanitize_stdio(); 1388 bb_sanitize_stdio();
1389 /* Equivalent of doing a fflush after every \n */
1390 setlinebuf(stdout);
1391 /* Create pidfile */ 1389 /* Create pidfile */
1392 write_pidfile(client_config.pidfile); 1390 write_pidfile(client_config.pidfile);
1393 /* Goes to stdout (unless NOMMU) and possibly syslog */ 1391 /* Goes to stdout (unless NOMMU) and possibly syslog */
@@ -1732,8 +1730,10 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1732 /* paranoia: must not be too small and not prone to overflows */ 1730 /* paranoia: must not be too small and not prone to overflows */
1733 if (lease_seconds < 0x10) 1731 if (lease_seconds < 0x10)
1734 lease_seconds = 0x10; 1732 lease_seconds = 0x10;
1735 if (lease_seconds > 0x7fffffff / 1000) 1733 //if (lease_seconds > 0x7fffffff)
1736 lease_seconds = 0x7fffffff / 1000; 1734 // lease_seconds = 0x7fffffff;
1735 //^^^not necessary since "timeout = lease_seconds / 2"
1736 //does not overflow even for 0xffffffff.
1737 } 1737 }
1738#if ENABLE_FEATURE_UDHCPC_ARPING 1738#if ENABLE_FEATURE_UDHCPC_ARPING
1739 if (opt & OPT_a) { 1739 if (opt & OPT_a) {
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index 238542bb0..093239536 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -45,7 +45,7 @@
45#include "dhcpd.h" 45#include "dhcpd.h"
46 46
47/* globals */ 47/* globals */
48struct dyn_lease *g_leases; 48#define g_leases ((struct dyn_lease*)ptr_to_globals)
49/* struct server_config_t server_config is in bb_common_bufsiz1 */ 49/* struct server_config_t server_config is in bb_common_bufsiz1 */
50 50
51/* Takes the address of the pointer to the static_leases linked list, 51/* Takes the address of the pointer to the static_leases linked list,
@@ -856,8 +856,6 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
856 856
857 /* Make sure fd 0,1,2 are open */ 857 /* Make sure fd 0,1,2 are open */
858 bb_sanitize_stdio(); 858 bb_sanitize_stdio();
859 /* Equivalent of doing a fflush after every \n */
860 setlinebuf(stdout);
861 859
862 /* Create pidfile */ 860 /* Create pidfile */
863 write_pidfile(server_config.pidfile); 861 write_pidfile(server_config.pidfile);
@@ -880,7 +878,9 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
880 server_config.max_leases = num_ips; 878 server_config.max_leases = num_ips;
881 } 879 }
882 880
883 g_leases = xzalloc(server_config.max_leases * sizeof(g_leases[0])); 881 /* this sets g_leases */
882 SET_PTR_TO_GLOBALS(xzalloc(server_config.max_leases * sizeof(g_leases[0])));
883
884 read_leases(server_config.lease_file); 884 read_leases(server_config.lease_file);
885 885
886 if (udhcp_read_interface(server_config.interface, 886 if (udhcp_read_interface(server_config.interface,
diff --git a/networking/udhcp/dhcprelay.c b/networking/udhcp/dhcprelay.c
index 4d5644093..86dcb1af0 100644
--- a/networking/udhcp/dhcprelay.c
+++ b/networking/udhcp/dhcprelay.c
@@ -254,7 +254,7 @@ static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds)
254} 254}
255 255
256int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 256int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
257int dhcprelay_main(int argc, char **argv) 257int dhcprelay_main(int argc UNUSED_PARAM, char **argv)
258{ 258{
259 struct sockaddr_in server_addr; 259 struct sockaddr_in server_addr;
260 char **iface_list; 260 char **iface_list;
@@ -269,11 +269,11 @@ int dhcprelay_main(int argc, char **argv)
269 server_addr.sin_port = htons(SERVER_PORT); 269 server_addr.sin_port = htons(SERVER_PORT);
270 270
271 /* dhcprelay CLIENT_IFACE1[,CLIENT_IFACE2...] SERVER_IFACE [SERVER_IP] */ 271 /* dhcprelay CLIENT_IFACE1[,CLIENT_IFACE2...] SERVER_IFACE [SERVER_IP] */
272 if (argc == 4) { 272 if (!argv[1] || !argv[2])
273 bb_show_usage();
274 if (argv[3]) {
273 if (!inet_aton(argv[3], &server_addr.sin_addr)) 275 if (!inet_aton(argv[3], &server_addr.sin_addr))
274 bb_perror_msg_and_die("bad server IP"); 276 bb_perror_msg_and_die("bad server IP");
275 } else if (argc != 3) {
276 bb_show_usage();
277 } 277 }
278 278
279 iface_list = make_iface_list(argv + 1, &num_sockets); 279 iface_list = make_iface_list(argv + 1, &num_sockets);
diff --git a/networking/wget.c b/networking/wget.c
index 1f5ab8bc2..b9225fac0 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -48,6 +48,7 @@
48//config: 48//config:
49//config:config FEATURE_WGET_HTTPS 49//config:config FEATURE_WGET_HTTPS
50//config: bool "Support HTTPS using internal TLS code" 50//config: bool "Support HTTPS using internal TLS code"
51//it also enables FTPS support, but it's not well tested yet
51//config: default y 52//config: default y
52//config: depends on WGET 53//config: depends on WGET
53//config: select TLS 54//config: select TLS
@@ -176,6 +177,9 @@ struct host_info {
176static const char P_FTP[] ALIGN1 = "ftp"; 177static const char P_FTP[] ALIGN1 = "ftp";
177static const char P_HTTP[] ALIGN1 = "http"; 178static const char P_HTTP[] ALIGN1 = "http";
178#if SSL_SUPPORTED 179#if SSL_SUPPORTED
180# if ENABLE_FEATURE_WGET_HTTPS
181static const char P_FTPS[] ALIGN1 = "ftps";
182# endif
179static const char P_HTTPS[] ALIGN1 = "https"; 183static const char P_HTTPS[] ALIGN1 = "https";
180#endif 184#endif
181 185
@@ -348,15 +352,6 @@ static char *base64enc(const char *str)
348} 352}
349#endif 353#endif
350 354
351static char* sanitize_string(char *s)
352{
353 unsigned char *p = (void *) s;
354 while (*p >= ' ')
355 p++;
356 *p = '\0';
357 return s;
358}
359
360#if ENABLE_FEATURE_WGET_TIMEOUT 355#if ENABLE_FEATURE_WGET_TIMEOUT
361static void alarm_handler(int sig UNUSED_PARAM) 356static void alarm_handler(int sig UNUSED_PARAM)
362{ 357{
@@ -419,22 +414,49 @@ static FILE *open_socket(len_and_sockaddr *lsa)
419 return fp; 414 return fp;
420} 415}
421 416
417/* We balk at any control chars in other side's messages.
418 * This prevents nasty surprises (e.g. ESC sequences) in "Location:" URLs
419 * and error messages.
420 *
421 * The only exception is tabs, which are converted to (one) space:
422 * HTTP's "headers: <whitespace> values" may have those.
423 */
424static char* sanitize_string(char *s)
425{
426 unsigned char *p = (void *) s;
427 while (*p) {
428 if (*p < ' ') {
429 if (*p != '\t')
430 break;
431 *p = ' ';
432 }
433 p++;
434 }
435 *p = '\0';
436 return s;
437}
438
422/* Returns '\n' if it was seen, else '\0'. Trims at first '\r' or '\n' */ 439/* Returns '\n' if it was seen, else '\0'. Trims at first '\r' or '\n' */
423static char fgets_and_trim(FILE *fp, const char *fmt) 440static char fgets_trim_sanitize(FILE *fp, const char *fmt)
424{ 441{
425 char c; 442 char c;
426 char *buf_ptr; 443 char *buf_ptr;
427 444
428 set_alarm(); 445 set_alarm();
429 if (fgets(G.wget_buf, sizeof(G.wget_buf) - 1, fp) == NULL) 446 if (fgets(G.wget_buf, sizeof(G.wget_buf), fp) == NULL)
430 bb_perror_msg_and_die("error getting response"); 447 bb_perror_msg_and_die("error getting response");
431 clear_alarm(); 448 clear_alarm();
432 449
433 buf_ptr = strchrnul(G.wget_buf, '\n'); 450 buf_ptr = strchrnul(G.wget_buf, '\n');
434 c = *buf_ptr; 451 c = *buf_ptr;
452#if 1
453 /* Disallow any control chars: trim at first char < 0x20 */
454 sanitize_string(G.wget_buf);
455#else
435 *buf_ptr = '\0'; 456 *buf_ptr = '\0';
436 buf_ptr = strchrnul(G.wget_buf, '\r'); 457 buf_ptr = strchrnul(G.wget_buf, '\r');
437 *buf_ptr = '\0'; 458 *buf_ptr = '\0';
459#endif
438 460
439 log_io("< %s", G.wget_buf); 461 log_io("< %s", G.wget_buf);
440 462
@@ -461,8 +483,10 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp)
461#endif 483#endif
462 } 484 }
463 485
486 /* Read until "Nxx something" is received */
487 G.wget_buf[3] = 0;
464 do { 488 do {
465 fgets_and_trim(fp, "%s\n"); 489 fgets_trim_sanitize(fp, "%s\n");
466 } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' '); 490 } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' ');
467#if ENABLE_PLATFORM_MINGW32 491#if ENABLE_PLATFORM_MINGW32
468 fseek(fp, 0L, SEEK_CUR); 492 fseek(fp, 0L, SEEK_CUR);
@@ -490,6 +514,12 @@ static void parse_url(const char *src_url, struct host_info *h)
490 h->port = bb_lookup_port(P_FTP, "tcp", 21); 514 h->port = bb_lookup_port(P_FTP, "tcp", 21);
491 } else 515 } else
492#if SSL_SUPPORTED 516#if SSL_SUPPORTED
517# if ENABLE_FEATURE_WGET_HTTPS
518 if (strcmp(url, P_FTPS) == 0) {
519 h->port = bb_lookup_port(P_FTPS, "tcp", 990);
520 h->protocol = P_FTPS;
521 } else
522# endif
493 if (strcmp(url, P_HTTPS) == 0) { 523 if (strcmp(url, P_HTTPS) == 0) {
494 h->port = bb_lookup_port(P_HTTPS, "tcp", 443); 524 h->port = bb_lookup_port(P_HTTPS, "tcp", 443);
495 h->protocol = P_HTTPS; 525 h->protocol = P_HTTPS;
@@ -501,7 +531,7 @@ static void parse_url(const char *src_url, struct host_info *h)
501 h->protocol = P_HTTP; 531 h->protocol = P_HTTP;
502 } else { 532 } else {
503 *p = ':'; 533 *p = ':';
504 bb_error_msg_and_die("not an http or ftp url: %s", sanitize_string(url)); 534 bb_error_msg_and_die("not an http or ftp url: %s", url);
505 } 535 }
506 } else { 536 } else {
507 // GNU wget is user-friendly and falls back to http:// 537 // GNU wget is user-friendly and falls back to http://
@@ -556,13 +586,13 @@ static void parse_url(const char *src_url, struct host_info *h)
556 */ 586 */
557} 587}
558 588
559static char *gethdr(FILE *fp) 589static char *get_sanitized_hdr(FILE *fp)
560{ 590{
561 char *s, *hdrval; 591 char *s, *hdrval;
562 int c; 592 int c;
563 593
564 /* retrieve header line */ 594 /* retrieve header line */
565 c = fgets_and_trim(fp, " %s\n"); 595 c = fgets_trim_sanitize(fp, " %s\n");
566 596
567 /* end of the headers? */ 597 /* end of the headers? */
568 if (G.wget_buf[0] == '\0') 598 if (G.wget_buf[0] == '\0')
@@ -584,7 +614,7 @@ static char *gethdr(FILE *fp)
584 614
585 /* verify we are at the end of the header name */ 615 /* verify we are at the end of the header name */
586 if (*s != ':') 616 if (*s != ':')
587 bb_error_msg_and_die("bad header line: %s", sanitize_string(G.wget_buf)); 617 bb_error_msg_and_die("bad header line: %s", G.wget_buf);
588 618
589 /* locate the start of the header value */ 619 /* locate the start of the header value */
590 *s++ = '\0'; 620 *s++ = '\0';
@@ -608,87 +638,6 @@ static void reset_beg_range_to_zero(void)
608 /* ftruncate(G.output_fd, 0); */ 638 /* ftruncate(G.output_fd, 0); */
609} 639}
610 640
611static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa)
612{
613 FILE *sfp;
614 char *str;
615 int port;
616
617 if (!target->user)
618 target->user = xstrdup("anonymous:busybox@");
619
620 sfp = open_socket(lsa);
621 if (ftpcmd(NULL, NULL, sfp) != 220)
622 bb_error_msg_and_die("%s", sanitize_string(G.wget_buf + 4));
623
624 /*
625 * Splitting username:password pair,
626 * trying to log in
627 */
628 str = strchr(target->user, ':');
629 if (str)
630 *str++ = '\0';
631 switch (ftpcmd("USER ", target->user, sfp)) {
632 case 230:
633 break;
634 case 331:
635 if (ftpcmd("PASS ", str, sfp) == 230)
636 break;
637 /* fall through (failed login) */
638 default:
639 bb_error_msg_and_die("ftp login: %s", sanitize_string(G.wget_buf + 4));
640 }
641
642 ftpcmd("TYPE I", NULL, sfp);
643
644 /*
645 * Querying file size
646 */
647 if (ftpcmd("SIZE ", target->path, sfp) == 213) {
648 G.content_len = BB_STRTOOFF(G.wget_buf + 4, NULL, 10);
649 if (G.content_len < 0 || errno) {
650 bb_error_msg_and_die("SIZE value is garbage");
651 }
652 G.got_clen = 1;
653 }
654
655 /*
656 * Entering passive mode
657 */
658 if (ftpcmd("PASV", NULL, sfp) != 227) {
659 pasv_error:
660 bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(G.wget_buf));
661 }
662 // Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage]
663 // Server's IP is N1.N2.N3.N4 (we ignore it)
664 // Server's port for data connection is P1*256+P2
665 str = strrchr(G.wget_buf, ')');
666 if (str) str[0] = '\0';
667 str = strrchr(G.wget_buf, ',');
668 if (!str) goto pasv_error;
669 port = xatou_range(str+1, 0, 255);
670 *str = '\0';
671 str = strrchr(G.wget_buf, ',');
672 if (!str) goto pasv_error;
673 port += xatou_range(str+1, 0, 255) * 256;
674 set_nport(&lsa->u.sa, htons(port));
675
676 *dfpp = open_socket(lsa);
677
678 if (G.beg_range != 0) {
679 sprintf(G.wget_buf, "REST %"OFF_FMT"u", G.beg_range);
680 if (ftpcmd(G.wget_buf, NULL, sfp) == 350)
681 G.content_len -= G.beg_range;
682 else
683 reset_beg_range_to_zero();
684 }
685
686 if (ftpcmd("RETR ", target->path, sfp) > 150)
687 bb_error_msg_and_die("bad response to %s: %s", "RETR", sanitize_string(G.wget_buf));
688
689 return sfp;
690}
691
692#if ENABLE_FEATURE_WGET_OPENSSL 641#if ENABLE_FEATURE_WGET_OPENSSL
693static int spawn_https_helper_openssl(const char *host, unsigned port) 642static int spawn_https_helper_openssl(const char *host, unsigned port)
694{ 643{
@@ -765,7 +714,7 @@ static int spawn_https_helper_openssl(const char *host, unsigned port)
765#endif 714#endif
766 715
767#if ENABLE_FEATURE_WGET_HTTPS 716#if ENABLE_FEATURE_WGET_HTTPS
768static void spawn_ssl_client(const char *host, int network_fd) 717static void spawn_ssl_client(const char *host, int network_fd, int flags)
769{ 718{
770 int sp[2]; 719 int sp[2];
771 int pid; 720 int pid;
@@ -790,17 +739,19 @@ static void spawn_ssl_client(const char *host, int network_fd)
790 tls_state_t *tls = new_tls_state(); 739 tls_state_t *tls = new_tls_state();
791 tls->ifd = tls->ofd = network_fd; 740 tls->ifd = tls->ofd = network_fd;
792 tls_handshake(tls, servername); 741 tls_handshake(tls, servername);
793 tls_run_copy_loop(tls); 742 tls_run_copy_loop(tls, flags);
794 exit(0); 743 exit(0);
795 } else { 744 } else {
796 char *argv[5]; 745 char *argv[6];
746
797 xmove_fd(network_fd, 3); 747 xmove_fd(network_fd, 3);
798 argv[0] = (char*)"ssl_client"; 748 argv[0] = (char*)"ssl_client";
799 argv[1] = (char*)"-s3"; 749 argv[1] = (char*)"-s3";
800 //TODO: if (!is_ip_address(servername))... 750 //TODO: if (!is_ip_address(servername))...
801 argv[2] = (char*)"-n"; 751 argv[2] = (char*)"-n";
802 argv[3] = servername; 752 argv[3] = servername;
803 argv[4] = NULL; 753 argv[4] = (flags & TLSLOOP_EXIT_ON_LOCAL_EOF ? (char*)"-e" : NULL);
754 argv[5] = NULL;
804 BB_EXECVP(argv[0], argv); 755 BB_EXECVP(argv[0], argv);
805 bb_perror_msg_and_die("can't execute '%s'", argv[0]); 756 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
806 } 757 }
@@ -814,6 +765,101 @@ static void spawn_ssl_client(const char *host, int network_fd)
814} 765}
815#endif 766#endif
816 767
768static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa)
769{
770 FILE *sfp;
771 char *str;
772 int port;
773
774 if (!target->user)
775 target->user = xstrdup("anonymous:busybox@");
776
777 sfp = open_socket(lsa);
778#if ENABLE_FEATURE_WGET_HTTPS
779 if (target->protocol == P_FTPS)
780 spawn_ssl_client(target->host, fileno(sfp), TLSLOOP_EXIT_ON_LOCAL_EOF);
781#endif
782
783 if (ftpcmd(NULL, NULL, sfp) != 220)
784 bb_error_msg_and_die("%s", G.wget_buf);
785 /* note: ftpcmd() sanitizes G.wget_buf, ok to print */
786
787 /*
788 * Splitting username:password pair,
789 * trying to log in
790 */
791 str = strchr(target->user, ':');
792 if (str)
793 *str++ = '\0';
794 switch (ftpcmd("USER ", target->user, sfp)) {
795 case 230:
796 break;
797 case 331:
798 if (ftpcmd("PASS ", str, sfp) == 230)
799 break;
800 /* fall through (failed login) */
801 default:
802 bb_error_msg_and_die("ftp login: %s", G.wget_buf);
803 }
804
805 ftpcmd("TYPE I", NULL, sfp);
806
807 /*
808 * Querying file size
809 */
810 if (ftpcmd("SIZE ", target->path, sfp) == 213) {
811 G.content_len = BB_STRTOOFF(G.wget_buf + 4, NULL, 10);
812 if (G.content_len < 0 || errno) {
813 bb_error_msg_and_die("SIZE value is garbage");
814 }
815 G.got_clen = 1;
816 }
817
818 /*
819 * Entering passive mode
820 */
821 if (ENABLE_FEATURE_IPV6 && ftpcmd("EPSV", NULL, sfp) == 229) {
822 /* good */
823 } else
824 if (ftpcmd("PASV", NULL, sfp) != 227) {
825 pasv_error:
826 bb_error_msg_and_die("bad response to %s: %s", "PASV", G.wget_buf);
827 }
828 port = parse_pasv_epsv(G.wget_buf);
829 if (port < 0)
830 goto pasv_error;
831
832 set_nport(&lsa->u.sa, htons(port));
833
834 *dfpp = open_socket(lsa);
835
836#if ENABLE_FEATURE_WGET_HTTPS
837 if (target->protocol == P_FTPS) {
838 /* "PROT P" enables encryption of data stream.
839 * Without it (or with "PROT C"), data is sent unencrypted.
840 */
841 if (ftpcmd("PROT P", NULL, sfp) == 200)
842 spawn_ssl_client(target->host, fileno(*dfpp), /*flags*/ 0);
843 }
844#endif
845
846 if (G.beg_range != 0) {
847 sprintf(G.wget_buf, "REST %"OFF_FMT"u", G.beg_range);
848 if (ftpcmd(G.wget_buf, NULL, sfp) == 350)
849 G.content_len -= G.beg_range;
850 else
851 reset_beg_range_to_zero();
852 }
853
854//TODO: needs ftp-escaping 0xff and '\n' bytes here.
855//Or disallow '\n' altogether via sanitize_string() in parse_url().
856//But 0xff's are possible in valid utf8 filenames.
857 if (ftpcmd("RETR ", target->path, sfp) > 150)
858 bb_error_msg_and_die("bad response to %s: %s", "RETR", G.wget_buf);
859
860 return sfp;
861}
862
817static void NOINLINE retrieve_file_data(FILE *dfp) 863static void NOINLINE retrieve_file_data(FILE *dfp)
818{ 864{
819#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT 865#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
@@ -930,9 +976,9 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
930 if (!G.chunked) 976 if (!G.chunked)
931 break; 977 break;
932 978
933 fgets_and_trim(dfp, NULL); /* Eat empty line */ 979 fgets_trim_sanitize(dfp, NULL); /* Eat empty line */
934 get_clen: 980 get_clen:
935 fgets_and_trim(dfp, NULL); 981 fgets_trim_sanitize(dfp, NULL);
936 G.content_len = STRTOOFF(G.wget_buf, NULL, 16); 982 G.content_len = STRTOOFF(G.wget_buf, NULL, 16);
937 /* FIXME: error check? */ 983 /* FIXME: error check? */
938 if (G.content_len == 0) 984 if (G.content_len == 0)
@@ -987,7 +1033,7 @@ static void download_one_url(const char *url)
987 /* Use the proxy if necessary */ 1033 /* Use the proxy if necessary */
988 use_proxy = (strcmp(G.proxy_flag, "off") != 0); 1034 use_proxy = (strcmp(G.proxy_flag, "off") != 0);
989 if (use_proxy) { 1035 if (use_proxy) {
990 proxy = getenv(target.protocol == P_FTP ? "ftp_proxy" : "http_proxy"); 1036 proxy = getenv(target.protocol[0] == 'f' ? "ftp_proxy" : "http_proxy");
991//FIXME: what if protocol is https? Ok to use http_proxy? 1037//FIXME: what if protocol is https? Ok to use http_proxy?
992 use_proxy = (proxy && proxy[0]); 1038 use_proxy = (proxy && proxy[0]);
993 if (use_proxy) 1039 if (use_proxy)
@@ -1048,7 +1094,7 @@ static void download_one_url(const char *url)
1048 /*G.content_len = 0; - redundant, got_clen = 0 is enough */ 1094 /*G.content_len = 0; - redundant, got_clen = 0 is enough */
1049 G.got_clen = 0; 1095 G.got_clen = 0;
1050 G.chunked = 0; 1096 G.chunked = 0;
1051 if (use_proxy || target.protocol != P_FTP) { 1097 if (use_proxy || target.protocol[0] != 'f' /*not ftp[s]*/) {
1052 /* 1098 /*
1053 * HTTP session 1099 * HTTP session
1054 */ 1100 */
@@ -1066,7 +1112,7 @@ static void download_one_url(const char *url)
1066# if ENABLE_FEATURE_WGET_HTTPS 1112# if ENABLE_FEATURE_WGET_HTTPS
1067 if (fd < 0) { /* no openssl? try internal */ 1113 if (fd < 0) { /* no openssl? try internal */
1068 sfp = open_socket(lsa); 1114 sfp = open_socket(lsa);
1069 spawn_ssl_client(server.host, fileno(sfp)); 1115 spawn_ssl_client(server.host, fileno(sfp), /*flags*/ 0);
1070 goto socket_opened; 1116 goto socket_opened;
1071 } 1117 }
1072# else 1118# else
@@ -1083,7 +1129,7 @@ static void download_one_url(const char *url)
1083 /* Only internal TLS support is configured */ 1129 /* Only internal TLS support is configured */
1084 sfp = open_socket(lsa); 1130 sfp = open_socket(lsa);
1085 if (target.protocol == P_HTTPS) 1131 if (target.protocol == P_HTTPS)
1086 spawn_ssl_client(server.host, fileno(sfp)); 1132 spawn_ssl_client(server.host, fileno(sfp), /*flags*/ 0);
1087#else 1133#else
1088 /* ssl (https) support is not configured */ 1134 /* ssl (https) support is not configured */
1089 sfp = open_socket(lsa); 1135 sfp = open_socket(lsa);
@@ -1162,7 +1208,7 @@ static void download_one_url(const char *url)
1162 * Retrieve HTTP response line and check for "200" status code. 1208 * Retrieve HTTP response line and check for "200" status code.
1163 */ 1209 */
1164 read_response: 1210 read_response:
1165 fgets_and_trim(sfp, " %s\n"); 1211 fgets_trim_sanitize(sfp, " %s\n");
1166 1212
1167 str = G.wget_buf; 1213 str = G.wget_buf;
1168 str = skip_non_whitespace(str); 1214 str = skip_non_whitespace(str);
@@ -1173,7 +1219,7 @@ static void download_one_url(const char *url)
1173 switch (status) { 1219 switch (status) {
1174 case 0: 1220 case 0:
1175 case 100: 1221 case 100:
1176 while (gethdr(sfp) != NULL) 1222 while (get_sanitized_hdr(sfp) != NULL)
1177 /* eat all remaining headers */; 1223 /* eat all remaining headers */;
1178 goto read_response; 1224 goto read_response;
1179 1225
@@ -1237,13 +1283,13 @@ However, in real world it was observed that some web servers
1237 /* Partial Content even though we did not ask for it??? */ 1283 /* Partial Content even though we did not ask for it??? */
1238 /* fall through */ 1284 /* fall through */
1239 default: 1285 default:
1240 bb_error_msg_and_die("server returned error: %s", sanitize_string(G.wget_buf)); 1286 bb_error_msg_and_die("server returned error: %s", G.wget_buf);
1241 } 1287 }
1242 1288
1243 /* 1289 /*
1244 * Retrieve HTTP headers. 1290 * Retrieve HTTP headers.
1245 */ 1291 */
1246 while ((str = gethdr(sfp)) != NULL) { 1292 while ((str = get_sanitized_hdr(sfp)) != NULL) {
1247 static const char keywords[] ALIGN1 = 1293 static const char keywords[] ALIGN1 =
1248 "content-length\0""transfer-encoding\0""location\0"; 1294 "content-length\0""transfer-encoding\0""location\0";
1249 enum { 1295 enum {
@@ -1251,7 +1297,7 @@ However, in real world it was observed that some web servers
1251 }; 1297 };
1252 smalluint key; 1298 smalluint key;
1253 1299
1254 /* gethdr converted "FOO:" string to lowercase */ 1300 /* get_sanitized_hdr converted "FOO:" string to lowercase */
1255 1301
1256 /* strip trailing whitespace */ 1302 /* strip trailing whitespace */
1257 char *s = strchrnul(str, '\0') - 1; 1303 char *s = strchrnul(str, '\0') - 1;
@@ -1263,14 +1309,14 @@ However, in real world it was observed that some web servers
1263 if (key == KEY_content_length) { 1309 if (key == KEY_content_length) {
1264 G.content_len = BB_STRTOOFF(str, NULL, 10); 1310 G.content_len = BB_STRTOOFF(str, NULL, 10);
1265 if (G.content_len < 0 || errno) { 1311 if (G.content_len < 0 || errno) {
1266 bb_error_msg_and_die("content-length %s is garbage", sanitize_string(str)); 1312 bb_error_msg_and_die("content-length %s is garbage", str);
1267 } 1313 }
1268 G.got_clen = 1; 1314 G.got_clen = 1;
1269 continue; 1315 continue;
1270 } 1316 }
1271 if (key == KEY_transfer_encoding) { 1317 if (key == KEY_transfer_encoding) {
1272 if (strcmp(str_tolower(str), "chunked") != 0) 1318 if (strcmp(str_tolower(str), "chunked") != 0)
1273 bb_error_msg_and_die("transfer encoding '%s' is not supported", sanitize_string(str)); 1319 bb_error_msg_and_die("transfer encoding '%s' is not supported", str);
1274 G.chunked = 1; 1320 G.chunked = 1;
1275 } 1321 }
1276 if (key == KEY_location && status >= 300) { 1322 if (key == KEY_location && status >= 300) {
@@ -1279,7 +1325,7 @@ However, in real world it was observed that some web servers
1279 fclose(sfp); 1325 fclose(sfp);
1280 if (str[0] == '/') { 1326 if (str[0] == '/') {
1281 free(redirected_path); 1327 free(redirected_path);
1282 target.path = redirected_path = xstrdup(str+1); 1328 target.path = redirected_path = xstrdup(str + 1);
1283 /* lsa stays the same: it's on the same server */ 1329 /* lsa stays the same: it's on the same server */
1284 } else { 1330 } else {
1285 parse_url(str, &target); 1331 parse_url(str, &target);
@@ -1326,7 +1372,7 @@ However, in real world it was observed that some web servers
1326 /* It's ftp. Close data connection properly */ 1372 /* It's ftp. Close data connection properly */
1327 fclose(dfp); 1373 fclose(dfp);
1328 if (ftpcmd(NULL, NULL, sfp) != 226) 1374 if (ftpcmd(NULL, NULL, sfp) != 226)
1329 bb_error_msg_and_die("ftp error: %s", sanitize_string(G.wget_buf + 4)); 1375 bb_error_msg_and_die("ftp error: %s", G.wget_buf);
1330 /* ftpcmd("QUIT", NULL, sfp); - why bother? */ 1376 /* ftpcmd("QUIT", NULL, sfp); - why bother? */
1331 } 1377 }
1332 fclose(sfp); 1378 fclose(sfp);