1/* Based on ipsvd utilities written by Gerrit Pape <pape@smarden.org>
2 * which are released into public domain by the author.
3 * Homepage: http://smarden.sunsite.dk/ipsvd/
4 *
5 * Copyright (C) 2007 Denis Vlasenko.
6 *
7 * Licensed under GPLv2, see file LICENSE in this tarball for details.
8 */
9
10/* Based on ipsvd ipsvd-0.12.1. This tcpsvd accepts all options
11 * which are supported by one from ipsvd-0.12.1, but not all are
12 * functional. See help text at the end of this file for details.
13 *
14 * Code inside "#ifdef SSLSVD" is for sslsvd and is currently unused.
15 *
16 * Output of verbose mode matches original (modulo bugs and
17 * unimplemented stuff). Unnatural splitting of IP and PORT
18 * is retained (personally I prefer one-value "IP:PORT" notation -
19 * it is a natural string representation of struct sockaddr_XX).
20 *
21 * TCPORIGDST{IP,PORT} is busybox-specific addition
22 *
23 * udp server is hacked up by reusing TCP code. It has the following
24 * limitation inherent in Unix DGRAM sockets implementation:
25 * - local IP address is retrieved (using recvmsg voodoo) but
26 *   child's socket is not bound to it (bind cannot be called on
27 *   already bound socket). Thus it still can emit outgoing packets
28 *   with wrong source IP...
29 * - don't know how to retrieve ORIGDST for udp.
30 */
31
32#include <limits.h>
33#include <linux/netfilter_ipv4.h> /* wants <limits.h> */
34
35#include "libbb.h"
36#include "ipsvd_perhost.h"
37
38#ifdef SSLSVD
39#include "matrixSsl.h"
40#include "ssl_io.h"
41#endif
42
43static unsigned verbose;
44static unsigned max_per_host;
45static unsigned cur_per_host;
46static unsigned cnum;
47static unsigned cmax = 30;
48
49static void xsetenv_proto(const char *proto, const char *n, const char *v)
50{
51	putenv(xasprintf("%s%s=%s", proto, n, v));
52}
53
54static void sig_term_handler(int sig)
55{
56	if (verbose)
57		printf("%s: info: sigterm received, exit\n", applet_name);
58	exit(0);
59}
60
61/* Little bloated, but tries to give accurate info how child exited.
62 * Makes easier to spot segfaulting children etc... */
63static void print_waitstat(unsigned pid, int wstat)
64{
65	unsigned e = 0;
66	const char *cause = "?exit";
67
68	if (WIFEXITED(wstat)) {
69		cause++;
70		e = WEXITSTATUS(wstat);
71	} else if (WIFSIGNALED(wstat)) {
72		cause = "signal";
73		e = WTERMSIG(wstat);
74	}
75	printf("%s: info: end %d %s %d\n", applet_name, pid, cause, e);
76}
77
78/* Must match getopt32 in main! */
79enum {
80	OPT_c = (1 << 0),
81	OPT_C = (1 << 1),
82	OPT_i = (1 << 2),
83	OPT_x = (1 << 3),
84	OPT_u = (1 << 4),
85	OPT_l = (1 << 5),
86	OPT_E = (1 << 6),
87	OPT_b = (1 << 7),
88	OPT_h = (1 << 8),
89	OPT_p = (1 << 9),
90	OPT_t = (1 << 10),
91	OPT_v = (1 << 11),
92	OPT_V = (1 << 12),
93	OPT_U = (1 << 13), /* from here: sslsvd only */
94	OPT_slash = (1 << 14),
95	OPT_Z = (1 << 15),
96	OPT_K = (1 << 16),
97};
98
99static void connection_status(void)
100{
101	/* "only 1 client max" desn't need this */
102	if (cmax > 1)
103		printf("%s: info: status %u/%u\n", applet_name, cnum, cmax);
104}
105
106static void sig_child_handler(int sig)
107{
108	int wstat;
109	int pid;
110
111	while ((pid = wait_nohang(&wstat)) > 0) {
112		if (max_per_host)
113			ipsvd_perhost_remove(pid);
114		if (cnum)
115			cnum--;
116		if (verbose)
117			print_waitstat(pid, wstat);
118	}
119	if (verbose)
120		connection_status();
121}
122
123int tcpudpsvd_main(int argc, char **argv);
124int tcpudpsvd_main(int argc, char **argv)
125{
126	char *str_c, *str_C, *str_b, *str_t;
127	char *user;
128	struct hcc *hccp;
129	const char *instructs;
130	char *msg_per_host = NULL;
131	unsigned len_per_host = len_per_host; /* gcc */
132#ifndef SSLSVD
133	struct bb_uidgid_t ugid;
134#endif
135	bool need_hostnames, need_remote_ip, tcp;
136	uint16_t local_port;
137	char *local_hostname = NULL;
138	char *remote_hostname = (char*)""; /* "" used if no -h */
139	char *local_addr = local_addr; /* gcc */
140	char *remote_addr = remote_addr; /* gcc */
141	char *remote_ip = remote_addr; /* gcc */
142	len_and_sockaddr *lsa;
143	len_and_sockaddr local, remote;
144	socklen_t sa_len;
145	int pid;
146	int sock;
147	int conn;
148	unsigned backlog = 20;
149
150	tcp = (applet_name[0] == 't');
151
152	/* 3+ args, -i at most once, -p implies -h, -v is counter */
153	opt_complementary = "-3:i--i:ph:vv";
154#ifdef SSLSVD
155	getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:",
156		&str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
157		&str_b, &str_t, &ssluser, &root, &cert, &key, &verbose
158	);
159#else
160	getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:v",
161		&str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
162		&str_b, &str_t, &verbose
163	);
164#endif
165	if (option_mask32 & OPT_c)
166		cmax = xatou_range(str_c, 1, INT_MAX);
167	if (option_mask32 & OPT_C) { /* -C n[:message] */
168		max_per_host = bb_strtou(str_C, &str_C, 10);
169		if (str_C[0]) {
170			if (str_C[0] != ':')
171				bb_show_usage();
172			msg_per_host = str_C + 1;
173			len_per_host = strlen(msg_per_host);
174		}
175	}
176	if (max_per_host > cmax)
177		max_per_host = cmax;
178	if (option_mask32 & OPT_u) {
179		if (!get_uidgid(&ugid, user, 1))
180			bb_error_msg_and_die("unknown user/group: %s", user);
181	}
182	if (option_mask32 & OPT_b)
183		backlog = xatou(str_b);
184#ifdef SSLSVD
185	if (option_mask32 & OPT_U) ssluser = optarg;
186	if (option_mask32 & OPT_slash) root = optarg;
187	if (option_mask32 & OPT_Z) cert = optarg;
188	if (option_mask32 & OPT_K) key = optarg;
189#endif
190	argv += optind;
191	if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
192		argv[0] = (char*)"0.0.0.0";
193
194	/* Per-IP flood protection is not thought-out for UDP */
195	if (!tcp)
196		max_per_host = 0;
197
198	/* stdout is used for logging, don't buffer */
199	setlinebuf(stdout);
200	bb_sanitize_stdio(); /* fd# 0,1,2 must be opened */
201
202	need_hostnames = verbose || !(option_mask32 & OPT_E);
203	need_remote_ip = max_per_host || need_hostnames;
204
205#ifdef SSLSVD
206	sslser = user;
207	client = 0;
208	if ((getuid() == 0) && !(option_mask32 & OPT_u)) {
209		xfunc_exitcode = 100;
210		bb_error_msg_and_die("fatal: -U ssluser must be set when running as root");
211	}
212	if (option_mask32 & OPT_u)
213		if (!uidgid_get(&sslugid, ssluser, 1)) {
214			if (errno) {
215				bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser);
216			}
217			bb_error_msg_and_die("fatal: unknown user/group '%s'", ssluser);
218		}
219	if (!cert) cert = "./cert.pem";
220	if (!key) key = cert;
221	if (matrixSslOpen() < 0)
222		fatal("cannot initialize ssl");
223	if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
224		if (client)
225			fatal("cannot read cert, key, or ca file");
226		fatal("cannot read cert or key file");
227	}
228	if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
229		fatal("cannot create ssl session");
230#endif
231
232	sig_block(SIGCHLD);
233	signal(SIGCHLD, sig_child_handler);
234	signal(SIGTERM, sig_term_handler);
235	signal(SIGPIPE, SIG_IGN);
236
237	if (max_per_host)
238		ipsvd_perhost_init(cmax);
239
240	local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0);
241	lsa = xhost2sockaddr(argv[0], local_port);
242	sock = xsocket(lsa->sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
243	setsockopt_reuseaddr(sock);
244	sa_len = lsa->len; /* I presume sockaddr len stays the same */
245	xbind(sock, &lsa->sa, sa_len);
246	if (tcp)
247		xlisten(sock, backlog);
248	else /* udp: needed for recv_from_to to work: */
249		socket_want_pktinfo(sock);
250	/* ndelay_off(sock); - it is the default I think? */
251
252#ifndef SSLSVD
253	if (option_mask32 & OPT_u) {
254		/* drop permissions */
255		xsetgid(ugid.gid);
256		xsetuid(ugid.uid);
257	}
258#endif
259
260	if (verbose) {
261		char *addr = xmalloc_sockaddr2dotted(&lsa->sa);
262		printf("%s: info: listening on %s", applet_name, addr);
263		free(addr);
264#ifndef SSLSVD
265		if (option_mask32 & OPT_u)
266			printf(", uid %u, gid %u",
267				(unsigned)ugid.uid, (unsigned)ugid.gid);
268#endif
269		puts(", starting");
270	}
271
272	/* Main accept() loop */
273
274 again:
275	hccp = NULL;
276
277	while (cnum >= cmax)
278		sig_pause(); /* wait for any signal (expecting SIGCHLD) */
279
280	/* Accept a connection to fd #0 */
281 again1:
282	close(0);
283 again2:
284	sig_unblock(SIGCHLD);
285	if (tcp) {
286		remote.len = sa_len;
287		conn = accept(sock, &remote.sa, &remote.len);
288	} else {
289		/* In case recv_from_to won't be able to recover local addr.
290		 * Also sets port - recv_from_to is unable to do it. */
291		local = *lsa;
292		conn = recv_from_to(sock, NULL, 0, MSG_PEEK, &remote.sa, &local.sa, sa_len);
293	}
294	sig_block(SIGCHLD);
295	if (conn < 0) {
296		if (errno != EINTR)
297			bb_perror_msg(tcp ? "accept" : "recv");
298		goto again2;
299	}
300	xmove_fd(tcp ? conn : sock, 0);
301
302	if (max_per_host) {
303		/* Drop connection immediately if cur_per_host > max_per_host
304		 * (minimizing load under SYN flood) */
305		remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa);
306		cur_per_host = ipsvd_perhost_add(remote_ip, max_per_host, &hccp);
307		if (cur_per_host > max_per_host) {
308			/* ipsvd_perhost_add detected that max is exceeded
309			 * (and did not store ip in connection table) */
310			free(remote_ip);
311			if (msg_per_host) {
312				/* don't block or test for errors */
313				ndelay_on(0);
314				write(0, msg_per_host, len_per_host);
315			}
316			goto again1;
317		}
318	}
319
320	if (!tcp) {
321		/* Voodoo magic: making udp sockets each receive its own
322		 * packets is not trivial, and I still not sure
323		 * I do it 100% right.
324		 * 1) we have to do it before fork()
325		 * 2) order is important - is it right now? */
326
327		/* Make plain write/send work for this socket by supplying default
328		 * destination address. This also restricts incoming packets
329		 * to ones coming from this remote IP. */
330		xconnect(0, &remote.sa, sa_len);
331	/* hole? at this point we have no wildcard udp socket...
332	 * can this cause clients to get "port unreachable" icmp?
333	 * Yup, time window is very small, but it exists (is it?) */
334		/* Open new non-connected UDP socket for further clients */
335		sock = xsocket(lsa->sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
336		setsockopt_reuseaddr(sock);
337		xbind(sock, &lsa->sa, sa_len);
338		socket_want_pktinfo(sock);
339
340		/* Doesn't work:
341		 * we cannot replace fd #0 - we will lose pending packet
342		 * which is already buffered for us! And we cannot use fd #1
343		 * instead - it will "intercept" all following packets, but child
344		 * does not expect data coming *from fd #1*! */
345	}
346
347	pid = fork();
348	if (pid == -1) {
349		bb_perror_msg("fork");
350		goto again;
351	}
352
353
354	if (pid != 0) {
355		/* parent */
356		cnum++;
357		if (verbose)
358			connection_status();
359		if (hccp)
360			hccp->pid = pid;
361		goto again;
362	}
363
364	/* Child: prepare env, log, and exec prog */
365
366	/* Closing tcp listening socket */
367	if (tcp)
368		close(sock);
369
370	if (need_remote_ip)
371		remote_addr = xmalloc_sockaddr2dotted(&remote.sa);
372
373	if (need_hostnames) {
374		if (option_mask32 & OPT_h) {
375			remote_hostname = xmalloc_sockaddr2host_noport(&remote.sa);
376			if (!remote_hostname) {
377				bb_error_msg("warning: cannot look up hostname for %s", remote_addr);
378				remote_hostname = (char*)"";
379			}
380		}
381		/* Find out local IP peer connected to.
382		 * Errors ignored (I'm not paranoid enough to imagine kernel
383		 * which doesn't know local IP). */
384		if (tcp) {
385			local.len = sa_len;
386			getsockname(0, &local.sa, &local.len);
387		}
388		local_addr = xmalloc_sockaddr2dotted(&local.sa);
389		if (!local_hostname) {
390			local_hostname = xmalloc_sockaddr2host_noport(&local.sa);
391			if (!local_hostname)
392				bb_error_msg_and_die("warning: cannot look up hostname for %s"+9, local_addr);
393		}
394	}
395
396	if (verbose) {
397		pid = getpid();
398		printf("%s: info: pid %u from %s\n", applet_name, pid, remote_addr);
399		if (max_per_host)
400			printf("%s: info: concurrency %u %s %u/%u\n",
401				applet_name, pid, remote_ip, cur_per_host, max_per_host);
402		printf("%s: info: start %u %s:%s :%s:%s\n",
403			applet_name, pid,
404			local_hostname, local_addr,
405			remote_hostname, remote_addr);
406	}
407
408	if (!(option_mask32 & OPT_E)) {
409		/* setup ucspi env */
410		const char *proto = tcp ? "TCP" : "UDP";
411
412		/* Extract "original" destination addr:port
413		 * from Linux firewall. Useful when you redirect
414		 * an outbond connection to local handler, and it needs
415		 * to know where it originally tried to connect */
416		if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &lsa->sa, &lsa->len) == 0) {
417			char *addr = xmalloc_sockaddr2dotted(&lsa->sa);
418			xsetenv("TCPORIGDSTADDR", addr);
419			free(addr);
420		}
421		xsetenv("PROTO", proto);
422		xsetenv_proto(proto, "LOCALADDR", local_addr);
423		xsetenv_proto(proto, "LOCALHOST", local_hostname);
424		xsetenv_proto(proto, "REMOTEADDR", remote_addr);
425		if (option_mask32 & OPT_h) {
426			xsetenv_proto(proto, "REMOTEHOST", remote_hostname);
427		}
428		xsetenv_proto(proto, "REMOTEINFO", "");
429		/* additional */
430		if (cur_per_host > 0) /* can not be true for udp */
431			xsetenv("TCPCONCURRENCY", utoa(cur_per_host));
432	}
433
434	dup2(0, 1);
435
436	signal(SIGTERM, SIG_DFL);
437	signal(SIGPIPE, SIG_DFL);
438	signal(SIGCHLD, SIG_DFL);
439	sig_unblock(SIGCHLD);
440
441	argv += 2;
442#ifdef SSLSVD
443	strcpy(id, utoa(pid);
444	ssl_io(0, argv);
445#else
446	BB_EXECVP(argv[0], argv);
447#endif
448	bb_perror_msg_and_die("exec '%s'", argv[0]);
449}
450
451/*
452tcpsvd [-hpEvv] [-c n] [-C n:msg] [-b n] [-u user] [-l name]
453	[-i dir|-x cdb] [ -t sec] host port prog
454
455tcpsvd creates a TCP/IP socket, binds it to the address host:port,
456and listens on the socket for incoming connections.
457
458On each incoming connection, tcpsvd conditionally runs a program,
459with standard input reading from the socket, and standard output
460writing to the socket, to handle this connection. tcpsvd keeps
461listening on the socket for new connections, and can handle
462multiple connections simultaneously.
463
464tcpsvd optionally checks for special instructions depending
465on the IP address or hostname of the client that initiated
466the connection, see ipsvd-instruct(5).
467
468host
469    host either is a hostname, or a dotted-decimal IP address,
470    or 0. If host is 0, tcpsvd accepts connections to any local
471    IP address.
472    * busybox accepts IPv6 addresses and host:port pairs too
473      In this case second parameter is ignored
474port
475    tcpsvd accepts connections to host:port. port may be a name
476    from /etc/services or a number.
477prog
478    prog consists of one or more arguments. For each connection,
479    tcpsvd normally runs prog, with file descriptor 0 reading from
480    the network, and file descriptor 1 writing to the network.
481    By default it also sets up TCP-related environment variables,
482    see tcp-environ(5)
483-i dir
484    read instructions for handling new connections from the instructions
485    directory dir. See ipsvd-instruct(5) for details.
486    * ignored by busyboxed version
487-x cdb
488    read instructions for handling new connections from the constant database
489    cdb. The constant database normally is created from an instructions
490    directory by running ipsvd-cdb(8).
491    * ignored by busyboxed version
492-t sec
493    timeout. This option only takes effect if the -i option is given.
494    While checking the instructions directory, check the time of last access
495    of the file that matches the clients address or hostname if any, discard
496    and remove the file if it wasn't accessed within the last sec seconds;
497    tcpsvd does not discard or remove a file if the user's write permission
498    is not set, for those files the timeout is disabled. Default is 0,
499    which means that the timeout is disabled.
500    * ignored by busyboxed version
501-l name
502    local hostname. Do not look up the local hostname in DNS, but use name
503    as hostname. This option must be set if tcpsvd listens on port 53
504    to avoid loops.
505-u user[:group]
506    drop permissions. Switch user ID to user's UID, and group ID to user's
507    primary GID after creating and binding to the socket. If user is followed
508    by a colon and a group name, the group ID is switched to the GID of group
509    instead. All supplementary groups are removed.
510-c n
511    concurrency. Handle up to n connections simultaneously. Default is 30.
512    If there are n connections active, tcpsvd defers acceptance of a new
513    connection until an active connection is closed.
514-C n[:msg]
515    per host concurrency. Allow only up to n connections from the same IP
516    address simultaneously. If there are n active connections from one IP
517    address, new incoming connections from this IP address are closed
518    immediately. If n is followed by :msg, the message msg is written
519    to the client if possible, before closing the connection. By default
520    msg is empty. See ipsvd-instruct(5) for supported escape sequences in msg.
521
522    For each accepted connection, the current per host concurrency is
523    available through the environment variable TCPCONCURRENCY. n and msg
524    can be overwritten by ipsvd(7) instructions, see ipsvd-instruct(5).
525    By default tcpsvd doesn't keep track of connections.
526-h
527    Look up the client's hostname in DNS.
528-p
529    paranoid. After looking up the client's hostname in DNS, look up the IP
530    addresses in DNS for that hostname, and forget about the hostname
531    if none of the addresses match the client's IP address. You should
532    set this option if you use hostname based instructions. The -p option
533    implies the -h option.
534    * ignored by busyboxed version
535-b n
536    backlog. Allow a backlog of approximately n TCP SYNs. On some systems n
537    is silently limited. Default is 20.
538-E
539    no special environment. Do not set up TCP-related environment variables.
540-v
541    verbose. Print verbose messsages to standard output.
542-vv
543    more verbose. Print more verbose messages to standard output.
544    * no difference between -v and -vv in busyboxed version
545*/
546