summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES3
-rw-r--r--docs/manual/mod/core.xml34
-rw-r--r--include/http_core.h1
-rw-r--r--include/http_vhost.h13
-rw-r--r--server/core.c20
-rw-r--r--server/protocol.c21
-rw-r--r--server/vhost.c38
7 files changed, 119 insertions, 11 deletions
diff --git a/CHANGES b/CHANGES
index 75d41c2da0..0dfe56d11c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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;
}
/**