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