|
1 /* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ |
|
2 /* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ |
|
3 |
|
4 /* |
|
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
|
6 * All rights reserved. |
|
7 * |
|
8 * Redistribution and use in source and binary forms, with or without |
|
9 * modification, are permitted provided that the following conditions |
|
10 * are met: |
|
11 * 1. Redistributions of source code must retain the above copyright |
|
12 * notice, this list of conditions and the following disclaimer. |
|
13 * 2. Redistributions in binary form must reproduce the above copyright |
|
14 * notice, this list of conditions and the following disclaimer in the |
|
15 * documentation and/or other materials provided with the distribution. |
|
16 * 3. Neither the name of the project nor the names of its contributors |
|
17 * may be used to endorse or promote products derived from this software |
|
18 * without specific prior written permission. |
|
19 * |
|
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
|
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
|
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
30 * SUCH DAMAGE. |
|
31 */ |
|
32 |
|
33 /* |
|
34 * This version of getaddrinfo.c is derived from Android 2.3 "Gingerbread", |
|
35 * which contains uncredited changes by Android/Google developers. It has |
|
36 * been modified in 2011 for use in the Android build of Mozilla Firefox by |
|
37 * Mozilla contributors (including Michael Edwards <m.k.edwards@gmail.com>, |
|
38 * and Steve Workman <sjhworkman@gmail.com>). |
|
39 * These changes are offered under the same license as the original NetBSD |
|
40 * file, whose copyright and license are unchanged above. |
|
41 */ |
|
42 #define ANDROID_CHANGES 1 |
|
43 #define INET6 1 |
|
44 |
|
45 /* |
|
46 * Issues to be discussed: |
|
47 * - Return values. There are nonstandard return values defined and used |
|
48 * in the source code. This is because RFC2553 is silent about which error |
|
49 * code must be returned for which situation. |
|
50 * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2 |
|
51 * says to use inet_aton() to convert IPv4 numeric to binary (alows |
|
52 * classful form as a result). |
|
53 * current code - disallow classful form for IPv4 (due to use of inet_pton). |
|
54 * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is |
|
55 * invalid. |
|
56 * current code - SEGV on freeaddrinfo(NULL) |
|
57 * Note: |
|
58 * - We use getipnodebyname() just for thread-safeness. There's no intent |
|
59 * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to |
|
60 * getipnodebyname(). |
|
61 * - MOZILLA: Thread safeness for pre-Honeycomb Android versions implemented by |
|
62 * way of open/gets/close and mmap rather than fopen/fgets/fclose. Affects |
|
63 * _files_getaddrinfo for hosts file. Note: Honeycomb and later versions use |
|
64 * a thread-safe stdio, so for those versions normal Bionic libc getaddrinfo |
|
65 * is used. |
|
66 * - The code filters out AFs that are not supported by the kernel, |
|
67 * when globbing NULL hostname (to loopback, or wildcard). Is it the right |
|
68 * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG |
|
69 * in ai_flags? |
|
70 * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. |
|
71 * (1) what should we do against numeric hostname (2) what should we do |
|
72 * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? |
|
73 * non-loopback address configured? global address configured? |
|
74 * - To avoid search order issue, we have a big amount of code duplicate |
|
75 * from gethnamaddr.c and some other places. The issues that there's no |
|
76 * lower layer function to lookup "IPv4 or IPv6" record. Calling |
|
77 * gethostbyname2 from getaddrinfo will end up in wrong search order, as |
|
78 * follows: |
|
79 * - The code makes use of following calls when asked to resolver with |
|
80 * ai_family = PF_UNSPEC: |
|
81 * getipnodebyname(host, AF_INET6); |
|
82 * getipnodebyname(host, AF_INET); |
|
83 * This will result in the following queries if the node is configure to |
|
84 * prefer /etc/hosts than DNS: |
|
85 * lookup /etc/hosts for IPv6 address |
|
86 * lookup DNS for IPv6 address |
|
87 * lookup /etc/hosts for IPv4 address |
|
88 * lookup DNS for IPv4 address |
|
89 * which may not meet people's requirement. |
|
90 * The right thing to happen is to have underlying layer which does |
|
91 * PF_UNSPEC lookup (lookup both) and return chain of addrinfos. |
|
92 * This would result in a bit of code duplicate with _dns_ghbyname() and |
|
93 * friends. |
|
94 */ |
|
95 |
|
96 #include <fcntl.h> |
|
97 #include <sys/cdefs.h> |
|
98 #include <sys/types.h> |
|
99 #include <sys/stat.h> |
|
100 #include <sys/param.h> |
|
101 #include <sys/socket.h> |
|
102 #include <sys/un.h> |
|
103 #include <sys/mman.h> |
|
104 #include <net/if.h> |
|
105 #include <netinet/in.h> |
|
106 #include <arpa/inet.h> |
|
107 #include "arpa_nameser.h" |
|
108 #include <assert.h> |
|
109 #include <ctype.h> |
|
110 #include <errno.h> |
|
111 #include <netdb.h> |
|
112 #include "resolv_private.h" |
|
113 #include <stddef.h> |
|
114 #include <stdlib.h> |
|
115 #include <string.h> |
|
116 #include <unistd.h> |
|
117 |
|
118 #include <syslog.h> |
|
119 #include <stdarg.h> |
|
120 #include "nsswitch.h" |
|
121 |
|
122 #ifdef MOZ_GETADDRINFO_LOG_VERBOSE |
|
123 #include <android/log.h> |
|
124 #endif |
|
125 |
|
126 #ifdef ANDROID_CHANGES |
|
127 #include <sys/system_properties.h> |
|
128 #endif /* ANDROID_CHANGES */ |
|
129 |
|
130 typedef struct _pseudo_FILE { |
|
131 int fd; |
|
132 off_t maplen; |
|
133 void* mapping; |
|
134 off_t offset; |
|
135 } _pseudo_FILE; |
|
136 |
|
137 #define _PSEUDO_FILE_INITIALIZER { -1, 0, MAP_FAILED, 0 } |
|
138 |
|
139 static void |
|
140 _pseudo_fclose(_pseudo_FILE * __restrict__ fp) |
|
141 { |
|
142 assert(fp); |
|
143 fp->offset = 0; |
|
144 if (fp->mapping != MAP_FAILED) { |
|
145 (void) munmap(fp->mapping, fp->maplen); |
|
146 fp->mapping = MAP_FAILED; |
|
147 } |
|
148 fp->maplen = 0; |
|
149 if (fp->fd != -1) { |
|
150 (void) close(fp->fd); |
|
151 fp->fd = -1; |
|
152 } |
|
153 } |
|
154 |
|
155 static _pseudo_FILE * |
|
156 _pseudo_fopen_r(_pseudo_FILE * __restrict__ fp, const char* fname) |
|
157 { |
|
158 struct stat statbuf; |
|
159 assert(fp); |
|
160 fp->fd = open(fname, O_RDONLY); |
|
161 if (fp->fd < 0) { |
|
162 fp->fd = -1; |
|
163 return NULL; |
|
164 } |
|
165 if ((0 != fstat(fp->fd, &statbuf)) || (statbuf.st_size <= 0)) { |
|
166 close(fp->fd); |
|
167 fp->fd = -1; |
|
168 return NULL; |
|
169 } |
|
170 fp->maplen = statbuf.st_size; |
|
171 fp->mapping = mmap(NULL, fp->maplen, PROT_READ, MAP_PRIVATE, fp->fd, 0); |
|
172 if (fp->mapping == MAP_FAILED) { |
|
173 close(fp->fd); |
|
174 fp->fd = -1; |
|
175 return NULL; |
|
176 } |
|
177 fp->offset = 0; |
|
178 return fp; |
|
179 } |
|
180 |
|
181 static void |
|
182 _pseudo_rewind(_pseudo_FILE * __restrict__ fp) |
|
183 { |
|
184 assert(fp); |
|
185 fp->offset = 0; |
|
186 } |
|
187 |
|
188 static char* |
|
189 _pseudo_fgets(char* buf, int bufsize, _pseudo_FILE * __restrict__ fp) |
|
190 { |
|
191 char* current; |
|
192 char* endp; |
|
193 int maxcopy; |
|
194 assert(fp); |
|
195 maxcopy = fp->maplen - fp->offset; |
|
196 if (fp->mapping == MAP_FAILED) |
|
197 return NULL; |
|
198 if (maxcopy > bufsize - 1) |
|
199 maxcopy = bufsize - 1; |
|
200 if (maxcopy <= 0) |
|
201 return NULL; |
|
202 current = ((char*) fp->mapping) + fp->offset; |
|
203 endp = memccpy(buf, current, '\n', maxcopy); |
|
204 if (endp) |
|
205 maxcopy = endp - buf; |
|
206 buf[maxcopy] = '\0'; |
|
207 fp->offset += maxcopy; |
|
208 return buf; |
|
209 } |
|
210 |
|
211 typedef union sockaddr_union { |
|
212 struct sockaddr generic; |
|
213 struct sockaddr_in in; |
|
214 struct sockaddr_in6 in6; |
|
215 } sockaddr_union; |
|
216 |
|
217 #define SUCCESS 0 |
|
218 #define ANY 0 |
|
219 #define YES 1 |
|
220 #define NO 0 |
|
221 |
|
222 static const char in_addrany[] = { 0, 0, 0, 0 }; |
|
223 static const char in_loopback[] = { 127, 0, 0, 1 }; |
|
224 #ifdef INET6 |
|
225 static const char in6_addrany[] = { |
|
226 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
|
227 }; |
|
228 static const char in6_loopback[] = { |
|
229 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 |
|
230 }; |
|
231 #endif |
|
232 |
|
233 static const struct afd { |
|
234 int a_af; |
|
235 int a_addrlen; |
|
236 int a_socklen; |
|
237 int a_off; |
|
238 const char *a_addrany; |
|
239 const char *a_loopback; |
|
240 int a_scoped; |
|
241 } afdl [] = { |
|
242 #ifdef INET6 |
|
243 {PF_INET6, sizeof(struct in6_addr), |
|
244 sizeof(struct sockaddr_in6), |
|
245 offsetof(struct sockaddr_in6, sin6_addr), |
|
246 in6_addrany, in6_loopback, 1}, |
|
247 #endif |
|
248 {PF_INET, sizeof(struct in_addr), |
|
249 sizeof(struct sockaddr_in), |
|
250 offsetof(struct sockaddr_in, sin_addr), |
|
251 in_addrany, in_loopback, 0}, |
|
252 {0, 0, 0, 0, NULL, NULL, 0}, |
|
253 }; |
|
254 |
|
255 struct explore { |
|
256 int e_af; |
|
257 int e_socktype; |
|
258 int e_protocol; |
|
259 const char *e_protostr; |
|
260 int e_wild; |
|
261 #define WILD_AF(ex) ((ex)->e_wild & 0x01) |
|
262 #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) |
|
263 #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) |
|
264 }; |
|
265 |
|
266 static const struct explore explore[] = { |
|
267 #if 0 |
|
268 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, |
|
269 #endif |
|
270 #ifdef INET6 |
|
271 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, |
|
272 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, |
|
273 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, |
|
274 #endif |
|
275 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, |
|
276 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, |
|
277 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, |
|
278 { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, |
|
279 { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, |
|
280 { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, |
|
281 { -1, 0, 0, NULL, 0 }, |
|
282 }; |
|
283 |
|
284 #ifdef INET6 |
|
285 #define PTON_MAX 16 |
|
286 #else |
|
287 #define PTON_MAX 4 |
|
288 #endif |
|
289 |
|
290 static const ns_src default_dns_files[] = { |
|
291 { NSSRC_FILES, NS_SUCCESS }, |
|
292 { NSSRC_DNS, NS_SUCCESS }, |
|
293 { 0, 0 } |
|
294 }; |
|
295 |
|
296 #define MAXPACKET (64*1024) |
|
297 |
|
298 typedef union { |
|
299 HEADER hdr; |
|
300 u_char buf[MAXPACKET]; |
|
301 } querybuf; |
|
302 |
|
303 struct res_target { |
|
304 struct res_target *next; |
|
305 const char *name; /* domain name */ |
|
306 int qclass, qtype; /* class and type of query */ |
|
307 u_char *answer; /* buffer to put answer */ |
|
308 int anslen; /* size of answer buffer */ |
|
309 int n; /* result length */ |
|
310 }; |
|
311 |
|
312 static int str2number(const char *); |
|
313 static int explore_fqdn(const struct addrinfo *, const char *, |
|
314 const char *, struct addrinfo **); |
|
315 static int explore_null(const struct addrinfo *, |
|
316 const char *, struct addrinfo **); |
|
317 static int explore_numeric(const struct addrinfo *, const char *, |
|
318 const char *, struct addrinfo **, const char *); |
|
319 static int explore_numeric_scope(const struct addrinfo *, const char *, |
|
320 const char *, struct addrinfo **); |
|
321 static int get_canonname(const struct addrinfo *, |
|
322 struct addrinfo *, const char *); |
|
323 static struct addrinfo *get_ai(const struct addrinfo *, |
|
324 const struct afd *, const char *); |
|
325 static int get_portmatch(const struct addrinfo *, const char *); |
|
326 static int get_port(const struct addrinfo *, const char *, int); |
|
327 static const struct afd *find_afd(int); |
|
328 #ifdef INET6 |
|
329 static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *); |
|
330 #endif |
|
331 |
|
332 static struct addrinfo *getanswer(const querybuf *, int, const char *, int, |
|
333 const struct addrinfo *); |
|
334 static int _dns_getaddrinfo(void *, void *, va_list); |
|
335 static void _sethtent(_pseudo_FILE * __restrict__); |
|
336 static void _endhtent(_pseudo_FILE * __restrict__); |
|
337 static struct addrinfo *_gethtent(_pseudo_FILE * __restrict__, const char *, |
|
338 const struct addrinfo *); |
|
339 static int _files_getaddrinfo(void *, void *, va_list); |
|
340 |
|
341 static int res_queryN(const char *, struct res_target *, res_state); |
|
342 static int res_searchN(const char *, struct res_target *, res_state); |
|
343 static int res_querydomainN(const char *, const char *, |
|
344 struct res_target *, res_state); |
|
345 |
|
346 static const char * const ai_errlist[] = { |
|
347 "Success", |
|
348 "Address family for hostname not supported", /* EAI_ADDRFAMILY */ |
|
349 "Temporary failure in name resolution", /* EAI_AGAIN */ |
|
350 "Invalid value for ai_flags", /* EAI_BADFLAGS */ |
|
351 "Non-recoverable failure in name resolution", /* EAI_FAIL */ |
|
352 "ai_family not supported", /* EAI_FAMILY */ |
|
353 "Memory allocation failure", /* EAI_MEMORY */ |
|
354 "No address associated with hostname", /* EAI_NODATA */ |
|
355 "hostname nor servname provided, or not known", /* EAI_NONAME */ |
|
356 "servname not supported for ai_socktype", /* EAI_SERVICE */ |
|
357 "ai_socktype not supported", /* EAI_SOCKTYPE */ |
|
358 "System error returned in errno", /* EAI_SYSTEM */ |
|
359 "Invalid value for hints", /* EAI_BADHINTS */ |
|
360 "Resolved protocol is unknown", /* EAI_PROTOCOL */ |
|
361 "Argument buffer overflow", /* EAI_OVERFLOW */ |
|
362 "Unknown error", /* EAI_MAX */ |
|
363 }; |
|
364 |
|
365 /* XXX macros that make external reference is BAD. */ |
|
366 |
|
367 #define GET_AI(ai, afd, addr) \ |
|
368 do { \ |
|
369 /* external reference: pai, error, and label free */ \ |
|
370 (ai) = get_ai(pai, (afd), (addr)); \ |
|
371 if ((ai) == NULL) { \ |
|
372 error = EAI_MEMORY; \ |
|
373 goto free; \ |
|
374 } \ |
|
375 } while (/*CONSTCOND*/0) |
|
376 |
|
377 #define GET_PORT(ai, serv) \ |
|
378 do { \ |
|
379 /* external reference: error and label free */ \ |
|
380 error = get_port((ai), (serv), 0); \ |
|
381 if (error != 0) \ |
|
382 goto free; \ |
|
383 } while (/*CONSTCOND*/0) |
|
384 |
|
385 #define GET_CANONNAME(ai, str) \ |
|
386 do { \ |
|
387 /* external reference: pai, error and label free */ \ |
|
388 error = get_canonname(pai, (ai), (str)); \ |
|
389 if (error != 0) \ |
|
390 goto free; \ |
|
391 } while (/*CONSTCOND*/0) |
|
392 |
|
393 #define ERR(err) \ |
|
394 do { \ |
|
395 /* external reference: error, and label bad */ \ |
|
396 error = (err); \ |
|
397 goto bad; \ |
|
398 /*NOTREACHED*/ \ |
|
399 } while (/*CONSTCOND*/0) |
|
400 |
|
401 #define MATCH_FAMILY(x, y, w) \ |
|
402 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || \ |
|
403 (y) == PF_UNSPEC))) |
|
404 #define MATCH(x, y, w) \ |
|
405 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) |
|
406 |
|
407 #pragma GCC visibility push(default) |
|
408 |
|
409 extern const char * |
|
410 __wrap_gai_strerror(int ecode); |
|
411 extern void |
|
412 __wrap_freeaddrinfo(struct addrinfo *ai); |
|
413 extern int |
|
414 __wrap_getaddrinfo(const char *hostname, const char *servname, |
|
415 const struct addrinfo *hints, struct addrinfo **res); |
|
416 |
|
417 int android_sdk_version; |
|
418 |
|
419 #pragma GCC visibility pop |
|
420 |
|
421 int android_sdk_version = -1; |
|
422 |
|
423 static int honeycomb_or_later() |
|
424 { |
|
425 #ifdef MOZ_GETADDRINFO_LOG_VERBOSE |
|
426 __android_log_print(ANDROID_LOG_INFO, "getaddrinfo", |
|
427 "I am%s Honeycomb\n", |
|
428 (android_sdk_version >= 11) ? "" : " not"); |
|
429 #endif |
|
430 return android_sdk_version >= 11; |
|
431 } |
|
432 |
|
433 const char * |
|
434 __wrap_gai_strerror(int ecode) |
|
435 { |
|
436 if (honeycomb_or_later()) |
|
437 return gai_strerror(ecode); |
|
438 if (ecode < 0 || ecode > EAI_MAX) |
|
439 ecode = EAI_MAX; |
|
440 return ai_errlist[ecode]; |
|
441 } |
|
442 |
|
443 void |
|
444 __wrap_freeaddrinfo(struct addrinfo *ai) |
|
445 { |
|
446 struct addrinfo *next; |
|
447 |
|
448 if (honeycomb_or_later()) { |
|
449 freeaddrinfo(ai); |
|
450 return; |
|
451 } |
|
452 |
|
453 assert(ai != NULL); |
|
454 |
|
455 do { |
|
456 next = ai->ai_next; |
|
457 if (ai->ai_canonname) |
|
458 free(ai->ai_canonname); |
|
459 /* no need to free(ai->ai_addr) */ |
|
460 free(ai); |
|
461 ai = next; |
|
462 } while (ai); |
|
463 } |
|
464 |
|
465 static int |
|
466 str2number(const char *p) |
|
467 { |
|
468 char *ep; |
|
469 unsigned long v; |
|
470 |
|
471 assert(p != NULL); |
|
472 |
|
473 if (*p == '\0') |
|
474 return -1; |
|
475 ep = NULL; |
|
476 errno = 0; |
|
477 v = strtoul(p, &ep, 10); |
|
478 if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) |
|
479 return v; |
|
480 else |
|
481 return -1; |
|
482 } |
|
483 |
|
484 /* |
|
485 * Connect a UDP socket to a given unicast address. This will cause no network |
|
486 * traffic, but will fail fast if the system has no or limited reachability to |
|
487 * the destination (e.g., no IPv4 address, no IPv6 default route, ...). |
|
488 */ |
|
489 static int |
|
490 _test_connect(int pf, struct sockaddr *addr, size_t addrlen) { |
|
491 int s = socket(pf, SOCK_DGRAM, IPPROTO_UDP); |
|
492 if (s < 0) |
|
493 return 0; |
|
494 int ret; |
|
495 do { |
|
496 ret = connect(s, addr, addrlen); |
|
497 } while (ret < 0 && errno == EINTR); |
|
498 int success = (ret == 0); |
|
499 do { |
|
500 ret = close(s); |
|
501 } while (ret < 0 && errno == EINTR); |
|
502 return success; |
|
503 } |
|
504 |
|
505 /* |
|
506 * The following functions determine whether IPv4 or IPv6 connectivity is |
|
507 * available in order to implement AI_ADDRCONFIG. |
|
508 * |
|
509 * Strictly speaking, AI_ADDRCONFIG should not look at whether connectivity is |
|
510 * available, but whether addresses of the specified family are "configured |
|
511 * on the local system". However, bionic doesn't currently support getifaddrs, |
|
512 * so checking for connectivity is the next best thing. |
|
513 */ |
|
514 static int |
|
515 _have_ipv6() { |
|
516 static const struct sockaddr_in6 sin6_test = { |
|
517 .sin6_family = AF_INET6, |
|
518 .sin6_addr.s6_addr = { // 2000:: |
|
519 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} |
|
520 }; |
|
521 sockaddr_union addr = { .in6 = sin6_test }; |
|
522 return _test_connect(PF_INET6, &addr.generic, sizeof(addr.in6)); |
|
523 } |
|
524 |
|
525 static int |
|
526 _have_ipv4() { |
|
527 static const struct sockaddr_in sin_test = { |
|
528 .sin_family = AF_INET, |
|
529 .sin_addr.s_addr = __constant_htonl(0x08080808L) // 8.8.8.8 |
|
530 }; |
|
531 sockaddr_union addr = { .in = sin_test }; |
|
532 return _test_connect(PF_INET, &addr.generic, sizeof(addr.in)); |
|
533 } |
|
534 |
|
535 int |
|
536 __wrap_getaddrinfo(const char *hostname, const char *servname, |
|
537 const struct addrinfo *hints, struct addrinfo **res) |
|
538 { |
|
539 struct addrinfo sentinel; |
|
540 struct addrinfo *cur; |
|
541 int error = 0; |
|
542 struct addrinfo ai; |
|
543 struct addrinfo ai0; |
|
544 struct addrinfo *pai; |
|
545 const struct explore *ex; |
|
546 |
|
547 if (honeycomb_or_later()) |
|
548 return getaddrinfo(hostname, servname, hints, res); |
|
549 |
|
550 /* hostname is allowed to be NULL */ |
|
551 /* servname is allowed to be NULL */ |
|
552 /* hints is allowed to be NULL */ |
|
553 assert(res != NULL); |
|
554 |
|
555 memset(&sentinel, 0, sizeof(sentinel)); |
|
556 cur = &sentinel; |
|
557 pai = &ai; |
|
558 pai->ai_flags = 0; |
|
559 pai->ai_family = PF_UNSPEC; |
|
560 pai->ai_socktype = ANY; |
|
561 pai->ai_protocol = ANY; |
|
562 pai->ai_addrlen = 0; |
|
563 pai->ai_canonname = NULL; |
|
564 pai->ai_addr = NULL; |
|
565 pai->ai_next = NULL; |
|
566 |
|
567 if (hostname == NULL && servname == NULL) |
|
568 return EAI_NONAME; |
|
569 if (hints) { |
|
570 /* error check for hints */ |
|
571 if (hints->ai_addrlen || hints->ai_canonname || |
|
572 hints->ai_addr || hints->ai_next) |
|
573 ERR(EAI_BADHINTS); /* xxx */ |
|
574 if (hints->ai_flags & ~AI_MASK) |
|
575 ERR(EAI_BADFLAGS); |
|
576 switch (hints->ai_family) { |
|
577 case PF_UNSPEC: |
|
578 case PF_INET: |
|
579 #ifdef INET6 |
|
580 case PF_INET6: |
|
581 #endif |
|
582 break; |
|
583 default: |
|
584 ERR(EAI_FAMILY); |
|
585 } |
|
586 memcpy(pai, hints, sizeof(*pai)); |
|
587 |
|
588 /* |
|
589 * if both socktype/protocol are specified, check if they |
|
590 * are meaningful combination. |
|
591 */ |
|
592 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { |
|
593 for (ex = explore; ex->e_af >= 0; ex++) { |
|
594 if (pai->ai_family != ex->e_af) |
|
595 continue; |
|
596 if (ex->e_socktype == ANY) |
|
597 continue; |
|
598 if (ex->e_protocol == ANY) |
|
599 continue; |
|
600 if (pai->ai_socktype == ex->e_socktype |
|
601 && pai->ai_protocol != ex->e_protocol) { |
|
602 ERR(EAI_BADHINTS); |
|
603 } |
|
604 } |
|
605 } |
|
606 } |
|
607 |
|
608 /* |
|
609 * check for special cases. (1) numeric servname is disallowed if |
|
610 * socktype/protocol are left unspecified. (2) servname is disallowed |
|
611 * for raw and other inet{,6} sockets. |
|
612 */ |
|
613 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) |
|
614 #ifdef PF_INET6 |
|
615 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) |
|
616 #endif |
|
617 ) { |
|
618 ai0 = *pai; /* backup *pai */ |
|
619 |
|
620 if (pai->ai_family == PF_UNSPEC) { |
|
621 #ifdef PF_INET6 |
|
622 pai->ai_family = PF_INET6; |
|
623 #else |
|
624 pai->ai_family = PF_INET; |
|
625 #endif |
|
626 } |
|
627 error = get_portmatch(pai, servname); |
|
628 if (error) |
|
629 ERR(error); |
|
630 |
|
631 *pai = ai0; |
|
632 } |
|
633 |
|
634 ai0 = *pai; |
|
635 |
|
636 /* NULL hostname, or numeric hostname */ |
|
637 for (ex = explore; ex->e_af >= 0; ex++) { |
|
638 *pai = ai0; |
|
639 |
|
640 /* PF_UNSPEC entries are prepared for DNS queries only */ |
|
641 if (ex->e_af == PF_UNSPEC) |
|
642 continue; |
|
643 |
|
644 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) |
|
645 continue; |
|
646 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) |
|
647 continue; |
|
648 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) |
|
649 continue; |
|
650 |
|
651 if (pai->ai_family == PF_UNSPEC) |
|
652 pai->ai_family = ex->e_af; |
|
653 if (pai->ai_socktype == ANY && ex->e_socktype != ANY) |
|
654 pai->ai_socktype = ex->e_socktype; |
|
655 if (pai->ai_protocol == ANY && ex->e_protocol != ANY) |
|
656 pai->ai_protocol = ex->e_protocol; |
|
657 |
|
658 if (hostname == NULL) |
|
659 error = explore_null(pai, servname, &cur->ai_next); |
|
660 else |
|
661 error = explore_numeric_scope(pai, hostname, servname, |
|
662 &cur->ai_next); |
|
663 |
|
664 if (error) |
|
665 goto free; |
|
666 |
|
667 while (cur->ai_next) |
|
668 cur = cur->ai_next; |
|
669 } |
|
670 |
|
671 /* |
|
672 * XXX |
|
673 * If numeric representation of AF1 can be interpreted as FQDN |
|
674 * representation of AF2, we need to think again about the code below. |
|
675 */ |
|
676 if (sentinel.ai_next) |
|
677 goto good; |
|
678 |
|
679 if (hostname == NULL) |
|
680 ERR(EAI_NODATA); |
|
681 if (pai->ai_flags & AI_NUMERICHOST) |
|
682 ERR(EAI_NONAME); |
|
683 |
|
684 /* |
|
685 * hostname as alphabetical name. |
|
686 * we would like to prefer AF_INET6 than AF_INET, so we'll make a |
|
687 * outer loop by AFs. |
|
688 */ |
|
689 for (ex = explore; ex->e_af >= 0; ex++) { |
|
690 *pai = ai0; |
|
691 |
|
692 /* require exact match for family field */ |
|
693 if (pai->ai_family != ex->e_af) |
|
694 continue; |
|
695 |
|
696 if (!MATCH(pai->ai_socktype, ex->e_socktype, |
|
697 WILD_SOCKTYPE(ex))) { |
|
698 continue; |
|
699 } |
|
700 if (!MATCH(pai->ai_protocol, ex->e_protocol, |
|
701 WILD_PROTOCOL(ex))) { |
|
702 continue; |
|
703 } |
|
704 |
|
705 if (pai->ai_socktype == ANY && ex->e_socktype != ANY) |
|
706 pai->ai_socktype = ex->e_socktype; |
|
707 if (pai->ai_protocol == ANY && ex->e_protocol != ANY) |
|
708 pai->ai_protocol = ex->e_protocol; |
|
709 |
|
710 error = explore_fqdn(pai, hostname, servname, |
|
711 &cur->ai_next); |
|
712 |
|
713 while (cur && cur->ai_next) |
|
714 cur = cur->ai_next; |
|
715 } |
|
716 |
|
717 /* XXX */ |
|
718 if (sentinel.ai_next) |
|
719 error = 0; |
|
720 |
|
721 if (error) |
|
722 goto free; |
|
723 if (error == 0) { |
|
724 if (sentinel.ai_next) { |
|
725 good: |
|
726 *res = sentinel.ai_next; |
|
727 return SUCCESS; |
|
728 } else |
|
729 error = EAI_FAIL; |
|
730 } |
|
731 free: |
|
732 bad: |
|
733 if (sentinel.ai_next) |
|
734 __wrap_freeaddrinfo(sentinel.ai_next); |
|
735 *res = NULL; |
|
736 return error; |
|
737 } |
|
738 |
|
739 /* |
|
740 * FQDN hostname, DNS lookup |
|
741 */ |
|
742 static int |
|
743 explore_fqdn(const struct addrinfo *pai, const char *hostname, |
|
744 const char *servname, struct addrinfo **res) |
|
745 { |
|
746 struct addrinfo *result; |
|
747 struct addrinfo *cur; |
|
748 int error = 0; |
|
749 static const ns_dtab dtab[] = { |
|
750 NS_FILES_CB(_files_getaddrinfo, NULL) |
|
751 { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ |
|
752 NS_NIS_CB(_yp_getaddrinfo, NULL) |
|
753 { 0, 0, 0 } |
|
754 }; |
|
755 |
|
756 assert(pai != NULL); |
|
757 /* hostname may be NULL */ |
|
758 /* servname may be NULL */ |
|
759 assert(res != NULL); |
|
760 |
|
761 result = NULL; |
|
762 |
|
763 /* |
|
764 * if the servname does not match socktype/protocol, ignore it. |
|
765 */ |
|
766 if (get_portmatch(pai, servname) != 0) |
|
767 return 0; |
|
768 |
|
769 switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", |
|
770 default_dns_files, hostname, pai)) { |
|
771 case NS_TRYAGAIN: |
|
772 error = EAI_AGAIN; |
|
773 goto free; |
|
774 case NS_UNAVAIL: |
|
775 error = EAI_FAIL; |
|
776 goto free; |
|
777 case NS_NOTFOUND: |
|
778 error = EAI_NODATA; |
|
779 goto free; |
|
780 case NS_SUCCESS: |
|
781 error = 0; |
|
782 for (cur = result; cur; cur = cur->ai_next) { |
|
783 GET_PORT(cur, servname); |
|
784 /* canonname should be filled already */ |
|
785 } |
|
786 break; |
|
787 } |
|
788 |
|
789 *res = result; |
|
790 |
|
791 return 0; |
|
792 |
|
793 free: |
|
794 if (result) |
|
795 __wrap_freeaddrinfo(result); |
|
796 return error; |
|
797 } |
|
798 |
|
799 /* |
|
800 * hostname == NULL. |
|
801 * passive socket -> anyaddr (0.0.0.0 or ::) |
|
802 * non-passive socket -> localhost (127.0.0.1 or ::1) |
|
803 */ |
|
804 static int |
|
805 explore_null(const struct addrinfo *pai, const char *servname, |
|
806 struct addrinfo **res) |
|
807 { |
|
808 int s; |
|
809 const struct afd *afd; |
|
810 struct addrinfo *cur; |
|
811 struct addrinfo sentinel; |
|
812 int error; |
|
813 |
|
814 assert(pai != NULL); |
|
815 /* servname may be NULL */ |
|
816 assert(res != NULL); |
|
817 |
|
818 *res = NULL; |
|
819 sentinel.ai_next = NULL; |
|
820 cur = &sentinel; |
|
821 |
|
822 /* |
|
823 * filter out AFs that are not supported by the kernel |
|
824 * XXX errno? |
|
825 */ |
|
826 s = socket(pai->ai_family, SOCK_DGRAM, 0); |
|
827 if (s < 0) { |
|
828 if (errno != EMFILE) |
|
829 return 0; |
|
830 } else |
|
831 close(s); |
|
832 |
|
833 /* |
|
834 * if the servname does not match socktype/protocol, ignore it. |
|
835 */ |
|
836 if (get_portmatch(pai, servname) != 0) |
|
837 return 0; |
|
838 |
|
839 afd = find_afd(pai->ai_family); |
|
840 if (afd == NULL) |
|
841 return 0; |
|
842 |
|
843 if (pai->ai_flags & AI_PASSIVE) { |
|
844 GET_AI(cur->ai_next, afd, afd->a_addrany); |
|
845 /* xxx meaningless? |
|
846 * GET_CANONNAME(cur->ai_next, "anyaddr"); |
|
847 */ |
|
848 GET_PORT(cur->ai_next, servname); |
|
849 } else { |
|
850 GET_AI(cur->ai_next, afd, afd->a_loopback); |
|
851 /* xxx meaningless? |
|
852 * GET_CANONNAME(cur->ai_next, "localhost"); |
|
853 */ |
|
854 GET_PORT(cur->ai_next, servname); |
|
855 } |
|
856 cur = cur->ai_next; |
|
857 |
|
858 *res = sentinel.ai_next; |
|
859 return 0; |
|
860 |
|
861 free: |
|
862 if (sentinel.ai_next) |
|
863 __wrap_freeaddrinfo(sentinel.ai_next); |
|
864 return error; |
|
865 } |
|
866 |
|
867 /* |
|
868 * numeric hostname |
|
869 */ |
|
870 static int |
|
871 explore_numeric(const struct addrinfo *pai, const char *hostname, |
|
872 const char *servname, struct addrinfo **res, const char *canonname) |
|
873 { |
|
874 const struct afd *afd; |
|
875 struct addrinfo *cur; |
|
876 struct addrinfo sentinel; |
|
877 int error; |
|
878 char pton[PTON_MAX]; |
|
879 |
|
880 assert(pai != NULL); |
|
881 /* hostname may be NULL */ |
|
882 /* servname may be NULL */ |
|
883 assert(res != NULL); |
|
884 |
|
885 *res = NULL; |
|
886 sentinel.ai_next = NULL; |
|
887 cur = &sentinel; |
|
888 |
|
889 /* |
|
890 * if the servname does not match socktype/protocol, ignore it. |
|
891 */ |
|
892 if (get_portmatch(pai, servname) != 0) |
|
893 return 0; |
|
894 |
|
895 afd = find_afd(pai->ai_family); |
|
896 if (afd == NULL) |
|
897 return 0; |
|
898 |
|
899 switch (afd->a_af) { |
|
900 #if 0 /*X/Open spec*/ |
|
901 case AF_INET: |
|
902 if (inet_aton(hostname, (struct in_addr *)pton) == 1) { |
|
903 if (pai->ai_family == afd->a_af || |
|
904 pai->ai_family == PF_UNSPEC /*?*/) { |
|
905 GET_AI(cur->ai_next, afd, pton); |
|
906 GET_PORT(cur->ai_next, servname); |
|
907 if ((pai->ai_flags & AI_CANONNAME)) { |
|
908 /* |
|
909 * Set the numeric address itself as |
|
910 * the canonical name, based on a |
|
911 * clarification in rfc2553bis-03. |
|
912 */ |
|
913 GET_CANONNAME(cur->ai_next, canonname); |
|
914 } |
|
915 while (cur && cur->ai_next) |
|
916 cur = cur->ai_next; |
|
917 } else |
|
918 ERR(EAI_FAMILY); /*xxx*/ |
|
919 } |
|
920 break; |
|
921 #endif |
|
922 default: |
|
923 if (inet_pton(afd->a_af, hostname, pton) == 1) { |
|
924 if (pai->ai_family == afd->a_af || |
|
925 pai->ai_family == PF_UNSPEC /*?*/) { |
|
926 GET_AI(cur->ai_next, afd, pton); |
|
927 GET_PORT(cur->ai_next, servname); |
|
928 if ((pai->ai_flags & AI_CANONNAME)) { |
|
929 /* |
|
930 * Set the numeric address itself as |
|
931 * the canonical name, based on a |
|
932 * clarification in rfc2553bis-03. |
|
933 */ |
|
934 GET_CANONNAME(cur->ai_next, canonname); |
|
935 } |
|
936 while (cur->ai_next) |
|
937 cur = cur->ai_next; |
|
938 } else |
|
939 ERR(EAI_FAMILY); /*xxx*/ |
|
940 } |
|
941 break; |
|
942 } |
|
943 |
|
944 *res = sentinel.ai_next; |
|
945 return 0; |
|
946 |
|
947 free: |
|
948 bad: |
|
949 if (sentinel.ai_next) |
|
950 __wrap_freeaddrinfo(sentinel.ai_next); |
|
951 return error; |
|
952 } |
|
953 |
|
954 /* |
|
955 * numeric hostname with scope |
|
956 */ |
|
957 static int |
|
958 explore_numeric_scope(const struct addrinfo *pai, const char *hostname, |
|
959 const char *servname, struct addrinfo **res) |
|
960 { |
|
961 #if !defined(SCOPE_DELIMITER) || !defined(INET6) |
|
962 return explore_numeric(pai, hostname, servname, res, hostname); |
|
963 #else |
|
964 const struct afd *afd; |
|
965 struct addrinfo *cur; |
|
966 int error; |
|
967 char *cp, *hostname2 = NULL, *scope, *addr; |
|
968 struct sockaddr_in6 *sin6; |
|
969 |
|
970 assert(pai != NULL); |
|
971 /* hostname may be NULL */ |
|
972 /* servname may be NULL */ |
|
973 assert(res != NULL); |
|
974 |
|
975 /* |
|
976 * if the servname does not match socktype/protocol, ignore it. |
|
977 */ |
|
978 if (get_portmatch(pai, servname) != 0) |
|
979 return 0; |
|
980 |
|
981 afd = find_afd(pai->ai_family); |
|
982 if (afd == NULL) |
|
983 return 0; |
|
984 |
|
985 if (!afd->a_scoped) |
|
986 return explore_numeric(pai, hostname, servname, res, hostname); |
|
987 |
|
988 cp = strchr(hostname, SCOPE_DELIMITER); |
|
989 if (cp == NULL) |
|
990 return explore_numeric(pai, hostname, servname, res, hostname); |
|
991 |
|
992 /* |
|
993 * Handle special case of <scoped_address><delimiter><scope id> |
|
994 */ |
|
995 hostname2 = strdup(hostname); |
|
996 if (hostname2 == NULL) |
|
997 return EAI_MEMORY; |
|
998 /* terminate at the delimiter */ |
|
999 hostname2[cp - hostname] = '\0'; |
|
1000 addr = hostname2; |
|
1001 scope = cp + 1; |
|
1002 |
|
1003 error = explore_numeric(pai, addr, servname, res, hostname); |
|
1004 if (error == 0) { |
|
1005 u_int32_t scopeid; |
|
1006 |
|
1007 for (cur = *res; cur; cur = cur->ai_next) { |
|
1008 if (cur->ai_family != AF_INET6) |
|
1009 continue; |
|
1010 sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; |
|
1011 if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { |
|
1012 free(hostname2); |
|
1013 return(EAI_NODATA); /* XXX: is return OK? */ |
|
1014 } |
|
1015 sin6->sin6_scope_id = scopeid; |
|
1016 } |
|
1017 } |
|
1018 |
|
1019 free(hostname2); |
|
1020 |
|
1021 return error; |
|
1022 #endif |
|
1023 } |
|
1024 |
|
1025 static int |
|
1026 get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str) |
|
1027 { |
|
1028 |
|
1029 assert(pai != NULL); |
|
1030 assert(ai != NULL); |
|
1031 assert(str != NULL); |
|
1032 |
|
1033 if ((pai->ai_flags & AI_CANONNAME) != 0) { |
|
1034 ai->ai_canonname = strdup(str); |
|
1035 if (ai->ai_canonname == NULL) |
|
1036 return EAI_MEMORY; |
|
1037 } |
|
1038 return 0; |
|
1039 } |
|
1040 |
|
1041 static struct addrinfo * |
|
1042 get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr) |
|
1043 { |
|
1044 char *p; |
|
1045 struct addrinfo *ai; |
|
1046 |
|
1047 assert(pai != NULL); |
|
1048 assert(afd != NULL); |
|
1049 assert(addr != NULL); |
|
1050 |
|
1051 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) |
|
1052 + (afd->a_socklen)); |
|
1053 if (ai == NULL) |
|
1054 return NULL; |
|
1055 |
|
1056 memcpy(ai, pai, sizeof(struct addrinfo)); |
|
1057 ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); |
|
1058 memset(ai->ai_addr, 0, (size_t)afd->a_socklen); |
|
1059 |
|
1060 #ifdef HAVE_SA_LEN |
|
1061 ai->ai_addr->sa_len = afd->a_socklen; |
|
1062 #endif |
|
1063 |
|
1064 ai->ai_addrlen = afd->a_socklen; |
|
1065 #if defined (__alpha__) || (defined(__i386__) && defined(_LP64)) || defined(__sparc64__) |
|
1066 ai->__ai_pad0 = 0; |
|
1067 #endif |
|
1068 ai->ai_addr->sa_family = ai->ai_family = afd->a_af; |
|
1069 p = (char *)(void *)(ai->ai_addr); |
|
1070 memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); |
|
1071 return ai; |
|
1072 } |
|
1073 |
|
1074 static int |
|
1075 get_portmatch(const struct addrinfo *ai, const char *servname) |
|
1076 { |
|
1077 |
|
1078 assert(ai != NULL); |
|
1079 /* servname may be NULL */ |
|
1080 |
|
1081 return get_port(ai, servname, 1); |
|
1082 } |
|
1083 |
|
1084 static int |
|
1085 get_port(const struct addrinfo *ai, const char *servname, int matchonly) |
|
1086 { |
|
1087 const char *proto; |
|
1088 struct servent *sp; |
|
1089 int port; |
|
1090 int allownumeric; |
|
1091 |
|
1092 assert(ai != NULL); |
|
1093 /* servname may be NULL */ |
|
1094 |
|
1095 if (servname == NULL) |
|
1096 return 0; |
|
1097 switch (ai->ai_family) { |
|
1098 case AF_INET: |
|
1099 #ifdef AF_INET6 |
|
1100 case AF_INET6: |
|
1101 #endif |
|
1102 break; |
|
1103 default: |
|
1104 return 0; |
|
1105 } |
|
1106 |
|
1107 switch (ai->ai_socktype) { |
|
1108 case SOCK_RAW: |
|
1109 return EAI_SERVICE; |
|
1110 case SOCK_DGRAM: |
|
1111 case SOCK_STREAM: |
|
1112 allownumeric = 1; |
|
1113 break; |
|
1114 case ANY: |
|
1115 #if 1 /* ANDROID-SPECIFIC CHANGE TO MATCH GLIBC */ |
|
1116 allownumeric = 1; |
|
1117 #else |
|
1118 allownumeric = 0; |
|
1119 #endif |
|
1120 break; |
|
1121 default: |
|
1122 return EAI_SOCKTYPE; |
|
1123 } |
|
1124 |
|
1125 port = str2number(servname); |
|
1126 if (port >= 0) { |
|
1127 if (!allownumeric) |
|
1128 return EAI_SERVICE; |
|
1129 if (port < 0 || port > 65535) |
|
1130 return EAI_SERVICE; |
|
1131 port = htons(port); |
|
1132 } else { |
|
1133 if (ai->ai_flags & AI_NUMERICSERV) |
|
1134 return EAI_NONAME; |
|
1135 |
|
1136 switch (ai->ai_socktype) { |
|
1137 case SOCK_DGRAM: |
|
1138 proto = "udp"; |
|
1139 break; |
|
1140 case SOCK_STREAM: |
|
1141 proto = "tcp"; |
|
1142 break; |
|
1143 default: |
|
1144 proto = NULL; |
|
1145 break; |
|
1146 } |
|
1147 |
|
1148 if ((sp = getservbyname(servname, proto)) == NULL) |
|
1149 return EAI_SERVICE; |
|
1150 port = sp->s_port; |
|
1151 } |
|
1152 |
|
1153 if (!matchonly) { |
|
1154 switch (ai->ai_family) { |
|
1155 case AF_INET: |
|
1156 ((struct sockaddr_in *)(void *) |
|
1157 ai->ai_addr)->sin_port = port; |
|
1158 break; |
|
1159 #ifdef INET6 |
|
1160 case AF_INET6: |
|
1161 ((struct sockaddr_in6 *)(void *) |
|
1162 ai->ai_addr)->sin6_port = port; |
|
1163 break; |
|
1164 #endif |
|
1165 } |
|
1166 } |
|
1167 |
|
1168 return 0; |
|
1169 } |
|
1170 |
|
1171 static const struct afd * |
|
1172 find_afd(int af) |
|
1173 { |
|
1174 const struct afd *afd; |
|
1175 |
|
1176 if (af == PF_UNSPEC) |
|
1177 return NULL; |
|
1178 for (afd = afdl; afd->a_af; afd++) { |
|
1179 if (afd->a_af == af) |
|
1180 return afd; |
|
1181 } |
|
1182 return NULL; |
|
1183 } |
|
1184 |
|
1185 #ifdef INET6 |
|
1186 /* convert a string to a scope identifier. XXX: IPv6 specific */ |
|
1187 static int |
|
1188 ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid) |
|
1189 { |
|
1190 u_long lscopeid; |
|
1191 struct in6_addr *a6; |
|
1192 char *ep; |
|
1193 |
|
1194 assert(scope != NULL); |
|
1195 assert(sin6 != NULL); |
|
1196 assert(scopeid != NULL); |
|
1197 |
|
1198 a6 = &sin6->sin6_addr; |
|
1199 |
|
1200 /* empty scopeid portion is invalid */ |
|
1201 if (*scope == '\0') |
|
1202 return -1; |
|
1203 |
|
1204 if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { |
|
1205 /* |
|
1206 * We currently assume a one-to-one mapping between links |
|
1207 * and interfaces, so we simply use interface indices for |
|
1208 * like-local scopes. |
|
1209 */ |
|
1210 *scopeid = if_nametoindex(scope); |
|
1211 if (*scopeid == 0) |
|
1212 goto trynumeric; |
|
1213 return 0; |
|
1214 } |
|
1215 |
|
1216 /* still unclear about literal, allow numeric only - placeholder */ |
|
1217 if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) |
|
1218 goto trynumeric; |
|
1219 if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) |
|
1220 goto trynumeric; |
|
1221 else |
|
1222 goto trynumeric; /* global */ |
|
1223 |
|
1224 /* try to convert to a numeric id as a last resort */ |
|
1225 trynumeric: |
|
1226 errno = 0; |
|
1227 lscopeid = strtoul(scope, &ep, 10); |
|
1228 *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); |
|
1229 if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) |
|
1230 return 0; |
|
1231 else |
|
1232 return -1; |
|
1233 } |
|
1234 #endif |
|
1235 |
|
1236 /* code duplicate with gethnamaddr.c */ |
|
1237 |
|
1238 static const char AskedForGot[] = |
|
1239 "gethostby*.getanswer: asked for \"%s\", got \"%s\""; |
|
1240 |
|
1241 static struct addrinfo * |
|
1242 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, |
|
1243 const struct addrinfo *pai) |
|
1244 { |
|
1245 struct addrinfo sentinel, *cur; |
|
1246 struct addrinfo ai; |
|
1247 const struct afd *afd; |
|
1248 char *canonname; |
|
1249 const HEADER *hp; |
|
1250 const u_char *cp; |
|
1251 int n; |
|
1252 const u_char *eom; |
|
1253 char *bp, *ep; |
|
1254 int type, class, ancount, qdcount; |
|
1255 int haveanswer, had_error; |
|
1256 char tbuf[MAXDNAME]; |
|
1257 int (*name_ok) (const char *); |
|
1258 char hostbuf[8*1024]; |
|
1259 |
|
1260 assert(answer != NULL); |
|
1261 assert(qname != NULL); |
|
1262 assert(pai != NULL); |
|
1263 |
|
1264 memset(&sentinel, 0, sizeof(sentinel)); |
|
1265 cur = &sentinel; |
|
1266 |
|
1267 canonname = NULL; |
|
1268 eom = answer->buf + anslen; |
|
1269 switch (qtype) { |
|
1270 case T_A: |
|
1271 case T_AAAA: |
|
1272 case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ |
|
1273 name_ok = res_hnok; |
|
1274 break; |
|
1275 default: |
|
1276 return NULL; /* XXX should be abort(); */ |
|
1277 } |
|
1278 /* |
|
1279 * find first satisfactory answer |
|
1280 */ |
|
1281 hp = &answer->hdr; |
|
1282 ancount = ntohs(hp->ancount); |
|
1283 qdcount = ntohs(hp->qdcount); |
|
1284 bp = hostbuf; |
|
1285 ep = hostbuf + sizeof hostbuf; |
|
1286 cp = answer->buf + HFIXEDSZ; |
|
1287 if (qdcount != 1) { |
|
1288 h_errno = NO_RECOVERY; |
|
1289 return (NULL); |
|
1290 } |
|
1291 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); |
|
1292 if ((n < 0) || !(*name_ok)(bp)) { |
|
1293 h_errno = NO_RECOVERY; |
|
1294 return (NULL); |
|
1295 } |
|
1296 cp += n + QFIXEDSZ; |
|
1297 if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { |
|
1298 /* res_send() has already verified that the query name is the |
|
1299 * same as the one we sent; this just gets the expanded name |
|
1300 * (i.e., with the succeeding search-domain tacked on). |
|
1301 */ |
|
1302 n = strlen(bp) + 1; /* for the \0 */ |
|
1303 if (n >= MAXHOSTNAMELEN) { |
|
1304 h_errno = NO_RECOVERY; |
|
1305 return (NULL); |
|
1306 } |
|
1307 canonname = bp; |
|
1308 bp += n; |
|
1309 /* The qname can be abbreviated, but h_name is now absolute. */ |
|
1310 qname = canonname; |
|
1311 } |
|
1312 haveanswer = 0; |
|
1313 had_error = 0; |
|
1314 while (ancount-- > 0 && cp < eom && !had_error) { |
|
1315 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); |
|
1316 if ((n < 0) || !(*name_ok)(bp)) { |
|
1317 had_error++; |
|
1318 continue; |
|
1319 } |
|
1320 cp += n; /* name */ |
|
1321 type = _getshort(cp); |
|
1322 cp += INT16SZ; /* type */ |
|
1323 class = _getshort(cp); |
|
1324 cp += INT16SZ + INT32SZ; /* class, TTL */ |
|
1325 n = _getshort(cp); |
|
1326 cp += INT16SZ; /* len */ |
|
1327 if (class != C_IN) { |
|
1328 /* XXX - debug? syslog? */ |
|
1329 cp += n; |
|
1330 continue; /* XXX - had_error++ ? */ |
|
1331 } |
|
1332 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && |
|
1333 type == T_CNAME) { |
|
1334 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); |
|
1335 if ((n < 0) || !(*name_ok)(tbuf)) { |
|
1336 had_error++; |
|
1337 continue; |
|
1338 } |
|
1339 cp += n; |
|
1340 /* Get canonical name. */ |
|
1341 n = strlen(tbuf) + 1; /* for the \0 */ |
|
1342 if (n > ep - bp || n >= MAXHOSTNAMELEN) { |
|
1343 had_error++; |
|
1344 continue; |
|
1345 } |
|
1346 strlcpy(bp, tbuf, (size_t)(ep - bp)); |
|
1347 canonname = bp; |
|
1348 bp += n; |
|
1349 continue; |
|
1350 } |
|
1351 if (qtype == T_ANY) { |
|
1352 if (!(type == T_A || type == T_AAAA)) { |
|
1353 cp += n; |
|
1354 continue; |
|
1355 } |
|
1356 } else if (type != qtype) { |
|
1357 if (type != T_KEY && type != T_SIG) |
|
1358 syslog(LOG_NOTICE|LOG_AUTH, |
|
1359 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", |
|
1360 qname, p_class(C_IN), p_type(qtype), |
|
1361 p_type(type)); |
|
1362 cp += n; |
|
1363 continue; /* XXX - had_error++ ? */ |
|
1364 } |
|
1365 switch (type) { |
|
1366 case T_A: |
|
1367 case T_AAAA: |
|
1368 if (strcasecmp(canonname, bp) != 0) { |
|
1369 syslog(LOG_NOTICE|LOG_AUTH, |
|
1370 AskedForGot, canonname, bp); |
|
1371 cp += n; |
|
1372 continue; /* XXX - had_error++ ? */ |
|
1373 } |
|
1374 if (type == T_A && n != INADDRSZ) { |
|
1375 cp += n; |
|
1376 continue; |
|
1377 } |
|
1378 if (type == T_AAAA && n != IN6ADDRSZ) { |
|
1379 cp += n; |
|
1380 continue; |
|
1381 } |
|
1382 if (type == T_AAAA) { |
|
1383 struct in6_addr in6; |
|
1384 memcpy(&in6, cp, IN6ADDRSZ); |
|
1385 if (IN6_IS_ADDR_V4MAPPED(&in6)) { |
|
1386 cp += n; |
|
1387 continue; |
|
1388 } |
|
1389 } |
|
1390 if (!haveanswer) { |
|
1391 int nn; |
|
1392 |
|
1393 canonname = bp; |
|
1394 nn = strlen(bp) + 1; /* for the \0 */ |
|
1395 bp += nn; |
|
1396 } |
|
1397 |
|
1398 /* don't overwrite pai */ |
|
1399 ai = *pai; |
|
1400 ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; |
|
1401 afd = find_afd(ai.ai_family); |
|
1402 if (afd == NULL) { |
|
1403 cp += n; |
|
1404 continue; |
|
1405 } |
|
1406 cur->ai_next = get_ai(&ai, afd, (const char *)cp); |
|
1407 if (cur->ai_next == NULL) |
|
1408 had_error++; |
|
1409 while (cur && cur->ai_next) |
|
1410 cur = cur->ai_next; |
|
1411 cp += n; |
|
1412 break; |
|
1413 default: |
|
1414 abort(); |
|
1415 } |
|
1416 if (!had_error) |
|
1417 haveanswer++; |
|
1418 } |
|
1419 if (haveanswer) { |
|
1420 if (!canonname) |
|
1421 (void)get_canonname(pai, sentinel.ai_next, qname); |
|
1422 else |
|
1423 (void)get_canonname(pai, sentinel.ai_next, canonname); |
|
1424 h_errno = NETDB_SUCCESS; |
|
1425 return sentinel.ai_next; |
|
1426 } |
|
1427 |
|
1428 h_errno = NO_RECOVERY; |
|
1429 return NULL; |
|
1430 } |
|
1431 |
|
1432 struct addrinfo_sort_elem { |
|
1433 struct addrinfo *ai; |
|
1434 int has_src_addr; |
|
1435 sockaddr_union src_addr; |
|
1436 int original_order; |
|
1437 }; |
|
1438 |
|
1439 /*ARGSUSED*/ |
|
1440 static int |
|
1441 _get_scope(const struct sockaddr *addr) |
|
1442 { |
|
1443 if (addr->sa_family == AF_INET6) { |
|
1444 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; |
|
1445 if (IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr)) { |
|
1446 return IPV6_ADDR_MC_SCOPE(&addr6->sin6_addr); |
|
1447 } else if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr) || |
|
1448 IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr)) { |
|
1449 /* |
|
1450 * RFC 4291 section 2.5.3 says loopback is to be treated as having |
|
1451 * link-local scope. |
|
1452 */ |
|
1453 return IPV6_ADDR_SCOPE_LINKLOCAL; |
|
1454 } else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)) { |
|
1455 return IPV6_ADDR_SCOPE_SITELOCAL; |
|
1456 } else { |
|
1457 return IPV6_ADDR_SCOPE_GLOBAL; |
|
1458 } |
|
1459 } else if (addr->sa_family == AF_INET) { |
|
1460 const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; |
|
1461 unsigned long int na = ntohl(addr4->sin_addr.s_addr); |
|
1462 |
|
1463 if (IN_LOOPBACK(na) || /* 127.0.0.0/8 */ |
|
1464 (na & 0xffff0000) == 0xa9fe0000) { /* 169.254.0.0/16 */ |
|
1465 return IPV6_ADDR_SCOPE_LINKLOCAL; |
|
1466 } else { |
|
1467 /* |
|
1468 * According to draft-ietf-6man-rfc3484-revise-01 section 2.3, |
|
1469 * it is best not to treat the private IPv4 ranges |
|
1470 * (10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16) as being |
|
1471 * in a special scope, so we don't. |
|
1472 */ |
|
1473 return IPV6_ADDR_SCOPE_GLOBAL; |
|
1474 } |
|
1475 } else { |
|
1476 /* |
|
1477 * This should never happen. |
|
1478 * Return a scope with low priority as a last resort. |
|
1479 */ |
|
1480 return IPV6_ADDR_SCOPE_NODELOCAL; |
|
1481 } |
|
1482 } |
|
1483 |
|
1484 /* These macros are modelled after the ones in <netinet/in6.h>. */ |
|
1485 |
|
1486 /* RFC 4380, section 2.6 */ |
|
1487 #define IN6_IS_ADDR_TEREDO(a) \ |
|
1488 ((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == ntohl(0x20010000))) |
|
1489 |
|
1490 /* RFC 3056, section 2. */ |
|
1491 #define IN6_IS_ADDR_6TO4(a) \ |
|
1492 (((a)->s6_addr[0] == 0x20) && ((a)->s6_addr[1] == 0x02)) |
|
1493 |
|
1494 /* 6bone testing address area (3ffe::/16), deprecated in RFC 3701. */ |
|
1495 #define IN6_IS_ADDR_6BONE(a) \ |
|
1496 (((a)->s6_addr[0] == 0x3f) && ((a)->s6_addr[1] == 0xfe)) |
|
1497 |
|
1498 /* |
|
1499 * Get the label for a given IPv4/IPv6 address. |
|
1500 * RFC 3484, section 2.1, plus changes from draft-ietf-6man-rfc3484-revise-01. |
|
1501 */ |
|
1502 |
|
1503 /*ARGSUSED*/ |
|
1504 static int |
|
1505 _get_label(const struct sockaddr *addr) |
|
1506 { |
|
1507 if (addr->sa_family == AF_INET) { |
|
1508 return 3; |
|
1509 } else if (addr->sa_family == AF_INET6) { |
|
1510 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; |
|
1511 if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) { |
|
1512 return 0; |
|
1513 } else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) { |
|
1514 return 3; |
|
1515 } else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) { |
|
1516 return 4; |
|
1517 } else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) { |
|
1518 return 5; |
|
1519 } else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) { |
|
1520 return 10; |
|
1521 } else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)) { |
|
1522 return 11; |
|
1523 } else if (IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) { |
|
1524 return 12; |
|
1525 } else { |
|
1526 return 2; |
|
1527 } |
|
1528 } else { |
|
1529 /* |
|
1530 * This should never happen. |
|
1531 * Return a semi-random label as a last resort. |
|
1532 */ |
|
1533 return 1; |
|
1534 } |
|
1535 } |
|
1536 |
|
1537 /* |
|
1538 * Get the precedence for a given IPv4/IPv6 address. |
|
1539 * RFC 3484, section 2.1, plus changes from draft-ietf-6man-rfc3484-revise-01. |
|
1540 */ |
|
1541 |
|
1542 /*ARGSUSED*/ |
|
1543 static int |
|
1544 _get_precedence(const struct sockaddr *addr) |
|
1545 { |
|
1546 if (addr->sa_family == AF_INET) { |
|
1547 return 30; |
|
1548 } else if (addr->sa_family == AF_INET6) { |
|
1549 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; |
|
1550 if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) { |
|
1551 return 60; |
|
1552 } else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) { |
|
1553 return 30; |
|
1554 } else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) { |
|
1555 return 20; |
|
1556 } else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) { |
|
1557 return 10; |
|
1558 } else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr) || |
|
1559 IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr) || |
|
1560 IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) { |
|
1561 return 1; |
|
1562 } else { |
|
1563 return 40; |
|
1564 } |
|
1565 } else { |
|
1566 return 1; |
|
1567 } |
|
1568 } |
|
1569 |
|
1570 /* |
|
1571 * Find number of matching initial bits between the two addresses a1 and a2. |
|
1572 */ |
|
1573 |
|
1574 /*ARGSUSED*/ |
|
1575 static int |
|
1576 _common_prefix_len(const struct in6_addr *a1, const struct in6_addr *a2) |
|
1577 { |
|
1578 const char *p1 = (const char *)a1; |
|
1579 const char *p2 = (const char *)a2; |
|
1580 unsigned i; |
|
1581 |
|
1582 for (i = 0; i < sizeof(*a1); ++i) { |
|
1583 int x, j; |
|
1584 |
|
1585 if (p1[i] == p2[i]) { |
|
1586 continue; |
|
1587 } |
|
1588 x = p1[i] ^ p2[i]; |
|
1589 for (j = 0; j < CHAR_BIT; ++j) { |
|
1590 if (x & (1 << (CHAR_BIT - 1))) { |
|
1591 return i * CHAR_BIT + j; |
|
1592 } |
|
1593 x <<= 1; |
|
1594 } |
|
1595 } |
|
1596 return sizeof(*a1) * CHAR_BIT; |
|
1597 } |
|
1598 |
|
1599 /* |
|
1600 * Compare two source/destination address pairs. |
|
1601 * RFC 3484, section 6. |
|
1602 */ |
|
1603 |
|
1604 /*ARGSUSED*/ |
|
1605 static int |
|
1606 _rfc3484_compare(const void *ptr1, const void* ptr2) |
|
1607 { |
|
1608 const struct addrinfo_sort_elem *a1 = (const struct addrinfo_sort_elem *)ptr1; |
|
1609 const struct addrinfo_sort_elem *a2 = (const struct addrinfo_sort_elem *)ptr2; |
|
1610 int scope_src1, scope_dst1, scope_match1; |
|
1611 int scope_src2, scope_dst2, scope_match2; |
|
1612 int label_src1, label_dst1, label_match1; |
|
1613 int label_src2, label_dst2, label_match2; |
|
1614 int precedence1, precedence2; |
|
1615 int prefixlen1, prefixlen2; |
|
1616 |
|
1617 /* Rule 1: Avoid unusable destinations. */ |
|
1618 if (a1->has_src_addr != a2->has_src_addr) { |
|
1619 return a2->has_src_addr - a1->has_src_addr; |
|
1620 } |
|
1621 |
|
1622 /* Rule 2: Prefer matching scope. */ |
|
1623 scope_src1 = _get_scope(&a1->src_addr.generic); |
|
1624 scope_dst1 = _get_scope(a1->ai->ai_addr); |
|
1625 scope_match1 = (scope_src1 == scope_dst1); |
|
1626 |
|
1627 scope_src2 = _get_scope(&a2->src_addr.generic); |
|
1628 scope_dst2 = _get_scope(a2->ai->ai_addr); |
|
1629 scope_match2 = (scope_src2 == scope_dst2); |
|
1630 |
|
1631 if (scope_match1 != scope_match2) { |
|
1632 return scope_match2 - scope_match1; |
|
1633 } |
|
1634 |
|
1635 /* |
|
1636 * Rule 3: Avoid deprecated addresses. |
|
1637 * TODO(sesse): We don't currently have a good way of finding this. |
|
1638 */ |
|
1639 |
|
1640 /* |
|
1641 * Rule 4: Prefer home addresses. |
|
1642 * TODO(sesse): We don't currently have a good way of finding this. |
|
1643 */ |
|
1644 |
|
1645 /* Rule 5: Prefer matching label. */ |
|
1646 label_src1 = _get_label(&a1->src_addr.generic); |
|
1647 label_dst1 = _get_label(a1->ai->ai_addr); |
|
1648 label_match1 = (label_src1 == label_dst1); |
|
1649 |
|
1650 label_src2 = _get_label(&a2->src_addr.generic); |
|
1651 label_dst2 = _get_label(a2->ai->ai_addr); |
|
1652 label_match2 = (label_src2 == label_dst2); |
|
1653 |
|
1654 if (label_match1 != label_match2) { |
|
1655 return label_match2 - label_match1; |
|
1656 } |
|
1657 |
|
1658 /* Rule 6: Prefer higher precedence. */ |
|
1659 precedence1 = _get_precedence(a1->ai->ai_addr); |
|
1660 precedence2 = _get_precedence(a2->ai->ai_addr); |
|
1661 if (precedence1 != precedence2) { |
|
1662 return precedence2 - precedence1; |
|
1663 } |
|
1664 |
|
1665 /* |
|
1666 * Rule 7: Prefer native transport. |
|
1667 * TODO(sesse): We don't currently have a good way of finding this. |
|
1668 */ |
|
1669 |
|
1670 /* Rule 8: Prefer smaller scope. */ |
|
1671 if (scope_dst1 != scope_dst2) { |
|
1672 return scope_dst1 - scope_dst2; |
|
1673 } |
|
1674 |
|
1675 /* |
|
1676 * Rule 9: Use longest matching prefix. |
|
1677 * We implement this for IPv6 only, as the rules in RFC 3484 don't seem |
|
1678 * to work very well directly applied to IPv4. (glibc uses information from |
|
1679 * the routing table for a custom IPv4 implementation here.) |
|
1680 */ |
|
1681 if (a1->has_src_addr && a1->ai->ai_addr->sa_family == AF_INET6 && |
|
1682 a2->has_src_addr && a2->ai->ai_addr->sa_family == AF_INET6) { |
|
1683 const struct sockaddr_in6 *a1_src = &a1->src_addr.in6; |
|
1684 const struct sockaddr_in6 *a1_dst = (const struct sockaddr_in6 *)a1->ai->ai_addr; |
|
1685 const struct sockaddr_in6 *a2_src = &a2->src_addr.in6; |
|
1686 const struct sockaddr_in6 *a2_dst = (const struct sockaddr_in6 *)a2->ai->ai_addr; |
|
1687 prefixlen1 = _common_prefix_len(&a1_src->sin6_addr, &a1_dst->sin6_addr); |
|
1688 prefixlen2 = _common_prefix_len(&a2_src->sin6_addr, &a2_dst->sin6_addr); |
|
1689 if (prefixlen1 != prefixlen2) { |
|
1690 return prefixlen2 - prefixlen1; |
|
1691 } |
|
1692 } |
|
1693 |
|
1694 /* |
|
1695 * Rule 10: Leave the order unchanged. |
|
1696 * We need this since qsort() is not necessarily stable. |
|
1697 */ |
|
1698 return a1->original_order - a2->original_order; |
|
1699 } |
|
1700 |
|
1701 /* |
|
1702 * Find the source address that will be used if trying to connect to the given |
|
1703 * address. src_addr must be large enough to hold a struct sockaddr_in6. |
|
1704 * |
|
1705 * Returns 1 if a source address was found, 0 if the address is unreachable, |
|
1706 * and -1 if a fatal error occurred. If 0 or 1, the contents of src_addr are |
|
1707 * undefined. |
|
1708 */ |
|
1709 |
|
1710 /*ARGSUSED*/ |
|
1711 static int |
|
1712 _find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr) |
|
1713 { |
|
1714 int sock; |
|
1715 int ret; |
|
1716 socklen_t len; |
|
1717 |
|
1718 switch (addr->sa_family) { |
|
1719 case AF_INET: |
|
1720 len = sizeof(struct sockaddr_in); |
|
1721 break; |
|
1722 case AF_INET6: |
|
1723 len = sizeof(struct sockaddr_in6); |
|
1724 break; |
|
1725 default: |
|
1726 /* No known usable source address for non-INET families. */ |
|
1727 return 0; |
|
1728 } |
|
1729 |
|
1730 sock = socket(addr->sa_family, SOCK_DGRAM, IPPROTO_UDP); |
|
1731 if (sock == -1) { |
|
1732 if (errno == EAFNOSUPPORT) { |
|
1733 return 0; |
|
1734 } else { |
|
1735 return -1; |
|
1736 } |
|
1737 } |
|
1738 |
|
1739 do { |
|
1740 ret = connect(sock, addr, len); |
|
1741 } while (ret == -1 && errno == EINTR); |
|
1742 |
|
1743 if (ret == -1) { |
|
1744 close(sock); |
|
1745 return 0; |
|
1746 } |
|
1747 |
|
1748 if (getsockname(sock, src_addr, &len) == -1) { |
|
1749 close(sock); |
|
1750 return -1; |
|
1751 } |
|
1752 close(sock); |
|
1753 return 1; |
|
1754 } |
|
1755 |
|
1756 /* |
|
1757 * Sort the linked list starting at sentinel->ai_next in RFC3484 order. |
|
1758 * Will leave the list unchanged if an error occurs. |
|
1759 */ |
|
1760 |
|
1761 /*ARGSUSED*/ |
|
1762 static void |
|
1763 _rfc3484_sort(struct addrinfo *list_sentinel) |
|
1764 { |
|
1765 struct addrinfo *cur; |
|
1766 int nelem = 0, i; |
|
1767 struct addrinfo_sort_elem *elems; |
|
1768 |
|
1769 cur = list_sentinel->ai_next; |
|
1770 while (cur) { |
|
1771 ++nelem; |
|
1772 cur = cur->ai_next; |
|
1773 } |
|
1774 |
|
1775 elems = (struct addrinfo_sort_elem *)malloc(nelem * sizeof(struct addrinfo_sort_elem)); |
|
1776 if (elems == NULL) { |
|
1777 goto error; |
|
1778 } |
|
1779 |
|
1780 /* |
|
1781 * Convert the linked list to an array that also contains the candidate |
|
1782 * source address for each destination address. |
|
1783 */ |
|
1784 for (i = 0, cur = list_sentinel->ai_next; i < nelem; ++i, cur = cur->ai_next) { |
|
1785 int has_src_addr; |
|
1786 assert(cur != NULL); |
|
1787 elems[i].ai = cur; |
|
1788 elems[i].original_order = i; |
|
1789 |
|
1790 has_src_addr = _find_src_addr(cur->ai_addr, &elems[i].src_addr.generic); |
|
1791 if (has_src_addr == -1) { |
|
1792 goto error; |
|
1793 } |
|
1794 elems[i].has_src_addr = has_src_addr; |
|
1795 } |
|
1796 |
|
1797 /* Sort the addresses, and rearrange the linked list so it matches the sorted order. */ |
|
1798 qsort((void *)elems, nelem, sizeof(struct addrinfo_sort_elem), _rfc3484_compare); |
|
1799 |
|
1800 list_sentinel->ai_next = elems[0].ai; |
|
1801 for (i = 0; i < nelem - 1; ++i) { |
|
1802 elems[i].ai->ai_next = elems[i + 1].ai; |
|
1803 } |
|
1804 elems[nelem - 1].ai->ai_next = NULL; |
|
1805 |
|
1806 error: |
|
1807 free(elems); |
|
1808 } |
|
1809 |
|
1810 /*ARGSUSED*/ |
|
1811 static int |
|
1812 _dns_getaddrinfo(void *rv, void *cb_data, va_list ap) |
|
1813 { |
|
1814 struct addrinfo *ai; |
|
1815 querybuf *buf, *buf2; |
|
1816 const char *name; |
|
1817 const struct addrinfo *pai; |
|
1818 struct addrinfo sentinel, *cur; |
|
1819 struct res_target q, q2; |
|
1820 res_state res; |
|
1821 |
|
1822 name = va_arg(ap, char *); |
|
1823 pai = va_arg(ap, const struct addrinfo *); |
|
1824 //fprintf(stderr, "_dns_getaddrinfo() name = '%s'\n", name); |
|
1825 |
|
1826 memset(&q, 0, sizeof(q)); |
|
1827 memset(&q2, 0, sizeof(q2)); |
|
1828 memset(&sentinel, 0, sizeof(sentinel)); |
|
1829 cur = &sentinel; |
|
1830 |
|
1831 buf = malloc(sizeof(*buf)); |
|
1832 if (buf == NULL) { |
|
1833 h_errno = NETDB_INTERNAL; |
|
1834 return NS_NOTFOUND; |
|
1835 } |
|
1836 buf2 = malloc(sizeof(*buf2)); |
|
1837 if (buf2 == NULL) { |
|
1838 free(buf); |
|
1839 h_errno = NETDB_INTERNAL; |
|
1840 return NS_NOTFOUND; |
|
1841 } |
|
1842 |
|
1843 switch (pai->ai_family) { |
|
1844 case AF_UNSPEC: |
|
1845 /* prefer IPv6 */ |
|
1846 q.name = name; |
|
1847 q.qclass = C_IN; |
|
1848 q.answer = buf->buf; |
|
1849 q.anslen = sizeof(buf->buf); |
|
1850 int query_ipv6 = 1, query_ipv4 = 1; |
|
1851 if (pai->ai_flags & AI_ADDRCONFIG) { |
|
1852 query_ipv6 = _have_ipv6(); |
|
1853 query_ipv4 = _have_ipv4(); |
|
1854 } |
|
1855 if (query_ipv6) { |
|
1856 q.qtype = T_AAAA; |
|
1857 if (query_ipv4) { |
|
1858 q.next = &q2; |
|
1859 q2.name = name; |
|
1860 q2.qclass = C_IN; |
|
1861 q2.qtype = T_A; |
|
1862 q2.answer = buf2->buf; |
|
1863 q2.anslen = sizeof(buf2->buf); |
|
1864 } |
|
1865 } else if (query_ipv4) { |
|
1866 q.qtype = T_A; |
|
1867 } else { |
|
1868 free(buf); |
|
1869 free(buf2); |
|
1870 return NS_NOTFOUND; |
|
1871 } |
|
1872 break; |
|
1873 case AF_INET: |
|
1874 q.name = name; |
|
1875 q.qclass = C_IN; |
|
1876 q.qtype = T_A; |
|
1877 q.answer = buf->buf; |
|
1878 q.anslen = sizeof(buf->buf); |
|
1879 break; |
|
1880 case AF_INET6: |
|
1881 q.name = name; |
|
1882 q.qclass = C_IN; |
|
1883 q.qtype = T_AAAA; |
|
1884 q.answer = buf->buf; |
|
1885 q.anslen = sizeof(buf->buf); |
|
1886 break; |
|
1887 default: |
|
1888 free(buf); |
|
1889 free(buf2); |
|
1890 return NS_UNAVAIL; |
|
1891 } |
|
1892 |
|
1893 res = __res_get_state(); |
|
1894 if (res == NULL) { |
|
1895 free(buf); |
|
1896 free(buf2); |
|
1897 return NS_NOTFOUND; |
|
1898 } |
|
1899 |
|
1900 if (res_searchN(name, &q, res) < 0) { |
|
1901 __res_put_state(res); |
|
1902 free(buf); |
|
1903 free(buf2); |
|
1904 return NS_NOTFOUND; |
|
1905 } |
|
1906 ai = getanswer(buf, q.n, q.name, q.qtype, pai); |
|
1907 if (ai) { |
|
1908 cur->ai_next = ai; |
|
1909 while (cur && cur->ai_next) |
|
1910 cur = cur->ai_next; |
|
1911 } |
|
1912 if (q.next) { |
|
1913 ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai); |
|
1914 if (ai) |
|
1915 cur->ai_next = ai; |
|
1916 } |
|
1917 free(buf); |
|
1918 free(buf2); |
|
1919 if (sentinel.ai_next == NULL) { |
|
1920 __res_put_state(res); |
|
1921 switch (h_errno) { |
|
1922 case HOST_NOT_FOUND: |
|
1923 return NS_NOTFOUND; |
|
1924 case TRY_AGAIN: |
|
1925 return NS_TRYAGAIN; |
|
1926 default: |
|
1927 return NS_UNAVAIL; |
|
1928 } |
|
1929 } |
|
1930 |
|
1931 _rfc3484_sort(&sentinel); |
|
1932 |
|
1933 __res_put_state(res); |
|
1934 |
|
1935 *((struct addrinfo **)rv) = sentinel.ai_next; |
|
1936 return NS_SUCCESS; |
|
1937 } |
|
1938 |
|
1939 static void |
|
1940 _sethtent(_pseudo_FILE * __restrict__ hostf) |
|
1941 { |
|
1942 assert(hostf); |
|
1943 if (hostf->mapping == MAP_FAILED) |
|
1944 (void) _pseudo_fopen_r(hostf, _PATH_HOSTS); |
|
1945 else |
|
1946 _pseudo_rewind(hostf); |
|
1947 } |
|
1948 |
|
1949 static void |
|
1950 _endhtent(_pseudo_FILE * __restrict__ hostf) |
|
1951 { |
|
1952 assert(hostf); |
|
1953 (void) _pseudo_fclose(hostf); |
|
1954 } |
|
1955 |
|
1956 static struct addrinfo * |
|
1957 _gethtent(_pseudo_FILE * __restrict__ hostf, const char *name, const struct addrinfo *pai) |
|
1958 { |
|
1959 char *p; |
|
1960 char *cp, *tname, *cname; |
|
1961 struct addrinfo hints, *res0, *res; |
|
1962 int error; |
|
1963 const char *addr; |
|
1964 char hostbuf[8*1024]; |
|
1965 |
|
1966 assert(hostf); |
|
1967 // fprintf(stderr, "_gethtent() name = '%s'\n", name); |
|
1968 assert(name != NULL); |
|
1969 assert(pai != NULL); |
|
1970 |
|
1971 if (hostf->mapping == MAP_FAILED) |
|
1972 (void) _pseudo_fopen_r(hostf, _PATH_HOSTS); |
|
1973 if (hostf->mapping == MAP_FAILED) |
|
1974 return (NULL); |
|
1975 again: |
|
1976 if (!(p = _pseudo_fgets(hostbuf, sizeof hostbuf, hostf))) |
|
1977 return (NULL); |
|
1978 if (*p == '#') |
|
1979 goto again; |
|
1980 if (!(cp = strpbrk(p, "#\n"))) |
|
1981 goto again; |
|
1982 *cp = '\0'; |
|
1983 if (!(cp = strpbrk(p, " \t"))) |
|
1984 goto again; |
|
1985 *cp++ = '\0'; |
|
1986 addr = p; |
|
1987 /* if this is not something we're looking for, skip it. */ |
|
1988 cname = NULL; |
|
1989 while (cp && *cp) { |
|
1990 if (*cp == ' ' || *cp == '\t') { |
|
1991 cp++; |
|
1992 continue; |
|
1993 } |
|
1994 if (!cname) |
|
1995 cname = cp; |
|
1996 tname = cp; |
|
1997 if ((cp = strpbrk(cp, " \t")) != NULL) |
|
1998 *cp++ = '\0'; |
|
1999 // fprintf(stderr, "\ttname = '%s'", tname); |
|
2000 if (strcasecmp(name, tname) == 0) |
|
2001 goto found; |
|
2002 } |
|
2003 goto again; |
|
2004 |
|
2005 found: |
|
2006 hints = *pai; |
|
2007 hints.ai_flags = AI_NUMERICHOST; |
|
2008 error = __wrap_getaddrinfo(addr, NULL, &hints, &res0); |
|
2009 if (error) |
|
2010 goto again; |
|
2011 for (res = res0; res; res = res->ai_next) { |
|
2012 /* cover it up */ |
|
2013 res->ai_flags = pai->ai_flags; |
|
2014 |
|
2015 if (pai->ai_flags & AI_CANONNAME) { |
|
2016 if (get_canonname(pai, res, cname) != 0) { |
|
2017 __wrap_freeaddrinfo(res0); |
|
2018 goto again; |
|
2019 } |
|
2020 } |
|
2021 } |
|
2022 return res0; |
|
2023 } |
|
2024 |
|
2025 /*ARGSUSED*/ |
|
2026 static int |
|
2027 _files_getaddrinfo(void *rv, void *cb_data, va_list ap) |
|
2028 { |
|
2029 const char *name; |
|
2030 const struct addrinfo *pai; |
|
2031 struct addrinfo sentinel, *cur; |
|
2032 struct addrinfo *p; |
|
2033 _pseudo_FILE hostf = _PSEUDO_FILE_INITIALIZER; |
|
2034 |
|
2035 name = va_arg(ap, char *); |
|
2036 pai = va_arg(ap, struct addrinfo *); |
|
2037 |
|
2038 // fprintf(stderr, "_files_getaddrinfo() name = '%s'\n", name); |
|
2039 memset(&sentinel, 0, sizeof(sentinel)); |
|
2040 cur = &sentinel; |
|
2041 |
|
2042 _sethtent(&hostf); |
|
2043 while ((p = _gethtent(&hostf, name, pai)) != NULL) { |
|
2044 cur->ai_next = p; |
|
2045 while (cur && cur->ai_next) |
|
2046 cur = cur->ai_next; |
|
2047 } |
|
2048 _endhtent(&hostf); |
|
2049 |
|
2050 *((struct addrinfo **)rv) = sentinel.ai_next; |
|
2051 if (sentinel.ai_next == NULL) |
|
2052 return NS_NOTFOUND; |
|
2053 return NS_SUCCESS; |
|
2054 } |
|
2055 |
|
2056 /* resolver logic */ |
|
2057 |
|
2058 /* |
|
2059 * Formulate a normal query, send, and await answer. |
|
2060 * Returned answer is placed in supplied buffer "answer". |
|
2061 * Perform preliminary check of answer, returning success only |
|
2062 * if no error is indicated and the answer count is nonzero. |
|
2063 * Return the size of the response on success, -1 on error. |
|
2064 * Error number is left in h_errno. |
|
2065 * |
|
2066 * Caller must parse answer and determine whether it answers the question. |
|
2067 */ |
|
2068 static int |
|
2069 res_queryN(const char *name, /* domain name */ struct res_target *target, |
|
2070 res_state res) |
|
2071 { |
|
2072 u_char buf[MAXPACKET]; |
|
2073 HEADER *hp; |
|
2074 int n; |
|
2075 struct res_target *t; |
|
2076 int rcode; |
|
2077 int ancount; |
|
2078 |
|
2079 assert(name != NULL); |
|
2080 /* XXX: target may be NULL??? */ |
|
2081 |
|
2082 rcode = NOERROR; |
|
2083 ancount = 0; |
|
2084 |
|
2085 for (t = target; t; t = t->next) { |
|
2086 int class, type; |
|
2087 u_char *answer; |
|
2088 int anslen; |
|
2089 |
|
2090 hp = (HEADER *)(void *)t->answer; |
|
2091 hp->rcode = NOERROR; /* default */ |
|
2092 |
|
2093 /* make it easier... */ |
|
2094 class = t->qclass; |
|
2095 type = t->qtype; |
|
2096 answer = t->answer; |
|
2097 anslen = t->anslen; |
|
2098 #ifdef DEBUG |
|
2099 if (res->options & RES_DEBUG) |
|
2100 printf(";; res_nquery(%s, %d, %d)\n", name, class, type); |
|
2101 #endif |
|
2102 |
|
2103 n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL, |
|
2104 buf, sizeof(buf)); |
|
2105 #ifdef RES_USE_EDNS0 |
|
2106 if (n > 0 && (res->options & RES_USE_EDNS0) != 0) |
|
2107 n = res_nopt(res, n, buf, sizeof(buf), anslen); |
|
2108 #endif |
|
2109 if (n <= 0) { |
|
2110 #ifdef DEBUG |
|
2111 if (res->options & RES_DEBUG) |
|
2112 printf(";; res_nquery: mkquery failed\n"); |
|
2113 #endif |
|
2114 h_errno = NO_RECOVERY; |
|
2115 return n; |
|
2116 } |
|
2117 n = res_nsend(res, buf, n, answer, anslen); |
|
2118 #if 0 |
|
2119 if (n < 0) { |
|
2120 #ifdef DEBUG |
|
2121 if (res->options & RES_DEBUG) |
|
2122 printf(";; res_query: send error\n"); |
|
2123 #endif |
|
2124 h_errno = TRY_AGAIN; |
|
2125 return n; |
|
2126 } |
|
2127 #endif |
|
2128 |
|
2129 if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { |
|
2130 rcode = hp->rcode; /* record most recent error */ |
|
2131 #ifdef DEBUG |
|
2132 if (res->options & RES_DEBUG) |
|
2133 printf(";; rcode = %u, ancount=%u\n", hp->rcode, |
|
2134 ntohs(hp->ancount)); |
|
2135 #endif |
|
2136 continue; |
|
2137 } |
|
2138 |
|
2139 ancount += ntohs(hp->ancount); |
|
2140 |
|
2141 t->n = n; |
|
2142 } |
|
2143 |
|
2144 if (ancount == 0) { |
|
2145 switch (rcode) { |
|
2146 case NXDOMAIN: |
|
2147 h_errno = HOST_NOT_FOUND; |
|
2148 break; |
|
2149 case SERVFAIL: |
|
2150 h_errno = TRY_AGAIN; |
|
2151 break; |
|
2152 case NOERROR: |
|
2153 h_errno = NO_DATA; |
|
2154 break; |
|
2155 case FORMERR: |
|
2156 case NOTIMP: |
|
2157 case REFUSED: |
|
2158 default: |
|
2159 h_errno = NO_RECOVERY; |
|
2160 break; |
|
2161 } |
|
2162 return -1; |
|
2163 } |
|
2164 return ancount; |
|
2165 } |
|
2166 |
|
2167 /* |
|
2168 * Formulate a normal query, send, and retrieve answer in supplied buffer. |
|
2169 * Return the size of the response on success, -1 on error. |
|
2170 * If enabled, implement search rules until answer or unrecoverable failure |
|
2171 * is detected. Error code, if any, is left in h_errno. |
|
2172 */ |
|
2173 static int |
|
2174 res_searchN(const char *name, struct res_target *target, res_state res) |
|
2175 { |
|
2176 const char *cp, * const *domain; |
|
2177 HEADER *hp; |
|
2178 u_int dots; |
|
2179 int trailing_dot, ret, saved_herrno; |
|
2180 int got_nodata = 0, got_servfail = 0, tried_as_is = 0; |
|
2181 |
|
2182 assert(name != NULL); |
|
2183 assert(target != NULL); |
|
2184 |
|
2185 hp = (HEADER *)(void *)target->answer; /*XXX*/ |
|
2186 |
|
2187 errno = 0; |
|
2188 h_errno = HOST_NOT_FOUND; /* default, if we never query */ |
|
2189 dots = 0; |
|
2190 for (cp = name; *cp; cp++) |
|
2191 dots += (*cp == '.'); |
|
2192 trailing_dot = 0; |
|
2193 if (cp > name && *--cp == '.') |
|
2194 trailing_dot++; |
|
2195 |
|
2196 |
|
2197 //fprintf(stderr, "res_searchN() name = '%s'\n", name); |
|
2198 |
|
2199 /* |
|
2200 * if there aren't any dots, it could be a user-level alias |
|
2201 */ |
|
2202 if (!dots && (cp = __hostalias(name)) != NULL) { |
|
2203 ret = res_queryN(cp, target, res); |
|
2204 return ret; |
|
2205 } |
|
2206 |
|
2207 /* |
|
2208 * If there are dots in the name already, let's just give it a try |
|
2209 * 'as is'. The threshold can be set with the "ndots" option. |
|
2210 */ |
|
2211 saved_herrno = -1; |
|
2212 if (dots >= res->ndots) { |
|
2213 ret = res_querydomainN(name, NULL, target, res); |
|
2214 if (ret > 0) |
|
2215 return (ret); |
|
2216 saved_herrno = h_errno; |
|
2217 tried_as_is++; |
|
2218 } |
|
2219 |
|
2220 /* |
|
2221 * We do at least one level of search if |
|
2222 * - there is no dot and RES_DEFNAME is set, or |
|
2223 * - there is at least one dot, there is no trailing dot, |
|
2224 * and RES_DNSRCH is set. |
|
2225 */ |
|
2226 if ((!dots && (res->options & RES_DEFNAMES)) || |
|
2227 (dots && !trailing_dot && (res->options & RES_DNSRCH))) { |
|
2228 int done = 0; |
|
2229 |
|
2230 for (domain = (const char * const *)res->dnsrch; |
|
2231 *domain && !done; |
|
2232 domain++) { |
|
2233 |
|
2234 ret = res_querydomainN(name, *domain, target, res); |
|
2235 if (ret > 0) |
|
2236 return ret; |
|
2237 |
|
2238 /* |
|
2239 * If no server present, give up. |
|
2240 * If name isn't found in this domain, |
|
2241 * keep trying higher domains in the search list |
|
2242 * (if that's enabled). |
|
2243 * On a NO_DATA error, keep trying, otherwise |
|
2244 * a wildcard entry of another type could keep us |
|
2245 * from finding this entry higher in the domain. |
|
2246 * If we get some other error (negative answer or |
|
2247 * server failure), then stop searching up, |
|
2248 * but try the input name below in case it's |
|
2249 * fully-qualified. |
|
2250 */ |
|
2251 if (errno == ECONNREFUSED) { |
|
2252 h_errno = TRY_AGAIN; |
|
2253 return -1; |
|
2254 } |
|
2255 |
|
2256 switch (h_errno) { |
|
2257 case NO_DATA: |
|
2258 got_nodata++; |
|
2259 /* FALLTHROUGH */ |
|
2260 case HOST_NOT_FOUND: |
|
2261 /* keep trying */ |
|
2262 break; |
|
2263 case TRY_AGAIN: |
|
2264 if (hp->rcode == SERVFAIL) { |
|
2265 /* try next search element, if any */ |
|
2266 got_servfail++; |
|
2267 break; |
|
2268 } |
|
2269 /* FALLTHROUGH */ |
|
2270 default: |
|
2271 /* anything else implies that we're done */ |
|
2272 done++; |
|
2273 } |
|
2274 /* |
|
2275 * if we got here for some reason other than DNSRCH, |
|
2276 * we only wanted one iteration of the loop, so stop. |
|
2277 */ |
|
2278 if (!(res->options & RES_DNSRCH)) |
|
2279 done++; |
|
2280 } |
|
2281 } |
|
2282 |
|
2283 /* |
|
2284 * if we have not already tried the name "as is", do that now. |
|
2285 * note that we do this regardless of how many dots were in the |
|
2286 * name or whether it ends with a dot. |
|
2287 */ |
|
2288 if (!tried_as_is) { |
|
2289 ret = res_querydomainN(name, NULL, target, res); |
|
2290 if (ret > 0) |
|
2291 return ret; |
|
2292 } |
|
2293 |
|
2294 /* |
|
2295 * if we got here, we didn't satisfy the search. |
|
2296 * if we did an initial full query, return that query's h_errno |
|
2297 * (note that we wouldn't be here if that query had succeeded). |
|
2298 * else if we ever got a nodata, send that back as the reason. |
|
2299 * else send back meaningless h_errno, that being the one from |
|
2300 * the last DNSRCH we did. |
|
2301 */ |
|
2302 if (saved_herrno != -1) |
|
2303 h_errno = saved_herrno; |
|
2304 else if (got_nodata) |
|
2305 h_errno = NO_DATA; |
|
2306 else if (got_servfail) |
|
2307 h_errno = TRY_AGAIN; |
|
2308 return -1; |
|
2309 } |
|
2310 |
|
2311 /* |
|
2312 * Perform a call on res_query on the concatenation of name and domain, |
|
2313 * removing a trailing dot from name if domain is NULL. |
|
2314 */ |
|
2315 static int |
|
2316 res_querydomainN(const char *name, const char *domain, |
|
2317 struct res_target *target, res_state res) |
|
2318 { |
|
2319 char nbuf[MAXDNAME]; |
|
2320 const char *longname = nbuf; |
|
2321 size_t n, d; |
|
2322 |
|
2323 assert(name != NULL); |
|
2324 /* XXX: target may be NULL??? */ |
|
2325 |
|
2326 #ifdef DEBUG |
|
2327 if (res->options & RES_DEBUG) |
|
2328 printf(";; res_querydomain(%s, %s)\n", |
|
2329 name, domain?domain:"<Nil>"); |
|
2330 #endif |
|
2331 if (domain == NULL) { |
|
2332 /* |
|
2333 * Check for trailing '.'; |
|
2334 * copy without '.' if present. |
|
2335 */ |
|
2336 n = strlen(name); |
|
2337 if (n + 1 > sizeof(nbuf)) { |
|
2338 h_errno = NO_RECOVERY; |
|
2339 return -1; |
|
2340 } |
|
2341 if (n > 0 && name[--n] == '.') { |
|
2342 strncpy(nbuf, name, n); |
|
2343 nbuf[n] = '\0'; |
|
2344 } else |
|
2345 longname = name; |
|
2346 } else { |
|
2347 n = strlen(name); |
|
2348 d = strlen(domain); |
|
2349 if (n + 1 + d + 1 > sizeof(nbuf)) { |
|
2350 h_errno = NO_RECOVERY; |
|
2351 return -1; |
|
2352 } |
|
2353 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); |
|
2354 } |
|
2355 return res_queryN(longname, target, res); |
|
2356 } |