Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / lib / libc / net / name6.c
1 /*      $FreeBSD: src/lib/libc/net/name6.c,v 1.6.2.9 2002/11/02 18:54:57 ume Exp $      */
2 /*      $DragonFly: src/lib/libc/net/name6.c,v 1.9 2005/11/13 02:04:47 swildner Exp $   */
3 /*      $KAME: name6.c,v 1.25 2000/06/26 16:44:40 itojun Exp $  */
4
5 /*
6  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the project nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 /*
34  * ++Copyright++ 1985, 1988, 1993
35  * -
36  * Copyright (c) 1985, 1988, 1993
37  *    The Regents of the University of California.  All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. Neither the name of the University nor the names of its contributors
48  *    may be used to endorse or promote products derived from this software
49  *    without specific prior written permission.
50  *
51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61  * SUCH DAMAGE.
62  * -
63  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
64  *
65  * Permission to use, copy, modify, and distribute this software for any
66  * purpose with or without fee is hereby granted, provided that the above
67  * copyright notice and this permission notice appear in all copies, and that
68  * the name of Digital Equipment Corporation not be used in advertising or
69  * publicity pertaining to distribution of the document or software without
70  * specific, written prior permission.
71  *
72  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
73  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
74  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
75  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
76  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
77  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
78  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
79  * SOFTWARE.
80  * -
81  * --Copyright--
82  */
83
84 /*
85  *      Atsushi Onoe <onoe@sm.sony.co.jp>
86  */
87
88 /*
89  * TODO for thread safe
90  *      use mutex for _hostconf, _hostconf_init.
91  *      rewrite resolvers to be thread safe
92  */
93
94 #include "namespace.h"
95 #include <sys/param.h>
96 #include <sys/socket.h>
97 #include <sys/time.h>
98 #include <sys/queue.h>
99 #include <netinet/in.h>
100
101 #include <arpa/inet.h>
102 #include <arpa/nameser.h>
103
104 #include <errno.h>
105 #include <netdb.h>
106 #include <resolv.h>
107 #include <stdio.h>
108 #include <stdlib.h>
109 #include <string.h>
110 #include <unistd.h>
111 #include "un-namespace.h"
112
113 #ifndef _PATH_HOSTS
114 #define _PATH_HOSTS     "/etc/hosts"
115 #endif
116
117 #ifndef MAXALIASES
118 #define MAXALIASES      10
119 #endif
120 #ifndef MAXADDRS
121 #define MAXADDRS        20
122 #endif
123 #ifndef MAXDNAME
124 #define MAXDNAME        1025
125 #endif
126
127 #ifdef INET6
128 #define ADDRLEN(af)     ((af) == AF_INET6 ? sizeof(struct in6_addr) : \
129                                             sizeof(struct in_addr))
130 #else
131 #define ADDRLEN(af)     sizeof(struct in_addr)
132 #endif
133
134 #define MAPADDR(ab, ina) \
135 do {                                                                    \
136         memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr));         \
137         memset((ab)->map_zero, 0, sizeof((ab)->map_zero));              \
138         memset((ab)->map_one, 0xff, sizeof((ab)->map_one));             \
139 } while (0)
140 #define MAPADDRENABLED(flags) \
141         (((flags) & AI_V4MAPPED) || \
142          (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled()))
143
144 union inx_addr {
145         struct in_addr  in_addr;
146 #ifdef INET6
147         struct in6_addr in6_addr;
148 #endif
149         struct {
150                 u_char  mau_zero[10];
151                 u_char  mau_one[2];
152                 struct in_addr mau_inaddr;
153         }               map_addr_un;
154 #define map_zero        map_addr_un.mau_zero
155 #define map_one         map_addr_un.mau_one
156 #define map_inaddr      map_addr_un.mau_inaddr
157 };
158
159 static struct    hostent *_hpcopy(struct hostent *hp, int *errp);
160 static struct    hostent *_hpaddr(int af, const char *name, void *addr, int *errp);
161 static struct    hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp);
162 #ifdef INET6
163 static struct    hostent *_hpmapv6(struct hostent *hp, int *errp);
164 #endif
165 static struct    hostent *_hpsort(struct hostent *hp);
166 static struct    hostent *_ghbyname(const char *name, int af, int flags, int *errp);
167 static char     *_hgetword(char **pp);
168 static int       _mapped_addr_enabled(void);
169
170 static FILE     *_files_open(int *errp);
171 static struct    hostent *_files_ghbyname(const char *name, int af, int *errp);
172 static struct    hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
173 #ifdef YP
174 static struct    hostent *_nis_ghbyname(const char *name, int af, int *errp);
175 static struct    hostent *_nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
176 #endif
177 static struct    hostent *_dns_ghbyname(const char *name, int af, int *errp);
178 static struct    hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
179 #ifdef ICMPNL
180 static struct    hostent *_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
181 #endif /* ICMPNL */
182
183 /* Make getipnodeby*() thread-safe in libc for use with kernel threads. */
184 #include "libc_private.h"
185 #include "spinlock.h"
186 /*
187  * XXX: Our res_*() is not thread-safe.  So, we share lock between
188  * getaddrinfo() and getipnodeby*().  Still, we cannot use
189  * getaddrinfo() and getipnodeby*() in conjunction with other
190  * functions which call res_*().
191  */
192 extern spinlock_t __getaddrinfo_thread_lock;
193 #define THREAD_LOCK() \
194         if (__isthreaded) _SPINLOCK(&__getaddrinfo_thread_lock);
195 #define THREAD_UNLOCK() \
196         if (__isthreaded) _SPINUNLOCK(&__getaddrinfo_thread_lock);
197
198 /*
199  * Select order host function.
200  */
201 #define MAXHOSTCONF     4
202
203 #ifndef HOSTCONF
204 #  define       HOSTCONF        "/etc/host.conf"
205 #endif /* !HOSTCONF */
206
207 struct _hostconf {
208         struct hostent *(*byname)(const char *name, int af, int *errp);
209         struct hostent *(*byaddr)(const void *addr, int addrlen, int af, int *errp);
210 };
211
212 /* default order */
213 static struct _hostconf _hostconf[MAXHOSTCONF] = {
214         { _dns_ghbyname,        _dns_ghbyaddr },
215         { _files_ghbyname,      _files_ghbyaddr },
216 #ifdef ICMPNL
217         { NULL,                 _icmp_ghbyaddr },
218 #endif /* ICMPNL */
219 };
220
221 static int      _hostconf_init_done;
222 static void     _hostconf_init(void);
223
224 /*
225  * Initialize hostconf structure.
226  */
227
228 static void
229 _hostconf_init(void)
230 {
231         FILE *fp;
232         int n;
233         const char *p;
234         char *line;
235         char buf[BUFSIZ];
236
237         _hostconf_init_done = 1;
238         n = 0;
239         p = HOSTCONF;
240         if ((fp = fopen(p, "r")) == NULL)
241                 return;
242         while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) {
243                 line = buf;
244                 if ((p = _hgetword(&line)) == NULL)
245                         continue;
246                 do {
247                         if (strcmp(p, "hosts") == 0
248                         ||  strcmp(p, "local") == 0
249                         ||  strcmp(p, "file") == 0
250                         ||  strcmp(p, "files") == 0) {
251                                 _hostconf[n].byname = _files_ghbyname;
252                                 _hostconf[n].byaddr = _files_ghbyaddr;
253                                 n++;
254                         }
255                         else if (strcmp(p, "dns") == 0
256                              ||  strcmp(p, "bind") == 0) {
257                                 _hostconf[n].byname = _dns_ghbyname;
258                                 _hostconf[n].byaddr = _dns_ghbyaddr;
259                                 n++;
260                         }
261 #ifdef YP
262                         else if (strcmp(p, "nis") == 0) {
263                                 _hostconf[n].byname = _nis_ghbyname;
264                                 _hostconf[n].byaddr = _nis_ghbyaddr;
265                                 n++;
266                         }
267 #endif
268 #ifdef ICMPNL
269                         else if (strcmp(p, "icmp") == 0) {
270                                 _hostconf[n].byname = NULL;
271                                 _hostconf[n].byaddr = _icmp_ghbyaddr;
272                                 n++;
273                         }
274 #endif /* ICMPNL */
275                 } while ((p = _hgetword(&line)) != NULL);
276         }
277         fclose(fp);
278         if (n < 0) {
279                 /* no keyword found. do not change default configuration */
280                 return;
281         }
282         for (; n < MAXHOSTCONF; n++) {
283                 _hostconf[n].byname = NULL;
284                 _hostconf[n].byaddr = NULL;
285         }
286 }
287
288 /*
289  * Check if kernel supports mapped address.
290  *      implementation dependent
291  */
292 #ifdef __KAME__
293 #include <sys/sysctl.h>
294 #endif /* __KAME__ */
295
296 static int
297 _mapped_addr_enabled(void)
298 {
299         /* implementation dependent check */
300 #if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR)
301         int mib[4];
302         size_t len;
303         int val;
304
305         mib[0] = CTL_NET;
306         mib[1] = PF_INET6;
307         mib[2] = IPPROTO_IPV6;
308         mib[3] = IPV6CTL_MAPPED_ADDR;
309         len = sizeof(val);
310         if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0)
311                 return 1;
312 #endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */
313         return 0;
314 }
315
316 /*
317  * Functions defined in RFC2553
318  *      getipnodebyname, getipnodebyaddr, freehostent
319  */
320
321 static struct hostent *
322 _ghbyname(const char *name, int af, int flags, int *errp)
323 {
324         struct hostent *hp;
325         int i;
326
327         if (flags & AI_ADDRCONFIG) {
328                 int s;
329
330                 /*
331                  * TODO:
332                  * Note that implementation dependent test for address
333                  * configuration should be done everytime called
334                  * (or apropriate interval),
335                  * because addresses will be dynamically assigned or deleted.
336                  */
337                 if (af == AF_UNSPEC) {
338                         if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
339                                 af = AF_INET;
340                         else {
341                                 _close(s);
342                                 if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0)
343                                         af = AF_INET6;
344                                 else
345                                 _close(s);
346                         }
347
348                 }
349                 if (af != AF_UNSPEC) {
350                         if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
351                                 return NULL;
352                         _close(s);
353                 }
354         }
355
356         THREAD_LOCK();
357         for (i = 0; i < MAXHOSTCONF; i++) {
358                 if (_hostconf[i].byname
359                     && (hp = (*_hostconf[i].byname)(name, af, errp)) != NULL) {
360                         THREAD_UNLOCK();
361                         return hp;
362                 }
363         }
364         THREAD_UNLOCK();
365
366         return NULL;
367 }
368
369 /* getipnodebyname() internal routine for multiple query(PF_UNSPEC) support. */
370 static struct hostent *
371 _getipnodebyname_multi(const char *name, int af, int flags, int *errp)
372 {
373         struct hostent *hp;
374         union inx_addr addrbuf;
375
376         /* XXX: PF_UNSPEC is only supposed to be passed from getaddrinfo() */
377         if (af != AF_INET
378 #ifdef INET6
379             && af != AF_INET6
380 #endif
381             && af != PF_UNSPEC
382                 )
383         {
384                 *errp = NO_RECOVERY;
385                 return NULL;
386         }
387
388 #ifdef INET6
389         /* special case for literal address */
390         if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
391                 if (af != AF_INET6) {
392                         *errp = HOST_NOT_FOUND;
393                         return NULL;
394                 }
395                 return _hpaddr(af, name, &addrbuf, errp);
396         }
397 #endif
398         if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) {
399                 if (af != AF_INET) {
400                         if (MAPADDRENABLED(flags)) {
401                                 MAPADDR(&addrbuf, &addrbuf.in_addr);
402                         } else {
403                                 *errp = HOST_NOT_FOUND;
404                                 return NULL;
405                         }
406                 }
407                 return _hpaddr(af, name, &addrbuf, errp);
408         }
409
410         if (!_hostconf_init_done)
411                 _hostconf_init();
412
413         *errp = HOST_NOT_FOUND;
414         hp = _ghbyname(name, af, flags, errp);
415
416 #ifdef INET6
417         if (af == AF_INET6
418         &&  ((flags & AI_ALL) || hp == NULL)
419         &&  (MAPADDRENABLED(flags))) {
420                 struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp);
421                 if (hp == NULL)
422                         hp = _hpmapv6(hp2, errp);
423                 else {
424                         if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) {
425                                 freehostent(hp2);
426                                 hp2 = NULL;
427                         }
428                         hp = _hpmerge(hp, hp2, errp);
429                 }
430         }
431 #endif
432         return _hpsort(hp);
433 }
434
435 struct hostent *
436 getipnodebyname(const char *name, int af, int flags, int *errp)
437 {
438         if (af != AF_INET
439 #ifdef INET6
440             && af != AF_INET6
441 #endif
442                 )
443         {
444                 *errp = NO_RECOVERY;
445                 return NULL;
446         }
447         return(_getipnodebyname_multi(name, af ,flags, errp));
448 }
449
450 struct hostent *
451 getipnodebyaddr(const void *src, size_t len, int af, int *errp)
452 {
453         struct hostent *hp;
454         int i;
455 #ifdef INET6
456         struct in6_addr addrbuf;
457 #else
458         struct in_addr addrbuf;
459 #endif
460
461         *errp = HOST_NOT_FOUND;
462
463         switch (af) {
464         case AF_INET:
465                 if (len != sizeof(struct in_addr)) {
466                         *errp = NO_RECOVERY;
467                         return NULL;
468                 }
469                 if ((long)src & ~(sizeof(struct in_addr) - 1)) {
470                         memcpy(&addrbuf, src, len);
471                         src = &addrbuf;
472                 }
473                 if (((const struct in_addr *)src)->s_addr == 0)
474                         return NULL;
475                 break;
476 #ifdef INET6
477         case AF_INET6:
478                 if (len != sizeof(struct in6_addr)) {
479                         *errp = NO_RECOVERY;
480                         return NULL;
481                 }
482                 if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) {   /*XXX*/
483                         memcpy(&addrbuf, src, len);
484                         src = &addrbuf;
485                 }
486                 if (IN6_IS_ADDR_UNSPECIFIED((const struct in6_addr *)src))
487                         return NULL;
488                 if (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src)
489                 ||  IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src)) {
490                         src = (const char *)src +
491                             (sizeof(struct in6_addr) - sizeof(struct in_addr));
492                         af = AF_INET;
493                         len = sizeof(struct in_addr);
494                 }
495                 break;
496 #endif
497         default:
498                 *errp = NO_RECOVERY;
499                 return NULL;
500         }
501
502         if (!_hostconf_init_done)
503                 _hostconf_init();
504         THREAD_LOCK();
505         for (i = 0; i < MAXHOSTCONF; i++) {
506                 if (_hostconf[i].byaddr
507                 && (hp = (*_hostconf[i].byaddr)(src, len, af, errp)) != NULL) {
508                         THREAD_UNLOCK();
509                         return hp;
510                 }
511         }
512         THREAD_UNLOCK();
513
514         return NULL;
515 }
516
517 void
518 freehostent(struct hostent *ptr)
519 {
520         free(ptr);
521 }
522
523 #if 0
524
525 /* XXX: should be deprecated */
526 struct hostent *
527 getnodebyname(const char *name, int af, int flags)
528 {
529         return getipnodebyname(name, af, flags, &h_errno);
530 }
531
532 #ifdef __warn_references
533 __warn_references(getnodebyname,
534         "warning: getnodebyname() deprecated, "
535         "should use getaddrinfo() or getipnodebyname()");
536 #endif
537
538 struct hostent *
539 getnodebyaddr(const void *src, size_t len, int af)
540 {
541         return getipnodebyaddr(src, len, af, &h_errno);
542 }
543
544 #ifdef __warn_references
545 __warn_references(getnodebyaddr,
546         "warning: getnodebyaddr() deprecated, "
547         "should use getnameinfo() or getipnodebyaddr()");
548 #endif
549
550 #endif
551
552 /*
553  * Private utility functions
554  */
555
556 /*
557  * _hpcopy: allocate and copy hostent structure
558  */
559 static struct hostent *
560 _hpcopy(struct hostent *hp, int *errp)
561 {
562         struct hostent *nhp;
563         char *cp, **pp;
564         int size, addrsize;
565         int nalias = 0, naddr = 0;
566         int al_off;
567         int i;
568
569         if (hp == NULL)
570                 return hp;
571
572         /* count size to be allocated */
573         size = sizeof(struct hostent);
574         if (hp->h_name != NULL)
575                 size += strlen(hp->h_name) + 1;
576         if ((pp = hp->h_aliases) != NULL) {
577                 for (i = 0; *pp != NULL; i++, pp++) {
578                         if (**pp != '\0') {
579                                 size += strlen(*pp) + 1;
580                                 nalias++;
581                         }
582                 }
583         }
584         /* adjust alignment */
585         size = ALIGN(size);
586         al_off = size;
587         size += sizeof(char *) * (nalias + 1);
588         addrsize = ALIGN(hp->h_length);
589         if ((pp = hp->h_addr_list) != NULL) {
590                 while (*pp++ != NULL)
591                         naddr++;
592         }
593         size += addrsize * naddr;
594         size += sizeof(char *) * (naddr + 1);
595
596         /* copy */
597         if ((nhp = (struct hostent *)malloc(size)) == NULL) {
598                 *errp = TRY_AGAIN;
599                 return NULL;
600         }
601         cp = (char *)&nhp[1];
602         if (hp->h_name != NULL) {
603                 nhp->h_name = cp;
604                 strcpy(cp, hp->h_name);
605                 cp += strlen(cp) + 1;
606         } else
607                 nhp->h_name = NULL;
608         nhp->h_aliases = (char **)((char *)nhp + al_off);
609         if ((pp = hp->h_aliases) != NULL) {
610                 for (i = 0; *pp != NULL; pp++) {
611                         if (**pp != '\0') {
612                                 nhp->h_aliases[i++] = cp;
613                                 strcpy(cp, *pp);
614                                 cp += strlen(cp) + 1;
615                         }
616                 }
617         }
618         nhp->h_aliases[nalias] = NULL;
619         cp = (char *)&nhp->h_aliases[nalias + 1];
620         nhp->h_addrtype = hp->h_addrtype;
621         nhp->h_length = hp->h_length;
622         nhp->h_addr_list = (char **)cp;
623         if ((pp = hp->h_addr_list) != NULL) {
624                 cp = (char *)&nhp->h_addr_list[naddr + 1];
625                 for (i = 0; *pp != NULL; pp++) {
626                         nhp->h_addr_list[i++] = cp;
627                         memcpy(cp, *pp, hp->h_length);
628                         cp += addrsize;
629                 }
630         }
631         nhp->h_addr_list[naddr] = NULL;
632         return nhp;
633 }
634
635 /*
636  * _hpaddr: construct hostent structure with one address
637  */
638 static struct hostent *
639 _hpaddr(int af, const char *name, void *addr, int *errp)
640 {
641         struct hostent *hp, hpbuf;
642         char *addrs[2];
643
644         hp = &hpbuf;
645         hp->h_name = name;
646         hp->h_aliases = NULL;
647         hp->h_addrtype = af;
648         hp->h_length = ADDRLEN(af);
649         hp->h_addr_list = addrs;
650         addrs[0] = addr;
651         addrs[1] = NULL;
652         return _hpcopy(hp, errp);
653 }
654
655 /*
656  * _hpmerge: merge 2 hostent structure, arguments will be freed
657  */
658 static struct hostent *
659 _hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp)
660 {
661         int i, j;
662         int naddr, nalias;
663         char **pp;
664         struct hostent *hp, hpbuf;
665         char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1];
666         union inx_addr addrbuf[MAXADDRS];
667
668         if (hp1 == NULL)
669                 return hp2;
670         if (hp2 == NULL)
671                 return hp1;
672
673 #define HP(i)   (i == 1 ? hp1 : hp2)
674         hp = &hpbuf;
675         hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name);
676         hp->h_aliases = aliases;
677         nalias = 0;
678         for (i = 1; i <= 2; i++) {
679                 if ((pp = HP(i)->h_aliases) == NULL)
680                         continue;
681                 for (; nalias < MAXALIASES && *pp != NULL; pp++) {
682                         /* check duplicates */
683                         for (j = 0; j < nalias; j++)
684                                 if (strcasecmp(*pp, aliases[j]) == 0)
685                                         break;
686                         if (j == nalias)
687                                 aliases[nalias++] = *pp;
688                 }
689         }
690         aliases[nalias] = NULL;
691 #ifdef INET6
692         if (hp1->h_length != hp2->h_length) {
693                 hp->h_addrtype = AF_INET6;
694                 hp->h_length = sizeof(struct in6_addr);
695         } else {
696 #endif
697                 hp->h_addrtype = hp1->h_addrtype;
698                 hp->h_length = hp1->h_length;
699 #ifdef INET6
700         }
701 #endif
702         hp->h_addr_list = addrs;
703         naddr = 0;
704         for (i = 1; i <= 2; i++) {
705                 if ((pp = HP(i)->h_addr_list) == NULL)
706                         continue;
707                 if (HP(i)->h_length == hp->h_length) {
708                         while (naddr < MAXADDRS && *pp != NULL)
709                                 addrs[naddr++] = *pp++;
710                 } else {
711                         /* copy IPv4 addr as mapped IPv6 addr */
712                         while (naddr < MAXADDRS && *pp != NULL) {
713                                 MAPADDR(&addrbuf[naddr], *pp++);
714                                 addrs[naddr] = (char *)&addrbuf[naddr];
715                                 naddr++;
716                         }
717                 }
718         }
719         addrs[naddr] = NULL;
720         hp = _hpcopy(hp, errp);
721         freehostent(hp1);
722         freehostent(hp2);
723         return hp;
724 }
725
726 /*
727  * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses
728  */
729 #ifdef INET6
730 static struct hostent *
731 _hpmapv6(struct hostent *hp, int *errp)
732 {
733         struct hostent *hp6;
734
735         if (hp == NULL)
736                 return NULL;
737         if (hp->h_addrtype == AF_INET6)
738                 return hp;
739
740         /* make dummy hostent to convert IPv6 address */
741         if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) {
742                 *errp = TRY_AGAIN;
743                 return NULL;
744         }
745         hp6->h_name = NULL;
746         hp6->h_aliases = NULL;
747         hp6->h_addrtype = AF_INET6;
748         hp6->h_length = sizeof(struct in6_addr);
749         hp6->h_addr_list = NULL;
750         return _hpmerge(hp6, hp, errp);
751 }
752 #endif
753
754 /*
755  * _hpsort: sort address by sortlist
756  */
757 static struct hostent *
758 _hpsort(struct hostent *hp)
759 {
760         int i, j, n;
761         u_char *ap, *sp, *mp, **pp;
762         char t;
763         char order[MAXADDRS];
764         int nsort = _res.nsort;
765
766         if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0)
767                 return hp;
768         for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) {
769                 for (j = 0; j < nsort; j++) {
770 #ifdef INET6
771                         if (_res_ext.sort_list[j].af != hp->h_addrtype)
772                                 continue;
773                         sp = (u_char *)&_res_ext.sort_list[j].addr;
774                         mp = (u_char *)&_res_ext.sort_list[j].mask;
775 #else
776                         sp = (u_char *)&_res.sort_list[j].addr;
777                         mp = (u_char *)&_res.sort_list[j].mask;
778 #endif
779                         for (n = 0; n < hp->h_length; n++) {
780                                 if ((ap[n] & mp[n]) != sp[n])
781                                         break;
782                         }
783                         if (n == hp->h_length)
784                                 break;
785                 }
786                 order[i] = j;
787         }
788         n = i;
789         pp = (u_char **)hp->h_addr_list;
790         for (i = 0; i < n - 1; i++) {
791                 for (j = i + 1; j < n; j++) {
792                         if (order[i] > order[j]) {
793                                 ap = pp[i];
794                                 pp[i] = pp[j];
795                                 pp[j] = ap;
796                                 t = order[i];
797                                 order[i] = order[j];
798                                 order[j] = t;
799                         }
800                 }
801         }
802         return hp;
803 }
804
805 static char *
806 _hgetword(char **pp)
807 {
808         char c, *p, *ret;
809         const char *sp;
810         static const char sep[] = "# \t\n";
811
812         ret = NULL;
813         for (p = *pp; (c = *p) != '\0'; p++) {
814                 for (sp = sep; *sp != '\0'; sp++) {
815                         if (c == *sp)
816                                 break;
817                 }
818                 if (c == '#')
819                         p[1] = '\0';    /* ignore rest of line */
820                 if (ret == NULL) {
821                         if (*sp == '\0')
822                                 ret = p;
823                 } else {
824                         if (*sp != '\0') {
825                                 *p++ = '\0';
826                                 break;
827                         }
828                 }
829         }
830         *pp = p;
831         if (ret == NULL || *ret == '\0')
832                 return NULL;
833         return ret;
834 }
835
836 /*
837  * FILES (/etc/hosts)
838  */
839
840 static FILE *
841 _files_open(int *errp)
842 {
843         FILE *fp;
844         fp = fopen(_PATH_HOSTS, "r");
845         if (fp == NULL)
846                 *errp = NO_RECOVERY;
847         return fp;
848 }
849
850 static struct hostent *
851 _files_ghbyname(const char *name, int af, int *errp)
852 {
853         int match, nalias;
854         char *p, *line, *addrstr, *cname;
855         FILE *fp;
856         struct hostent *rethp, *hp, hpbuf;
857         char *aliases[MAXALIASES + 1], *addrs[2];
858         union inx_addr addrbuf;
859         char buf[BUFSIZ];
860         int af0 = af;
861
862         if ((fp = _files_open(errp)) == NULL)
863                 return NULL;
864         rethp = hp = NULL;
865
866         while (fgets(buf, sizeof(buf), fp)) {
867                 line = buf;
868                 if ((addrstr = _hgetword(&line)) == NULL
869                 ||  (cname = _hgetword(&line)) == NULL)
870                         continue;
871                 match = (strcasecmp(cname, name) == 0);
872                 nalias = 0;
873                 while ((p = _hgetword(&line)) != NULL) {
874                         if (!match)
875                                 match = (strcasecmp(p, name) == 0);
876                         if (nalias < MAXALIASES)
877                                 aliases[nalias++] = p;
878                 }
879                 if (!match)
880                         continue;
881                 switch (af0) {
882                 case AF_INET:
883                         if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
884                             != 1) {
885                                 *errp = NO_DATA;        /* name found */
886                                 continue;
887                         }
888                         af = af0;
889                         break;
890 #ifdef INET6
891                 case AF_INET6:
892                         if (inet_pton(af, addrstr, &addrbuf) != 1) {
893                                 *errp = NO_DATA;        /* name found */
894                                 continue;
895                         }
896                         af = af0;
897                         break;
898 #endif
899                 case AF_UNSPEC:
900                         if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
901                             == 1) {
902                                 af = AF_INET;
903                                 break;
904                         }
905 #ifdef INET6
906                         if (inet_pton(AF_INET6, addrstr, &addrbuf) == 1) {
907                                 af = AF_INET6;
908                                 break; 
909                         }
910 #endif
911                         *errp = NO_DATA;        /* name found */
912                         continue;
913                         /* NOTREACHED */
914                 }
915                 hp = &hpbuf;
916                 hp->h_name = cname;
917                 hp->h_aliases = aliases;
918                 aliases[nalias] = NULL;
919                 hp->h_addrtype = af;
920                 hp->h_length = ADDRLEN(af);
921                 hp->h_addr_list = addrs;
922                 addrs[0] = (char *)&addrbuf;
923                 addrs[1] = NULL;
924                 hp = _hpcopy(hp, errp);
925                 rethp = _hpmerge(rethp, hp, errp);
926         }
927         fclose(fp);
928         return rethp;
929 }
930
931 static struct hostent *
932 _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
933 {
934         int nalias;
935         char *p, *line;
936         FILE *fp;
937         struct hostent *hp, hpbuf;
938         char *aliases[MAXALIASES + 1], *addrs[2];
939         union inx_addr addrbuf;
940         char buf[BUFSIZ];
941
942         if ((fp = _files_open(errp)) == NULL)
943                 return NULL;
944         hp = NULL;
945         while (fgets(buf, sizeof(buf), fp)) {
946                 line = buf;
947                 if ((p = _hgetword(&line)) == NULL
948                 ||  (af == AF_INET
949                      ? inet_aton(p, (struct in_addr *)&addrbuf)
950                      : inet_pton(af, p, &addrbuf)) != 1
951                 ||  memcmp(addr, &addrbuf, addrlen) != 0
952                 ||  (p = _hgetword(&line)) == NULL)
953                         continue;
954                 hp = &hpbuf;
955                 hp->h_name = p;
956                 hp->h_aliases = aliases;
957                 nalias = 0;
958                 while ((p = _hgetword(&line)) != NULL) {
959                         if (nalias < MAXALIASES)
960                                 aliases[nalias++] = p;
961                 }
962                 aliases[nalias] = NULL;
963                 hp->h_addrtype = af;
964                 hp->h_length = addrlen;
965                 hp->h_addr_list = addrs;
966                 addrs[0] = (char *)&addrbuf;
967                 addrs[1] = NULL;
968                 hp = _hpcopy(hp, errp);
969                 break;
970         }
971         fclose(fp);
972         return hp;
973 }
974
975 #ifdef YP
976 /*
977  * NIS
978  *
979  * XXX actually a hack, these are INET4 specific.
980  */
981 static struct hostent *
982 _nis_ghbyname(const char *name, int af, int *errp)
983 {
984         struct hostent *hp = NULL;
985
986         if (af == AF_UNSPEC)
987                 af = AF_INET;
988         if (af == AF_INET) {
989                 hp = _gethostbynisname(name, af);
990                 if (hp != NULL)
991                         hp = _hpcopy(hp, errp);
992         }
993         return (hp);
994         
995 }
996
997 static struct hostent *
998 _nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
999 {
1000         struct hostent *hp = NULL;
1001
1002         if (af == AF_INET) {
1003                 hp = _gethostbynisaddr(addr, addrlen, af);
1004                 if (hp != NULL)
1005                         hp = _hpcopy(hp, errp);
1006         }
1007         return (hp);
1008 }
1009 #endif
1010
1011 struct __res_type_list {
1012         SLIST_ENTRY(__res_type_list) rtl_entry;
1013         int     rtl_type;
1014 };
1015
1016 #define MAXPACKET       (64*1024)
1017
1018 typedef union {
1019         HEADER hdr;
1020         u_char buf[MAXPACKET];
1021 } querybuf;
1022
1023 static struct hostent *getanswer (const querybuf *, int, const char *,
1024         int, struct hostent *, int *);
1025
1026 /*
1027  * we don't need to take care about sorting, nor IPv4 mapped address here.
1028  */
1029 static struct hostent *
1030 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
1031           struct hostent *template, int *errp)
1032 {
1033         const HEADER *hp;
1034         const u_char *cp;
1035         int n;
1036         const u_char *eom, *erdata;
1037         char *bp, **ap, **hap, *obp;
1038         int type, class, buflen, ancount, qdcount;
1039         int haveanswer, had_error;
1040         char tbuf[MAXDNAME];
1041         const char *tname;
1042         int (*name_ok) (const char *);
1043         static char *h_addr_ptrs[MAXADDRS + 1];
1044         static char *host_aliases[MAXALIASES];
1045         static char hostbuf[8*1024];
1046
1047 #define BOUNDED_INCR(x) \
1048         do { \
1049                 cp += x; \
1050                 if (cp > eom) { \
1051                         *errp = NO_RECOVERY; \
1052                         return (NULL); \
1053                 } \
1054         } while (0)
1055
1056 #define BOUNDS_CHECK(ptr, count) \
1057         do { \
1058                 if ((ptr) + (count) > eom) { \
1059                         *errp = NO_RECOVERY; \
1060                         return (NULL); \
1061                 } \
1062         } while (0)
1063
1064 /* XXX do {} while (0) cannot be put here */
1065 #define DNS_ASSERT(x) \
1066         {                               \
1067                 if (!(x)) {             \
1068                         cp += n;        \
1069                         continue;       \
1070                 }                       \
1071         }
1072
1073 /* XXX do {} while (0) cannot be put here */
1074 #define DNS_FATAL(x) \
1075         {                               \
1076                 if (!(x)) {             \
1077                         had_error++;    \
1078                         continue;       \
1079                 }                       \
1080         }
1081
1082         tname = qname;
1083         template->h_name = NULL;
1084         eom = answer->buf + anslen;
1085         switch (qtype) {
1086         case T_A:
1087         case T_AAAA:
1088                 name_ok = res_hnok;
1089                 break;
1090         case T_PTR:
1091                 name_ok = res_dnok;
1092                 break;
1093         default:
1094                 return (NULL);  /* XXX should be abort(); */
1095         }
1096         /*
1097          * find first satisfactory answer
1098          */
1099         hp = &answer->hdr;
1100         ancount = ntohs(hp->ancount);
1101         qdcount = ntohs(hp->qdcount);
1102         bp = hostbuf;
1103         buflen = sizeof hostbuf;
1104         cp = answer->buf;
1105         BOUNDED_INCR(HFIXEDSZ);
1106         if (qdcount != 1) {
1107                 *errp = NO_RECOVERY;
1108                 return (NULL);
1109         }
1110         n = dn_expand(answer->buf, eom, cp, bp, buflen);
1111         if ((n < 0) || !(*name_ok)(bp)) {
1112                 *errp = NO_RECOVERY;
1113                 return (NULL);
1114         }
1115         BOUNDED_INCR(n + QFIXEDSZ);
1116         if (qtype == T_A || qtype == T_AAAA) {
1117                 /* res_send() has already verified that the query name is the
1118                  * same as the one we sent; this just gets the expanded name
1119                  * (i.e., with the succeeding search-domain tacked on).
1120                  */
1121                 n = strlen(bp) + 1;             /* for the \0 */
1122                 if (n >= MAXHOSTNAMELEN) {
1123                         *errp = NO_RECOVERY;
1124                         return (NULL);
1125                 }
1126                 template->h_name = bp;
1127                 bp += n;
1128                 buflen -= n;
1129                 /* The qname can be abbreviated, but h_name is now absolute. */
1130                 qname = template->h_name;
1131         }
1132         ap = host_aliases;
1133         *ap = NULL;
1134         template->h_aliases = host_aliases;
1135         hap = h_addr_ptrs;
1136         *hap = NULL;
1137         template->h_addr_list = h_addr_ptrs;
1138         haveanswer = 0;
1139         had_error = 0;
1140         while (ancount-- > 0 && cp < eom && !had_error) {
1141                 n = dn_expand(answer->buf, eom, cp, bp, buflen);
1142                 DNS_FATAL(n >= 0);
1143                 DNS_FATAL((*name_ok)(bp));
1144                 cp += n;                        /* name */
1145                 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
1146                 NS_GET16(type, cp);             /* type */
1147                 NS_GET16(class, cp);            /* class */
1148                 cp += INT32SZ;                  /* skip TTL */
1149                 NS_GET16(n, cp);                /* len */
1150                 BOUNDS_CHECK(cp, n);
1151                 erdata = cp + n;
1152                 DNS_ASSERT(class == C_IN);
1153                 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
1154                         if (ap >= &host_aliases[MAXALIASES-1])
1155                                 continue;
1156                         n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
1157                         DNS_FATAL(n >= 0);
1158                         DNS_FATAL((*name_ok)(tbuf));
1159                         cp += n;
1160                         if (cp != erdata) {
1161                                 *errp = NO_RECOVERY;
1162                                 return (NULL);
1163                         }
1164                         /* Store alias. */
1165                         *ap++ = bp;
1166                         n = strlen(bp) + 1;     /* for the \0 */
1167                         DNS_FATAL(n < MAXHOSTNAMELEN);
1168                         bp += n;
1169                         buflen -= n;
1170                         /* Get canonical name. */
1171                         n = strlen(tbuf) + 1;   /* for the \0 */
1172                         DNS_FATAL(n <= buflen);
1173                         DNS_FATAL(n < MAXHOSTNAMELEN);
1174                         strcpy(bp, tbuf);
1175                         template->h_name = bp;
1176                         bp += n;
1177                         buflen -= n;
1178                         continue;
1179                 }
1180                 if (qtype == T_PTR && type == T_CNAME) {
1181                         n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
1182                         if (n < 0 || !res_dnok(tbuf)) {
1183                                 had_error++;
1184                                 continue;
1185                         }
1186                         cp += n;
1187                         if (cp != erdata) {
1188                                 *errp = NO_RECOVERY;
1189                                 return (NULL);
1190                         }
1191                         /* Get canonical name. */
1192                         n = strlen(tbuf) + 1;   /* for the \0 */
1193                         if (n > buflen || n >= MAXHOSTNAMELEN) {
1194                                 had_error++;
1195                                 continue;
1196                         }
1197                         strcpy(bp, tbuf);
1198                         tname = bp;
1199                         bp += n;
1200                         buflen -= n;
1201                         continue;
1202                 }
1203                 DNS_ASSERT(type == qtype);
1204                 switch (type) {
1205                 case T_PTR:
1206                         DNS_ASSERT(strcasecmp(tname, bp) == 0);
1207                         n = dn_expand(answer->buf, eom, cp, bp, buflen);
1208                         DNS_FATAL(n >= 0);
1209                         DNS_FATAL(res_hnok(bp));
1210 #if MULTI_PTRS_ARE_ALIASES
1211                         cp += n;
1212                         if (cp != erdata) {
1213                                 *errp = NO_RECOVERY;
1214                                 return (NULL);
1215                         }
1216                         if (!haveanswer)
1217                                 template->h_name = bp;
1218                         else if (ap < &host_aliases[MAXALIASES-1])
1219                                 *ap++ = bp;
1220                         else
1221                                 n = -1;
1222                         if (n != -1) {
1223                                 n = strlen(bp) + 1;     /* for the \0 */
1224                                 if (n >= MAXHOSTNAMELEN) {
1225                                         had_error++;
1226                                         break;
1227                                 }
1228                                 bp += n;
1229                                 buflen -= n;
1230                         }
1231                         break;
1232 #else
1233                         template->h_name = bp;
1234                         *errp = NETDB_SUCCESS;
1235                         return (template);
1236 #endif
1237                 case T_A:
1238                 case T_AAAA:
1239                         DNS_ASSERT(strcasecmp(template->h_name, bp) == 0);
1240                         DNS_ASSERT(n == template->h_length);
1241                         if (!haveanswer) {
1242                                 int nn;
1243
1244                                 template->h_name = bp;
1245                                 nn = strlen(bp) + 1;    /* for the \0 */
1246                                 bp += nn;
1247                                 buflen -= nn;
1248                         }
1249                         obp = bp; /* ALIGN rounds up */
1250                         bp = (char *)ALIGN(bp);
1251                         buflen -= (bp - obp);
1252
1253                         DNS_FATAL(bp + n < &hostbuf[sizeof hostbuf]);
1254                         DNS_ASSERT(hap < &h_addr_ptrs[MAXADDRS-1]);
1255 #ifdef FILTER_V4MAPPED
1256                         if (type == T_AAAA) {
1257                                 struct in6_addr in6;
1258                                 memcpy(&in6, cp, sizeof(in6));
1259                                 DNS_ASSERT(IN6_IS_ADDR_V4MAPPED(&in6) == 0);
1260                         }
1261 #endif
1262                         bcopy(cp, *hap++ = bp, n);
1263                         bp += n;
1264                         buflen -= n;
1265                         cp += n;
1266                         if (cp != erdata) {
1267                                 *errp = NO_RECOVERY;
1268                                 return (NULL);
1269                         }
1270                         break;
1271                 default:
1272                         abort();
1273                 }
1274                 if (!had_error)
1275                         haveanswer++;
1276         }
1277         if (haveanswer) {
1278                 *ap = NULL;
1279                 *hap = NULL;
1280                 if (!template->h_name) {
1281                         n = strlen(qname) + 1;  /* for the \0 */
1282                         if (n > buflen || n >= MAXHOSTNAMELEN)
1283                                 goto no_recovery;
1284                         strcpy(bp, qname);
1285                         template->h_name = bp;
1286                         bp += n;
1287                         buflen -= n;
1288                 }
1289                 *errp = NETDB_SUCCESS;
1290                 return (template);
1291         }
1292  no_recovery:
1293         *errp = NO_RECOVERY;
1294         return (NULL);
1295
1296 #undef BOUNDED_INCR
1297 #undef BOUNDS_CHECK
1298 #undef DNS_ASSERT
1299 #undef DNS_FATAL
1300 }
1301
1302 /* res_search() variant with multiple query support. */
1303 static struct hostent *
1304 _res_search_multi(const char *name, struct __res_type_list *rtl, int *errp)
1305 {
1306         const char *cp, * const *domain;
1307         struct hostent *hp0 = NULL, *hp;
1308         struct hostent hpbuf;
1309         u_int dots;
1310         int trailing_dot, ret, saved_herrno;
1311         int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1312         struct __res_type_list *rtl0 = rtl;
1313         querybuf *buf;
1314
1315         if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1316                 *errp = NETDB_INTERNAL;
1317                 return (NULL);
1318         }
1319         dots = 0;
1320         for (cp = name; *cp; cp++)
1321                 dots += (*cp == '.');
1322         trailing_dot = 0;
1323         if (cp > name && *--cp == '.')
1324                 trailing_dot++;
1325
1326         buf = malloc(sizeof(*buf));
1327         if (buf == NULL) {
1328                 *errp = NETDB_INTERNAL;
1329                 return NULL;
1330         }
1331
1332         /* If there aren't any dots, it could be a user-level alias */
1333         if (!dots && (cp = hostalias(name)) != NULL) {
1334                 for(rtl = rtl0; rtl != NULL;
1335                     rtl = SLIST_NEXT(rtl, rtl_entry)) {
1336                         ret = res_query(cp, C_IN, rtl->rtl_type, buf->buf,
1337                                              sizeof(buf->buf));
1338                         if (ret > 0 && (size_t)ret < sizeof(buf->buf)) {
1339                                 hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
1340                                     ? AF_INET6 : AF_INET;
1341                                 hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
1342                                 hp = getanswer(buf, ret, name, rtl->rtl_type,
1343                                                     &hpbuf, errp);
1344                                 if (!hp)
1345                                         continue;
1346                                 hp = _hpcopy(&hpbuf, errp);
1347                                 hp0 = _hpmerge(hp0, hp, errp);
1348                         }
1349                 }
1350                 free(buf);
1351                 return (hp0);
1352         }
1353
1354         /*
1355          * If there are dots in the name already, let's just give it a try
1356          * 'as is'.  The threshold can be set with the "ndots" option.
1357          */
1358         saved_herrno = -1;
1359         if (dots >= _res.ndots) {
1360                 for(rtl = rtl0; rtl != NULL;
1361                     rtl = SLIST_NEXT(rtl, rtl_entry)) {
1362                         ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type,
1363                                               buf->buf, sizeof(buf->buf));
1364                         if (ret > 0 && (size_t)ret < sizeof(buf->buf)) {
1365                                 hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
1366                                     ? AF_INET6 : AF_INET;
1367                                 hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
1368                                 hp = getanswer(buf, ret, name, rtl->rtl_type,
1369                                                     &hpbuf, errp);
1370                                 if (!hp)
1371                                         continue;
1372                                 hp = _hpcopy(&hpbuf, errp);
1373                                 hp0 = _hpmerge(hp0, hp, errp);
1374                         }
1375                 }
1376                 if (hp0 != NULL) {
1377                         free(buf);
1378                         return (hp0);
1379                 }
1380                 saved_herrno = *errp;
1381                 tried_as_is++;
1382         }
1383
1384         /*
1385          * We do at least one level of search if
1386          *      - there is no dot and RES_DEFNAME is set, or
1387          *      - there is at least one dot, there is no trailing dot,
1388          *        and RES_DNSRCH is set.
1389          */
1390         if ((!dots && (_res.options & RES_DEFNAMES)) ||
1391             (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
1392                 int done = 0;
1393
1394                 for (domain = (const char * const *)_res.dnsrch;
1395                      *domain && !done;
1396                      domain++) {
1397
1398                         for(rtl = rtl0; rtl != NULL;
1399                             rtl = SLIST_NEXT(rtl, rtl_entry)) {
1400                                 ret = res_querydomain(name, *domain, C_IN,
1401                                                       rtl->rtl_type,
1402                                                       buf->buf, sizeof(buf->buf));
1403                                 if (ret > 0 && (size_t)ret < sizeof(buf->buf)) {
1404                                         hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
1405                                             ? AF_INET6 : AF_INET;
1406                                         hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
1407                                         hp = getanswer(buf, ret, name,
1408                                             rtl->rtl_type, &hpbuf, errp);
1409                                         if (!hp)
1410                                                 continue;
1411                                         hp = _hpcopy(&hpbuf, errp);
1412                                         hp0 = _hpmerge(hp0, hp, errp);
1413                                 }
1414                         }
1415                         if (hp0 != NULL) {
1416                                 free(buf);
1417                                 return (hp0);
1418                         }
1419
1420                         /*
1421                          * If no server present, give up.
1422                          * If name isn't found in this domain,
1423                          * keep trying higher domains in the search list
1424                          * (if that's enabled).
1425                          * On a NO_DATA error, keep trying, otherwise
1426                          * a wildcard entry of another type could keep us
1427                          * from finding this entry higher in the domain.
1428                          * If we get some other error (negative answer or
1429                          * server failure), then stop searching up,
1430                          * but try the input name below in case it's
1431                          * fully-qualified.
1432                          */
1433                         if (errno == ECONNREFUSED) {
1434                                 free(buf);
1435                                 *errp = TRY_AGAIN;
1436                                 return (NULL);
1437                         }
1438
1439                         switch (*errp) {
1440                         case NO_DATA:
1441                                 got_nodata++;
1442                                 /* FALLTHROUGH */
1443                         case HOST_NOT_FOUND:
1444                                 /* keep trying */
1445                                 break;
1446                         case TRY_AGAIN:
1447                                 if (buf->hdr.rcode == SERVFAIL) {
1448                                         /* try next search element, if any */
1449                                         got_servfail++;
1450                                         break;
1451                                 }
1452                                 /* FALLTHROUGH */
1453                         default:
1454                                 /* anything else implies that we're done */
1455                                 done++;
1456                         }
1457
1458                         /* if we got here for some reason other than DNSRCH,
1459                          * we only wanted one iteration of the loop, so stop.
1460                          */
1461                         if (!(_res.options & RES_DNSRCH))
1462                                 done++;
1463                 }
1464         }
1465
1466         /*
1467          * If we have not already tried the name "as is", do that now.
1468          * note that we do this regardless of how many dots were in the
1469          * name or whether it ends with a dot unless NOTLDQUERY is set.
1470          */
1471         if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) {
1472                 for(rtl = rtl0; rtl != NULL;
1473                     rtl = SLIST_NEXT(rtl, rtl_entry)) {
1474                         ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type,
1475                                               buf->buf, sizeof(buf->buf));
1476                         if (ret > 0 && (size_t)ret < sizeof(buf->buf)) {
1477                                 hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
1478                                     ? AF_INET6 : AF_INET;
1479                                 hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
1480                                 hp = getanswer(buf, ret, name, rtl->rtl_type,
1481                                     &hpbuf, errp);
1482                                 if (!hp)
1483                                         continue;
1484                                 hp = _hpcopy(&hpbuf, errp);
1485                                 hp0 = _hpmerge(hp0, hp, errp);
1486                         }
1487                 }
1488                 if (hp0 != NULL) {
1489                         free(buf);
1490                         return (hp0);
1491                 }
1492         }
1493
1494         free(buf);
1495
1496         /* if we got here, we didn't satisfy the search.
1497          * if we did an initial full query, return that query's h_errno
1498          * (note that we wouldn't be here if that query had succeeded).
1499          * else if we ever got a nodata, send that back as the reason.
1500          * else send back meaningless h_errno, that being the one from
1501          * the last DNSRCH we did.
1502          */
1503         if (saved_herrno != -1)
1504                 *errp = saved_herrno;
1505         else if (got_nodata)
1506                 *errp = NO_DATA;
1507         else if (got_servfail)
1508                 *errp = TRY_AGAIN;
1509         return (NULL);
1510 }
1511
1512 static struct hostent *
1513 _dns_ghbyname(const char *name, int af, int *errp)
1514 {
1515         struct __res_type_list *rtl, rtl4;
1516 #ifdef INET6
1517         struct __res_type_list rtl6;
1518 #endif
1519
1520 #ifdef INET6
1521         switch (af) {
1522         case AF_UNSPEC:
1523                 SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
1524                 SLIST_NEXT(&rtl6, rtl_entry) = &rtl4; rtl6.rtl_type = T_AAAA;
1525                 rtl = &rtl6;
1526                 break;
1527         case AF_INET6:
1528                 SLIST_NEXT(&rtl6, rtl_entry) = NULL; rtl6.rtl_type = T_AAAA;
1529                 rtl = &rtl6;
1530                 break;
1531         case AF_INET:
1532                 SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
1533                 rtl = &rtl4;
1534                 break;
1535         default:
1536                 return(NULL);
1537         }
1538 #else
1539         SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
1540         rtl = &rtl4;
1541 #endif
1542         return(_res_search_multi(name, rtl, errp));
1543 }
1544
1545 static struct hostent *
1546 _dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
1547 {
1548         int n;
1549         struct hostent *hp;
1550         u_char c;
1551         const u_char *cp;
1552         char *bp;
1553         struct hostent hbuf;
1554         int na;
1555 #ifdef INET6
1556         static const char hex[] = "0123456789abcdef";
1557 #endif
1558         querybuf *buf;
1559         char qbuf[MAXDNAME+1];
1560         char *hlist[2];
1561         const char *tld6[] = { "ip6.arpa", "ip6.int", NULL };
1562         const char *tld4[] = { "in-addr.arpa", NULL };
1563         const char **tld;
1564
1565 #ifdef INET6
1566         /* XXX */
1567         if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr))
1568                 return NULL;
1569 #endif
1570
1571         switch (af) {
1572 #ifdef INET6
1573         case AF_INET6:
1574                 tld = tld6;
1575                 break;
1576 #endif
1577         case AF_INET:
1578                 tld = tld4;
1579                 break;
1580         default:
1581                 return NULL;
1582         }
1583
1584         if ((_res.options & RES_INIT) == 0) {
1585                 if (res_init() < 0) {
1586                         *errp = h_errno;
1587                         return NULL;
1588                 }
1589         }
1590         memset(&hbuf, 0, sizeof(hbuf));
1591         hbuf.h_name = NULL;
1592         hbuf.h_addrtype = af;
1593         hbuf.h_length = addrlen;
1594         na = 0;
1595
1596         buf = malloc(sizeof(*buf));
1597         if (buf == NULL) {
1598                 *errp = NETDB_INTERNAL;
1599                 return NULL;
1600         }
1601         for (/* nothing */; *tld; tld++) {
1602                 /*
1603                  * XXX assumes that MAXDNAME is big enough - error checks
1604                  * has been made by callers
1605                  */
1606                 n = 0;
1607                 bp = qbuf;
1608                 cp = (const uint8_t *)addr+addrlen-1;
1609                 switch (af) {
1610 #ifdef INET6
1611                 case AF_INET6:
1612                         for (; n < addrlen; n++, cp--) {
1613                                 c = *cp;
1614                                 *bp++ = hex[c & 0xf];
1615                                 *bp++ = '.';
1616                                 *bp++ = hex[c >> 4];
1617                                 *bp++ = '.';
1618                         }
1619                         strcpy(bp, *tld);
1620                         break;
1621 #endif
1622                 case AF_INET:
1623                         for (; n < addrlen; n++, cp--) {
1624                                 c = *cp;
1625                                 if (c >= 100)
1626                                         *bp++ = '0' + c / 100;
1627                                 if (c >= 10)
1628                                         *bp++ = '0' + (c % 100) / 10;
1629                                 *bp++ = '0' + c % 10;
1630                                 *bp++ = '.';
1631                         }
1632                         strcpy(bp, *tld);
1633                         break;
1634                 }
1635
1636                 n = res_query(qbuf, C_IN, T_PTR, buf->buf, sizeof buf->buf);
1637                 if (n < 0) {
1638                         *errp = h_errno;
1639                         continue;
1640                 } else if ((size_t)n > sizeof(buf->buf)) {
1641                         *errp = NETDB_INTERNAL;
1642 #if 0
1643                         errno = ERANGE; /* XXX is it OK to set errno here? */
1644 #endif
1645                         continue;
1646                 }
1647                 hp = getanswer(buf, n, qbuf, T_PTR, &hbuf, errp);
1648                 if (!hp)
1649                         continue;
1650                 free(buf);
1651                 hbuf.h_addrtype = af;
1652                 hbuf.h_length = addrlen;
1653                 hbuf.h_addr_list = hlist;
1654                 hlist[0] = addr;
1655                 hlist[1] = NULL;
1656                 return _hpcopy(&hbuf, errp);
1657         }
1658         free(buf);
1659         return NULL;
1660 }
1661
1662 #ifdef ICMPNL
1663
1664 /*
1665  * experimental:
1666  *      draft-ietf-ipngwg-icmp-namelookups-02.txt
1667  *      ifindex is assumed to be encoded in addr.
1668  */
1669 #include <sys/uio.h>
1670 #include <netinet/ip6.h>
1671 #include <netinet/icmp6.h>
1672
1673 struct _icmp_host_cache {
1674         struct _icmp_host_cache *hc_next;
1675         int hc_ifindex;
1676         struct in6_addr hc_addr;
1677         char *hc_name;
1678 };
1679
1680 static char *
1681 _icmp_fqdn_query(const struct in6_addr *addr, int ifindex)
1682 {
1683         int s;
1684         struct icmp6_filter filter;
1685         struct msghdr msg;
1686         struct cmsghdr *cmsg;
1687         struct in6_pktinfo *pkt;
1688         char cbuf[256];
1689         char buf[1024];
1690         int cc;
1691         struct icmp6_fqdn_query *fq;
1692         struct icmp6_fqdn_reply *fr;
1693         struct _icmp_host_cache *hc;
1694         struct sockaddr_in6 sin6;
1695         struct iovec iov;
1696         fd_set s_fds, fds;
1697         struct timeval tout;
1698         int len;
1699         char *name;
1700         static int pid;
1701         static struct _icmp_host_cache *hc_head;
1702
1703         for (hc = hc_head; hc; hc = hc->hc_next) {
1704                 if (hc->hc_ifindex == ifindex
1705                 &&  IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr))
1706                         return hc->hc_name;
1707         }
1708
1709         if (pid == 0)
1710                 pid = getpid();
1711
1712         ICMP6_FILTER_SETBLOCKALL(&filter);
1713         ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter);
1714
1715         FD_ZERO(&s_fds);
1716         tout.tv_sec = 0;
1717         tout.tv_usec = 200000;  /*XXX: 200ms*/
1718
1719         fq = (struct icmp6_fqdn_query *)buf;
1720         fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY;
1721         fq->icmp6_fqdn_code = 0;
1722         fq->icmp6_fqdn_cksum = 0;
1723         fq->icmp6_fqdn_id = (u_short)pid;
1724         fq->icmp6_fqdn_unused = 0;
1725         fq->icmp6_fqdn_cookie[0] = 0;
1726         fq->icmp6_fqdn_cookie[1] = 0;
1727
1728         memset(&sin6, 0, sizeof(sin6));
1729         sin6.sin6_family = AF_INET6;
1730         sin6.sin6_addr = *addr;
1731
1732         memset(&msg, 0, sizeof(msg));
1733         msg.msg_name = (caddr_t)&sin6;
1734         msg.msg_namelen = sizeof(sin6);
1735         msg.msg_iov = &iov;
1736         msg.msg_iovlen = 1;
1737         msg.msg_control = NULL;
1738         msg.msg_controllen = 0;
1739         iov.iov_base = (caddr_t)buf;
1740         iov.iov_len = sizeof(struct icmp6_fqdn_query);
1741
1742         if (ifindex) {
1743                 msg.msg_control = cbuf;
1744                 msg.msg_controllen = sizeof(cbuf);
1745                 cmsg = CMSG_FIRSTHDR(&msg);
1746                 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1747                 cmsg->cmsg_level = IPPROTO_IPV6;
1748                 cmsg->cmsg_type = IPV6_PKTINFO;
1749                 pkt = (struct in6_pktinfo *)&cmsg[1];
1750                 memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
1751                 pkt->ipi6_ifindex = ifindex;
1752                 cmsg = CMSG_NXTHDR(&msg, cmsg);
1753                 msg.msg_controllen = (char *)cmsg - cbuf;
1754         }
1755
1756         if ((s = _socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
1757                 return NULL;
1758         _setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
1759                     (char *)&filter, sizeof(filter));
1760         cc = _sendmsg(s, &msg, 0);
1761         if (cc < 0) {
1762                 _close(s);
1763                 return NULL;
1764         }
1765         FD_SET(s, &s_fds);
1766         for (;;) {
1767                 fds = s_fds;
1768                 if (select(s + 1, &fds, NULL, NULL, &tout) <= 0) {
1769                         _close(s);
1770                         return NULL;
1771                 }
1772                 len = sizeof(sin6);
1773                 cc = _recvfrom(s, buf, sizeof(buf), 0,
1774                               (struct sockaddr *)&sin6, &len);
1775                 if (cc <= 0) {
1776                         _close(s);
1777                         return NULL;
1778                 }
1779                 if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
1780                         continue;
1781                 if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr))
1782                         continue;
1783                 fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr));
1784                 if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY)
1785                         break;
1786         }
1787         _close(s);
1788         if (fr->icmp6_fqdn_cookie[1] != 0) {
1789                 /* rfc1788 type */
1790                 name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4;
1791                 len = (buf + cc) - name;
1792         } else {
1793                 len = fr->icmp6_fqdn_namelen;
1794                 name = fr->icmp6_fqdn_name;
1795         }
1796         if (len <= 0)
1797                 return NULL;
1798         name[len] = 0;
1799
1800         if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL)
1801                 return NULL;
1802         /* XXX: limit number of cached entries */
1803         hc->hc_ifindex = ifindex;
1804         hc->hc_addr = *addr;
1805         hc->hc_name = strdup(name);
1806         hc->hc_next = hc_head;
1807         hc_head = hc;
1808         return hc->hc_name;
1809 }
1810
1811 static struct hostent *
1812 _icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
1813 {
1814         char *hname;
1815         int ifindex;
1816         struct in6_addr addr6;
1817
1818         if (af != AF_INET6) {
1819                 /*
1820                  * Note: rfc1788 defines Who Are You for IPv4,
1821                  * but no one implements it.
1822                  */
1823                 return NULL;
1824         }
1825
1826         memcpy(&addr6, addr, addrlen);
1827         ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
1828         addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
1829
1830         if (!IN6_IS_ADDR_LINKLOCAL(&addr6))
1831                 return NULL;    /*XXX*/
1832
1833         if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL)
1834                 return NULL;
1835         return _hpaddr(af, hname, &addr6, errp);
1836 }
1837 #endif /* ICMPNL */