Add nsswitch support.
[dragonfly.git] / lib / libc / net / getaddrinfo.c
1 /*      $FreeBSD: src/lib/libc/net/getaddrinfo.c,v 1.9.2.14 2002/11/08 17:49:31 ume Exp $       */
2 /*      $DragonFly: src/lib/libc/net/getaddrinfo.c,v 1.9 2008/10/04 22:38:42 swildner Exp $     */
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
67 #include "namespace.h"
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
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
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
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 #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
145 struct 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
156 static 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
180 static const ns_src default_dns_files[] = {
181         { NSSRC_FILES,  NS_SUCCESS },
182         { NSSRC_DNS,    NS_SUCCESS },
183         { 0 }
184 };
185
186 #define MAXPACKET       (64*1024)
187
188 typedef union {
189         HEADER hdr;
190         u_char buf[MAXPACKET];
191 } querybuf;
192
193 struct 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
202 static int str2number (const char *);
203 static int explore_fqdn (const struct addrinfo *, const char *,
204         const char *, struct addrinfo **);
205 static int explore_null (const struct addrinfo *,
206         const char *, struct addrinfo **);
207 static int explore_numeric (const struct addrinfo *, const char *,
208         const char *, struct addrinfo **);
209 static int explore_numeric_scope (const struct addrinfo *, const char *,
210         const char *, struct addrinfo **);
211 static int get_canonname (const struct addrinfo *,
212         struct addrinfo *, const char *);
213 static struct addrinfo *get_ai (const struct addrinfo *,
214         const struct afd *, const char *);
215 static int get_portmatch (const struct addrinfo *, const char *);
216 static int get_port (struct addrinfo *, const char *, int);
217 static const struct afd *find_afd (int);
218 static int addrconfig (struct addrinfo *);
219 #ifdef INET6
220 static int ip6_str2scopeid (char *, struct sockaddr_in6 *, u_int32_t *);
221 #endif
222
223 static struct addrinfo *getanswer (const querybuf *, int, const char *,
224         int, const struct addrinfo *);
225 static int _dns_getaddrinfo (void *, void *, va_list);
226 static void _sethtent (void);
227 static void _endhtent (void);
228 static struct addrinfo *_gethtent (const char *, const struct addrinfo *);
229 static int _files_getaddrinfo (void *, void *, va_list);
230 #ifdef YP
231 static struct addrinfo *_yphostent (char *, const struct addrinfo *);
232 static int _yp_getaddrinfo (void *, void *, va_list);
233 #endif
234 #ifdef NS_CACHING
235 static int addrinfo_id_func(char *, size_t *, va_list, void *);
236 static int addrinfo_marshal_func(char *, size_t *, void *, va_list, void *);
237 static int addrinfo_unmarshal_func(char *, size_t, void *, va_list, void *);
238 #endif
239
240 static int res_queryN (const char *, struct res_target *);
241 static int res_searchN (const char *, struct res_target *);
242 static int res_querydomainN (const char *, const char *,
243         struct res_target *);
244
245 static const char *ai_errlist[] = {
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   */
260         "Argument buffer overflow",                     /* EAI_OVERFLOW   */
261         "Unknown error",                                /* EAI_MAX        */
262 };
263
264 /* Make getaddrinfo() thread-safe in libc for use with kernel threads. */
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  */
272 spinlock_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) \
281 do { \
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) \
291 do { \
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) \
299 do { \
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) \
307 do { \
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
319 const char *
320 gai_strerror(int ecode)
321 {
322         if (ecode < 0 || ecode > EAI_MAX)
323                 ecode = EAI_MAX;
324         return ai_errlist[ecode];
325 }
326
327 void
328 freeaddrinfo(struct addrinfo *ai)
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
342 static int
343 str2number(const char *p)
344 {
345         char *ep;
346         unsigned long v;
347
348         if (*p == '\0')
349                 return -1;
350         ep = NULL;
351         errno = 0;
352         v = strtoul(p, &ep, 10);
353         if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX)
354                 return v;
355         else
356                 return -1;
357 }
358
359 int
360 getaddrinfo(const char *hostname, const char *servname,
361             const struct addrinfo *hints, struct addrinfo **res)
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
578 /*
579  * FQDN hostname, DNS lookup
580  */
581 static int
582 explore_fqdn(const struct addrinfo *pai, const char *hostname,
583              const char *servname, struct addrinfo **res)
584 {
585         struct addrinfo *result;
586         struct addrinfo *cur;
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         };
604
605         result = NULL;
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
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;
630                 for (cur = result; cur; cur = cur->ai_next) {
631                         GET_PORT(cur, servname);
632                         /* canonname should be filled already */
633                 }
634                 THREAD_UNLOCK();
635                 break;
636         }
637
638         *res = result;
639
640         return 0;
641
642 free:
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  */
654 static int
655 explore_null(const struct addrinfo *pai, const char *servname,
656              struct addrinfo **res)
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          */
672         s = _socket(pai->ai_family, SOCK_DGRAM, 0);
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
707 free:
708         if (sentinel.ai_next)
709                 freeaddrinfo(sentinel.ai_next);
710         return error;
711 }
712
713 /*
714  * numeric hostname
715  */
716 static int
717 explore_numeric(const struct addrinfo *pai, const char *hostname,
718                 const char *servname, struct addrinfo **res)
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
772 free:
773 bad:
774         if (sentinel.ai_next)
775                 freeaddrinfo(sentinel.ai_next);
776         return error;
777 }
778
779 /*
780  * numeric hostname with scope
781  */
782 static int
783 explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
784                       const char *servname, struct addrinfo **res)
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
844 static int
845 get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str)
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
856 static struct addrinfo *
857 get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
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;
914         p = (char *)(void *)(ai->ai_addr);
915 #ifdef FAITH
916         if (translate == 1)
917                 memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen);
918         else
919 #endif
920         memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
921
922         return ai;
923 }
924
925 static int
926 get_portmatch(const struct addrinfo *ai, const char *servname)
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
934 static int
935 get_port(struct addrinfo *ai, const char *servname, int matchonly)
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
968         port = str2number(servname);
969         if (port >= 0) {
970                 if (!allownumeric)
971                         return EAI_SERVICE;
972                 if (port < 0 || port > 65535)
973                         return EAI_SERVICE;
974                 port = htons(port);
975         } else {
976                 if (ai->ai_flags & AI_NUMERICSERV)
977                         return EAI_NONAME;
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
1013 static const struct afd *
1014 find_afd(int af)
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  */
1036 static int
1037 addrconfig(struct addrinfo *pai)
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) {
1050                 if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1051                         af = AF_INET;
1052                 else {
1053                         _close(s);
1054                         if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1055                                 af = AF_INET6;
1056                         else
1057                                 _close(s);
1058                 }
1059
1060         }
1061         if (af != AF_UNSPEC) {
1062                 if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
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 */
1072 static int
1073 ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid)
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
1118 struct addr_ptr {
1119         struct addrinfo *ai;
1120         int aval;
1121 };
1122
1123 static int
1124 addr4sort(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
1184 static const char AskedForGot[] =
1185         "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
1186 #endif
1187 static FILE *hostf = NULL;
1188
1189 static struct addrinfo *
1190 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
1191           const struct addrinfo *pai)
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];
1205         int (*name_ok) (const char *);
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)
1384                         get_canonname(pai, sentinel.ai_next, qname);
1385                 else
1386                         get_canonname(pai, sentinel.ai_next, canonname);
1387                 h_errno = NETDB_SUCCESS;
1388                 return sentinel.ai_next;
1389         }
1390
1391         h_errno = NO_RECOVERY;
1392         return NULL;
1393 }
1394
1395 /*ARGSUSED*/
1396 static int
1397 _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
1398 {
1399         struct addrinfo *ai;
1400         querybuf *buf, *buf2;
1401         const char *name;
1402         const struct addrinfo *pai;
1403         struct addrinfo sentinel, *cur;
1404         struct res_target q, q2;
1405
1406         name = va_arg(ap, char *);
1407         pai = va_arg(ap, const struct addrinfo *);
1408
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:
1428                 q.name = name;
1429                 q.qclass = C_IN;
1430                 q.qtype = T_A;
1431                 q.answer = buf->buf;
1432                 q.anslen = sizeof(buf->buf);
1433                 q.next = &q2;
1434                 q2.name = name;
1435                 q2.qclass = C_IN;
1436                 q2.qtype = T_AAAA;
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);
1457                 return NS_UNAVAIL;
1458         }
1459         if (res_searchN(name, &q) < 0) {
1460                 free(buf);
1461                 free(buf2);
1462                 return NS_NOTFOUND;
1463         }
1464         /* prefer IPv6 */
1465         if (q.next) {
1466                 ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
1467                 if (ai) {
1468                         cur->ai_next = ai;
1469                         while (cur && cur->ai_next)
1470                                 cur = cur->ai_next;
1471                 }
1472         }
1473
1474         ai = getanswer(buf, q.n, q.name, q.qtype, pai);
1475         if (ai)
1476                 cur->ai_next = ai;
1477         free(buf);
1478         free(buf2);
1479         if (sentinel.ai_next == NULL)
1480                 switch (h_errno) {
1481                 case HOST_NOT_FOUND:
1482                         return NS_NOTFOUND;
1483                 case TRY_AGAIN:
1484                         return NS_TRYAGAIN;
1485                 default:
1486                         return NS_UNAVAIL;
1487                 }
1488         *((struct addrinfo **)rv) = sentinel.ai_next;
1489         return NS_SUCCESS;
1490 }
1491
1492 static void
1493 _sethtent(void)
1494 {
1495         if (!hostf)
1496                 hostf = fopen(_PATH_HOSTS, "r" );
1497         else
1498                 rewind(hostf);
1499 }
1500
1501 static void
1502 _endhtent(void)
1503 {
1504         if (hostf) {
1505                 fclose(hostf);
1506                 hostf = NULL;
1507         }
1508 }
1509
1510 static struct addrinfo *
1511 _gethtent(const char *name, const struct addrinfo *pai)
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
1520         if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" )))
1521                 return (NULL);
1522 again:
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
1551 found:
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*/
1586 static int
1587 _files_getaddrinfo(void *rv, void *cb_data, va_list ap)
1588 {
1589         const char *name;
1590         const struct addrinfo *pai;
1591         struct addrinfo sentinel, *cur;
1592         struct addrinfo *p;
1593
1594         name = va_arg(ap, char *);
1595         pai = va_arg(ap, struct addrinfo *);
1596
1597         memset(&sentinel, 0, sizeof(sentinel));
1598         cur = &sentinel;
1599
1600         _sethtent();
1601         while ((p = _gethtent(name, pai)) != NULL) {
1602                 cur->ai_next = p;
1603                 while (cur && cur->ai_next)
1604                         cur = cur->ai_next;
1605         }
1606         _endhtent();
1607
1608         *((struct addrinfo **)rv) = sentinel.ai_next;
1609         if (sentinel.ai_next == NULL)
1610                 return NS_NOTFOUND;
1611         return NS_SUCCESS;
1612 }
1613
1614 #ifdef YP
1615 static char *__ypdomain;
1616
1617 /*ARGSUSED*/
1618 static struct addrinfo *
1619 _yphostent(char *line, const struct addrinfo *pai)
1620 {
1621         struct addrinfo sentinel, *cur;
1622         struct addrinfo hints, *res, *res0;
1623         int error;
1624         char *p = line;
1625         const char *addr, *canonname;
1626         char *nextline;
1627         char *cp;
1628
1629         addr = canonname = NULL;
1630
1631         memset(&sentinel, 0, sizeof(sentinel));
1632         cur = &sentinel;
1633
1634 nextline:
1635         /* terminate line */
1636         cp = strchr(p, '\n');
1637         if (cp) {
1638                 *cp++ = '\0';
1639                 nextline = cp;
1640         } else
1641                 nextline = NULL;
1642
1643         cp = strpbrk(p, " \t");
1644         if (cp == NULL) {
1645                 if (canonname == NULL)
1646                         return (NULL);
1647                 else
1648                         goto done;
1649         }
1650         *cp++ = '\0';
1651
1652         addr = p;
1653
1654         while (cp && *cp) {
1655                 if (*cp == ' ' || *cp == '\t') {
1656                         cp++;
1657                         continue;
1658                 }
1659                 if (!canonname)
1660                         canonname = cp;
1661                 if ((cp = strpbrk(cp, " \t")) != NULL)
1662                         *cp++ = '\0';
1663         }
1664
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;
1672
1673                         if (pai->ai_flags & AI_CANONNAME)
1674                                 get_canonname(pai, res, canonname);
1675                 }
1676         } else
1677                 res0 = NULL;
1678         if (res0) {
1679                 cur->ai_next = res0;
1680                 while (cur && cur->ai_next)
1681                         cur = cur->ai_next;
1682         }
1683
1684         if (nextline) {
1685                 p = nextline;
1686                 goto nextline;
1687         }
1688
1689 done:
1690         return sentinel.ai_next;
1691 }
1692
1693 /*ARGSUSED*/
1694 static 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;
1754 }
1755 #endif
1756
1757 /* resolver logic */
1758
1759 extern const char *__hostalias (const char *);
1760 extern int h_errno;
1761
1762
1763 #ifdef NS_CACHING
1764 static int
1765 addrinfo_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
1833 static int
1834 addrinfo_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
1885 static int
1886 addrinfo_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
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  */
1951 static int
1952 res_queryN(const char *name,            /* domain name */
1953            struct res_target *target)
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  */
2068 static int
2069 res_searchN(const char *name,           /* domain name */
2070             struct res_target *target)
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  */
2206 static int
2207 res_querydomainN(const char *name, const char *domain,
2208                  struct res_target *target)
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 }