source: MondoRescue/branches/3.2/mindi-busybox/networking/tcpudp.c@ 3232

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