xref: /freebsd/lib/libc/net/name6.c (revision e6f35403)
17d56d374SYoshinobu Inoue /*
27d56d374SYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
37d56d374SYoshinobu Inoue  * All rights reserved.
47d56d374SYoshinobu Inoue  *
57d56d374SYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
67d56d374SYoshinobu Inoue  * modification, are permitted provided that the following conditions
77d56d374SYoshinobu Inoue  * are met:
87d56d374SYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
97d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
107d56d374SYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
117d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
127d56d374SYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
137d56d374SYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
147d56d374SYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
157d56d374SYoshinobu Inoue  *    without specific prior written permission.
167d56d374SYoshinobu Inoue  *
177d56d374SYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
187d56d374SYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
197d56d374SYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
207d56d374SYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
217d56d374SYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
227d56d374SYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
237d56d374SYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
247d56d374SYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
257d56d374SYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
267d56d374SYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
277d56d374SYoshinobu Inoue  * SUCH DAMAGE.
287d56d374SYoshinobu Inoue  *
297d56d374SYoshinobu Inoue  * $FreeBSD$
307d56d374SYoshinobu Inoue  */
317d56d374SYoshinobu Inoue /* $Id: name6.c,v 1.9 1999/10/29 03:04:26 itojun Exp $ */
327d56d374SYoshinobu Inoue /*
337d56d374SYoshinobu Inoue  *	Atsushi Onoe <onoe@sm.sony.co.jp>
347d56d374SYoshinobu Inoue  */
357d56d374SYoshinobu Inoue 
367d56d374SYoshinobu Inoue /*
377d56d374SYoshinobu Inoue  * TODO for thread safe
387d56d374SYoshinobu Inoue  *	use mutex for _hostconf, _hostconf_init.
397d56d374SYoshinobu Inoue  *	rewrite resolvers to be thread safe
407d56d374SYoshinobu Inoue  */
417d56d374SYoshinobu Inoue 
427d56d374SYoshinobu Inoue #include <sys/param.h>
437d56d374SYoshinobu Inoue #include <sys/socket.h>
447d56d374SYoshinobu Inoue #include <sys/time.h>
45e6f35403SYoshinobu Inoue #include <sys/queue.h>
467d56d374SYoshinobu Inoue #include <netinet/in.h>
477d56d374SYoshinobu Inoue 
487d56d374SYoshinobu Inoue #include <arpa/inet.h>
497d56d374SYoshinobu Inoue #include <arpa/nameser.h>
507d56d374SYoshinobu Inoue 
51e6f35403SYoshinobu Inoue #include <errno.h>
527d56d374SYoshinobu Inoue #include <netdb.h>
537d56d374SYoshinobu Inoue #include <resolv.h>
547d56d374SYoshinobu Inoue #include <stdio.h>
557d56d374SYoshinobu Inoue #include <stdlib.h>
567d56d374SYoshinobu Inoue #include <string.h>
577d56d374SYoshinobu Inoue #include <unistd.h>
587d56d374SYoshinobu Inoue 
597d56d374SYoshinobu Inoue #ifndef _PATH_HOSTS
607d56d374SYoshinobu Inoue #define	_PATH_HOSTS	"/etc/hosts"
617d56d374SYoshinobu Inoue #endif
627d56d374SYoshinobu Inoue 
637d56d374SYoshinobu Inoue #ifndef MAXALIASES
647d56d374SYoshinobu Inoue #define	MAXALIASES	10
657d56d374SYoshinobu Inoue #endif
667d56d374SYoshinobu Inoue #ifndef	MAXADDRS
677d56d374SYoshinobu Inoue #define	MAXADDRS	20
687d56d374SYoshinobu Inoue #endif
697d56d374SYoshinobu Inoue #ifndef MAXDNAME
707d56d374SYoshinobu Inoue #define	MAXDNAME	1025
717d56d374SYoshinobu Inoue #endif
727d56d374SYoshinobu Inoue 
737d56d374SYoshinobu Inoue #ifdef INET6
747d56d374SYoshinobu Inoue #define	ADDRLEN(af)	((af) == AF_INET6 ? sizeof(struct in6_addr) : \
757d56d374SYoshinobu Inoue 					    sizeof(struct in_addr))
767d56d374SYoshinobu Inoue #else
777d56d374SYoshinobu Inoue #define	ADDRLEN(af)	sizeof(struct in_addr)
787d56d374SYoshinobu Inoue #endif
797d56d374SYoshinobu Inoue 
807d56d374SYoshinobu Inoue #define	MAPADDR(ab, ina) \
817d56d374SYoshinobu Inoue do {									\
827d56d374SYoshinobu Inoue 	memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr));		\
837d56d374SYoshinobu Inoue 	memset((ab)->map_zero, 0, sizeof((ab)->map_zero));		\
847d56d374SYoshinobu Inoue 	memset((ab)->map_one, 0xff, sizeof((ab)->map_one));		\
857d56d374SYoshinobu Inoue } while (0)
867d56d374SYoshinobu Inoue #define	MAPADDRENABLED(flags) \
877d56d374SYoshinobu Inoue 	(((flags) & AI_V4MAPPED) || \
887d56d374SYoshinobu Inoue 	 (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled()))
897d56d374SYoshinobu Inoue 
907d56d374SYoshinobu Inoue union inx_addr {
917d56d374SYoshinobu Inoue 	struct in_addr	in_addr;
927d56d374SYoshinobu Inoue #ifdef INET6
937d56d374SYoshinobu Inoue 	struct in6_addr	in6_addr;
947d56d374SYoshinobu Inoue #endif
957d56d374SYoshinobu Inoue 	struct {
967d56d374SYoshinobu Inoue 		u_char	mau_zero[10];
977d56d374SYoshinobu Inoue 		u_char	mau_one[2];
987d56d374SYoshinobu Inoue 		struct in_addr mau_inaddr;
997d56d374SYoshinobu Inoue 	}		map_addr_un;
1007d56d374SYoshinobu Inoue #define	map_zero	map_addr_un.mau_zero
1017d56d374SYoshinobu Inoue #define	map_one		map_addr_un.mau_one
1027d56d374SYoshinobu Inoue #define	map_inaddr	map_addr_un.mau_inaddr
1037d56d374SYoshinobu Inoue };
1047d56d374SYoshinobu Inoue 
1057d56d374SYoshinobu Inoue static struct	 hostent *_hpcopy(struct hostent *hp, int *errp);
1067d56d374SYoshinobu Inoue static struct	 hostent *_hpaddr(int af, const char *name, void *addr, int *errp);
1077d56d374SYoshinobu Inoue static struct	 hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp);
1087d56d374SYoshinobu Inoue #ifdef INET6
1097d56d374SYoshinobu Inoue static struct	 hostent *_hpmapv6(struct hostent *hp, int *errp);
1107d56d374SYoshinobu Inoue #endif
1117d56d374SYoshinobu Inoue static struct	 hostent *_hpsort(struct hostent *hp);
1127d56d374SYoshinobu Inoue static struct	 hostent *_ghbyname(const char *name, int af, int flags, int *errp);
1137d56d374SYoshinobu Inoue static char	*_hgetword(char **pp);
1147d56d374SYoshinobu Inoue static int	 _mapped_addr_enabled(void);
1157d56d374SYoshinobu Inoue 
1167d56d374SYoshinobu Inoue static FILE	*_files_open(int *errp);
1177d56d374SYoshinobu Inoue static struct	 hostent *_files_ghbyname(const char *name, int af, int *errp);
1187d56d374SYoshinobu Inoue static struct	 hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
1197d56d374SYoshinobu Inoue static void	 _files_shent(int stayopen);
1207d56d374SYoshinobu Inoue static void	 _files_ehent(void);
12163858012SJonathan Lemon static struct	 hostent *_nis_ghbyname(const char *name, int af, int *errp);
12263858012SJonathan Lemon static struct	 hostent *_nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
1237d56d374SYoshinobu Inoue static struct	 hostent *_dns_ghbyname(const char *name, int af, int *errp);
1247d56d374SYoshinobu Inoue static struct	 hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
1257d56d374SYoshinobu Inoue static void	 _dns_shent(int stayopen);
1267d56d374SYoshinobu Inoue static void	 _dns_ehent(void);
1277d56d374SYoshinobu Inoue #ifdef ICMPNL
1287d56d374SYoshinobu Inoue static struct	 hostent *_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
1297d56d374SYoshinobu Inoue #endif /* ICMPNL */
1307d56d374SYoshinobu Inoue 
1317d56d374SYoshinobu Inoue /*
1327d56d374SYoshinobu Inoue  * Select order host function.
1337d56d374SYoshinobu Inoue  */
1347d56d374SYoshinobu Inoue #define	MAXHOSTCONF	4
1357d56d374SYoshinobu Inoue 
1367d56d374SYoshinobu Inoue #ifndef HOSTCONF
1377d56d374SYoshinobu Inoue #  define	HOSTCONF	"/etc/host.conf"
1387d56d374SYoshinobu Inoue #endif /* !HOSTCONF */
1397d56d374SYoshinobu Inoue 
1407d56d374SYoshinobu Inoue struct _hostconf {
1417d56d374SYoshinobu Inoue 	struct hostent *(*byname)(const char *name, int af, int *errp);
1427d56d374SYoshinobu Inoue 	struct hostent *(*byaddr)(const void *addr, int addrlen, int af, int *errp);
1437d56d374SYoshinobu Inoue };
1447d56d374SYoshinobu Inoue 
1457d56d374SYoshinobu Inoue /* default order */
1467d56d374SYoshinobu Inoue static struct _hostconf _hostconf[MAXHOSTCONF] = {
1477d56d374SYoshinobu Inoue 	{ _dns_ghbyname,	_dns_ghbyaddr },
1487d56d374SYoshinobu Inoue 	{ _files_ghbyname,	_files_ghbyaddr },
1497d56d374SYoshinobu Inoue #ifdef ICMPNL
1507d56d374SYoshinobu Inoue 	{ NULL,			_icmp_ghbyaddr },
1517d56d374SYoshinobu Inoue #endif /* ICMPNL */
1527d56d374SYoshinobu Inoue };
1537d56d374SYoshinobu Inoue 
1547d56d374SYoshinobu Inoue static int	_hostconf_init_done;
1557d56d374SYoshinobu Inoue static void	_hostconf_init(void);
1567d56d374SYoshinobu Inoue 
1577d56d374SYoshinobu Inoue /*
1587d56d374SYoshinobu Inoue  * Initialize hostconf structure.
1597d56d374SYoshinobu Inoue  */
1607d56d374SYoshinobu Inoue 
1617d56d374SYoshinobu Inoue static void
1627d56d374SYoshinobu Inoue _hostconf_init(void)
1637d56d374SYoshinobu Inoue {
1647d56d374SYoshinobu Inoue 	FILE *fp;
1657d56d374SYoshinobu Inoue 	int n;
1667d56d374SYoshinobu Inoue 	char *p, *line;
1677d56d374SYoshinobu Inoue 	char buf[BUFSIZ];
1687d56d374SYoshinobu Inoue 
1697d56d374SYoshinobu Inoue 	_hostconf_init_done = 1;
1707d56d374SYoshinobu Inoue 	n = 0;
1717d56d374SYoshinobu Inoue 	p = HOSTCONF;
1727d56d374SYoshinobu Inoue 	if ((fp = fopen(p, "r")) == NULL)
1737d56d374SYoshinobu Inoue 		return;
1747d56d374SYoshinobu Inoue 	while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) {
1757d56d374SYoshinobu Inoue 		line = buf;
1767d56d374SYoshinobu Inoue 		if ((p = _hgetword(&line)) == NULL)
1777d56d374SYoshinobu Inoue 			continue;
1787d56d374SYoshinobu Inoue 		do {
1797d56d374SYoshinobu Inoue 			if (strcmp(p, "hosts") == 0
1807d56d374SYoshinobu Inoue 			||  strcmp(p, "local") == 0
1817d56d374SYoshinobu Inoue 			||  strcmp(p, "file") == 0
1827d56d374SYoshinobu Inoue 			||  strcmp(p, "files") == 0) {
1837d56d374SYoshinobu Inoue 				_hostconf[n].byname = _files_ghbyname;
1847d56d374SYoshinobu Inoue 				_hostconf[n].byaddr = _files_ghbyaddr;
1857d56d374SYoshinobu Inoue 				n++;
1867d56d374SYoshinobu Inoue 			}
1877d56d374SYoshinobu Inoue 			else if (strcmp(p, "dns") == 0
1887d56d374SYoshinobu Inoue 			     ||  strcmp(p, "bind") == 0) {
1897d56d374SYoshinobu Inoue 				_hostconf[n].byname = _dns_ghbyname;
1907d56d374SYoshinobu Inoue 				_hostconf[n].byaddr = _dns_ghbyaddr;
1917d56d374SYoshinobu Inoue 				n++;
1927d56d374SYoshinobu Inoue 			}
19363858012SJonathan Lemon 			else if (strcmp(p, "nis") == 0) {
19463858012SJonathan Lemon 				_hostconf[n].byname = _nis_ghbyname;
19563858012SJonathan Lemon 				_hostconf[n].byaddr = _nis_ghbyaddr;
19663858012SJonathan Lemon 				n++;
19763858012SJonathan Lemon 			}
1987d56d374SYoshinobu Inoue #ifdef ICMPNL
1997d56d374SYoshinobu Inoue 			else if (strcmp(p, "icmp") == 0) {
2007d56d374SYoshinobu Inoue 				_hostconf[n].byname = NULL;
2017d56d374SYoshinobu Inoue 				_hostconf[n].byaddr = _icmp_ghbyaddr;
2027d56d374SYoshinobu Inoue 				n++;
2037d56d374SYoshinobu Inoue 			}
2047d56d374SYoshinobu Inoue #endif /* ICMPNL */
2057d56d374SYoshinobu Inoue 		} while ((p = _hgetword(&line)) != NULL);
2067d56d374SYoshinobu Inoue 	}
2077d56d374SYoshinobu Inoue 	fclose(fp);
2087d56d374SYoshinobu Inoue 	if (n < 0) {
2097d56d374SYoshinobu Inoue 		/* no keyword found. do not change default configuration */
2107d56d374SYoshinobu Inoue 		return;
2117d56d374SYoshinobu Inoue 	}
2127d56d374SYoshinobu Inoue 	for (; n < MAXHOSTCONF; n++) {
2137d56d374SYoshinobu Inoue 		_hostconf[n].byname = NULL;
2147d56d374SYoshinobu Inoue 		_hostconf[n].byaddr = NULL;
2157d56d374SYoshinobu Inoue 	}
2167d56d374SYoshinobu Inoue }
2177d56d374SYoshinobu Inoue 
2187d56d374SYoshinobu Inoue /*
2197d56d374SYoshinobu Inoue  * Check if kernel supports mapped address.
2207d56d374SYoshinobu Inoue  *	implementation dependent
2217d56d374SYoshinobu Inoue  */
2227d56d374SYoshinobu Inoue #ifdef __KAME__
2237d56d374SYoshinobu Inoue #include <sys/sysctl.h>
2247d56d374SYoshinobu Inoue #endif /* __KAME__ */
2257d56d374SYoshinobu Inoue 
2267d56d374SYoshinobu Inoue static int
2277d56d374SYoshinobu Inoue _mapped_addr_enabled(void)
2287d56d374SYoshinobu Inoue {
2297d56d374SYoshinobu Inoue 	/* implementation dependent check */
2307d56d374SYoshinobu Inoue #if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR)
2317d56d374SYoshinobu Inoue 	int mib[4];
2327d56d374SYoshinobu Inoue 	size_t len;
2337d56d374SYoshinobu Inoue 	int val;
2347d56d374SYoshinobu Inoue 
2357d56d374SYoshinobu Inoue 	mib[0] = CTL_NET;
2367d56d374SYoshinobu Inoue 	mib[1] = PF_INET6;
2377d56d374SYoshinobu Inoue 	mib[2] = IPPROTO_IPV6;
2387d56d374SYoshinobu Inoue 	mib[3] = IPV6CTL_MAPPED_ADDR;
2397d56d374SYoshinobu Inoue 	len = sizeof(val);
2407d56d374SYoshinobu Inoue 	if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0)
2417d56d374SYoshinobu Inoue 		return 1;
2427d56d374SYoshinobu Inoue #endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */
2437d56d374SYoshinobu Inoue 	return 0;
2447d56d374SYoshinobu Inoue }
2457d56d374SYoshinobu Inoue 
2467d56d374SYoshinobu Inoue /*
2477d56d374SYoshinobu Inoue  * Functions defined in RFC2553
2487d56d374SYoshinobu Inoue  *	getipnodebyname, getipnodebyadr, freehostent
2497d56d374SYoshinobu Inoue  */
2507d56d374SYoshinobu Inoue 
2517d56d374SYoshinobu Inoue static struct hostent *
2527d56d374SYoshinobu Inoue _ghbyname(const char *name, int af, int flags, int *errp)
2537d56d374SYoshinobu Inoue {
2547d56d374SYoshinobu Inoue 	struct hostent *hp;
2557d56d374SYoshinobu Inoue 	int i;
2567d56d374SYoshinobu Inoue 
2577d56d374SYoshinobu Inoue 	if (flags & AI_ADDRCONFIG) {
2587d56d374SYoshinobu Inoue 		int s;
2597d56d374SYoshinobu Inoue 
2607d56d374SYoshinobu Inoue 		/*
2617d56d374SYoshinobu Inoue 		 * TODO:
2627d56d374SYoshinobu Inoue 		 * Note that implementation dependent test for address
2637d56d374SYoshinobu Inoue 		 * configuration should be done everytime called
2647d56d374SYoshinobu Inoue 		 * (or apropriate interval),
2657d56d374SYoshinobu Inoue 		 * because addresses will be dynamically assigned or deleted.
2667d56d374SYoshinobu Inoue 		 */
267e6f35403SYoshinobu Inoue 		if (af == AF_UNSPEC) {
268e6f35403SYoshinobu Inoue 			if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
269e6f35403SYoshinobu Inoue 				af = AF_INET;
270e6f35403SYoshinobu Inoue 			else {
2719233c4d9SJason Evans 				_close(s);
272e6f35403SYoshinobu Inoue 				if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
273e6f35403SYoshinobu Inoue 					af = AF_INET6;
274e6f35403SYoshinobu Inoue 				else
275e6f35403SYoshinobu Inoue 				_close(s);
276e6f35403SYoshinobu Inoue 			}
277e6f35403SYoshinobu Inoue 
278e6f35403SYoshinobu Inoue 		}
279e6f35403SYoshinobu Inoue 		if (af != AF_UNSPEC) {
280e6f35403SYoshinobu Inoue 			if ((s = socket(af, SOCK_DGRAM, 0)) < 0)
281e6f35403SYoshinobu Inoue 				return NULL;
282e6f35403SYoshinobu Inoue 			_close(s);
283e6f35403SYoshinobu Inoue 		}
2847d56d374SYoshinobu Inoue 	}
2857d56d374SYoshinobu Inoue 
2867d56d374SYoshinobu Inoue 	for (i = 0; i < MAXHOSTCONF; i++) {
2877d56d374SYoshinobu Inoue 		if (_hostconf[i].byname
2887d56d374SYoshinobu Inoue 		&&  (hp = (*_hostconf[i].byname)(name, af, errp))
2897d56d374SYoshinobu Inoue 		    != NULL)
2907d56d374SYoshinobu Inoue 			return hp;
2917d56d374SYoshinobu Inoue 	}
2927d56d374SYoshinobu Inoue 
2937d56d374SYoshinobu Inoue 	return NULL;
2947d56d374SYoshinobu Inoue }
2957d56d374SYoshinobu Inoue 
296e6f35403SYoshinobu Inoue /* getipnodebyname() internal routine for multiple query(PF_UNSPEC) support. */
2977d56d374SYoshinobu Inoue struct hostent *
298e6f35403SYoshinobu Inoue _getipnodebyname_multi(const char *name, int af, int flags, int *errp)
2997d56d374SYoshinobu Inoue {
3007d56d374SYoshinobu Inoue 	struct hostent *hp;
3017d56d374SYoshinobu Inoue 	union inx_addr addrbuf;
3027d56d374SYoshinobu Inoue 
303e6f35403SYoshinobu Inoue 	/* XXX: PF_UNSPEC is only supposed to be passed from getaddrinfo() */
3047d56d374SYoshinobu Inoue 	if (af != AF_INET
3057d56d374SYoshinobu Inoue #ifdef INET6
3067d56d374SYoshinobu Inoue 	    && af != AF_INET6
3077d56d374SYoshinobu Inoue #endif
308e6f35403SYoshinobu Inoue 	    && af != PF_UNSPEC
3097d56d374SYoshinobu Inoue 		)
3107d56d374SYoshinobu Inoue 	{
3117d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
3127d56d374SYoshinobu Inoue 		return NULL;
3137d56d374SYoshinobu Inoue 	}
3147d56d374SYoshinobu Inoue 
3157d56d374SYoshinobu Inoue #ifdef INET6
3167d56d374SYoshinobu Inoue 	/* special case for literal address */
3177d56d374SYoshinobu Inoue 	if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
3187d56d374SYoshinobu Inoue 		if (af != AF_INET6) {
3197d56d374SYoshinobu Inoue 			*errp = HOST_NOT_FOUND;
3207d56d374SYoshinobu Inoue 			return NULL;
3217d56d374SYoshinobu Inoue 		}
3227d56d374SYoshinobu Inoue 		return _hpaddr(af, name, &addrbuf, errp);
3237d56d374SYoshinobu Inoue 	}
3247d56d374SYoshinobu Inoue #endif
325be26adb5SYoshinobu Inoue 	if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) {
3267d56d374SYoshinobu Inoue 		if (af != AF_INET) {
3277d56d374SYoshinobu Inoue 			if (MAPADDRENABLED(flags)) {
3287d56d374SYoshinobu Inoue 				MAPADDR(&addrbuf, &addrbuf.in_addr);
3297d56d374SYoshinobu Inoue 			} else {
3307d56d374SYoshinobu Inoue 				*errp = HOST_NOT_FOUND;
3317d56d374SYoshinobu Inoue 				return NULL;
3327d56d374SYoshinobu Inoue 			}
3337d56d374SYoshinobu Inoue 		}
3347d56d374SYoshinobu Inoue 		return _hpaddr(af, name, &addrbuf, errp);
3357d56d374SYoshinobu Inoue 	}
3367d56d374SYoshinobu Inoue 
3377d56d374SYoshinobu Inoue 	if (!_hostconf_init_done)
3387d56d374SYoshinobu Inoue 		_hostconf_init();
3397d56d374SYoshinobu Inoue 
3407d56d374SYoshinobu Inoue 	*errp = HOST_NOT_FOUND;
3417d56d374SYoshinobu Inoue 	hp = _ghbyname(name, af, flags, errp);
3427d56d374SYoshinobu Inoue 
3437d56d374SYoshinobu Inoue #ifdef INET6
3447d56d374SYoshinobu Inoue 	if (af == AF_INET6
3457d56d374SYoshinobu Inoue 	&&  ((flags & AI_ALL) || hp == NULL)
3467d56d374SYoshinobu Inoue 	&&  (MAPADDRENABLED(flags))) {
3477d56d374SYoshinobu Inoue 		struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp);
3487d56d374SYoshinobu Inoue 		if (hp == NULL)
3497d56d374SYoshinobu Inoue 			hp = _hpmapv6(hp2, errp);
3507d56d374SYoshinobu Inoue 		else {
3517d56d374SYoshinobu Inoue 			if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) {
3527d56d374SYoshinobu Inoue 				freehostent(hp2);
3537d56d374SYoshinobu Inoue 				hp2 = NULL;
3547d56d374SYoshinobu Inoue 			}
3557d56d374SYoshinobu Inoue 			hp = _hpmerge(hp, hp2, errp);
3567d56d374SYoshinobu Inoue 		}
3577d56d374SYoshinobu Inoue 	}
3587d56d374SYoshinobu Inoue #endif
3597d56d374SYoshinobu Inoue 	return _hpsort(hp);
3607d56d374SYoshinobu Inoue }
3617d56d374SYoshinobu Inoue 
3627d56d374SYoshinobu Inoue struct hostent *
363e6f35403SYoshinobu Inoue getipnodebyname(const char *name, int af, int flags, int *errp)
364e6f35403SYoshinobu Inoue {
365e6f35403SYoshinobu Inoue 	if (af != AF_INET
366e6f35403SYoshinobu Inoue #ifdef INET6
367e6f35403SYoshinobu Inoue 	    && af != AF_INET6
368e6f35403SYoshinobu Inoue #endif
369e6f35403SYoshinobu Inoue 		)
370e6f35403SYoshinobu Inoue 	{
371e6f35403SYoshinobu Inoue 		*errp = NO_RECOVERY;
372e6f35403SYoshinobu Inoue 		return NULL;
373e6f35403SYoshinobu Inoue 	}
374e6f35403SYoshinobu Inoue 	return(_getipnodebyname_multi(name, af ,flags, errp));
375e6f35403SYoshinobu Inoue }
376e6f35403SYoshinobu Inoue 
377e6f35403SYoshinobu Inoue struct hostent *
3787d56d374SYoshinobu Inoue getipnodebyaddr(const void *src, size_t len, int af, int *errp)
3797d56d374SYoshinobu Inoue {
3807d56d374SYoshinobu Inoue 	struct hostent *hp;
3817d56d374SYoshinobu Inoue 	int i;
3827d56d374SYoshinobu Inoue #ifdef INET6
3837d56d374SYoshinobu Inoue 	struct in6_addr addrbuf;
3847d56d374SYoshinobu Inoue #else
3857d56d374SYoshinobu Inoue 	struct in_addr addrbuf;
3867d56d374SYoshinobu Inoue #endif
3877d56d374SYoshinobu Inoue 
3887d56d374SYoshinobu Inoue 	*errp = HOST_NOT_FOUND;
3897d56d374SYoshinobu Inoue 
3907d56d374SYoshinobu Inoue 	switch (af) {
3917d56d374SYoshinobu Inoue 	case AF_INET:
3927d56d374SYoshinobu Inoue 		if (len != sizeof(struct in_addr)) {
3937d56d374SYoshinobu Inoue 			*errp = NO_RECOVERY;
3947d56d374SYoshinobu Inoue 			return NULL;
3957d56d374SYoshinobu Inoue 		}
3967d56d374SYoshinobu Inoue 		if ((long)src & ~(sizeof(struct in_addr) - 1)) {
3977d56d374SYoshinobu Inoue 			memcpy(&addrbuf, src, len);
3987d56d374SYoshinobu Inoue 			src = &addrbuf;
3997d56d374SYoshinobu Inoue 		}
4007d56d374SYoshinobu Inoue 		if (((struct in_addr *)src)->s_addr == 0)
4017d56d374SYoshinobu Inoue 			return NULL;
4027d56d374SYoshinobu Inoue 		break;
4037d56d374SYoshinobu Inoue #ifdef INET6
4047d56d374SYoshinobu Inoue 	case AF_INET6:
4057d56d374SYoshinobu Inoue 		if (len != sizeof(struct in6_addr)) {
4067d56d374SYoshinobu Inoue 			*errp = NO_RECOVERY;
4077d56d374SYoshinobu Inoue 			return NULL;
4087d56d374SYoshinobu Inoue 		}
4097d56d374SYoshinobu Inoue 		if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) {	/*XXX*/
4107d56d374SYoshinobu Inoue 			memcpy(&addrbuf, src, len);
4117d56d374SYoshinobu Inoue 			src = &addrbuf;
4127d56d374SYoshinobu Inoue 		}
4133d670abcSYoshinobu Inoue 		if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src))
4143d670abcSYoshinobu Inoue 			return NULL;
4157d56d374SYoshinobu Inoue 		if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)
4167d56d374SYoshinobu Inoue 		||  IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) {
4177d56d374SYoshinobu Inoue 			src = (char *)src +
4187d56d374SYoshinobu Inoue 			    (sizeof(struct in6_addr) - sizeof(struct in_addr));
4197d56d374SYoshinobu Inoue 			af = AF_INET;
4207d56d374SYoshinobu Inoue 			len = sizeof(struct in_addr);
4217d56d374SYoshinobu Inoue 		}
4227d56d374SYoshinobu Inoue 		break;
4237d56d374SYoshinobu Inoue #endif
4247d56d374SYoshinobu Inoue 	default:
4257d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
4267d56d374SYoshinobu Inoue 		return NULL;
4277d56d374SYoshinobu Inoue 	}
4287d56d374SYoshinobu Inoue 
4297d56d374SYoshinobu Inoue 	if (!_hostconf_init_done)
4307d56d374SYoshinobu Inoue 		_hostconf_init();
4317d56d374SYoshinobu Inoue 	for (i = 0; i < MAXHOSTCONF; i++) {
4327d56d374SYoshinobu Inoue 		if (_hostconf[i].byaddr
4337d56d374SYoshinobu Inoue 		&&  (hp = (*_hostconf[i].byaddr)(src, len, af, errp)) != NULL)
4347d56d374SYoshinobu Inoue 			return hp;
4357d56d374SYoshinobu Inoue 	}
4367d56d374SYoshinobu Inoue 
4377d56d374SYoshinobu Inoue 	return NULL;
4387d56d374SYoshinobu Inoue }
4397d56d374SYoshinobu Inoue 
4407d56d374SYoshinobu Inoue void
4417d56d374SYoshinobu Inoue freehostent(struct hostent *ptr)
4427d56d374SYoshinobu Inoue {
4437d56d374SYoshinobu Inoue 	free(ptr);
4447d56d374SYoshinobu Inoue }
4457d56d374SYoshinobu Inoue 
4467d56d374SYoshinobu Inoue #if 0
4477d56d374SYoshinobu Inoue 
4487d56d374SYoshinobu Inoue /* XXX: should be deprecated */
4497d56d374SYoshinobu Inoue struct hostent *
4507d56d374SYoshinobu Inoue getnodebyname(const char *name, int af, int flags)
4517d56d374SYoshinobu Inoue {
4527d56d374SYoshinobu Inoue 	return getipnodebyname(name, af, flags, &h_errno);
4537d56d374SYoshinobu Inoue }
4547d56d374SYoshinobu Inoue 
4557d56d374SYoshinobu Inoue #ifdef __warn_references
4567d56d374SYoshinobu Inoue __warn_references(getnodebyname,
4577d56d374SYoshinobu Inoue 	"warning: getnodebyname() deprecated, "
4587d56d374SYoshinobu Inoue 	"should use getaddrinfo() or getipnodebyname()");
4597d56d374SYoshinobu Inoue #endif
4607d56d374SYoshinobu Inoue 
4617d56d374SYoshinobu Inoue struct hostent *
4627d56d374SYoshinobu Inoue getnodebyaddr(const void *src, size_t len, int af)
4637d56d374SYoshinobu Inoue {
4647d56d374SYoshinobu Inoue 	return getipnodebyaddr(src, len, af, &h_errno);
4657d56d374SYoshinobu Inoue }
4667d56d374SYoshinobu Inoue 
4677d56d374SYoshinobu Inoue #ifdef __warn_references
4687d56d374SYoshinobu Inoue __warn_references(getnodebyaddr,
4697d56d374SYoshinobu Inoue 	"warning: getnodebyaddr() deprecated, "
4707d56d374SYoshinobu Inoue 	"should use getnameinfo() or getipnodebyaddr()");
4717d56d374SYoshinobu Inoue #endif
4727d56d374SYoshinobu Inoue 
4737d56d374SYoshinobu Inoue #endif
4747d56d374SYoshinobu Inoue 
4757d56d374SYoshinobu Inoue /*
4767d56d374SYoshinobu Inoue  * Private utility functions
4777d56d374SYoshinobu Inoue  */
4787d56d374SYoshinobu Inoue 
4797d56d374SYoshinobu Inoue /*
4807d56d374SYoshinobu Inoue  * _hpcopy: allocate and copy hostent structure
4817d56d374SYoshinobu Inoue  */
4827d56d374SYoshinobu Inoue static struct hostent *
4837d56d374SYoshinobu Inoue _hpcopy(struct hostent *hp, int *errp)
4847d56d374SYoshinobu Inoue {
4857d56d374SYoshinobu Inoue 	struct hostent *nhp;
4867d56d374SYoshinobu Inoue 	char *cp, **pp;
4877d56d374SYoshinobu Inoue 	int size, addrsize;
4887d56d374SYoshinobu Inoue 	int nalias = 0, naddr = 0;
4897d56d374SYoshinobu Inoue 	int al_off;
4907d56d374SYoshinobu Inoue 	int i;
4917d56d374SYoshinobu Inoue 
4927d56d374SYoshinobu Inoue 	if (hp == NULL)
4937d56d374SYoshinobu Inoue 		return hp;
4947d56d374SYoshinobu Inoue 
4957d56d374SYoshinobu Inoue 	/* count size to be allocated */
4967d56d374SYoshinobu Inoue 	size = sizeof(struct hostent);
4977d56d374SYoshinobu Inoue 	if (hp->h_name != NULL && *hp->h_name != '\0')
4987d56d374SYoshinobu Inoue 		size += strlen(hp->h_name) + 1;
4997d56d374SYoshinobu Inoue 	if ((pp = hp->h_aliases) != NULL) {
5007d56d374SYoshinobu Inoue 		for (i = 0; *pp != NULL; i++, pp++) {
5017d56d374SYoshinobu Inoue 			if (**pp != '\0') {
5027d56d374SYoshinobu Inoue 				size += strlen(*pp) + 1;
5037d56d374SYoshinobu Inoue 				nalias++;
5047d56d374SYoshinobu Inoue 			}
5057d56d374SYoshinobu Inoue 		}
5067d56d374SYoshinobu Inoue 	}
5077d56d374SYoshinobu Inoue 	/* adjust alignment */
5087d56d374SYoshinobu Inoue 	size = ALIGN(size);
5097d56d374SYoshinobu Inoue 	al_off = size;
5107d56d374SYoshinobu Inoue 	size += sizeof(char *) * (nalias + 1);
5117d56d374SYoshinobu Inoue 	addrsize = ALIGN(hp->h_length);
5127d56d374SYoshinobu Inoue 	if ((pp = hp->h_addr_list) != NULL) {
5137d56d374SYoshinobu Inoue 		while (*pp++ != NULL)
5147d56d374SYoshinobu Inoue 			naddr++;
5157d56d374SYoshinobu Inoue 	}
5167d56d374SYoshinobu Inoue 	size += addrsize * naddr;
5177d56d374SYoshinobu Inoue 	size += sizeof(char *) * (naddr + 1);
5187d56d374SYoshinobu Inoue 
5197d56d374SYoshinobu Inoue 	/* copy */
5207d56d374SYoshinobu Inoue 	if ((nhp = (struct hostent *)malloc(size)) == NULL) {
5217d56d374SYoshinobu Inoue 		*errp = TRY_AGAIN;
5227d56d374SYoshinobu Inoue 		return NULL;
5237d56d374SYoshinobu Inoue 	}
5247d56d374SYoshinobu Inoue 	cp = (char *)&nhp[1];
5257d56d374SYoshinobu Inoue 	if (hp->h_name != NULL && *hp->h_name != '\0') {
5267d56d374SYoshinobu Inoue 		nhp->h_name = cp;
5277d56d374SYoshinobu Inoue 		strcpy(cp, hp->h_name);
5287d56d374SYoshinobu Inoue 		cp += strlen(cp) + 1;
5297d56d374SYoshinobu Inoue 	} else
5307d56d374SYoshinobu Inoue 		nhp->h_name = NULL;
5317d56d374SYoshinobu Inoue 	nhp->h_aliases = (char **)((char *)nhp + al_off);
5327d56d374SYoshinobu Inoue 	if ((pp = hp->h_aliases) != NULL) {
5337d56d374SYoshinobu Inoue 		for (i = 0; *pp != NULL; pp++) {
5347d56d374SYoshinobu Inoue 			if (**pp != '\0') {
5357d56d374SYoshinobu Inoue 				nhp->h_aliases[i++] = cp;
5367d56d374SYoshinobu Inoue 				strcpy(cp, *pp);
5377d56d374SYoshinobu Inoue 				cp += strlen(cp) + 1;
5387d56d374SYoshinobu Inoue 			}
5397d56d374SYoshinobu Inoue 		}
5407d56d374SYoshinobu Inoue 	}
5417d56d374SYoshinobu Inoue 	nhp->h_aliases[nalias] = NULL;
5427d56d374SYoshinobu Inoue 	cp = (char *)&nhp->h_aliases[nalias + 1];
5437d56d374SYoshinobu Inoue 	nhp->h_addrtype = hp->h_addrtype;
5447d56d374SYoshinobu Inoue 	nhp->h_length = hp->h_length;
5457d56d374SYoshinobu Inoue 	nhp->h_addr_list = (char **)cp;
5467d56d374SYoshinobu Inoue 	if ((pp = hp->h_addr_list) != NULL) {
5477d56d374SYoshinobu Inoue 		cp = (char *)&nhp->h_addr_list[naddr + 1];
5487d56d374SYoshinobu Inoue 		for (i = 0; *pp != NULL; pp++) {
5497d56d374SYoshinobu Inoue 			nhp->h_addr_list[i++] = cp;
5507d56d374SYoshinobu Inoue 			memcpy(cp, *pp, hp->h_length);
5517d56d374SYoshinobu Inoue 			cp += addrsize;
5527d56d374SYoshinobu Inoue 		}
5537d56d374SYoshinobu Inoue 	}
5547d56d374SYoshinobu Inoue 	nhp->h_addr_list[naddr] = NULL;
5557d56d374SYoshinobu Inoue 	return nhp;
5567d56d374SYoshinobu Inoue }
5577d56d374SYoshinobu Inoue 
5587d56d374SYoshinobu Inoue /*
5597d56d374SYoshinobu Inoue  * _hpaddr: construct hostent structure with one address
5607d56d374SYoshinobu Inoue  */
5617d56d374SYoshinobu Inoue static struct hostent *
5627d56d374SYoshinobu Inoue _hpaddr(int af, const char *name, void *addr, int *errp)
5637d56d374SYoshinobu Inoue {
5647d56d374SYoshinobu Inoue 	struct hostent *hp, hpbuf;
5657d56d374SYoshinobu Inoue 	char *addrs[2];
5667d56d374SYoshinobu Inoue 
5677d56d374SYoshinobu Inoue 	hp = &hpbuf;
5687d56d374SYoshinobu Inoue 	hp->h_name = (char *)name;
5697d56d374SYoshinobu Inoue 	hp->h_aliases = NULL;
5707d56d374SYoshinobu Inoue 	hp->h_addrtype = af;
5717d56d374SYoshinobu Inoue 	hp->h_length = ADDRLEN(af);
5727d56d374SYoshinobu Inoue 	hp->h_addr_list = addrs;
5737d56d374SYoshinobu Inoue 	addrs[0] = (char *)addr;
5747d56d374SYoshinobu Inoue 	addrs[1] = NULL;
5757d56d374SYoshinobu Inoue 	return _hpcopy(hp, errp);
5767d56d374SYoshinobu Inoue }
5777d56d374SYoshinobu Inoue 
5787d56d374SYoshinobu Inoue /*
5797d56d374SYoshinobu Inoue  * _hpmerge: merge 2 hostent structure, arguments will be freed
5807d56d374SYoshinobu Inoue  */
5817d56d374SYoshinobu Inoue static struct hostent *
5827d56d374SYoshinobu Inoue _hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp)
5837d56d374SYoshinobu Inoue {
5847d56d374SYoshinobu Inoue 	int i, j;
5857d56d374SYoshinobu Inoue 	int naddr, nalias;
5867d56d374SYoshinobu Inoue 	char **pp;
5877d56d374SYoshinobu Inoue 	struct hostent *hp, hpbuf;
5887d56d374SYoshinobu Inoue 	char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1];
5897d56d374SYoshinobu Inoue 	union inx_addr addrbuf[MAXADDRS];
5907d56d374SYoshinobu Inoue 
5917d56d374SYoshinobu Inoue 	if (hp1 == NULL)
5927d56d374SYoshinobu Inoue 		return hp2;
5937d56d374SYoshinobu Inoue 	if (hp2 == NULL)
5947d56d374SYoshinobu Inoue 		return hp1;
5957d56d374SYoshinobu Inoue 
5967d56d374SYoshinobu Inoue #define	HP(i)	(i == 1 ? hp1 : hp2)
5977d56d374SYoshinobu Inoue 	hp = &hpbuf;
5987d56d374SYoshinobu Inoue 	hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name);
5997d56d374SYoshinobu Inoue 	hp->h_aliases = aliases;
6007d56d374SYoshinobu Inoue 	nalias = 0;
6017d56d374SYoshinobu Inoue 	for (i = 1; i <= 2; i++) {
6027d56d374SYoshinobu Inoue 		if ((pp = HP(i)->h_aliases) == NULL)
6037d56d374SYoshinobu Inoue 			continue;
6047d56d374SYoshinobu Inoue 		for (; nalias < MAXALIASES && *pp != NULL; pp++) {
6057d56d374SYoshinobu Inoue 			/* check duplicates */
6067d56d374SYoshinobu Inoue 			for (j = 0; j < nalias; j++)
6077d56d374SYoshinobu Inoue 				if (strcasecmp(*pp, aliases[j]) == 0)
6087d56d374SYoshinobu Inoue 					break;
6097d56d374SYoshinobu Inoue 			if (j == nalias)
6107d56d374SYoshinobu Inoue 				aliases[nalias++] = *pp;
6117d56d374SYoshinobu Inoue 		}
6127d56d374SYoshinobu Inoue 	}
6137d56d374SYoshinobu Inoue 	aliases[nalias] = NULL;
6147d56d374SYoshinobu Inoue #ifdef INET6
6157d56d374SYoshinobu Inoue 	if (hp1->h_length != hp2->h_length) {
6167d56d374SYoshinobu Inoue 		hp->h_addrtype = AF_INET6;
6177d56d374SYoshinobu Inoue 		hp->h_length = sizeof(struct in6_addr);
6187d56d374SYoshinobu Inoue 	} else {
6197d56d374SYoshinobu Inoue #endif
6207d56d374SYoshinobu Inoue 		hp->h_addrtype = hp1->h_addrtype;
6217d56d374SYoshinobu Inoue 		hp->h_length = hp1->h_length;
6227d56d374SYoshinobu Inoue #ifdef INET6
6237d56d374SYoshinobu Inoue 	}
6247d56d374SYoshinobu Inoue #endif
6257d56d374SYoshinobu Inoue 	hp->h_addr_list = addrs;
6267d56d374SYoshinobu Inoue 	naddr = 0;
6277d56d374SYoshinobu Inoue 	for (i = 1; i <= 2; i++) {
6287d56d374SYoshinobu Inoue 		if ((pp = HP(i)->h_addr_list) == NULL)
6297d56d374SYoshinobu Inoue 			continue;
6307d56d374SYoshinobu Inoue 		if (HP(i)->h_length == hp->h_length) {
6317d56d374SYoshinobu Inoue 			while (naddr < MAXADDRS && *pp != NULL)
6327d56d374SYoshinobu Inoue 				addrs[naddr++] = *pp++;
6337d56d374SYoshinobu Inoue 		} else {
6347d56d374SYoshinobu Inoue 			/* copy IPv4 addr as mapped IPv6 addr */
6357d56d374SYoshinobu Inoue 			while (naddr < MAXADDRS && *pp != NULL) {
6367d56d374SYoshinobu Inoue 				MAPADDR(&addrbuf[naddr], *pp++);
6377d56d374SYoshinobu Inoue 				addrs[naddr] = (char *)&addrbuf[naddr];
6387d56d374SYoshinobu Inoue 				naddr++;
6397d56d374SYoshinobu Inoue 			}
6407d56d374SYoshinobu Inoue 		}
6417d56d374SYoshinobu Inoue 	}
6427d56d374SYoshinobu Inoue 	addrs[naddr] = NULL;
6437d56d374SYoshinobu Inoue 	hp = _hpcopy(hp, errp);
6447d56d374SYoshinobu Inoue 	freehostent(hp1);
6457d56d374SYoshinobu Inoue 	freehostent(hp2);
6467d56d374SYoshinobu Inoue 	return hp;
6477d56d374SYoshinobu Inoue }
6487d56d374SYoshinobu Inoue 
6497d56d374SYoshinobu Inoue /*
6507d56d374SYoshinobu Inoue  * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses
6517d56d374SYoshinobu Inoue  */
6527d56d374SYoshinobu Inoue #ifdef INET6
6537d56d374SYoshinobu Inoue static struct hostent *
6547d56d374SYoshinobu Inoue _hpmapv6(struct hostent *hp, int *errp)
6557d56d374SYoshinobu Inoue {
6567d56d374SYoshinobu Inoue 	struct hostent *hp6;
6577d56d374SYoshinobu Inoue 
6587d56d374SYoshinobu Inoue 	if (hp == NULL)
6597d56d374SYoshinobu Inoue 		return NULL;
6607d56d374SYoshinobu Inoue 	if (hp->h_addrtype == AF_INET6)
6617d56d374SYoshinobu Inoue 		return hp;
6627d56d374SYoshinobu Inoue 
6637d56d374SYoshinobu Inoue 	/* make dummy hostent to convert IPv6 address */
6647d56d374SYoshinobu Inoue 	if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) {
6657d56d374SYoshinobu Inoue 		*errp = TRY_AGAIN;
6667d56d374SYoshinobu Inoue 		return NULL;
6677d56d374SYoshinobu Inoue 	}
6687d56d374SYoshinobu Inoue 	hp6->h_name = NULL;
6697d56d374SYoshinobu Inoue 	hp6->h_aliases = NULL;
6707d56d374SYoshinobu Inoue 	hp6->h_addrtype = AF_INET6;
6717d56d374SYoshinobu Inoue 	hp6->h_length = sizeof(struct in6_addr);
6727d56d374SYoshinobu Inoue 	hp6->h_addr_list = NULL;
6737d56d374SYoshinobu Inoue 	return _hpmerge(hp6, hp, errp);
6747d56d374SYoshinobu Inoue }
6757d56d374SYoshinobu Inoue #endif
6767d56d374SYoshinobu Inoue 
6777d56d374SYoshinobu Inoue /*
6787d56d374SYoshinobu Inoue  * _hpsort: sort address by sortlist
6797d56d374SYoshinobu Inoue  */
6807d56d374SYoshinobu Inoue static struct hostent *
6817d56d374SYoshinobu Inoue _hpsort(struct hostent *hp)
6827d56d374SYoshinobu Inoue {
6837d56d374SYoshinobu Inoue 	int i, j, n;
6847d56d374SYoshinobu Inoue 	u_char *ap, *sp, *mp, **pp;
6857d56d374SYoshinobu Inoue 	char t;
6867d56d374SYoshinobu Inoue 	char order[MAXADDRS];
6877d56d374SYoshinobu Inoue 	int nsort = _res.nsort;
6887d56d374SYoshinobu Inoue 
6897d56d374SYoshinobu Inoue 	if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0)
6907d56d374SYoshinobu Inoue 		return hp;
6917d56d374SYoshinobu Inoue 	for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) {
6927d56d374SYoshinobu Inoue 		for (j = 0; j < nsort; j++) {
6937d56d374SYoshinobu Inoue #ifdef INET6
6947d56d374SYoshinobu Inoue 			if (_res_ext.sort_list[j].af != hp->h_addrtype)
6957d56d374SYoshinobu Inoue 				continue;
6967d56d374SYoshinobu Inoue 			sp = (u_char *)&_res_ext.sort_list[j].addr;
6977d56d374SYoshinobu Inoue 			mp = (u_char *)&_res_ext.sort_list[j].mask;
6987d56d374SYoshinobu Inoue #else
6997d56d374SYoshinobu Inoue 			sp = (u_char *)&_res.sort_list[j].addr;
7007d56d374SYoshinobu Inoue 			mp = (u_char *)&_res.sort_list[j].mask;
7017d56d374SYoshinobu Inoue #endif
7027d56d374SYoshinobu Inoue 			for (n = 0; n < hp->h_length; n++) {
7037d56d374SYoshinobu Inoue 				if ((ap[n] & mp[n]) != sp[n])
7047d56d374SYoshinobu Inoue 					break;
7057d56d374SYoshinobu Inoue 			}
7067d56d374SYoshinobu Inoue 			if (n == hp->h_length)
7077d56d374SYoshinobu Inoue 				break;
7087d56d374SYoshinobu Inoue 		}
7097d56d374SYoshinobu Inoue 		order[i] = j;
7107d56d374SYoshinobu Inoue 	}
7117d56d374SYoshinobu Inoue 	n = i;
7127d56d374SYoshinobu Inoue 	pp = (u_char **)hp->h_addr_list;
7137d56d374SYoshinobu Inoue 	for (i = 0; i < n - 1; i++) {
7147d56d374SYoshinobu Inoue 		for (j = i + 1; j < n; j++) {
7157d56d374SYoshinobu Inoue 			if (order[i] > order[j]) {
7167d56d374SYoshinobu Inoue 				ap = pp[i];
7177d56d374SYoshinobu Inoue 				pp[i] = pp[j];
7187d56d374SYoshinobu Inoue 				pp[j] = ap;
7197d56d374SYoshinobu Inoue 				t = order[i];
7207d56d374SYoshinobu Inoue 				order[i] = order[j];
7217d56d374SYoshinobu Inoue 				order[j] = t;
7227d56d374SYoshinobu Inoue 			}
7237d56d374SYoshinobu Inoue 		}
7247d56d374SYoshinobu Inoue 	}
7257d56d374SYoshinobu Inoue 	return hp;
7267d56d374SYoshinobu Inoue }
7277d56d374SYoshinobu Inoue 
7287d56d374SYoshinobu Inoue static char *
7297d56d374SYoshinobu Inoue _hgetword(char **pp)
7307d56d374SYoshinobu Inoue {
7317d56d374SYoshinobu Inoue 	char c, *p, *ret;
7327d56d374SYoshinobu Inoue 	const char *sp;
7337d56d374SYoshinobu Inoue 	static const char sep[] = "# \t\n";
7347d56d374SYoshinobu Inoue 
7357d56d374SYoshinobu Inoue 	ret = NULL;
7367d56d374SYoshinobu Inoue 	for (p = *pp; (c = *p) != '\0'; p++) {
7377d56d374SYoshinobu Inoue 		for (sp = sep; *sp != '\0'; sp++) {
7387d56d374SYoshinobu Inoue 			if (c == *sp)
7397d56d374SYoshinobu Inoue 				break;
7407d56d374SYoshinobu Inoue 		}
7417d56d374SYoshinobu Inoue 		if (c == '#')
7427d56d374SYoshinobu Inoue 			p[1] = '\0';	/* ignore rest of line */
7437d56d374SYoshinobu Inoue 		if (ret == NULL) {
7447d56d374SYoshinobu Inoue 			if (*sp == '\0')
7457d56d374SYoshinobu Inoue 				ret = p;
7467d56d374SYoshinobu Inoue 		} else {
7477d56d374SYoshinobu Inoue 			if (*sp != '\0') {
7487d56d374SYoshinobu Inoue 				*p++ = '\0';
7497d56d374SYoshinobu Inoue 				break;
7507d56d374SYoshinobu Inoue 			}
7517d56d374SYoshinobu Inoue 		}
7527d56d374SYoshinobu Inoue 	}
7537d56d374SYoshinobu Inoue 	*pp = p;
7547d56d374SYoshinobu Inoue 	if (ret == NULL || *ret == '\0')
7557d56d374SYoshinobu Inoue 		return NULL;
7567d56d374SYoshinobu Inoue 	return ret;
7577d56d374SYoshinobu Inoue }
7587d56d374SYoshinobu Inoue 
7597d56d374SYoshinobu Inoue /*
7607d56d374SYoshinobu Inoue  * FILES (/etc/hosts)
7617d56d374SYoshinobu Inoue  */
7627d56d374SYoshinobu Inoue 
7637d56d374SYoshinobu Inoue static FILE *
7647d56d374SYoshinobu Inoue _files_open(int *errp)
7657d56d374SYoshinobu Inoue {
7667d56d374SYoshinobu Inoue 	FILE *fp;
7677d56d374SYoshinobu Inoue 	fp = fopen(_PATH_HOSTS, "r");
7687d56d374SYoshinobu Inoue 	if (fp == NULL)
7697d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
7707d56d374SYoshinobu Inoue 	return fp;
7717d56d374SYoshinobu Inoue }
7727d56d374SYoshinobu Inoue 
7737d56d374SYoshinobu Inoue static struct hostent *
7747d56d374SYoshinobu Inoue _files_ghbyname(const char *name, int af, int *errp)
7757d56d374SYoshinobu Inoue {
7767d56d374SYoshinobu Inoue 	int match, nalias;
7777d56d374SYoshinobu Inoue 	char *p, *line, *addrstr, *cname;
7787d56d374SYoshinobu Inoue 	FILE *fp;
7797d56d374SYoshinobu Inoue 	struct hostent *rethp, *hp, hpbuf;
7807d56d374SYoshinobu Inoue 	char *aliases[MAXALIASES + 1], *addrs[2];
7817d56d374SYoshinobu Inoue 	union inx_addr addrbuf;
7827d56d374SYoshinobu Inoue 	char buf[BUFSIZ];
783e6f35403SYoshinobu Inoue 	int af0 = af;
7847d56d374SYoshinobu Inoue 
7857d56d374SYoshinobu Inoue 	if ((fp = _files_open(errp)) == NULL)
7867d56d374SYoshinobu Inoue 		return NULL;
7877d56d374SYoshinobu Inoue 	rethp = hp = NULL;
7887d56d374SYoshinobu Inoue 
7897d56d374SYoshinobu Inoue 	while (fgets(buf, sizeof(buf), fp)) {
7907d56d374SYoshinobu Inoue 		line = buf;
7917d56d374SYoshinobu Inoue 		if ((addrstr = _hgetword(&line)) == NULL
7927d56d374SYoshinobu Inoue 		||  (cname = _hgetword(&line)) == NULL)
7937d56d374SYoshinobu Inoue 			continue;
7947d56d374SYoshinobu Inoue 		match = (strcasecmp(cname, name) == 0);
7957d56d374SYoshinobu Inoue 		nalias = 0;
7967d56d374SYoshinobu Inoue 		while ((p = _hgetword(&line)) != NULL) {
7977d56d374SYoshinobu Inoue 			if (!match)
7987d56d374SYoshinobu Inoue 				match = (strcasecmp(p, name) == 0);
7997d56d374SYoshinobu Inoue 			if (nalias < MAXALIASES)
8007d56d374SYoshinobu Inoue 				aliases[nalias++] = p;
8017d56d374SYoshinobu Inoue 		}
8027d56d374SYoshinobu Inoue 		if (!match)
8037d56d374SYoshinobu Inoue 			continue;
804e6f35403SYoshinobu Inoue 		switch (af0) {
805e6f35403SYoshinobu Inoue 		case AF_INET:
806e6f35403SYoshinobu Inoue 			if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
807e6f35403SYoshinobu Inoue 			    != 1) {
8087d56d374SYoshinobu Inoue 				*errp = NO_DATA;	/* name found */
8097d56d374SYoshinobu Inoue 				continue;
8107d56d374SYoshinobu Inoue 			}
811e6f35403SYoshinobu Inoue 			af = af0;
812e6f35403SYoshinobu Inoue 			break;
813e6f35403SYoshinobu Inoue #ifdef INET6
814e6f35403SYoshinobu Inoue 		case AF_INET6:
815e6f35403SYoshinobu Inoue 			if (inet_pton(af, addrstr, &addrbuf) != 1) {
816e6f35403SYoshinobu Inoue 				*errp = NO_DATA;	/* name found */
817e6f35403SYoshinobu Inoue 				continue;
818e6f35403SYoshinobu Inoue 			}
819e6f35403SYoshinobu Inoue 			af = af0;
820e6f35403SYoshinobu Inoue 			break;
821e6f35403SYoshinobu Inoue #endif
822e6f35403SYoshinobu Inoue 		case AF_UNSPEC:
823e6f35403SYoshinobu Inoue 			if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
824e6f35403SYoshinobu Inoue 			    == 1) {
825e6f35403SYoshinobu Inoue 				af = AF_INET;
826e6f35403SYoshinobu Inoue 				break;
827e6f35403SYoshinobu Inoue 			}
828e6f35403SYoshinobu Inoue #ifdef INET6
829e6f35403SYoshinobu Inoue 			if (inet_pton(AF_INET6, addrstr, &addrbuf) == 1) {
830e6f35403SYoshinobu Inoue 				af = AF_INET6;
831e6f35403SYoshinobu Inoue 				break;
832e6f35403SYoshinobu Inoue 			}
833e6f35403SYoshinobu Inoue #endif
834e6f35403SYoshinobu Inoue 			*errp = NO_DATA;	/* name found */
835e6f35403SYoshinobu Inoue 			continue;
836e6f35403SYoshinobu Inoue 			/* NOTREACHED */
837e6f35403SYoshinobu Inoue 		}
8387d56d374SYoshinobu Inoue 		hp = &hpbuf;
8397d56d374SYoshinobu Inoue 		hp->h_name = cname;
8407d56d374SYoshinobu Inoue 		hp->h_aliases = aliases;
8417d56d374SYoshinobu Inoue 		aliases[nalias] = NULL;
8427d56d374SYoshinobu Inoue 		hp->h_addrtype = af;
8437d56d374SYoshinobu Inoue 		hp->h_length = ADDRLEN(af);
8447d56d374SYoshinobu Inoue 		hp->h_addr_list = addrs;
8457d56d374SYoshinobu Inoue 		addrs[0] = (char *)&addrbuf;
8467d56d374SYoshinobu Inoue 		addrs[1] = NULL;
8477d56d374SYoshinobu Inoue 		hp = _hpcopy(hp, errp);
8487d56d374SYoshinobu Inoue 		rethp = _hpmerge(rethp, hp, errp);
8497d56d374SYoshinobu Inoue 	}
8507d56d374SYoshinobu Inoue 	fclose(fp);
8517d56d374SYoshinobu Inoue 	return rethp;
8527d56d374SYoshinobu Inoue }
8537d56d374SYoshinobu Inoue 
8547d56d374SYoshinobu Inoue static struct hostent *
8557d56d374SYoshinobu Inoue _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
8567d56d374SYoshinobu Inoue {
8577d56d374SYoshinobu Inoue 	int nalias;
8587d56d374SYoshinobu Inoue 	char *p, *line;
8597d56d374SYoshinobu Inoue 	FILE *fp;
8607d56d374SYoshinobu Inoue 	struct hostent *hp, hpbuf;
8617d56d374SYoshinobu Inoue 	char *aliases[MAXALIASES + 1], *addrs[2];
8627d56d374SYoshinobu Inoue 	union inx_addr addrbuf;
8637d56d374SYoshinobu Inoue 	char buf[BUFSIZ];
8647d56d374SYoshinobu Inoue 
8657d56d374SYoshinobu Inoue 	if ((fp = _files_open(errp)) == NULL)
8667d56d374SYoshinobu Inoue 		return NULL;
8677d56d374SYoshinobu Inoue 	hp = NULL;
8687d56d374SYoshinobu Inoue 	while (fgets(buf, sizeof(buf), fp)) {
8697d56d374SYoshinobu Inoue 		line = buf;
8707d56d374SYoshinobu Inoue 		if ((p = _hgetword(&line)) == NULL
871be26adb5SYoshinobu Inoue 		||  (af == AF_INET
872be26adb5SYoshinobu Inoue 		     ? inet_aton(p, (struct in_addr *)&addrbuf)
873be26adb5SYoshinobu Inoue 		     : inet_pton(af, p, &addrbuf)) != 1
8747d56d374SYoshinobu Inoue 		||  memcmp(addr, &addrbuf, addrlen) != 0
8757d56d374SYoshinobu Inoue 		||  (p = _hgetword(&line)) == NULL)
8767d56d374SYoshinobu Inoue 			continue;
8777d56d374SYoshinobu Inoue 		hp = &hpbuf;
8787d56d374SYoshinobu Inoue 		hp->h_name = p;
8797d56d374SYoshinobu Inoue 		hp->h_aliases = aliases;
8807d56d374SYoshinobu Inoue 		nalias = 0;
8817d56d374SYoshinobu Inoue 		while ((p = _hgetword(&line)) != NULL) {
8827d56d374SYoshinobu Inoue 			if (nalias < MAXALIASES)
8837d56d374SYoshinobu Inoue 				aliases[nalias++] = p;
8847d56d374SYoshinobu Inoue 		}
8857d56d374SYoshinobu Inoue 		aliases[nalias] = NULL;
8867d56d374SYoshinobu Inoue 		hp->h_addrtype = af;
8877d56d374SYoshinobu Inoue 		hp->h_length = addrlen;
8887d56d374SYoshinobu Inoue 		hp->h_addr_list = addrs;
8897d56d374SYoshinobu Inoue 		addrs[0] = (char *)&addrbuf;
8907d56d374SYoshinobu Inoue 		addrs[1] = NULL;
8917d56d374SYoshinobu Inoue 		hp = _hpcopy(hp, errp);
8927d56d374SYoshinobu Inoue 		break;
8937d56d374SYoshinobu Inoue 	}
8947d56d374SYoshinobu Inoue 	fclose(fp);
8957d56d374SYoshinobu Inoue 	return hp;
8967d56d374SYoshinobu Inoue }
8977d56d374SYoshinobu Inoue 
89863858012SJonathan Lemon /*
89963858012SJonathan Lemon  * NIS
90063858012SJonathan Lemon  *
90163858012SJonathan Lemon  * XXX actually a hack, these are INET4 specific.
90263858012SJonathan Lemon  */
90363858012SJonathan Lemon static struct hostent *
90463858012SJonathan Lemon _nis_ghbyname(const char *name, int af, int *errp)
90563858012SJonathan Lemon {
90638775c5eSJonathan Lemon 	struct hostent *hp = NULL;
90763858012SJonathan Lemon 
908e6f35403SYoshinobu Inoue 	if (af == AF_UNSPEC)
909e6f35403SYoshinobu Inoue 		af = AF_INET;
91063858012SJonathan Lemon 	if (af == AF_INET) {
91163858012SJonathan Lemon 		hp = _gethostbynisname(name, af);
91263858012SJonathan Lemon 		if (hp != NULL)
91363858012SJonathan Lemon 			hp = _hpcopy(hp, errp);
91463858012SJonathan Lemon 	}
91563858012SJonathan Lemon 	return (hp);
91663858012SJonathan Lemon 
91763858012SJonathan Lemon }
91863858012SJonathan Lemon 
91963858012SJonathan Lemon static struct hostent *
92063858012SJonathan Lemon _nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
92163858012SJonathan Lemon {
92263858012SJonathan Lemon 	struct hostent *hp = NULL;
92363858012SJonathan Lemon 
92463858012SJonathan Lemon 	if (af == AF_INET) {
92563858012SJonathan Lemon 		hp = _gethostbynisaddr(addr, addrlen, af);
92663858012SJonathan Lemon 		if (hp != NULL)
92763858012SJonathan Lemon 			hp = _hpcopy(hp, errp);
92863858012SJonathan Lemon 	}
92963858012SJonathan Lemon 	return (hp);
93063858012SJonathan Lemon }
93163858012SJonathan Lemon 
9327d56d374SYoshinobu Inoue #ifdef DEBUG
9337d56d374SYoshinobu Inoue #define	DNS_ASSERT(X)	if (!(X)) { fprintf(stderr, "ASSFAIL: %s %d: %s\n", __FILE__, __LINE__, #X); goto badanswer; }
9347d56d374SYoshinobu Inoue #else
9357d56d374SYoshinobu Inoue #define	DNS_ASSERT(X)	if (!(X)) { goto badanswer; }
9367d56d374SYoshinobu Inoue #endif
9377d56d374SYoshinobu Inoue 
938e6f35403SYoshinobu Inoue struct __res_type_list {
939e6f35403SYoshinobu Inoue         SLIST_ENTRY(__res_type_list) rtl_entry;
940e6f35403SYoshinobu Inoue         int     rtl_type;
941e6f35403SYoshinobu Inoue };
942e6f35403SYoshinobu Inoue 
9437d56d374SYoshinobu Inoue static struct hostent *
944e6f35403SYoshinobu Inoue _gethpbyanswer(answer, anslen, qtype, errp)
945e6f35403SYoshinobu Inoue 	const u_char *answer;
946e6f35403SYoshinobu Inoue 	int anslen;
947e6f35403SYoshinobu Inoue 	int qtype;
948e6f35403SYoshinobu Inoue 	int *errp;
9497d56d374SYoshinobu Inoue {
9507d56d374SYoshinobu Inoue 	int n;
9517d56d374SYoshinobu Inoue 	char tbuf[MAXDNAME+1];
9527d56d374SYoshinobu Inoue 	HEADER *hp;
953e6f35403SYoshinobu Inoue 	const u_char *cp, *eom;
9547d56d374SYoshinobu Inoue 	int type, class, ancount, qdcount;
9557d56d374SYoshinobu Inoue 	u_long ttl;
9567d56d374SYoshinobu Inoue 	char hostbuf[BUFSIZ];
9577d56d374SYoshinobu Inoue 	char *bp;
9587d56d374SYoshinobu Inoue 	char *alist[MAXALIASES];
9597d56d374SYoshinobu Inoue 	char *hlist[MAXADDRS];
9607d56d374SYoshinobu Inoue 	struct hostent hbuf;
9617d56d374SYoshinobu Inoue 	int buflen;
9627d56d374SYoshinobu Inoue 	int na, nh;
9637d56d374SYoshinobu Inoue 
9647d56d374SYoshinobu Inoue 	hbuf.h_aliases = alist;
965e6f35403SYoshinobu Inoue 	hbuf.h_addrtype =
966e6f35403SYoshinobu Inoue #ifdef INET6
967e6f35403SYoshinobu Inoue 		(qtype == T_AAAA) ? AF_INET6 :
968e6f35403SYoshinobu Inoue #endif
969e6f35403SYoshinobu Inoue 		AF_INET;
970e6f35403SYoshinobu Inoue 	hbuf.h_length = ADDRLEN(hbuf.h_addrtype);
9717d56d374SYoshinobu Inoue 	hbuf.h_addr_list = hlist;
9727d56d374SYoshinobu Inoue 	na = nh = 0;
9737d56d374SYoshinobu Inoue 	hp = (HEADER *)answer;
974e6f35403SYoshinobu Inoue 	eom = answer + anslen;
9757d56d374SYoshinobu Inoue 	ancount = ntohs(hp->ancount);
9767d56d374SYoshinobu Inoue 	qdcount = ntohs(hp->qdcount);
9777d56d374SYoshinobu Inoue 	DNS_ASSERT(qdcount == 1);
9787d56d374SYoshinobu Inoue 	cp = answer + sizeof(HEADER);
9797d56d374SYoshinobu Inoue 	bp = hostbuf;
9807d56d374SYoshinobu Inoue 	buflen = sizeof(hostbuf);
9817d56d374SYoshinobu Inoue 
9827d56d374SYoshinobu Inoue 	n = dn_expand(answer, eom, cp, bp, buflen);
9837d56d374SYoshinobu Inoue 	DNS_ASSERT(n >= 0);
9847d56d374SYoshinobu Inoue 	cp += n + QFIXEDSZ;
9857d56d374SYoshinobu Inoue 	hbuf.h_name = bp;
9867d56d374SYoshinobu Inoue 	n = strlen(bp) + 1;
9877d56d374SYoshinobu Inoue 	bp += n;
9887d56d374SYoshinobu Inoue 	buflen -= n;
9897d56d374SYoshinobu Inoue 	while (ancount-- > 0 && cp < eom) {
9907d56d374SYoshinobu Inoue 		n = dn_expand(answer, eom, cp, bp, buflen);
9917d56d374SYoshinobu Inoue 		DNS_ASSERT(n >= 0);
9927d56d374SYoshinobu Inoue 		cp += n;		/* name */
9937d56d374SYoshinobu Inoue 		type = _getshort(cp);
9947d56d374SYoshinobu Inoue 		cp += 2;		/* type */
9957d56d374SYoshinobu Inoue 		class = _getshort(cp);
9967d56d374SYoshinobu Inoue 		cp += 2;		/* class */
9977d56d374SYoshinobu Inoue 		ttl = _getlong(cp);
9987d56d374SYoshinobu Inoue 		cp += 4;		/* ttl */
9997d56d374SYoshinobu Inoue 		n = _getshort(cp);
10007d56d374SYoshinobu Inoue 		cp += 2;		/* len */
10017d56d374SYoshinobu Inoue 		DNS_ASSERT(class == C_IN);
10027d56d374SYoshinobu Inoue 		switch (type) {
10037d56d374SYoshinobu Inoue 		case T_CNAME:
10047d56d374SYoshinobu Inoue 			if (na >= MAXALIASES-1) {
10057d56d374SYoshinobu Inoue 				cp += n;
10067d56d374SYoshinobu Inoue 				break;
10077d56d374SYoshinobu Inoue 			}
10087d56d374SYoshinobu Inoue 			n = dn_expand(answer, eom, cp, tbuf, sizeof(tbuf));
10097d56d374SYoshinobu Inoue 			DNS_ASSERT(n >= 0);
10107d56d374SYoshinobu Inoue 			cp += n;
10117d56d374SYoshinobu Inoue 			/* alias */
10127d56d374SYoshinobu Inoue 			alist[na++] = bp;
10137d56d374SYoshinobu Inoue 			n = strlen(bp) + 1;
10147d56d374SYoshinobu Inoue 			bp += n;
10157d56d374SYoshinobu Inoue 			buflen -= n;
10167d56d374SYoshinobu Inoue 			/* canon */
10177d56d374SYoshinobu Inoue 			n = strlen(tbuf) + 1;
10187d56d374SYoshinobu Inoue 			DNS_ASSERT(n < buflen);
10197d56d374SYoshinobu Inoue 			strcpy(bp, tbuf);
10207d56d374SYoshinobu Inoue 			hbuf.h_name = bp;
10217d56d374SYoshinobu Inoue 			bp += n;
10227d56d374SYoshinobu Inoue 			buflen -= n;
10237d56d374SYoshinobu Inoue 			break;
10247d56d374SYoshinobu Inoue 		case T_A:
10257d56d374SYoshinobu Inoue #ifdef INET6
10267d56d374SYoshinobu Inoue 		case T_AAAA:
10277d56d374SYoshinobu Inoue #endif
10287d56d374SYoshinobu Inoue 			DNS_ASSERT(type == qtype);
10297d56d374SYoshinobu Inoue 			bp = (char *)ALIGN(bp);
10307d56d374SYoshinobu Inoue 			DNS_ASSERT(n == hbuf.h_length);
10317d56d374SYoshinobu Inoue 			DNS_ASSERT(n < buflen);
10327d56d374SYoshinobu Inoue 			if (nh < MAXADDRS-1) {
10337d56d374SYoshinobu Inoue 				hlist[nh++] = bp;
10347d56d374SYoshinobu Inoue 				memcpy(bp, cp, n);
10357d56d374SYoshinobu Inoue 				bp += n;
10367d56d374SYoshinobu Inoue 				buflen -= n;
10377d56d374SYoshinobu Inoue 			}
10387d56d374SYoshinobu Inoue 			cp += n;
10397d56d374SYoshinobu Inoue 			break;
10407d56d374SYoshinobu Inoue 		default:
10417d56d374SYoshinobu Inoue 			DNS_ASSERT(0);
10427d56d374SYoshinobu Inoue 			cp += n;
10437d56d374SYoshinobu Inoue 			break;
10447d56d374SYoshinobu Inoue 		}
10457d56d374SYoshinobu Inoue 	}
10467d56d374SYoshinobu Inoue 	if (nh == 0) {
10477d56d374SYoshinobu Inoue   badanswer:
10487d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
10497d56d374SYoshinobu Inoue 		return NULL;
10507d56d374SYoshinobu Inoue 	}
10517d56d374SYoshinobu Inoue 	alist[na] = NULL;
10527d56d374SYoshinobu Inoue 	hlist[nh] = NULL;
10537d56d374SYoshinobu Inoue 	return _hpcopy(&hbuf, errp);
10547d56d374SYoshinobu Inoue }
10557d56d374SYoshinobu Inoue 
1056e6f35403SYoshinobu Inoue /* res_search() variant with multiple query support. */
1057e6f35403SYoshinobu Inoue static struct hostent *
1058e6f35403SYoshinobu Inoue _res_search_multi(name, rtl, errp)
1059e6f35403SYoshinobu Inoue 	const char *name;	/* domain name */
1060e6f35403SYoshinobu Inoue 	struct	__res_type_list *rtl; /* list of query types */
1061e6f35403SYoshinobu Inoue 	int *errp;
1062e6f35403SYoshinobu Inoue {
1063e6f35403SYoshinobu Inoue 	u_char answer[BUFSIZ];	/* buffer to put answer */
1064e6f35403SYoshinobu Inoue 	const char *cp, * const *domain;
1065e6f35403SYoshinobu Inoue 	struct hostent *hp0 = NULL, *hp;
1066e6f35403SYoshinobu Inoue 	u_int dots;
1067e6f35403SYoshinobu Inoue 	int trailing_dot, ret, saved_herrno;
1068e6f35403SYoshinobu Inoue 	int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1069e6f35403SYoshinobu Inoue 	struct __res_type_list *rtl0 = rtl;
1070e6f35403SYoshinobu Inoue 
1071e6f35403SYoshinobu Inoue 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1072e6f35403SYoshinobu Inoue 		*errp = NETDB_INTERNAL;
1073e6f35403SYoshinobu Inoue 		return (NULL);
1074e6f35403SYoshinobu Inoue 	}
1075e6f35403SYoshinobu Inoue 	dots = 0;
1076e6f35403SYoshinobu Inoue 	for (cp = name; *cp; cp++)
1077e6f35403SYoshinobu Inoue 		dots += (*cp == '.');
1078e6f35403SYoshinobu Inoue 	trailing_dot = 0;
1079e6f35403SYoshinobu Inoue 	if (cp > name && *--cp == '.')
1080e6f35403SYoshinobu Inoue 		trailing_dot++;
1081e6f35403SYoshinobu Inoue 
1082e6f35403SYoshinobu Inoue 	/* If there aren't any dots, it could be a user-level alias */
1083e6f35403SYoshinobu Inoue 	if (!dots && (cp = hostalias(name)) != NULL) {
1084e6f35403SYoshinobu Inoue 		for(rtl = rtl0; rtl != NULL;
1085e6f35403SYoshinobu Inoue 		    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1086e6f35403SYoshinobu Inoue 			ret = res_query(cp, C_IN, rtl->rtl_type, answer,
1087e6f35403SYoshinobu Inoue 					     sizeof(answer));
1088e6f35403SYoshinobu Inoue 			if (ret > 0) {
1089e6f35403SYoshinobu Inoue 				hp = _gethpbyanswer(answer, ret, rtl->rtl_type,
1090e6f35403SYoshinobu Inoue 						    errp);
1091e6f35403SYoshinobu Inoue 				hp0 = _hpmerge(hp0, hp, errp);
1092e6f35403SYoshinobu Inoue 			}
1093e6f35403SYoshinobu Inoue 		}
1094e6f35403SYoshinobu Inoue 		return (hp0);
1095e6f35403SYoshinobu Inoue 	}
1096e6f35403SYoshinobu Inoue 
1097e6f35403SYoshinobu Inoue 	/*
1098e6f35403SYoshinobu Inoue 	 * If there are dots in the name already, let's just give it a try
1099e6f35403SYoshinobu Inoue 	 * 'as is'.  The threshold can be set with the "ndots" option.
1100e6f35403SYoshinobu Inoue 	 */
1101e6f35403SYoshinobu Inoue 	saved_herrno = -1;
1102e6f35403SYoshinobu Inoue 	if (dots >= _res.ndots) {
1103e6f35403SYoshinobu Inoue 		for(rtl = rtl0; rtl != NULL;
1104e6f35403SYoshinobu Inoue 		    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1105e6f35403SYoshinobu Inoue 			ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type,
1106e6f35403SYoshinobu Inoue 					      answer, sizeof(answer));
1107e6f35403SYoshinobu Inoue 			if (ret > 0) {
1108e6f35403SYoshinobu Inoue 				hp = _gethpbyanswer(answer, ret, rtl->rtl_type,
1109e6f35403SYoshinobu Inoue 						    errp);
1110e6f35403SYoshinobu Inoue 				hp0 = _hpmerge(hp0, hp, errp);
1111e6f35403SYoshinobu Inoue 			}
1112e6f35403SYoshinobu Inoue 		}
1113e6f35403SYoshinobu Inoue 		if (hp0 != NULL)
1114e6f35403SYoshinobu Inoue 			return (hp0);
1115e6f35403SYoshinobu Inoue 		saved_herrno = *errp;
1116e6f35403SYoshinobu Inoue 		tried_as_is++;
1117e6f35403SYoshinobu Inoue 	}
1118e6f35403SYoshinobu Inoue 
1119e6f35403SYoshinobu Inoue 	/*
1120e6f35403SYoshinobu Inoue 	 * We do at least one level of search if
1121e6f35403SYoshinobu Inoue 	 *	- there is no dot and RES_DEFNAME is set, or
1122e6f35403SYoshinobu Inoue 	 *	- there is at least one dot, there is no trailing dot,
1123e6f35403SYoshinobu Inoue 	 *	  and RES_DNSRCH is set.
1124e6f35403SYoshinobu Inoue 	 */
1125e6f35403SYoshinobu Inoue 	if ((!dots && (_res.options & RES_DEFNAMES)) ||
1126e6f35403SYoshinobu Inoue 	    (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
1127e6f35403SYoshinobu Inoue 		int done = 0;
1128e6f35403SYoshinobu Inoue 
1129e6f35403SYoshinobu Inoue 		for (domain = (const char * const *)_res.dnsrch;
1130e6f35403SYoshinobu Inoue 		     *domain && !done;
1131e6f35403SYoshinobu Inoue 		     domain++) {
1132e6f35403SYoshinobu Inoue 
1133e6f35403SYoshinobu Inoue 			for(rtl = rtl0; rtl != NULL;
1134e6f35403SYoshinobu Inoue 			    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1135e6f35403SYoshinobu Inoue 				ret = res_querydomain(name, *domain, C_IN,
1136e6f35403SYoshinobu Inoue 						      rtl->rtl_type,
1137e6f35403SYoshinobu Inoue 						      answer, sizeof(answer));
1138e6f35403SYoshinobu Inoue 				if (ret > 0) {
1139e6f35403SYoshinobu Inoue 					hp = _gethpbyanswer(answer, ret,
1140e6f35403SYoshinobu Inoue 							      rtl->rtl_type,
1141e6f35403SYoshinobu Inoue 							      errp);
1142e6f35403SYoshinobu Inoue 					hp0 = _hpmerge(hp0, hp, errp);
1143e6f35403SYoshinobu Inoue 				}
1144e6f35403SYoshinobu Inoue 			}
1145e6f35403SYoshinobu Inoue 			if (hp0 != NULL)
1146e6f35403SYoshinobu Inoue 				return (hp0);
1147e6f35403SYoshinobu Inoue 
1148e6f35403SYoshinobu Inoue 			/*
1149e6f35403SYoshinobu Inoue 			 * If no server present, give up.
1150e6f35403SYoshinobu Inoue 			 * If name isn't found in this domain,
1151e6f35403SYoshinobu Inoue 			 * keep trying higher domains in the search list
1152e6f35403SYoshinobu Inoue 			 * (if that's enabled).
1153e6f35403SYoshinobu Inoue 			 * On a NO_DATA error, keep trying, otherwise
1154e6f35403SYoshinobu Inoue 			 * a wildcard entry of another type could keep us
1155e6f35403SYoshinobu Inoue 			 * from finding this entry higher in the domain.
1156e6f35403SYoshinobu Inoue 			 * If we get some other error (negative answer or
1157e6f35403SYoshinobu Inoue 			 * server failure), then stop searching up,
1158e6f35403SYoshinobu Inoue 			 * but try the input name below in case it's
1159e6f35403SYoshinobu Inoue 			 * fully-qualified.
1160e6f35403SYoshinobu Inoue 			 */
1161e6f35403SYoshinobu Inoue 			if (errno == ECONNREFUSED) {
1162e6f35403SYoshinobu Inoue 				*errp = TRY_AGAIN;
1163e6f35403SYoshinobu Inoue 				return (NULL);
1164e6f35403SYoshinobu Inoue 			}
1165e6f35403SYoshinobu Inoue 
1166e6f35403SYoshinobu Inoue 			switch (*errp) {
1167e6f35403SYoshinobu Inoue 			case NO_DATA:
1168e6f35403SYoshinobu Inoue 				got_nodata++;
1169e6f35403SYoshinobu Inoue 				/* FALLTHROUGH */
1170e6f35403SYoshinobu Inoue 			case HOST_NOT_FOUND:
1171e6f35403SYoshinobu Inoue 				/* keep trying */
1172e6f35403SYoshinobu Inoue 				break;
1173e6f35403SYoshinobu Inoue 			case TRY_AGAIN:
1174e6f35403SYoshinobu Inoue 				if (((HEADER *)answer)->rcode == SERVFAIL) {
1175e6f35403SYoshinobu Inoue 					/* try next search element, if any */
1176e6f35403SYoshinobu Inoue 					got_servfail++;
1177e6f35403SYoshinobu Inoue 					break;
1178e6f35403SYoshinobu Inoue 				}
1179e6f35403SYoshinobu Inoue 				/* FALLTHROUGH */
1180e6f35403SYoshinobu Inoue 			default:
1181e6f35403SYoshinobu Inoue 				/* anything else implies that we're done */
1182e6f35403SYoshinobu Inoue 				done++;
1183e6f35403SYoshinobu Inoue 			}
1184e6f35403SYoshinobu Inoue 
1185e6f35403SYoshinobu Inoue 			/* if we got here for some reason other than DNSRCH,
1186e6f35403SYoshinobu Inoue 			 * we only wanted one iteration of the loop, so stop.
1187e6f35403SYoshinobu Inoue 			 */
1188e6f35403SYoshinobu Inoue 			if (!(_res.options & RES_DNSRCH))
1189e6f35403SYoshinobu Inoue 				done++;
1190e6f35403SYoshinobu Inoue 		}
1191e6f35403SYoshinobu Inoue 	}
1192e6f35403SYoshinobu Inoue 
1193e6f35403SYoshinobu Inoue 	/*
1194e6f35403SYoshinobu Inoue 	 * If we have not already tried the name "as is", do that now.
1195e6f35403SYoshinobu Inoue 	 * note that we do this regardless of how many dots were in the
1196e6f35403SYoshinobu Inoue 	 * name or whether it ends with a dot unless NOTLDQUERY is set.
1197e6f35403SYoshinobu Inoue 	 */
1198e6f35403SYoshinobu Inoue 	if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) {
1199e6f35403SYoshinobu Inoue 		for(rtl = rtl0; rtl != NULL;
1200e6f35403SYoshinobu Inoue 		    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1201e6f35403SYoshinobu Inoue 			ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type,
1202e6f35403SYoshinobu Inoue 					      answer, sizeof(answer));
1203e6f35403SYoshinobu Inoue 			if (ret > 0) {
1204e6f35403SYoshinobu Inoue 				hp = _gethpbyanswer(answer, ret, rtl->rtl_type,
1205e6f35403SYoshinobu Inoue 						    errp);
1206e6f35403SYoshinobu Inoue 				hp0 = _hpmerge(hp0, hp, errp);
1207e6f35403SYoshinobu Inoue 			}
1208e6f35403SYoshinobu Inoue 		}
1209e6f35403SYoshinobu Inoue 		if (hp0 != NULL)
1210e6f35403SYoshinobu Inoue 			return (hp0);
1211e6f35403SYoshinobu Inoue 	}
1212e6f35403SYoshinobu Inoue 
1213e6f35403SYoshinobu Inoue 	/* if we got here, we didn't satisfy the search.
1214e6f35403SYoshinobu Inoue 	 * if we did an initial full query, return that query's h_errno
1215e6f35403SYoshinobu Inoue 	 * (note that we wouldn't be here if that query had succeeded).
1216e6f35403SYoshinobu Inoue 	 * else if we ever got a nodata, send that back as the reason.
1217e6f35403SYoshinobu Inoue 	 * else send back meaningless h_errno, that being the one from
1218e6f35403SYoshinobu Inoue 	 * the last DNSRCH we did.
1219e6f35403SYoshinobu Inoue 	 */
1220e6f35403SYoshinobu Inoue 	if (saved_herrno != -1)
1221e6f35403SYoshinobu Inoue 		*errp = saved_herrno;
1222e6f35403SYoshinobu Inoue 	else if (got_nodata)
1223e6f35403SYoshinobu Inoue 		*errp = NO_DATA;
1224e6f35403SYoshinobu Inoue 	else if (got_servfail)
1225e6f35403SYoshinobu Inoue 		*errp = TRY_AGAIN;
1226e6f35403SYoshinobu Inoue 	return (NULL);
1227e6f35403SYoshinobu Inoue }
1228e6f35403SYoshinobu Inoue 
1229e6f35403SYoshinobu Inoue static struct hostent *
1230e6f35403SYoshinobu Inoue _dns_ghbyname(const char *name, int af, int *errp)
1231e6f35403SYoshinobu Inoue {
1232e6f35403SYoshinobu Inoue 	struct __res_type_list *rtl, rtl4;
1233e6f35403SYoshinobu Inoue #ifdef INET6
1234e6f35403SYoshinobu Inoue 	struct __res_type_list rtl6;
1235e6f35403SYoshinobu Inoue #endif
1236e6f35403SYoshinobu Inoue 
1237e6f35403SYoshinobu Inoue #ifdef INET6
1238e6f35403SYoshinobu Inoue 	switch (af) {
1239e6f35403SYoshinobu Inoue 	case AF_UNSPEC:
1240e6f35403SYoshinobu Inoue 		SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
1241e6f35403SYoshinobu Inoue 		SLIST_NEXT(&rtl6, rtl_entry) = &rtl4; rtl6.rtl_type = T_AAAA;
1242e6f35403SYoshinobu Inoue 		rtl = &rtl6;
1243e6f35403SYoshinobu Inoue 		break;
1244e6f35403SYoshinobu Inoue 	case AF_INET6:
1245e6f35403SYoshinobu Inoue 		SLIST_NEXT(&rtl6, rtl_entry) = NULL; rtl6.rtl_type = T_AAAA;
1246e6f35403SYoshinobu Inoue 		rtl = &rtl6;
1247e6f35403SYoshinobu Inoue 		break;
1248e6f35403SYoshinobu Inoue 	case AF_INET:
1249e6f35403SYoshinobu Inoue 		SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
1250e6f35403SYoshinobu Inoue 		rtl = &rtl4;
1251e6f35403SYoshinobu Inoue 		break;
1252e6f35403SYoshinobu Inoue 	}
1253e6f35403SYoshinobu Inoue #else
1254e6f35403SYoshinobu Inoue 	SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
1255e6f35403SYoshinobu Inoue 	rtl = &rtl4;
1256e6f35403SYoshinobu Inoue #endif
1257e6f35403SYoshinobu Inoue 	return(_res_search_multi(name, rtl, errp));
1258e6f35403SYoshinobu Inoue }
1259e6f35403SYoshinobu Inoue 
12607d56d374SYoshinobu Inoue static struct hostent *
12617d56d374SYoshinobu Inoue _dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
12627d56d374SYoshinobu Inoue {
12637d56d374SYoshinobu Inoue 	int n;
12647d56d374SYoshinobu Inoue 	u_char answer[BUFSIZ];
12657d56d374SYoshinobu Inoue 	HEADER *hp;
12667d56d374SYoshinobu Inoue 	u_char c, *cp, *eom;
12677d56d374SYoshinobu Inoue 	int type, class, ancount, qdcount;
12687d56d374SYoshinobu Inoue 	u_long ttl;
12697d56d374SYoshinobu Inoue 	char hostbuf[BUFSIZ];
12707d56d374SYoshinobu Inoue 	char *bp;
12717d56d374SYoshinobu Inoue 	char *alist[MAXALIASES];
12727d56d374SYoshinobu Inoue 	char *hlist[2];
12737d56d374SYoshinobu Inoue 	struct hostent hbuf;
12747d56d374SYoshinobu Inoue 	int buflen;
12757d56d374SYoshinobu Inoue 	int na;
12767d56d374SYoshinobu Inoue #ifdef INET6
12777d56d374SYoshinobu Inoue 	static const char hex[] = "0123456789abcdef";
12787d56d374SYoshinobu Inoue #endif
12797d56d374SYoshinobu Inoue 
12807d56d374SYoshinobu Inoue #ifdef INET6
12817d56d374SYoshinobu Inoue 	/* XXX */
12827d56d374SYoshinobu Inoue 	if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
12837d56d374SYoshinobu Inoue 		return NULL;
12847d56d374SYoshinobu Inoue #endif
12857d56d374SYoshinobu Inoue 
12867d56d374SYoshinobu Inoue 	if ((_res.options & RES_INIT) == 0) {
12877d56d374SYoshinobu Inoue 		if (res_init() < 0) {
12887d56d374SYoshinobu Inoue 			*errp = h_errno;
12897d56d374SYoshinobu Inoue 			return NULL;
12907d56d374SYoshinobu Inoue 		}
12917d56d374SYoshinobu Inoue 	}
12927d56d374SYoshinobu Inoue 	hbuf.h_name = NULL;
12937d56d374SYoshinobu Inoue 	hbuf.h_aliases = alist;
12947d56d374SYoshinobu Inoue 	hbuf.h_addrtype = af;
12957d56d374SYoshinobu Inoue 	hbuf.h_length = addrlen;
12967d56d374SYoshinobu Inoue 	hbuf.h_addr_list = hlist;
12977d56d374SYoshinobu Inoue 	hlist[0] = (char *)addr;
12987d56d374SYoshinobu Inoue 	hlist[1] = NULL;
12997d56d374SYoshinobu Inoue 	na = 0;
13007d56d374SYoshinobu Inoue 
13017d56d374SYoshinobu Inoue 	n = 0;
13027d56d374SYoshinobu Inoue 	bp = hostbuf;
13037d56d374SYoshinobu Inoue 	cp = (u_char *)addr+addrlen-1;
13047d56d374SYoshinobu Inoue 	switch (af) {
13057d56d374SYoshinobu Inoue #ifdef INET6
13067d56d374SYoshinobu Inoue 	case AF_INET6:
13077d56d374SYoshinobu Inoue 		for (; n < addrlen; n++, cp--) {
13087d56d374SYoshinobu Inoue 			c = *cp;
13097d56d374SYoshinobu Inoue 			*bp++ = hex[c & 0xf];
13107d56d374SYoshinobu Inoue 			*bp++ = '.';
13117d56d374SYoshinobu Inoue 			*bp++ = hex[c >> 4];
13127d56d374SYoshinobu Inoue 			*bp++ = '.';
13137d56d374SYoshinobu Inoue 		}
13147d56d374SYoshinobu Inoue 		strcpy(bp, "ip6.int");
13157d56d374SYoshinobu Inoue 		break;
13167d56d374SYoshinobu Inoue #endif
13177d56d374SYoshinobu Inoue 	default:
13187d56d374SYoshinobu Inoue 		for (; n < addrlen; n++, cp--) {
13197d56d374SYoshinobu Inoue 			c = *cp;
13207d56d374SYoshinobu Inoue 			if (c >= 100)
13217d56d374SYoshinobu Inoue 				*bp++ = '0' + c / 100;
13227d56d374SYoshinobu Inoue 			if (c >= 10)
13237d56d374SYoshinobu Inoue 				*bp++ = '0' + (c % 100) / 10;
13247d56d374SYoshinobu Inoue 			*bp++ = '0' + c % 10;
13257d56d374SYoshinobu Inoue 			*bp++ = '.';
13267d56d374SYoshinobu Inoue 		}
13277d56d374SYoshinobu Inoue 		strcpy(bp, "in-addr.arpa");
13287d56d374SYoshinobu Inoue 		break;
13297d56d374SYoshinobu Inoue 	}
13307d56d374SYoshinobu Inoue 
13317d56d374SYoshinobu Inoue 	n = res_query(hostbuf, C_IN, T_PTR, answer, sizeof(answer));
13327d56d374SYoshinobu Inoue 	if (n < 0) {
13337d56d374SYoshinobu Inoue 		*errp = h_errno;
13347d56d374SYoshinobu Inoue 		return NULL;
13357d56d374SYoshinobu Inoue 	}
13367d56d374SYoshinobu Inoue 	hp = (HEADER *)answer;
13377d56d374SYoshinobu Inoue 	eom = answer + n;
13387d56d374SYoshinobu Inoue 	ancount = ntohs(hp->ancount);
13397d56d374SYoshinobu Inoue 	qdcount = ntohs(hp->qdcount);
13407d56d374SYoshinobu Inoue 	DNS_ASSERT(qdcount == 1);
13417d56d374SYoshinobu Inoue 	cp = answer + sizeof(HEADER);
13427d56d374SYoshinobu Inoue 	bp = hostbuf;
13437d56d374SYoshinobu Inoue 	buflen = sizeof(hostbuf);
13447d56d374SYoshinobu Inoue 
13457d56d374SYoshinobu Inoue 	n = dn_expand(answer, eom, cp, bp, buflen);
13467d56d374SYoshinobu Inoue 	DNS_ASSERT(n >= 0);
13477d56d374SYoshinobu Inoue 	cp += n + QFIXEDSZ;
13487d56d374SYoshinobu Inoue 	while (ancount-- > 0 && cp < eom) {
13497d56d374SYoshinobu Inoue 		n = dn_expand(answer, eom, cp, bp, buflen);
13507d56d374SYoshinobu Inoue 		DNS_ASSERT(n >= 0);
13517d56d374SYoshinobu Inoue 		cp += n;		/* name */
13527d56d374SYoshinobu Inoue 		type = _getshort(cp);
13537d56d374SYoshinobu Inoue 		cp += 2;		/* type */
13547d56d374SYoshinobu Inoue 		class = _getshort(cp);
13557d56d374SYoshinobu Inoue 		cp += 2;		/* class */
13567d56d374SYoshinobu Inoue 		ttl = _getlong(cp);
13577d56d374SYoshinobu Inoue 		cp += 4;		/* ttl */
13587d56d374SYoshinobu Inoue 		n = _getshort(cp);
13597d56d374SYoshinobu Inoue 		cp += 2;		/* len */
13607d56d374SYoshinobu Inoue 		DNS_ASSERT(class == C_IN);
13617d56d374SYoshinobu Inoue 		switch (type) {
13627d56d374SYoshinobu Inoue 		case T_PTR:
13637d56d374SYoshinobu Inoue 			n = dn_expand(answer, eom, cp, bp, buflen);
13647d56d374SYoshinobu Inoue 			DNS_ASSERT(n >= 0);
13657d56d374SYoshinobu Inoue 			cp += n;
13667d56d374SYoshinobu Inoue 			if (na >= MAXALIASES-1)
13677d56d374SYoshinobu Inoue 				break;
13687d56d374SYoshinobu Inoue 			if (hbuf.h_name == NULL)
13697d56d374SYoshinobu Inoue 				hbuf.h_name = bp;
13707d56d374SYoshinobu Inoue 			else
13717d56d374SYoshinobu Inoue 				alist[na++] = bp;
13727d56d374SYoshinobu Inoue 			n = strlen(bp) + 1;
13737d56d374SYoshinobu Inoue 			bp += n;
13747d56d374SYoshinobu Inoue 			buflen -= n;
13757d56d374SYoshinobu Inoue 			break;
13767d56d374SYoshinobu Inoue 		case T_CNAME:
13777d56d374SYoshinobu Inoue 			cp += n;
13787d56d374SYoshinobu Inoue 			break;
13797d56d374SYoshinobu Inoue 		default:
13807d56d374SYoshinobu Inoue   badanswer:
13817d56d374SYoshinobu Inoue 			*errp = NO_RECOVERY;
13827d56d374SYoshinobu Inoue 			return NULL;
13837d56d374SYoshinobu Inoue 		}
13847d56d374SYoshinobu Inoue 	}
13857d56d374SYoshinobu Inoue 	if (hbuf.h_name == NULL) {
13867d56d374SYoshinobu Inoue 		*errp = h_errno;
13877d56d374SYoshinobu Inoue 		return NULL;
13887d56d374SYoshinobu Inoue 	}
13897d56d374SYoshinobu Inoue 	alist[na] = NULL;
13907d56d374SYoshinobu Inoue 	return _hpcopy(&hbuf, errp);
13917d56d374SYoshinobu Inoue }
13927d56d374SYoshinobu Inoue 
13937d56d374SYoshinobu Inoue #ifdef ICMPNL
13947d56d374SYoshinobu Inoue 
13957d56d374SYoshinobu Inoue /*
13967d56d374SYoshinobu Inoue  * experimental:
13977d56d374SYoshinobu Inoue  *	draft-ietf-ipngwg-icmp-namelookups-02.txt
13987d56d374SYoshinobu Inoue  *	ifindex is assumed to be encoded in addr.
13997d56d374SYoshinobu Inoue  */
14007d56d374SYoshinobu Inoue #include <sys/uio.h>
14017d56d374SYoshinobu Inoue #include <netinet/ip6.h>
14027d56d374SYoshinobu Inoue #include <netinet/icmp6.h>
14037d56d374SYoshinobu Inoue 
14047d56d374SYoshinobu Inoue struct _icmp_host_cache {
14057d56d374SYoshinobu Inoue 	struct _icmp_host_cache *hc_next;
14067d56d374SYoshinobu Inoue 	int hc_ifindex;
14077d56d374SYoshinobu Inoue 	struct in6_addr hc_addr;
14087d56d374SYoshinobu Inoue 	char *hc_name;
14097d56d374SYoshinobu Inoue };
14107d56d374SYoshinobu Inoue 
14117d56d374SYoshinobu Inoue static char *
14127d56d374SYoshinobu Inoue _icmp_fqdn_query(const struct in6_addr *addr, int ifindex)
14137d56d374SYoshinobu Inoue {
14147d56d374SYoshinobu Inoue 	int s;
14157d56d374SYoshinobu Inoue 	struct icmp6_filter filter;
14167d56d374SYoshinobu Inoue 	struct msghdr msg;
14177d56d374SYoshinobu Inoue 	struct cmsghdr *cmsg;
14187d56d374SYoshinobu Inoue 	struct in6_pktinfo *pkt;
14197d56d374SYoshinobu Inoue 	char cbuf[256];
14207d56d374SYoshinobu Inoue 	char buf[1024];
14217d56d374SYoshinobu Inoue 	int cc;
14227d56d374SYoshinobu Inoue 	struct icmp6_fqdn_query *fq;
14237d56d374SYoshinobu Inoue 	struct icmp6_fqdn_reply *fr;
14247d56d374SYoshinobu Inoue 	struct _icmp_host_cache *hc;
14257d56d374SYoshinobu Inoue 	struct sockaddr_in6 sin6;
14267d56d374SYoshinobu Inoue 	struct iovec iov;
14277d56d374SYoshinobu Inoue 	fd_set s_fds, fds;
14287d56d374SYoshinobu Inoue 	struct timeval tout;
14297d56d374SYoshinobu Inoue 	int len;
14307d56d374SYoshinobu Inoue 	char *name;
14317d56d374SYoshinobu Inoue 	static int pid;
14327d56d374SYoshinobu Inoue 	static struct _icmp_host_cache *hc_head;
14337d56d374SYoshinobu Inoue 
14347d56d374SYoshinobu Inoue 	for (hc = hc_head; hc; hc = hc->hc_next) {
14357d56d374SYoshinobu Inoue 		if (hc->hc_ifindex == ifindex
14367d56d374SYoshinobu Inoue 		&&  IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr))
14377d56d374SYoshinobu Inoue 			return hc->hc_name;
14387d56d374SYoshinobu Inoue 	}
14397d56d374SYoshinobu Inoue 
14407d56d374SYoshinobu Inoue 	if (pid == 0)
14417d56d374SYoshinobu Inoue 		pid = getpid();
14427d56d374SYoshinobu Inoue 
14437d56d374SYoshinobu Inoue 	ICMP6_FILTER_SETBLOCKALL(&filter);
14447d56d374SYoshinobu Inoue 	ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter);
14457d56d374SYoshinobu Inoue 
14467d56d374SYoshinobu Inoue 	FD_ZERO(&s_fds);
14477d56d374SYoshinobu Inoue 	tout.tv_sec = 0;
14487d56d374SYoshinobu Inoue 	tout.tv_usec = 200000;	/*XXX: 200ms*/
14497d56d374SYoshinobu Inoue 
14507d56d374SYoshinobu Inoue 	fq = (struct icmp6_fqdn_query *)buf;
14517d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY;
14527d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_code = 0;
14537d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_cksum = 0;
14547d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_id = (u_short)pid;
14557d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_unused = 0;
14567d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_cookie[0] = 0;
14577d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_cookie[1] = 0;
14587d56d374SYoshinobu Inoue 
14597d56d374SYoshinobu Inoue 	memset(&sin6, 0, sizeof(sin6));
14607d56d374SYoshinobu Inoue 	sin6.sin6_family = AF_INET6;
14617d56d374SYoshinobu Inoue 	sin6.sin6_addr = *addr;
14627d56d374SYoshinobu Inoue 
14637d56d374SYoshinobu Inoue 	memset(&msg, 0, sizeof(msg));
14647d56d374SYoshinobu Inoue 	msg.msg_name = (caddr_t)&sin6;
14657d56d374SYoshinobu Inoue 	msg.msg_namelen = sizeof(sin6);
14667d56d374SYoshinobu Inoue 	msg.msg_iov = &iov;
14677d56d374SYoshinobu Inoue 	msg.msg_iovlen = 1;
14687d56d374SYoshinobu Inoue 	msg.msg_control = NULL;
14697d56d374SYoshinobu Inoue 	msg.msg_controllen = 0;
14707d56d374SYoshinobu Inoue 	iov.iov_base = (caddr_t)buf;
14717d56d374SYoshinobu Inoue 	iov.iov_len = sizeof(struct icmp6_fqdn_query);
14727d56d374SYoshinobu Inoue 
14737d56d374SYoshinobu Inoue 	if (ifindex) {
14747d56d374SYoshinobu Inoue 		msg.msg_control = cbuf;
14757d56d374SYoshinobu Inoue 		msg.msg_controllen = sizeof(cbuf);
14767d56d374SYoshinobu Inoue 		cmsg = CMSG_FIRSTHDR(&msg);
14777d56d374SYoshinobu Inoue 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
14787d56d374SYoshinobu Inoue 		cmsg->cmsg_level = IPPROTO_IPV6;
14797d56d374SYoshinobu Inoue 		cmsg->cmsg_type = IPV6_PKTINFO;
14807d56d374SYoshinobu Inoue 		pkt = (struct in6_pktinfo *)&cmsg[1];
14817d56d374SYoshinobu Inoue 		memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
14827d56d374SYoshinobu Inoue 		pkt->ipi6_ifindex = ifindex;
14837d56d374SYoshinobu Inoue 		cmsg = CMSG_NXTHDR(&msg, cmsg);
14847d56d374SYoshinobu Inoue 		msg.msg_controllen = (char *)cmsg - cbuf;
14857d56d374SYoshinobu Inoue 	}
14867d56d374SYoshinobu Inoue 
14877d56d374SYoshinobu Inoue 	if ((s = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
14887d56d374SYoshinobu Inoue 		return NULL;
14897d56d374SYoshinobu Inoue 	(void)setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
14907d56d374SYoshinobu Inoue 			 (char *)&filter, sizeof(filter));
14917d56d374SYoshinobu Inoue 	cc = sendmsg(s, &msg, 0);
14927d56d374SYoshinobu Inoue 	if (cc < 0) {
14939233c4d9SJason Evans 		_close(s);
14947d56d374SYoshinobu Inoue 		return NULL;
14957d56d374SYoshinobu Inoue 	}
14967d56d374SYoshinobu Inoue 	FD_SET(s, &s_fds);
14977d56d374SYoshinobu Inoue 	for (;;) {
14987d56d374SYoshinobu Inoue 		fds = s_fds;
14997d56d374SYoshinobu Inoue 		if (select(s + 1, &fds, NULL, NULL, &tout) <= 0) {
15009233c4d9SJason Evans 			_close(s);
15017d56d374SYoshinobu Inoue 			return NULL;
15027d56d374SYoshinobu Inoue 		}
15037d56d374SYoshinobu Inoue 		len = sizeof(sin6);
15047d56d374SYoshinobu Inoue 		cc = recvfrom(s, buf, sizeof(buf), 0,
15057d56d374SYoshinobu Inoue 			      (struct sockaddr *)&sin6, &len);
15067d56d374SYoshinobu Inoue 		if (cc <= 0) {
15079233c4d9SJason Evans 			_close(s);
15087d56d374SYoshinobu Inoue 			return NULL;
15097d56d374SYoshinobu Inoue 		}
15107d56d374SYoshinobu Inoue 		if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
15117d56d374SYoshinobu Inoue 			continue;
15127d56d374SYoshinobu Inoue 		if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr))
15137d56d374SYoshinobu Inoue 			continue;
15147d56d374SYoshinobu Inoue 		fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr));
15157d56d374SYoshinobu Inoue 		if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY)
15167d56d374SYoshinobu Inoue 			break;
15177d56d374SYoshinobu Inoue 	}
15189233c4d9SJason Evans 	_close(s);
15197d56d374SYoshinobu Inoue 	if (fr->icmp6_fqdn_cookie[1] != 0) {
15207d56d374SYoshinobu Inoue 		/* rfc1788 type */
15217d56d374SYoshinobu Inoue 		name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4;
15227d56d374SYoshinobu Inoue 		len = (buf + cc) - name;
15237d56d374SYoshinobu Inoue 	} else {
15247d56d374SYoshinobu Inoue 		len = fr->icmp6_fqdn_namelen;
15257d56d374SYoshinobu Inoue 		name = fr->icmp6_fqdn_name;
15267d56d374SYoshinobu Inoue 	}
15277d56d374SYoshinobu Inoue 	if (len <= 0)
15287d56d374SYoshinobu Inoue 		return NULL;
15297d56d374SYoshinobu Inoue 	name[len] = 0;
15307d56d374SYoshinobu Inoue 
15317d56d374SYoshinobu Inoue 	if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL)
15327d56d374SYoshinobu Inoue 		return NULL;
15337d56d374SYoshinobu Inoue 	/* XXX: limit number of cached entries */
15347d56d374SYoshinobu Inoue 	hc->hc_ifindex = ifindex;
15357d56d374SYoshinobu Inoue 	hc->hc_addr = *addr;
15367d56d374SYoshinobu Inoue 	hc->hc_name = strdup(name);
15377d56d374SYoshinobu Inoue 	hc->hc_next = hc_head;
15387d56d374SYoshinobu Inoue 	hc_head = hc;
15397d56d374SYoshinobu Inoue 	return hc->hc_name;
15407d56d374SYoshinobu Inoue }
15417d56d374SYoshinobu Inoue 
15427d56d374SYoshinobu Inoue static struct hostent *
15437d56d374SYoshinobu Inoue _icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
15447d56d374SYoshinobu Inoue {
15457d56d374SYoshinobu Inoue 	char *hname;
15467d56d374SYoshinobu Inoue 	int ifindex;
15477d56d374SYoshinobu Inoue 	struct in6_addr addr6;
15487d56d374SYoshinobu Inoue 
15497d56d374SYoshinobu Inoue 	if (af != AF_INET6) {
15507d56d374SYoshinobu Inoue 		/*
15517d56d374SYoshinobu Inoue 		 * Note: rfc1788 defines Who Are You for IPv4,
15527d56d374SYoshinobu Inoue 		 * but no one implements it.
15537d56d374SYoshinobu Inoue 		 */
15547d56d374SYoshinobu Inoue 		return NULL;
15557d56d374SYoshinobu Inoue 	}
15567d56d374SYoshinobu Inoue 
15577d56d374SYoshinobu Inoue 	memcpy(&addr6, addr, addrlen);
15587d56d374SYoshinobu Inoue 	ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
15597d56d374SYoshinobu Inoue 	addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
15607d56d374SYoshinobu Inoue 
15617d56d374SYoshinobu Inoue 	if (!IN6_IS_ADDR_LINKLOCAL(&addr6))
15627d56d374SYoshinobu Inoue 		return NULL;	/*XXX*/
15637d56d374SYoshinobu Inoue 
15647d56d374SYoshinobu Inoue 	if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL)
15657d56d374SYoshinobu Inoue 		return NULL;
15667d56d374SYoshinobu Inoue 	return _hpaddr(af, hname, &addr6, errp);
15677d56d374SYoshinobu Inoue }
15687d56d374SYoshinobu Inoue #endif /* ICMPNL */
1569