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