From: Jim Jagielski Date: Mon, 9 Jun 2008 13:36:42 +0000 (+0000) Subject: Merge r664535 from trunk: X-Git-Tag: 2.2.9~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ce2ccc1ac16c9689e3a2674e2d118527d85f3f98;p=thirdparty%2Fapache%2Fhttpd.git Merge r664535 from trunk: core: Fix address-in-use startup failure on some platforms caused by attempting to set up an IPv4 listener which overlaps with an existing IPv6 listener. The failure occurred on the second pass of the open-logs hook in a configuration such as the following: Listen 8080 Listen 0.0.0.0:8081 Listen [::]:8081 During the first pass, the two port 8081 listen recs were adjacent and existing logic prevented binding to 0.0.0.0:8081. On the second pass, they were not adjacent and we then tried to bind to 0.0.0.0:8081, leading to failure on some platforms (seen on SLES 9 and Ubuntu 7.10, not seen on many other Unix-ish platforms). Leave a note about other unhandled configurations. Submitted by: trawick Reviewed by: jim git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@664705 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 2bc9d52e1f7..e9e3b3e7d58 100644 --- a/CHANGES +++ b/CHANGES @@ -5,6 +5,10 @@ Changes with Apache 2.2.9 mod_proxy_balancer: Prevent CSRF attacks against the balancer-manager interface. [Joe Orton] + *) core: Fix address-in-use startup failure on some platforms caused + by creating an IPv4 listener which overlaps with an existing IPv6 + listener. [Jeff Trawick] + *) mod_proxy: Make all proxy modules nocanon aware and do not add the query string again in this case. PR 44803. [Jim Jagielski, Ruediger Pluem] diff --git a/STATUS b/STATUS index 600f9160cac..ee60076e615 100644 --- a/STATUS +++ b/STATUS @@ -84,14 +84,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - * core: Fix address-in-use startup failure on some platforms caused - by attempting to set up an IPv4 listener which overlaps with an - existing IPv6 listener. - Trunk version of patch: - http://svn.apache.org/viewvc?rev=664535&view=rev - Backport version for 2.2.x of patch: - Trunk version of patch works - +1: trawick, jim, rpluem PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] diff --git a/server/listen.c b/server/listen.c index f679f058200..d1e6da8ebfd 100644 --- a/server/listen.c +++ b/server/listen.c @@ -377,14 +377,22 @@ static int open_listeners(apr_pool_t *pool) } else { #if APR_HAVE_IPV6 + ap_listen_rec *cur; int v6only_setting; + int skip = 0; /* If we have the unspecified IPv4 address (0.0.0.0) and * the unspecified IPv6 address (::) is next, we need to * swap the order of these in the list. We always try to * bind to IPv6 first, then IPv4, since an IPv6 socket * might be able to receive IPv4 packets if V6ONLY is not - * enabled, but never the other way around. */ + * enabled, but never the other way around. + * Note: In some configurations, the unspecified IPv6 address + * could be even later in the list. This logic only corrects + * the situation where it is next in the list, such as when + * apr_sockaddr_info_get() returns an IPv4 and an IPv6 address, + * in that order. + */ if (lr->next != NULL && IS_INADDR_ANY(lr->bind_addr) && lr->bind_addr->port == lr->next->bind_addr->port @@ -402,26 +410,32 @@ static int open_listeners(apr_pool_t *pool) lr = next; } - /* If we are trying to bind to 0.0.0.0 and the previous listener + /* If we are trying to bind to 0.0.0.0 and a previous listener * was :: on the same port and in turn that socket does not have * the IPV6_V6ONLY flag set; we must skip the current attempt to * listen (which would generate an error). IPv4 will be handled * on the established IPv6 socket. */ - if (previous != NULL - && IS_INADDR_ANY(lr->bind_addr) - && lr->bind_addr->port == previous->bind_addr->port - && IS_IN6ADDR_ANY(previous->bind_addr) - && apr_socket_opt_get(previous->sd, APR_IPV6_V6ONLY, - &v6only_setting) == APR_SUCCESS - && v6only_setting == 0) { - - /* Remove the current listener from the list */ - previous->next = lr->next; - lr = previous; /* maintain current value of previous after - * post-loop expression is evaluated - */ - continue; + if (IS_INADDR_ANY(lr->bind_addr)) { + for (cur = ap_listeners; cur != lr; cur = cur->next) { + if (lr->bind_addr->port == cur->bind_addr->port + && IS_IN6ADDR_ANY(cur->bind_addr) + && apr_socket_opt_get(cur->sd, APR_IPV6_V6ONLY, + &v6only_setting) == APR_SUCCESS + && v6only_setting == 0) { + + /* Remove the current listener from the list */ + previous->next = lr->next; + lr = previous; /* maintain current value of previous after + * post-loop expression is evaluated + */ + skip = 1; + break; + } + } + if (skip) { + continue; + } } #endif if (make_sock(pool, lr) == APR_SUCCESS) {