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/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
26 #include "intcommon.h"
34 static void start_server( struct intercept_s *ip );
35 static void terminate_server( struct intercept_s *ip );
37 typedef struct intercept_s *(*initfunc)() ;
41 initfunc initializer ;
46 static struct lookup_table intercept_lookup_table[] =
48 { di_init, SOCK_DGRAM },
49 { si_init, SOCK_STREAM },
55 * This variable has file scope for the benefit of the signal handler
57 static struct intercept_s *intp = NULL;
61 static initfunc find_initializer( int type )
63 struct lookup_table *ltp ;
65 for ( ltp = intercept_lookup_table ; ltp->initializer ; ltp++ )
66 if ( ltp->socket_type == type )
67 return( ltp->initializer ) ;
68 msg( LOG_ERR, "find_initializer", "No initializer for type %d", type ) ;
76 * This function is the interface of the intercept code with the rest of
79 void intercept( struct server *serp )
81 struct service *sp = SERVER_SERVICE( serp ) ;
82 initfunc initializer ;
84 #ifdef DEBUG_INTERCEPTOR
87 msg( LOG_DEBUG, "intercept", "%d is sleeping", getpid() ) ;
92 initializer = find_initializer( SVC_SOCKET_TYPE( sp ) ) ;
93 intp = (*initializer)( serp ) ;
94 start_server( intp ) ;
95 (*intp->int_ops->mux)() ;
96 terminate_server( intp ) ;
98 * the terminate_server function should not return but even if it
99 * does, child_process will do the _exit.
105 * Create a socket and bind it to (INADDR_LOOPBACK,0)
107 static int get_server_socket( struct intercept_s *ip )
109 struct service *sp = SERVER_SERVICE( INT_SERVER( ip ) ) ;
110 union xsockaddr *sinp = INT_LOCALADDR( ip ) ;
113 const char *func = "get_server_socket" ;
115 if( SC_IPV6(SVC_CONF(sp)) ) {
116 struct addrinfo hint, *res = NULL;
117 memset(&hint, 0, sizeof(struct addrinfo));
118 hint.ai_family = AF_INET6;
119 hint.ai_flags = AI_NUMERICHOST;
120 sinp->sa_in6.sin6_family = AF_INET6;
121 sinp->sa_in6.sin6_port = 0;
122 if( getaddrinfo("::1", NULL, &hint, &res) != 0 )
123 int_fail( ip, "can't find ::1" );
125 int_fail( ip, "no results for ::1" );
126 if( res->ai_family != AF_INET6 )
127 int_fail( ip, "non IPv6 result for ::1" );
128 memcpy(sinp, res->ai_addr, sizeof( struct sockaddr_in6 ));
130 size = sizeof(struct sockaddr_in6);
131 } else if( SC_IPV4(SVC_CONF(sp)) ) {
132 sinp->sa_in.sin_family = AF_INET;
133 sinp->sa_in.sin_port = 0;
134 sinp->sa_in.sin_addr.s_addr = inet_addr( "127.0.0.1" );
135 size = sizeof(struct sockaddr_in);
137 int_fail( ip, "unknown socket family" );
139 if ( ( sd = socket( sinp->sa.sa_family, SVC_SOCKET_TYPE( sp ), SC_PROTOVAL(SVC_CONF(sp)) ) ) == -1 )
140 int_fail( ip, "socket creation" ) ;
142 if ( bind( sd, SA( sinp ), size ) == -1 )
143 int_fail( ip, "bind" ) ;
145 size = sizeof( *sinp ) ;
146 if ( getsockname( sd, SA( sinp ), &size ) == -1 )
147 int_fail( ip, "getsockname" ) ;
150 msg( LOG_DEBUG, func, "address = %s, port = %d",
151 xaddrname( sinp ), ntohs( xaddrport( sinp ) ) ) ;
153 if ( ip->int_socket_type == SOCK_STREAM )
154 (void) listen( sd, LISTEN_BACKLOG ) ;
160 static void start_server( struct intercept_s *ip )
162 struct server *serp = INT_SERVER( ip ) ;
163 struct service *sp = SERVER_SERVICE( serp ) ;
167 server_socket = get_server_socket( ip ) ;
174 int_fail( ip, "fork" ) ;
178 CONN_SET_DESCRIPTOR( SERVER_CONNECTION( serp ), server_socket ) ;
179 SVC_MAKE_EXTERNAL( sp ) ; /* avoid looping */
180 child_process( serp ) ;
184 SERVER_SET_PID( serp, pid ) ;
185 (void) Sclose( server_socket ) ;
193 * OK if the server died
196 static status_e wait_child( struct intercept_s *ip )
198 const char *func = "wait_child" ;
200 status_e ret = FAILED;
203 while( (pid = waitpid( -1, &status, WNOHANG )) != 0 )
208 if ( errno != EINTR )
210 msg( LOG_ERR, func, "wait: %m" ) ;
214 else if ( pid == SERVER_PID( INT_SERVER( ip ) ) )
216 if ( PROC_STOPPED( status ) )
218 SERVER_SET_EXIT_STATUS( INT_SERVER( ip ), status ) ;
225 /* Ideally, this will never be executed */
227 "wait returned pid of unknown process: %d", pid ) ;
229 /* Since we don't have the intercept pointer to this service,
230 * do our best to shut it down safely...
232 for( u = 0; u < pset_count( SERVERS(ps) ); u++ ) {
233 struct server *p = SERP( pset_pointer( SERVERS(ps), u) );
235 if( (p != NULL) && (SERVER_PID(p) == pid) ) {
236 struct service *sp = SERVER_SERVICE(p);
237 struct service_config *scp = SVC_CONF(sp);
239 if( SC_PROTOVAL(scp) == IPPROTO_TCP ) {
240 SERVER_SET_EXIT_STATUS( p, status );
242 } else if( SC_PROTOVAL(scp) == IPPROTO_UDP ) {
243 SERVER_SET_EXIT_STATUS( p, status );
246 msg( LOG_ERR, func, "Don't know how to exit %d", pid);
258 static void terminate_server( struct intercept_s *ip )
260 pid_t pid = SERVER_PID( INT_SERVER( intp ) ) ;
263 (void) kill( pid, SIGKILL ) ;
266 * Normally, wait_child should never return since a SIGCHLD will
267 * invoke the signal handler which will then call the exit function.
269 if ( wait_child( ip ) == OK )
270 (*intp->int_ops->exit)() ;
274 void int_sighandler( int sig )
276 const char *func = "int_sighandler" ;
279 msg( LOG_DEBUG, func, "Received signal %s", sig_name( sig ) ) ;
281 if ( sig == SERVER_EXIT_SIG )
283 if ( wait_child( intp ) == OK )
284 (*intp->int_ops->exit)() ;
286 else if ( sig == INTERCEPT_SIG )
287 INTERCEPT( intp ) = FALSE ;
288 else if ( sig == SIGTERM )
289 terminate_server( intp ) ;