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/
5 * Copyright (C) 2007 Denis Vlasenko.
7 * Licensed under GPLv2, see file LICENSE in this tarball for details.
10 /* TCP and UDP server are using a lot of same string constants
11 * We reuse them by keeping both in one source file */
15 static unsigned verbose;
17 static void sig_term_handler(int sig)
20 printf("%s: info: sigterm received, exit\n", applet_name);
24 /* Little bloated, but tries to give accurate info how child exited.
25 * Makes easier to spot segfaulting children etc... */
26 static void print_waitstat(unsigned pid, int wstat)
29 const char *cause = "?exit";
31 if (WIFEXITED(wstat)) {
33 e = WEXITSTATUS(wstat);
34 } else if (WIFSIGNALED(wstat)) {
38 printf("%s: info: end %d %s %d\n", applet_name, pid, cause, e);
43 /* Based on ipsvd ipsvd-0.12.1. This udpsvd accepts all options
44 * which are supported by one from ipsvd-0.12.1, but not all are
45 * functional. See help text at the end of this file for details.
47 * Output of verbose mode matches original (modulo bugs and
48 * unimplemented stuff). Unnatural splitting of IP and PORT
49 * is retained (personally I prefer one-value "IP:PORT" notation -
50 * it is a natural string representation of struct sockaddr_XX).
55 int udpsvd_main(int argc, char **argv);
56 int udpsvd_main(int argc, char **argv)
58 const char *instructs;
62 char *remote_hostname = (char*)""; /* used if no -h */
63 char *local_hostname = NULL;
65 char *local_ip;// = local_ip; /* gcc */
66 uint16_t local_port, remote_port;
67 len_and_sockaddr remote;
68 len_and_sockaddr *localp;
71 struct bb_uidgid_t ugid;
84 opt_complementary = "-3:ph:vv";
85 opt = getopt32(argc, argv, "vu:l:hpi:x:t:",
86 &user, &local_hostname, &instructs, &instructs, &str_t, &verbose);
88 if (!get_uidgid(&ugid, user, 1))
89 bb_error_msg_and_die("unknown user/group: %s", user);
92 if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
93 argv[0] = (char*)"0.0.0.0";
95 /* stdout is used for logging, don't buffer */
97 bb_sanitize_stdio(); /* fd# 1,2 must be opened */
99 signal(SIGTERM, sig_term_handler);
100 signal(SIGPIPE, SIG_IGN);
102 local_port = bb_lookup_port(argv[1], "udp", 0);
103 localp = xhost2sockaddr(argv[0], local_port);
104 /* fd #0 is the open UDP socket */
105 xmove_fd(xsocket(localp->sa.sa_family, SOCK_DGRAM, 0), 0);
106 setsockopt_reuseaddr(0); /* crucial */
107 xbind(0, &localp->sa, localp->len);
108 socket_want_pktinfo(0); /* needed for recv_from_to to work */
110 if (opt & OPT_u) { /* drop permissions */
116 /* we do it only for ":port" cosmetics... oh well */
117 char *addr = xmalloc_sockaddr2dotted(&localp->sa, localp->len);
119 printf("%s: info: listening on %s", applet_name, addr);
121 if (option_mask32 & OPT_u)
122 printf(", uid %u, gid %u",
123 (unsigned)ugid.uid, (unsigned)ugid.gid);
128 /* if (recvfrom(0, NULL, 0, MSG_PEEK, &remote.sa, &localp->len) < 0) { */
129 if (recv_from_to(0, NULL, 0, MSG_PEEK, &remote.sa, &localp->sa, localp->len) < 0) {
130 bb_perror_msg("recvfrom");
134 while ((pid = fork()) < 0) {
135 bb_perror_msg("fork failed, sleeping");
138 if (pid > 0) { /* parent */
139 while (wait_pid(&wstat, pid) < 0)
140 bb_perror_msg("error waiting for child");
142 print_waitstat(pid, wstat);
149 remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, localp->len);
150 local_ip = xmalloc_sockaddr2dotted_noport(&localp->sa, localp->len);
153 printf("%s: info: pid %u from %s\n", applet_name, pid, remote_ip);
155 if (!local_hostname) {
156 local_hostname = xmalloc_sockaddr2host_noport(&localp->sa, localp->len);
158 bb_error_msg_and_die("cannot look up local hostname for %s", local_ip);
161 remote_hostname = xmalloc_sockaddr2host(&remote.sa, localp->len);
162 if (!remote_hostname) {
163 bb_error_msg("warning: cannot look up hostname for %s", remote_ip);
164 remote_hostname = (char*)"";
168 remote_port = get_nport(&remote.sa);
169 remote_port = ntohs(remote_port);
170 printf("%s: info: %u %s:%s :%s:%s:%u\n",
171 applet_name, pid, local_hostname, local_ip,
172 remote_hostname, remote_ip, remote_port);
176 * we cannot replace fd #0 - we will lose pending packet
177 * which is already buffered for us! And we cannot use fd #1
178 * instead - it will "intercept" all following packets, but child
179 * do not expect data coming *from fd #1*! */
181 /* Make it so that local addr is fixed to localp->sa
182 * and we don't accidentally accept packets to other local IPs. */
183 /* NB: we possibly bind to the _very_ same_ address & port as the one
184 * already bound in parent! This seems to work in Linux.
185 * (otherwise we can move socket to fd #0 only if bind succeeds) */
187 set_nport(localp, htons(local_port));
188 xmove_fd(xsocket(localp->sa.sa_family, SOCK_DGRAM, 0), 0);
189 setsockopt_reuseaddr(0); /* crucial */
190 xbind(0, &localp->sa, localp->len);
193 /* Make plain write to fd #1 work for the child by supplying default
194 * destination address. This also restricts incoming packets
195 * to ones coming from this remote IP. */
196 xconnect(0, &remote.sa, localp->len);
199 signal(SIGTERM, SIG_DFL);
200 signal(SIGPIPE, SIG_DFL);
203 BB_EXECVP(argv[0], argv);
204 bb_perror_msg_and_die("exec '%s'", argv[0]);
209 udpsvd [-hpvv] [-u user] [-l name] [-i dir|-x cdb] [-t sec] host port prog
211 udpsvd creates an UDP/IP socket, binds it to the address host:port,
212 and listens on the socket for incoming datagrams.
214 If a datagram is available on the socket, udpsvd conditionally starts
215 a program, with standard input reading from the socket, and standard
216 output redirected to standard error, to handle this, and possibly
217 more datagrams. udpsvd does not start the program if another program
218 that it has started before still is running. If the program exits,
219 udpsvd again listens to the socket until a new datagram is available.
220 If there are still datagrams available on the socket, the program
221 is restarted immediately.
223 udpsvd optionally checks for special intructions depending on
224 the IP address or hostname of the client sending the datagram which
225 not yet was handled by a running program, see ipsvd-instruct(5)
229 UDP is a connectionless protocol. Most programs that handle user datagrams,
230 such as talkd(8), keep running after receiving a datagram, and process
231 subsequent datagrams sent to the socket until a timeout is reached.
232 udpsvd only checks special instructions for a datagram that causes a startup
233 of the program; not if a program handling datagrams already is running.
234 It doesn't make much sense to restrict access through special instructions
235 when using such a program.
237 On the other hand, it makes perfectly sense with programs like tftpd(8),
238 that fork to establish a separate connection to the client when receiving
239 the datagram. In general it's adequate to set up special instructions for
240 programs that support being run by tcpwrapper.
244 host either is a hostname, or a dotted-decimal IP address, or 0.
245 If host is 0, udpsvd accepts datagrams to any local IP address.
247 udpsvd accepts datagrams to host:port. port may be a name from
248 /etc/services or a number.
250 prog consists of one or more arguments. udpsvd normally runs prog
251 to handle a datagram, and possibly more, that is sent to the socket,
252 if there is no program that was started before by udpsvd still running
253 and handling datagrams.
255 read instructions for handling new connections from the instructions
256 directory dir. See ipsvd-instruct(5) for details.
258 read instructions for handling new connections from the constant
259 database cdb. The constant database normally is created from
260 an instructions directory by running ipsvd-cdb(8).
262 timeout. This option only takes effect if the -i option is given.
263 While checking the instructions directory, check the time of last
264 access of the file that matches the clients address or hostname if any,
265 discard and remove the file if it wasn't accessed within the last
266 sec seconds; udpsvd does not discard or remove a file if the user's
267 write permission is not set, for those files the timeout is disabled.
268 Default is 0, which means that the timeout is disabled.
270 local hostname. Do not look up the local hostname in DNS, but use name
271 as hostname. By default udpsvd looks up the local hostname once at startup.
273 drop permissions. Switch user ID to user's UID, and group ID to user's
274 primary GID after creating and binding to the socket. If user
275 is followed by a colon and a group name, the group ID is switched
276 to the GID of group instead. All supplementary groups are removed.
278 Look up the client's hostname in DNS.
280 paranoid. After looking up the client's hostname in DNS, look up
281 the IP addresses in DNS for that hostname, and forget the hostname
282 if none of the addresses match the client's IP address. You should
283 set this option if you use hostname based instructions. The -p option
284 implies the -h option.
286 verbose. Print verbose messages to standard output.
288 more verbose. Print more verbose messages to standard output.
294 /* Based on ipsvd ipsvd-0.12.1. This tcpsvd accepts all options
295 * which are supported by one from ipsvd-0.12.1, but not all are
296 * functional. See help text at the end of this file for details.
298 * Code inside "#ifdef SSLSVD" is for sslsvd and is currently unused.
300 * Output of verbose mode matches original (modulo bugs and
301 * unimplemented stuff). Unnatural splitting of IP and PORT
302 * is retained (personally I prefer one-value "IP:PORT" notation -
303 * it is a natural string representation of struct sockaddr_XX).
305 * TCPORIGDST{IP,PORT} is busybox-specific addition
309 #include <linux/netfilter_ipv4.h> /* wants <limits.h> */
310 #include "ipsvd_perhost.h"
313 #include "matrixSsl.h"
317 static unsigned max_per_host; /* originally in ipsvd_check.c */
318 static unsigned cur_per_host;
319 static unsigned cnum;
320 static unsigned cmax = 30;
322 /* Must match getopt32 in main! */
337 OPT_U = (1 << 13), /* from here: sslsvd only */
338 OPT_slash = (1 << 14),
343 static void connection_status(void)
345 printf("%s: info: status %u/%u\n", applet_name, cnum, cmax);
348 static void sig_child_handler(int sig)
353 while ((pid = wait_nohang(&wstat)) > 0) {
355 ipsvd_perhost_remove(pid);
359 print_waitstat(pid, wstat);
365 int tcpsvd_main(int argc, char **argv);
366 int tcpsvd_main(int argc, char **argv)
368 char *str_c, *str_C, *str_b, *str_t;
371 const char *instructs;
372 char *msg_per_host = NULL;
373 unsigned len_per_host = len_per_host; /* gcc */
374 int need_hostnames, need_remote_ip;
378 unsigned backlog = 20;
379 len_and_sockaddr *lsa;
381 uint16_t remote_port = remote_port; /* gcc */
382 char *local_hostname = NULL;
383 char *remote_hostname = (char*)""; /* "" used if no -h */
384 char *local_ip = local_ip; /* gcc */
385 char *remote_ip = remote_ip; /* gcc */
387 struct bb_uidgid_t ugid;
390 /* 3+ args, -i at most once, -p implies -h, -v is counter */
391 opt_complementary = "-3:?:i--i:ph:vv";
393 getopt32(argc, argv, "c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:",
394 &str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
395 &str_b, &str_t, &ssluser, &root, &cert, &key, &verbose
398 getopt32(argc, argv, "c:C:i:x:u:l:Eb:hpt:v",
399 &str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
400 &str_b, &str_t, &verbose
403 if (option_mask32 & OPT_c)
404 cmax = xatou_range(str_c, 1, INT_MAX);
405 if (option_mask32 & OPT_C) { /* -C n[:message] */
406 max_per_host = bb_strtou(str_C, &str_C, 10);
410 msg_per_host = str_C + 1;
411 len_per_host = strlen(msg_per_host);
414 if (max_per_host > cmax)
416 if (option_mask32 & OPT_u) {
417 if (!get_uidgid(&ugid, user, 1))
418 bb_error_msg_and_die("unknown user/group: %s", user);
420 if (option_mask32 & OPT_b)
421 backlog = xatou(str_b);
423 if (option_mask32 & OPT_U) ssluser = (char*)optarg; break;
424 if (option_mask32 & OPT_slash) root = (char*)optarg; break;
425 if (option_mask32 & OPT_Z) cert = (char*)optarg; break;
426 if (option_mask32 & OPT_K) key = (char*)optarg; break;
429 if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
430 argv[0] = (char*)"0.0.0.0";
432 /* stdout is used for logging, don't buffer */
434 bb_sanitize_stdio(); /* fd# 1,2 must be opened */
436 need_hostnames = verbose || !(option_mask32 & OPT_E);
437 need_remote_ip = max_per_host || need_hostnames;
442 if ((getuid() == 0) && !(option_mask32 & OPT_u)) {
443 xfunc_exitcode = 100;
444 bb_error_msg_and_die("fatal: -U ssluser must be set when running as root");
446 if (option_mask32 & OPT_u)
447 if (!uidgid_get(&sslugid, ssluser, 1)) {
449 xfunc_exitcode = 100;
450 bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser);
452 xfunc_exitcode = 111;
453 bb_error_msg_and_die("fatal: unknown user/group '%s'", ssluser);
455 if (!cert) cert = "./cert.pem";
456 if (!key) key = cert;
457 if (matrixSslOpen() < 0)
458 fatal("cannot initialize ssl");
459 if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
461 fatal("cannot read cert, key, or ca file");
462 fatal("cannot read cert or key file");
464 if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
465 fatal("cannot create ssl session");
469 signal(SIGCHLD, sig_child_handler);
470 signal(SIGTERM, sig_term_handler);
471 signal(SIGPIPE, SIG_IGN);
474 ipsvd_perhost_init(cmax);
476 local_port = bb_lookup_port(argv[1], "tcp", 0);
477 lsa = xhost2sockaddr(argv[0], local_port);
478 sock = xsocket(lsa->sa.sa_family, SOCK_STREAM, 0);
479 setsockopt_reuseaddr(sock); /* desirable */
480 xbind(sock, &lsa->sa, lsa->len);
481 xlisten(sock, backlog);
482 /* ndelay_off(sock); - it is the default I think? */
485 if (option_mask32 & OPT_u) {
486 /* drop permissions */
493 /* we do it only for ":port" cosmetics... oh well */
494 char *addr = xmalloc_sockaddr2dotted(&lsa->sa, lsa->len);
496 printf("%s: info: listening on %s", applet_name, addr);
499 if (option_mask32 & OPT_u)
500 printf(", uid %u, gid %u",
501 (unsigned)ugid.uid, (unsigned)ugid.gid);
506 /* The rest is a main accept() loop */
512 sig_pause(); /* wait for any signal (expecting SIGCHLD) */
514 /* Accept a connection to fd #0 */
518 sig_unblock(SIGCHLD);
519 conn = accept(sock, &lsa->sa, &lsa->len);
523 bb_perror_msg("accept");
529 /* Drop connection immediately if cur_per_host > max_per_host
530 * (minimizing load under SYN flood) */
531 remote_ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
532 cur_per_host = ipsvd_perhost_add(remote_ip, max_per_host, &hccp);
533 if (cur_per_host > max_per_host) {
534 /* ipsvd_perhost_add detected that max is exceeded
535 * (and did not store ip in connection table) */
538 /* don't block or test for errors */
540 write(0, msg_per_host, len_per_host);
552 bb_perror_msg("fork");
562 /* Child: prepare env, log, and exec prog */
564 close(sock); /* listening socket */
565 /* Find out local IP peer connected to.
566 * Errors ignored (I'm not paranoid enough to imagine kernel
567 * which doesn't know local IP). */
568 getsockname(0, &lsa->sa, &lsa->len);
570 if (need_remote_ip) {
572 remote_ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
573 /* else it is already done */
574 remote_port = get_nport(&lsa->sa);
575 remote_port = ntohs(remote_port);
578 if (need_hostnames) {
579 if (option_mask32 & OPT_h) {
580 remote_hostname = xmalloc_sockaddr2host(&lsa->sa, lsa->len);
581 if (!remote_hostname) {
582 bb_error_msg("warning: cannot look up hostname for %s", remote_ip);
583 remote_hostname = (char*)"";
586 local_ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
587 local_port = get_nport(&lsa->sa);
588 local_port = ntohs(local_port);
589 if (!local_hostname) {
590 local_hostname = xmalloc_sockaddr2host_noport(&lsa->sa, lsa->len);
592 bb_error_msg_and_die("cannot look up local hostname for %s", local_ip);
598 printf("%s: info: pid %u from %s\n", applet_name, pid, remote_ip);
600 printf("%s: info: concurrency %u %s %u/%u\n",
601 applet_name, pid, remote_ip, cur_per_host, max_per_host);
602 printf("%s: info: start %u %s:%s :%s:%s:%u\n",
604 local_hostname, local_ip,
605 remote_hostname, remote_ip, (unsigned)remote_port);
608 if (!(option_mask32 & OPT_E)) {
609 /* setup ucspi env */
611 /* Extract "original" destination addr:port
612 * from Linux firewall. Useful when you redirect
613 * an outbond connection to local handler, and it needs
614 * to know where it originally tried to connect */
615 if (getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &lsa->sa, &lsa->len) == 0) {
616 char *ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
617 unsigned port = get_nport(&lsa->sa);
619 xsetenv("TCPORIGDSTIP", ip);
620 xsetenv("TCPORIGDSTPORT", utoa(port));
623 xsetenv("PROTO", "TCP");
624 xsetenv("TCPLOCALIP", local_ip);
625 xsetenv("TCPLOCALPORT", utoa(local_port));
626 xsetenv("TCPLOCALHOST", local_hostname);
627 xsetenv("TCPREMOTEIP", remote_ip);
628 xsetenv("TCPREMOTEPORT", utoa(remote_port));
629 if (option_mask32 & OPT_h) {
630 xsetenv("TCPREMOTEHOST", remote_hostname);
632 xsetenv("TCPREMOTEINFO", "");
634 if (cur_per_host > 0)
635 xsetenv("TCPCONCURRENCY", utoa(cur_per_host));
640 signal(SIGTERM, SIG_DFL);
641 signal(SIGPIPE, SIG_DFL);
642 signal(SIGCHLD, SIG_DFL);
643 sig_unblock(SIGCHLD);
647 strcpy(id, utoa(pid);
650 BB_EXECVP(argv[0], argv);
652 bb_perror_msg_and_die("exec '%s'", argv[0]);
656 tcpsvd [-hpEvv] [-c n] [-C n:msg] [-b n] [-u user] [-l name]
657 [-i dir|-x cdb] [ -t sec] host port prog
659 tcpsvd creates a TCP/IP socket, binds it to the address host:port,
660 and listens on the socket for incoming connections.
662 On each incoming connection, tcpsvd conditionally runs a program,
663 with standard input reading from the socket, and standard output
664 writing to the socket, to handle this connection. tcpsvd keeps
665 listening on the socket for new connections, and can handle
666 multiple connections simultaneously.
668 tcpsvd optionally checks for special instructions depending
669 on the IP address or hostname of the client that initiated
670 the connection, see ipsvd-instruct(5).
673 host either is a hostname, or a dotted-decimal IP address,
674 or 0. If host is 0, tcpsvd accepts connections to any local
676 * busybox accepts IPv6 addresses and host:port pairs too
677 In this case second parameter is ignored
679 tcpsvd accepts connections to host:port. port may be a name
680 from /etc/services or a number.
682 prog consists of one or more arguments. For each connection,
683 tcpsvd normally runs prog, with file descriptor 0 reading from
684 the network, and file descriptor 1 writing to the network.
685 By default it also sets up TCP-related environment variables,
688 read instructions for handling new connections from the instructions
689 directory dir. See ipsvd-instruct(5) for details.
690 * ignored by busyboxed version
692 read instructions for handling new connections from the constant database
693 cdb. The constant database normally is created from an instructions
694 directory by running ipsvd-cdb(8).
695 * ignored by busyboxed version
697 timeout. This option only takes effect if the -i option is given.
698 While checking the instructions directory, check the time of last access
699 of the file that matches the clients address or hostname if any, discard
700 and remove the file if it wasn't accessed within the last sec seconds;
701 tcpsvd does not discard or remove a file if the user's write permission
702 is not set, for those files the timeout is disabled. Default is 0,
703 which means that the timeout is disabled.
704 * ignored by busyboxed version
706 local hostname. Do not look up the local hostname in DNS, but use name
707 as hostname. This option must be set if tcpsvd listens on port 53
710 drop permissions. Switch user ID to user's UID, and group ID to user's
711 primary GID after creating and binding to the socket. If user is followed
712 by a colon and a group name, the group ID is switched to the GID of group
713 instead. All supplementary groups are removed.
715 concurrency. Handle up to n connections simultaneously. Default is 30.
716 If there are n connections active, tcpsvd defers acceptance of a new
717 connection until an active connection is closed.
719 per host concurrency. Allow only up to n connections from the same IP
720 address simultaneously. If there are n active connections from one IP
721 address, new incoming connections from this IP address are closed
722 immediately. If n is followed by :msg, the message msg is written
723 to the client if possible, before closing the connection. By default
724 msg is empty. See ipsvd-instruct(5) for supported escape sequences in msg.
726 For each accepted connection, the current per host concurrency is
727 available through the environment variable TCPCONCURRENCY. n and msg
728 can be overwritten by ipsvd(7) instructions, see ipsvd-instruct(5).
729 By default tcpsvd doesn't keep track of connections.
731 Look up the client's hostname in DNS.
733 paranoid. After looking up the client's hostname in DNS, look up the IP
734 addresses in DNS for that hostname, and forget about the hostname
735 if none of the addresses match the client's IP address. You should
736 set this option if you use hostname based instructions. The -p option
737 implies the -h option.
738 * ignored by busyboxed version
740 backlog. Allow a backlog of approximately n TCP SYNs. On some systems n
741 is silently limited. Default is 20.
743 no special environment. Do not set up TCP-related environment variables.
745 verbose. Print verbose messsages to standard output.
747 more verbose. Print more verbose messages to standard output.
748 * no difference between -v and -vv in busyboxed version