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