Bug 190495
Summary: | getaddrinfo forces preference of IPv4 over IPv6 addresses | ||||||
---|---|---|---|---|---|---|---|
Product: | [Fedora] Fedora | Reporter: | Valdis Kletnieks <valdis.kletnieks> | ||||
Component: | glibc | Assignee: | Jakub Jelinek <jakub> | ||||
Status: | CLOSED WONTFIX | QA Contact: | Brian Brock <bbrock> | ||||
Severity: | medium | Docs Contact: | |||||
Priority: | medium | ||||||
Version: | rawhide | CC: | dedourek, drepper, dwmw2, pb, pekkas | ||||
Target Milestone: | --- | ||||||
Target Release: | --- | ||||||
Hardware: | All | ||||||
OS: | Linux | ||||||
Whiteboard: | |||||||
Fixed In Version: | Doc Type: | Bug Fix | |||||
Doc Text: | Story Points: | --- | |||||
Clone Of: | Environment: | ||||||
Last Closed: | 2006-05-03 15:26:48 UTC | Type: | --- | ||||
Regression: | --- | Mount Type: | --- | ||||
Documentation: | --- | CRM: | |||||
Verified Versions: | Category: | --- | |||||
oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |||||
Cloudforms Team: | --- | Target Upstream Version: | |||||
Embargoed: | |||||||
Attachments: |
|
Description
Valdis Kletnieks
2006-05-02 21:35:31 UTC
Using the value we had before causes real problems with networks where there are site-local IPv6 networks. Real problems as in connections hang for minutes before they are failing. This is worse then giving precedence to IPv4. This cannot be resolved until there is a mechanism to configure getaddrifo from the outside. This is hinted at in rfc 3484 but no details are given. If you have proposals what needs to be configured and how I'd be happy to hear about this. But this is a new bug and this one is none. It's a decision which had to be made until a more complete solution is available. Do we need configuration? The default selection should depend on whether we have a Global IPv6 address on the system -- and I think it used to. For example, when connecting to www.infradead.org, it should use 2002:d592:9a28::1 first if the local system has a Global IPv6 address, and 213.146.154.40 if not. I believe the recent change was committed because glibc was choosing the IPv6 address first even when the local system has only a Site-local IPv6 address. The solution to that problem wasn't to favour IPv4 _unconditionally_, surely? Checking for a global address would probably be the *optimal* solution. However, I'd settle for leaving the precedence value at 100, and adding a new magic value for the RES_OPTIONS 'prefer_v6' that would stuff a 10 in there instead. Or some similar method for configuring it. Are there any real-life use cases that need precedence tables other than the rfc3484 tables in section 2.1 (the "default") and 10.3 ("prefer ipv4")? If not, we can hang this off almost anything that can flag a boolean into the innards of glibc.... There are apparently other configuration possibilities people want. After rfc 4193 people need to specify information for various local IPv6 addresses. I'm not interested in another RES_* option. It must be something more complete. And AI_ADDRCONFIG is the only automatic recognition of the addresses and it only controls whether IPv4 or IPv6 addresses are looked for and returned at all. I agree with the decision not to implement more configuration, at least for now until/unless something more complete is planned. But we've regressed in the _basic_ case, where we're trying to connect to a remote system which has both IPv6 Global address and IPv4 addresses. That's the most common case where everyone cares about RFC3484 -- we should pick the remote system's IPv6 address if we have a Global IPv6 address of our own, and we should pick its IPv4 address if we don't. That doesn't require any special configuration from the user -- it's a basic implementation of the default RFC3484 behaviour. We did not "regressed". There is no regression if the code still works. And this is the safer of the two options for the moment so I won't change it again. Once there is the configuration capability you can change it to your in whatever way you want. For now I want a configuration which has the least probability to cause _problems_. In Fedora Core 4, we used to get IPv6 connectivity to IPv6 hosts. Now we don't -- and that's a regression in RFC3484 compliance. Even when we have the configuration capability I'd only want the _basic_ RFC3484 compliance -- connect with IPv6 if that makes sense, else use IPv4. And I'd argue that that should be the _default_. Maybe we need to handle this similar to the way glibc handles timezones? Maybe a default in-library table that "mostly works", and then read in a precompiled table from a specified file. Of course, then we'll also need a program to take an ASCII (or GUI) representation and write out the precompiled table... David, stop that nonsense. It's no regressions. It's a change in behavior. If the program still works nobody can or should care. And yes, outside config files of some sort are needed. I'm not sure we need a precompiled data file because the data is likely not that plentiful. That's something which can be decided later. For the beginning, it might be sufficient to provide the possibility to overwrite the label and precedence tables. We'll see whether label handling needs to be overwritten, too. Such an implementation need not be complicated. We can just read in the table (from text or binary form) and then use it instead of the default_{label,precedence} tables. Something like this might be sufficient: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BEGIN LABEL ::1/128 0 :/0 1 2002::/16 2 ::/96 3 ::ffff:0:0/96 4 END LABEL BEGIN PRECEDENCE ::1/128 50 ::/0 40 2002::/16 30 ::/96 20 ::ffff:0:0/96 10 END PRECEDENCE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The only tricky bit is to sort the entries so that more generic entries do not what before the more specific ones. I think the precedence tables are a red herring. Preferring IPv6 should be fine, as long as we implement Rule 2 ("Prefer matching scope"). To go back to my example... if we have a Global IPv6 address which matches the scope of the AAAA record of 'www.infradead.org', that would be preferred. Otherwise, the IPv4 address would be preferred. You could even argue that it's Rule 1 ("Avoid unusable destinations"), since it's a fairly safe bet that if you don't have a Global IPv6 address, you can't communicate with another host on its Global IPv6 address. Whatever we _used_ to do would be fine. "It's no regressions. It's a change in behavior. If the program still works nobody can or should care." Users probably don't care. Network managers and designers certainly *do* care. Just like users don't care if a DNS round-robins the A records, but *somebody* certainly can and does care. It's a change in behaviour which seems to make us less compliant with RFC3484 than we used to be -- and is very suboptimal at least for me, because I want to _use_ IPv6 connectivity so that it gets tested. (The change in behaviour has been identified as a kernel change. See bug #188364 for details) Hmm.. I don't see why site-locals should be a problem if "prefer matching scope" is implemented correctly. Unique Local addresses could be a problem, but that's a topic for a different day. Btw, you want a local optimization, you should configure IPv6 border routers of the site-local domain to return ICMPv6 unreachables for global address space, instead of discarding the packets. That way linux would fall back to IPv4 immediately. (In reply to comment #14) > Hmm.. I don't see why site-locals should be a problem if "prefer matching > scope" is implemented correctly. Unique Local addresses could be a problem, > but that's a topic for a different day. I think the problem might arise because the IPv4 scope doesn't match _either_. The local address is RFC1918 IPv4, which doesn't match the global IPv4 scope in the A record. So they're _both_ mismatching scope. I suspect that (our implementation of) Rule 2 should be amended to recognise that some scopes are more unequal than others: Mismatching IPv6 scope is be _worse_ than mismatching IPv4 scope, because IPv4 is almost always NATted, while IPv6 never is. So IPv6 with mismatching scope should be lower down the list than IPv4 with mismatching scope. > Btw, you want a local optimization, you should configure IPv6 border routers > of the site-local domain to return ICMPv6 unreachables for global address > space, instead of discarding the packets. That way linux would fall back to > IPv4 immediately. Yes, that's a separate issue -- the border routers shouldn't have a default route, and should be returning unreachables already. But 'immediate' fallback is unfortunately not good enough anyway, while we still have broken software which uses only the first result from getaddrinfo() anyway. It needs to 'just work' like it did before, or I'm not going to get away with running radvd on the network. Perhaps a suitable solution to this would be to add this line to the default gai.conf: label fec0::/16 5 AIUI this should mean that Rule 5 of the destination address selection would kick in and do what we want. I've updated a FC5 machine to glibc-2.4-7 from updates-testing. I've installed /etc/gai.conf as follows: label ::1/128 0 label ::/0 1 label 2002::/16 2 label ::/96 3 label ::ffff:0:0/96 4 label fec0::/16 5 # precedence ::1/128 50 precedence ::/0 40 precedence 2002::/16 30 precedence ::/96 20 precedence ::ffff:0:0/96 100 However, it's still giving me the IPv6 address first. In fact, it was doing that even before I installed my own gai.conf. Shouldn't it have been giving me the IPv4 address first? open("/etc/gai.conf", O_RDONLY) = 3 socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP) = 3 connect(3, {sa_family=AF_INET6, sin6_port=htons(80), inet_pton(AF_INET6, "2001:8b0:10b:1::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0 getsockname(3, {sa_family=AF_INET6, sin6_port=htons(32772), inet_pton(AF_INET6, "::172.16.18.67", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28]) = 0 socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 3 connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("81.187.2.161")}, 16) = 0 getsockname(3, {sa_family=AF_INET, sin_port=htons(32772), sin_addr=inet_addr("172.16.18.67")}, [16]) = 0 Trying 2001:8b0:10b:1::1... After a reboot, the system is working properly. This default gai.conf ought to DTRT for all systems (add label for site-local, back to IPv6 preference): label ::1/128 0 label ::/0 1 label 2002::/16 2 label ::/96 3 label ::ffff:0:0/96 4 label fec0::/16 5 # precedence ::1/128 50 precedence ::/0 40 precedence 2002::/16 30 precedence ::/96 20 precedence ::ffff:0:0/96 10 The default gai.conf shipped in the documentation needs s/precendence/precedence/ throughout, btw. I picked up glibc 2.4.90-6, and it didn't even require a reboot. It *did* require fixing the typo that David spotted though. I'd have been sitting here for a long afternoon staring at that otherwise.. ;) Unless somebody has a issue that isn't solved with the proper gai.conf, I think this one can be moved to CLOSED/RAWHIDE... (In reply to comment #19) > Unless somebody has a issue that isn't solved with the proper gai.conf, I think > this one can be moved to CLOSED/RAWHIDE... By 'proper gai.conf' I assume you're referring to the one I suggest in comment #18? I wouldn't refer to that as 'proper' -- it's different from the default which glibc says we SHOULD be using. However, we're _already_ diverging from RFC3484's suggested default, and 'SHOULD' only means 'unless you have a damn good reason' -- which we do. Don't think it can quite be moved to CLOSED/RAWHIDE until Uli and Jakub have actually changed the default though, right? There are a couple of things. First, should this be added to the default file in the sources. By default, we don't install a gai.conf file because the parsing etc slows down the first call. Not much but still unnecessary. A counter argument is that special casing the obsolete (whether you like it or not) site-local addresses isn't the most politically correct thing to do. Second, the RFC 4193 addresses likely should be handled the same way. Third, this all assumes that site-local IPv4 addresses are NATed. This by itself need not be the case. This is unlikely right now and at the very least has to be documented. As of this release, for *most* sites, preferring a V4 address is the best choice, so coding that and leaving gai.conf optional is probably the best choice. We'll probably want to revisit that around FC 7 or so. If a site is using "site-local" IPv4 addresses that aren't in the 3 RFC1918 address spaces, they deserve what they get, and can hand-configure it for themselves. :) First, I think it _should_ be the default in the sources. You overruled the counter argument yourself -- fec0::/16 isn't going to be re-used any time soon. And to hear you talking about political correctness instead of technical usefulness is, erm, strange. :) Secondly, er, maybe. I don't care much about that but you're probably right. Third, no. We're only really assuming that site-local IPv4 are more _likely_ to be NATted than site-local IPv6. That is universally true, since IPv6 is _never_ NATted. Given the choice of RFC1918->Globalv4 or Site-local->Globalv6, I cannot comprehend a situation in which it's going to be correct to choose the IPv6 version over the IPv4. The suggested default is only reverting to the long-standing behaviour we used to have by coincidence. Re: #22, while preferring v4 could possibly have been a good transition practice, if everyone had been chosen that approach like 5 years ago, I think it's NOT a good idea to change that preference right now -- at least with an update such as this. Changing it would break a lot of apps (e.g., server-side v6 apps that don't use IPV6_V6ONLY sockopt as they can no longer create a v6 socket) and more important, almost every IPv6 deployer's expectations on how getaddrinfo behaves by default. Pekka, please could you comment on my suggested plan of just adding an entry to the default label/precedence table for site-local scope with a distinct label? That should return us to the behaviour we used to have and everyone should be happy, right? Re: #25, I see no harm in adding a site-local label [*]. (Btw, the prefix is fec0::/10.) To restore old functionality, it would seem to be a good approach to do so. I'd further encourage to consider removing the label in (say) FC7 timeframe so that folks don't end up using site-locals forever. I'm not certain it fixes all the problems under every circumstance though, as the source address selection rule 5 prefers outgoing interface over the label. [*] site-local address leaks (e.g., in global DNS) cause minor issues though, but as those are due to misconfiguration, that should be OK. If you are not concerned about ULA leaks either, you might also consider adding yet another label for FC00::/7, but that's a separate issue and I'm not certain what's the best approach for this in longer term, so it doesn't need to be done now. Created attachment 129314 [details]
Patch to add default labels for fec0::/10 and fc00::/7, fix precedence of ::ffff:0:0 to 10
glibc packages with this patch applied are available from ftp://ftp.infradead.org/pub/dwmw2-fc5/ Following bugs are partially related to this one: https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=181061 https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=199680 I have installed now glibc from https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=190495#c28 which solves the sort order issue for mentioned bugs. It does not solve the connect to the wrong host if IPv6 connect results in connection refused. try following: # Behavior IPv4-only: 1) extend /etc/resolv.conf: search 3.getaddrinfo.bieringer.de 5.getaddrinfo.bieringer.de 2) telnet to a unresolvable host $ telnet test.unknown Trying 127.0.0.3... telnet: connect to address 127.0.0.3: Connection refused -> end of program $ host -t any test.unknown.3.getaddrinfo.bieringer.de test.unknown.3.getaddrinfo.bieringer.de has address 127.0.0.3 $ host -t any test.unknown.5.getaddrinfo.bieringer.de test.unknown.5.getaddrinfo.bieringer.de has address 127.0.0.5 Correct behavior, result from search suffix 5.getaddrinfo.bieringer.de is not used. # Behavior IPv4/IPv6 mixed environment: 2) extend /etc/resolv.conf: search 2.getaddrinfo.bieringer.de 3.getaddrinfo.bieringer.de $ telnet test.unknown Trying fec0::2... telnet: connect to address fec0::2: Connection refused Trying 127.0.0.3... telnet: connect to address 127.0.0.3: Connection refused -> end of program $ host -t any test.unknown.2.getaddrinfo.bieringer.de test.unknown.2.getaddrinfo.bieringer.de has IPv6 address fec0::2 $ host -t any test.unknown.3.getaddrinfo.bieringer.de test.unknown.3.getaddrinfo.bieringer.de has address 127.0.0.3 Faulty behavior. After IPv6 connect to test.unknown.2.getaddrinfo.bieringer.de fails it falls back to IPv4 connect to test.unknown.3.getaddrinfo.bieringer.de, which is a different host! This should not happen imho, glibc has to prevent (or filter results) from other search suffices than the one with leads to a the successful AAAA lookup. The glibc installed from https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=190495#c28 has still a strange impact which can be greatly demonstrated using e.g. firefox. 1) setup a local http server 2) configure site local addresses to your loopback interface by e.g. # for i in 1 2 3 4 5; do ip addr add fec0::$i dev lo; done 3) add at least 2.getaddrinfo.bieringer.de to your search suffices 4) start firefox and go to URL www.redhat.com Result: default page of local http server is displayed. Reason (check using tcpdump), AAAA queries are made through all search suffices, afterwards A queries are done. Because of the sorting, now the AAAA result wins, but for host "www.redhat.com.2.getaddrinfo.bieringer.de", which points to fec0::2. AAAA? www.redhat.com. (32) AAAA? www.redhat.com. (43) AAAA? www.redhat.com.2.getaddrinfo.bieringer.de. (59) A? www.redhat.com. (32) This is imho a faulty and bad behavior. Lookups have to be done in a different way like: for $suffix in ("", searchsuffices(/etc/resolv.conf)) { $result_aaaa = lookup(AAAA,$host.$suffix) $result_a = lookup(A, $host.$suffix) if (defined $result_aaaa || $defined result_a) { break; }; } sortresults($result_a, $result_aaaa) Current implementation looks like working in following manner: for $suffix in ("", searchsuffices(/etc/resolv.conf)) { $result_aaaa = lookup(AAAA,$host.$suffix) if (defined $result_aaaa) { break; }; }; for $suffix in ("", searchsuffices(/etc/resolv.conf)) { $result_a = lookup(A, $host.$suffix) if ($defined result_a) { break; }; }; sortresults($result_a, $result_aaaa) And this leads to strange behavior and has a security impact because unexpected addresses can be delivered to a client. BTW: if you add only 1.getaddrinfo.bieringer.de, nothing will happen at all...except that I can track all your request (via named query log) to hosts which still doesn't provide an AAAA entry. This would be a privacy issue. I recommend to fix all currently maintained glibc version to prevent such issue. |