-*- 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.
</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>
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 */
*/
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.
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;
}
? 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;
}
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_;
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"),
core_cmds, /* command apr_table_t */
register_hooks /* register hooks */
};
-
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);
/* 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
#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>
}
-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
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;
}
* 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.
*/
}
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) {
/*
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) {
/*
/* 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;
}
/**