419551d8dd70fa48367d76fe33e6bbe9c57487fd
[oweals/busybox.git] / ipsvd / tcpudp.c
1 /* Based on ipsvd utilities written by Gerrit Pape <pape@smarden.org>
2  * which are released into public domain by the author.
3  * Homepage: http://smarden.sunsite.dk/ipsvd/
4  *
5  * Copyright (C) 2007 Denis Vlasenko.
6  *
7  * Licensed under GPLv2, see file LICENSE in this tarball for details.
8  */
9
10 /* TCP and UDP server are using a lot of same string constants
11  * We reuse them by keeping both in one source file */
12
13 #include "busybox.h"
14
15 static unsigned verbose;
16
17 static void sig_term_handler(int sig)
18 {
19         if (verbose)
20                 printf("%s: info: sigterm received, exit\n", applet_name);
21         exit(0);
22 }
23
24 /* Little bloated, but tries to give accurate info how child exited.
25  * Makes easier to spot segfaulting children etc... */
26 static void print_waitstat(unsigned pid, int wstat)
27 {
28         unsigned e = 0;
29         const char *cause = "?exit";
30
31         if (WIFEXITED(wstat)) {
32                 cause++;
33                 e = WEXITSTATUS(wstat);
34         } else if (WIFSIGNALED(wstat)) {
35                 cause = "signal";
36                 e = WTERMSIG(wstat);
37         }
38         printf("%s: info: end %d %s %d\n", applet_name, pid, cause, e);
39 }
40
41
42 #if ENABLE_UDPSVD
43 /* Based on ipsvd ipsvd-0.12.1. This udpsvd accepts all options
44  * which are supported by one from ipsvd-0.12.1, but not all are
45  * functional. See help text at the end of this file for details.
46  *
47  * Output of verbose mode matches original (modulo bugs and
48  * unimplemented stuff). Unnatural splitting of IP and PORT
49  * is retained (personally I prefer one-value "IP:PORT" notation -
50  * it is a natural string representation of struct sockaddr_XX).
51  */
52
53 #include "udp_io.c"
54
55 int udpsvd_main(int argc, char **argv);
56 int udpsvd_main(int argc, char **argv)
57 {
58         const char *instructs;
59         char *str_t, *user;
60         unsigned opt;
61
62         char *remote_hostname = (char*)""; /* used if no -h */
63         char *local_hostname = NULL;
64         char *remote_ip;
65         char *local_ip;// = local_ip; /* gcc */
66         uint16_t local_port, remote_port;
67         len_and_sockaddr remote;
68         len_and_sockaddr *localp;
69         int wstat;
70         unsigned pid;
71         struct bb_uidgid_t ugid;
72
73         enum {
74                 OPT_v = (1 << 0),
75                 OPT_u = (1 << 1),
76                 OPT_l = (1 << 2),
77                 OPT_h = (1 << 3),
78                 OPT_p = (1 << 4),
79                 OPT_i = (1 << 5),
80                 OPT_x = (1 << 6),
81                 OPT_t = (1 << 7),
82         };
83
84         opt_complementary = "-3:ph:vv";
85         opt = getopt32(argc, argv, "vu:l:hpi:x:t:",
86                         &user, &local_hostname, &instructs, &instructs, &str_t, &verbose);
87         if (opt & OPT_u) {
88                 if (!get_uidgid(&ugid, user, 1))
89                         bb_error_msg_and_die("unknown user/group: %s", user);
90         }
91         argv += optind;
92         if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
93                 argv[0] = (char*)"0.0.0.0";
94
95         /* stdout is used for logging, don't buffer */
96         setlinebuf(stdout);
97         bb_sanitize_stdio(); /* fd# 1,2 must be opened */
98
99         signal(SIGTERM, sig_term_handler);
100         signal(SIGPIPE, SIG_IGN);
101
102         local_port = bb_lookup_port(argv[1], "udp", 0);
103         localp = xhost2sockaddr(argv[0], local_port);
104         /* fd #0 is the open UDP socket */
105         xmove_fd(xsocket(localp->sa.sa_family, SOCK_DGRAM, 0), 0);
106         setsockopt_reuseaddr(0); /* crucial */
107         xbind(0, &localp->sa, localp->len);
108         socket_want_pktinfo(0); /* needed for recv_from_to to work */
109
110         if (opt & OPT_u) { /* drop permissions */
111                 xsetgid(ugid.gid);
112                 xsetuid(ugid.uid);
113         }
114
115         if (verbose) {
116                 /* we do it only for ":port" cosmetics... oh well */
117                 char *addr = xmalloc_sockaddr2dotted(&localp->sa, localp->len);
118
119                 printf("%s: info: listening on %s", applet_name, addr);
120                 free(addr);
121                 if (option_mask32 & OPT_u)
122                         printf(", uid %u, gid %u",
123                                 (unsigned)ugid.uid, (unsigned)ugid.gid);
124                 puts(", starting");
125         }
126
127  again:
128         /* if (recvfrom(0, NULL, 0, MSG_PEEK, &remote.sa, &localp->len) < 0) { */
129         if (recv_from_to(0, NULL, 0, MSG_PEEK, &remote.sa, &localp->sa, localp->len) < 0) {
130                 bb_perror_msg("recvfrom");
131                 goto again;
132         }
133
134         while ((pid = fork()) < 0) {
135                 bb_perror_msg("fork failed, sleeping");
136                 sleep(5);
137         }
138         if (pid > 0) { /* parent */
139                 while (wait_pid(&wstat, pid) < 0)
140                         bb_perror_msg("error waiting for child");
141                 if (verbose)
142                         print_waitstat(pid, wstat);
143                 goto again;
144         }
145
146         /* Child */
147
148         if (verbose) {
149                 remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, localp->len);
150                 local_ip = xmalloc_sockaddr2dotted_noport(&localp->sa, localp->len);
151
152                 pid = getpid();
153                 printf("%s: info: pid %u from %s\n", applet_name, pid, remote_ip);
154
155                 if (!local_hostname) {
156                         local_hostname = xmalloc_sockaddr2host_noport(&localp->sa, localp->len);
157                         if (!local_hostname)
158                                 bb_error_msg_and_die("cannot look up local hostname for %s", local_ip);
159                 }
160                 if (opt & OPT_h) {
161                         remote_hostname = xmalloc_sockaddr2host(&remote.sa, localp->len);
162                         if (!remote_hostname) {
163                                 bb_error_msg("warning: cannot look up hostname for %s", remote_ip);
164                                 remote_hostname = (char*)"";
165                         }
166                 }
167
168                 remote_port = get_nport(&remote.sa);
169                 remote_port = ntohs(remote_port);
170                 printf("%s: info: %u %s:%s :%s:%s:%u\n",
171                                 applet_name, pid, local_hostname, local_ip,
172                                 remote_hostname, remote_ip, remote_port);
173         }
174
175         /* Doesn't work:
176          * we cannot replace fd #0 - we will lose pending packet
177          * which is already buffered for us! And we cannot use fd #1
178          * instead - it will "intercept" all following packets, but child
179          * do not expect data coming *from fd #1*! */
180 #if 0
181         /* Make it so that local addr is fixed to localp->sa
182          * and we don't accidentally accept packets to other local IPs. */
183         /* NB: we possibly bind to the _very_ same_ address & port as the one
184          * already bound in parent! This seems to work in Linux.
185          * (otherwise we can move socket to fd #0 only if bind succeeds) */
186         close(0);
187         set_nport(localp, htons(local_port));
188         xmove_fd(xsocket(localp->sa.sa_family, SOCK_DGRAM, 0), 0);
189         setsockopt_reuseaddr(0); /* crucial */
190         xbind(0, &localp->sa, localp->len);
191 #endif
192
193         /* Make plain write to fd #1 work for the child by supplying default
194          * destination address. This also restricts incoming packets
195          * to ones coming from this remote IP. */
196         xconnect(0, &remote.sa, localp->len);
197         dup2(0 ,1);
198
199         signal(SIGTERM, SIG_DFL);
200         signal(SIGPIPE, SIG_DFL);
201
202         argv += 2;
203         BB_EXECVP(argv[0], argv);
204         bb_perror_msg_and_die("exec '%s'", argv[0]);
205 }
206
207
208 /*
209 udpsvd [-hpvv] [-u user] [-l name] [-i dir|-x cdb] [-t sec] host port prog
210
211 udpsvd creates an UDP/IP socket, binds it to the address host:port,
212 and listens on the socket for incoming datagrams.
213
214 If a datagram is available on the socket, udpsvd conditionally starts
215 a program, with standard input reading from the socket, and standard
216 output redirected to standard error, to handle this, and possibly
217 more datagrams. udpsvd does not start the program if another program
218 that it has started before still is running. If the program exits,
219 udpsvd again listens to the socket until a new datagram is available.
220 If there are still datagrams available on the socket, the program
221 is restarted immediately.
222
223 udpsvd optionally checks for special intructions depending on
224 the IP address or hostname of the client sending the datagram which
225 not yet was handled by a running program, see ipsvd-instruct(5)
226 for details.
227
228 Attention:
229 UDP is a connectionless protocol. Most programs that handle user datagrams,
230 such as talkd(8), keep running after receiving a datagram, and process
231 subsequent datagrams sent to the socket until a timeout is reached.
232 udpsvd only checks special instructions for a datagram that causes a startup
233 of the program; not if a program handling datagrams already is running.
234 It doesn't make much sense to restrict access through special instructions
235 when using such a program.
236
237 On the other hand, it makes perfectly sense with programs like tftpd(8),
238 that fork to establish a separate connection to the client when receiving
239 the datagram. In general it's adequate to set up special instructions for
240 programs that support being run by tcpwrapper.
241 Options
242
243 host
244     host either is a hostname, or a dotted-decimal IP address, or 0.
245     If host is 0, udpsvd accepts datagrams to any local IP address.
246 port
247     udpsvd accepts datagrams to host:port. port may be a name from
248     /etc/services or a number.
249 prog
250     prog consists of one or more arguments. udpsvd normally runs prog
251     to handle a datagram, and possibly more, that is sent to the socket,
252     if there is no program that was started before by udpsvd still running
253     and handling datagrams.
254 -i dir
255     read instructions for handling new connections from the instructions
256     directory dir. See ipsvd-instruct(5) for details.
257 -x cdb
258     read instructions for handling new connections from the constant
259     database cdb. The constant database normally is created from
260     an instructions directory by running ipsvd-cdb(8).
261 -t sec
262     timeout. This option only takes effect if the -i option is given.
263     While checking the instructions directory, check the time of last
264     access of the file that matches the clients address or hostname if any,
265     discard and remove the file if it wasn't accessed within the last
266     sec seconds; udpsvd does not discard or remove a file if the user's
267     write permission is not set, for those files the timeout is disabled.
268     Default is 0, which means that the timeout is disabled.
269 -l name
270     local hostname. Do not look up the local hostname in DNS, but use name
271     as hostname. By default udpsvd looks up the local hostname once at startup.
272 -u user[:group]
273     drop permissions. Switch user ID to user's UID, and group ID to user's
274     primary GID after creating and binding to the socket. If user
275     is followed by a colon and a group name, the group ID is switched
276     to the GID of group instead. All supplementary groups are removed.
277 -h
278     Look up the client's hostname in DNS.
279 -p
280     paranoid. After looking up the client's hostname in DNS, look up
281     the IP addresses in DNS for that hostname, and forget the hostname
282     if none of the addresses match the client's IP address. You should
283     set this option if you use hostname based instructions. The -p option
284     implies the -h option.
285 -v
286     verbose. Print verbose messages to standard output.
287 -vv
288     more verbose. Print more verbose messages to standard output.
289 */
290 #endif
291
292
293 #if ENABLE_TCPSVD
294 /* Based on ipsvd ipsvd-0.12.1. This tcpsvd accepts all options
295  * which are supported by one from ipsvd-0.12.1, but not all are
296  * functional. See help text at the end of this file for details.
297  *
298  * Code inside "#ifdef SSLSVD" is for sslsvd and is currently unused.
299  *
300  * Output of verbose mode matches original (modulo bugs and
301  * unimplemented stuff). Unnatural splitting of IP and PORT
302  * is retained (personally I prefer one-value "IP:PORT" notation -
303  * it is a natural string representation of struct sockaddr_XX).
304  *
305  * TCPORIGDST{IP,PORT} is busybox-specific addition
306  */
307
308 #include <limits.h>
309 #include <linux/netfilter_ipv4.h> /* wants <limits.h> */
310 #include "ipsvd_perhost.h"
311
312 #ifdef SSLSVD
313 #include "matrixSsl.h"
314 #include "ssl_io.h"
315 #endif
316
317 static unsigned max_per_host; /* originally in ipsvd_check.c */
318 static unsigned cur_per_host;
319 static unsigned cnum;
320 static unsigned cmax = 30;
321
322 /* Must match getopt32 in main! */
323 enum {
324         OPT_c = (1 << 0),
325         OPT_C = (1 << 1),
326         OPT_i = (1 << 2),
327         OPT_x = (1 << 3),
328         OPT_u = (1 << 4),
329         OPT_l = (1 << 5),
330         OPT_E = (1 << 6),
331         OPT_b = (1 << 7),
332         OPT_h = (1 << 8),
333         OPT_p = (1 << 9),
334         OPT_t = (1 << 10),
335         OPT_v = (1 << 11),
336         OPT_V = (1 << 12),
337         OPT_U = (1 << 13), /* from here: sslsvd only */
338         OPT_slash = (1 << 14),
339         OPT_Z = (1 << 15),
340         OPT_K = (1 << 16),
341 };
342
343 static void connection_status(void)
344 {
345         printf("%s: info: status %u/%u\n", applet_name, cnum, cmax);
346 }
347
348 static void sig_child_handler(int sig)
349 {
350         int wstat;
351         int pid;
352
353         while ((pid = wait_nohang(&wstat)) > 0) {
354                 if (max_per_host)
355                         ipsvd_perhost_remove(pid);
356                 if (cnum)
357                         cnum--;
358                 if (verbose)
359                         print_waitstat(pid, wstat);
360         }
361         if (verbose)
362                 connection_status();
363 }
364
365 int tcpsvd_main(int argc, char **argv);
366 int tcpsvd_main(int argc, char **argv)
367 {
368         char *str_c, *str_C, *str_b, *str_t;
369         char *user;
370         struct hcc *hccp;
371         const char *instructs;
372         char *msg_per_host = NULL;
373         unsigned len_per_host = len_per_host; /* gcc */
374         int need_hostnames, need_remote_ip;
375         int pid;
376         int sock;
377         int conn;
378         unsigned backlog = 20;
379         len_and_sockaddr *lsa;
380         uint16_t local_port;
381         uint16_t remote_port = remote_port; /* gcc */
382         char *local_hostname = NULL;
383         char *remote_hostname = (char*)""; /* "" used if no -h */
384         char *local_ip = local_ip; /* gcc */
385         char *remote_ip = remote_ip; /* gcc */
386 #ifndef SSLSVD
387         struct bb_uidgid_t ugid;
388 #endif
389
390         /* 3+ args, -i at most once, -p implies -h, -v is counter */
391         opt_complementary = "-3:?:i--i:ph:vv";
392 #ifdef SSLSVD
393         getopt32(argc, argv, "c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:",
394                 &str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
395                 &str_b, &str_t, &ssluser, &root, &cert, &key, &verbose
396         );
397 #else
398         getopt32(argc, argv, "c:C:i:x:u:l:Eb:hpt:v",
399                 &str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
400                 &str_b, &str_t, &verbose
401         );
402 #endif
403         if (option_mask32 & OPT_c)
404                 cmax = xatou_range(str_c, 1, INT_MAX);
405         if (option_mask32 & OPT_C) { /* -C n[:message] */
406                 max_per_host = bb_strtou(str_C, &str_C, 10);
407                 if (str_C[0]) {
408                         if (str_C[0] != ':')
409                                 bb_show_usage();
410                         msg_per_host = str_C + 1;
411                         len_per_host = strlen(msg_per_host);
412                 }
413         }
414         if (max_per_host > cmax)
415                 max_per_host = cmax;
416         if (option_mask32 & OPT_u) {
417                 if (!get_uidgid(&ugid, user, 1))
418                         bb_error_msg_and_die("unknown user/group: %s", user);
419         }
420         if (option_mask32 & OPT_b)
421                 backlog = xatou(str_b);
422 #ifdef SSLSVD
423         if (option_mask32 & OPT_U) ssluser = (char*)optarg; break;
424         if (option_mask32 & OPT_slash) root = (char*)optarg; break;
425         if (option_mask32 & OPT_Z) cert = (char*)optarg; break;
426         if (option_mask32 & OPT_K) key = (char*)optarg; break;
427 #endif
428         argv += optind;
429         if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
430                 argv[0] = (char*)"0.0.0.0";
431
432         /* stdout is used for logging, don't buffer */
433         setlinebuf(stdout);
434         bb_sanitize_stdio(); /* fd# 1,2 must be opened */
435
436         need_hostnames = verbose || !(option_mask32 & OPT_E);
437         need_remote_ip = max_per_host || need_hostnames;
438
439 #ifdef SSLSVD
440         sslser = user;
441         client = 0;
442         if ((getuid() == 0) && !(option_mask32 & OPT_u)) {
443                 xfunc_exitcode = 100;
444                 bb_error_msg_and_die("fatal: -U ssluser must be set when running as root");
445         }
446         if (option_mask32 & OPT_u)
447                 if (!uidgid_get(&sslugid, ssluser, 1)) {
448                         if (errno) {
449                                 xfunc_exitcode = 100;
450                                 bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser);
451                         }
452                         xfunc_exitcode = 111;
453                         bb_error_msg_and_die("fatal: unknown user/group '%s'", ssluser);
454                 }
455         if (!cert) cert = "./cert.pem";
456         if (!key) key = cert;
457         if (matrixSslOpen() < 0)
458                 fatal("cannot initialize ssl");
459         if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
460                 if (client)
461                         fatal("cannot read cert, key, or ca file");
462                 fatal("cannot read cert or key file");
463         }
464         if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
465                 fatal("cannot create ssl session");
466 #endif
467
468         sig_block(SIGCHLD);
469         signal(SIGCHLD, sig_child_handler);
470         signal(SIGTERM, sig_term_handler);
471         signal(SIGPIPE, SIG_IGN);
472
473         if (max_per_host)
474                 ipsvd_perhost_init(cmax);
475
476         local_port = bb_lookup_port(argv[1], "tcp", 0);
477         lsa = xhost2sockaddr(argv[0], local_port);
478         sock = xsocket(lsa->sa.sa_family, SOCK_STREAM, 0);
479         setsockopt_reuseaddr(sock); /* desirable */
480         xbind(sock, &lsa->sa, lsa->len);
481         xlisten(sock, backlog);
482         /* ndelay_off(sock); - it is the default I think? */
483
484 #ifndef SSLSVD
485         if (option_mask32 & OPT_u) {
486                 /* drop permissions */
487                 xsetgid(ugid.gid);
488                 xsetuid(ugid.uid);
489         }
490 #endif
491
492         if (verbose) {
493                 /* we do it only for ":port" cosmetics... oh well */
494                 char *addr = xmalloc_sockaddr2dotted(&lsa->sa, lsa->len);
495
496                 printf("%s: info: listening on %s", applet_name, addr);
497                 free(addr);
498 #ifndef SSLSVD
499                 if (option_mask32 & OPT_u)
500                         printf(", uid %u, gid %u",
501                                 (unsigned)ugid.uid, (unsigned)ugid.gid);
502 #endif
503                 puts(", starting");
504         }
505
506         /* The rest is a main accept() loop */
507
508  again:
509         hccp = NULL;
510
511         while (cnum >= cmax)
512                 sig_pause(); /* wait for any signal (expecting SIGCHLD) */
513
514         /* Accept a connection to fd #0 */
515  again1:
516         close(0);
517  again2:
518         sig_unblock(SIGCHLD);
519         conn = accept(sock, &lsa->sa, &lsa->len);
520         sig_block(SIGCHLD);
521         if (conn < 0) {
522                 if (errno != EINTR)
523                         bb_perror_msg("accept");
524                 goto again2;
525         }
526         xmove_fd(conn, 0);
527
528         if (max_per_host) {
529                 /* Drop connection immediately if cur_per_host > max_per_host
530                  * (minimizing load under SYN flood) */
531                 remote_ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
532                 cur_per_host = ipsvd_perhost_add(remote_ip, max_per_host, &hccp);
533                 if (cur_per_host > max_per_host) {
534                         /* ipsvd_perhost_add detected that max is exceeded
535                          * (and did not store ip in connection table) */
536                         free(remote_ip);
537                         if (msg_per_host) {
538                                 /* don't block or test for errors */
539                                 ndelay_on(0);
540                                 write(0, msg_per_host, len_per_host);
541                         }
542                         goto again1;
543                 }
544         }
545
546         cnum++;
547         if (verbose)
548                 connection_status();
549
550         pid = fork();
551         if (pid == -1) {
552                 bb_perror_msg("fork");
553                 goto again;
554         }
555         if (pid != 0) {
556                 /* parent */
557                 if (hccp)
558                         hccp->pid = pid;
559                 goto again;
560         }
561
562         /* Child: prepare env, log, and exec prog */
563
564         close(sock); /* listening socket */
565         /* Find out local IP peer connected to.
566          * Errors ignored (I'm not paranoid enough to imagine kernel
567          * which doesn't know local IP). */
568         getsockname(0, &lsa->sa, &lsa->len);
569
570         if (need_remote_ip) {
571                 if (!max_per_host)
572                         remote_ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
573                 /* else it is already done */
574                 remote_port = get_nport(&lsa->sa);
575                 remote_port = ntohs(remote_port);
576         }
577
578         if (need_hostnames) {
579                 if (option_mask32 & OPT_h) {
580                         remote_hostname = xmalloc_sockaddr2host(&lsa->sa, lsa->len);
581                         if (!remote_hostname) {
582                                 bb_error_msg("warning: cannot look up hostname for %s", remote_ip);
583                                 remote_hostname = (char*)"";
584                         }
585                 }
586                 local_ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
587                 local_port = get_nport(&lsa->sa);
588                 local_port = ntohs(local_port);
589                 if (!local_hostname) {
590                         local_hostname = xmalloc_sockaddr2host_noport(&lsa->sa, lsa->len);
591                         if (!local_hostname)
592                                 bb_error_msg_and_die("cannot look up local hostname for %s", local_ip);
593                 }
594         }
595
596         if (verbose) {
597                 pid = getpid();
598                 printf("%s: info: pid %u from %s\n", applet_name, pid, remote_ip);
599                 if (max_per_host)
600                         printf("%s: info: concurrency %u %s %u/%u\n",
601                                 applet_name, pid, remote_ip, cur_per_host, max_per_host);
602                 printf("%s: info: start %u %s:%s :%s:%s:%u\n",
603                         applet_name, pid,
604                         local_hostname, local_ip,
605                         remote_hostname, remote_ip, (unsigned)remote_port);
606         }
607
608         if (!(option_mask32 & OPT_E)) {
609                 /* setup ucspi env */
610
611                 /* Extract "original" destination addr:port
612                  * from Linux firewall. Useful when you redirect
613                  * an outbond connection to local handler, and it needs
614                  * to know where it originally tried to connect */
615                 if (getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &lsa->sa, &lsa->len) == 0) {
616                         char *ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len);
617                         unsigned port = get_nport(&lsa->sa);
618                         port = ntohs(port);
619                         xsetenv("TCPORIGDSTIP", ip);
620                         xsetenv("TCPORIGDSTPORT", utoa(port));
621                         free(ip);
622                 }
623                 xsetenv("PROTO", "TCP");
624                 xsetenv("TCPLOCALIP", local_ip);
625                 xsetenv("TCPLOCALPORT", utoa(local_port));
626                 xsetenv("TCPLOCALHOST", local_hostname);
627                 xsetenv("TCPREMOTEIP", remote_ip);
628                 xsetenv("TCPREMOTEPORT", utoa(remote_port));
629                 if (option_mask32 & OPT_h) {
630                         xsetenv("TCPREMOTEHOST", remote_hostname);
631                 }
632                 xsetenv("TCPREMOTEINFO", "");
633                 /* additional */
634                 if (cur_per_host > 0)
635                         xsetenv("TCPCONCURRENCY", utoa(cur_per_host));
636         }
637
638         dup2(0, 1);
639
640         signal(SIGTERM, SIG_DFL);
641         signal(SIGPIPE, SIG_DFL);
642         signal(SIGCHLD, SIG_DFL);
643         sig_unblock(SIGCHLD);
644
645         argv += 2;
646 #ifdef SSLSVD
647         strcpy(id, utoa(pid);
648         ssl_io(0, argv);
649 #else
650         BB_EXECVP(argv[0], argv);
651 #endif
652         bb_perror_msg_and_die("exec '%s'", argv[0]);
653 }
654
655 /*
656 tcpsvd [-hpEvv] [-c n] [-C n:msg] [-b n] [-u user] [-l name]
657         [-i dir|-x cdb] [ -t sec] host port prog
658
659 tcpsvd creates a TCP/IP socket, binds it to the address host:port,
660 and listens on the socket for incoming connections.
661
662 On each incoming connection, tcpsvd conditionally runs a program,
663 with standard input reading from the socket, and standard output
664 writing to the socket, to handle this connection. tcpsvd keeps
665 listening on the socket for new connections, and can handle
666 multiple connections simultaneously.
667
668 tcpsvd optionally checks for special instructions depending
669 on the IP address or hostname of the client that initiated
670 the connection, see ipsvd-instruct(5).
671
672 host
673     host either is a hostname, or a dotted-decimal IP address,
674     or 0. If host is 0, tcpsvd accepts connections to any local
675     IP address.
676     * busybox accepts IPv6 addresses and host:port pairs too
677       In this case second parameter is ignored
678 port
679     tcpsvd accepts connections to host:port. port may be a name
680     from /etc/services or a number.
681 prog
682     prog consists of one or more arguments. For each connection,
683     tcpsvd normally runs prog, with file descriptor 0 reading from
684     the network, and file descriptor 1 writing to the network.
685     By default it also sets up TCP-related environment variables,
686     see tcp-environ(5)
687 -i dir
688     read instructions for handling new connections from the instructions
689     directory dir. See ipsvd-instruct(5) for details.
690     * ignored by busyboxed version
691 -x cdb
692     read instructions for handling new connections from the constant database
693     cdb. The constant database normally is created from an instructions
694     directory by running ipsvd-cdb(8).
695     * ignored by busyboxed version
696 -t sec
697     timeout. This option only takes effect if the -i option is given.
698     While checking the instructions directory, check the time of last access
699     of the file that matches the clients address or hostname if any, discard
700     and remove the file if it wasn't accessed within the last sec seconds;
701     tcpsvd does not discard or remove a file if the user's write permission
702     is not set, for those files the timeout is disabled. Default is 0,
703     which means that the timeout is disabled.
704     * ignored by busyboxed version
705 -l name
706     local hostname. Do not look up the local hostname in DNS, but use name
707     as hostname. This option must be set if tcpsvd listens on port 53
708     to avoid loops.
709 -u user[:group]
710     drop permissions. Switch user ID to user's UID, and group ID to user's
711     primary GID after creating and binding to the socket. If user is followed
712     by a colon and a group name, the group ID is switched to the GID of group
713     instead. All supplementary groups are removed.
714 -c n
715     concurrency. Handle up to n connections simultaneously. Default is 30.
716     If there are n connections active, tcpsvd defers acceptance of a new
717     connection until an active connection is closed.
718 -C n[:msg]
719     per host concurrency. Allow only up to n connections from the same IP
720     address simultaneously. If there are n active connections from one IP
721     address, new incoming connections from this IP address are closed
722     immediately. If n is followed by :msg, the message msg is written
723     to the client if possible, before closing the connection. By default
724     msg is empty. See ipsvd-instruct(5) for supported escape sequences in msg.
725
726     For each accepted connection, the current per host concurrency is
727     available through the environment variable TCPCONCURRENCY. n and msg
728     can be overwritten by ipsvd(7) instructions, see ipsvd-instruct(5).
729     By default tcpsvd doesn't keep track of connections.
730 -h
731     Look up the client's hostname in DNS.
732 -p
733     paranoid. After looking up the client's hostname in DNS, look up the IP
734     addresses in DNS for that hostname, and forget about the hostname
735     if none of the addresses match the client's IP address. You should
736     set this option if you use hostname based instructions. The -p option
737     implies the -h option.
738     * ignored by busyboxed version
739 -b n
740     backlog. Allow a backlog of approximately n TCP SYNs. On some systems n
741     is silently limited. Default is 20.
742 -E
743     no special environment. Do not set up TCP-related environment variables.
744 -v
745     verbose. Print verbose messsages to standard output.
746 -vv
747     more verbose. Print more verbose messages to standard output.
748     * no difference between -v and -vv in busyboxed version
749 */
750 #endif