6a11539c7a3c3a26c8515a23f53c58a8c773759b
[platform/upstream/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 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
43 static unsigned verbose;
44 static unsigned max_per_host;
45 static unsigned cur_per_host;
46 static unsigned cnum;
47 static unsigned cmax = 30;
48
49 static void xsetenv_proto(const char *proto, const char *n, const char *v)
50 {
51         putenv(xasprintf("%s%s=%s", proto, n, v));
52 }
53
54 static 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... */
63 static 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! */
79 enum {
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
99 static 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
106 static 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
123 int tcpudpsvd_main(int argc, char **argv);
124 int 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 #if 0
346                 /* Make it so that local addr is fixed to localp->sa
347                  * and we don't accidentally accept packets to other local IPs. */
348                 /* NB: we possibly bind to the _very_ same_ address & port as the one
349                  * already bound in parent! This seems to work in Linux.
350                  * (otherwise we can move socket to fd #0 only if bind succeeds) */
351                 close(0);
352                 set_nport(localp, htons(local_port));
353                 xmove_fd(xsocket(localp->sa.sa_family, SOCK_DGRAM, 0), 0);
354                 setsockopt_reuseaddr(0); /* crucial */
355                 xbind(0, &localp->sa, localp->len);
356 #endif
357         }
358
359         pid = fork();
360         if (pid == -1) {
361                 bb_perror_msg("fork");
362                 goto again;
363         }
364
365
366         if (pid != 0) {
367                 /* parent */
368                 cnum++;
369                 if (verbose)
370                         connection_status();
371                 if (hccp)
372                         hccp->pid = pid;
373                 goto again;
374         }
375
376         /* Child: prepare env, log, and exec prog */
377
378         /* Closing tcp listening socket */
379         if (tcp)
380                 close(sock);
381
382         if (need_remote_ip)
383                 remote_addr = xmalloc_sockaddr2dotted(&remote.sa);
384
385         if (need_hostnames) {
386                 if (option_mask32 & OPT_h) {
387                         remote_hostname = xmalloc_sockaddr2host_noport(&remote.sa);
388                         if (!remote_hostname) {
389                                 bb_error_msg("warning: cannot look up hostname for %s", remote_addr);
390                                 remote_hostname = (char*)"";
391                         }
392                 }
393                 /* Find out local IP peer connected to.
394                  * Errors ignored (I'm not paranoid enough to imagine kernel
395                  * which doesn't know local IP). */
396                 if (tcp) {
397                         local.len = sa_len;
398                         getsockname(0, &local.sa, &local.len);
399                 }
400                 local_addr = xmalloc_sockaddr2dotted(&local.sa);
401                 if (!local_hostname) {
402                         local_hostname = xmalloc_sockaddr2host_noport(&local.sa);
403                         if (!local_hostname)
404                                 bb_error_msg_and_die("warning: cannot look up hostname for %s"+9, local_addr);
405                 }
406         }
407
408         if (verbose) {
409                 pid = getpid();
410                 printf("%s: info: pid %u from %s\n", applet_name, pid, remote_addr);
411                 if (max_per_host)
412                         printf("%s: info: concurrency %u %s %u/%u\n",
413                                 applet_name, pid, remote_ip, cur_per_host, max_per_host);
414                 printf("%s: info: start %u %s:%s :%s:%s\n",
415                         applet_name, pid,
416                         local_hostname, local_addr,
417                         remote_hostname, remote_addr);
418         }
419
420         if (!(option_mask32 & OPT_E)) {
421                 /* setup ucspi env */
422                 const char *proto = tcp ? "TCP" : "UDP";
423
424                 /* Extract "original" destination addr:port
425                  * from Linux firewall. Useful when you redirect
426                  * an outbond connection to local handler, and it needs
427                  * to know where it originally tried to connect */
428                 if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &lsa->sa, &lsa->len) == 0) {
429                         char *addr = xmalloc_sockaddr2dotted(&lsa->sa);
430                         xsetenv("TCPORIGDSTADDR", addr);
431                         free(addr);
432                 }
433                 xsetenv("PROTO", proto);
434                 xsetenv_proto(proto, "LOCALADDR", local_addr);
435                 xsetenv_proto(proto, "LOCALHOST", local_hostname);
436                 xsetenv_proto(proto, "REMOTEADDR", remote_addr);
437                 if (option_mask32 & OPT_h) {
438                         xsetenv_proto(proto, "REMOTEHOST", remote_hostname);
439                 }
440                 xsetenv_proto(proto, "REMOTEINFO", "");
441                 /* additional */
442                 if (cur_per_host > 0) /* can not be true for udp */
443                         xsetenv("TCPCONCURRENCY", utoa(cur_per_host));
444         }
445
446         dup2(0, 1);
447
448         signal(SIGTERM, SIG_DFL);
449         signal(SIGPIPE, SIG_DFL);
450         signal(SIGCHLD, SIG_DFL);
451         sig_unblock(SIGCHLD);
452
453         argv += 2;
454 #ifdef SSLSVD
455         strcpy(id, utoa(pid);
456         ssl_io(0, argv);
457 #else
458         BB_EXECVP(argv[0], argv);
459 #endif
460         bb_perror_msg_and_die("exec '%s'", argv[0]);
461 }
462
463 /*
464 tcpsvd [-hpEvv] [-c n] [-C n:msg] [-b n] [-u user] [-l name]
465         [-i dir|-x cdb] [ -t sec] host port prog
466
467 tcpsvd creates a TCP/IP socket, binds it to the address host:port,
468 and listens on the socket for incoming connections.
469
470 On each incoming connection, tcpsvd conditionally runs a program,
471 with standard input reading from the socket, and standard output
472 writing to the socket, to handle this connection. tcpsvd keeps
473 listening on the socket for new connections, and can handle
474 multiple connections simultaneously.
475
476 tcpsvd optionally checks for special instructions depending
477 on the IP address or hostname of the client that initiated
478 the connection, see ipsvd-instruct(5).
479
480 host
481     host either is a hostname, or a dotted-decimal IP address,
482     or 0. If host is 0, tcpsvd accepts connections to any local
483     IP address.
484     * busybox accepts IPv6 addresses and host:port pairs too
485       In this case second parameter is ignored
486 port
487     tcpsvd accepts connections to host:port. port may be a name
488     from /etc/services or a number.
489 prog
490     prog consists of one or more arguments. For each connection,
491     tcpsvd normally runs prog, with file descriptor 0 reading from
492     the network, and file descriptor 1 writing to the network.
493     By default it also sets up TCP-related environment variables,
494     see tcp-environ(5)
495 -i dir
496     read instructions for handling new connections from the instructions
497     directory dir. See ipsvd-instruct(5) for details.
498     * ignored by busyboxed version
499 -x cdb
500     read instructions for handling new connections from the constant database
501     cdb. The constant database normally is created from an instructions
502     directory by running ipsvd-cdb(8).
503     * ignored by busyboxed version
504 -t sec
505     timeout. This option only takes effect if the -i option is given.
506     While checking the instructions directory, check the time of last access
507     of the file that matches the clients address or hostname if any, discard
508     and remove the file if it wasn't accessed within the last sec seconds;
509     tcpsvd does not discard or remove a file if the user's write permission
510     is not set, for those files the timeout is disabled. Default is 0,
511     which means that the timeout is disabled.
512     * ignored by busyboxed version
513 -l name
514     local hostname. Do not look up the local hostname in DNS, but use name
515     as hostname. This option must be set if tcpsvd listens on port 53
516     to avoid loops.
517 -u user[:group]
518     drop permissions. Switch user ID to user's UID, and group ID to user's
519     primary GID after creating and binding to the socket. If user is followed
520     by a colon and a group name, the group ID is switched to the GID of group
521     instead. All supplementary groups are removed.
522 -c n
523     concurrency. Handle up to n connections simultaneously. Default is 30.
524     If there are n connections active, tcpsvd defers acceptance of a new
525     connection until an active connection is closed.
526 -C n[:msg]
527     per host concurrency. Allow only up to n connections from the same IP
528     address simultaneously. If there are n active connections from one IP
529     address, new incoming connections from this IP address are closed
530     immediately. If n is followed by :msg, the message msg is written
531     to the client if possible, before closing the connection. By default
532     msg is empty. See ipsvd-instruct(5) for supported escape sequences in msg.
533
534     For each accepted connection, the current per host concurrency is
535     available through the environment variable TCPCONCURRENCY. n and msg
536     can be overwritten by ipsvd(7) instructions, see ipsvd-instruct(5).
537     By default tcpsvd doesn't keep track of connections.
538 -h
539     Look up the client's hostname in DNS.
540 -p
541     paranoid. After looking up the client's hostname in DNS, look up the IP
542     addresses in DNS for that hostname, and forget about the hostname
543     if none of the addresses match the client's IP address. You should
544     set this option if you use hostname based instructions. The -p option
545     implies the -h option.
546     * ignored by busyboxed version
547 -b n
548     backlog. Allow a backlog of approximately n TCP SYNs. On some systems n
549     is silently limited. Default is 20.
550 -E
551     no special environment. Do not set up TCP-related environment variables.
552 -v
553     verbose. Print verbose messsages to standard output.
554 -vv
555     more verbose. Print more verbose messages to standard output.
556     * no difference between -v and -vv in busyboxed version
557 */