commit 45918e237cd32bb3d9a5fde83f81f83b52584771 Author: Stefan Saraev Date: Tue Oct 1 12:09:07 2013 +0300 fix dns with broken routers ref: https://fedoraproject.org/wiki/Networking/NameResolution/ADDRCONFIG --- a/sysdeps/posix/getaddrinfo.c +++ b/sysdeps/posix/getaddrinfo.c @@ -730,6 +730,38 @@ gaih_inet (const char *name, const struc if (res_ctx == NULL) no_more = 1; + /* AI_ADDRCONFIG determines whether or not we should suppress any + * hostname lookups. If the local host has only IPv4 interfaces, + * then suppress lookups for IPv6 addresses, and vice versa; if + * the local host has only IPv6 interfaces, suppress any lookups + * for IPv4 addresses.. + * + * Link-local IPv6 addresses and loopback addresses of either + * family are ignored when determining whether or not the host has + * an interface of the given address family, cf. __check_pf(). + * + * This logic is only applied for AF_UNSPEC. If the caller + * explicitly requested an address family, give him what he asked + * for. + * + * If we didn't find any interfaces of either address family, + * we ignore AI_ADDRCONFIG and return all available resutlts. */ + int suppress_af = 0; + if (req->ai_family == AF_UNSPEC) + { + struct in6addrinfo *in6ai = NULL; + size_t in6ailen = 0; + bool seen_ipv4 = false; + bool seen_ipv6 = false; + __check_pf (&seen_ipv4, &seen_ipv6, &in6ai, &in6ailen); + __free_in6ai (in6ai); + + if(seen_ipv4 && !seen_ipv6) + suppress_af = AF_INET6; + else if(seen_ipv6 && !seen_ipv4) + suppress_af = AF_INET; + } + while (!no_more) { no_data = 0; @@ -737,7 +769,7 @@ gaih_inet (const char *name, const struc /* gethostbyname4_r sends out parallel A and AAAA queries and is thus only suitable for PF_UNSPEC. */ - if (req->ai_family == PF_UNSPEC) + if (req->ai_family == PF_UNSPEC && !suppress_af) fct4 = __nss_lookup_function (nip, "gethostbyname4_r"); if (fct4 != NULL) @@ -826,25 +858,27 @@ gaih_inet (const char *name, const struc if (fct != NULL) { - if (req->ai_family == AF_INET6 - || req->ai_family == AF_UNSPEC) + if ((req->ai_family == AF_INET6 + || req->ai_family == AF_UNSPEC) + && suppress_af != AF_INET6) { if ((result = gethosts (fct, AF_INET6, name, req, tmpbuf, res, &status, &no_data)) != 0) { __resolv_context_put (res_ctx); goto out; } no_inet6_data = no_data; inet6_status = status; } - if (req->ai_family == AF_INET - || req->ai_family == AF_UNSPEC - || (req->ai_family == AF_INET6 - && (req->ai_flags & AI_V4MAPPED) - /* Avoid generating the mapped addresses if we - know we are not going to need them. */ - && ((req->ai_flags & AI_ALL) || !res->got_ipv6))) + if ((req->ai_family == AF_INET + || req->ai_family == AF_UNSPEC + || (req->ai_family == AF_INET6 + && (req->ai_flags & AI_V4MAPPED) + /* Avoid generating the mapped addresses if we + know we are not going to need them. */ + && ((req->ai_flags & AI_ALL) || !res->got_ipv6))) + && suppress_af != AF_INET) { if ((result = gethosts (fct, AF_INET, name, req, tmpbuf, res, &status, &no_data)) != 0) --- a/sysdeps/unix/sysv/linux/check_pf.c +++ b/sysdeps/unix/sysv/linux/check_pf.c @@ -224,7 +224,8 @@ make_request (int fd, pid_t pid) } else { - if (!IN6_IS_ADDR_LOOPBACK (address)) + if (!IN6_IS_ADDR_LOOPBACK (address) && + !IN6_IS_ADDR_LINKLOCAL (address)) seen_ipv6 = true; } }