]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/net/name6.c
Document RFTHREAD
[FreeBSD/FreeBSD.git] / lib / libc / net / name6.c
1 /*      $KAME: name6.c,v 1.25 2000/06/26 16:44:40 itojun Exp $  */
2
3 /*
4  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 /*
32  * ++Copyright++ 1985, 1988, 1993
33  * -
34  * Copyright (c) 1985, 1988, 1993
35  *    The Regents of the University of California.  All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  * 3. All advertising materials mentioning features or use of this software
46  *    must display the following acknowledgement:
47  *      This product includes software developed by the University of
48  *      California, Berkeley and its contributors.
49  * 4. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  * -
65  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
66  *
67  * Permission to use, copy, modify, and distribute this software for any
68  * purpose with or without fee is hereby granted, provided that the above
69  * copyright notice and this permission notice appear in all copies, and that
70  * the name of Digital Equipment Corporation not be used in advertising or
71  * publicity pertaining to distribution of the document or software without
72  * specific, written prior permission.
73  *
74  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
75  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
76  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
77  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
78  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
79  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
80  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
81  * SOFTWARE.
82  * -
83  * --Copyright--
84  */
85
86 /*
87  *      Atsushi Onoe <onoe@sm.sony.co.jp>
88  */
89
90 #include <sys/cdefs.h>
91 __FBSDID("$FreeBSD$");
92
93 #include "namespace.h"
94 #include <sys/param.h>
95 #include <sys/socket.h>
96 #include <sys/time.h>
97 #include <sys/queue.h>
98 #include <netinet/in.h>
99 #ifdef INET6
100 #include <net/if.h>
101 #include <net/if_var.h>
102 #include <sys/sysctl.h>
103 #include <sys/ioctl.h>
104 #include <netinet6/in6_var.h>   /* XXX */
105 #endif
106
107 #include <arpa/inet.h>
108 #include <arpa/nameser.h>
109
110 #include <errno.h>
111 #include <netdb.h>
112 #include <resolv.h>
113 #include <stdio.h>
114 #include <stdlib.h>
115 #include <string.h>
116 #include <stdarg.h>
117 #include <nsswitch.h>
118 #include <unistd.h>
119 #include "un-namespace.h"
120 #include "netdb_private.h"
121 #include "res_config.h"
122 #include "res_private.h"
123 #ifdef NS_CACHING
124 #include "nscache.h"
125 #endif
126
127 #ifndef _PATH_HOSTS
128 #define _PATH_HOSTS     "/etc/hosts"
129 #endif
130
131 #ifndef MAXALIASES
132 #define MAXALIASES      10
133 #endif
134 #ifndef MAXADDRS
135 #define MAXADDRS        20
136 #endif
137 #ifndef MAXDNAME
138 #define MAXDNAME        1025
139 #endif
140
141 #ifdef INET6
142 #define ADDRLEN(af)     ((af) == AF_INET6 ? sizeof(struct in6_addr) : \
143                                             sizeof(struct in_addr))
144 #else
145 #define ADDRLEN(af)     sizeof(struct in_addr)
146 #endif
147
148 #define MAPADDR(ab, ina) \
149 do {                                                                    \
150         memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr));         \
151         memset((ab)->map_zero, 0, sizeof((ab)->map_zero));              \
152         memset((ab)->map_one, 0xff, sizeof((ab)->map_one));             \
153 } while (0)
154 #define MAPADDRENABLED(flags) \
155         (((flags) & AI_V4MAPPED) || \
156          (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled()))
157
158 union inx_addr {
159         struct in_addr  in_addr;
160 #ifdef INET6
161         struct in6_addr in6_addr;
162 #endif
163         struct {
164                 u_char  mau_zero[10];
165                 u_char  mau_one[2];
166                 struct in_addr mau_inaddr;
167         }               map_addr_un;
168 #define map_zero        map_addr_un.mau_zero
169 #define map_one         map_addr_un.mau_one
170 #define map_inaddr      map_addr_un.mau_inaddr
171 };
172
173 struct policyqueue {
174         TAILQ_ENTRY(policyqueue) pc_entry;
175 #ifdef INET6
176         struct in6_addrpolicy pc_policy;
177 #endif
178 };
179 TAILQ_HEAD(policyhead, policyqueue);
180
181 #define AIO_SRCFLAG_DEPRECATED  0x1
182
183 struct hp_order {
184         union {
185                 struct sockaddr_storage aiou_ss;
186                 struct sockaddr aiou_sa;
187         } aio_src_un;
188 #define aio_srcsa aio_src_un.aiou_sa
189         u_int32_t aio_srcflag;
190         int aio_srcscope;
191         int aio_dstscope;
192         struct policyqueue *aio_srcpolicy;
193         struct policyqueue *aio_dstpolicy;
194         union {
195                 struct sockaddr_storage aiou_ss;
196                 struct sockaddr aiou_sa;
197         } aio_un;
198 #define aio_sa aio_un.aiou_sa
199         int aio_matchlen;
200         char *aio_h_addr;
201 };
202
203 static struct    hostent *_hpcopy(struct hostent *, int *);
204 static struct    hostent *_hpaddr(int, const char *, void *, int *);
205 static struct    hostent *_hpmerge(struct hostent *, struct hostent *, int *);
206 #ifdef INET6
207 static struct    hostent *_hpmapv6(struct hostent *, int *);
208 #endif
209 static struct    hostent *_hpsort(struct hostent *, res_state);
210 static struct    hostent *_ghbyname(const char *, int, int, int *);
211 static char     *_hgetword(char **);
212 static int       _mapped_addr_enabled(void);
213
214 static struct    hostent *_hpreorder(struct hostent *);
215 static int       get_addrselectpolicy(struct policyhead *);
216 static void      free_addrselectpolicy(struct policyhead *);
217 static struct    policyqueue *match_addrselectpolicy(struct sockaddr *,
218         struct policyhead *);
219 static void      set_source(struct hp_order *, struct policyhead *);
220 static int       matchlen(struct sockaddr *, struct sockaddr *);
221 static int       comp_dst(const void *, const void *);
222 static int       gai_addr2scopetype(struct sockaddr *);
223
224 static FILE     *_files_open(int *);
225 static int       _files_ghbyname(void *, void *, va_list);
226 static int       _files_ghbyaddr(void *, void *, va_list);
227 #ifdef YP
228 static int       _nis_ghbyname(void *, void *, va_list);
229 static int       _nis_ghbyaddr(void *, void *, va_list);
230 #endif
231 static int       _dns_ghbyname(void *, void *, va_list);
232 static int       _dns_ghbyaddr(void *, void *, va_list);
233 static void      _dns_shent(int) __unused;
234 static void      _dns_ehent(void) __unused;
235 #ifdef ICMPNL
236 static int       _icmp_ghbyaddr(void *, void *, va_list);
237 #endif /* ICMPNL */
238 #ifdef NS_CACHING
239 static int ipnode_id_func(char *, size_t *, va_list, void *);
240 static int ipnode_marshal_func(char *, size_t *, void *, va_list, void *);
241 static int ipnode_unmarshal_func(char *, size_t, void *, va_list, void *);
242 #endif
243
244 /* Host lookup order if nsswitch.conf is broken or nonexistant */
245 static const ns_src default_src[] = {
246         { NSSRC_FILES, NS_SUCCESS },
247         { NSSRC_DNS, NS_SUCCESS },
248 #ifdef ICMPNL
249 #define NSSRC_ICMP "icmp"
250         { NSSRC_ICMP, NS_SUCCESS },
251 #endif
252         { 0 }
253 };
254
255 /*
256  * Check if kernel supports mapped address.
257  *      implementation dependent
258  */
259 #ifdef __KAME__
260 #include <sys/sysctl.h>
261 #endif /* __KAME__ */
262
263 static int
264 _mapped_addr_enabled(void)
265 {
266         /* implementation dependent check */
267 #if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR)
268         int mib[4];
269         size_t len;
270         int val;
271
272         mib[0] = CTL_NET;
273         mib[1] = PF_INET6;
274         mib[2] = IPPROTO_IPV6;
275         mib[3] = IPV6CTL_MAPPED_ADDR;
276         len = sizeof(val);
277         if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0)
278                 return 1;
279 #endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */
280         return 0;
281 }
282
283 #ifdef NS_CACHING
284 static int
285 ipnode_id_func(char *buffer, size_t *buffer_size, va_list ap,
286     void *cache_mdata)
287 {
288         res_state statp;
289         u_long res_options;
290
291         const int op_id = 2;
292         char *name;
293         int af;
294         size_t len;
295         void *src;
296
297         char *p;
298         size_t desired_size, size;
299         enum nss_lookup_type lookup_type;
300         int res = NS_UNAVAIL;
301
302         statp = __res_state();
303         res_options = statp->options & (RES_RECURSE | RES_DEFNAMES |
304             RES_DNSRCH | RES_NOALIASES | RES_USE_INET6);
305
306         lookup_type = (enum nss_lookup_type)cache_mdata;
307         switch (lookup_type) {
308         case nss_lt_name:
309                 name = va_arg(ap, char *);
310                 af = va_arg(ap, int);
311
312                 size = strlen(name);
313                 desired_size = sizeof(res_options) + sizeof(int) +
314                     sizeof(enum nss_lookup_type) + sizeof(int) + size + 1;
315
316                 if (desired_size > *buffer_size) {
317                         res = NS_RETURN;
318                         goto fin;
319                 }
320
321                 p = buffer;
322                 memcpy(p, &res_options, sizeof(res_options));
323                 p += sizeof(res_options);
324
325                 memcpy(p, &op_id, sizeof(int));
326                 p += sizeof(int);
327
328                 memcpy(p, &lookup_type, sizeof(enum nss_lookup_type));
329                 p += sizeof(enum nss_lookup_type);
330
331                 memcpy(p, &af, sizeof(int));
332                 p += sizeof(int);
333
334                 memcpy(p, name, size + 1);
335
336                 res = NS_SUCCESS;
337                 break;
338         case nss_lt_id:
339                 src = va_arg(ap, void *);
340                 len = va_arg(ap, size_t);
341                 af = va_arg(ap, int);
342
343                 desired_size = sizeof(res_options) + sizeof(int) +
344                     sizeof(enum nss_lookup_type) + sizeof(int) +
345                     sizeof(size_t) + len;
346
347                 if (desired_size > *buffer_size) {
348                         res = NS_RETURN;
349                         goto fin;
350                 }
351
352                 p = buffer;
353                 memcpy(p, &res_options, sizeof(res_options));
354                 p += sizeof(res_options);
355
356                 memcpy(p, &op_id, sizeof(int));
357                 p += sizeof(int);
358
359                 memcpy(p, &lookup_type, sizeof(enum nss_lookup_type));
360                 p += sizeof(enum nss_lookup_type);
361
362                 memcpy(p, &af, sizeof(int));
363                 p += sizeof(int);
364
365                 memcpy(p, &len, sizeof(size_t));
366                 p += sizeof(size_t);
367
368                 memcpy(p, src, len);
369
370                 res = NS_SUCCESS;
371                 break;
372         default:
373                 /* should be unreachable */
374                 return (NS_UNAVAIL);
375         }
376
377 fin:
378         *buffer_size = desired_size;
379         return (res);
380 }
381
382 static int
383 ipnode_marshal_func(char *buffer, size_t *buffer_size, void *retval,
384     va_list ap, void *cache_mdata)
385 {
386         struct hostent *ht;
387
388         struct hostent new_ht;
389         size_t desired_size, aliases_size, addr_size, size;
390         char *p, **iter;
391
392         ht = *((struct hostent **)retval);
393
394         desired_size = _ALIGNBYTES + sizeof(struct hostent) + sizeof(char *);
395         if (ht->h_name != NULL)
396                 desired_size += strlen(ht->h_name) + 1;
397
398         if (ht->h_aliases != NULL) {
399                 aliases_size = 0;
400                 for (iter = ht->h_aliases; *iter; ++iter) {
401                         desired_size += strlen(*iter) + 1;
402                         ++aliases_size;
403                 }
404
405                 desired_size += _ALIGNBYTES +
406                     (aliases_size + 1) * sizeof(char *);
407         }
408
409         if (ht->h_addr_list != NULL) {
410                 addr_size = 0;
411                 for (iter = ht->h_addr_list; *iter; ++iter)
412                         ++addr_size;
413
414                 desired_size += addr_size * _ALIGN(ht->h_length);
415                 desired_size += _ALIGNBYTES + (addr_size + 1) * sizeof(char *);
416         }
417
418         if (desired_size > *buffer_size) {
419                 /* this assignment is here for future use */
420                 *buffer_size = desired_size;
421                 return (NS_RETURN);
422         }
423
424         memcpy(&new_ht, ht, sizeof(struct hostent));
425         memset(buffer, 0, desired_size);
426
427         *buffer_size = desired_size;
428         p = buffer + sizeof(struct hostent) + sizeof(char *);
429         memcpy(buffer + sizeof(struct hostent), &p, sizeof(char *));
430         p = (char *)_ALIGN(p);
431
432         if (new_ht.h_name != NULL) {
433                 size = strlen(new_ht.h_name);
434                 memcpy(p, new_ht.h_name, size);
435                 new_ht.h_name = p;
436                 p += size + 1;
437         }
438
439         if (new_ht.h_aliases != NULL) {
440                 p = (char *)_ALIGN(p);
441                 memcpy(p, new_ht.h_aliases, sizeof(char *) * aliases_size);
442                 new_ht.h_aliases = (char **)p;
443                 p += sizeof(char *) * (aliases_size + 1);
444
445                 for (iter = new_ht.h_aliases; *iter; ++iter) {
446                         size = strlen(*iter);
447                         memcpy(p, *iter, size);
448                         *iter = p;
449                         p += size + 1;
450                 }
451         }
452
453         if (new_ht.h_addr_list != NULL) {
454                 p = (char *)_ALIGN(p);
455                 memcpy(p, new_ht.h_addr_list, sizeof(char *) * addr_size);
456                 new_ht.h_addr_list = (char **)p;
457                 p += sizeof(char *) * (addr_size + 1);
458
459                 size = _ALIGN(new_ht.h_length);
460                 for (iter = new_ht.h_addr_list; *iter; ++iter) {
461                         memcpy(p, *iter, size);
462                         *iter = p;
463                         p += size + 1;
464                 }
465         }
466         memcpy(buffer, &new_ht, sizeof(struct hostent));
467         return (NS_SUCCESS);
468 }
469
470 static int
471 ipnode_unmarshal_func(char *buffer, size_t buffer_size, void *retval,
472     va_list ap, void *cache_mdata)
473 {
474         struct hostent new_ht;
475         struct hostent *ht;
476
477         char *p;
478         char **iter;
479         char *orig_buf;
480         int err;
481
482         ht = &new_ht;
483
484         memcpy(ht, buffer, sizeof(struct hostent));
485         memcpy(&p, buffer + sizeof(struct hostent), sizeof(char *));
486
487         orig_buf = buffer + sizeof(struct hostent) + sizeof(char *) +
488             _ALIGN(p) - (size_t)p;
489         p = (char *)_ALIGN(p);
490
491
492         NS_APPLY_OFFSET(ht->h_name, orig_buf, p, char *);
493         if (ht->h_aliases != NULL) {
494                 NS_APPLY_OFFSET(ht->h_aliases, orig_buf, p, char **);
495
496                 for (iter = ht->h_aliases; *iter; ++iter)
497                         NS_APPLY_OFFSET(*iter, orig_buf, p, char *);
498         }
499
500         if (ht->h_addr_list != NULL) {
501                 NS_APPLY_OFFSET(ht->h_addr_list, orig_buf, p, char **);
502
503                 for (iter = ht->h_addr_list; *iter; ++iter)
504                         NS_APPLY_OFFSET(*iter, orig_buf, p, char *);
505         }
506
507         ht = _hpcopy(ht, &err);
508         if (ht == NULL)
509                 return (NS_UNAVAIL);
510
511         *((struct hostent **)retval) = ht;
512         return (NS_SUCCESS);
513 }
514 #endif
515
516 /*
517  * Functions defined in RFC2553
518  *      getipnodebyname, getipnodebyaddr, freehostent
519  */
520
521 static struct hostent *
522 _ghbyname(const char *name, int af, int flags, int *errp)
523 {
524         struct hostent *hp;
525         int rval;
526
527 #ifdef NS_CACHING
528         static const nss_cache_info cache_info =
529         NS_COMMON_CACHE_INFO_INITIALIZER(
530                 hosts, (void *)nss_lt_name,
531                 ipnode_id_func, ipnode_marshal_func, ipnode_unmarshal_func);
532 #endif
533         static const ns_dtab dtab[] = {
534                 NS_FILES_CB(_files_ghbyname, NULL)
535                 { NSSRC_DNS, _dns_ghbyname, NULL },
536                 NS_NIS_CB(_nis_ghbyname, NULL)
537 #ifdef NS_CACHING
538                 NS_CACHE_CB(&cache_info)
539 #endif
540                 { 0 }
541         };
542
543         if (flags & AI_ADDRCONFIG) {
544                 int s;
545
546                 if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
547                         return NULL;
548                 /*
549                  * TODO:
550                  * Note that implementation dependent test for address
551                  * configuration should be done everytime called
552                  * (or apropriate interval),
553                  * because addresses will be dynamically assigned or deleted.
554                  */
555                 _close(s);
556         }
557
558         rval = _nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyname", default_src,
559                           name, af, errp);
560         return (rval == NS_SUCCESS) ? hp : NULL;
561 }
562
563 struct hostent *
564 getipnodebyname(const char *name, int af, int flags, int *errp)
565 {
566         struct hostent *hp;
567         union inx_addr addrbuf;
568         res_state statp;
569
570         switch (af) {
571         case AF_INET:
572 #ifdef INET6
573         case AF_INET6:
574 #endif
575                 break;
576         default:
577                 *errp = NO_RECOVERY;
578                 return NULL;
579         }
580
581 #ifdef INET6
582         /* special case for literal address */
583         if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
584                 if (af != AF_INET6) {
585                         *errp = HOST_NOT_FOUND;
586                         return NULL;
587                 }
588                 return _hpaddr(af, name, &addrbuf, errp);
589         }
590 #endif
591         if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) {
592                 if (af != AF_INET) {
593                         if (MAPADDRENABLED(flags)) {
594                                 MAPADDR(&addrbuf, &addrbuf.in_addr);
595                         } else {
596                                 *errp = HOST_NOT_FOUND;
597                                 return NULL;
598                         }
599                 }
600                 return _hpaddr(af, name, &addrbuf, errp);
601         }
602
603         statp = __res_state();
604         if ((statp->options & RES_INIT) == 0) {
605                 if (res_ninit(statp) < 0) {
606                         *errp = NETDB_INTERNAL;
607                         return NULL;
608                 }
609         }
610
611         *errp = HOST_NOT_FOUND;
612         hp = _ghbyname(name, af, flags, errp);
613
614 #ifdef INET6
615         if (af == AF_INET6 && ((flags & AI_ALL) || hp == NULL) &&
616             MAPADDRENABLED(flags)) {
617                 struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp);
618                 if (hp == NULL)
619                         hp = _hpmapv6(hp2, errp);
620                 else {
621                         if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) {
622                                 freehostent(hp2);
623                                 hp2 = NULL;
624                         }
625                         hp = _hpmerge(hp, hp2, errp);
626                 }
627         }
628 #endif
629         return _hpreorder(_hpsort(hp, statp));
630 }
631
632 struct hostent *
633 getipnodebyaddr(const void *src, size_t len, int af, int *errp)
634 {
635         struct hostent *hp;
636         int rval;
637 #ifdef INET6
638         struct in6_addr addrbuf;
639 #else
640         struct in_addr addrbuf;
641 #endif
642
643 #ifdef NS_CACHING
644         static const nss_cache_info cache_info =
645         NS_COMMON_CACHE_INFO_INITIALIZER(
646                 hosts, (void *)nss_lt_id,
647                 ipnode_id_func, ipnode_marshal_func, ipnode_unmarshal_func);
648 #endif
649         static const ns_dtab dtab[] = {
650                 NS_FILES_CB(_files_ghbyaddr, NULL)
651                 { NSSRC_DNS, _dns_ghbyaddr, NULL },
652                 NS_NIS_CB(_nis_ghbyaddr, NULL)
653 #ifdef ICMPNL
654                 { NSSRC_ICMP, _icmp_ghbyaddr, NULL },
655 #endif
656 #ifdef NS_CACHING
657                 NS_CACHE_CB(&cache_info)
658 #endif
659                 { 0 }
660         };
661
662         *errp = HOST_NOT_FOUND;
663
664         switch (af) {
665         case AF_INET:
666                 if (len != sizeof(struct in_addr)) {
667                         *errp = NO_RECOVERY;
668                         return NULL;
669                 }
670                 if ((long)src & ~(sizeof(struct in_addr) - 1)) {
671                         memcpy(&addrbuf, src, len);
672                         src = &addrbuf;
673                 }
674                 if (((struct in_addr *)src)->s_addr == 0)
675                         return NULL;
676                 break;
677 #ifdef INET6
678         case AF_INET6:
679                 if (len != sizeof(struct in6_addr)) {
680                         *errp = NO_RECOVERY;
681                         return NULL;
682                 }
683                 if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) {   /*XXX*/
684                         memcpy(&addrbuf, src, len);
685                         src = &addrbuf;
686                 }
687                 if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src))
688                         return NULL;
689                 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)
690                 ||  IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) {
691                         src = (char *)src +
692                             (sizeof(struct in6_addr) - sizeof(struct in_addr));
693                         af = AF_INET;
694                         len = sizeof(struct in_addr);
695                 }
696                 break;
697 #endif
698         default:
699                 *errp = NO_RECOVERY;
700                 return NULL;
701         }
702
703         rval = _nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyaddr", default_src,
704                           src, len, af, errp);
705         return (rval == NS_SUCCESS) ? hp : NULL;
706 }
707
708 void
709 freehostent(struct hostent *ptr)
710 {
711         free(ptr);
712 }
713
714 /*
715  * Private utility functions
716  */
717
718 /*
719  * _hpcopy: allocate and copy hostent structure
720  */
721 static struct hostent *
722 _hpcopy(struct hostent *hp, int *errp)
723 {
724         struct hostent *nhp;
725         char *cp, **pp;
726         int size, addrsize;
727         int nalias = 0, naddr = 0;
728         int al_off;
729         int i;
730
731         if (hp == NULL)
732                 return hp;
733
734         /* count size to be allocated */
735         size = sizeof(struct hostent);
736         if (hp->h_name != NULL)
737                 size += strlen(hp->h_name) + 1;
738         if ((pp = hp->h_aliases) != NULL) {
739                 for (i = 0; *pp != NULL; i++, pp++) {
740                         if (**pp != '\0') {
741                                 size += strlen(*pp) + 1;
742                                 nalias++;
743                         }
744                 }
745         }
746         /* adjust alignment */
747         size = ALIGN(size);
748         al_off = size;
749         size += sizeof(char *) * (nalias + 1);
750         addrsize = ALIGN(hp->h_length);
751         if ((pp = hp->h_addr_list) != NULL) {
752                 while (*pp++ != NULL)
753                         naddr++;
754         }
755         size += addrsize * naddr;
756         size += sizeof(char *) * (naddr + 1);
757
758         /* copy */
759         if ((nhp = (struct hostent *)malloc(size)) == NULL) {
760                 *errp = TRY_AGAIN;
761                 return NULL;
762         }
763         cp = (char *)&nhp[1];
764         if (hp->h_name != NULL) {
765                 nhp->h_name = cp;
766                 strcpy(cp, hp->h_name);
767                 cp += strlen(cp) + 1;
768         } else
769                 nhp->h_name = NULL;
770         nhp->h_aliases = (char **)((char *)nhp + al_off);
771         if ((pp = hp->h_aliases) != NULL) {
772                 for (i = 0; *pp != NULL; pp++) {
773                         if (**pp != '\0') {
774                                 nhp->h_aliases[i++] = cp;
775                                 strcpy(cp, *pp);
776                                 cp += strlen(cp) + 1;
777                         }
778                 }
779         }
780         nhp->h_aliases[nalias] = NULL;
781         cp = (char *)&nhp->h_aliases[nalias + 1];
782         nhp->h_addrtype = hp->h_addrtype;
783         nhp->h_length = hp->h_length;
784         nhp->h_addr_list = (char **)cp;
785         if ((pp = hp->h_addr_list) != NULL) {
786                 cp = (char *)&nhp->h_addr_list[naddr + 1];
787                 for (i = 0; *pp != NULL; pp++) {
788                         nhp->h_addr_list[i++] = cp;
789                         memcpy(cp, *pp, hp->h_length);
790                         cp += addrsize;
791                 }
792         }
793         nhp->h_addr_list[naddr] = NULL;
794         return nhp;
795 }
796
797 /*
798  * _hpaddr: construct hostent structure with one address
799  */
800 static struct hostent *
801 _hpaddr(int af, const char *name, void *addr, int *errp)
802 {
803         struct hostent *hp, hpbuf;
804         char *addrs[2];
805
806         hp = &hpbuf;
807         hp->h_name = (char *)name;
808         hp->h_aliases = NULL;
809         hp->h_addrtype = af;
810         hp->h_length = ADDRLEN(af);
811         hp->h_addr_list = addrs;
812         addrs[0] = (char *)addr;
813         addrs[1] = NULL;
814         return _hpcopy(hp, errp);
815 }
816
817 /*
818  * _hpmerge: merge 2 hostent structure, arguments will be freed
819  */
820 static struct hostent *
821 _hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp)
822 {
823         int i, j;
824         int naddr, nalias;
825         char **pp;
826         struct hostent *hp, hpbuf;
827         char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1];
828         union inx_addr addrbuf[MAXADDRS];
829
830         if (hp1 == NULL)
831                 return hp2;
832         if (hp2 == NULL)
833                 return hp1;
834
835 #define HP(i)   (i == 1 ? hp1 : hp2)
836         hp = &hpbuf;
837         hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name);
838         hp->h_aliases = aliases;
839         nalias = 0;
840         for (i = 1; i <= 2; i++) {
841                 if ((pp = HP(i)->h_aliases) == NULL)
842                         continue;
843                 for (; nalias < MAXALIASES && *pp != NULL; pp++) {
844                         /* check duplicates */
845                         for (j = 0; j < nalias; j++)
846                                 if (strcasecmp(*pp, aliases[j]) == 0)
847                                         break;
848                         if (j == nalias)
849                                 aliases[nalias++] = *pp;
850                 }
851         }
852         aliases[nalias] = NULL;
853 #ifdef INET6
854         if (hp1->h_length != hp2->h_length) {
855                 hp->h_addrtype = AF_INET6;
856                 hp->h_length = sizeof(struct in6_addr);
857         } else {
858 #endif
859                 hp->h_addrtype = hp1->h_addrtype;
860                 hp->h_length = hp1->h_length;
861 #ifdef INET6
862         }
863 #endif
864         hp->h_addr_list = addrs;
865         naddr = 0;
866         for (i = 1; i <= 2; i++) {
867                 if ((pp = HP(i)->h_addr_list) == NULL)
868                         continue;
869                 if (HP(i)->h_length == hp->h_length) {
870                         while (naddr < MAXADDRS && *pp != NULL)
871                                 addrs[naddr++] = *pp++;
872                 } else {
873                         /* copy IPv4 addr as mapped IPv6 addr */
874                         while (naddr < MAXADDRS && *pp != NULL) {
875                                 MAPADDR(&addrbuf[naddr], *pp++);
876                                 addrs[naddr] = (char *)&addrbuf[naddr];
877                                 naddr++;
878                         }
879                 }
880         }
881         addrs[naddr] = NULL;
882         hp = _hpcopy(hp, errp);
883         freehostent(hp1);
884         freehostent(hp2);
885         return hp;
886 }
887
888 /*
889  * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses
890  */
891 #ifdef INET6
892 static struct hostent *
893 _hpmapv6(struct hostent *hp, int *errp)
894 {
895         struct hostent *hp6;
896
897         if (hp == NULL)
898                 return NULL;
899         if (hp->h_addrtype == AF_INET6)
900                 return hp;
901
902         /* make dummy hostent to convert IPv6 address */
903         if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) {
904                 *errp = TRY_AGAIN;
905                 return NULL;
906         }
907         hp6->h_name = NULL;
908         hp6->h_aliases = NULL;
909         hp6->h_addrtype = AF_INET6;
910         hp6->h_length = sizeof(struct in6_addr);
911         hp6->h_addr_list = NULL;
912         return _hpmerge(hp6, hp, errp);
913 }
914 #endif
915
916 /*
917  * _hpsort: sort address by sortlist
918  */
919 static struct hostent *
920 _hpsort(struct hostent *hp, res_state statp)
921 {
922         int i, j, n;
923         u_char *ap, *sp, *mp, **pp;
924         char t;
925         char order[MAXADDRS];
926         int nsort = statp->nsort;
927
928         if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0)
929                 return hp;
930         for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) {
931                 for (j = 0; j < nsort; j++) {
932 #ifdef INET6
933                         if (statp->_u._ext.ext->sort_list[j].af !=
934                             hp->h_addrtype)
935                                 continue;
936                         sp = (u_char *)&statp->_u._ext.ext->sort_list[j].addr;
937                         mp = (u_char *)&statp->_u._ext.ext->sort_list[j].mask;
938 #else
939                         sp = (u_char *)&statp->sort_list[j].addr;
940                         mp = (u_char *)&statp->sort_list[j].mask;
941 #endif
942                         for (n = 0; n < hp->h_length; n++) {
943                                 if ((ap[n] & mp[n]) != sp[n])
944                                         break;
945                         }
946                         if (n == hp->h_length)
947                                 break;
948                 }
949                 order[i] = j;
950         }
951         n = i;
952         pp = (u_char **)hp->h_addr_list;
953         for (i = 0; i < n - 1; i++) {
954                 for (j = i + 1; j < n; j++) {
955                         if (order[i] > order[j]) {
956                                 ap = pp[i];
957                                 pp[i] = pp[j];
958                                 pp[j] = ap;
959                                 t = order[i];
960                                 order[i] = order[j];
961                                 order[j] = t;
962                         }
963                 }
964         }
965         return hp;
966 }
967
968 static char *
969 _hgetword(char **pp)
970 {
971         char c, *p, *ret;
972         const char *sp;
973         static const char sep[] = "# \t\n";
974
975         ret = NULL;
976         for (p = *pp; (c = *p) != '\0'; p++) {
977                 for (sp = sep; *sp != '\0'; sp++) {
978                         if (c == *sp)
979                                 break;
980                 }
981                 if (c == '#')
982                         p[1] = '\0';    /* ignore rest of line */
983                 if (ret == NULL) {
984                         if (*sp == '\0')
985                                 ret = p;
986                 } else {
987                         if (*sp != '\0') {
988                                 *p++ = '\0';
989                                 break;
990                         }
991                 }
992         }
993         *pp = p;
994         if (ret == NULL || *ret == '\0')
995                 return NULL;
996         return ret;
997 }
998
999 /*
1000  * _hpreorder: sort address by default address selection
1001  */
1002 static struct hostent *
1003 _hpreorder(struct hostent *hp)
1004 {
1005         struct hp_order *aio;
1006         int i, n;
1007         char *ap;
1008         struct sockaddr *sa;
1009         struct policyhead policyhead;
1010
1011         if (hp == NULL)
1012                 return hp;
1013
1014         switch (hp->h_addrtype) {
1015         case AF_INET:
1016 #ifdef INET6
1017         case AF_INET6:
1018 #endif
1019                 break;
1020         default:
1021                 free_addrselectpolicy(&policyhead);
1022                 return hp;
1023         }
1024
1025         /* count the number of addrinfo elements for sorting. */
1026         for (n = 0; hp->h_addr_list[n] != NULL; n++)
1027                 ;
1028
1029         /*
1030          * If the number is small enough, we can skip the reordering process.
1031          */
1032         if (n <= 1)
1033                 return hp;
1034
1035         /* allocate a temporary array for sort and initialization of it. */
1036         if ((aio = malloc(sizeof(*aio) * n)) == NULL)
1037                 return hp;      /* give up reordering */
1038         memset(aio, 0, sizeof(*aio) * n);
1039
1040         /* retrieve address selection policy from the kernel */
1041         TAILQ_INIT(&policyhead);
1042         if (!get_addrselectpolicy(&policyhead)) {
1043                 /* no policy is installed into kernel, we don't sort. */
1044                 free(aio);
1045                 return hp;
1046         }
1047
1048         for (i = 0; i < n; i++) {
1049                 ap = hp->h_addr_list[i];
1050                 aio[i].aio_h_addr = ap;
1051                 sa = &aio[i].aio_sa;
1052                 switch (hp->h_addrtype) {
1053                 case AF_INET:
1054                         sa->sa_family = AF_INET;
1055                         sa->sa_len = sizeof(struct sockaddr_in);
1056                         memcpy(&((struct sockaddr_in *)sa)->sin_addr, ap,
1057                             sizeof(struct in_addr));
1058                         break;
1059 #ifdef INET6
1060                 case AF_INET6:
1061                         if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
1062                                 sa->sa_family = AF_INET;
1063                                 sa->sa_len = sizeof(struct sockaddr_in);
1064                                 memcpy(&((struct sockaddr_in *)sa)->sin_addr,
1065                                     &ap[12], sizeof(struct in_addr));
1066                         } else {
1067                                 sa->sa_family = AF_INET6;
1068                                 sa->sa_len = sizeof(struct sockaddr_in6);
1069                                 memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr,
1070                                     ap, sizeof(struct in6_addr));
1071                         }
1072                         break;
1073 #endif
1074                 }
1075                 aio[i].aio_dstscope = gai_addr2scopetype(sa);
1076                 aio[i].aio_dstpolicy = match_addrselectpolicy(sa, &policyhead);
1077                 set_source(&aio[i], &policyhead);
1078         }
1079
1080         /* perform sorting. */
1081         qsort(aio, n, sizeof(*aio), comp_dst);
1082
1083         /* reorder the h_addr_list. */
1084         for (i = 0; i < n; i++)
1085                 hp->h_addr_list[i] = aio[i].aio_h_addr;
1086
1087         /* cleanup and return */
1088         free(aio);
1089         free_addrselectpolicy(&policyhead);
1090         return hp;
1091 }
1092
1093 static int
1094 get_addrselectpolicy(struct policyhead *head)
1095 {
1096 #ifdef INET6
1097         int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY };
1098         size_t l;
1099         char *buf;
1100         struct in6_addrpolicy *pol, *ep;
1101
1102         if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0)
1103                 return (0);
1104         if ((buf = malloc(l)) == NULL)
1105                 return (0);
1106         if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
1107                 free(buf);
1108                 return (0);
1109         }
1110
1111         ep = (struct in6_addrpolicy *)(buf + l);
1112         for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) {
1113                 struct policyqueue *new;
1114
1115                 if ((new = malloc(sizeof(*new))) == NULL) {
1116                         free_addrselectpolicy(head); /* make the list empty */
1117                         break;
1118                 }
1119                 new->pc_policy = *pol;
1120                 TAILQ_INSERT_TAIL(head, new, pc_entry);
1121         }
1122
1123         free(buf);
1124         return (1);
1125 #else
1126         return (0);
1127 #endif
1128 }
1129
1130 static void
1131 free_addrselectpolicy(struct policyhead *head)
1132 {
1133         struct policyqueue *ent, *nent;
1134
1135         for (ent = TAILQ_FIRST(head); ent; ent = nent) {
1136                 nent = TAILQ_NEXT(ent, pc_entry);
1137                 TAILQ_REMOVE(head, ent, pc_entry);
1138                 free(ent);
1139         }
1140 }
1141
1142 static struct policyqueue *
1143 match_addrselectpolicy(struct sockaddr *addr, struct policyhead *head)
1144 {
1145 #ifdef INET6
1146         struct policyqueue *ent, *bestent = NULL;
1147         struct in6_addrpolicy *pol;
1148         int matchlen, bestmatchlen = -1;
1149         u_char *mp, *ep, *k, *p, m;
1150         struct sockaddr_in6 key;
1151
1152         switch(addr->sa_family) {
1153         case AF_INET6:
1154                 key = *(struct sockaddr_in6 *)addr;
1155                 break;
1156         case AF_INET:
1157                 /* convert the address into IPv4-mapped IPv6 address. */
1158                 memset(&key, 0, sizeof(key));
1159                 key.sin6_family = AF_INET6;
1160                 key.sin6_len = sizeof(key);
1161                 key.sin6_addr.s6_addr[10] = 0xff;
1162                 key.sin6_addr.s6_addr[11] = 0xff;
1163                 memcpy(&key.sin6_addr.s6_addr[12],
1164                        &((struct sockaddr_in *)addr)->sin_addr, 4);
1165                 break;
1166         default:
1167                 return(NULL);
1168         }
1169
1170         for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) {
1171                 pol = &ent->pc_policy;
1172                 matchlen = 0;
1173
1174                 mp = (u_char *)&pol->addrmask.sin6_addr;
1175                 ep = mp + 16;   /* XXX: scope field? */
1176                 k = (u_char *)&key.sin6_addr;
1177                 p = (u_char *)&pol->addr.sin6_addr;
1178                 for (; mp < ep && *mp; mp++, k++, p++) {
1179                         m = *mp;
1180                         if ((*k & m) != *p)
1181                                 goto next; /* not match */
1182                         if (m == 0xff) /* short cut for a typical case */
1183                                 matchlen += 8;
1184                         else {
1185                                 while (m >= 0x80) {
1186                                         matchlen++;
1187                                         m <<= 1;
1188                                 }
1189                         }
1190                 }
1191
1192                 /* matched.  check if this is better than the current best. */
1193                 if (matchlen > bestmatchlen) {
1194                         bestent = ent;
1195                         bestmatchlen = matchlen;
1196                 }
1197
1198           next:
1199                 continue;
1200         }
1201
1202         return(bestent);
1203 #else
1204         return(NULL);
1205 #endif
1206
1207 }
1208
1209 static void
1210 set_source(struct hp_order *aio, struct policyhead *ph)
1211 {
1212         struct sockaddr_storage ss = aio->aio_un.aiou_ss;
1213         socklen_t srclen;
1214         int s;
1215
1216         /* set unspec ("no source is available"), just in case */
1217         aio->aio_srcsa.sa_family = AF_UNSPEC;
1218         aio->aio_srcscope = -1;
1219
1220         switch(ss.ss_family) {
1221         case AF_INET:
1222                 ((struct sockaddr_in *)&ss)->sin_port = htons(1);
1223                 break;
1224 #ifdef INET6
1225         case AF_INET6:
1226                 ((struct sockaddr_in6 *)&ss)->sin6_port = htons(1);
1227                 break;
1228 #endif
1229         default:                /* ignore unsupported AFs explicitly */
1230                 return;
1231         }
1232
1233         /* open a socket to get the source address for the given dst */
1234         if ((s = _socket(ss.ss_family, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1235                 return;         /* give up */
1236         if (_connect(s, (struct sockaddr *)&ss, ss.ss_len) < 0)
1237                 goto cleanup;
1238         srclen = ss.ss_len;
1239         if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) {
1240                 aio->aio_srcsa.sa_family = AF_UNSPEC;
1241                 goto cleanup;
1242         }
1243         aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa);
1244         aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph);
1245         aio->aio_matchlen = matchlen(&aio->aio_srcsa, (struct sockaddr *)&ss);
1246 #ifdef INET6
1247         if (ss.ss_family == AF_INET6) {
1248                 struct in6_ifreq ifr6;
1249                 u_int32_t flags6;
1250
1251                 /* XXX: interface name should not be hardcoded */
1252                 strncpy(ifr6.ifr_name, "lo0", sizeof(ifr6.ifr_name));
1253                 memset(&ifr6, 0, sizeof(ifr6));
1254                 memcpy(&ifr6.ifr_addr, &ss, ss.ss_len);
1255                 if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) {
1256                         flags6 = ifr6.ifr_ifru.ifru_flags6;
1257                         if ((flags6 & IN6_IFF_DEPRECATED))
1258                                 aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED;
1259                 }
1260         }
1261 #endif
1262
1263   cleanup:
1264         _close(s);
1265         return;
1266 }
1267
1268 static int
1269 matchlen(struct sockaddr *src, struct sockaddr *dst)
1270 {
1271         int match = 0;
1272         u_char *s, *d;
1273         u_char *lim, r;
1274         int addrlen;
1275
1276         switch (src->sa_family) {
1277 #ifdef INET6
1278         case AF_INET6:
1279                 s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr;
1280                 d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr;
1281                 addrlen = sizeof(struct in6_addr);
1282                 lim = s + addrlen;
1283                 break;
1284 #endif
1285         case AF_INET:
1286                 s = (u_char *)&((struct sockaddr_in *)src)->sin_addr;
1287                 d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr;
1288                 addrlen = sizeof(struct in_addr);
1289                 lim = s + addrlen;
1290                 break;
1291         default:
1292                 return(0);
1293         }
1294
1295         while (s < lim)
1296                 if ((r = (*d++ ^ *s++)) != 0) {
1297                         while (r < addrlen * 8) {
1298                                 match++;
1299                                 r <<= 1;
1300                         }
1301                         break;
1302                 } else
1303                         match += 8;
1304         return(match);
1305 }
1306
1307 static int
1308 comp_dst(const void *arg1, const void *arg2)
1309 {
1310         const struct hp_order *dst1 = arg1, *dst2 = arg2;
1311
1312         /*
1313          * Rule 1: Avoid unusable destinations.
1314          * XXX: we currently do not consider if an appropriate route exists.
1315          */
1316         if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
1317             dst2->aio_srcsa.sa_family == AF_UNSPEC) {
1318                 return(-1);
1319         }
1320         if (dst1->aio_srcsa.sa_family == AF_UNSPEC &&
1321             dst2->aio_srcsa.sa_family != AF_UNSPEC) {
1322                 return(1);
1323         }
1324
1325         /* Rule 2: Prefer matching scope. */
1326         if (dst1->aio_dstscope == dst1->aio_srcscope &&
1327             dst2->aio_dstscope != dst2->aio_srcscope) {
1328                 return(-1);
1329         }
1330         if (dst1->aio_dstscope != dst1->aio_srcscope &&
1331             dst2->aio_dstscope == dst2->aio_srcscope) {
1332                 return(1);
1333         }
1334
1335         /* Rule 3: Avoid deprecated addresses. */
1336         if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
1337             dst2->aio_srcsa.sa_family != AF_UNSPEC) {
1338                 if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
1339                     (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
1340                         return(-1);
1341                 }
1342                 if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
1343                     !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
1344                         return(1);
1345                 }
1346         }
1347
1348         /* Rule 4: Prefer home addresses. */
1349         /* XXX: not implemented yet */
1350
1351         /* Rule 5: Prefer matching label. */
1352 #ifdef INET6
1353         if (dst1->aio_srcpolicy && dst1->aio_dstpolicy &&
1354             dst1->aio_srcpolicy->pc_policy.label ==
1355             dst1->aio_dstpolicy->pc_policy.label &&
1356             (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL ||
1357              dst2->aio_srcpolicy->pc_policy.label !=
1358              dst2->aio_dstpolicy->pc_policy.label)) {
1359                 return(-1);
1360         }
1361         if (dst2->aio_srcpolicy && dst2->aio_dstpolicy &&
1362             dst2->aio_srcpolicy->pc_policy.label ==
1363             dst2->aio_dstpolicy->pc_policy.label &&
1364             (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL ||
1365              dst1->aio_srcpolicy->pc_policy.label !=
1366              dst1->aio_dstpolicy->pc_policy.label)) {
1367                 return(1);
1368         }
1369 #endif
1370
1371         /* Rule 6: Prefer higher precedence. */
1372 #ifdef INET6
1373         if (dst1->aio_dstpolicy &&
1374             (dst2->aio_dstpolicy == NULL ||
1375              dst1->aio_dstpolicy->pc_policy.preced >
1376              dst2->aio_dstpolicy->pc_policy.preced)) {
1377                 return(-1);
1378         }
1379         if (dst2->aio_dstpolicy &&
1380             (dst1->aio_dstpolicy == NULL ||
1381              dst2->aio_dstpolicy->pc_policy.preced >
1382              dst1->aio_dstpolicy->pc_policy.preced)) {
1383                 return(1);
1384         }
1385 #endif
1386
1387         /* Rule 7: Prefer native transport. */
1388         /* XXX: not implemented yet */
1389
1390         /* Rule 8: Prefer smaller scope. */
1391         if (dst1->aio_dstscope >= 0 &&
1392             dst1->aio_dstscope < dst2->aio_dstscope) {
1393                 return(-1);
1394         }
1395         if (dst2->aio_dstscope >= 0 &&
1396             dst2->aio_dstscope < dst1->aio_dstscope) {
1397                 return(1);
1398         }
1399
1400         /*
1401          * Rule 9: Use longest matching prefix.
1402          * We compare the match length in a same AF only.
1403          */
1404         if (dst1->aio_sa.sa_family == dst2->aio_sa.sa_family) {
1405                 if (dst1->aio_matchlen > dst2->aio_matchlen) {
1406                         return(-1);
1407                 }
1408                 if (dst1->aio_matchlen < dst2->aio_matchlen) {
1409                         return(1);
1410                 }
1411         }
1412
1413         /* Rule 10: Otherwise, leave the order unchanged. */
1414         return(-1);
1415 }
1416
1417 /*
1418  * Copy from scope.c.
1419  * XXX: we should standardize the functions and link them as standard
1420  * library.
1421  */
1422 static int
1423 gai_addr2scopetype(struct sockaddr *sa)
1424 {
1425 #ifdef INET6
1426         struct sockaddr_in6 *sa6;
1427 #endif
1428         struct sockaddr_in *sa4;
1429
1430         switch(sa->sa_family) {
1431 #ifdef INET6
1432         case AF_INET6:
1433                 sa6 = (struct sockaddr_in6 *)sa;
1434                 if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
1435                         /* just use the scope field of the multicast address */
1436                         return(sa6->sin6_addr.s6_addr[2] & 0x0f);
1437                 }
1438                 /*
1439                  * Unicast addresses: map scope type to corresponding scope
1440                  * value defined for multcast addresses.
1441                  * XXX: hardcoded scope type values are bad...
1442                  */
1443                 if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr))
1444                         return(1); /* node local scope */
1445                 if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr))
1446                         return(2); /* link-local scope */
1447                 if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr))
1448                         return(5); /* site-local scope */
1449                 return(14);     /* global scope */
1450                 break;
1451 #endif
1452         case AF_INET:
1453                 /*
1454                  * IPv4 pseudo scoping according to RFC 3484.
1455                  */
1456                 sa4 = (struct sockaddr_in *)sa;
1457                 /* IPv4 autoconfiguration addresses have link-local scope. */
1458                 if (((u_char *)&sa4->sin_addr)[0] == 169 &&
1459                     ((u_char *)&sa4->sin_addr)[1] == 254)
1460                         return(2);
1461                 /* Private addresses have site-local scope. */
1462                 if (((u_char *)&sa4->sin_addr)[0] == 10 ||
1463                     (((u_char *)&sa4->sin_addr)[0] == 172 &&
1464                      (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) ||
1465                     (((u_char *)&sa4->sin_addr)[0] == 192 &&
1466                      ((u_char *)&sa4->sin_addr)[1] == 168))
1467                         return(14);     /* XXX: It should be 5 unless NAT */
1468                 /* Loopback addresses have link-local scope. */
1469                 if (((u_char *)&sa4->sin_addr)[0] == 127)
1470                         return(2);
1471                 return(14);
1472                 break;
1473         default:
1474                 errno = EAFNOSUPPORT; /* is this a good error? */
1475                 return(-1);
1476         }
1477 }
1478
1479 /*
1480  * FILES (/etc/hosts)
1481  */
1482
1483 static FILE *
1484 _files_open(int *errp)
1485 {
1486         FILE *fp;
1487         fp = fopen(_PATH_HOSTS, "r");
1488         if (fp == NULL)
1489                 *errp = NO_RECOVERY;
1490         return fp;
1491 }
1492
1493 static int
1494 _files_ghbyname(void *rval, void *cb_data, va_list ap)
1495 {
1496         const char *name;
1497         int af;
1498         int *errp;
1499         int match, nalias;
1500         char *p, *line, *addrstr, *cname;
1501         FILE *fp;
1502         struct hostent *rethp, *hp, hpbuf;
1503         char *aliases[MAXALIASES + 1], *addrs[2];
1504         union inx_addr addrbuf;
1505         char buf[BUFSIZ];
1506
1507         name = va_arg(ap, const char *);
1508         af = va_arg(ap, int);
1509         errp = va_arg(ap, int *);
1510
1511         *(struct hostent **)rval = NULL;
1512
1513         if ((fp = _files_open(errp)) == NULL)
1514                 return NS_UNAVAIL;
1515         rethp = hp = NULL;
1516
1517         while (fgets(buf, sizeof(buf), fp)) {
1518                 line = buf;
1519                 if ((addrstr = _hgetword(&line)) == NULL
1520                 ||  (cname = _hgetword(&line)) == NULL)
1521                         continue;
1522                 match = (strcasecmp(cname, name) == 0);
1523                 nalias = 0;
1524                 while ((p = _hgetword(&line)) != NULL) {
1525                         if (!match)
1526                                 match = (strcasecmp(p, name) == 0);
1527                         if (nalias < MAXALIASES)
1528                                 aliases[nalias++] = p;
1529                 }
1530                 if (!match)
1531                         continue;
1532                 switch (af) {
1533                 case AF_INET:
1534                         if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
1535                             != 1) {
1536                                 *errp = NO_DATA;        /* name found */
1537                                 continue;
1538                         }
1539                         break;
1540 #ifdef INET6
1541                 case AF_INET6:
1542                         if (inet_pton(af, addrstr, &addrbuf) != 1) {
1543                                 *errp = NO_DATA;        /* name found */
1544                                 continue;
1545                         }
1546                         break;
1547 #endif
1548                 }
1549                 hp = &hpbuf;
1550                 hp->h_name = cname;
1551                 hp->h_aliases = aliases;
1552                 aliases[nalias] = NULL;
1553                 hp->h_addrtype = af;
1554                 hp->h_length = ADDRLEN(af);
1555                 hp->h_addr_list = addrs;
1556                 addrs[0] = (char *)&addrbuf;
1557                 addrs[1] = NULL;
1558                 hp = _hpcopy(hp, errp);
1559                 rethp = _hpmerge(rethp, hp, errp);
1560         }
1561         fclose(fp);
1562         *(struct hostent **)rval = rethp;
1563         return (rethp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
1564 }
1565
1566 static int
1567 _files_ghbyaddr(void *rval, void *cb_data, va_list ap)
1568 {
1569         const void *addr;
1570         int addrlen;
1571         int af;
1572         int *errp;
1573         int nalias;
1574         char *p, *line;
1575         FILE *fp;
1576         struct hostent *hp, hpbuf;
1577         char *aliases[MAXALIASES + 1], *addrs[2];
1578         union inx_addr addrbuf;
1579         char buf[BUFSIZ];
1580
1581         addr = va_arg(ap, const void *);
1582         addrlen = va_arg(ap, int);
1583         af = va_arg(ap, int);
1584         errp = va_arg(ap, int *);
1585
1586         *(struct hostent**)rval = NULL;
1587
1588         if ((fp = _files_open(errp)) == NULL)
1589                 return NS_UNAVAIL;
1590         hp = NULL;
1591         while (fgets(buf, sizeof(buf), fp)) {
1592                 line = buf;
1593                 if ((p = _hgetword(&line)) == NULL
1594                 ||  (af == AF_INET
1595                      ? inet_aton(p, (struct in_addr *)&addrbuf)
1596                      : inet_pton(af, p, &addrbuf)) != 1
1597                 ||  memcmp(addr, &addrbuf, addrlen) != 0
1598                 ||  (p = _hgetword(&line)) == NULL)
1599                         continue;
1600                 hp = &hpbuf;
1601                 hp->h_name = p;
1602                 hp->h_aliases = aliases;
1603                 nalias = 0;
1604                 while ((p = _hgetword(&line)) != NULL) {
1605                         if (nalias < MAXALIASES)
1606                                 aliases[nalias++] = p;
1607                 }
1608                 aliases[nalias] = NULL;
1609                 hp->h_addrtype = af;
1610                 hp->h_length = addrlen;
1611                 hp->h_addr_list = addrs;
1612                 addrs[0] = (char *)&addrbuf;
1613                 addrs[1] = NULL;
1614                 hp = _hpcopy(hp, errp);
1615                 break;
1616         }
1617         fclose(fp);
1618         *(struct hostent **)rval = hp;
1619         return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
1620 }
1621
1622 #ifdef YP
1623 /*
1624  * NIS
1625  *
1626  * XXX actually a hack.
1627  */
1628 static int
1629 _nis_ghbyname(void *rval, void *cb_data, va_list ap)
1630 {
1631         const char *name;
1632         int af;
1633         int *errp;
1634         struct hostent *hp = NULL;
1635
1636         name = va_arg(ap, const char *);
1637         af = va_arg(ap, int);
1638         errp = va_arg(ap, int *);
1639
1640         hp = _gethostbynisname(name, af);
1641         if (hp != NULL)
1642                 hp = _hpcopy(hp, errp);
1643
1644         *(struct hostent **)rval = hp;
1645         return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
1646 }
1647
1648 static int
1649 _nis_ghbyaddr(void *rval, void *cb_data, va_list ap)
1650 {
1651         const void *addr;
1652         int addrlen;
1653         int af;
1654         int *errp;
1655         struct hostent *hp = NULL;
1656
1657         addr = va_arg(ap, const void *);
1658         addrlen = va_arg(ap, int);
1659         af = va_arg(ap, int);
1660
1661         hp = _gethostbynisaddr(addr, addrlen, af);
1662         if (hp != NULL)
1663                 hp = _hpcopy(hp, errp);
1664         *(struct hostent **)rval = hp;
1665         return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
1666 }
1667 #endif
1668
1669 #define MAXPACKET       (64*1024)
1670
1671 typedef union {
1672         HEADER hdr;
1673         u_char buf[MAXPACKET];
1674 } querybuf;
1675
1676 static struct hostent *getanswer(const querybuf *, int, const char *, int,
1677             struct hostent *, int *);
1678
1679 /*
1680  * we don't need to take care about sorting, nor IPv4 mapped address here.
1681  */
1682 static struct hostent *
1683 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
1684     struct hostent *template, int *errp)
1685 {
1686         const HEADER *hp;
1687         const u_char *cp;
1688         int n;
1689         const u_char *eom, *erdata;
1690         char *bp, *ep, **ap, **hap;
1691         int type, class, ancount, qdcount;
1692         int haveanswer, had_error;
1693         char tbuf[MAXDNAME];
1694         const char *tname;
1695         int (*name_ok)(const char *);
1696         static char *h_addr_ptrs[MAXADDRS + 1];
1697         static char *host_aliases[MAXALIASES];
1698         static char hostbuf[8*1024];
1699
1700 #define BOUNDED_INCR(x) \
1701         do { \
1702                 cp += x; \
1703                 if (cp > eom) { \
1704                         *errp = NO_RECOVERY; \
1705                         return (NULL); \
1706                 } \
1707         } while (0)
1708
1709 #define BOUNDS_CHECK(ptr, count) \
1710         do { \
1711                 if ((ptr) + (count) > eom) { \
1712                         *errp = NO_RECOVERY; \
1713                         return (NULL); \
1714                 } \
1715         } while (0)
1716
1717 /* XXX do {} while (0) cannot be put here */
1718 #define DNS_ASSERT(x) \
1719         {                               \
1720                 if (!(x)) {             \
1721                         cp += n;        \
1722                         continue;       \
1723                 }                       \
1724         }
1725
1726 /* XXX do {} while (0) cannot be put here */
1727 #define DNS_FATAL(x) \
1728         {                               \
1729                 if (!(x)) {             \
1730                         had_error++;    \
1731                         continue;       \
1732                 }                       \
1733         }
1734
1735         tname = qname;
1736         template->h_name = NULL;
1737         eom = answer->buf + anslen;
1738         switch (qtype) {
1739         case T_A:
1740         case T_AAAA:
1741                 name_ok = res_hnok;
1742                 break;
1743         case T_PTR:
1744                 name_ok = res_dnok;
1745                 break;
1746         default:
1747                 return (NULL);  /* XXX should be abort(); */
1748         }
1749         /*
1750          * find first satisfactory answer
1751          */
1752         hp = &answer->hdr;
1753         ancount = ntohs(hp->ancount);
1754         qdcount = ntohs(hp->qdcount);
1755         bp = hostbuf;
1756         ep = hostbuf + sizeof hostbuf;
1757         cp = answer->buf;
1758         BOUNDED_INCR(HFIXEDSZ);
1759         if (qdcount != 1) {
1760                 *errp = NO_RECOVERY;
1761                 return (NULL);
1762         }
1763         n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1764         if ((n < 0) || !(*name_ok)(bp)) {
1765                 *errp = NO_RECOVERY;
1766                 return (NULL);
1767         }
1768         BOUNDED_INCR(n + QFIXEDSZ);
1769         if (qtype == T_A || qtype == T_AAAA) {
1770                 /* res_send() has already verified that the query name is the
1771                  * same as the one we sent; this just gets the expanded name
1772                  * (i.e., with the succeeding search-domain tacked on).
1773                  */
1774                 n = strlen(bp) + 1;             /* for the \0 */
1775                 if (n >= MAXHOSTNAMELEN) {
1776                         *errp = NO_RECOVERY;
1777                         return (NULL);
1778                 }
1779                 template->h_name = bp;
1780                 bp += n;
1781                 /* The qname can be abbreviated, but h_name is now absolute. */
1782                 qname = template->h_name;
1783         }
1784         ap = host_aliases;
1785         *ap = NULL;
1786         template->h_aliases = host_aliases;
1787         hap = h_addr_ptrs;
1788         *hap = NULL;
1789         template->h_addr_list = h_addr_ptrs;
1790         haveanswer = 0;
1791         had_error = 0;
1792         while (ancount-- > 0 && cp < eom && !had_error) {
1793                 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1794                 DNS_FATAL(n >= 0);
1795                 DNS_FATAL((*name_ok)(bp));
1796                 cp += n;                        /* name */
1797                 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
1798                 type = _getshort(cp);
1799                 cp += INT16SZ;                  /* type */
1800                 class = _getshort(cp);
1801                 cp += INT16SZ + INT32SZ;        /* class, TTL */
1802                 n = _getshort(cp);
1803                 cp += INT16SZ;                  /* len */
1804                 BOUNDS_CHECK(cp, n);
1805                 erdata = cp + n;
1806                 DNS_ASSERT(class == C_IN);
1807                 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
1808                         if (ap >= &host_aliases[MAXALIASES-1])
1809                                 continue;
1810                         n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
1811                         DNS_FATAL(n >= 0);
1812                         DNS_FATAL((*name_ok)(tbuf));
1813                         cp += n;
1814                         if (cp != erdata) {
1815                                 *errp = NO_RECOVERY;
1816                                 return (NULL);
1817                         }
1818                         /* Store alias. */
1819                         *ap++ = bp;
1820                         n = strlen(bp) + 1;     /* for the \0 */
1821                         DNS_FATAL(n < MAXHOSTNAMELEN);
1822                         bp += n;
1823                         /* Get canonical name. */
1824                         n = strlen(tbuf) + 1;   /* for the \0 */
1825                         DNS_FATAL(n <= ep - bp);
1826                         DNS_FATAL(n < MAXHOSTNAMELEN);
1827                         strcpy(bp, tbuf);
1828                         template->h_name = bp;
1829                         bp += n;
1830                         continue;
1831                 }
1832                 if (qtype == T_PTR && type == T_CNAME) {
1833                         n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
1834                         if (n < 0 || !res_dnok(tbuf)) {
1835                                 had_error++;
1836                                 continue;
1837                         }
1838                         cp += n;
1839                         if (cp != erdata) {
1840                                 *errp = NO_RECOVERY;
1841                                 return (NULL);
1842                         }
1843                         /* Get canonical name. */
1844                         n = strlen(tbuf) + 1;   /* for the \0 */
1845                         if (n > ep - bp || n >= MAXHOSTNAMELEN) {
1846                                 had_error++;
1847                                 continue;
1848                         }
1849                         strcpy(bp, tbuf);
1850                         tname = bp;
1851                         bp += n;
1852                         continue;
1853                 }
1854                 DNS_ASSERT(type == qtype);
1855                 switch (type) {
1856                 case T_PTR:
1857                         DNS_ASSERT(strcasecmp(tname, bp) == 0);
1858                         n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
1859                         DNS_FATAL(n >= 0);
1860                         DNS_FATAL(res_hnok(bp));
1861 #if MULTI_PTRS_ARE_ALIASES
1862                         cp += n;
1863                         if (cp != erdata) {
1864                                 *errp = NO_RECOVERY;
1865                                 return (NULL);
1866                         }
1867                         if (!haveanswer)
1868                                 template->h_name = bp;
1869                         else if (ap < &host_aliases[MAXALIASES-1])
1870                                 *ap++ = bp;
1871                         else
1872                                 n = -1;
1873                         if (n != -1) {
1874                                 n = strlen(bp) + 1;     /* for the \0 */
1875                                 if (n >= MAXHOSTNAMELEN) {
1876                                         had_error++;
1877                                         break;
1878                                 }
1879                                 bp += n;
1880                         }
1881                         break;
1882 #else
1883                         template->h_name = bp;
1884                         *errp = NETDB_SUCCESS;
1885                         return (template);
1886 #endif
1887                 case T_A:
1888                 case T_AAAA:
1889                         DNS_ASSERT(strcasecmp(template->h_name, bp) == 0);
1890                         DNS_ASSERT(n == template->h_length);
1891                         if (!haveanswer) {
1892                                 int nn;
1893
1894                                 template->h_name = bp;
1895                                 nn = strlen(bp) + 1;    /* for the \0 */
1896                                 bp += nn;
1897                         }
1898                         bp = (char *)ALIGN(bp);
1899
1900                         DNS_FATAL(bp + n < ep);
1901                         DNS_ASSERT(hap < &h_addr_ptrs[MAXADDRS-1]);
1902 #ifdef FILTER_V4MAPPED
1903                         if (type == T_AAAA) {
1904                                 struct in6_addr in6;
1905                                 memcpy(&in6, cp, sizeof(in6));
1906                                 DNS_ASSERT(IN6_IS_ADDR_V4MAPPED(&in6) == 0);
1907                         }
1908 #endif
1909                         bcopy(cp, *hap++ = bp, n);
1910                         bp += n;
1911                         cp += n;
1912                         if (cp != erdata) {
1913                                 *errp = NO_RECOVERY;
1914                                 return (NULL);
1915                         }
1916                         break;
1917                 default:
1918                         abort();
1919                 }
1920                 if (!had_error)
1921                         haveanswer++;
1922         }
1923         if (haveanswer) {
1924                 *ap = NULL;
1925                 *hap = NULL;
1926                 if (!template->h_name) {
1927                         n = strlen(qname) + 1;  /* for the \0 */
1928                         if (n > ep - bp || n >= MAXHOSTNAMELEN)
1929                                 goto no_recovery;
1930                         strcpy(bp, qname);
1931                         template->h_name = bp;
1932                         bp += n;
1933                 }
1934                 *errp = NETDB_SUCCESS;
1935                 return (template);
1936         }
1937  no_recovery:
1938         *errp = NO_RECOVERY;
1939         return (NULL);
1940
1941 #undef BOUNDED_INCR
1942 #undef BOUNDS_CHECK
1943 #undef DNS_ASSERT
1944 #undef DNS_FATAL
1945 }
1946
1947 static int
1948 _dns_ghbyname(void *rval, void *cb_data, va_list ap)
1949 {
1950         const char *name;
1951         int af;
1952         int *errp;
1953         int n;
1954         struct hostent *hp;
1955         int qtype;
1956         struct hostent hbuf;
1957         querybuf *buf;
1958         res_state statp;
1959
1960         name = va_arg(ap, const char *);
1961         af = va_arg(ap, int);
1962         errp = va_arg(ap, int *);
1963
1964         statp = __res_state();
1965
1966         memset(&hbuf, 0, sizeof(hbuf));
1967         hbuf.h_addrtype = af;
1968         hbuf.h_length = ADDRLEN(af);
1969
1970         switch (af) {
1971 #ifdef INET6
1972         case AF_INET6:
1973                 qtype = T_AAAA;
1974                 break;
1975 #endif
1976         case AF_INET:
1977                 qtype = T_A;
1978                 break;
1979         default:
1980                 *errp = NO_RECOVERY;
1981                 return NS_NOTFOUND;
1982         }
1983         buf = malloc(sizeof(*buf));
1984         if (buf == NULL) {
1985                 *errp = NETDB_INTERNAL;
1986                 return NS_UNAVAIL;
1987         }
1988         n = res_nsearch(statp, name, C_IN, qtype, buf->buf, sizeof(buf->buf));
1989         if (n < 0) {
1990                 free(buf);
1991                 *errp = statp->res_h_errno;
1992                 return NS_UNAVAIL;
1993         }
1994         hp = getanswer(buf, n, name, qtype, &hbuf, errp);
1995         free(buf);
1996         if (!hp) {
1997                 *errp = NO_RECOVERY;
1998                 return NS_NOTFOUND;
1999         }
2000         *(struct hostent **)rval = _hpcopy(&hbuf, errp);
2001         if (*(struct hostent **)rval != NULL)
2002                 return NS_SUCCESS;
2003         else if (*errp == TRY_AGAIN)
2004                 return NS_TRYAGAIN;
2005         else
2006                 return NS_NOTFOUND;
2007 }
2008
2009 static int
2010 _dns_ghbyaddr(void *rval, void *cb_data, va_list ap)
2011 {
2012         const void *addr;
2013         int addrlen;
2014         int af;
2015         int *errp;
2016         int n;
2017         int err;
2018         struct hostent *hp;
2019         u_char c, *cp;
2020         char *bp;
2021         struct hostent hbuf;
2022 #ifdef INET6
2023         static const char hex[] = "0123456789abcdef";
2024 #endif
2025         querybuf *buf;
2026         char qbuf[MAXDNAME+1];
2027         char *hlist[2];
2028 #ifdef INET6
2029         char *tld6[] = { "ip6.arpa", NULL };
2030 #endif
2031         char *tld4[] = { "in-addr.arpa", NULL };
2032         char **tld;
2033         res_state statp;
2034
2035         addr = va_arg(ap, const void *);
2036         addrlen = va_arg(ap, int);
2037         af = va_arg(ap, int);
2038         errp = va_arg(ap, int *);
2039
2040         *(struct hostent **)rval = NULL;
2041
2042 #ifdef INET6
2043         /* XXX */
2044         if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
2045                 return NS_NOTFOUND;
2046 #endif
2047
2048         switch (af) {
2049 #ifdef INET6
2050         case AF_INET6:
2051                 tld = tld6;
2052                 break;
2053 #endif
2054         case AF_INET:
2055                 tld = tld4;
2056                 break;
2057         default:
2058                 return NS_NOTFOUND;
2059         }
2060
2061         statp = __res_state();
2062         if ((statp->options & RES_INIT) == 0) {
2063                 if (res_ninit(statp) < 0) {
2064                         *errp = NETDB_INTERNAL;
2065                         return NS_UNAVAIL;
2066                 }
2067         }
2068         memset(&hbuf, 0, sizeof(hbuf));
2069         hbuf.h_name = NULL;
2070         hbuf.h_addrtype = af;
2071         hbuf.h_length = addrlen;
2072
2073         buf = malloc(sizeof(*buf));
2074         if (buf == NULL) {
2075                 *errp = NETDB_INTERNAL;
2076                 return NS_UNAVAIL;
2077         }
2078         err = NS_SUCCESS;
2079         for (/* nothing */; *tld; tld++) {
2080                 /*
2081                  * XXX assumes that MAXDNAME is big enough - error checks
2082                  * has been made by callers
2083                  */
2084                 n = 0;
2085                 bp = qbuf;
2086                 cp = (u_char *)addr+addrlen-1;
2087                 switch (af) {
2088 #ifdef INET6
2089                 case AF_INET6:
2090                         for (; n < addrlen; n++, cp--) {
2091                                 c = *cp;
2092                                 *bp++ = hex[c & 0xf];
2093                                 *bp++ = '.';
2094                                 *bp++ = hex[c >> 4];
2095                                 *bp++ = '.';
2096                         }
2097                         strcpy(bp, *tld);
2098                         break;
2099 #endif
2100                 case AF_INET:
2101                         for (; n < addrlen; n++, cp--) {
2102                                 c = *cp;
2103                                 if (c >= 100)
2104                                         *bp++ = '0' + c / 100;
2105                                 if (c >= 10)
2106                                         *bp++ = '0' + (c % 100) / 10;
2107                                 *bp++ = '0' + c % 10;
2108                                 *bp++ = '.';
2109                         }
2110                         strcpy(bp, *tld);
2111                         break;
2112                 }
2113
2114                 n = res_nquery(statp, qbuf, C_IN, T_PTR, buf->buf,
2115                     sizeof buf->buf);
2116                 if (n < 0) {
2117                         *errp = statp->res_h_errno;
2118                         err = NS_UNAVAIL;
2119                         continue;
2120                 } else if (n > sizeof(buf->buf)) {
2121 #if 0
2122                         errno = ERANGE; /* XXX is it OK to set errno here? */
2123 #endif
2124                         *errp = NETDB_INTERNAL;
2125                         err = NS_UNAVAIL;
2126                         continue;
2127                 }
2128                 hp = getanswer(buf, n, qbuf, T_PTR, &hbuf, errp);
2129                 if (!hp) {
2130                         err = NS_NOTFOUND;
2131                         continue;
2132                 }
2133                 free(buf);
2134                 hbuf.h_addrtype = af;
2135                 hbuf.h_length = addrlen;
2136                 hbuf.h_addr_list = hlist;
2137                 hlist[0] = (char *)addr;
2138                 hlist[1] = NULL;
2139                 *(struct hostent **)rval = _hpcopy(&hbuf, errp);
2140                 return NS_SUCCESS;
2141         }
2142         free(buf);
2143         return err;
2144 }
2145
2146 static void
2147 _dns_shent(int stayopen)
2148 {
2149         res_state statp;
2150
2151         statp = __res_state();
2152         if ((statp->options & RES_INIT) == 0) {
2153                 if (res_ninit(statp) < 0)
2154                         return;
2155         }
2156         if (stayopen)
2157                 statp->options |= RES_STAYOPEN | RES_USEVC;
2158 }
2159
2160 static void
2161 _dns_ehent(void)
2162 {
2163         res_state statp;
2164
2165         statp = __res_state();
2166         statp->options &= ~(RES_STAYOPEN | RES_USEVC);
2167         res_nclose(statp);
2168 }
2169
2170 #ifdef ICMPNL
2171
2172 /*
2173  * experimental:
2174  *      draft-ietf-ipngwg-icmp-namelookups-09.txt
2175  *      ifindex is assumed to be encoded in addr.
2176  */
2177 #include <sys/uio.h>
2178 #include <netinet/ip6.h>
2179 #include <netinet/icmp6.h>
2180 #include <ctype.h>
2181
2182 #ifndef NI_QTYPE_NODENAME
2183 #define NI_QTYPE_NODENAME       NI_QTYPE_DNSNAME
2184 #endif
2185
2186 static char *
2187 dnsdecode(sp, ep, base, buf, bufsiz)
2188         const u_char **sp;
2189         const u_char *ep;
2190         const u_char *base;     /*base for compressed name*/
2191         u_char *buf;
2192         size_t bufsiz;
2193 {
2194         int i;
2195         const u_char *cp;
2196         char cresult[MAXDNAME + 1];
2197         const u_char *comp;
2198         int l;
2199
2200         cp = *sp;
2201         *buf = '\0';
2202
2203         if (cp >= ep)
2204                 return NULL;
2205         while (cp < ep) {
2206                 i = *cp;
2207                 if (i == 0 || cp != *sp) {
2208                         if (strlcat(buf, ".", bufsiz) >= bufsiz)
2209                                 return NULL;    /* result overrun */
2210                 }
2211                 if (i == 0)
2212                         break;
2213                 cp++;
2214
2215                 if ((i & 0xc0) == 0xc0 && cp - base > (i & 0x3f)) {
2216                         /* DNS compression */
2217                         if (!base)
2218                                 return NULL;
2219
2220                         comp = base + (i & 0x3f);
2221                         if (dnsdecode(&comp, cp, base, cresult,
2222                             sizeof(cresult)) == NULL)
2223                                 return NULL;
2224                         if (strlcat(buf, cresult, bufsiz) >= bufsiz)
2225                                 return NULL;    /* result overrun */
2226                         break;
2227                 } else if ((i & 0x3f) == i) {
2228                         if (i > ep - cp)
2229                                 return NULL;    /* source overrun */
2230                         while (i-- > 0 && cp < ep) {
2231                                 l = snprintf(cresult, sizeof(cresult),
2232                                     isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff);
2233                                 if (l >= sizeof(cresult) || l < 0)
2234                                         return NULL;
2235                                 if (strlcat(buf, cresult, bufsiz) >= bufsiz)
2236                                         return NULL;    /* result overrun */
2237                                 cp++;
2238                         }
2239                 } else
2240                         return NULL;    /* invalid label */
2241         }
2242         if (i != 0)
2243                 return NULL;    /* not terminated */
2244         cp++;
2245         *sp = cp;
2246         return buf;
2247 }
2248
2249 static char *
2250 _icmp_nodeinfo_query(const struct in6_addr *addr, int ifindex, char *dnsname)
2251 {
2252         int s;
2253         struct icmp6_filter filter;
2254         struct msghdr msg;
2255         struct cmsghdr *cmsg;
2256         struct in6_pktinfo *pkt;
2257         char cbuf[256], buf[1024], *cp, *end;
2258         int cc;
2259         struct icmp6_nodeinfo niq, *nir;
2260         struct sockaddr_in6 sin6;
2261         struct iovec iov;
2262         fd_set s_fds, fds;
2263         struct timeval tout;
2264         int len;
2265         static int pid;
2266         u_int32_t r1, r2;
2267
2268         if (pid == 0)
2269                 pid = getpid();
2270
2271         ICMP6_FILTER_SETBLOCKALL(&filter);
2272         ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filter);
2273
2274         FD_ZERO(&s_fds);
2275         tout.tv_sec = 0;
2276         tout.tv_usec = 500000;  /* 500ms */
2277
2278         memset(&niq, 0, sizeof(niq));
2279         niq.ni_type = ICMP6_NI_QUERY;
2280         niq.ni_code = ICMP6_NI_SUBJ_IPV6;
2281         niq.ni_qtype = htons(NI_QTYPE_NODENAME);
2282         niq.ni_flags = 0;
2283         r1 = arc4random();
2284         r2 = arc4random();
2285         memcpy(&niq.icmp6_ni_nonce[0], &r1, sizeof(r1));
2286         memcpy(&niq.icmp6_ni_nonce[4], &r2, sizeof(r2));
2287
2288         memset(&sin6, 0, sizeof(sin6));
2289         sin6.sin6_family = AF_INET6;
2290         sin6.sin6_addr = *addr;
2291
2292         memset(&msg, 0, sizeof(msg));
2293         msg.msg_name = (caddr_t)&sin6;
2294         msg.msg_namelen = sizeof(sin6);
2295         msg.msg_iov = &iov;
2296         msg.msg_iovlen = 1;
2297         msg.msg_control = NULL;
2298         msg.msg_controllen = 0;
2299         iov.iov_base = (caddr_t)&niq;
2300         iov.iov_len = sizeof(struct icmp6_nodeinfo);
2301
2302         if (ifindex) {
2303                 msg.msg_control = cbuf;
2304                 msg.msg_controllen = sizeof(cbuf);
2305                 cmsg = CMSG_FIRSTHDR(&msg);
2306                 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
2307                 cmsg->cmsg_level = IPPROTO_IPV6;
2308                 cmsg->cmsg_type = IPV6_PKTINFO;
2309                 pkt = (struct in6_pktinfo *)&cmsg[1];
2310                 memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
2311                 pkt->ipi6_ifindex = ifindex;
2312                 cmsg = CMSG_NXTHDR(&msg, cmsg);
2313                 msg.msg_controllen = (char *)cmsg - cbuf;
2314         }
2315
2316         /* XXX: we need root privilege here */
2317         if ((s = _socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
2318                 return NULL;
2319         (void)_setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
2320                          (char *)&filter, sizeof(filter));
2321         cc = _sendmsg(s, &msg, 0);
2322         if (cc < 0) {
2323                 _close(s);
2324                 return (NULL);
2325         }
2326         FD_SET(s, &s_fds);
2327         for (;;) {
2328                 fds = s_fds;
2329                 if (_select(s + 1, &fds, NULL, NULL, &tout) <= 0) {
2330                         _close(s);
2331                         return (NULL);
2332                 }
2333                 len = sizeof(sin6);
2334                 cc = _recvfrom(s, buf, sizeof(buf), 0,
2335                               (struct sockaddr *)&sin6, &len);
2336                 if (cc <= 0) {
2337                         _close(s);
2338                         return (NULL);
2339                 }
2340                 if (cc < sizeof(struct icmp6_hdr))
2341                         continue;
2342                 nir = (struct icmp6_nodeinfo *)buf;
2343                 if (nir->ni_type != ICMP6_NI_REPLY)
2344                         continue;
2345                 if (nir->ni_qtype != htons(NI_QTYPE_NODENAME))
2346                         continue;
2347                 if (memcmp(nir->icmp6_ni_nonce, niq.icmp6_ni_nonce,
2348                     sizeof(nir->icmp6_ni_nonce)) != 0) {
2349                         continue;
2350                 }
2351                 if (nir->ni_code != htons(ICMP6_NI_SUCCESS))
2352                         continue; /* or should we fail? */
2353
2354                 /* this is an expected reply. */
2355                 break;
2356         }
2357         _close(s);
2358
2359         memset(dnsname, 0, MAXDNAME + 1);
2360         cp = (char *)(nir + 1);
2361         end = ((char *)nir) + cc;
2362         if (end - cp < sizeof(int32_t)) /* for TTL.  we don't use it. */
2363                 return (NULL);
2364         cp += sizeof(int32_t);
2365         if (*cp == end - cp - 1) { /* an old version */
2366                 int nlen;
2367
2368                 cp++;   /* skip length */
2369                 nlen = end - cp;
2370                 if (nlen > MAXDNAME)
2371                         return (NULL); /* XXX: use it anyway? */
2372                 memcpy(dnsname, cp, nlen);
2373         } else {
2374                 /* XXX: should we use a generic function? */
2375                 if (dnsdecode((const u_char **)(void *)&cp, end,
2376                     (const u_char *)(nir + 1), dnsname, MAXDNAME + 1)
2377                     == NULL) {
2378                         return (NULL); /* bogus name */
2379                 }
2380                 /* Name-lookup special handling for truncated name. */
2381                 if (cp + 1 <= end && !*cp && strlen(dnsname) > 0)
2382                         dnsname[strlen(dnsname) - 1] = '\0';
2383
2384                 /* There may be other names, but we ignore them. */
2385         }
2386
2387         return (dnsname);
2388 }
2389
2390 static int
2391 _icmp_ghbyaddr(void *rval, void *cb_data, va_list ap)
2392 {
2393         const void *addr;
2394         int addrlen;
2395         int af;
2396         int *errp;
2397         char *hname;
2398         int ifindex = 0;
2399         struct in6_addr addr6;
2400         char dnsname[MAXDNAME + 1];
2401
2402         addr = va_arg(ap, const void *);
2403         addrlen = va_arg(ap, int);
2404         af = va_arg(ap, int);
2405         errp = va_arg(ap, int *);
2406
2407         *(struct hostent **)rval = NULL;
2408
2409         if (af != AF_INET6 || addrlen != sizeof(addr6)) {
2410                 /*
2411                  * Note: rfc1788 defines Who Are You for IPv4,
2412                  * but no one implements it.
2413                  */
2414                 return (NS_NOTFOUND);
2415         }
2416
2417         memcpy(&addr6, addr, addrlen);
2418         if (IN6_IS_ADDR_LINKLOCAL(&addr6)) {
2419                 ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
2420                 addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
2421         }
2422
2423         if ((hname = _icmp_nodeinfo_query(&addr6, ifindex, dnsname)) == NULL)
2424                 return (NS_NOTFOUND);
2425         *(struct hostent **)rval =_hpaddr(af, hname, &addr6, errp);
2426         return (NS_SUCCESS);
2427 }
2428 #endif /* ICMPNL */