xref: /freebsd/lib/libc/net/name6.c (revision d201fe46)
173b30f0cSJun-ichiro itojun Hagino /*	$FreeBSD$	*/
23f587e57SKris Kennaway /*	$KAME: name6.c,v 1.25 2000/06/26 16:44:40 itojun Exp $	*/
373b30f0cSJun-ichiro itojun Hagino 
47d56d374SYoshinobu Inoue /*
57d56d374SYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
67d56d374SYoshinobu Inoue  * All rights reserved.
77d56d374SYoshinobu Inoue  *
87d56d374SYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
97d56d374SYoshinobu Inoue  * modification, are permitted provided that the following conditions
107d56d374SYoshinobu Inoue  * are met:
117d56d374SYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
127d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
137d56d374SYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
147d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
157d56d374SYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
167d56d374SYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
177d56d374SYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
187d56d374SYoshinobu Inoue  *    without specific prior written permission.
197d56d374SYoshinobu Inoue  *
207d56d374SYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
217d56d374SYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
227d56d374SYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
237d56d374SYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
247d56d374SYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
257d56d374SYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
267d56d374SYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
277d56d374SYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
287d56d374SYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
297d56d374SYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
307d56d374SYoshinobu Inoue  * SUCH DAMAGE.
317d56d374SYoshinobu Inoue  */
3273b30f0cSJun-ichiro itojun Hagino /*
3373b30f0cSJun-ichiro itojun Hagino  * ++Copyright++ 1985, 1988, 1993
3473b30f0cSJun-ichiro itojun Hagino  * -
3573b30f0cSJun-ichiro itojun Hagino  * Copyright (c) 1985, 1988, 1993
3673b30f0cSJun-ichiro itojun Hagino  *    The Regents of the University of California.  All rights reserved.
3773b30f0cSJun-ichiro itojun Hagino  *
3873b30f0cSJun-ichiro itojun Hagino  * Redistribution and use in source and binary forms, with or without
3973b30f0cSJun-ichiro itojun Hagino  * modification, are permitted provided that the following conditions
4073b30f0cSJun-ichiro itojun Hagino  * are met:
4173b30f0cSJun-ichiro itojun Hagino  * 1. Redistributions of source code must retain the above copyright
4273b30f0cSJun-ichiro itojun Hagino  *    notice, this list of conditions and the following disclaimer.
4373b30f0cSJun-ichiro itojun Hagino  * 2. Redistributions in binary form must reproduce the above copyright
4473b30f0cSJun-ichiro itojun Hagino  *    notice, this list of conditions and the following disclaimer in the
4573b30f0cSJun-ichiro itojun Hagino  *    documentation and/or other materials provided with the distribution.
4673b30f0cSJun-ichiro itojun Hagino  * 3. All advertising materials mentioning features or use of this software
4773b30f0cSJun-ichiro itojun Hagino  *    must display the following acknowledgement:
4873b30f0cSJun-ichiro itojun Hagino  * 	This product includes software developed by the University of
4973b30f0cSJun-ichiro itojun Hagino  * 	California, Berkeley and its contributors.
5073b30f0cSJun-ichiro itojun Hagino  * 4. Neither the name of the University nor the names of its contributors
5173b30f0cSJun-ichiro itojun Hagino  *    may be used to endorse or promote products derived from this software
5273b30f0cSJun-ichiro itojun Hagino  *    without specific prior written permission.
5373b30f0cSJun-ichiro itojun Hagino  *
5473b30f0cSJun-ichiro itojun Hagino  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5573b30f0cSJun-ichiro itojun Hagino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5673b30f0cSJun-ichiro itojun Hagino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5773b30f0cSJun-ichiro itojun Hagino  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5873b30f0cSJun-ichiro itojun Hagino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5973b30f0cSJun-ichiro itojun Hagino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6073b30f0cSJun-ichiro itojun Hagino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6173b30f0cSJun-ichiro itojun Hagino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6273b30f0cSJun-ichiro itojun Hagino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6373b30f0cSJun-ichiro itojun Hagino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6473b30f0cSJun-ichiro itojun Hagino  * SUCH DAMAGE.
6573b30f0cSJun-ichiro itojun Hagino  * -
6673b30f0cSJun-ichiro itojun Hagino  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
6773b30f0cSJun-ichiro itojun Hagino  *
6873b30f0cSJun-ichiro itojun Hagino  * Permission to use, copy, modify, and distribute this software for any
6973b30f0cSJun-ichiro itojun Hagino  * purpose with or without fee is hereby granted, provided that the above
7073b30f0cSJun-ichiro itojun Hagino  * copyright notice and this permission notice appear in all copies, and that
7173b30f0cSJun-ichiro itojun Hagino  * the name of Digital Equipment Corporation not be used in advertising or
7273b30f0cSJun-ichiro itojun Hagino  * publicity pertaining to distribution of the document or software without
7373b30f0cSJun-ichiro itojun Hagino  * specific, written prior permission.
7473b30f0cSJun-ichiro itojun Hagino  *
7573b30f0cSJun-ichiro itojun Hagino  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
7673b30f0cSJun-ichiro itojun Hagino  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
7773b30f0cSJun-ichiro itojun Hagino  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
7873b30f0cSJun-ichiro itojun Hagino  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
7973b30f0cSJun-ichiro itojun Hagino  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
8073b30f0cSJun-ichiro itojun Hagino  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
8173b30f0cSJun-ichiro itojun Hagino  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
8273b30f0cSJun-ichiro itojun Hagino  * SOFTWARE.
8373b30f0cSJun-ichiro itojun Hagino  * -
8473b30f0cSJun-ichiro itojun Hagino  * --Copyright--
8573b30f0cSJun-ichiro itojun Hagino  */
8673b30f0cSJun-ichiro itojun Hagino 
877d56d374SYoshinobu Inoue /*
887d56d374SYoshinobu Inoue  *	Atsushi Onoe <onoe@sm.sony.co.jp>
897d56d374SYoshinobu Inoue  */
907d56d374SYoshinobu Inoue 
917d56d374SYoshinobu Inoue /*
927d56d374SYoshinobu Inoue  * TODO for thread safe
937d56d374SYoshinobu Inoue  *	use mutex for _hostconf, _hostconf_init.
947d56d374SYoshinobu Inoue  *	rewrite resolvers to be thread safe
957d56d374SYoshinobu Inoue  */
967d56d374SYoshinobu Inoue 
97d201fe46SDaniel Eischen #include "namespace.h"
987d56d374SYoshinobu Inoue #include <sys/param.h>
997d56d374SYoshinobu Inoue #include <sys/socket.h>
1007d56d374SYoshinobu Inoue #include <sys/time.h>
101e6f35403SYoshinobu Inoue #include <sys/queue.h>
1027d56d374SYoshinobu Inoue #include <netinet/in.h>
1037d56d374SYoshinobu Inoue 
1047d56d374SYoshinobu Inoue #include <arpa/inet.h>
1057d56d374SYoshinobu Inoue #include <arpa/nameser.h>
1067d56d374SYoshinobu Inoue 
107e6f35403SYoshinobu Inoue #include <errno.h>
1087d56d374SYoshinobu Inoue #include <netdb.h>
1097d56d374SYoshinobu Inoue #include <resolv.h>
1107d56d374SYoshinobu Inoue #include <stdio.h>
1117d56d374SYoshinobu Inoue #include <stdlib.h>
1127d56d374SYoshinobu Inoue #include <string.h>
113248aee62SJacques Vidrine #include <stdarg.h>
114248aee62SJacques Vidrine #include <nsswitch.h>
1157d56d374SYoshinobu Inoue #include <unistd.h>
116d201fe46SDaniel Eischen #include "un-namespace.h"
1177d56d374SYoshinobu Inoue 
1187d56d374SYoshinobu Inoue #ifndef _PATH_HOSTS
1197d56d374SYoshinobu Inoue #define	_PATH_HOSTS	"/etc/hosts"
1207d56d374SYoshinobu Inoue #endif
1217d56d374SYoshinobu Inoue 
1227d56d374SYoshinobu Inoue #ifndef MAXALIASES
1237d56d374SYoshinobu Inoue #define	MAXALIASES	10
1247d56d374SYoshinobu Inoue #endif
1257d56d374SYoshinobu Inoue #ifndef	MAXADDRS
1267d56d374SYoshinobu Inoue #define	MAXADDRS	20
1277d56d374SYoshinobu Inoue #endif
1287d56d374SYoshinobu Inoue #ifndef MAXDNAME
1297d56d374SYoshinobu Inoue #define	MAXDNAME	1025
1307d56d374SYoshinobu Inoue #endif
1317d56d374SYoshinobu Inoue 
1327d56d374SYoshinobu Inoue #ifdef INET6
1337d56d374SYoshinobu Inoue #define	ADDRLEN(af)	((af) == AF_INET6 ? sizeof(struct in6_addr) : \
1347d56d374SYoshinobu Inoue 					    sizeof(struct in_addr))
1357d56d374SYoshinobu Inoue #else
1367d56d374SYoshinobu Inoue #define	ADDRLEN(af)	sizeof(struct in_addr)
1377d56d374SYoshinobu Inoue #endif
1387d56d374SYoshinobu Inoue 
1397d56d374SYoshinobu Inoue #define	MAPADDR(ab, ina) \
1407d56d374SYoshinobu Inoue do {									\
1417d56d374SYoshinobu Inoue 	memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr));		\
1427d56d374SYoshinobu Inoue 	memset((ab)->map_zero, 0, sizeof((ab)->map_zero));		\
1437d56d374SYoshinobu Inoue 	memset((ab)->map_one, 0xff, sizeof((ab)->map_one));		\
1447d56d374SYoshinobu Inoue } while (0)
1457d56d374SYoshinobu Inoue #define	MAPADDRENABLED(flags) \
1467d56d374SYoshinobu Inoue 	(((flags) & AI_V4MAPPED) || \
1477d56d374SYoshinobu Inoue 	 (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled()))
1487d56d374SYoshinobu Inoue 
1497d56d374SYoshinobu Inoue union inx_addr {
1507d56d374SYoshinobu Inoue 	struct in_addr	in_addr;
1517d56d374SYoshinobu Inoue #ifdef INET6
1527d56d374SYoshinobu Inoue 	struct in6_addr	in6_addr;
1537d56d374SYoshinobu Inoue #endif
1547d56d374SYoshinobu Inoue 	struct {
1557d56d374SYoshinobu Inoue 		u_char	mau_zero[10];
1567d56d374SYoshinobu Inoue 		u_char	mau_one[2];
1577d56d374SYoshinobu Inoue 		struct in_addr mau_inaddr;
1587d56d374SYoshinobu Inoue 	}		map_addr_un;
1597d56d374SYoshinobu Inoue #define	map_zero	map_addr_un.mau_zero
1607d56d374SYoshinobu Inoue #define	map_one		map_addr_un.mau_one
1617d56d374SYoshinobu Inoue #define	map_inaddr	map_addr_un.mau_inaddr
1627d56d374SYoshinobu Inoue };
1637d56d374SYoshinobu Inoue 
1647d56d374SYoshinobu Inoue static struct	 hostent *_hpcopy(struct hostent *hp, int *errp);
1657d56d374SYoshinobu Inoue static struct	 hostent *_hpaddr(int af, const char *name, void *addr, int *errp);
1667d56d374SYoshinobu Inoue static struct	 hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp);
1677d56d374SYoshinobu Inoue #ifdef INET6
1687d56d374SYoshinobu Inoue static struct	 hostent *_hpmapv6(struct hostent *hp, int *errp);
1697d56d374SYoshinobu Inoue #endif
1707d56d374SYoshinobu Inoue static struct	 hostent *_hpsort(struct hostent *hp);
1717d56d374SYoshinobu Inoue static struct	 hostent *_ghbyname(const char *name, int af, int flags, int *errp);
1727d56d374SYoshinobu Inoue static char	*_hgetword(char **pp);
1737d56d374SYoshinobu Inoue static int	 _mapped_addr_enabled(void);
1747d56d374SYoshinobu Inoue 
1757d56d374SYoshinobu Inoue static FILE	*_files_open(int *errp);
176248aee62SJacques Vidrine static int	 _files_ghbyname(void *, void *, va_list);
177248aee62SJacques Vidrine static int	 _files_ghbyaddr(void *, void *, va_list);
1787d56d374SYoshinobu Inoue static void	 _files_shent(int stayopen);
1797d56d374SYoshinobu Inoue static void	 _files_ehent(void);
18073b30f0cSJun-ichiro itojun Hagino #ifdef YP
181248aee62SJacques Vidrine static int	 _nis_ghbyname(void *, void *, va_list);
182248aee62SJacques Vidrine static int	 _nis_ghbyaddr(void *, void *, va_list);
18373b30f0cSJun-ichiro itojun Hagino #endif
184248aee62SJacques Vidrine static int	 _dns_ghbyname(void *, void *, va_list);
185248aee62SJacques Vidrine static int	 _dns_ghbyaddr(void *, void *, va_list);
1867d56d374SYoshinobu Inoue static void	 _dns_shent(int stayopen);
1877d56d374SYoshinobu Inoue static void	 _dns_ehent(void);
1887d56d374SYoshinobu Inoue #ifdef ICMPNL
189248aee62SJacques Vidrine static int	 _icmp_ghbyaddr(void *, void *, va_list);
1907d56d374SYoshinobu Inoue #endif /* ICMPNL */
1917d56d374SYoshinobu Inoue 
192248aee62SJacques Vidrine /* Host lookup order if nsswitch.conf is broken or nonexistant */
193248aee62SJacques Vidrine static const ns_src default_src[] = {
194248aee62SJacques Vidrine 	{ NSSRC_FILES, NS_SUCCESS },
195248aee62SJacques Vidrine 	{ NSSRC_DNS, NS_SUCCESS },
1967d56d374SYoshinobu Inoue #ifdef ICMPNL
197248aee62SJacques Vidrine #define NSSRC_ICMP "icmp"
198248aee62SJacques Vidrine 	{ NSSRC_ICMP, NS_SUCCESS },
19973b30f0cSJun-ichiro itojun Hagino #endif
200248aee62SJacques Vidrine 	{ 0 }
201248aee62SJacques Vidrine };
2027d56d374SYoshinobu Inoue 
2037d56d374SYoshinobu Inoue /*
2047d56d374SYoshinobu Inoue  * Check if kernel supports mapped address.
2057d56d374SYoshinobu Inoue  *	implementation dependent
2067d56d374SYoshinobu Inoue  */
2077d56d374SYoshinobu Inoue #ifdef __KAME__
2087d56d374SYoshinobu Inoue #include <sys/sysctl.h>
2097d56d374SYoshinobu Inoue #endif /* __KAME__ */
2107d56d374SYoshinobu Inoue 
2117d56d374SYoshinobu Inoue static int
2127d56d374SYoshinobu Inoue _mapped_addr_enabled(void)
2137d56d374SYoshinobu Inoue {
2147d56d374SYoshinobu Inoue 	/* implementation dependent check */
2157d56d374SYoshinobu Inoue #if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR)
2167d56d374SYoshinobu Inoue 	int mib[4];
2177d56d374SYoshinobu Inoue 	size_t len;
2187d56d374SYoshinobu Inoue 	int val;
2197d56d374SYoshinobu Inoue 
2207d56d374SYoshinobu Inoue 	mib[0] = CTL_NET;
2217d56d374SYoshinobu Inoue 	mib[1] = PF_INET6;
2227d56d374SYoshinobu Inoue 	mib[2] = IPPROTO_IPV6;
2237d56d374SYoshinobu Inoue 	mib[3] = IPV6CTL_MAPPED_ADDR;
2247d56d374SYoshinobu Inoue 	len = sizeof(val);
2257d56d374SYoshinobu Inoue 	if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0)
2267d56d374SYoshinobu Inoue 		return 1;
2277d56d374SYoshinobu Inoue #endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */
2287d56d374SYoshinobu Inoue 	return 0;
2297d56d374SYoshinobu Inoue }
2307d56d374SYoshinobu Inoue 
2317d56d374SYoshinobu Inoue /*
2327d56d374SYoshinobu Inoue  * Functions defined in RFC2553
23373b30f0cSJun-ichiro itojun Hagino  *	getipnodebyname, getipnodebyaddr, freehostent
2347d56d374SYoshinobu Inoue  */
2357d56d374SYoshinobu Inoue 
2367d56d374SYoshinobu Inoue static struct hostent *
2377d56d374SYoshinobu Inoue _ghbyname(const char *name, int af, int flags, int *errp)
2387d56d374SYoshinobu Inoue {
2397d56d374SYoshinobu Inoue 	struct hostent *hp;
240cb0600bdSJacques Vidrine 	int rval;
241248aee62SJacques Vidrine 
242248aee62SJacques Vidrine 	static const ns_dtab dtab[] = {
243248aee62SJacques Vidrine 		NS_FILES_CB(_files_ghbyname, NULL)
244248aee62SJacques Vidrine 		{ NSSRC_DNS, _dns_ghbyname, NULL },
245248aee62SJacques Vidrine 		NS_NIS_CB(_nis_ghbyname, NULL)
246248aee62SJacques Vidrine 		{ 0 }
247248aee62SJacques Vidrine 	};
2487d56d374SYoshinobu Inoue 
2497d56d374SYoshinobu Inoue 	if (flags & AI_ADDRCONFIG) {
2507d56d374SYoshinobu Inoue 		int s;
2517d56d374SYoshinobu Inoue 
2527d56d374SYoshinobu Inoue 		/*
2537d56d374SYoshinobu Inoue 		 * TODO:
2547d56d374SYoshinobu Inoue 		 * Note that implementation dependent test for address
2557d56d374SYoshinobu Inoue 		 * configuration should be done everytime called
2567d56d374SYoshinobu Inoue 		 * (or apropriate interval),
2577d56d374SYoshinobu Inoue 		 * because addresses will be dynamically assigned or deleted.
2587d56d374SYoshinobu Inoue 		 */
259e6f35403SYoshinobu Inoue 		if (af == AF_UNSPEC) {
260d201fe46SDaniel Eischen 			if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
261e6f35403SYoshinobu Inoue 				af = AF_INET;
262e6f35403SYoshinobu Inoue 			else {
2639233c4d9SJason Evans 				_close(s);
264d201fe46SDaniel Eischen 				if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0)
265e6f35403SYoshinobu Inoue 					af = AF_INET6;
266e6f35403SYoshinobu Inoue 				else
267e6f35403SYoshinobu Inoue 				_close(s);
268e6f35403SYoshinobu Inoue 			}
269e6f35403SYoshinobu Inoue 
270e6f35403SYoshinobu Inoue 		}
271e6f35403SYoshinobu Inoue 		if (af != AF_UNSPEC) {
272d201fe46SDaniel Eischen 			if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
273e6f35403SYoshinobu Inoue 				return NULL;
274e6f35403SYoshinobu Inoue 			_close(s);
275e6f35403SYoshinobu Inoue 		}
2767d56d374SYoshinobu Inoue 	}
2777d56d374SYoshinobu Inoue 
278248aee62SJacques Vidrine 	rval = nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyname", default_src,
279248aee62SJacques Vidrine 			  name, af, errp);
280248aee62SJacques Vidrine 	return (rval == NS_SUCCESS) ? hp : NULL;
2817d56d374SYoshinobu Inoue }
2827d56d374SYoshinobu Inoue 
283e6f35403SYoshinobu Inoue /* getipnodebyname() internal routine for multiple query(PF_UNSPEC) support. */
2847d56d374SYoshinobu Inoue struct hostent *
285e6f35403SYoshinobu Inoue _getipnodebyname_multi(const char *name, int af, int flags, int *errp)
2867d56d374SYoshinobu Inoue {
2877d56d374SYoshinobu Inoue 	struct hostent *hp;
2887d56d374SYoshinobu Inoue 	union inx_addr addrbuf;
2897d56d374SYoshinobu Inoue 
290e6f35403SYoshinobu Inoue 	/* XXX: PF_UNSPEC is only supposed to be passed from getaddrinfo() */
2917d56d374SYoshinobu Inoue 	if (af != AF_INET
2927d56d374SYoshinobu Inoue #ifdef INET6
2937d56d374SYoshinobu Inoue 	    && af != AF_INET6
2947d56d374SYoshinobu Inoue #endif
295e6f35403SYoshinobu Inoue 	    && af != PF_UNSPEC
2967d56d374SYoshinobu Inoue 		)
2977d56d374SYoshinobu Inoue 	{
2987d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
2997d56d374SYoshinobu Inoue 		return NULL;
3007d56d374SYoshinobu Inoue 	}
3017d56d374SYoshinobu Inoue 
3027d56d374SYoshinobu Inoue #ifdef INET6
3037d56d374SYoshinobu Inoue 	/* special case for literal address */
3047d56d374SYoshinobu Inoue 	if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
3057d56d374SYoshinobu Inoue 		if (af != AF_INET6) {
3067d56d374SYoshinobu Inoue 			*errp = HOST_NOT_FOUND;
3077d56d374SYoshinobu Inoue 			return NULL;
3087d56d374SYoshinobu Inoue 		}
3097d56d374SYoshinobu Inoue 		return _hpaddr(af, name, &addrbuf, errp);
3107d56d374SYoshinobu Inoue 	}
3117d56d374SYoshinobu Inoue #endif
312be26adb5SYoshinobu Inoue 	if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) {
3137d56d374SYoshinobu Inoue 		if (af != AF_INET) {
3147d56d374SYoshinobu Inoue 			if (MAPADDRENABLED(flags)) {
3157d56d374SYoshinobu Inoue 				MAPADDR(&addrbuf, &addrbuf.in_addr);
3167d56d374SYoshinobu Inoue 			} else {
3177d56d374SYoshinobu Inoue 				*errp = HOST_NOT_FOUND;
3187d56d374SYoshinobu Inoue 				return NULL;
3197d56d374SYoshinobu Inoue 			}
3207d56d374SYoshinobu Inoue 		}
3217d56d374SYoshinobu Inoue 		return _hpaddr(af, name, &addrbuf, errp);
3227d56d374SYoshinobu Inoue 	}
3237d56d374SYoshinobu Inoue 
3247d56d374SYoshinobu Inoue 	*errp = HOST_NOT_FOUND;
3257d56d374SYoshinobu Inoue 	hp = _ghbyname(name, af, flags, errp);
3267d56d374SYoshinobu Inoue 
3277d56d374SYoshinobu Inoue #ifdef INET6
3287d56d374SYoshinobu Inoue 	if (af == AF_INET6
3297d56d374SYoshinobu Inoue 	&&  ((flags & AI_ALL) || hp == NULL)
3307d56d374SYoshinobu Inoue 	&&  (MAPADDRENABLED(flags))) {
3317d56d374SYoshinobu Inoue 		struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp);
3327d56d374SYoshinobu Inoue 		if (hp == NULL)
3337d56d374SYoshinobu Inoue 			hp = _hpmapv6(hp2, errp);
3347d56d374SYoshinobu Inoue 		else {
3357d56d374SYoshinobu Inoue 			if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) {
3367d56d374SYoshinobu Inoue 				freehostent(hp2);
3377d56d374SYoshinobu Inoue 				hp2 = NULL;
3387d56d374SYoshinobu Inoue 			}
3397d56d374SYoshinobu Inoue 			hp = _hpmerge(hp, hp2, errp);
3407d56d374SYoshinobu Inoue 		}
3417d56d374SYoshinobu Inoue 	}
3427d56d374SYoshinobu Inoue #endif
3437d56d374SYoshinobu Inoue 	return _hpsort(hp);
3447d56d374SYoshinobu Inoue }
3457d56d374SYoshinobu Inoue 
3467d56d374SYoshinobu Inoue struct hostent *
347e6f35403SYoshinobu Inoue getipnodebyname(const char *name, int af, int flags, int *errp)
348e6f35403SYoshinobu Inoue {
349e6f35403SYoshinobu Inoue 	if (af != AF_INET
350e6f35403SYoshinobu Inoue #ifdef INET6
351e6f35403SYoshinobu Inoue 	    && af != AF_INET6
352e6f35403SYoshinobu Inoue #endif
353e6f35403SYoshinobu Inoue 		)
354e6f35403SYoshinobu Inoue 	{
355e6f35403SYoshinobu Inoue 		*errp = NO_RECOVERY;
356e6f35403SYoshinobu Inoue 		return NULL;
357e6f35403SYoshinobu Inoue 	}
358e6f35403SYoshinobu Inoue 	return(_getipnodebyname_multi(name, af ,flags, errp));
359e6f35403SYoshinobu Inoue }
360e6f35403SYoshinobu Inoue 
361e6f35403SYoshinobu Inoue struct hostent *
3627d56d374SYoshinobu Inoue getipnodebyaddr(const void *src, size_t len, int af, int *errp)
3637d56d374SYoshinobu Inoue {
3647d56d374SYoshinobu Inoue 	struct hostent *hp;
365cb0600bdSJacques Vidrine 	int rval;
3667d56d374SYoshinobu Inoue #ifdef INET6
3677d56d374SYoshinobu Inoue 	struct in6_addr addrbuf;
3687d56d374SYoshinobu Inoue #else
3697d56d374SYoshinobu Inoue 	struct in_addr addrbuf;
3707d56d374SYoshinobu Inoue #endif
3717d56d374SYoshinobu Inoue 
372248aee62SJacques Vidrine 	static const ns_dtab dtab[] = {
373248aee62SJacques Vidrine 		NS_FILES_CB(_files_ghbyaddr, NULL)
374248aee62SJacques Vidrine 		{ NSSRC_DNS, _dns_ghbyaddr, NULL },
375248aee62SJacques Vidrine 		NS_NIS_CB(_nis_ghbyaddr, NULL)
376248aee62SJacques Vidrine #ifdef ICMPNL
377248aee62SJacques Vidrine 		{ NSSRC_ICMP, _icmp_ghbyaddr, NULL },
378248aee62SJacques Vidrine #endif
379248aee62SJacques Vidrine 		{ 0 }
380248aee62SJacques Vidrine 	};
381248aee62SJacques Vidrine 
3827d56d374SYoshinobu Inoue 	*errp = HOST_NOT_FOUND;
3837d56d374SYoshinobu Inoue 
3847d56d374SYoshinobu Inoue 	switch (af) {
3857d56d374SYoshinobu Inoue 	case AF_INET:
3867d56d374SYoshinobu Inoue 		if (len != sizeof(struct in_addr)) {
3877d56d374SYoshinobu Inoue 			*errp = NO_RECOVERY;
3887d56d374SYoshinobu Inoue 			return NULL;
3897d56d374SYoshinobu Inoue 		}
3907d56d374SYoshinobu Inoue 		if ((long)src & ~(sizeof(struct in_addr) - 1)) {
3917d56d374SYoshinobu Inoue 			memcpy(&addrbuf, src, len);
3927d56d374SYoshinobu Inoue 			src = &addrbuf;
3937d56d374SYoshinobu Inoue 		}
3947d56d374SYoshinobu Inoue 		if (((struct in_addr *)src)->s_addr == 0)
3957d56d374SYoshinobu Inoue 			return NULL;
3967d56d374SYoshinobu Inoue 		break;
3977d56d374SYoshinobu Inoue #ifdef INET6
3987d56d374SYoshinobu Inoue 	case AF_INET6:
3997d56d374SYoshinobu Inoue 		if (len != sizeof(struct in6_addr)) {
4007d56d374SYoshinobu Inoue 			*errp = NO_RECOVERY;
4017d56d374SYoshinobu Inoue 			return NULL;
4027d56d374SYoshinobu Inoue 		}
4037d56d374SYoshinobu Inoue 		if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) {	/*XXX*/
4047d56d374SYoshinobu Inoue 			memcpy(&addrbuf, src, len);
4057d56d374SYoshinobu Inoue 			src = &addrbuf;
4067d56d374SYoshinobu Inoue 		}
4073d670abcSYoshinobu Inoue 		if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src))
4083d670abcSYoshinobu Inoue 			return NULL;
4097d56d374SYoshinobu Inoue 		if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)
4107d56d374SYoshinobu Inoue 		||  IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) {
4117d56d374SYoshinobu Inoue 			src = (char *)src +
4127d56d374SYoshinobu Inoue 			    (sizeof(struct in6_addr) - sizeof(struct in_addr));
4137d56d374SYoshinobu Inoue 			af = AF_INET;
4147d56d374SYoshinobu Inoue 			len = sizeof(struct in_addr);
4157d56d374SYoshinobu Inoue 		}
4167d56d374SYoshinobu Inoue 		break;
4177d56d374SYoshinobu Inoue #endif
4187d56d374SYoshinobu Inoue 	default:
4197d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
4207d56d374SYoshinobu Inoue 		return NULL;
4217d56d374SYoshinobu Inoue 	}
4227d56d374SYoshinobu Inoue 
423248aee62SJacques Vidrine 	rval = nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyaddr", default_src,
424248aee62SJacques Vidrine 			  src, len, af, errp);
425248aee62SJacques Vidrine 	return (rval == NS_SUCCESS) ? hp : NULL;
4267d56d374SYoshinobu Inoue }
4277d56d374SYoshinobu Inoue 
4287d56d374SYoshinobu Inoue void
4297d56d374SYoshinobu Inoue freehostent(struct hostent *ptr)
4307d56d374SYoshinobu Inoue {
4317d56d374SYoshinobu Inoue 	free(ptr);
4327d56d374SYoshinobu Inoue }
4337d56d374SYoshinobu Inoue 
4347d56d374SYoshinobu Inoue #if 0
4357d56d374SYoshinobu Inoue 
4367d56d374SYoshinobu Inoue /* XXX: should be deprecated */
4377d56d374SYoshinobu Inoue struct hostent *
4387d56d374SYoshinobu Inoue getnodebyname(const char *name, int af, int flags)
4397d56d374SYoshinobu Inoue {
4407d56d374SYoshinobu Inoue 	return getipnodebyname(name, af, flags, &h_errno);
4417d56d374SYoshinobu Inoue }
4427d56d374SYoshinobu Inoue 
4437d56d374SYoshinobu Inoue #ifdef __warn_references
4447d56d374SYoshinobu Inoue __warn_references(getnodebyname,
4457d56d374SYoshinobu Inoue 	"warning: getnodebyname() deprecated, "
4467d56d374SYoshinobu Inoue 	"should use getaddrinfo() or getipnodebyname()");
4477d56d374SYoshinobu Inoue #endif
4487d56d374SYoshinobu Inoue 
4497d56d374SYoshinobu Inoue struct hostent *
4507d56d374SYoshinobu Inoue getnodebyaddr(const void *src, size_t len, int af)
4517d56d374SYoshinobu Inoue {
4527d56d374SYoshinobu Inoue 	return getipnodebyaddr(src, len, af, &h_errno);
4537d56d374SYoshinobu Inoue }
4547d56d374SYoshinobu Inoue 
4557d56d374SYoshinobu Inoue #ifdef __warn_references
4567d56d374SYoshinobu Inoue __warn_references(getnodebyaddr,
4577d56d374SYoshinobu Inoue 	"warning: getnodebyaddr() deprecated, "
4587d56d374SYoshinobu Inoue 	"should use getnameinfo() or getipnodebyaddr()");
4597d56d374SYoshinobu Inoue #endif
4607d56d374SYoshinobu Inoue 
4617d56d374SYoshinobu Inoue #endif
4627d56d374SYoshinobu Inoue 
4637d56d374SYoshinobu Inoue /*
4647d56d374SYoshinobu Inoue  * Private utility functions
4657d56d374SYoshinobu Inoue  */
4667d56d374SYoshinobu Inoue 
4677d56d374SYoshinobu Inoue /*
4687d56d374SYoshinobu Inoue  * _hpcopy: allocate and copy hostent structure
4697d56d374SYoshinobu Inoue  */
4707d56d374SYoshinobu Inoue static struct hostent *
4717d56d374SYoshinobu Inoue _hpcopy(struct hostent *hp, int *errp)
4727d56d374SYoshinobu Inoue {
4737d56d374SYoshinobu Inoue 	struct hostent *nhp;
4747d56d374SYoshinobu Inoue 	char *cp, **pp;
4757d56d374SYoshinobu Inoue 	int size, addrsize;
4767d56d374SYoshinobu Inoue 	int nalias = 0, naddr = 0;
4777d56d374SYoshinobu Inoue 	int al_off;
4787d56d374SYoshinobu Inoue 	int i;
4797d56d374SYoshinobu Inoue 
4807d56d374SYoshinobu Inoue 	if (hp == NULL)
4817d56d374SYoshinobu Inoue 		return hp;
4827d56d374SYoshinobu Inoue 
4837d56d374SYoshinobu Inoue 	/* count size to be allocated */
4847d56d374SYoshinobu Inoue 	size = sizeof(struct hostent);
48505c36511SHajimu UMEMOTO 	if (hp->h_name != NULL)
4867d56d374SYoshinobu Inoue 		size += strlen(hp->h_name) + 1;
4877d56d374SYoshinobu Inoue 	if ((pp = hp->h_aliases) != NULL) {
4887d56d374SYoshinobu Inoue 		for (i = 0; *pp != NULL; i++, pp++) {
4897d56d374SYoshinobu Inoue 			if (**pp != '\0') {
4907d56d374SYoshinobu Inoue 				size += strlen(*pp) + 1;
4917d56d374SYoshinobu Inoue 				nalias++;
4927d56d374SYoshinobu Inoue 			}
4937d56d374SYoshinobu Inoue 		}
4947d56d374SYoshinobu Inoue 	}
4957d56d374SYoshinobu Inoue 	/* adjust alignment */
4967d56d374SYoshinobu Inoue 	size = ALIGN(size);
4977d56d374SYoshinobu Inoue 	al_off = size;
4987d56d374SYoshinobu Inoue 	size += sizeof(char *) * (nalias + 1);
4997d56d374SYoshinobu Inoue 	addrsize = ALIGN(hp->h_length);
5007d56d374SYoshinobu Inoue 	if ((pp = hp->h_addr_list) != NULL) {
5017d56d374SYoshinobu Inoue 		while (*pp++ != NULL)
5027d56d374SYoshinobu Inoue 			naddr++;
5037d56d374SYoshinobu Inoue 	}
5047d56d374SYoshinobu Inoue 	size += addrsize * naddr;
5057d56d374SYoshinobu Inoue 	size += sizeof(char *) * (naddr + 1);
5067d56d374SYoshinobu Inoue 
5077d56d374SYoshinobu Inoue 	/* copy */
5087d56d374SYoshinobu Inoue 	if ((nhp = (struct hostent *)malloc(size)) == NULL) {
5097d56d374SYoshinobu Inoue 		*errp = TRY_AGAIN;
5107d56d374SYoshinobu Inoue 		return NULL;
5117d56d374SYoshinobu Inoue 	}
5127d56d374SYoshinobu Inoue 	cp = (char *)&nhp[1];
51305c36511SHajimu UMEMOTO 	if (hp->h_name != NULL) {
5147d56d374SYoshinobu Inoue 		nhp->h_name = cp;
5157d56d374SYoshinobu Inoue 		strcpy(cp, hp->h_name);
5167d56d374SYoshinobu Inoue 		cp += strlen(cp) + 1;
5177d56d374SYoshinobu Inoue 	} else
5187d56d374SYoshinobu Inoue 		nhp->h_name = NULL;
5197d56d374SYoshinobu Inoue 	nhp->h_aliases = (char **)((char *)nhp + al_off);
5207d56d374SYoshinobu Inoue 	if ((pp = hp->h_aliases) != NULL) {
5217d56d374SYoshinobu Inoue 		for (i = 0; *pp != NULL; pp++) {
5227d56d374SYoshinobu Inoue 			if (**pp != '\0') {
5237d56d374SYoshinobu Inoue 				nhp->h_aliases[i++] = cp;
5247d56d374SYoshinobu Inoue 				strcpy(cp, *pp);
5257d56d374SYoshinobu Inoue 				cp += strlen(cp) + 1;
5267d56d374SYoshinobu Inoue 			}
5277d56d374SYoshinobu Inoue 		}
5287d56d374SYoshinobu Inoue 	}
5297d56d374SYoshinobu Inoue 	nhp->h_aliases[nalias] = NULL;
5307d56d374SYoshinobu Inoue 	cp = (char *)&nhp->h_aliases[nalias + 1];
5317d56d374SYoshinobu Inoue 	nhp->h_addrtype = hp->h_addrtype;
5327d56d374SYoshinobu Inoue 	nhp->h_length = hp->h_length;
5337d56d374SYoshinobu Inoue 	nhp->h_addr_list = (char **)cp;
5347d56d374SYoshinobu Inoue 	if ((pp = hp->h_addr_list) != NULL) {
5357d56d374SYoshinobu Inoue 		cp = (char *)&nhp->h_addr_list[naddr + 1];
5367d56d374SYoshinobu Inoue 		for (i = 0; *pp != NULL; pp++) {
5377d56d374SYoshinobu Inoue 			nhp->h_addr_list[i++] = cp;
5387d56d374SYoshinobu Inoue 			memcpy(cp, *pp, hp->h_length);
5397d56d374SYoshinobu Inoue 			cp += addrsize;
5407d56d374SYoshinobu Inoue 		}
5417d56d374SYoshinobu Inoue 	}
5427d56d374SYoshinobu Inoue 	nhp->h_addr_list[naddr] = NULL;
5437d56d374SYoshinobu Inoue 	return nhp;
5447d56d374SYoshinobu Inoue }
5457d56d374SYoshinobu Inoue 
5467d56d374SYoshinobu Inoue /*
5477d56d374SYoshinobu Inoue  * _hpaddr: construct hostent structure with one address
5487d56d374SYoshinobu Inoue  */
5497d56d374SYoshinobu Inoue static struct hostent *
5507d56d374SYoshinobu Inoue _hpaddr(int af, const char *name, void *addr, int *errp)
5517d56d374SYoshinobu Inoue {
5527d56d374SYoshinobu Inoue 	struct hostent *hp, hpbuf;
5537d56d374SYoshinobu Inoue 	char *addrs[2];
5547d56d374SYoshinobu Inoue 
5557d56d374SYoshinobu Inoue 	hp = &hpbuf;
5567d56d374SYoshinobu Inoue 	hp->h_name = (char *)name;
5577d56d374SYoshinobu Inoue 	hp->h_aliases = NULL;
5587d56d374SYoshinobu Inoue 	hp->h_addrtype = af;
5597d56d374SYoshinobu Inoue 	hp->h_length = ADDRLEN(af);
5607d56d374SYoshinobu Inoue 	hp->h_addr_list = addrs;
5617d56d374SYoshinobu Inoue 	addrs[0] = (char *)addr;
5627d56d374SYoshinobu Inoue 	addrs[1] = NULL;
5637d56d374SYoshinobu Inoue 	return _hpcopy(hp, errp);
5647d56d374SYoshinobu Inoue }
5657d56d374SYoshinobu Inoue 
5667d56d374SYoshinobu Inoue /*
5677d56d374SYoshinobu Inoue  * _hpmerge: merge 2 hostent structure, arguments will be freed
5687d56d374SYoshinobu Inoue  */
5697d56d374SYoshinobu Inoue static struct hostent *
5707d56d374SYoshinobu Inoue _hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp)
5717d56d374SYoshinobu Inoue {
5727d56d374SYoshinobu Inoue 	int i, j;
5737d56d374SYoshinobu Inoue 	int naddr, nalias;
5747d56d374SYoshinobu Inoue 	char **pp;
5757d56d374SYoshinobu Inoue 	struct hostent *hp, hpbuf;
5767d56d374SYoshinobu Inoue 	char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1];
5777d56d374SYoshinobu Inoue 	union inx_addr addrbuf[MAXADDRS];
5787d56d374SYoshinobu Inoue 
5797d56d374SYoshinobu Inoue 	if (hp1 == NULL)
5807d56d374SYoshinobu Inoue 		return hp2;
5817d56d374SYoshinobu Inoue 	if (hp2 == NULL)
5827d56d374SYoshinobu Inoue 		return hp1;
5837d56d374SYoshinobu Inoue 
5847d56d374SYoshinobu Inoue #define	HP(i)	(i == 1 ? hp1 : hp2)
5857d56d374SYoshinobu Inoue 	hp = &hpbuf;
5867d56d374SYoshinobu Inoue 	hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name);
5877d56d374SYoshinobu Inoue 	hp->h_aliases = aliases;
5887d56d374SYoshinobu Inoue 	nalias = 0;
5897d56d374SYoshinobu Inoue 	for (i = 1; i <= 2; i++) {
5907d56d374SYoshinobu Inoue 		if ((pp = HP(i)->h_aliases) == NULL)
5917d56d374SYoshinobu Inoue 			continue;
5927d56d374SYoshinobu Inoue 		for (; nalias < MAXALIASES && *pp != NULL; pp++) {
5937d56d374SYoshinobu Inoue 			/* check duplicates */
5947d56d374SYoshinobu Inoue 			for (j = 0; j < nalias; j++)
5957d56d374SYoshinobu Inoue 				if (strcasecmp(*pp, aliases[j]) == 0)
5967d56d374SYoshinobu Inoue 					break;
5977d56d374SYoshinobu Inoue 			if (j == nalias)
5987d56d374SYoshinobu Inoue 				aliases[nalias++] = *pp;
5997d56d374SYoshinobu Inoue 		}
6007d56d374SYoshinobu Inoue 	}
6017d56d374SYoshinobu Inoue 	aliases[nalias] = NULL;
6027d56d374SYoshinobu Inoue #ifdef INET6
6037d56d374SYoshinobu Inoue 	if (hp1->h_length != hp2->h_length) {
6047d56d374SYoshinobu Inoue 		hp->h_addrtype = AF_INET6;
6057d56d374SYoshinobu Inoue 		hp->h_length = sizeof(struct in6_addr);
6067d56d374SYoshinobu Inoue 	} else {
6077d56d374SYoshinobu Inoue #endif
6087d56d374SYoshinobu Inoue 		hp->h_addrtype = hp1->h_addrtype;
6097d56d374SYoshinobu Inoue 		hp->h_length = hp1->h_length;
6107d56d374SYoshinobu Inoue #ifdef INET6
6117d56d374SYoshinobu Inoue 	}
6127d56d374SYoshinobu Inoue #endif
6137d56d374SYoshinobu Inoue 	hp->h_addr_list = addrs;
6147d56d374SYoshinobu Inoue 	naddr = 0;
6157d56d374SYoshinobu Inoue 	for (i = 1; i <= 2; i++) {
6167d56d374SYoshinobu Inoue 		if ((pp = HP(i)->h_addr_list) == NULL)
6177d56d374SYoshinobu Inoue 			continue;
6187d56d374SYoshinobu Inoue 		if (HP(i)->h_length == hp->h_length) {
6197d56d374SYoshinobu Inoue 			while (naddr < MAXADDRS && *pp != NULL)
6207d56d374SYoshinobu Inoue 				addrs[naddr++] = *pp++;
6217d56d374SYoshinobu Inoue 		} else {
6227d56d374SYoshinobu Inoue 			/* copy IPv4 addr as mapped IPv6 addr */
6237d56d374SYoshinobu Inoue 			while (naddr < MAXADDRS && *pp != NULL) {
6247d56d374SYoshinobu Inoue 				MAPADDR(&addrbuf[naddr], *pp++);
6257d56d374SYoshinobu Inoue 				addrs[naddr] = (char *)&addrbuf[naddr];
6267d56d374SYoshinobu Inoue 				naddr++;
6277d56d374SYoshinobu Inoue 			}
6287d56d374SYoshinobu Inoue 		}
6297d56d374SYoshinobu Inoue 	}
6307d56d374SYoshinobu Inoue 	addrs[naddr] = NULL;
6317d56d374SYoshinobu Inoue 	hp = _hpcopy(hp, errp);
6327d56d374SYoshinobu Inoue 	freehostent(hp1);
6337d56d374SYoshinobu Inoue 	freehostent(hp2);
6347d56d374SYoshinobu Inoue 	return hp;
6357d56d374SYoshinobu Inoue }
6367d56d374SYoshinobu Inoue 
6377d56d374SYoshinobu Inoue /*
6387d56d374SYoshinobu Inoue  * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses
6397d56d374SYoshinobu Inoue  */
6407d56d374SYoshinobu Inoue #ifdef INET6
6417d56d374SYoshinobu Inoue static struct hostent *
6427d56d374SYoshinobu Inoue _hpmapv6(struct hostent *hp, int *errp)
6437d56d374SYoshinobu Inoue {
6447d56d374SYoshinobu Inoue 	struct hostent *hp6;
6457d56d374SYoshinobu Inoue 
6467d56d374SYoshinobu Inoue 	if (hp == NULL)
6477d56d374SYoshinobu Inoue 		return NULL;
6487d56d374SYoshinobu Inoue 	if (hp->h_addrtype == AF_INET6)
6497d56d374SYoshinobu Inoue 		return hp;
6507d56d374SYoshinobu Inoue 
6517d56d374SYoshinobu Inoue 	/* make dummy hostent to convert IPv6 address */
6527d56d374SYoshinobu Inoue 	if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) {
6537d56d374SYoshinobu Inoue 		*errp = TRY_AGAIN;
6547d56d374SYoshinobu Inoue 		return NULL;
6557d56d374SYoshinobu Inoue 	}
6567d56d374SYoshinobu Inoue 	hp6->h_name = NULL;
6577d56d374SYoshinobu Inoue 	hp6->h_aliases = NULL;
6587d56d374SYoshinobu Inoue 	hp6->h_addrtype = AF_INET6;
6597d56d374SYoshinobu Inoue 	hp6->h_length = sizeof(struct in6_addr);
6607d56d374SYoshinobu Inoue 	hp6->h_addr_list = NULL;
6617d56d374SYoshinobu Inoue 	return _hpmerge(hp6, hp, errp);
6627d56d374SYoshinobu Inoue }
6637d56d374SYoshinobu Inoue #endif
6647d56d374SYoshinobu Inoue 
6657d56d374SYoshinobu Inoue /*
6667d56d374SYoshinobu Inoue  * _hpsort: sort address by sortlist
6677d56d374SYoshinobu Inoue  */
6687d56d374SYoshinobu Inoue static struct hostent *
6697d56d374SYoshinobu Inoue _hpsort(struct hostent *hp)
6707d56d374SYoshinobu Inoue {
6717d56d374SYoshinobu Inoue 	int i, j, n;
6727d56d374SYoshinobu Inoue 	u_char *ap, *sp, *mp, **pp;
6737d56d374SYoshinobu Inoue 	char t;
6747d56d374SYoshinobu Inoue 	char order[MAXADDRS];
6757d56d374SYoshinobu Inoue 	int nsort = _res.nsort;
6767d56d374SYoshinobu Inoue 
6777d56d374SYoshinobu Inoue 	if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0)
6787d56d374SYoshinobu Inoue 		return hp;
6797d56d374SYoshinobu Inoue 	for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) {
6807d56d374SYoshinobu Inoue 		for (j = 0; j < nsort; j++) {
6817d56d374SYoshinobu Inoue #ifdef INET6
6827d56d374SYoshinobu Inoue 			if (_res_ext.sort_list[j].af != hp->h_addrtype)
6837d56d374SYoshinobu Inoue 				continue;
6847d56d374SYoshinobu Inoue 			sp = (u_char *)&_res_ext.sort_list[j].addr;
6857d56d374SYoshinobu Inoue 			mp = (u_char *)&_res_ext.sort_list[j].mask;
6867d56d374SYoshinobu Inoue #else
6877d56d374SYoshinobu Inoue 			sp = (u_char *)&_res.sort_list[j].addr;
6887d56d374SYoshinobu Inoue 			mp = (u_char *)&_res.sort_list[j].mask;
6897d56d374SYoshinobu Inoue #endif
6907d56d374SYoshinobu Inoue 			for (n = 0; n < hp->h_length; n++) {
6917d56d374SYoshinobu Inoue 				if ((ap[n] & mp[n]) != sp[n])
6927d56d374SYoshinobu Inoue 					break;
6937d56d374SYoshinobu Inoue 			}
6947d56d374SYoshinobu Inoue 			if (n == hp->h_length)
6957d56d374SYoshinobu Inoue 				break;
6967d56d374SYoshinobu Inoue 		}
6977d56d374SYoshinobu Inoue 		order[i] = j;
6987d56d374SYoshinobu Inoue 	}
6997d56d374SYoshinobu Inoue 	n = i;
7007d56d374SYoshinobu Inoue 	pp = (u_char **)hp->h_addr_list;
7017d56d374SYoshinobu Inoue 	for (i = 0; i < n - 1; i++) {
7027d56d374SYoshinobu Inoue 		for (j = i + 1; j < n; j++) {
7037d56d374SYoshinobu Inoue 			if (order[i] > order[j]) {
7047d56d374SYoshinobu Inoue 				ap = pp[i];
7057d56d374SYoshinobu Inoue 				pp[i] = pp[j];
7067d56d374SYoshinobu Inoue 				pp[j] = ap;
7077d56d374SYoshinobu Inoue 				t = order[i];
7087d56d374SYoshinobu Inoue 				order[i] = order[j];
7097d56d374SYoshinobu Inoue 				order[j] = t;
7107d56d374SYoshinobu Inoue 			}
7117d56d374SYoshinobu Inoue 		}
7127d56d374SYoshinobu Inoue 	}
7137d56d374SYoshinobu Inoue 	return hp;
7147d56d374SYoshinobu Inoue }
7157d56d374SYoshinobu Inoue 
7167d56d374SYoshinobu Inoue static char *
7177d56d374SYoshinobu Inoue _hgetword(char **pp)
7187d56d374SYoshinobu Inoue {
7197d56d374SYoshinobu Inoue 	char c, *p, *ret;
7207d56d374SYoshinobu Inoue 	const char *sp;
7217d56d374SYoshinobu Inoue 	static const char sep[] = "# \t\n";
7227d56d374SYoshinobu Inoue 
7237d56d374SYoshinobu Inoue 	ret = NULL;
7247d56d374SYoshinobu Inoue 	for (p = *pp; (c = *p) != '\0'; p++) {
7257d56d374SYoshinobu Inoue 		for (sp = sep; *sp != '\0'; sp++) {
7267d56d374SYoshinobu Inoue 			if (c == *sp)
7277d56d374SYoshinobu Inoue 				break;
7287d56d374SYoshinobu Inoue 		}
7297d56d374SYoshinobu Inoue 		if (c == '#')
7307d56d374SYoshinobu Inoue 			p[1] = '\0';	/* ignore rest of line */
7317d56d374SYoshinobu Inoue 		if (ret == NULL) {
7327d56d374SYoshinobu Inoue 			if (*sp == '\0')
7337d56d374SYoshinobu Inoue 				ret = p;
7347d56d374SYoshinobu Inoue 		} else {
7357d56d374SYoshinobu Inoue 			if (*sp != '\0') {
7367d56d374SYoshinobu Inoue 				*p++ = '\0';
7377d56d374SYoshinobu Inoue 				break;
7387d56d374SYoshinobu Inoue 			}
7397d56d374SYoshinobu Inoue 		}
7407d56d374SYoshinobu Inoue 	}
7417d56d374SYoshinobu Inoue 	*pp = p;
7427d56d374SYoshinobu Inoue 	if (ret == NULL || *ret == '\0')
7437d56d374SYoshinobu Inoue 		return NULL;
7447d56d374SYoshinobu Inoue 	return ret;
7457d56d374SYoshinobu Inoue }
7467d56d374SYoshinobu Inoue 
7477d56d374SYoshinobu Inoue /*
7487d56d374SYoshinobu Inoue  * FILES (/etc/hosts)
7497d56d374SYoshinobu Inoue  */
7507d56d374SYoshinobu Inoue 
7517d56d374SYoshinobu Inoue static FILE *
7527d56d374SYoshinobu Inoue _files_open(int *errp)
7537d56d374SYoshinobu Inoue {
7547d56d374SYoshinobu Inoue 	FILE *fp;
7557d56d374SYoshinobu Inoue 	fp = fopen(_PATH_HOSTS, "r");
7567d56d374SYoshinobu Inoue 	if (fp == NULL)
7577d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
7587d56d374SYoshinobu Inoue 	return fp;
7597d56d374SYoshinobu Inoue }
7607d56d374SYoshinobu Inoue 
761248aee62SJacques Vidrine static int
762248aee62SJacques Vidrine _files_ghbyname(void *rval, void *cb_data, va_list ap)
7637d56d374SYoshinobu Inoue {
764248aee62SJacques Vidrine 	const char *name;
765248aee62SJacques Vidrine 	int af;
766248aee62SJacques Vidrine 	int *errp;
7677d56d374SYoshinobu Inoue 	int match, nalias;
7687d56d374SYoshinobu Inoue 	char *p, *line, *addrstr, *cname;
7697d56d374SYoshinobu Inoue 	FILE *fp;
7707d56d374SYoshinobu Inoue 	struct hostent *rethp, *hp, hpbuf;
7717d56d374SYoshinobu Inoue 	char *aliases[MAXALIASES + 1], *addrs[2];
7727d56d374SYoshinobu Inoue 	union inx_addr addrbuf;
7737d56d374SYoshinobu Inoue 	char buf[BUFSIZ];
774cb0600bdSJacques Vidrine 	int af0;
7757d56d374SYoshinobu Inoue 
776248aee62SJacques Vidrine 	name = va_arg(ap, const char *);
777248aee62SJacques Vidrine 	af = va_arg(ap, int);
778248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
779248aee62SJacques Vidrine 
780248aee62SJacques Vidrine 	*(struct hostent **)rval = NULL;
781248aee62SJacques Vidrine 
7827d56d374SYoshinobu Inoue 	if ((fp = _files_open(errp)) == NULL)
783248aee62SJacques Vidrine 		return NS_UNAVAIL;
7847d56d374SYoshinobu Inoue 	rethp = hp = NULL;
7857d56d374SYoshinobu Inoue 
786cb0600bdSJacques Vidrine 	af0 = af;
7877d56d374SYoshinobu Inoue 	while (fgets(buf, sizeof(buf), fp)) {
7887d56d374SYoshinobu Inoue 		line = buf;
7897d56d374SYoshinobu Inoue 		if ((addrstr = _hgetword(&line)) == NULL
7907d56d374SYoshinobu Inoue 		||  (cname = _hgetword(&line)) == NULL)
7917d56d374SYoshinobu Inoue 			continue;
7927d56d374SYoshinobu Inoue 		match = (strcasecmp(cname, name) == 0);
7937d56d374SYoshinobu Inoue 		nalias = 0;
7947d56d374SYoshinobu Inoue 		while ((p = _hgetword(&line)) != NULL) {
7957d56d374SYoshinobu Inoue 			if (!match)
7967d56d374SYoshinobu Inoue 				match = (strcasecmp(p, name) == 0);
7977d56d374SYoshinobu Inoue 			if (nalias < MAXALIASES)
7987d56d374SYoshinobu Inoue 				aliases[nalias++] = p;
7997d56d374SYoshinobu Inoue 		}
8007d56d374SYoshinobu Inoue 		if (!match)
8017d56d374SYoshinobu Inoue 			continue;
802e6f35403SYoshinobu Inoue 		switch (af0) {
803e6f35403SYoshinobu Inoue 		case AF_INET:
804e6f35403SYoshinobu Inoue 			if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
805e6f35403SYoshinobu Inoue 			    != 1) {
8067d56d374SYoshinobu Inoue 				*errp = NO_DATA;	/* name found */
8077d56d374SYoshinobu Inoue 				continue;
8087d56d374SYoshinobu Inoue 			}
809e6f35403SYoshinobu Inoue 			af = af0;
810e6f35403SYoshinobu Inoue 			break;
811e6f35403SYoshinobu Inoue #ifdef INET6
812e6f35403SYoshinobu Inoue 		case AF_INET6:
813e6f35403SYoshinobu Inoue 			if (inet_pton(af, addrstr, &addrbuf) != 1) {
814e6f35403SYoshinobu Inoue 				*errp = NO_DATA;	/* name found */
815e6f35403SYoshinobu Inoue 				continue;
816e6f35403SYoshinobu Inoue 			}
817e6f35403SYoshinobu Inoue 			af = af0;
818e6f35403SYoshinobu Inoue 			break;
819e6f35403SYoshinobu Inoue #endif
820e6f35403SYoshinobu Inoue 		case AF_UNSPEC:
821e6f35403SYoshinobu Inoue 			if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
822e6f35403SYoshinobu Inoue 			    == 1) {
823e6f35403SYoshinobu Inoue 				af = AF_INET;
824e6f35403SYoshinobu Inoue 				break;
825e6f35403SYoshinobu Inoue 			}
826e6f35403SYoshinobu Inoue #ifdef INET6
827e6f35403SYoshinobu Inoue 			if (inet_pton(AF_INET6, addrstr, &addrbuf) == 1) {
828e6f35403SYoshinobu Inoue 				af = AF_INET6;
829e6f35403SYoshinobu Inoue 				break;
830e6f35403SYoshinobu Inoue 			}
831e6f35403SYoshinobu Inoue #endif
832e6f35403SYoshinobu Inoue 			*errp = NO_DATA;	/* name found */
833e6f35403SYoshinobu Inoue 			continue;
834e6f35403SYoshinobu Inoue 			/* NOTREACHED */
835e6f35403SYoshinobu Inoue 		}
8367d56d374SYoshinobu Inoue 		hp = &hpbuf;
8377d56d374SYoshinobu Inoue 		hp->h_name = cname;
8387d56d374SYoshinobu Inoue 		hp->h_aliases = aliases;
8397d56d374SYoshinobu Inoue 		aliases[nalias] = NULL;
8407d56d374SYoshinobu Inoue 		hp->h_addrtype = af;
8417d56d374SYoshinobu Inoue 		hp->h_length = ADDRLEN(af);
8427d56d374SYoshinobu Inoue 		hp->h_addr_list = addrs;
8437d56d374SYoshinobu Inoue 		addrs[0] = (char *)&addrbuf;
8447d56d374SYoshinobu Inoue 		addrs[1] = NULL;
8457d56d374SYoshinobu Inoue 		hp = _hpcopy(hp, errp);
8467d56d374SYoshinobu Inoue 		rethp = _hpmerge(rethp, hp, errp);
8477d56d374SYoshinobu Inoue 	}
8487d56d374SYoshinobu Inoue 	fclose(fp);
849248aee62SJacques Vidrine 	*(struct hostent **)rval = rethp;
850248aee62SJacques Vidrine 	return (rethp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
8517d56d374SYoshinobu Inoue }
8527d56d374SYoshinobu Inoue 
853248aee62SJacques Vidrine static int
854248aee62SJacques Vidrine _files_ghbyaddr(void *rval, void *cb_data, va_list ap)
8557d56d374SYoshinobu Inoue {
856248aee62SJacques Vidrine 	const void *addr;
857248aee62SJacques Vidrine 	int addrlen;
858248aee62SJacques Vidrine 	int af;
859248aee62SJacques Vidrine 	int *errp;
8607d56d374SYoshinobu Inoue 	int nalias;
8617d56d374SYoshinobu Inoue 	char *p, *line;
8627d56d374SYoshinobu Inoue 	FILE *fp;
8637d56d374SYoshinobu Inoue 	struct hostent *hp, hpbuf;
8647d56d374SYoshinobu Inoue 	char *aliases[MAXALIASES + 1], *addrs[2];
8657d56d374SYoshinobu Inoue 	union inx_addr addrbuf;
8667d56d374SYoshinobu Inoue 	char buf[BUFSIZ];
8677d56d374SYoshinobu Inoue 
868248aee62SJacques Vidrine 	addr = va_arg(ap, const void *);
869248aee62SJacques Vidrine 	addrlen = va_arg(ap, int);
870248aee62SJacques Vidrine 	af = va_arg(ap, int);
871248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
872248aee62SJacques Vidrine 
873248aee62SJacques Vidrine 	*(struct hostent**)rval = NULL;
874248aee62SJacques Vidrine 
8757d56d374SYoshinobu Inoue 	if ((fp = _files_open(errp)) == NULL)
876248aee62SJacques Vidrine 		return NS_UNAVAIL;
8777d56d374SYoshinobu Inoue 	hp = NULL;
8787d56d374SYoshinobu Inoue 	while (fgets(buf, sizeof(buf), fp)) {
8797d56d374SYoshinobu Inoue 		line = buf;
8807d56d374SYoshinobu Inoue 		if ((p = _hgetword(&line)) == NULL
881be26adb5SYoshinobu Inoue 		||  (af == AF_INET
882be26adb5SYoshinobu Inoue 		     ? inet_aton(p, (struct in_addr *)&addrbuf)
883be26adb5SYoshinobu Inoue 		     : inet_pton(af, p, &addrbuf)) != 1
8847d56d374SYoshinobu Inoue 		||  memcmp(addr, &addrbuf, addrlen) != 0
8857d56d374SYoshinobu Inoue 		||  (p = _hgetword(&line)) == NULL)
8867d56d374SYoshinobu Inoue 			continue;
8877d56d374SYoshinobu Inoue 		hp = &hpbuf;
8887d56d374SYoshinobu Inoue 		hp->h_name = p;
8897d56d374SYoshinobu Inoue 		hp->h_aliases = aliases;
8907d56d374SYoshinobu Inoue 		nalias = 0;
8917d56d374SYoshinobu Inoue 		while ((p = _hgetword(&line)) != NULL) {
8927d56d374SYoshinobu Inoue 			if (nalias < MAXALIASES)
8937d56d374SYoshinobu Inoue 				aliases[nalias++] = p;
8947d56d374SYoshinobu Inoue 		}
8957d56d374SYoshinobu Inoue 		aliases[nalias] = NULL;
8967d56d374SYoshinobu Inoue 		hp->h_addrtype = af;
8977d56d374SYoshinobu Inoue 		hp->h_length = addrlen;
8987d56d374SYoshinobu Inoue 		hp->h_addr_list = addrs;
8997d56d374SYoshinobu Inoue 		addrs[0] = (char *)&addrbuf;
9007d56d374SYoshinobu Inoue 		addrs[1] = NULL;
9017d56d374SYoshinobu Inoue 		hp = _hpcopy(hp, errp);
9027d56d374SYoshinobu Inoue 		break;
9037d56d374SYoshinobu Inoue 	}
9047d56d374SYoshinobu Inoue 	fclose(fp);
905248aee62SJacques Vidrine 	*(struct hostent **)rval = hp;
906248aee62SJacques Vidrine 	return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
9077d56d374SYoshinobu Inoue }
9087d56d374SYoshinobu Inoue 
90973b30f0cSJun-ichiro itojun Hagino #ifdef YP
91063858012SJonathan Lemon /*
91163858012SJonathan Lemon  * NIS
91263858012SJonathan Lemon  *
91363858012SJonathan Lemon  * XXX actually a hack, these are INET4 specific.
91463858012SJonathan Lemon  */
915248aee62SJacques Vidrine static int
916248aee62SJacques Vidrine _nis_ghbyname(void *rval, void *cb_data, va_list ap)
91763858012SJonathan Lemon {
918248aee62SJacques Vidrine 	const char *name;
919248aee62SJacques Vidrine 	int af;
920248aee62SJacques Vidrine 	int *errp;
92138775c5eSJonathan Lemon 	struct hostent *hp = NULL;
92263858012SJonathan Lemon 
923248aee62SJacques Vidrine 	name = va_arg(ap, const char *);
924248aee62SJacques Vidrine 	af = va_arg(ap, int);
925248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
926248aee62SJacques Vidrine 
927e6f35403SYoshinobu Inoue 	if (af == AF_UNSPEC)
928e6f35403SYoshinobu Inoue 		af = AF_INET;
92963858012SJonathan Lemon 	if (af == AF_INET) {
93063858012SJonathan Lemon 		hp = _gethostbynisname(name, af);
93163858012SJonathan Lemon 		if (hp != NULL)
93263858012SJonathan Lemon 			hp = _hpcopy(hp, errp);
93363858012SJonathan Lemon 	}
934248aee62SJacques Vidrine 
935248aee62SJacques Vidrine 	*(struct hostent **)rval = hp;
936248aee62SJacques Vidrine 	return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
93763858012SJonathan Lemon 
93863858012SJonathan Lemon }
93963858012SJonathan Lemon 
940248aee62SJacques Vidrine static int
941248aee62SJacques Vidrine _nis_ghbyaddr(void *rval, void *cb_data, va_list ap)
94263858012SJonathan Lemon {
943248aee62SJacques Vidrine 	const void *addr;
944248aee62SJacques Vidrine 	int addrlen;
945248aee62SJacques Vidrine 	int af;
946248aee62SJacques Vidrine 	int *errp;
94763858012SJonathan Lemon 	struct hostent *hp = NULL;
94863858012SJonathan Lemon 
949248aee62SJacques Vidrine 	addr = va_arg(ap, const void *);
950248aee62SJacques Vidrine 	addrlen = va_arg(ap, int);
951248aee62SJacques Vidrine 	af = va_arg(ap, int);
952248aee62SJacques Vidrine 
95363858012SJonathan Lemon 	if (af == AF_INET) {
95463858012SJonathan Lemon 		hp = _gethostbynisaddr(addr, addrlen, af);
95563858012SJonathan Lemon 		if (hp != NULL)
95663858012SJonathan Lemon 			hp = _hpcopy(hp, errp);
95763858012SJonathan Lemon 	}
958248aee62SJacques Vidrine 	*(struct hostent **)rval = hp;
959248aee62SJacques Vidrine 	return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
96063858012SJonathan Lemon }
9617d56d374SYoshinobu Inoue #endif
9627d56d374SYoshinobu Inoue 
963e6f35403SYoshinobu Inoue struct __res_type_list {
964e3975643SJake Burkholder         SLIST_ENTRY(__res_type_list) rtl_entry;
965e6f35403SYoshinobu Inoue         int     rtl_type;
966e6f35403SYoshinobu Inoue };
967e6f35403SYoshinobu Inoue 
96873b30f0cSJun-ichiro itojun Hagino #if PACKETSZ > 1024
96973b30f0cSJun-ichiro itojun Hagino #define	MAXPACKET	PACKETSZ
97073b30f0cSJun-ichiro itojun Hagino #else
97173b30f0cSJun-ichiro itojun Hagino #define	MAXPACKET	1024
97273b30f0cSJun-ichiro itojun Hagino #endif
97373b30f0cSJun-ichiro itojun Hagino 
97473b30f0cSJun-ichiro itojun Hagino typedef union {
97573b30f0cSJun-ichiro itojun Hagino 	HEADER hdr;
97673b30f0cSJun-ichiro itojun Hagino 	u_char buf[MAXPACKET];
97773b30f0cSJun-ichiro itojun Hagino } querybuf;
97873b30f0cSJun-ichiro itojun Hagino 
97973b30f0cSJun-ichiro itojun Hagino static struct hostent *getanswer __P((const querybuf *, int, const char *,
98073b30f0cSJun-ichiro itojun Hagino 	int, struct hostent *, int *));
98173b30f0cSJun-ichiro itojun Hagino 
98273b30f0cSJun-ichiro itojun Hagino /*
98373b30f0cSJun-ichiro itojun Hagino  * we don't need to take care about sorting, nor IPv4 mapped address here.
98473b30f0cSJun-ichiro itojun Hagino  */
9857d56d374SYoshinobu Inoue static struct hostent *
98673b30f0cSJun-ichiro itojun Hagino getanswer(answer, anslen, qname, qtype, template, errp)
98773b30f0cSJun-ichiro itojun Hagino 	const querybuf *answer;
988e6f35403SYoshinobu Inoue 	int anslen;
98973b30f0cSJun-ichiro itojun Hagino 	const char *qname;
990e6f35403SYoshinobu Inoue 	int qtype;
99173b30f0cSJun-ichiro itojun Hagino 	struct hostent *template;
992e6f35403SYoshinobu Inoue 	int *errp;
9937d56d374SYoshinobu Inoue {
99473b30f0cSJun-ichiro itojun Hagino 	register const HEADER *hp;
99573b30f0cSJun-ichiro itojun Hagino 	register const u_char *cp;
99673b30f0cSJun-ichiro itojun Hagino 	register int n;
99773b30f0cSJun-ichiro itojun Hagino 	const u_char *eom, *erdata;
99873b30f0cSJun-ichiro itojun Hagino 	char *bp, **ap, **hap;
99973b30f0cSJun-ichiro itojun Hagino 	int type, class, buflen, ancount, qdcount;
100073b30f0cSJun-ichiro itojun Hagino 	int haveanswer, had_error;
100173b30f0cSJun-ichiro itojun Hagino 	char tbuf[MAXDNAME];
100273b30f0cSJun-ichiro itojun Hagino 	const char *tname;
100373b30f0cSJun-ichiro itojun Hagino 	int (*name_ok) __P((const char *));
100473b30f0cSJun-ichiro itojun Hagino 	static char *h_addr_ptrs[MAXADDRS + 1];
100573b30f0cSJun-ichiro itojun Hagino 	static char *host_aliases[MAXALIASES];
100673b30f0cSJun-ichiro itojun Hagino 	static char hostbuf[8*1024];
10077d56d374SYoshinobu Inoue 
100873b30f0cSJun-ichiro itojun Hagino #define BOUNDED_INCR(x) \
100973b30f0cSJun-ichiro itojun Hagino 	do { \
101073b30f0cSJun-ichiro itojun Hagino 		cp += x; \
101173b30f0cSJun-ichiro itojun Hagino 		if (cp > eom) { \
101273b30f0cSJun-ichiro itojun Hagino 			*errp = NO_RECOVERY; \
101373b30f0cSJun-ichiro itojun Hagino 			return (NULL); \
101473b30f0cSJun-ichiro itojun Hagino 		} \
101573b30f0cSJun-ichiro itojun Hagino 	} while (0)
10167d56d374SYoshinobu Inoue 
101773b30f0cSJun-ichiro itojun Hagino #define BOUNDS_CHECK(ptr, count) \
101873b30f0cSJun-ichiro itojun Hagino 	do { \
101973b30f0cSJun-ichiro itojun Hagino 		if ((ptr) + (count) > eom) { \
102073b30f0cSJun-ichiro itojun Hagino 			*errp = NO_RECOVERY; \
102173b30f0cSJun-ichiro itojun Hagino 			return (NULL); \
102273b30f0cSJun-ichiro itojun Hagino 		} \
102373b30f0cSJun-ichiro itojun Hagino 	} while (0)
102473b30f0cSJun-ichiro itojun Hagino 
10253f587e57SKris Kennaway /* XXX do {} while (0) cannot be put here */
102673b30f0cSJun-ichiro itojun Hagino #define DNS_ASSERT(x) \
10273f587e57SKris Kennaway 	{				\
102873b30f0cSJun-ichiro itojun Hagino 		if (!(x)) {		\
102973b30f0cSJun-ichiro itojun Hagino 			cp += n;	\
103073b30f0cSJun-ichiro itojun Hagino 			continue;	\
103173b30f0cSJun-ichiro itojun Hagino 		}			\
10323f587e57SKris Kennaway 	}
103373b30f0cSJun-ichiro itojun Hagino 
10343f587e57SKris Kennaway /* XXX do {} while (0) cannot be put here */
103573b30f0cSJun-ichiro itojun Hagino #define DNS_FATAL(x) \
10363f587e57SKris Kennaway 	{				\
103773b30f0cSJun-ichiro itojun Hagino 		if (!(x)) {		\
103873b30f0cSJun-ichiro itojun Hagino 			had_error++;	\
103973b30f0cSJun-ichiro itojun Hagino 			continue;	\
104073b30f0cSJun-ichiro itojun Hagino 		}			\
10413f587e57SKris Kennaway 	}
104273b30f0cSJun-ichiro itojun Hagino 
104373b30f0cSJun-ichiro itojun Hagino 	tname = qname;
104473b30f0cSJun-ichiro itojun Hagino 	template->h_name = NULL;
104573b30f0cSJun-ichiro itojun Hagino 	eom = answer->buf + anslen;
104673b30f0cSJun-ichiro itojun Hagino 	switch (qtype) {
10477d56d374SYoshinobu Inoue 	case T_A:
10487d56d374SYoshinobu Inoue 	case T_AAAA:
104973b30f0cSJun-ichiro itojun Hagino 		name_ok = res_hnok;
105073b30f0cSJun-ichiro itojun Hagino 		break;
105173b30f0cSJun-ichiro itojun Hagino 	case T_PTR:
105273b30f0cSJun-ichiro itojun Hagino 		name_ok = res_dnok;
10537d56d374SYoshinobu Inoue 		break;
10547d56d374SYoshinobu Inoue 	default:
105573b30f0cSJun-ichiro itojun Hagino 		return (NULL);	/* XXX should be abort(); */
105673b30f0cSJun-ichiro itojun Hagino 	}
105773b30f0cSJun-ichiro itojun Hagino 	/*
105873b30f0cSJun-ichiro itojun Hagino 	 * find first satisfactory answer
105973b30f0cSJun-ichiro itojun Hagino 	 */
106073b30f0cSJun-ichiro itojun Hagino 	hp = &answer->hdr;
106173b30f0cSJun-ichiro itojun Hagino 	ancount = ntohs(hp->ancount);
106273b30f0cSJun-ichiro itojun Hagino 	qdcount = ntohs(hp->qdcount);
106373b30f0cSJun-ichiro itojun Hagino 	bp = hostbuf;
106473b30f0cSJun-ichiro itojun Hagino 	buflen = sizeof hostbuf;
106573b30f0cSJun-ichiro itojun Hagino 	cp = answer->buf;
106673b30f0cSJun-ichiro itojun Hagino 	BOUNDED_INCR(HFIXEDSZ);
106773b30f0cSJun-ichiro itojun Hagino 	if (qdcount != 1) {
106873b30f0cSJun-ichiro itojun Hagino 		*errp = NO_RECOVERY;
106973b30f0cSJun-ichiro itojun Hagino 		return (NULL);
107073b30f0cSJun-ichiro itojun Hagino 	}
107173b30f0cSJun-ichiro itojun Hagino 	n = dn_expand(answer->buf, eom, cp, bp, buflen);
107273b30f0cSJun-ichiro itojun Hagino 	if ((n < 0) || !(*name_ok)(bp)) {
107373b30f0cSJun-ichiro itojun Hagino 		*errp = NO_RECOVERY;
107473b30f0cSJun-ichiro itojun Hagino 		return (NULL);
107573b30f0cSJun-ichiro itojun Hagino 	}
107673b30f0cSJun-ichiro itojun Hagino 	BOUNDED_INCR(n + QFIXEDSZ);
107773b30f0cSJun-ichiro itojun Hagino 	if (qtype == T_A || qtype == T_AAAA) {
107873b30f0cSJun-ichiro itojun Hagino 		/* res_send() has already verified that the query name is the
107973b30f0cSJun-ichiro itojun Hagino 		 * same as the one we sent; this just gets the expanded name
108073b30f0cSJun-ichiro itojun Hagino 		 * (i.e., with the succeeding search-domain tacked on).
108173b30f0cSJun-ichiro itojun Hagino 		 */
108273b30f0cSJun-ichiro itojun Hagino 		n = strlen(bp) + 1;		/* for the \0 */
108373b30f0cSJun-ichiro itojun Hagino 		if (n >= MAXHOSTNAMELEN) {
108473b30f0cSJun-ichiro itojun Hagino 			*errp = NO_RECOVERY;
108573b30f0cSJun-ichiro itojun Hagino 			return (NULL);
108673b30f0cSJun-ichiro itojun Hagino 		}
108773b30f0cSJun-ichiro itojun Hagino 		template->h_name = bp;
108873b30f0cSJun-ichiro itojun Hagino 		bp += n;
108973b30f0cSJun-ichiro itojun Hagino 		buflen -= n;
109073b30f0cSJun-ichiro itojun Hagino 		/* The qname can be abbreviated, but h_name is now absolute. */
109173b30f0cSJun-ichiro itojun Hagino 		qname = template->h_name;
109273b30f0cSJun-ichiro itojun Hagino 	}
109373b30f0cSJun-ichiro itojun Hagino 	ap = host_aliases;
109473b30f0cSJun-ichiro itojun Hagino 	*ap = NULL;
109573b30f0cSJun-ichiro itojun Hagino 	template->h_aliases = host_aliases;
109673b30f0cSJun-ichiro itojun Hagino 	hap = h_addr_ptrs;
109773b30f0cSJun-ichiro itojun Hagino 	*hap = NULL;
109873b30f0cSJun-ichiro itojun Hagino 	template->h_addr_list = h_addr_ptrs;
109973b30f0cSJun-ichiro itojun Hagino 	haveanswer = 0;
110073b30f0cSJun-ichiro itojun Hagino 	had_error = 0;
110173b30f0cSJun-ichiro itojun Hagino 	while (ancount-- > 0 && cp < eom && !had_error) {
110273b30f0cSJun-ichiro itojun Hagino 		n = dn_expand(answer->buf, eom, cp, bp, buflen);
110373b30f0cSJun-ichiro itojun Hagino 		DNS_FATAL(n >= 0);
110473b30f0cSJun-ichiro itojun Hagino 		DNS_FATAL((*name_ok)(bp));
110573b30f0cSJun-ichiro itojun Hagino 		cp += n;			/* name */
110673b30f0cSJun-ichiro itojun Hagino 		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
110773b30f0cSJun-ichiro itojun Hagino 		type = _getshort(cp);
110873b30f0cSJun-ichiro itojun Hagino  		cp += INT16SZ;			/* type */
110973b30f0cSJun-ichiro itojun Hagino 		class = _getshort(cp);
111073b30f0cSJun-ichiro itojun Hagino  		cp += INT16SZ + INT32SZ;	/* class, TTL */
111173b30f0cSJun-ichiro itojun Hagino 		n = _getshort(cp);
111273b30f0cSJun-ichiro itojun Hagino 		cp += INT16SZ;			/* len */
111373b30f0cSJun-ichiro itojun Hagino 		BOUNDS_CHECK(cp, n);
111473b30f0cSJun-ichiro itojun Hagino 		erdata = cp + n;
111573b30f0cSJun-ichiro itojun Hagino 		DNS_ASSERT(class == C_IN);
111673b30f0cSJun-ichiro itojun Hagino 		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
111773b30f0cSJun-ichiro itojun Hagino 			if (ap >= &host_aliases[MAXALIASES-1])
111873b30f0cSJun-ichiro itojun Hagino 				continue;
111973b30f0cSJun-ichiro itojun Hagino 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
112073b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n >= 0);
112173b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL((*name_ok)(tbuf));
11227d56d374SYoshinobu Inoue 			cp += n;
112373b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
112473b30f0cSJun-ichiro itojun Hagino 				*errp = NO_RECOVERY;
112573b30f0cSJun-ichiro itojun Hagino 				return (NULL);
112673b30f0cSJun-ichiro itojun Hagino 			}
112773b30f0cSJun-ichiro itojun Hagino 			/* Store alias. */
112873b30f0cSJun-ichiro itojun Hagino 			*ap++ = bp;
112973b30f0cSJun-ichiro itojun Hagino 			n = strlen(bp) + 1;	/* for the \0 */
113073b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n < MAXHOSTNAMELEN);
113173b30f0cSJun-ichiro itojun Hagino 			bp += n;
113273b30f0cSJun-ichiro itojun Hagino 			buflen -= n;
113373b30f0cSJun-ichiro itojun Hagino 			/* Get canonical name. */
113473b30f0cSJun-ichiro itojun Hagino 			n = strlen(tbuf) + 1;	/* for the \0 */
113573b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n <= buflen);
113673b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n < MAXHOSTNAMELEN);
113773b30f0cSJun-ichiro itojun Hagino 			strcpy(bp, tbuf);
113873b30f0cSJun-ichiro itojun Hagino 			template->h_name = bp;
113973b30f0cSJun-ichiro itojun Hagino 			bp += n;
114073b30f0cSJun-ichiro itojun Hagino 			buflen -= n;
114173b30f0cSJun-ichiro itojun Hagino 			continue;
114273b30f0cSJun-ichiro itojun Hagino 		}
114373b30f0cSJun-ichiro itojun Hagino 		if (qtype == T_PTR && type == T_CNAME) {
114473b30f0cSJun-ichiro itojun Hagino 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
114573b30f0cSJun-ichiro itojun Hagino 			if (n < 0 || !res_dnok(tbuf)) {
114673b30f0cSJun-ichiro itojun Hagino 				had_error++;
114773b30f0cSJun-ichiro itojun Hagino 				continue;
114873b30f0cSJun-ichiro itojun Hagino 			}
114973b30f0cSJun-ichiro itojun Hagino 			cp += n;
115073b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
115173b30f0cSJun-ichiro itojun Hagino 				*errp = NO_RECOVERY;
115273b30f0cSJun-ichiro itojun Hagino 				return (NULL);
115373b30f0cSJun-ichiro itojun Hagino 			}
115473b30f0cSJun-ichiro itojun Hagino 			/* Get canonical name. */
115573b30f0cSJun-ichiro itojun Hagino 			n = strlen(tbuf) + 1;	/* for the \0 */
115673b30f0cSJun-ichiro itojun Hagino 			if (n > buflen || n >= MAXHOSTNAMELEN) {
115773b30f0cSJun-ichiro itojun Hagino 				had_error++;
115873b30f0cSJun-ichiro itojun Hagino 				continue;
115973b30f0cSJun-ichiro itojun Hagino 			}
116073b30f0cSJun-ichiro itojun Hagino 			strcpy(bp, tbuf);
11613f587e57SKris Kennaway 			tname = bp;
116273b30f0cSJun-ichiro itojun Hagino 			bp += n;
116373b30f0cSJun-ichiro itojun Hagino 			buflen -= n;
116473b30f0cSJun-ichiro itojun Hagino 			continue;
116573b30f0cSJun-ichiro itojun Hagino 		}
116673b30f0cSJun-ichiro itojun Hagino 		DNS_ASSERT(type == qtype);
116773b30f0cSJun-ichiro itojun Hagino 		switch (type) {
116873b30f0cSJun-ichiro itojun Hagino 		case T_PTR:
116973b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(strcasecmp(tname, bp) == 0);
117073b30f0cSJun-ichiro itojun Hagino 			n = dn_expand(answer->buf, eom, cp, bp, buflen);
117173b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n >= 0);
117273b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(res_hnok(bp));
117373b30f0cSJun-ichiro itojun Hagino #if MULTI_PTRS_ARE_ALIASES
117473b30f0cSJun-ichiro itojun Hagino 			cp += n;
117573b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
117673b30f0cSJun-ichiro itojun Hagino 				*errp = NO_RECOVERY;
117773b30f0cSJun-ichiro itojun Hagino 				return (NULL);
117873b30f0cSJun-ichiro itojun Hagino 			}
117973b30f0cSJun-ichiro itojun Hagino 			if (!haveanswer)
118073b30f0cSJun-ichiro itojun Hagino 				template->h_name = bp;
118173b30f0cSJun-ichiro itojun Hagino 			else if (ap < &host_aliases[MAXALIASES-1])
118273b30f0cSJun-ichiro itojun Hagino 				*ap++ = bp;
118373b30f0cSJun-ichiro itojun Hagino 			else
118473b30f0cSJun-ichiro itojun Hagino 				n = -1;
118573b30f0cSJun-ichiro itojun Hagino 			if (n != -1) {
118673b30f0cSJun-ichiro itojun Hagino 				n = strlen(bp) + 1;	/* for the \0 */
118773b30f0cSJun-ichiro itojun Hagino 				if (n >= MAXHOSTNAMELEN) {
118873b30f0cSJun-ichiro itojun Hagino 					had_error++;
11897d56d374SYoshinobu Inoue 					break;
11907d56d374SYoshinobu Inoue 				}
119173b30f0cSJun-ichiro itojun Hagino 				bp += n;
119273b30f0cSJun-ichiro itojun Hagino 				buflen -= n;
11937d56d374SYoshinobu Inoue 			}
119473b30f0cSJun-ichiro itojun Hagino 			break;
119573b30f0cSJun-ichiro itojun Hagino #else
119673b30f0cSJun-ichiro itojun Hagino 			template->h_name = bp;
119773b30f0cSJun-ichiro itojun Hagino 			*errp = NETDB_SUCCESS;
119873b30f0cSJun-ichiro itojun Hagino 			return (template);
119973b30f0cSJun-ichiro itojun Hagino #endif
120073b30f0cSJun-ichiro itojun Hagino 		case T_A:
120173b30f0cSJun-ichiro itojun Hagino 		case T_AAAA:
120273b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(strcasecmp(template->h_name, bp) == 0);
120373b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(n == template->h_length);
120473b30f0cSJun-ichiro itojun Hagino 			if (!haveanswer) {
120573b30f0cSJun-ichiro itojun Hagino 				register int nn;
120673b30f0cSJun-ichiro itojun Hagino 
120773b30f0cSJun-ichiro itojun Hagino 				template->h_name = bp;
120873b30f0cSJun-ichiro itojun Hagino 				nn = strlen(bp) + 1;	/* for the \0 */
120973b30f0cSJun-ichiro itojun Hagino 				bp += nn;
121073b30f0cSJun-ichiro itojun Hagino 				buflen -= nn;
121173b30f0cSJun-ichiro itojun Hagino 			}
121273b30f0cSJun-ichiro itojun Hagino 			bp = (char *)ALIGN(bp);
121373b30f0cSJun-ichiro itojun Hagino 
121473b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(bp + n < &hostbuf[sizeof hostbuf]);
121573b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(hap < &h_addr_ptrs[MAXADDRS-1]);
121673b30f0cSJun-ichiro itojun Hagino #ifdef FILTER_V4MAPPED
121773b30f0cSJun-ichiro itojun Hagino 			if (type == T_AAAA) {
121873b30f0cSJun-ichiro itojun Hagino 				struct in6_addr in6;
121973b30f0cSJun-ichiro itojun Hagino 				memcpy(&in6, cp, sizeof(in6));
122073b30f0cSJun-ichiro itojun Hagino 				DNS_ASSERT(IN6_IS_ADDR_V4MAPPED(&in6) == 0);
122173b30f0cSJun-ichiro itojun Hagino 			}
122273b30f0cSJun-ichiro itojun Hagino #endif
122373b30f0cSJun-ichiro itojun Hagino 			bcopy(cp, *hap++ = bp, n);
122473b30f0cSJun-ichiro itojun Hagino 			bp += n;
122573b30f0cSJun-ichiro itojun Hagino 			buflen -= n;
122673b30f0cSJun-ichiro itojun Hagino 			cp += n;
122773b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
12287d56d374SYoshinobu Inoue 				*errp = NO_RECOVERY;
122973b30f0cSJun-ichiro itojun Hagino 				return (NULL);
12307d56d374SYoshinobu Inoue 			}
123173b30f0cSJun-ichiro itojun Hagino 			break;
123273b30f0cSJun-ichiro itojun Hagino 		default:
123373b30f0cSJun-ichiro itojun Hagino 			abort();
123473b30f0cSJun-ichiro itojun Hagino 		}
123573b30f0cSJun-ichiro itojun Hagino 		if (!had_error)
123673b30f0cSJun-ichiro itojun Hagino 			haveanswer++;
123773b30f0cSJun-ichiro itojun Hagino 	}
123873b30f0cSJun-ichiro itojun Hagino 	if (haveanswer) {
123973b30f0cSJun-ichiro itojun Hagino 		*ap = NULL;
124073b30f0cSJun-ichiro itojun Hagino 		*hap = NULL;
124173b30f0cSJun-ichiro itojun Hagino 		if (!template->h_name) {
124273b30f0cSJun-ichiro itojun Hagino 			n = strlen(qname) + 1;	/* for the \0 */
124373b30f0cSJun-ichiro itojun Hagino 			if (n > buflen || n >= MAXHOSTNAMELEN)
124473b30f0cSJun-ichiro itojun Hagino 				goto no_recovery;
124573b30f0cSJun-ichiro itojun Hagino 			strcpy(bp, qname);
124673b30f0cSJun-ichiro itojun Hagino 			template->h_name = bp;
124773b30f0cSJun-ichiro itojun Hagino 			bp += n;
124873b30f0cSJun-ichiro itojun Hagino 			buflen -= n;
124973b30f0cSJun-ichiro itojun Hagino 		}
125073b30f0cSJun-ichiro itojun Hagino 		*errp = NETDB_SUCCESS;
125173b30f0cSJun-ichiro itojun Hagino 		return (template);
125273b30f0cSJun-ichiro itojun Hagino 	}
125373b30f0cSJun-ichiro itojun Hagino  no_recovery:
125473b30f0cSJun-ichiro itojun Hagino 	*errp = NO_RECOVERY;
125573b30f0cSJun-ichiro itojun Hagino 	return (NULL);
125673b30f0cSJun-ichiro itojun Hagino 
125773b30f0cSJun-ichiro itojun Hagino #undef BOUNDED_INCR
125873b30f0cSJun-ichiro itojun Hagino #undef BOUNDS_CHECK
125973b30f0cSJun-ichiro itojun Hagino #undef DNS_ASSERT
126073b30f0cSJun-ichiro itojun Hagino #undef DNS_FATAL
12617d56d374SYoshinobu Inoue }
12627d56d374SYoshinobu Inoue 
1263e6f35403SYoshinobu Inoue /* res_search() variant with multiple query support. */
1264e6f35403SYoshinobu Inoue static struct hostent *
1265e6f35403SYoshinobu Inoue _res_search_multi(name, rtl, errp)
1266e6f35403SYoshinobu Inoue 	const char *name;	/* domain name */
1267e6f35403SYoshinobu Inoue 	struct	__res_type_list *rtl; /* list of query types */
1268e6f35403SYoshinobu Inoue 	int *errp;
1269e6f35403SYoshinobu Inoue {
1270e6f35403SYoshinobu Inoue 	const char *cp, * const *domain;
1271e6f35403SYoshinobu Inoue 	struct hostent *hp0 = NULL, *hp;
127273b30f0cSJun-ichiro itojun Hagino 	struct hostent hpbuf;
1273e6f35403SYoshinobu Inoue 	u_int dots;
1274e6f35403SYoshinobu Inoue 	int trailing_dot, ret, saved_herrno;
1275e6f35403SYoshinobu Inoue 	int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1276e6f35403SYoshinobu Inoue 	struct __res_type_list *rtl0 = rtl;
127773b30f0cSJun-ichiro itojun Hagino 	querybuf buf;
1278e6f35403SYoshinobu Inoue 
1279e6f35403SYoshinobu Inoue 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1280e6f35403SYoshinobu Inoue 		*errp = NETDB_INTERNAL;
1281e6f35403SYoshinobu Inoue 		return (NULL);
1282e6f35403SYoshinobu Inoue 	}
1283e6f35403SYoshinobu Inoue 	dots = 0;
1284e6f35403SYoshinobu Inoue 	for (cp = name; *cp; cp++)
1285e6f35403SYoshinobu Inoue 		dots += (*cp == '.');
1286e6f35403SYoshinobu Inoue 	trailing_dot = 0;
1287e6f35403SYoshinobu Inoue 	if (cp > name && *--cp == '.')
1288e6f35403SYoshinobu Inoue 		trailing_dot++;
1289e6f35403SYoshinobu Inoue 
1290e6f35403SYoshinobu Inoue 	/* If there aren't any dots, it could be a user-level alias */
1291e6f35403SYoshinobu Inoue 	if (!dots && (cp = hostalias(name)) != NULL) {
1292e6f35403SYoshinobu Inoue 		for(rtl = rtl0; rtl != NULL;
1293e6f35403SYoshinobu Inoue 		    rtl = SLIST_NEXT(rtl, rtl_entry)) {
129473b30f0cSJun-ichiro itojun Hagino 			ret = res_query(cp, C_IN, rtl->rtl_type, buf.buf,
129573b30f0cSJun-ichiro itojun Hagino 					     sizeof(buf.buf));
1296e6f35403SYoshinobu Inoue 			if (ret > 0) {
129773b30f0cSJun-ichiro itojun Hagino 				hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
129873b30f0cSJun-ichiro itojun Hagino 				    ? AF_INET6 : AF_INET;
129973b30f0cSJun-ichiro itojun Hagino 				hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
130073b30f0cSJun-ichiro itojun Hagino 				hp = getanswer(&buf, ret, name, rtl->rtl_type,
130173b30f0cSJun-ichiro itojun Hagino 						    &hpbuf, errp);
13023f587e57SKris Kennaway 				if (!hp)
13033f587e57SKris Kennaway 					continue;
130473b30f0cSJun-ichiro itojun Hagino 				hp = _hpcopy(&hpbuf, errp);
1305e6f35403SYoshinobu Inoue 				hp0 = _hpmerge(hp0, hp, errp);
1306e6f35403SYoshinobu Inoue 			}
1307e6f35403SYoshinobu Inoue 		}
1308e6f35403SYoshinobu Inoue 		return (hp0);
1309e6f35403SYoshinobu Inoue 	}
1310e6f35403SYoshinobu Inoue 
1311e6f35403SYoshinobu Inoue 	/*
1312e6f35403SYoshinobu Inoue 	 * If there are dots in the name already, let's just give it a try
1313e6f35403SYoshinobu Inoue 	 * 'as is'.  The threshold can be set with the "ndots" option.
1314e6f35403SYoshinobu Inoue 	 */
1315e6f35403SYoshinobu Inoue 	saved_herrno = -1;
1316e6f35403SYoshinobu Inoue 	if (dots >= _res.ndots) {
1317e6f35403SYoshinobu Inoue 		for(rtl = rtl0; rtl != NULL;
1318e6f35403SYoshinobu Inoue 		    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1319e6f35403SYoshinobu Inoue 			ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type,
132073b30f0cSJun-ichiro itojun Hagino 					      buf.buf, sizeof(buf.buf));
1321e6f35403SYoshinobu Inoue 			if (ret > 0) {
132273b30f0cSJun-ichiro itojun Hagino 				hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
132373b30f0cSJun-ichiro itojun Hagino 				    ? AF_INET6 : AF_INET;
132473b30f0cSJun-ichiro itojun Hagino 				hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
132573b30f0cSJun-ichiro itojun Hagino 				hp = getanswer(&buf, ret, name, rtl->rtl_type,
132673b30f0cSJun-ichiro itojun Hagino 						    &hpbuf, errp);
13273f587e57SKris Kennaway 				if (!hp)
13283f587e57SKris Kennaway 					continue;
132973b30f0cSJun-ichiro itojun Hagino 				hp = _hpcopy(&hpbuf, errp);
1330e6f35403SYoshinobu Inoue 				hp0 = _hpmerge(hp0, hp, errp);
1331e6f35403SYoshinobu Inoue 			}
1332e6f35403SYoshinobu Inoue 		}
1333e6f35403SYoshinobu Inoue 		if (hp0 != NULL)
1334e6f35403SYoshinobu Inoue 			return (hp0);
1335e6f35403SYoshinobu Inoue 		saved_herrno = *errp;
1336e6f35403SYoshinobu Inoue 		tried_as_is++;
1337e6f35403SYoshinobu Inoue 	}
1338e6f35403SYoshinobu Inoue 
1339e6f35403SYoshinobu Inoue 	/*
1340e6f35403SYoshinobu Inoue 	 * We do at least one level of search if
1341e6f35403SYoshinobu Inoue 	 *	- there is no dot and RES_DEFNAME is set, or
1342e6f35403SYoshinobu Inoue 	 *	- there is at least one dot, there is no trailing dot,
1343e6f35403SYoshinobu Inoue 	 *	  and RES_DNSRCH is set.
1344e6f35403SYoshinobu Inoue 	 */
1345e6f35403SYoshinobu Inoue 	if ((!dots && (_res.options & RES_DEFNAMES)) ||
1346e6f35403SYoshinobu Inoue 	    (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
1347e6f35403SYoshinobu Inoue 		int done = 0;
1348e6f35403SYoshinobu Inoue 
1349e6f35403SYoshinobu Inoue 		for (domain = (const char * const *)_res.dnsrch;
1350e6f35403SYoshinobu Inoue 		     *domain && !done;
1351e6f35403SYoshinobu Inoue 		     domain++) {
1352e6f35403SYoshinobu Inoue 
1353e6f35403SYoshinobu Inoue 			for(rtl = rtl0; rtl != NULL;
1354e6f35403SYoshinobu Inoue 			    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1355e6f35403SYoshinobu Inoue 				ret = res_querydomain(name, *domain, C_IN,
1356e6f35403SYoshinobu Inoue 						      rtl->rtl_type,
135773b30f0cSJun-ichiro itojun Hagino 						      buf.buf, sizeof(buf.buf));
1358e6f35403SYoshinobu Inoue 				if (ret > 0) {
135973b30f0cSJun-ichiro itojun Hagino 					hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
136073b30f0cSJun-ichiro itojun Hagino 					    ? AF_INET6 : AF_INET;
136173b30f0cSJun-ichiro itojun Hagino 					hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
136273b30f0cSJun-ichiro itojun Hagino 					hp = getanswer(&buf, ret, name,
136373b30f0cSJun-ichiro itojun Hagino 					    rtl->rtl_type, &hpbuf, errp);
13643f587e57SKris Kennaway 					if (!hp)
13653f587e57SKris Kennaway 						continue;
136673b30f0cSJun-ichiro itojun Hagino 					hp = _hpcopy(&hpbuf, errp);
1367e6f35403SYoshinobu Inoue 					hp0 = _hpmerge(hp0, hp, errp);
1368e6f35403SYoshinobu Inoue 				}
1369e6f35403SYoshinobu Inoue 			}
1370e6f35403SYoshinobu Inoue 			if (hp0 != NULL)
1371e6f35403SYoshinobu Inoue 				return (hp0);
1372e6f35403SYoshinobu Inoue 
1373e6f35403SYoshinobu Inoue 			/*
1374e6f35403SYoshinobu Inoue 			 * If no server present, give up.
1375e6f35403SYoshinobu Inoue 			 * If name isn't found in this domain,
1376e6f35403SYoshinobu Inoue 			 * keep trying higher domains in the search list
1377e6f35403SYoshinobu Inoue 			 * (if that's enabled).
1378e6f35403SYoshinobu Inoue 			 * On a NO_DATA error, keep trying, otherwise
1379e6f35403SYoshinobu Inoue 			 * a wildcard entry of another type could keep us
1380e6f35403SYoshinobu Inoue 			 * from finding this entry higher in the domain.
1381e6f35403SYoshinobu Inoue 			 * If we get some other error (negative answer or
1382e6f35403SYoshinobu Inoue 			 * server failure), then stop searching up,
1383e6f35403SYoshinobu Inoue 			 * but try the input name below in case it's
1384e6f35403SYoshinobu Inoue 			 * fully-qualified.
1385e6f35403SYoshinobu Inoue 			 */
1386e6f35403SYoshinobu Inoue 			if (errno == ECONNREFUSED) {
1387e6f35403SYoshinobu Inoue 				*errp = TRY_AGAIN;
1388e6f35403SYoshinobu Inoue 				return (NULL);
1389e6f35403SYoshinobu Inoue 			}
1390e6f35403SYoshinobu Inoue 
1391e6f35403SYoshinobu Inoue 			switch (*errp) {
1392e6f35403SYoshinobu Inoue 			case NO_DATA:
1393e6f35403SYoshinobu Inoue 				got_nodata++;
1394e6f35403SYoshinobu Inoue 				/* FALLTHROUGH */
1395e6f35403SYoshinobu Inoue 			case HOST_NOT_FOUND:
1396e6f35403SYoshinobu Inoue 				/* keep trying */
1397e6f35403SYoshinobu Inoue 				break;
1398e6f35403SYoshinobu Inoue 			case TRY_AGAIN:
139973b30f0cSJun-ichiro itojun Hagino 				if (buf.hdr.rcode == SERVFAIL) {
1400e6f35403SYoshinobu Inoue 					/* try next search element, if any */
1401e6f35403SYoshinobu Inoue 					got_servfail++;
1402e6f35403SYoshinobu Inoue 					break;
1403e6f35403SYoshinobu Inoue 				}
1404e6f35403SYoshinobu Inoue 				/* FALLTHROUGH */
1405e6f35403SYoshinobu Inoue 			default:
1406e6f35403SYoshinobu Inoue 				/* anything else implies that we're done */
1407e6f35403SYoshinobu Inoue 				done++;
1408e6f35403SYoshinobu Inoue 			}
1409e6f35403SYoshinobu Inoue 
1410e6f35403SYoshinobu Inoue 			/* if we got here for some reason other than DNSRCH,
1411e6f35403SYoshinobu Inoue 			 * we only wanted one iteration of the loop, so stop.
1412e6f35403SYoshinobu Inoue 			 */
1413e6f35403SYoshinobu Inoue 			if (!(_res.options & RES_DNSRCH))
1414e6f35403SYoshinobu Inoue 				done++;
1415e6f35403SYoshinobu Inoue 		}
1416e6f35403SYoshinobu Inoue 	}
1417e6f35403SYoshinobu Inoue 
1418e6f35403SYoshinobu Inoue 	/*
1419e6f35403SYoshinobu Inoue 	 * If we have not already tried the name "as is", do that now.
1420e6f35403SYoshinobu Inoue 	 * note that we do this regardless of how many dots were in the
1421e6f35403SYoshinobu Inoue 	 * name or whether it ends with a dot unless NOTLDQUERY is set.
1422e6f35403SYoshinobu Inoue 	 */
1423e6f35403SYoshinobu Inoue 	if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) {
1424e6f35403SYoshinobu Inoue 		for(rtl = rtl0; rtl != NULL;
1425e6f35403SYoshinobu Inoue 		    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1426e6f35403SYoshinobu Inoue 			ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type,
142773b30f0cSJun-ichiro itojun Hagino 					      buf.buf, sizeof(buf.buf));
1428e6f35403SYoshinobu Inoue 			if (ret > 0) {
142973b30f0cSJun-ichiro itojun Hagino 				hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
143073b30f0cSJun-ichiro itojun Hagino 				    ? AF_INET6 : AF_INET;
143173b30f0cSJun-ichiro itojun Hagino 				hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
143273b30f0cSJun-ichiro itojun Hagino 				hp = getanswer(&buf, ret, name, rtl->rtl_type,
143373b30f0cSJun-ichiro itojun Hagino 				    &hpbuf, errp);
14343f587e57SKris Kennaway 				if (!hp)
14353f587e57SKris Kennaway 					continue;
143673b30f0cSJun-ichiro itojun Hagino 				hp = _hpcopy(&hpbuf, errp);
1437e6f35403SYoshinobu Inoue 				hp0 = _hpmerge(hp0, hp, errp);
1438e6f35403SYoshinobu Inoue 			}
1439e6f35403SYoshinobu Inoue 		}
1440e6f35403SYoshinobu Inoue 		if (hp0 != NULL)
1441e6f35403SYoshinobu Inoue 			return (hp0);
1442e6f35403SYoshinobu Inoue 	}
1443e6f35403SYoshinobu Inoue 
1444e6f35403SYoshinobu Inoue 	/* if we got here, we didn't satisfy the search.
1445e6f35403SYoshinobu Inoue 	 * if we did an initial full query, return that query's h_errno
1446e6f35403SYoshinobu Inoue 	 * (note that we wouldn't be here if that query had succeeded).
1447e6f35403SYoshinobu Inoue 	 * else if we ever got a nodata, send that back as the reason.
1448e6f35403SYoshinobu Inoue 	 * else send back meaningless h_errno, that being the one from
1449e6f35403SYoshinobu Inoue 	 * the last DNSRCH we did.
1450e6f35403SYoshinobu Inoue 	 */
1451e6f35403SYoshinobu Inoue 	if (saved_herrno != -1)
1452e6f35403SYoshinobu Inoue 		*errp = saved_herrno;
1453e6f35403SYoshinobu Inoue 	else if (got_nodata)
1454e6f35403SYoshinobu Inoue 		*errp = NO_DATA;
1455e6f35403SYoshinobu Inoue 	else if (got_servfail)
1456e6f35403SYoshinobu Inoue 		*errp = TRY_AGAIN;
1457e6f35403SYoshinobu Inoue 	return (NULL);
1458e6f35403SYoshinobu Inoue }
1459e6f35403SYoshinobu Inoue 
1460248aee62SJacques Vidrine static int
1461248aee62SJacques Vidrine _dns_ghbyname(void *rval, void *cb_data, va_list ap)
1462e6f35403SYoshinobu Inoue {
1463248aee62SJacques Vidrine 	const char *name;
1464248aee62SJacques Vidrine 	int af;
1465248aee62SJacques Vidrine 	int *errp;
1466e6f35403SYoshinobu Inoue 	struct __res_type_list *rtl, rtl4;
1467e6f35403SYoshinobu Inoue #ifdef INET6
1468e6f35403SYoshinobu Inoue 	struct __res_type_list rtl6;
1469e6f35403SYoshinobu Inoue #endif
1470e6f35403SYoshinobu Inoue 
1471248aee62SJacques Vidrine 	name = va_arg(ap, const char *);
1472248aee62SJacques Vidrine 	af = va_arg(ap, int);
1473248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
1474248aee62SJacques Vidrine 
1475e6f35403SYoshinobu Inoue #ifdef INET6
1476e6f35403SYoshinobu Inoue 	switch (af) {
1477e6f35403SYoshinobu Inoue 	case AF_UNSPEC:
1478e6f35403SYoshinobu Inoue 		SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
1479e6f35403SYoshinobu Inoue 		SLIST_NEXT(&rtl6, rtl_entry) = &rtl4; rtl6.rtl_type = T_AAAA;
1480e6f35403SYoshinobu Inoue 		rtl = &rtl6;
1481e6f35403SYoshinobu Inoue 		break;
1482e6f35403SYoshinobu Inoue 	case AF_INET6:
1483e6f35403SYoshinobu Inoue 		SLIST_NEXT(&rtl6, rtl_entry) = NULL; rtl6.rtl_type = T_AAAA;
1484e6f35403SYoshinobu Inoue 		rtl = &rtl6;
1485e6f35403SYoshinobu Inoue 		break;
1486e6f35403SYoshinobu Inoue 	case AF_INET:
1487e6f35403SYoshinobu Inoue 		SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
1488e6f35403SYoshinobu Inoue 		rtl = &rtl4;
1489e6f35403SYoshinobu Inoue 		break;
1490e6f35403SYoshinobu Inoue 	}
1491e6f35403SYoshinobu Inoue #else
1492e6f35403SYoshinobu Inoue 	SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
1493e6f35403SYoshinobu Inoue 	rtl = &rtl4;
1494e6f35403SYoshinobu Inoue #endif
1495248aee62SJacques Vidrine 	*(struct hostent **)rval = _res_search_multi(name, rtl, errp);
1496248aee62SJacques Vidrine 	return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
1497e6f35403SYoshinobu Inoue }
1498e6f35403SYoshinobu Inoue 
1499248aee62SJacques Vidrine static int
1500248aee62SJacques Vidrine _dns_ghbyaddr(void *rval, void *cb_data, va_list ap)
15017d56d374SYoshinobu Inoue {
1502248aee62SJacques Vidrine 	const void *addr;
1503248aee62SJacques Vidrine 	int addrlen;
1504248aee62SJacques Vidrine 	int af;
1505248aee62SJacques Vidrine 	int *errp;
15067d56d374SYoshinobu Inoue 	int n;
150773b30f0cSJun-ichiro itojun Hagino 	struct hostent *hp;
150873b30f0cSJun-ichiro itojun Hagino 	u_char c, *cp;
15097d56d374SYoshinobu Inoue 	char *bp;
15107d56d374SYoshinobu Inoue 	struct hostent hbuf;
15117d56d374SYoshinobu Inoue 	int na;
15127d56d374SYoshinobu Inoue #ifdef INET6
15137d56d374SYoshinobu Inoue 	static const char hex[] = "0123456789abcdef";
15147d56d374SYoshinobu Inoue #endif
151573b30f0cSJun-ichiro itojun Hagino 	querybuf buf;
151673b30f0cSJun-ichiro itojun Hagino 	char qbuf[MAXDNAME+1];
151773b30f0cSJun-ichiro itojun Hagino 	char *hlist[2];
15187d56d374SYoshinobu Inoue 
1519248aee62SJacques Vidrine 	addr = va_arg(ap, const void *);
1520248aee62SJacques Vidrine 	addrlen = va_arg(ap, int);
1521248aee62SJacques Vidrine 	af = va_arg(ap, int);
1522248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
1523248aee62SJacques Vidrine 
1524248aee62SJacques Vidrine 	*(struct hostent **)rval = NULL;
1525248aee62SJacques Vidrine 
15267d56d374SYoshinobu Inoue #ifdef INET6
15277d56d374SYoshinobu Inoue 	/* XXX */
15287d56d374SYoshinobu Inoue 	if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
1529248aee62SJacques Vidrine 		return NS_NOTFOUND;
15307d56d374SYoshinobu Inoue #endif
15317d56d374SYoshinobu Inoue 
15327d56d374SYoshinobu Inoue 	if ((_res.options & RES_INIT) == 0) {
15337d56d374SYoshinobu Inoue 		if (res_init() < 0) {
15347d56d374SYoshinobu Inoue 			*errp = h_errno;
1535248aee62SJacques Vidrine 			return NS_UNAVAIL;
15367d56d374SYoshinobu Inoue 		}
15377d56d374SYoshinobu Inoue 	}
153873b30f0cSJun-ichiro itojun Hagino 	memset(&hbuf, 0, sizeof(hbuf));
15397d56d374SYoshinobu Inoue 	hbuf.h_name = NULL;
15407d56d374SYoshinobu Inoue 	hbuf.h_addrtype = af;
15417d56d374SYoshinobu Inoue 	hbuf.h_length = addrlen;
15427d56d374SYoshinobu Inoue 	na = 0;
15437d56d374SYoshinobu Inoue 
154473b30f0cSJun-ichiro itojun Hagino 	/* XXX assumes that MAXDNAME is big enough */
15457d56d374SYoshinobu Inoue 	n = 0;
154673b30f0cSJun-ichiro itojun Hagino 	bp = qbuf;
15477d56d374SYoshinobu Inoue 	cp = (u_char *)addr+addrlen-1;
15487d56d374SYoshinobu Inoue 	switch (af) {
15497d56d374SYoshinobu Inoue #ifdef INET6
15507d56d374SYoshinobu Inoue 	case AF_INET6:
15517d56d374SYoshinobu Inoue 		for (; n < addrlen; n++, cp--) {
15527d56d374SYoshinobu Inoue 			c = *cp;
15537d56d374SYoshinobu Inoue 			*bp++ = hex[c & 0xf];
15547d56d374SYoshinobu Inoue 			*bp++ = '.';
15557d56d374SYoshinobu Inoue 			*bp++ = hex[c >> 4];
15567d56d374SYoshinobu Inoue 			*bp++ = '.';
15577d56d374SYoshinobu Inoue 		}
15587d56d374SYoshinobu Inoue 		strcpy(bp, "ip6.int");
15597d56d374SYoshinobu Inoue 		break;
15607d56d374SYoshinobu Inoue #endif
15617d56d374SYoshinobu Inoue 	default:
15627d56d374SYoshinobu Inoue 		for (; n < addrlen; n++, cp--) {
15637d56d374SYoshinobu Inoue 			c = *cp;
15647d56d374SYoshinobu Inoue 			if (c >= 100)
15657d56d374SYoshinobu Inoue 				*bp++ = '0' + c / 100;
15667d56d374SYoshinobu Inoue 			if (c >= 10)
15677d56d374SYoshinobu Inoue 				*bp++ = '0' + (c % 100) / 10;
15687d56d374SYoshinobu Inoue 			*bp++ = '0' + c % 10;
15697d56d374SYoshinobu Inoue 			*bp++ = '.';
15707d56d374SYoshinobu Inoue 		}
15717d56d374SYoshinobu Inoue 		strcpy(bp, "in-addr.arpa");
15727d56d374SYoshinobu Inoue 		break;
15737d56d374SYoshinobu Inoue 	}
15747d56d374SYoshinobu Inoue 
157573b30f0cSJun-ichiro itojun Hagino 	n = res_query(qbuf, C_IN, T_PTR, buf.buf, sizeof buf.buf);
15767d56d374SYoshinobu Inoue 	if (n < 0) {
15777d56d374SYoshinobu Inoue 		*errp = h_errno;
1578248aee62SJacques Vidrine 		return NS_UNAVAIL;
15797d56d374SYoshinobu Inoue 	}
158073b30f0cSJun-ichiro itojun Hagino 	hp = getanswer(&buf, n, qbuf, T_PTR, &hbuf, errp);
15813f587e57SKris Kennaway 	if (!hp)
1582248aee62SJacques Vidrine 		return NS_NOTFOUND;
158373b30f0cSJun-ichiro itojun Hagino 	hbuf.h_addrtype = af;
158473b30f0cSJun-ichiro itojun Hagino 	hbuf.h_length = addrlen;
158573b30f0cSJun-ichiro itojun Hagino 	hbuf.h_addr_list = hlist;
158673b30f0cSJun-ichiro itojun Hagino 	hlist[0] = (char *)addr;
158773b30f0cSJun-ichiro itojun Hagino 	hlist[1] = NULL;
1588248aee62SJacques Vidrine 	*(struct hostent **)rval = _hpcopy(&hbuf, errp);
1589248aee62SJacques Vidrine 	return NS_SUCCESS;
15907d56d374SYoshinobu Inoue }
15917d56d374SYoshinobu Inoue 
159273b30f0cSJun-ichiro itojun Hagino static void
159373b30f0cSJun-ichiro itojun Hagino _dns_shent(int stayopen)
159473b30f0cSJun-ichiro itojun Hagino {
159573b30f0cSJun-ichiro itojun Hagino 	if ((_res.options & RES_INIT) == 0) {
159673b30f0cSJun-ichiro itojun Hagino 		if (res_init() < 0)
159773b30f0cSJun-ichiro itojun Hagino 			return;
159873b30f0cSJun-ichiro itojun Hagino 	}
159973b30f0cSJun-ichiro itojun Hagino 	if (stayopen)
160073b30f0cSJun-ichiro itojun Hagino 		_res.options |= RES_STAYOPEN | RES_USEVC;
160173b30f0cSJun-ichiro itojun Hagino }
160273b30f0cSJun-ichiro itojun Hagino 
160373b30f0cSJun-ichiro itojun Hagino static void
160473b30f0cSJun-ichiro itojun Hagino _dns_ehent(void)
160573b30f0cSJun-ichiro itojun Hagino {
160673b30f0cSJun-ichiro itojun Hagino 	_res.options &= ~(RES_STAYOPEN | RES_USEVC);
160773b30f0cSJun-ichiro itojun Hagino 	res_close();
160873b30f0cSJun-ichiro itojun Hagino }
160973b30f0cSJun-ichiro itojun Hagino 
16107d56d374SYoshinobu Inoue #ifdef ICMPNL
16117d56d374SYoshinobu Inoue 
16127d56d374SYoshinobu Inoue /*
16137d56d374SYoshinobu Inoue  * experimental:
16147d56d374SYoshinobu Inoue  *	draft-ietf-ipngwg-icmp-namelookups-02.txt
16157d56d374SYoshinobu Inoue  *	ifindex is assumed to be encoded in addr.
16167d56d374SYoshinobu Inoue  */
16177d56d374SYoshinobu Inoue #include <sys/uio.h>
16187d56d374SYoshinobu Inoue #include <netinet/ip6.h>
16197d56d374SYoshinobu Inoue #include <netinet/icmp6.h>
16207d56d374SYoshinobu Inoue 
16217d56d374SYoshinobu Inoue struct _icmp_host_cache {
16227d56d374SYoshinobu Inoue 	struct _icmp_host_cache *hc_next;
16237d56d374SYoshinobu Inoue 	int hc_ifindex;
16247d56d374SYoshinobu Inoue 	struct in6_addr hc_addr;
16257d56d374SYoshinobu Inoue 	char *hc_name;
16267d56d374SYoshinobu Inoue };
16277d56d374SYoshinobu Inoue 
16287d56d374SYoshinobu Inoue static char *
16297d56d374SYoshinobu Inoue _icmp_fqdn_query(const struct in6_addr *addr, int ifindex)
16307d56d374SYoshinobu Inoue {
16317d56d374SYoshinobu Inoue 	int s;
16327d56d374SYoshinobu Inoue 	struct icmp6_filter filter;
16337d56d374SYoshinobu Inoue 	struct msghdr msg;
16347d56d374SYoshinobu Inoue 	struct cmsghdr *cmsg;
16357d56d374SYoshinobu Inoue 	struct in6_pktinfo *pkt;
16367d56d374SYoshinobu Inoue 	char cbuf[256];
16377d56d374SYoshinobu Inoue 	char buf[1024];
16387d56d374SYoshinobu Inoue 	int cc;
16397d56d374SYoshinobu Inoue 	struct icmp6_fqdn_query *fq;
16407d56d374SYoshinobu Inoue 	struct icmp6_fqdn_reply *fr;
16417d56d374SYoshinobu Inoue 	struct _icmp_host_cache *hc;
16427d56d374SYoshinobu Inoue 	struct sockaddr_in6 sin6;
16437d56d374SYoshinobu Inoue 	struct iovec iov;
16447d56d374SYoshinobu Inoue 	fd_set s_fds, fds;
16457d56d374SYoshinobu Inoue 	struct timeval tout;
16467d56d374SYoshinobu Inoue 	int len;
16477d56d374SYoshinobu Inoue 	char *name;
16487d56d374SYoshinobu Inoue 	static int pid;
16497d56d374SYoshinobu Inoue 	static struct _icmp_host_cache *hc_head;
16507d56d374SYoshinobu Inoue 
16517d56d374SYoshinobu Inoue 	for (hc = hc_head; hc; hc = hc->hc_next) {
16527d56d374SYoshinobu Inoue 		if (hc->hc_ifindex == ifindex
16537d56d374SYoshinobu Inoue 		&&  IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr))
16547d56d374SYoshinobu Inoue 			return hc->hc_name;
16557d56d374SYoshinobu Inoue 	}
16567d56d374SYoshinobu Inoue 
16577d56d374SYoshinobu Inoue 	if (pid == 0)
16587d56d374SYoshinobu Inoue 		pid = getpid();
16597d56d374SYoshinobu Inoue 
16607d56d374SYoshinobu Inoue 	ICMP6_FILTER_SETBLOCKALL(&filter);
16617d56d374SYoshinobu Inoue 	ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter);
16627d56d374SYoshinobu Inoue 
16637d56d374SYoshinobu Inoue 	FD_ZERO(&s_fds);
16647d56d374SYoshinobu Inoue 	tout.tv_sec = 0;
16657d56d374SYoshinobu Inoue 	tout.tv_usec = 200000;	/*XXX: 200ms*/
16667d56d374SYoshinobu Inoue 
16677d56d374SYoshinobu Inoue 	fq = (struct icmp6_fqdn_query *)buf;
16687d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY;
16697d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_code = 0;
16707d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_cksum = 0;
16717d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_id = (u_short)pid;
16727d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_unused = 0;
16737d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_cookie[0] = 0;
16747d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_cookie[1] = 0;
16757d56d374SYoshinobu Inoue 
16767d56d374SYoshinobu Inoue 	memset(&sin6, 0, sizeof(sin6));
16777d56d374SYoshinobu Inoue 	sin6.sin6_family = AF_INET6;
16787d56d374SYoshinobu Inoue 	sin6.sin6_addr = *addr;
16797d56d374SYoshinobu Inoue 
16807d56d374SYoshinobu Inoue 	memset(&msg, 0, sizeof(msg));
16817d56d374SYoshinobu Inoue 	msg.msg_name = (caddr_t)&sin6;
16827d56d374SYoshinobu Inoue 	msg.msg_namelen = sizeof(sin6);
16837d56d374SYoshinobu Inoue 	msg.msg_iov = &iov;
16847d56d374SYoshinobu Inoue 	msg.msg_iovlen = 1;
16857d56d374SYoshinobu Inoue 	msg.msg_control = NULL;
16867d56d374SYoshinobu Inoue 	msg.msg_controllen = 0;
16877d56d374SYoshinobu Inoue 	iov.iov_base = (caddr_t)buf;
16887d56d374SYoshinobu Inoue 	iov.iov_len = sizeof(struct icmp6_fqdn_query);
16897d56d374SYoshinobu Inoue 
16907d56d374SYoshinobu Inoue 	if (ifindex) {
16917d56d374SYoshinobu Inoue 		msg.msg_control = cbuf;
16927d56d374SYoshinobu Inoue 		msg.msg_controllen = sizeof(cbuf);
16937d56d374SYoshinobu Inoue 		cmsg = CMSG_FIRSTHDR(&msg);
16947d56d374SYoshinobu Inoue 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
16957d56d374SYoshinobu Inoue 		cmsg->cmsg_level = IPPROTO_IPV6;
16967d56d374SYoshinobu Inoue 		cmsg->cmsg_type = IPV6_PKTINFO;
16977d56d374SYoshinobu Inoue 		pkt = (struct in6_pktinfo *)&cmsg[1];
16987d56d374SYoshinobu Inoue 		memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
16997d56d374SYoshinobu Inoue 		pkt->ipi6_ifindex = ifindex;
17007d56d374SYoshinobu Inoue 		cmsg = CMSG_NXTHDR(&msg, cmsg);
17017d56d374SYoshinobu Inoue 		msg.msg_controllen = (char *)cmsg - cbuf;
17027d56d374SYoshinobu Inoue 	}
17037d56d374SYoshinobu Inoue 
1704d201fe46SDaniel Eischen 	if ((s = _socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
17057d56d374SYoshinobu Inoue 		return NULL;
1706d201fe46SDaniel Eischen 	(void)_setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
17077d56d374SYoshinobu Inoue 			 (char *)&filter, sizeof(filter));
1708d201fe46SDaniel Eischen 	cc = _sendmsg(s, &msg, 0);
17097d56d374SYoshinobu Inoue 	if (cc < 0) {
17109233c4d9SJason Evans 		_close(s);
17117d56d374SYoshinobu Inoue 		return NULL;
17127d56d374SYoshinobu Inoue 	}
17137d56d374SYoshinobu Inoue 	FD_SET(s, &s_fds);
17147d56d374SYoshinobu Inoue 	for (;;) {
17157d56d374SYoshinobu Inoue 		fds = s_fds;
1716d201fe46SDaniel Eischen 		if (_select(s + 1, &fds, NULL, NULL, &tout) <= 0) {
17179233c4d9SJason Evans 			_close(s);
17187d56d374SYoshinobu Inoue 			return NULL;
17197d56d374SYoshinobu Inoue 		}
17207d56d374SYoshinobu Inoue 		len = sizeof(sin6);
1721d201fe46SDaniel Eischen 		cc = _recvfrom(s, buf, sizeof(buf), 0,
17227d56d374SYoshinobu Inoue 			      (struct sockaddr *)&sin6, &len);
17237d56d374SYoshinobu Inoue 		if (cc <= 0) {
17249233c4d9SJason Evans 			_close(s);
17257d56d374SYoshinobu Inoue 			return NULL;
17267d56d374SYoshinobu Inoue 		}
17277d56d374SYoshinobu Inoue 		if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
17287d56d374SYoshinobu Inoue 			continue;
17297d56d374SYoshinobu Inoue 		if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr))
17307d56d374SYoshinobu Inoue 			continue;
17317d56d374SYoshinobu Inoue 		fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr));
17327d56d374SYoshinobu Inoue 		if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY)
17337d56d374SYoshinobu Inoue 			break;
17347d56d374SYoshinobu Inoue 	}
17359233c4d9SJason Evans 	_close(s);
17367d56d374SYoshinobu Inoue 	if (fr->icmp6_fqdn_cookie[1] != 0) {
17377d56d374SYoshinobu Inoue 		/* rfc1788 type */
17387d56d374SYoshinobu Inoue 		name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4;
17397d56d374SYoshinobu Inoue 		len = (buf + cc) - name;
17407d56d374SYoshinobu Inoue 	} else {
17417d56d374SYoshinobu Inoue 		len = fr->icmp6_fqdn_namelen;
17427d56d374SYoshinobu Inoue 		name = fr->icmp6_fqdn_name;
17437d56d374SYoshinobu Inoue 	}
17447d56d374SYoshinobu Inoue 	if (len <= 0)
17457d56d374SYoshinobu Inoue 		return NULL;
17467d56d374SYoshinobu Inoue 	name[len] = 0;
17477d56d374SYoshinobu Inoue 
17487d56d374SYoshinobu Inoue 	if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL)
17497d56d374SYoshinobu Inoue 		return NULL;
17507d56d374SYoshinobu Inoue 	/* XXX: limit number of cached entries */
17517d56d374SYoshinobu Inoue 	hc->hc_ifindex = ifindex;
17527d56d374SYoshinobu Inoue 	hc->hc_addr = *addr;
17537d56d374SYoshinobu Inoue 	hc->hc_name = strdup(name);
17547d56d374SYoshinobu Inoue 	hc->hc_next = hc_head;
17557d56d374SYoshinobu Inoue 	hc_head = hc;
17567d56d374SYoshinobu Inoue 	return hc->hc_name;
17577d56d374SYoshinobu Inoue }
17587d56d374SYoshinobu Inoue 
17597d56d374SYoshinobu Inoue static struct hostent *
17607d56d374SYoshinobu Inoue _icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
17617d56d374SYoshinobu Inoue {
17627d56d374SYoshinobu Inoue 	char *hname;
17637d56d374SYoshinobu Inoue 	int ifindex;
17647d56d374SYoshinobu Inoue 	struct in6_addr addr6;
17657d56d374SYoshinobu Inoue 
17667d56d374SYoshinobu Inoue 	if (af != AF_INET6) {
17677d56d374SYoshinobu Inoue 		/*
17687d56d374SYoshinobu Inoue 		 * Note: rfc1788 defines Who Are You for IPv4,
17697d56d374SYoshinobu Inoue 		 * but no one implements it.
17707d56d374SYoshinobu Inoue 		 */
17717d56d374SYoshinobu Inoue 		return NULL;
17727d56d374SYoshinobu Inoue 	}
17737d56d374SYoshinobu Inoue 
17747d56d374SYoshinobu Inoue 	memcpy(&addr6, addr, addrlen);
17757d56d374SYoshinobu Inoue 	ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
17767d56d374SYoshinobu Inoue 	addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
17777d56d374SYoshinobu Inoue 
17787d56d374SYoshinobu Inoue 	if (!IN6_IS_ADDR_LINKLOCAL(&addr6))
17797d56d374SYoshinobu Inoue 		return NULL;	/*XXX*/
17807d56d374SYoshinobu Inoue 
17817d56d374SYoshinobu Inoue 	if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL)
17827d56d374SYoshinobu Inoue 		return NULL;
17837d56d374SYoshinobu Inoue 	return _hpaddr(af, hname, &addr6, errp);
17847d56d374SYoshinobu Inoue }
17857d56d374SYoshinobu Inoue #endif /* ICMPNL */
1786