1 /*
2    onenetd: a single-process inetd equivalent
3    Copyright 2001, 2002, 2003, 2005, 2014 Adam Sampson <ats@offog.org>
4 
5    Permission to use, copy, modify, and/or distribute this software for any
6    purpose with or without fee is hereby granted, provided that the above
7    copyright notice and this permission notice appear in all copies.
8 
9    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17 
18 #include <unistd.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/socket.h>
22 #include <netdb.h>
23 #include <netinet/in.h>
24 #include <netinet/tcp.h>
25 #include <arpa/inet.h>
26 #include <sys/time.h>
27 #include <sys/types.h>
28 #include <signal.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <sys/wait.h>
32 #include <stdio.h>
33 #include "config.h"
34 
35 int max_conns = 40;
36 int conn_count = 0;
37 int bind_family = AF_INET;
38 int use_gid = 0;
39 gid_t gid = 0;
40 int use_uid = 0;
41 uid_t uid = 0;
42 int show_port = 0;
43 int backlog = 10;
44 int no_delay = 0;
45 int verbose = 0;
46 int stderr_to_socket = 0;
47 char *response = NULL;
48 char **command;
49 
50 /* This pipe is used to safely detect SIGCHLD: the SIGCHLD handler writes a
51    character to it, and the main loop can then reap children later.
52    (See http://cr.yp.to/docs/selfpipe.html for details.) */
53 int selfpipe[2];
54 
55 typedef struct client {
56 	int fd;
57 	char *message;
58 	size_t left;
59 	struct client *next;
60 } client;
61 client *clients = NULL;
62 
63 /* Structure big enough to contain either an IPv4 or IPv6 socket address. */
64 typedef union {
65 	struct sockaddr_in v4;
66 	struct sockaddr_in6 v6;
67 } either_addr_t;
68 
69 /* Get the UCSPI PROTO value for an address. */
get_proto(const either_addr_t * addr)70 const char *get_proto(const either_addr_t *addr) {
71 	if (addr->v4.sin_family == AF_INET6
72 		&& !IN6_IS_ADDR_V4MAPPED(&addr->v6.sin6_addr))
73 		return "TCP6";
74 	else
75 		return "TCP";
76 }
77 
78 /* Get the UCSPI *IP value for an address.
79    Returns a pointer to a static buffer. */
get_addr(const either_addr_t * addr)80 const char *get_addr(const either_addr_t *addr) {
81 	static char buf[INET6_ADDRSTRLEN];
82 	const void *src;
83 	int family = addr->v4.sin_family;
84 
85 	if (family == AF_INET) {
86 		src = &addr->v4.sin_addr;
87 	} else if (IN6_IS_ADDR_V4MAPPED(&addr->v6.sin6_addr)) {
88 		/* An IPv4-mapped IPv6 address; display as IPv4. */
89 		family = AF_INET;
90 		src = ((char *)(&addr->v6.sin6_addr)) + 12;
91 	} else {
92 		src = &addr->v6.sin6_addr;
93 	}
94 
95 	const char *s = inet_ntop(family, src, buf, sizeof buf);
96 	if (s == NULL)
97 		return "-";
98 	return s;
99 }
100 
101 /* Get the UCSPI *PORT value for an address. */
get_port(const either_addr_t * addr)102 int get_port(const either_addr_t *addr) {
103 	if (addr->v4.sin_family == AF_INET)
104 		return ntohs(addr->v4.sin_port);
105 	else
106 		return ntohs(addr->v6.sin6_port);
107 }
108 
109 /* Print a warning. */
warn(const char * msg)110 void warn(const char *msg) {
111 	fprintf(stderr, "%s\n", msg);
112 }
113 
114 /* Die with an error message. */
die(const char * msg)115 void die(const char *msg) {
116 	warn(msg);
117 	exit(20);
118 }
119 
120 /* Handle SIGCHLD. */
handle_sigchld(int dummy)121 void handle_sigchld(int dummy) {
122 	int old_errno = errno;
123 	write(selfpipe[1], "c", 1);
124 	errno = old_errno;
125 }
126 
127 /* Change the flags on an fd. */
change_flags(int fd,int add,int remove)128 int change_flags(int fd, int add, int remove) {
129 	int flags = fcntl(fd, F_GETFL);
130 	int newflags;
131 	if (flags == -1)
132 		return -1;
133 
134 	newflags = (flags | add) & ~remove;
135 
136 	if (newflags != flags) {
137 		if (fcntl(fd, F_SETFL, flags) < 0)
138 			return -1;
139 	}
140 
141 	return 0;
142 }
143 
144 /* Set the FD_CLOEXEC flag on an fd. */
set_fd_cloexec(int fd)145 void set_fd_cloexec(int fd) {
146 	if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
147 		die("unable to set FD_CLOEXEC");
148 }
149 
150 /* Add an fd to an FD_SET, updating a maximum. */
fd_set_add(int fd,fd_set * fds,int * max)151 void fd_set_add(int fd, fd_set *fds, int *max) {
152 	FD_SET(fd, fds);
153 	if (fd > *max) *max = fd;
154 }
155 
156 /* Equivalent to putenv(strdup(s)), with error checking. */
putenv_dup(const char * s)157 int putenv_dup(const char *s) {
158 	char *copy = strdup(s);
159 	if (copy == NULL)
160 		die("strdup failed");
161 
162 	return putenv(copy);
163 }
164 
165 /* Print the usage message. */
usage(int code)166 void usage(int code) {
167 	fprintf(stderr, "onenetd version " VERSION "\n"
168 		"\n"
169 		"Usage: onenetd [options] address port command ...\n"
170 		"  address  Address to bind to (0 for all local addresses)\n"
171 		"  port     TCP port to bind to (0 for any available port)\n"
172 		"  command  Command to execute\n"
173 		"Options:\n"
174 		"  -c N     limit to at most N children running (default 40).\n"
175 		"           Further connections will be deferred unless -r\n"
176 		"           is specified.\n"
177 		"  -6       bind to an IPv6 address (default IPv4)\n"
178 		"  -g gid   setgid(gid) after binding\n"
179 		"  -u uid   setuid(uid) after binding\n"
180 		"  -U       setuid($UID) and setgid($GID) after binding\n"
181 		"  -1       print local port number to stdout after binding\n"
182 		"  -b N     set listen() backlog to N\n"
183 		"  -D       set TCP_NODELAY option on sockets\n"
184 		"  -e       redirect stderr of children to socket\n"
185 		"  -v       be verbose\n"
186 		"  -Q       don't be verbose (default)\n"
187 		"  -r resp  once -c limit is reached, refuse clients\n"
188 		"           with 'resp' rather than deferring them.\n"
189 		"           resp may contain \\r, \\n, \\t.\n"
190 		"  -h       show this usage message\n"
191 		"\n"
192 		"Report bugs to <ats@offog.org>.\n");
193 	exit(code);
194 }
195 
196 /* Create and bind the listening socket. */
make_listen_socket(const char * address,const char * port)197 int make_listen_socket(const char *address, const char *port) {
198 	struct addrinfo hints = {};
199 	struct addrinfo *ai;
200 	int rc, n, fd;
201 
202 	hints.ai_family = bind_family;
203 	hints.ai_socktype = SOCK_STREAM;
204 	hints.ai_flags = AI_PASSIVE;
205 	hints.ai_protocol = 0;
206 
207 	rc = getaddrinfo(address, port, &hints, &ai);
208 	if (rc != 0) {
209 		die(gai_strerror(rc));
210 	}
211 
212 	fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
213 	if (fd < 0)
214 		die("unable to create socket");
215 	if (change_flags(fd, O_NONBLOCK, 0) < 0)
216 		die("unable to set O_NONBLOCK");
217 	set_fd_cloexec(fd);
218 	n = 1;
219 	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n) < 0)
220 		die("unable to set SO_REUSEADDR");
221 	if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0)
222 		die("unable to bind to listen address");
223 	if (listen(fd, backlog) < 0)
224 		die("unable to listen");
225 
226 	if (show_port) {
227 		either_addr_t addr;
228 		socklen_t size = sizeof addr;
229 
230 		if (getsockname(fd, (struct sockaddr *)&addr, &size) < 0)
231 			die("unable to get bound address");
232 
233 		printf("%d\n", get_port(&addr));
234 		fflush(stdout);
235 	}
236 
237 	freeaddrinfo(ai);
238 
239 	return fd;
240 }
241 
242 /* Try to send a chunk of the response to a client. Remove the client
243    from the list if we've sent all of it. */
try_to_send(client * prev_cl,client * cl)244 void try_to_send(client *prev_cl, client *cl) {
245 	int remove = 0;
246 	ssize_t count = write(cl->fd, cl->message, cl->left);
247 
248 	if (count >= 0) {
249 		cl->message += count;
250 		cl->left -= count;
251 
252 		if (cl->left == 0)
253 			remove = 1;
254 	} else if (errno == EAGAIN) {
255 		/* ignorable error */
256 	} else {
257 		/* another error while writing */
258 		remove = 1;
259 	}
260 
261 	if (remove) {
262 		close(cl->fd);
263 		if (prev_cl) {
264 			prev_cl->next = cl->next;
265 		} else {
266 			clients = cl->next;
267 		}
268 		free(cl);
269 	}
270 }
271 
272 /* Accept a new connection, and either spawn a new child process or add it to
273    the list of clients to reject. */
accept_connection(int listen_fd,int full)274 void accept_connection(int listen_fd, int full) {
275 	pid_t pid;
276 	either_addr_t local_addr, child_addr;
277 	socklen_t len = sizeof child_addr;
278 	int child_fd;
279 	int n;
280 
281 	child_fd = accept(listen_fd, (struct sockaddr *)&child_addr, &len);
282 	if (len > sizeof child_addr) {
283 		warn("unable to get remote address");
284 		goto no_conn;
285 	}
286 	if (child_fd < 0 && errno == EAGAIN)
287 		goto no_conn;
288 	if (child_fd < 0) {
289 		warn("accept failed");
290 		goto no_conn;
291 	}
292 	set_fd_cloexec(child_fd);
293 
294 	len = sizeof local_addr;
295 	if (getsockname(child_fd, (struct sockaddr *)&local_addr, &len) < 0
296 		|| len > sizeof local_addr) {
297 		warn("unable to get local address");
298 		goto no_conn;
299 	}
300 
301 	if (full) {
302 		client *cl;
303 
304 		/* Avoid overfilling the fd_set. */
305 		if (child_fd >= FD_SETSIZE && verbose) {
306 			fprintf(stderr, "- dropped from %s port %d\n",
307 				get_addr(&child_addr),
308 				get_port(&child_addr));
309 		}
310 		if (child_fd >= FD_SETSIZE)
311 			goto no_conn;
312 
313 		if (change_flags(child_fd, O_NONBLOCK, 0) < 0) {
314 			warn("unable to set O_NONBLOCK");
315 			goto no_conn;
316 		}
317 
318 		cl = malloc(sizeof *cl);
319 		if (!cl) {
320 			warn("out of memory");
321 			goto no_conn;
322 		}
323 
324 		cl->fd = child_fd;
325 		child_fd = -1;
326 		cl->message = response;
327 		cl->left = strlen(cl->message);
328 		cl->next = clients;
329 		clients = cl;
330 
331 		if (verbose)
332 			fprintf(stderr, "- refused from %s port %d\n",
333 				get_addr(&child_addr),
334 				get_port(&child_addr));
335 
336 		/* Try to send the response now; if we send
337 		   all of it it'll get removed from the list
338 		   again. */
339 		try_to_send(NULL, cl);
340 
341 		goto no_conn;
342 	}
343 
344 	n = 1;
345 	if (no_delay && setsockopt(child_fd, IPPROTO_TCP,
346 		TCP_NODELAY, &n, sizeof n) < 0) {
347 		warn("unable to set TCP_NODELAY");
348 		goto no_conn;
349 	}
350 
351 	pid = fork();
352 	if (pid < 0) {
353 		warn("fork failed");
354 		goto no_conn;
355 	}
356 	if (pid == 0) {
357 		char buf[80];
358 
359 		dup2(child_fd, 0);
360 		dup2(child_fd, 1);
361 		if (stderr_to_socket)
362 			dup2(child_fd, 2);
363 
364 		snprintf(buf, sizeof buf, "PROTO=%s",
365 			get_proto(&local_addr));
366 		putenv_dup(buf);
367 		snprintf(buf, sizeof buf, "TCPLOCALIP=%s",
368 			get_addr(&local_addr));
369 		putenv_dup(buf);
370 		snprintf(buf, sizeof buf, "TCPLOCALPORT=%d",
371 			get_port(&local_addr));
372 		putenv_dup(buf);
373 		snprintf(buf, sizeof buf, "TCPREMOTEIP=%s",
374 			get_addr(&child_addr));
375 		putenv_dup(buf);
376 		snprintf(buf, sizeof buf, "TCPREMOTEPORT=%d",
377 			get_port(&child_addr));
378 		putenv_dup(buf);
379 
380 		execvp(command[0], command);
381 		_exit(20);
382 	}
383 
384 	conn_count++;
385 	if (verbose)
386 		fprintf(stderr, "%ld connected from %s port %d (%d/%d)\n",
387 			(long) pid,
388 			get_addr(&child_addr),
389 			get_port(&child_addr),
390 			conn_count, max_conns);
391 
392 no_conn:
393 	if (child_fd >= 0)
394 		close(child_fd);
395 }
396 
397 /* Check for child processes that have exited. */
reap_children(void)398 void reap_children(void) {
399 	while (1) {
400 		pid_t pid = waitpid(-1, NULL, WNOHANG);
401 		if (pid <= 0)
402 			break;
403 
404 		conn_count--;
405 		if (verbose)
406 			fprintf(stderr, "%ld closed (%d/%d)\n",
407 				(long) pid, conn_count, max_conns);
408 	}
409 }
410 
main(int argc,char ** argv)411 int main(int argc, char **argv) {
412 	struct sigaction sa;
413 	sigset_t sig_chld;
414 	int listen_fd;
415 	char *s, *r;
416 	int n;
417 
418 	while (1) {
419 		int c = getopt(argc, argv, "+c:6g:u:U1b:DQvehr:");
420 		if (c == -1)
421 			break;
422 		switch (c) {
423 		case 'c':
424 			max_conns = atoi(optarg);
425 			break;
426 		case '6':
427 			bind_family = AF_INET6;
428 			break;
429 		case 'g':
430 			use_gid = 1;
431 			gid = atoi(optarg);
432 			break;
433 		case 'u':
434 			use_uid = 1;
435 			uid = atoi(optarg);
436 			break;
437 		case 'U':
438 			s = getenv("GID");
439 			if (!s)
440 				die("-U specified but no $GID");
441 			use_gid = 1;
442 			gid = atoi(s);
443 			s = getenv("UID");
444 			if (!s)
445 				die("-U specified but no $UID");
446 			use_uid = 1;
447 			uid = atoi(s);
448 			break;
449 		case '1':
450 			show_port = 1;
451 			break;
452 		case 'b':
453 			backlog = atoi(optarg);
454 			break;
455 		case 'D':
456 			no_delay = 1;
457 			break;
458 		case 'Q':
459 			verbose = 0;
460 			break;
461 		case 'v':
462 			verbose = 1;
463 			break;
464 		case 'e':
465 			stderr_to_socket = 1;
466 			break;
467 		case 'h':
468 			usage(0);
469 			break;
470 		case 'r':
471 			r = response = malloc(strlen(optarg) + 1);
472 			if (!r)
473 				die("out of memory");
474 			for (s = optarg; *s != '\0'; s++) {
475 				if (*s == '\\') {
476 					s++;
477 					if (*s == 'r')
478 						*r++ = '\r';
479 					else if (*s == 'n')
480 						*r++ = '\n';
481 					else if (*s == 't')
482 						*r++ = '\t';
483 					else
484 						usage(20);
485 				} else {
486 					*r++ = *s;
487 				}
488 			}
489 			*r = '\0';
490 			break;
491 		default:
492 			usage(20);
493 		}
494 	}
495 
496 	if ((argc - optind) < 3)
497 		usage(20);
498 
499 	listen_fd = make_listen_socket(argv[optind], argv[optind + 1]);
500 	command = &argv[optind + 2];
501 
502 	/* Drop privileges. */
503 	if (use_gid)
504 		if (setgid(gid) < 0)
505 			die("unable to setgid");
506 	if (use_uid)
507 		if (setuid(uid) < 0)
508 			die("unable to setuid");
509 
510 	/* Create the self-pipe. */
511 	if (pipe(selfpipe) < 0)
512 		die("unable to create self-pipe");
513 	if (change_flags(selfpipe[1], O_NONBLOCK, 0) < 0)
514 		die("unable to set O_NONBLOCK");
515 	set_fd_cloexec(selfpipe[0]);
516 	set_fd_cloexec(selfpipe[1]);
517 
518         /* Mask SIGCHLD, except when we're blocked in select(). This is because
519            many of the system calls we use are interruptable, and we'd
520            otherwise have to handle EINTR everywhere.  (It would be simpler to
521            just use SA_RESTART for SIGCHLD -- but POSIX says that it's
522            implementation-defined whether select() is interrupted in that case
523            or not.) */
524 	sigemptyset(&sig_chld);
525 	sigaddset(&sig_chld, SIGCHLD);
526 	if (sigprocmask(SIG_BLOCK, &sig_chld, NULL) < 0)
527 		die("unable to block SIGCHLD");
528 
529 	sa.sa_handler = handle_sigchld;
530 	sigemptyset(&sa.sa_mask);
531 	sa.sa_flags = SA_NOCLDSTOP;
532 	sigaction(SIGCHLD, &sa, NULL);
533 
534 	while (1) {
535 		int full;
536 		client *cl, *prev_cl, *next_cl;
537 		fd_set read_fds, write_fds;
538 
539 		do {
540 			sigset_t old_sigs;
541 			int max = -1;
542 
543 			full = conn_count >= max_conns;
544 			FD_ZERO(&read_fds);
545 			fd_set_add(selfpipe[0], &read_fds, &max);
546 			/* If we're full, and we don't have a response to send,
547 			   then we don't want to accept new connections -- so
548 			   don't check listen_fd. */
549 			if (!(full && !response))
550 				fd_set_add(listen_fd, &read_fds, &max);
551 
552 			FD_ZERO(&write_fds);
553 			for (cl = clients; cl; cl = cl->next)
554 				fd_set_add(cl->fd, &write_fds, &max);
555 
556 			if (sigprocmask(SIG_UNBLOCK, &sig_chld, &old_sigs) < 0)
557 				die("unable to unblock SIGCHLD");
558 
559 			n = select(max + 1, &read_fds, &write_fds, NULL, NULL);
560 			if (n < 0 && errno != EINTR)
561 				warn("select failed");
562 
563 			if (sigprocmask(SIG_SETMASK, &old_sigs, NULL) < 0)
564 				die("unable to restore signal mask");
565 		} while (n < 0);
566 
567 		if (FD_ISSET(selfpipe[0], &read_fds)) {
568 			char c;
569 
570 			/* We don't care if this fails. */
571 			read(selfpipe[0], &c, 1);
572 
573 			reap_children();
574 		}
575 
576 		if (FD_ISSET(listen_fd, &read_fds)) {
577 			accept_connection(listen_fd, full);
578 		}
579 
580 		prev_cl = NULL;
581 		for (cl = clients; cl; cl = next_cl) {
582 			next_cl = cl->next;
583 
584 			if (FD_ISSET(cl->fd, &write_fds))
585 				try_to_send(prev_cl, cl);
586 			prev_cl = cl;
587 		}
588 	}
589 
590 	return 0;
591 }
592