Skip to content

Commit 891944a

Browse files
committed
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
1 parent 006f104 commit 891944a

3 files changed

Lines changed: 34 additions & 24 deletions

File tree

CHANGES

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ Changes with Apache 2.2.9
55
mod_proxy_balancer: Prevent CSRF attacks against the balancer-manager
66
interface. [Joe Orton]
77

8+
*) core: Fix address-in-use startup failure on some platforms caused
9+
by creating an IPv4 listener which overlaps with an existing IPv6
10+
listener. [Jeff Trawick]
11+
812
*) mod_proxy: Make all proxy modules nocanon aware and do not add the
913
query string again in this case. PR 44803.
1014
[Jim Jagielski, Ruediger Pluem]

STATUS

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,6 @@ RELEASE SHOWSTOPPERS:
8484
PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
8585
[ start all new proposals below, under PATCHES PROPOSED. ]
8686

87-
* core: Fix address-in-use startup failure on some platforms caused
88-
by attempting to set up an IPv4 listener which overlaps with an
89-
existing IPv6 listener.
90-
Trunk version of patch:
91-
http://svn.apache.org/viewvc?rev=664535&view=rev
92-
Backport version for 2.2.x of patch:
93-
Trunk version of patch works
94-
+1: trawick, jim, rpluem
9587

9688
PATCHES PROPOSED TO BACKPORT FROM TRUNK:
9789
[ New proposals should be added at the end of the list ]

server/listen.c

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -377,14 +377,22 @@ static int open_listeners(apr_pool_t *pool)
377377
}
378378
else {
379379
#if APR_HAVE_IPV6
380+
ap_listen_rec *cur;
380381
int v6only_setting;
382+
int skip = 0;
381383

382384
/* If we have the unspecified IPv4 address (0.0.0.0) and
383385
* the unspecified IPv6 address (::) is next, we need to
384386
* swap the order of these in the list. We always try to
385387
* bind to IPv6 first, then IPv4, since an IPv6 socket
386388
* might be able to receive IPv4 packets if V6ONLY is not
387-
* enabled, but never the other way around. */
389+
* enabled, but never the other way around.
390+
* Note: In some configurations, the unspecified IPv6 address
391+
* could be even later in the list. This logic only corrects
392+
* the situation where it is next in the list, such as when
393+
* apr_sockaddr_info_get() returns an IPv4 and an IPv6 address,
394+
* in that order.
395+
*/
388396
if (lr->next != NULL
389397
&& IS_INADDR_ANY(lr->bind_addr)
390398
&& lr->bind_addr->port == lr->next->bind_addr->port
@@ -402,26 +410,32 @@ static int open_listeners(apr_pool_t *pool)
402410
lr = next;
403411
}
404412

405-
/* If we are trying to bind to 0.0.0.0 and the previous listener
413+
/* If we are trying to bind to 0.0.0.0 and a previous listener
406414
* was :: on the same port and in turn that socket does not have
407415
* the IPV6_V6ONLY flag set; we must skip the current attempt to
408416
* listen (which would generate an error). IPv4 will be handled
409417
* on the established IPv6 socket.
410418
*/
411-
if (previous != NULL
412-
&& IS_INADDR_ANY(lr->bind_addr)
413-
&& lr->bind_addr->port == previous->bind_addr->port
414-
&& IS_IN6ADDR_ANY(previous->bind_addr)
415-
&& apr_socket_opt_get(previous->sd, APR_IPV6_V6ONLY,
416-
&v6only_setting) == APR_SUCCESS
417-
&& v6only_setting == 0) {
418-
419-
/* Remove the current listener from the list */
420-
previous->next = lr->next;
421-
lr = previous; /* maintain current value of previous after
422-
* post-loop expression is evaluated
423-
*/
424-
continue;
419+
if (IS_INADDR_ANY(lr->bind_addr)) {
420+
for (cur = ap_listeners; cur != lr; cur = cur->next) {
421+
if (lr->bind_addr->port == cur->bind_addr->port
422+
&& IS_IN6ADDR_ANY(cur->bind_addr)
423+
&& apr_socket_opt_get(cur->sd, APR_IPV6_V6ONLY,
424+
&v6only_setting) == APR_SUCCESS
425+
&& v6only_setting == 0) {
426+
427+
/* Remove the current listener from the list */
428+
previous->next = lr->next;
429+
lr = previous; /* maintain current value of previous after
430+
* post-loop expression is evaluated
431+
*/
432+
skip = 1;
433+
break;
434+
}
435+
}
436+
if (skip) {
437+
continue;
438+
}
425439
}
426440
#endif
427441
if (make_sock(pool, lr) == APR_SUCCESS) {

0 commit comments

Comments
 (0)