diff options
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | docs/manual/mod/core.xml | 34 | ||||
-rw-r--r-- | include/http_core.h | 1 | ||||
-rw-r--r-- | include/http_vhost.h | 13 | ||||
-rw-r--r-- | server/core.c | 20 | ||||
-rw-r--r-- | server/protocol.c | 21 | ||||
-rw-r--r-- | server/vhost.c | 38 |
7 files changed, 119 insertions, 11 deletions
@@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.1 + *) core: Add StrictHostCheck to allow ucnonfigured hostnames to be + rejected. [Eric Covener] + *) mod_status: Cumulate CPU time of exited child processes in the "cu" and "cs" values. Add CPU time of the parent process to the "c" and "s" values. diff --git a/docs/manual/mod/core.xml b/docs/manual/mod/core.xml index a315816330..090719f8eb 100644 --- a/docs/manual/mod/core.xml +++ b/docs/manual/mod/core.xml @@ -5240,6 +5240,40 @@ as if 'QualifyRedirectURL ON' was configured.</compatibility> </usage> </directivesynopsis> +<directivesynopsis> +<name>StrictHostCheck</name> +<description>Controls whether the server requires the requested hostname be + listed enumerated in the virtual host handling the request + </description> +<syntax>StrictHostCheck ON|OFF</syntax> +<default>StrictHostCheck OFF</default> +<contextlist><context>server config</context><context>virtual host</context> +</contextlist> +<compatibility>Added in 2.5.1</compatibility> +<usage> + <p>By default, the server will respond to requests for any hostname, + including requests addressed to unexpected or unconfigured hostnames. + While this is convenient, it is sometimes desirable to limit what hostnames + a backend application handles since it will often generate self-referential + responses.</p> + + <p>By setting <directive>StrictHostCheck</directive> to <em>ON</em>, + the server will return an HTTP 400 error if the requested hostname + hasn't been explicitly listed by either <directive module="core" + >ServerName</directive> or <directive module="core" + >ServerAlias</directive> in the virtual host that best matches the + details of the incoming connection.</p> + + <p>This directive also allows matching of the requested hostname to hostnames + specified within the opening <directive module="core">VirtualHost</directive> + tag, which is a relatively obscure configuration mechanism that acts like + additional <directive module="core">ServerAlias</directive> entries.</p> + + <p>This directive has no affect in non-default virtual hosts. The value + inherited from the global server configuration, or the default virtualhost + for the ip:port the underlying connection, determine the effective value.</p> +</usage> +</directivesynopsis> </modulesynopsis> diff --git a/include/http_core.h b/include/http_core.h index 3b43b38f3e..fe3836fb34 100644 --- a/include/http_core.h +++ b/include/http_core.h @@ -770,6 +770,7 @@ typedef struct { apr_size_t flush_max_threshold; apr_int32_t flush_max_pipelined; + unsigned int strict_host_check; } core_server_config; /* for AddOutputFiltersByType in core.c */ diff --git a/include/http_vhost.h b/include/http_vhost.h index 3941c2b22c..91903cd58a 100644 --- a/include/http_vhost.h +++ b/include/http_vhost.h @@ -100,6 +100,19 @@ AP_DECLARE(void) ap_update_vhost_given_ip(conn_rec *conn); AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r); /** + * Updates r->server with the best name-based virtual host match, within + * the chain of matching virtual hosts selected by ap_update_vhost_given_ip. + * @param r The current request + * @param require_match 1 to return an HTTP error if the requested hostname is + * not explicitly matched to a VirtualHost. + * @return return HTTP_OK unless require_match was specified and the requested + * hostname did not match any ServerName, ServerAlias, or VirtualHost + * address-spec. + */ +AP_DECLARE(int) ap_update_vhost_from_headers_ex(request_rec *r, int require_match); + + +/** * Match the host in the header with the hostname of the server for this * request. * @param r The current request diff --git a/server/core.c b/server/core.c index ffaa647f4b..d3f2d256b9 100644 --- a/server/core.c +++ b/server/core.c @@ -525,6 +525,7 @@ static void *create_core_server_config(apr_pool_t *a, server_rec *s) conf->protocols = apr_array_make(a, 5, sizeof(const char *)); conf->protocols_honor_order = -1; conf->async_filter = 0; + conf->strict_host_check= AP_CORE_CONFIG_UNSET; return (void *)conf; } @@ -620,6 +621,12 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv) ? virt->flush_max_pipelined : base->flush_max_pipelined; + conf->strict_host_check = (virt->strict_host_check != AP_CORE_CONFIG_UNSET) + ? virt->strict_host_check + : base->strict_host_check; + + AP_CORE_MERGE_FLAG(strict_host_check, conf, base, virt); + return conf; } @@ -1962,7 +1969,12 @@ static const char *set_qualify_redirect_url(cmd_parms *cmd, void *d_, int flag) return NULL; } - +static const char *set_core_server_flag(cmd_parms *cmd, void *s_, int flag) +{ + core_server_config *conf = + ap_get_core_module_config(cmd->server->module_config); + return ap_set_flag_slot(cmd, conf, flag); +} static const char *set_override_list(cmd_parms *cmd, void *d_, int argc, char *const argv[]) { core_dir_config *d = d_; @@ -4816,7 +4828,10 @@ AP_INIT_TAKE2("CGIVar", set_cgi_var, NULL, OR_FILEINFO, AP_INIT_FLAG("QualifyRedirectURL", set_qualify_redirect_url, NULL, OR_FILEINFO, "Controls whether the REDIRECT_URL environment variable is fully " "qualified"), - +AP_INIT_FLAG("StrictHostCheck", set_core_server_flag, + (void *)APR_OFFSETOF(core_server_config, strict_host_check), + RSRC_CONF, + "Controls whether a hostname match is required"), AP_INIT_TAKE1("ForceType", ap_set_string_slot_lower, (void *)APR_OFFSETOF(core_dir_config, mime_type), OR_FILEINFO, "a mime type that overrides other configured type"), @@ -5891,4 +5906,3 @@ AP_DECLARE_MODULE(core) = { core_cmds, /* command apr_table_t */ register_hooks /* register hooks */ }; - diff --git a/server/protocol.c b/server/protocol.c index f98707472d..d57f64f65a 100644 --- a/server/protocol.c +++ b/server/protocol.c @@ -1348,10 +1348,11 @@ request_rec *ap_read_request(conn_rec *conn) apr_bucket_brigade *tmp_bb; apr_socket_t *csd; apr_interval_time_t cur_timeout; - + core_server_config *conf = NULL; request_rec *r = ap_create_request(conn); + conf = ap_get_core_module_config(r->server->module_config); tmp_bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); ap_run_pre_read_request(r, conn); @@ -1455,7 +1456,23 @@ request_rec *ap_read_request(conn_rec *conn) /* update what we think the virtual host is based on the headers we've * now read. may update status. */ - ap_update_vhost_from_headers(r); + + access_status = ap_update_vhost_from_headers_ex(r, conf->strict_host_check == AP_CORE_CONFIG_ON); + if (conf->strict_host_check == AP_CORE_CONFIG_ON && access_status != HTTP_OK) { + if (r->server == ap_server_conf) { + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO() + "Requested hostname '%s' did not match any ServerName/ServerAlias " + "in the global server configuration ", r->hostname); + } else { + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO() + "Requested hostname '%s' did not match any ServerName/ServerAlias " + "in the matching virtual host (default vhost for " + "current connection is %s:%u)", + r->hostname, r->server->defn_name, r->server->defn_line_number); + } + r->status = access_status; + } + access_status = r->status; /* Toggle to the Host:-based vhost's timeout mode to fetch the diff --git a/server/vhost.c b/server/vhost.c index 45f521269e..98b34cadb6 100644 --- a/server/vhost.c +++ b/server/vhost.c @@ -35,6 +35,7 @@ #include "http_vhost.h" #include "http_protocol.h" #include "http_core.h" +#include "http_main.h" #if APR_HAVE_ARPA_INET_H #include <arpa/inet.h> @@ -976,7 +977,13 @@ AP_DECLARE(int) ap_matches_request_vhost(request_rec *r, const char *host, } -static void check_hostalias(request_rec *r) +/* + * Updates r->server from ServerName/ServerAlias. Per the interaction + * of ip and name-based vhosts, it only looks in the best match from the + * connection-level ip-based matching. + * Returns HTTP_BAD_REQUEST if there was no match. + */ +static int update_server_from_aliases(request_rec *r) { /* * Even if the request has a Host: header containing a port we ignore @@ -1053,11 +1060,18 @@ static void check_hostalias(request_rec *r) goto found; } - return; + if (r->server == ap_server_conf) { + if (matches_aliases(ap_server_conf, host)) { + s = ap_server_conf; + goto found; + } + } + return HTTP_BAD_REQUEST; found: /* s is the first matching server, we're done */ r->server = s; + return HTTP_OK; } @@ -1074,7 +1088,7 @@ static void check_serverpath(request_rec *r) * This is in conjunction with the ServerPath code in http_core, so we * get the right host attached to a non- Host-sending request. * - * See the comment in check_hostalias about how each vhost can be + * See the comment in update_server_from_aliases about how each vhost can be * listed multiple times. */ @@ -1138,10 +1152,16 @@ static APR_INLINE const char *construct_host_header(request_rec *r, AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r) { + ap_update_vhost_from_headers_ex(r, 0); +} + +AP_DECLARE(int) ap_update_vhost_from_headers_ex(request_rec *r, int require_match) +{ core_server_config *conf = ap_get_core_module_config(r->server->module_config); const char *host_header = apr_table_get(r->headers_in, "Host"); int is_v6literal = 0; int have_hostname_from_url = 0; + int rc = HTTP_OK; if (r->hostname) { /* @@ -1154,8 +1174,8 @@ AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r) else if (host_header != NULL) { is_v6literal = fix_hostname(r, host_header, conf->http_conformance); } - if (r->status != HTTP_OK) - return; + if (!require_match && r->status != HTTP_OK) + return HTTP_OK; if (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE) { /* @@ -1176,10 +1196,16 @@ AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r) /* check if we tucked away a name_chain */ if (r->connection->vhost_lookup_data) { if (r->hostname) - check_hostalias(r); + rc = update_server_from_aliases(r); else check_serverpath(r); } + else if (require_match) { + /* check the base server config */ + rc = update_server_from_aliases(r); + } + + return rc; } /** |