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 #include "config.h"
9 #include <sys/types.h>
10 #include <sys/time.h>
11 #include <sys/socket.h>
12 #include <signal.h>
13 #include <syslog.h>
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17
18 #include "intcommon.h"
19 #include "msg.h"
20 #include "signals.h"
21 #include "connection.h"
22 #include "sconf.h"
23 #include "state.h"
24 #include "main.h"
25 #include "xconfig.h"
26
27
int_fail(const struct intercept_s * ip,const char * lsyscall)28 void int_fail( const struct intercept_s *ip, const char *lsyscall )
29 {
30 msg( LOG_ERR, "fail", "%s failed: %m", lsyscall ) ;
31 (*ip->int_ops->exit)() ;
32 /* NOTREACHED */
33 }
34
35
36 /*
37 * Returns either a positive number or -1
38 */
int_select(int max,fd_set * read_mask)39 int int_select( int max, fd_set *read_mask )
40 {
41 const char *func = "int_select" ;
42
43 for ( ;; )
44 {
45 int n_ready ;
46
47 n_ready = select( max+1, read_mask,
48 FD_SET_NULL, FD_SET_NULL, TIMEVAL_NULL ) ;
49 if ( n_ready > 0 )
50 return( n_ready ) ;
51 else if ( n_ready == -1 ) {
52 if ( errno == EINTR )
53 continue ;
54 else
55 {
56 msg( LOG_ERR, func, "select: %m" ) ;
57 return( -1 ) ;
58 }
59 }
60 }
61 }
62
63
int_exit(struct intercept_s * ip)64 void int_exit( struct intercept_s *ip )
65 {
66 int status = SERVER_EXITSTATUS( INT_SERVER( ip ) ) ;
67 const char *func = "int_exit" ;
68
69 if ( debug.on )
70 {
71 if ( PROC_EXITED( status ) )
72 msg( LOG_DEBUG, func, "intercepted server died" ) ;
73 else if ( PROC_SIGNALED( status ) )
74 msg( LOG_DEBUG, func, "intercepted server received signal %s",
75 sig_name( (int) PROC_TERMSIG( status ) ) ) ;
76 }
77 _exit( (int) PROC_EXITSTATUS( status ) ) ;
78 }
79
80
81 /*
82 * The ops vector must be installed before invoking this function
83 */
int_init(struct intercept_s * ip,struct server * serp)84 void int_init( struct intercept_s *ip, struct server *serp )
85 {
86 unsigned u ;
87 const char *func = "int_init" ;
88
89 /*
90 * Sanity test
91 */
92 if ( SERVER_SERVICE( serp ) != SERVER_CONNSERVICE( serp ) )
93 {
94 msg( LOG_ERR, func, "server service (%s) != connection service (%s)",
95 SVC_ID( SERVER_SERVICE( serp ) ),
96 SVC_ID( SERVER_CONNSERVICE( serp ) ) ) ;
97 exit( 1 ) ;
98 }
99
100 /*
101 * Close all unneeded descriptors
102 */
103 for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ )
104 {
105 struct service *sp = SP( pset_pointer( SERVICES( ps ), u ) ) ;
106
107 if ( sp == SERVER_SERVICE( serp ) )
108 continue ;
109 if ( LOG_GET_TYPE( SC_LOG( SVC_CONF( sp ) ) ) == L_FILE )
110 xlog_destroy( SVC_LOG( sp ) ) ;
111 (void) Sclose( SVC_FD( sp ) ) ;
112 }
113
114 /*
115 * Setup signal handling
116 */
117 if ( signal( SERVER_EXIT_SIG, int_sighandler ) == SIG_ERR )
118 int_fail( ip, "signal" ) ;
119 if ( signal( INTERCEPT_SIG, int_sighandler ) == SIG_ERR )
120 int_fail( ip, "signal" ) ;
121 if ( signal( SIGTERM, int_sighandler ) == SIG_ERR )
122 int_fail( ip, "signal" ) ;
123
124 /*
125 * Initialize state
126 */
127 INTERCEPT( ip ) = TRUE ;
128 *INT_SERVER( ip ) = *serp ;
129 INT_REMOTE( ip ) = SERVER_FD( serp ) ;
130
131 INT_CONNECTIONS( ip ) = pset_create( 0, 0 ) ;
132 if ( INT_CONNECTIONS( ip ) == NULL )
133 {
134 msg( LOG_ERR, func, ES_NOMEM ) ;
135 (*ip->int_ops->exit)() ;
136 }
137 }
138
139
140 /*
141 * Make a new connection to the local server
142 */
int_newconn(struct intercept_s * ip,union xsockaddr * sinp,int remote_socket)143 channel_s *int_newconn( struct intercept_s *ip,
144 union xsockaddr *sinp,
145 int remote_socket )
146 {
147 struct service *sp = SERVER_SERVICE( INT_SERVER( ip ) ) ;
148 int socket_type = SVC_SOCKET_TYPE( sp ) ;
149 union xsockaddr *local = INT_LOCALADDR( ip ) ;
150 char *sid = SVC_ID( sp ) ;
151 channel_s *chp ;
152 int sd ;
153 const char *func = "int_newconn" ;
154
155 /*
156 * Get a socket and connect it to the local address
157 *
158 */
159 if ( ( sd = socket( local->sa.sa_family, socket_type, SC_PROTOVAL(SVC_CONF(sp)) ) ) == -1 )
160 {
161 msg( LOG_ERR, func,"(intercepting %s) socket creation failed: %m", sid ) ;
162 return( CHANNEL_NULL ) ;
163 }
164
165 if ( connect( sd, SA( local ), sizeof( *local ) ) == -1 )
166 {
167 msg( LOG_ERR, func, "(intercepting %s) connect failed: %m", sid ) ;
168 (void) Sclose( sd ) ;
169 return( CHANNEL_NULL ) ;
170 }
171
172 chp = NEW_CHANNEL() ;
173 if ( chp == CHANNEL_NULL )
174 {
175 msg( LOG_ERR, func, ES_NOMEM ) ;
176 (void) Sclose( sd ) ;
177 return( CHANNEL_NULL ) ;
178 }
179
180 if ( pset_add( INT_CONNECTIONS( ip ), chp ) == NULL )
181 {
182 msg( LOG_ERR, func, ES_NOMEM ) ;
183 FREE_CHANNEL( chp ) ;
184 (void) Sclose( sd ) ;
185 return( CHANNEL_NULL ) ;
186 }
187
188 chp->ch_state = GOOD_CHANNEL ;
189 chp->ch_from = *sinp ;
190 chp->ch_local_socket = sd ;
191 chp->ch_remote_socket = remote_socket ;
192 return( chp ) ;
193 }
194
195
196
197 /*
198 * Check if the (address,port) in sinp is already in the connection table.
199 * Return value:
200 * a connection pointer if the address is found
201 * NULL if the address if not found
202 *
203 * *addr_checked is set to TRUE of FALSE depending on whether there
204 * is already a connection from the same IP address in the table.
205 */
int_lookupconn(struct intercept_s * ip,union xsockaddr * sinp,bool_int * addr_checked)206 channel_s *int_lookupconn( struct intercept_s *ip,
207 union xsockaddr *sinp,
208 bool_int *addr_checked )
209 {
210 unsigned u ;
211 pset_h conntab = INT_CONNECTIONS( ip ) ;
212
213 *addr_checked = FALSE ;
214
215 for ( u = 0 ; u < pset_count( conntab ) ; u++ )
216 {
217 register channel_s *chp = CHP( pset_pointer( conntab, u ) ) ;
218
219 if ( memcmp( &chp->ch_from, sinp, sizeof( *sinp ) ) == 0 )
220 {
221 *addr_checked = TRUE ;
222 if ( xaddrport(&chp->ch_from) == xaddrport(sinp) )
223 return( chp ) ;
224 }
225 }
226 return( CHANNEL_NULL ) ;
227 }
228