diff options
| -rw-r--r-- | networking/httpd.c | 69 |
1 files changed, 45 insertions, 24 deletions
diff --git a/networking/httpd.c b/networking/httpd.c index 4c04df86f..ed6b0682e 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
| @@ -290,7 +290,29 @@ | |||
| 290 | //usage: "\n -e STRING HTML encode STRING" | 290 | //usage: "\n -e STRING HTML encode STRING" |
| 291 | //usage: "\n -d STRING URL decode STRING" | 291 | //usage: "\n -d STRING URL decode STRING" |
| 292 | 292 | ||
| 293 | /* TODO: use TCP_CORK, parse_config() */ | 293 | /* Robustness |
| 294 | * | ||
| 295 | * Even though the design is geared towards simplicity, it is meant to | ||
| 296 | * survive in a mildly adversarial environment: | ||
| 297 | * - it does not accept unlimited number of connections (-M MAXCONN) | ||
| 298 | * - it requires clients to send their incoming requests quickly | ||
| 299 | * (HEADER_READ_TIMEOUT) | ||
| 300 | * - if client stops consuming its result ("stalled receiver" attack), | ||
| 301 | * the server will drop the connection (DATA_WRITE_TIMEOUT) | ||
| 302 | * | ||
| 303 | * To limit the number of simultaneously running CGI children, | ||
| 304 | * you may use the helper tool, httpd_ratelimit_cgi.c: | ||
| 305 | * it replies with "429 Too Many Requests" and exits when limit is exceeded. | ||
| 306 | * The limit can be set per CGI type: "I accept up to 256 connections, | ||
| 307 | * but only up to 100 of them may be to /cgi-bin/simple_cgi, | ||
| 308 | * and 20 to /cgi-bin/HEAVY_cgi". | ||
| 309 | * | ||
| 310 | * TODO: | ||
| 311 | * - do not allow all MAXCONN connections be taken up by the same remote IP. | ||
| 312 | */ | ||
| 313 | #define HEADER_READ_TIMEOUT 30 | ||
| 314 | #define DATA_WRITE_TIMEOUT 60 | ||
| 315 | |||
| 294 | 316 | ||
| 295 | #include "libbb.h" | 317 | #include "libbb.h" |
| 296 | #include "common_bufsiz.h" | 318 | #include "common_bufsiz.h" |
| @@ -322,9 +344,6 @@ | |||
| 322 | #define IOBUF_SIZE 8192 | 344 | #define IOBUF_SIZE 8192 |
| 323 | #define MAX_HTTP_HEADERS_SIZE (32*1024) | 345 | #define MAX_HTTP_HEADERS_SIZE (32*1024) |
| 324 | 346 | ||
| 325 | #define HEADER_READ_TIMEOUT 30 | ||
| 326 | #define DATA_WRITE_TIMEOUT 60 | ||
| 327 | |||
| 328 | #define STR1(s) #s | 347 | #define STR1(s) #s |
| 329 | #define STR(s) STR1(s) | 348 | #define STR(s) STR1(s) |
| 330 | 349 | ||
| @@ -699,6 +718,7 @@ static int scan_ip_mask(const char *str, unsigned *ipp, unsigned *maskp) | |||
| 699 | * path Path where to look for httpd.conf (without filename). | 718 | * path Path where to look for httpd.conf (without filename). |
| 700 | * flag Type of the parse request. | 719 | * flag Type of the parse request. |
| 701 | */ | 720 | */ |
| 721 | //TODO: use parse_config() from libbb? | ||
| 702 | /* flag param: */ | 722 | /* flag param: */ |
| 703 | enum { | 723 | enum { |
| 704 | FIRST_PARSE = 0, /* path will be "/etc" */ | 724 | FIRST_PARSE = 0, /* path will be "/etc" */ |
| @@ -1062,24 +1082,24 @@ static int openServer(void) | |||
| 1062 | 1082 | ||
| 1063 | /* | 1083 | /* |
| 1064 | * Log the connection closure and exit. | 1084 | * Log the connection closure and exit. |
| 1085 | * Two variants: one signals EOF (clean termination), | ||
| 1086 | * the other might signal that connection is reset, not closed normally | ||
| 1087 | * (usually RST is sent if there is unsent buffered data in the socket buffer). | ||
| 1065 | */ | 1088 | */ |
| 1066 | static void log_and_exit(void) NORETURN; | 1089 | static void log_and_exit(void) NORETURN; |
| 1067 | static void log_and_exit(void) | 1090 | static void log_and_exit(void) |
| 1068 | { | 1091 | { |
| 1069 | /* Paranoia. IE said to be buggy. It may send some extra data | ||
| 1070 | * or be confused by us just exiting without SHUT_WR. Oh well. */ | ||
| 1071 | shutdown(STDOUT_FILENO, SHUT_WR); | ||
| 1072 | /* Why?? | ||
| 1073 | (this also messes up stdin when user runs httpd -i from terminal) | ||
| 1074 | ndelay_on(0); | ||
| 1075 | while (read(STDIN_FILENO, iobuf, IOBUF_SIZE) > 0) | ||
| 1076 | continue; | ||
| 1077 | */ | ||
| 1078 | |||
| 1079 | if (VERBOSE_3) | 1092 | if (VERBOSE_3) |
| 1080 | bb_simple_error_msg("closed"); | 1093 | bb_simple_error_msg("closed"); |
| 1081 | _exit(xfunc_error_retval); | 1094 | _exit(xfunc_error_retval); |
| 1082 | } | 1095 | } |
| 1096 | static void send_EOF_and_exit(void) NORETURN; | ||
| 1097 | static void send_EOF_and_exit(void) | ||
| 1098 | { | ||
| 1099 | /* This makes sure on TCP level, the connection is closed with FIN, not RST */ | ||
| 1100 | shutdown(STDOUT_FILENO, SHUT_WR); | ||
| 1101 | log_and_exit(); | ||
| 1102 | } | ||
| 1083 | 1103 | ||
| 1084 | /* | 1104 | /* |
| 1085 | * Create and send HTTP response headers. | 1105 | * Create and send HTTP response headers. |
| @@ -1304,7 +1324,7 @@ static void send_headers_and_exit(int responseNum) | |||
| 1304 | IF_FEATURE_HTTPD_GZIP(content_gzip = 0;) | 1324 | IF_FEATURE_HTTPD_GZIP(content_gzip = 0;) |
| 1305 | file_size = -1; /* no Last-Modified:, ETag:, Content-Length: */ | 1325 | file_size = -1; /* no Last-Modified:, ETag:, Content-Length: */ |
| 1306 | send_headers(responseNum); | 1326 | send_headers(responseNum); |
| 1307 | log_and_exit(); | 1327 | send_EOF_and_exit(); |
| 1308 | } | 1328 | } |
| 1309 | 1329 | ||
| 1310 | /* | 1330 | /* |
| @@ -1436,7 +1456,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post | |||
| 1436 | bb_error_msg("CGI killed, signal=%u", WTERMSIG(status)); | 1456 | bb_error_msg("CGI killed, signal=%u", WTERMSIG(status)); |
| 1437 | } | 1457 | } |
| 1438 | #endif | 1458 | #endif |
| 1439 | break; | 1459 | send_EOF_and_exit(); |
| 1440 | } | 1460 | } |
| 1441 | 1461 | ||
| 1442 | if (pfd[TO_CGI].revents) { | 1462 | if (pfd[TO_CGI].revents) { |
| @@ -1500,7 +1520,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post | |||
| 1500 | full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1); | 1520 | full_write(STDOUT_FILENO, HTTP_200, sizeof(HTTP_200)-1); |
| 1501 | full_write(STDOUT_FILENO, rbuf, out_cnt); | 1521 | full_write(STDOUT_FILENO, rbuf, out_cnt); |
| 1502 | } | 1522 | } |
| 1503 | break; /* CGI stdout is closed, exiting */ | 1523 | send_EOF_and_exit(); /* CGI stdout is closed, exiting */ |
| 1504 | } | 1524 | } |
| 1505 | out_cnt += count; | 1525 | out_cnt += count; |
| 1506 | count = 0; | 1526 | count = 0; |
| @@ -1535,7 +1555,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post | |||
| 1535 | } else { | 1555 | } else { |
| 1536 | count = safe_read(fromCgi_rd, rbuf, IOBUF_SIZE); | 1556 | count = safe_read(fromCgi_rd, rbuf, IOBUF_SIZE); |
| 1537 | if (count <= 0) | 1557 | if (count <= 0) |
| 1538 | break; /* eof (or error) */ | 1558 | send_EOF_and_exit(); /* eof (or error) */ |
| 1539 | } | 1559 | } |
| 1540 | if (full_write(STDOUT_FILENO, rbuf, count) != count) | 1560 | if (full_write(STDOUT_FILENO, rbuf, count) != count) |
| 1541 | break; | 1561 | break; |
| @@ -1794,10 +1814,10 @@ static NOINLINE void send_file_and_exit(const char *url, int what) | |||
| 1794 | dbg("can't open '%s'\n", url); | 1814 | dbg("can't open '%s'\n", url); |
| 1795 | /* Error pages are sent by using send_file_and_exit(SEND_BODY). | 1815 | /* Error pages are sent by using send_file_and_exit(SEND_BODY). |
| 1796 | * IOW: it is unsafe to call send_headers_and_exit | 1816 | * IOW: it is unsafe to call send_headers_and_exit |
| 1797 | * if what is SEND_BODY! Can recurse! */ | 1817 | * if "what" is SEND_BODY! Can recurse! */ |
| 1798 | if (what != SEND_BODY) | 1818 | if (what != SEND_BODY) |
| 1799 | send_headers_and_exit(HTTP_NOT_FOUND); | 1819 | send_headers_and_exit(HTTP_NOT_FOUND); |
| 1800 | log_and_exit(); | 1820 | send_EOF_and_exit(); |
| 1801 | } | 1821 | } |
| 1802 | #if ENABLE_FEATURE_HTTPD_ETAG | 1822 | #if ENABLE_FEATURE_HTTPD_ETAG |
| 1803 | /* ETag is "hex(last_mod)-hex(file_size)" e.g. "5e132e20-417" */ | 1823 | /* ETag is "hex(last_mod)-hex(file_size)" e.g. "5e132e20-417" */ |
| @@ -1925,17 +1945,17 @@ static NOINLINE void send_file_and_exit(const char *url, int what) | |||
| 1925 | if (offset == range_start) /* was it the very 1st sendfile? */ | 1945 | if (offset == range_start) /* was it the very 1st sendfile? */ |
| 1926 | break; /* fall back to read/write loop */ | 1946 | break; /* fall back to read/write loop */ |
| 1927 | if (VERBOSE_1) { | 1947 | if (VERBOSE_1) { |
| 1928 | if (errno == EAGAIN) | ||
| 1929 | errno = ETIMEDOUT; | ||
| 1930 | // SO_SNDTIME on our socket causes write timeouts manifest as EAGAIN "Resource temporarily unavailable". | 1948 | // SO_SNDTIME on our socket causes write timeouts manifest as EAGAIN "Resource temporarily unavailable". |
| 1931 | // Not the best error message (when reading the log: "Er... what resource?!") | 1949 | // Not the best error message (when reading the log: "Er... what resource?!") |
| 1950 | if (errno == EAGAIN) | ||
| 1951 | errno = ETIMEDOUT; | ||
| 1932 | bb_simple_perror_msg("sendfile error"); | 1952 | bb_simple_perror_msg("sendfile error"); |
| 1933 | } | 1953 | } |
| 1934 | log_and_exit(); | 1954 | log_and_exit(); |
| 1935 | } | 1955 | } |
| 1936 | IF_FEATURE_HTTPD_RANGES(range_len -= count;) | 1956 | IF_FEATURE_HTTPD_RANGES(range_len -= count;) |
| 1937 | if (count == 0 || range_len == 0) | 1957 | if (count == 0 || range_len == 0) |
| 1938 | log_and_exit(); | 1958 | send_EOF_and_exit(); |
| 1939 | } | 1959 | } |
| 1940 | } | 1960 | } |
| 1941 | #endif | 1961 | #endif |
| @@ -1948,6 +1968,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) | |||
| 1948 | if (errno == EAGAIN) | 1968 | if (errno == EAGAIN) |
| 1949 | errno = ETIMEDOUT; | 1969 | errno = ETIMEDOUT; |
| 1950 | bb_simple_perror_msg("write error"); | 1970 | bb_simple_perror_msg("write error"); |
| 1971 | log_and_exit(); | ||
| 1951 | } | 1972 | } |
| 1952 | break; | 1973 | break; |
| 1953 | } | 1974 | } |
| @@ -1959,7 +1980,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) | |||
| 1959 | if (VERBOSE_1) | 1980 | if (VERBOSE_1) |
| 1960 | bb_simple_perror_msg("read error"); | 1981 | bb_simple_perror_msg("read error"); |
| 1961 | } | 1982 | } |
| 1962 | log_and_exit(); | 1983 | send_EOF_and_exit(); |
| 1963 | } | 1984 | } |
| 1964 | 1985 | ||
| 1965 | #if ENABLE_FEATURE_HTTPD_ACL_IP | 1986 | #if ENABLE_FEATURE_HTTPD_ACL_IP |
