From 7275f9bcc5e87b6fa243479aed8ed64b28c85cd5 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Thu, 27 Feb 2014 14:52:12 +0000 Subject: [PATCH] Don't reuse a SSL backend connection whose SNI differs. PR 55782. This may happen when ProxyPreserveHost is on and the proxy-worker handles connections to different Hosts. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1572606 13f79535-47bb-0310-9956-ffa450edef68 --- modules/proxy/mod_proxy.h | 1 + modules/proxy/mod_proxy_http.c | 23 ++++------------------- modules/proxy/proxy_util.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index b99ee17b90d..e2978890147 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -254,6 +254,7 @@ typedef struct { unsigned int need_flush:1; /* Flag to decide whether we need to flush the * filter chain or not */ unsigned int inreslist:1; /* connection in apr_reslist? */ + const char *ssl_hostname; /* Hostname (SNI) in use by SSL connection */ } proxy_conn_rec; typedef struct { diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index 9f7a6b40266..6ebc2ccb0b4 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -1975,25 +1975,10 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, * requested, such that mod_ssl can check if it is requested to do * so. */ - if (is_ssl) { - proxy_dir_conf *dconf; - const char *ssl_hostname; - - /* - * In the case of ProxyPreserveHost on use the hostname of - * the request if present otherwise use the one from the - * backend request URI. - */ - dconf = ap_get_module_config(r->per_dir_config, &proxy_module); - if ((dconf->preserve_host != 0) && (r->hostname != NULL)) { - ssl_hostname = r->hostname; - } - else { - ssl_hostname = uri->hostname; - } - - apr_table_set(backend->connection->notes, "proxy-request-hostname", - ssl_hostname); + if (backend->ssl_hostname) { + apr_table_setn(backend->connection->notes, + "proxy-request-hostname", + backend->ssl_hostname); } /* Step Three-and-a-Half: See if the socket is still connected (if diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 0cd27c8ea09..27cd0f456fe 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -1405,6 +1405,7 @@ static void socket_cleanup(proxy_conn_rec *conn) { conn->sock = NULL; conn->connection = NULL; + conn->ssl_hostname = NULL; apr_pool_clear(conn->scpool); } @@ -2346,6 +2347,35 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, return ap_proxyerror(r, HTTP_FORBIDDEN, "Connect to remote machine blocked"); } + /* + * When SSL is configured, determine the hostname (SNI) for the request + * and save it in conn->ssl_hostname. Close any reused connection whose + * SNI differs. + */ + if (conn->is_ssl) { + proxy_dir_conf *dconf; + const char *ssl_hostname; + /* + * In the case of ProxyPreserveHost on use the hostname of + * the request if present otherwise use the one from the + * backend request URI. + */ + dconf = ap_get_module_config(r->per_dir_config, &proxy_module); + if (dconf->preserve_host) { + ssl_hostname = r->hostname; + } + else { + ssl_hostname = conn->hostname; + } + if (conn->ssl_hostname != NULL && + (!ssl_hostname || strcasecmp(conn->ssl_hostname, + ssl_hostname) != 0)) { + socket_cleanup(conn); + } + if (conn->ssl_hostname == NULL) { + conn->ssl_hostname = apr_pstrdup(conn->scpool, ssl_hostname); + } + } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00947) "connected %s to %s:%d", *url, conn->hostname, conn->port); return OK; -- 2.47.3