fixes init script for non ipv6 enabled systems #472755
[packages/xinetd.git] / xinetd / tcpint.c
1 /*
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.
6  */
7
8
9 #include "config.h"
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <sys/time.h>
13 #include <syslog.h>
14 #include <signal.h>
15 #include <errno.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19
20 #ifdef HAVE_SYS_SELECT_H
21 #include <sys/select.h>
22 #endif
23
24 #include "tcpint.h"
25 #include "intcommon.h"
26 #include "msg.h"
27 #include "log.h"
28 #include "xconfig.h"
29 #include "sconf.h"
30
31 typedef enum { S_OK, S_SERVER_ERR, S_CLIENT_ERR } stream_status_e ;
32
33 struct istream_private
34 {
35    unsigned accepted_connections ;
36 } ;
37
38 #define SIP( p )                  ((struct istream_private *)(p))
39
40 static struct istream_private istream ;
41 static struct intercept_s stream_intercept_state ;
42 static void si_mux(void) ;
43
44
45 static struct intercept_ops istream_ops =
46 {
47       si_mux,
48       si_exit
49 } ;
50
51
52
53 struct intercept_s *si_init( struct server *serp )
54 {
55    struct intercept_s *ip = &stream_intercept_state ;
56
57    ip->int_socket_type = SOCK_STREAM ;
58    ip->int_priv = (void *) &istream ;
59    ip->int_ops = &istream_ops ;
60    int_init( ip, serp ) ;
61    if ( signal( SIGPIPE, SIG_IGN ) == SIG_ERR )
62       int_fail( ip, "signal" ) ;
63    return( ip ) ;
64 }
65
66 static status_e handle_io( psi_h iter, channel_s *chp, fd_set *maskp, stream_status_e (*iofunc)() );
67 static stream_status_e tcp_local_to_remote( channel_s *chp );
68 static stream_status_e tcp_remote_to_local( channel_s *chp );
69 static void connection_request( struct intercept_s *ip, channel_s **chpp );
70
71 /* Unfortunatly, this can't be private... */
72 void si_exit(void)
73 {
74    struct intercept_s *ip = &stream_intercept_state ;
75    
76    if ( SIP( ip->int_priv )->accepted_connections == 0 )
77       (void) accept( INT_REMOTE( ip ), SA( NULL ), NULL ) ;
78    int_exit( ip ) ;
79 }
80
81
82 static void si_mux(void)
83 {
84    struct intercept_s   *ip = &stream_intercept_state ;
85    fd_set                     socket_mask ;
86    int                        mask_max ;
87    psi_h                      iter ;
88    const char                *func = "si_mux" ;
89
90    FD_ZERO( &socket_mask ) ;
91    FD_SET( INT_REMOTE( ip ), &socket_mask ) ;
92    mask_max = INT_REMOTE( ip ) ;
93
94    iter = psi_create( INT_CONNECTIONS( ip ) ) ;
95    if ( iter == NULL )
96    {
97       msg( LOG_ERR, func, ES_NOMEM ) ;
98       return ;
99    }
100
101    for ( ;; )
102    {
103       channel_s *chp ;
104       fd_set read_mask ;
105       int n_ready ;
106
107       read_mask = socket_mask ;
108       n_ready = int_select( mask_max+1, &read_mask ) ;
109
110       if ( n_ready == -1 )
111          return ;
112       
113       if ( FD_ISSET( INT_REMOTE( ip ), &read_mask ) )
114       {
115          connection_request( ip, &chp ) ;
116          if ( chp != NULL )
117          {
118             FD_SET( chp->ch_local_socket, &socket_mask ) ;
119             if ( chp->ch_local_socket > mask_max )
120                mask_max = chp->ch_local_socket ;
121             FD_SET( chp->ch_remote_socket, &socket_mask ) ;
122             if ( chp->ch_remote_socket > mask_max )
123                mask_max = chp->ch_remote_socket ;
124          }
125          if ( --n_ready == 0 )
126             continue ;
127       }
128
129       for ( chp = CHP( psi_start(iter) ) ; chp ; chp = CHP( psi_next(iter) ) )
130       {
131          if ( FD_ISSET( chp->ch_local_socket, &read_mask ) )
132          {
133 #ifdef DEBUG_TCPINT
134             if ( debug.on )
135                msg( LOG_DEBUG, func, "Input available on local socket %d", 
136                                                          chp->ch_local_socket ) ;
137 #endif
138             if ( handle_io( iter, chp, &socket_mask, tcp_local_to_remote ) == FAILED )
139                return ;
140             if ( --n_ready == 0 )
141                break ;
142          }
143
144          if ( FD_ISSET( chp->ch_remote_socket, &read_mask ) )
145          {
146 #ifdef DEBUG_TCPINT
147             msg( LOG_DEBUG, func, "Input available on remote socket %d", 
148                                                       chp->ch_remote_socket ) ;
149 #endif
150             if ( handle_io( iter, chp,
151                         &socket_mask, tcp_remote_to_local ) == FAILED )
152                return ;
153             if ( --n_ready == 0 )
154                break ;
155          }
156       }
157    }
158 }
159
160
161 static status_e handle_io( psi_h iter, 
162                             channel_s *chp, 
163                             fd_set *maskp, 
164                             stream_status_e (*iofunc)() )
165 {
166    const char *func = "handle_io" ;
167
168    switch ( (*iofunc)( chp ) )
169    {
170       case S_SERVER_ERR:
171          return( FAILED ) ;
172       
173       case S_CLIENT_ERR:
174
175          if ( debug.on )
176             msg( LOG_DEBUG, func,
177                "Closing channel to %s,%d using sockets %d(l),%d(r)",
178                   xaddrname( &chp->ch_from ), ntohs(xaddrport( &chp->ch_from )),
179                         chp->ch_local_socket, chp->ch_remote_socket ) ;
180
181          FD_CLR( chp->ch_local_socket, maskp ) ;
182          FD_CLR( chp->ch_remote_socket, maskp ) ;
183          (void) Sclose( chp->ch_remote_socket ) ;
184          (void) Sclose( chp->ch_local_socket ) ;
185          psi_remove( iter ) ;
186          FREE_CHANNEL( chp ) ;
187          break ;
188       case S_OK:
189          break ;
190    }
191    return( OK ) ;
192 }
193
194
195 static void connection_request( struct intercept_s *ip, channel_s **chpp )
196 {
197    union xsockaddr      csin ;
198    socklen_t            sin_len = 0;
199    channel_s           *chp ;
200    int                  sd ;
201    bool_int             addr_checked ;
202    const char          *func = "connection_request" ;
203
204    *chpp = NULL ;
205    if( SC_IPV4( SVC_CONF( SERVER_SERVICE( INT_SERVER( ip ) ) ) ) )
206       sin_len = sizeof(struct sockaddr_in);
207    if( SC_IPV6( SVC_CONF( SERVER_SERVICE( INT_SERVER( ip ) ) ) ) )
208       sin_len = sizeof(struct sockaddr_in6);
209
210    if ( ( sd = accept( INT_REMOTE( ip ), SA( &csin ), &sin_len ) ) == -1 ) 
211       return ;
212    
213    SIP( ip->int_priv )->accepted_connections++ ;
214
215    if ( debug.on )
216       msg( LOG_DEBUG, func, "connection request from %s,%d",
217          xaddrname( &csin ), ntohs( xaddrport( &csin ) ) ) ;
218
219    chp = int_lookupconn( ip, &csin, &addr_checked ) ;
220    if ( chp == NULL )
221    {
222       struct server  *serp  = INT_SERVER( ip ) ;
223       struct service *sp    = SERVER_SERVICE( serp ) ;
224       connection_s   *cop   = SERVER_CONNECTION( serp ) ;
225
226       CONN_SETADDR( cop, &csin ) ;
227
228       if ( INTERCEPT( ip ) )
229       {
230          mask_t check_mask ;
231          access_e result ;
232          
233          M_OR( check_mask, XMASK( CF_ADDRESS ), XMASK( CF_TIME ) ) ;
234          result = access_control( sp, cop, &check_mask ) ;
235
236          if ( result != AC_OK )
237          {
238             svc_log_failure( sp, cop, result ) ;
239             (void) Sclose( sd ) ;
240             return ;
241          }
242       }
243
244       if ( ( chp = int_newconn( ip, &csin, sd ) ) == NULL )
245       {
246          (void) Sclose( sd ) ;
247          return ;
248       }
249       
250       if ( ! addr_checked )
251          svc_log_success( sp, cop, SERVER_PID( serp ) ) ;
252
253 #if defined( TCP_NODELAY )
254       {
255          int on = 1 ;
256
257          (void) setsockopt( chp->ch_local_socket, IPPROTO_TCP,
258                               TCP_NODELAY, (char *) &on, sizeof( on ) ) ;
259          (void) setsockopt( chp->ch_remote_socket, IPPROTO_TCP,
260                               TCP_NODELAY, (char *) &on, sizeof( on ) ) ;
261       }
262 #endif   /* TCP_NODELAY */
263       
264       *chpp = chp ;
265    }
266    else
267       msg( LOG_ERR, func,
268          "Received another connection request from %s,%d",
269             xaddrname( &csin ), ntohs( xaddrport( &csin ) ) ) ;
270 }
271
272
273 static stream_status_e tcp_local_to_remote( channel_s *chp )
274 {
275    char  buf[ DATAGRAM_SIZE ] ;
276    int   rcc, wcc ;
277    char *p ;
278    int   left ;
279    const char *func = "tcp_local_to_remote" ;
280
281    for ( ;; )
282    {
283       rcc = recv( chp->ch_local_socket, buf, sizeof( buf ), 0 ) ;
284       if ( rcc == 0 )
285          return( S_SERVER_ERR ) ;
286       else if ( rcc == -1 )
287       {
288          if ( errno != EINTR )
289          {
290             msg( LOG_ERR, func, "recv: %m" ) ;
291             return( S_SERVER_ERR ) ;
292          }
293       }
294       else
295          break ;
296    }
297
298    for ( p = buf, left = rcc ; left ; p += wcc, left -= wcc )
299    {
300       wcc = send( chp->ch_remote_socket, p, left, 0 ) ;
301       if ( wcc == 0 )
302          return( S_CLIENT_ERR ) ;
303       else if ( wcc == -1 )
304       {
305          if ( errno == EINTR )
306             wcc = 0 ;
307          else
308          {
309             msg( LOG_ERR, func, "send: %m" ) ;
310             return( S_CLIENT_ERR ) ;
311          }
312       }
313    }
314
315 #ifdef DEBUG_TCPINT
316    if ( debug.on )
317       msg( LOG_DEBUG, func,
318          "Transferred %d bytes from local socket %d to remote socket %d",
319             rcc, chp->ch_local_socket, chp->ch_remote_socket ) ;
320 #endif
321
322    return( S_OK ) ;
323 }
324
325
326 static stream_status_e tcp_remote_to_local( channel_s *chp )
327 {
328    char  buf[ DATAGRAM_SIZE ] ;
329    int   rcc, wcc ;
330    int   left ;
331    char *p ;
332    const char *func = "tcp_remote_to_local" ;
333
334    for ( ;; )
335    {
336       rcc = recv( chp->ch_remote_socket, buf, sizeof( buf ), 0 ) ;
337       if ( rcc == 0 )
338          return( S_CLIENT_ERR ) ;
339       else if ( rcc == -1 )
340       {
341          if ( errno != EINTR )
342          {
343             msg( LOG_ERR, func, "recv: %m" ) ;
344             return( S_CLIENT_ERR ) ;
345          }
346       }
347       else
348          break ;
349    }
350
351    for ( p = buf, left = rcc ; left ; p += wcc, left -= wcc )
352    {
353       wcc = send( chp->ch_local_socket, p, left, 0 ) ;
354       if ( wcc == 0 ) {
355          return( S_SERVER_ERR ) ;
356       } else if ( wcc == -1 ) {
357          if ( errno == EINTR ) {
358             rcc = 0 ;
359          } else {
360             msg( LOG_ERR, func, "send: %m" ) ;
361             return( S_SERVER_ERR ) ;
362          }
363       }
364    }
365
366 #ifdef DEBUG_TCPINT
367    if ( debug.on )
368       msg( LOG_DEBUG, func,
369          "Transferred %d bytes from remote socket %d to local socket %d",
370             rcc, chp->ch_remote_socket, chp->ch_local_socket ) ;
371 #endif
372
373    return( S_OK ) ;
374 }
375