aboutsummaryrefslogtreecommitdiff
path: root/networking
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--networking/Config.src30
-rw-r--r--networking/ftpgetput.c6
-rw-r--r--networking/hostname.c4
-rw-r--r--networking/httpd.c299
-rw-r--r--networking/libiproute/iproute.c16
-rw-r--r--networking/nc.c12
-rw-r--r--networking/ntpd.c6
-rw-r--r--networking/ssl_client.c21
-rw-r--r--networking/telnetd.c4
-rw-r--r--networking/tftp.c2
-rw-r--r--networking/tls.c771
-rw-r--r--networking/tls.h7
-rw-r--r--networking/tls_aesgcm.c5
-rw-r--r--networking/udhcp/d6_dhcpc.c193
-rw-r--r--networking/udhcp/d6_packet.c16
-rw-r--r--networking/udhcp/dhcpd.c58
-rw-r--r--networking/wget.c53
17 files changed, 1210 insertions, 293 deletions
diff --git a/networking/Config.src b/networking/Config.src
index 0942645c3..aa0806a18 100644
--- a/networking/Config.src
+++ b/networking/Config.src
@@ -72,9 +72,28 @@ config FEATURE_HWIB
72 help 72 help
73 Support for printing infiniband addresses in network applets. 73 Support for printing infiniband addresses in network applets.
74 74
75choice
76 prompt "TLS implementation"
77 default FEATURE_TLS_INTERNAL
78
79config FEATURE_TLS_INTERNAL
80 bool "Internal"
81 depends on TLS
82 help
83 Use the BusyBox default internal TLS implementation.
84
85config FEATURE_TLS_SCHANNEL
86 bool "Schannel SSP"
87 depends on TLS && PLATFORM_MINGW32
88 help
89 Use the Schannel SSP to provide TLS support.
90 Reduces code size and enables certificate checking.
91
92endchoice
93
75config FEATURE_TLS_SHA1 94config FEATURE_TLS_SHA1
76 bool "In TLS code, support ciphers which use deprecated SHA1" 95 bool "In TLS code, support ciphers which use deprecated SHA1"
77 depends on TLS 96 depends on FEATURE_TLS_INTERNAL
78 default n 97 default n
79 help 98 help
80 Selecting this option increases interoperability with very old 99 Selecting this option increases interoperability with very old
@@ -83,6 +102,15 @@ config FEATURE_TLS_SHA1
83 Most TLS servers support SHA256 today (2018), since SHA1 is 102 Most TLS servers support SHA256 today (2018), since SHA1 is
84 considered possibly insecure (although not yet definitely broken). 103 considered possibly insecure (although not yet definitely broken).
85 104
105config FEATURE_TLS_SCHANNEL_1_3
106 bool "Enable TLS 1.3 support for Schannel"
107 depends on FEATURE_TLS_SCHANNEL
108 default n
109 help
110 Enable TLS 1.3 support for Schannel.
111 This only works on Windows 11/Server 2022
112 and up.
113
86INSERT 114INSERT
87 115
88source networking/udhcp/Config.in 116source networking/udhcp/Config.in
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c
index 1172850ce..86342769b 100644
--- a/networking/ftpgetput.c
+++ b/networking/ftpgetput.c
@@ -106,6 +106,9 @@ static int ftpcmd(const char *s1, const char *s2)
106 fprintf(control_stream, (s2 ? "%s %s\r\n" : "%s %s\r\n"+3), 106 fprintf(control_stream, (s2 ? "%s %s\r\n" : "%s %s\r\n"+3),
107 s1, s2); 107 s1, s2);
108 fflush(control_stream); 108 fflush(control_stream);
109#if ENABLE_PLATFORM_MINGW32
110 fseek(control_stream, 0L, SEEK_CUR);
111#endif
109 } 112 }
110 113
111 do { 114 do {
@@ -114,6 +117,9 @@ static int ftpcmd(const char *s1, const char *s2)
114 ftp_die(NULL); 117 ftp_die(NULL);
115 } 118 }
116 } while (!isdigit(buf[0]) || buf[3] != ' '); 119 } while (!isdigit(buf[0]) || buf[3] != ' ');
120#if ENABLE_PLATFORM_MINGW32
121 fseek(control_stream, 0L, SEEK_CUR);
122#endif
117 123
118 buf[3] = '\0'; 124 buf[3] = '\0';
119 n = xatou(buf); 125 n = xatou(buf);
diff --git a/networking/hostname.c b/networking/hostname.c
index 36cb70866..101b89e77 100644
--- a/networking/hostname.c
+++ b/networking/hostname.c
@@ -25,8 +25,8 @@
25//applet:IF_DNSDOMAINNAME(APPLET_NOEXEC(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname)) 25//applet:IF_DNSDOMAINNAME(APPLET_NOEXEC(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname))
26//applet:IF_HOSTNAME( APPLET_NOEXEC(hostname, hostname, BB_DIR_BIN, BB_SUID_DROP, hostname )) 26//applet:IF_HOSTNAME( APPLET_NOEXEC(hostname, hostname, BB_DIR_BIN, BB_SUID_DROP, hostname ))
27 27
28//kbuild: lib-$(CONFIG_HOSTNAME) += hostname.o 28//kbuild:lib-$(CONFIG_HOSTNAME) += hostname.o
29//kbuild: lib-$(CONFIG_DNSDOMAINNAME) += hostname.o 29//kbuild:lib-$(CONFIG_DNSDOMAINNAME) += hostname.o
30 30
31//usage:#define hostname_trivial_usage 31//usage:#define hostname_trivial_usage
32//usage: "[-sidf] [HOSTNAME | -F FILE]" 32//usage: "[-sidf] [HOSTNAME | -F FILE]"
diff --git a/networking/httpd.c b/networking/httpd.c
index ddcb03bca..50595104c 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -264,7 +264,12 @@
264//kbuild:lib-$(CONFIG_HTTPD) += httpd.o 264//kbuild:lib-$(CONFIG_HTTPD) += httpd.o
265 265
266//usage:#define httpd_trivial_usage 266//usage:#define httpd_trivial_usage
267//usage: IF_NOT_PLATFORM_MINGW32(
267//usage: "[-ifv[v]]" 268//usage: "[-ifv[v]]"
269//usage: )
270//usage: IF_PLATFORM_MINGW32(
271//usage: "[-fv[v]]"
272//usage: )
268//usage: " [-c CONFFILE]" 273//usage: " [-c CONFFILE]"
269//usage: " [-p [IP:]PORT]" 274//usage: " [-p [IP:]PORT]"
270//usage: IF_FEATURE_HTTPD_SETUID(" [-u USER[:GRP]]") 275//usage: IF_FEATURE_HTTPD_SETUID(" [-u USER[:GRP]]")
@@ -273,7 +278,9 @@
273//usage: "or httpd -d/-e" IF_FEATURE_HTTPD_AUTH_MD5("/-m") " STRING" 278//usage: "or httpd -d/-e" IF_FEATURE_HTTPD_AUTH_MD5("/-m") " STRING"
274//usage:#define httpd_full_usage "\n\n" 279//usage:#define httpd_full_usage "\n\n"
275//usage: "Listen for incoming HTTP requests\n" 280//usage: "Listen for incoming HTTP requests\n"
281//usage: IF_NOT_PLATFORM_MINGW32(
276//usage: "\n -i Inetd mode" 282//usage: "\n -i Inetd mode"
283//usage: )
277//usage: "\n -f Run in foreground" 284//usage: "\n -f Run in foreground"
278//usage: "\n -v[v] Verbose" 285//usage: "\n -v[v] Verbose"
279//usage: "\n -p [IP:]PORT Bind to IP:PORT (default *:"STR(CONFIG_FEATURE_HTTPD_PORT_DEFAULT)")" 286//usage: "\n -p [IP:]PORT Bind to IP:PORT (default *:"STR(CONFIG_FEATURE_HTTPD_PORT_DEFAULT)")"
@@ -292,6 +299,9 @@
292 299
293#include "libbb.h" 300#include "libbb.h"
294#include "common_bufsiz.h" 301#include "common_bufsiz.h"
302#if ENABLE_PLATFORM_MINGW32
303# include "BB_VER.h"
304#endif
295#if ENABLE_PAM 305#if ENABLE_PAM
296/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */ 306/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */
297# undef setlocale 307# undef setlocale
@@ -322,6 +332,8 @@
322 332
323#define HEADER_READ_TIMEOUT 60 333#define HEADER_READ_TIMEOUT 60
324 334
335static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN;
336
325#define STR1(s) #s 337#define STR1(s) #s
326#define STR(s) STR1(s) 338#define STR(s) STR1(s)
327 339
@@ -452,6 +464,13 @@ static const struct {
452 464
453struct globals { 465struct globals {
454 int verbose; /* must be int (used by getopt32) */ 466 int verbose; /* must be int (used by getopt32) */
467#if ENABLE_PLATFORM_MINGW32
468 smallint foreground;
469# if ENABLE_FEATURE_HTTPD_CGI
470 int server_argc;
471 char **server_argv;
472# endif
473#endif
455 smallint flg_deny_all; 474 smallint flg_deny_all;
456#if ENABLE_FEATURE_HTTPD_GZIP 475#if ENABLE_FEATURE_HTTPD_GZIP
457 /* client can handle gzip / we are going to send gzip */ 476 /* client can handle gzip / we are going to send gzip */
@@ -509,6 +528,11 @@ struct globals {
509}; 528};
510#define G (*ptr_to_globals) 529#define G (*ptr_to_globals)
511#define verbose (G.verbose ) 530#define verbose (G.verbose )
531#if ENABLE_PLATFORM_MINGW32
532#define foreground (G.foreground )
533#define server_argc (G.server_argc )
534#define server_argv (G.server_argv )
535#endif
512#define flg_deny_all (G.flg_deny_all ) 536#define flg_deny_all (G.flg_deny_all )
513#if ENABLE_FEATURE_HTTPD_GZIP 537#if ENABLE_FEATURE_HTTPD_GZIP
514# define content_gzip (G.content_gzip ) 538# define content_gzip (G.content_gzip )
@@ -557,7 +581,12 @@ enum {
557} while (0) 581} while (0)
558 582
559 583
584#if !ENABLE_PLATFORM_MINGW32
560#define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1) 585#define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1)
586#else
587/* Not exactly equivalent to strncasecmp(), but OK for its use here */
588#define STRNCASECMP(a, str) (!is_prefixed_with_case((a), (str)))
589#endif
561 590
562/* Prototypes */ 591/* Prototypes */
563enum { 592enum {
@@ -721,8 +750,16 @@ static int parse_conf(const char *path, int flag)
721 750
722 filename = opt_c_configFile; 751 filename = opt_c_configFile;
723 if (flag == SUBDIR_PARSE || filename == NULL) { 752 if (flag == SUBDIR_PARSE || filename == NULL) {
753#if !ENABLE_PLATFORM_MINGW32
724 filename = alloca(strlen(path) + sizeof(HTTPD_CONF) + 2); 754 filename = alloca(strlen(path) + sizeof(HTTPD_CONF) + 2);
725 sprintf((char *)filename, "%s/%s", path, HTTPD_CONF); 755 sprintf((char *)filename, "%s/%s", path, HTTPD_CONF);
756#else
757 const char *sd = "";
758 if (root_len(path) == 0 && (path[0] == '/' || path[0] == '\\'))
759 sd = get_system_drive();
760
761 filename = auto_string(xasprintf("%s%s/%s", sd, path, HTTPD_CONF));
762#endif
726 } 763 }
727 764
728 while ((f = fopen_for_read(filename)) == NULL) { 765 while ((f = fopen_for_read(filename)) == NULL) {
@@ -771,6 +808,7 @@ static int parse_conf(const char *path, int flag)
771 * without needless copying, therefore we don't merge 808 * without needless copying, therefore we don't merge
772 * this operation into next while loop. */ 809 * this operation into next while loop. */
773 while ((ch = *p0) != '\0' && ch != '\n' && ch != '#' 810 while ((ch = *p0) != '\0' && ch != '\n' && ch != '#'
811 IF_PLATFORM_MINGW32(&& ch != '\r')
774 && ch != ' ' && ch != '\t' 812 && ch != ' ' && ch != '\t'
775 ) { 813 ) {
776 p0++; 814 p0++;
@@ -778,7 +816,11 @@ static int parse_conf(const char *path, int flag)
778 p = p0; 816 p = p0;
779 /* if we enter this loop, we have some whitespace. 817 /* if we enter this loop, we have some whitespace.
780 * discard it */ 818 * discard it */
819#if !ENABLE_PLATFORM_MINGW32
781 while (ch != '\0' && ch != '\n' && ch != '#') { 820 while (ch != '\0' && ch != '\n' && ch != '#') {
821#else
822 while (ch != '\0' && ch != '\n' && ch != '\r' && ch != '#') {
823#endif
782 if (ch != ' ' && ch != '\t') { 824 if (ch != ' ' && ch != '\t') {
783 *p++ = ch; 825 *p++ = ch;
784 } 826 }
@@ -1311,7 +1353,21 @@ static unsigned get_line(void)
1311 count = 0; 1353 count = 0;
1312 while (1) { 1354 while (1) {
1313 if (hdr_cnt <= 0) { 1355 if (hdr_cnt <= 0) {
1356#if ENABLE_PLATFORM_MINGW32
1357 int nfds = 1;
1358 struct pollfd fds = {STDIN_FILENO, POLLIN, 0};
1359
1360 switch (poll(&fds, nfds, HEADER_READ_TIMEOUT*1000)) {
1361 case 0:
1362 send_REQUEST_TIMEOUT_and_exit(0);
1363 break;
1364 case -1:
1365 bb_simple_perror_msg_and_die("poll");
1366 break;
1367 }
1368#else
1314 alarm(HEADER_READ_TIMEOUT); 1369 alarm(HEADER_READ_TIMEOUT);
1370#endif
1315 hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf); 1371 hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf);
1316 if (hdr_cnt <= 0) 1372 if (hdr_cnt <= 0)
1317 goto ret; 1373 goto ret;
@@ -1523,6 +1579,47 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
1523#endif 1579#endif
1524 1580
1525#if ENABLE_FEATURE_HTTPD_CGI 1581#if ENABLE_FEATURE_HTTPD_CGI
1582# if ENABLE_PLATFORM_MINGW32
1583static void cgi_handler(char **argv)
1584{
1585 struct fd_pair fromCgi; /* CGI -> httpd pipe */
1586 struct fd_pair toCgi; /* httpd -> CGI pipe */
1587
1588 xfunc_error_retval = 242;
1589
1590 if (sscanf(argv[0], "%d:%d:%d:%d", &toCgi.wr, &toCgi.rd,
1591 &fromCgi.wr, &fromCgi.rd) != 4) {
1592 exit(242);
1593 }
1594
1595 /* NB: close _first_, then move fds! */
1596 close(toCgi.wr);
1597 close(fromCgi.rd);
1598 xmove_fd(toCgi.rd, 0); /* replace stdin with the pipe */
1599 xmove_fd(fromCgi.wr, 1); /* replace stdout with the pipe */
1600
1601 if (argv[1][0] && chdir_or_warn(argv[1]) != 0) {
1602 goto error_execing_cgi;
1603 }
1604
1605 /* set argv[0] to name without path */
1606 argv += 2;
1607
1608 /* _NOT_ execvp. We do not search PATH. argv[0] is a filename
1609 * without any dir components and will only match a file
1610 * in the current directory */
1611 if (foreground)
1612 execv(argv[0], argv);
1613 else
1614 httpd_execv_detach(argv[0], argv);
1615 if (verbose)
1616 bb_perror_msg("can't execute '%s'", argv[0]);
1617 error_execing_cgi:
1618 /* send to stdout */
1619 iobuf = xmalloc(IOBUF_SIZE);
1620 send_headers_and_exit(HTTP_NOT_FOUND);
1621}
1622# endif
1526 1623
1527static void setenv1(const char *name, const char *value) 1624static void setenv1(const char *name, const char *value)
1528{ 1625{
@@ -1556,6 +1653,10 @@ static void send_cgi_and_exit(
1556 struct fd_pair toCgi; /* httpd -> CGI pipe */ 1653 struct fd_pair toCgi; /* httpd -> CGI pipe */
1557 char *script, *last_slash; 1654 char *script, *last_slash;
1558 int pid; 1655 int pid;
1656#if ENABLE_PLATFORM_MINGW32
1657 const char *script_dir;
1658 char **argv;
1659#endif
1559 1660
1560 /* Make a copy. NB: caller guarantees: 1661 /* Make a copy. NB: caller guarantees:
1561 * url[0] == '/', url[1] != '/' */ 1662 * url[0] == '/', url[1] != '/' */
@@ -1592,7 +1693,11 @@ static void send_cgi_and_exit(
1592 *script = '\0'; /* cut off /PATH_INFO */ 1693 *script = '\0'; /* cut off /PATH_INFO */
1593 1694
1594 /* SCRIPT_FILENAME is required by PHP in CGI mode */ 1695 /* SCRIPT_FILENAME is required by PHP in CGI mode */
1696#if ENABLE_PLATFORM_MINGW32
1697 if (!is_relative_path(home_httpd)) {
1698#else
1595 if (home_httpd[0] == '/') { 1699 if (home_httpd[0] == '/') {
1700#endif
1596 char *fullpath = concat_path_file(home_httpd, url); 1701 char *fullpath = concat_path_file(home_httpd, url);
1597 setenv1("SCRIPT_FILENAME", fullpath); 1702 setenv1("SCRIPT_FILENAME", fullpath);
1598 } 1703 }
@@ -1642,6 +1747,50 @@ static void send_cgi_and_exit(
1642 xpiped_pair(fromCgi); 1747 xpiped_pair(fromCgi);
1643 xpiped_pair(toCgi); 1748 xpiped_pair(toCgi);
1644 1749
1750#if ENABLE_PLATFORM_MINGW32
1751 /* Find script's dir */
1752 script_dir = "";
1753 script = last_slash;
1754 if (script != url) { /* paranoia */
1755 *script = '\0';
1756 script_dir = url + 1;
1757 }
1758 script++;
1759
1760 argv = xzalloc((server_argc + 9) * sizeof(char *));
1761 argv[0] = (char *)bb_busybox_exec_path;
1762 argv[1] = (char *)"--busybox";
1763 argv[2] = (char *)"-httpd"; // don't daemonise in main()
1764 argv[3] = (char *)"-I0";
1765 memcpy(argv + 4, server_argv, sizeof(*argv) * server_argc);
1766 argv[server_argc + 4] = xasprintf("%d:%d:%d:%d", toCgi.wr, toCgi.rd,
1767 fromCgi.wr, fromCgi.rd);
1768 argv[server_argc + 5] = (char *)script_dir; // script directory
1769 argv[server_argc + 6] = (char *)script; // script name
1770
1771#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
1772 {
1773 char *suffix = strrchr(script, '.');
1774
1775 if (suffix) {
1776 Htaccess *cur;
1777 for (cur = script_i; cur; cur = cur->next) {
1778 if (strcmp(cur->before_colon + 1, suffix) == 0) {
1779 /* found interpreter name */
1780 argv[server_argc + 6] = (char *)cur->after_colon;
1781 argv[server_argc + 7] = (char *)script;
1782 break;
1783 }
1784 }
1785 }
1786 }
1787#endif
1788 /* argv[server_argc + N] = NULL; - xzalloc did it */
1789
1790 pid = foreground ? mingw_spawn(argv) : mingw_spawn_detach(argv);
1791 if (pid == -1)
1792 log_and_exit();
1793#else
1645 pid = vfork(); 1794 pid = vfork();
1646 if (pid < 0) { 1795 if (pid < 0) {
1647 /* TODO: log perror? */ 1796 /* TODO: log perror? */
@@ -1719,6 +1868,7 @@ static void send_cgi_and_exit(
1719 1868
1720 /* Restore variables possibly changed by child */ 1869 /* Restore variables possibly changed by child */
1721 xfunc_error_retval = 0; 1870 xfunc_error_retval = 0;
1871#endif
1722 1872
1723 /* Pump data */ 1873 /* Pump data */
1724 close(fromCgi.wr); 1874 close(fromCgi.wr);
@@ -1770,7 +1920,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
1770 } 1920 }
1771#if ENABLE_FEATURE_HTTPD_ETAG 1921#if ENABLE_FEATURE_HTTPD_ETAG
1772 /* ETag is "hex(last_mod)-hex(file_size)" e.g. "5e132e20-417" */ 1922 /* ETag is "hex(last_mod)-hex(file_size)" e.g. "5e132e20-417" */
1773 sprintf(G.etag, "\"%llx-%llx\"", (unsigned long long)last_mod, (unsigned long long)file_size); 1923 sprintf(G.etag, "\"%"LL_FMT"x-%"LL_FMT"x\"", (unsigned long long)last_mod, (unsigned long long)file_size);
1774 1924
1775 if (G.if_none_match) { 1925 if (G.if_none_match) {
1776 dbg("If-None-Match:'%s' file's ETag:'%s'\n", G.if_none_match, G.etag); 1926 dbg("If-None-Match:'%s' file's ETag:'%s'\n", G.if_none_match, G.etag);
@@ -2025,7 +2175,11 @@ static int check_user_passwd(const char *path, char *user_and_passwd)
2025 2175
2026 /* WHY? */ 2176 /* WHY? */
2027 /* If already saw a match, don't accept other different matches */ 2177 /* If already saw a match, don't accept other different matches */
2178#if !ENABLE_PLATFORM_MINGW32
2028 if (prev && strcmp(prev, dir_prefix) != 0) 2179 if (prev && strcmp(prev, dir_prefix) != 0)
2180#else
2181 if (prev && strcasecmp(prev, dir_prefix) != 0)
2182#endif
2029 continue; 2183 continue;
2030 2184
2031 dbg("checkPerm: '%s' ? '%s'\n", dir_prefix, user_and_passwd); 2185 dbg("checkPerm: '%s' ? '%s'\n", dir_prefix, user_and_passwd);
@@ -2033,7 +2187,11 @@ static int check_user_passwd(const char *path, char *user_and_passwd)
2033 /* If it's not a prefix match, continue searching */ 2187 /* If it's not a prefix match, continue searching */
2034 len = strlen(dir_prefix); 2188 len = strlen(dir_prefix);
2035 if (len != 1 /* dir_prefix "/" matches all, don't need to check */ 2189 if (len != 1 /* dir_prefix "/" matches all, don't need to check */
2190#if !ENABLE_PLATFORM_MINGW32
2036 && (strncmp(dir_prefix, path, len) != 0 2191 && (strncmp(dir_prefix, path, len) != 0
2192#else
2193 && (strncasecmp(dir_prefix, path, len) != 0
2194#endif
2037 || (path[len] != '/' && path[len] != '\0') 2195 || (path[len] != '/' && path[len] != '\0')
2038 ) 2196 )
2039 ) { 2197 ) {
@@ -2055,6 +2213,7 @@ static int check_user_passwd(const char *path, char *user_and_passwd)
2055 goto bad_input; 2213 goto bad_input;
2056 2214
2057 /* compare "user:" */ 2215 /* compare "user:" */
2216# if !ENABLE_PLATFORM_MINGW32
2058 if (cur->after_colon[0] != '*' 2217 if (cur->after_colon[0] != '*'
2059 && strncmp(cur->after_colon, user_and_passwd, 2218 && strncmp(cur->after_colon, user_and_passwd,
2060 colon_after_user - user_and_passwd + 1) != 0 2219 colon_after_user - user_and_passwd + 1) != 0
@@ -2062,11 +2221,20 @@ static int check_user_passwd(const char *path, char *user_and_passwd)
2062 continue; 2221 continue;
2063 } 2222 }
2064 /* this cfg entry is '*' or matches username from peer */ 2223 /* this cfg entry is '*' or matches username from peer */
2224# else
2225 if (strncmp(cur->after_colon, user_and_passwd,
2226 colon_after_user - user_and_passwd + 1) != 0
2227 ) {
2228 continue;
2229 }
2230 /* this cfg entry matches username from peer */
2231# endif
2065 2232
2066 passwd = strchr(cur->after_colon, ':'); 2233 passwd = strchr(cur->after_colon, ':');
2067 if (!passwd) 2234 if (!passwd)
2068 goto bad_input; 2235 goto bad_input;
2069 passwd++; 2236 passwd++;
2237# if !ENABLE_PLATFORM_MINGW32
2070 if (passwd[0] == '*') { 2238 if (passwd[0] == '*') {
2071# if ENABLE_PAM 2239# if ENABLE_PAM
2072 struct pam_userinfo userinfo; 2240 struct pam_userinfo userinfo;
@@ -2114,11 +2282,12 @@ static int check_user_passwd(const char *path, char *user_and_passwd)
2114 goto check_encrypted; 2282 goto check_encrypted;
2115# endif /* ENABLE_PAM */ 2283# endif /* ENABLE_PAM */
2116 } 2284 }
2285# endif /* !ENABLE_PLATFORM_MINGW32 */
2117 /* Else: passwd is from httpd.conf, it is either plaintext or encrypted */ 2286 /* Else: passwd is from httpd.conf, it is either plaintext or encrypted */
2118 2287
2119 if (passwd[0] == '$' && isdigit(passwd[1])) { 2288 if (passwd[0] == '$' && isdigit(passwd[1])) {
2120 char *encrypted; 2289 char *encrypted;
2121# if !ENABLE_PAM 2290# if !ENABLE_PAM && !ENABLE_PLATFORM_MINGW32
2122 check_encrypted: 2291 check_encrypted:
2123# endif 2292# endif
2124 /* encrypt pwd from peer and check match with local one */ 2293 /* encrypt pwd from peer and check match with local one */
@@ -2167,7 +2336,6 @@ static Htaccess_Proxy *find_proxy_entry(const char *url)
2167/* 2336/*
2168 * Handle timeouts 2337 * Handle timeouts
2169 */ 2338 */
2170static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN;
2171static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM) 2339static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM)
2172{ 2340{
2173 send_headers_and_exit(HTTP_REQUEST_TIMEOUT); 2341 send_headers_and_exit(HTTP_REQUEST_TIMEOUT);
@@ -2231,17 +2399,29 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2231 remote_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr); 2399 remote_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr);
2232 } 2400 }
2233# if ENABLE_FEATURE_IPV6 2401# if ENABLE_FEATURE_IPV6
2402# if !ENABLE_PLATFORM_MINGW32
2234 if (fromAddr->u.sa.sa_family == AF_INET6 2403 if (fromAddr->u.sa.sa_family == AF_INET6
2235 && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0 2404 && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0
2236 && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0 2405 && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0
2237 && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff) 2406 && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff)
2238 remote_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]); 2407 remote_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]);
2408# else
2409 if (fromAddr->u.sa.sa_family == AF_INET6
2410 && fromAddr->u.sin6.sin6_addr.s6_words[0] == 0
2411 && fromAddr->u.sin6.sin6_addr.s6_words[1] == 0
2412 && fromAddr->u.sin6.sin6_addr.s6_words[2] == 0
2413 && fromAddr->u.sin6.sin6_addr.s6_words[3] == 0
2414 && ntohl(*(uint32_t *)(fromAddr->u.sin6.sin6_addr.s6_words+4)) == 0xffff)
2415 remote_ip = ntohl(*(uint32_t *)(fromAddr->u.sin6.sin6_addr.s6_words+6));
2416# endif
2239# endif 2417# endif
2240 if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip); 2418 if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip);
2241#endif 2419#endif
2242 2420
2421#ifdef SIGALRM
2243 /* Install timeout handler. get_line() needs it. */ 2422 /* Install timeout handler. get_line() needs it. */
2244 signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit); 2423 signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit);
2424#endif
2245 2425
2246 if (!get_line()) { /* EOF or error or empty line */ 2426 if (!get_line()) { /* EOF or error or empty line */
2247 /* Observed Firefox to "speculatively" open 2427 /* Observed Firefox to "speculatively" open
@@ -2580,7 +2760,11 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2580 /* We are done reading headers, disable peer timeout */ 2760 /* We are done reading headers, disable peer timeout */
2581 alarm(0); 2761 alarm(0);
2582 2762
2763#if !ENABLE_PLATFORM_MINGW32
2583 if (strcmp(bb_basename(urlcopy), HTTPD_CONF) == 0) { 2764 if (strcmp(bb_basename(urlcopy), HTTPD_CONF) == 0) {
2765#else
2766 if (strcasecmp(bb_basename(urlcopy), HTTPD_CONF) == 0) {
2767#endif
2584 /* protect listing [/path]/httpd.conf or IP deny */ 2768 /* protect listing [/path]/httpd.conf or IP deny */
2585 send_headers_and_exit(HTTP_FORBIDDEN); 2769 send_headers_and_exit(HTTP_FORBIDDEN);
2586 } 2770 }
@@ -2626,12 +2810,14 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2626 ); 2810 );
2627} 2811}
2628 2812
2813
2629/* 2814/*
2630 * The main http server function. 2815 * The main http server function.
2631 * Given a socket, listen for new connections and farm out 2816 * Given a socket, listen for new connections and farm out
2632 * the processing as a [v]forked process. 2817 * the processing as a [v]forked process.
2633 * Never returns. 2818 * Never returns.
2634 */ 2819 */
2820# if !ENABLE_PLATFORM_MINGW32
2635#if BB_MMU 2821#if BB_MMU
2636static void mini_httpd(int server_socket) NORETURN; 2822static void mini_httpd(int server_socket) NORETURN;
2637static void mini_httpd(int server_socket) 2823static void mini_httpd(int server_socket)
@@ -2720,6 +2906,40 @@ static void mini_httpd_nommu(int server_socket, int argc, char **argv)
2720 /* never reached */ 2906 /* never reached */
2721} 2907}
2722#endif 2908#endif
2909#else /* ENABLE_PLATFORM_MINGW32 */
2910static void mini_httpd_win32(int sock, int argc, char **argv) NORETURN;
2911static void mini_httpd_win32(int sock, int argc, char **argv)
2912{
2913 char *argv_copy[argc + 5];
2914
2915 argv_copy[0] = (char *)bb_busybox_exec_path;
2916 argv_copy[1] = (char *)"--busybox";
2917 argv_copy[2] = (char *)"-httpd"; // don't daemonise in main()
2918 argv_copy[3] = (char *)"-I";
2919 memcpy(&argv_copy[5], &argv[1], argc * sizeof(argv[0]));
2920
2921 while (1) {
2922 int n;
2923
2924 /* Wait for connections... */
2925 n = accept(sock, NULL, NULL);
2926 if (n < 0)
2927 continue;
2928
2929 /* set the KEEPALIVE option to cull dead connections */
2930 setsockopt_keepalive(n);
2931
2932 argv_copy[4] = itoa(n);
2933 if ((foreground ?
2934 spawn(argv_copy) : mingw_spawn_detach(argv_copy)) == -1)
2935 bb_perror_msg_and_die("can't execute 'httpd'");
2936
2937 /* parent, or spawn failed */
2938 close(n);
2939 } /* while (1) */
2940 /* never reached */
2941}
2942#endif
2723 2943
2724/* 2944/*
2725 * Process a HTTP connection on stdin/out. 2945 * Process a HTTP connection on stdin/out.
@@ -2737,12 +2957,36 @@ static void mini_httpd_inetd(void)
2737 handle_incoming_and_exit(&fromAddr); 2957 handle_incoming_and_exit(&fromAddr);
2738} 2958}
2739 2959
2960#if ENABLE_PLATFORM_MINGW32
2961static void mingw_daemonize(char **argv)
2962{
2963 char **new_argv;
2964 int fd;
2965
2966 new_argv = grow_argv(argv + 1, 3);
2967 new_argv[0] = (char *)bb_busybox_exec_path;
2968 new_argv[1] = (char *)"--busybox";
2969 // don't daemonise in main(), we explicitly detach below
2970 new_argv[2] = (char *)"-httpd";
2971
2972 fd = xopen(bb_dev_null, O_RDWR);
2973 xdup2(fd, 0);
2974 xdup2(fd, 1);
2975 xdup2(fd, 2);
2976 close(fd);
2977
2978 exit(mingw_spawn_detach(new_argv) == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
2979}
2980#endif
2981
2982#if !ENABLE_PLATFORM_MINGW32
2740static void sighup_handler(int sig UNUSED_PARAM) 2983static void sighup_handler(int sig UNUSED_PARAM)
2741{ 2984{
2742 int sv = errno; 2985 int sv = errno;
2743 parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE); 2986 parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE);
2744 errno = sv; 2987 errno = sv;
2745} 2988}
2989#endif
2746 2990
2747enum { 2991enum {
2748 c_opt_config_file = 0, 2992 c_opt_config_file = 0,
@@ -2780,6 +3024,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2780 IF_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;) 3024 IF_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;)
2781 IF_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;) 3025 IF_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;)
2782 IF_FEATURE_HTTPD_AUTH_MD5(const char *pass;) 3026 IF_FEATURE_HTTPD_AUTH_MD5(const char *pass;)
3027 IF_PLATFORM_MINGW32(int fd;)
2783 3028
2784 INIT_G(); 3029 INIT_G();
2785 3030
@@ -2798,16 +3043,19 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2798 IF_FEATURE_HTTPD_BASIC_AUTH("r:") 3043 IF_FEATURE_HTTPD_BASIC_AUTH("r:")
2799 IF_FEATURE_HTTPD_AUTH_MD5("m:") 3044 IF_FEATURE_HTTPD_AUTH_MD5("m:")
2800 IF_FEATURE_HTTPD_SETUID("u:") 3045 IF_FEATURE_HTTPD_SETUID("u:")
2801 "p:ifv" 3046 IF_NOT_PLATFORM_MINGW32("p:ifv")
3047 IF_PLATFORM_MINGW32("p:I:+fv")
2802 "\0" 3048 "\0"
2803 /* -v counts, -i implies -f */ 3049 /* -v counts, -i implies -f */
2804 "vv:if", 3050 IF_NOT_PLATFORM_MINGW32("vv:if",)
3051 IF_PLATFORM_MINGW32("vv:",)
2805 &opt_c_configFile, &url_for_decode, &home_httpd 3052 &opt_c_configFile, &url_for_decode, &home_httpd
2806 IF_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode) 3053 IF_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode)
2807 IF_FEATURE_HTTPD_BASIC_AUTH(, &g_realm) 3054 IF_FEATURE_HTTPD_BASIC_AUTH(, &g_realm)
2808 IF_FEATURE_HTTPD_AUTH_MD5(, &pass) 3055 IF_FEATURE_HTTPD_AUTH_MD5(, &pass)
2809 IF_FEATURE_HTTPD_SETUID(, &s_ugid) 3056 IF_FEATURE_HTTPD_SETUID(, &s_ugid)
2810 , &bind_addr_or_port 3057 , &bind_addr_or_port
3058 IF_PLATFORM_MINGW32(, &fd)
2811 , &verbose 3059 , &verbose
2812 ); 3060 );
2813 if (opt & OPT_DECODE_URL) { 3061 if (opt & OPT_DECODE_URL) {
@@ -2826,7 +3074,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2826 salt[0] = '$'; 3074 salt[0] = '$';
2827 salt[1] = '1'; 3075 salt[1] = '1';
2828 salt[2] = '$'; 3076 salt[2] = '$';
2829 crypt_make_salt(salt + 3, 4); 3077 crypt_make_rand64encoded(salt + 3, 8 / 2); /* 8 chars */
2830 puts(pw_encrypt(pass, salt, /*cleanup:*/ 0)); 3078 puts(pw_encrypt(pass, salt, /*cleanup:*/ 0));
2831 return 0; 3079 return 0;
2832 } 3080 }
@@ -2837,20 +3085,33 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2837 } 3085 }
2838#endif 3086#endif
2839 3087
3088#if !ENABLE_PLATFORM_MINGW32
2840#if !BB_MMU 3089#if !BB_MMU
2841 if (!(opt & OPT_FOREGROUND)) { 3090 if (!(opt & OPT_FOREGROUND)) {
2842 bb_daemonize_or_rexec(0, argv); /* don't change current directory */ 3091 bb_daemonize_or_rexec(0, argv); /* don't change current directory */
2843 re_execed = 0; /* for the following chdir to work */ 3092 re_execed = 0; /* for the following chdir to work */
2844 } 3093 }
2845#endif 3094#endif
3095#else /* ENABLE_PLATFORM_MINGW32 */
3096 foreground = (opt & OPT_FOREGROUND) == OPT_FOREGROUND;
3097 if (!foreground && argv[0][0] != '-')
3098 mingw_daemonize(argv);
3099#endif
3100
2846 /* Chdir to home (unless we were re_exec()ed for NOMMU case 3101 /* Chdir to home (unless we were re_exec()ed for NOMMU case
2847 * in mini_httpd_nommu(): we are already in the home dir then). 3102 * in mini_httpd_nommu(): we are already in the home dir then).
2848 */ 3103 */
3104#if ENABLE_PLATFORM_MINGW32
3105 if (!(opt & OPT_INETD))
3106#else
2849 if (!re_execed) 3107 if (!re_execed)
3108#endif
2850 xchdir(home_httpd); 3109 xchdir(home_httpd);
2851 3110
2852 if (!(opt & OPT_INETD)) { 3111 if (!(opt & OPT_INETD)) {
3112#ifdef SIGCHLD
2853 signal(SIGCHLD, SIG_IGN); 3113 signal(SIGCHLD, SIG_IGN);
3114#endif
2854 server_socket = openServer(); 3115 server_socket = openServer();
2855#if ENABLE_FEATURE_HTTPD_SETUID 3116#if ENABLE_FEATURE_HTTPD_SETUID
2856 /* drop privileges */ 3117 /* drop privileges */
@@ -2884,12 +3145,35 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2884#endif 3145#endif
2885 3146
2886 parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE); 3147 parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE);
3148#if ENABLE_PLATFORM_MINGW32
3149# if ENABLE_FEATURE_HTTPD_CGI
3150 if ((opt & OPT_INETD) && fd == 0) {
3151 cgi_handler(argv + optind);
3152 return 0;
3153 }
3154# endif
3155#else
2887 if (!(opt & OPT_INETD)) 3156 if (!(opt & OPT_INETD))
2888 signal(SIGHUP, sighup_handler); 3157 signal(SIGHUP, sighup_handler);
3158#endif
2889 3159
2890 xfunc_error_retval = 0; 3160 xfunc_error_retval = 0;
3161#if ENABLE_PLATFORM_MINGW32
3162 if (opt & OPT_INETD) {
3163 xmove_fd(fd, 0);
3164 xdup2(0, 1);
3165 while (--fd > 2)
3166 close(fd);
3167# if ENABLE_FEATURE_HTTPD_CGI
3168 /* Skip 'httpd -I N' and omit any non-option arguments */
3169 server_argc = optind - 3;
3170 server_argv = argv + 3;
3171# endif
3172 }
3173#endif
2891 if (opt & OPT_INETD) 3174 if (opt & OPT_INETD)
2892 mini_httpd_inetd(); /* never returns */ 3175 mini_httpd_inetd(); /* never returns */
3176#if !ENABLE_PLATFORM_MINGW32
2893#if BB_MMU 3177#if BB_MMU
2894 if (!(opt & OPT_FOREGROUND)) 3178 if (!(opt & OPT_FOREGROUND))
2895 bb_daemonize(0); /* don't change current directory */ 3179 bb_daemonize(0); /* don't change current directory */
@@ -2897,5 +3181,8 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2897#else 3181#else
2898 mini_httpd_nommu(server_socket, argc, argv); /* never returns */ 3182 mini_httpd_nommu(server_socket, argc, argv); /* never returns */
2899#endif 3183#endif
3184#else /* ENABLE_PLATFORM_MINGW32 */
3185 mini_httpd_win32(server_socket, argc, argv);
3186#endif
2900 /* return 0; */ 3187 /* return 0; */
2901} 3188}
diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c
index cd77f642f..a30f070eb 100644
--- a/networking/libiproute/iproute.c
+++ b/networking/libiproute/iproute.c
@@ -302,24 +302,22 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
302 printf("notify "); 302 printf("notify ");
303 } 303 }
304 304
305 if (r->rtm_family == AF_INET6) { 305 if (r->rtm_family == AF_INET || r->rtm_family == AF_INET6) {
306 struct rta_cacheinfo *ci = NULL; 306 if (r->rtm_family == AF_INET) {
307 if (tb[RTA_CACHEINFO]) {
308 ci = RTA_DATA(tb[RTA_CACHEINFO]);
309 }
310 if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
311 if (r->rtm_flags & RTM_F_CLONED) { 307 if (r->rtm_flags & RTM_F_CLONED) {
312 printf("%c cache ", _SL_); 308 printf("%c cache ", _SL_);
309 /* upstream: print_cache_flags() prints more here */
313 } 310 }
311 }
312 if (tb[RTA_CACHEINFO]) {
313 struct rta_cacheinfo *ci = RTA_DATA(tb[RTA_CACHEINFO]);
314 if (ci->rta_expires) { 314 if (ci->rta_expires) {
315 printf(" expires %dsec", ci->rta_expires / get_hz()); 315 printf(" expires %dsec", ci->rta_expires / get_hz());
316 } 316 }
317 if (ci->rta_error != 0) { 317 if (ci->rta_error != 0) {
318 printf(" error %d", ci->rta_error); 318 printf(" error %d", ci->rta_error);
319 } 319 }
320 } else if (ci) { 320 /* upstream: print_rta_cacheinfo() prints more here */
321 if (ci->rta_error != 0)
322 printf(" error %d", ci->rta_error);
323 } 321 }
324 } 322 }
325 if (tb[RTA_IIF] && G_filter.iif == 0) { 323 if (tb[RTA_IIF] && G_filter.iif == 0) {
diff --git a/networking/nc.c b/networking/nc.c
index ab1316339..ee008595d 100644
--- a/networking/nc.c
+++ b/networking/nc.c
@@ -30,7 +30,7 @@
30//config:config NC_EXTRA 30//config:config NC_EXTRA
31//config: bool "Netcat extensions (-eiw and -f FILE)" 31//config: bool "Netcat extensions (-eiw and -f FILE)"
32//config: default y 32//config: default y
33//config: depends on NC || NETCAT 33//config: depends on (NC || NETCAT) && PLATFORM_POSIX
34//config: help 34//config: help
35//config: Add -e (support for executing the rest of the command line after 35//config: Add -e (support for executing the rest of the command line after
36//config: making or receiving a successful connection), -i (delay interval for 36//config: making or receiving a successful connection), -i (delay interval for
@@ -110,10 +110,12 @@
110 * when compared to "standard" nc 110 * when compared to "standard" nc
111 */ 111 */
112 112
113#if !ENABLE_PLATFORM_MINGW32
113static void timeout(int signum UNUSED_PARAM) 114static void timeout(int signum UNUSED_PARAM)
114{ 115{
115 bb_simple_error_msg_and_die("timed out"); 116 bb_simple_error_msg_and_die("timed out");
116} 117}
118#endif
117 119
118int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 120int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
119int nc_main(int argc, char **argv) 121int nc_main(int argc, char **argv)
@@ -123,7 +125,9 @@ int nc_main(int argc, char **argv)
123 int cfd = 0; 125 int cfd = 0;
124 unsigned lport = 0; 126 unsigned lport = 0;
125 IF_NOT_NC_SERVER(const) unsigned do_listen = 0; 127 IF_NOT_NC_SERVER(const) unsigned do_listen = 0;
128#if !ENABLE_PLATFORM_MINGW32
126 IF_NOT_NC_EXTRA (const) unsigned wsecs = 0; 129 IF_NOT_NC_EXTRA (const) unsigned wsecs = 0;
130#endif
127 IF_NOT_NC_EXTRA (const) unsigned delay = 0; 131 IF_NOT_NC_EXTRA (const) unsigned delay = 0;
128 IF_NOT_NC_EXTRA (const int execparam = 0;) 132 IF_NOT_NC_EXTRA (const int execparam = 0;)
129 IF_NC_EXTRA (char **execparam = NULL;) 133 IF_NC_EXTRA (char **execparam = NULL;)
@@ -187,10 +191,12 @@ int nc_main(int argc, char **argv)
187 argv++; 191 argv++;
188 } 192 }
189 193
194#if !ENABLE_PLATFORM_MINGW32
190 if (wsecs) { 195 if (wsecs) {
191 signal(SIGALRM, timeout); 196 signal(SIGALRM, timeout);
192 alarm(wsecs); 197 alarm(wsecs);
193 } 198 }
199#endif
194 200
195 if (!cfd) { 201 if (!cfd) {
196 if (do_listen) { 202 if (do_listen) {
@@ -208,7 +214,7 @@ int nc_main(int argc, char **argv)
208 } 214 }
209#endif 215#endif
210 close_on_exec_on(sfd); 216 close_on_exec_on(sfd);
211 accept_again: 217 IF_NOT_PLATFORM_MINGW32(accept_again:)
212 cfd = accept(sfd, NULL, 0); 218 cfd = accept(sfd, NULL, 0);
213 if (cfd < 0) 219 if (cfd < 0)
214 bb_simple_perror_msg_and_die("accept"); 220 bb_simple_perror_msg_and_die("accept");
@@ -220,6 +226,7 @@ int nc_main(int argc, char **argv)
220 } 226 }
221 } 227 }
222 228
229#if !ENABLE_PLATFORM_MINGW32
223 if (wsecs) { 230 if (wsecs) {
224 alarm(0); 231 alarm(0);
225 /* Non-ignored signals revert to SIG_DFL on exec anyway */ 232 /* Non-ignored signals revert to SIG_DFL on exec anyway */
@@ -244,6 +251,7 @@ int nc_main(int argc, char **argv)
244 IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);) 251 IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);)
245 IF_NC_EXTRA(bb_perror_msg_and_die("can't execute '%s'", execparam[0]);) 252 IF_NC_EXTRA(bb_perror_msg_and_die("can't execute '%s'", execparam[0]);)
246 } 253 }
254#endif
247 255
248 /* loop copying stdin to cfd, and cfd to stdout */ 256 /* loop copying stdin to cfd, and cfd to stdout */
249 257
diff --git a/networking/ntpd.c b/networking/ntpd.c
index dcbdb8e60..dd0a9c91f 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -205,7 +205,7 @@
205#define MINDISP 0.01 /* minimum dispersion (sec) */ 205#define MINDISP 0.01 /* minimum dispersion (sec) */
206#define MAXDISP 16 /* maximum dispersion (sec) */ 206#define MAXDISP 16 /* maximum dispersion (sec) */
207#define MAXSTRAT 16 /* maximum stratum (infinity metric) */ 207#define MAXSTRAT 16 /* maximum stratum (infinity metric) */
208#define MAXDIST 1 /* distance threshold (sec) */ 208#define MAXDIST 3 /* distance threshold (sec): do not use peers who are farther away */
209#define MIN_SELECTED 1 /* minimum intersection survivors */ 209#define MIN_SELECTED 1 /* minimum intersection survivors */
210#define MIN_CLUSTERED 3 /* minimum cluster survivors */ 210#define MIN_CLUSTERED 3 /* minimum cluster survivors */
211 211
@@ -1057,7 +1057,7 @@ step_time(double offset)
1057 } 1057 }
1058 tval = tvn.tv_sec; 1058 tval = tvn.tv_sec;
1059 strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval); 1059 strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval);
1060 bb_info_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset); 1060 bb_error_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset);
1061 //maybe? G.FREQHOLD_cnt = 0; 1061 //maybe? G.FREQHOLD_cnt = 0;
1062 1062
1063 /* Correct various fields which contain time-relative values: */ 1063 /* Correct various fields which contain time-relative values: */
@@ -1976,7 +1976,7 @@ recv_and_process_peer_pkt(peer_t *p)
1976 1976
1977 p->reachable_bits |= 1; 1977 p->reachable_bits |= 1;
1978 if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) { 1978 if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) {
1979 bb_info_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x", 1979 bb_error_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x",
1980 p->p_dotted, 1980 p->p_dotted,
1981 offset, 1981 offset,
1982 p->p_raw_delay, 1982 p->p_raw_delay,
diff --git a/networking/ssl_client.c b/networking/ssl_client.c
index 582fb0e71..757745896 100644
--- a/networking/ssl_client.c
+++ b/networking/ssl_client.c
@@ -15,7 +15,12 @@
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: IF_NOT_PLATFORM_MINGW32(
18//usage: "[-e] -s FD [-r FD] [-n SNI]" 19//usage: "[-e] -s FD [-r FD] [-n SNI]"
20//usage: )
21//usage: IF_PLATFORM_MINGW32(
22//usage: "[-e] -h handle [-n SNI]"
23//usage: )
19//usage:#define ssl_client_full_usage "" 24//usage:#define ssl_client_full_usage ""
20 25
21#include "libbb.h" 26#include "libbb.h"
@@ -26,15 +31,23 @@ int ssl_client_main(int argc UNUSED_PARAM, char **argv)
26 tls_state_t *tls; 31 tls_state_t *tls;
27 const char *sni = NULL; 32 const char *sni = NULL;
28 int opt; 33 int opt;
34#if ENABLE_PLATFORM_MINGW32
35 char *hstr = NULL;
36 HANDLE h;
37#endif
29 38
30 // INIT_G(); 39 // INIT_G();
31 40
32 tls = new_tls_state(); 41 tls = new_tls_state();
42#if !ENABLE_PLATFORM_MINGW32
33 opt = getopt32(argv, "es:+r:+n:", &tls->ofd, &tls->ifd, &sni); 43 opt = getopt32(argv, "es:+r:+n:", &tls->ofd, &tls->ifd, &sni);
34 if (!(opt & (1<<2))) { 44 if (!(opt & (1<<2))) {
35 /* -r N defaults to -s N */ 45 /* -r N defaults to -s N */
36 tls->ifd = tls->ofd; 46 tls->ifd = tls->ofd;
37 } 47 }
48#else
49 opt = getopt32(argv, "eh:n:", &hstr, &sni);
50#endif
38 51
39 if (!(opt & (3<<1))) { 52 if (!(opt & (3<<1))) {
40 if (!argv[1]) 53 if (!argv[1])
@@ -47,6 +60,14 @@ int ssl_client_main(int argc UNUSED_PARAM, char **argv)
47 sni = argv[1]; 60 sni = argv[1];
48 tls->ifd = tls->ofd = create_and_connect_stream_or_die(argv[1], 443); 61 tls->ifd = tls->ofd = create_and_connect_stream_or_die(argv[1], 443);
49 } 62 }
63#if ENABLE_PLATFORM_MINGW32
64 else {
65 if (!hstr || sscanf(hstr, "%p", &h) != 1)
66 bb_error_msg_and_die("invalid handle");
67 init_winsock();
68 tls->ifd = tls->ofd = _open_osfhandle((intptr_t)h, _O_RDWR|_O_BINARY);
69 }
70#endif
50 71
51 tls_handshake(tls, sni); 72 tls_handshake(tls, sni);
52 73
diff --git a/networking/telnetd.c b/networking/telnetd.c
index bfeea1400..a5a783047 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -104,8 +104,8 @@
104//usage:#define telnetd_full_usage "\n\n" 104//usage:#define telnetd_full_usage "\n\n"
105//usage: "Handle incoming telnet connections" 105//usage: "Handle incoming telnet connections"
106//usage: IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" 106//usage: IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n"
107//usage: "\n -l LOGIN Exec LOGIN on connect" 107//usage: "\n -l LOGIN Exec LOGIN on connect (default /bin/login)"
108//usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" 108//usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue.net"
109//usage: "\n -K Close connection as soon as login exits" 109//usage: "\n -K Close connection as soon as login exits"
110//usage: "\n (normally wait until all programs close slave pty)" 110//usage: "\n (normally wait until all programs close slave pty)"
111//usage: IF_FEATURE_TELNETD_STANDALONE( 111//usage: IF_FEATURE_TELNETD_STANDALONE(
diff --git a/networking/tftp.c b/networking/tftp.c
index f5b4367ca..b698a9288 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -250,7 +250,7 @@ static int tftp_blksize_check(const char *blksize_str, int maxsize)
250 return -1; 250 return -1;
251 } 251 }
252# if ENABLE_TFTP_DEBUG 252# if ENABLE_TFTP_DEBUG
253 bb_info_msg("using blksize %u", blksize); 253 bb_error_msg("using blksize %u", blksize);
254# endif 254# endif
255 return blksize; 255 return blksize;
256} 256}
diff --git a/networking/tls.c b/networking/tls.c
index 8d074c058..9c05364ea 100644
--- a/networking/tls.c
+++ b/networking/tls.c
@@ -10,18 +10,19 @@
10//Config.src also defines FEATURE_TLS_SHA1 option 10//Config.src also defines FEATURE_TLS_SHA1 option
11 11
12//kbuild:lib-$(CONFIG_TLS) += tls.o 12//kbuild:lib-$(CONFIG_TLS) += tls.o
13//kbuild:lib-$(CONFIG_TLS) += tls_pstm.o 13//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm.o
14//kbuild:lib-$(CONFIG_TLS) += tls_pstm_montgomery_reduce.o 14//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm_montgomery_reduce.o
15//kbuild:lib-$(CONFIG_TLS) += tls_pstm_mul_comba.o 15//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm_mul_comba.o
16//kbuild:lib-$(CONFIG_TLS) += tls_pstm_sqr_comba.o 16//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm_sqr_comba.o
17//kbuild:lib-$(CONFIG_TLS) += tls_aes.o 17//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_aes.o
18//kbuild:lib-$(CONFIG_TLS) += tls_aesgcm.o 18//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_aesgcm.o
19//kbuild:lib-$(CONFIG_TLS) += tls_rsa.o 19//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_rsa.o
20//kbuild:lib-$(CONFIG_TLS) += tls_fe.o 20//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_fe.o
21//kbuild:lib-$(CONFIG_TLS) += tls_sp_c32.o 21//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_sp_c32.o
22 22
23#include "tls.h" 23#include "tls.h"
24 24
25#if !ENABLE_FEATURE_TLS_SCHANNEL
25// Usually enabled. You can disable some of them to force only 26// Usually enabled. You can disable some of them to force only
26// specific ciphers to be advertized to server. 27// specific ciphers to be advertized to server.
27// (this would not exclude code to handle disabled ciphers, no code size win) 28// (this would not exclude code to handle disabled ciphers, no code size win)
@@ -188,8 +189,6 @@
188#define TLS_MAX_OUTBUF (1 << 14) 189#define TLS_MAX_OUTBUF (1 << 14)
189 190
190enum { 191enum {
191 SHA_INSIZE = 64,
192
193 AES128_KEYSIZE = 16, 192 AES128_KEYSIZE = 16,
194 AES256_KEYSIZE = 32, 193 AES256_KEYSIZE = 32,
195 194
@@ -331,38 +330,10 @@ static void dump_tls_record(const void *vp, int len)
331 330
332void FAST_FUNC tls_get_random(void *buf, unsigned len) 331void FAST_FUNC tls_get_random(void *buf, unsigned len)
333{ 332{
334 if (len != open_read_close("/dev/urandom", buf, len)) 333 if (len != MINGW_SPECIAL(open_read_close)("/dev/urandom", buf, len))
335 xfunc_die(); 334 xfunc_die();
336} 335}
337 336
338static void xorbuf3(void *dst, const void *src1, const void *src2, unsigned count)
339{
340 uint8_t *d = dst;
341 const uint8_t *s1 = src1;
342 const uint8_t* s2 = src2;
343 while (count--)
344 *d++ = *s1++ ^ *s2++;
345}
346
347void FAST_FUNC xorbuf(void *dst, const void *src, unsigned count)
348{
349 xorbuf3(dst, dst, src, count);
350}
351
352void FAST_FUNC xorbuf_aligned_AES_BLOCK_SIZE(void *dst, const void *src)
353{
354 unsigned long *d = dst;
355 const unsigned long *s = src;
356 d[0] ^= s[0];
357#if ULONG_MAX <= 0xffffffffffffffff
358 d[1] ^= s[1];
359 #if ULONG_MAX == 0xffffffff
360 d[2] ^= s[2];
361 d[3] ^= s[3];
362 #endif
363#endif
364}
365
366#if !TLS_DEBUG_HASH 337#if !TLS_DEBUG_HASH
367# define hash_handshake(tls, fmt, buffer, len) \ 338# define hash_handshake(tls, fmt, buffer, len) \
368 hash_handshake(tls, buffer, len) 339 hash_handshake(tls, buffer, len)
@@ -393,128 +364,6 @@ static void hash_handshake(tls_state_t *tls, const char *fmt, const void *buffer
393# define TLS_MAC_SIZE(tls) (tls)->MAC_size 364# define TLS_MAC_SIZE(tls) (tls)->MAC_size
394#endif 365#endif
395 366
396// RFC 2104:
397// HMAC(key, text) based on a hash H (say, sha256) is:
398// ipad = [0x36 x INSIZE]
399// opad = [0x5c x INSIZE]
400// HMAC(key, text) = H((key XOR opad) + H((key XOR ipad) + text))
401//
402// H(key XOR opad) and H(key XOR ipad) can be precomputed
403// if we often need HMAC hmac with the same key.
404//
405// text is often given in disjoint pieces.
406typedef struct hmac_precomputed {
407 md5sha_ctx_t hashed_key_xor_ipad;
408 md5sha_ctx_t hashed_key_xor_opad;
409} hmac_precomputed_t;
410
411typedef void md5sha_begin_func(md5sha_ctx_t *ctx) FAST_FUNC;
412#if !ENABLE_FEATURE_TLS_SHA1
413#define hmac_begin(pre,key,key_size,begin) \
414 hmac_begin(pre,key,key_size)
415#define begin sha256_begin
416#endif
417static void hmac_begin(hmac_precomputed_t *pre, uint8_t *key, unsigned key_size, md5sha_begin_func *begin)
418{
419 uint8_t key_xor_ipad[SHA_INSIZE];
420 uint8_t key_xor_opad[SHA_INSIZE];
421// uint8_t tempkey[SHA1_OUTSIZE < SHA256_OUTSIZE ? SHA256_OUTSIZE : SHA1_OUTSIZE];
422 unsigned i;
423
424 // "The authentication key can be of any length up to INSIZE, the
425 // block length of the hash function. Applications that use keys longer
426 // than INSIZE bytes will first hash the key using H and then use the
427 // resultant OUTSIZE byte string as the actual key to HMAC."
428 if (key_size > SHA_INSIZE) {
429 bb_simple_error_msg_and_die("HMAC key>64"); //does not happen (yet?)
430// md5sha_ctx_t ctx;
431// begin(&ctx);
432// md5sha_hash(&ctx, key, key_size);
433// key_size = sha_end(&ctx, tempkey);
434// //key = tempkey; - right? RIGHT? why does it work without this?
435// // because SHA_INSIZE is 64, but hmac() is always called with
436// // key_size = tls->MAC_size = SHA1/256_OUTSIZE (20 or 32),
437// // and prf_hmac_sha256() -> hmac_sha256() key sizes are:
438// // - RSA_PREMASTER_SIZE is 48
439// // - CURVE25519_KEYSIZE is 32
440// // - master_secret[] is 48
441 }
442
443 for (i = 0; i < key_size; i++) {
444 key_xor_ipad[i] = key[i] ^ 0x36;
445 key_xor_opad[i] = key[i] ^ 0x5c;
446 }
447 for (; i < SHA_INSIZE; i++) {
448 key_xor_ipad[i] = 0x36;
449 key_xor_opad[i] = 0x5c;
450 }
451
452 begin(&pre->hashed_key_xor_ipad);
453 begin(&pre->hashed_key_xor_opad);
454 md5sha_hash(&pre->hashed_key_xor_ipad, key_xor_ipad, SHA_INSIZE);
455 md5sha_hash(&pre->hashed_key_xor_opad, key_xor_opad, SHA_INSIZE);
456}
457#undef begin
458
459static unsigned hmac_sha_precomputed_v(
460 hmac_precomputed_t *pre,
461 uint8_t *out,
462 va_list va)
463{
464 uint8_t *text;
465 unsigned len;
466
467 /* pre->hashed_key_xor_ipad contains unclosed "H((key XOR ipad) +" state */
468 /* pre->hashed_key_xor_opad contains unclosed "H((key XOR opad) +" state */
469
470 /* calculate out = H((key XOR ipad) + text) */
471 while ((text = va_arg(va, uint8_t*)) != NULL) {
472 unsigned text_size = va_arg(va, unsigned);
473 md5sha_hash(&pre->hashed_key_xor_ipad, text, text_size);
474 }
475 len = sha_end(&pre->hashed_key_xor_ipad, out);
476
477 /* out = H((key XOR opad) + out) */
478 md5sha_hash(&pre->hashed_key_xor_opad, out, len);
479 return sha_end(&pre->hashed_key_xor_opad, out);
480}
481
482static unsigned hmac_sha_precomputed(hmac_precomputed_t *pre_init, uint8_t *out, ...)
483{
484 hmac_precomputed_t pre;
485 va_list va;
486 unsigned len;
487
488 va_start(va, out);
489 pre = *pre_init; /* struct copy */
490 len = hmac_sha_precomputed_v(&pre, out, va);
491 va_end(va);
492 return len;
493}
494
495#if !ENABLE_FEATURE_TLS_SHA1
496#define hmac(tls,out,key,key_size,...) \
497 hmac(out,key,key_size, __VA_ARGS__)
498#endif
499static unsigned hmac(tls_state_t *tls, uint8_t *out, uint8_t *key, unsigned key_size, ...)
500{
501 hmac_precomputed_t pre;
502 va_list va;
503 unsigned len;
504
505 va_start(va, key_size);
506
507 hmac_begin(&pre, key, key_size,
508 (ENABLE_FEATURE_TLS_SHA1 && tls->MAC_size == SHA1_OUTSIZE)
509 ? sha1_begin
510 : sha256_begin
511 );
512 len = hmac_sha_precomputed_v(&pre, out, va);
513
514 va_end(va);
515 return len;
516}
517
518// RFC 5246: 367// RFC 5246:
519// 5. HMAC and the Pseudorandom Function 368// 5. HMAC and the Pseudorandom Function
520//... 369//...
@@ -559,7 +408,7 @@ static void prf_hmac_sha256(/*tls_state_t *tls,*/
559 const char *label, 408 const char *label,
560 uint8_t *seed, unsigned seed_size) 409 uint8_t *seed, unsigned seed_size)
561{ 410{
562 hmac_precomputed_t pre; 411 hmac_ctx_t ctx;
563 uint8_t a[TLS_MAX_MAC_SIZE]; 412 uint8_t a[TLS_MAX_MAC_SIZE];
564 uint8_t *out_p = outbuf; 413 uint8_t *out_p = outbuf;
565 unsigned label_size = strlen(label); 414 unsigned label_size = strlen(label);
@@ -569,26 +418,27 @@ static void prf_hmac_sha256(/*tls_state_t *tls,*/
569#define SEED label, label_size, seed, seed_size 418#define SEED label, label_size, seed, seed_size
570#define A a, MAC_size 419#define A a, MAC_size
571 420
572 hmac_begin(&pre, secret, secret_size, sha256_begin); 421 hmac_begin(&ctx, secret, secret_size, sha256_begin_hmac);
573 422
574 /* A(1) = HMAC_hash(secret, seed) */ 423 /* A(1) = HMAC_hash(secret, seed) */
575 hmac_sha_precomputed(&pre, a, SEED, NULL); 424 hmac_peek_hash(&ctx, a, SEED, NULL);
576 425
577 for (;;) { 426 for (;;) {
578 /* HMAC_hash(secret, A(1) + seed) */ 427 /* HMAC_hash(secret, A(1) + seed) */
579 if (outbuf_size <= MAC_size) { 428 if (outbuf_size <= MAC_size) {
580 /* Last, possibly incomplete, block */ 429 /* Last, possibly incomplete, block */
581 /* (use a[] as temp buffer) */ 430 /* (use a[] as temp buffer) */
582 hmac_sha_precomputed(&pre, a, A, SEED, NULL); 431 hmac_peek_hash(&ctx, a, A, SEED, NULL);
583 memcpy(out_p, a, outbuf_size); 432 memcpy(out_p, a, outbuf_size);
433 hmac_uninit(&ctx);
584 return; 434 return;
585 } 435 }
586 /* Not last block. Store directly to result buffer */ 436 /* Not last block. Store directly to result buffer */
587 hmac_sha_precomputed(&pre, out_p, A, SEED, NULL); 437 hmac_peek_hash(&ctx, out_p, A, SEED, NULL);
588 out_p += MAC_size; 438 out_p += MAC_size;
589 outbuf_size -= MAC_size; 439 outbuf_size -= MAC_size;
590 /* A(2) = HMAC_hash(secret, A(1)) */ 440 /* A(2) = HMAC_hash(secret, A(1)) */
591 hmac_sha_precomputed(&pre, a, A, NULL); 441 hmac_peek_hash(&ctx, a, A, NULL);
592 } 442 }
593#undef A 443#undef A
594#undef SECRET 444#undef SECRET
@@ -655,6 +505,32 @@ static void *tls_get_zeroed_outbuf(tls_state_t *tls, int len)
655 return record; 505 return record;
656} 506}
657 507
508/* Calculate the HMAC over the list of blocks */
509#if !ENABLE_FEATURE_TLS_SHA1
510#define hmac_blocks(tls,out,key,key_size,...) \
511 hmac_blocks(out,key,key_size, __VA_ARGS__)
512#endif
513static unsigned hmac_blocks(tls_state_t *tls, uint8_t *out, uint8_t *key, unsigned key_size, ...)
514{
515 hmac_ctx_t ctx;
516 va_list va;
517 unsigned len;
518
519 hmac_begin(&ctx, key, key_size,
520 (ENABLE_FEATURE_TLS_SHA1 && tls->MAC_size == SHA1_OUTSIZE)
521 ? sha1_begin_hmac
522 : sha256_begin_hmac
523 );
524
525 va_start(va, key_size);
526 hmac_hash_v(&ctx, va);
527 va_end(va);
528
529 len = hmac_end(&ctx, out);
530 hmac_uninit(&ctx);
531 return len;
532}
533
658static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type) 534static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type)
659{ 535{
660 uint8_t *buf = tls->outbuf + OUTBUF_PFX; 536 uint8_t *buf = tls->outbuf + OUTBUF_PFX;
@@ -676,7 +552,7 @@ static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, un
676 xhdr->len16_lo = size & 0xff; 552 xhdr->len16_lo = size & 0xff;
677 553
678 /* Calculate MAC signature */ 554 /* Calculate MAC signature */
679 hmac(tls, buf + size, /* result */ 555 hmac_blocks(tls, buf + size, /* result */
680 tls->client_write_MAC_key, TLS_MAC_SIZE(tls), 556 tls->client_write_MAC_key, TLS_MAC_SIZE(tls),
681 &tls->write_seq64_be, sizeof(tls->write_seq64_be), 557 &tls->write_seq64_be, sizeof(tls->write_seq64_be),
682 xhdr, RECHDR_LEN, 558 xhdr, RECHDR_LEN,
@@ -865,8 +741,13 @@ static void xwrite_encrypted_aesgcm(tls_state_t *tls, unsigned size, unsigned ty
865 cnt++; 741 cnt++;
866 COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ 742 COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */
867 aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch); 743 aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch);
868 n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining; 744 if (remaining >= AES_BLOCK_SIZE) {
869 xorbuf(buf, scratch, n); 745 n = AES_BLOCK_SIZE;
746 xorbuf_AES_BLOCK_SIZE(buf, scratch);
747 } else {
748 n = remaining;
749 xorbuf(buf, scratch, n);
750 }
870 buf += n; 751 buf += n;
871 remaining -= n; 752 remaining -= n;
872 } 753 }
@@ -1024,7 +905,7 @@ static void tls_aesgcm_decrypt(tls_state_t *tls, uint8_t *buf, int size)
1024 COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ 905 COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */
1025 aes_encrypt_one_block(&tls->aes_decrypt, nonce, scratch); 906 aes_encrypt_one_block(&tls->aes_decrypt, nonce, scratch);
1026 n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining; 907 n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining;
1027 xorbuf3(buf, scratch, buf + 8, n); 908 xorbuf_3(buf, scratch, buf + 8, n);
1028 buf += n; 909 buf += n;
1029 remaining -= n; 910 remaining -= n;
1030 } 911 }
@@ -2481,3 +2362,549 @@ void FAST_FUNC tls_run_copy_loop(tls_state_t *tls, unsigned flags)
2481 } 2362 }
2482 } 2363 }
2483} 2364}
2365#else
2366
2367#if ENABLE_FEATURE_TLS_SCHANNEL_1_3
2368#include <subauth.h>
2369#endif
2370
2371#define SCHANNEL_USE_BLACKLISTS
2372
2373#include <security.h>
2374#include <schannel.h>
2375
2376
2377#define BB_SCHANNEL_ISC_FLAGS \
2378 (ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY | ISC_REQ_REPLAY_DETECT | \
2379 ISC_REQ_SEQUENCE_DETECT | ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS)
2380
2381static char *hresult_to_error_string(HRESULT result) {
2382 char *output = NULL;
2383
2384 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
2385 | FORMAT_MESSAGE_IGNORE_INSERTS |
2386 FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, result,
2387 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2388 (char *) &output, 0, NULL);
2389 return output;
2390}
2391
2392static ssize_t tls_read(struct tls_state *state, char *buf, ssize_t len) {
2393 ssize_t amount_read = 0;
2394
2395 if (state->closed) {
2396 return 0;
2397 }
2398
2399 while (len > 0) {
2400 if (state->out_buffer && (state->out_buffer_size > 0)) {
2401 unsigned long copy_amount =
2402 min(len, (ssize_t) state->out_buffer_size);
2403 memcpy(buf, state->out_buffer, copy_amount);
2404
2405 amount_read += copy_amount;
2406 buf += copy_amount;
2407 len -= copy_amount;
2408
2409 if (copy_amount == state->out_buffer_size) {
2410 // We've used all the decrypted data
2411 // Move extra data to the front
2412 memmove(state->in_buffer,
2413 state->in_buffer + state->out_buffer_used,
2414 state->in_buffer_size - state->out_buffer_used);
2415 state->in_buffer_size -= state->out_buffer_used;
2416
2417 state->out_buffer = NULL;
2418 state->out_buffer_used = 0;
2419 state->out_buffer_size = 0;
2420 } else {
2421 state->out_buffer_size -= copy_amount;
2422 state->out_buffer += copy_amount;
2423 }
2424 } else {
2425 SECURITY_STATUS status;
2426
2427 int received;
2428
2429 SecBuffer buffers[4];
2430
2431 SecBufferDesc desc;
2432
2433 buffers[0].BufferType = SECBUFFER_DATA;
2434 buffers[0].pvBuffer = state->in_buffer;
2435 buffers[0].cbBuffer = state->in_buffer_size;
2436
2437 buffers[1].BufferType = SECBUFFER_EMPTY;
2438 buffers[1].pvBuffer = NULL;
2439 buffers[1].cbBuffer = 0;
2440
2441 buffers[2].BufferType = SECBUFFER_EMPTY;
2442 buffers[2].pvBuffer = NULL;
2443 buffers[2].cbBuffer = 0;
2444
2445 buffers[3].BufferType = SECBUFFER_EMPTY;
2446 buffers[3].pvBuffer = NULL;
2447 buffers[3].cbBuffer = 0;
2448
2449 desc.ulVersion = SECBUFFER_VERSION;
2450 desc.pBuffers = buffers;
2451 desc.cBuffers = _countof(buffers);
2452
2453 status = DecryptMessage(&state->ctx_handle, &desc, 0, NULL);
2454
2455 switch (status) {
2456 case SEC_E_OK:{
2457 state->out_buffer = buffers[1].pvBuffer;
2458 state->out_buffer_size = buffers[1].cbBuffer;
2459
2460 state->out_buffer_used = state->in_buffer_size;
2461 if (buffers[3].BufferType == SECBUFFER_EXTRA) {
2462 state->out_buffer_used -= buffers[3].cbBuffer;
2463 }
2464
2465 continue;
2466 }
2467 case SEC_I_CONTEXT_EXPIRED:{
2468 state->closed = 1;
2469 goto Success;
2470 }
2471 case SEC_I_RENEGOTIATE:{
2472 // Renegotiate the TLS connection.
2473 // Microsoft repurposed this flag
2474 // for TLS 1.3 support.
2475 int i;
2476
2477 DWORD flags;
2478
2479 SecBuffer in_buffers[2];
2480
2481 SecBuffer out_buffers[2];
2482
2483 SecBufferDesc in_desc;
2484
2485 SecBufferDesc out_desc;
2486
2487
2488 for (i = 0; i < 4; i++) {
2489 if (buffers[i].BufferType == SECBUFFER_EXTRA)
2490 break;
2491 }
2492
2493 flags = BB_SCHANNEL_ISC_FLAGS;
2494
2495 in_buffers[0].BufferType = SECBUFFER_TOKEN;
2496 in_buffers[0].pvBuffer = buffers[i].pvBuffer;
2497 in_buffers[0].cbBuffer = buffers[i].cbBuffer;
2498
2499 in_buffers[1].BufferType = SECBUFFER_EMPTY;
2500 in_buffers[1].pvBuffer = NULL;
2501 in_buffers[1].cbBuffer = 0;
2502
2503 out_buffers[0].BufferType = SECBUFFER_TOKEN;
2504 out_buffers[0].pvBuffer = NULL;
2505 out_buffers[0].cbBuffer = 0;
2506
2507 out_buffers[1].BufferType = SECBUFFER_ALERT;
2508 out_buffers[1].pvBuffer = NULL;
2509 out_buffers[1].cbBuffer = 0;
2510
2511 in_desc.ulVersion = SECBUFFER_VERSION;
2512 in_desc.pBuffers = in_buffers;
2513 in_desc.cBuffers = _countof(in_buffers);
2514
2515 out_desc.ulVersion = SECBUFFER_VERSION;
2516 out_desc.pBuffers = out_buffers;
2517 out_desc.cBuffers = _countof(out_buffers);
2518
2519 status = InitializeSecurityContext(&state->cred_handle,
2520 state->initialized ?
2521 &state->ctx_handle : NULL,
2522 state->initialized ? NULL :
2523 state->hostname, flags, 0,
2524 0,
2525 state->initialized ?
2526 &in_desc : NULL, 0,
2527 state->initialized ? NULL :
2528 &state->ctx_handle,
2529 &out_desc, &flags, 0);
2530
2531 if (status != SEC_E_OK) {
2532 bb_error_msg_and_die("schannel: renegotiate failed: (0x%08lx): %s",
2533 status, hresult_to_error_string(status));
2534 }
2535
2536 if (in_buffers[1].BufferType == SECBUFFER_EXTRA) {
2537 memmove(state->in_buffer,
2538 state->in_buffer + (state->in_buffer_size -
2539 in_buffers[1].cbBuffer),
2540 in_buffers[1].cbBuffer);
2541 }
2542
2543 state->out_buffer_used =
2544 state->in_buffer_size - in_buffers[1].cbBuffer;
2545 state->in_buffer_size = in_buffers[1].cbBuffer;
2546
2547 continue;
2548 }
2549 case SEC_E_INCOMPLETE_MESSAGE:{
2550 break;
2551 }
2552 default:{
2553 bb_error_msg_and_die("schannel: DecryptMessage failed: (0x%08lx): %s", status,
2554 hresult_to_error_string(status));
2555 }
2556 }
2557
2558 received =
2559 safe_read(state->ifd,
2560 state->in_buffer + state->in_buffer_size,
2561 sizeof(state->in_buffer) - state->in_buffer_size);
2562 if (received == 0) {
2563 state->closed = 1;
2564 goto Success;
2565 } else if (received < 0) {
2566 bb_error_msg_and_die("schannel: read() failed");
2567 }
2568
2569 state->in_buffer_size += received;
2570 }
2571 }
2572
2573 Success:
2574 return amount_read;
2575}
2576
2577static void tls_write(struct tls_state *state, char *buf, size_t len) {
2578 if (state->closed) {
2579 bb_error_msg_and_die("schannel: attempted to write to a closed connection");
2580 }
2581
2582 while (len > 0) {
2583 unsigned long copy_amount =
2584 min(len, (size_t) state->stream_sizes.cbMaximumMessage);
2585 char *write_buffer = _alloca(sizeof(state->in_buffer));
2586
2587 SECURITY_STATUS status;
2588
2589 SecBuffer buffers[4];
2590
2591 SecBufferDesc desc;
2592
2593 buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
2594 buffers[0].pvBuffer = write_buffer;
2595 buffers[0].cbBuffer = state->stream_sizes.cbHeader;
2596
2597 buffers[1].BufferType = SECBUFFER_DATA;
2598 buffers[1].pvBuffer = write_buffer + state->stream_sizes.cbHeader;
2599 buffers[1].cbBuffer = copy_amount;
2600
2601 buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
2602 buffers[2].pvBuffer =
2603 write_buffer + state->stream_sizes.cbHeader + copy_amount;
2604 buffers[2].cbBuffer = state->stream_sizes.cbTrailer;
2605
2606 buffers[3].BufferType = SECBUFFER_EMPTY;
2607 buffers[3].pvBuffer = NULL;
2608 buffers[3].cbBuffer = 0;
2609
2610 memcpy(buffers[1].pvBuffer, buf, copy_amount);
2611
2612 desc.ulVersion = SECBUFFER_VERSION;
2613 desc.pBuffers = buffers;
2614 desc.cBuffers = _countof(buffers);
2615
2616 status = EncryptMessage(&state->ctx_handle, 0, &desc, 0);
2617 if (status != SEC_E_OK) {
2618 bb_error_msg_and_die("schannel: EncryptMessage failed: (0x%08lx): %s", status,
2619 hresult_to_error_string(status));
2620 }
2621
2622 xwrite(state->ofd, write_buffer,
2623 buffers[0].cbBuffer + buffers[1].cbBuffer +
2624 buffers[2].cbBuffer);
2625
2626 len -= copy_amount;
2627 }
2628}
2629
2630static void tls_disconnect(tls_state_t * state) {
2631 SECURITY_STATUS status;
2632 DWORD token = SCHANNEL_SHUTDOWN;
2633 DWORD flags = BB_SCHANNEL_ISC_FLAGS;
2634
2635 SecBuffer buf_token;
2636
2637 SecBufferDesc buf_token_desc;
2638
2639 SecBuffer in_buffers[2];
2640 SecBuffer out_buffers[2];
2641
2642 SecBufferDesc in_desc;
2643 SecBufferDesc out_desc;
2644
2645 buf_token.BufferType = SECBUFFER_TOKEN;
2646 buf_token.pvBuffer = &token;
2647 buf_token.cbBuffer = sizeof(token);
2648
2649 buf_token_desc.ulVersion = SECBUFFER_VERSION;
2650 buf_token_desc.pBuffers = &buf_token;
2651 buf_token_desc.cBuffers = 1;
2652
2653 ApplyControlToken(&state->ctx_handle, &buf_token_desc);
2654
2655 // attempt to send any final data
2656
2657 in_buffers[0].BufferType = SECBUFFER_TOKEN;
2658 in_buffers[0].pvBuffer = state->in_buffer;
2659 in_buffers[0].cbBuffer = state->in_buffer_size;
2660
2661 in_buffers[1].BufferType = SECBUFFER_EMPTY;
2662 in_buffers[1].pvBuffer = NULL;
2663 in_buffers[1].cbBuffer = 0;
2664
2665 out_buffers[0].BufferType = SECBUFFER_TOKEN;
2666 out_buffers[0].pvBuffer = NULL;
2667 out_buffers[0].cbBuffer = 0;
2668
2669 out_buffers[1].BufferType = SECBUFFER_ALERT;
2670 out_buffers[1].pvBuffer = NULL;
2671 out_buffers[1].cbBuffer = 0;
2672
2673 in_desc.ulVersion = SECBUFFER_VERSION;
2674 in_desc.pBuffers = in_buffers;
2675 in_desc.cBuffers = _countof(in_buffers);
2676
2677 out_desc.ulVersion = SECBUFFER_VERSION;
2678 out_desc.pBuffers = out_buffers;
2679 out_desc.cBuffers = _countof(out_buffers);
2680
2681 status = InitializeSecurityContext(&state->cred_handle,
2682 state->
2683 initialized ? &state->ctx_handle :
2684 NULL,
2685 state->
2686 initialized ? NULL : state->hostname,
2687 flags, 0, 0,
2688 state->initialized ? &in_desc : NULL,
2689 0,
2690 state->
2691 initialized ? NULL :
2692 &state->ctx_handle, &out_desc, &flags,
2693 0);
2694
2695 if (status == SEC_E_OK) {
2696 // attempt to write any extra data
2697 write(state->ofd, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer);
2698 }
2699
2700 DeleteSecurityContext(&state->ctx_handle);
2701 FreeCredentialsHandle(&state->cred_handle);
2702 free(state->hostname);
2703}
2704
2705
2706void FAST_FUNC tls_handshake(tls_state_t * state, const char *hostname) {
2707 SECURITY_STATUS status;
2708 int received;
2709
2710#if ENABLE_FEATURE_TLS_SCHANNEL_1_3
2711 SCH_CREDENTIALS credential = {.dwVersion = SCH_CREDENTIALS_VERSION,
2712 .dwCredFormat = 0,
2713 .cCreds = 0,
2714 .paCred = NULL,
2715 .hRootStore = NULL,
2716 .cMappers = 0,
2717 .aphMappers = NULL,
2718 .dwSessionLifespan = 0,
2719 .dwFlags =
2720 SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS |
2721 SCH_USE_STRONG_CRYPTO,
2722 .cTlsParameters = 0,
2723 .pTlsParameters = NULL
2724 };
2725#else
2726 SCHANNEL_CRED credential = {.dwVersion = SCHANNEL_CRED_VERSION,
2727 .cCreds = 0,
2728 .paCred = NULL,
2729 .hRootStore = NULL,
2730 .cMappers = 0,
2731 .aphMappers = NULL,
2732 .cSupportedAlgs = 0,
2733 .palgSupportedAlgs = NULL,
2734 .grbitEnabledProtocols =
2735 SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_1_CLIENT |
2736 SP_PROT_TLS1_2_CLIENT,
2737 .dwMinimumCipherStrength = 0,
2738 .dwMaximumCipherStrength = 0,
2739 .dwSessionLifespan = 0,
2740 .dwFlags =
2741 SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS |
2742 SCH_USE_STRONG_CRYPTO,
2743 .dwCredFormat = 0
2744 };
2745#endif
2746
2747 if ((status = AcquireCredentialsHandleA(NULL, (SEC_CHAR *) UNISP_NAME_A,
2748 SECPKG_CRED_OUTBOUND, NULL,
2749 &credential,
2750 NULL, NULL, &state->cred_handle,
2751 NULL)) != SEC_E_OK) {
2752 bb_error_msg_and_die("schannel: AcquireCredentialsHandleA failed: (0x%08lx): %s",
2753 status, hresult_to_error_string(status));
2754 }
2755
2756 state->in_buffer_size = 0;
2757 state->out_buffer_size = 0;
2758 state->out_buffer_used = 0;
2759
2760 state->out_buffer = NULL;
2761
2762 state->hostname = strdup(hostname);
2763
2764 state->initialized = 0;
2765 state->closed = 0;
2766
2767 while (1) {
2768 DWORD flags = BB_SCHANNEL_ISC_FLAGS;
2769
2770 SecBuffer in_buffers[2];
2771 SecBuffer out_buffers[2];
2772
2773 SecBufferDesc in_desc;
2774 SecBufferDesc out_desc;
2775
2776 in_buffers[0].BufferType = SECBUFFER_TOKEN;
2777 in_buffers[0].pvBuffer = state->in_buffer;
2778 in_buffers[0].cbBuffer = state->in_buffer_size;
2779
2780 in_buffers[1].BufferType = SECBUFFER_EMPTY;
2781 in_buffers[1].pvBuffer = NULL;
2782 in_buffers[1].cbBuffer = 0;
2783
2784 out_buffers[0].BufferType = SECBUFFER_TOKEN;
2785 out_buffers[0].pvBuffer = NULL;
2786 out_buffers[0].cbBuffer = 0;
2787
2788 out_buffers[1].BufferType = SECBUFFER_ALERT;
2789 out_buffers[1].pvBuffer = NULL;
2790 out_buffers[1].cbBuffer = 0;
2791
2792 in_desc.ulVersion = SECBUFFER_VERSION;
2793 in_desc.pBuffers = in_buffers;
2794 in_desc.cBuffers = _countof(in_buffers);
2795
2796 out_desc.ulVersion = SECBUFFER_VERSION;
2797 out_desc.pBuffers = out_buffers;
2798 out_desc.cBuffers = _countof(out_buffers);
2799
2800 status = InitializeSecurityContext(&state->cred_handle,
2801 state->
2802 initialized ? &state->ctx_handle :
2803 NULL,
2804 state->
2805 initialized ? NULL :
2806 state->hostname, flags, 0, 0,
2807 state->initialized ? &in_desc :
2808 NULL, 0,
2809 state->initialized ? NULL :
2810 &state->ctx_handle, &out_desc,
2811 &flags, 0);
2812
2813 state->initialized = 1;
2814
2815 if (in_buffers[1].BufferType == SECBUFFER_EXTRA) {
2816 memmove(state->in_buffer,
2817 state->in_buffer + (state->in_buffer_size -
2818 in_buffers[1].cbBuffer),
2819 in_buffers[1].cbBuffer);
2820 state->in_buffer_size = in_buffers[1].cbBuffer;
2821 } else if (status != SEC_E_INCOMPLETE_MESSAGE) {
2822 state->in_buffer_size = 0;
2823 }
2824
2825 switch (status) {
2826 case SEC_E_OK:{
2827 if (out_buffers[0].cbBuffer > 0) {
2828 xwrite(state->ofd, out_buffers[0].pvBuffer,
2829 out_buffers[0].cbBuffer);
2830 FreeContextBuffer(out_buffers[0].pvBuffer);
2831 }
2832 goto Success;
2833 }
2834 case SEC_I_CONTINUE_NEEDED:{
2835 xwrite(state->ofd, out_buffers[0].pvBuffer,
2836 out_buffers[0].cbBuffer);
2837 FreeContextBuffer(out_buffers[0].pvBuffer);
2838 break;
2839 }
2840 case SEC_I_INCOMPLETE_CREDENTIALS:{
2841 // we don't support this
2842 bb_error_msg_and_die("schannel: client certificates not supported");
2843 }
2844 case SEC_E_INCOMPLETE_MESSAGE:{
2845 break;
2846 }
2847 default:{
2848 bb_error_msg_and_die("schannel: handshake failed: (0x%08lx): %s",
2849 status, hresult_to_error_string(status));
2850 }
2851 }
2852
2853 received =
2854 safe_read(state->ifd, state->in_buffer + state->in_buffer_size,
2855 sizeof(state->in_buffer) - state->in_buffer_size);
2856 if (received <= 0) {
2857 bb_error_msg_and_die("schannel: handshake read() failed");
2858 }
2859 state->in_buffer_size += received;
2860 }
2861
2862 Success:
2863 QueryContextAttributes(&state->ctx_handle, SECPKG_ATTR_STREAM_SIZES,
2864 &state->stream_sizes);
2865
2866 //SecPkgContext_ConnectionInfo info;
2867 //QueryContextAttributes(&state->ctx_handle, SECPKG_ATTR_CONNECTION_INFO,
2868 // &info);
2869 //
2870 //fprintf(stderr, "TLS 1.%d\n", (((uint32_t)(8 * sizeof(unsigned long long) - __builtin_clzll((info.dwProtocol)) - 1)) - 7)/2);
2871}
2872
2873void FAST_FUNC tls_run_copy_loop(tls_state_t * tls, unsigned flags) {
2874 char buffer[65536];
2875
2876 struct pollfd pfds[2];
2877
2878 pfds[0].fd = STDIN_FILENO;
2879 pfds[0].events = POLLIN;
2880 pfds[1].fd = tls->ifd;
2881 pfds[1].events = POLLIN;
2882
2883 for (;;) {
2884 int nread;
2885
2886 if (safe_poll(pfds, 2, -1) < 0)
2887 bb_simple_perror_msg_and_die("poll");
2888
2889 if (pfds[0].revents) {
2890 nread = safe_read(STDIN_FILENO, buffer, sizeof(buffer));
2891 if (nread < 1) {
2892 pfds[0].fd = -1;
2893 tls_disconnect(tls);
2894 if (flags & TLSLOOP_EXIT_ON_LOCAL_EOF)
2895 break;
2896 } else {
2897 tls_write(tls, buffer, nread);
2898 }
2899 }
2900 if (pfds[1].revents) {
2901 nread = tls_read(tls, buffer, sizeof(buffer));
2902 if (nread < 1) {
2903 tls_disconnect(tls);
2904 break;
2905 }
2906 xwrite(STDOUT_FILENO, buffer, nread);
2907 }
2908 }
2909}
2910#endif
diff --git a/networking/tls.h b/networking/tls.h
index 0173b87b2..eee5a7617 100644
--- a/networking/tls.h
+++ b/networking/tls.h
@@ -11,6 +11,7 @@
11#include "libbb.h" 11#include "libbb.h"
12 12
13 13
14#if !ENABLE_FEATURE_TLS_SCHANNEL
14/* Config tweaks */ 15/* Config tweaks */
15#define HAVE_NATIVE_INT64 16#define HAVE_NATIVE_INT64
16#undef USE_1024_KEY_SPEED_OPTIMIZATIONS 17#undef USE_1024_KEY_SPEED_OPTIMIZATIONS
@@ -82,10 +83,9 @@ typedef int16_t int16;
82 83
83void tls_get_random(void *buf, unsigned len) FAST_FUNC; 84void tls_get_random(void *buf, unsigned len) FAST_FUNC;
84 85
85void xorbuf(void* buf, const void* mask, unsigned count) FAST_FUNC;
86
87#define ALIGNED_long ALIGNED(sizeof(long)) 86#define ALIGNED_long ALIGNED(sizeof(long))
88void xorbuf_aligned_AES_BLOCK_SIZE(void* buf, const void* mask) FAST_FUNC; 87#define xorbuf_aligned_AES_BLOCK_SIZE(dst,src) xorbuf16_aligned_long(dst,src)
88#define xorbuf_AES_BLOCK_SIZE(dst,src) xorbuf16(dst,src)
89 89
90#define matrixCryptoGetPrngData(buf, len, userPtr) (tls_get_random(buf, len), PS_SUCCESS) 90#define matrixCryptoGetPrngData(buf, len, userPtr) (tls_get_random(buf, len), PS_SUCCESS)
91 91
@@ -120,3 +120,4 @@ void curve_P256_compute_pubkey_and_premaster(
120void curve_P256_compute_pubkey_and_premaster_NEW( 120void curve_P256_compute_pubkey_and_premaster_NEW(
121 uint8_t *pubkey2x32, uint8_t *premaster32, 121 uint8_t *pubkey2x32, uint8_t *premaster32,
122 const uint8_t *peerkey2x32) FAST_FUNC; 122 const uint8_t *peerkey2x32) FAST_FUNC;
123#endif
diff --git a/networking/tls_aesgcm.c b/networking/tls_aesgcm.c
index 5ddcdd2ad..9c2381a57 100644
--- a/networking/tls_aesgcm.c
+++ b/networking/tls_aesgcm.c
@@ -167,10 +167,7 @@ void FAST_FUNC aesgcm_GHASH(byte* h,
167 blocks = cSz / AES_BLOCK_SIZE; 167 blocks = cSz / AES_BLOCK_SIZE;
168 partial = cSz % AES_BLOCK_SIZE; 168 partial = cSz % AES_BLOCK_SIZE;
169 while (blocks--) { 169 while (blocks--) {
170 if (BB_UNALIGNED_MEMACCESS_OK) // c is not guaranteed to be aligned 170 xorbuf_AES_BLOCK_SIZE(x, c);
171 xorbuf_aligned_AES_BLOCK_SIZE(x, c);
172 else
173 xorbuf(x, c, AES_BLOCK_SIZE);
174 GMULT(x, h); 171 GMULT(x, h);
175 c += AES_BLOCK_SIZE; 172 c += AES_BLOCK_SIZE;
176 } 173 }
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 79cef1999..19c961d5c 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -148,10 +148,11 @@ enum {
148 OPT_o = 1 << 12, 148 OPT_o = 1 << 12,
149 OPT_x = 1 << 13, 149 OPT_x = 1 << 13,
150 OPT_f = 1 << 14, 150 OPT_f = 1 << 14,
151 OPT_l = 1 << 15, 151 OPT_m = 1 << 15,
152 OPT_d = 1 << 16, 152 OPT_l = 1 << 16,
153 OPT_d = 1 << 17,
153/* The rest has variable bit positions, need to be clever */ 154/* The rest has variable bit positions, need to be clever */
154 OPTBIT_d = 16, 155 OPTBIT_d = 17,
155 USE_FOR_MMU( OPTBIT_b,) 156 USE_FOR_MMU( OPTBIT_b,)
156 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) 157 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
157 IF_FEATURE_UDHCP_PORT( OPTBIT_P,) 158 IF_FEATURE_UDHCP_PORT( OPTBIT_P,)
@@ -268,6 +269,23 @@ static void option_to_env(const uint8_t *option, const uint8_t *option_end)
268 //case D6_OPT_SERVERID: 269 //case D6_OPT_SERVERID:
269 case D6_OPT_IA_NA: 270 case D6_OPT_IA_NA:
270 case D6_OPT_IA_PD: 271 case D6_OPT_IA_PD:
272/* 0 1 2 3
273 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
274 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
275 * | OPTION_IA_PD | option-length |
276 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
277 * | IAID (4 octets) |
278 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
279 * | T1 |
280 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
281 * | T2 |
282 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
283 * . .
284 * . IA_PD-options .
285 * . .
286 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
287 */
288 /* recurse to handle "IA_PD-options" field */
271 option_to_env(option + 16, option + 4 + option[3]); 289 option_to_env(option + 16, option + 4 + option[3]);
272 break; 290 break;
273 //case D6_OPT_IA_TA: 291 //case D6_OPT_IA_TA:
@@ -604,6 +622,31 @@ static NOINLINE int send_d6_info_request(void)
604 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr); 622 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
605} 623}
606 624
625/*
626 * RFC 3315 10. Identity Association
627 *
628 * An "identity-association" (IA) is a construct through which a server
629 * and a client can identify, group, and manage a set of related IPv6
630 * addresses. Each IA consists of an IAID and associated configuration
631 * information.
632 *
633 * A client must associate at least one distinct IA with each of its
634 * network interfaces for which it is to request the assignment of IPv6
635 * addresses from a DHCP server. The client uses the IAs assigned to an
636 * interface to obtain configuration information from a server for that
637 * interface. Each IA must be associated with exactly one interface.
638 *
639 * The IAID uniquely identifies the IA and must be chosen to be unique
640 * among the IAIDs on the client. The IAID is chosen by the client.
641 * For any given use of an IA by the client, the IAID for that IA MUST
642 * be consistent across restarts of the DHCP client...
643 */
644/* Generate IAID. We base it on our MAC address' last 4 bytes */
645static void generate_iaid(uint8_t *iaid)
646{
647 memcpy(iaid, &client_data.client_mac[2], 4);
648}
649
607/* Multicast a DHCPv6 Solicit packet to the network, with an optionally requested IP. 650/* Multicast a DHCPv6 Solicit packet to the network, with an optionally requested IP.
608 * 651 *
609 * RFC 3315 17.1.1. Creation of Solicit Messages 652 * RFC 3315 17.1.1. Creation of Solicit Messages
@@ -703,7 +746,7 @@ static NOINLINE int send_d6_discover(struct in6_addr *requested_ipv6)
703 client6_data.ia_na = xzalloc(len); 746 client6_data.ia_na = xzalloc(len);
704 client6_data.ia_na->code = D6_OPT_IA_NA; 747 client6_data.ia_na->code = D6_OPT_IA_NA;
705 client6_data.ia_na->len = len - 4; 748 client6_data.ia_na->len = len - 4;
706 *(bb__aliased_uint32_t*)client6_data.ia_na->data = rand(); /* IAID */ 749 generate_iaid(client6_data.ia_na->data); /* IAID */
707 if (requested_ipv6) { 750 if (requested_ipv6) {
708 struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4); 751 struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4);
709 iaaddr->code = D6_OPT_IAADDR; 752 iaaddr->code = D6_OPT_IAADDR;
@@ -721,7 +764,7 @@ static NOINLINE int send_d6_discover(struct in6_addr *requested_ipv6)
721 client6_data.ia_pd = xzalloc(len); 764 client6_data.ia_pd = xzalloc(len);
722 client6_data.ia_pd->code = D6_OPT_IA_PD; 765 client6_data.ia_pd->code = D6_OPT_IA_PD;
723 client6_data.ia_pd->len = len - 4; 766 client6_data.ia_pd->len = len - 4;
724 *(bb__aliased_uint32_t*)client6_data.ia_pd->data = rand(); /* IAID */ 767 generate_iaid(client6_data.ia_pd->data); /* IAID */
725 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len); 768 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len);
726 } 769 }
727 770
@@ -1131,12 +1174,11 @@ static void client_background(void)
1131//usage:#endif 1174//usage:#endif
1132//usage:#define udhcpc6_trivial_usage 1175//usage:#define udhcpc6_trivial_usage
1133//usage: "[-fbq"IF_UDHCP_VERBOSE("v")"R] [-t N] [-T SEC] [-A SEC|-n] [-i IFACE] [-s PROG]\n" 1176//usage: "[-fbq"IF_UDHCP_VERBOSE("v")"R] [-t N] [-T SEC] [-A SEC|-n] [-i IFACE] [-s PROG]\n"
1134//usage: " [-p PIDFILE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-ldo] [-r IPv6] [-x OPT:VAL]... [-O OPT]..." 1177//usage: " [-p PIDFILE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-mldo] [-r IPv6] [-x OPT:VAL]... [-O OPT]..."
1135//usage:#define udhcpc6_full_usage "\n" 1178//usage:#define udhcpc6_full_usage "\n"
1136//usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")" 1179//usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")"
1137//usage: "\n -p FILE Create pidfile" 1180//usage: "\n -p FILE Create pidfile"
1138//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC6_DEFAULT_SCRIPT")" 1181//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC6_DEFAULT_SCRIPT")"
1139//usage: "\n -B Request broadcast replies"
1140//usage: "\n -t N Send up to N discover packets" 1182//usage: "\n -t N Send up to N discover packets"
1141//usage: "\n -T SEC Pause between packets (default 3)" 1183//usage: "\n -T SEC Pause between packets (default 3)"
1142//usage: "\n -A SEC Wait if lease is not obtained (default 20)" 1184//usage: "\n -A SEC Wait if lease is not obtained (default 20)"
@@ -1154,6 +1196,7 @@ static void client_background(void)
1154////usage: IF_FEATURE_UDHCPC_ARPING( 1196////usage: IF_FEATURE_UDHCPC_ARPING(
1155////usage: "\n -a Use arping to validate offered address" 1197////usage: "\n -a Use arping to validate offered address"
1156////usage: ) 1198////usage: )
1199//usage: "\n -m Send multicast renew requests rather than unicast ones"
1157//usage: "\n -l Send 'information request' instead of 'solicit'" 1200//usage: "\n -l Send 'information request' instead of 'solicit'"
1158//usage: "\n (used for servers which do not assign IPv6 addresses)" 1201//usage: "\n (used for servers which do not assign IPv6 addresses)"
1159//usage: "\n -r IPv6 Request this address ('no' to not request any IP)" 1202//usage: "\n -r IPv6 Request this address ('no' to not request any IP)"
@@ -1211,7 +1254,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1211 /* Parse command line */ 1254 /* Parse command line */
1212 opt = getopt32long(argv, "^" 1255 opt = getopt32long(argv, "^"
1213 /* O,x: list; -T,-t,-A take numeric param */ 1256 /* O,x: list; -T,-t,-A take numeric param */
1214 "i:np:qRr:s:T:+t:+SA:+O:*ox:*fld" 1257 "i:np:qRr:s:T:+t:+SA:+O:*ox:*fmld"
1215 USE_FOR_MMU("b") 1258 USE_FOR_MMU("b")
1216 ///IF_FEATURE_UDHCPC_ARPING("a") 1259 ///IF_FEATURE_UDHCPC_ARPING("a")
1217 IF_FEATURE_UDHCP_PORT("P:") 1260 IF_FEATURE_UDHCP_PORT("P:")
@@ -1464,7 +1507,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1464 if (opt & OPT_l) 1507 if (opt & OPT_l)
1465 send_d6_info_request(); 1508 send_d6_info_request();
1466 else 1509 else
1467 send_d6_renew(&srv6_buf, requested_ipv6); 1510 send_d6_renew(OPT_m ? NULL : &srv6_buf, requested_ipv6);
1468 timeout = discover_timeout; 1511 timeout = discover_timeout;
1469 packet_num++; 1512 packet_num++;
1470 continue; 1513 continue;
@@ -1606,62 +1649,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1606 case RENEW_REQUESTED: 1649 case RENEW_REQUESTED:
1607 case REBINDING: 1650 case REBINDING:
1608 if (packet.d6_msg_type == D6_MSG_REPLY) { 1651 if (packet.d6_msg_type == D6_MSG_REPLY) {
1609 unsigned start;
1610 uint32_t lease_seconds;
1611 struct d6_option *option;
1612 unsigned address_timeout;
1613 unsigned prefix_timeout;
1614 type_is_ok:
1615 change_listen_mode(LISTEN_NONE);
1616
1617 address_timeout = 0;
1618 prefix_timeout = 0;
1619 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
1620 if (option && (option->data[0] | option->data[1]) != 0) {
1621///FIXME:
1622// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1623// | OPTION_STATUS_CODE | option-len |
1624// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1625// | status-code | |
1626// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1627// . status-message .
1628// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1629// so why do we think it's NAK if data[0] is zero but data[1] is not? That's wrong...
1630// we should also check that option->len is ok (i.e. not 0), right?
1631 /* return to init state */
1632 bb_info_msg("received DHCP NAK (%u)", option->data[4]);
1633 d6_run_script(packet.d6_options,
1634 packet_end, "nak");
1635 if (client_data.state != REQUESTING)
1636 d6_run_script_no_option("deconfig");
1637 sleep(3); /* avoid excessive network traffic */
1638 client_data.state = INIT_SELECTING;
1639 client_data.first_secs = 0; /* make secs field count from 0 */
1640 requested_ipv6 = NULL;
1641 timeout = 0;
1642 packet_num = 0;
1643 continue;
1644 }
1645 option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID);
1646 if (!option) {
1647 bb_simple_info_msg("no server ID, ignoring packet");
1648 continue;
1649 /* still selecting - this server looks bad */
1650 }
1651//Note: we do not bother comparing server IDs in Advertise and Reply msgs.
1652//server_id variable is used solely for creation of proper server_id option
1653//in outgoing packets. (why DHCPv6 even introduced it is a mystery).
1654 free(client6_data.server_id);
1655 client6_data.server_id = option;
1656 if (packet.d6_msg_type == D6_MSG_ADVERTISE) {
1657 /* enter requesting state */
1658 change_listen_mode(LISTEN_RAW);
1659 client_data.state = REQUESTING;
1660 timeout = 0;
1661 packet_num = 0;
1662 continue;
1663 }
1664 /* It's a D6_MSG_REPLY */
1665/* 1652/*
1666 * RFC 3315 18.1.8. Receipt of Reply Messages 1653 * RFC 3315 18.1.8. Receipt of Reply Messages
1667 * 1654 *
@@ -1747,6 +1734,67 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1747 * . . 1734 * . .
1748 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1735 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1749 */ 1736 */
1737 unsigned start;
1738 uint32_t lease_seconds;
1739 struct d6_option *option;
1740 unsigned address_timeout;
1741 unsigned prefix_timeout;
1742 type_is_ok:
1743 change_listen_mode(LISTEN_NONE);
1744
1745 address_timeout = 0;
1746 prefix_timeout = 0;
1747 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
1748 if (option) {
1749// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1750// | OPTION_STATUS_CODE | option-len |
1751// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1752// | status-code | |
1753// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1754// . status-message .
1755// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1756 unsigned len, status;
1757 len = ((unsigned)option->len_hi << 8) + option->len;
1758 if (len < 2) {
1759 bb_simple_error_msg("invalid OPTION_STATUS_CODE, ignoring packet");
1760 continue;
1761 }
1762 status = ((unsigned)option->data[0] << 8) + option->data[1];
1763 if (status != 0) {
1764//TODO: handle status == 5 (UseMulticast)?
1765 /* return to init state */
1766 bb_info_msg("received DHCP NAK: %u '%.*s'", status, len - 2, option->data + 2);
1767 d6_run_script(packet.d6_options, packet_end, "nak");
1768 if (client_data.state != REQUESTING)
1769 d6_run_script_no_option("deconfig");
1770 sleep(3); /* avoid excessive network traffic */
1771 client_data.state = INIT_SELECTING;
1772 client_data.first_secs = 0; /* make secs field count from 0 */
1773 requested_ipv6 = NULL;
1774 timeout = 0;
1775 packet_num = 0;
1776 continue;
1777 }
1778 }
1779 option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID);
1780 if (!option) {
1781 bb_simple_info_msg("no server ID, ignoring packet");
1782 continue;
1783 /* still selecting - this server looks bad */
1784 }
1785//Note: we do not bother comparing server IDs in Advertise and Reply msgs.
1786//server_id variable is used solely for creation of proper server_id option
1787//in outgoing packets. (why DHCPv6 even introduced it is a mystery).
1788 free(client6_data.server_id);
1789 client6_data.server_id = option;
1790 if (packet.d6_msg_type == D6_MSG_ADVERTISE) {
1791 /* enter requesting state */
1792 change_listen_mode(LISTEN_RAW);
1793 client_data.state = REQUESTING;
1794 timeout = 0;
1795 packet_num = 0;
1796 continue;
1797 }
1750 if (option_mask32 & OPT_r) { 1798 if (option_mask32 & OPT_r) {
1751 struct d6_option *iaaddr; 1799 struct d6_option *iaaddr;
1752 1800
@@ -1790,6 +1838,21 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1790 1838
1791 free(client6_data.ia_pd); 1839 free(client6_data.ia_pd);
1792 client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD); 1840 client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD);
1841// 0 1 2 3
1842// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1843// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1844// | OPTION_IA_PD | option-length |
1845// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1846// | IAID (4 octets) |
1847// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1848// | T1 |
1849// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1850// | T2 |
1851// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1852// . .
1853// . IA_PD-options .
1854// . .
1855// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1793 if (!client6_data.ia_pd) { 1856 if (!client6_data.ia_pd) {
1794 bb_info_msg("no %s option%s", "IA_PD", ", ignoring packet"); 1857 bb_info_msg("no %s option%s", "IA_PD", ", ignoring packet");
1795 continue; 1858 continue;
diff --git a/networking/udhcp/d6_packet.c b/networking/udhcp/d6_packet.c
index 142de9b43..1d7541948 100644
--- a/networking/udhcp/d6_packet.c
+++ b/networking/udhcp/d6_packet.c
@@ -153,13 +153,15 @@ int FAST_FUNC d6_send_kernel_packet_from_client_data_ifindex(
153 } 153 }
154 setsockopt_reuseaddr(fd); 154 setsockopt_reuseaddr(fd);
155 155
156 memset(&sa, 0, sizeof(sa)); 156 if (src_ipv6) {
157 sa.sin6_family = AF_INET6; 157 memset(&sa, 0, sizeof(sa));
158 sa.sin6_port = htons(source_port); 158 sa.sin6_family = AF_INET6;
159 sa.sin6_addr = *src_ipv6; /* struct copy */ 159 sa.sin6_port = htons(source_port);
160 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { 160 sa.sin6_addr = *src_ipv6; /* struct copy */
161 msg = "bind(%s)"; 161 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
162 goto ret_close; 162 msg = "bind(%s)";
163 goto ret_close;
164 }
163 } 165 }
164 166
165 memset(&sa, 0, sizeof(sa)); 167 memset(&sa, 0, sizeof(sa));
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index 2904119e5..b9cbd6464 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -575,29 +575,51 @@ static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadc
575 const uint8_t *chaddr; 575 const uint8_t *chaddr;
576 uint32_t ciaddr; 576 uint32_t ciaddr;
577 577
578 // Was: 578 // Logic:
579 //if (force_broadcast) { /* broadcast */ } 579 //if (force_broadcast) { /* broadcast */ }
580 //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ } 580 //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ }
581 // ^^^ dhcp_pkt->ciaddr comes from client's request packet.
582 // We expect such clients to have an UDP socket listening on that IP.
581 //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ } 583 //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ }
582 //else { /* unicast to dhcp_pkt->yiaddr */ } 584 //else { /* unicast to dhcp_pkt->yiaddr */ }
583 // But this is wrong: yiaddr is _our_ idea what client's IP is 585 // ^^^ The last case is confusing, but *should* work.
584 // (for example, from lease file). Client may not know that, 586 // It's a case where client have sent a DISCOVER
585 // and may not have UDP socket listening on that IP! 587 // and does not have a kernel UDP socket listening on the IP
586 // We should never unicast to dhcp_pkt->yiaddr! 588 // we are offering in yiaddr (it does not know the IP yet)!
587 // dhcp_pkt->ciaddr, OTOH, comes from client's request packet, 589 // This *should* work because client *should* listen on a raw socket
588 // and can be used. 590 // instead at this time (IOW: it should examine ALL IPv4 packets
589 591 // "by hand", not relying on kernel's UDP stack.)
590 if (force_broadcast 592
591 || (dhcp_pkt->flags & htons(BROADCAST_FLAG)) 593 chaddr = dhcp_pkt->chaddr;
592 || dhcp_pkt->ciaddr == 0 594
595 if (dhcp_pkt->ciaddr == 0
596 || force_broadcast /* sending DHCPNAK pkt? */
593 ) { 597 ) {
594 log1s("broadcasting packet to client"); 598 if (dhcp_pkt->flags & htons(BROADCAST_FLAG)
595 ciaddr = INADDR_BROADCAST; 599 || force_broadcast /* sending DHCPNAK pkt? */
596 chaddr = MAC_BCAST_ADDR; 600 ) {
601// RFC 2131:
602// If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is
603// set, then the server broadcasts DHCPOFFER and DHCPACK messages to
604// 0xffffffff. ...
605// In all cases, when 'giaddr' is zero, the server broadcasts any DHCPNAK
606// messages to 0xffffffff.
607 ciaddr = INADDR_BROADCAST;
608 chaddr = MAC_BCAST_ADDR;
609 log1s("broadcasting packet to client");
610 } else {
611// If the broadcast bit is not set and 'giaddr' is zero and
612// 'ciaddr' is zero, then the server unicasts DHCPOFFER and DHCPACK
613// messages to the client's hardware address and 'yiaddr' address.
614 ciaddr = dhcp_pkt->yiaddr;
615 log1("unicasting packet to client %ciaddr", 'y');
616 }
597 } else { 617 } else {
598 log1s("unicasting packet to client ciaddr"); 618// If the 'giaddr'
619// field is zero and the 'ciaddr' field is nonzero, then the server
620// unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'.
599 ciaddr = dhcp_pkt->ciaddr; 621 ciaddr = dhcp_pkt->ciaddr;
600 chaddr = dhcp_pkt->chaddr; 622 log1("unicasting packet to client %ciaddr", 'c');
601 } 623 }
602 624
603 udhcp_send_raw_packet(dhcp_pkt, 625 udhcp_send_raw_packet(dhcp_pkt,
@@ -624,6 +646,10 @@ static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
624static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) 646static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
625{ 647{
626 if (dhcp_pkt->gateway_nip) 648 if (dhcp_pkt->gateway_nip)
649// RFC 2131:
650// If the 'giaddr' field in a DHCP message from a client is non-zero,
651// the server sends any return messages to the 'DHCP server' port on the
652// BOOTP relay agent whose address appears in 'giaddr'.
627 send_packet_to_relay(dhcp_pkt); 653 send_packet_to_relay(dhcp_pkt);
628 else 654 else
629 send_packet_to_client(dhcp_pkt, force_broadcast); 655 send_packet_to_client(dhcp_pkt, force_broadcast);
diff --git a/networking/wget.c b/networking/wget.c
index ec3767793..6a64836fb 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -214,6 +214,9 @@ enum {
214 HDR_CONTENT_TYPE = (1<<3), 214 HDR_CONTENT_TYPE = (1<<3),
215 HDR_AUTH = (1<<4) * ENABLE_FEATURE_WGET_AUTHENTICATION, 215 HDR_AUTH = (1<<4) * ENABLE_FEATURE_WGET_AUTHENTICATION,
216 HDR_PROXY_AUTH = (1<<5) * ENABLE_FEATURE_WGET_AUTHENTICATION, 216 HDR_PROXY_AUTH = (1<<5) * ENABLE_FEATURE_WGET_AUTHENTICATION,
217# if ENABLE_PLATFORM_MINGW32
218 HDR_CONTENT_LENGTH = (1<<(4 + 2 * ENABLE_FEATURE_WGET_AUTHENTICATION)),
219# endif
217}; 220};
218static const char wget_user_headers[] ALIGN1 = 221static const char wget_user_headers[] ALIGN1 =
219 "Host:\0" 222 "Host:\0"
@@ -224,6 +227,9 @@ static const char wget_user_headers[] ALIGN1 =
224 "Authorization:\0" 227 "Authorization:\0"
225 "Proxy-Authorization:\0" 228 "Proxy-Authorization:\0"
226# endif 229# endif
230# if ENABLE_PLATFORM_MINGW32
231 "Content-Length:\0"
232# endif
227 ; 233 ;
228# define USR_HEADER_HOST (G.user_headers & HDR_HOST) 234# define USR_HEADER_HOST (G.user_headers & HDR_HOST)
229# define USR_HEADER_USER_AGENT (G.user_headers & HDR_USER_AGENT) 235# define USR_HEADER_USER_AGENT (G.user_headers & HDR_USER_AGENT)
@@ -231,6 +237,7 @@ static const char wget_user_headers[] ALIGN1 =
231# define USR_HEADER_CONTENT_TYPE (G.user_headers & HDR_CONTENT_TYPE) 237# define USR_HEADER_CONTENT_TYPE (G.user_headers & HDR_CONTENT_TYPE)
232# define USR_HEADER_AUTH (G.user_headers & HDR_AUTH) 238# define USR_HEADER_AUTH (G.user_headers & HDR_AUTH)
233# define USR_HEADER_PROXY_AUTH (G.user_headers & HDR_PROXY_AUTH) 239# define USR_HEADER_PROXY_AUTH (G.user_headers & HDR_PROXY_AUTH)
240# define USR_HEADER_CONTENT_LENGTH (G.user_headers & HDR_CONTENT_LENGTH)
234#else /* No long options, no user-headers :( */ 241#else /* No long options, no user-headers :( */
235# define USR_HEADER_HOST 0 242# define USR_HEADER_HOST 0
236# define USR_HEADER_USER_AGENT 0 243# define USR_HEADER_USER_AGENT 0
@@ -238,6 +245,7 @@ static const char wget_user_headers[] ALIGN1 =
238# define USR_HEADER_CONTENT_TYPE 0 245# define USR_HEADER_CONTENT_TYPE 0
239# define USR_HEADER_AUTH 0 246# define USR_HEADER_AUTH 0
240# define USR_HEADER_PROXY_AUTH 0 247# define USR_HEADER_PROXY_AUTH 0
248# define USR_HEADER_CONTENT_LENGTH 0
241#endif 249#endif
242 250
243/* Globals */ 251/* Globals */
@@ -517,6 +525,9 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp)
517 fprintf(stderr, "--> %s%s\n\n", s1, s2); 525 fprintf(stderr, "--> %s%s\n\n", s1, s2);
518 fflush(fp); 526 fflush(fp);
519 log_io("> %s%s", s1, s2); 527 log_io("> %s%s", s1, s2);
528#if ENABLE_PLATFORM_MINGW32
529 fseek(fp, 0L, SEEK_CUR);
530#endif
520 } 531 }
521 532
522 /* Read until "Nxx something" is received */ 533 /* Read until "Nxx something" is received */
@@ -524,6 +535,9 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp)
524 do { 535 do {
525 fgets_trim_sanitize(fp, "%s\n"); 536 fgets_trim_sanitize(fp, "%s\n");
526 } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' '); 537 } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' ');
538#if ENABLE_PLATFORM_MINGW32
539 fseek(fp, 0L, SEEK_CUR);
540#endif
527 541
528 G.wget_buf[3] = '\0'; 542 G.wget_buf[3] = '\0';
529 result = xatoi_positive(G.wget_buf); 543 result = xatoi_positive(G.wget_buf);
@@ -766,6 +780,7 @@ static int spawn_https_helper_openssl(const char *host, unsigned port)
766#endif 780#endif
767 781
768#if ENABLE_FEATURE_WGET_HTTPS 782#if ENABLE_FEATURE_WGET_HTTPS
783# if !ENABLE_PLATFORM_MINGW32
769static void spawn_ssl_client(const char *host, int network_fd, int flags) 784static void spawn_ssl_client(const char *host, int network_fd, int flags)
770{ 785{
771 int sp[2]; 786 int sp[2];
@@ -820,6 +835,31 @@ static void spawn_ssl_client(const char *host, int network_fd, int flags)
820 close(sp[1]); 835 close(sp[1]);
821 xmove_fd(sp[0], network_fd); 836 xmove_fd(sp[0], network_fd);
822} 837}
838# else
839static void spawn_ssl_client(const char *host, int network_fd, int flags)
840{
841 int fd1;
842 char *servername, *p, *cmd;
843
844 servername = xstrdup(host);
845 p = strrchr(servername, ':');
846 if (p) *p = '\0';
847
848 fflush_all();
849
850 cmd = xasprintf("ssl_client -h %p -n %s%s",
851 (void *)_get_osfhandle(network_fd), servername,
852 flags & TLSLOOP_EXIT_ON_LOCAL_EOF ? " -e" : "");
853
854 if ((fd1=mingw_popen_fd("ssl_client", cmd, "b", -1, NULL)) == -1) {
855 bb_perror_msg_and_die("can't execute ssl_client");
856 }
857
858 free(cmd);
859 free(servername);
860 xmove_fd(fd1, network_fd);
861}
862# endif
823#endif 863#endif
824 864
825#if ENABLE_FEATURE_WGET_FTP 865#if ENABLE_FEATURE_WGET_FTP
@@ -1273,6 +1313,18 @@ static void download_one_url(const char *url)
1273 "Content-Type: application/x-www-form-urlencoded\r\n" 1313 "Content-Type: application/x-www-form-urlencoded\r\n"
1274 ); 1314 );
1275 } 1315 }
1316# if ENABLE_PLATFORM_MINGW32
1317 if (!USR_HEADER_CONTENT_LENGTH)
1318 SENDFMT(sfp, "Content-Length: %u\r\n",
1319 (int)strlen(G.post_data)
1320 );
1321 SENDFMT(sfp,
1322 "\r\n"
1323 "%s",
1324 G.post_data
1325 );
1326 } else
1327# else
1276 SENDFMT(sfp, 1328 SENDFMT(sfp,
1277 "Content-Length: %u\r\n" 1329 "Content-Length: %u\r\n"
1278 "\r\n" 1330 "\r\n"
@@ -1280,6 +1332,7 @@ static void download_one_url(const char *url)
1280 (int) strlen(G.post_data), G.post_data 1332 (int) strlen(G.post_data), G.post_data
1281 ); 1333 );
1282 } else 1334 } else
1335# endif
1283#endif 1336#endif
1284 { 1337 {
1285 SENDFMT(sfp, "\r\n"); 1338 SENDFMT(sfp, "\r\n");