commit b3dc5f8

uint  ·  2026-01-28 23:25:34 +0000 UTC
parent b2b738a
add rlimits, CLOEXEC, socket io timeouts

.
5 files changed,  +110, -6
+19, -0
 1@@ -91,6 +91,25 @@ Example:
 2 .Bd -literal -offset indent
 3 cors_origin=http://127.0.0.1:8000
 4 .Ed
 5+
 6+.It Ic http_io_timeout
 7+Maximum number of seconds the server will block on a single socket
 8+read/write operation.
 9+.Pp
10+This limits how long a client may stall for while sending a request or
11+while receiving a response.
12+If the timeout is exceeded, the connection is closed.
13+.Pp
14+This option used for protecting against stalled or bad-acting clients.
15+This does not limit the duration of a request or stream, only I/O operations.
16+.Pp
17+Valid values are integers in the range 1 to 300.
18+.Pp
19+Example:
20+.Bd -literal -offset indent
21+http_io_timeout=5
22+.Ed
23+
24 .El
25 .Sh AUTHENTICATION
26 Authentication entries are specified using repeated groups of the keys
+12, -0
 1@@ -28,6 +28,18 @@ server_port=8088
 2 #verbose_log=false
 3 verbose_log=true
 4 
 5+# Security
 6+#
 7+# HTTP IO timeout (in seconds)
 8+#
 9+# Limits how long the server will block on a single socket read/write.
10+# This does not apply for requests/streaming.
11+# If a client stops sending data or stops reading responses for longer
12+# than this value, the connection is dropped.
13+#
14+# Recommended:  LAN=5, WAN/VPN/Mobile=15-30
15+http_io_timeout=5
16+
17 # Cross-Origin Resource Sharing (CORS)
18 #
19 # Controls which web origins may access the API.
+20, -3
 1@@ -18,6 +18,7 @@ char server_addr[64] = "127.0.0.1";
 2 int  server_port = 8088;
 3 bool verbose_log = true;
 4 char cors_origin[1024] = "";
 5+int http_io_timeout = 5;
 6 
 7 static int load_path(const char* path)
 8 {
 9@@ -104,12 +105,23 @@ static int set_kv(const char* k, const char* v)
10 		return 0;
11 	}
12 
13-	/* auth */
14 	if (strcmp(k, "cors_origin") == 0) {
15 		snprintf(cors_origin, sizeof(cors_origin), "%s", v);
16 		return 0;
17 	}
18 
19+	if (strcmp(k, "io_timeout_sec") == 0) {
20+		char* end = NULL;
21+		long t = strtol(v, &end, 10);
22+		if (!end || *end != '\0')
23+			return -1;
24+		if (t < 1 || t > 300)
25+			return -1;
26+		http_io_timeout = (int)t;
27+		return 0;
28+	}
29+
30+	/* auth */
31 	if (strcmp(k, "user") == 0) {
32 		return users_push(v);
33 	}
34@@ -166,15 +178,20 @@ void config_load(void)
35 	return;
36 
37 log:
38+	(void)0;
39+
40+	char port[8];
41+	char tmo[16];
42+
43 	LOG(true, "CONF", "Config File        %s", path);
44 	LOG(true, "CONF", "Media Directory    %s", media_dir);
45 	LOG(true, "CONF", "Server Address     %s", server_addr);
46-
47-	char port[8];
48 	snprintf(port, sizeof(port), "%d", server_port);
49 	LOG(true, "CONF", "Server Port        %s", port);
50 	LOG(true, "CONF", "Verbose Logging    %s", (verbose_log) ? "true" : "false");
51 	LOG(true, "CONF", "CORS origins       %s", cors_origin);
52+	snprintf(tmo, sizeof(tmo), "%d", http_io_timeout);
53+	LOG(true, "CONF", "HTTP IO Timeout    %s", tmo);
54 
55 	return;
56 }
+3, -2
 1@@ -7,9 +7,10 @@
 2 
 3 extern char media_dir[4096];
 4 extern char server_addr[64];
 5-extern int server_port;
 6-extern bool verbose_log;
 7 extern char cors_origin[1024];
 8+extern bool verbose_log;
 9+extern int server_port;
10+extern int http_io_timeout;
11 
12 enum {
13 	HTTP_REQ_MAX   = 8192,
+56, -1
  1@@ -9,6 +9,7 @@
  2 */
  3 
  4 #include <errno.h>
  5+#include <fcntl.h>
  6 #include <signal.h>
  7 #include <stdarg.h>
  8 #include <stdbool.h>
  9@@ -16,7 +17,9 @@
 10 #include <stdio.h>
 11 #include <stdlib.h>
 12 #include <string.h>
 13+#include <sys/resource.h>
 14 #include <sys/socket.h>
 15+#include <sys/time.h>
 16 #include <time.h>
 17 #include <unistd.h>
 18 
 19@@ -28,6 +31,10 @@
 20 #include "log.h"
 21 #include "scan.h"
 22 
 23+static void apply_rlimits(void);
 24+static void fd_set_cloexec(int fd);
 25+static void sock_set_timeouts(int fd);
 26+
 27 void die(const char* s, int e);
 28 void run(void);
 29 void setup(void);
 30@@ -35,6 +42,40 @@ void setup(void);
 31 int sock;
 32 struct library lib;
 33 
 34+static void apply_rlimits(void)
 35+{
 36+	struct rlimit rl;
 37+
 38+	rl.rlim_cur = 0;
 39+	rl.rlim_max = 0;
 40+	(void)setrlimit(RLIMIT_CORE, &rl);
 41+
 42+	rl.rlim_cur = 1024;
 43+	rl.rlim_max = 1024;
 44+	(void)setrlimit(RLIMIT_NOFILE, &rl);
 45+
 46+	rl.rlim_cur = 256;
 47+	rl.rlim_max = 256;
 48+	(void)setrlimit(RLIMIT_NPROC, &rl);
 49+}
 50+
 51+static void fd_set_cloexec(int fd)
 52+{
 53+	int f = fcntl(fd, F_GETFD);
 54+	if (f >= 0)
 55+		(void)fcntl(fd, F_SETFD, f | FD_CLOEXEC);
 56+}
 57+
 58+static void sock_set_timeouts(int fd)
 59+{
 60+	struct timeval tv;
 61+	tv.tv_sec = http_io_timeout;
 62+	tv.tv_usec = 0;
 63+
 64+	(void)setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
 65+	(void)setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
 66+}
 67+
 68 void die(const char* s, int e)
 69 {
 70 	perror(s);
 71@@ -50,6 +91,7 @@ void run(void)
 72 				continue;
 73 			continue;
 74 		}
 75+		fd_set_cloexec(c);
 76 		LOG(verbose_log, "CORE", "Connection         Accepted");
 77 
 78 		pid_t pid = fork();
 79@@ -59,6 +101,11 @@ void run(void)
 80 		}
 81 
 82 		if (pid == 0) {
 83+#ifdef __OpenBSD__
 84+			if (pledge("stdio inet rpath", NULL) < 0)
 85+				_exit(EXIT_FAILURE);
 86+#endif
 87+			sock_set_timeouts(c);
 88 			(void)http_handle(c);
 89 			shutdown(c, SHUT_WR);
 90 			close(c);
 91@@ -76,11 +123,13 @@ void setup(void)
 92 								 them to turn into zombies */
 93 
 94 	config_load();
 95+	apply_rlimits();
 96 
 97 	int ret = 1;
 98 	sock = socket(AF_INET, SOCK_STREAM, 0);
 99 	if (sock < 0)
100 		die("socket", EXIT_FAILURE);
101+	fd_set_cloexec(sock);
102 
103 	int yes = 1;
104 	ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
105@@ -108,6 +157,12 @@ void setup(void)
106 		die("listen", EXIT_FAILURE);
107 
108 	LOG(verbose_log, "CORE", "Listening on       %s:%d", server_addr, server_port);
109+#ifdef __OpenBSD__
110+	if (unveil(media_dir, "r") < 0)
111+		die("unveil", EXIT_FAILURE);
112+	if (unveil(NULL, NULL) < 0)
113+		die("unveil", EXIT_FAILURE);
114+#endif
115 }
116 
117 int main(int argc, char* argv[])
118@@ -134,7 +189,7 @@ int main(int argc, char* argv[])
119 
120 	setup();
121 #ifdef __OpenBSD__
122-	if (pledge("stdio inet", NULL) < 0)
123+	if (pledge("stdio inet proc rpath", NULL) < 0)
124 		die("pledge", EXIT_FAILURE);
125 #endif /* __OpenBSD__ */
126 	run();