home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / xinetd / xinetd.2.0.6 / udpint.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-22  |  6.4 KB  |  341 lines

  1. /*
  2.  * (c) Copyright 1992 by Panagiotis Tsirigotis
  3.  * All rights reserved.  The file named COPYRIGHT specifies the terms 
  4.  * and conditions for redistribution.
  5.  */
  6.  
  7. static char RCSid[] = "$Id: udpint.c,v 5.1 1992/11/01 00:01:21 panos Exp $" ;
  8.  
  9. #include <sys/types.h>
  10. #include <sys/socket.h>
  11. #include <netinet/in.h>
  12. #include <netdb.h>
  13. #include <sys/time.h>
  14. #include <syslog.h>
  15. #include <errno.h>
  16.  
  17. #include "access.h"
  18. #include "defs.h"
  19. #include "int.h"
  20. #include "config.h"
  21.  
  22. char *inet_ntoa() ;
  23.  
  24. void msg() ;
  25.  
  26. struct packet
  27. {
  28.     struct sockaddr_in from ;
  29.     char *data ;
  30.     int size ;
  31. } ;
  32.  
  33. typedef struct packet packet_s ;
  34.  
  35.  
  36. struct idgram_private
  37. {
  38.     unsigned received_packets ;
  39. } ;
  40.  
  41. #define IDP( p )                    ((struct idgram_private *)(p))
  42.  
  43.  
  44. static struct idgram_private idgram ;
  45.  
  46. void di_mux() ;
  47. void di_exit() ;
  48.  
  49. static struct intercept_ops idgram_ops =
  50.     {
  51.         di_mux,
  52.         di_exit
  53.     } ;
  54.  
  55.  
  56. static struct intercept dgram_intercept_state ;
  57.  
  58.  
  59. struct intercept *di_init( serp )
  60.     struct server *serp ;
  61. {
  62.     register struct intercept *ip = &dgram_intercept_state ;
  63.     
  64.     ip->socket_type = SOCK_DGRAM ;
  65.     ip->priv = &idgram ;
  66.     ip->ops = &idgram_ops ;
  67.     int_init( ip, serp ) ;
  68.     return( ip ) ;
  69. }
  70.  
  71.  
  72. PRIVATE void di_exit()
  73. {
  74.     register struct intercept *ip = &dgram_intercept_state ;
  75.     void drain() ;
  76.  
  77.     if ( IDP( ip->priv )->received_packets == 0 )
  78.         drain( INT_REMOTE( ip ) ) ;
  79.     int_exit( ip ) ;
  80. }
  81.  
  82.  
  83. /*
  84.  * Returns only if there is an I/O error while communicating with the server
  85.  */
  86. PRIVATE void di_mux()
  87. {
  88.     register struct intercept *ip = &dgram_intercept_state ;
  89.     fd_set socket_mask ;
  90.     int mask_max ;
  91.     void udp_remote_to_local() ;
  92.     status_e udp_local_to_remote() ;
  93.  
  94.     FD_ZERO( &socket_mask ) ;
  95.     FD_SET( INT_REMOTE( ip ), &socket_mask ) ;
  96.     mask_max = INT_REMOTE( ip ) ;
  97.  
  98.     for ( ;; )
  99.     {
  100.         register unsigned u ;
  101.         channel_s *chp ;
  102.         fd_set read_mask ;
  103.         int n_ready ;
  104.  
  105.         read_mask = socket_mask ;
  106.         n_ready = int_select( mask_max+1, &read_mask ) ;
  107.  
  108.         if ( n_ready == -1 )
  109.             return ;
  110.         
  111.         if ( FD_ISSET( INT_REMOTE( ip ), &read_mask ) )
  112.         {
  113.             udp_remote_to_local( ip, &chp ) ;
  114.             if ( chp != NULL )
  115.             {
  116.                 FD_SET( chp->local_socket, &socket_mask ) ;
  117.                 if ( chp->local_socket > mask_max )
  118.                     mask_max = chp->local_socket ;
  119.             }
  120.             if ( --n_ready == 0 )
  121.                 continue ;
  122.         }
  123.  
  124.         for ( u = 0 ; u < pset_count( INT_CONNECTIONS( ip ) ) ; u++ )
  125.         {
  126.             chp = CHP( pset_pointer( INT_CONNECTIONS( ip ), u ) ) ;
  127.  
  128.             if ( FD_ISSET( chp->local_socket, &read_mask ) )
  129.             {
  130.                 if ( udp_local_to_remote( chp ) == FAILED )
  131.                     return ;
  132.                 if ( --n_ready == 0 )
  133.                     break ;
  134.             }
  135.         }
  136.     }
  137. }
  138.  
  139.  
  140. /*
  141.  * Read data from the remote socket and send it to the appropriate local 
  142.  * socket.
  143.  * If this is a new connection, insert it in the connection table and
  144.  * place its handle in *chpp.
  145.  */
  146. PRIVATE void udp_remote_to_local( ip, chpp )
  147.     struct intercept *ip ;
  148.     channel_s **chpp ;
  149. {
  150.     char buf[ DATAGRAM_SIZE ] ;
  151.     packet_s packet ;
  152.     channel_s *chp ;
  153.     bool_int addr_checked ;
  154.     void send_data() ;
  155.     status_e get_incoming_packet() ;
  156.     void log_failure() ;
  157.     void log_success() ;
  158.  
  159.     *chpp = NULL ;
  160.  
  161.     packet.data = buf ;
  162.     packet.size = sizeof( buf ) ;
  163.     if ( get_incoming_packet( ip, &packet ) == FAILED )
  164.         return ;
  165.  
  166.     chp = int_lookupconn( ip, &packet.from, &addr_checked ) ;
  167.     if ( chp == NULL )
  168.     {
  169.         struct server *serp = INT_SERVER( ip ) ;
  170.         connection_s *cop = SERVER_CONNECTION( serp ) ;
  171.  
  172.         if ( ( chp = int_newconn( ip, &packet.from, INT_REMOTE( ip ) ) ) == NULL )
  173.             return ;
  174.  
  175.         conn_fill( cop, &packet.from ) ;        /* for logging */
  176.  
  177.         if ( INTERCEPT( ip ) )
  178.         {
  179.             mask_t check_mask ;
  180.             access_e result ;
  181.             struct service *sp = SERVER_SERVICE( serp ) ;
  182.  
  183.             M_OR( check_mask, MASK( CF_ADDRESS ), MASK( CF_TIME ) ) ;
  184.             result = access_control( sp, cop, &check_mask ) ;
  185.  
  186.             if ( result != AC_OK )
  187.             {
  188.                 log_failure( result, sp, cop ) ;
  189.                 chp->state = BAD_CHANNEL ;
  190.                 return ;
  191.             }
  192.         }
  193.         
  194.         /*
  195.          * Since we don't distinguish ports, there is no point to log
  196.          * another successful attempt from the same address
  197.          */
  198.         if ( ! addr_checked )
  199.             log_success( serp ) ;
  200.             
  201.         *chpp = chp ;
  202.     }
  203.     else if ( chp->state == BAD_CHANNEL )
  204.         return ;
  205.     
  206. #ifdef DEBUG_UDPINT
  207.     if ( debug.on )
  208.         msg( LOG_DEBUG, "udp_remote_to_local",
  209.                     "sending %d bytes to server on port %d",
  210.                             packet.size, ntohs( INT_LOCALADDR( ip )->sin_port ) ) ;
  211. #endif
  212.  
  213.     send_data( chp->local_socket, packet.data, packet.size, SOCKADDRIN_NULL ) ;
  214. }
  215.  
  216.  
  217. /*
  218.  * Send the data in buf to destination addr using the socket sd.
  219.  * If addr is NULL, use the default socket destination
  220.  */
  221. PRIVATE void send_data( sd, buf, len, addr )
  222.     int sd ;
  223.     char *buf ;
  224.     int len ;
  225.     struct sockaddr_in *addr ;
  226. {
  227.     char *p ;
  228.     int left ;
  229.     int cc ;
  230.     char *func = "send_data" ;
  231.  
  232.     for ( p = buf, left = len ; left > 0 ; left -= cc, p+= cc )
  233.     {
  234.         if ( addr == SOCKADDRIN_NULL )
  235.             cc = send( sd, p, left, 0 ) ;
  236.         else
  237.             cc = sendto( sd, p, left, 0, SA( addr ), sizeof( *addr ) ) ;
  238.  
  239.         if ( cc == -1 )
  240.             if ( errno == EINTR )
  241.             {
  242.                 cc = 0 ;
  243.                 continue ;
  244.             }
  245.             else
  246.             {
  247.                 msg( LOG_ERR, func, "%s: %m", addr ? "sendto" : "send" ) ;
  248.                 return ;
  249.             }
  250.     }
  251. }
  252.  
  253.  
  254. PRIVATE status_e get_incoming_packet( ip, pp )
  255.     struct intercept *ip ;
  256.     packet_s *pp ;
  257. {
  258.     int from_len ;
  259.     char *func = "get_incoming_packet" ;
  260.  
  261.     for ( ;; )
  262.     {
  263.         int cc ;
  264.  
  265.         from_len = sizeof( pp->from ) ;
  266.         cc = recvfrom( INT_REMOTE( ip ), pp->data, pp->size,
  267.                                                 0, SA( &pp->from ), &from_len ) ;
  268.         if ( cc == -1 )
  269.         {
  270.             if ( errno != EINTR )
  271.             {
  272.                 msg( LOG_ERR, func, "recvfrom error: %m" ) ;
  273.                 return( FAILED ) ;
  274.             }
  275.         }
  276.         else if ( cc == 0 )
  277.             return( FAILED ) ;
  278.         else
  279.         {
  280.             pp->size = cc ;
  281.             IDP( ip->priv )->received_packets++ ;
  282.             break ;
  283.         }
  284.     }
  285.  
  286.     if ( from_len == 0 )
  287.     {
  288.         msg( LOG_ERR, func, "0 length address" ) ;
  289.         return( FAILED ) ;
  290.     }
  291.     
  292. #ifdef DEBUG_UDPINT
  293.     if ( debug.on )
  294.         msg( LOG_DEBUG, func, "Received %d bytes from address: %s,%d",
  295.             pp->size,
  296.                 inet_ntoa( pp->from.sin_addr ), ntohs( pp->from.sin_port ) ) ;
  297. #endif
  298.  
  299.     return( OK ) ;
  300. }
  301.  
  302.  
  303.  
  304. PRIVATE status_e udp_local_to_remote( chp )
  305.     channel_s *chp ;
  306. {
  307.     char buf[ DATAGRAM_SIZE ] ;
  308.     int cc ;
  309.     char *func = "udp_local_to_remote" ;
  310.  
  311.     for ( ;; )
  312.     {
  313.         cc = recv( chp->local_socket, buf, sizeof( buf ), 0 ) ;
  314.     
  315.         if ( cc == -1 )
  316.         {
  317.             if ( errno != EINTR ) 
  318.             {
  319.                 msg( LOG_ERR, func, "recv from daemon: %m" ) ;
  320.                 return( FAILED ) ;
  321.             }
  322.         }
  323.         else if ( cc == 0 )
  324.             return( FAILED ) ;
  325.         else
  326.             break ;
  327.     }
  328.     
  329. #ifdef DEBUG_UDPINT
  330.     if ( debug.on )
  331.         msg( LOG_DEBUG, func, "sending %d bytes to address %s,%d",
  332.             cc, inet_ntoa( chp->from.sin_addr ), ntohs( chp->from.sin_port ) ) ;
  333. #endif
  334.  
  335.     send_data( chp->remote_socket, buf, cc, &chp->from ) ;
  336.     return( OK ) ;
  337. }
  338.  
  339.  
  340.  
  341.