source: rtems-libbsd/freebsd/lib/libc/net/getaddrinfo.c @ f41a394

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since f41a394 was 3d1e767, checked in by Sebastian Huber <sebastian.huber@…>, on 04/27/16 at 08:25:22

Directly use <sys/types.h> provided by Newlib

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