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