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