/** * Establish a connection from proxenet -> server. * If proxy forwarding configured, then this function performs the negociation with the other proxy. * If the host applies for SSL intercept rules, this function also handles the SSL handshake. * * @return 0 if successful, -1 otherwise */ int create_http_socket(request_t* req, sock_t* server_sock, sock_t* client_sock, ssl_context_t* ssl_ctx) { int retcode; char *host, *port; char sport[7] = {0, }; http_infos_t* http_infos = &req->http_infos; bool use_proxy = (cfg->proxy.host != NULL); bool use_socks_proxy = use_proxy && (cfg->is_socks_proxy==true); bool use_http_proxy = use_proxy && (cfg->is_socks_proxy==false); char errmsg[512]={0,}; if (parse_http_request(req) < 0){ xlog(LOG_ERROR, "%s\n", "Failed to extract valid parameters from URL."); return -1; } ssl_ctx->use_ssl = req->is_ssl; proxenet_xsnprintf(sport, sizeof(sport), "%hu", http_infos->port); /* do we forward to another proxy ? */ if (use_proxy) { host = cfg->proxy.host; port = cfg->proxy.port; } else { host = http_infos->hostname; port = sport; } #ifdef DEBUG xlog(LOG_DEBUG, "Relay request %s to '%s:%s (type=%d)'\n", use_http_proxy ? "via HTTP proxy" : "direct", host, port, http_infos->proto_type); #endif retcode = proxenet_open_socket(host, port); if (retcode < 0) { proxenet_xsnprintf(errmsg, sizeof(errmsg), "Cannot connect to %s:%s<br><br>Reason: %s", host, port, errno?strerror(errno):"<i>proxenet_open_socket()</i> failed"); generic_http_error_page(*server_sock, errmsg); return -1; } if (cfg->verbose > 2) xlog(LOG_INFO, "Socket to %s '%s:%s': fd=%d\n", use_http_proxy?"HTTP proxy":(use_socks_proxy?"SOCKS4 proxy":"server"), host, port, retcode); *client_sock = retcode; req->do_intercept = apply_intercept_rules(http_infos); if (cfg->verbose > 1) { xlog(LOG_INFO, "Server '%s' %s match filter '%s' with pattern '%s'\n", http_infos->hostname, req->do_intercept ? "do" : "do not", cfg->intercept_mode==INTERCEPT_ONLY?"INTERCEPT_ONLY":"INTERCEPT_EXCEPT", cfg->intercept_pattern); } if(use_socks_proxy){ char*rhost = http_infos->hostname; int rport = http_infos->port; retcode = proxenet_socks_connect(*client_sock, rhost, rport, true); if( retcode<0 ){ proxenet_xsnprintf(errmsg, sizeof(errmsg), "Failed to open SOCKS4 tunnel to %s:%s.\n", host, port); generic_http_error_page(*server_sock, errmsg); xlog(LOG_ERROR, "%s", errmsg); return -1; } } /* set up specific sockets */ switch (http_infos->proto_type){ case HTTPS: if(cfg->verbose > 2) xlog(LOG_INFO, "Creating a new HTTPS socket: %d/%d proxy=%s\n", client_sock, server_sock, use_socks_proxy?"true":"false"); return create_https_socket(req, client_sock, server_sock, ssl_ctx, use_socks_proxy); default: break; } return 0; }
/** * Establish a connection from proxenet -> server. * If proxy forwarding configured, then this function performs the negociation with the other proxy. * If the host applies for SSL intercept rules, this function also handles the SSL handshake. * * @return 0 if successful, -1 otherwise */ int create_http_socket(request_t* req, sock_t* server_sock, sock_t* client_sock, ssl_context_t* ssl_ctx) { int retcode; char *host, *port; char sport[7] = {0, }; http_request_t* http_infos = &req->http_infos; bool use_proxy = (cfg->proxy.host != NULL); bool use_http_proxy = use_proxy && (cfg->is_socks_proxy == false); bool use_socks_proxy = use_proxy && cfg->is_socks_proxy; char errmsg[512]={0,}; if (update_http_infos(req) < 0){ xlog(LOG_ERROR, "%s\n", "Failed to extract valid parameters from URL."); return -1; } ssl_ctx->use_ssl = req->is_ssl; proxenet_xsnprintf(sport, sizeof(sport), "%hu", http_infos->port); /* do we forward to another proxy ? */ if (use_proxy) { host = cfg->proxy.host; port = cfg->proxy.port; } else { host = http_infos->hostname; port = sport; } #ifdef DEBUG xlog(LOG_DEBUG, "Relay request %s to '%s:%s'\n", use_http_proxy ? "via HTTP proxy" : "direct", host, port); #endif retcode = proxenet_open_socket(host, port); if (retcode < 0) { proxenet_xsnprintf(errmsg, sizeof(errmsg), "Cannot connect to %s:%s<br><br>Reason: %s", host, port, errno?strerror(errno):"<i>proxenet_open_socket()</i> failed"); generic_http_error_page(*server_sock, errmsg); return -1; } #ifdef DEBUG xlog(LOG_DEBUG, "Socket to %s '%s:%s': fd=%d\n", use_http_proxy?"HTTP proxy":(use_socks_proxy?"SOCKS4 proxy":"server"), host, port, retcode); #endif *client_sock = retcode; req->do_intercept = ( (cfg->intercept_mode==INTERCEPT_ONLY && \ fnmatch(cfg->intercept_pattern, http_infos->hostname, 0)==0) || \ (cfg->intercept_mode==INTERCEPT_EXCEPT && \ fnmatch(cfg->intercept_pattern, http_infos->hostname, 0)==FNM_NOMATCH) ); #ifdef DEBUG xlog(LOG_DEBUG, "Server '%s' %s match interception '%s' with pattern '%s'\n", http_infos->hostname, req->do_intercept?"do":"do not", cfg->intercept_mode==INTERCEPT_ONLY?"INTERCEPT_ONLY":"INTERCEPT_EXCEPT", cfg->intercept_pattern); #endif if(use_socks_proxy){ char*rhost = http_infos->hostname; int rport = http_infos->port; retcode = proxenet_socks_connect(*client_sock, rhost, rport, true); if( retcode<0 ){ proxenet_xsnprintf(errmsg, sizeof(errmsg), "Failed to open SOCKS4 tunnel to %s:%s.\n", host, port); generic_http_error_page(*server_sock, errmsg); xlog(LOG_ERROR, "%s", errmsg); return -1; } } /* set up ssl layer */ if (req->is_ssl) { /* adjust do_intercept if we do not SSL intercept was explicitely disabled */ req->do_intercept = cfg->ssl_intercept; if (use_http_proxy) { char *connect_buf = NULL; /* 0. set up proxy->proxy ssl session (i.e. forward CONNECT request) */ retcode = proxenet_write(*client_sock, req->data, req->size); if (retcode < 0) { xlog(LOG_ERROR, "%s failed to CONNECT to proxy\n", PROGNAME); return -1; } /* read response */ retcode = proxenet_read_all(*client_sock, &connect_buf, NULL); if (retcode < 0) { xlog(LOG_ERROR, "%s Failed to read from proxy\n", PROGNAME); return -1; } /* expect HTTP 200 */ if ( (strncmp(connect_buf, "HTTP/1.0 200", 12) != 0) && (strncmp(connect_buf, "HTTP/1.1 200", 12) != 0)) { xlog(LOG_ERROR, "%s->proxy: bad HTTP version\n", PROGNAME); if (cfg->verbose) xlog(LOG_ERROR, "Received %s\n", connect_buf); return -1; } #ifdef DEBUG xlog(LOG_DEBUG, "HTTP Connect Ok with '%s:%s', cli_sock=%d\n", host, port, *client_sock); #endif } if (req->do_intercept){ /* 1. set up proxy->server ssl session with hostname */ if(proxenet_ssl_init_client_context(&(ssl_ctx->client), http_infos->hostname) < 0) { return -1; } proxenet_ssl_wrap_socket(&(ssl_ctx->client.context), client_sock); retcode = proxenet_ssl_handshake(&(ssl_ctx->client.context)); if (retcode < 0) { xlog(LOG_ERROR, "handshake %s->server failed [code: %#x]\n", PROGNAME, retcode); xlog(LOG_ERROR, "Client SSL handshake failed for '%s:%d'.\n", http_infos->hostname, http_infos->port, retcode); return -1; } #ifdef DEBUG xlog(LOG_DEBUG, "SSL handshake with %s done, cli_sock=%d\n", use_http_proxy?"proxy":"server", *client_sock); #endif } if (proxenet_write(*server_sock, "HTTP/1.0 200 Connection established\r\n\r\n", 39) < 0){ return -1; } if (req->do_intercept) { /* 2. set up proxy->browser ssl session with hostname */ if(proxenet_ssl_init_server_context(&(ssl_ctx->server), http_infos->hostname) < 0) { return -1; } proxenet_ssl_wrap_socket(&(ssl_ctx->server.context), server_sock); retcode = proxenet_ssl_handshake(&(ssl_ctx->server.context)); if (retcode < 0) { xlog(LOG_ERROR, "handshake %s->client failed [code: %#x]\n", PROGNAME, retcode); xlog(LOG_ERROR, "Server SSL handshake failed for '%s:%d'.\n", http_infos->hostname, http_infos->port, retcode); return -1; } #ifdef DEBUG xlog(LOG_DEBUG, "SSL handshake with client done, srv_sock=%d\n", *server_sock); #endif } } return retcode; }