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 Denys Vlasenko.
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
9
10 /* Based on 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 * Busybox version exports TCPLOCALADDR instead of
17 * TCPLOCALIP + TCPLOCALPORT pair. ADDR more closely matches reality
18 * (which is "struct sockaddr_XXX". Port is not a separate entity,
19 * it's just a part of (AF_INET[6]) sockaddr!).
20 *
21 * TCPORIGDSTADDR 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 //config:config TCPSVD
32 //config: bool "tcpsvd (14 kb)"
33 //config: default y
34 //config: help
35 //config: tcpsvd listens on a TCP port and runs a program for each new
36 //config: connection.
37 //config:
38 //config:config UDPSVD
39 //config: bool "udpsvd (13 kb)"
40 //config: default y
41 //config: help
42 //config: udpsvd listens on an UDP port and runs a program for each new
43 //config: connection.
44
45 //applet:IF_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, BB_DIR_USR_BIN, BB_SUID_DROP, tcpsvd))
46 //applet:IF_UDPSVD(APPLET_ODDNAME(udpsvd, tcpudpsvd, BB_DIR_USR_BIN, BB_SUID_DROP, udpsvd))
47
48 //kbuild:lib-$(CONFIG_TCPSVD) += tcpudp.o tcpudp_perhost.o
49 //kbuild:lib-$(CONFIG_UDPSVD) += tcpudp.o tcpudp_perhost.o
50
51 //usage:#define tcpsvd_trivial_usage
52 //usage: "[-hEv] [-c N] [-C N[:MSG]] [-b N] [-u USER] [-l NAME] IP PORT PROG"
53 /* with not-implemented options: */
54 /* //usage: "[-hpEvv] [-c N] [-C N[:MSG]] [-b N] [-u USER] [-l NAME] [-i DIR|-x CDB] [-t SEC] IP PORT PROG" */
55 //usage:#define tcpsvd_full_usage "\n\n"
56 //usage: "Create TCP socket, bind to IP:PORT and listen for incoming connections.\n"
57 //usage: "Run PROG for each connection.\n"
58 //usage: "\n IP PORT IP:PORT to listen on"
59 //usage: "\n PROG ARGS Program to run"
60 //usage: "\n -u USER[:GRP] Change to user/group after bind"
61 //usage: "\n -c N Up to N connections simultaneously (default 30)"
62 //usage: "\n -b N Allow backlog of approximately N TCP SYNs (default 20)"
63 //usage: "\n -C N[:MSG] Allow only up to N connections from the same IP:"
64 //usage: "\n new connections from this IP address are closed"
65 //usage: "\n immediately, MSG is written to the peer before close"
66 //usage: "\n -E Don't set up environment"
67 //usage: "\n -h Look up peer's hostname"
68 //usage: "\n -l NAME Local hostname (else look up local hostname in DNS)"
69 //usage: "\n -v Verbose"
70 //usage: "\n"
71 //usage: "\nEnvironment if no -E:"
72 //usage: "\nPROTO='TCP'"
73 //usage: "\nTCPREMOTEADDR='ip:port'" IF_FEATURE_IPV6(" ('[ip]:port' for IPv6)")
74 //usage: "\nTCPLOCALADDR='ip:port'"
75 //usage: "\nTCPORIGDSTADDR='ip:port' of destination before firewall"
76 //usage: "\n Useful for REDIRECTed-to-local connections:"
77 //usage: "\n iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to 8080"
78 //usage: "\nTCPCONCURRENCY=num_of_connects_from_this_ip"
79 //usage: "\nIf -h:"
80 //usage: "\nTCPLOCALHOST='hostname' (-l NAME is used if specified)"
81 //usage: "\nTCPREMOTEHOST='hostname'"
82
83 //usage:
84 //usage:#define udpsvd_trivial_usage
85 //usage: "[-hEv] [-c N] [-u USER] [-l NAME] IP PORT PROG"
86 //usage:#define udpsvd_full_usage "\n\n"
87 //usage: "Create UDP socket, bind to IP:PORT and wait for incoming packets.\n"
88 //usage: "Run PROG for each packet, redirecting all further packets with same\n"
89 //usage: "peer ip:port to it.\n"
90 //usage: "\n IP PORT IP:PORT to listen on"
91 //usage: "\n PROG ARGS Program to run"
92 //usage: "\n -u USER[:GRP] Change to user/group after bind"
93 //usage: "\n -c N Up to N connections simultaneously (default 30)"
94 //usage: "\n -E Don't set up environment"
95 //usage: "\n -h Look up peer's hostname"
96 //usage: "\n -l NAME Local hostname (else look up local hostname in DNS)"
97 //usage: "\n -v Verbose"
98 //usage: "\n"
99 //usage: "\nEnvironment if no -E:"
100 //usage: "\nPROTO='UDP'"
101 //usage: "\nUDPREMOTEADDR='ip:port'" IF_FEATURE_IPV6(" ('[ip]:port' for IPv6)")
102 //usage: "\nUDPLOCALADDR='ip:port'"
103 //usage: "\nIf -h:"
104 //usage: "\nUDPLOCALHOST='hostname' (-l NAME is used if specified)"
105 //usage: "\nUDPREMOTEHOST='hostname'"
106
107 #include "libbb.h"
108 #include "common_bufsiz.h"
109
110 #ifdef __linux__
111 /* from linux/netfilter_ipv4.h: */
112 # undef SO_ORIGINAL_DST
113 # define SO_ORIGINAL_DST 80
114 #endif
115
116 // TODO: move into this file:
117 #include "tcpudp_perhost.h"
118
119 #ifdef SSLSVD
120 #include "matrixSsl.h"
121 #include "ssl_io.h"
122 #endif
123
124 struct globals {
125 unsigned verbose;
126 unsigned max_per_host;
127 unsigned cur_per_host;
128 unsigned cnum;
129 unsigned cmax;
130 struct hcc *cc;
131 char **env_cur;
132 char *env_var[1]; /* actually bigger */
133 } FIX_ALIASING;
134 #define G (*(struct globals*)bb_common_bufsiz1)
135 #define verbose (G.verbose )
136 #define max_per_host (G.max_per_host)
137 #define cur_per_host (G.cur_per_host)
138 #define cnum (G.cnum )
139 #define cmax (G.cmax )
140 #define env_cur (G.env_cur )
141 #define env_var (G.env_var )
142 #define INIT_G() do { \
143 setup_common_bufsiz(); \
144 cmax = 30; \
145 env_cur = &env_var[0]; \
146 } while (0)
147
148
149 /* We have to be careful about leaking memory in repeated setenv's */
xsetenv_plain(const char * n,const char * v)150 static void xsetenv_plain(const char *n, const char *v)
151 {
152 char *var = xasprintf("%s=%s", n, v);
153 *env_cur++ = var;
154 putenv(var);
155 }
156
xsetenv_proto(const char * proto,const char * n,const char * v)157 static void xsetenv_proto(const char *proto, const char *n, const char *v)
158 {
159 char *var = xasprintf("%s%s=%s", proto, n, v);
160 *env_cur++ = var;
161 putenv(var);
162 }
163
undo_xsetenv(void)164 static void undo_xsetenv(void)
165 {
166 char **pp = env_cur = &env_var[0];
167 while (*pp) {
168 char *var = *pp;
169 bb_unsetenv_and_free(var);
170 *pp++ = NULL;
171 }
172 }
173
sig_term_handler(int sig)174 static void sig_term_handler(int sig)
175 {
176 if (verbose)
177 bb_error_msg("got signal %u, exit", sig);
178 kill_myself_with_sig(sig);
179 }
180
181 /* Little bloated, but tries to give accurate info how child exited.
182 * Makes easier to spot segfaulting children etc... */
print_waitstat(unsigned pid,int wstat)183 static void print_waitstat(unsigned pid, int wstat)
184 {
185 unsigned e = 0;
186 const char *cause = "?exit";
187
188 if (WIFEXITED(wstat)) {
189 cause++;
190 e = WEXITSTATUS(wstat);
191 } else if (WIFSIGNALED(wstat)) {
192 cause = "signal";
193 e = WTERMSIG(wstat);
194 }
195 bb_error_msg("end %d %s %d", pid, cause, e);
196 }
197
198 /* Must match getopt32 in main! */
199 enum {
200 OPT_c = (1 << 0),
201 OPT_C = (1 << 1),
202 OPT_i = (1 << 2),
203 OPT_x = (1 << 3),
204 OPT_u = (1 << 4),
205 OPT_l = (1 << 5),
206 OPT_E = (1 << 6),
207 OPT_b = (1 << 7),
208 OPT_h = (1 << 8),
209 OPT_p = (1 << 9),
210 OPT_t = (1 << 10),
211 OPT_v = (1 << 11),
212 OPT_V = (1 << 12),
213 OPT_U = (1 << 13), /* from here: sslsvd only */
214 OPT_slash = (1 << 14),
215 OPT_Z = (1 << 15),
216 OPT_K = (1 << 16),
217 };
218
if_verbose_print_connection_status(void)219 static void if_verbose_print_connection_status(void)
220 {
221 if (verbose) {
222 /* "only 1 client max" desn't need this */
223 if (cmax > 1)
224 bb_error_msg("status %u/%u", cnum, cmax);
225 }
226 }
227
228 /* SIGCHLD handler is reentrancy-safe because SIGCHLD is unmasked
229 * only over accept() or recvfrom() calls, not over memory allocations
230 * or printouts. Do need to save/restore errno in order not to mangle
231 * these syscalls' error code, if any.
232 */
sig_child_handler(int sig UNUSED_PARAM)233 static void sig_child_handler(int sig UNUSED_PARAM)
234 {
235 int wstat;
236 pid_t pid;
237 int sv_errno = errno;
238
239 while ((pid = wait_any_nohang(&wstat)) > 0) {
240 if (max_per_host)
241 ipsvd_perhost_remove(G.cc, pid);
242 if (cnum)
243 cnum--;
244 if (verbose)
245 print_waitstat(pid, wstat);
246 }
247 if_verbose_print_connection_status();
248 errno = sv_errno;
249 }
250
251 int tcpudpsvd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
tcpudpsvd_main(int argc UNUSED_PARAM,char ** argv)252 int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv)
253 {
254 char *str_C, *str_t;
255 char *user;
256 struct hcc *hccp;
257 const char *instructs;
258 char *msg_per_host = NULL;
259 unsigned len_per_host = len_per_host; /* gcc */
260 #ifndef SSLSVD
261 struct bb_uidgid_t ugid;
262 #endif
263 bool tcp;
264 uint16_t local_port;
265 char *preset_local_hostname = NULL;
266 char *remote_hostname = remote_hostname; /* for compiler */
267 char *remote_addr = remote_addr; /* for compiler */
268 len_and_sockaddr *lsa;
269 len_and_sockaddr local, remote;
270 socklen_t sa_len;
271 int pid;
272 int sock;
273 int conn;
274 unsigned backlog = 20;
275 unsigned opts;
276
277 INIT_G();
278
279 tcp = (applet_name[0] == 't');
280
281 /* "+": stop on first non-option */
282 #ifdef SSLSVD
283 opts = getopt32(argv, "^+"
284 "c:+C:i:x:u:l:Eb:+hpt:vU:/:Z:K:" /* -c NUM, -b NUM */
285 "\0"
286 /* 3+ args, -i at most once, -p implies -h, -v is a counter */
287 "-3:i--i:ph:vv",
288 &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname,
289 &backlog, &str_t, &ssluser, &root, &cert, &key, &verbose
290 );
291 #else
292 opts = getopt32(argv, "^+"
293 "c:+C:i:x:u:l:Eb:+hpt:v" /* -c NUM, -b NUM */
294 "\0"
295 /* 3+ args, -i at most once, -p implies -h, -v is a counter */
296 "-3:i--i:ph:vv",
297 &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname,
298 &backlog, &str_t, &verbose
299 );
300 #endif
301 if (opts & OPT_C) { /* -C n[:message] */
302 max_per_host = bb_strtou(str_C, &str_C, 10);
303 if (str_C[0]) {
304 if (str_C[0] != ':')
305 bb_show_usage();
306 msg_per_host = str_C + 1;
307 len_per_host = strlen(msg_per_host);
308 }
309 }
310 if (max_per_host > cmax)
311 max_per_host = cmax;
312 if (opts & OPT_u) {
313 xget_uidgid(&ugid, user);
314 }
315 #ifdef SSLSVD
316 if (opts & OPT_U) ssluser = optarg;
317 if (opts & OPT_slash) root = optarg;
318 if (opts & OPT_Z) cert = optarg;
319 if (opts & OPT_K) key = optarg;
320 #endif
321 argv += optind;
322 if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
323 argv[0] = (char*)"0.0.0.0";
324
325 /* Per-IP flood protection is not thought-out for UDP */
326 if (!tcp)
327 max_per_host = 0;
328
329 bb_sanitize_stdio(); /* fd# 0,1,2 must be opened */
330
331 #ifdef SSLSVD
332 sslser = user;
333 client = 0;
334 if ((getuid() == 0) && !(opts & OPT_u)) {
335 xfunc_error_retval = 100;
336 bb_simple_error_msg_and_die(bb_msg_you_must_be_root);
337 }
338 if (opts & OPT_u)
339 if (!uidgid_get(&sslugid, ssluser, 1)) {
340 if (errno) {
341 bb_perror_msg_and_die("can't get user/group: %s", ssluser);
342 }
343 bb_error_msg_and_die("unknown user/group %s", ssluser);
344 }
345 if (!cert) cert = "./cert.pem";
346 if (!key) key = cert;
347 if (matrixSslOpen() < 0)
348 fatal("can't initialize ssl");
349 if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
350 if (client)
351 fatal("can't read cert, key, or ca file");
352 fatal("can't read cert or key file");
353 }
354 if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
355 fatal("can't create ssl session");
356 #endif
357
358 sig_block(SIGCHLD);
359 signal(SIGCHLD, sig_child_handler);
360 bb_signals(BB_FATAL_SIGS, sig_term_handler);
361 signal(SIGPIPE, SIG_IGN);
362
363 if (max_per_host)
364 G.cc = ipsvd_perhost_init(cmax);
365
366 local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0);
367 lsa = xhost2sockaddr(argv[0], local_port);
368 argv += 2;
369
370 sock = xsocket(lsa->u.sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
371 setsockopt_reuseaddr(sock);
372 sa_len = lsa->len; /* I presume sockaddr len stays the same */
373 xbind(sock, &lsa->u.sa, sa_len);
374 if (tcp) {
375 xlisten(sock, backlog);
376 close_on_exec_on(sock);
377 } else { /* udp: needed for recv_from_to to work: */
378 socket_want_pktinfo(sock);
379 }
380 /* ndelay_off(sock); - it is the default I think? */
381
382 #ifndef SSLSVD
383 if (opts & OPT_u) {
384 /* drop permissions */
385 xsetgid(ugid.gid);
386 xsetuid(ugid.uid);
387 }
388 #endif
389
390 if (verbose) {
391 char *addr = xmalloc_sockaddr2dotted(&lsa->u.sa);
392 if (opts & OPT_u)
393 bb_error_msg("listening on %s, starting, uid %u, gid %u", addr,
394 (unsigned)ugid.uid, (unsigned)ugid.gid);
395 else
396 bb_error_msg("listening on %s, starting", addr);
397 free(addr);
398 }
399
400 /* Main accept() loop */
401
402 again:
403 hccp = NULL;
404
405 again1:
406 close(0);
407 /* It's important to close(0) _before_ wait loop:
408 * fd#0 can be a shared connection fd.
409 * If kept open by us, peer can't detect PROG closing it.
410 */
411 while (cnum >= cmax)
412 wait_for_any_sig(); /* expecting SIGCHLD */
413
414 again2:
415 sig_unblock(SIGCHLD);
416 local.len = remote.len = sa_len;
417 if (tcp) {
418 /* Accept a connection to fd #0 */
419 conn = accept(sock, &remote.u.sa, &remote.len);
420 } else {
421 /* In case recv_from_to won't be able to recover local addr.
422 * Also sets port - recv_from_to is unable to do it. */
423 local = *lsa;
424 conn = recv_from_to(sock, NULL, 0, MSG_PEEK,
425 &remote.u.sa, &local.u.sa, sa_len);
426 }
427 sig_block(SIGCHLD);
428 if (conn < 0) {
429 if (errno != EINTR)
430 bb_simple_perror_msg(tcp ? "accept" : "recv");
431 goto again2;
432 }
433 xmove_fd(tcp ? conn : sock, 0);
434
435 if (max_per_host) {
436 /* Drop connection immediately if cur_per_host > max_per_host
437 * (minimizing load under SYN flood) */
438 remote_addr = xmalloc_sockaddr2dotted_noport(&remote.u.sa);
439 cur_per_host = ipsvd_perhost_add(G.cc, remote_addr, max_per_host, &hccp);
440 if (cur_per_host > max_per_host) {
441 /* ipsvd_perhost_add detected that max is exceeded
442 * (and did not store ip in connection table) */
443 free(remote_addr);
444 if (msg_per_host) {
445 /* don't block or test for errors */
446 send(0, msg_per_host, len_per_host, MSG_DONTWAIT);
447 }
448 goto again1;
449 }
450 /* NB: remote_addr is not leaked, it is stored in conn table */
451 }
452
453 if (!tcp) {
454 /* Voodoo magic: making udp sockets each receive its own
455 * packets is not trivial, and I still not sure
456 * I do it 100% right.
457 * 1) we have to do it before fork()
458 * 2) order is important - is it right now? */
459
460 /* Open new non-connected UDP socket for further clients... */
461 sock = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0);
462 setsockopt_reuseaddr(sock);
463 /* Make plain write/send work for old socket by supplying default
464 * destination address. This also restricts incoming packets
465 * to ones coming from this remote IP. */
466 xconnect(0, &remote.u.sa, sa_len);
467 /* hole? at this point we have no wildcard udp socket...
468 * can this cause clients to get "port unreachable" icmp?
469 * Yup, time window is very small, but it exists (does it?) */
470 /* ..."open new socket", continued */
471 xbind(sock, &lsa->u.sa, sa_len);
472 socket_want_pktinfo(sock);
473
474 /* Doesn't work:
475 * we cannot replace fd #0 - we will lose pending packet
476 * which is already buffered for us! And we cannot use fd #1
477 * instead - it will "intercept" all following packets, but child
478 * does not expect data coming *from fd #1*! */
479 #if 0
480 /* Make it so that local addr is fixed to localp->u.sa
481 * and we don't accidentally accept packets to other local IPs. */
482 /* NB: we possibly bind to the _very_ same_ address & port as the one
483 * already bound in parent! This seems to work in Linux.
484 * (otherwise we can move socket to fd #0 only if bind succeeds) */
485 close(0);
486 set_nport(&localp->u.sa, htons(local_port));
487 xmove_fd(xsocket(localp->u.sa.sa_family, SOCK_DGRAM, 0), 0);
488 setsockopt_reuseaddr(0); /* crucial */
489 xbind(0, &localp->u.sa, localp->len);
490 #endif
491 }
492
493 pid = vfork();
494 if (pid == -1) {
495 bb_simple_perror_msg("vfork");
496 goto again;
497 }
498
499 if (pid != 0) {
500 /* Parent */
501 cnum++;
502 if_verbose_print_connection_status();
503 if (hccp)
504 hccp->pid = pid;
505 /* clean up changes done by vforked child */
506 undo_xsetenv();
507 goto again;
508 }
509
510 /* Child: prepare env, log, and exec prog */
511
512 { /* vfork alert! every xmalloc in this block should be freed! */
513 char *local_hostname = local_hostname; /* for compiler */
514 char *local_addr = NULL;
515 char *free_me0 = NULL;
516 char *free_me1 = NULL;
517 char *free_me2 = NULL;
518
519 if (verbose || !(opts & OPT_E)) {
520 if (!max_per_host) /* remote_addr is not yet known */
521 free_me0 = remote_addr = xmalloc_sockaddr2dotted(&remote.u.sa);
522 if (opts & OPT_h) {
523 free_me1 = remote_hostname = xmalloc_sockaddr2host_noport(&remote.u.sa);
524 if (!remote_hostname) {
525 bb_error_msg("can't look up hostname for %s", remote_addr);
526 remote_hostname = remote_addr;
527 }
528 }
529 /* Find out local IP peer connected to.
530 * Errors ignored (I'm not paranoid enough to imagine kernel
531 * which doesn't know local IP). */
532 if (tcp)
533 getsockname(0, &local.u.sa, &local.len);
534 /* else: for UDP it is done earlier by parent */
535 local_addr = xmalloc_sockaddr2dotted(&local.u.sa);
536 if (opts & OPT_h) {
537 local_hostname = preset_local_hostname;
538 if (!local_hostname) {
539 free_me2 = local_hostname = xmalloc_sockaddr2host_noport(&local.u.sa);
540 if (!local_hostname)
541 bb_error_msg_and_die("can't look up hostname for %s", local_addr);
542 }
543 /* else: local_hostname is not NULL, but is NOT malloced! */
544 }
545 }
546 if (verbose) {
547 pid = getpid();
548 if (max_per_host) {
549 bb_error_msg("concurrency %s %u/%u",
550 remote_addr,
551 cur_per_host, max_per_host);
552 }
553 bb_error_msg((opts & OPT_h)
554 ? "start %u %s-%s (%s-%s)"
555 : "start %u %s-%s",
556 pid,
557 local_addr, remote_addr,
558 local_hostname, remote_hostname);
559 }
560
561 if (!(opts & OPT_E)) {
562 /* setup ucspi env */
563 const char *proto = tcp ? "TCP" : "UDP";
564
565 #ifdef SO_ORIGINAL_DST
566 /* Extract "original" destination addr:port
567 * from Linux firewall. Useful when you redirect
568 * an outbond connection to local handler, and it needs
569 * to know where it originally tried to connect */
570 if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &local.u.sa, &local.len) == 0) {
571 char *addr = xmalloc_sockaddr2dotted(&local.u.sa);
572 xsetenv_plain("TCPORIGDSTADDR", addr);
573 free(addr);
574 }
575 #endif
576 xsetenv_plain("PROTO", proto);
577 xsetenv_proto(proto, "LOCALADDR", local_addr);
578 xsetenv_proto(proto, "REMOTEADDR", remote_addr);
579 if (opts & OPT_h) {
580 xsetenv_proto(proto, "LOCALHOST", local_hostname);
581 xsetenv_proto(proto, "REMOTEHOST", remote_hostname);
582 }
583 //compat? xsetenv_proto(proto, "REMOTEINFO", "");
584 /* additional */
585 if (cur_per_host > 0) /* can not be true for udp */
586 xsetenv_plain("TCPCONCURRENCY", utoa(cur_per_host));
587 }
588 free(local_addr);
589 free(free_me0);
590 free(free_me1);
591 free(free_me2);
592 }
593
594 xdup2(0, 1);
595
596 /* Restore signal handling for the to-be-execed process */
597 signal(SIGPIPE, SIG_DFL); /* this one was SIG_IGNed */
598 /* Non-ignored signals revert to SIG_DFL on exec anyway
599 * But we can get signals BEFORE execvp(), this is unlikely
600 * but it would invoke sig_child_handler(), which would
601 * check waitpid(WNOHANG), then print "status N/M" if verbose.
602 * I guess we can live with that possibility.
603 */
604 /*signal(SIGCHLD, SIG_DFL);*/
605 sig_unblock(SIGCHLD);
606
607 #ifdef SSLSVD
608 strcpy(id, utoa(pid));
609 ssl_io(0, argv);
610 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
611 #else
612 BB_EXECVP_or_die(argv);
613 #endif
614 }
615
616 /*
617 tcpsvd [-hpEvv] [-c n] [-C n:msg] [-b n] [-u user] [-l name]
618 [-i dir|-x cdb] [ -t sec] host port prog
619
620 tcpsvd creates a TCP/IP socket, binds it to the address host:port,
621 and listens on the socket for incoming connections.
622
623 On each incoming connection, tcpsvd conditionally runs a program,
624 with standard input reading from the socket, and standard output
625 writing to the socket, to handle this connection. tcpsvd keeps
626 listening on the socket for new connections, and can handle
627 multiple connections simultaneously.
628
629 tcpsvd optionally checks for special instructions depending
630 on the IP address or hostname of the client that initiated
631 the connection, see ipsvd-instruct(5).
632
633 host
634 host either is a hostname, or a dotted-decimal IP address,
635 or 0. If host is 0, tcpsvd accepts connections to any local
636 IP address.
637 * busybox accepts IPv6 addresses and host:port pairs too
638 In this case second parameter is ignored
639 port
640 tcpsvd accepts connections to host:port. port may be a name
641 from /etc/services or a number.
642 prog
643 prog consists of one or more arguments. For each connection,
644 tcpsvd normally runs prog, with file descriptor 0 reading from
645 the network, and file descriptor 1 writing to the network.
646 By default it also sets up TCP-related environment variables,
647 see tcp-environ(5)
648 -i dir
649 read instructions for handling new connections from the instructions
650 directory dir. See ipsvd-instruct(5) for details.
651 * ignored by busyboxed version
652 -x cdb
653 read instructions for handling new connections from the constant database
654 cdb. The constant database normally is created from an instructions
655 directory by running ipsvd-cdb(8).
656 * ignored by busyboxed version
657 -t sec
658 timeout. This option only takes effect if the -i option is given.
659 While checking the instructions directory, check the time of last access
660 of the file that matches the clients address or hostname if any, discard
661 and remove the file if it wasn't accessed within the last sec seconds;
662 tcpsvd does not discard or remove a file if the user's write permission
663 is not set, for those files the timeout is disabled. Default is 0,
664 which means that the timeout is disabled.
665 * ignored by busyboxed version
666 -l name
667 local hostname. Do not look up the local hostname in DNS, but use name
668 as hostname. This option must be set if tcpsvd listens on port 53
669 to avoid loops.
670 -u user[:group]
671 drop permissions. Switch user ID to user's UID, and group ID to user's
672 primary GID after creating and binding to the socket. If user is followed
673 by a colon and a group name, the group ID is switched to the GID of group
674 instead. All supplementary groups are removed.
675 -c n
676 concurrency. Handle up to n connections simultaneously. Default is 30.
677 If there are n connections active, tcpsvd defers acceptance of a new
678 connection until an active connection is closed.
679 -C n[:msg]
680 per host concurrency. Allow only up to n connections from the same IP
681 address simultaneously. If there are n active connections from one IP
682 address, new incoming connections from this IP address are closed
683 immediately. If n is followed by :msg, the message msg is written
684 to the client if possible, before closing the connection. By default
685 msg is empty. See ipsvd-instruct(5) for supported escape sequences in msg.
686
687 For each accepted connection, the current per host concurrency is
688 available through the environment variable TCPCONCURRENCY. n and msg
689 can be overwritten by ipsvd(7) instructions, see ipsvd-instruct(5).
690 By default tcpsvd doesn't keep track of connections.
691 -h
692 Look up the client's hostname in DNS.
693 -p
694 paranoid. After looking up the client's hostname in DNS, look up the IP
695 addresses in DNS for that hostname, and forget about the hostname
696 if none of the addresses match the client's IP address. You should
697 set this option if you use hostname based instructions. The -p option
698 implies the -h option.
699 * ignored by busyboxed version
700 -b n
701 backlog. Allow a backlog of approximately n TCP SYNs. On some systems n
702 is silently limited. Default is 20.
703 -E
704 no special environment. Do not set up TCP-related environment variables.
705 -v
706 verbose. Print verbose messages to standard output.
707 -vv
708 more verbose. Print more verbose messages to standard output.
709 * no difference between -v and -vv in busyboxed version
710 */
711