From: William A. Rowe Jr Date: Thu, 11 Feb 2016 21:43:32 +0000 (+0000) Subject: Introduce an ap_get_useragent_host() accessor to replace the old X-Git-Tag: 2.5.0-alpha~2114 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=69479166433991df62715f6fa4c6a5889121f4f8;p=thirdparty%2Fapache%2Fhttpd.git Introduce an ap_get_useragent_host() accessor to replace the old ap_get_remote_host() in most applications, but preserve the original behavior for all ap_get_remote_host() consumers (mostly, because we don't have the request_rec in the first place, and also to avoid any unintended consequences). This accessor continues to store the remote_host of connection based uesr agents within the conn_rec for optimization. Only where some other module modifies the useragent_addr will we perform a per-request query of the remote_host. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1729897 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/include/ap_mmn.h b/include/ap_mmn.h index b25abcd4ce2..aca47eb4974 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -500,6 +500,8 @@ * 20150222.9 (2.5.0-dev) Add epxr_hander to core_dir_config. * 20150222.10 (2.5.0-dev) Add new ap_update_child_status...() methods, * add protocol to worker_score in scoreboard.h + * 20150222.11 (2.5.0-dev) Split useragent_host from the conn_rec into + * the request_rec, with ap_get_useragent_host() */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ @@ -507,7 +509,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20150222 #endif -#define MODULE_MAGIC_NUMBER_MINOR 10 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 11 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/http_core.h b/include/http_core.h index 684fba49cfc..a6f1d28b8b2 100644 --- a/include/http_core.h +++ b/include/http_core.h @@ -158,6 +158,32 @@ AP_DECLARE(int) ap_allow_overrides(request_rec *r); */ AP_DECLARE(const char *) ap_document_root(request_rec *r); +/** + * Lookup the remote user agent's DNS name or IP address + * @ingroup get_remote_hostname + * @param req The current request + * @param type The type of lookup to perform. One of: + *
+ *     REMOTE_HOST returns the hostname, or NULL if the hostname
+ *                 lookup fails.  It will force a DNS lookup according to the
+ *                 HostnameLookups setting.
+ *     REMOTE_NAME returns the hostname, or the dotted quad if the
+ *                 hostname lookup fails.  It will force a DNS lookup according
+ *                 to the HostnameLookups setting.
+ *     REMOTE_NOLOOKUP is like REMOTE_NAME except that a DNS lookup is
+ *                     never forced.
+ *     REMOTE_DOUBLE_REV will always force a DNS lookup, and also force
+ *                   a double reverse lookup, regardless of the HostnameLookups
+ *                   setting.  The result is the (double reverse checked)
+ *                   hostname, or NULL if any of the lookups fail.
+ * 
+ * @param str_is_ip unless NULL is passed, this will be set to non-zero on + * output when an IP address string is returned + * @return The remote hostname (based on the request useragent_ip) + */ +AP_DECLARE(const char *) ap_get_useragent_host(request_rec *req, int type, + int *str_is_ip); + /** * Lookup the remote client's DNS name or IP address * @ingroup get_remote_host @@ -180,7 +206,7 @@ AP_DECLARE(const char *) ap_document_root(request_rec *r); * * @param str_is_ip unless NULL is passed, this will be set to non-zero on output when an IP address * string is returned - * @return The remote hostname + * @return The remote hostname (based on the connection client_ip) */ AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config, int type, int *str_is_ip); diff --git a/include/httpd.h b/include/httpd.h index 196de1d6e10..28d275b1d35 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -1056,6 +1056,16 @@ struct request_rec { apr_table_t *trailers_in; /** MIME trailer environment from the response */ apr_table_t *trailers_out; + + /** Originator's DNS name, if known. NULL if DNS hasn't been checked, + * "" if it has and no address was found. N.B. Only access this though + * ap_get_useragent_host() */ + char *useragent_host; + /** have we done double-reverse DNS? -1 yes/failure, 0 not yet, + * 1 yes/success + * TODO: 2 bit signed bitfield when this structure is compacted + */ + int double_reverse; }; /** diff --git a/server/core.c b/server/core.c index 6de6474624e..2c56d08741c 100644 --- a/server/core.c +++ b/server/core.c @@ -887,27 +887,30 @@ char *ap_response_code_string(request_rec *r, int error_index) /* Code from Harald Hanche-Olsen */ -static APR_INLINE void do_double_reverse (conn_rec *conn) +static APR_INLINE void do_double_reverse (int *double_reverse, + const char *remote_host, + apr_sockaddr_t *client_addr, + apr_pool_t *pool) { apr_sockaddr_t *sa; apr_status_t rv; - if (conn->double_reverse) { + if (*double_reverse) { /* already done */ return; } - if (conn->remote_host == NULL || conn->remote_host[0] == '\0') { + if (remote_host == NULL || remote_host[0] == '\0') { /* single reverse failed, so don't bother */ - conn->double_reverse = -1; + *double_reverse = -1; return; } - rv = apr_sockaddr_info_get(&sa, conn->remote_host, APR_UNSPEC, 0, 0, conn->pool); + rv = apr_sockaddr_info_get(&sa, remote_host, APR_UNSPEC, 0, 0, pool); if (rv == APR_SUCCESS) { while (sa) { - if (apr_sockaddr_equal(sa, conn->client_addr)) { - conn->double_reverse = 1; + if (apr_sockaddr_equal(sa, client_addr)) { + *double_reverse = 1; return; } @@ -915,7 +918,7 @@ static APR_INLINE void do_double_reverse (conn_rec *conn) } } - conn->double_reverse = -1; + *double_reverse = -1; } AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config, @@ -953,7 +956,8 @@ AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config, ap_str_tolower(conn->remote_host); if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) { - do_double_reverse(conn); + do_double_reverse(&conn->double_reverse, conn->remote_host, + conn->client_addr, conn->pool) if (conn->double_reverse != 1) { conn->remote_host = NULL; } @@ -967,7 +971,8 @@ AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config, } if (type == REMOTE_DOUBLE_REV) { - do_double_reverse(conn); + do_double_reverse(&conn->double_reverse, conn->remote_host, + conn->client_addr, conn->pool) if (conn->double_reverse == -1) { return NULL; } @@ -992,6 +997,80 @@ AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config, } } +AP_DECLARE(const char *) ap_get_useragent_host(request_rec *r, + int type, int *str_is_ip) +{ + conn_rec *conn = r->connection; + int hostname_lookups; + int ignored_str_is_ip; + + if (req->useragent_addr == conn->client_addr) { + return ap_get_remote_host(conn, r->per_dir_config, type, str_is_ip); + } + + if (!str_is_ip) { /* caller doesn't want to know */ + str_is_ip = &ignored_str_is_ip; + } + *str_is_ip = 0; + + hostname_lookups = ((core_dir_config *) + ap_get_core_module_config(r->per_dir_config)) + ->hostname_lookups; + if (hostname_lookups == HOSTNAME_LOOKUP_UNSET) { + hostname_lookups = HOSTNAME_LOOKUP_OFF; + } + + if (type != REMOTE_NOLOOKUP + && r->useragent_host == NULL + && (type == REMOTE_DOUBLE_REV + || hostname_lookups != HOSTNAME_LOOKUP_OFF)) { + + if (apr_getnameinfo(&r->useragent_host, r->useragent_addr, 0) + == APR_SUCCESS) { + ap_str_tolower(r->useragent_host); + + if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) { + do_double_reverse(&r->double_reverse, r->useragent_host, + r->useragent_addr, r->pool) + if (r->double_reverse != 1) { + r->useragent_host = NULL; + } + } + } + + /* if failed, set it to the NULL string to indicate error */ + if (r->useragent_host == NULL) { + r->useragent_host = ""; + } + } + + if (type == REMOTE_DOUBLE_REV) { + do_double_reverse(&r->double_reverse, r->useragent_host, + r->useragent_addr, r->pool) + if (r->double_reverse == -1) { + return NULL; + } + } + + /* + * Return the desired information; either the remote DNS name, if found, + * or either NULL (if the hostname was requested) or the IP address + * (if any identifier was requested). + */ + if (r->useragent_host != NULL && r->useragent_host[0] != '\0') { + return r->useragent_host; + } + else { + if (type == REMOTE_HOST || type == REMOTE_DOUBLE_REV) { + return NULL; + } + else { + *str_is_ip = 1; + return r->useragent_ip; + } + } +} + /* * Optional function coming from mod_ident, used for looking up ident user */ @@ -1015,6 +1094,7 @@ AP_DECLARE(const char *) ap_get_remote_logname(request_rec *r) * name" as supplied by a possible Host: header or full URI. * * The DNS option to UseCanonicalName causes this routine to do a + / * reverse lookup on the local IP address of the connection and use * that for the ServerName. This makes its value more reliable while * at the same time allowing Demon's magic virtual hosting to work. @@ -5359,7 +5439,7 @@ static void core_dump_config(apr_pool_t *p, server_rec *s) } } -static int core_upgrade_handler(request_rec *r) +static int core_upgrade_request(request_rec *r) { conn_rec *c = r->connection; const char *upgrade; @@ -5387,8 +5467,15 @@ static int core_upgrade_handler(request_rec *r) if (offers && offers->nelts > 0) { const char *protocol = ap_select_protocol(c, r, NULL, offers); if (protocol && strcmp(protocol, ap_get_protocol(c))) { + apr_status_t rv; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02909) "Upgrade selects '%s'", protocol); + /* RFC7230 6.7: Stupid constraint, detect request body, + * send 100-continue, read it immediately, and set it aside + * for the filters/handler to process after upgrade + * XXX: TODO + */ + /* Let the client know what we are upgrading to. */ apr_table_clear(r->headers_out); apr_table_setn(r->headers_out, "Upgrade", protocol); @@ -5398,20 +5485,25 @@ static int core_upgrade_handler(request_rec *r) r->status_line = ap_get_status_line(r->status); ap_send_interim_response(r, 1); - ap_switch_protocol(c, r, r->server, protocol); - - /* make sure httpd closes the connection after this */ - c->keepalive = AP_CONN_CLOSE; - return DONE; + rv = ap_switch_protocol(c, r, r->server, protocol); + if (rv == APR_EOF) + { + /* make sure httpd closes the connection after this */ + c->keepalive = AP_CONN_CLOSE; + return DONE; + } } } } } - else if (!c->keepalives) { - /* first request on a master connection, if we have protocols other - * than the current one enabled here, announce them to the - * client. If the client is already talking a protocol with requests - * on slave connections, leave it be. */ + else { + /* first request on a master connection, announce our presence + * and presume an h2c client will remember the advertisement. + */ + if (!c->keepalives) { + /* No upgrade: requested; if we have protocols other than the current + * one enabled here, announce them to the client. + */ const apr_array_header_t *upgrades; ap_get_protocol_upgrades(c, r, NULL, 0, &upgrades); if (upgrades && upgrades->nelts > 0) { @@ -5420,16 +5512,7 @@ static int core_upgrade_handler(request_rec *r) apr_table_setn(r->headers_out, "Connection", "Upgrade"); } } - - return DECLINED; -} -static int core_upgrade_storage(request_rec *r) -{ - if ((r->method_number == M_OPTIONS) && r->uri && (r->uri[0] == '*') && - (r->uri[1] == '\0')) { - return core_upgrade_handler(r); - } return DECLINED; } @@ -5455,12 +5538,11 @@ static void register_hooks(apr_pool_t *p) ap_hook_check_config(core_check_config,NULL,NULL,APR_HOOK_FIRST); ap_hook_test_config(core_dump_config,NULL,NULL,APR_HOOK_FIRST); ap_hook_translate_name(ap_core_translate,NULL,NULL,APR_HOOK_REALLY_LAST); - ap_hook_map_to_storage(core_upgrade_storage,NULL,NULL,APR_HOOK_REALLY_FIRST); ap_hook_map_to_storage(core_map_to_storage,NULL,NULL,APR_HOOK_REALLY_LAST); ap_hook_open_logs(ap_open_logs,NULL,NULL,APR_HOOK_REALLY_FIRST); ap_hook_child_init(core_child_init,NULL,NULL,APR_HOOK_REALLY_FIRST); ap_hook_child_init(ap_logs_child_init,NULL,NULL,APR_HOOK_MIDDLE); - ap_hook_handler(core_upgrade_handler,NULL,NULL,APR_HOOK_REALLY_FIRST); + ap_hook_post_read_request(core_upgrade_request,NULL,NULL,APR_HOOK_LAST); ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST); /* FIXME: I suspect we can eliminate the need for these do_nothings - Ben */ ap_hook_type_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);