"Fossies" - the Fresh Open Source Software Archive

Member "tcpproxy-2.0.0-beta15/tcpproxy.c" (30 Aug 2007, 25838 Bytes) of package /linux/privat/old/tcpproxy-2.0.0-beta15.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tcpproxy.c" see the Fossies "Dox" file reference documentation.

    1 
    2 /*
    3 
    4     File: tcpproxy.c
    5 
    6     Copyright (C) 1999,2000,2004,2005,2007  Wolfgang Zekoll  <wzk@quietsche-entchen.de>
    7   
    8     This software is free software; you can redistribute it and/or modify
    9     it under the terms of the GNU General Public License as published by
   10     the Free Software Foundation; either version 2 of the License, or
   11     (at your option) any later version.
   12   
   13     This program is distributed in the hope that it will be useful,
   14     but WITHOUT ANY WARRANTY; without even the implied warranty of
   15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16     GNU General Public License for more details.
   17   
   18     You should have received a copy of the GNU General Public License
   19     along with this program; if not, write to the Free Software
   20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   21 
   22  */
   23 
   24 
   25 #include <stdlib.h>
   26 #include <stdio.h>
   27 #include <string.h>
   28 #include <unistd.h>
   29 
   30 #include <ctype.h>
   31 #include <signal.h>
   32 #include <wait.h>
   33 #include <errno.h>
   34 #include <time.h>
   35 
   36 #include <pwd.h>
   37 #include <grp.h>
   38 #include <sys/types.h>
   39 #include <sys/stat.h>
   40 #include <sys/fcntl.h>
   41 #include <sys/socket.h>
   42 #include <netdb.h>
   43 #include <netinet/in.h>
   44 #include <arpa/inet.h>
   45 #include <syslog.h>
   46 #include <sys/time.h>
   47 
   48 #include <linux/netfilter_ipv4.h>
   49 
   50 
   51 
   52 #include "lib.h"
   53 #include "ip-lib.h"
   54 #include "procinfo.h"
   55 #include "tcpproxy.h"
   56 
   57 
   58 char    *program =      "";
   59 char    progname[80] =      "";
   60 
   61 int debug =         0;
   62 int listports =     0;
   63 int onlynumbers =       0;
   64 char    configfile[300] =   "";
   65 /* char varname[40] =       "PROXY_"; */
   66 
   67 
   68 int use_errorlog =      0;
   69 char    errorlog[200] =     ERROR_LOG;
   70 
   71 
   72 
   73 int printerror(int rc, char *type, char *format, ...)
   74 {
   75     char    tag[30], error[400];
   76     va_list ap;
   77 
   78     va_start(ap, format);
   79     vsnprintf (error, sizeof(error) - 2, format, ap);
   80     va_end(ap);
   81 
   82     *tag = 0;
   83     if (*type != 0)
   84         snprintf (tag, sizeof(tag) - 2, "%s: ", type);
   85 
   86     if (debug != 0)
   87         fprintf (stderr, "%s[%u]: %s%s\n", program, getpid(), tag, error);
   88     else if ((rc & ERR_STDERR) != 0  &&  isatty(0) != 0)
   89         fprintf (stderr, "%s: %s\n", program, error);
   90     else
   91         syslog(LOG_NOTICE, "%s%s", tag, error);
   92 
   93     if (pi.sessionfp != NULL) {
   94         fprintf (pi.sessionfp, "%lu %s[%u]: %s%s\n", time(NULL), program, getpid(), tag, error);
   95         fflush(pi.sessionfp);
   96         }
   97 
   98 
   99     if ((rc & ERR_INFO) != 0)
  100         pi.havemessages = 1;
  101 
  102     if ((rc & ERR_EXITCODEMASK) != 0  &&  (rc & ERR_STDERR) == 0) {
  103         run_errorhandler(rc & (~ERR_EXITCODEMASK));
  104         exit (rc & ERR_EXITCODEMASK);
  105         }
  106 
  107     return (0);
  108 }
  109 
  110 int writestatfile(proxy_t *x, char *status)
  111 {
  112     if (getstatfp() == NULL)
  113         return (0);
  114 
  115     if (pi.statfp != NULL) {
  116         rewind(pi.statfp);
  117         fprintf (pi.statfp, "%s %s %u %lu %s:%u %s %s %s:%u %s:%u %s\n",
  118                 PROXYNAME, *x->logname == 0? program: x->logname, getpid(),
  119                 x->started,
  120                 x->sock.ipnum, x->sock.port,
  121                 x->client.ipnum, x->client.name,
  122                 x->s.ipnum, x->s.port,
  123                 x->origdst.ipnum, x->origdst.port,
  124                 status);
  125         fflush(pi.statfp);
  126         }
  127 
  128     return (0);
  129 }
  130 
  131 void signalhandler(int sig)
  132 {
  133     if (sig == SIGPIPE) {
  134 
  135         /* Ignore here and make write() return -1. */
  136          
  137         signal(SIGPIPE, signalhandler);
  138         return;
  139         }
  140 
  141     printerror(0, "+INFO", "caught signal #%d", sig);
  142     exit(0);
  143 }
  144 
  145 char *gettime(void)
  146 {
  147     char    time[20];
  148     struct tm tm;
  149     struct timeval tv;
  150     struct timezone tz;
  151     static char string[80];
  152 
  153     gettimeofday(&tv, &tz);
  154     tm = *localtime(&tv.tv_sec);
  155     strftime(time, sizeof(time) - 2, "%H:%M:%S", &tm);
  156     snprintf (string, sizeof(string) - 2, "%s.%06d", time, (int) tv.tv_usec);
  157 
  158     return (string);
  159 }
  160 
  161 
  162 int multiaccept_loop(config_t *config)
  163 {
  164     int i, max;
  165     fd_set  bound, available;
  166 
  167     FD_ZERO(&bound);
  168     max = 0;
  169     for (i=0; i < config->binds; i++) {
  170         if (config->bindport[i].sock < 0) {
  171             syslog(LOG_NOTICE, "invalid socket number found: %d", config->bindport[i].sock);
  172             exit (1);
  173             }
  174             
  175         FD_SET(config->bindport[i].sock, &bound);
  176         if (config->bindport[i].sock > max)
  177             max = config->bindport[i].sock;
  178         }
  179 
  180 
  181     while (1) {
  182         memmove(&available, &bound, sizeof(fd_set));
  183         if (select(max + 1, &available, NULL, NULL, NULL) < 0) {
  184             if (errno == EINTR) {
  185                 syslog(LOG_NOTICE, "interrupted select call");
  186                 continue;
  187                 }
  188 
  189             syslog(LOG_NOTICE, "select error: %m");
  190             exit (1);
  191             }
  192 
  193         for (i=0; i < config->binds; i++) {
  194             if (FD_ISSET(config->bindport[i].sock, &available)) {
  195                 unsigned int len;
  196                 int connect, pid;
  197                 struct sockaddr_in client;
  198 
  199                 /*
  200                  * hier kommt ein accept an
  201                  */
  202 
  203                 len = sizeof(client);
  204                 if ((connect = accept(config->bindport[i].sock, (struct sockaddr *) &client, &len)) < 0) {
  205                     if (errno == EINTR  ||  errno == ECONNABORTED)
  206                         continue;
  207 
  208                     syslog(LOG_NOTICE, "accept error: %m");
  209                     exit (1);
  210                     }
  211         
  212                 if ((pid = fork()) < 0) {
  213                     syslog(LOG_NOTICE, "can't fork process: %m");
  214                     exit (1);
  215                     }
  216                 else if (pid == 0) {
  217                     dup2(connect, 0);
  218                     dup2(connect, 1);
  219 /*                  dup2(connect, 2); */
  220 
  221                     close (connect);
  222                     close (config->bindport[i].sock);
  223 
  224                     /*
  225                      * We have to close all listening ports
  226                      * before returning -- 24MAR00wzk
  227                      */
  228 
  229                     for (i=0; i < config->binds; i++) {
  230                         if (config->bindport[i].sock >= 0)
  231                             close (config->bindport[i].sock);
  232                         }
  233 
  234                     return (0);
  235                     }
  236 
  237                 close (connect);
  238                 }
  239             }
  240         }
  241 
  242     printerror(1, "-ERR", "server broke while loop -- terminating");
  243     return (0);
  244 }
  245 
  246 
  247 int proxy_request(proxy_t *x, int cfd)
  248 {
  249     int sfd, rc, bytes, errcode;
  250     unsigned long started, now;
  251     char    buffer[4096];
  252     struct timeval tov;
  253     fd_set  connection, available;
  254     FILE    *fp;
  255 
  256 
  257     fp = NULL;
  258     if (*x->writefile != 0) {
  259         char    filename[200];
  260 
  261         snprintf (filename, sizeof(filename) - 2, "%s.%d.log", x->writefile, getpid());
  262         if ((fp = fopen(filename, "a")) == NULL)
  263             printerror(0 | ERR_INFO, "-INFO", "can't open writefile: %s, error= %s", filename, strerror(errno));
  264         }
  265 
  266     time((time_t *) &started); 
  267     cfd = cfd;
  268 
  269     setvar(varname, "NAME", x->name);
  270     setvar(varname, "SERVERARG", x->server);
  271 
  272     x->srcip.port = 0;
  273     if (x->srcip.count == 0)
  274         sfd = openip(x->server, x->port, NULL, 0, &x->s);
  275     else if (x->srcip.count == 1)
  276         sfd = openip(x->server, x->port, x->srcip.srcip[0], 0, &x->s);
  277     else {
  278         int i;
  279         unsigned int srcport;
  280 
  281         srcport = 8000 + x->port;
  282         sfd = -1;   /* to make the compiler happy */
  283         for (i=0; i<x->srcip.count; i++) {
  284             sfd = openip(x->server, x->port, x->srcip.srcip[i], srcport, &x->s);
  285             if (sfd >= 0) {
  286                 x->srcip.port = srcport;
  287                 copy_string(x->srcip.interface, x->srcip.srcip[i], sizeof(x->srcip.interface));
  288                 break;
  289                 }
  290             }
  291         }
  292 
  293     if (sfd < 0) {
  294         printerror(1 | ERR_CONNECT, "-ERR", "connection error: client= %s, server= %s:%u, error= %s",
  295             x->client.name, x->s.name, x->s.port, strerror(errno));
  296         }
  297     
  298 
  299     setvar(varname, "SERVER", x->s.ipnum);
  300     setvar(varname, "SERVERNAME", x->s.name);
  301     setnumvar(varname, "SERVERPORT", x->s.port);
  302 
  303     if (x->extendedinfo != 0) {
  304         peer_t  incoming, outgoing;
  305 
  306         incoming.port = get_interface_info(0, &incoming);
  307         outgoing.port = get_interface_info(sfd, &outgoing);
  308         printerror(0, "+INFO", "connect: client= %s:%u, interface= %s:%u, outgoing= %s:%u, server= %s:%u, timeout= %d, uid/gid= %u/%u",
  309             x->client.ipnum, x->client.port,
  310             incoming.ipnum, incoming.port,
  311             outgoing.ipnum, outgoing.port,
  312             x->s.name, x->s.port, x->timeout, getuid(), getgid());
  313         }
  314     else if (x->srcip.port != 0) {
  315         printerror(0, "+INFO", "connect: client= %s, interface= %s:%u, server= %s:%u, timeout= %d, uid/gid= %u/%u",
  316             x->client.name,
  317             x->srcip.interface, x->srcip.port,
  318             x->s.name, x->s.port, x->timeout, getuid(), getgid());
  319         }
  320     else {
  321         printerror(0, "+INFO", "connect: client= %s, server= %s:%u, timeout= %d, uid/gid= %u/%u",
  322             x->client.name, x->s.name, x->s.port, x->timeout, getuid(), getgid());
  323         }
  324 
  325     writestatfile(x, "connected");
  326     FD_ZERO(&connection);
  327     FD_SET(cfd, &connection);
  328     FD_SET(sfd, &connection);
  329 
  330     errcode = 0;
  331     while (1) {
  332         memmove(&available, &connection, sizeof(fd_set));
  333         tov.tv_sec  = x->timeout;
  334         tov.tv_usec = 0;
  335 
  336         rc = select(sfd + 1, &available, (fd_set *) NULL, (fd_set *) NULL, &tov);
  337         if (rc < 0) {
  338             printerror(0, "-ERR", "select() error, error= %s", strerror(errno));
  339             break;
  340             }
  341         else if (rc == 0) {
  342             errcode = ERR_TIMEOUT;
  343             printerror(0, "-ERR", "connection timed out: client= %s, server= %s:%u",
  344                 x->client.name, x->s.name, x->s.port);
  345             break;
  346             }
  347 
  348         if (FD_ISSET(cfd, &available)) {
  349             if ((bytes = read(cfd, buffer, sizeof(buffer))) <= 0) {
  350                 if (bytes < 0) {
  351                     if (errno != ECONNRESET) {
  352                         errcode = ERR_CLIENT;
  353                         printerror(0 | ERR_INFO, "-INFO", "client close() detected, error= %s", strerror(errno));
  354                         }
  355                     }
  356                 else if (debug != 0)    /* bytes == 0 */
  357                     printerror(0, "+DEBUG", "client close() detected");
  358 
  359 /*              shutdown(sfd, 1); */
  360                 shutdown(sfd, SHUT_WR);
  361 
  362                 FD_ZERO(&connection);
  363                 FD_SET(sfd, &connection);
  364                 }
  365             else if (write(sfd, buffer, bytes) != bytes) {
  366                 errcode = ERR_SERVER;
  367                 printerror(0, "-ERR", "server write error, error= %s", strerror(errno));
  368                 break;
  369                 }
  370 
  371             if (fp != NULL) {
  372                 int c, i;
  373 
  374                 fprintf (fp, "--- CLIENT [%d] %s (%d):\n", getpid(), gettime(), bytes);
  375                 for (i=0; i<bytes; i++) {
  376                     c = buffer[i];
  377                     if (c < 32  ||  c > 127  ||  c == '#')
  378                         fprintf (fp, "#%02X", c);
  379                     else
  380                         fprintf (fp, "%c", c);
  381                     }
  382 
  383                 fprintf (fp, "\n");
  384                 }
  385 
  386             if (bytes > 0)
  387                 x->bytes_send = x->bytes_send + bytes;
  388             }
  389 
  390         if (FD_ISSET(sfd, &available)) {
  391             bytes = read(sfd, buffer, sizeof(buffer));
  392             if (bytes <= 0) {
  393                 if (bytes < 0) {
  394                     if (errno != ECONNRESET) {
  395                         errcode = ERR_SERVER;
  396                         printerror(0 | ERR_INFO, "-INFO", "server close() detected, error= %s", strerror(errno));
  397                         }
  398                     }
  399                 else if (debug != 0) {
  400                     printerror(0, "+INFO", "server close() detected");
  401                     }
  402 
  403                 break;
  404                 }
  405             else {
  406                 int count;
  407 
  408                 count = write(1, buffer, bytes);
  409                 if (count != bytes) {
  410                     errcode = ERR_CLIENT;
  411                     printerror(0, "-ERR", "client write error, error= %s", strerror(errno));
  412                     break;
  413                     }
  414                 }
  415 
  416             if (fp != NULL) {
  417                 int c, i;
  418 
  419                 fprintf (fp, "--- SERVER [%d] %s (%d):\n", getpid(), gettime(), bytes);
  420                 for (i=0; i<bytes; i++) {
  421                     c = buffer[i];
  422                     if (c < 32  ||  c > 127  ||  c == '#')
  423                         fprintf (fp, "#%02X", c);
  424                     else
  425                         fprintf (fp, "%c", c);
  426                     }
  427 
  428                 fprintf (fp, "\n");
  429                 }
  430 
  431             if (bytes > 0)
  432                 x->bytes_received = x->bytes_received + bytes;
  433             }
  434         }
  435 
  436     time((time_t *) &now); 
  437     setnumvar(varname, "BYTES_CTS", x->bytes_send);
  438     setnumvar(varname, "BYTES_STC", x->bytes_received);
  439     setnumvar(varname, "DURATION", now - started);
  440 
  441     writestatfile(x, "disconnected");
  442     printerror(0, "+OK", "disconnect: client= %s, server= %s:%u, received= %ld, send= %ld, duration= %ld",
  443         x->client.name, x->s.name, x->s.port,
  444         x->bytes_received, x->bytes_send,
  445         now - started);
  446 
  447     if (errcode != 0)
  448         run_errorhandler(errcode);
  449 
  450     return (0);
  451 }
  452 
  453 
  454 int open_errorlog(char *filename)
  455 {
  456     int fno;
  457 
  458     if (use_errorlog == 0)
  459         return (0);
  460 
  461     if ((fno = open(filename, O_WRONLY | O_CREAT | O_APPEND, 0664)) >= 0)
  462         dup2(fno, 2);
  463     else 
  464         printerror(ERR_STDERR, "-INFO", "can't open %s, using stderr", filename);
  465 
  466     return (0);
  467 }
  468 
  469 void missing_arg(int c, char *string)
  470 {
  471     printerror(ERR_STDERR, "-ERR", "missing arg: -%c, %s", c, string);
  472     exit (1);
  473 }
  474 
  475 int main(int argc, char *argv[], char *envp[])
  476 {
  477     int c, i, k, bound;
  478     char    *p, option[80];
  479     proxy_t *x, *precon;
  480     config_t *config;
  481 
  482 
  483     if ((p = strrchr(argv[0], '/')) == NULL)
  484         program = argv[0];
  485     else {
  486         copy_string(progname, &p[1], sizeof(progname));
  487         program = progname;
  488         }
  489 
  490     config = allocate(sizeof(config_t));
  491 
  492     x = config->def = allocate(sizeof(proxy_t));
  493     x->timeout   = 60;
  494     x->redirmode = REDIR_NONE;
  495     set_username(x, "nobody", "default-config", 0);
  496 
  497     init_procinfo("PROXY_");
  498     precon = allocate(sizeof(proxy_t));
  499 
  500     config->bindport = allocate(sizeof(port_t) * MAX_PORT);
  501     openlog(program, LOG_PID, LOG_MAIL);
  502 
  503     bound = 0;
  504     k = 1;
  505     while (k < argc  &&  argv[k][0] == '-'  &&  argv[k][1] != 0) {
  506         copy_string(option, argv[k++], sizeof(option));
  507         for (i=1; (c = option[i]) != 0; i++) {
  508             if (c == 'd')
  509                 debug = 1;
  510             else if (c == 'a') {
  511                 if (k >= argc)
  512                     missing_arg(c, "access control program");
  513 
  514                 copy_string(x->acp, argv[k++], sizeof(x->acp));
  515                 }
  516             else if (c == 'b') {
  517                 char    addr[300];
  518                 
  519                 if (k >= argc)
  520                     missing_arg(c, "bind address and port");
  521 
  522                 copy_string(addr, argv[k++], sizeof(addr));
  523                 if ((p = strchr(addr, ':')) == NULL)
  524                     x->port = getportnum(addr);
  525                 else {
  526                     *p++ = 0;
  527                     x->port = getportnum(p);
  528                     copy_string(x->interface, addr, sizeof(x->interface));
  529                     }
  530 
  531                 bound = 1;
  532                 config->standalone = 1;
  533                 }
  534             else if (c == 'e') {
  535                 if (use_errorlog != 0) {
  536                     if (k >= argc)
  537                         missing_arg(c, "logfile name");
  538 
  539                     copy_string(errorlog, argv[k++], sizeof(errorlog));
  540                     }
  541                     
  542                 use_errorlog = 1;
  543                 }
  544             else if (c == 'f'  ||  c == 'c') {
  545                 if (k >= argc)
  546                     missing_arg(c, "configuration file");
  547 
  548                 copy_string(configfile, argv[k++], sizeof(configfile));
  549                 }
  550             else if (c == 'i') {
  551                 if (k >= argc)
  552                     missing_arg(c, "rotation interfaces");
  553 
  554                 addsrc(x, argv[k++], "command-line", 0);
  555                 }
  556             else if (c == 'l') {
  557                 if (k >= argc)
  558                     missing_arg(c, "logname");
  559 
  560                 copy_string(config->logname, argv[k++], sizeof(config->logname));
  561                 }
  562             else if (c == 'n')
  563                 onlynumbers = 1;
  564             else if (c == 'o') {
  565                 if (k >= argc)
  566                     missing_arg(c, "statdir");
  567 
  568                 copy_string(statdir, argv[k++], sizeof(statdir));
  569                 }
  570             else if (c == 'p') {
  571                 if (*pi.pidfile == 0)
  572                     setpidfile(PIDFILE);
  573                 else {
  574                     if (k >= argc)
  575                         missing_arg(c, "pidfile");
  576 
  577                     setpidfile(argv[k++]);
  578                     }
  579                 }
  580             else if (c == 'q') {
  581                 if (k >= argc)
  582                     missing_arg(c, "source ipnum");
  583 
  584                 addsrcip(x , argv[k++]);
  585                 }
  586             else if (c == 'r') {
  587                 if (k >= argc)
  588                     missing_arg(c, "redirect mode");
  589 
  590                 set_redirmode(x, argv[k++], "command-line", 0);
  591                 }
  592             else if (c == 's')
  593                 config->standalone = 1;
  594             else if (c == 't') {
  595                 if (k >= argc)
  596                     missing_arg(c, "timeout");
  597 
  598                 x->timeout = atoi(argv[k++]);
  599                 if (x->timeout < 1)
  600                     x->timeout = 60;
  601                 }
  602             else if (c == 'u') {
  603                 if (k >= argc)
  604                     missing_arg(c, "username");
  605 
  606                 set_username(x, argv[k++], "command-line", 0);
  607                 }
  608             else if (c == 'v') {
  609                 if (k >= argc)
  610                     missing_arg(c, "varname prefix");
  611 
  612                 copy_string(varname, argv[k++], sizeof(varname));
  613                 }
  614             else if (c == 'w') {
  615                 if (k >= argc)
  616                     missing_arg(c, "write file");
  617 
  618                 copy_string(x->writefile, argv[k++], sizeof(x->writefile));
  619                 }
  620             else if (c == 'x') {
  621                 if (k >= argc)
  622                     missing_arg(c, "ctp");
  623 
  624                 copy_string(x->ctp, argv[k++], sizeof(x->ctp));
  625                 }
  626             else if (c == 'y')
  627                 x->cleanenv = 1;
  628             else if (c == 'z') {
  629                 if (listports == 0)
  630                     listports = 1;
  631                 else
  632                     listports = 2;
  633                 }
  634             else if (c == 'A') {
  635                 if (k >= argc)
  636                     missing_arg(c, "acl parameter");
  637 
  638                 append(&x->acl, x->acl.len > 0? " ": "", argv[k++]);
  639                 }
  640             else if (c == 'E') {
  641                 char    mode[40], par[200];
  642 
  643                 if (k >= argc)
  644                     missing_arg(c, "session mode parameter");
  645 
  646                 p = copy_string(par, argv[k++], sizeof(par));
  647                 p = get_quoted(&p, ',', mode, sizeof(mode));
  648                 set_sessionmode(mode, "command-line", 0);
  649                 get_quoted(&p, ',', sessiondir, sizeof(sessiondir));
  650 
  651                 get_quoted(&p, ',', par, sizeof(par));
  652                 set_exithandler(par);
  653 
  654                 set_exitcodes(ERR_ANY);
  655                 }
  656             else if (c == 'I')
  657                 x->extendedinfo = 1;
  658             else if (c == 'O') {
  659                 if (k >= argc)
  660                     missing_arg(c, "sessiondir");
  661 
  662                 copy_string(sessiondir, argv[k++], sizeof(sessiondir));
  663                 }
  664             else if (c == 'V') {
  665                 printf ("%s %s\n", program, VERSION);
  666                 exit (0);
  667                 }
  668             else {
  669                 printerror(ERR_STDERR, "-ERR", "unknown option: -%c", c);
  670                 exit (1);
  671                 }
  672             }
  673         }
  674 
  675 
  676 
  677     if (*configfile != 0)
  678         read_configuration(config, configfile);
  679     else if (bound == 0  &&  k >= argc) {
  680         copy_string(configfile, "/etc/tcpproxy.conf", sizeof(configfile));
  681 
  682         /* This default is the most common cause for tcpproxy installations
  683          * to fail initially.
  684          *
  685          * config->standalone = 1;
  686          *
  687          * Only if stdin is not a socket then tcpproxy will bind and go
  688          * into standalone. -- 2007-08-30/wzk
  689          */
  690 
  691         if (issock(0) != 0)
  692             config->standalone = 1;
  693 
  694         read_configuration(config, configfile);
  695         }
  696     else if (listports == 1)
  697         /* ist ok, ein Serverprogramm wird nicht benoetigt */ ;
  698     else if (k >= argc) {
  699         printerror(ERR_STDERR, "-ERR", "missing server");
  700         exit (1);
  701         }
  702     else {
  703         if (*argv[k] == '/'  ||  *argv[k] == '.') {
  704             x->proxytype = PROXY_PROGRAM;
  705             copy_string(x->server, argv[k++], sizeof(x->server));
  706 
  707 /*          x->proxytype = PROXY_PROGRAM;
  708  *
  709  *          i = 0;
  710  *          while (k < argc)
  711  *              x->u.program.argv[i++] = argv[k++];
  712  *
  713  *          x->u.program.argv[i] = NULL;
  714  */
  715             }
  716         else {
  717             x->proxytype = PROXY_SERVER;
  718 
  719             copy_string(x->server, argv[k++], sizeof(x->server));
  720             if (k < argc) {
  721                 printerror(ERR_STDERR, "-ERR", "extra arguments after server");
  722                 exit (1);
  723                 }
  724             }
  725         }
  726     
  727 
  728     if (*sessiondir == 0) {
  729         if (pi.errormode != ERRMODE_NONE  &&  *statdir != 0)
  730             copy_string(sessiondir, statdir, sizeof(sessiondir));
  731         }
  732 
  733     if (*config->logname != 0) {
  734         copy_string(progname, config->logname, sizeof(progname));
  735         closelog();
  736         openlog(config->logname, LOG_PID, LOG_MAIL);
  737         }
  738 
  739     if (config->first == NULL) {
  740         x = new_configuration(config, x);
  741         config->bindport[config->binds].port  = x->port;
  742         config->bindport[config->binds].count = 1;
  743         config->binds++;
  744         }
  745 
  746 
  747     if (listports == 1) {
  748         for (i=0; i < config->binds; i++) {
  749             if (config->bindport[i].port != 0)
  750                 printf ("%u\n", config->bindport[i].port);
  751             }
  752             
  753         exit (0);
  754         }
  755     else if (listports == 2) {
  756         proxy_t *y;
  757 
  758         y = config->first;
  759         while (y != NULL) {
  760             printf ("%s %u", y->interface, y->port);
  761             if (y->proxytype == PROXY_PROGRAM) {
  762 /*              int i; */
  763 
  764                 printf ("  exec:");
  765 /*              for (i=0; y->u.program.argv[i] != NULL; i++)
  766  *                  printf (" %s", y->u.program.argv[i]);
  767  */
  768                 }
  769             else {
  770                 printf ("  proxy:");
  771                 printf (" %s", y->server);
  772                 }
  773 
  774             printf ("\n");
  775             y = y->next;
  776             }
  777 
  778         exit (0);
  779         }
  780 
  781 
  782     atexit(exithandler);
  783     signal(SIGHUP, signalhandler);
  784     signal(SIGINT, signalhandler);
  785     signal(SIGQUIT, signalhandler);
  786     signal(SIGUSR1, signalhandler);
  787     signal(SIGUSR2, signalhandler);
  788     signal(SIGTERM, signalhandler);
  789     signal(SIGPIPE, signalhandler);
  790 
  791     if (config->standalone != 0) {
  792         int i;
  793         char    *ip, *bindip;
  794         proxy_t *x;
  795 
  796         /*
  797          * Compute to which ports we have to bind.
  798          */
  799 
  800         config->binds = 0;
  801         x = config->first;
  802         while (x != NULL) {
  803             for (i=0; i < config->binds; i++) {
  804                 if (config->bindport[i].port == x->port) {
  805                     config->bindport[i].count++;
  806                     *config->bindport[i].ip = 0;
  807 
  808                     break;
  809                     }
  810                 }
  811 
  812             if (i >= config->binds) {
  813                 int k;
  814 
  815                 k = config->binds++;
  816                 config->bindport[k].count = 1;
  817                 config->bindport[k].port  = x->port;
  818                 copy_string(config->bindport[k].ip, x->interface, sizeof(config->bindport[k].ip));
  819                 }
  820 
  821             x = x->next;
  822             }
  823 
  824 
  825         pi.mainpid = getpid();
  826         for (i=0; i < config->binds; i++) {
  827             if (config->bindport[i].port == 0)
  828                 continue;   /* Mogelt sich irgendwie in die Port-Liste -- 20AUG99wzk */
  829                 
  830             ip = config->bindport[i].ip;
  831             if (strcmp(ip, "*") == 0  ||  config->bindport[i].count > 1)
  832                 ip = "0.0.0.0";
  833 
  834             if (*ip == 0  ||  strcmp(ip, "0.0.0.0") == 0  ||  isalpha(*ip) != 0)
  835                 bindip = "0.0.0.0";
  836             else
  837                 bindip = ip;
  838 
  839 /*          config->bindport[i].sock = bind_to_port(strcmp(ip, "0.0.0.0") == 0? "": ip, config->bindport[i].port); */
  840             config->bindport[i].sock = bind_to_port(bindip, config->bindport[i].port);
  841             printerror(0, "", "bound to %s:%u",
  842                 bindip, config->bindport[i].port);
  843             }
  844             
  845         signal(SIGCHLD, SIG_IGN);
  846         config->standalone = 1;
  847         }
  848 
  849 
  850     /*
  851      * Go into the background.
  852      */
  853 
  854     if (debug == 0) {
  855         if (config->standalone != 0) {
  856             int pid;
  857         
  858             if ((pid = fork()) < 0) {
  859                 printerror(ERR_STDERR, "-ERR", "can't fork into background");
  860                 exit (1);
  861                 }
  862             else if (pid > 0)
  863                 exit (0);
  864 
  865             printerror(0, "", "ready");
  866             }
  867         
  868         open_errorlog(errorlog);
  869         }
  870 
  871     /*
  872      * Write the pidfile if we are in standalone mode.
  873      */
  874 
  875     if (config->standalone != 0  &&  *pi.pidfile != 0) {
  876         FILE    *fp;
  877 
  878         if ((fp = fopen(pi.pidfile, "w")) == NULL)
  879             printerror(1, "-ERR", "can't write pidfile: %s, error= %s", pi.pidfile, strerror(errno));
  880 
  881         fprintf (fp, "%d\n", getpid());
  882         pi.mainpid = getpid();
  883 
  884         fclose (fp);
  885         }
  886 
  887 
  888     /*
  889      * We are ready to run.
  890      */
  891      
  892     if (config->standalone != 0)
  893         multiaccept_loop(config);
  894 
  895     signal(SIGCHLD, SIG_DFL);
  896     setvar(varname, "PROXYNAME", PROXYNAME);
  897     setnumvar(varname, "PID", getpid());
  898 
  899 
  900     /*
  901      * At this point we have an incoming connection on stdin and
  902      * stdout.  If tcpproxy is in standalone mode the server
  903      * process is still in multiaccept_loop().
  904      *
  905      * Let's do some basic setup first.
  906      */
  907 
  908     if (*sessiondir != 0) {
  909         snprintf (pi.sessionfile, sizeof(pi.sessionfile) - 2, "%s/%s-%05d.log",
  910                 sessiondir, program, getpid());
  911         if ((pi.sessionfp = fopen(pi.sessionfile, "w+")) == NULL) {
  912             printerror(0, "-ERR", "can't create session file %s, error= %s",
  913                     pi.sessionfile, strerror(errno));
  914             }
  915         }
  916 
  917     /*
  918      * Fill the "pre connection" proxy data structure to use
  919      * it until we have the correct configuration.
  920      */
  921 
  922     get_interface_info(0, &precon->sock);
  923     setvar(varname, "INTERFACE", precon->sock.ipnum);
  924     setnumvar(varname, "PORT", precon->sock.port);
  925 
  926     precon->port = get_client_info(0, &precon->client, onlynumbers);
  927     setvar(varname, "CLIENT", precon->client.ipnum);
  928     setvar(varname, "CLIENTNAME", precon->client.name);
  929 
  930     printerror(0, "+INFO", "connected on %s:%u, client= %s:%u",
  931                     precon->sock.ipnum, precon->sock.port,
  932                     precon->client.ipnum, precon->client.port);
  933 
  934     /*
  935      * Search the configuration for the port and interface of the
  936      * connection.  It there is none, terminate.
  937      */
  938 
  939     x = find_configuration(config, precon->sock.ipnum, precon->sock.port);
  940     if (x == NULL) {
  941         printerror(1, "-ERR", "no configuration found for interface %s:%u, client= %s",
  942                 precon->sock.ipnum, precon->sock.port, precon->client.ipnum);
  943         }
  944 
  945     setvar(varname, "LOGNAME", (*x->logname != 0)? x->logname: program);
  946     snprintf (option, sizeof(option) - 2, "%s:%u", x->interface, x->port);
  947     setvar(varname, "CONFIG", option);
  948 
  949 
  950     /*
  951      * Take socket and client information and create the statfile.
  952      */
  953 
  954     x->sock   = precon->sock;
  955     x->client = precon->client;
  956     free(precon);
  957 
  958     /*
  959      * Initialize the original destination ...
  960      */
  961 
  962     copy_string(x->origdst.ipnum, "0.0.0.0", sizeof(x->origdst.ipnum));
  963     x->origdst.port = 0;
  964 
  965     /*
  966      * ... the startup time ...
  967      */
  968     
  969     x->started = time(NULL);
  970     setnumvar(varname, "STARTED", x->started);
  971 
  972 
  973     /*
  974      * ... and write the statfile if configured.
  975      */
  976 
  977     writestatfile(x, "request");
  978 
  979 
  980 
  981     /*
  982      * Apply uid/gid and log settings from the configuration.
  983      */
  984 
  985     if (*x->logname != 0) {
  986         closelog();
  987         openlog(x->logname, LOG_PID, LOG_MAIL);
  988         }
  989 
  990     if (getuid() != 0  &&  geteuid() != 0)
  991         /* nichts */ ;
  992     else {
  993         struct passwd *pw;
  994 
  995         if (pi.statfp != NULL)
  996             fchown(fileno(pi.statfp), x->uid, x->gid);
  997 
  998         if (pi.sessionfp != NULL)
  999             fchown(fileno(pi.sessionfp), x->uid, x->gid);
 1000 
 1001         if ((pw = getpwuid(x->uid)) != NULL) {
 1002             if (initgroups(pw->pw_name, pw->pw_gid) != 0) {
 1003                 printerror(0, "-INFO", "can't initgroups, error= %s", strerror(errno));
 1004                 }
 1005             }
 1006 
 1007         if (setgid(x->gid) != 0  ||  setuid(x->uid) != 0) {
 1008             printerror(1, "-ERR", "can't change uid/gid to %u/%u, error= %s",
 1009                     x->uid, x->gid, strerror(errno));
 1010             }
 1011         }
 1012 
 1013 
 1014     if (x->redirmode != 0) {
 1015         int rc;
 1016         size_t  socksize;
 1017         struct sockaddr_in sock;
 1018 
 1019         socksize = sizeof(sock);
 1020         rc = getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &sock, &socksize);
 1021         if (rc != 0)
 1022             ;
 1023         else if (strcmp((char *) inet_ntoa(sock.sin_addr), x->sock.ipnum) != 0  ||
 1024              ntohs(sock.sin_port) != x->sock.port) {
 1025 
 1026             /*
 1027              * Take the original server information if it's
 1028              * a redirected request.
 1029              */
 1030 
 1031             copy_string(x->origdst.ipnum, (char *) inet_ntoa(sock.sin_addr), sizeof(x->origdst.ipnum));
 1032             x->origdst.port = ntohs(sock.sin_port);
 1033             setvar(varname, "ORIGDST_SERVER", x->origdst.ipnum);
 1034             setnumvar(varname, "ORIGDST_PORT", x->origdst.port);
 1035 
 1036             printerror(0, "+INFO", "connection redirected, origdst: %s:%u", x->origdst.ipnum, x->origdst.port);
 1037             }
 1038         }
 1039 
 1040 
 1041     /*
 1042      * Check acl if we have one.
 1043      */
 1044 
 1045     if (x->acl.len > 0) {
 1046         if (checkacl(x->acl.ptr, x->client.ipnum, ACL_DENY) != ACL_ALLOW) {
 1047             printerror(1 | ERR_ACCESS, "-ERR", "access denied by acl: client= %s, ip= %s",
 1048                 x->client.name, x->client.ipnum);
 1049             }
 1050         }
 1051 
 1052 
 1053     /*
 1054      * Access control Programm ausfuehren
 1055      */
 1056 
 1057     if (*x->acp != 0) {
 1058         int rc;
 1059 
 1060         rc = run_acp(x);
 1061         if (rc != 0)
 1062             exit (0);
 1063         }
 1064 
 1065 
 1066     /*
 1067      * Handle transparent redirection if required.
 1068      */
 1069 
 1070     if (x->origdst.port != 0) {
 1071         if (x->redirmode == REDIR_FORWARD  ||  x->redirmode == REDIR_FORWARD_ONLY) {
 1072 
 1073             /*
 1074              * Take original requested destination as server.
 1075              */
 1076 
 1077             snprintf (x->server, sizeof(x->server) - 2, "%s:%u",
 1078                     x->origdst.ipnum, x->origdst.port);
 1079             }
 1080         }
 1081     else if (x->redirmode == REDIR_FORWARD_ONLY)
 1082         printerror(1, "-ERR", "connection not redirected, client= %s", x->client.name);
 1083 
 1084 
 1085     /*
 1086      * Start server program or proxy connection.
 1087      */
 1088 
 1089     if (*x->server == '/') {
 1090         int argc;
 1091         char    *argv[32];
 1092 
 1093         printerror(0, "", "starting `%s', client= %s, uid/gid= %u/%u",
 1094                 x->server, x->client.name, getuid(), getgid());
 1095         
 1096         exithandler();      /* cleanup */
 1097         if (x->cleanenv != 0)
 1098             cleanenv(envp);
 1099 
 1100         argc = split(x->server, argv, ' ', 30);
 1101         argv[argc] = NULL;
 1102         execvp(argv[0], argv);
 1103         
 1104         printerror(1, "-ERR", "can't execute %s, error= %s", argv[0], strerror(errno));
 1105         exit (1);
 1106         }
 1107     else {
 1108         proxy_request(x, 0);
 1109         close(0);
 1110 
 1111         if (pi.errorcode == 0) {
 1112             if (pi.havemessages != 0)
 1113                 run_errorhandler(ERR_INFO);
 1114             else
 1115                 run_errorhandler(ERR_OK);
 1116             }
 1117         }
 1118 
 1119     exit (0);
 1120 }
 1121 
 1122