diff options
Diffstat (limited to '')
-rw-r--r-- | networking/Config.src | 30 | ||||
-rw-r--r-- | networking/ftpgetput.c | 6 | ||||
-rw-r--r-- | networking/hostname.c | 4 | ||||
-rw-r--r-- | networking/httpd.c | 299 | ||||
-rw-r--r-- | networking/libiproute/iproute.c | 16 | ||||
-rw-r--r-- | networking/nc.c | 12 | ||||
-rw-r--r-- | networking/ntpd.c | 6 | ||||
-rw-r--r-- | networking/ssl_client.c | 21 | ||||
-rw-r--r-- | networking/telnetd.c | 4 | ||||
-rw-r--r-- | networking/tftp.c | 2 | ||||
-rw-r--r-- | networking/tls.c | 771 | ||||
-rw-r--r-- | networking/tls.h | 7 | ||||
-rw-r--r-- | networking/tls_aesgcm.c | 5 | ||||
-rw-r--r-- | networking/udhcp/d6_dhcpc.c | 193 | ||||
-rw-r--r-- | networking/udhcp/d6_packet.c | 16 | ||||
-rw-r--r-- | networking/udhcp/dhcpd.c | 58 | ||||
-rw-r--r-- | networking/wget.c | 53 |
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 | ||
75 | choice | ||
76 | prompt "TLS implementation" | ||
77 | default FEATURE_TLS_INTERNAL | ||
78 | |||
79 | config FEATURE_TLS_INTERNAL | ||
80 | bool "Internal" | ||
81 | depends on TLS | ||
82 | help | ||
83 | Use the BusyBox default internal TLS implementation. | ||
84 | |||
85 | config 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 | |||
92 | endchoice | ||
93 | |||
75 | config FEATURE_TLS_SHA1 | 94 | config 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 | ||
105 | config 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 | |||
86 | INSERT | 114 | INSERT |
87 | 115 | ||
88 | source networking/udhcp/Config.in | 116 | source 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 | ||
335 | static 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 | ||
453 | struct globals { | 465 | struct 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 */ |
563 | enum { | 592 | enum { |
@@ -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 | ||
1583 | static 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 | ||
1527 | static void setenv1(const char *name, const char *value) | 1624 | static 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 | */ |
2170 | static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN; | ||
2171 | static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM) | 2339 | static 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 |
2636 | static void mini_httpd(int server_socket) NORETURN; | 2822 | static void mini_httpd(int server_socket) NORETURN; |
2637 | static void mini_httpd(int server_socket) | 2823 | static 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 */ | ||
2910 | static void mini_httpd_win32(int sock, int argc, char **argv) NORETURN; | ||
2911 | static 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 | ||
2961 | static 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 | ||
2740 | static void sighup_handler(int sig UNUSED_PARAM) | 2983 | static 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 | ||
2747 | enum { | 2991 | enum { |
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 | ||
113 | static void timeout(int signum UNUSED_PARAM) | 114 | static 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 | ||
118 | int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 120 | int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
119 | int nc_main(int argc, char **argv) | 121 | int 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 | ||
190 | enum { | 191 | enum { |
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 | ||
332 | void FAST_FUNC tls_get_random(void *buf, unsigned len) | 331 | void 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 | ||
338 | static 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 | |||
347 | void FAST_FUNC xorbuf(void *dst, const void *src, unsigned count) | ||
348 | { | ||
349 | xorbuf3(dst, dst, src, count); | ||
350 | } | ||
351 | |||
352 | void 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. | ||
406 | typedef struct hmac_precomputed { | ||
407 | md5sha_ctx_t hashed_key_xor_ipad; | ||
408 | md5sha_ctx_t hashed_key_xor_opad; | ||
409 | } hmac_precomputed_t; | ||
410 | |||
411 | typedef 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 | ||
417 | static 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 | |||
459 | static 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 | |||
482 | static 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 | ||
499 | static 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 | ||
513 | static 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 | |||
658 | static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type) | 534 | static 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 | |||
2381 | static 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 | |||
2392 | static 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 | |||
2577 | static 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 | |||
2630 | static 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 | |||
2706 | void 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 | |||
2873 | void 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 | ||
83 | void tls_get_random(void *buf, unsigned len) FAST_FUNC; | 84 | void tls_get_random(void *buf, unsigned len) FAST_FUNC; |
84 | 85 | ||
85 | void 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)) |
88 | void 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( | |||
120 | void curve_P256_compute_pubkey_and_premaster_NEW( | 120 | void 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 */ | ||
645 | static 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) | |||
624 | static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) | 646 | static 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 | }; |
218 | static const char wget_user_headers[] ALIGN1 = | 221 | static 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 | ||
769 | static void spawn_ssl_client(const char *host, int network_fd, int flags) | 784 | static 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 | ||
839 | static 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"); |