"Fossies" - the Fresh Open Source Software Archive

Member "portfwd-0.29/src/portfwd.cc" (30 May 2005, 7258 Bytes) of package /linux/privat/old/portfwd-0.29.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.

    1 /*
    2   portfwd.c
    3 
    4   $Id: portfwd.cc,v 1.8 2005/05/30 02:13:28 evertonm Exp $
    5  */
    6 
    7 #include <stdio.h>
    8 #include <string.h>
    9 #include <sys/types.h>
   10 #include <sys/wait.h>
   11 #include <unistd.h>
   12 #include <errno.h>
   13 #include <signal.h>
   14 #include <syslog.h>
   15 #include <stdlib.h>
   16 
   17 #include "getopt.h"
   18 #include "portfwd.h"
   19 #include "util.h"
   20 #include "vector.hpp"
   21 #include "iterator.hpp"
   22 #include "entry.hpp"
   23 #include "config.h"
   24 #include "fd_set.h"
   25 
   26 extern FILE           *yyin;
   27 extern int            yyparse();
   28 extern int            conf_syntax_errors;
   29 extern vector<entry*> *entry_vector;
   30 
   31 const int BUF_SZ = 8192;
   32 const char * const portfwd_version = VERSION;
   33 
   34 #ifdef HAVE_MSG_PROXY
   35 int transparent_proxy = 0;
   36 #endif 
   37 
   38 int on_the_fly_dns = 0;
   39 int foreground = 0;
   40 
   41 void usage(FILE *out) 
   42 {
   43   const char *prog = get_prog_name();
   44   fprintf(out, "Usage: %s [<options>]\n"
   45            "       -h               | --help\n"
   46            "       -v               | --version\n"
   47            "       -d               | --debug\n"
   48 
   49 #ifdef HAVE_MSG_PROXY
   50                "       -t               | --transparent-proxy\n"
   51 #endif
   52 
   53            "       -f               | --on-the-fly-dns\n"
   54            "       -g               | --foreground\n"
   55            "       -c <config-file> | --config <config-file>\n",
   56       prog);
   57 }
   58 
   59 void show_version(FILE *out) 
   60 {
   61   fprintf(out, "%s %s\n", get_prog_name(), portfwd_version);
   62 }
   63 
   64 #
   65 void parse_cmdline(int argc, const char *argv[], const char **config)
   66 {
   67   const char * me = argv[0];
   68   const char * const DEFAULT_CONFIG = PORTFWD_CONF;
   69 
   70   int opt;
   71   int option_index = 0;
   72   struct option long_options[] =
   73   {
   74     {"help", 0, 0, 'h'},
   75     {"version", 0, 0, 'v'},
   76     {"debug", 0, 0, 'd'},
   77 
   78 #ifdef HAVE_MSG_PROXY
   79     {"transparent-proxy", 0, 0, 't'},
   80 #endif 
   81 
   82     {"on-the-fly-dns", 0, 0, 'f'},
   83     {"foreground", 0, 0, 'g'},
   84     {"config", 1, 0, 'c'},
   85     {0, 0, 0, 0}
   86   };
   87 
   88   *config  = 0;
   89 
   90   for (;;) {
   91          
   92     opt = getopt_long(argc, (char ** const) argv, "hvdtfgc:", long_options, &option_index);
   93     if (opt == -1)
   94       break;
   95 
   96     switch (opt) {
   97     case 'h':
   98       usage(stdout);
   99       exit(0);
  100       break;
  101     case 'v':
  102       show_version(stdout);
  103       exit(0);
  104       break;
  105     case 'd':
  106       ++verbose_mode;
  107       break;
  108 
  109 #ifdef HAVE_MSG_PROXY
  110     case 't':
  111       ++transparent_proxy;
  112       break;
  113 #endif
  114 
  115     case 'f':
  116       ++on_the_fly_dns;
  117       break;
  118     case 'g':
  119       ++foreground;
  120       break;
  121     case 'c':
  122       if (*config) {
  123     fprintf(stderr, "%s: Configuration file redefinition: %s", me, optarg);
  124     exit(1);
  125       }
  126       *config = optarg;
  127       break;
  128     case '?':
  129       usage(stderr);
  130       exit(1);
  131       break;
  132     default:
  133       fprintf(stderr, "%s: getopt() returned unknown option: %c (%d)", me, opt, opt);
  134       exit(1);
  135     }
  136   }
  137 
  138   if (optind < argc) {
  139     fprintf(stderr, "%s: Invalid argument: %s", me, argv[optind]);
  140     exit(1);
  141   }
  142 
  143   if (!*config)
  144     *config = DEFAULT_CONFIG;
  145 }
  146 
  147 void read_config(const char *cfg)
  148 {
  149   ONVERBOSE(syslog(LOG_INFO, "Configuration file: '%s'", cfg));
  150 
  151   yyin = fopen(cfg, "r");
  152   if (!yyin) {
  153     syslog(LOG_ERR, "Can't open configuration file: '%s': %m", cfg);
  154     exit(1);
  155   }
  156 
  157   yyparse();
  158   
  159   if (conf_syntax_errors) {
  160     syslog(LOG_ERR, "Syntax errors: %d", conf_syntax_errors);
  161     exit(1);
  162   }
  163 
  164   if (fclose(yyin)) {
  165     syslog(LOG_ERR, "Can't close configuration file: '%s'", cfg);
  166     exit(1);
  167   }
  168 }
  169 
  170 void do_show(vector<entry*>* entries)
  171 {
  172   if (!entries) {
  173     syslog(LOG_ERR, "Internal error: Null entry vector (!)");
  174     return;
  175   }
  176 
  177   if (!entries->get_size()) {
  178     syslog(LOG_INFO, "/* Empty */");
  179     return;
  180   }
  181 
  182   iterator<vector<entry*>,entry*> it(*entries);
  183   for (it.start(); it.cont(); it.next())
  184     it.get()->show();
  185 }
  186 
  187 
  188 void do_forward(vector<entry*>* entries)
  189 {
  190   if (!entries) {
  191     syslog(LOG_ERR, "Internal error: Null entry vector (!)");
  192     return;
  193   }
  194 
  195   if (!entries->get_size()) {
  196     syslog(LOG_NOTICE, "Nothing to do: empty configuration file");
  197     return;
  198   }
  199 
  200   iterator<vector<entry*>,entry*> it(*entries);
  201   for (it.start(); it.cont(); it.next())
  202     it.get()->serve();
  203 }
  204 
  205 void child_reaper(int sig)
  206 {
  207   int status;
  208   void (*prev_handler)(int);
  209 
  210   /* pid_t child_pid = waitpid(-1, &status, WNOHANG); */
  211   pid_t child_pid = wait(&status);
  212   prev_handler = signal(SIGCHLD, child_reaper);
  213   if (prev_handler == SIG_ERR) {
  214     syslog(LOG_ERR, "signal() failed on child_reaper re-install: %m");
  215     return;
  216   }
  217 
  218   if (child_pid == -1) {
  219     syslog(LOG_ERR, "Error waiting pid of child: %m");
  220     return;
  221   }
  222   
  223   if (WIFEXITED(status)) {
  224     syslog(LOG_WARNING, "Child with PID %d exited normally with exit status: %d", child_pid, WEXITSTATUS(status));
  225     return;
  226   }
  227 
  228   if (WIFSIGNALED(status))
  229     syslog(LOG_NOTICE, "Child received signal: %d", WTERMSIG(status)); 
  230     
  231   syslog(LOG_ERR, "Child with PID %d exited abnormally", child_pid);
  232 }
  233 
  234 void term_handler(int sig)
  235 {
  236   void (*prev_handler)(int);
  237 
  238   prev_handler = signal(SIGTERM, SIG_IGN);
  239   if (prev_handler == SIG_ERR)
  240     syslog(LOG_ERR, "signal() failed on term_handler de-install: %m");
  241 
  242   if (kill(0, SIGTERM))
  243     syslog(LOG_ERR, "Can't terminate children");
  244 
  245   syslog(LOG_INFO, "SIGTERM - Program terminated");
  246 
  247   closelog();
  248 
  249   exit(0);
  250 }
  251 
  252 int main(int argc, const char *argv[]) 
  253 {
  254   set_prog_name("portfwd");
  255 
  256   /*
  257    * Read arguments from command line.
  258    */
  259   const char *config;
  260   parse_cmdline(argc, argv, &config);
  261 
  262   /*
  263    * Close file descriptors.
  264    */
  265   close_fds(0);
  266 
  267   /*
  268    * Connect standard IO to /dev/null.
  269    */
  270   std_to_null(); 
  271 
  272   /*
  273    * Open interface to syslog.
  274    */
  275   openlog(get_prog_name(), LOG_CONS | LOG_PID, LOG_DAEMON);
  276   syslog(LOG_INFO, "%s %s started", get_prog_name(), portfwd_version);
  277 
  278   ONVERBOSE(syslog(LOG_DEBUG, "Verbose mode: %d", verbose_mode));
  279 
  280 #ifdef HAVE_MSG_PROXY
  281   ONVERBOSE(syslog(LOG_INFO, "Transparent proxy mode: %s (%d)", transparent_proxy ? "on" : "off", transparent_proxy));
  282 #else
  283   ONVERBOSE(syslog(LOG_INFO, "Transparent proxy mode: disabled on compile time"));
  284 #endif
  285 
  286   ONVERBOSE(syslog(LOG_INFO, "On the fly DNS mode: %s (%d)", on_the_fly_dns ? "on" : "off", on_the_fly_dns));
  287 
  288   ONVERBOSE(syslog(LOG_INFO, "Foreground: %s (%d)", foreground ? "on" : "off", foreground));
  289 
  290   /*
  291    * Go to background.
  292    */
  293   if (!foreground) {
  294     int dmz = daemonize();
  295     if (dmz) {
  296       syslog(LOG_ERR, "daemonize() failed: %d", dmz);
  297       exit(1);
  298     }
  299   }
  300 
  301   /*
  302    * Connect standard IO to /dev/null.
  303    */
  304   /* std_to_null(); */
  305 
  306   solve_protonumbers();
  307 
  308   /*
  309    * Load configuration.
  310    */
  311   read_config(config);
  312   ONVERBOSE(do_show(entry_vector));
  313 
  314   /*
  315    * Go to root (/) directory to prevent disturbing umount.
  316    */
  317   cd_root();
  318 
  319   /*
  320    * Install handler to take care of children.
  321    */
  322   void (*prev_handler)(int);
  323   prev_handler = signal(SIGCHLD, child_reaper);
  324   if (prev_handler == SIG_ERR) {
  325     syslog(LOG_ERR, "signal() failed on child_reaper install: %m");
  326     exit(1);
  327   }
  328 
  329   /*
  330    * Spawn forwarders.
  331    */
  332   do_forward(entry_vector);
  333 
  334   /*
  335    * Install handler for TERM signal.
  336    */
  337   prev_handler = signal(SIGTERM, term_handler);
  338   if (prev_handler == SIG_ERR) {
  339     syslog(LOG_ERR, "signal() failed on term_handler install: %m");
  340     exit(1);
  341   }
  342 
  343   /*
  344    * Wait forever.
  345    */
  346   for (;;)
  347     sleep(3600);
  348 
  349   return 0;
  350 }