summaryrefslogtreecommitdiff
path: root/ipsvd/tcpudp.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipsvd/tcpudp.c')
-rw-r--r--ipsvd/tcpudp.c750
1 files changed, 750 insertions, 0 deletions
diff --git a/ipsvd/tcpudp.c b/ipsvd/tcpudp.c
new file mode 100644
index 000000000..419551d8d
--- /dev/null
+++ b/ipsvd/tcpudp.c
@@ -0,0 +1,750 @@
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/* TCP and UDP server are using a lot of same string constants
11 * We reuse them by keeping both in one source file */
12
13#include "busybox.h"
14
15static unsigned verbose;
16
17static void sig_term_handler(int sig)
18{
19 if (verbose)
20 printf("%s: info: sigterm received, exit\n", applet_name);
21 exit(0);
22}
23
24/* Little bloated, but tries to give accurate info how child exited.
25 * Makes easier to spot segfaulting children etc... */
26static void print_waitstat(unsigned pid, int wstat)
27{
28 unsigned e = 0;
29 const char *cause = "?exit";
30
31 if (WIFEXITED(wstat)) {
32 cause++;
33 e = WEXITSTATUS(wstat);
34 } else if (WIFSIGNALED(wstat)) {
35 cause = "signal";
36 e = WTERMSIG(wstat);
37 }
38 printf("%s: info: end %d %s %d\n", applet_name, pid, cause, e);
39}
40
41
42#if ENABLE_UDPSVD
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.
46 *
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).
51 */
52
53#include "udp_io.c"
54
55int udpsvd_main(int argc, char **argv);
56int udpsvd_main(int argc, char **argv)
57{
58 const char *instructs;
59 char *str_t, *user;
60 unsigned opt;
61
62 char *remote_hostname = (char*)""; /* used if no -h */
63 char *local_hostname = NULL;
64 char *remote_ip;
65 char *local_ip;// = local_ip; /* gcc */
66 uint16_t local_port, remote_port;
67 len_and_sockaddr remote;
68 len_and_sockaddr *localp;
69 int wstat;
70 unsigned pid;
71 struct bb_uidgid_t ugid;
72
73 enum {
74 OPT_v = (1 << 0),
75 OPT_u = (1 << 1),
76 OPT_l = (1 << 2),
77 OPT_h = (1 << 3),
78 OPT_p = (1 << 4),
79 OPT_i = (1 << 5),
80 OPT_x = (1 << 6),
81 OPT_t = (1 << 7),
82 };
83
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);
87 if (opt & OPT_u) {
88 if (!get_uidgid(&ugid, user, 1))
89 bb_error_msg_and_die("unknown user/group: %s", user);
90 }
91 argv += optind;
92 if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
93 argv[0] = (char*)"0.0.0.0";
94
95 /* stdout is used for logging, don't buffer */
96 setlinebuf(stdout);
97 bb_sanitize_stdio(); /* fd# 1,2 must be opened */
98
99 signal(SIGTERM, sig_term_handler);
100 signal(SIGPIPE, SIG_IGN);
101
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 */
109
110 if (opt & OPT_u) { /* drop permissions */
111 xsetgid(ugid.gid);
112 xsetuid(ugid.uid);
113 }
114
115 if (verbose) {
116 /* we do it only for ":port" cosmetics... oh well */
117 char *addr = xmalloc_sockaddr2dotted(&localp->sa, localp->len);
118
119 printf("%s: info: listening on %s", applet_name, addr);
120 free(addr);
121 if (option_mask32 & OPT_u)
122 printf(", uid %u, gid %u",
123 (unsigned)ugid.uid, (unsigned)ugid.gid);
124 puts(", starting");
125 }
126
127 again:
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");
131 goto again;
132 }
133
134 while ((pid = fork()) < 0) {
135 bb_perror_msg("fork failed, sleeping");
136 sleep(5);
137 }
138 if (pid > 0) { /* parent */
139 while (wait_pid(&wstat, pid) < 0)
140 bb_perror_msg("error waiting for child");
141 if (verbose)
142 print_waitstat(pid, wstat);
143 goto again;
144 }
145
146 /* Child */
147
148 if (verbose) {
149 remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, localp->len);
150 local_ip = xmalloc_sockaddr2dotted_noport(&localp->sa, localp->len);
151
152 pid = getpid();
153 printf("%s: info: pid %u from %s\n", applet_name, pid, remote_ip);
154
155 if (!local_hostname) {
156 local_hostname = xmalloc_sockaddr2host_noport(&localp->sa, localp->len);
157 if (!local_hostname)
158 bb_error_msg_and_die("cannot look up local hostname for %s", local_ip);
159 }
160 if (opt & OPT_h) {
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*)"";
165 }
166 }
167
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);
173 }
174
175 /* Doesn't work:
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*! */
180#if 0
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) */
186 close(0);
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);
191#endif
192
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);
197 dup2(0 ,1);
198
199 signal(SIGTERM, SIG_DFL);
200 signal(SIGPIPE, SIG_DFL);
201
202 argv += 2;
203 BB_EXECVP(argv[0], argv);
204 bb_perror_msg_and_die("exec '%s'", argv[0]);
205}
206
207
208/*
209udpsvd [-hpvv] [-u user] [-l name] [-i dir|-x cdb] [-t sec] host port prog
210
211udpsvd creates an UDP/IP socket, binds it to the address host:port,
212and listens on the socket for incoming datagrams.
213
214If a datagram is available on the socket, udpsvd conditionally starts
215a program, with standard input reading from the socket, and standard
216output redirected to standard error, to handle this, and possibly
217more datagrams. udpsvd does not start the program if another program
218that it has started before still is running. If the program exits,
219udpsvd again listens to the socket until a new datagram is available.
220If there are still datagrams available on the socket, the program
221is restarted immediately.
222
223udpsvd optionally checks for special intructions depending on
224the IP address or hostname of the client sending the datagram which
225not yet was handled by a running program, see ipsvd-instruct(5)
226for details.
227
228Attention:
229UDP is a connectionless protocol. Most programs that handle user datagrams,
230such as talkd(8), keep running after receiving a datagram, and process
231subsequent datagrams sent to the socket until a timeout is reached.
232udpsvd only checks special instructions for a datagram that causes a startup
233of the program; not if a program handling datagrams already is running.
234It doesn't make much sense to restrict access through special instructions
235when using such a program.
236
237On the other hand, it makes perfectly sense with programs like tftpd(8),
238that fork to establish a separate connection to the client when receiving
239the datagram. In general it's adequate to set up special instructions for
240programs that support being run by tcpwrapper.
241Options
242
243host
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.
246port
247 udpsvd accepts datagrams to host:port. port may be a name from
248 /etc/services or a number.
249prog
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.
254-i dir
255 read instructions for handling new connections from the instructions
256 directory dir. See ipsvd-instruct(5) for details.
257-x cdb
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).
261-t sec
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.
269-l name
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.
272-u user[:group]
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.
277-h
278 Look up the client's hostname in DNS.
279-p
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.
285-v
286 verbose. Print verbose messages to standard output.
287-vv
288 more verbose. Print more verbose messages to standard output.
289*/
290#endif
291
292
293#if ENABLE_TCPSVD
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.
297 *
298 * Code inside "#ifdef SSLSVD" is for sslsvd and is currently unused.
299 *
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).
304 *
305 * TCPORIGDST{IP,PORT} is busybox-specific addition
306 */
307
308#include <limits.h>
309#include <linux/netfilter_ipv4.h> /* wants <limits.h> */
310#include "ipsvd_perhost.h"
311
312#ifdef SSLSVD
313#include "matrixSsl.h"
314#include "ssl_io.h"
315#endif
316
317static unsigned max_per_host; /* originally in ipsvd_check.c */
318static unsigned cur_per_host;
319static unsigned cnum;
320static unsigned cmax = 30;
321
322/* Must match getopt32 in main! */
323enum {
324 OPT_c = (1 << 0),
325 OPT_C = (1 << 1),
326 OPT_i = (1 << 2),
327 OPT_x = (1 << 3),
328 OPT_u = (1 << 4),
329 OPT_l = (1 << 5),
330 OPT_E = (1 << 6),
331 OPT_b = (1 << 7),
332 OPT_h = (1 << 8),
333 OPT_p = (1 << 9),
334 OPT_t = (1 << 10),
335 OPT_v = (1 << 11),
336 OPT_V = (1 << 12),
337 OPT_U = (1 << 13), /* from here: sslsvd only */
338 OPT_slash = (1 << 14),
339 OPT_Z = (1 << 15),
340 OPT_K = (1 << 16),
341};
342
343static void connection_status(void)
344{
345 printf("%s: info: status %u/%u\n", applet_name, cnum, cmax);
346}
347
348static void sig_child_handler(int sig)
349{
350 int wstat;
351 int pid;
352
353 while ((pid = wait_nohang(&wstat)) > 0) {
354 if (max_per_host)
355 ipsvd_perhost_remove(pid);
356 if (cnum)
357 cnum--;
358 if (verbose)
359 print_waitstat(pid, wstat);
360 }
361 if (verbose)
362 connection_status();
363}
364
365int tcpsvd_main(int argc, char **argv);
366int tcpsvd_main(int argc, char **argv)
367{
368 char *str_c, *str_C, *str_b, *str_t;
369 char *user;
370 struct hcc *hccp;
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;
375 int pid;
376 int sock;
377 int conn;
378 unsigned backlog = 20;
379 len_and_sockaddr *lsa;
380 uint16_t local_port;
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 */
386#ifndef SSLSVD
387 struct bb_uidgid_t ugid;
388#endif
389
390 /* 3+ args, -i at most once, -p implies -h, -v is counter */
391 opt_complementary = "-3:?:i--i:ph:vv";
392#ifdef SSLSVD
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
396 );
397#else
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
401 );
402#endif
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);
407 if (str_C[0]) {
408 if (str_C[0] != ':')
409 bb_show_usage();
410 msg_per_host = str_C + 1;
411 len_per_host = strlen(msg_per_host);
412 }
413 }
414 if (max_per_host > cmax)
415 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);
419 }
420 if (option_mask32 & OPT_b)
421 backlog = xatou(str_b);
422#ifdef SSLSVD
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;
427#endif
428 argv += optind;
429 if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
430 argv[0] = (char*)"0.0.0.0";
431
432 /* stdout is used for logging, don't buffer */
433 setlinebuf(stdout);
434 bb_sanitize_stdio(); /* fd# 1,2 must be opened */
435
436 need_hostnames = verbose || !(option_mask32 & OPT_E);
437 need_remote_ip = max_per_host || need_hostnames;
438
439#ifdef SSLSVD
440 sslser = user;
441 client = 0;
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");
445 }
446 if (option_mask32 & OPT_u)
447 if (!uidgid_get(&sslugid, ssluser, 1)) {
448 if (errno) {
449 xfunc_exitcode = 100;
450 bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser);
451 }
452 xfunc_exitcode = 111;
453 bb_error_msg_and_die("fatal: unknown user/group '%s'", ssluser);
454 }
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) {
460 if (client)
461 fatal("cannot read cert, key, or ca file");
462 fatal("cannot read cert or key file");
463 }
464 if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
465 fatal("cannot create ssl session");
466#endif
467
468 sig_block(SIGCHLD);
469 signal(SIGCHLD, sig_child_handler);
470 signal(SIGTERM, sig_term_handler);
471 signal(SIGPIPE, SIG_IGN);
472
473 if (max_per_host)
474 ipsvd_perhost_init(cmax);
475
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? */
483
484#ifndef SSLSVD
485 if (option_mask32 & OPT_u) {
486 /* drop permissions */
487 xsetgid(ugid.gid);
488 xsetuid(ugid.uid);
489 }
490#endif
491
492 if (verbose) {
493 /* we do it only for ":port" cosmetics... oh well */
494 char *addr = xmalloc_sockaddr2dotted(&lsa->sa, lsa->len);
495
496 printf("%s: info: listening on %s", applet_name, addr);
497 free(addr);
498#ifndef SSLSVD
499 if (option_mask32 & OPT_u)
500 printf(", uid %u, gid %u",
501 (unsigned)ugid.uid, (unsigned)ugid.gid);
502#endif
503 puts(", starting");
504 }
505
506 /* The rest is a main accept() loop */
507
508 again:
509 hccp = NULL;
510
511 while (cnum >= cmax)
512 sig_pause(); /* wait for any signal (expecting SIGCHLD) */
513
514 /* Accept a connection to fd #0 */
515 again1:
516 close(0);
517 again2:
518 sig_unblock(SIGCHLD);
519 conn = accept(sock, &lsa->sa, &lsa->len);
520 sig_block(SIGCHLD);
521 if (conn < 0) {
522 if (errno != EINTR)
523 bb_perror_msg("accept");
524 goto again2;
525 }
526 xmove_fd(conn, 0);
527
528 if (max_per_host) {
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) */
536 free(remote_ip);
537 if (msg_per_host) {
538 /* don't block or test for errors */
539 ndelay_on(0);
540 write(0, msg_per_host, len_per_host);
541 }
542 goto again1;
543 }
544 }
545
546 cnum++;
547 if (verbose)
548 connection_status();
549
550 pid = fork();
551 if (pid == -1) {
552 bb_perror_msg("fork");
553 goto again;
554 }
555 if (pid != 0) {
556 /* parent */
557 if (hccp)
558 hccp->pid = pid;
559 goto again;
560 }
561
562 /* Child: prepare env, log, and exec prog */
563
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);
569
570 if (need_remote_ip) {
571 if (!max_per_host)
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);
576 }
577
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*)"";
584 }
585 }
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);
591 if (!local_hostname)
592 bb_error_msg_and_die("cannot look up local hostname for %s", local_ip);
593 }
594 }
595
596 if (verbose) {
597 pid = getpid();
598 printf("%s: info: pid %u from %s\n", applet_name, pid, remote_ip);
599 if (max_per_host)
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",
603 applet_name, pid,
604 local_hostname, local_ip,
605 remote_hostname, remote_ip, (unsigned)remote_port);
606 }
607
608 if (!(option_mask32 & OPT_E)) {
609 /* setup ucspi env */
610
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);
618 port = ntohs(port);
619 xsetenv("TCPORIGDSTIP", ip);
620 xsetenv("TCPORIGDSTPORT", utoa(port));
621 free(ip);
622 }
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);
631 }
632 xsetenv("TCPREMOTEINFO", "");
633 /* additional */
634 if (cur_per_host > 0)
635 xsetenv("TCPCONCURRENCY", utoa(cur_per_host));
636 }
637
638 dup2(0, 1);
639
640 signal(SIGTERM, SIG_DFL);
641 signal(SIGPIPE, SIG_DFL);
642 signal(SIGCHLD, SIG_DFL);
643 sig_unblock(SIGCHLD);
644
645 argv += 2;
646#ifdef SSLSVD
647 strcpy(id, utoa(pid);
648 ssl_io(0, argv);
649#else
650 BB_EXECVP(argv[0], argv);
651#endif
652 bb_perror_msg_and_die("exec '%s'", argv[0]);
653}
654
655/*
656tcpsvd [-hpEvv] [-c n] [-C n:msg] [-b n] [-u user] [-l name]
657 [-i dir|-x cdb] [ -t sec] host port prog
658
659tcpsvd creates a TCP/IP socket, binds it to the address host:port,
660and listens on the socket for incoming connections.
661
662On each incoming connection, tcpsvd conditionally runs a program,
663with standard input reading from the socket, and standard output
664writing to the socket, to handle this connection. tcpsvd keeps
665listening on the socket for new connections, and can handle
666multiple connections simultaneously.
667
668tcpsvd optionally checks for special instructions depending
669on the IP address or hostname of the client that initiated
670the connection, see ipsvd-instruct(5).
671
672host
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
675 IP address.
676 * busybox accepts IPv6 addresses and host:port pairs too
677 In this case second parameter is ignored
678port
679 tcpsvd accepts connections to host:port. port may be a name
680 from /etc/services or a number.
681prog
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,
686 see tcp-environ(5)
687-i dir
688 read instructions for handling new connections from the instructions
689 directory dir. See ipsvd-instruct(5) for details.
690 * ignored by busyboxed version
691-x cdb
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
696-t sec
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
705-l name
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
708 to avoid loops.
709-u user[:group]
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.
714-c n
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.
718-C n[:msg]
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.
725
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.
730-h
731 Look up the client's hostname in DNS.
732-p
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
739-b n
740 backlog. Allow a backlog of approximately n TCP SYNs. On some systems n
741 is silently limited. Default is 20.
742-E
743 no special environment. Do not set up TCP-related environment variables.
744-v
745 verbose. Print verbose messsages to standard output.
746-vv
747 more verbose. Print more verbose messages to standard output.
748 * no difference between -v and -vv in busyboxed version
749*/
750#endif