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