getaddrinfo.c revision 1.108 1 /* $NetBSD: getaddrinfo.c,v 1.108 2015/09/10 11:33:27 christos 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.108 2015/09/10 11:33:27 christos 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 <net/if.h>
68 #include <netinet/in.h>
69 #include <arpa/inet.h>
70 #include <arpa/nameser.h>
71 #include <assert.h>
72 #include <ctype.h>
73 #include <errno.h>
74 #include <netdb.h>
75 #include <resolv.h>
76 #include <stddef.h>
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <string.h>
80 #include <unistd.h>
81 #include <ifaddrs.h>
82
83 #include <syslog.h>
84 #include <stdarg.h>
85 #include <nsswitch.h>
86
87 #ifdef YP
88 #include <rpc/rpc.h>
89 #include <rpcsvc/yp_prot.h>
90 #include <rpcsvc/ypclnt.h>
91 #endif
92
93 #include "servent.h"
94
95 #ifndef RUMP_ACTION
96 #ifdef __weak_alias
97 __weak_alias(getaddrinfo,_getaddrinfo)
98 __weak_alias(freeaddrinfo,_freeaddrinfo)
99 __weak_alias(gai_strerror,_gai_strerror)
100 #endif
101 #endif
102
103 #define SUCCESS 0
104 #define ANY 0
105 #define YES 1
106 #define NO 0
107
108 static const char in_addrany[] = { 0, 0, 0, 0 };
109 static const char in_loopback[] = { 127, 0, 0, 1 };
110 #ifdef INET6
111 static const char in6_addrany[] = {
112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
113 };
114 static const char in6_loopback[] = {
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
116 };
117 #endif
118
119 static const struct afd {
120 int a_af;
121 int a_addrlen;
122 int a_socklen;
123 int a_off;
124 const char *a_addrany;
125 const char *a_loopback;
126 int a_scoped;
127 } afdl [] = {
128 #ifdef INET6
129 {PF_INET6, sizeof(struct in6_addr),
130 sizeof(struct sockaddr_in6),
131 offsetof(struct sockaddr_in6, sin6_addr),
132 in6_addrany, in6_loopback, 1},
133 #endif
134 {PF_INET, sizeof(struct in_addr),
135 sizeof(struct sockaddr_in),
136 offsetof(struct sockaddr_in, sin_addr),
137 in_addrany, in_loopback, 0},
138 {0, 0, 0, 0, NULL, NULL, 0},
139 };
140
141 struct explore {
142 int e_af;
143 int e_socktype;
144 int e_protocol;
145 const char *e_protostr;
146 int e_wild;
147 #define WILD_AF(ex) ((ex)->e_wild & 0x01)
148 #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
149 #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
150 };
151
152 static const struct explore explore[] = {
153 #if 0
154 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
155 #endif
156 #ifdef INET6
157 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
158 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
159 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
160 #endif
161 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
162 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
163 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
164 { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
165 { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
166 { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
167 { -1, 0, 0, NULL, 0 },
168 };
169
170 #ifdef INET6
171 #define PTON_MAX 16
172 #else
173 #define PTON_MAX 4
174 #endif
175
176 static const ns_src default_dns_files[] = {
177 { NSSRC_FILES, NS_SUCCESS },
178 { NSSRC_DNS, NS_SUCCESS },
179 { 0, 0 }
180 };
181
182 #define MAXPACKET (64*1024)
183
184 typedef union {
185 HEADER hdr;
186 u_char buf[MAXPACKET];
187 } querybuf;
188
189 struct res_target {
190 struct res_target *next;
191 const char *name; /* domain name */
192 int qclass, qtype; /* class and type of query */
193 u_char *answer; /* buffer to put answer */
194 int anslen; /* size of answer buffer */
195 int n; /* result length */
196 };
197
198 struct srvinfo {
199 struct srvinfo *next;
200 char name[MAXDNAME];
201 int port, pri, weight;
202 };
203
204 static int gai_srvok(const char *);
205 static int str2number(const char *);
206 static int explore_fqdn(const struct addrinfo *, const char *,
207 const char *, struct addrinfo **, struct servent_data *);
208 static int explore_null(const struct addrinfo *,
209 const char *, struct addrinfo **, struct servent_data *);
210 static int explore_numeric(const struct addrinfo *, const char *,
211 const char *, struct addrinfo **, const char *, struct servent_data *);
212 static int explore_numeric_scope(const struct addrinfo *, const char *,
213 const char *, struct addrinfo **, struct servent_data *);
214 static int get_canonname(const struct addrinfo *,
215 struct addrinfo *, const char *);
216 static struct addrinfo *get_ai(const struct addrinfo *,
217 const struct afd *, const char *);
218 static int get_portmatch(const struct addrinfo *, const char *,
219 struct servent_data *);
220 static int get_port(const struct addrinfo *, const char *, int,
221 struct servent_data *);
222 static const struct afd *find_afd(int);
223 static int addrconfig(uint64_t *);
224 #ifdef INET6
225 static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *);
226 #endif
227
228 static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
229 const struct addrinfo *);
230 static void aisort(struct addrinfo *s, res_state res);
231 static struct addrinfo * _dns_query(struct res_target *,
232 const struct addrinfo *, res_state, int);
233 static struct addrinfo * _dns_srv_lookup(const char *, const char *,
234 const struct addrinfo *);
235 static struct addrinfo * _dns_host_lookup(const char *,
236 const struct addrinfo *);
237 static int _dns_getaddrinfo(void *, void *, va_list);
238 static void _sethtent(FILE **);
239 static void _endhtent(FILE **);
240 static struct addrinfo *_gethtent(FILE **, const char *,
241 const struct addrinfo *);
242 static int _files_getaddrinfo(void *, void *, va_list);
243 #ifdef YP
244 static struct addrinfo *_yphostent(char *, const struct addrinfo *);
245 static int _yp_getaddrinfo(void *, void *, va_list);
246 #endif
247
248 static int res_queryN(const char *, struct res_target *, res_state);
249 static int res_searchN(const char *, struct res_target *, res_state);
250 static int res_querydomainN(const char *, const char *,
251 struct res_target *, res_state);
252
253 static const char * const ai_errlist[] = {
254 "Success",
255 "Address family for hostname not supported", /* EAI_ADDRFAMILY */
256 "Temporary failure in name resolution", /* EAI_AGAIN */
257 "Invalid value for ai_flags", /* EAI_BADFLAGS */
258 "Non-recoverable failure in name resolution", /* EAI_FAIL */
259 "ai_family not supported", /* EAI_FAMILY */
260 "Memory allocation failure", /* EAI_MEMORY */
261 "No address associated with hostname", /* EAI_NODATA */
262 "hostname nor servname provided, or not known", /* EAI_NONAME */
263 "servname not supported for ai_socktype", /* EAI_SERVICE */
264 "ai_socktype not supported", /* EAI_SOCKTYPE */
265 "System error returned in errno", /* EAI_SYSTEM */
266 "Invalid value for hints", /* EAI_BADHINTS */
267 "Resolved protocol is unknown", /* EAI_PROTOCOL */
268 "Argument buffer overflow", /* EAI_OVERFLOW */
269 "Unknown error", /* EAI_MAX */
270 };
271
272 /* XXX macros that make external reference is BAD. */
273
274 #define GET_AI(ai, afd, addr) \
275 do { \
276 /* external reference: pai, error, and label free */ \
277 (ai) = get_ai(pai, (afd), (addr)); \
278 if ((ai) == NULL) { \
279 error = EAI_MEMORY; \
280 goto free; \
281 } \
282 } while (/*CONSTCOND*/0)
283
284 #define GET_PORT(ai, serv, svd) \
285 do { \
286 /* external reference: error and label free */ \
287 error = get_port((ai), (serv), 0, (svd)); \
288 if (error != 0) \
289 goto free; \
290 } while (/*CONSTCOND*/0)
291
292 #define GET_CANONNAME(ai, str) \
293 do { \
294 /* external reference: pai, error and label free */ \
295 error = get_canonname(pai, (ai), (str)); \
296 if (error != 0) \
297 goto free; \
298 } while (/*CONSTCOND*/0)
299
300 #define ERR(err) \
301 do { \
302 /* external reference: error, and label bad */ \
303 error = (err); \
304 goto bad; \
305 /*NOTREACHED*/ \
306 } while (/*CONSTCOND*/0)
307
308 #define MATCH_FAMILY(x, y, w) \
309 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || \
310 (y) == PF_UNSPEC)))
311 #define MATCH(x, y, w) \
312 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
313
314 const char *
315 gai_strerror(int ecode)
316 {
317 if (ecode < 0 || ecode > EAI_MAX)
318 ecode = EAI_MAX;
319 return ai_errlist[ecode];
320 }
321
322 void
323 freeaddrinfo(struct addrinfo *ai)
324 {
325 struct addrinfo *next;
326
327 _DIAGASSERT(ai != NULL);
328
329 do {
330 next = ai->ai_next;
331 if (ai->ai_canonname)
332 free(ai->ai_canonname);
333 /* no need to free(ai->ai_addr) */
334 free(ai);
335 ai = next;
336 } while (ai);
337 }
338
339 /*
340 * We don't want localization to affect us
341 */
342 #define PERIOD '.'
343 #define hyphenchar(c) ((c) == '-')
344 #define periodchar(c) ((c) == PERIOD)
345 #define underschar(c) ((c) == '_')
346 #define alphachar(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
347 #define digitchar(c) ((c) >= '0' && (c) <= '9')
348
349 #define firstchar(c) (alphachar(c) || digitchar(c) || underschar(c))
350 #define lastchar(c) (alphachar(c) || digitchar(c))
351 #define middlechar(c) (lastchar(c) || hyphenchar(c))
352
353 static int
354 gai_srvok(const char *dn)
355 {
356 int nch, pch, ch;
357
358 for (pch = PERIOD, nch = ch = *dn++; ch != '\0'; pch = ch, ch = nch) {
359 if (periodchar(ch))
360 continue;
361 if (periodchar(pch)) {
362 if (!firstchar(ch))
363 return 0;
364 } else if (periodchar(nch) || nch == '\0') {
365 if (!lastchar(ch))
366 return 0;
367 } else if (!middlechar(ch))
368 return 0;
369 }
370 return 1;
371 }
372
373 static in_port_t *
374 getport(struct addrinfo *ai) {
375 static in_port_t p;
376
377 switch (ai->ai_family) {
378 case AF_INET:
379 return &((struct sockaddr_in *)(void *)ai->ai_addr)->sin_port;
380 #ifdef INET6
381 case AF_INET6:
382 return &((struct sockaddr_in6 *)(void *)ai->ai_addr)->sin6_port;
383 #endif
384 default:
385 p = 0;
386 /* XXX: abort()? */
387 return &p;
388 }
389 }
390
391 static int
392 str2number(const char *p)
393 {
394 char *ep;
395 unsigned long v;
396
397 _DIAGASSERT(p != NULL);
398
399 if (*p == '\0')
400 return -1;
401 ep = NULL;
402 errno = 0;
403 v = strtoul(p, &ep, 10);
404 if (errno == 0 && ep && *ep == '\0' && v <= INT_MAX)
405 return (int)v;
406 else
407 return -1;
408 }
409
410 int
411 getaddrinfo(const char *hostname, const char *servname,
412 const struct addrinfo *hints, struct addrinfo **res)
413 {
414 struct addrinfo sentinel;
415 struct addrinfo *cur;
416 int error = 0;
417 struct addrinfo ai;
418 struct addrinfo ai0;
419 struct addrinfo *pai;
420 const struct explore *ex;
421 struct servent_data svd;
422 uint64_t mask = (uint64_t)~0ULL;
423
424 /* hostname is allowed to be NULL */
425 /* servname is allowed to be NULL */
426 /* hints is allowed to be NULL */
427 _DIAGASSERT(res != NULL);
428
429 (void)memset(&svd, 0, sizeof(svd));
430 memset(&sentinel, 0, sizeof(sentinel));
431 cur = &sentinel;
432 memset(&ai, 0, sizeof(ai));
433 pai = &ai;
434 pai->ai_flags = 0;
435 pai->ai_family = PF_UNSPEC;
436 pai->ai_socktype = ANY;
437 pai->ai_protocol = ANY;
438 pai->ai_addrlen = 0;
439 pai->ai_canonname = NULL;
440 pai->ai_addr = NULL;
441 pai->ai_next = NULL;
442
443 if (hostname == NULL && servname == NULL)
444 return EAI_NONAME;
445 if (hints) {
446 /* error check for hints */
447 if (hints->ai_addrlen || hints->ai_canonname ||
448 hints->ai_addr || hints->ai_next)
449 ERR(EAI_BADHINTS); /* xxx */
450 if (hints->ai_flags & ~AI_MASK)
451 ERR(EAI_BADFLAGS);
452 switch (hints->ai_family) {
453 case PF_UNSPEC:
454 case PF_INET:
455 #ifdef INET6
456 case PF_INET6:
457 #endif
458 break;
459 default:
460 ERR(EAI_FAMILY);
461 }
462 memcpy(pai, hints, sizeof(*pai));
463
464 /*
465 * if both socktype/protocol are specified, check if they
466 * are meaningful combination.
467 */
468 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
469 for (ex = explore; ex->e_af >= 0; ex++) {
470 if (pai->ai_family != ex->e_af)
471 continue;
472 if (ex->e_socktype == ANY)
473 continue;
474 if (ex->e_protocol == ANY)
475 continue;
476 if (pai->ai_socktype == ex->e_socktype
477 && pai->ai_protocol != ex->e_protocol) {
478 ERR(EAI_BADHINTS);
479 }
480 }
481 }
482 }
483
484 if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && addrconfig(&mask) == -1)
485 ERR(EAI_FAIL);
486
487 /*
488 * check for special cases. (1) numeric servname is disallowed if
489 * socktype/protocol are left unspecified. (2) servname is disallowed
490 * for raw and other inet{,6} sockets.
491 */
492 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
493 #ifdef PF_INET6
494 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
495 #endif
496 ) {
497 ai0 = *pai; /* backup *pai */
498
499 if (pai->ai_family == PF_UNSPEC) {
500 #ifdef PF_INET6
501 pai->ai_family = PF_INET6;
502 #else
503 pai->ai_family = PF_INET;
504 #endif
505 }
506 error = get_portmatch(pai, servname, &svd);
507 if (error)
508 goto bad;
509
510 *pai = ai0;
511 }
512
513 ai0 = *pai;
514
515 /* NULL hostname, or numeric hostname */
516 for (ex = explore; ex->e_af >= 0; ex++) {
517 *pai = ai0;
518
519 /* ADDRCONFIG check */
520 if ((((uint64_t)1 << ex->e_af) & mask) == 0)
521 continue;
522
523 /* PF_UNSPEC entries are prepared for DNS queries only */
524 if (ex->e_af == PF_UNSPEC)
525 continue;
526
527 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
528 continue;
529 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
530 continue;
531 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
532 continue;
533 if (pai->ai_family == PF_UNSPEC)
534 pai->ai_family = ex->e_af;
535 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
536 pai->ai_socktype = ex->e_socktype;
537 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
538 pai->ai_protocol = ex->e_protocol;
539
540 if (hostname == NULL)
541 error = explore_null(pai, servname, &cur->ai_next,
542 &svd);
543 else
544 error = explore_numeric_scope(pai, hostname, servname,
545 &cur->ai_next, &svd);
546
547 if (error)
548 goto free;
549
550 while (cur->ai_next)
551 cur = cur->ai_next;
552 }
553
554 /*
555 * XXX
556 * If numeric representation of AF1 can be interpreted as FQDN
557 * representation of AF2, we need to think again about the code below.
558 */
559 if (sentinel.ai_next)
560 goto good;
561
562 if (hostname == NULL)
563 ERR(EAI_NODATA);
564 if (pai->ai_flags & AI_NUMERICHOST)
565 ERR(EAI_NONAME);
566
567 /*
568 * hostname as alphabetical name.
569 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
570 * outer loop by AFs.
571 */
572 for (ex = explore; ex->e_af >= 0; ex++) {
573 *pai = ai0;
574
575
576 /* ADDRCONFIG check */
577 /* PF_UNSPEC entries are prepared for DNS queries only */
578 if (ex->e_af != PF_UNSPEC &&
579 (((uint64_t)1 << ex->e_af) & mask) == 0)
580 continue;
581
582 /* require exact match for family field */
583 if (pai->ai_family != ex->e_af)
584 continue;
585
586 if (!MATCH(pai->ai_socktype, ex->e_socktype,
587 WILD_SOCKTYPE(ex))) {
588 continue;
589 }
590 if (!MATCH(pai->ai_protocol, ex->e_protocol,
591 WILD_PROTOCOL(ex))) {
592 continue;
593 }
594
595 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
596 pai->ai_socktype = ex->e_socktype;
597 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
598 pai->ai_protocol = ex->e_protocol;
599
600 error = explore_fqdn(pai, hostname, servname, &cur->ai_next,
601 &svd);
602
603 while (cur && cur->ai_next)
604 cur = cur->ai_next;
605 }
606
607 /* XXX */
608 if (sentinel.ai_next)
609 error = 0;
610
611 if (error)
612 goto free;
613
614 if (sentinel.ai_next) {
615 good:
616 endservent_r(&svd);
617 *res = sentinel.ai_next;
618 return SUCCESS;
619 } else
620 error = EAI_FAIL;
621 free:
622 bad:
623 endservent_r(&svd);
624 if (sentinel.ai_next)
625 freeaddrinfo(sentinel.ai_next);
626 *res = NULL;
627 return error;
628 }
629
630 /*
631 * FQDN hostname, DNS lookup
632 */
633 static int
634 explore_fqdn(const struct addrinfo *pai, const char *hostname,
635 const char *servname, struct addrinfo **res, struct servent_data *svd)
636 {
637 struct addrinfo *result;
638 struct addrinfo *cur;
639 int error = 0;
640 static const ns_dtab dtab[] = {
641 NS_FILES_CB(_files_getaddrinfo, NULL)
642 { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */
643 NS_NIS_CB(_yp_getaddrinfo, NULL)
644 NS_NULL_CB
645 };
646
647 _DIAGASSERT(pai != NULL);
648 /* hostname may be NULL */
649 /* servname may be NULL */
650 _DIAGASSERT(res != NULL);
651
652 result = NULL;
653
654 /*
655 * if the servname does not match socktype/protocol, ignore it.
656 */
657 if (get_portmatch(pai, servname, svd) != 0)
658 return 0;
659
660 switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
661 default_dns_files, hostname, pai, servname)) {
662 case NS_TRYAGAIN:
663 error = EAI_AGAIN;
664 goto free;
665 case NS_UNAVAIL:
666 error = EAI_FAIL;
667 goto free;
668 case NS_NOTFOUND:
669 error = EAI_NODATA;
670 goto free;
671 case NS_SUCCESS:
672 error = 0;
673 for (cur = result; cur; cur = cur->ai_next) {
674 /* Check for already filled port. */
675 if (*getport(cur))
676 continue;
677 GET_PORT(cur, servname, svd);
678 /* canonname should be filled already */
679 }
680 break;
681 }
682
683 *res = result;
684
685 return 0;
686
687 free:
688 if (result)
689 freeaddrinfo(result);
690 return error;
691 }
692
693 /*
694 * hostname == NULL.
695 * passive socket -> anyaddr (0.0.0.0 or ::)
696 * non-passive socket -> localhost (127.0.0.1 or ::1)
697 */
698 static int
699 explore_null(const struct addrinfo *pai, const char *servname,
700 struct addrinfo **res, struct servent_data *svd)
701 {
702 int s;
703 const struct afd *afd;
704 struct addrinfo *cur;
705 struct addrinfo sentinel;
706 int error;
707
708 _DIAGASSERT(pai != NULL);
709 /* servname may be NULL */
710 _DIAGASSERT(res != NULL);
711
712 *res = NULL;
713 sentinel.ai_next = NULL;
714 cur = &sentinel;
715
716 /*
717 * filter out AFs that are not supported by the kernel
718 * XXX errno?
719 */
720 s = socket(pai->ai_family, SOCK_DGRAM, 0);
721 if (s < 0) {
722 if (errno != EMFILE)
723 return 0;
724 } else
725 close(s);
726
727 /*
728 * if the servname does not match socktype/protocol, ignore it.
729 */
730 if (get_portmatch(pai, servname, svd) != 0)
731 return 0;
732
733 afd = find_afd(pai->ai_family);
734 if (afd == NULL)
735 return 0;
736
737 if (pai->ai_flags & AI_PASSIVE) {
738 GET_AI(cur->ai_next, afd, afd->a_addrany);
739 /* xxx meaningless?
740 * GET_CANONNAME(cur->ai_next, "anyaddr");
741 */
742 GET_PORT(cur->ai_next, servname, svd);
743 } else {
744 GET_AI(cur->ai_next, afd, afd->a_loopback);
745 /* xxx meaningless?
746 * GET_CANONNAME(cur->ai_next, "localhost");
747 */
748 GET_PORT(cur->ai_next, servname, svd);
749 }
750 cur = cur->ai_next;
751
752 *res = sentinel.ai_next;
753 return 0;
754
755 free:
756 if (sentinel.ai_next)
757 freeaddrinfo(sentinel.ai_next);
758 return error;
759 }
760
761 /*
762 * numeric hostname
763 */
764 static int
765 explore_numeric(const struct addrinfo *pai, const char *hostname,
766 const char *servname, struct addrinfo **res, const char *canonname,
767 struct servent_data *svd)
768 {
769 const struct afd *afd;
770 struct addrinfo *cur;
771 struct addrinfo sentinel;
772 int error;
773 char pton[PTON_MAX];
774
775 _DIAGASSERT(pai != NULL);
776 /* hostname may be NULL */
777 /* servname may be NULL */
778 _DIAGASSERT(res != NULL);
779
780 *res = NULL;
781 sentinel.ai_next = NULL;
782 cur = &sentinel;
783
784 /*
785 * if the servname does not match socktype/protocol, ignore it.
786 */
787 if (get_portmatch(pai, servname, svd) != 0)
788 return 0;
789
790 afd = find_afd(pai->ai_family);
791 if (afd == NULL)
792 return 0;
793
794 switch (afd->a_af) {
795 #if 0 /*X/Open spec*/
796 case AF_INET:
797 if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
798 if (pai->ai_family == afd->a_af ||
799 pai->ai_family == PF_UNSPEC /*?*/) {
800 GET_AI(cur->ai_next, afd, pton);
801 GET_PORT(cur->ai_next, servname, svd);
802 if ((pai->ai_flags & AI_CANONNAME)) {
803 /*
804 * Set the numeric address itself as
805 * the canonical name, based on a
806 * clarification in rfc2553bis-03.
807 */
808 GET_CANONNAME(cur->ai_next, canonname);
809 }
810 while (cur && cur->ai_next)
811 cur = cur->ai_next;
812 } else
813 ERR(EAI_FAMILY); /*xxx*/
814 }
815 break;
816 #endif
817 default:
818 if (inet_pton(afd->a_af, hostname, pton) == 1) {
819 if (pai->ai_family == afd->a_af ||
820 pai->ai_family == PF_UNSPEC /*?*/) {
821 GET_AI(cur->ai_next, afd, pton);
822 GET_PORT(cur->ai_next, servname, svd);
823 if ((pai->ai_flags & AI_CANONNAME)) {
824 /*
825 * Set the numeric address itself as
826 * the canonical name, based on a
827 * clarification in rfc2553bis-03.
828 */
829 GET_CANONNAME(cur->ai_next, canonname);
830 }
831 while (cur->ai_next)
832 cur = cur->ai_next;
833 } else
834 ERR(EAI_FAMILY); /*xxx*/
835 }
836 break;
837 }
838
839 *res = sentinel.ai_next;
840 return 0;
841
842 free:
843 bad:
844 if (sentinel.ai_next)
845 freeaddrinfo(sentinel.ai_next);
846 return error;
847 }
848
849 /*
850 * numeric hostname with scope
851 */
852 static int
853 explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
854 const char *servname, struct addrinfo **res, struct servent_data *svd)
855 {
856 #if !defined(SCOPE_DELIMITER) || !defined(INET6)
857 return explore_numeric(pai, hostname, servname, res, hostname, svd);
858 #else
859 const struct afd *afd;
860 struct addrinfo *cur;
861 int error;
862 char *cp, *hostname2 = NULL, *scope, *addr;
863 struct sockaddr_in6 *sin6;
864
865 _DIAGASSERT(pai != NULL);
866 /* hostname may be NULL */
867 /* servname may be NULL */
868 _DIAGASSERT(res != NULL);
869
870 /*
871 * if the servname does not match socktype/protocol, ignore it.
872 */
873 if (get_portmatch(pai, servname, svd) != 0)
874 return 0;
875
876 afd = find_afd(pai->ai_family);
877 if (afd == NULL)
878 return 0;
879
880 if (!afd->a_scoped)
881 return explore_numeric(pai, hostname, servname, res, hostname,
882 svd);
883
884 cp = strchr(hostname, SCOPE_DELIMITER);
885 if (cp == NULL)
886 return explore_numeric(pai, hostname, servname, res, hostname,
887 svd);
888
889 /*
890 * Handle special case of <scoped_address><delimiter><scope id>
891 */
892 hostname2 = strdup(hostname);
893 if (hostname2 == NULL)
894 return EAI_MEMORY;
895 /* terminate at the delimiter */
896 hostname2[cp - hostname] = '\0';
897 addr = hostname2;
898 scope = cp + 1;
899
900 error = explore_numeric(pai, addr, servname, res, hostname, svd);
901 if (error == 0) {
902 u_int32_t scopeid;
903
904 for (cur = *res; cur; cur = cur->ai_next) {
905 if (cur->ai_family != AF_INET6)
906 continue;
907 sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
908 if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
909 free(hostname2);
910 return(EAI_NODATA); /* XXX: is return OK? */
911 }
912 sin6->sin6_scope_id = scopeid;
913 }
914 }
915
916 free(hostname2);
917
918 return error;
919 #endif
920 }
921
922 static int
923 get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str)
924 {
925
926 _DIAGASSERT(pai != NULL);
927 _DIAGASSERT(ai != NULL);
928 _DIAGASSERT(str != NULL);
929
930 if ((pai->ai_flags & AI_CANONNAME) != 0) {
931 ai->ai_canonname = strdup(str);
932 if (ai->ai_canonname == NULL)
933 return EAI_MEMORY;
934 }
935 return 0;
936 }
937
938 static struct addrinfo *
939 allocaddrinfo(socklen_t addrlen)
940 {
941 struct addrinfo *ai;
942
943 ai = calloc(sizeof(struct addrinfo) + addrlen, 1);
944 if (ai) {
945 ai->ai_addr = (void *)(ai+1);
946 ai->ai_addrlen = ai->ai_addr->sa_len = addrlen;
947 }
948
949 return ai;
950 }
951
952 static struct addrinfo *
953 get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
954 {
955 char *p;
956 struct addrinfo *ai;
957 struct sockaddr *save;
958
959 _DIAGASSERT(pai != NULL);
960 _DIAGASSERT(afd != NULL);
961 _DIAGASSERT(addr != NULL);
962
963 ai = allocaddrinfo((socklen_t)afd->a_socklen);
964 if (ai == NULL)
965 return NULL;
966
967 save = ai->ai_addr;
968 memcpy(ai, pai, sizeof(struct addrinfo));
969
970 /* since we just overwrote all of ai, we have
971 to restore ai_addr and ai_addrlen */
972 ai->ai_addr = save;
973 ai->ai_addrlen = (socklen_t)afd->a_socklen;
974
975 ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
976 p = (char *)(void *)(ai->ai_addr);
977 memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
978 return ai;
979 }
980
981 static int
982 get_portmatch(const struct addrinfo *ai, const char *servname,
983 struct servent_data *svd)
984 {
985
986 _DIAGASSERT(ai != NULL);
987 /* servname may be NULL */
988
989 return get_port(ai, servname, 1, svd);
990 }
991
992 static int
993 get_port(const struct addrinfo *ai, const char *servname, int matchonly,
994 struct servent_data *svd)
995 {
996 const char *proto;
997 struct servent *sp;
998 int port;
999 int allownumeric;
1000
1001 _DIAGASSERT(ai != NULL);
1002 /* servname may be NULL */
1003
1004 if (servname == NULL)
1005 return 0;
1006 switch (ai->ai_family) {
1007 case AF_INET:
1008 #ifdef AF_INET6
1009 case AF_INET6:
1010 #endif
1011 break;
1012 default:
1013 return 0;
1014 }
1015
1016 switch (ai->ai_socktype) {
1017 case SOCK_RAW:
1018 return EAI_SERVICE;
1019 case SOCK_DGRAM:
1020 case SOCK_STREAM:
1021 allownumeric = 1;
1022 break;
1023 case ANY:
1024 /*
1025 * This was 0. It is now 1 so that queries specifying
1026 * a NULL hint, or hint without socktype (but, hopefully,
1027 * with protocol) and numeric address actually work.
1028 */
1029 allownumeric = 1;
1030 break;
1031 default:
1032 return EAI_SOCKTYPE;
1033 }
1034
1035 port = str2number(servname);
1036 if (port >= 0) {
1037 if (!allownumeric)
1038 return EAI_SERVICE;
1039 if (port < 0 || port > 65535)
1040 return EAI_SERVICE;
1041 port = htons(port);
1042 } else {
1043 struct servent sv;
1044 if (ai->ai_flags & AI_NUMERICSERV)
1045 return EAI_NONAME;
1046
1047 switch (ai->ai_socktype) {
1048 case SOCK_DGRAM:
1049 proto = "udp";
1050 break;
1051 case SOCK_STREAM:
1052 proto = "tcp";
1053 break;
1054 default:
1055 proto = NULL;
1056 break;
1057 }
1058
1059 sp = getservbyname_r(servname, proto, &sv, svd);
1060 if (sp == NULL)
1061 return EAI_SERVICE;
1062 port = sp->s_port;
1063 }
1064
1065 if (!matchonly)
1066 *getport(__UNCONST(ai)) = port;
1067 return 0;
1068 }
1069
1070 static const struct afd *
1071 find_afd(int af)
1072 {
1073 const struct afd *afd;
1074
1075 if (af == PF_UNSPEC)
1076 return NULL;
1077 for (afd = afdl; afd->a_af; afd++) {
1078 if (afd->a_af == af)
1079 return afd;
1080 }
1081 return NULL;
1082 }
1083
1084 /*
1085 * AI_ADDRCONFIG check: Build a mask containing a bit set for each address
1086 * family configured in the system.
1087 *
1088 */
1089 static int
1090 addrconfig(uint64_t *mask)
1091 {
1092 struct ifaddrs *ifaddrs, *ifa;
1093
1094 if (getifaddrs(&ifaddrs) == -1)
1095 return -1;
1096
1097 *mask = 0;
1098 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
1099 if (ifa->ifa_addr && (ifa->ifa_flags & IFF_UP)) {
1100 _DIAGASSERT(ifa->ifa_addr->sa_family < 64);
1101 *mask |= (uint64_t)1 << ifa->ifa_addr->sa_family;
1102 }
1103
1104 freeifaddrs(ifaddrs);
1105 return 0;
1106 }
1107
1108 #ifdef INET6
1109 /* convert a string to a scope identifier. XXX: IPv6 specific */
1110 static int
1111 ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid)
1112 {
1113 u_long lscopeid;
1114 struct in6_addr *a6;
1115 char *ep;
1116
1117 _DIAGASSERT(scope != NULL);
1118 _DIAGASSERT(sin6 != NULL);
1119 _DIAGASSERT(scopeid != NULL);
1120
1121 a6 = &sin6->sin6_addr;
1122
1123 /* empty scopeid portion is invalid */
1124 if (*scope == '\0')
1125 return -1;
1126
1127 if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
1128 /*
1129 * We currently assume a one-to-one mapping between links
1130 * and interfaces, so we simply use interface indices for
1131 * like-local scopes.
1132 */
1133 *scopeid = if_nametoindex(scope);
1134 if (*scopeid == 0)
1135 goto trynumeric;
1136 return 0;
1137 }
1138
1139 /* still unclear about literal, allow numeric only - placeholder */
1140 if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
1141 goto trynumeric;
1142 if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
1143 goto trynumeric;
1144 else
1145 goto trynumeric; /* global */
1146
1147 /* try to convert to a numeric id as a last resort */
1148 trynumeric:
1149 errno = 0;
1150 lscopeid = strtoul(scope, &ep, 10);
1151 *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL);
1152 if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid)
1153 return 0;
1154 else
1155 return -1;
1156 }
1157 #endif
1158
1159 /* code duplicate with gethnamaddr.c */
1160
1161 static const char AskedForGot[] =
1162 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
1163
1164 static struct addrinfo *
1165 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
1166 const struct addrinfo *pai)
1167 {
1168 struct addrinfo sentinel, *cur;
1169 struct addrinfo ai, *aip;
1170 const struct afd *afd;
1171 char *canonname;
1172 const HEADER *hp;
1173 const u_char *cp;
1174 int n;
1175 const u_char *eom;
1176 char *bp, *ep;
1177 int type, class, ancount, qdcount;
1178 int haveanswer, had_error;
1179 char tbuf[MAXDNAME];
1180 int (*name_ok) (const char *);
1181 char hostbuf[8*1024];
1182 int port, pri, weight;
1183 struct srvinfo *srvlist, *srv, *csrv;
1184
1185 _DIAGASSERT(answer != NULL);
1186 _DIAGASSERT(qname != NULL);
1187 _DIAGASSERT(pai != NULL);
1188
1189 memset(&sentinel, 0, sizeof(sentinel));
1190 cur = &sentinel;
1191
1192 canonname = NULL;
1193 eom = answer->buf + anslen;
1194 switch (qtype) {
1195 case T_A:
1196 case T_AAAA:
1197 case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/
1198 name_ok = res_hnok;
1199 break;
1200 case T_SRV:
1201 name_ok = gai_srvok;
1202 break;
1203 default:
1204 return NULL; /* XXX should be abort(); */
1205 }
1206 /*
1207 * find first satisfactory answer
1208 */
1209 hp = &answer->hdr;
1210 ancount = ntohs(hp->ancount);
1211 qdcount = ntohs(hp->qdcount);
1212 bp = hostbuf;
1213 ep = hostbuf + sizeof hostbuf;
1214 cp = answer->buf + HFIXEDSZ;
1215 if (qdcount != 1) {
1216 h_errno = NO_RECOVERY;
1217 return (NULL);
1218 }
1219 n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
1220 if ((n < 0) || !(*name_ok)(bp)) {
1221 h_errno = NO_RECOVERY;
1222 return (NULL);
1223 }
1224 cp += n + QFIXEDSZ;
1225 if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
1226 /* res_send() has already verified that the query name is the
1227 * same as the one we sent; this just gets the expanded name
1228 * (i.e., with the succeeding search-domain tacked on).
1229 */
1230 n = (int)strlen(bp) + 1; /* for the \0 */
1231 if (n >= MAXHOSTNAMELEN) {
1232 h_errno = NO_RECOVERY;
1233 return (NULL);
1234 }
1235 canonname = bp;
1236 bp += n;
1237 /* The qname can be abbreviated, but h_name is now absolute. */
1238 qname = canonname;
1239 }
1240 haveanswer = 0;
1241 had_error = 0;
1242 srvlist = NULL;
1243 while (ancount-- > 0 && cp < eom && !had_error) {
1244 n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
1245 if ((n < 0) || !(*name_ok)(bp)) {
1246 had_error++;
1247 continue;
1248 }
1249 cp += n; /* name */
1250 type = _getshort(cp);
1251 cp += INT16SZ; /* type */
1252 class = _getshort(cp);
1253 cp += INT16SZ + INT32SZ; /* class, TTL */
1254 n = _getshort(cp);
1255 cp += INT16SZ; /* len */
1256 if (class != C_IN) {
1257 /* XXX - debug? syslog? */
1258 cp += n;
1259 continue; /* XXX - had_error++ ? */
1260 }
1261 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
1262 type == T_CNAME) {
1263 n = dn_expand(answer->buf, eom, cp, tbuf, (int)sizeof tbuf);
1264 if ((n < 0) || !(*name_ok)(tbuf)) {
1265 had_error++;
1266 continue;
1267 }
1268 cp += n;
1269 /* Get canonical name. */
1270 n = (int)strlen(tbuf) + 1; /* for the \0 */
1271 if (n > ep - bp || n >= MAXHOSTNAMELEN) {
1272 had_error++;
1273 continue;
1274 }
1275 strlcpy(bp, tbuf, (size_t)(ep - bp));
1276 canonname = bp;
1277 bp += n;
1278 continue;
1279 }
1280 if (qtype == T_ANY) {
1281 if (!(type == T_A || type == T_AAAA)) {
1282 cp += n;
1283 continue;
1284 }
1285 } else if (type != qtype) {
1286 if (type != T_KEY && type != T_SIG) {
1287 struct syslog_data sd = SYSLOG_DATA_INIT;
1288 syslog_r(LOG_NOTICE|LOG_AUTH, &sd,
1289 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
1290 qname, p_class(C_IN), p_type(qtype),
1291 p_type(type));
1292 }
1293 cp += n;
1294 continue; /* XXX - had_error++ ? */
1295 }
1296 switch (type) {
1297 case T_A:
1298 case T_AAAA:
1299 if (strcasecmp(canonname, bp) != 0) {
1300 struct syslog_data sd = SYSLOG_DATA_INIT;
1301 syslog_r(LOG_NOTICE|LOG_AUTH, &sd,
1302 AskedForGot, canonname, bp);
1303 cp += n;
1304 continue; /* XXX - had_error++ ? */
1305 }
1306 if (type == T_A && n != INADDRSZ) {
1307 cp += n;
1308 continue;
1309 }
1310 if (type == T_AAAA && n != IN6ADDRSZ) {
1311 cp += n;
1312 continue;
1313 }
1314 if (type == T_AAAA) {
1315 struct in6_addr in6;
1316 memcpy(&in6, cp, IN6ADDRSZ);
1317 if (IN6_IS_ADDR_V4MAPPED(&in6)) {
1318 cp += n;
1319 continue;
1320 }
1321 }
1322 if (!haveanswer) {
1323 int nn;
1324
1325 canonname = bp;
1326 nn = (int)strlen(bp) + 1; /* for the \0 */
1327 bp += nn;
1328 }
1329
1330 /* don't overwrite pai */
1331 ai = *pai;
1332 ai.ai_family = (type == T_A) ? AF_INET : AF_INET6;
1333 afd = find_afd(ai.ai_family);
1334 if (afd == NULL) {
1335 cp += n;
1336 continue;
1337 }
1338 cur->ai_next = get_ai(&ai, afd, (const char *)cp);
1339 if (cur->ai_next == NULL)
1340 had_error++;
1341 while (cur && cur->ai_next)
1342 cur = cur->ai_next;
1343 cp += n;
1344 break;
1345 case T_SRV:
1346 /* Add to SRV list. Insertion sort on priority. */
1347 pri = _getshort(cp);
1348 cp += INT16SZ;
1349 weight = _getshort(cp);
1350 cp += INT16SZ;
1351 port = _getshort(cp);
1352 cp += INT16SZ;
1353 n = dn_expand(answer->buf, eom, cp, tbuf,
1354 (int)sizeof(tbuf));
1355 if ((n < 0) || !res_hnok(tbuf)) {
1356 had_error++;
1357 continue;
1358 }
1359 cp += n;
1360 if (strlen(tbuf) + 1 >= MAXDNAME) {
1361 had_error++;
1362 continue;
1363 }
1364 srv = malloc(sizeof(*srv));
1365 if (!srv) {
1366 had_error++;
1367 continue;
1368 }
1369 strlcpy(srv->name, tbuf, sizeof(srv->name));
1370 srv->pri = pri;
1371 srv->weight = weight;
1372 srv->port = port;
1373 /* Weight 0 is sorted before other weights. */
1374 if (!srvlist
1375 || srv->pri < srvlist->pri
1376 || (srv->pri == srvlist->pri &&
1377 (!srv->weight || srvlist->weight))) {
1378 srv->next = srvlist;
1379 srvlist = srv;
1380 } else {
1381 for (csrv = srvlist;
1382 csrv->next && csrv->next->pri <= srv->pri;
1383 csrv = csrv->next) {
1384 if (csrv->next->pri == srv->pri
1385 && (!srv->weight ||
1386 csrv->next->weight))
1387 break;
1388 }
1389 srv->next = csrv->next;
1390 csrv->next = srv;
1391 }
1392 continue; /* Don't add to haveanswer yet. */
1393 default:
1394 abort();
1395 }
1396 if (!had_error)
1397 haveanswer++;
1398 }
1399
1400 if (srvlist) {
1401 res_state res;
1402 /*
1403 * Check for explicit rejection.
1404 */
1405 if (!srvlist->next && !srvlist->name[0]) {
1406 free(srvlist);
1407 h_errno = HOST_NOT_FOUND;
1408 return NULL;
1409 }
1410 res = __res_get_state();
1411 if (res == NULL) {
1412 while (srvlist != NULL) {
1413 srv = srvlist;
1414 srvlist = srvlist->next;
1415 free(srv);
1416 }
1417 h_errno = NETDB_INTERNAL;
1418 return NULL;
1419 }
1420
1421 while (srvlist) {
1422 struct res_target q, q2;
1423
1424 srv = srvlist;
1425 srvlist = srvlist->next;
1426
1427 /*
1428 * Since res_* doesn't give the additional
1429 * section, we always look up.
1430 */
1431 memset(&q, 0, sizeof(q));
1432 memset(&q2, 0, sizeof(q2));
1433
1434 q.name = srv->name;
1435 q.qclass = C_IN;
1436 q.qtype = T_AAAA;
1437 q.next = &q2;
1438 q2.name = srv->name;
1439 q2.qclass = C_IN;
1440 q2.qtype = T_A;
1441
1442 aip = _dns_query(&q, pai, res, 0);
1443
1444 if (aip != NULL) {
1445 cur->ai_next = aip;
1446 while (cur && cur->ai_next) {
1447 cur = cur->ai_next;
1448 *getport(cur) = htons(srv->port);
1449 haveanswer++;
1450 }
1451 }
1452 free(srv);
1453 }
1454 __res_put_state(res);
1455 }
1456 if (haveanswer) {
1457 if (!sentinel.ai_next->ai_canonname)
1458 (void)get_canonname(pai, sentinel.ai_next,
1459 canonname ? canonname : qname);
1460 h_errno = NETDB_SUCCESS;
1461 return sentinel.ai_next;
1462 }
1463
1464 h_errno = NO_RECOVERY;
1465 return NULL;
1466 }
1467
1468 #define SORTEDADDR(p) (((struct sockaddr_in *)(void *)(p->ai_next->ai_addr))->sin_addr.s_addr)
1469 #define SORTMATCH(p, s) ((SORTEDADDR(p) & (s).mask) == (s).addr.s_addr)
1470
1471 static void
1472 aisort(struct addrinfo *s, res_state res)
1473 {
1474 struct addrinfo head, *t, *p;
1475 int i;
1476
1477 head.ai_next = NULL;
1478 t = &head;
1479
1480 for (i = 0; i < res->nsort; i++) {
1481 p = s;
1482 while (p->ai_next) {
1483 if ((p->ai_next->ai_family != AF_INET)
1484 || SORTMATCH(p, res->sort_list[i])) {
1485 t->ai_next = p->ai_next;
1486 t = t->ai_next;
1487 p->ai_next = p->ai_next->ai_next;
1488 } else {
1489 p = p->ai_next;
1490 }
1491 }
1492 }
1493
1494 /* add rest of list and reset s to the new list*/
1495 t->ai_next = s->ai_next;
1496 s->ai_next = head.ai_next;
1497 }
1498
1499 static struct addrinfo *
1500 _dns_query(struct res_target *q, const struct addrinfo *pai,
1501 res_state res, int dosearch)
1502 {
1503 struct res_target *q2 = q->next;
1504 querybuf *buf, *buf2;
1505 struct addrinfo sentinel, *cur, *ai;
1506
1507 #ifdef DNS_DEBUG
1508 struct res_target *iter;
1509 for (iter = q; iter; iter = iter->next)
1510 printf("Query type %d for %s\n", iter->qtype, iter->name);
1511 #endif
1512
1513 buf = malloc(sizeof(*buf));
1514 if (buf == NULL) {
1515 h_errno = NETDB_INTERNAL;
1516 return NULL;
1517 }
1518 buf2 = malloc(sizeof(*buf2));
1519 if (buf2 == NULL) {
1520 free(buf);
1521 h_errno = NETDB_INTERNAL;
1522 return NULL;
1523 }
1524
1525 memset(&sentinel, 0, sizeof(sentinel));
1526 cur = &sentinel;
1527
1528 q->answer = buf->buf;
1529 q->anslen = sizeof(buf->buf);
1530 if (q2) {
1531 q2->answer = buf2->buf;
1532 q2->anslen = sizeof(buf2->buf);
1533 }
1534
1535 if (dosearch) {
1536 if (res_searchN(q->name, q, res) < 0)
1537 goto out;
1538 } else {
1539 if (res_queryN(q->name, q, res) < 0)
1540 goto out;
1541 }
1542
1543 ai = getanswer(buf, q->n, q->name, q->qtype, pai);
1544 if (ai) {
1545 cur->ai_next = ai;
1546 while (cur && cur->ai_next)
1547 cur = cur->ai_next;
1548 }
1549 if (q2) {
1550 ai = getanswer(buf2, q2->n, q2->name, q2->qtype, pai);
1551 if (ai)
1552 cur->ai_next = ai;
1553 }
1554 free(buf);
1555 free(buf2);
1556 return sentinel.ai_next;
1557 out:
1558 free(buf);
1559 free(buf2);
1560 return NULL;
1561 }
1562
1563 /*ARGSUSED*/
1564 static struct addrinfo *
1565 _dns_srv_lookup(const char *name, const char *servname,
1566 const struct addrinfo *pai)
1567 {
1568 static const char * const srvprotos[] = { "tcp", "udp" };
1569 static const int srvnottype[] = { SOCK_DGRAM, SOCK_STREAM };
1570 static const int nsrvprotos = 2;
1571 struct addrinfo sentinel, *cur, *ai;
1572 struct servent *serv, sv;
1573 struct servent_data svd;
1574 struct res_target q;
1575 res_state res;
1576 char *tname;
1577 int i;
1578
1579 res = __res_get_state();
1580 if (res == NULL)
1581 return NULL;
1582
1583 memset(&svd, 0, sizeof(svd));
1584 memset(&sentinel, 0, sizeof(sentinel));
1585 cur = &sentinel;
1586
1587 /*
1588 * Iterate over supported SRV protocols.
1589 * (currently UDP and TCP only)
1590 */
1591 for (i = 0; i < nsrvprotos; i++) {
1592 /*
1593 * Check that the caller didn't specify a hint
1594 * which precludes this protocol.
1595 */
1596 if (pai->ai_socktype == srvnottype[i])
1597 continue;
1598 /*
1599 * If the caller specified a port,
1600 * then lookup the database for the
1601 * official service name.
1602 */
1603 serv = getservbyname_r(servname, srvprotos[i], &sv, &svd);
1604 if (serv == NULL)
1605 continue;
1606
1607 /*
1608 * Construct service DNS name.
1609 */
1610 if (asprintf(&tname, "_%s._%s.%s", serv->s_name, serv->s_proto,
1611 name) < 0)
1612 continue;
1613
1614 memset(&q, 0, sizeof(q));
1615 q.name = tname;
1616 q.qclass = C_IN;
1617 q.qtype = T_SRV;
1618
1619 /*
1620 * Do SRV query.
1621 */
1622 ai = _dns_query(&q, pai, res, 1);
1623 if (ai) {
1624 cur->ai_next = ai;
1625 while (cur && cur->ai_next)
1626 cur = cur->ai_next;
1627 }
1628 free(tname);
1629 }
1630
1631 if (res->nsort)
1632 aisort(&sentinel, res);
1633
1634 __res_put_state(res);
1635
1636 return sentinel.ai_next;
1637 }
1638
1639 /*ARGSUSED*/
1640 static struct addrinfo *
1641 _dns_host_lookup(const char *name, const struct addrinfo *pai)
1642 {
1643 struct res_target q, q2;
1644 struct addrinfo sentinel, *ai;
1645 res_state res;
1646
1647 res = __res_get_state();
1648 if (res == NULL)
1649 return NULL;
1650
1651 memset(&q, 0, sizeof(q2));
1652 memset(&q2, 0, sizeof(q2));
1653
1654 switch (pai->ai_family) {
1655 case AF_UNSPEC:
1656 /* prefer IPv6 */
1657 q.name = name;
1658 q.qclass = C_IN;
1659 q.qtype = T_AAAA;
1660 q.next = &q2;
1661 q2.name = name;
1662 q2.qclass = C_IN;
1663 q2.qtype = T_A;
1664 break;
1665 case AF_INET:
1666 q.name = name;
1667 q.qclass = C_IN;
1668 q.qtype = T_A;
1669 break;
1670 case AF_INET6:
1671 q.name = name;
1672 q.qclass = C_IN;
1673 q.qtype = T_AAAA;
1674 break;
1675 default:
1676 __res_put_state(res);
1677 h_errno = NETDB_INTERNAL;
1678 return NULL;
1679 }
1680
1681 ai = _dns_query(&q, pai, res, 1);
1682
1683 memset(&sentinel, 0, sizeof(sentinel));
1684 sentinel.ai_next = ai;
1685
1686 if (ai != NULL && res->nsort)
1687 aisort(&sentinel, res);
1688
1689 __res_put_state(res);
1690
1691 return sentinel.ai_next;
1692 }
1693
1694 /*ARGSUSED*/
1695 static int
1696 _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
1697 {
1698 struct addrinfo *ai = NULL;
1699 const char *name, *servname;
1700 const struct addrinfo *pai;
1701
1702 name = va_arg(ap, char *);
1703 pai = va_arg(ap, const struct addrinfo *);
1704 servname = va_arg(ap, char *);
1705
1706 /*
1707 * Try doing SRV lookup on service first.
1708 */
1709 if (servname
1710 #ifdef AI_SRV
1711 && (pai->ai_flags & AI_SRV)
1712 #endif
1713 && !(pai->ai_flags & AI_NUMERICSERV)
1714 && str2number(servname) == -1) {
1715
1716 #ifdef DNS_DEBUG
1717 printf("%s: try SRV lookup\n", __func__);
1718 #endif
1719 ai = _dns_srv_lookup(name, servname, pai);
1720 }
1721
1722 /*
1723 * Do lookup on name.
1724 */
1725 if (ai == NULL) {
1726
1727 #ifdef DNS_DEBUG
1728 printf("%s: try HOST lookup\n", __func__);
1729 #endif
1730 ai = _dns_host_lookup(name, pai);
1731
1732 if (ai == NULL) {
1733 switch (h_errno) {
1734 case HOST_NOT_FOUND:
1735 return NS_NOTFOUND;
1736 case TRY_AGAIN:
1737 return NS_TRYAGAIN;
1738 default:
1739 return NS_UNAVAIL;
1740 }
1741 }
1742 }
1743
1744 *((struct addrinfo **)rv) = ai;
1745 return NS_SUCCESS;
1746 }
1747
1748 static void
1749 _sethtent(FILE **hostf)
1750 {
1751
1752 if (!*hostf)
1753 *hostf = fopen(_PATH_HOSTS, "re");
1754 else
1755 rewind(*hostf);
1756 }
1757
1758 static void
1759 _endhtent(FILE **hostf)
1760 {
1761
1762 if (*hostf) {
1763 (void) fclose(*hostf);
1764 *hostf = NULL;
1765 }
1766 }
1767
1768 static struct addrinfo *
1769 _gethtent(FILE **hostf, const char *name, const struct addrinfo *pai)
1770 {
1771 char *p;
1772 char *cp, *tname, *cname;
1773 struct addrinfo hints, *res0, *res;
1774 int error;
1775 const char *addr;
1776 char hostbuf[8*1024];
1777
1778 _DIAGASSERT(name != NULL);
1779 _DIAGASSERT(pai != NULL);
1780
1781 if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "re")))
1782 return (NULL);
1783 again:
1784 if (!(p = fgets(hostbuf, (int)sizeof hostbuf, *hostf)))
1785 return (NULL);
1786 if (*p == '#')
1787 goto again;
1788 if (!(cp = strpbrk(p, "#\n")))
1789 goto again;
1790 *cp = '\0';
1791 if (!(cp = strpbrk(p, " \t")))
1792 goto again;
1793 *cp++ = '\0';
1794 addr = p;
1795 /* if this is not something we're looking for, skip it. */
1796 cname = NULL;
1797 while (cp && *cp) {
1798 if (*cp == ' ' || *cp == '\t') {
1799 cp++;
1800 continue;
1801 }
1802 if (!cname)
1803 cname = cp;
1804 tname = cp;
1805 if ((cp = strpbrk(cp, " \t")) != NULL)
1806 *cp++ = '\0';
1807 if (strcasecmp(name, tname) == 0)
1808 goto found;
1809 }
1810 goto again;
1811
1812 found:
1813 hints = *pai;
1814 hints.ai_flags = AI_NUMERICHOST;
1815 error = getaddrinfo(addr, NULL, &hints, &res0);
1816 if (error)
1817 goto again;
1818 for (res = res0; res; res = res->ai_next) {
1819 /* cover it up */
1820 res->ai_flags = pai->ai_flags;
1821
1822 if (pai->ai_flags & AI_CANONNAME) {
1823 if (get_canonname(pai, res, cname) != 0) {
1824 freeaddrinfo(res0);
1825 goto again;
1826 }
1827 }
1828 }
1829 return res0;
1830 }
1831
1832 /*ARGSUSED*/
1833 static int
1834 _files_getaddrinfo(void *rv, void *cb_data, va_list ap)
1835 {
1836 const char *name;
1837 const struct addrinfo *pai;
1838 struct addrinfo sentinel, *cur;
1839 struct addrinfo *p;
1840 #ifndef _REENTRANT
1841 static
1842 #endif
1843 FILE *hostf = NULL;
1844
1845 name = va_arg(ap, char *);
1846 pai = va_arg(ap, const struct addrinfo *);
1847
1848 memset(&sentinel, 0, sizeof(sentinel));
1849 cur = &sentinel;
1850
1851 _sethtent(&hostf);
1852 while ((p = _gethtent(&hostf, name, pai)) != NULL) {
1853 cur->ai_next = p;
1854 while (cur && cur->ai_next)
1855 cur = cur->ai_next;
1856 }
1857 _endhtent(&hostf);
1858
1859 *((struct addrinfo **)rv) = sentinel.ai_next;
1860 if (sentinel.ai_next == NULL)
1861 return NS_NOTFOUND;
1862 return NS_SUCCESS;
1863 }
1864
1865 #ifdef YP
1866 /*ARGSUSED*/
1867 static struct addrinfo *
1868 _yphostent(char *line, const struct addrinfo *pai)
1869 {
1870 struct addrinfo sentinel, *cur;
1871 struct addrinfo hints, *res, *res0;
1872 int error;
1873 char *p;
1874 const char *addr, *canonname;
1875 char *nextline;
1876 char *cp;
1877
1878 _DIAGASSERT(line != NULL);
1879 _DIAGASSERT(pai != NULL);
1880
1881 p = line;
1882 addr = canonname = NULL;
1883
1884 memset(&sentinel, 0, sizeof(sentinel));
1885 cur = &sentinel;
1886
1887 nextline:
1888 /* terminate line */
1889 cp = strchr(p, '\n');
1890 if (cp) {
1891 *cp++ = '\0';
1892 nextline = cp;
1893 } else
1894 nextline = NULL;
1895
1896 cp = strpbrk(p, " \t");
1897 if (cp == NULL) {
1898 if (canonname == NULL)
1899 return (NULL);
1900 else
1901 goto done;
1902 }
1903 *cp++ = '\0';
1904
1905 addr = p;
1906
1907 while (cp && *cp) {
1908 if (*cp == ' ' || *cp == '\t') {
1909 cp++;
1910 continue;
1911 }
1912 if (!canonname)
1913 canonname = cp;
1914 if ((cp = strpbrk(cp, " \t")) != NULL)
1915 *cp++ = '\0';
1916 }
1917
1918 hints = *pai;
1919 hints.ai_flags = AI_NUMERICHOST;
1920 error = getaddrinfo(addr, NULL, &hints, &res0);
1921 if (error == 0) {
1922 for (res = res0; res; res = res->ai_next) {
1923 /* cover it up */
1924 res->ai_flags = pai->ai_flags;
1925
1926 if (pai->ai_flags & AI_CANONNAME)
1927 (void)get_canonname(pai, res, canonname);
1928 }
1929 } else
1930 res0 = NULL;
1931 if (res0) {
1932 cur->ai_next = res0;
1933 while (cur->ai_next)
1934 cur = cur->ai_next;
1935 }
1936
1937 if (nextline) {
1938 p = nextline;
1939 goto nextline;
1940 }
1941
1942 done:
1943 return sentinel.ai_next;
1944 }
1945
1946 /*ARGSUSED*/
1947 static int
1948 _yp_getaddrinfo(void *rv, void *cb_data, va_list ap)
1949 {
1950 struct addrinfo sentinel, *cur;
1951 struct addrinfo *ai = NULL;
1952 char *ypbuf;
1953 int ypbuflen, r;
1954 const char *name;
1955 const struct addrinfo *pai;
1956 char *ypdomain;
1957
1958 if (_yp_check(&ypdomain) == 0)
1959 return NS_UNAVAIL;
1960
1961 name = va_arg(ap, char *);
1962 pai = va_arg(ap, const struct addrinfo *);
1963
1964 memset(&sentinel, 0, sizeof(sentinel));
1965 cur = &sentinel;
1966
1967 /* hosts.byname is only for IPv4 (Solaris8) */
1968 if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
1969 r = yp_match(ypdomain, "hosts.byname", name,
1970 (int)strlen(name), &ypbuf, &ypbuflen);
1971 if (r == 0) {
1972 struct addrinfo ai4;
1973
1974 ai4 = *pai;
1975 ai4.ai_family = AF_INET;
1976 ai = _yphostent(ypbuf, &ai4);
1977 if (ai) {
1978 cur->ai_next = ai;
1979 while (cur && cur->ai_next)
1980 cur = cur->ai_next;
1981 }
1982 }
1983 free(ypbuf);
1984 }
1985
1986 /* ipnodes.byname can hold both IPv4/v6 */
1987 r = yp_match(ypdomain, "ipnodes.byname", name,
1988 (int)strlen(name), &ypbuf, &ypbuflen);
1989 if (r == 0) {
1990 ai = _yphostent(ypbuf, pai);
1991 if (ai)
1992 cur->ai_next = ai;
1993 free(ypbuf);
1994 }
1995
1996 if (sentinel.ai_next == NULL) {
1997 h_errno = HOST_NOT_FOUND;
1998 return NS_NOTFOUND;
1999 }
2000 *((struct addrinfo **)rv) = sentinel.ai_next;
2001 return NS_SUCCESS;
2002 }
2003 #endif
2004
2005 /* resolver logic */
2006
2007 /*
2008 * Formulate a normal query, send, and await answer.
2009 * Returned answer is placed in supplied buffer "answer".
2010 * Perform preliminary check of answer, returning success only
2011 * if no error is indicated and the answer count is nonzero.
2012 * Return the size of the response on success, -1 on error.
2013 * Error number is left in h_errno.
2014 *
2015 * Caller must parse answer and determine whether it answers the question.
2016 */
2017 static int
2018 res_queryN(const char *name, /* domain name */ struct res_target *target,
2019 res_state res)
2020 {
2021 u_char buf[MAXPACKET];
2022 HEADER *hp;
2023 int n;
2024 struct res_target *t;
2025 int rcode;
2026 int ancount;
2027
2028 _DIAGASSERT(name != NULL);
2029 /* XXX: target may be NULL??? */
2030
2031 rcode = NOERROR;
2032 ancount = 0;
2033
2034 for (t = target; t; t = t->next) {
2035 int class, type;
2036 u_char *answer;
2037 int anslen;
2038
2039 hp = (HEADER *)(void *)t->answer;
2040 hp->rcode = NOERROR; /* default */
2041
2042 /* make it easier... */
2043 class = t->qclass;
2044 type = t->qtype;
2045 answer = t->answer;
2046 anslen = t->anslen;
2047 #ifdef DEBUG
2048 if (res->options & RES_DEBUG)
2049 printf(";; res_nquery(%s, %d, %d)\n", name, class, type);
2050 #endif
2051
2052 n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL,
2053 buf, (int)sizeof(buf));
2054 #ifdef RES_USE_EDNS0
2055 if (n > 0 && (res->options & RES_USE_EDNS0) != 0)
2056 n = res_nopt(res, n, buf, (int)sizeof(buf), anslen);
2057 #endif
2058 if (n <= 0) {
2059 #ifdef DEBUG
2060 if (res->options & RES_DEBUG)
2061 printf(";; res_nquery: mkquery failed\n");
2062 #endif
2063 h_errno = NO_RECOVERY;
2064 return n;
2065 }
2066 n = res_nsend(res, buf, n, answer, anslen);
2067 #if 0
2068 if (n < 0) {
2069 #ifdef DEBUG
2070 if (res->options & RES_DEBUG)
2071 printf(";; res_query: send error\n");
2072 #endif
2073 h_errno = TRY_AGAIN;
2074 return n;
2075 }
2076 #endif
2077
2078 if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
2079 rcode = hp->rcode; /* record most recent error */
2080 #ifdef DEBUG
2081 if (res->options & RES_DEBUG)
2082 printf(";; rcode = %u, ancount=%u\n", hp->rcode,
2083 ntohs(hp->ancount));
2084 #endif
2085 continue;
2086 }
2087
2088 ancount += ntohs(hp->ancount);
2089
2090 t->n = n;
2091 }
2092
2093 if (ancount == 0) {
2094 switch (rcode) {
2095 case NXDOMAIN:
2096 h_errno = HOST_NOT_FOUND;
2097 break;
2098 case SERVFAIL:
2099 h_errno = TRY_AGAIN;
2100 break;
2101 case NOERROR:
2102 h_errno = NO_DATA;
2103 break;
2104 case FORMERR:
2105 case NOTIMP:
2106 case REFUSED:
2107 default:
2108 h_errno = NO_RECOVERY;
2109 break;
2110 }
2111 return -1;
2112 }
2113 return ancount;
2114 }
2115
2116 /*
2117 * Formulate a normal query, send, and retrieve answer in supplied buffer.
2118 * Return the size of the response on success, -1 on error.
2119 * If enabled, implement search rules until answer or unrecoverable failure
2120 * is detected. Error code, if any, is left in h_errno.
2121 */
2122 static int
2123 res_searchN(const char *name, struct res_target *target, res_state res)
2124 {
2125 const char *cp, * const *domain;
2126 HEADER *hp;
2127 u_int dots;
2128 char buf[MAXHOSTNAMELEN];
2129 int trailing_dot, ret, saved_herrno;
2130 int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
2131
2132 _DIAGASSERT(name != NULL);
2133 _DIAGASSERT(target != NULL);
2134
2135 hp = (HEADER *)(void *)target->answer; /*XXX*/
2136
2137 errno = 0;
2138 h_errno = HOST_NOT_FOUND; /* default, if we never query */
2139 dots = 0;
2140 for (cp = name; *cp; cp++)
2141 dots += (*cp == '.');
2142 trailing_dot = 0;
2143 if (cp > name && *--cp == '.')
2144 trailing_dot++;
2145
2146 /*
2147 * if there aren't any dots, it could be a user-level alias
2148 */
2149 if (!dots && (cp = res_hostalias(res, name, buf, sizeof(buf))) != NULL) {
2150 ret = res_queryN(cp, target, res);
2151 return ret;
2152 }
2153
2154 /*
2155 * If there are dots in the name already, let's just give it a try
2156 * 'as is'. The threshold can be set with the "ndots" option.
2157 */
2158 saved_herrno = -1;
2159 if (dots >= res->ndots) {
2160 ret = res_querydomainN(name, NULL, target, res);
2161 if (ret > 0)
2162 return (ret);
2163 saved_herrno = h_errno;
2164 tried_as_is++;
2165 }
2166
2167 /*
2168 * We do at least one level of search if
2169 * - there is no dot and RES_DEFNAME is set, or
2170 * - there is at least one dot, there is no trailing dot,
2171 * and RES_DNSRCH is set.
2172 */
2173 if ((!dots && (res->options & RES_DEFNAMES)) ||
2174 (dots && !trailing_dot && (res->options & RES_DNSRCH))) {
2175 int done = 0;
2176
2177 for (domain = (const char * const *)res->dnsrch;
2178 *domain && !done;
2179 domain++) {
2180
2181 ret = res_querydomainN(name, *domain, target, res);
2182 if (ret > 0)
2183 return ret;
2184
2185 /*
2186 * If no server present, give up.
2187 * If name isn't found in this domain,
2188 * keep trying higher domains in the search list
2189 * (if that's enabled).
2190 * On a NO_DATA error, keep trying, otherwise
2191 * a wildcard entry of another type could keep us
2192 * from finding this entry higher in the domain.
2193 * If we get some other error (negative answer or
2194 * server failure), then stop searching up,
2195 * but try the input name below in case it's
2196 * fully-qualified.
2197 */
2198 if (errno == ECONNREFUSED) {
2199 h_errno = TRY_AGAIN;
2200 return -1;
2201 }
2202
2203 switch (h_errno) {
2204 case NO_DATA:
2205 got_nodata++;
2206 /* FALLTHROUGH */
2207 case HOST_NOT_FOUND:
2208 /* keep trying */
2209 break;
2210 case TRY_AGAIN:
2211 if (hp->rcode == SERVFAIL) {
2212 /* try next search element, if any */
2213 got_servfail++;
2214 break;
2215 }
2216 /* FALLTHROUGH */
2217 default:
2218 /* anything else implies that we're done */
2219 done++;
2220 }
2221 /*
2222 * if we got here for some reason other than DNSRCH,
2223 * we only wanted one iteration of the loop, so stop.
2224 */
2225 if (!(res->options & RES_DNSRCH))
2226 done++;
2227 }
2228 }
2229
2230 /*
2231 * if we have not already tried the name "as is", do that now.
2232 * note that we do this regardless of how many dots were in the
2233 * name or whether it ends with a dot.
2234 */
2235 if (!tried_as_is) {
2236 ret = res_querydomainN(name, NULL, target, res);
2237 if (ret > 0)
2238 return ret;
2239 }
2240
2241 /*
2242 * if we got here, we didn't satisfy the search.
2243 * if we did an initial full query, return that query's h_errno
2244 * (note that we wouldn't be here if that query had succeeded).
2245 * else if we ever got a nodata, send that back as the reason.
2246 * else send back meaningless h_errno, that being the one from
2247 * the last DNSRCH we did.
2248 */
2249 if (saved_herrno != -1)
2250 h_errno = saved_herrno;
2251 else if (got_nodata)
2252 h_errno = NO_DATA;
2253 else if (got_servfail)
2254 h_errno = TRY_AGAIN;
2255 return -1;
2256 }
2257
2258 /*
2259 * Perform a call on res_query on the concatenation of name and domain,
2260 * removing a trailing dot from name if domain is NULL.
2261 */
2262 static int
2263 res_querydomainN(const char *name, const char *domain,
2264 struct res_target *target, res_state res)
2265 {
2266 char nbuf[MAXDNAME];
2267 const char *longname = nbuf;
2268 size_t n, d;
2269
2270 _DIAGASSERT(name != NULL);
2271 /* XXX: target may be NULL??? */
2272
2273 #ifdef DEBUG
2274 if (res->options & RES_DEBUG)
2275 printf(";; res_querydomain(%s, %s)\n",
2276 name, domain?domain:"<Nil>");
2277 #endif
2278 if (domain == NULL) {
2279 /*
2280 * Check for trailing '.';
2281 * copy without '.' if present.
2282 */
2283 n = strlen(name);
2284 if (n + 1 > sizeof(nbuf)) {
2285 h_errno = NO_RECOVERY;
2286 return -1;
2287 }
2288 if (n > 0 && name[--n] == '.') {
2289 strncpy(nbuf, name, n);
2290 nbuf[n] = '\0';
2291 } else
2292 longname = name;
2293 } else {
2294 n = strlen(name);
2295 d = strlen(domain);
2296 if (n + 1 + d + 1 > sizeof(nbuf)) {
2297 h_errno = NO_RECOVERY;
2298 return -1;
2299 }
2300 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
2301 }
2302 return res_queryN(longname, target, res);
2303 }
2304
2305 #ifdef TEST
2306 int
2307 main(int argc, char *argv[]) {
2308 struct addrinfo *ai, *sai;
2309 int i, e;
2310 char buf[1024];
2311
2312 for (i = 1; i < argc; i++) {
2313 if ((e = getaddrinfo(argv[i], NULL, NULL, &sai)) != 0)
2314 warnx("%s: %s", argv[i], gai_strerror(e));
2315 for (ai = sai; ai; ai = ai->ai_next) {
2316 sockaddr_snprintf(buf, sizeof(buf), "%a", ai->ai_addr);
2317 printf("flags=0x%x family=%d socktype=%d protocol=%d "
2318 "addrlen=%zu addr=%s canonname=%s next=%p\n",
2319 ai->ai_flags,
2320 ai->ai_family,
2321 ai->ai_socktype,
2322 ai->ai_protocol,
2323 (size_t)ai->ai_addrlen,
2324 buf,
2325 ai->ai_canonname,
2326 ai->ai_next);
2327 }
2328 if (sai)
2329 freeaddrinfo(sai);
2330 }
2331 return 0;
2332 }
2333 #endif
2334