From e4db2b2120efe5388a852aac377421a5059ff21f Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Tue, 24 Jul 2012 12:17:00 +0000 Subject: [PATCH] Fix handling of ProxyBlock if a forward proxy is configured, and fix mod_proxy_connect to avoid an inappropriate DNS lookup: * modules/proxy/proxy_util.c (ap_proxy_checkproxyblock): Take hostname argument, make address argument optional. Check names against hostname arg, omit if addr not given. (ap_proxy_determine_connection): Adjust for the above; pass hostname from URI not the next hop. * modules/proxy/mod_proxy_ftp.c (proxy_ftp_handler): Adjust for ap_proxy_checkproxyblock change. * modules/proxy/mod_proxy_connect.c (proxy_connect_handler): Adjust similarly, and avoid the DNS lookup on the request-URI hostname if a proxy is used. * include/ap_mmn.h: Bump MMN. PR: 43697 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1365001 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 6 ++++ include/ap_mmn.h | 5 +-- modules/proxy/mod_proxy.h | 14 +++++++- modules/proxy/mod_proxy_connect.c | 58 ++++++++++++------------------- modules/proxy/mod_proxy_ftp.c | 2 +- modules/proxy/proxy_util.c | 30 ++++++++++------ 6 files changed, 64 insertions(+), 51 deletions(-) diff --git a/CHANGES b/CHANGES index 323ca3123f3..0690112e5f7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,12 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.0 + *) mod_proxy: Check hostname from request URI against ProxyBlock list, + not forward proxy, if ProxyRemote* is configured. [Joe Orton] + + *) mod_proxy_connect: Avoid DNS lookup on hostname from request URI + if ProxyRemote* is configured. PR 43697. [Joe Orton] + *) mod_lbmethod_heartbeat, mod_heartmonitor: Respect DefaultRuntimeDir/ DEFAULT_REL_RUNTIMEDIR for the heartbeat storage file. [Jeff Trawick] diff --git a/include/ap_mmn.h b/include/ap_mmn.h index f80cfca3c36..cf77bd7fbf4 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -397,14 +397,15 @@ * 20120211.2 (2.5.0-dev) Add ap_runtime_dir_relative * 20120211.3 (2.5.0-dev) Add forcerecovery to proxy_balancer_shared struct * 20120211.4 (2.5.0-dev) Add missing HTTP status codes registered with IANA. + * 20120724.0 (2.5.0-dev) Add hostname argument to ap_proxy_checkproxyblock. */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ #ifndef MODULE_MAGIC_NUMBER_MAJOR -#define MODULE_MAGIC_NUMBER_MAJOR 20120211 +#define MODULE_MAGIC_NUMBER_MAJOR 20120724 #endif -#define MODULE_MAGIC_NUMBER_MINOR 4 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 0 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 5ad91fb595d..6cde1412f79 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -533,7 +533,19 @@ PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, en PROXY_DECLARE(char *)ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp, char **passwordp, char **hostp, apr_port_t *port); PROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *message); -PROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, apr_sockaddr_t *uri_addr); + +/** Test whether the hostname/address of the request are blocked by the ProxyBlock + * configuration. + * @param r request + * @param conf server configuration + * @param hostname hostname from request URI + * @param addr resolved address of hostname, or NULL if not known + * @return OK on success, or else an errro + */ +PROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, + const char *hostname, apr_sockaddr_t *addr); + + PROXY_DECLARE(int) ap_proxy_pre_http_request(conn_rec *c, request_rec *r); /* DEPRECATED (will be replaced with ap_proxy_connect_backend */ PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **, const char *, apr_sockaddr_t *, const char *, proxy_server_conf *, request_rec *); diff --git a/modules/proxy/mod_proxy_connect.c b/modules/proxy/mod_proxy_connect.c index 9a14eb71446..1636c16dbff 100644 --- a/modules/proxy/mod_proxy_connect.c +++ b/modules/proxy/mod_proxy_connect.c @@ -205,7 +205,7 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, conn_rec *backconn; apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc); - apr_status_t err, rv; + apr_status_t rv; apr_size_t nbytes; char buffer[HUGE_STRING_LEN]; apr_socket_t *client_socket = ap_get_conn_socket(c); @@ -216,7 +216,7 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, const apr_pollfd_t *signalled; apr_int32_t pollcnt, pi; apr_int16_t pollevent; - apr_sockaddr_t *uri_addr, *connect_addr; + apr_sockaddr_t *nexthop; apr_uri_t uri; const char *connectname; @@ -246,37 +246,32 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01019) "connecting %s to %s:%d", url, uri.hostname, uri.port); - /* do a DNS lookup for the destination host */ - err = apr_sockaddr_info_get(&uri_addr, uri.hostname, APR_UNSPEC, uri.port, - 0, p); - if (APR_SUCCESS != err) { + /* Determine host/port of next hop; from request URI or of a proxy. */ + connectname = proxyname ? proxyname : uri.hostname; + connectport = proxyname ? proxyport : uri.port; + + /* Do a DNS lookup for the next hop */ + rv = apr_sockaddr_info_get(&nexthop, connectname, APR_UNSPEC, + connectport, 0, p); + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO() + "failed to resolve hostname '%s'", connectname); return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p, "DNS lookup failure for: ", - uri.hostname, NULL)); + connectname, NULL)); } - /* are we connecting directly, or via a proxy? */ - if (proxyname) { - connectname = proxyname; - connectport = proxyport; - err = apr_sockaddr_info_get(&connect_addr, proxyname, APR_UNSPEC, - proxyport, 0, p); - } - else { - connectname = uri.hostname; - connectport = uri.port; - connect_addr = uri_addr; + /* Check ProxyBlock directive on the hostname/address. */ + if (ap_proxy_checkproxyblock(r, conf, uri.hostname, + proxyname ? NULL : nexthop) != OK) { + return ap_proxyerror(r, HTTP_FORBIDDEN, + "Connect to remote machine blocked"); } + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "connecting to remote proxy %s on port %d", connectname, connectport); - /* check if ProxyBlock directive on this host */ - if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) { - return ap_proxyerror(r, HTTP_FORBIDDEN, - "Connect to remote machine blocked"); - } - /* Check if it is an allowed port */ if(!allowed_port(c_conf, uri.port)) { return ap_proxyerror(r, HTTP_FORBIDDEN, @@ -289,15 +284,6 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, * We have determined who to connect to. Now make the connection. */ - /* get all the possible IP addresses for the destname and loop through them - * until we get a successful connection - */ - if (APR_SUCCESS != err) { - return ap_proxyerror(r, HTTP_BAD_GATEWAY, - apr_pstrcat(p, "DNS lookup failure for: ", - connectname, NULL)); - } - /* * At this point we have a list of one or more IP addresses of * the machine to connect to. If configured, reorder this @@ -308,7 +294,7 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, * For now we do nothing, ie we get DNS round robin. * XXX FIXME */ - failed = ap_proxy_connect_to_backend(&sock, "CONNECT", connect_addr, + failed = ap_proxy_connect_to_backend(&sock, "CONNECT", nexthop, connectname, conf, r); /* handle a permanent error from the above loop */ @@ -355,7 +341,7 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, /* peer reset */ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01021) "an error occurred creating a new connection " - "to %pI (%s)", connect_addr, connectname); + "to %pI (%s)", nexthop, connectname); apr_socket_close(sock); return HTTP_INTERNAL_SERVER_ERROR; } @@ -370,7 +356,7 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, "connection complete to %pI (%s)", - connect_addr, connectname); + nexthop, connectname); apr_table_setn(r->notes, "proxy-source-port", apr_psprintf(r->pool, "%hu", backconn->local_addr->port)); diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c index 8db694a13fb..825e2094f0d 100644 --- a/modules/proxy/mod_proxy_ftp.c +++ b/modules/proxy/mod_proxy_ftp.c @@ -1143,7 +1143,7 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, } /* check if ProxyBlock directive on this host */ - if (OK != ap_proxy_checkproxyblock(r, conf, connect_addr)) { + if (OK != ap_proxy_checkproxyblock(r, conf, connectname, connect_addr)) { return ap_proxyerror(r, HTTP_FORBIDDEN, "Connect to remote machine blocked"); } diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 7063b152073..1a28ed8aa6d 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -759,29 +759,36 @@ static int proxy_match_word(struct dirconn_entry *This, request_rec *r) return host != NULL && ap_strstr_c(host, This->name) != NULL; } -/* checks whether a host in uri_addr matches proxyblock */ PROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, - apr_sockaddr_t *uri_addr) + const char *hostname, apr_sockaddr_t *addr) { int j; - apr_sockaddr_t * src_uri_addr = uri_addr; + /* XXX FIXME: conf->noproxies->elts is part of an opaque structure */ for (j = 0; j < conf->noproxies->nelts; j++) { struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts; struct apr_sockaddr_t *conf_addr = npent[j].addr; - uri_addr = src_uri_addr; + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "checking remote machine [%s] against [%s]", - uri_addr->hostname, npent[j].name); - if (ap_strstr_c(uri_addr->hostname, npent[j].name) + hostname, npent[j].name); + if (ap_strstr_c(hostname, npent[j].name) || npent[j].name[0] == '*') { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(00916) "connect to remote machine %s blocked: name %s " - "matched", uri_addr->hostname, npent[j].name); + "matched", hostname, npent[j].name); return HTTP_FORBIDDEN; } + + /* No IP address checks if no IP address was passed in, + * i.e. the forward address proxy case, where this server does + * not resolve the hostname. */ + if (!addr) + continue; + while (conf_addr) { - uri_addr = src_uri_addr; + apr_sockaddr_t *uri_addr = addr; + while (uri_addr) { char *conf_ip; char *uri_ip; @@ -792,8 +799,8 @@ PROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *c uri_ip); if (!apr_strnatcasecmp(conf_ip, uri_ip)) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(00917) - "connect to remote machine %s blocked: " - "IP %s matched", uri_addr->hostname, conf_ip); + "connect to remote machine %s blocked: " + "IP %s matched", hostname, conf_ip); return HTTP_FORBIDDEN; } uri_addr = uri_addr->next; @@ -2128,7 +2135,8 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, } } /* check if ProxyBlock directive on this host */ - if (OK != ap_proxy_checkproxyblock(r, conf, conn->addr)) { + if (OK != ap_proxy_checkproxyblock(r, conf, uri->hostname, + proxyname ? NULL : conn->addr)) { return ap_proxyerror(r, HTTP_FORBIDDEN, "Connect to remote machine blocked"); } -- 2.47.3