diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2021-05-05 15:00:09 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2021-05-05 15:00:09 +0200 |
commit | ad16f89547a5e335f3c45506eb5b43bcc1bf505e (patch) | |
tree | b1ac083e94dc29c1ce55988d6b2e35b994bd391b | |
parent | 91a58b207ea04e6078f44cecae6c3356e059da8a (diff) | |
download | busybox-w32-ad16f89547a5e335f3c45506eb5b43bcc1bf505e.tar.gz busybox-w32-ad16f89547a5e335f3c45506eb5b43bcc1bf505e.tar.bz2 busybox-w32-ad16f89547a5e335f3c45506eb5b43bcc1bf505e.zip |
httpd: if no request was given at all, close the socket without generating error page
For one, an attacker can try to overload us by just opening and immediately
closing tons of connections - reduce our work to the minimum for this case.
function old new delta
handle_incoming_and_exit 2172 2200 +28
.rodata 103225 103246 +21
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 49/0) Total: 49 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/httpd.c | 51 |
1 files changed, 30 insertions, 21 deletions
diff --git a/networking/httpd.c b/networking/httpd.c index 6bc58995b..fb6ffe542 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -305,6 +305,12 @@ | |||
305 | 305 | ||
306 | #define DEBUG 0 | 306 | #define DEBUG 0 |
307 | 307 | ||
308 | #if DEBUG | ||
309 | # define dbg(...) fprintf(stderr, __VA_ARGS__) | ||
310 | #else | ||
311 | # define dbg(...) ((void)0) | ||
312 | #endif | ||
313 | |||
308 | #define IOBUF_SIZE 8192 | 314 | #define IOBUF_SIZE 8192 |
309 | #define MAX_HTTP_HEADERS_SIZE (32*1024) | 315 | #define MAX_HTTP_HEADERS_SIZE (32*1024) |
310 | 316 | ||
@@ -1158,8 +1164,7 @@ static void send_headers(unsigned responseNum) | |||
1158 | fprintf(stderr, "headers: '%s'\n", iobuf); | 1164 | fprintf(stderr, "headers: '%s'\n", iobuf); |
1159 | } | 1165 | } |
1160 | full_write(STDOUT_FILENO, iobuf, len); | 1166 | full_write(STDOUT_FILENO, iobuf, len); |
1161 | if (DEBUG) | 1167 | dbg("writing error page: '%s'\n", error_page); |
1162 | fprintf(stderr, "writing error page: '%s'\n", error_page); | ||
1163 | return send_file_and_exit(error_page, SEND_BODY); | 1168 | return send_file_and_exit(error_page, SEND_BODY); |
1164 | } | 1169 | } |
1165 | #endif | 1170 | #endif |
@@ -1500,8 +1505,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post | |||
1500 | } | 1505 | } |
1501 | if (full_write(STDOUT_FILENO, rbuf, count) != count) | 1506 | if (full_write(STDOUT_FILENO, rbuf, count) != count) |
1502 | break; | 1507 | break; |
1503 | if (DEBUG) | 1508 | dbg("cgi read %d bytes: '%.*s'\n", count, count, rbuf); |
1504 | fprintf(stderr, "cgi read %d bytes: '%.*s'\n", count, count, rbuf); | ||
1505 | } /* if (pfd[FROM_CGI].revents) */ | 1509 | } /* if (pfd[FROM_CGI].revents) */ |
1506 | } /* while (1) */ | 1510 | } /* while (1) */ |
1507 | log_and_exit(); | 1511 | log_and_exit(); |
@@ -1747,8 +1751,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) | |||
1747 | /* file_size and last_mod are already populated */ | 1751 | /* file_size and last_mod are already populated */ |
1748 | } | 1752 | } |
1749 | if (fd < 0) { | 1753 | if (fd < 0) { |
1750 | if (DEBUG) | 1754 | dbg("can't open '%s'\n", url); |
1751 | bb_perror_msg("can't open '%s'", url); | ||
1752 | /* Error pages are sent by using send_file_and_exit(SEND_BODY). | 1755 | /* Error pages are sent by using send_file_and_exit(SEND_BODY). |
1753 | * IOW: it is unsafe to call send_headers_and_exit | 1756 | * IOW: it is unsafe to call send_headers_and_exit |
1754 | * if what is SEND_BODY! Can recurse! */ | 1757 | * if what is SEND_BODY! Can recurse! */ |
@@ -1761,8 +1764,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) | |||
1761 | sprintf(G.etag, "\"%llx-%llx\"", (unsigned long long)last_mod, (unsigned long long)file_size); | 1764 | sprintf(G.etag, "\"%llx-%llx\"", (unsigned long long)last_mod, (unsigned long long)file_size); |
1762 | 1765 | ||
1763 | if (G.if_none_match) { | 1766 | if (G.if_none_match) { |
1764 | if (DEBUG) | 1767 | dbg("If-None-Match:'%s' file's ETag:'%s'\n", G.if_none_match, G.etag); |
1765 | bb_perror_msg("If-None-Match and file's ETag are: '%s' '%s'\n", G.if_none_match, G.etag); | ||
1766 | /* Weak ETag comparision. | 1768 | /* Weak ETag comparision. |
1767 | * If-None-Match may have many ETags but they are quoted so we can use simple substring search */ | 1769 | * If-None-Match may have many ETags but they are quoted so we can use simple substring search */ |
1768 | if (strstr(G.if_none_match, G.etag)) | 1770 | if (strstr(G.if_none_match, G.etag)) |
@@ -1838,9 +1840,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) | |||
1838 | } | 1840 | } |
1839 | } | 1841 | } |
1840 | 1842 | ||
1841 | if (DEBUG) | 1843 | dbg("sending file '%s' content-type:%s\n", url, found_mime_type); |
1842 | bb_error_msg("sending file '%s' content-type: %s", | ||
1843 | url, found_mime_type); | ||
1844 | 1844 | ||
1845 | #if ENABLE_FEATURE_HTTPD_RANGES | 1845 | #if ENABLE_FEATURE_HTTPD_RANGES |
1846 | if (what == SEND_BODY /* err pages and ranges don't mix */ | 1846 | if (what == SEND_BODY /* err pages and ranges don't mix */ |
@@ -1910,9 +1910,7 @@ static void if_ip_denied_send_HTTP_FORBIDDEN_and_exit(unsigned remote_ip) | |||
1910 | Htaccess_IP *cur; | 1910 | Htaccess_IP *cur; |
1911 | 1911 | ||
1912 | for (cur = G.ip_a_d; cur; cur = cur->next) { | 1912 | for (cur = G.ip_a_d; cur; cur = cur->next) { |
1913 | #if DEBUG | 1913 | dbg("checkPermIP: '%s' ? '%u.%u.%u.%u/%u.%u.%u.%u'\n", |
1914 | fprintf(stderr, | ||
1915 | "checkPermIP: '%s' ? '%u.%u.%u.%u/%u.%u.%u.%u'\n", | ||
1916 | rmt_ip_str, | 1914 | rmt_ip_str, |
1917 | (unsigned char)(cur->ip >> 24), | 1915 | (unsigned char)(cur->ip >> 24), |
1918 | (unsigned char)(cur->ip >> 16), | 1916 | (unsigned char)(cur->ip >> 16), |
@@ -1923,7 +1921,6 @@ static void if_ip_denied_send_HTTP_FORBIDDEN_and_exit(unsigned remote_ip) | |||
1923 | (unsigned char)(cur->mask >> 8), | 1921 | (unsigned char)(cur->mask >> 8), |
1924 | (unsigned char)(cur->mask) | 1922 | (unsigned char)(cur->mask) |
1925 | ); | 1923 | ); |
1926 | #endif | ||
1927 | if ((remote_ip & cur->mask) == cur->ip) { | 1924 | if ((remote_ip & cur->mask) == cur->ip) { |
1928 | if (cur->allow_deny == 'A') | 1925 | if (cur->allow_deny == 'A') |
1929 | return; | 1926 | return; |
@@ -2015,8 +2012,7 @@ static int check_user_passwd(const char *path, char *user_and_passwd) | |||
2015 | if (prev && strcmp(prev, dir_prefix) != 0) | 2012 | if (prev && strcmp(prev, dir_prefix) != 0) |
2016 | continue; | 2013 | continue; |
2017 | 2014 | ||
2018 | if (DEBUG) | 2015 | dbg("checkPerm: '%s' ? '%s'\n", dir_prefix, user_and_passwd); |
2019 | fprintf(stderr, "checkPerm: '%s' ? '%s'\n", dir_prefix, user_and_passwd); | ||
2020 | 2016 | ||
2021 | /* If it's not a prefix match, continue searching */ | 2017 | /* If it's not a prefix match, continue searching */ |
2022 | len = strlen(dir_prefix); | 2018 | len = strlen(dir_prefix); |
@@ -2231,8 +2227,22 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2231 | /* Install timeout handler. get_line() needs it. */ | 2227 | /* Install timeout handler. get_line() needs it. */ |
2232 | signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit); | 2228 | signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit); |
2233 | 2229 | ||
2234 | if (!get_line()) /* EOF or error or empty line */ | 2230 | if (!get_line()) { /* EOF or error or empty line */ |
2235 | send_headers_and_exit(HTTP_BAD_REQUEST); | 2231 | /* Observed Firefox to "speculatively" open |
2232 | * extra connections to a new site on first access, | ||
2233 | * they are closed in ~5 seconds with nothing | ||
2234 | * being sent at all. | ||
2235 | * (Presumably it's a method to decrease latency?) | ||
2236 | */ | ||
2237 | if (verbose > 2) | ||
2238 | bb_simple_error_msg("eof on read, closing"); | ||
2239 | /* Don't bother generating error page in this case, | ||
2240 | * just close the socket. | ||
2241 | */ | ||
2242 | //send_headers_and_exit(HTTP_BAD_REQUEST); | ||
2243 | _exit(xfunc_error_retval); | ||
2244 | } | ||
2245 | dbg("Request:'%s'\n", iobuf); | ||
2236 | 2246 | ||
2237 | /* Find URL */ | 2247 | /* Find URL */ |
2238 | // rfc2616: method and URI is separated by exactly one space | 2248 | // rfc2616: method and URI is separated by exactly one space |
@@ -2445,8 +2455,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2445 | if (total_headers_len >= MAX_HTTP_HEADERS_SIZE) | 2455 | if (total_headers_len >= MAX_HTTP_HEADERS_SIZE) |
2446 | send_headers_and_exit(HTTP_ENTITY_TOO_LARGE); | 2456 | send_headers_and_exit(HTTP_ENTITY_TOO_LARGE); |
2447 | #endif | 2457 | #endif |
2448 | if (DEBUG) | 2458 | dbg("header:'%s'\n", iobuf); |
2449 | bb_error_msg("header: '%s'", iobuf); | ||
2450 | #if ENABLE_FEATURE_HTTPD_CGI | 2459 | #if ENABLE_FEATURE_HTTPD_CGI |
2451 | /* Only POST needs to know POST_length */ | 2460 | /* Only POST needs to know POST_length */ |
2452 | if (prequest == request_POST && STRNCASECMP(iobuf, "Content-Length:") == 0) { | 2461 | if (prequest == request_POST && STRNCASECMP(iobuf, "Content-Length:") == 0) { |