The short story
In the testing we performed on SLC5 (patched glibc 2.5) we were apparently relying on the classical pattern of two mistakes (or, better, asymmetries between IPv4 and IPv6) compensating to produce the correct (or, at least, expected) result of preferring dual-stack binding for services that bind and listen on TCP or UDP. When we upgraded to SLC6 (patched glibc 2.12) we inherited the fix of one of the asymmetries (appearing with this commit in glibc 2.9, to comply with RFC 4291 2.5.3), and we were left with the other, that comes straight out of RFC 3484 2.1 and 5/rule 6. The result is that services that used to bind on both stacks on SLC5 (e.g. the GridFTP server) started binding on IPv4 only, unless the symmetry between IPv4 and IPv6 is restored by installing this file as /etc/gai.conf
.
The ugly details
-
The results of the libc
getaddrinfo
call get ordered by the rules of RFC 3484 section 5. Services that need to listen on a TCP/UDP port typically bind to the addresses that are returned bygetaddrinfo
, upon a request of
. The order of the results of this call in a given libc installation can be tested by running this test program.
ai_req.ai_flags = AI_PASSIVE; ai_req.ai_family = PF_UNSPEC; -
Binding on the IPv6 “unspecified” (
::
) address usually results, with the hybrid IP stacks deployed in the testbed Linux installations, in binding to both IPv6 and IPv4. -
There are services (all of the Globus services, including the GridFTP service) that bind to the first result of
getaddrinfo
only. The only currently available way to have them bind and listen on IPv6 (and IPv4) is to havegetaddrinfo
prefer IPv6 in thisAI_PASSIVE/PF_UNSPEC
case. -
getaddrinfo
orders the results of theAI_PASSIVE/PF_UNSPEC
query by applying the rules of RFC 3484 section 5 to these two pairs of addresses:
Source address: | Destination address: | |
---|---|---|
IPv6 |
:: (all-zeros, unspecified) |
::1 (loopback/localhost) |
IPv4 |
0.0.0.0 (all-zeros, unspecified) |
127.0.0.1 (loopback/localhost) |
-
Up to and including glibc 2.8 (actually until this May 14th, 2008 commit became effective) the IPv6 unspecified and localhost address were assigned the same scope (’14’), while the IPv4 unspecified address was given scope ‘14’ and the IPv4 localhost address was given scope ‘2’. This led the IPv6 address to be preferred by section 5, rule 2 of RFC 3484:
1651 if (a1_dst_scope == a1_src_scope && a2_dst_scope != a2_src_scope) 1652 return -1;
-
The May 14th, 2008 commit removed this asymmetry, correctly giving the IPv6 localhost address scope ‘2’ (link-local), conforming to RFC 4291 2.5.3:
@@ -1409,7 +1323,10 @@
{ if (! IN6_IS_ADDR_MULTICAST (&in6->sin6_addr)) { - if (IN6_IS_ADDR_LINKLOCAL (&in6->sin6_addr)) + if (IN6_IS_ADDR_LINKLOCAL (&in6->sin6_addr) + /* RFC 4291 2.5.3 says that the loopback address is to be + treated like a link-local address. */ + || IN6_IS_ADDR_LOOPBACK (&in6->sin6_addr)) scope = 2; else if (IN6_IS_ADDR_SITELOCAL (&in6->sin6_addr)) scope = 5;
Prefix | Precedence | Label |
---|---|---|
::1/128 | 50 | 0 |
::/0 | 40 | 1 |
2002::/16 | 30 | 2 |
::/96 | 20 | 3 |
::ffff:0:0/96 | 10 | 4 |
-
Here, the localhost and unspecified IPv6 addresses are assigned different labels (0 and 3), while all of the IPv4 space, including localhost is assigned the same label (4). The asymmetry of dealing with the IPv4 and IPv6 unspecified and localhost address is back, and reversed, leading to prefer the IPv4 binding!
-
The IPv4 localhost address can be assigned to a different label (and therefore be handled in similar fashion to the IPv6 localhost address) by adding a rule to the
getaddrinfo
configuration file (/etc/gai.conf
) as in this example:label ::ffff:7f00:0001/128 8
-
This way, the symmetry of dealing with IPv4 and IPv6 is restored, and IPv6 is preferred, as per the general default
getaddrinfo
preference. Unless there was a specific reason for the default label scheme in RFC 3484, it should probably be amended. This would preferable to either changing all server code to scan all thegetaddrinfo
results to prefer IPv6 when needed or configuring/etc/gai.conf
in all installations (though this could be done as part of distributing glibc, or for specific distributions such as Scientific Linux). There are several (1,2,3) tickets and threads open on this issue, but no action was taken so far on distributions, libc or the RFC. If this stall continues, server code patching may remain the only way forward.
- Log in to post comments