2 * (c) Copyright 1992 by Panagiotis Tsirigotis
3 * (c) Sections Copyright 1998-2001 by Rob Braun
4 * All rights reserved. The file named COPYRIGHT specifies the terms
5 * and conditions for redistribution.
10 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #include <arpa/inet.h>
18 #ifdef HAVE_SYS_SELECT_H
19 #include <sys/select.h>
23 #include "intcommon.h"
25 #include "connection.h"
32 * Datagrams greater than this will be truncated
34 #define MAX_DATAGRAM_SIZE ( 32 * 1024 )
38 union xsockaddr from ;
43 typedef struct packet packet_s ;
48 unsigned received_packets ;
51 #define IDP( p ) ((struct idgram_private *)(p))
54 static struct idgram_private idgram ;
56 static void di_mux(void) ;
57 static void udp_remote_to_local( struct intercept_s *ip, channel_s **chpp );
58 static status_e udp_local_to_remote( channel_s *chp );
59 static void send_data( int sd, char *buf, int len, union xsockaddr *addr );
60 static status_e get_incoming_packet( struct intercept_s *ip, packet_s *pp );
62 static const struct intercept_ops idgram_ops =
69 static struct intercept_s dgram_intercept_state ;
72 struct intercept_s *di_init( struct server *serp )
74 struct intercept_s *ip = &dgram_intercept_state ;
76 ip->int_socket_type = SOCK_DGRAM ;
77 ip->int_priv = (void *) &idgram ;
78 ip->int_ops = &idgram_ops ;
79 int_init( ip, serp ) ;
86 struct intercept_s *ip = &dgram_intercept_state ;
88 if ( IDP( ip->int_priv )->received_packets == 0 )
89 drain( INT_REMOTE( ip ) ) ;
95 * Returns only if there is an I/O error while communicating with the server
97 static void di_mux(void)
99 struct intercept_s *ip = &dgram_intercept_state ;
103 FD_ZERO( &socket_mask ) ;
104 FD_SET( INT_REMOTE( ip ), &socket_mask ) ;
105 mask_max = INT_REMOTE( ip ) ;
114 read_mask = socket_mask ;
115 n_ready = int_select( mask_max+1, &read_mask ) ;
120 if ( FD_ISSET( INT_REMOTE( ip ), &read_mask ) )
122 udp_remote_to_local( ip, &chp ) ;
125 FD_SET( chp->ch_local_socket, &socket_mask ) ;
126 if ( chp->ch_local_socket > mask_max )
127 mask_max = chp->ch_local_socket ;
129 if ( --n_ready == 0 )
133 for ( u = 0 ; u < pset_count( INT_CONNECTIONS( ip ) ) ; u++ )
135 chp = CHP( pset_pointer( INT_CONNECTIONS( ip ), u ) ) ;
137 if ( FD_ISSET( chp->ch_local_socket, &read_mask ) )
139 if ( udp_local_to_remote( chp ) == FAILED )
141 if ( --n_ready == 0 )
150 * Read data from the remote socket and send it to the appropriate local
152 * If this is a new connection, insert it in the connection table and
153 * place its handle in *chpp.
155 static void udp_remote_to_local( struct intercept_s *ip, channel_s **chpp )
157 char buf[ MAX_DATAGRAM_SIZE ] ;
160 bool_int addr_checked ;
162 *chpp = CHANNEL_NULL ;
165 packet.size = sizeof( buf ) ;
166 if ( get_incoming_packet( ip, &packet ) == FAILED )
169 chp = int_lookupconn( ip, &packet.from, &addr_checked ) ;
170 if ( chp == CHANNEL_NULL )
172 struct server *serp = INT_SERVER( ip ) ;
173 struct service *sp = SERVER_SERVICE( serp ) ;
174 connection_s *cop = SERVER_CONNECTION( serp ) ;
176 if ( ( chp = int_newconn( ip, &packet.from, INT_REMOTE( ip ) ) ) == NULL )
179 CONN_SETADDR( cop, &packet.from ) ; /* for logging */
181 if ( INTERCEPT( ip ) )
186 M_OR( check_mask, XMASK( CF_ADDRESS ), XMASK( CF_TIME ) ) ;
187 result = access_control( sp, cop, &check_mask ) ;
189 if ( result != AC_OK )
191 svc_log_failure( sp, cop, result ) ;
192 chp->ch_state = BAD_CHANNEL ;
198 * Since we don't distinguish ports, there is no point to log
199 * another successful attempt from the same address
201 if ( ! addr_checked )
202 svc_log_success( sp, cop, SERVER_PID( serp ) ) ;
206 else if ( chp->ch_state == BAD_CHANNEL )
211 msg( LOG_DEBUG, "udp_remote_to_local",
212 "sending %d bytes to server on port %d",
213 packet.size, ntohs( INT_LOCALADDR( ip )->sin_port ) ) ;
216 send_data( chp->ch_local_socket,
217 packet.data, packet.size, NULL ) ;
222 * Send the data in buf to destination addr using the socket sd.
223 * If addr is NULL, use the default socket destination
225 static void send_data( int sd, char *buf, int len, union xsockaddr *addr )
230 const char *func = "send_data" ;
232 for ( p = buf, left = len ; left > 0 ; left -= cc, p+= cc )
235 cc = send( sd, p, left, 0 ) ;
237 cc = sendto( sd, p, left, 0, SA( addr ), sizeof( *addr ) ) ;
240 if ( errno == EINTR )
247 msg( LOG_ERR, func, "%s: %m", addr ? "sendto" : "send" ) ;
255 static status_e get_incoming_packet( struct intercept_s *ip, packet_s *pp )
257 socklen_t from_len = 0;
258 const char *func = "get_incoming_packet" ;
260 if( SC_IPV4( SVC_CONF( SERVER_SERVICE( INT_SERVER( ip ) ) ) ) )
261 from_len = sizeof( struct sockaddr_in );
262 if( SC_IPV6( SVC_CONF( SERVER_SERVICE( INT_SERVER( ip ) ) ) ) )
263 from_len = sizeof( struct sockaddr_in6 );
269 from_len = sizeof( pp->from ) ;
270 cc = recvfrom( INT_REMOTE( ip ), pp->data, pp->size,
271 0, SA( &pp->from ), &from_len ) ;
274 if ( errno != EINTR )
276 msg( LOG_ERR, func, "recvfrom error: %m" ) ;
285 IDP( ip->int_priv )->received_packets++ ;
292 msg( LOG_ERR, func, "incoming packet had 0 length address" ) ;
298 msg( LOG_DEBUG, func, "Received %d bytes from address: %s,%d",
299 pp->size, xaddrname( &pp->from ), ntohs( xaddrport(&pp->from) ) );
306 static status_e udp_local_to_remote( channel_s *chp )
308 char buf[ MAX_DATAGRAM_SIZE ] ;
310 const char *func = "udp_local_to_remote" ;
314 cc = recv( chp->ch_local_socket, buf, sizeof( buf ), 0 ) ;
318 if ( errno != EINTR )
320 msg( LOG_ERR, func, "recv from daemon: %m" ) ;
332 msg( LOG_DEBUG, func, "sending %d bytes to address %s,%d",
333 cc, xaddrname( &chp->ch_from ), ntohs( xaddrport(&chp->ch_from) ) ) ;
336 send_data( chp->ch_remote_socket, buf, cc, &chp->ch_from ) ;