]>
Commit | Line | Data |
---|---|---|
ef28628d AM |
1 | #! /bin/sh -e |
2 | ||
3 | # DP: Hack for some ordering in getaddrinfo lookups | |
4 | ||
5 | if [ $# -ne 2 ]; then | |
6 | echo >&2 "`basename $0`: script expects -patch|-unpatch as argument" | |
7 | exit 1 | |
8 | fi | |
9 | case "$1" in | |
10 | -patch) patch -d "$2" -f --no-backup-if-mismatch -p1 < $0;; | |
11 | -unpatch) patch -d "$2" -f --no-backup-if-mismatch -R -p1 < $0;; | |
12 | *) | |
13 | echo >&2 "`basename $0`: script expects -patch|-unpatch as argument" | |
14 | exit 1 | |
15 | esac | |
16 | exit 0 | |
17 | ||
18 | --- glibc/sysdeps/posix/getaddrinfo.c~ 2000/11/18 08:30:02 1.34 | |
19 | +++ glibc/sysdeps/posix/getaddrinfo.c 2001/01/09 01:46:49 | |
20 | @@ -264,7 +264,7 @@ | |
21 | return 0; | |
22 | } | |
23 | ||
24 | -#define gethosts(_family, _type) \ | |
25 | +#define gethosts(_family, _type, _name) \ | |
26 | { \ | |
27 | int i, herrno; \ | |
28 | size_t tmpbuflen; \ | |
29 | @@ -275,11 +275,12 @@ | |
30 | do { \ | |
31 | tmpbuflen *= 2; \ | |
e841f13b | 32 | tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \ |
ef28628d AM |
33 | - rc = __gethostbyname2_r (name, _family, &th, tmpbuf, \ |
34 | + rc = __gethostbyname2_r (_name, _family, &th, tmpbuf, \ | |
35 | tmpbuflen, &h, &herrno); \ | |
36 | } while (rc == ERANGE && herrno == NETDB_INTERNAL); \ | |
37 | if (rc != 0) \ | |
38 | { \ | |
39 | + succeeded--; \ | |
40 | if (herrno == NETDB_INTERNAL) \ | |
41 | { \ | |
42 | __set_h_errno (herrno); \ | |
43 | @@ -307,6 +308,26 @@ | |
44 | } \ | |
45 | } | |
46 | ||
47 | +/* If we are looking for both IPv4 and IPv6 address we don't | |
48 | + want the lookup functions to automatically promote IPv4 | |
49 | + addresses to IPv6 addresses. Currently this is decided | |
50 | + by setting the RES_USE_INET6 bit in _res.options. */ | |
51 | +#define tryname(__name) \ | |
52 | + { \ | |
53 | + succeeded = req->ai_family == AF_UNSPEC ? 2 : 1; \ | |
54 | + if (req->ai_family == AF_UNSPEC) \ | |
55 | + _res.options &= ~RES_USE_INET6; \ | |
56 | + if (req->ai_family == AF_UNSPEC || \ | |
57 | + req->ai_family == AF_INET6) \ | |
58 | + gethosts (AF_INET6, struct in6_addr, __name); \ | |
59 | + no_inet6_data = no_data; \ | |
60 | + if (req->ai_family == AF_UNSPEC) \ | |
61 | + _res.options = old_res_options; \ | |
62 | + if (req->ai_family == AF_UNSPEC || \ | |
63 | + req->ai_family == AF_INET) \ | |
64 | + gethosts (AF_INET, struct in_addr, __name); \ | |
65 | + } | |
66 | + | |
67 | static int | |
68 | gaih_inet (const char *name, const struct gaih_service *service, | |
69 | const struct addrinfo *req, struct addrinfo **pai) | |
70 | @@ -316,6 +337,10 @@ | |
71 | struct gaih_addrtuple *at = NULL; | |
72 | int rc; | |
73 | ||
74 | + /* Make sure we are initialized now */ | |
75 | + if (!(_res.options & RES_INIT)) | |
76 | + res_ninit(&_res); | |
77 | + | |
78 | if (req->ai_protocol || req->ai_socktype) | |
79 | { | |
80 | ++tp; | |
81 | @@ -489,34 +514,47 @@ | |
82 | struct gaih_addrtuple **pat = &at; | |
83 | int no_data = 0; | |
84 | int no_inet6_data; | |
85 | + int succeeded = -1; | |
86 | int old_res_options = _res.options; | |
87 | ||
88 | - /* If we are looking for both IPv4 and IPv6 address we don't | |
89 | - want the lookup functions to automatically promote IPv4 | |
90 | - addresses to IPv6 addresses. Currently this is decided | |
91 | - by setting the RES_USE_INET6 bit in _res.options. */ | |
92 | - if (req->ai_family == AF_UNSPEC) | |
93 | - _res.options &= ~RES_USE_INET6; | |
94 | - | |
95 | - if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) | |
96 | - gethosts (AF_INET6, struct in6_addr); | |
97 | - no_inet6_data = no_data; | |
98 | + /* If we have a dotted name, first try an absolute lookup. This | |
99 | + avoids problem where the resolver will try to search domains | |
100 | + even though we may have a fqdn, which is bad since ipv6 lookups | |
101 | + are performed first. */ | |
102 | + if (strchr(name, '.') != NULL) | |
103 | + { | |
104 | + int namelen = strlen(name); | |
105 | + char *newname = __alloca(namelen + 2); | |
106 | ||
107 | - if (req->ai_family == AF_UNSPEC) | |
108 | - _res.options = old_res_options; | |
109 | + strcpy(newname, name); | |
110 | + newname[namelen] = '.'; | |
111 | + newname[namelen+1] = '\0'; | |
112 | ||
113 | - if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) | |
114 | - gethosts (AF_INET, struct in_addr); | |
115 | + tryname(newname); | |
116 | + } | |
117 | ||
118 | - if (no_data != 0 && no_inet6_data != 0) | |
119 | + /* If the previous didn't work, or we don't have a dotted name, | |
120 | + we try again like normal, letting the resolver manage domain | |
121 | + searching. */ | |
122 | + if (succeeded <= 0) | |
123 | { | |
124 | - /* If both requests timed out report this. */ | |
125 | - if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) | |
126 | - return -EAI_AGAIN; | |
127 | - | |
128 | - /* We made requests but they turned out no data. The name | |
129 | - is known, though. */ | |
130 | - return (GAIH_OKIFUNSPEC | -EAI_NODATA); | |
131 | + _res.options = old_res_options; | |
132 | + | |
133 | + if (succeeded == 0) /* we've tried absolute, now try searches */ | |
134 | + _res.ndots = 99; | |
135 | + | |
136 | + tryname(name); | |
137 | + | |
138 | + if (no_data != 0 && no_inet6_data != 0) | |
139 | + { | |
140 | + /* If both requests timed out report this. */ | |
141 | + if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) | |
142 | + return -EAI_AGAIN; | |
143 | + | |
144 | + /* We made requests but they turned out no data. The name | |
145 | + is known, though. */ | |
146 | + return (GAIH_OKIFUNSPEC | -EAI_NODATA); | |
147 | + } | |
148 | } | |
149 | } | |
150 |