#! /bin/sh -e # DP: Hack for some ordering in getaddrinfo lookups if [ $# -ne 2 ]; then echo >&2 "`basename $0`: script expects -patch|-unpatch as argument" exit 1 fi case "$1" in -patch) patch -d "$2" -f --no-backup-if-mismatch -p1 < $0;; -unpatch) patch -d "$2" -f --no-backup-if-mismatch -R -p1 < $0;; *) echo >&2 "`basename $0`: script expects -patch|-unpatch as argument" exit 1 esac exit 0 --- glibc/sysdeps/posix/getaddrinfo.c~ 2000/11/18 08:30:02 1.34 +++ glibc/sysdeps/posix/getaddrinfo.c 2001/01/09 01:46:49 @@ -264,7 +264,7 @@ return 0; } -#define gethosts(_family, _type) \ +#define gethosts(_family, _type, _name) \ { \ int i, herrno; \ size_t tmpbuflen; \ @@ -275,11 +275,12 @@ do { \ tmpbuflen *= 2; \ tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \ - rc = __gethostbyname2_r (name, _family, &th, tmpbuf, \ + rc = __gethostbyname2_r (_name, _family, &th, tmpbuf, \ tmpbuflen, &h, &herrno); \ } while (rc == ERANGE && herrno == NETDB_INTERNAL); \ if (rc != 0) \ { \ + succeeded--; \ if (herrno == NETDB_INTERNAL) \ { \ __set_h_errno (herrno); \ @@ -307,6 +308,26 @@ } \ } +/* If we are looking for both IPv4 and IPv6 address we don't + want the lookup functions to automatically promote IPv4 + addresses to IPv6 addresses. Currently this is decided + by setting the RES_USE_INET6 bit in _res.options. */ +#define tryname(__name) \ + { \ + succeeded = req->ai_family == AF_UNSPEC ? 2 : 1; \ + if (req->ai_family == AF_UNSPEC) \ + _res.options &= ~RES_USE_INET6; \ + if (req->ai_family == AF_UNSPEC || \ + req->ai_family == AF_INET6) \ + gethosts (AF_INET6, struct in6_addr, __name); \ + no_inet6_data = no_data; \ + if (req->ai_family == AF_UNSPEC) \ + _res.options = old_res_options; \ + if (req->ai_family == AF_UNSPEC || \ + req->ai_family == AF_INET) \ + gethosts (AF_INET, struct in_addr, __name); \ + } + static int gaih_inet (const char *name, const struct gaih_service *service, const struct addrinfo *req, struct addrinfo **pai) @@ -316,6 +337,10 @@ struct gaih_addrtuple *at = NULL; int rc; + /* Make sure we are initialized now */ + if (!(_res.options & RES_INIT)) + res_ninit(&_res); + if (req->ai_protocol || req->ai_socktype) { ++tp; @@ -489,34 +514,47 @@ struct gaih_addrtuple **pat = &at; int no_data = 0; int no_inet6_data; + int succeeded = -1; int old_res_options = _res.options; - /* If we are looking for both IPv4 and IPv6 address we don't - want the lookup functions to automatically promote IPv4 - addresses to IPv6 addresses. Currently this is decided - by setting the RES_USE_INET6 bit in _res.options. */ - if (req->ai_family == AF_UNSPEC) - _res.options &= ~RES_USE_INET6; - - if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) - gethosts (AF_INET6, struct in6_addr); - no_inet6_data = no_data; + /* If we have a dotted name, first try an absolute lookup. This + avoids problem where the resolver will try to search domains + even though we may have a fqdn, which is bad since ipv6 lookups + are performed first. */ + if (strchr(name, '.') != NULL) + { + int namelen = strlen(name); + char *newname = __alloca(namelen + 2); - if (req->ai_family == AF_UNSPEC) - _res.options = old_res_options; + strcpy(newname, name); + newname[namelen] = '.'; + newname[namelen+1] = '\0'; - if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) - gethosts (AF_INET, struct in_addr); + tryname(newname); + } - if (no_data != 0 && no_inet6_data != 0) + /* If the previous didn't work, or we don't have a dotted name, + we try again like normal, letting the resolver manage domain + searching. */ + if (succeeded <= 0) { - /* If both requests timed out report this. */ - if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) - return -EAI_AGAIN; - - /* We made requests but they turned out no data. The name - is known, though. */ - return (GAIH_OKIFUNSPEC | -EAI_NODATA); + _res.options = old_res_options; + + if (succeeded == 0) /* we've tried absolute, now try searches */ + _res.ndots = 99; + + tryname(name); + + if (no_data != 0 && no_inet6_data != 0) + { + /* If both requests timed out report this. */ + if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) + return -EAI_AGAIN; + + /* We made requests but they turned out no data. The name + is known, though. */ + return (GAIH_OKIFUNSPEC | -EAI_NODATA); + } } }