"Fossies" - the Fresh Open Source Software Archive

Member "portfwd-0.29/src/host_map.cc" (8 May 2002, 10443 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   host_map.cc
    3 
    4   $Id: host_map.cc,v 1.15 2002/05/08 03:50:03 evertonm Exp $
    5  */
    6 
    7 #include <string.h>
    8 #include <syslog.h>
    9 #include <errno.h>
   10 #include <sys/time.h>
   11 #include <sys/types.h>
   12 #include <unistd.h>
   13 #include <sys/socket.h>
   14 #include <netinet/in.h>
   15 #include <arpa/inet.h>
   16 #include "portfwd.h"
   17 #include "host_map.hpp"
   18 #include "solve.h"
   19 
   20 void host_map::show() const
   21 {
   22   iterator<vector<from_addr*>,from_addr*> it(*src_list);
   23   it.start();
   24   if (it.cont()) {
   25     it.get()->show();
   26     it.next();
   27   }
   28   for (; it.cont(); it.next()) {
   29     syslog(LOG_INFO, ", ");
   30     it.get()->show();
   31   }
   32 
   33   syslog(LOG_INFO, " => ");
   34 
   35   iterator<vector<to_addr*>,to_addr*> it2(*dst_list);
   36   it2.start();
   37   if (it2.cont()) {
   38     it2.get()->show();
   39     it2.next();
   40   }
   41   for (; it2.cont(); it2.next()) {
   42     syslog(LOG_INFO, ", ");
   43     it2.get()->show();
   44   }
   45 }
   46 
   47 static int make_tcp_outgoing_socket(const struct ip_addr *src, const struct sockaddr_in *cli_sa, unsigned int cli_sa_len)
   48 {
   49   /*
   50    * Open socket for remote host
   51    */
   52   int rsd = socket(PF_INET, SOCK_STREAM, get_protonumber(P_TCP));
   53   if (rsd == -1) {
   54     syslog(LOG_ERR, "make_tcp_outgoing_socket: Can't create TCP socket: %m");
   55     return -1;
   56   }
   57   DEBUGFD(syslog(LOG_DEBUG, "make_tcp_outgoing_socket: socket open: FD %d", rsd));
   58 
   59   /*
   60    * Bind to user-supplied source address
   61    *
   62    * NOTE: This overrides transparent proxying.
   63    */
   64   if (src) {
   65 
   66 #ifdef HAVE_MSG_PROXY
   67     if (transparent_proxy)
   68       syslog(LOG_WARNING, "User-supplied source-address overriding transparent proxying for TCP socket");
   69 #endif
   70 
   71     struct sockaddr_in local_sa;  
   72     unsigned int local_sa_len = sizeof(local_sa);
   73     local_sa.sin_family = PF_INET;
   74     local_sa.sin_port   = htons(0);
   75     local_sa.sin_addr.s_addr = *((unsigned int *) src->addr);
   76 
   77     ONVERBOSE(syslog(LOG_INFO, "make_tcp_outgoing_socket: Binding to local source address: %s:%d", inet_ntoa(local_sa.sin_addr), htons(local_sa.sin_port)));
   78 
   79     /*
   80      * Bind local socket to user-supplied source address
   81      */
   82     if (bind(rsd, (struct sockaddr *) &local_sa, local_sa_len)) {
   83       syslog(LOG_ERR, "make_tcp_outgoing_socket: Can't bind TCP socket to local source address: %s:%d: %m", inet_ntoa(local_sa.sin_addr), ntohs(local_sa.sin_port));
   84       socket_close(rsd);
   85       return -1;
   86     }
   87 
   88   }
   89 
   90 #ifndef HAVE_MSG_PROXY
   91 ;
   92 #else  
   93 
   94   else 
   95 
   96     /*
   97      * Perform transparent proxy
   98      *
   99      * NOTE: User-supplied source address overrides transparent proxying.
  100      */
  101     if (transparent_proxy) {
  102       
  103       struct sockaddr_in local_sa;  
  104       unsigned int local_sa_len = sizeof(local_sa);
  105       
  106       /*
  107        * Copy client address
  108        */
  109       memcpy(&local_sa, cli_sa, cli_sa_len);
  110       local_sa.sin_port = htons(0);
  111       
  112       ONVERBOSE(syslog(LOG_INFO, "make_tcp_outgoing_socket: Transparent proxy - Binding to local address: %s:%d", inet_ntoa(local_sa.sin_addr), htons(local_sa.sin_port)));
  113       
  114       /*
  115        * Bind local socket to client address
  116        */
  117       if (bind(rsd, (struct sockaddr *) &local_sa, local_sa_len)) {
  118     syslog(LOG_ERR, "make_tcp_outgoing_socket: Can't bind TCP socket to client address: %m: %s:%d", inet_ntoa(local_sa.sin_addr), ntohs(local_sa.sin_port));
  119     socket_close(rsd);
  120     return -1;
  121       }
  122       
  123     } /* else if (transparent_proxy) */
  124 #endif /* HAVE_MSG_PROXY */
  125 
  126   return rsd;
  127 }
  128 
  129 /*
  130  * Returns -1 on failure; 0 on success.
  131  */
  132 int host_map::pipe(int *sd, const struct sockaddr_in *cli_sa, 
  133            unsigned int cli_sa_len, const struct ip_addr *ip, 
  134            int port, const struct ip_addr *src, 
  135            const struct sockaddr_in *local_cli_sa)
  136 {
  137   const int tmp_len = 32;
  138   char tmp[tmp_len];
  139 
  140   /*
  141    * Scan all destination addresses
  142    */
  143 
  144   /* Save starting address */
  145   int last_dst_index = next_dst_index;
  146 
  147   for (;;) {
  148 
  149     safe_strcpy(tmp, addrtostr(ip), tmp_len); 
  150 
  151     /*
  152      * Get current destination address
  153      */
  154     to_addr *dst_addr = dst_list->get_at(next_dst_index);
  155 
  156     const struct ip_addr *dst_ip;
  157     int dst_port;
  158     if (dst_addr->get_addr(get_protoname(P_TCP), cli_sa, local_cli_sa, &dst_ip, &dst_port)) {
  159       ONVERBOSE(syslog(LOG_INFO, "TCP pipe: Could not load next destination address for: %s:%d", tmp, port));
  160       return -1;
  161     }
  162     
  163     ONVERBOSE2(syslog(LOG_DEBUG, "TCP pipe: trying: %s:%d => %s:%d", tmp, port, addrtostr(dst_ip), dst_port));
  164 
  165     /*
  166      * Create outgoing socket
  167      */
  168     int rsd = make_tcp_outgoing_socket(src, cli_sa, cli_sa_len);
  169     if (rsd < 0) {
  170       syslog(LOG_ERR, "TCP pipe: Could not create outgoing socket");
  171       return -1;
  172     }
  173     
  174     /*
  175      * Put current destination address in a "sockaddr_in" struct
  176      */
  177 
  178     struct sockaddr_in sa;
  179     sa.sin_family      = PF_INET;
  180     sa.sin_port        = htons(dst_port);
  181     sa.sin_addr.s_addr = *((unsigned int *) dst_ip->addr);
  182     memset((char *) sa.sin_zero, 0, sizeof(sa.sin_zero));
  183 
  184     /*
  185      * Try current destination address
  186      */
  187     if (connect(rsd, (struct sockaddr *) &sa, sizeof(sa))) {
  188       ONVERBOSE(syslog(LOG_WARNING, "TCP pipe: Can't connect %s:%d to %s:%d: %m", tmp, port, inet_ntoa(sa.sin_addr), dst_port));
  189 
  190       /*
  191        * Close the socket, as it can't be reused
  192        */
  193       close(rsd); 
  194 
  195       /*
  196        * Switch to next address
  197        */
  198       next_dst_index = (next_dst_index + 1) % dst_list->get_size();
  199 
  200       /*
  201        * If all addresses were tried without success, give up
  202        */
  203       if (next_dst_index == last_dst_index) {
  204     syslog(LOG_ERR, "TCP pipe: Can't forward incoming connection from %s:%d to any destination", tmp, port);
  205     return -1;
  206       }
  207 
  208       continue;
  209     }
  210 
  211     /*
  212      * Here we have a good outgoing connection on "rsd"
  213      */
  214 
  215     /*
  216      * Return outgoing socket
  217      */
  218     *sd = rsd;
  219 
  220     ONVERBOSE2(syslog(LOG_DEBUG, "TCP pipe: connected: %s:%d => %s:%d", tmp, port, addrtostr(dst_ip), dst_port));
  221     
  222     break;
  223   }
  224 
  225   /*
  226    * Switch to next destination address
  227    * (left ready for the next incoming connection)
  228    */
  229   next_dst_index = (next_dst_index + 1) % dst_list->get_size();
  230   
  231   return 0;
  232 }
  233 
  234 /*
  235  * Returns -1 on failure; file descriptor on success.
  236  */
  237 int host_map::tcp_match(const struct ip_addr *ip, int port) const
  238 {
  239   iterator<vector<from_addr*>,from_addr*> it(*src_list);
  240   for (it.start(); it.cont(); it.next()) {
  241     if (it.get()->match(ip, port))
  242       return -1;
  243   }
  244 
  245   return 0;
  246 }
  247 
  248 void host_map::udp_forward(const struct ip_addr *source, 
  249                const struct sockaddr_in *cli_sa, 
  250                const struct sockaddr_in *local_cli_sa,
  251                const struct ip_addr *ip, int port, 
  252                const char *buf, int buf_len)
  253 {
  254   /*
  255    * Get next destination address
  256    */
  257   to_addr *dst_addr = dst_list->get_at(next_dst_index);
  258 
  259   const struct ip_addr *dst_ip;
  260   int dst_port;
  261   if (dst_addr->get_addr(get_protoname(P_UDP), cli_sa, local_cli_sa, &dst_ip, &dst_port)) {
  262 
  263     const int tmp_len = 32;
  264     char tmp[tmp_len];
  265     safe_strcpy(tmp, addrtostr(ip), tmp_len); 
  266 
  267     ONVERBOSE(syslog(LOG_INFO, "host_map::udp_forward(): Could not load next destination address for: %s:%d", tmp, port));
  268 
  269     return;
  270   }
  271 
  272   {
  273     const int tmp_len = 32;
  274     char tmp[tmp_len];
  275 
  276     ONVERBOSE(safe_strcpy(tmp, addrtostr(ip), tmp_len)); 
  277     ONVERBOSE(syslog(LOG_DEBUG, "host_map::udp_forward(): %s:%d => %s:%d", tmp, port, addrtostr(dst_ip), dst_port));
  278   }
  279 
  280   int rsd = socket(PF_INET, SOCK_DGRAM, get_protonumber(P_UDP));
  281   if (rsd == -1) {
  282     syslog(LOG_ERR, "host_map::udp_forward(): Can't create UDP socket: %m");
  283     return;
  284   }
  285 
  286   /* 
  287    * Allow outgoing broadcast datagrams
  288    */
  289 #ifndef NO_SO_BROADCAST
  290   {
  291     int one = 1;
  292 
  293     ONVERBOSE2(syslog(LOG_DEBUG, "Setting SO_BROADCAST for outgoing UDP socket"));
  294 
  295     if (setsockopt(rsd, SOL_SOCKET, SO_BROADCAST, (char *) &one, sizeof(one)))
  296       syslog(LOG_ERR, "host_map::udp_forward(): Can't allow broadcast datagrams for outgoing UDP socket: setsockopt(SO_BROADCAST) failed: %m");
  297   }
  298 #endif /* NO_SO_BROADCAST */
  299 
  300   struct sockaddr_in local_sa;  
  301 
  302   /*
  303    * Bind to user-supplied source address
  304    *
  305    * NOTE: This overrides transparent proxying.
  306    */
  307   if (source) {
  308 
  309 #ifdef HAVE_MSG_PROXY
  310     if (transparent_proxy)
  311       syslog(LOG_WARNING, "User-supplied source-address overriding transparent proxying for UDP socket");
  312 #endif
  313 
  314     local_sa.sin_family = PF_INET;
  315     local_sa.sin_port   = htons(0);
  316     local_sa.sin_addr.s_addr = *((unsigned int *) source->addr);
  317 
  318     ONVERBOSE2(syslog(LOG_ERR, "host_map::udp_forward: \"Binding\" to local source address: %s:%d", inet_ntoa(local_sa.sin_addr), ntohs(local_sa.sin_port)));
  319     
  320   }
  321 
  322 #ifndef HAVE_MSG_PROXY
  323 ;
  324 #else
  325 
  326   else
  327    
  328     /*
  329      * Perform transparent proxy
  330      *
  331      * NOTE: User-supplied source address overrides transparent proxying.
  332      */
  333     if (transparent_proxy) {
  334 
  335       unsigned int local_sa_len = sizeof(local_sa);
  336 
  337       /*
  338        * Copy client address
  339        */
  340       memcpy(&local_sa, cli_sa, local_sa_len);
  341       
  342       ONVERBOSE2(syslog(LOG_ERR, "host_map::udp_forward: Transparent proxy - \"Binding\" to local address: %s:%d", inet_ntoa(local_sa.sin_addr), ntohs(local_sa.sin_port)));
  343       
  344     } /* else if (transparent_proxy) */
  345 
  346 #endif /* HAVE_MSG_PROXY */
  347   
  348   /*
  349    * Destination address
  350    */
  351   struct sockaddr_in sa;
  352   sa.sin_family      = PF_INET;
  353   sa.sin_port        = htons(dst_port);
  354   sa.sin_addr.s_addr = *((unsigned int *) dst_ip->addr);
  355   memset((char *) sa.sin_zero, 0, sizeof(sa.sin_zero));
  356 
  357 #ifdef HAVE_MSG_PROXY  
  358   if (source || transparent_proxy) 
  359 #else
  360   if (source) 
  361 #endif
  362     memcpy((char *) sa.sin_zero, &local_sa, 8);
  363   
  364 #ifdef HAVE_MSG_PROXY
  365   int wr = sendto(rsd, buf, buf_len, \
  366           ((source || transparent_proxy) ? MSG_PROXY : 0), \
  367           (struct sockaddr *) &sa, sizeof(sa));
  368 #else
  369   int wr = sendto(rsd, buf, buf_len, 0, \
  370           (struct sockaddr *) &sa, sizeof(sa));
  371 #endif
  372 
  373   if (wr < 0)
  374     syslog(LOG_ERR, "forward: sendto() failed: %m");
  375   else if (wr < buf_len)
  376     syslog(LOG_ERR, "forward: Partial write on sendto: %m");
  377 
  378   if (close(rsd))
  379     syslog(LOG_WARNING, "forward: close() on socket failed: %m");
  380 
  381   /*
  382    * Switch to next address
  383    */
  384   next_dst_index = (next_dst_index + 1) % dst_list->get_size();
  385 }
  386 
  387 /*
  388  * -1 = match; 0 = miss.
  389  */
  390 int host_map::udp_match(const struct ip_addr *ip, int port, const char *buf, int buf_len) const
  391 {
  392   iterator<vector<from_addr*>,from_addr*> it(*src_list);
  393   for (it.start(); it.cont(); it.next())
  394     if (it.get()->match(ip, port))
  395       return -1;
  396 
  397   return 0;
  398 }
  399 
  400 /* Eof: host_map.cc */