mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
implement a common function for getting a socket and trying to connect
to the target host; use that common function for proxy HTTP and proxy CONNECT In that new function, fix this problem: Proxy HTTP and CONNECT: Keep trying other addresses from the DNS when we can't get a socket in the specified address family. We may have gotten back an IPv6 address first and yet our system is not configured to allow IPv6 sockets. An example host is www.ipv6.org. The first address I get back is an IPv6 address, but my machine may not be configured to allow an AF_INET6 socket. Before the fix: The apr_socket() failure was fatal. After the fix: When apr_socket() fails, we go to the next address from the resolver, successfully create a socket in the specified family (AF_INET), and all is well. (an unrelated fix in this commit was to pass a server_rec in a broken ap_log_error() call) git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@93787 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -1103,3 +1103,77 @@ PROXY_DECLARE(void) ap_proxy_table_unmerge(apr_pool_t *p, apr_table_t *t, char *
|
||||
}
|
||||
apr_table_add(t, key, value + offset);
|
||||
}
|
||||
|
||||
PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **newsock,
|
||||
const char *proxy_function,
|
||||
apr_sockaddr_t *backend_addr,
|
||||
const char *backend_name,
|
||||
proxy_server_conf *conf,
|
||||
server_rec *s,
|
||||
apr_pool_t *p)
|
||||
{
|
||||
apr_status_t rv;
|
||||
int connected = 0;
|
||||
int loglevel;
|
||||
|
||||
while (backend_addr && !connected) {
|
||||
if ((rv = apr_socket_create(newsock, backend_addr->family,
|
||||
SOCK_STREAM, p)) != APR_SUCCESS) {
|
||||
loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
|
||||
ap_log_error(APLOG_MARK, loglevel, rv, s,
|
||||
"proxy: %s: error creating fam %d socket for target %s",
|
||||
proxy_function,
|
||||
backend_addr->family,
|
||||
backend_name);
|
||||
/* this could be an IPv6 address from the DNS but the
|
||||
* local machine won't give us an IPv6 socket; hopefully the
|
||||
* DNS returned an additional address to try
|
||||
*/
|
||||
backend_addr = backend_addr->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
#if !defined(TPF) && !defined(BEOS)
|
||||
if (conf->recv_buffer_size > 0 &&
|
||||
(rv = apr_setsocketopt(*newsock, APR_SO_RCVBUF,
|
||||
conf->recv_buffer_size))) {
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
|
||||
"setsockopt(SO_RCVBUF): Failed to set "
|
||||
"ProxyReceiveBufferSize, using default");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set a timeout on the socket */
|
||||
if (conf->timeout_set == 1) {
|
||||
apr_setsocketopt(*newsock, APR_SO_TIMEOUT,
|
||||
(int)(conf->timeout * APR_USEC_PER_SEC));
|
||||
}
|
||||
else {
|
||||
apr_setsocketopt(*newsock, APR_SO_TIMEOUT,
|
||||
(int)(s->timeout * APR_USEC_PER_SEC));
|
||||
}
|
||||
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, s,
|
||||
"proxy: %s: fam %d socket created to connect to %s",
|
||||
proxy_function, backend_addr->family, backend_name);
|
||||
|
||||
/* make the connection out of the socket */
|
||||
rv = apr_connect(*newsock, backend_addr);
|
||||
|
||||
/* if an error occurred, loop round and try again */
|
||||
if (rv != APR_SUCCESS) {
|
||||
apr_socket_close(*newsock);
|
||||
loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
|
||||
ap_log_error(APLOG_MARK, loglevel, rv, s,
|
||||
"proxy: %s: attempt to connect to %pI (%s) failed",
|
||||
proxy_function,
|
||||
backend_addr,
|
||||
backend_name);
|
||||
backend_addr = backend_addr->next;
|
||||
continue;
|
||||
}
|
||||
connected = 1;
|
||||
}
|
||||
return connected ? 0 : 1;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user