diff options
author | Ron Yorston <rmy@pobox.com> | 2018-02-13 09:44:44 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2018-02-13 09:44:44 +0000 |
commit | dc19a361bd6c6df30338371532691bbc7f7126bb (patch) | |
tree | 1fb2cd646d54b5f8e425c4f11f3e09fc21d1966b /networking | |
parent | 096aee2bb468d1ab044de36e176ed1f6c7e3674d (diff) | |
parent | 3459024bf404af814cacfe90a0deb719e282ae62 (diff) | |
download | busybox-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.c | 193 | ||||
-rw-r--r-- | networking/ftpd.c | 14 | ||||
-rw-r--r-- | networking/ftpgetput.c | 44 | ||||
-rw-r--r-- | networking/inetd.c | 5 | ||||
-rw-r--r-- | networking/libiproute/Kbuild.src | 6 | ||||
-rw-r--r-- | networking/libiproute/ipaddress.c | 6 | ||||
-rw-r--r-- | networking/libiproute/iplink.c | 4 | ||||
-rw-r--r-- | networking/libiproute/ipneigh.c | 10 | ||||
-rw-r--r-- | networking/libiproute/iproute.c | 4 | ||||
-rw-r--r-- | networking/libiproute/iprule.c | 2 | ||||
-rw-r--r-- | networking/libiproute/libnetlink.c | 7 | ||||
-rw-r--r-- | networking/libiproute/ll_map.c | 2 | ||||
-rw-r--r-- | networking/ntpd.c | 4 | ||||
-rw-r--r-- | networking/parse_pasv_epsv.c | 66 | ||||
-rw-r--r-- | networking/ssl_client.c | 14 | ||||
-rw-r--r-- | networking/tc.c | 128 | ||||
-rw-r--r-- | networking/tftp.c | 3 | ||||
-rw-r--r-- | networking/tls.c | 98 | ||||
-rw-r--r-- | networking/udhcp/Config.src | 2 | ||||
-rw-r--r-- | networking/udhcp/d6_common.h | 1 | ||||
-rw-r--r-- | networking/udhcp/d6_dhcpc.c | 246 | ||||
-rw-r--r-- | networking/udhcp/d6_socket.c | 31 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.c | 8 | ||||
-rw-r--r-- | networking/udhcp/dhcpd.c | 8 | ||||
-rw-r--r-- | networking/udhcp/dhcprelay.c | 8 | ||||
-rw-r--r-- | networking/wget.c | 278 |
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 | ||
47 | enum { | 47 | enum { |
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 | ||
57 | struct globals { | 66 | struct 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 | ||
102 | static int send_pack(struct in_addr *src_addr, | 112 | static 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) | |||
258 | static void | 262 | static void |
259 | cmdio_write_ok(unsigned status) | 263 | cmdio_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) | |||
269 | static void | 273 | static void |
270 | cmdio_write_error(unsigned status) | 274 | cmdio_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 | |||
599 | handle_rest(void) | 603 | handle_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 | ||
159 | static int xconnect_ftpdata(void) | 159 | static 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) { |
165 | TODO: PASV command will not work for IPv6. RFC2428 describes | 164 | /* good */ |
166 | IPv6-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 | ||
169 | in specified protocol. Protocol is 1 for IPv4, 2 for IPv6. | ||
170 | If not specified, defaults to "same as used for control connection". | ||
171 | If server understood you, it should answer "229 <some text>(|||port|)" | ||
172 | where "|" are literal pipe chars and "port" is ASCII decimal port#. | ||
173 | |||
174 | There is also an IPv6-capable replacement for PORT (EPRT), | ||
175 | but we don't need that. | ||
176 | |||
177 | NB: PASV may still work for some servers even over IPv6. | ||
178 | For example, vsftp happily answers | ||
179 | "227 Entering Passive Mode (0,0,0,0,n,n)" and proceeds as usual. | ||
180 | |||
181 | TODO2: 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 | |||
12 | lib-$(CONFIG_SLATTACH) += \ | 12 | lib-$(CONFIG_SLATTACH) += \ |
13 | utils.o | 13 | utils.o |
14 | 14 | ||
15 | lib-$(CONFIG_TC) += \ | ||
16 | libnetlink.o \ | ||
17 | ll_map.o \ | ||
18 | ll_proto.o \ | ||
19 | utils.o | ||
20 | |||
15 | lib-$(CONFIG_IP) += \ | 21 | lib-$(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 | ||
16 | void FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/) | 16 | void 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 | ||
402 | void FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) | 399 | void 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 | |||
14 | int 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 | ||
55 | enum | ||
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". */ |
188 | static int prio_parse_opt(int argc, char **argv, struct nlmsghdr *n) | 202 | static int prio_parse_opt(int argc, char **argv, struct nlmsghdr *n) |
189 | { | 203 | { |
190 | return 0; | 204 | return 0; |
191 | } | 205 | } |
206 | #endif | ||
192 | static int prio_print_opt(struct rtattr *opt) | 207 | static 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 */ |
215 | static int cbq_parse_opt(int argc, char **argv, struct nlmsghdr *n) | 231 | static int cbq_parse_opt(int argc, char **argv, struct nlmsghdr *n) |
216 | { | 232 | { |
217 | return 0; | 233 | return 0; |
218 | } | 234 | } |
235 | #endif | ||
219 | static int cbq_print_opt(struct rtattr *opt) | 236 | static 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 | ||
311 | static int print_qdisc(const struct sockaddr_nl *who UNUSED_PARAM, | 328 | static 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 | ||
367 | static int print_class(const struct sockaddr_nl *who UNUSED_PARAM, | 386 | static 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 | ||
435 | static int print_filter(const struct sockaddr_nl *who UNUSED_PARAM, | 456 | static 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 |
212 | static void tftp_progress_update(void) | 212 | static 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 | ||
776 | static int tls_xread_record(tls_state_t *tls) | 780 | static 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) | |||
1137 | static int tls_xread_handshake_block(tls_state_t *tls, int min_len) | 1144 | static 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 | ||
1716 | void FAST_FUNC tls_run_copy_loop(tls_state_t *tls) | 1730 | void 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 | |||
94 | config UDHCPC_DEFAULT_SCRIPT | 94 | config 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 { | |||
133 | struct client6_data_t { | 133 | struct 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 */ |
48 | struct 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 | ||
256 | int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 256 | int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
257 | int dhcprelay_main(int argc, char **argv) | 257 | int 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 { | |||
176 | static const char P_FTP[] ALIGN1 = "ftp"; | 177 | static const char P_FTP[] ALIGN1 = "ftp"; |
177 | static const char P_HTTP[] ALIGN1 = "http"; | 178 | static const char P_HTTP[] ALIGN1 = "http"; |
178 | #if SSL_SUPPORTED | 179 | #if SSL_SUPPORTED |
180 | # if ENABLE_FEATURE_WGET_HTTPS | ||
181 | static const char P_FTPS[] ALIGN1 = "ftps"; | ||
182 | # endif | ||
179 | static const char P_HTTPS[] ALIGN1 = "https"; | 183 | static 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 | ||
351 | static 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 |
361 | static void alarm_handler(int sig UNUSED_PARAM) | 356 | static 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 | */ | ||
424 | static 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' */ |
423 | static char fgets_and_trim(FILE *fp, const char *fmt) | 440 | static 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 | ||
559 | static char *gethdr(FILE *fp) | 589 | static 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 | ||
611 | static 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 |
693 | static int spawn_https_helper_openssl(const char *host, unsigned port) | 642 | static 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 |
768 | static void spawn_ssl_client(const char *host, int network_fd) | 717 | static 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 | ||
768 | static 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 | |||
817 | static void NOINLINE retrieve_file_data(FILE *dfp) | 863 | static 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); |