blob: 66f44e9a6576eca78063304020623d027ca4198a [file] [log] [blame]
Denis Vlasenkob933ac12007-04-03 12:09:46 +00001/* 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
Denis Vlasenko02fd6682007-04-03 23:23:10 +000010/* 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:
Denis Vlasenko64a15122007-04-04 10:16:15 +000025 * - local IP address is retrieved (using recvmsg voodoo) but
Denis Vlasenko02fd6682007-04-03 23:23:10 +000026 * child's socket is not bound to it (bind cannot be called on
Denis Vlasenko64a15122007-04-04 10:16:15 +000027 * already bound socket). Thus it still can emit outgoing packets
Denis Vlasenko02fd6682007-04-03 23:23:10 +000028 * with wrong sorce IP...
29 * - don't know how to retrieve ORIGDST for udp.
30 */
31
32#include <limits.h>
33#include <linux/netfilter_ipv4.h> /* wants <limits.h> */
Denis Vlasenkob933ac12007-04-03 12:09:46 +000034
35#include "busybox.h"
36
Denis Vlasenko02fd6682007-04-03 23:23:10 +000037#include "udp_io.c"
38#include "ipsvd_perhost.h"
39
40#ifdef SSLSVD
41#include "matrixSsl.h"
42#include "ssl_io.h"
43#endif
44
Denis Vlasenkob933ac12007-04-03 12:09:46 +000045static unsigned verbose;
Denis Vlasenko02fd6682007-04-03 23:23:10 +000046static unsigned max_per_host;
47static unsigned cur_per_host;
48static unsigned cnum;
49static unsigned cmax = 30;
50
51static void xsetenv_proto(const char *proto, const char *n, const char *v)
52{
53 putenv(xasprintf("%s%s=%s", proto, n, v));
54}
Denis Vlasenkob933ac12007-04-03 12:09:46 +000055
56static void sig_term_handler(int sig)
57{
58 if (verbose)
59 printf("%s: info: sigterm received, exit\n", applet_name);
60 exit(0);
61}
62
63/* Little bloated, but tries to give accurate info how child exited.
64 * Makes easier to spot segfaulting children etc... */
65static void print_waitstat(unsigned pid, int wstat)
66{
67 unsigned e = 0;
68 const char *cause = "?exit";
69
70 if (WIFEXITED(wstat)) {
71 cause++;
72 e = WEXITSTATUS(wstat);
73 } else if (WIFSIGNALED(wstat)) {
74 cause = "signal";
75 e = WTERMSIG(wstat);
76 }
77 printf("%s: info: end %d %s %d\n", applet_name, pid, cause, e);
78}
79
Denis Vlasenkob933ac12007-04-03 12:09:46 +000080/* Must match getopt32 in main! */
81enum {
82 OPT_c = (1 << 0),
83 OPT_C = (1 << 1),
84 OPT_i = (1 << 2),
85 OPT_x = (1 << 3),
86 OPT_u = (1 << 4),
87 OPT_l = (1 << 5),
88 OPT_E = (1 << 6),
89 OPT_b = (1 << 7),
90 OPT_h = (1 << 8),
91 OPT_p = (1 << 9),
92 OPT_t = (1 << 10),
93 OPT_v = (1 << 11),
94 OPT_V = (1 << 12),
95 OPT_U = (1 << 13), /* from here: sslsvd only */
96 OPT_slash = (1 << 14),
97 OPT_Z = (1 << 15),
98 OPT_K = (1 << 16),
99};
100
101static void connection_status(void)
102{
Denis Vlasenko64a15122007-04-04 10:16:15 +0000103 /* "only 1 client max" don't need this */
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000104 if (cmax > 1)
105 printf("%s: info: status %u/%u\n", applet_name, cnum, cmax);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000106}
107
108static void sig_child_handler(int sig)
109{
110 int wstat;
111 int pid;
112
113 while ((pid = wait_nohang(&wstat)) > 0) {
114 if (max_per_host)
115 ipsvd_perhost_remove(pid);
116 if (cnum)
117 cnum--;
118 if (verbose)
119 print_waitstat(pid, wstat);
120 }
121 if (verbose)
122 connection_status();
123}
124
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000125int tcpudpsvd_main(int argc, char **argv);
126int tcpudpsvd_main(int argc, char **argv)
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000127{
128 char *str_c, *str_C, *str_b, *str_t;
129 char *user;
130 struct hcc *hccp;
131 const char *instructs;
132 char *msg_per_host = NULL;
133 unsigned len_per_host = len_per_host; /* gcc */
Denis Vlasenko64a15122007-04-04 10:16:15 +0000134#ifndef SSLSVD
135 struct bb_uidgid_t ugid;
136#endif
137 bool need_hostnames, need_remote_ip, tcp;
138 uint16_t local_port;
139 char *local_hostname = NULL;
140 char *remote_hostname = (char*)""; /* "" used if no -h */
141 char *local_addr = local_addr; /* gcc */
142 char *remote_addr = remote_addr; /* gcc */
143 char *remote_ip = remote_addr; /* gcc */
144 len_and_sockaddr *lsa;
145 len_and_sockaddr local, remote;
146 socklen_t sa_len;
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000147 int pid;
148 int sock;
149 int conn;
150 unsigned backlog = 20;
Denis Vlasenko64a15122007-04-04 10:16:15 +0000151
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000152 tcp = (applet_name[0] == 't');
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000153
154 /* 3+ args, -i at most once, -p implies -h, -v is counter */
155 opt_complementary = "-3:?:i--i:ph:vv";
156#ifdef SSLSVD
Denis Vlasenko64a15122007-04-04 10:16:15 +0000157 getopt32(argc, argv, "+c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:",
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000158 &str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
159 &str_b, &str_t, &ssluser, &root, &cert, &key, &verbose
160 );
161#else
Denis Vlasenko64a15122007-04-04 10:16:15 +0000162 getopt32(argc, argv, "+c:C:i:x:u:l:Eb:hpt:v",
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000163 &str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
164 &str_b, &str_t, &verbose
165 );
166#endif
167 if (option_mask32 & OPT_c)
168 cmax = xatou_range(str_c, 1, INT_MAX);
169 if (option_mask32 & OPT_C) { /* -C n[:message] */
170 max_per_host = bb_strtou(str_C, &str_C, 10);
171 if (str_C[0]) {
172 if (str_C[0] != ':')
173 bb_show_usage();
174 msg_per_host = str_C + 1;
175 len_per_host = strlen(msg_per_host);
176 }
177 }
178 if (max_per_host > cmax)
179 max_per_host = cmax;
180 if (option_mask32 & OPT_u) {
181 if (!get_uidgid(&ugid, user, 1))
182 bb_error_msg_and_die("unknown user/group: %s", user);
183 }
184 if (option_mask32 & OPT_b)
185 backlog = xatou(str_b);
186#ifdef SSLSVD
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000187 if (option_mask32 & OPT_U) ssluser = optarg;
188 if (option_mask32 & OPT_slash) root = optarg;
189 if (option_mask32 & OPT_Z) cert = optarg;
190 if (option_mask32 & OPT_K) key = optarg;
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000191#endif
192 argv += optind;
193 if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
194 argv[0] = (char*)"0.0.0.0";
195
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000196 /* Per-IP flood protection is not thought-out for UDP */
197 if (!tcp)
198 max_per_host = 0;
199
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000200 /* stdout is used for logging, don't buffer */
201 setlinebuf(stdout);
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000202 bb_sanitize_stdio(); /* fd# 0,1,2 must be opened */
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000203
204 need_hostnames = verbose || !(option_mask32 & OPT_E);
205 need_remote_ip = max_per_host || need_hostnames;
206
207#ifdef SSLSVD
208 sslser = user;
209 client = 0;
210 if ((getuid() == 0) && !(option_mask32 & OPT_u)) {
211 xfunc_exitcode = 100;
212 bb_error_msg_and_die("fatal: -U ssluser must be set when running as root");
213 }
214 if (option_mask32 & OPT_u)
215 if (!uidgid_get(&sslugid, ssluser, 1)) {
216 if (errno) {
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000217 bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser);
218 }
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000219 bb_error_msg_and_die("fatal: unknown user/group '%s'", ssluser);
220 }
221 if (!cert) cert = "./cert.pem";
222 if (!key) key = cert;
223 if (matrixSslOpen() < 0)
224 fatal("cannot initialize ssl");
225 if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
226 if (client)
227 fatal("cannot read cert, key, or ca file");
228 fatal("cannot read cert or key file");
229 }
230 if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
231 fatal("cannot create ssl session");
232#endif
233
234 sig_block(SIGCHLD);
235 signal(SIGCHLD, sig_child_handler);
236 signal(SIGTERM, sig_term_handler);
237 signal(SIGPIPE, SIG_IGN);
238
239 if (max_per_host)
240 ipsvd_perhost_init(cmax);
241
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000242 local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000243 lsa = xhost2sockaddr(argv[0], local_port);
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000244 sock = xsocket(lsa->sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
245 setsockopt_reuseaddr(sock);
Denis Vlasenko64a15122007-04-04 10:16:15 +0000246 sa_len = lsa->len; /* I presume sockaddr len stays the same */
247 xbind(sock, &lsa->sa, sa_len);
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000248 if (tcp)
249 xlisten(sock, backlog);
250 else /* udp: needed for recv_from_to to work: */
251 socket_want_pktinfo(sock);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000252 /* ndelay_off(sock); - it is the default I think? */
253
254#ifndef SSLSVD
255 if (option_mask32 & OPT_u) {
256 /* drop permissions */
257 xsetgid(ugid.gid);
258 xsetuid(ugid.uid);
259 }
260#endif
261
262 if (verbose) {
Denis Vlasenko64a15122007-04-04 10:16:15 +0000263 char *addr = xmalloc_sockaddr2dotted(&lsa->sa, sa_len);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000264 printf("%s: info: listening on %s", applet_name, addr);
265 free(addr);
266#ifndef SSLSVD
267 if (option_mask32 & OPT_u)
268 printf(", uid %u, gid %u",
269 (unsigned)ugid.uid, (unsigned)ugid.gid);
270#endif
271 puts(", starting");
272 }
273
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000274 /* Main accept() loop */
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000275
276 again:
277 hccp = NULL;
278
279 while (cnum >= cmax)
280 sig_pause(); /* wait for any signal (expecting SIGCHLD) */
281
282 /* Accept a connection to fd #0 */
283 again1:
284 close(0);
285 again2:
286 sig_unblock(SIGCHLD);
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000287 if (tcp) {
Denis Vlasenko64a15122007-04-04 10:16:15 +0000288 remote.len = sa_len;
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000289 conn = accept(sock, &remote.sa, &remote.len);
Denis Vlasenko64a15122007-04-04 10:16:15 +0000290 } else {
291 /* In case we won't be able to recover local below.
292 * Also sets port - recv_from_to is unable to do it. */
293 local = *lsa;
294 conn = recv_from_to(sock, NULL, 0, MSG_PEEK, &remote.sa, &local.sa, sa_len);
295 }
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000296 sig_block(SIGCHLD);
297 if (conn < 0) {
298 if (errno != EINTR)
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000299 bb_perror_msg(tcp ? "accept" : "recv");
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000300 goto again2;
301 }
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000302 xmove_fd(tcp ? conn : sock, 0);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000303
304 if (max_per_host) {
305 /* Drop connection immediately if cur_per_host > max_per_host
306 * (minimizing load under SYN flood) */
Denis Vlasenko64a15122007-04-04 10:16:15 +0000307 remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, sa_len);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000308 cur_per_host = ipsvd_perhost_add(remote_ip, max_per_host, &hccp);
309 if (cur_per_host > max_per_host) {
310 /* ipsvd_perhost_add detected that max is exceeded
311 * (and did not store ip in connection table) */
312 free(remote_ip);
313 if (msg_per_host) {
314 /* don't block or test for errors */
315 ndelay_on(0);
316 write(0, msg_per_host, len_per_host);
317 }
318 goto again1;
319 }
320 }
321
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000322 if (!tcp) {
323 /* Voodoo magic: making udp sockets each receive its own
Denis Vlasenko64a15122007-04-04 10:16:15 +0000324 * packets is not trivial, and I still not sure
325 * I do it 100% right.
326 * 1) we have to do it before fork()
327 * 2) order is important - is it right now? */
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000328
Denis Vlasenko64a15122007-04-04 10:16:15 +0000329 /* Make plain write/send work for this socket by supplying default
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000330 * destination address. This also restricts incoming packets
331 * to ones coming from this remote IP. */
Denis Vlasenko64a15122007-04-04 10:16:15 +0000332 xconnect(0, &remote.sa, sa_len);
333 /* hole? at this point we have no wildcard udp socket...
Denis Vlasenko79468792007-04-04 11:02:55 +0000334 * can this cause clients to get "port unreachable" icmp?
335 * Yup, time window is very small, but it exists (is it?) */
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000336 /* Open new non-connected UDP socket for further clients */
337 sock = xsocket(lsa->sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
338 setsockopt_reuseaddr(sock);
Denis Vlasenko64a15122007-04-04 10:16:15 +0000339 xbind(sock, &lsa->sa, sa_len);
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000340 socket_want_pktinfo(sock);
Denis Vlasenko79468792007-04-04 11:02:55 +0000341
342 /* Doesn't work:
343 * we cannot replace fd #0 - we will lose pending packet
344 * which is already buffered for us! And we cannot use fd #1
345 * instead - it will "intercept" all following packets, but child
346 * do not expect data coming *from fd #1*! */
347#if 0
348 /* Make it so that local addr is fixed to localp->sa
349 * and we don't accidentally accept packets to other local IPs. */
350 /* NB: we possibly bind to the _very_ same_ address & port as the one
351 * already bound in parent! This seems to work in Linux.
352 * (otherwise we can move socket to fd #0 only if bind succeeds) */
353 close(0);
354 set_nport(localp, htons(local_port));
355 xmove_fd(xsocket(localp->sa.sa_family, SOCK_DGRAM, 0), 0);
356 setsockopt_reuseaddr(0); /* crucial */
357 xbind(0, &localp->sa, localp->len);
358#endif
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000359 }
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000360
361 pid = fork();
362 if (pid == -1) {
363 bb_perror_msg("fork");
364 goto again;
365 }
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000366
367
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000368 if (pid != 0) {
369 /* parent */
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000370 cnum++;
371 if (verbose)
372 connection_status();
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000373 if (hccp)
374 hccp->pid = pid;
375 goto again;
376 }
377
378 /* Child: prepare env, log, and exec prog */
379
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000380 /* Closing tcp listening socket */
381 if (tcp)
382 close(sock);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000383
Denis Vlasenko64a15122007-04-04 10:16:15 +0000384 if (need_remote_ip)
385 remote_addr = xmalloc_sockaddr2dotted(&remote.sa, sa_len);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000386
387 if (need_hostnames) {
388 if (option_mask32 & OPT_h) {
Denis Vlasenko64a15122007-04-04 10:16:15 +0000389 remote_hostname = xmalloc_sockaddr2host_noport(&remote.sa, sa_len);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000390 if (!remote_hostname) {
Denis Vlasenko64a15122007-04-04 10:16:15 +0000391 bb_error_msg("warning: cannot look up hostname for %s", remote_addr);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000392 remote_hostname = (char*)"";
393 }
394 }
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000395 /* Find out local IP peer connected to.
396 * Errors ignored (I'm not paranoid enough to imagine kernel
397 * which doesn't know local IP). */
Denis Vlasenko64a15122007-04-04 10:16:15 +0000398 if (tcp) {
399 local.len = sa_len;
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000400 getsockname(0, &local.sa, &local.len);
Denis Vlasenko64a15122007-04-04 10:16:15 +0000401 }
402 local_addr = xmalloc_sockaddr2dotted(&local.sa, sa_len);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000403 if (!local_hostname) {
Denis Vlasenko64a15122007-04-04 10:16:15 +0000404 local_hostname = xmalloc_sockaddr2host_noport(&local.sa, sa_len);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000405 if (!local_hostname)
Denis Vlasenko64a15122007-04-04 10:16:15 +0000406 bb_error_msg_and_die("warning: cannot look up hostname for %s"+9, local_addr);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000407 }
408 }
409
410 if (verbose) {
411 pid = getpid();
Denis Vlasenko64a15122007-04-04 10:16:15 +0000412 printf("%s: info: pid %u from %s\n", applet_name, pid, remote_addr);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000413 if (max_per_host)
414 printf("%s: info: concurrency %u %s %u/%u\n",
415 applet_name, pid, remote_ip, cur_per_host, max_per_host);
Denis Vlasenko64a15122007-04-04 10:16:15 +0000416 printf("%s: info: start %u %s:%s :%s:%s\n",
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000417 applet_name, pid,
Denis Vlasenko64a15122007-04-04 10:16:15 +0000418 local_hostname, local_addr,
419 remote_hostname, remote_addr);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000420 }
421
422 if (!(option_mask32 & OPT_E)) {
423 /* setup ucspi env */
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000424 const char *proto = tcp ? "TCP" : "UDP";
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000425
426 /* Extract "original" destination addr:port
427 * from Linux firewall. Useful when you redirect
428 * an outbond connection to local handler, and it needs
429 * to know where it originally tried to connect */
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000430 if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &lsa->sa, &lsa->len) == 0) {
Denis Vlasenko64a15122007-04-04 10:16:15 +0000431 char *addr = xmalloc_sockaddr2dotted(&lsa->sa, sa_len);
432 xsetenv("TCPORIGDSTADDR", addr);
433 free(addr);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000434 }
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000435 xsetenv("PROTO", proto);
Denis Vlasenko64a15122007-04-04 10:16:15 +0000436 xsetenv_proto(proto, "LOCALADDR", local_addr);
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000437 xsetenv_proto(proto, "LOCALHOST", local_hostname);
Denis Vlasenko64a15122007-04-04 10:16:15 +0000438 xsetenv_proto(proto, "REMOTEADDR", remote_addr);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000439 if (option_mask32 & OPT_h) {
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000440 xsetenv_proto(proto, "REMOTEHOST", remote_hostname);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000441 }
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000442 xsetenv_proto(proto, "REMOTEINFO", "");
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000443 /* additional */
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000444 if (cur_per_host > 0) /* can not be true for udp */
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000445 xsetenv("TCPCONCURRENCY", utoa(cur_per_host));
446 }
447
448 dup2(0, 1);
449
450 signal(SIGTERM, SIG_DFL);
451 signal(SIGPIPE, SIG_DFL);
452 signal(SIGCHLD, SIG_DFL);
453 sig_unblock(SIGCHLD);
454
455 argv += 2;
456#ifdef SSLSVD
457 strcpy(id, utoa(pid);
458 ssl_io(0, argv);
459#else
460 BB_EXECVP(argv[0], argv);
461#endif
462 bb_perror_msg_and_die("exec '%s'", argv[0]);
463}
464
465/*
466tcpsvd [-hpEvv] [-c n] [-C n:msg] [-b n] [-u user] [-l name]
467 [-i dir|-x cdb] [ -t sec] host port prog
468
469tcpsvd creates a TCP/IP socket, binds it to the address host:port,
470and listens on the socket for incoming connections.
471
472On each incoming connection, tcpsvd conditionally runs a program,
473with standard input reading from the socket, and standard output
474writing to the socket, to handle this connection. tcpsvd keeps
475listening on the socket for new connections, and can handle
476multiple connections simultaneously.
477
478tcpsvd optionally checks for special instructions depending
479on the IP address or hostname of the client that initiated
480the connection, see ipsvd-instruct(5).
481
482host
483 host either is a hostname, or a dotted-decimal IP address,
484 or 0. If host is 0, tcpsvd accepts connections to any local
485 IP address.
486 * busybox accepts IPv6 addresses and host:port pairs too
487 In this case second parameter is ignored
488port
489 tcpsvd accepts connections to host:port. port may be a name
490 from /etc/services or a number.
491prog
492 prog consists of one or more arguments. For each connection,
493 tcpsvd normally runs prog, with file descriptor 0 reading from
494 the network, and file descriptor 1 writing to the network.
495 By default it also sets up TCP-related environment variables,
496 see tcp-environ(5)
497-i dir
498 read instructions for handling new connections from the instructions
499 directory dir. See ipsvd-instruct(5) for details.
500 * ignored by busyboxed version
501-x cdb
502 read instructions for handling new connections from the constant database
503 cdb. The constant database normally is created from an instructions
504 directory by running ipsvd-cdb(8).
505 * ignored by busyboxed version
506-t sec
507 timeout. This option only takes effect if the -i option is given.
508 While checking the instructions directory, check the time of last access
509 of the file that matches the clients address or hostname if any, discard
510 and remove the file if it wasn't accessed within the last sec seconds;
511 tcpsvd does not discard or remove a file if the user's write permission
512 is not set, for those files the timeout is disabled. Default is 0,
513 which means that the timeout is disabled.
514 * ignored by busyboxed version
515-l name
516 local hostname. Do not look up the local hostname in DNS, but use name
517 as hostname. This option must be set if tcpsvd listens on port 53
518 to avoid loops.
519-u user[:group]
520 drop permissions. Switch user ID to user's UID, and group ID to user's
521 primary GID after creating and binding to the socket. If user is followed
522 by a colon and a group name, the group ID is switched to the GID of group
523 instead. All supplementary groups are removed.
524-c n
525 concurrency. Handle up to n connections simultaneously. Default is 30.
526 If there are n connections active, tcpsvd defers acceptance of a new
527 connection until an active connection is closed.
528-C n[:msg]
529 per host concurrency. Allow only up to n connections from the same IP
530 address simultaneously. If there are n active connections from one IP
531 address, new incoming connections from this IP address are closed
532 immediately. If n is followed by :msg, the message msg is written
533 to the client if possible, before closing the connection. By default
534 msg is empty. See ipsvd-instruct(5) for supported escape sequences in msg.
535
536 For each accepted connection, the current per host concurrency is
537 available through the environment variable TCPCONCURRENCY. n and msg
538 can be overwritten by ipsvd(7) instructions, see ipsvd-instruct(5).
539 By default tcpsvd doesn't keep track of connections.
540-h
541 Look up the client's hostname in DNS.
542-p
543 paranoid. After looking up the client's hostname in DNS, look up the IP
544 addresses in DNS for that hostname, and forget about the hostname
545 if none of the addresses match the client's IP address. You should
546 set this option if you use hostname based instructions. The -p option
547 implies the -h option.
548 * ignored by busyboxed version
549-b n
550 backlog. Allow a backlog of approximately n TCP SYNs. On some systems n
551 is silently limited. Default is 20.
552-E
553 no special environment. Do not set up TCP-related environment variables.
554-v
555 verbose. Print verbose messsages to standard output.
556-vv
557 more verbose. Print more verbose messages to standard output.
558 * no difference between -v and -vv in busyboxed version
559*/