"Fossies" - the Fresh Open Source Software Archive

Member "portfwd-0.29/src/director.cc" (30 May 2005, 7678 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   director.cc
    3 
    4   $Id: director.cc,v 1.10 2005/05/30 02:13:28 evertonm Exp $
    5  */
    6 
    7 
    8 #include <sys/types.h>
    9 #include <syslog.h>
   10 #include <string.h>
   11 #include <errno.h>
   12 #include <sys/socket.h>
   13 #include <netinet/in.h>
   14 #include <arpa/inet.h>
   15 
   16 
   17 #include "signal.h"
   18 #include "util.h"
   19 #include "addr.h"
   20 #include "solve.h"
   21 #include "vector.hpp"
   22 #include "director.hpp"
   23 #include "fd_set.h"
   24 
   25 
   26 void director::close_sockets()
   27 {
   28   close(fd[0]);
   29   close(fd[1]);
   30   fd[0] = -1;
   31   fd[1] = -1;
   32 }
   33 
   34 void director::kill_child()
   35 {
   36   if (child == -1)
   37     return;
   38 
   39   kill(child, SIGTERM);
   40   child = -1;
   41 }
   42 
   43 void director::run(char *argv[])
   44 {
   45 
   46   ONVERBOSE(syslog(LOG_DEBUG, "Spawning director: %s", argv[0]));
   47 
   48   /*
   49    * Create unix domain socket
   50    */
   51   if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) {
   52     syslog(LOG_ERR, "Failure creating unix domain socket: %m");
   53     return;
   54   }
   55 
   56   pid_t child_pid = fork();
   57   if (child_pid) {
   58     /*
   59      * Parent code
   60      */
   61 
   62     if (child_pid == -1) {
   63       syslog(LOG_ERR, "director::run(): fork() failed for temporary child: %m");
   64       close_sockets();
   65       return;
   66     }
   67 
   68     return;
   69   }
   70 
   71   /*
   72    * Temporary child code
   73    */
   74 
   75   child = fork();
   76   if (child) {
   77     /*
   78      * Temporary child
   79      */
   80     
   81     if (child == -1) {
   82       syslog(LOG_ERR, "director::run(): fork() failed for actual child: %m");
   83       exit(1);
   84     }
   85 
   86     ONVERBOSE(syslog(LOG_INFO, "Delegating child PID %d to init", child));
   87     exit(0);
   88   }
   89 
   90   /*
   91    * Actual child
   92    */
   93 
   94   /* Attach stdin to fd[1] */
   95   if (dup2(fd[1], 0) == -1) {
   96     syslog(LOG_ERR, "Director child: fatal: could not attach stdin to unix domain socket: %m");
   97     exit(1);
   98   }
   99 
  100   /* Attach stdout to fd[1] */
  101   if (dup2(fd[1], 1) == -1) {
  102     syslog(LOG_ERR, "Director child: fatal: could not attach stdout to unix domain socket: %m");
  103     exit(1);
  104   }
  105 
  106   /*
  107    * Restore default SIGPIPE disposition
  108    */
  109   void (*prev_handler)(int);
  110   prev_handler = signal(SIGPIPE, SIG_DFL);
  111   if (prev_handler == SIG_ERR)
  112     syslog(LOG_ERR, "Director child: signal() failed restoring default SIGPIPE disposition: %m");
  113 
  114   ONVERBOSE(syslog(LOG_DEBUG, "Invoking director: %s", argv[0]));
  115 
  116   /*
  117    * Invoke external director program
  118    */
  119 
  120   close_fds(2); /* release all file descriptors */
  121 
  122   execv(argv[0], argv);
  123 
  124   syslog(LOG_ERR, "Director child PID %d: fatal: execv(%s) failed: %m", getpid(), argv[0]);
  125   exit(1);
  126 }
  127 
  128 int director::spawn()
  129 {
  130   int result = -1;
  131   char **argv = 0;
  132   char *dir_str = safe_strdup(args);
  133 
  134   ONVERBOSE(syslog(LOG_DEBUG, "Parsing director: %s", args));
  135 
  136   /*
  137    * Parse director string into argv
  138    */
  139 
  140   const char *SEP = "\r\n\t ";
  141 
  142   char *prog_name = strtok(dir_str, SEP);
  143   if (!prog_name) {
  144     syslog(LOG_ERR, "Invalid null director!");
  145     goto clean;
  146   }
  147 
  148   {
  149     vector<char*> arg_list;
  150     arg_list.push(prog_name);
  151     
  152     for (;;) {
  153       char *arg = strtok(0, SEP);
  154       if (!arg)
  155     break;
  156       arg_list.push(arg);
  157     }
  158     
  159     argv = (char **) malloc((arg_list.get_size() + 1) * sizeof(char*));
  160     if (!argv)
  161       goto clean;
  162     
  163     {
  164       int i = 0;
  165       iterator<vector<char*>,char*> it(arg_list);
  166       for (it.start(); it.cont(); it.next(), ++i)
  167     argv[i] = it.get();
  168       argv[i] = 0;
  169     }
  170   }
  171 
  172   /*
  173    * Run external director
  174    */
  175   run(argv);
  176 
  177   result = 0;
  178 
  179 clean:
  180   free(dir_str);
  181 
  182   if (argv)
  183     free(argv);
  184 
  185   return result;
  186 }
  187 
  188 director::director(const char *str)
  189 {
  190   args = safe_strdup(str);
  191   fd[0] = -1;
  192   fd[1] = -1;
  193   child = -1;
  194   address_buf_size = 32;
  195   address.len = 0;
  196   address.addr = (char *) malloc(address_buf_size * sizeof(char *));
  197   if (!address.addr) {
  198     syslog(LOG_ERR, "director::director(): malloc(%d) failed", address_buf_size);
  199     exit(1);
  200   }
  201 }
  202 
  203 void director::show() const
  204 {
  205   syslog(LOG_INFO, "[%s]", args);
  206 }
  207 
  208 int director::get_addr(const char *protoname, 
  209     const struct sockaddr_in *cli_sa, 
  210     const struct sockaddr_in *local_cli_sa, 
  211     const struct ip_addr **addr, int *prt)
  212 {
  213   int fd0 = fd[0];
  214 
  215   if (fd0 == -1) {
  216     if (spawn())
  217       syslog(LOG_ERR, "director::get_addr(): spawn() failed");
  218 
  219     return -1;
  220   }
  221 
  222   int cli_src_port = htons(cli_sa->sin_port);
  223   int cli_loc_port = htons(local_cli_sa->sin_port);
  224 
  225   const int ADDR_STR_BUF_SZ = 128;
  226   char cli_src_addr[ADDR_STR_BUF_SZ];
  227   char cli_loc_addr[ADDR_STR_BUF_SZ];
  228 
  229   safe_strcpy(cli_src_addr, inet_ntoa(cli_sa->sin_addr), ADDR_STR_BUF_SZ);
  230   safe_strcpy(cli_loc_addr, inet_ntoa(local_cli_sa->sin_addr), ADDR_STR_BUF_SZ);
  231 
  232   /*
  233    * Write query
  234    */
  235 
  236   const int WR_BUF_SZ = 128;
  237   char wr_buf[WR_BUF_SZ];
  238 
  239   int len = snprintf(wr_buf, WR_BUF_SZ, "%s %s %d %s %d\n", protoname, cli_src_addr, cli_src_port, cli_loc_addr, cli_loc_port);
  240   if (len == -1) {
  241     syslog(LOG_ERR, "director::get_addr() failed due to snprintf() overflow");
  242     return -1;
  243   }
  244 
  245   int wr = write(fd0, wr_buf, len);
  246   if (wr != len) {
  247     if (wr == -1) {
  248       switch (errno) {
  249       case EBADF:
  250       case EINVAL:
  251       case EPIPE:
  252     syslog(LOG_ERR, "director::get_addr(): finishing child: can't write to external director: %m");
  253     close_sockets();
  254     kill_child();
  255     break;
  256       default:
  257     syslog(LOG_ERR, "director::get_addr(): skipping: can't write to external director: %m");
  258       }
  259 
  260       return -1;
  261     }
  262   }
  263 
  264   /*
  265    * Read response
  266    */
  267 
  268   const int RD_BUF_SZ = 128;
  269   char rd_buf[RD_BUF_SZ];
  270 
  271   int rd = read(fd0, rd_buf, RD_BUF_SZ);
  272   if (rd == -1) {
  273     switch (errno) {
  274       case EBADF:
  275       case EINVAL:
  276     syslog(LOG_ERR, "director::get_addr(): finishing child: can't read from external director: %m");
  277     close_sockets();
  278     kill_child();
  279     break;
  280     default:
  281     syslog(LOG_ERR, "director::get_addr(): skipping: can't read from external director: %m");
  282     }
  283 
  284     return -1;
  285   }
  286 
  287   if (rd == 0) {
  288     syslog(LOG_ERR, "director::get_addr(): can't read from external director: external director closed communication");
  289     close_sockets();
  290     kill_child();
  291 
  292     return -1;
  293   }
  294 
  295   /*
  296    * Parse response
  297    */
  298 
  299   const char *SEP = "\r\n\t ";
  300   char *response = strtok(rd_buf, SEP);
  301   if (!response) {
  302     syslog(LOG_ERR, "External director returned null response");
  303     return -1;
  304   }
  305   
  306   if (!strcmp(response, "reject")) {
  307     ONVERBOSE(syslog(LOG_INFO, "External director rejected source"));
  308     return -1;
  309   }
  310 
  311   if (strcmp(response, "forward")) {
  312     syslog(LOG_ERR, "External director returned invalid response: %s", response);
  313     return -1;
  314   }
  315 
  316   char *remote_host = strtok(0, SEP);
  317   if (!remote_host) {
  318     syslog(LOG_ERR, "External director returned null hostname");
  319     return -1;
  320   }
  321 
  322   char *remote_port = strtok(0, SEP);
  323   if (!remote_port) {
  324     syslog(LOG_ERR, "External director returned null port");
  325     return -1;
  326   }
  327 
  328   ONVERBOSE2(syslog(LOG_DEBUG, "External director forwarded to %s:%s", remote_host, remote_port));
  329 
  330   /*
  331    * Solve response
  332    */
  333 
  334   int rem_port = solve_portnumber(remote_port, protoname);
  335   if (rem_port == -1) {
  336     syslog(LOG_ERR, "Can't resolve port pointed by external director: %s", remote_port);
  337     return -1;
  338   }
  339 
  340   const int ADDR_BUF_SZ = 32;
  341   char addr_buf[ADDR_BUF_SZ];
  342   size_t addr_buf_len = ADDR_BUF_SZ;
  343 
  344   int result = solve_hostname_addr(addr_buf, &addr_buf_len, remote_host);
  345   if (result) {
  346     syslog(LOG_ERR, "Can't resolve hostname pointed by external director: %s", remote_host);
  347     return -1;
  348   }
  349 
  350   /*
  351    * Return address/port
  352    */
  353 
  354   if (addr_buf_len > address_buf_size) {
  355     syslog(LOG_ERR, "Insufficient space in local buffer for address (local_buffer_size=%d < address_length=%d)", address_buf_size, addr_buf_len);
  356     return -1;
  357   }
  358 
  359   /* Copy address */
  360   memcpy(address.addr, addr_buf, addr_buf_len);
  361   address.len = addr_buf_len;
  362 
  363   *addr = &address;
  364   *prt = rem_port;
  365 
  366   return 0;
  367 }
  368 
  369 /* Eof: dst_addr.cc */