Index: modules/proxy/proxy_util.c =================================================================== --- modules/proxy/proxy_util.c (revision 662381) +++ modules/proxy/proxy_util.c (working copy) @@ -2275,7 +2275,7 @@ apr_status_t rv; int connected = 0; int loglevel; - apr_sockaddr_t *backend_addr = conn->addr; + apr_sockaddr_t *backend_addr = conn->addr, *local_addr; apr_socket_t *newsock; void *sconf = s->module_config; proxy_server_conf *conf = @@ -2349,6 +2349,36 @@ "proxy: %s: fam %d socket created to connect to %s", proxy_function, backend_addr->family, worker->hostname); + if (conf->bindopt_set) { + const int idx = conf->bind_idx; + const int range = conf->bind_range; + const int start = conf->bind_port; + for(int i = 0; i < range; ++i) { /* loop until we can bind correctly*/ + int port = start + ((idx + i) % range); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: %s: trying to bind to %s:%u", + proxy_function, conf->bind_addr,port, NULL); + + local_addr = conf->bind_addr; + local_addr->sa.sin.sin_port = htons(port); + local_addr->port = port; + + if ((rv = apr_socket_bind(newsock, local_addr)) == APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: %s: bound to %s:%u", + proxy_function, conf->bind_addr, local_addr->port, NULL); + conf->bind_idx = i + 1; + break; + } else { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: %s: not bound to %s%u", + proxy_function, conf->bind_addr, local_addr->port, NULL); + } + } + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "proxy: %s: can not bind to %s:%u+%u", + proxy_function,conf->bind_addr, conf->bind_port, conf->bind_range, NULL); + return DECLINED; + } + } + /* make the connection out of the socket */ rv = apr_socket_connect(newsock, backend_addr); Index: modules/proxy/mod_proxy.c =================================================================== --- modules/proxy/mod_proxy.c (revision 662381) +++ modules/proxy/mod_proxy.c (working copy) @@ -1066,6 +1066,8 @@ ps->timeout_set = 0; ps->badopt = bad_error; ps->badopt_set = 0; + ps->bindopt_set = 0; + ps->bind_idx = 0; ps->pool = p; return ps; @@ -1109,6 +1111,7 @@ ps->badopt_set = overrides->badopt_set || base->badopt_set; ps->proxy_status = (overrides->proxy_status_set == 0) ? base->proxy_status : overrides->proxy_status; ps->proxy_status_set = overrides->proxy_status_set || base->proxy_status_set; + ps->bindopt_set = overrides->bindopt_set || base->bindopt_set; ps->pool = p; return ps; } @@ -1706,6 +1709,54 @@ return NULL; } +static const char* + set_proxy_bindaddr(cmd_parms *parms, void *dummy, const char *addr) +{ + char *range, *host, *scope_id; + apr_port_t port; + int r = 0; + + proxy_server_conf *psf = + ap_get_module_config(parms->server->module_config, &proxy_module); + + range = ap_strrchr((char*)addr, '+'); + if (range) { + *range++ = 0; + r = atoi(range); + } + + /* We dont accept a single port with out a range as it would be same + * as a single threaded single process http-client + * + * We do not allow ip:0+0 or ip:0 as it can be specified more clearly + * as just ip. + * + * we dont accept a range with out a port either. + */ + if((apr_parse_addr_port(&host, &scope_id, &port, addr, parms->pool) + != APR_SUCCESS) + || scope_id /* we dont know how to use scope_id */ + || (!port && range) /* only a combo [port+range] is valid */ + || (port && !range) + || ((port + r) < 0) /* or an invalid portnumber (p+r) */ + || ((port + r) > 65534) + ) + return "ProxyBindAddress: Invalid address -" + " format is [:+]"; + + /* Preparse the address */ + apr_sockaddr_info_get(&(psf->bind_addr), host, APR_UNSPEC, 0, 0, parms->pool); + + psf->bind_port = port; + /* If there didn't exist a port then there was no range either. so we have the + * starting value 0 for r when no port was specified.*/ + psf->bind_range = r + 1; + psf->bind_idx = 0; + psf->bindopt_set = 1; + + return NULL; +} + static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) { server_rec *s = cmd->server; @@ -2088,6 +2139,8 @@ "A balancer or worker name with list of params"), AP_INIT_TAKE1("ProxyFtpDirCharset", set_ftp_directory_charset, NULL, RSRC_CONF|ACCESS_CONF, "Define the character set for proxied FTP listings"), + AP_INIT_TAKE1("ProxyBindAddress", set_proxy_bindaddr, NULL, RSRC_CONF, + "Set the source address for a proxied connection. "), {NULL} }; Index: modules/proxy/mod_proxy.h =================================================================== --- modules/proxy/mod_proxy.h (revision 662381) +++ modules/proxy/mod_proxy.h (working copy) @@ -190,6 +190,12 @@ status_full } proxy_status; /* Status display options */ char proxy_status_set; + /*bind to local ports*/ + apr_sockaddr_t *bind_addr; + apr_port_t bind_port; + apr_port_t bind_range; /* restrict the source ports used by mod_proxy */ + int bind_idx; + char bindopt_set; apr_pool_t *pool; /* Pool used for allocating this struct */ } proxy_server_conf;