1 | /* $NetBSD: getaddrinfo.c,v 1.119 2018/12/13 04:41:41 dholland 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 | * Issues to be discussed: |
35 | * - Return values. There are nonstandard return values defined and used |
36 | * in the source code. This is because RFC2553 is silent about which error |
37 | * code must be returned for which situation. |
38 | * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2 |
39 | * says to use inet_aton() to convert IPv4 numeric to binary (alows |
40 | * classful form as a result). |
41 | * current code - disallow classful form for IPv4 (due to use of inet_pton). |
42 | * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is |
43 | * invalid. |
44 | * current code - SEGV on freeaddrinfo(NULL) |
45 | * Note: |
46 | * - The code filters out AFs that are not supported by the kernel, |
47 | * when globbing NULL hostname (to loopback, or wildcard). Is it the right |
48 | * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG |
49 | * in ai_flags? |
50 | * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. |
51 | * (1) what should we do against numeric hostname (2) what should we do |
52 | * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? |
53 | * non-loopback address configured? global address configured? |
54 | */ |
55 | |
56 | #include <sys/cdefs.h> |
57 | #if defined(LIBC_SCCS) && !defined(lint) |
58 | __RCSID("$NetBSD: getaddrinfo.c,v 1.119 2018/12/13 04:41:41 dholland Exp $" ); |
59 | #endif /* LIBC_SCCS and not lint */ |
60 | |
61 | #ifndef RUMP_ACTION |
62 | #include "namespace.h" |
63 | #endif |
64 | #include <sys/types.h> |
65 | #include <sys/param.h> |
66 | #include <sys/socket.h> |
67 | #include <sys/ioctl.h> |
68 | #include <sys/sysctl.h> |
69 | #include <net/if.h> |
70 | #include <netinet/in.h> |
71 | #include <netinet6/in6_var.h> |
72 | #include <arpa/inet.h> |
73 | #include <arpa/nameser.h> |
74 | #include <assert.h> |
75 | #include <ctype.h> |
76 | #include <errno.h> |
77 | #include <netdb.h> |
78 | #include <resolv.h> |
79 | #include <stddef.h> |
80 | #include <stdio.h> |
81 | #include <stdlib.h> |
82 | #include <string.h> |
83 | #include <unistd.h> |
84 | #include <ifaddrs.h> |
85 | |
86 | #include <syslog.h> |
87 | #include <stdarg.h> |
88 | #include <nsswitch.h> |
89 | |
90 | #ifdef YP |
91 | #include <rpc/rpc.h> |
92 | #include <rpcsvc/yp_prot.h> |
93 | #include <rpcsvc/ypclnt.h> |
94 | #endif |
95 | |
96 | #include "servent.h" |
97 | |
98 | #ifndef RUMP_ACTION |
99 | #ifdef __weak_alias |
100 | __weak_alias(getaddrinfo,_getaddrinfo) |
101 | __weak_alias(allocaddrinfo,_allocaddrinfo) |
102 | __weak_alias(freeaddrinfo,_freeaddrinfo) |
103 | __weak_alias(gai_strerror,_gai_strerror) |
104 | #endif |
105 | #endif |
106 | |
107 | #define SUCCESS 0 |
108 | #define ANY 0 |
109 | #define YES 1 |
110 | #define NO 0 |
111 | |
112 | #define sa4addr(sa) ((void *)&((struct sockaddr_in *)(void *)sa)->sin_addr) |
113 | #define sa6addr(sa) ((void *)&((struct sockaddr_in6 *)(void *)sa)->sin6_addr) |
114 | |
115 | static const char in_addrany[] = { 0, 0, 0, 0 }; |
116 | static const char in_loopback[] = { 127, 0, 0, 1 }; |
117 | #ifdef INET6 |
118 | static const char in6_addrany[] = { |
119 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
120 | }; |
121 | static const char in6_loopback[] = { |
122 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 |
123 | }; |
124 | #endif |
125 | |
126 | struct policyqueue { |
127 | TAILQ_ENTRY(policyqueue) pc_entry; |
128 | #ifdef INET6 |
129 | struct in6_addrpolicy pc_policy; |
130 | #endif |
131 | }; |
132 | TAILQ_HEAD(policyhead, policyqueue); |
133 | |
134 | static const struct afd { |
135 | int a_af; |
136 | int a_addrlen; |
137 | int a_socklen; |
138 | int a_off; |
139 | const char *a_addrany; |
140 | const char *a_loopback; |
141 | int a_scoped; |
142 | } afdl [] = { |
143 | #ifdef INET6 |
144 | {PF_INET6, sizeof(struct in6_addr), |
145 | sizeof(struct sockaddr_in6), |
146 | offsetof(struct sockaddr_in6, sin6_addr), |
147 | in6_addrany, in6_loopback, 1}, |
148 | #endif |
149 | {PF_INET, sizeof(struct in_addr), |
150 | sizeof(struct sockaddr_in), |
151 | offsetof(struct sockaddr_in, sin_addr), |
152 | in_addrany, in_loopback, 0}, |
153 | {0, 0, 0, 0, NULL, NULL, 0}, |
154 | }; |
155 | |
156 | struct explore { |
157 | int e_af; |
158 | int e_socktype; |
159 | int e_protocol; |
160 | const char *e_protostr; |
161 | int e_wild; |
162 | #define WILD_AF(ex) ((ex)->e_wild & 0x01) |
163 | #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) |
164 | #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) |
165 | }; |
166 | |
167 | static const struct explore explore[] = { |
168 | #if 0 |
169 | { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, |
170 | #endif |
171 | #ifdef INET6 |
172 | { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp" , 0x07 }, |
173 | { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp" , 0x07 }, |
174 | { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, |
175 | #endif |
176 | { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp" , 0x07 }, |
177 | { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp" , 0x07 }, |
178 | { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, |
179 | { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp" , 0x07 }, |
180 | { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp" , 0x07 }, |
181 | { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, |
182 | { -1, 0, 0, NULL, 0 }, |
183 | }; |
184 | |
185 | #ifdef INET6 |
186 | #define PTON_MAX 16 |
187 | #else |
188 | #define PTON_MAX 4 |
189 | #endif |
190 | |
191 | #define AIO_SRCFLAG_DEPRECATED 0x1 |
192 | |
193 | struct ai_order { |
194 | union { |
195 | struct sockaddr_storage aiou_ss; |
196 | struct sockaddr aiou_sa; |
197 | } aio_src_un; |
198 | #define aio_srcsa aio_src_un.aiou_sa |
199 | u_int32_t aio_srcflag; |
200 | int aio_srcscope; |
201 | int aio_dstscope; |
202 | struct policyqueue *aio_srcpolicy; |
203 | struct policyqueue *aio_dstpolicy; |
204 | struct addrinfo *aio_ai; |
205 | int aio_matchlen; |
206 | }; |
207 | |
208 | static const ns_src default_dns_files[] = { |
209 | { NSSRC_FILES, NS_SUCCESS }, |
210 | { NSSRC_DNS, NS_SUCCESS }, |
211 | { 0, 0 } |
212 | }; |
213 | |
214 | #define MAXPACKET (64*1024) |
215 | |
216 | typedef union { |
217 | HEADER hdr; |
218 | u_char buf[MAXPACKET]; |
219 | } querybuf; |
220 | |
221 | struct res_target { |
222 | struct res_target *next; |
223 | const char *name; /* domain name */ |
224 | int qclass, qtype; /* class and type of query */ |
225 | u_char *answer; /* buffer to put answer */ |
226 | int anslen; /* size of answer buffer */ |
227 | int n; /* result length */ |
228 | }; |
229 | |
230 | struct srvinfo { |
231 | struct srvinfo *next; |
232 | char name[MAXDNAME]; |
233 | int port, pri, weight; |
234 | }; |
235 | |
236 | static int gai_srvok(const char *); |
237 | static int str2number(const char *); |
238 | static int explore_fqdn(const struct addrinfo *, const char *, |
239 | const char *, struct addrinfo **, struct servent_data *); |
240 | static int explore_null(const struct addrinfo *, |
241 | const char *, struct addrinfo **, struct servent_data *); |
242 | static int explore_numeric(const struct addrinfo *, const char *, |
243 | const char *, struct addrinfo **, const char *, struct servent_data *); |
244 | static int explore_numeric_scope(const struct addrinfo *, const char *, |
245 | const char *, struct addrinfo **, struct servent_data *); |
246 | static int get_canonname(const struct addrinfo *, |
247 | struct addrinfo *, const char *); |
248 | static struct addrinfo *get_ai(const struct addrinfo *, |
249 | const struct afd *, const char *); |
250 | static int get_portmatch(const struct addrinfo *, const char *, |
251 | struct servent_data *); |
252 | static int get_port(const struct addrinfo *, const char *, int, |
253 | struct servent_data *); |
254 | static const struct afd *find_afd(int); |
255 | static int addrconfig(uint64_t *); |
256 | static void set_source(struct ai_order *, struct policyhead *, |
257 | struct servent_data *); |
258 | static int comp_dst(const void *, const void *); |
259 | #ifdef INET6 |
260 | static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *); |
261 | #endif |
262 | static int gai_addr2scopetype(struct sockaddr *); |
263 | |
264 | static int reorder(struct addrinfo *, struct servent_data *); |
265 | static int get_addrselectpolicy(struct policyhead *); |
266 | static void free_addrselectpolicy(struct policyhead *); |
267 | static struct policyqueue *match_addrselectpolicy(struct sockaddr *, |
268 | struct policyhead *); |
269 | static int matchlen(struct sockaddr *, struct sockaddr *); |
270 | |
271 | static struct addrinfo *getanswer(res_state, const querybuf *, int, |
272 | const char *, int, const struct addrinfo *); |
273 | static void aisort(struct addrinfo *s, res_state res); |
274 | static struct addrinfo * _dns_query(struct res_target *, |
275 | const struct addrinfo *, res_state, int); |
276 | static struct addrinfo * _dns_srv_lookup(const char *, const char *, |
277 | const struct addrinfo *); |
278 | static struct addrinfo * _dns_host_lookup(const char *, |
279 | const struct addrinfo *); |
280 | static int _dns_getaddrinfo(void *, void *, va_list); |
281 | static void _sethtent(FILE **); |
282 | static void _endhtent(FILE **); |
283 | static struct addrinfo *_gethtent(FILE **, const char *, |
284 | const struct addrinfo *); |
285 | static int _files_getaddrinfo(void *, void *, va_list); |
286 | #ifdef YP |
287 | static struct addrinfo *_yphostent(char *, const struct addrinfo *); |
288 | static int _yp_getaddrinfo(void *, void *, va_list); |
289 | #endif |
290 | |
291 | static int res_queryN(const char *, struct res_target *, res_state); |
292 | static int res_searchN(const char *, struct res_target *, res_state); |
293 | static int res_querydomainN(const char *, const char *, |
294 | struct res_target *, res_state); |
295 | |
296 | static const char * const ai_errlist[] = { |
297 | "Success" , |
298 | "Address family for hostname not supported" , /* EAI_ADDRFAMILY */ |
299 | "Temporary failure in name resolution" , /* EAI_AGAIN */ |
300 | "Invalid value for ai_flags" , /* EAI_BADFLAGS */ |
301 | "Non-recoverable failure in name resolution" , /* EAI_FAIL */ |
302 | "ai_family not supported" , /* EAI_FAMILY */ |
303 | "Memory allocation failure" , /* EAI_MEMORY */ |
304 | "No address associated with hostname" , /* EAI_NODATA */ |
305 | "hostname or servname not provided or not known" , /* EAI_NONAME */ |
306 | "servname not supported for ai_socktype" , /* EAI_SERVICE */ |
307 | "ai_socktype not supported" , /* EAI_SOCKTYPE */ |
308 | "System error returned in errno" , /* EAI_SYSTEM */ |
309 | "Invalid value for hints" , /* EAI_BADHINTS */ |
310 | "Resolved protocol is unknown" , /* EAI_PROTOCOL */ |
311 | "Argument buffer overflow" , /* EAI_OVERFLOW */ |
312 | "Unknown error" , /* EAI_MAX */ |
313 | }; |
314 | |
315 | /* XXX macros that make external reference is BAD. */ |
316 | |
317 | #define GET_AI(ai, afd, addr) \ |
318 | do { \ |
319 | /* external reference: pai, error, and label free */ \ |
320 | (ai) = get_ai(pai, (afd), (addr)); \ |
321 | if ((ai) == NULL) { \ |
322 | error = EAI_MEMORY; \ |
323 | goto free; \ |
324 | } \ |
325 | } while (/*CONSTCOND*/0) |
326 | |
327 | #define GET_PORT(ai, serv, svd) \ |
328 | do { \ |
329 | /* external reference: error and label free */ \ |
330 | error = get_port((ai), (serv), 0, (svd)); \ |
331 | if (error != 0) \ |
332 | goto free; \ |
333 | } while (/*CONSTCOND*/0) |
334 | |
335 | #define GET_CANONNAME(ai, str) \ |
336 | do { \ |
337 | /* external reference: pai, error and label free */ \ |
338 | error = get_canonname(pai, (ai), (str)); \ |
339 | if (error != 0) \ |
340 | goto free; \ |
341 | } while (/*CONSTCOND*/0) |
342 | |
343 | #define ERR(err) \ |
344 | do { \ |
345 | /* external reference: error, and label bad */ \ |
346 | error = (err); \ |
347 | goto bad; \ |
348 | /*NOTREACHED*/ \ |
349 | } while (/*CONSTCOND*/0) |
350 | |
351 | #define MATCH_FAMILY(x, y, w) \ |
352 | ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || \ |
353 | (y) == PF_UNSPEC))) |
354 | #define MATCH(x, y, w) \ |
355 | ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) |
356 | |
357 | const char * |
358 | gai_strerror(int ecode) |
359 | { |
360 | if (ecode < 0 || ecode > EAI_MAX) |
361 | ecode = EAI_MAX; |
362 | return ai_errlist[ecode]; |
363 | } |
364 | |
365 | void |
366 | freeaddrinfo(struct addrinfo *ai) |
367 | { |
368 | struct addrinfo *next; |
369 | |
370 | _DIAGASSERT(ai != NULL); |
371 | |
372 | do { |
373 | next = ai->ai_next; |
374 | if (ai->ai_canonname) |
375 | free(ai->ai_canonname); |
376 | /* no need to free(ai->ai_addr) */ |
377 | free(ai); |
378 | ai = next; |
379 | } while (ai); |
380 | } |
381 | |
382 | /* |
383 | * We don't want localization to affect us |
384 | */ |
385 | #define PERIOD '.' |
386 | #define hyphenchar(c) ((c) == '-') |
387 | #define periodchar(c) ((c) == PERIOD) |
388 | #define underschar(c) ((c) == '_') |
389 | #define alphachar(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) |
390 | #define digitchar(c) ((c) >= '0' && (c) <= '9') |
391 | |
392 | #define firstchar(c) (alphachar(c) || digitchar(c) || underschar(c)) |
393 | #define lastchar(c) (alphachar(c) || digitchar(c)) |
394 | #define middlechar(c) (lastchar(c) || hyphenchar(c)) |
395 | |
396 | static int |
397 | gai_srvok(const char *dn) |
398 | { |
399 | int nch, pch, ch; |
400 | |
401 | for (pch = PERIOD, nch = ch = *dn++; ch != '\0'; pch = ch, ch = nch) { |
402 | if (periodchar(ch)) |
403 | continue; |
404 | if (periodchar(pch)) { |
405 | if (!firstchar(ch)) |
406 | return 0; |
407 | } else if (periodchar(nch) || nch == '\0') { |
408 | if (!lastchar(ch)) |
409 | return 0; |
410 | } else if (!middlechar(ch)) |
411 | return 0; |
412 | } |
413 | return 1; |
414 | } |
415 | |
416 | static in_port_t * |
417 | getport(struct addrinfo *ai) { |
418 | static in_port_t p; |
419 | |
420 | switch (ai->ai_family) { |
421 | case AF_INET: |
422 | return &((struct sockaddr_in *)(void *)ai->ai_addr)->sin_port; |
423 | #ifdef INET6 |
424 | case AF_INET6: |
425 | return &((struct sockaddr_in6 *)(void *)ai->ai_addr)->sin6_port; |
426 | #endif |
427 | default: |
428 | p = 0; |
429 | /* XXX: abort()? */ |
430 | return &p; |
431 | } |
432 | } |
433 | |
434 | static int |
435 | str2number(const char *p) |
436 | { |
437 | char *ep; |
438 | unsigned long v; |
439 | |
440 | _DIAGASSERT(p != NULL); |
441 | |
442 | if (*p == '\0') |
443 | return -1; |
444 | ep = NULL; |
445 | errno = 0; |
446 | v = strtoul(p, &ep, 10); |
447 | if (errno == 0 && ep && *ep == '\0' && v <= INT_MAX) |
448 | return (int)v; |
449 | else |
450 | return -1; |
451 | } |
452 | |
453 | int |
454 | getaddrinfo(const char *hostname, const char *servname, |
455 | const struct addrinfo *hints, struct addrinfo **res) |
456 | { |
457 | struct addrinfo sentinel; |
458 | struct addrinfo *cur; |
459 | int error = 0; |
460 | struct addrinfo ai; |
461 | struct addrinfo ai0; |
462 | struct addrinfo *pai; |
463 | const struct explore *ex; |
464 | struct servent_data svd; |
465 | uint64_t mask = (uint64_t)~0ULL; |
466 | int numeric = 0; |
467 | |
468 | /* hostname is allowed to be NULL */ |
469 | /* servname is allowed to be NULL */ |
470 | /* hints is allowed to be NULL */ |
471 | _DIAGASSERT(res != NULL); |
472 | |
473 | (void)memset(&svd, 0, sizeof(svd)); |
474 | memset(&sentinel, 0, sizeof(sentinel)); |
475 | cur = &sentinel; |
476 | memset(&ai, 0, sizeof(ai)); |
477 | pai = &ai; |
478 | pai->ai_flags = 0; |
479 | pai->ai_family = PF_UNSPEC; |
480 | pai->ai_socktype = ANY; |
481 | pai->ai_protocol = ANY; |
482 | pai->ai_addrlen = 0; |
483 | pai->ai_canonname = NULL; |
484 | pai->ai_addr = NULL; |
485 | pai->ai_next = NULL; |
486 | |
487 | if (hostname == NULL && servname == NULL) |
488 | return EAI_NONAME; |
489 | if (hints) { |
490 | /* error check for hints */ |
491 | if (hints->ai_addrlen || hints->ai_canonname || |
492 | hints->ai_addr || hints->ai_next) |
493 | ERR(EAI_BADHINTS); /* xxx */ |
494 | if (hints->ai_flags & ~AI_MASK) |
495 | ERR(EAI_BADFLAGS); |
496 | switch (hints->ai_family) { |
497 | case PF_UNSPEC: |
498 | case PF_INET: |
499 | #ifdef INET6 |
500 | case PF_INET6: |
501 | #endif |
502 | break; |
503 | default: |
504 | ERR(EAI_FAMILY); |
505 | } |
506 | memcpy(pai, hints, sizeof(*pai)); |
507 | |
508 | /* |
509 | * if both socktype/protocol are specified, check if they |
510 | * are meaningful combination. |
511 | */ |
512 | if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { |
513 | for (ex = explore; ex->e_af >= 0; ex++) { |
514 | if (pai->ai_family != ex->e_af) |
515 | continue; |
516 | if (ex->e_socktype == ANY) |
517 | continue; |
518 | if (ex->e_protocol == ANY) |
519 | continue; |
520 | if (pai->ai_socktype == ex->e_socktype |
521 | && pai->ai_protocol != ex->e_protocol) { |
522 | ERR(EAI_BADHINTS); |
523 | } |
524 | } |
525 | } |
526 | } |
527 | |
528 | if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && addrconfig(&mask) == -1) |
529 | ERR(EAI_FAIL); |
530 | |
531 | /* |
532 | * check for special cases. (1) numeric servname is disallowed if |
533 | * socktype/protocol are left unspecified. (2) servname is disallowed |
534 | * for raw and other inet{,6} sockets. |
535 | */ |
536 | if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) |
537 | #ifdef PF_INET6 |
538 | || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) |
539 | #endif |
540 | ) { |
541 | ai0 = *pai; /* backup *pai */ |
542 | |
543 | if (pai->ai_family == PF_UNSPEC) { |
544 | #ifdef PF_INET6 |
545 | pai->ai_family = PF_INET6; |
546 | #else |
547 | pai->ai_family = PF_INET; |
548 | #endif |
549 | } |
550 | error = get_portmatch(pai, servname, &svd); |
551 | if (error) |
552 | goto bad; |
553 | |
554 | *pai = ai0; |
555 | } |
556 | |
557 | ai0 = *pai; |
558 | |
559 | /* NULL hostname, or numeric hostname */ |
560 | for (ex = explore; ex->e_af >= 0; ex++) { |
561 | *pai = ai0; |
562 | |
563 | /* ADDRCONFIG check */ |
564 | if ((((uint64_t)1 << ex->e_af) & mask) == 0) |
565 | continue; |
566 | |
567 | /* PF_UNSPEC entries are prepared for DNS queries only */ |
568 | if (ex->e_af == PF_UNSPEC) |
569 | continue; |
570 | |
571 | if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) |
572 | continue; |
573 | if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) |
574 | continue; |
575 | if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) |
576 | continue; |
577 | if (pai->ai_family == PF_UNSPEC) |
578 | pai->ai_family = ex->e_af; |
579 | if (pai->ai_socktype == ANY && ex->e_socktype != ANY) |
580 | pai->ai_socktype = ex->e_socktype; |
581 | if (pai->ai_protocol == ANY && ex->e_protocol != ANY) |
582 | pai->ai_protocol = ex->e_protocol; |
583 | |
584 | if (hostname == NULL) |
585 | error = explore_null(pai, servname, &cur->ai_next, |
586 | &svd); |
587 | else |
588 | error = explore_numeric_scope(pai, hostname, servname, |
589 | &cur->ai_next, &svd); |
590 | |
591 | if (error) |
592 | goto free; |
593 | |
594 | while (cur->ai_next) |
595 | cur = cur->ai_next; |
596 | } |
597 | |
598 | /* |
599 | * XXX |
600 | * If numeric representation of AF1 can be interpreted as FQDN |
601 | * representation of AF2, we need to think again about the code below. |
602 | */ |
603 | if (sentinel.ai_next) { |
604 | numeric = 1; |
605 | goto good; |
606 | } |
607 | |
608 | if (hostname == NULL) |
609 | ERR(EAI_NODATA); |
610 | if (pai->ai_flags & AI_NUMERICHOST) |
611 | ERR(EAI_NONAME); |
612 | |
613 | /* |
614 | * hostname as alphabetical name. |
615 | * we would like to prefer AF_INET6 than AF_INET, so we'll make a |
616 | * outer loop by AFs. |
617 | */ |
618 | for (ex = explore; ex->e_af >= 0; ex++) { |
619 | *pai = ai0; |
620 | |
621 | |
622 | /* ADDRCONFIG check */ |
623 | /* PF_UNSPEC entries are prepared for DNS queries only */ |
624 | if (ex->e_af != PF_UNSPEC && |
625 | (((uint64_t)1 << ex->e_af) & mask) == 0) |
626 | continue; |
627 | |
628 | /* require exact match for family field */ |
629 | if (pai->ai_family != ex->e_af) |
630 | continue; |
631 | |
632 | if (!MATCH(pai->ai_socktype, ex->e_socktype, |
633 | WILD_SOCKTYPE(ex))) { |
634 | continue; |
635 | } |
636 | if (!MATCH(pai->ai_protocol, ex->e_protocol, |
637 | WILD_PROTOCOL(ex))) { |
638 | continue; |
639 | } |
640 | |
641 | if (pai->ai_socktype == ANY && ex->e_socktype != ANY) |
642 | pai->ai_socktype = ex->e_socktype; |
643 | if (pai->ai_protocol == ANY && ex->e_protocol != ANY) |
644 | pai->ai_protocol = ex->e_protocol; |
645 | |
646 | error = explore_fqdn(pai, hostname, servname, &cur->ai_next, |
647 | &svd); |
648 | |
649 | while (cur && cur->ai_next) |
650 | cur = cur->ai_next; |
651 | } |
652 | |
653 | /* XXX */ |
654 | if (sentinel.ai_next) |
655 | error = 0; |
656 | |
657 | if (error) |
658 | goto free; |
659 | |
660 | if (sentinel.ai_next) { |
661 | good: |
662 | /* |
663 | * If the returned entry is for an active connection, |
664 | * and the given name is not numeric, reorder the |
665 | * list, so that the application would try the list |
666 | * in the most efficient order. Since the head entry |
667 | * of the original list may contain ai_canonname and |
668 | * that entry may be moved elsewhere in the new list, |
669 | * we keep the pointer and will restore it in the new |
670 | * head entry. (Note that RFC3493 requires the head |
671 | * entry store it when requested by the caller). |
672 | */ |
673 | if (hints == NULL || !(hints->ai_flags & AI_PASSIVE)) { |
674 | if (!numeric) { |
675 | char *canonname; |
676 | |
677 | canonname = sentinel.ai_next->ai_canonname; |
678 | sentinel.ai_next->ai_canonname = NULL; |
679 | (void)reorder(&sentinel, &svd); |
680 | if (sentinel.ai_next->ai_canonname == NULL) { |
681 | sentinel.ai_next->ai_canonname |
682 | = canonname; |
683 | } else if (canonname != NULL) |
684 | free(canonname); |
685 | } |
686 | } |
687 | endservent_r(&svd); |
688 | *res = sentinel.ai_next; |
689 | return SUCCESS; |
690 | } else |
691 | error = EAI_FAIL; |
692 | free: |
693 | bad: |
694 | endservent_r(&svd); |
695 | if (sentinel.ai_next) |
696 | freeaddrinfo(sentinel.ai_next); |
697 | *res = NULL; |
698 | return error; |
699 | } |
700 | |
701 | static int |
702 | reorder(struct addrinfo *sentinel, struct servent_data *svd) |
703 | { |
704 | struct addrinfo *ai, **aip; |
705 | struct ai_order *aio; |
706 | int i, n; |
707 | struct policyhead policyhead; |
708 | |
709 | /* count the number of addrinfo elements for sorting. */ |
710 | for (n = 0, ai = sentinel->ai_next; ai != NULL; ai = ai->ai_next, n++) |
711 | ; |
712 | |
713 | /* |
714 | * If the number is small enough, we can skip the reordering process. |
715 | */ |
716 | if (n <= 1) |
717 | return n; |
718 | |
719 | /* allocate a temporary array for sort and initialization of it. */ |
720 | if ((aio = malloc(sizeof(*aio) * n)) == NULL) |
721 | return n; /* give up reordering */ |
722 | memset(aio, 0, sizeof(*aio) * n); |
723 | |
724 | /* retrieve address selection policy from the kernel */ |
725 | TAILQ_INIT(&policyhead); |
726 | if (!get_addrselectpolicy(&policyhead)) { |
727 | /* no policy is installed into kernel, we don't sort. */ |
728 | free(aio); |
729 | return n; |
730 | } |
731 | |
732 | for (i = 0, ai = sentinel->ai_next; i < n; ai = ai->ai_next, i++) { |
733 | aio[i].aio_ai = ai; |
734 | aio[i].aio_dstscope = gai_addr2scopetype(ai->ai_addr); |
735 | aio[i].aio_dstpolicy = match_addrselectpolicy(ai->ai_addr, |
736 | &policyhead); |
737 | set_source(&aio[i], &policyhead, svd); |
738 | } |
739 | |
740 | /* perform sorting. */ |
741 | qsort(aio, n, sizeof(*aio), comp_dst); |
742 | |
743 | /* reorder the addrinfo chain. */ |
744 | for (i = 0, aip = &sentinel->ai_next; i < n; i++) { |
745 | *aip = aio[i].aio_ai; |
746 | aip = &aio[i].aio_ai->ai_next; |
747 | } |
748 | *aip = NULL; |
749 | |
750 | /* cleanup and return */ |
751 | free(aio); |
752 | free_addrselectpolicy(&policyhead); |
753 | return n; |
754 | } |
755 | |
756 | static int |
757 | get_addrselectpolicy(struct policyhead *head) |
758 | { |
759 | #ifdef INET6 |
760 | static const int mib[] = { |
761 | CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY }; |
762 | static const u_int miblen = (u_int)__arraycount(mib); |
763 | size_t l; |
764 | char *buf; |
765 | struct in6_addrpolicy *pol, *ep; |
766 | |
767 | if (sysctl(mib, miblen, NULL, &l, NULL, 0) < 0) |
768 | return 0; |
769 | if (l == 0) |
770 | return 0; |
771 | if ((buf = malloc(l)) == NULL) |
772 | return 0; |
773 | if (sysctl(mib, miblen, buf, &l, NULL, 0) < 0) { |
774 | free(buf); |
775 | return 0; |
776 | } |
777 | |
778 | ep = (void *)(buf + l); |
779 | for (pol = (void *)buf; pol + 1 <= ep; pol++) { |
780 | struct policyqueue *new; |
781 | |
782 | if ((new = malloc(sizeof(*new))) == NULL) { |
783 | free_addrselectpolicy(head); /* make the list empty */ |
784 | break; |
785 | } |
786 | new->pc_policy = *pol; |
787 | TAILQ_INSERT_TAIL(head, new, pc_entry); |
788 | } |
789 | |
790 | free(buf); |
791 | return 1; |
792 | #else |
793 | return 0; |
794 | #endif |
795 | } |
796 | |
797 | static void |
798 | free_addrselectpolicy(struct policyhead *head) |
799 | { |
800 | struct policyqueue *ent, *nent; |
801 | |
802 | for (ent = TAILQ_FIRST(head); ent; ent = nent) { |
803 | nent = TAILQ_NEXT(ent, pc_entry); |
804 | TAILQ_REMOVE(head, ent, pc_entry); |
805 | free(ent); |
806 | } |
807 | } |
808 | |
809 | static struct policyqueue * |
810 | match_addrselectpolicy(struct sockaddr *addr, struct policyhead *head) |
811 | { |
812 | #ifdef INET6 |
813 | struct policyqueue *ent, *bestent = NULL; |
814 | struct in6_addrpolicy *pol; |
815 | int curmatchlen, bestmatchlen = -1; |
816 | u_char *mp, *ep, *k, *p; |
817 | u_int m; |
818 | struct sockaddr_in6 key; |
819 | |
820 | switch(addr->sa_family) { |
821 | case AF_INET6: |
822 | memcpy(&key, addr, sizeof(key)); |
823 | break; |
824 | case AF_INET: |
825 | /* convert the address into IPv4-mapped IPv6 address. */ |
826 | memset(&key, 0, sizeof(key)); |
827 | key.sin6_family = AF_INET6; |
828 | key.sin6_len = sizeof(key); |
829 | key.sin6_addr.s6_addr[10] = 0xff; |
830 | key.sin6_addr.s6_addr[11] = 0xff; |
831 | memcpy(&key.sin6_addr.s6_addr[12], sa4addr(addr), 4); |
832 | break; |
833 | default: |
834 | return NULL; |
835 | } |
836 | |
837 | for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) { |
838 | pol = &ent->pc_policy; |
839 | curmatchlen = 0; |
840 | |
841 | mp = (void *)&pol->addrmask.sin6_addr; |
842 | ep = mp + 16; /* XXX: scope field? */ |
843 | k = (void *)&key.sin6_addr; |
844 | p = (void *)&pol->addr.sin6_addr; |
845 | for (; mp < ep && *mp; mp++, k++, p++) { |
846 | m = *mp; |
847 | if ((*k & m) != *p) |
848 | goto next; /* not match */ |
849 | if (m == 0xff) /* short cut for a typical case */ |
850 | curmatchlen += 8; |
851 | else { |
852 | while (m >= 0x80) { |
853 | curmatchlen++; |
854 | m <<= 1; |
855 | } |
856 | } |
857 | } |
858 | |
859 | /* matched. check if this is better than the current best. */ |
860 | if (curmatchlen > bestmatchlen) { |
861 | bestent = ent; |
862 | bestmatchlen = curmatchlen; |
863 | } |
864 | |
865 | next: |
866 | continue; |
867 | } |
868 | |
869 | return bestent; |
870 | #else |
871 | return NULL; |
872 | #endif |
873 | |
874 | } |
875 | |
876 | static void |
877 | set_source(struct ai_order *aio, struct policyhead *ph, |
878 | struct servent_data *svd) |
879 | { |
880 | struct addrinfo ai = *aio->aio_ai; |
881 | struct sockaddr_storage ss; |
882 | socklen_t srclen; |
883 | int s; |
884 | |
885 | /* set unspec ("no source is available"), just in case */ |
886 | aio->aio_srcsa.sa_family = AF_UNSPEC; |
887 | aio->aio_srcscope = -1; |
888 | |
889 | switch(ai.ai_family) { |
890 | case AF_INET: |
891 | #ifdef INET6 |
892 | case AF_INET6: |
893 | #endif |
894 | break; |
895 | default: /* ignore unsupported AFs explicitly */ |
896 | return; |
897 | } |
898 | |
899 | /* XXX: make a dummy addrinfo to call connect() */ |
900 | ai.ai_socktype = SOCK_DGRAM; |
901 | ai.ai_protocol = IPPROTO_UDP; /* is UDP too specific? */ |
902 | ai.ai_next = NULL; |
903 | memset(&ss, 0, sizeof(ss)); |
904 | memcpy(&ss, ai.ai_addr, ai.ai_addrlen); |
905 | ai.ai_addr = (void *)&ss; |
906 | get_port(&ai, "1" , 0, svd); |
907 | |
908 | /* open a socket to get the source address for the given dst */ |
909 | if ((s = socket(ai.ai_family, ai.ai_socktype | SOCK_CLOEXEC, |
910 | ai.ai_protocol)) < 0) |
911 | return; /* give up */ |
912 | if (connect(s, ai.ai_addr, ai.ai_addrlen) < 0) |
913 | goto cleanup; |
914 | srclen = ai.ai_addrlen; |
915 | if (getsockname(s, &aio->aio_srcsa, &srclen) < 0) { |
916 | aio->aio_srcsa.sa_family = AF_UNSPEC; |
917 | goto cleanup; |
918 | } |
919 | aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa); |
920 | aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph); |
921 | aio->aio_matchlen = matchlen(&aio->aio_srcsa, aio->aio_ai->ai_addr); |
922 | #ifdef INET6 |
923 | if (ai.ai_family == AF_INET6) { |
924 | struct in6_ifreq ifr6; |
925 | u_int32_t flags6; |
926 | |
927 | memset(&ifr6, 0, sizeof(ifr6)); |
928 | memcpy(&ifr6.ifr_addr, ai.ai_addr, ai.ai_addrlen); |
929 | if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) { |
930 | flags6 = ifr6.ifr_ifru.ifru_flags6; |
931 | if ((flags6 & IN6_IFF_DEPRECATED)) |
932 | aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED; |
933 | } |
934 | } |
935 | #endif |
936 | |
937 | cleanup: |
938 | close(s); |
939 | return; |
940 | } |
941 | |
942 | static int |
943 | matchlen(struct sockaddr *src, struct sockaddr *dst) |
944 | { |
945 | int match = 0; |
946 | u_char *s, *d; |
947 | u_char *lim; |
948 | u_int r, addrlen; |
949 | |
950 | switch (src->sa_family) { |
951 | #ifdef INET6 |
952 | case AF_INET6: |
953 | s = sa6addr(src); |
954 | d = sa6addr(dst); |
955 | addrlen = sizeof(struct in6_addr); |
956 | lim = s + addrlen; |
957 | break; |
958 | #endif |
959 | case AF_INET: |
960 | s = sa4addr(src); |
961 | d = sa4addr(dst); |
962 | addrlen = sizeof(struct in_addr); |
963 | lim = s + addrlen; |
964 | break; |
965 | default: |
966 | return 0; |
967 | } |
968 | |
969 | while (s < lim) |
970 | if ((r = (*d++ ^ *s++)) != 0) { |
971 | while (r < addrlen * 8) { |
972 | match++; |
973 | r <<= 1; |
974 | } |
975 | break; |
976 | } else |
977 | match += 8; |
978 | return match; |
979 | } |
980 | |
981 | static int |
982 | comp_dst(const void *arg1, const void *arg2) |
983 | { |
984 | const struct ai_order *dst1 = arg1, *dst2 = arg2; |
985 | |
986 | /* |
987 | * Rule 1: Avoid unusable destinations. |
988 | * XXX: we currently do not consider if an appropriate route exists. |
989 | */ |
990 | if (dst1->aio_srcsa.sa_family != AF_UNSPEC && |
991 | dst2->aio_srcsa.sa_family == AF_UNSPEC) { |
992 | return -1; |
993 | } |
994 | if (dst1->aio_srcsa.sa_family == AF_UNSPEC && |
995 | dst2->aio_srcsa.sa_family != AF_UNSPEC) { |
996 | return 1; |
997 | } |
998 | |
999 | /* Rule 2: Prefer matching scope. */ |
1000 | if (dst1->aio_dstscope == dst1->aio_srcscope && |
1001 | dst2->aio_dstscope != dst2->aio_srcscope) { |
1002 | return -1; |
1003 | } |
1004 | if (dst1->aio_dstscope != dst1->aio_srcscope && |
1005 | dst2->aio_dstscope == dst2->aio_srcscope) { |
1006 | return 1; |
1007 | } |
1008 | |
1009 | /* Rule 3: Avoid deprecated addresses. */ |
1010 | if (dst1->aio_srcsa.sa_family != AF_UNSPEC && |
1011 | dst2->aio_srcsa.sa_family != AF_UNSPEC) { |
1012 | if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && |
1013 | (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { |
1014 | return -1; |
1015 | } |
1016 | if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && |
1017 | !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { |
1018 | return 1; |
1019 | } |
1020 | } |
1021 | |
1022 | /* Rule 4: Prefer home addresses. */ |
1023 | /* XXX: not implemented yet */ |
1024 | |
1025 | /* Rule 5: Prefer matching label. */ |
1026 | #ifdef INET6 |
1027 | if (dst1->aio_srcpolicy && dst1->aio_dstpolicy && |
1028 | dst1->aio_srcpolicy->pc_policy.label == |
1029 | dst1->aio_dstpolicy->pc_policy.label && |
1030 | (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL || |
1031 | dst2->aio_srcpolicy->pc_policy.label != |
1032 | dst2->aio_dstpolicy->pc_policy.label)) { |
1033 | return -1; |
1034 | } |
1035 | if (dst2->aio_srcpolicy && dst2->aio_dstpolicy && |
1036 | dst2->aio_srcpolicy->pc_policy.label == |
1037 | dst2->aio_dstpolicy->pc_policy.label && |
1038 | (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL || |
1039 | dst1->aio_srcpolicy->pc_policy.label != |
1040 | dst1->aio_dstpolicy->pc_policy.label)) { |
1041 | return 1; |
1042 | } |
1043 | #endif |
1044 | |
1045 | /* Rule 6: Prefer higher precedence. */ |
1046 | #ifdef INET6 |
1047 | if (dst1->aio_dstpolicy && |
1048 | (dst2->aio_dstpolicy == NULL || |
1049 | dst1->aio_dstpolicy->pc_policy.preced > |
1050 | dst2->aio_dstpolicy->pc_policy.preced)) { |
1051 | return -1; |
1052 | } |
1053 | if (dst2->aio_dstpolicy && |
1054 | (dst1->aio_dstpolicy == NULL || |
1055 | dst2->aio_dstpolicy->pc_policy.preced > |
1056 | dst1->aio_dstpolicy->pc_policy.preced)) { |
1057 | return 1; |
1058 | } |
1059 | #endif |
1060 | |
1061 | /* Rule 7: Prefer native transport. */ |
1062 | /* XXX: not implemented yet */ |
1063 | |
1064 | /* Rule 8: Prefer smaller scope. */ |
1065 | if (dst1->aio_dstscope >= 0 && |
1066 | dst1->aio_dstscope < dst2->aio_dstscope) { |
1067 | return -1; |
1068 | } |
1069 | if (dst2->aio_dstscope >= 0 && |
1070 | dst2->aio_dstscope < dst1->aio_dstscope) { |
1071 | return 1; |
1072 | } |
1073 | |
1074 | /* |
1075 | * Rule 9: Use longest matching prefix. |
1076 | * We compare the match length in a same AF only. |
1077 | */ |
1078 | if (dst1->aio_ai->ai_addr->sa_family == |
1079 | dst2->aio_ai->ai_addr->sa_family && |
1080 | dst1->aio_ai->ai_addr->sa_family != AF_INET) { |
1081 | if (dst1->aio_matchlen > dst2->aio_matchlen) { |
1082 | return -1; |
1083 | } |
1084 | if (dst1->aio_matchlen < dst2->aio_matchlen) { |
1085 | return 1; |
1086 | } |
1087 | } |
1088 | |
1089 | /* Rule 10: Otherwise, leave the order unchanged. */ |
1090 | return -1; |
1091 | } |
1092 | |
1093 | /* |
1094 | * Copy from scope.c. |
1095 | * XXX: we should standardize the functions and link them as standard |
1096 | * library. |
1097 | */ |
1098 | static int |
1099 | gai_addr2scopetype(struct sockaddr *sa) |
1100 | { |
1101 | #ifdef INET6 |
1102 | struct sockaddr_in6 *sa6; |
1103 | #endif |
1104 | struct sockaddr_in *sa4; |
1105 | u_char *p; |
1106 | |
1107 | switch(sa->sa_family) { |
1108 | #ifdef INET6 |
1109 | case AF_INET6: |
1110 | sa6 = (void *)sa; |
1111 | if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { |
1112 | /* just use the scope field of the multicast address */ |
1113 | return sa6->sin6_addr.s6_addr[2] & 0x0f; |
1114 | } |
1115 | /* |
1116 | * Unicast addresses: map scope type to corresponding scope |
1117 | * value defined for multcast addresses. |
1118 | * XXX: hardcoded scope type values are bad... |
1119 | */ |
1120 | if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) |
1121 | return 1; /* node local scope */ |
1122 | if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) |
1123 | return 2; /* link-local scope */ |
1124 | if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr)) |
1125 | return 5; /* site-local scope */ |
1126 | return 14; /* global scope */ |
1127 | #endif |
1128 | case AF_INET: |
1129 | /* |
1130 | * IPv4 pseudo scoping according to RFC 3484. |
1131 | */ |
1132 | sa4 = (void *)sa; |
1133 | p = (u_char *)(void *)&sa4->sin_addr; |
1134 | /* IPv4 autoconfiguration addresses have link-local scope. */ |
1135 | if (p[0] == 169 && p[1] == 254) |
1136 | return 2; |
1137 | /* Private addresses have site-local scope. */ |
1138 | if (p[0] == 10 || |
1139 | (p[0] == 172 && (p[1] & 0xf0) == 16) || |
1140 | (p[0] == 192 && p[1] == 168)) |
1141 | return 14; /* XXX: It should be 5 unless NAT */ |
1142 | /* Loopback addresses have link-local scope. */ |
1143 | if (p[0] == 127) |
1144 | return 2; |
1145 | return 14; |
1146 | default: |
1147 | errno = EAFNOSUPPORT; /* is this a good error? */ |
1148 | return -1; |
1149 | } |
1150 | } |
1151 | |
1152 | /* |
1153 | * FQDN hostname, DNS lookup |
1154 | */ |
1155 | static int |
1156 | explore_fqdn(const struct addrinfo *pai, const char *hostname, |
1157 | const char *servname, struct addrinfo **res, struct servent_data *svd) |
1158 | { |
1159 | struct addrinfo *result; |
1160 | struct addrinfo *cur; |
1161 | int error = 0; |
1162 | static const ns_dtab dtab[] = { |
1163 | NS_FILES_CB(_files_getaddrinfo, NULL) |
1164 | { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ |
1165 | NS_NIS_CB(_yp_getaddrinfo, NULL) |
1166 | NS_NULL_CB |
1167 | }; |
1168 | |
1169 | _DIAGASSERT(pai != NULL); |
1170 | /* hostname may be NULL */ |
1171 | /* servname may be NULL */ |
1172 | _DIAGASSERT(res != NULL); |
1173 | |
1174 | result = NULL; |
1175 | |
1176 | /* |
1177 | * if the servname does not match socktype/protocol, ignore it. |
1178 | */ |
1179 | if (get_portmatch(pai, servname, svd) != 0) |
1180 | return 0; |
1181 | |
1182 | switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo" , |
1183 | default_dns_files, hostname, pai, servname)) { |
1184 | case NS_TRYAGAIN: |
1185 | error = EAI_AGAIN; |
1186 | goto free; |
1187 | case NS_UNAVAIL: |
1188 | error = EAI_FAIL; |
1189 | goto free; |
1190 | case NS_NOTFOUND: |
1191 | error = EAI_NODATA; |
1192 | goto free; |
1193 | case NS_SUCCESS: |
1194 | error = 0; |
1195 | for (cur = result; cur; cur = cur->ai_next) { |
1196 | /* Check for already filled port. */ |
1197 | if (*getport(cur)) |
1198 | continue; |
1199 | GET_PORT(cur, servname, svd); |
1200 | /* canonname should be filled already */ |
1201 | } |
1202 | break; |
1203 | } |
1204 | |
1205 | *res = result; |
1206 | |
1207 | return 0; |
1208 | |
1209 | free: |
1210 | if (result) |
1211 | freeaddrinfo(result); |
1212 | return error; |
1213 | } |
1214 | |
1215 | /* |
1216 | * hostname == NULL. |
1217 | * passive socket -> anyaddr (0.0.0.0 or ::) |
1218 | * non-passive socket -> localhost (127.0.0.1 or ::1) |
1219 | */ |
1220 | static int |
1221 | explore_null(const struct addrinfo *pai, const char *servname, |
1222 | struct addrinfo **res, struct servent_data *svd) |
1223 | { |
1224 | int s; |
1225 | const struct afd *afd; |
1226 | struct addrinfo *cur; |
1227 | struct addrinfo sentinel; |
1228 | int error; |
1229 | |
1230 | _DIAGASSERT(pai != NULL); |
1231 | /* servname may be NULL */ |
1232 | _DIAGASSERT(res != NULL); |
1233 | |
1234 | *res = NULL; |
1235 | sentinel.ai_next = NULL; |
1236 | cur = &sentinel; |
1237 | |
1238 | /* |
1239 | * filter out AFs that are not supported by the kernel |
1240 | * XXX errno? |
1241 | */ |
1242 | s = socket(pai->ai_family, SOCK_DGRAM, 0); |
1243 | if (s < 0) { |
1244 | if (errno != EMFILE) |
1245 | return 0; |
1246 | } else |
1247 | close(s); |
1248 | |
1249 | /* |
1250 | * if the servname does not match socktype/protocol, ignore it. |
1251 | */ |
1252 | if (get_portmatch(pai, servname, svd) != 0) |
1253 | return 0; |
1254 | |
1255 | afd = find_afd(pai->ai_family); |
1256 | if (afd == NULL) |
1257 | return 0; |
1258 | |
1259 | if (pai->ai_flags & AI_PASSIVE) { |
1260 | GET_AI(cur->ai_next, afd, afd->a_addrany); |
1261 | /* xxx meaningless? |
1262 | * GET_CANONNAME(cur->ai_next, "anyaddr"); |
1263 | */ |
1264 | GET_PORT(cur->ai_next, servname, svd); |
1265 | } else { |
1266 | GET_AI(cur->ai_next, afd, afd->a_loopback); |
1267 | /* xxx meaningless? |
1268 | * GET_CANONNAME(cur->ai_next, "localhost"); |
1269 | */ |
1270 | GET_PORT(cur->ai_next, servname, svd); |
1271 | } |
1272 | cur = cur->ai_next; |
1273 | |
1274 | *res = sentinel.ai_next; |
1275 | return 0; |
1276 | |
1277 | free: |
1278 | if (sentinel.ai_next) |
1279 | freeaddrinfo(sentinel.ai_next); |
1280 | return error; |
1281 | } |
1282 | |
1283 | /* |
1284 | * numeric hostname |
1285 | */ |
1286 | static int |
1287 | explore_numeric(const struct addrinfo *pai, const char *hostname, |
1288 | const char *servname, struct addrinfo **res, const char *canonname, |
1289 | struct servent_data *svd) |
1290 | { |
1291 | const struct afd *afd; |
1292 | struct addrinfo *cur; |
1293 | struct addrinfo sentinel; |
1294 | int error; |
1295 | char pton[PTON_MAX]; |
1296 | |
1297 | _DIAGASSERT(pai != NULL); |
1298 | /* hostname may be NULL */ |
1299 | /* servname may be NULL */ |
1300 | _DIAGASSERT(res != NULL); |
1301 | |
1302 | *res = NULL; |
1303 | sentinel.ai_next = NULL; |
1304 | cur = &sentinel; |
1305 | |
1306 | /* |
1307 | * if the servname does not match socktype/protocol, ignore it. |
1308 | */ |
1309 | if (get_portmatch(pai, servname, svd) != 0) |
1310 | return 0; |
1311 | |
1312 | afd = find_afd(pai->ai_family); |
1313 | if (afd == NULL) |
1314 | return 0; |
1315 | |
1316 | switch (afd->a_af) { |
1317 | case AF_INET: |
1318 | /* |
1319 | * RFC3493 section 6.1, requires getaddrinfo() to accept |
1320 | * AF_INET formats that are accepted by inet_addr(); here |
1321 | * we use the equivalent inet_aton() function so we can |
1322 | * check for errors. inet_pton() only accepts addresses |
1323 | * in the dotted quad format and only in base 10, so we |
1324 | * need to treat AF_INET specially. |
1325 | * |
1326 | * We also check for trailing characters and fail if there |
1327 | * are any. This matches the inet_pton6(), but not the |
1328 | * inet_pton4() behavior. We choose to make the protocol |
1329 | * behavior consistent. |
1330 | */ |
1331 | if (inet_aton(hostname, (void *)pton) == 1 && |
1332 | hostname[strspn(hostname, "0123456789.xabcdefXABCDEF" )] |
1333 | == '\0') { |
1334 | if (pai->ai_family == afd->a_af || |
1335 | pai->ai_family == PF_UNSPEC /*?*/) { |
1336 | GET_AI(cur->ai_next, afd, pton); |
1337 | GET_PORT(cur->ai_next, servname, svd); |
1338 | if ((pai->ai_flags & AI_CANONNAME)) { |
1339 | /* |
1340 | * Set the numeric address itself as |
1341 | * the canonical name, based on a |
1342 | * clarification in rfc2553bis-03. |
1343 | */ |
1344 | GET_CANONNAME(cur->ai_next, canonname); |
1345 | } |
1346 | while (cur && cur->ai_next) |
1347 | cur = cur->ai_next; |
1348 | } else |
1349 | ERR(EAI_FAMILY); /*xxx*/ |
1350 | } |
1351 | break; |
1352 | default: |
1353 | if (inet_pton(afd->a_af, hostname, pton) == 1) { |
1354 | if (pai->ai_family == afd->a_af || |
1355 | pai->ai_family == PF_UNSPEC /*?*/) { |
1356 | GET_AI(cur->ai_next, afd, pton); |
1357 | GET_PORT(cur->ai_next, servname, svd); |
1358 | if ((pai->ai_flags & AI_CANONNAME)) { |
1359 | /* |
1360 | * Set the numeric address itself as |
1361 | * the canonical name, based on a |
1362 | * clarification in rfc2553bis-03. |
1363 | */ |
1364 | GET_CANONNAME(cur->ai_next, canonname); |
1365 | } |
1366 | while (cur->ai_next) |
1367 | cur = cur->ai_next; |
1368 | } else |
1369 | ERR(EAI_FAMILY); /*xxx*/ |
1370 | } |
1371 | break; |
1372 | } |
1373 | |
1374 | *res = sentinel.ai_next; |
1375 | return 0; |
1376 | |
1377 | free: |
1378 | bad: |
1379 | if (sentinel.ai_next) |
1380 | freeaddrinfo(sentinel.ai_next); |
1381 | return error; |
1382 | } |
1383 | |
1384 | /* |
1385 | * numeric hostname with scope |
1386 | */ |
1387 | static int |
1388 | explore_numeric_scope(const struct addrinfo *pai, const char *hostname, |
1389 | const char *servname, struct addrinfo **res, struct servent_data *svd) |
1390 | { |
1391 | #if !defined(SCOPE_DELIMITER) || !defined(INET6) |
1392 | return explore_numeric(pai, hostname, servname, res, hostname, svd); |
1393 | #else |
1394 | const struct afd *afd; |
1395 | struct addrinfo *cur; |
1396 | int error; |
1397 | char *cp, *hostname2 = NULL, *scope, *addr; |
1398 | struct sockaddr_in6 *sin6; |
1399 | |
1400 | _DIAGASSERT(pai != NULL); |
1401 | /* hostname may be NULL */ |
1402 | /* servname may be NULL */ |
1403 | _DIAGASSERT(res != NULL); |
1404 | |
1405 | /* |
1406 | * if the servname does not match socktype/protocol, ignore it. |
1407 | */ |
1408 | if (get_portmatch(pai, servname, svd) != 0) |
1409 | return 0; |
1410 | |
1411 | afd = find_afd(pai->ai_family); |
1412 | if (afd == NULL) |
1413 | return 0; |
1414 | |
1415 | if (!afd->a_scoped) |
1416 | return explore_numeric(pai, hostname, servname, res, hostname, |
1417 | svd); |
1418 | |
1419 | cp = strchr(hostname, SCOPE_DELIMITER); |
1420 | if (cp == NULL) |
1421 | return explore_numeric(pai, hostname, servname, res, hostname, |
1422 | svd); |
1423 | |
1424 | /* |
1425 | * Handle special case of <scoped_address><delimiter><scope id> |
1426 | */ |
1427 | hostname2 = strdup(hostname); |
1428 | if (hostname2 == NULL) |
1429 | return EAI_MEMORY; |
1430 | /* terminate at the delimiter */ |
1431 | hostname2[cp - hostname] = '\0'; |
1432 | addr = hostname2; |
1433 | scope = cp + 1; |
1434 | |
1435 | error = explore_numeric(pai, addr, servname, res, hostname, svd); |
1436 | if (error == 0) { |
1437 | u_int32_t scopeid; |
1438 | |
1439 | for (cur = *res; cur; cur = cur->ai_next) { |
1440 | if (cur->ai_family != AF_INET6) |
1441 | continue; |
1442 | sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; |
1443 | if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { |
1444 | free(hostname2); |
1445 | return EAI_NODATA; /* XXX: is return OK? */ |
1446 | } |
1447 | sin6->sin6_scope_id = scopeid; |
1448 | } |
1449 | } |
1450 | |
1451 | free(hostname2); |
1452 | |
1453 | return error; |
1454 | #endif |
1455 | } |
1456 | |
1457 | static int |
1458 | get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str) |
1459 | { |
1460 | |
1461 | _DIAGASSERT(pai != NULL); |
1462 | _DIAGASSERT(ai != NULL); |
1463 | _DIAGASSERT(str != NULL); |
1464 | |
1465 | if ((pai->ai_flags & AI_CANONNAME) != 0) { |
1466 | ai->ai_canonname = strdup(str); |
1467 | if (ai->ai_canonname == NULL) |
1468 | return EAI_MEMORY; |
1469 | } |
1470 | return 0; |
1471 | } |
1472 | |
1473 | struct addrinfo * |
1474 | allocaddrinfo(socklen_t addrlen) |
1475 | { |
1476 | struct addrinfo *ai; |
1477 | |
1478 | ai = calloc(sizeof(struct addrinfo) + addrlen, 1); |
1479 | if (ai) { |
1480 | ai->ai_addr = (void *)(ai+1); |
1481 | ai->ai_addrlen = ai->ai_addr->sa_len = addrlen; |
1482 | } |
1483 | |
1484 | return ai; |
1485 | } |
1486 | |
1487 | static struct addrinfo * |
1488 | get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr) |
1489 | { |
1490 | char *p; |
1491 | struct addrinfo *ai; |
1492 | struct sockaddr *save; |
1493 | |
1494 | _DIAGASSERT(pai != NULL); |
1495 | _DIAGASSERT(afd != NULL); |
1496 | _DIAGASSERT(addr != NULL); |
1497 | |
1498 | ai = allocaddrinfo((socklen_t)afd->a_socklen); |
1499 | if (ai == NULL) |
1500 | return NULL; |
1501 | |
1502 | save = ai->ai_addr; |
1503 | memcpy(ai, pai, sizeof(struct addrinfo)); |
1504 | |
1505 | /* since we just overwrote all of ai, we have |
1506 | to restore ai_addr and ai_addrlen */ |
1507 | ai->ai_addr = save; |
1508 | ai->ai_addrlen = (socklen_t)afd->a_socklen; |
1509 | |
1510 | ai->ai_addr->sa_family = ai->ai_family = afd->a_af; |
1511 | p = (char *)(void *)(ai->ai_addr); |
1512 | memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); |
1513 | return ai; |
1514 | } |
1515 | |
1516 | static int |
1517 | get_portmatch(const struct addrinfo *ai, const char *servname, |
1518 | struct servent_data *svd) |
1519 | { |
1520 | |
1521 | _DIAGASSERT(ai != NULL); |
1522 | /* servname may be NULL */ |
1523 | |
1524 | return get_port(ai, servname, 1, svd); |
1525 | } |
1526 | |
1527 | static int |
1528 | get_port(const struct addrinfo *ai, const char *servname, int matchonly, |
1529 | struct servent_data *svd) |
1530 | { |
1531 | const char *proto; |
1532 | struct servent *sp; |
1533 | int port; |
1534 | int allownumeric; |
1535 | |
1536 | _DIAGASSERT(ai != NULL); |
1537 | /* servname may be NULL */ |
1538 | |
1539 | if (servname == NULL) |
1540 | return 0; |
1541 | switch (ai->ai_family) { |
1542 | case AF_INET: |
1543 | #ifdef AF_INET6 |
1544 | case AF_INET6: |
1545 | #endif |
1546 | break; |
1547 | default: |
1548 | return 0; |
1549 | } |
1550 | |
1551 | switch (ai->ai_socktype) { |
1552 | case SOCK_RAW: |
1553 | return EAI_SERVICE; |
1554 | case SOCK_DGRAM: |
1555 | case SOCK_STREAM: |
1556 | allownumeric = 1; |
1557 | break; |
1558 | case ANY: |
1559 | /* |
1560 | * This was 0. It is now 1 so that queries specifying |
1561 | * a NULL hint, or hint without socktype (but, hopefully, |
1562 | * with protocol) and numeric address actually work. |
1563 | */ |
1564 | allownumeric = 1; |
1565 | break; |
1566 | default: |
1567 | return EAI_SOCKTYPE; |
1568 | } |
1569 | |
1570 | port = str2number(servname); |
1571 | if (port >= 0) { |
1572 | if (!allownumeric) |
1573 | return EAI_SERVICE; |
1574 | if (port < 0 || port > 65535) |
1575 | return EAI_SERVICE; |
1576 | port = htons(port); |
1577 | } else { |
1578 | struct servent sv; |
1579 | if (ai->ai_flags & AI_NUMERICSERV) |
1580 | return EAI_NONAME; |
1581 | |
1582 | switch (ai->ai_socktype) { |
1583 | case SOCK_DGRAM: |
1584 | proto = "udp" ; |
1585 | break; |
1586 | case SOCK_STREAM: |
1587 | proto = "tcp" ; |
1588 | break; |
1589 | default: |
1590 | proto = NULL; |
1591 | break; |
1592 | } |
1593 | |
1594 | sp = getservbyname_r(servname, proto, &sv, svd); |
1595 | if (sp == NULL) |
1596 | return EAI_SERVICE; |
1597 | port = sp->s_port; |
1598 | } |
1599 | |
1600 | if (!matchonly) |
1601 | *getport(__UNCONST(ai)) = port; |
1602 | return 0; |
1603 | } |
1604 | |
1605 | static const struct afd * |
1606 | find_afd(int af) |
1607 | { |
1608 | const struct afd *afd; |
1609 | |
1610 | if (af == PF_UNSPEC) |
1611 | return NULL; |
1612 | for (afd = afdl; afd->a_af; afd++) { |
1613 | if (afd->a_af == af) |
1614 | return afd; |
1615 | } |
1616 | return NULL; |
1617 | } |
1618 | |
1619 | /* |
1620 | * AI_ADDRCONFIG check: Build a mask containing a bit set for each address |
1621 | * family configured in the system. |
1622 | * |
1623 | */ |
1624 | static int |
1625 | addrconfig(uint64_t *mask) |
1626 | { |
1627 | struct ifaddrs *ifaddrs, *ifa; |
1628 | |
1629 | if (getifaddrs(&ifaddrs) == -1) |
1630 | return -1; |
1631 | |
1632 | *mask = 0; |
1633 | for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) |
1634 | if (ifa->ifa_addr && (ifa->ifa_flags & IFF_UP)) { |
1635 | _DIAGASSERT(ifa->ifa_addr->sa_family < 64); |
1636 | *mask |= (uint64_t)1 << ifa->ifa_addr->sa_family; |
1637 | } |
1638 | |
1639 | freeifaddrs(ifaddrs); |
1640 | return 0; |
1641 | } |
1642 | |
1643 | #ifdef INET6 |
1644 | /* convert a string to a scope identifier. XXX: IPv6 specific */ |
1645 | static int |
1646 | ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid) |
1647 | { |
1648 | u_long lscopeid; |
1649 | struct in6_addr *a6; |
1650 | char *ep; |
1651 | |
1652 | _DIAGASSERT(scope != NULL); |
1653 | _DIAGASSERT(sin6 != NULL); |
1654 | _DIAGASSERT(scopeid != NULL); |
1655 | |
1656 | a6 = &sin6->sin6_addr; |
1657 | |
1658 | /* empty scopeid portion is invalid */ |
1659 | if (*scope == '\0') |
1660 | return -1; |
1661 | |
1662 | if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { |
1663 | /* |
1664 | * We currently assume a one-to-one mapping between links |
1665 | * and interfaces, so we simply use interface indices for |
1666 | * like-local scopes. |
1667 | */ |
1668 | *scopeid = if_nametoindex(scope); |
1669 | if (*scopeid == 0) |
1670 | goto trynumeric; |
1671 | return 0; |
1672 | } |
1673 | |
1674 | /* still unclear about literal, allow numeric only - placeholder */ |
1675 | if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) |
1676 | goto trynumeric; |
1677 | if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) |
1678 | goto trynumeric; |
1679 | else |
1680 | goto trynumeric; /* global */ |
1681 | |
1682 | /* try to convert to a numeric id as a last resort */ |
1683 | trynumeric: |
1684 | errno = 0; |
1685 | lscopeid = strtoul(scope, &ep, 10); |
1686 | *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); |
1687 | if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) |
1688 | return 0; |
1689 | else |
1690 | return -1; |
1691 | } |
1692 | #endif |
1693 | |
1694 | /* code duplicate with gethnamaddr.c */ |
1695 | |
1696 | static const char AskedForGot[] = |
1697 | "gethostby*.getanswer: asked for \"%s\", got \"%s\"" ; |
1698 | |
1699 | #define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \ |
1700 | (ok)(nm) != 0) |
1701 | static struct addrinfo * |
1702 | getanswer(res_state res, const querybuf *answer, int anslen, const char *qname, |
1703 | int qtype, const struct addrinfo *pai) |
1704 | { |
1705 | struct addrinfo sentinel, *cur; |
1706 | struct addrinfo ai, *aip; |
1707 | const struct afd *afd; |
1708 | char *canonname; |
1709 | const HEADER *hp; |
1710 | const u_char *cp; |
1711 | int n; |
1712 | const u_char *eom; |
1713 | char *bp, *ep; |
1714 | int type, class, ancount, qdcount; |
1715 | int haveanswer, had_error; |
1716 | char tbuf[MAXDNAME]; |
1717 | int (*name_ok) (const char *); |
1718 | char hostbuf[8*1024]; |
1719 | int port, pri, weight; |
1720 | struct srvinfo *srvlist, *srv, *csrv; |
1721 | |
1722 | _DIAGASSERT(answer != NULL); |
1723 | _DIAGASSERT(qname != NULL); |
1724 | _DIAGASSERT(pai != NULL); |
1725 | _DIAGASSERT(res != NULL); |
1726 | |
1727 | memset(&sentinel, 0, sizeof(sentinel)); |
1728 | cur = &sentinel; |
1729 | |
1730 | canonname = NULL; |
1731 | eom = answer->buf + anslen; |
1732 | switch (qtype) { |
1733 | case T_A: |
1734 | case T_AAAA: |
1735 | case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ |
1736 | name_ok = res_hnok; |
1737 | break; |
1738 | case T_SRV: |
1739 | name_ok = gai_srvok; |
1740 | break; |
1741 | default: |
1742 | return NULL; /* XXX should be abort(); */ |
1743 | } |
1744 | /* |
1745 | * find first satisfactory answer |
1746 | */ |
1747 | hp = &answer->hdr; |
1748 | ancount = ntohs(hp->ancount); |
1749 | qdcount = ntohs(hp->qdcount); |
1750 | bp = hostbuf; |
1751 | ep = hostbuf + sizeof hostbuf; |
1752 | cp = answer->buf + HFIXEDSZ; |
1753 | if (qdcount != 1) { |
1754 | h_errno = NO_RECOVERY; |
1755 | return NULL; |
1756 | } |
1757 | n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp)); |
1758 | if ((n < 0) || !maybe_ok(res, bp, name_ok)) { |
1759 | h_errno = NO_RECOVERY; |
1760 | return NULL; |
1761 | } |
1762 | cp += n + QFIXEDSZ; |
1763 | if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { |
1764 | /* res_send() has already verified that the query name is the |
1765 | * same as the one we sent; this just gets the expanded name |
1766 | * (i.e., with the succeeding search-domain tacked on). |
1767 | */ |
1768 | n = (int)strlen(bp) + 1; /* for the \0 */ |
1769 | if (n >= MAXHOSTNAMELEN) { |
1770 | h_errno = NO_RECOVERY; |
1771 | return NULL; |
1772 | } |
1773 | canonname = bp; |
1774 | bp += n; |
1775 | /* The qname can be abbreviated, but h_name is now absolute. */ |
1776 | qname = canonname; |
1777 | } |
1778 | haveanswer = 0; |
1779 | had_error = 0; |
1780 | srvlist = NULL; |
1781 | while (ancount-- > 0 && cp < eom && !had_error) { |
1782 | n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp)); |
1783 | if ((n < 0) || !maybe_ok(res, bp, name_ok)) { |
1784 | had_error++; |
1785 | continue; |
1786 | } |
1787 | cp += n; /* name */ |
1788 | type = _getshort(cp); |
1789 | cp += INT16SZ; /* type */ |
1790 | class = _getshort(cp); |
1791 | cp += INT16SZ + INT32SZ; /* class, TTL */ |
1792 | n = _getshort(cp); |
1793 | cp += INT16SZ; /* len */ |
1794 | if (class != C_IN) { |
1795 | /* XXX - debug? syslog? */ |
1796 | cp += n; |
1797 | continue; /* XXX - had_error++ ? */ |
1798 | } |
1799 | if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && |
1800 | type == T_CNAME) { |
1801 | n = dn_expand(answer->buf, eom, cp, tbuf, (int)sizeof tbuf); |
1802 | if ((n < 0) || !maybe_ok(res, tbuf, name_ok)) { |
1803 | had_error++; |
1804 | continue; |
1805 | } |
1806 | cp += n; |
1807 | /* Get canonical name. */ |
1808 | n = (int)strlen(tbuf) + 1; /* for the \0 */ |
1809 | if (n > ep - bp || n >= MAXHOSTNAMELEN) { |
1810 | had_error++; |
1811 | continue; |
1812 | } |
1813 | strlcpy(bp, tbuf, (size_t)(ep - bp)); |
1814 | canonname = bp; |
1815 | bp += n; |
1816 | continue; |
1817 | } |
1818 | if (qtype == T_ANY) { |
1819 | if (!(type == T_A || type == T_AAAA)) { |
1820 | cp += n; |
1821 | continue; |
1822 | } |
1823 | } else if (type != qtype) { |
1824 | if (type != T_KEY && type != T_SIG) { |
1825 | struct syslog_data sd = SYSLOG_DATA_INIT; |
1826 | syslog_r(LOG_NOTICE|LOG_AUTH, &sd, |
1827 | "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"" , |
1828 | qname, p_class(C_IN), p_type(qtype), |
1829 | p_type(type)); |
1830 | } |
1831 | cp += n; |
1832 | continue; /* XXX - had_error++ ? */ |
1833 | } |
1834 | switch (type) { |
1835 | case T_A: |
1836 | case T_AAAA: |
1837 | if (strcasecmp(canonname, bp) != 0) { |
1838 | struct syslog_data sd = SYSLOG_DATA_INIT; |
1839 | syslog_r(LOG_NOTICE|LOG_AUTH, &sd, |
1840 | AskedForGot, canonname, bp); |
1841 | cp += n; |
1842 | continue; /* XXX - had_error++ ? */ |
1843 | } |
1844 | if (type == T_A && n != INADDRSZ) { |
1845 | cp += n; |
1846 | continue; |
1847 | } |
1848 | if (type == T_AAAA && n != IN6ADDRSZ) { |
1849 | cp += n; |
1850 | continue; |
1851 | } |
1852 | if (type == T_AAAA) { |
1853 | struct in6_addr in6; |
1854 | memcpy(&in6, cp, IN6ADDRSZ); |
1855 | if (IN6_IS_ADDR_V4MAPPED(&in6)) { |
1856 | cp += n; |
1857 | continue; |
1858 | } |
1859 | } |
1860 | if (!haveanswer) { |
1861 | int nn; |
1862 | |
1863 | canonname = bp; |
1864 | nn = (int)strlen(bp) + 1; /* for the \0 */ |
1865 | bp += nn; |
1866 | } |
1867 | |
1868 | /* don't overwrite pai */ |
1869 | ai = *pai; |
1870 | ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; |
1871 | afd = find_afd(ai.ai_family); |
1872 | if (afd == NULL) { |
1873 | cp += n; |
1874 | continue; |
1875 | } |
1876 | cur->ai_next = get_ai(&ai, afd, (const char *)cp); |
1877 | if (cur->ai_next == NULL) |
1878 | had_error++; |
1879 | while (cur && cur->ai_next) |
1880 | cur = cur->ai_next; |
1881 | cp += n; |
1882 | break; |
1883 | case T_SRV: |
1884 | /* Add to SRV list. Insertion sort on priority. */ |
1885 | pri = _getshort(cp); |
1886 | cp += INT16SZ; |
1887 | weight = _getshort(cp); |
1888 | cp += INT16SZ; |
1889 | port = _getshort(cp); |
1890 | cp += INT16SZ; |
1891 | n = dn_expand(answer->buf, eom, cp, tbuf, |
1892 | (int)sizeof(tbuf)); |
1893 | if ((n < 0) || !maybe_ok(res, tbuf, res_hnok)) { |
1894 | had_error++; |
1895 | continue; |
1896 | } |
1897 | cp += n; |
1898 | if (strlen(tbuf) + 1 >= MAXDNAME) { |
1899 | had_error++; |
1900 | continue; |
1901 | } |
1902 | srv = malloc(sizeof(*srv)); |
1903 | if (!srv) { |
1904 | had_error++; |
1905 | continue; |
1906 | } |
1907 | strlcpy(srv->name, tbuf, sizeof(srv->name)); |
1908 | srv->pri = pri; |
1909 | srv->weight = weight; |
1910 | srv->port = port; |
1911 | /* Weight 0 is sorted before other weights. */ |
1912 | if (!srvlist |
1913 | || srv->pri < srvlist->pri |
1914 | || (srv->pri == srvlist->pri && |
1915 | (!srv->weight || srvlist->weight))) { |
1916 | srv->next = srvlist; |
1917 | srvlist = srv; |
1918 | } else { |
1919 | for (csrv = srvlist; |
1920 | csrv->next && csrv->next->pri <= srv->pri; |
1921 | csrv = csrv->next) { |
1922 | if (csrv->next->pri == srv->pri |
1923 | && (!srv->weight || |
1924 | csrv->next->weight)) |
1925 | break; |
1926 | } |
1927 | srv->next = csrv->next; |
1928 | csrv->next = srv; |
1929 | } |
1930 | continue; /* Don't add to haveanswer yet. */ |
1931 | default: |
1932 | abort(); |
1933 | } |
1934 | if (!had_error) |
1935 | haveanswer++; |
1936 | } |
1937 | |
1938 | if (srvlist) { |
1939 | /* |
1940 | * Check for explicit rejection. |
1941 | */ |
1942 | if (!srvlist->next && !srvlist->name[0]) { |
1943 | free(srvlist); |
1944 | h_errno = HOST_NOT_FOUND; |
1945 | return NULL; |
1946 | } |
1947 | |
1948 | while (srvlist) { |
1949 | struct res_target q, q2; |
1950 | |
1951 | srv = srvlist; |
1952 | srvlist = srvlist->next; |
1953 | |
1954 | /* |
1955 | * Since res_* doesn't give the additional |
1956 | * section, we always look up. |
1957 | */ |
1958 | memset(&q, 0, sizeof(q)); |
1959 | memset(&q2, 0, sizeof(q2)); |
1960 | |
1961 | q.name = srv->name; |
1962 | q.qclass = C_IN; |
1963 | q.qtype = T_AAAA; |
1964 | q.next = &q2; |
1965 | q2.name = srv->name; |
1966 | q2.qclass = C_IN; |
1967 | q2.qtype = T_A; |
1968 | |
1969 | aip = _dns_query(&q, pai, res, 0); |
1970 | |
1971 | if (aip != NULL) { |
1972 | cur->ai_next = aip; |
1973 | while (cur && cur->ai_next) { |
1974 | cur = cur->ai_next; |
1975 | *getport(cur) = htons(srv->port); |
1976 | haveanswer++; |
1977 | } |
1978 | } |
1979 | free(srv); |
1980 | } |
1981 | } |
1982 | if (haveanswer) { |
1983 | if (!sentinel.ai_next->ai_canonname) |
1984 | (void)get_canonname(pai, sentinel.ai_next, |
1985 | canonname ? canonname : qname); |
1986 | h_errno = NETDB_SUCCESS; |
1987 | return sentinel.ai_next; |
1988 | } |
1989 | |
1990 | /* We could have walked a CNAME chain, */ |
1991 | /* but the ultimate target may not have what we looked for */ |
1992 | h_errno = ntohs(hp->ancount) > 0? NO_DATA : NO_RECOVERY; |
1993 | return NULL; |
1994 | } |
1995 | |
1996 | #define SORTEDADDR(p) (((struct sockaddr_in *)(void *)(p->ai_next->ai_addr))->sin_addr.s_addr) |
1997 | #define SORTMATCH(p, s) ((SORTEDADDR(p) & (s).mask) == (s).addr.s_addr) |
1998 | |
1999 | static void |
2000 | aisort(struct addrinfo *s, res_state res) |
2001 | { |
2002 | struct addrinfo head, *t, *p; |
2003 | int i; |
2004 | |
2005 | head.ai_next = NULL; |
2006 | t = &head; |
2007 | |
2008 | for (i = 0; i < res->nsort; i++) { |
2009 | p = s; |
2010 | while (p->ai_next) { |
2011 | if ((p->ai_next->ai_family != AF_INET) |
2012 | || SORTMATCH(p, res->sort_list[i])) { |
2013 | t->ai_next = p->ai_next; |
2014 | t = t->ai_next; |
2015 | p->ai_next = p->ai_next->ai_next; |
2016 | } else { |
2017 | p = p->ai_next; |
2018 | } |
2019 | } |
2020 | } |
2021 | |
2022 | /* add rest of list and reset s to the new list*/ |
2023 | t->ai_next = s->ai_next; |
2024 | s->ai_next = head.ai_next; |
2025 | } |
2026 | |
2027 | static struct addrinfo * |
2028 | _dns_query(struct res_target *q, const struct addrinfo *pai, |
2029 | res_state res, int dosearch) |
2030 | { |
2031 | struct res_target *q2 = q->next; |
2032 | querybuf *buf, *buf2; |
2033 | struct addrinfo sentinel, *cur, *ai; |
2034 | |
2035 | #ifdef DNS_DEBUG |
2036 | struct res_target *iter; |
2037 | for (iter = q; iter; iter = iter->next) |
2038 | printf("Query type %d for %s\n" , iter->qtype, iter->name); |
2039 | #endif |
2040 | |
2041 | buf = malloc(sizeof(*buf)); |
2042 | if (buf == NULL) { |
2043 | h_errno = NETDB_INTERNAL; |
2044 | return NULL; |
2045 | } |
2046 | buf2 = malloc(sizeof(*buf2)); |
2047 | if (buf2 == NULL) { |
2048 | free(buf); |
2049 | h_errno = NETDB_INTERNAL; |
2050 | return NULL; |
2051 | } |
2052 | |
2053 | memset(&sentinel, 0, sizeof(sentinel)); |
2054 | cur = &sentinel; |
2055 | |
2056 | q->answer = buf->buf; |
2057 | q->anslen = sizeof(buf->buf); |
2058 | if (q2) { |
2059 | q2->answer = buf2->buf; |
2060 | q2->anslen = sizeof(buf2->buf); |
2061 | } |
2062 | |
2063 | if (dosearch) { |
2064 | if (res_searchN(q->name, q, res) < 0) |
2065 | goto out; |
2066 | } else { |
2067 | if (res_queryN(q->name, q, res) < 0) |
2068 | goto out; |
2069 | } |
2070 | |
2071 | ai = getanswer(res, buf, q->n, q->name, q->qtype, pai); |
2072 | if (ai) { |
2073 | cur->ai_next = ai; |
2074 | while (cur && cur->ai_next) |
2075 | cur = cur->ai_next; |
2076 | } |
2077 | if (q2) { |
2078 | ai = getanswer(res, buf2, q2->n, q2->name, q2->qtype, pai); |
2079 | if (ai) |
2080 | cur->ai_next = ai; |
2081 | } |
2082 | free(buf); |
2083 | free(buf2); |
2084 | return sentinel.ai_next; |
2085 | out: |
2086 | free(buf); |
2087 | free(buf2); |
2088 | return NULL; |
2089 | } |
2090 | |
2091 | /*ARGSUSED*/ |
2092 | static struct addrinfo * |
2093 | _dns_srv_lookup(const char *name, const char *servname, |
2094 | const struct addrinfo *pai) |
2095 | { |
2096 | static const char * const srvprotos[] = { "tcp" , "udp" }; |
2097 | static const int srvnottype[] = { SOCK_DGRAM, SOCK_STREAM }; |
2098 | static const int nsrvprotos = 2; |
2099 | struct addrinfo sentinel, *cur, *ai; |
2100 | struct servent *serv, sv; |
2101 | struct servent_data svd; |
2102 | struct res_target q; |
2103 | res_state res; |
2104 | char *tname; |
2105 | int i; |
2106 | |
2107 | res = __res_get_state(); |
2108 | if (res == NULL) |
2109 | return NULL; |
2110 | |
2111 | memset(&svd, 0, sizeof(svd)); |
2112 | memset(&sentinel, 0, sizeof(sentinel)); |
2113 | cur = &sentinel; |
2114 | |
2115 | /* |
2116 | * Iterate over supported SRV protocols. |
2117 | * (currently UDP and TCP only) |
2118 | */ |
2119 | for (i = 0; i < nsrvprotos; i++) { |
2120 | /* |
2121 | * Check that the caller didn't specify a hint |
2122 | * which precludes this protocol. |
2123 | */ |
2124 | if (pai->ai_socktype == srvnottype[i]) |
2125 | continue; |
2126 | /* |
2127 | * If the caller specified a port, |
2128 | * then lookup the database for the |
2129 | * official service name. |
2130 | */ |
2131 | serv = getservbyname_r(servname, srvprotos[i], &sv, &svd); |
2132 | if (serv == NULL) |
2133 | continue; |
2134 | |
2135 | /* |
2136 | * Construct service DNS name. |
2137 | */ |
2138 | if (asprintf(&tname, "_%s._%s.%s" , serv->s_name, serv->s_proto, |
2139 | name) < 0) |
2140 | continue; |
2141 | |
2142 | memset(&q, 0, sizeof(q)); |
2143 | q.name = tname; |
2144 | q.qclass = C_IN; |
2145 | q.qtype = T_SRV; |
2146 | |
2147 | /* |
2148 | * Do SRV query. |
2149 | */ |
2150 | ai = _dns_query(&q, pai, res, 1); |
2151 | if (ai) { |
2152 | cur->ai_next = ai; |
2153 | while (cur && cur->ai_next) |
2154 | cur = cur->ai_next; |
2155 | } |
2156 | free(tname); |
2157 | } |
2158 | |
2159 | if (res->nsort) |
2160 | aisort(&sentinel, res); |
2161 | |
2162 | __res_put_state(res); |
2163 | |
2164 | return sentinel.ai_next; |
2165 | } |
2166 | |
2167 | /*ARGSUSED*/ |
2168 | static struct addrinfo * |
2169 | _dns_host_lookup(const char *name, const struct addrinfo *pai) |
2170 | { |
2171 | struct res_target q, q2; |
2172 | struct addrinfo sentinel, *ai; |
2173 | res_state res; |
2174 | |
2175 | res = __res_get_state(); |
2176 | if (res == NULL) |
2177 | return NULL; |
2178 | |
2179 | memset(&q, 0, sizeof(q2)); |
2180 | memset(&q2, 0, sizeof(q2)); |
2181 | |
2182 | switch (pai->ai_family) { |
2183 | case AF_UNSPEC: |
2184 | /* prefer IPv6 */ |
2185 | q.name = name; |
2186 | q.qclass = C_IN; |
2187 | q.qtype = T_AAAA; |
2188 | q.next = &q2; |
2189 | q2.name = name; |
2190 | q2.qclass = C_IN; |
2191 | q2.qtype = T_A; |
2192 | break; |
2193 | case AF_INET: |
2194 | q.name = name; |
2195 | q.qclass = C_IN; |
2196 | q.qtype = T_A; |
2197 | break; |
2198 | case AF_INET6: |
2199 | q.name = name; |
2200 | q.qclass = C_IN; |
2201 | q.qtype = T_AAAA; |
2202 | break; |
2203 | default: |
2204 | __res_put_state(res); |
2205 | h_errno = NETDB_INTERNAL; |
2206 | return NULL; |
2207 | } |
2208 | |
2209 | ai = _dns_query(&q, pai, res, 1); |
2210 | |
2211 | memset(&sentinel, 0, sizeof(sentinel)); |
2212 | sentinel.ai_next = ai; |
2213 | |
2214 | if (ai != NULL && res->nsort) |
2215 | aisort(&sentinel, res); |
2216 | |
2217 | __res_put_state(res); |
2218 | |
2219 | return sentinel.ai_next; |
2220 | } |
2221 | |
2222 | /*ARGSUSED*/ |
2223 | static int |
2224 | _dns_getaddrinfo(void *rv, void *cb_data, va_list ap) |
2225 | { |
2226 | struct addrinfo *ai = NULL; |
2227 | const char *name, *servname; |
2228 | const struct addrinfo *pai; |
2229 | |
2230 | name = va_arg(ap, char *); |
2231 | pai = va_arg(ap, const struct addrinfo *); |
2232 | servname = va_arg(ap, char *); |
2233 | |
2234 | /* |
2235 | * Try doing SRV lookup on service first. |
2236 | */ |
2237 | if (servname |
2238 | #ifdef AI_SRV |
2239 | && (pai->ai_flags & AI_SRV) |
2240 | #endif |
2241 | && !(pai->ai_flags & AI_NUMERICSERV) |
2242 | && str2number(servname) == -1) { |
2243 | |
2244 | #ifdef DNS_DEBUG |
2245 | printf("%s: try SRV lookup\n" , __func__); |
2246 | #endif |
2247 | ai = _dns_srv_lookup(name, servname, pai); |
2248 | } |
2249 | |
2250 | /* |
2251 | * Do lookup on name. |
2252 | */ |
2253 | if (ai == NULL) { |
2254 | |
2255 | #ifdef DNS_DEBUG |
2256 | printf("%s: try HOST lookup\n" , __func__); |
2257 | #endif |
2258 | ai = _dns_host_lookup(name, pai); |
2259 | |
2260 | if (ai == NULL) { |
2261 | switch (h_errno) { |
2262 | case HOST_NOT_FOUND: |
2263 | case NO_DATA: // XXX: Perhaps we could differentiate |
2264 | // So that we could return EAI_NODATA? |
2265 | return NS_NOTFOUND; |
2266 | case TRY_AGAIN: |
2267 | return NS_TRYAGAIN; |
2268 | default: |
2269 | return NS_UNAVAIL; |
2270 | } |
2271 | } |
2272 | } |
2273 | |
2274 | *((struct addrinfo **)rv) = ai; |
2275 | return NS_SUCCESS; |
2276 | } |
2277 | |
2278 | static void |
2279 | _sethtent(FILE **hostf) |
2280 | { |
2281 | |
2282 | if (!*hostf) |
2283 | *hostf = fopen(_PATH_HOSTS, "re" ); |
2284 | else |
2285 | rewind(*hostf); |
2286 | } |
2287 | |
2288 | static void |
2289 | _endhtent(FILE **hostf) |
2290 | { |
2291 | |
2292 | if (*hostf) { |
2293 | (void) fclose(*hostf); |
2294 | *hostf = NULL; |
2295 | } |
2296 | } |
2297 | |
2298 | static struct addrinfo * |
2299 | _gethtent(FILE **hostf, const char *name, const struct addrinfo *pai) |
2300 | { |
2301 | char *p; |
2302 | char *cp, *tname, *cname; |
2303 | struct addrinfo hints, *res0, *res; |
2304 | int error; |
2305 | const char *addr; |
2306 | char hostbuf[8*1024]; |
2307 | |
2308 | _DIAGASSERT(name != NULL); |
2309 | _DIAGASSERT(pai != NULL); |
2310 | |
2311 | if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "re" ))) |
2312 | return NULL; |
2313 | again: |
2314 | if (!(p = fgets(hostbuf, (int)sizeof hostbuf, *hostf))) |
2315 | return NULL; |
2316 | if (*p == '#') |
2317 | goto again; |
2318 | if (!(cp = strpbrk(p, "#\n" ))) |
2319 | goto again; |
2320 | *cp = '\0'; |
2321 | if (!(cp = strpbrk(p, " \t" ))) |
2322 | goto again; |
2323 | *cp++ = '\0'; |
2324 | addr = p; |
2325 | /* if this is not something we're looking for, skip it. */ |
2326 | cname = NULL; |
2327 | while (cp && *cp) { |
2328 | if (*cp == ' ' || *cp == '\t') { |
2329 | cp++; |
2330 | continue; |
2331 | } |
2332 | if (!cname) |
2333 | cname = cp; |
2334 | tname = cp; |
2335 | if ((cp = strpbrk(cp, " \t" )) != NULL) |
2336 | *cp++ = '\0'; |
2337 | if (strcasecmp(name, tname) == 0) |
2338 | goto found; |
2339 | } |
2340 | goto again; |
2341 | |
2342 | found: |
2343 | hints = *pai; |
2344 | hints.ai_flags = AI_NUMERICHOST; |
2345 | error = getaddrinfo(addr, NULL, &hints, &res0); |
2346 | if (error) |
2347 | goto again; |
2348 | for (res = res0; res; res = res->ai_next) { |
2349 | /* cover it up */ |
2350 | res->ai_flags = pai->ai_flags; |
2351 | |
2352 | if (pai->ai_flags & AI_CANONNAME) { |
2353 | if (get_canonname(pai, res, cname) != 0) { |
2354 | freeaddrinfo(res0); |
2355 | goto again; |
2356 | } |
2357 | } |
2358 | } |
2359 | return res0; |
2360 | } |
2361 | |
2362 | /*ARGSUSED*/ |
2363 | static int |
2364 | _files_getaddrinfo(void *rv, void *cb_data, va_list ap) |
2365 | { |
2366 | const char *name; |
2367 | const struct addrinfo *pai; |
2368 | struct addrinfo sentinel, *cur; |
2369 | struct addrinfo *p; |
2370 | #ifndef _REENTRANT |
2371 | static |
2372 | #endif |
2373 | FILE *hostf = NULL; |
2374 | |
2375 | name = va_arg(ap, char *); |
2376 | pai = va_arg(ap, const struct addrinfo *); |
2377 | |
2378 | memset(&sentinel, 0, sizeof(sentinel)); |
2379 | cur = &sentinel; |
2380 | |
2381 | _sethtent(&hostf); |
2382 | while ((p = _gethtent(&hostf, name, pai)) != NULL) { |
2383 | cur->ai_next = p; |
2384 | while (cur && cur->ai_next) |
2385 | cur = cur->ai_next; |
2386 | } |
2387 | _endhtent(&hostf); |
2388 | |
2389 | *((struct addrinfo **)rv) = sentinel.ai_next; |
2390 | if (sentinel.ai_next == NULL) |
2391 | return NS_NOTFOUND; |
2392 | return NS_SUCCESS; |
2393 | } |
2394 | |
2395 | #ifdef YP |
2396 | /*ARGSUSED*/ |
2397 | static struct addrinfo * |
2398 | _yphostent(char *line, const struct addrinfo *pai) |
2399 | { |
2400 | struct addrinfo sentinel, *cur; |
2401 | struct addrinfo hints, *res, *res0; |
2402 | int error; |
2403 | char *p; |
2404 | const char *addr, *canonname; |
2405 | char *nextline; |
2406 | char *cp; |
2407 | |
2408 | _DIAGASSERT(line != NULL); |
2409 | _DIAGASSERT(pai != NULL); |
2410 | |
2411 | p = line; |
2412 | addr = canonname = NULL; |
2413 | |
2414 | memset(&sentinel, 0, sizeof(sentinel)); |
2415 | cur = &sentinel; |
2416 | |
2417 | nextline: |
2418 | /* terminate line */ |
2419 | cp = strchr(p, '\n'); |
2420 | if (cp) { |
2421 | *cp++ = '\0'; |
2422 | nextline = cp; |
2423 | } else |
2424 | nextline = NULL; |
2425 | |
2426 | cp = strpbrk(p, " \t" ); |
2427 | if (cp == NULL) { |
2428 | if (canonname == NULL) |
2429 | return NULL; |
2430 | else |
2431 | goto done; |
2432 | } |
2433 | *cp++ = '\0'; |
2434 | |
2435 | addr = p; |
2436 | |
2437 | while (cp && *cp) { |
2438 | if (*cp == ' ' || *cp == '\t') { |
2439 | cp++; |
2440 | continue; |
2441 | } |
2442 | if (!canonname) |
2443 | canonname = cp; |
2444 | if ((cp = strpbrk(cp, " \t" )) != NULL) |
2445 | *cp++ = '\0'; |
2446 | } |
2447 | |
2448 | hints = *pai; |
2449 | hints.ai_flags = AI_NUMERICHOST; |
2450 | error = getaddrinfo(addr, NULL, &hints, &res0); |
2451 | if (error == 0) { |
2452 | for (res = res0; res; res = res->ai_next) { |
2453 | /* cover it up */ |
2454 | res->ai_flags = pai->ai_flags; |
2455 | |
2456 | if (pai->ai_flags & AI_CANONNAME) |
2457 | (void)get_canonname(pai, res, canonname); |
2458 | } |
2459 | } else |
2460 | res0 = NULL; |
2461 | if (res0) { |
2462 | cur->ai_next = res0; |
2463 | while (cur->ai_next) |
2464 | cur = cur->ai_next; |
2465 | } |
2466 | |
2467 | if (nextline) { |
2468 | p = nextline; |
2469 | goto nextline; |
2470 | } |
2471 | |
2472 | done: |
2473 | return sentinel.ai_next; |
2474 | } |
2475 | |
2476 | /*ARGSUSED*/ |
2477 | static int |
2478 | _yp_getaddrinfo(void *rv, void *cb_data, va_list ap) |
2479 | { |
2480 | struct addrinfo sentinel, *cur; |
2481 | struct addrinfo *ai = NULL; |
2482 | char *ypbuf; |
2483 | int ypbuflen, r; |
2484 | const char *name; |
2485 | const struct addrinfo *pai; |
2486 | char *ypdomain; |
2487 | |
2488 | if (_yp_check(&ypdomain) == 0) |
2489 | return NS_UNAVAIL; |
2490 | |
2491 | name = va_arg(ap, char *); |
2492 | pai = va_arg(ap, const struct addrinfo *); |
2493 | |
2494 | memset(&sentinel, 0, sizeof(sentinel)); |
2495 | cur = &sentinel; |
2496 | |
2497 | /* hosts.byname is only for IPv4 (Solaris8) */ |
2498 | if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { |
2499 | r = yp_match(ypdomain, "hosts.byname" , name, |
2500 | (int)strlen(name), &ypbuf, &ypbuflen); |
2501 | if (r == 0) { |
2502 | struct addrinfo ai4; |
2503 | |
2504 | ai4 = *pai; |
2505 | ai4.ai_family = AF_INET; |
2506 | ai = _yphostent(ypbuf, &ai4); |
2507 | if (ai) { |
2508 | cur->ai_next = ai; |
2509 | while (cur && cur->ai_next) |
2510 | cur = cur->ai_next; |
2511 | } |
2512 | } |
2513 | free(ypbuf); |
2514 | } |
2515 | |
2516 | /* ipnodes.byname can hold both IPv4/v6 */ |
2517 | r = yp_match(ypdomain, "ipnodes.byname" , name, |
2518 | (int)strlen(name), &ypbuf, &ypbuflen); |
2519 | if (r == 0) { |
2520 | ai = _yphostent(ypbuf, pai); |
2521 | if (ai) |
2522 | cur->ai_next = ai; |
2523 | free(ypbuf); |
2524 | } |
2525 | |
2526 | if (sentinel.ai_next == NULL) { |
2527 | h_errno = HOST_NOT_FOUND; |
2528 | return NS_NOTFOUND; |
2529 | } |
2530 | *((struct addrinfo **)rv) = sentinel.ai_next; |
2531 | return NS_SUCCESS; |
2532 | } |
2533 | #endif |
2534 | |
2535 | /* resolver logic */ |
2536 | |
2537 | /* |
2538 | * Formulate a normal query, send, and await answer. |
2539 | * Returned answer is placed in supplied buffer "answer". |
2540 | * Perform preliminary check of answer, returning success only |
2541 | * if no error is indicated and the answer count is nonzero. |
2542 | * Return the size of the response on success, -1 on error. |
2543 | * Error number is left in h_errno. |
2544 | * |
2545 | * Caller must parse answer and determine whether it answers the question. |
2546 | */ |
2547 | static int |
2548 | res_queryN(const char *name, /* domain name */ struct res_target *target, |
2549 | res_state statp) |
2550 | { |
2551 | u_char buf[MAXPACKET]; |
2552 | HEADER *hp; |
2553 | int n; |
2554 | struct res_target *t; |
2555 | int rcode; |
2556 | u_char *rdata; |
2557 | int ancount; |
2558 | |
2559 | _DIAGASSERT(name != NULL); |
2560 | /* XXX: target may be NULL??? */ |
2561 | |
2562 | rcode = NOERROR; |
2563 | ancount = 0; |
2564 | |
2565 | for (t = target; t; t = t->next) { |
2566 | int class, type; |
2567 | u_char *answer; |
2568 | int anslen; |
2569 | u_int oflags; |
2570 | |
2571 | hp = (HEADER *)(void *)t->answer; |
2572 | oflags = statp->_flags; |
2573 | |
2574 | again: |
2575 | hp->rcode = NOERROR; /* default */ |
2576 | |
2577 | /* make it easier... */ |
2578 | class = t->qclass; |
2579 | type = t->qtype; |
2580 | answer = t->answer; |
2581 | anslen = t->anslen; |
2582 | #ifdef DEBUG |
2583 | if (statp->options & RES_DEBUG) |
2584 | printf(";; res_nquery(%s, %d, %d)\n" , name, class, type); |
2585 | #endif |
2586 | |
2587 | n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL, |
2588 | buf, (int)sizeof(buf)); |
2589 | #ifdef RES_USE_EDNS0 |
2590 | if (n > 0 && (statp->_flags & RES_F_EDNS0ERR) == 0 && |
2591 | (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) { |
2592 | n = res_nopt(statp, n, buf, (int)sizeof(buf), anslen); |
2593 | rdata = &buf[n]; |
2594 | if (n > 0 && (statp->options & RES_NSID) != 0U) { |
2595 | n = res_nopt_rdata(statp, n, buf, |
2596 | (int)sizeof(buf), |
2597 | rdata, NS_OPT_NSID, 0, NULL); |
2598 | } |
2599 | } |
2600 | #endif |
2601 | if (n <= 0) { |
2602 | #ifdef DEBUG |
2603 | if (statp->options & RES_DEBUG) |
2604 | printf(";; res_nquery: mkquery failed\n" ); |
2605 | #endif |
2606 | h_errno = NO_RECOVERY; |
2607 | return n; |
2608 | } |
2609 | n = res_nsend(statp, buf, n, answer, anslen); |
2610 | if (n < 0) { |
2611 | #ifdef RES_USE_EDNS0 |
2612 | /* if the query choked with EDNS0, retry without EDNS0 */ |
2613 | if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U && |
2614 | ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) { |
2615 | statp->_flags |= RES_F_EDNS0ERR; |
2616 | if (statp->options & RES_DEBUG) |
2617 | printf(";; res_nquery: retry without EDNS0\n" ); |
2618 | goto again; |
2619 | } |
2620 | #endif |
2621 | #if 0 |
2622 | #ifdef DEBUG |
2623 | if (statp->options & RES_DEBUG) |
2624 | printf(";; res_query: send error\n" ); |
2625 | #endif |
2626 | h_errno = TRY_AGAIN; |
2627 | return n; |
2628 | #endif |
2629 | } |
2630 | |
2631 | if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { |
2632 | rcode = hp->rcode; /* record most recent error */ |
2633 | #ifdef DEBUG |
2634 | if (statp->options & RES_DEBUG) |
2635 | printf(";; rcode = (%s), counts = an:%d ns:%d ar:%d\n" , |
2636 | p_rcode(hp->rcode), |
2637 | ntohs(hp->ancount), |
2638 | ntohs(hp->nscount), |
2639 | ntohs(hp->arcount)); |
2640 | #endif |
2641 | continue; |
2642 | } |
2643 | |
2644 | ancount += ntohs(hp->ancount); |
2645 | |
2646 | t->n = n; |
2647 | } |
2648 | |
2649 | if (ancount == 0) { |
2650 | switch (rcode) { |
2651 | case NXDOMAIN: |
2652 | h_errno = HOST_NOT_FOUND; |
2653 | break; |
2654 | case SERVFAIL: |
2655 | h_errno = TRY_AGAIN; |
2656 | break; |
2657 | case NOERROR: |
2658 | h_errno = NO_DATA; |
2659 | break; |
2660 | case FORMERR: |
2661 | case NOTIMP: |
2662 | case REFUSED: |
2663 | default: |
2664 | h_errno = NO_RECOVERY; |
2665 | break; |
2666 | } |
2667 | return -1; |
2668 | } |
2669 | return ancount; |
2670 | } |
2671 | |
2672 | /* |
2673 | * Formulate a normal query, send, and retrieve answer in supplied buffer. |
2674 | * Return the size of the response on success, -1 on error. |
2675 | * If enabled, implement search rules until answer or unrecoverable failure |
2676 | * is detected. Error code, if any, is left in h_errno. |
2677 | */ |
2678 | static int |
2679 | res_searchN(const char *name, struct res_target *target, res_state res) |
2680 | { |
2681 | const char *cp, * const *domain; |
2682 | HEADER *hp; |
2683 | u_int dots; |
2684 | char buf[MAXHOSTNAMELEN]; |
2685 | int trailing_dot, ret, saved_herrno; |
2686 | int got_nodata = 0, got_servfail = 0, tried_as_is = 0; |
2687 | |
2688 | _DIAGASSERT(name != NULL); |
2689 | _DIAGASSERT(target != NULL); |
2690 | |
2691 | hp = (HEADER *)(void *)target->answer; /*XXX*/ |
2692 | |
2693 | errno = 0; |
2694 | h_errno = HOST_NOT_FOUND; /* default, if we never query */ |
2695 | dots = 0; |
2696 | for (cp = name; *cp; cp++) |
2697 | dots += (*cp == '.'); |
2698 | trailing_dot = 0; |
2699 | if (cp > name && *--cp == '.') |
2700 | trailing_dot++; |
2701 | |
2702 | /* |
2703 | * if there aren't any dots, it could be a user-level alias |
2704 | */ |
2705 | if (!dots && (cp = res_hostalias(res, name, buf, sizeof(buf))) != NULL) { |
2706 | ret = res_queryN(cp, target, res); |
2707 | return ret; |
2708 | } |
2709 | |
2710 | /* |
2711 | * If there are dots in the name already, let's just give it a try |
2712 | * 'as is'. The threshold can be set with the "ndots" option. |
2713 | */ |
2714 | saved_herrno = -1; |
2715 | if (dots >= res->ndots) { |
2716 | ret = res_querydomainN(name, NULL, target, res); |
2717 | if (ret > 0) |
2718 | return ret; |
2719 | saved_herrno = h_errno; |
2720 | tried_as_is++; |
2721 | } |
2722 | |
2723 | /* |
2724 | * We do at least one level of search if |
2725 | * - there is no dot and RES_DEFNAME is set, or |
2726 | * - there is at least one dot, there is no trailing dot, |
2727 | * and RES_DNSRCH is set. |
2728 | */ |
2729 | if ((!dots && (res->options & RES_DEFNAMES)) || |
2730 | (dots && !trailing_dot && (res->options & RES_DNSRCH))) { |
2731 | int done = 0; |
2732 | |
2733 | for (domain = (const char * const *)res->dnsrch; |
2734 | *domain && !done; |
2735 | domain++) { |
2736 | |
2737 | ret = res_querydomainN(name, *domain, target, res); |
2738 | if (ret > 0) |
2739 | return ret; |
2740 | |
2741 | /* |
2742 | * If no server present, give up. |
2743 | * If name isn't found in this domain, |
2744 | * keep trying higher domains in the search list |
2745 | * (if that's enabled). |
2746 | * On a NO_DATA error, keep trying, otherwise |
2747 | * a wildcard entry of another type could keep us |
2748 | * from finding this entry higher in the domain. |
2749 | * If we get some other error (negative answer or |
2750 | * server failure), then stop searching up, |
2751 | * but try the input name below in case it's |
2752 | * fully-qualified. |
2753 | */ |
2754 | if (errno == ECONNREFUSED) { |
2755 | h_errno = TRY_AGAIN; |
2756 | return -1; |
2757 | } |
2758 | |
2759 | switch (h_errno) { |
2760 | case NO_DATA: |
2761 | got_nodata++; |
2762 | /* FALLTHROUGH */ |
2763 | case HOST_NOT_FOUND: |
2764 | /* keep trying */ |
2765 | break; |
2766 | case TRY_AGAIN: |
2767 | if (hp->rcode == SERVFAIL) { |
2768 | /* try next search element, if any */ |
2769 | got_servfail++; |
2770 | break; |
2771 | } |
2772 | /* FALLTHROUGH */ |
2773 | default: |
2774 | /* anything else implies that we're done */ |
2775 | done++; |
2776 | } |
2777 | /* |
2778 | * if we got here for some reason other than DNSRCH, |
2779 | * we only wanted one iteration of the loop, so stop. |
2780 | */ |
2781 | if (!(res->options & RES_DNSRCH)) |
2782 | done++; |
2783 | } |
2784 | } |
2785 | |
2786 | /* |
2787 | * if we have not already tried the name "as is", do that now. |
2788 | * note that we do this regardless of how many dots were in the |
2789 | * name or whether it ends with a dot. |
2790 | */ |
2791 | if (!tried_as_is) { |
2792 | ret = res_querydomainN(name, NULL, target, res); |
2793 | if (ret > 0) |
2794 | return ret; |
2795 | } |
2796 | |
2797 | /* |
2798 | * if we got here, we didn't satisfy the search. |
2799 | * if we did an initial full query, return that query's h_errno |
2800 | * (note that we wouldn't be here if that query had succeeded). |
2801 | * else if we ever got a nodata, send that back as the reason. |
2802 | * else send back meaningless h_errno, that being the one from |
2803 | * the last DNSRCH we did. |
2804 | */ |
2805 | if (saved_herrno != -1) |
2806 | h_errno = saved_herrno; |
2807 | else if (got_nodata) |
2808 | h_errno = NO_DATA; |
2809 | else if (got_servfail) |
2810 | h_errno = TRY_AGAIN; |
2811 | return -1; |
2812 | } |
2813 | |
2814 | /* |
2815 | * Perform a call on res_query on the concatenation of name and domain, |
2816 | * removing a trailing dot from name if domain is NULL. |
2817 | */ |
2818 | static int |
2819 | res_querydomainN(const char *name, const char *domain, |
2820 | struct res_target *target, res_state res) |
2821 | { |
2822 | char nbuf[MAXDNAME]; |
2823 | const char *longname = nbuf; |
2824 | size_t n, d; |
2825 | |
2826 | _DIAGASSERT(name != NULL); |
2827 | /* XXX: target may be NULL??? */ |
2828 | |
2829 | #ifdef DEBUG |
2830 | if (res->options & RES_DEBUG) |
2831 | printf(";; res_querydomain(%s, %s)\n" , |
2832 | name, domain?domain:"<Nil>" ); |
2833 | #endif |
2834 | if (domain == NULL) { |
2835 | /* |
2836 | * Check for trailing '.'; |
2837 | * copy without '.' if present. |
2838 | */ |
2839 | n = strlen(name); |
2840 | if (n + 1 > sizeof(nbuf)) { |
2841 | h_errno = NO_RECOVERY; |
2842 | return -1; |
2843 | } |
2844 | if (n > 0 && name[--n] == '.') { |
2845 | strncpy(nbuf, name, n); |
2846 | nbuf[n] = '\0'; |
2847 | } else |
2848 | longname = name; |
2849 | } else { |
2850 | n = strlen(name); |
2851 | d = strlen(domain); |
2852 | if (n + 1 + d + 1 > sizeof(nbuf)) { |
2853 | h_errno = NO_RECOVERY; |
2854 | return -1; |
2855 | } |
2856 | snprintf(nbuf, sizeof(nbuf), "%s.%s" , name, domain); |
2857 | } |
2858 | return res_queryN(longname, target, res); |
2859 | } |
2860 | |
2861 | #ifdef TEST |
2862 | int |
2863 | main(int argc, char *argv[]) { |
2864 | struct addrinfo *ai, *sai; |
2865 | int i, e; |
2866 | char buf[1024]; |
2867 | |
2868 | for (i = 1; i < argc; i++) { |
2869 | if ((e = getaddrinfo(argv[i], NULL, NULL, &sai)) != 0) |
2870 | warnx("%s: %s" , argv[i], gai_strerror(e)); |
2871 | for (ai = sai; ai; ai = ai->ai_next) { |
2872 | sockaddr_snprintf(buf, sizeof(buf), "%a" , ai->ai_addr); |
2873 | printf("flags=0x%x family=%d socktype=%d protocol=%d " |
2874 | "addrlen=%zu addr=%s canonname=%s next=%p\n" , |
2875 | ai->ai_flags, |
2876 | ai->ai_family, |
2877 | ai->ai_socktype, |
2878 | ai->ai_protocol, |
2879 | (size_t)ai->ai_addrlen, |
2880 | buf, |
2881 | ai->ai_canonname, |
2882 | ai->ai_next); |
2883 | } |
2884 | if (sai) |
2885 | freeaddrinfo(sai); |
2886 | } |
2887 | return 0; |
2888 | } |
2889 | #endif |
2890 | |