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