Index: modules/proxy/mod_proxy_connect.c =================================================================== --- modules/proxy/mod_proxy_connect.c (revision 908621) +++ modules/proxy/mod_proxy_connect.c (working copy) @@ -252,9 +252,15 @@ /* 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"); + "Connect to remote machine blocked by block"); } + /* check if ProxyAllow directive on this host */ + if (OK != ap_proxy_checkproxyallow(r, conf, uri_addr)) { + return ap_proxyerror(r, HTTP_FORBIDDEN, + "Connect to remote machine blocked by allow"); + } + /* Check if it is an allowed port */ if(!allowed_port(c_conf, uri.port)) { return ap_proxyerror(r, HTTP_FORBIDDEN, Index: modules/proxy/proxy_util.c =================================================================== --- modules/proxy/proxy_util.c (revision 908621) +++ modules/proxy/proxy_util.c (working copy) @@ -931,6 +931,47 @@ return OK; } +/* checks whether a host in uri_addr matches proxyallow */ +PROXY_DECLARE(int) ap_proxy_checkproxyallow(request_rec *r, proxy_server_conf *conf, + apr_sockaddr_t *uri_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->allowproxies->nelts; j++) { + struct noproxy_entry *apent = (struct noproxy_entry *) conf->allowproxies->elts; + struct apr_sockaddr_t *conf_addr = apent[j].addr; + uri_addr = src_uri_addr; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "proxy: checking remote machine [%s] against [%s]", uri_addr->hostname, apent[j].name); + if ((apent[j].name && ap_strstr_c(uri_addr->hostname, apent[j].name)) + || apent[j].name[0] == '*') { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, + "proxy: connect to remote machine %s allowed: name %s matched", uri_addr->hostname, apent[j].name); + return OK; + } + while (conf_addr) { + uri_addr = src_uri_addr; + while (uri_addr) { + char *conf_ip; + char *uri_ip; + apr_sockaddr_ip_get(&conf_ip, conf_addr); + apr_sockaddr_ip_get(&uri_ip, uri_addr); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "proxy: ProxyAllow comparing %s and %s", conf_ip, uri_ip); + if (!apr_strnatcasecmp(conf_ip, uri_ip)) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, + "proxy: connect to remote machine %s allow: IP %s matched", uri_addr->hostname, conf_ip); + return OK; + } + uri_addr = uri_addr->next; + } + conf_addr = conf_addr->next; + } + } + return HTTP_FORBIDDEN; +} + /* set up the minimal filter set */ PROXY_DECLARE(int) ap_proxy_pre_http_request(conn_rec *c, request_rec *r) { @@ -2174,6 +2215,11 @@ return ap_proxyerror(r, HTTP_FORBIDDEN, "Connect to remote machine blocked"); } + /* check if ProxyAllow directive on this host */ + if (OK != ap_proxy_checkproxyallow(r, conf, conn->addr)) { + return ap_proxyerror(r, HTTP_FORBIDDEN, + "Connect to remote machine blocked"); + } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: connected %s to %s:%d", *url, conn->hostname, conn->port); Index: modules/proxy/mod_proxy.c =================================================================== --- modules/proxy/mod_proxy.c (revision 908621) +++ modules/proxy/mod_proxy.c (working copy) @@ -1084,6 +1084,7 @@ ps->proxies = apr_array_make(p, 10, sizeof(struct proxy_remote)); ps->aliases = apr_array_make(p, 10, sizeof(struct proxy_alias)); ps->noproxies = apr_array_make(p, 10, sizeof(struct noproxy_entry)); + ps->allowproxies = apr_array_make(p, 10, sizeof(struct noproxy_entry)); ps->dirconn = apr_array_make(p, 10, sizeof(struct dirconn_entry)); ps->workers = apr_array_make(p, 10, sizeof(proxy_worker)); ps->balancers = apr_array_make(p, 10, sizeof(proxy_balancer)); @@ -1121,6 +1122,7 @@ ps->sec_proxy = apr_array_append(p, base->sec_proxy, overrides->sec_proxy); ps->aliases = apr_array_append(p, base->aliases, overrides->aliases); ps->noproxies = apr_array_append(p, base->noproxies, overrides->noproxies); + ps->allowproxies = apr_array_append(p, base->allowproxies, overrides->allowproxies); ps->dirconn = apr_array_append(p, base->dirconn, overrides->dirconn); ps->workers = apr_array_append(p, base->workers, overrides->workers); ps->balancers = apr_array_append(p, base->balancers, overrides->balancers); @@ -2067,6 +2069,8 @@ RSRC_CONF|ACCESS_CONF, "Domain rewrite rule for proxying cookies"), AP_INIT_ITERATE("ProxyBlock", set_proxy_exclude, NULL, RSRC_CONF, "A list of names, hosts or domains to which the proxy will not connect"), + AP_INIT_ITERATE("ProxyAllow", set_proxy_include, NULL, RSRC_CONF, + "A list of names, hosts or domains to which the proxy will connect"), AP_INIT_TAKE1("ProxyReceiveBufferSize", set_recv_buffer_size, NULL, RSRC_CONF, "Receive buffer size for outgoing HTTP and FTP connections in bytes"), AP_INIT_TAKE1("ProxyIOBufferSize", set_io_buffer_size, NULL, RSRC_CONF, @@ -2157,6 +2161,38 @@ return OK; } +static const char * + set_proxy_include(cmd_parms *parms, void *dummy, const char *arg) +{ + server_rec *s = parms->server; + proxy_server_conf *conf = + ap_get_module_config(s->module_config, &proxy_module); + struct noproxy_entry *new; + struct noproxy_entry *list = (struct noproxy_entry *) conf->allowproxies->elts; + struct apr_sockaddr_t *addr; + int found = 0; + int i; + + /* Don't duplicate entries */ + for (i = 0; i < conf->allowproxies->nelts; i++) { + if (strcasecmp(arg, list[i].name) == 0) { /* ignore case for host names */ + found = 1; + } + } + + if (!found) { + new = apr_array_push(conf->allowproxies); + new->name = arg; + if (APR_SUCCESS == apr_sockaddr_info_get(&addr, new->name, APR_UNSPEC, 0, 0, parms->pool)) { + new->addr = addr; + } + else { + new->addr = NULL; + } + } + return NULL; +} + /* * proxy Extension to mod_status */ Index: modules/proxy/mod_proxy.h =================================================================== --- modules/proxy/mod_proxy.h (revision 908621) +++ modules/proxy/mod_proxy.h (working copy) @@ -177,6 +177,7 @@ status_full } proxy_status; /* Status display options */ char proxy_status_set; + apr_array_header_t *allowproxies; apr_pool_t *pool; /* Pool used for allocating this struct */ } proxy_server_conf; Index: modules/proxy/mod_proxy_ftp.c =================================================================== --- modules/proxy/mod_proxy_ftp.c (revision 908621) +++ modules/proxy/mod_proxy_ftp.c (working copy) @@ -1079,6 +1079,12 @@ "Connect to remote machine blocked"); } + /* check if ProxyBlock directive on this host */ + if (OK != ap_proxy_checkproxyallow(r, conf, connect_addr)) { + return ap_proxyerror(r, HTTP_FORBIDDEN, + "Connect to remote machine blocked"); + } + /* create space for state information */ backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config, &proxy_ftp_module); if (!backend) {