Commit d8e8965d authored by Jeff Trawick's avatar Jeff Trawick
Browse files

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
parent 72474459
Loading
Loading
Loading
Loading
+4 −0
Changes for CHANGES: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -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]
+21 −7
Changes for server/listen.c: 21 added lines, 7 removed lines.
Original line number Diff line number Diff line
@@ -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,17 +409,17 @@ 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,
            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) {

@@ -420,8 +428,14 @@ static int open_listeners(apr_pool_t *pool)
                        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) {
                ++num_open;