blob: 6e8ec323cdd57ee352a8f8c6be44fee7eb3e3b99 [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:
25 * - local IP address is reptrieved (using recvmsg voodoo) but
26 * child's socket is not bound to it (bind cannot be called on
27 * already bound socket). Thus you still can get outgoing packets
28 * 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 Vlasenko02fd6682007-04-03 23:23:10 +0000103 /* UDP and "only 1 client max" TCP don't need this */
104 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 */
134 int need_hostnames, need_remote_ip;
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000135 int tcp;
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000136 int pid;
137 int sock;
138 int conn;
139 unsigned backlog = 20;
140 len_and_sockaddr *lsa;
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000141 len_and_sockaddr local, remote;
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000142 uint16_t local_port;
143 uint16_t remote_port = remote_port; /* gcc */
144 char *local_hostname = NULL;
145 char *remote_hostname = (char*)""; /* "" used if no -h */
146 char *local_ip = local_ip; /* gcc */
147 char *remote_ip = remote_ip; /* gcc */
148#ifndef SSLSVD
149 struct bb_uidgid_t ugid;
150#endif
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000151 tcp = (applet_name[0] == 't');
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000152
153 /* 3+ args, -i at most once, -p implies -h, -v is counter */
154 opt_complementary = "-3:?:i--i:ph:vv";
155#ifdef SSLSVD
156 getopt32(argc, argv, "c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:",
157 &str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
158 &str_b, &str_t, &ssluser, &root, &cert, &key, &verbose
159 );
160#else
161 getopt32(argc, argv, "c:C:i:x:u:l:Eb:hpt:v",
162 &str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
163 &str_b, &str_t, &verbose
164 );
165#endif
166 if (option_mask32 & OPT_c)
167 cmax = xatou_range(str_c, 1, INT_MAX);
168 if (option_mask32 & OPT_C) { /* -C n[:message] */
169 max_per_host = bb_strtou(str_C, &str_C, 10);
170 if (str_C[0]) {
171 if (str_C[0] != ':')
172 bb_show_usage();
173 msg_per_host = str_C + 1;
174 len_per_host = strlen(msg_per_host);
175 }
176 }
177 if (max_per_host > cmax)
178 max_per_host = cmax;
179 if (option_mask32 & OPT_u) {
180 if (!get_uidgid(&ugid, user, 1))
181 bb_error_msg_and_die("unknown user/group: %s", user);
182 }
183 if (option_mask32 & OPT_b)
184 backlog = xatou(str_b);
185#ifdef SSLSVD
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000186 if (option_mask32 & OPT_U) ssluser = optarg;
187 if (option_mask32 & OPT_slash) root = optarg;
188 if (option_mask32 & OPT_Z) cert = optarg;
189 if (option_mask32 & OPT_K) key = optarg;
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000190#endif
191 argv += optind;
192 if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
193 argv[0] = (char*)"0.0.0.0";
194
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000195 /* Per-IP flood protection is not thought-out for UDP */
196 if (!tcp)
197 max_per_host = 0;
198
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000199 /* stdout is used for logging, don't buffer */
200 setlinebuf(stdout);
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000201 bb_sanitize_stdio(); /* fd# 0,1,2 must be opened */
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000202
203 need_hostnames = verbose || !(option_mask32 & OPT_E);
204 need_remote_ip = max_per_host || need_hostnames;
205
206#ifdef SSLSVD
207 sslser = user;
208 client = 0;
209 if ((getuid() == 0) && !(option_mask32 & OPT_u)) {
210 xfunc_exitcode = 100;
211 bb_error_msg_and_die("fatal: -U ssluser must be set when running as root");
212 }
213 if (option_mask32 & OPT_u)
214 if (!uidgid_get(&sslugid, ssluser, 1)) {
215 if (errno) {
216 xfunc_exitcode = 100;
217 bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser);
218 }
219 xfunc_exitcode = 111;
220 bb_error_msg_and_die("fatal: unknown user/group '%s'", ssluser);
221 }
222 if (!cert) cert = "./cert.pem";
223 if (!key) key = cert;
224 if (matrixSslOpen() < 0)
225 fatal("cannot initialize ssl");
226 if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
227 if (client)
228 fatal("cannot read cert, key, or ca file");
229 fatal("cannot read cert or key file");
230 }
231 if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
232 fatal("cannot create ssl session");
233#endif
234
235 sig_block(SIGCHLD);
236 signal(SIGCHLD, sig_child_handler);
237 signal(SIGTERM, sig_term_handler);
238 signal(SIGPIPE, SIG_IGN);
239
240 if (max_per_host)
241 ipsvd_perhost_init(cmax);
242
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000243 local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000244 lsa = xhost2sockaddr(argv[0], local_port);
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000245 sock = xsocket(lsa->sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
246 setsockopt_reuseaddr(sock);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000247 xbind(sock, &lsa->sa, lsa->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) {
263 /* we do it only for ":port" cosmetics... oh well */
264 char *addr = xmalloc_sockaddr2dotted(&lsa->sa, lsa->len);
265
266 printf("%s: info: listening on %s", applet_name, addr);
267 free(addr);
268#ifndef SSLSVD
269 if (option_mask32 & OPT_u)
270 printf(", uid %u, gid %u",
271 (unsigned)ugid.uid, (unsigned)ugid.gid);
272#endif
273 puts(", starting");
274 }
275
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000276 /* Main accept() loop */
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000277
278 again:
279 hccp = NULL;
280
281 while (cnum >= cmax)
282 sig_pause(); /* wait for any signal (expecting SIGCHLD) */
283
284 /* Accept a connection to fd #0 */
285 again1:
286 close(0);
287 again2:
288 sig_unblock(SIGCHLD);
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000289 if (tcp) {
290 remote.len = lsa->len;
291 conn = accept(sock, &remote.sa, &remote.len);
292 } else
293 conn = recv_from_to(sock, NULL, 0, MSG_PEEK, &remote.sa, &local.sa, lsa->len);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000294 sig_block(SIGCHLD);
295 if (conn < 0) {
296 if (errno != EINTR)
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000297 bb_perror_msg(tcp ? "accept" : "recv");
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000298 goto again2;
299 }
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000300 xmove_fd(tcp ? conn : sock, 0);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000301
302 if (max_per_host) {
303 /* Drop connection immediately if cur_per_host > max_per_host
304 * (minimizing load under SYN flood) */
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000305 remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, lsa->len);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000306 cur_per_host = ipsvd_perhost_add(remote_ip, max_per_host, &hccp);
307 if (cur_per_host > max_per_host) {
308 /* ipsvd_perhost_add detected that max is exceeded
309 * (and did not store ip in connection table) */
310 free(remote_ip);
311 if (msg_per_host) {
312 /* don't block or test for errors */
313 ndelay_on(0);
314 write(0, msg_per_host, len_per_host);
315 }
316 goto again1;
317 }
318 }
319
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000320 if (!tcp) {
321 /* Voodoo magic: making udp sockets each receive its own
322 * packets is not trivial */
323
324 /* Make plain write work for this socket by supplying default
325 * destination address. This also restricts incoming packets
326 * to ones coming from this remote IP. */
327 xconnect(0, &remote.sa, lsa->len);
328 /* Open new non-connected UDP socket for further clients */
329 sock = xsocket(lsa->sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
330 setsockopt_reuseaddr(sock);
331 xbind(sock, &lsa->sa, lsa->len);
332 socket_want_pktinfo(sock);
333 }
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000334
335 pid = fork();
336 if (pid == -1) {
337 bb_perror_msg("fork");
338 goto again;
339 }
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000340
341
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000342 if (pid != 0) {
343 /* parent */
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000344 cnum++;
345 if (verbose)
346 connection_status();
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000347 if (hccp)
348 hccp->pid = pid;
349 goto again;
350 }
351
352 /* Child: prepare env, log, and exec prog */
353
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000354 /* Closing tcp listening socket */
355 if (tcp)
356 close(sock);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000357
358 if (need_remote_ip) {
359 if (!max_per_host)
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000360 remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, lsa->len);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000361 /* else it is already done */
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000362 remote_port = get_nport(&remote.sa);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000363 remote_port = ntohs(remote_port);
364 }
365
366 if (need_hostnames) {
367 if (option_mask32 & OPT_h) {
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000368 remote_hostname = xmalloc_sockaddr2host(&remote.sa, lsa->len);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000369 if (!remote_hostname) {
370 bb_error_msg("warning: cannot look up hostname for %s", remote_ip);
371 remote_hostname = (char*)"";
372 }
373 }
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000374 /* Find out local IP peer connected to.
375 * Errors ignored (I'm not paranoid enough to imagine kernel
376 * which doesn't know local IP). */
377 if (tcp)
378 getsockname(0, &local.sa, &local.len);
379 local_ip = xmalloc_sockaddr2dotted_noport(&local.sa, lsa->len);
380 local_port = get_nport(&local.sa);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000381 local_port = ntohs(local_port);
382 if (!local_hostname) {
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000383 local_hostname = xmalloc_sockaddr2host_noport(&local.sa, lsa->len);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000384 if (!local_hostname)
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000385 bb_error_msg_and_die("warning: cannot look up hostname for %s"+9, local_ip);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000386 }
387 }
388
389 if (verbose) {
390 pid = getpid();
391 printf("%s: info: pid %u from %s\n", applet_name, pid, remote_ip);
392 if (max_per_host)
393 printf("%s: info: concurrency %u %s %u/%u\n",
394 applet_name, pid, remote_ip, cur_per_host, max_per_host);
395 printf("%s: info: start %u %s:%s :%s:%s:%u\n",
396 applet_name, pid,
397 local_hostname, local_ip,
398 remote_hostname, remote_ip, (unsigned)remote_port);
399 }
400
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000401// TODO: stop splitiing port# from IP?
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000402 if (!(option_mask32 & OPT_E)) {
403 /* setup ucspi env */
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000404 const char *proto = tcp ? "TCP" : "UDP";
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000405
406 /* Extract "original" destination addr:port
407 * from Linux firewall. Useful when you redirect
408 * an outbond connection to local handler, and it needs
409 * to know where it originally tried to connect */
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000410 if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &lsa->sa, &lsa->len) == 0) {
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000411 char *ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
412 unsigned port = get_nport(&lsa->sa);
413 port = ntohs(port);
414 xsetenv("TCPORIGDSTIP", ip);
415 xsetenv("TCPORIGDSTPORT", utoa(port));
416 free(ip);
417 }
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000418 xsetenv("PROTO", proto);
419 xsetenv_proto(proto, "LOCALIP", local_ip);
420 xsetenv_proto(proto, "LOCALPORT", utoa(local_port));
421 xsetenv_proto(proto, "LOCALHOST", local_hostname);
422 xsetenv_proto(proto, "REMOTEIP", remote_ip);
423 xsetenv_proto(proto, "REMOTEPORT", utoa(remote_port));
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000424 if (option_mask32 & OPT_h) {
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000425 xsetenv_proto(proto, "REMOTEHOST", remote_hostname);
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000426 }
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000427 xsetenv_proto(proto, "REMOTEINFO", "");
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000428 /* additional */
Denis Vlasenko02fd6682007-04-03 23:23:10 +0000429 if (cur_per_host > 0) /* can not be true for udp */
Denis Vlasenkob933ac12007-04-03 12:09:46 +0000430 xsetenv("TCPCONCURRENCY", utoa(cur_per_host));
431 }
432
433 dup2(0, 1);
434
435 signal(SIGTERM, SIG_DFL);
436 signal(SIGPIPE, SIG_DFL);
437 signal(SIGCHLD, SIG_DFL);
438 sig_unblock(SIGCHLD);
439
440 argv += 2;
441#ifdef SSLSVD
442 strcpy(id, utoa(pid);
443 ssl_io(0, argv);
444#else
445 BB_EXECVP(argv[0], argv);
446#endif
447 bb_perror_msg_and_die("exec '%s'", argv[0]);
448}
449
450/*
451tcpsvd [-hpEvv] [-c n] [-C n:msg] [-b n] [-u user] [-l name]
452 [-i dir|-x cdb] [ -t sec] host port prog
453
454tcpsvd creates a TCP/IP socket, binds it to the address host:port,
455and listens on the socket for incoming connections.
456
457On each incoming connection, tcpsvd conditionally runs a program,
458with standard input reading from the socket, and standard output
459writing to the socket, to handle this connection. tcpsvd keeps
460listening on the socket for new connections, and can handle
461multiple connections simultaneously.
462
463tcpsvd optionally checks for special instructions depending
464on the IP address or hostname of the client that initiated
465the connection, see ipsvd-instruct(5).
466
467host
468 host either is a hostname, or a dotted-decimal IP address,
469 or 0. If host is 0, tcpsvd accepts connections to any local
470 IP address.
471 * busybox accepts IPv6 addresses and host:port pairs too
472 In this case second parameter is ignored
473port
474 tcpsvd accepts connections to host:port. port may be a name
475 from /etc/services or a number.
476prog
477 prog consists of one or more arguments. For each connection,
478 tcpsvd normally runs prog, with file descriptor 0 reading from
479 the network, and file descriptor 1 writing to the network.
480 By default it also sets up TCP-related environment variables,
481 see tcp-environ(5)
482-i dir
483 read instructions for handling new connections from the instructions
484 directory dir. See ipsvd-instruct(5) for details.
485 * ignored by busyboxed version
486-x cdb
487 read instructions for handling new connections from the constant database
488 cdb. The constant database normally is created from an instructions
489 directory by running ipsvd-cdb(8).
490 * ignored by busyboxed version
491-t sec
492 timeout. This option only takes effect if the -i option is given.
493 While checking the instructions directory, check the time of last access
494 of the file that matches the clients address or hostname if any, discard
495 and remove the file if it wasn't accessed within the last sec seconds;
496 tcpsvd does not discard or remove a file if the user's write permission
497 is not set, for those files the timeout is disabled. Default is 0,
498 which means that the timeout is disabled.
499 * ignored by busyboxed version
500-l name
501 local hostname. Do not look up the local hostname in DNS, but use name
502 as hostname. This option must be set if tcpsvd listens on port 53
503 to avoid loops.
504-u user[:group]
505 drop permissions. Switch user ID to user's UID, and group ID to user's
506 primary GID after creating and binding to the socket. If user is followed
507 by a colon and a group name, the group ID is switched to the GID of group
508 instead. All supplementary groups are removed.
509-c n
510 concurrency. Handle up to n connections simultaneously. Default is 30.
511 If there are n connections active, tcpsvd defers acceptance of a new
512 connection until an active connection is closed.
513-C n[:msg]
514 per host concurrency. Allow only up to n connections from the same IP
515 address simultaneously. If there are n active connections from one IP
516 address, new incoming connections from this IP address are closed
517 immediately. If n is followed by :msg, the message msg is written
518 to the client if possible, before closing the connection. By default
519 msg is empty. See ipsvd-instruct(5) for supported escape sequences in msg.
520
521 For each accepted connection, the current per host concurrency is
522 available through the environment variable TCPCONCURRENCY. n and msg
523 can be overwritten by ipsvd(7) instructions, see ipsvd-instruct(5).
524 By default tcpsvd doesn't keep track of connections.
525-h
526 Look up the client's hostname in DNS.
527-p
528 paranoid. After looking up the client's hostname in DNS, look up the IP
529 addresses in DNS for that hostname, and forget about the hostname
530 if none of the addresses match the client's IP address. You should
531 set this option if you use hostname based instructions. The -p option
532 implies the -h option.
533 * ignored by busyboxed version
534-b n
535 backlog. Allow a backlog of approximately n TCP SYNs. On some systems n
536 is silently limited. Default is 20.
537-E
538 no special environment. Do not set up TCP-related environment variables.
539-v
540 verbose. Print verbose messsages to standard output.
541-vv
542 more verbose. Print more verbose messages to standard output.
543 * no difference between -v and -vv in busyboxed version
544*/