From 4893a6193d5f125d2ea6771026ed5813bd3fd6ab Mon Sep 17 00:00:00 2001 From: Jeff Trawick Date: Sun, 8 Jun 2008 18:13:35 +0000 Subject: [PATCH] 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. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@664535 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 4 ++++ server/listen.c | 46 ++++++++++++++++++++++++++++++---------------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/CHANGES b/CHANGES index 8b07da76d5..0256f6bb9b 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,10 @@ Changes with Apache 2.3.0 [ When backported to 2.2.x, remove entry from this file ] + *) 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_http: Do not forward requests with 'Expect: 100-continue' to known HTTP/1.0 servers. Return 'Expectation failed' (417) instead. [Ruediger Pluem] diff --git a/server/listen.c b/server/listen.c index f2d78f5762..eff2751075 100644 --- a/server/listen.c +++ b/server/listen.c @@ -376,14 +376,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 @@ -401,26 +409,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) { -- 2.40.0