]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Merge r664535 from trunk:
authorJim Jagielski <jim@apache.org>
Mon, 9 Jun 2008 13:36:42 +0000 (13:36 +0000)
committerJim Jagielski <jim@apache.org>
Mon, 9 Jun 2008 13:36:42 +0000 (13:36 +0000)
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

CHANGES
STATUS
server/listen.c

diff --git a/CHANGES b/CHANGES
index 2bc9d52e1f79b6578b0ce4666bb5f39f5005446f..e9e3b3e7d588950e234ee33d5b1c5aa99b0ec2d8 100644 (file)
--- 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 600f9160cac71087886215b17b16d4caee3916e3..ee60076e6159c7b07862bbd4a8532d9b6f7e9a8f 100644 (file)
--- 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 ]
index f679f058200f133f5032902fa54232d274f830fa..d1e6da8ebfdd0a83ffedbedd22a989d805ea69fa 100644 (file)
@@ -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) {