#define CORE_PRIVATE #include "httpd.h" #include "http_config.h" #include "http_core.h" #include "http_log.h" #include "http_main.h" #include "http_protocol.h" #include "http_request.h" #include "util_script.h" #include "http_connection.h" #include "ap_config.h" #include "ap_regex.h" #include "apr_errno.h" #include "apr_network_io.h" #include "apr_strings.h" #define TRBUFF 255 #define APR_SOCK_SR_TEST(insct) \ if(r == APR_SUCCESS){\ insct\ }else if(APR_STATUS_IS_EAGAIN(r)){\ apr_sleep(1000);\ }else if(!APR_STATUS_IS_TIMEUP(r))\ break #define APR_SOCKET_SEND(__sock,__n,__size,__start,__buff) \ __n = __size-__start;\ r = apr_socket_send(__sock,__buff+__start,&__n);\ APR_SOCK_SR_TEST(\ __start += __n;\ ) static char buffer_hostname[APRMAXHOSTLEN + 1]; static char *mod_ucfwd_hostname=NULL; static int mod_ucfwd_port=-1; module AP_MODULE_DECLARE_DATA ucfwd_module; static void mod_ucfwd_forward(apr_socket_t *sockcl, apr_socket_t *socksrv){ char buff_c[TRBUFF],buff_s[TRBUFF]; apr_size_t n_c,n_s,start_c = TRBUFF,start_s = TRBUFF,size_c = TRBUFF,size_s = TRBUFF; apr_status_t r; // Met en non bloquant apr_socket_opt_set(sockcl, APR_SO_NONBLOCK, 1); apr_socket_opt_set(socksrv, APR_SO_NONBLOCK, 1); apr_socket_timeout_set(sockcl, 1000); apr_socket_timeout_set(socksrv, 1000); while(1){ // Client => Serveur if(start_c == size_c){ size_c = TRBUFF; start_c = 0; r = apr_socket_recv(sockcl,buff_c,&size_c); APR_SOCK_SR_TEST( APR_SOCKET_SEND(socksrv,n_c,size_c,start_c,buff_c); ); }else{ APR_SOCKET_SEND(socksrv,n_c,size_c,start_c,buff_c); } // Serveur => Client if(start_s == size_s){ size_s = TRBUFF; start_s = 0; r = apr_socket_recv(socksrv,buff_s,&size_s); APR_SOCK_SR_TEST( APR_SOCKET_SEND(sockcl,n_s,size_s,start_s,buff_s); ); }else{ APR_SOCKET_SEND(sockcl,n_s,size_s,start_s,buff_s); } } } static apr_socket_t *mod_ucfwd_connect(request_rec *r){ apr_socket_t *sock=NULL; apr_status_t ret; char buffer[255]; apr_sockaddr_t *addr=NULL; if(mod_ucfwd_port==-1){ fprintf(stderr,"Module mod_ucfwd : Unix socket is not supported yet.\n"); return NULL; } // Nouvelle adresse ret = apr_sockaddr_info_get(&addr,mod_ucfwd_hostname,APR_INET,mod_ucfwd_port,0,r->pool); if(ret!=APR_SUCCESS){ fprintf(stderr,"Module mod_ucfwd : Adress creation failed : %s\n",apr_strerror(ret,buffer,255)); return NULL; } // Nouvelle socket ret = apr_socket_create (&sock, APR_INET, SOCK_STREAM, APR_PROTO_TCP, r->pool); if(ret!=APR_SUCCESS){ fprintf(stderr,"Module mod_ucfwd : Socket creation failed : %s\n",apr_strerror(ret,buffer,255)); return NULL; } // Connection ret = apr_socket_connect(sock, addr); if(ret!=APR_SUCCESS){ fprintf(stderr,"Module mod_ucfwd : Connection failed : %s\n",apr_strerror(ret,buffer,255)); return NULL; } return sock; } static int mod_ucfwd_performGetRequest(request_rec *r) { apr_socket_t *socksrv; apr_socket_t *sockcl; ap_set_content_type(r, "text/html;charset=utf-8"); if(r->method_number==M_GET){ ap_rprintf(r, "\n" "UniComCtrl Connection Forwarder" "

UniComCtrl Connection Forwarder

"); } if(mod_ucfwd_hostname!=NULL){ if(r->method_number==M_GET){ if(mod_ucfwd_port==-1){ ap_rprintf(r,"

Configuration [OK].

Socket : UNIX
Path : %s",mod_ucfwd_hostname); }else{ ap_rprintf(r,"

Configuration [OK].

Socket : TCP
Hostname : %s
Port : %d", mod_ucfwd_hostname,mod_ucfwd_port); } } socksrv = mod_ucfwd_connect(r); if(socksrv != NULL){ if(r->method_number==M_GET){ ap_rprintf(r,"

Connection [OK].

"); }else{ sockcl = ap_get_module_config(r->connection->conn_config, &core_module); mod_ucfwd_forward(sockcl,socksrv); } }else{ if(r->method_number==M_GET){ ap_rprintf(r,"

Connection [!!] (see apache log for more informations).

"); } } }else{ if(r->method_number==M_GET){ ap_rprintf(r, "

Configuration [!!] (see apache log for more informations).

"); } } if(r->method_number==M_GET){ ap_rprintf(r, ""); } fflush(stderr); return 0; } static int mod_ucfwd_method_handler (request_rec *r) { if (!r->handler || strcmp(r->handler, "ucfwd")) return DECLINED; switch(r->method_number){ case M_CONNECT: case M_GET: mod_ucfwd_performGetRequest(r); break; default: return HTTP_METHOD_NOT_ALLOWED; } return OK; } static void mod_ucfwd_register_hooks (apr_pool_t *p) { ap_hook_handler(mod_ucfwd_method_handler, NULL, NULL, APR_HOOK_LAST); } static const char* mod_ucfwd_set_server(cmd_parms *cmd, void* empty, char* server) { char *prefix=NULL; char *portstr=NULL; int tmp; apr_size_t nmatch; ap_regmatch_t *pmatch; ap_regex_t *regex; mod_ucfwd_hostname=NULL; // Decoupage de l'adresse regex = ap_pregcomp(cmd->pool,"((unix)://)?([^:]+)(:([0-9]+))?",AP_REG_EXTENDED); if(regex==NULL){ fprintf(stderr,"Module mod_ucfwd : Regular expression \"((unix)://)?([^:]+)(:([0-9]+))?\" could not be compiled.\n"); return mod_ucfwd_hostname=NULL; } nmatch = regex->re_nsub+1; pmatch = apr_palloc(cmd->pool,sizeof(ap_regmatch_t) * nmatch); if(ap_regexec(regex,server,nmatch,pmatch,0)==AP_REG_NOMATCH){ fprintf(stderr,"Module mod_ucfwd : ModUCFwdServer must be in this format : [unix://]hostname_or_path[:port_number]\n"); return mod_ucfwd_hostname=NULL; } // Extraction des trois parties : prefixe, nom et numero de port if(pmatch[2].rm_so!=-1) prefix = apr_pstrndup(cmd->pool, server+pmatch[2].rm_so,pmatch[2].rm_eo - pmatch[2].rm_so); if(pmatch[3].rm_so!=-1){ tmp = pmatch[3].rm_eo-pmatch[3].rm_so; mod_ucfwd_hostname = strncpy(buffer_hostname,server+pmatch[3].rm_so,tmp>APRMAXHOSTLEN?APRMAXHOSTLEN:tmp); } if(pmatch[5].rm_so!=-1) portstr = apr_pstrndup(cmd->pool, server+pmatch[5].rm_so,pmatch[5].rm_eo-pmatch[5].rm_so); // Extraction des information et test de conformite (coherence) mod_ucfwd_port=-1; if(portstr != NULL) mod_ucfwd_port = (int)apr_atoi64(portstr); if(mod_ucfwd_hostname == NULL){ fprintf(stderr,"Module mod_ucfwd : Invalid hostname\n" "ModUCFwdServer must be in this format : [unix://]hostname_or_path[:port_number]\n"); return mod_ucfwd_hostname=NULL; } if(prefix == NULL){ }else if(strcmp(prefix,"unix")==0){ mod_ucfwd_port=-1; }else{ fprintf(stderr,"Module mod_ucfwd : Invalid prefix\n" "ModUCFwdServer must be in this format : [unix://]hostname_or_path[:port_number]\n"); return mod_ucfwd_hostname=NULL; } return NULL; } static const command_rec mod_ucfwd_cmd_tbl[] = { { "ModUCFwdServer", (const char *(*)()) mod_ucfwd_set_server, NULL, RSRC_CONF, TAKE1, "Server adress in this format : [unix://]hostname_or_path[:port_number]" }, { NULL } }; module ucfwd_module = { STANDARD20_MODULE_STUFF, NULL, NULL, NULL, NULL, mod_ucfwd_cmd_tbl, mod_ucfwd_register_hooks, };