1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-07 04:02:58 +03:00

Some code rewriting in ap_proxy_connect_handler():

*) Fixed bug where a hostname without a "." in it (such as "localhost")
would not trigger an IP address check with ProxyBlock.
*) Fixed ProxyBlock bugs with ap_proxy_http_handler() and
ap_proxy_connect_handler().
*) Updated ap_proxy_connect_handler() to support APR, while
moving some common code between http_handler and connect_handler
to proxy_util.c.
PR:
Obtained from:
Reviewed by:


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@88721 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Graham Leggett
2001-04-04 18:47:42 +00:00
parent 3cea69c4d1
commit 5f3bc1ebc9
5 changed files with 175 additions and 72 deletions

View File

@@ -553,16 +553,15 @@ static const char *
/* Don't duplicate entries */ /* Don't duplicate entries */
for (i = 0; i < conf->noproxies->nelts; i++) { for (i = 0; i < conf->noproxies->nelts; i++) {
if (strcasecmp(arg, list[i].name) == 0) /* ignore case for host names */ if (apr_strnatcasecmp(arg, list[i].name) == 0) { /* ignore case for host names */
found = 1; found = 1;
} }
}
if (!found) { if (!found) {
new = apr_array_push(conf->noproxies); new = apr_array_push(conf->noproxies);
new->name = arg; new->name = arg;
/* Don't do name lookups on things that aren't dotted */ if (APR_SUCCESS == apr_sockaddr_info_get(&addr, new->name, APR_UNSPEC, 0, 0, parms->pool)) {
if (ap_strchr_c(arg, '.') != NULL &&
apr_sockaddr_info_get(&addr, new->name, APR_UNSPEC, 0, 0, parms->pool)) {
new->addr = addr; new->addr = addr;
} }
else { else {

View File

@@ -156,6 +156,7 @@ struct proxy_alias {
struct dirconn_entry { struct dirconn_entry {
char *name; char *name;
// struct apr_sockaddr_t *addr;
struct in_addr addr, mask; struct in_addr addr, mask;
struct hostent *hostentry; struct hostent *hostentry;
int (*matcher) (struct dirconn_entry * This, request_rec *r); int (*matcher) (struct dirconn_entry * This, request_rec *r);
@@ -250,6 +251,7 @@ int ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p);
int ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p); int ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p);
int ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p); int ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p);
int ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p); int ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p);
int ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, apr_sockaddr_t *uri_addr);
apr_status_t ap_proxy_doconnect(apr_socket_t *sock, char *host, apr_uint32_t port, request_rec *r); apr_status_t ap_proxy_doconnect(apr_socket_t *sock, char *host, apr_uint32_t port, request_rec *r);
/* This function is called by ap_table_do() for all header lines */ /* This function is called by ap_table_do() for all header lines */
int ap_proxy_send_hdr_line(void *p, const char *key, const char *value); int ap_proxy_send_hdr_line(void *p, const char *key, const char *value);

View File

@@ -112,42 +112,64 @@ allowed_port(proxy_server_conf *conf, int port)
int ap_proxy_connect_handler(request_rec *r, char *url, int ap_proxy_connect_handler(request_rec *r, char *url,
const char *proxyhost, int proxyport) const char *proxyname, int proxyport)
{ {
const char *host; apr_pool_t *p = r->pool;
char *p;
int port;
apr_socket_t *sock; apr_socket_t *sock;
char buffer[HUGE_STRING_LEN]; char buffer[HUGE_STRING_LEN];
int nbytes, i; int nbytes, i, err;
apr_socket_t *client_sock = NULL; apr_socket_t *client_sock = NULL;
apr_pollfd_t *pollfd; apr_pollfd_t *pollfd;
apr_int32_t pollcnt; apr_int32_t pollcnt;
apr_int16_t pollevent; apr_int16_t pollevent;
apr_sockaddr_t *uri_addr, *connect_addr;
uri_components uri;
const char *connectname;
int connectport = 0;
void *sconf = r->server->module_config; void *sconf = r->server->module_config;
proxy_server_conf *conf = proxy_server_conf *conf =
(proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
/* Break the URL into host:port pairs */
host = url; /*
p = strchr(url, ':'); * Step One: Determine Who To Connect To
if (p == NULL) *
port = DEFAULT_HTTPS_PORT; * Break up the URL to determine the host to connect to
*/
/* we break the URL into host, port, uri */
if (HTTP_OK != ap_parse_uri_components(p, url, &uri)) {
return ap_proxyerror(r, HTTP_BAD_REQUEST,
apr_pstrcat(p, "URI cannot be parsed: ", url, NULL));
}
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
"proxy: CONNECT 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);
/* are we connecting directly, or via a proxy? */
if (proxyname) {
connectname = proxyname;
connectport = proxyport;
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
"CONNECT to remote proxy %s on port %d", proxyname, proxyport);
err = apr_sockaddr_info_get(&connect_addr, proxyname, APR_UNSPEC, proxyport, 0, p);
}
else { else {
port = atoi(p + 1); connectname = uri.hostname;
*p = '\0'; connectport = uri.port;
connect_addr = uri_addr;
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
"CONNECT to %s on port %d", connectname, connectport);
} }
/* check if ProxyBlock directive on this host */ /* check if ProxyBlock directive on this host */
/* XXX FIXME */ if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) {
/* destaddr.s_addr = ap_inet_addr(host); */
for (i = 0; i < conf->noproxies->nelts; i++) {
if ((npent[i].name != NULL && ap_strstr_c(host, npent[i].name) != NULL)
/* || destaddr.s_addr == npent[i].addr.s_addr */
|| npent[i].name[0] == '*')
return ap_proxyerror(r, HTTP_FORBIDDEN, return ap_proxyerror(r, HTTP_FORBIDDEN,
"Connect to remote machine blocked"); "Connect to remote machine blocked");
} }
@@ -155,51 +177,101 @@ int ap_proxy_connect_handler(request_rec *r, char *url,
/* Check if it is an allowed port */ /* Check if it is an allowed port */
if (conf->allowed_connect_ports->nelts == 0) { if (conf->allowed_connect_ports->nelts == 0) {
/* Default setting if not overridden by AllowCONNECT */ /* Default setting if not overridden by AllowCONNECT */
switch (port) { switch (uri.port) {
case DEFAULT_HTTPS_PORT: case DEFAULT_HTTPS_PORT:
case DEFAULT_SNEWS_PORT: case DEFAULT_SNEWS_PORT:
break; break;
default: default:
return HTTP_FORBIDDEN; return HTTP_FORBIDDEN;
} }
} else if(!allowed_port(conf, port)) } else if(!allowed_port(conf, uri.port))
return HTTP_FORBIDDEN; return HTTP_FORBIDDEN;
if (proxyhost) {
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, /*
"CONNECT to remote proxy %s on port %d", proxyhost, proxyport); * Step Two: Make the Connection
} *
else { * We have determined who to connect to. Now make the connection.
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, */
"CONNECT to %s on port %d", host, port);
/* 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));
} }
/* create a new socket */
if ((apr_socket_create(&sock, APR_INET, SOCK_STREAM, r->pool)) != APR_SUCCESS) { if ((apr_socket_create(&sock, APR_INET, SOCK_STREAM, r->pool)) != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"proxy: error creating socket"); "proxy: error creating socket");
return HTTP_INTERNAL_SERVER_ERROR; return HTTP_INTERNAL_SERVER_ERROR;
} }
if (ap_proxy_doconnect(sock, (char *)(proxyhost ? proxyhost : host), /*
proxyport ? proxyport : port, r) != APR_SUCCESS) { * At this point we have a list of one or more IP addresses of
apr_socket_close(sock); * the machine to connect to. If configured, reorder this
return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR, * list so that the "best candidate" is first try. "best
apr_pstrcat(r->pool, "Could not connect to remote machine:<br>", * candidate" could mean the least loaded server, the fastest
proxyhost, NULL)); * responding server, whatever.
*
* For now we do nothing, ie we get DNS round robin.
* XXX FIXME
*/
/* try each IP address until we connect successfully */
{
int failed = 1;
while (connect_addr) {
/* make the connection out of the socket */
err = apr_connect(sock, connect_addr);
/* if an error occurred, loop round and try again */
if (err != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server,
"proxy: attempt to connect to %pI (%s) failed", connect_addr, connectname);
connect_addr = connect_addr->next;
continue;
} }
/* if we get here, all is well */
failed = 0;
break;
}
/* handle a permanent error from the above loop */
if (failed) {
if (proxyname) {
return DECLINED;
}
else {
return HTTP_BAD_GATEWAY;
}
}
}
/*
* Step Three: Send the Request
*
* Send the HTTP/1.1 CONNECT request to the remote server
*/
/* If we are connecting through a remote proxy, we need to pass /* If we are connecting through a remote proxy, we need to pass
* the CONNECT request on to it. * the CONNECT request on to it.
*/ */
if (proxyport) { if (proxyport) {
/* FIXME: We should not be calling write() directly, but we currently /* FIXME: Error checking ignored. Also, we force
* have no alternative. Error checking ignored. Also, we force
* a HTTP/1.0 request to keep things simple. * a HTTP/1.0 request to keep things simple.
*/ */
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
"Sending the CONNECT request to the remote proxy"); "Sending the CONNECT request to the remote proxy");
nbytes = apr_snprintf(buffer, sizeof(buffer), nbytes = apr_snprintf(buffer, sizeof(buffer),
"CONNECT %s HTTP/1.0" CRLF, r->uri); "CONNECT %s HTTP/1.1" CRLF, r->uri);
apr_send(sock, buffer, &nbytes); apr_send(sock, buffer, &nbytes);
nbytes = apr_snprintf(buffer, sizeof(buffer), nbytes = apr_snprintf(buffer, sizeof(buffer),
"Proxy-agent: %s" CRLF CRLF, ap_get_server_version()); "Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
@@ -213,6 +285,13 @@ int ap_proxy_connect_handler(request_rec *r, char *url,
ap_rflush(r); ap_rflush(r);
} }
/*
* Step Four: Handle Data Transfer
*
* Handle two way transfer of data over the socket (this is a tunnel).
*/
if(apr_poll_setup(&pollfd, 2, r->pool) != APR_SUCCESS) if(apr_poll_setup(&pollfd, 2, r->pool) != APR_SUCCESS)
{ {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
@@ -297,6 +376,13 @@ int ap_proxy_connect_handler(request_rec *r, char *url,
break; break;
} }
/*
* Step Five: Clean Up
*
* Close the socket and clean up
*/
apr_socket_close(sock); apr_socket_close(sock);
return OK; return OK;

View File

@@ -187,7 +187,7 @@ int ap_proxy_http_handler(request_rec *r, char *url,
apr_sockaddr_t *connect_addr; apr_sockaddr_t *connect_addr;
char server_portstr[32]; char server_portstr[32];
apr_socket_t *sock; apr_socket_t *sock;
int i, j, len, backasswards, close=0, failed=0, new=0; int i, len, backasswards, close=0, failed=0, new=0;
apr_status_t err; apr_status_t err;
apr_array_header_t *headers_in_array; apr_array_header_t *headers_in_array;
apr_table_entry_t *headers_in; apr_table_entry_t *headers_in;
@@ -249,31 +249,9 @@ int ap_proxy_http_handler(request_rec *r, char *url,
} }
/* check if ProxyBlock directive on this host */ /* check if ProxyBlock directive on this host */
/* XXX FIXME: conf->noproxies->elts is part of an opaque structure */ if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) {
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;
if ((npent[j].name && ap_strstr_c(uri.hostname, npent[j].name))
|| npent[j].name[0] == '*') {
return ap_proxyerror(r, HTTP_FORBIDDEN, return ap_proxyerror(r, HTTP_FORBIDDEN,
"Connect to remote machine blocked (by name)"); "Connect to remote machine blocked");
}
while (conf_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|APLOG_NOERRNO, 0, r->server,
"Testing %s and %s", conf_ip, uri_ip); */
if (!apr_strnatcasecmp(conf_ip, uri_ip)) {
return ap_proxyerror(r, HTTP_FORBIDDEN,
"Connect to remote machine blocked (by IP address)");
}
uri_addr = uri_addr->next;
}
conf_addr = conf_addr->next;
}
} }

View File

@@ -1071,6 +1071,44 @@ static int proxy_match_word(struct dirconn_entry *This, request_rec *r)
return host != NULL && ap_strstr_c(host, This->name) != NULL; return host != NULL && ap_strstr_c(host, This->name) != NULL;
} }
/* checks whether a host in uri_addr matches proxyblock */
int ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf,
apr_sockaddr_t *uri_addr)
{
int j;
/* 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;
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
"proxy: checking remote machine [%s] against [%s]", uri_addr->hostname, npent[j].name);
if ((npent[j].name && ap_strstr_c(uri_addr->hostname, npent[j].name))
|| npent[j].name[0] == '*') {
ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
"proxy: connect to remote machine %s blocked: name %s matched", uri_addr->hostname, npent[j].name);
return HTTP_FORBIDDEN;
}
while (conf_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|APLOG_NOERRNO, 0, r->server,
"proxy: ProxyBlock comparing %s and %s", conf_ip, uri_ip);
if (!apr_strnatcasecmp(conf_ip, uri_ip)) {
ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
"proxy: connect to remote machine %s blocked: IP %s matched", uri_addr->hostname, conf_ip);
return HTTP_FORBIDDEN;
}
uri_addr = uri_addr->next;
}
conf_addr = conf_addr->next;
}
}
return OK;
}
apr_status_t ap_proxy_doconnect(apr_socket_t *sock, char *host, apr_uint32_t port, request_rec *r) apr_status_t ap_proxy_doconnect(apr_socket_t *sock, char *host, apr_uint32_t port, request_rec *r)
{ {
apr_status_t rv; apr_status_t rv;