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