aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--networking/httpd.c69
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: */
703enum { 723enum {
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 */
1066static void log_and_exit(void) NORETURN; 1089static void log_and_exit(void) NORETURN;
1067static void log_and_exit(void) 1090static 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}
1096static void send_EOF_and_exit(void) NORETURN;
1097static 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