xref: /freebsd/lib/libc/net/name6.c (revision 146cd1bc)
13f587e57SKris Kennaway /*	$KAME: name6.c,v 1.25 2000/06/26 16:44:40 itojun Exp $	*/
273b30f0cSJun-ichiro itojun Hagino 
37d56d374SYoshinobu Inoue /*
47d56d374SYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
57d56d374SYoshinobu Inoue  * All rights reserved.
67d56d374SYoshinobu Inoue  *
77d56d374SYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
87d56d374SYoshinobu Inoue  * modification, are permitted provided that the following conditions
97d56d374SYoshinobu Inoue  * are met:
107d56d374SYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
117d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
127d56d374SYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
137d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
147d56d374SYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
157d56d374SYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
167d56d374SYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
177d56d374SYoshinobu Inoue  *    without specific prior written permission.
187d56d374SYoshinobu Inoue  *
197d56d374SYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
207d56d374SYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
217d56d374SYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
227d56d374SYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
237d56d374SYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
247d56d374SYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
257d56d374SYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
267d56d374SYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
277d56d374SYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
287d56d374SYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
297d56d374SYoshinobu Inoue  * SUCH DAMAGE.
307d56d374SYoshinobu Inoue  */
3173b30f0cSJun-ichiro itojun Hagino /*
3273b30f0cSJun-ichiro itojun Hagino  * ++Copyright++ 1985, 1988, 1993
3373b30f0cSJun-ichiro itojun Hagino  * -
3473b30f0cSJun-ichiro itojun Hagino  * Copyright (c) 1985, 1988, 1993
3573b30f0cSJun-ichiro itojun Hagino  *    The Regents of the University of California.  All rights reserved.
3673b30f0cSJun-ichiro itojun Hagino  *
3773b30f0cSJun-ichiro itojun Hagino  * Redistribution and use in source and binary forms, with or without
3873b30f0cSJun-ichiro itojun Hagino  * modification, are permitted provided that the following conditions
3973b30f0cSJun-ichiro itojun Hagino  * are met:
4073b30f0cSJun-ichiro itojun Hagino  * 1. Redistributions of source code must retain the above copyright
4173b30f0cSJun-ichiro itojun Hagino  *    notice, this list of conditions and the following disclaimer.
4273b30f0cSJun-ichiro itojun Hagino  * 2. Redistributions in binary form must reproduce the above copyright
4373b30f0cSJun-ichiro itojun Hagino  *    notice, this list of conditions and the following disclaimer in the
4473b30f0cSJun-ichiro itojun Hagino  *    documentation and/or other materials provided with the distribution.
4573b30f0cSJun-ichiro itojun Hagino  * 3. All advertising materials mentioning features or use of this software
4673b30f0cSJun-ichiro itojun Hagino  *    must display the following acknowledgement:
4773b30f0cSJun-ichiro itojun Hagino  * 	This product includes software developed by the University of
4873b30f0cSJun-ichiro itojun Hagino  * 	California, Berkeley and its contributors.
4973b30f0cSJun-ichiro itojun Hagino  * 4. Neither the name of the University nor the names of its contributors
5073b30f0cSJun-ichiro itojun Hagino  *    may be used to endorse or promote products derived from this software
5173b30f0cSJun-ichiro itojun Hagino  *    without specific prior written permission.
5273b30f0cSJun-ichiro itojun Hagino  *
5373b30f0cSJun-ichiro itojun Hagino  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5473b30f0cSJun-ichiro itojun Hagino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5573b30f0cSJun-ichiro itojun Hagino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5673b30f0cSJun-ichiro itojun Hagino  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5773b30f0cSJun-ichiro itojun Hagino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5873b30f0cSJun-ichiro itojun Hagino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5973b30f0cSJun-ichiro itojun Hagino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6073b30f0cSJun-ichiro itojun Hagino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6173b30f0cSJun-ichiro itojun Hagino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6273b30f0cSJun-ichiro itojun Hagino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6373b30f0cSJun-ichiro itojun Hagino  * SUCH DAMAGE.
6473b30f0cSJun-ichiro itojun Hagino  * -
6573b30f0cSJun-ichiro itojun Hagino  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
6673b30f0cSJun-ichiro itojun Hagino  *
6773b30f0cSJun-ichiro itojun Hagino  * Permission to use, copy, modify, and distribute this software for any
6873b30f0cSJun-ichiro itojun Hagino  * purpose with or without fee is hereby granted, provided that the above
6973b30f0cSJun-ichiro itojun Hagino  * copyright notice and this permission notice appear in all copies, and that
7073b30f0cSJun-ichiro itojun Hagino  * the name of Digital Equipment Corporation not be used in advertising or
7173b30f0cSJun-ichiro itojun Hagino  * publicity pertaining to distribution of the document or software without
7273b30f0cSJun-ichiro itojun Hagino  * specific, written prior permission.
7373b30f0cSJun-ichiro itojun Hagino  *
7473b30f0cSJun-ichiro itojun Hagino  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
7573b30f0cSJun-ichiro itojun Hagino  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
7673b30f0cSJun-ichiro itojun Hagino  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
7773b30f0cSJun-ichiro itojun Hagino  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
7873b30f0cSJun-ichiro itojun Hagino  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
7973b30f0cSJun-ichiro itojun Hagino  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
8073b30f0cSJun-ichiro itojun Hagino  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
8173b30f0cSJun-ichiro itojun Hagino  * SOFTWARE.
8273b30f0cSJun-ichiro itojun Hagino  * -
8373b30f0cSJun-ichiro itojun Hagino  * --Copyright--
8473b30f0cSJun-ichiro itojun Hagino  */
8573b30f0cSJun-ichiro itojun Hagino 
867d56d374SYoshinobu Inoue /*
877d56d374SYoshinobu Inoue  *	Atsushi Onoe <onoe@sm.sony.co.jp>
887d56d374SYoshinobu Inoue  */
897d56d374SYoshinobu Inoue 
907d56d374SYoshinobu Inoue /*
917d56d374SYoshinobu Inoue  * TODO for thread safe
927d56d374SYoshinobu Inoue  *	use mutex for _hostconf, _hostconf_init.
937d56d374SYoshinobu Inoue  *	rewrite resolvers to be thread safe
947d56d374SYoshinobu Inoue  */
957d56d374SYoshinobu Inoue 
96333fc21eSDavid E. O'Brien #include <sys/cdefs.h>
97333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$");
98333fc21eSDavid E. O'Brien 
99d201fe46SDaniel Eischen #include "namespace.h"
1007d56d374SYoshinobu Inoue #include <sys/param.h>
1017d56d374SYoshinobu Inoue #include <sys/socket.h>
1027d56d374SYoshinobu Inoue #include <sys/time.h>
103e6f35403SYoshinobu Inoue #include <sys/queue.h>
1047d56d374SYoshinobu Inoue #include <netinet/in.h>
105b8b31f33SHajimu UMEMOTO #ifdef INET6
106b8b31f33SHajimu UMEMOTO #include <net/if.h>
107b8b31f33SHajimu UMEMOTO #include <net/if_var.h>
108b8b31f33SHajimu UMEMOTO #include <sys/sysctl.h>
109146cd1bcSHajimu UMEMOTO #include <sys/ioctl.h>
110b8b31f33SHajimu UMEMOTO #include <netinet6/in6_var.h>	/* XXX */
111b8b31f33SHajimu UMEMOTO #endif
1127d56d374SYoshinobu Inoue 
1137d56d374SYoshinobu Inoue #include <arpa/inet.h>
1147d56d374SYoshinobu Inoue #include <arpa/nameser.h>
1157d56d374SYoshinobu Inoue 
116e6f35403SYoshinobu Inoue #include <errno.h>
1177d56d374SYoshinobu Inoue #include <netdb.h>
1187d56d374SYoshinobu Inoue #include <resolv.h>
1197d56d374SYoshinobu Inoue #include <stdio.h>
1207d56d374SYoshinobu Inoue #include <stdlib.h>
1217d56d374SYoshinobu Inoue #include <string.h>
122248aee62SJacques Vidrine #include <stdarg.h>
123248aee62SJacques Vidrine #include <nsswitch.h>
124e8baaa70SDaniel Eischen #include <pthread.h>
1257d56d374SYoshinobu Inoue #include <unistd.h>
126d201fe46SDaniel Eischen #include "un-namespace.h"
1277d56d374SYoshinobu Inoue 
1287d56d374SYoshinobu Inoue #ifndef _PATH_HOSTS
1297d56d374SYoshinobu Inoue #define	_PATH_HOSTS	"/etc/hosts"
1307d56d374SYoshinobu Inoue #endif
1317d56d374SYoshinobu Inoue 
1327d56d374SYoshinobu Inoue #ifndef MAXALIASES
1337d56d374SYoshinobu Inoue #define	MAXALIASES	10
1347d56d374SYoshinobu Inoue #endif
1357d56d374SYoshinobu Inoue #ifndef	MAXADDRS
1367d56d374SYoshinobu Inoue #define	MAXADDRS	20
1377d56d374SYoshinobu Inoue #endif
1387d56d374SYoshinobu Inoue #ifndef MAXDNAME
1397d56d374SYoshinobu Inoue #define	MAXDNAME	1025
1407d56d374SYoshinobu Inoue #endif
1417d56d374SYoshinobu Inoue 
1427d56d374SYoshinobu Inoue #ifdef INET6
1437d56d374SYoshinobu Inoue #define	ADDRLEN(af)	((af) == AF_INET6 ? sizeof(struct in6_addr) : \
1447d56d374SYoshinobu Inoue 					    sizeof(struct in_addr))
1457d56d374SYoshinobu Inoue #else
1467d56d374SYoshinobu Inoue #define	ADDRLEN(af)	sizeof(struct in_addr)
1477d56d374SYoshinobu Inoue #endif
1487d56d374SYoshinobu Inoue 
1497d56d374SYoshinobu Inoue #define	MAPADDR(ab, ina) \
1507d56d374SYoshinobu Inoue do {									\
1517d56d374SYoshinobu Inoue 	memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr));		\
1527d56d374SYoshinobu Inoue 	memset((ab)->map_zero, 0, sizeof((ab)->map_zero));		\
1537d56d374SYoshinobu Inoue 	memset((ab)->map_one, 0xff, sizeof((ab)->map_one));		\
1547d56d374SYoshinobu Inoue } while (0)
1557d56d374SYoshinobu Inoue #define	MAPADDRENABLED(flags) \
1567d56d374SYoshinobu Inoue 	(((flags) & AI_V4MAPPED) || \
1577d56d374SYoshinobu Inoue 	 (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled()))
1587d56d374SYoshinobu Inoue 
1597d56d374SYoshinobu Inoue union inx_addr {
1607d56d374SYoshinobu Inoue 	struct in_addr	in_addr;
1617d56d374SYoshinobu Inoue #ifdef INET6
1627d56d374SYoshinobu Inoue 	struct in6_addr	in6_addr;
1637d56d374SYoshinobu Inoue #endif
1647d56d374SYoshinobu Inoue 	struct {
1657d56d374SYoshinobu Inoue 		u_char	mau_zero[10];
1667d56d374SYoshinobu Inoue 		u_char	mau_one[2];
1677d56d374SYoshinobu Inoue 		struct in_addr mau_inaddr;
1687d56d374SYoshinobu Inoue 	}		map_addr_un;
1697d56d374SYoshinobu Inoue #define	map_zero	map_addr_un.mau_zero
1707d56d374SYoshinobu Inoue #define	map_one		map_addr_un.mau_one
1717d56d374SYoshinobu Inoue #define	map_inaddr	map_addr_un.mau_inaddr
1727d56d374SYoshinobu Inoue };
1737d56d374SYoshinobu Inoue 
174b8b31f33SHajimu UMEMOTO struct policyqueue {
175b8b31f33SHajimu UMEMOTO 	TAILQ_ENTRY(policyqueue) pc_entry;
176b8b31f33SHajimu UMEMOTO #ifdef INET6
177b8b31f33SHajimu UMEMOTO 	struct in6_addrpolicy pc_policy;
178b8b31f33SHajimu UMEMOTO #endif
179b8b31f33SHajimu UMEMOTO };
180b8b31f33SHajimu UMEMOTO TAILQ_HEAD(policyhead, policyqueue);
181b8b31f33SHajimu UMEMOTO 
182146cd1bcSHajimu UMEMOTO #define AIO_SRCFLAG_DEPRECATED	0x1
183146cd1bcSHajimu UMEMOTO 
184146cd1bcSHajimu UMEMOTO struct hp_order {
185146cd1bcSHajimu UMEMOTO 	union {
186146cd1bcSHajimu UMEMOTO 		struct sockaddr_storage aiou_ss;
187146cd1bcSHajimu UMEMOTO 		struct sockaddr aiou_sa;
188146cd1bcSHajimu UMEMOTO 	} aio_src_un;
189146cd1bcSHajimu UMEMOTO #define aio_srcsa aio_src_un.aiou_sa
190146cd1bcSHajimu UMEMOTO 	u_int32_t aio_srcflag;
191146cd1bcSHajimu UMEMOTO 	int aio_srcscope;
192146cd1bcSHajimu UMEMOTO 	int aio_dstscope;
193146cd1bcSHajimu UMEMOTO 	struct policyqueue *aio_srcpolicy;
194146cd1bcSHajimu UMEMOTO 	struct policyqueue *aio_dstpolicy;
195146cd1bcSHajimu UMEMOTO 	union {
196146cd1bcSHajimu UMEMOTO 		struct sockaddr_storage aiou_ss;
197146cd1bcSHajimu UMEMOTO 		struct sockaddr aiou_sa;
198146cd1bcSHajimu UMEMOTO 	} aio_un;
199146cd1bcSHajimu UMEMOTO #define aio_sa aio_un.aiou_sa
200146cd1bcSHajimu UMEMOTO 	int aio_matchlen;
201146cd1bcSHajimu UMEMOTO 	u_char *aio_h_addr;
202146cd1bcSHajimu UMEMOTO };
203146cd1bcSHajimu UMEMOTO 
2047d56d374SYoshinobu Inoue static struct	 hostent *_hpcopy(struct hostent *hp, int *errp);
2057d56d374SYoshinobu Inoue static struct	 hostent *_hpaddr(int af, const char *name, void *addr, int *errp);
2067d56d374SYoshinobu Inoue static struct	 hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp);
2077d56d374SYoshinobu Inoue #ifdef INET6
2087d56d374SYoshinobu Inoue static struct	 hostent *_hpmapv6(struct hostent *hp, int *errp);
2097d56d374SYoshinobu Inoue #endif
2107d56d374SYoshinobu Inoue static struct	 hostent *_hpsort(struct hostent *hp);
2117d56d374SYoshinobu Inoue static struct	 hostent *_ghbyname(const char *name, int af, int flags, int *errp);
2127d56d374SYoshinobu Inoue static char	*_hgetword(char **pp);
2137d56d374SYoshinobu Inoue static int	 _mapped_addr_enabled(void);
2147d56d374SYoshinobu Inoue 
215b8b31f33SHajimu UMEMOTO static struct	 hostent *_hpreorder(struct hostent *hp);
216b8b31f33SHajimu UMEMOTO static int	 get_addrselectpolicy(struct policyhead *);
217b8b31f33SHajimu UMEMOTO static void	 free_addrselectpolicy(struct policyhead *);
218b8b31f33SHajimu UMEMOTO static struct	 policyqueue *match_addrselectpolicy(struct sockaddr *,
219b8b31f33SHajimu UMEMOTO 	struct policyhead *);
220146cd1bcSHajimu UMEMOTO static void	 set_source(struct hp_order *, struct policyhead *);
221146cd1bcSHajimu UMEMOTO static int	 matchlen(struct sockaddr *, struct sockaddr *);
222146cd1bcSHajimu UMEMOTO static int	 comp_dst(const void *, const void *);
223146cd1bcSHajimu UMEMOTO static int	 gai_addr2scopetype(struct sockaddr *);
224b8b31f33SHajimu UMEMOTO 
2257d56d374SYoshinobu Inoue static FILE	*_files_open(int *errp);
226248aee62SJacques Vidrine static int	 _files_ghbyname(void *, void *, va_list);
227248aee62SJacques Vidrine static int	 _files_ghbyaddr(void *, void *, va_list);
22873b30f0cSJun-ichiro itojun Hagino #ifdef YP
229248aee62SJacques Vidrine static int	 _nis_ghbyname(void *, void *, va_list);
230248aee62SJacques Vidrine static int	 _nis_ghbyaddr(void *, void *, va_list);
23173b30f0cSJun-ichiro itojun Hagino #endif
232248aee62SJacques Vidrine static int	 _dns_ghbyname(void *, void *, va_list);
233248aee62SJacques Vidrine static int	 _dns_ghbyaddr(void *, void *, va_list);
234e0554a53SJacques Vidrine static void	 _dns_shent(int stayopen) __unused;
235e0554a53SJacques Vidrine static void	 _dns_ehent(void) __unused;
2367d56d374SYoshinobu Inoue #ifdef ICMPNL
237248aee62SJacques Vidrine static int	 _icmp_ghbyaddr(void *, void *, va_list);
2387d56d374SYoshinobu Inoue #endif /* ICMPNL */
2397d56d374SYoshinobu Inoue 
24071918af6SHajimu UMEMOTO /*
24133dee819SBrian Feldman  * XXX: Many dependencies are not thread-safe.  So, we share lock between
24271918af6SHajimu UMEMOTO  * getaddrinfo() and getipnodeby*().  Still, we cannot use
24371918af6SHajimu UMEMOTO  * getaddrinfo() and getipnodeby*() in conjunction with other
24433dee819SBrian Feldman  * functions which call them.
24571918af6SHajimu UMEMOTO  */
246e8baaa70SDaniel Eischen #include "libc_private.h"
247e8baaa70SDaniel Eischen extern pthread_mutex_t __getaddrinfo_thread_lock;
24871918af6SHajimu UMEMOTO #define THREAD_LOCK() \
249e8baaa70SDaniel Eischen 	if (__isthreaded) _pthread_mutex_lock(&__getaddrinfo_thread_lock);
25071918af6SHajimu UMEMOTO #define THREAD_UNLOCK() \
251e8baaa70SDaniel Eischen 	if (__isthreaded) _pthread_mutex_unlock(&__getaddrinfo_thread_lock);
25271918af6SHajimu UMEMOTO 
253248aee62SJacques Vidrine /* Host lookup order if nsswitch.conf is broken or nonexistant */
254248aee62SJacques Vidrine static const ns_src default_src[] = {
255248aee62SJacques Vidrine 	{ NSSRC_FILES, NS_SUCCESS },
256248aee62SJacques Vidrine 	{ NSSRC_DNS, NS_SUCCESS },
2577d56d374SYoshinobu Inoue #ifdef ICMPNL
258248aee62SJacques Vidrine #define NSSRC_ICMP "icmp"
259248aee62SJacques Vidrine 	{ NSSRC_ICMP, NS_SUCCESS },
26073b30f0cSJun-ichiro itojun Hagino #endif
261248aee62SJacques Vidrine 	{ 0 }
262248aee62SJacques Vidrine };
2637d56d374SYoshinobu Inoue 
2647d56d374SYoshinobu Inoue /*
2657d56d374SYoshinobu Inoue  * Check if kernel supports mapped address.
2667d56d374SYoshinobu Inoue  *	implementation dependent
2677d56d374SYoshinobu Inoue  */
2687d56d374SYoshinobu Inoue #ifdef __KAME__
2697d56d374SYoshinobu Inoue #include <sys/sysctl.h>
2707d56d374SYoshinobu Inoue #endif /* __KAME__ */
2717d56d374SYoshinobu Inoue 
2727d56d374SYoshinobu Inoue static int
2737d56d374SYoshinobu Inoue _mapped_addr_enabled(void)
2747d56d374SYoshinobu Inoue {
2757d56d374SYoshinobu Inoue 	/* implementation dependent check */
2767d56d374SYoshinobu Inoue #if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR)
2777d56d374SYoshinobu Inoue 	int mib[4];
2787d56d374SYoshinobu Inoue 	size_t len;
2797d56d374SYoshinobu Inoue 	int val;
2807d56d374SYoshinobu Inoue 
2817d56d374SYoshinobu Inoue 	mib[0] = CTL_NET;
2827d56d374SYoshinobu Inoue 	mib[1] = PF_INET6;
2837d56d374SYoshinobu Inoue 	mib[2] = IPPROTO_IPV6;
2847d56d374SYoshinobu Inoue 	mib[3] = IPV6CTL_MAPPED_ADDR;
2857d56d374SYoshinobu Inoue 	len = sizeof(val);
2867d56d374SYoshinobu Inoue 	if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0)
2877d56d374SYoshinobu Inoue 		return 1;
2887d56d374SYoshinobu Inoue #endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */
2897d56d374SYoshinobu Inoue 	return 0;
2907d56d374SYoshinobu Inoue }
2917d56d374SYoshinobu Inoue 
2927d56d374SYoshinobu Inoue /*
2937d56d374SYoshinobu Inoue  * Functions defined in RFC2553
29473b30f0cSJun-ichiro itojun Hagino  *	getipnodebyname, getipnodebyaddr, freehostent
2957d56d374SYoshinobu Inoue  */
2967d56d374SYoshinobu Inoue 
2977d56d374SYoshinobu Inoue static struct hostent *
2987d56d374SYoshinobu Inoue _ghbyname(const char *name, int af, int flags, int *errp)
2997d56d374SYoshinobu Inoue {
3007d56d374SYoshinobu Inoue 	struct hostent *hp;
301cb0600bdSJacques Vidrine 	int rval;
302248aee62SJacques Vidrine 
303248aee62SJacques Vidrine 	static const ns_dtab dtab[] = {
304248aee62SJacques Vidrine 		NS_FILES_CB(_files_ghbyname, NULL)
305248aee62SJacques Vidrine 		{ NSSRC_DNS, _dns_ghbyname, NULL },
306248aee62SJacques Vidrine 		NS_NIS_CB(_nis_ghbyname, NULL)
307248aee62SJacques Vidrine 		{ 0 }
308248aee62SJacques Vidrine 	};
3097d56d374SYoshinobu Inoue 
3107d56d374SYoshinobu Inoue 	if (flags & AI_ADDRCONFIG) {
3117d56d374SYoshinobu Inoue 		int s;
3127d56d374SYoshinobu Inoue 
3137d56d374SYoshinobu Inoue 		/*
3147d56d374SYoshinobu Inoue 		 * TODO:
3157d56d374SYoshinobu Inoue 		 * Note that implementation dependent test for address
3167d56d374SYoshinobu Inoue 		 * configuration should be done everytime called
3177d56d374SYoshinobu Inoue 		 * (or apropriate interval),
3187d56d374SYoshinobu Inoue 		 * because addresses will be dynamically assigned or deleted.
3197d56d374SYoshinobu Inoue 		 */
320e6f35403SYoshinobu Inoue 		if (af == AF_UNSPEC) {
321d201fe46SDaniel Eischen 			if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
322e6f35403SYoshinobu Inoue 				af = AF_INET;
323e6f35403SYoshinobu Inoue 			else {
3249233c4d9SJason Evans 				_close(s);
325d201fe46SDaniel Eischen 				if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0)
326e6f35403SYoshinobu Inoue 					af = AF_INET6;
327e6f35403SYoshinobu Inoue 				else
328e6f35403SYoshinobu Inoue 				_close(s);
329e6f35403SYoshinobu Inoue 			}
330e6f35403SYoshinobu Inoue 
331e6f35403SYoshinobu Inoue 		}
332e6f35403SYoshinobu Inoue 		if (af != AF_UNSPEC) {
333d201fe46SDaniel Eischen 			if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
334e6f35403SYoshinobu Inoue 				return NULL;
335e6f35403SYoshinobu Inoue 			_close(s);
336e6f35403SYoshinobu Inoue 		}
3377d56d374SYoshinobu Inoue 	}
3387d56d374SYoshinobu Inoue 
33920e0e084SJacques Vidrine 	rval = _nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyname", default_src,
340248aee62SJacques Vidrine 			  name, af, errp);
341248aee62SJacques Vidrine 	return (rval == NS_SUCCESS) ? hp : NULL;
3427d56d374SYoshinobu Inoue }
3437d56d374SYoshinobu Inoue 
344e6f35403SYoshinobu Inoue /* getipnodebyname() internal routine for multiple query(PF_UNSPEC) support. */
3457d56d374SYoshinobu Inoue struct hostent *
346e6f35403SYoshinobu Inoue _getipnodebyname_multi(const char *name, int af, int flags, int *errp)
3477d56d374SYoshinobu Inoue {
3487d56d374SYoshinobu Inoue 	struct hostent *hp;
3497d56d374SYoshinobu Inoue 	union inx_addr addrbuf;
3507d56d374SYoshinobu Inoue 
351e6f35403SYoshinobu Inoue 	/* XXX: PF_UNSPEC is only supposed to be passed from getaddrinfo() */
3527d56d374SYoshinobu Inoue 	if (af != AF_INET
3537d56d374SYoshinobu Inoue #ifdef INET6
3547d56d374SYoshinobu Inoue 	    && af != AF_INET6
3557d56d374SYoshinobu Inoue #endif
356e6f35403SYoshinobu Inoue 	    && af != PF_UNSPEC
3577d56d374SYoshinobu Inoue 		)
3587d56d374SYoshinobu Inoue 	{
3597d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
3607d56d374SYoshinobu Inoue 		return NULL;
3617d56d374SYoshinobu Inoue 	}
3627d56d374SYoshinobu Inoue 
3637d56d374SYoshinobu Inoue #ifdef INET6
3647d56d374SYoshinobu Inoue 	/* special case for literal address */
3657d56d374SYoshinobu Inoue 	if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
3667d56d374SYoshinobu Inoue 		if (af != AF_INET6) {
3677d56d374SYoshinobu Inoue 			*errp = HOST_NOT_FOUND;
3687d56d374SYoshinobu Inoue 			return NULL;
3697d56d374SYoshinobu Inoue 		}
3707d56d374SYoshinobu Inoue 		return _hpaddr(af, name, &addrbuf, errp);
3717d56d374SYoshinobu Inoue 	}
3727d56d374SYoshinobu Inoue #endif
373be26adb5SYoshinobu Inoue 	if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) {
3747d56d374SYoshinobu Inoue 		if (af != AF_INET) {
3757d56d374SYoshinobu Inoue 			if (MAPADDRENABLED(flags)) {
3767d56d374SYoshinobu Inoue 				MAPADDR(&addrbuf, &addrbuf.in_addr);
3777d56d374SYoshinobu Inoue 			} else {
3787d56d374SYoshinobu Inoue 				*errp = HOST_NOT_FOUND;
3797d56d374SYoshinobu Inoue 				return NULL;
3807d56d374SYoshinobu Inoue 			}
3817d56d374SYoshinobu Inoue 		}
3827d56d374SYoshinobu Inoue 		return _hpaddr(af, name, &addrbuf, errp);
3837d56d374SYoshinobu Inoue 	}
3847d56d374SYoshinobu Inoue 
3857d56d374SYoshinobu Inoue 	*errp = HOST_NOT_FOUND;
3867d56d374SYoshinobu Inoue 	hp = _ghbyname(name, af, flags, errp);
3877d56d374SYoshinobu Inoue 
3887d56d374SYoshinobu Inoue #ifdef INET6
3897d56d374SYoshinobu Inoue 	if (af == AF_INET6
3907d56d374SYoshinobu Inoue 	&&  ((flags & AI_ALL) || hp == NULL)
3917d56d374SYoshinobu Inoue 	&&  (MAPADDRENABLED(flags))) {
3927d56d374SYoshinobu Inoue 		struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp);
3937d56d374SYoshinobu Inoue 		if (hp == NULL)
3947d56d374SYoshinobu Inoue 			hp = _hpmapv6(hp2, errp);
3957d56d374SYoshinobu Inoue 		else {
3967d56d374SYoshinobu Inoue 			if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) {
3977d56d374SYoshinobu Inoue 				freehostent(hp2);
3987d56d374SYoshinobu Inoue 				hp2 = NULL;
3997d56d374SYoshinobu Inoue 			}
4007d56d374SYoshinobu Inoue 			hp = _hpmerge(hp, hp2, errp);
4017d56d374SYoshinobu Inoue 		}
4027d56d374SYoshinobu Inoue 	}
4037d56d374SYoshinobu Inoue #endif
404b8b31f33SHajimu UMEMOTO 	return _hpreorder(_hpsort(hp));
4057d56d374SYoshinobu Inoue }
4067d56d374SYoshinobu Inoue 
4077d56d374SYoshinobu Inoue struct hostent *
408e6f35403SYoshinobu Inoue getipnodebyname(const char *name, int af, int flags, int *errp)
409e6f35403SYoshinobu Inoue {
410e6f35403SYoshinobu Inoue 	if (af != AF_INET
411e6f35403SYoshinobu Inoue #ifdef INET6
412e6f35403SYoshinobu Inoue 	    && af != AF_INET6
413e6f35403SYoshinobu Inoue #endif
414e6f35403SYoshinobu Inoue 		)
415e6f35403SYoshinobu Inoue 	{
416e6f35403SYoshinobu Inoue 		*errp = NO_RECOVERY;
417e6f35403SYoshinobu Inoue 		return NULL;
418e6f35403SYoshinobu Inoue 	}
419e6f35403SYoshinobu Inoue 	return(_getipnodebyname_multi(name, af ,flags, errp));
420e6f35403SYoshinobu Inoue }
421e6f35403SYoshinobu Inoue 
422e6f35403SYoshinobu Inoue struct hostent *
4237d56d374SYoshinobu Inoue getipnodebyaddr(const void *src, size_t len, int af, int *errp)
4247d56d374SYoshinobu Inoue {
4257d56d374SYoshinobu Inoue 	struct hostent *hp;
426cb0600bdSJacques Vidrine 	int rval;
4277d56d374SYoshinobu Inoue #ifdef INET6
4287d56d374SYoshinobu Inoue 	struct in6_addr addrbuf;
4297d56d374SYoshinobu Inoue #else
4307d56d374SYoshinobu Inoue 	struct in_addr addrbuf;
4317d56d374SYoshinobu Inoue #endif
4327d56d374SYoshinobu Inoue 
433248aee62SJacques Vidrine 	static const ns_dtab dtab[] = {
434248aee62SJacques Vidrine 		NS_FILES_CB(_files_ghbyaddr, NULL)
435248aee62SJacques Vidrine 		{ NSSRC_DNS, _dns_ghbyaddr, NULL },
436248aee62SJacques Vidrine 		NS_NIS_CB(_nis_ghbyaddr, NULL)
437248aee62SJacques Vidrine #ifdef ICMPNL
438248aee62SJacques Vidrine 		{ NSSRC_ICMP, _icmp_ghbyaddr, NULL },
439248aee62SJacques Vidrine #endif
440248aee62SJacques Vidrine 		{ 0 }
441248aee62SJacques Vidrine 	};
442248aee62SJacques Vidrine 
4437d56d374SYoshinobu Inoue 	*errp = HOST_NOT_FOUND;
4447d56d374SYoshinobu Inoue 
4457d56d374SYoshinobu Inoue 	switch (af) {
4467d56d374SYoshinobu Inoue 	case AF_INET:
4477d56d374SYoshinobu Inoue 		if (len != sizeof(struct in_addr)) {
4487d56d374SYoshinobu Inoue 			*errp = NO_RECOVERY;
4497d56d374SYoshinobu Inoue 			return NULL;
4507d56d374SYoshinobu Inoue 		}
4517d56d374SYoshinobu Inoue 		if ((long)src & ~(sizeof(struct in_addr) - 1)) {
4527d56d374SYoshinobu Inoue 			memcpy(&addrbuf, src, len);
4537d56d374SYoshinobu Inoue 			src = &addrbuf;
4547d56d374SYoshinobu Inoue 		}
4557d56d374SYoshinobu Inoue 		if (((struct in_addr *)src)->s_addr == 0)
4567d56d374SYoshinobu Inoue 			return NULL;
4577d56d374SYoshinobu Inoue 		break;
4587d56d374SYoshinobu Inoue #ifdef INET6
4597d56d374SYoshinobu Inoue 	case AF_INET6:
4607d56d374SYoshinobu Inoue 		if (len != sizeof(struct in6_addr)) {
4617d56d374SYoshinobu Inoue 			*errp = NO_RECOVERY;
4627d56d374SYoshinobu Inoue 			return NULL;
4637d56d374SYoshinobu Inoue 		}
4647d56d374SYoshinobu Inoue 		if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) {	/*XXX*/
4657d56d374SYoshinobu Inoue 			memcpy(&addrbuf, src, len);
4667d56d374SYoshinobu Inoue 			src = &addrbuf;
4677d56d374SYoshinobu Inoue 		}
4683d670abcSYoshinobu Inoue 		if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src))
4693d670abcSYoshinobu Inoue 			return NULL;
4707d56d374SYoshinobu Inoue 		if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)
4717d56d374SYoshinobu Inoue 		||  IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) {
4727d56d374SYoshinobu Inoue 			src = (char *)src +
4737d56d374SYoshinobu Inoue 			    (sizeof(struct in6_addr) - sizeof(struct in_addr));
4747d56d374SYoshinobu Inoue 			af = AF_INET;
4757d56d374SYoshinobu Inoue 			len = sizeof(struct in_addr);
4767d56d374SYoshinobu Inoue 		}
4777d56d374SYoshinobu Inoue 		break;
4787d56d374SYoshinobu Inoue #endif
4797d56d374SYoshinobu Inoue 	default:
4807d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
4817d56d374SYoshinobu Inoue 		return NULL;
4827d56d374SYoshinobu Inoue 	}
4837d56d374SYoshinobu Inoue 
48420e0e084SJacques Vidrine 	rval = _nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyaddr", default_src,
485248aee62SJacques Vidrine 			  src, len, af, errp);
486248aee62SJacques Vidrine 	return (rval == NS_SUCCESS) ? hp : NULL;
4877d56d374SYoshinobu Inoue }
4887d56d374SYoshinobu Inoue 
4897d56d374SYoshinobu Inoue void
4907d56d374SYoshinobu Inoue freehostent(struct hostent *ptr)
4917d56d374SYoshinobu Inoue {
4927d56d374SYoshinobu Inoue 	free(ptr);
4937d56d374SYoshinobu Inoue }
4947d56d374SYoshinobu Inoue 
4957d56d374SYoshinobu Inoue #if 0
4967d56d374SYoshinobu Inoue 
4977d56d374SYoshinobu Inoue /* XXX: should be deprecated */
4987d56d374SYoshinobu Inoue struct hostent *
4997d56d374SYoshinobu Inoue getnodebyname(const char *name, int af, int flags)
5007d56d374SYoshinobu Inoue {
5017d56d374SYoshinobu Inoue 	return getipnodebyname(name, af, flags, &h_errno);
5027d56d374SYoshinobu Inoue }
5037d56d374SYoshinobu Inoue 
5047d56d374SYoshinobu Inoue #ifdef __warn_references
5057d56d374SYoshinobu Inoue __warn_references(getnodebyname,
5067d56d374SYoshinobu Inoue 	"warning: getnodebyname() deprecated, "
5077d56d374SYoshinobu Inoue 	"should use getaddrinfo() or getipnodebyname()");
5087d56d374SYoshinobu Inoue #endif
5097d56d374SYoshinobu Inoue 
5107d56d374SYoshinobu Inoue struct hostent *
5117d56d374SYoshinobu Inoue getnodebyaddr(const void *src, size_t len, int af)
5127d56d374SYoshinobu Inoue {
5137d56d374SYoshinobu Inoue 	return getipnodebyaddr(src, len, af, &h_errno);
5147d56d374SYoshinobu Inoue }
5157d56d374SYoshinobu Inoue 
5167d56d374SYoshinobu Inoue #ifdef __warn_references
5177d56d374SYoshinobu Inoue __warn_references(getnodebyaddr,
5187d56d374SYoshinobu Inoue 	"warning: getnodebyaddr() deprecated, "
5197d56d374SYoshinobu Inoue 	"should use getnameinfo() or getipnodebyaddr()");
5207d56d374SYoshinobu Inoue #endif
5217d56d374SYoshinobu Inoue 
5227d56d374SYoshinobu Inoue #endif
5237d56d374SYoshinobu Inoue 
5247d56d374SYoshinobu Inoue /*
5257d56d374SYoshinobu Inoue  * Private utility functions
5267d56d374SYoshinobu Inoue  */
5277d56d374SYoshinobu Inoue 
5287d56d374SYoshinobu Inoue /*
5297d56d374SYoshinobu Inoue  * _hpcopy: allocate and copy hostent structure
5307d56d374SYoshinobu Inoue  */
5317d56d374SYoshinobu Inoue static struct hostent *
5327d56d374SYoshinobu Inoue _hpcopy(struct hostent *hp, int *errp)
5337d56d374SYoshinobu Inoue {
5347d56d374SYoshinobu Inoue 	struct hostent *nhp;
5357d56d374SYoshinobu Inoue 	char *cp, **pp;
5367d56d374SYoshinobu Inoue 	int size, addrsize;
5377d56d374SYoshinobu Inoue 	int nalias = 0, naddr = 0;
5387d56d374SYoshinobu Inoue 	int al_off;
5397d56d374SYoshinobu Inoue 	int i;
5407d56d374SYoshinobu Inoue 
5417d56d374SYoshinobu Inoue 	if (hp == NULL)
5427d56d374SYoshinobu Inoue 		return hp;
5437d56d374SYoshinobu Inoue 
5447d56d374SYoshinobu Inoue 	/* count size to be allocated */
5457d56d374SYoshinobu Inoue 	size = sizeof(struct hostent);
54605c36511SHajimu UMEMOTO 	if (hp->h_name != NULL)
5477d56d374SYoshinobu Inoue 		size += strlen(hp->h_name) + 1;
5487d56d374SYoshinobu Inoue 	if ((pp = hp->h_aliases) != NULL) {
5497d56d374SYoshinobu Inoue 		for (i = 0; *pp != NULL; i++, pp++) {
5507d56d374SYoshinobu Inoue 			if (**pp != '\0') {
5517d56d374SYoshinobu Inoue 				size += strlen(*pp) + 1;
5527d56d374SYoshinobu Inoue 				nalias++;
5537d56d374SYoshinobu Inoue 			}
5547d56d374SYoshinobu Inoue 		}
5557d56d374SYoshinobu Inoue 	}
5567d56d374SYoshinobu Inoue 	/* adjust alignment */
5577d56d374SYoshinobu Inoue 	size = ALIGN(size);
5587d56d374SYoshinobu Inoue 	al_off = size;
5597d56d374SYoshinobu Inoue 	size += sizeof(char *) * (nalias + 1);
5607d56d374SYoshinobu Inoue 	addrsize = ALIGN(hp->h_length);
5617d56d374SYoshinobu Inoue 	if ((pp = hp->h_addr_list) != NULL) {
5627d56d374SYoshinobu Inoue 		while (*pp++ != NULL)
5637d56d374SYoshinobu Inoue 			naddr++;
5647d56d374SYoshinobu Inoue 	}
5657d56d374SYoshinobu Inoue 	size += addrsize * naddr;
5667d56d374SYoshinobu Inoue 	size += sizeof(char *) * (naddr + 1);
5677d56d374SYoshinobu Inoue 
5687d56d374SYoshinobu Inoue 	/* copy */
5697d56d374SYoshinobu Inoue 	if ((nhp = (struct hostent *)malloc(size)) == NULL) {
5707d56d374SYoshinobu Inoue 		*errp = TRY_AGAIN;
5717d56d374SYoshinobu Inoue 		return NULL;
5727d56d374SYoshinobu Inoue 	}
5737d56d374SYoshinobu Inoue 	cp = (char *)&nhp[1];
57405c36511SHajimu UMEMOTO 	if (hp->h_name != NULL) {
5757d56d374SYoshinobu Inoue 		nhp->h_name = cp;
5767d56d374SYoshinobu Inoue 		strcpy(cp, hp->h_name);
5777d56d374SYoshinobu Inoue 		cp += strlen(cp) + 1;
5787d56d374SYoshinobu Inoue 	} else
5797d56d374SYoshinobu Inoue 		nhp->h_name = NULL;
5807d56d374SYoshinobu Inoue 	nhp->h_aliases = (char **)((char *)nhp + al_off);
5817d56d374SYoshinobu Inoue 	if ((pp = hp->h_aliases) != NULL) {
5827d56d374SYoshinobu Inoue 		for (i = 0; *pp != NULL; pp++) {
5837d56d374SYoshinobu Inoue 			if (**pp != '\0') {
5847d56d374SYoshinobu Inoue 				nhp->h_aliases[i++] = cp;
5857d56d374SYoshinobu Inoue 				strcpy(cp, *pp);
5867d56d374SYoshinobu Inoue 				cp += strlen(cp) + 1;
5877d56d374SYoshinobu Inoue 			}
5887d56d374SYoshinobu Inoue 		}
5897d56d374SYoshinobu Inoue 	}
5907d56d374SYoshinobu Inoue 	nhp->h_aliases[nalias] = NULL;
5917d56d374SYoshinobu Inoue 	cp = (char *)&nhp->h_aliases[nalias + 1];
5927d56d374SYoshinobu Inoue 	nhp->h_addrtype = hp->h_addrtype;
5937d56d374SYoshinobu Inoue 	nhp->h_length = hp->h_length;
5947d56d374SYoshinobu Inoue 	nhp->h_addr_list = (char **)cp;
5957d56d374SYoshinobu Inoue 	if ((pp = hp->h_addr_list) != NULL) {
5967d56d374SYoshinobu Inoue 		cp = (char *)&nhp->h_addr_list[naddr + 1];
5977d56d374SYoshinobu Inoue 		for (i = 0; *pp != NULL; pp++) {
5987d56d374SYoshinobu Inoue 			nhp->h_addr_list[i++] = cp;
5997d56d374SYoshinobu Inoue 			memcpy(cp, *pp, hp->h_length);
6007d56d374SYoshinobu Inoue 			cp += addrsize;
6017d56d374SYoshinobu Inoue 		}
6027d56d374SYoshinobu Inoue 	}
6037d56d374SYoshinobu Inoue 	nhp->h_addr_list[naddr] = NULL;
6047d56d374SYoshinobu Inoue 	return nhp;
6057d56d374SYoshinobu Inoue }
6067d56d374SYoshinobu Inoue 
6077d56d374SYoshinobu Inoue /*
6087d56d374SYoshinobu Inoue  * _hpaddr: construct hostent structure with one address
6097d56d374SYoshinobu Inoue  */
6107d56d374SYoshinobu Inoue static struct hostent *
6117d56d374SYoshinobu Inoue _hpaddr(int af, const char *name, void *addr, int *errp)
6127d56d374SYoshinobu Inoue {
6137d56d374SYoshinobu Inoue 	struct hostent *hp, hpbuf;
6147d56d374SYoshinobu Inoue 	char *addrs[2];
6157d56d374SYoshinobu Inoue 
6167d56d374SYoshinobu Inoue 	hp = &hpbuf;
6177d56d374SYoshinobu Inoue 	hp->h_name = (char *)name;
6187d56d374SYoshinobu Inoue 	hp->h_aliases = NULL;
6197d56d374SYoshinobu Inoue 	hp->h_addrtype = af;
6207d56d374SYoshinobu Inoue 	hp->h_length = ADDRLEN(af);
6217d56d374SYoshinobu Inoue 	hp->h_addr_list = addrs;
6227d56d374SYoshinobu Inoue 	addrs[0] = (char *)addr;
6237d56d374SYoshinobu Inoue 	addrs[1] = NULL;
6247d56d374SYoshinobu Inoue 	return _hpcopy(hp, errp);
6257d56d374SYoshinobu Inoue }
6267d56d374SYoshinobu Inoue 
6277d56d374SYoshinobu Inoue /*
6287d56d374SYoshinobu Inoue  * _hpmerge: merge 2 hostent structure, arguments will be freed
6297d56d374SYoshinobu Inoue  */
6307d56d374SYoshinobu Inoue static struct hostent *
6317d56d374SYoshinobu Inoue _hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp)
6327d56d374SYoshinobu Inoue {
6337d56d374SYoshinobu Inoue 	int i, j;
6347d56d374SYoshinobu Inoue 	int naddr, nalias;
6357d56d374SYoshinobu Inoue 	char **pp;
6367d56d374SYoshinobu Inoue 	struct hostent *hp, hpbuf;
6377d56d374SYoshinobu Inoue 	char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1];
6387d56d374SYoshinobu Inoue 	union inx_addr addrbuf[MAXADDRS];
6397d56d374SYoshinobu Inoue 
6407d56d374SYoshinobu Inoue 	if (hp1 == NULL)
6417d56d374SYoshinobu Inoue 		return hp2;
6427d56d374SYoshinobu Inoue 	if (hp2 == NULL)
6437d56d374SYoshinobu Inoue 		return hp1;
6447d56d374SYoshinobu Inoue 
6457d56d374SYoshinobu Inoue #define	HP(i)	(i == 1 ? hp1 : hp2)
6467d56d374SYoshinobu Inoue 	hp = &hpbuf;
6477d56d374SYoshinobu Inoue 	hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name);
6487d56d374SYoshinobu Inoue 	hp->h_aliases = aliases;
6497d56d374SYoshinobu Inoue 	nalias = 0;
6507d56d374SYoshinobu Inoue 	for (i = 1; i <= 2; i++) {
6517d56d374SYoshinobu Inoue 		if ((pp = HP(i)->h_aliases) == NULL)
6527d56d374SYoshinobu Inoue 			continue;
6537d56d374SYoshinobu Inoue 		for (; nalias < MAXALIASES && *pp != NULL; pp++) {
6547d56d374SYoshinobu Inoue 			/* check duplicates */
6557d56d374SYoshinobu Inoue 			for (j = 0; j < nalias; j++)
6567d56d374SYoshinobu Inoue 				if (strcasecmp(*pp, aliases[j]) == 0)
6577d56d374SYoshinobu Inoue 					break;
6587d56d374SYoshinobu Inoue 			if (j == nalias)
6597d56d374SYoshinobu Inoue 				aliases[nalias++] = *pp;
6607d56d374SYoshinobu Inoue 		}
6617d56d374SYoshinobu Inoue 	}
6627d56d374SYoshinobu Inoue 	aliases[nalias] = NULL;
6637d56d374SYoshinobu Inoue #ifdef INET6
6647d56d374SYoshinobu Inoue 	if (hp1->h_length != hp2->h_length) {
6657d56d374SYoshinobu Inoue 		hp->h_addrtype = AF_INET6;
6667d56d374SYoshinobu Inoue 		hp->h_length = sizeof(struct in6_addr);
6677d56d374SYoshinobu Inoue 	} else {
6687d56d374SYoshinobu Inoue #endif
6697d56d374SYoshinobu Inoue 		hp->h_addrtype = hp1->h_addrtype;
6707d56d374SYoshinobu Inoue 		hp->h_length = hp1->h_length;
6717d56d374SYoshinobu Inoue #ifdef INET6
6727d56d374SYoshinobu Inoue 	}
6737d56d374SYoshinobu Inoue #endif
6747d56d374SYoshinobu Inoue 	hp->h_addr_list = addrs;
6757d56d374SYoshinobu Inoue 	naddr = 0;
6767d56d374SYoshinobu Inoue 	for (i = 1; i <= 2; i++) {
6777d56d374SYoshinobu Inoue 		if ((pp = HP(i)->h_addr_list) == NULL)
6787d56d374SYoshinobu Inoue 			continue;
6797d56d374SYoshinobu Inoue 		if (HP(i)->h_length == hp->h_length) {
6807d56d374SYoshinobu Inoue 			while (naddr < MAXADDRS && *pp != NULL)
6817d56d374SYoshinobu Inoue 				addrs[naddr++] = *pp++;
6827d56d374SYoshinobu Inoue 		} else {
6837d56d374SYoshinobu Inoue 			/* copy IPv4 addr as mapped IPv6 addr */
6847d56d374SYoshinobu Inoue 			while (naddr < MAXADDRS && *pp != NULL) {
6857d56d374SYoshinobu Inoue 				MAPADDR(&addrbuf[naddr], *pp++);
6867d56d374SYoshinobu Inoue 				addrs[naddr] = (char *)&addrbuf[naddr];
6877d56d374SYoshinobu Inoue 				naddr++;
6887d56d374SYoshinobu Inoue 			}
6897d56d374SYoshinobu Inoue 		}
6907d56d374SYoshinobu Inoue 	}
6917d56d374SYoshinobu Inoue 	addrs[naddr] = NULL;
6927d56d374SYoshinobu Inoue 	hp = _hpcopy(hp, errp);
6937d56d374SYoshinobu Inoue 	freehostent(hp1);
6947d56d374SYoshinobu Inoue 	freehostent(hp2);
6957d56d374SYoshinobu Inoue 	return hp;
6967d56d374SYoshinobu Inoue }
6977d56d374SYoshinobu Inoue 
6987d56d374SYoshinobu Inoue /*
6997d56d374SYoshinobu Inoue  * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses
7007d56d374SYoshinobu Inoue  */
7017d56d374SYoshinobu Inoue #ifdef INET6
7027d56d374SYoshinobu Inoue static struct hostent *
7037d56d374SYoshinobu Inoue _hpmapv6(struct hostent *hp, int *errp)
7047d56d374SYoshinobu Inoue {
7057d56d374SYoshinobu Inoue 	struct hostent *hp6;
7067d56d374SYoshinobu Inoue 
7077d56d374SYoshinobu Inoue 	if (hp == NULL)
7087d56d374SYoshinobu Inoue 		return NULL;
7097d56d374SYoshinobu Inoue 	if (hp->h_addrtype == AF_INET6)
7107d56d374SYoshinobu Inoue 		return hp;
7117d56d374SYoshinobu Inoue 
7127d56d374SYoshinobu Inoue 	/* make dummy hostent to convert IPv6 address */
7137d56d374SYoshinobu Inoue 	if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) {
7147d56d374SYoshinobu Inoue 		*errp = TRY_AGAIN;
7157d56d374SYoshinobu Inoue 		return NULL;
7167d56d374SYoshinobu Inoue 	}
7177d56d374SYoshinobu Inoue 	hp6->h_name = NULL;
7187d56d374SYoshinobu Inoue 	hp6->h_aliases = NULL;
7197d56d374SYoshinobu Inoue 	hp6->h_addrtype = AF_INET6;
7207d56d374SYoshinobu Inoue 	hp6->h_length = sizeof(struct in6_addr);
7217d56d374SYoshinobu Inoue 	hp6->h_addr_list = NULL;
7227d56d374SYoshinobu Inoue 	return _hpmerge(hp6, hp, errp);
7237d56d374SYoshinobu Inoue }
7247d56d374SYoshinobu Inoue #endif
7257d56d374SYoshinobu Inoue 
7267d56d374SYoshinobu Inoue /*
7277d56d374SYoshinobu Inoue  * _hpsort: sort address by sortlist
7287d56d374SYoshinobu Inoue  */
7297d56d374SYoshinobu Inoue static struct hostent *
7307d56d374SYoshinobu Inoue _hpsort(struct hostent *hp)
7317d56d374SYoshinobu Inoue {
7327d56d374SYoshinobu Inoue 	int i, j, n;
7337d56d374SYoshinobu Inoue 	u_char *ap, *sp, *mp, **pp;
7347d56d374SYoshinobu Inoue 	char t;
7357d56d374SYoshinobu Inoue 	char order[MAXADDRS];
7367d56d374SYoshinobu Inoue 	int nsort = _res.nsort;
7377d56d374SYoshinobu Inoue 
7387d56d374SYoshinobu Inoue 	if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0)
7397d56d374SYoshinobu Inoue 		return hp;
7407d56d374SYoshinobu Inoue 	for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) {
7417d56d374SYoshinobu Inoue 		for (j = 0; j < nsort; j++) {
7427d56d374SYoshinobu Inoue #ifdef INET6
7437d56d374SYoshinobu Inoue 			if (_res_ext.sort_list[j].af != hp->h_addrtype)
7447d56d374SYoshinobu Inoue 				continue;
7457d56d374SYoshinobu Inoue 			sp = (u_char *)&_res_ext.sort_list[j].addr;
7467d56d374SYoshinobu Inoue 			mp = (u_char *)&_res_ext.sort_list[j].mask;
7477d56d374SYoshinobu Inoue #else
7487d56d374SYoshinobu Inoue 			sp = (u_char *)&_res.sort_list[j].addr;
7497d56d374SYoshinobu Inoue 			mp = (u_char *)&_res.sort_list[j].mask;
7507d56d374SYoshinobu Inoue #endif
7517d56d374SYoshinobu Inoue 			for (n = 0; n < hp->h_length; n++) {
7527d56d374SYoshinobu Inoue 				if ((ap[n] & mp[n]) != sp[n])
7537d56d374SYoshinobu Inoue 					break;
7547d56d374SYoshinobu Inoue 			}
7557d56d374SYoshinobu Inoue 			if (n == hp->h_length)
7567d56d374SYoshinobu Inoue 				break;
7577d56d374SYoshinobu Inoue 		}
7587d56d374SYoshinobu Inoue 		order[i] = j;
7597d56d374SYoshinobu Inoue 	}
7607d56d374SYoshinobu Inoue 	n = i;
7617d56d374SYoshinobu Inoue 	pp = (u_char **)hp->h_addr_list;
7627d56d374SYoshinobu Inoue 	for (i = 0; i < n - 1; i++) {
7637d56d374SYoshinobu Inoue 		for (j = i + 1; j < n; j++) {
7647d56d374SYoshinobu Inoue 			if (order[i] > order[j]) {
7657d56d374SYoshinobu Inoue 				ap = pp[i];
7667d56d374SYoshinobu Inoue 				pp[i] = pp[j];
7677d56d374SYoshinobu Inoue 				pp[j] = ap;
7687d56d374SYoshinobu Inoue 				t = order[i];
7697d56d374SYoshinobu Inoue 				order[i] = order[j];
7707d56d374SYoshinobu Inoue 				order[j] = t;
7717d56d374SYoshinobu Inoue 			}
7727d56d374SYoshinobu Inoue 		}
7737d56d374SYoshinobu Inoue 	}
7747d56d374SYoshinobu Inoue 	return hp;
7757d56d374SYoshinobu Inoue }
7767d56d374SYoshinobu Inoue 
7777d56d374SYoshinobu Inoue static char *
7787d56d374SYoshinobu Inoue _hgetword(char **pp)
7797d56d374SYoshinobu Inoue {
7807d56d374SYoshinobu Inoue 	char c, *p, *ret;
7817d56d374SYoshinobu Inoue 	const char *sp;
7827d56d374SYoshinobu Inoue 	static const char sep[] = "# \t\n";
7837d56d374SYoshinobu Inoue 
7847d56d374SYoshinobu Inoue 	ret = NULL;
7857d56d374SYoshinobu Inoue 	for (p = *pp; (c = *p) != '\0'; p++) {
7867d56d374SYoshinobu Inoue 		for (sp = sep; *sp != '\0'; sp++) {
7877d56d374SYoshinobu Inoue 			if (c == *sp)
7887d56d374SYoshinobu Inoue 				break;
7897d56d374SYoshinobu Inoue 		}
7907d56d374SYoshinobu Inoue 		if (c == '#')
7917d56d374SYoshinobu Inoue 			p[1] = '\0';	/* ignore rest of line */
7927d56d374SYoshinobu Inoue 		if (ret == NULL) {
7937d56d374SYoshinobu Inoue 			if (*sp == '\0')
7947d56d374SYoshinobu Inoue 				ret = p;
7957d56d374SYoshinobu Inoue 		} else {
7967d56d374SYoshinobu Inoue 			if (*sp != '\0') {
7977d56d374SYoshinobu Inoue 				*p++ = '\0';
7987d56d374SYoshinobu Inoue 				break;
7997d56d374SYoshinobu Inoue 			}
8007d56d374SYoshinobu Inoue 		}
8017d56d374SYoshinobu Inoue 	}
8027d56d374SYoshinobu Inoue 	*pp = p;
8037d56d374SYoshinobu Inoue 	if (ret == NULL || *ret == '\0')
8047d56d374SYoshinobu Inoue 		return NULL;
8057d56d374SYoshinobu Inoue 	return ret;
8067d56d374SYoshinobu Inoue }
8077d56d374SYoshinobu Inoue 
8087d56d374SYoshinobu Inoue /*
809b8b31f33SHajimu UMEMOTO  * _hpreorder: sort address by default address selection
810b8b31f33SHajimu UMEMOTO  */
811b8b31f33SHajimu UMEMOTO static struct hostent *
812b8b31f33SHajimu UMEMOTO _hpreorder(struct hostent *hp)
813b8b31f33SHajimu UMEMOTO {
814146cd1bcSHajimu UMEMOTO 	struct hp_order *aio;
815146cd1bcSHajimu UMEMOTO 	int i, n;
816146cd1bcSHajimu UMEMOTO 	u_char *ap;
817146cd1bcSHajimu UMEMOTO 	struct sockaddr *sa;
818b8b31f33SHajimu UMEMOTO 	struct policyhead policyhead;
819b8b31f33SHajimu UMEMOTO 
820146cd1bcSHajimu UMEMOTO 	if (hp == NULL)
821b8b31f33SHajimu UMEMOTO 		return hp;
822b8b31f33SHajimu UMEMOTO 
823b8b31f33SHajimu UMEMOTO 	switch (hp->h_addrtype) {
824b8b31f33SHajimu UMEMOTO 	case AF_INET:
825b8b31f33SHajimu UMEMOTO #ifdef INET6
826b8b31f33SHajimu UMEMOTO 	case AF_INET6:
827b8b31f33SHajimu UMEMOTO #endif
828146cd1bcSHajimu UMEMOTO 		break;
829b8b31f33SHajimu UMEMOTO 	default:
830b8b31f33SHajimu UMEMOTO 		free_addrselectpolicy(&policyhead);
831b8b31f33SHajimu UMEMOTO 		return hp;
832b8b31f33SHajimu UMEMOTO 	}
833b8b31f33SHajimu UMEMOTO 
834146cd1bcSHajimu UMEMOTO 	/* count the number of addrinfo elements for sorting. */
835146cd1bcSHajimu UMEMOTO 	for (n = 0; hp->h_addr_list[n] != NULL; n++)
836146cd1bcSHajimu UMEMOTO 		;
837146cd1bcSHajimu UMEMOTO 
838146cd1bcSHajimu UMEMOTO 	/*
839146cd1bcSHajimu UMEMOTO 	 * If the number is small enough, we can skip the reordering process.
840146cd1bcSHajimu UMEMOTO 	 */
841146cd1bcSHajimu UMEMOTO 	if (n <= 1)
842146cd1bcSHajimu UMEMOTO 		return hp;
843146cd1bcSHajimu UMEMOTO 
844146cd1bcSHajimu UMEMOTO 	/* allocate a temporary array for sort and initialization of it. */
845146cd1bcSHajimu UMEMOTO 	if ((aio = malloc(sizeof(*aio) * n)) == NULL)
846146cd1bcSHajimu UMEMOTO 		return hp;	/* give up reordering */
847146cd1bcSHajimu UMEMOTO 	memset(aio, 0, sizeof(*aio) * n);
848146cd1bcSHajimu UMEMOTO 
849146cd1bcSHajimu UMEMOTO 	/* retrieve address selection policy from the kernel */
850146cd1bcSHajimu UMEMOTO 	TAILQ_INIT(&policyhead);
851146cd1bcSHajimu UMEMOTO 	if (!get_addrselectpolicy(&policyhead)) {
852146cd1bcSHajimu UMEMOTO 		/* no policy is installed into kernel, we don't sort. */
853146cd1bcSHajimu UMEMOTO 		free(aio);
854146cd1bcSHajimu UMEMOTO 		return hp;
855b8b31f33SHajimu UMEMOTO 	}
856b8b31f33SHajimu UMEMOTO 
857146cd1bcSHajimu UMEMOTO 	for (i = 0; i < n; i++) {
858146cd1bcSHajimu UMEMOTO 		ap = (u_char *)hp->h_addr_list[i];
859146cd1bcSHajimu UMEMOTO 		aio[i].aio_h_addr = ap;
860146cd1bcSHajimu UMEMOTO 		sa = &aio[i].aio_sa;
861146cd1bcSHajimu UMEMOTO 		switch (hp->h_addrtype) {
862146cd1bcSHajimu UMEMOTO 		case AF_INET:
863146cd1bcSHajimu UMEMOTO 			sa->sa_family = AF_INET;
864146cd1bcSHajimu UMEMOTO 			sa->sa_len = sizeof(struct sockaddr_in);
865146cd1bcSHajimu UMEMOTO 			memcpy(&((struct sockaddr_in *)sa)->sin_addr, ap,
866146cd1bcSHajimu UMEMOTO 			    sizeof(struct in_addr));
867146cd1bcSHajimu UMEMOTO 			break;
868146cd1bcSHajimu UMEMOTO #ifdef INET6
869146cd1bcSHajimu UMEMOTO 		case AF_INET6:
870146cd1bcSHajimu UMEMOTO 			if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
871146cd1bcSHajimu UMEMOTO 				sa->sa_family = AF_INET;
872146cd1bcSHajimu UMEMOTO 				sa->sa_len = sizeof(struct sockaddr_in);
873146cd1bcSHajimu UMEMOTO 				memcpy(&((struct sockaddr_in *)sa)->sin_addr,
874146cd1bcSHajimu UMEMOTO 				    &ap[12], sizeof(struct in_addr));
875146cd1bcSHajimu UMEMOTO 			} else {
876146cd1bcSHajimu UMEMOTO 				sa->sa_family = AF_INET6;
877146cd1bcSHajimu UMEMOTO 				sa->sa_len = sizeof(struct sockaddr_in6);
878146cd1bcSHajimu UMEMOTO 				memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr,
879146cd1bcSHajimu UMEMOTO 				    ap, sizeof(struct in6_addr));
880146cd1bcSHajimu UMEMOTO 			}
881146cd1bcSHajimu UMEMOTO 			break;
882146cd1bcSHajimu UMEMOTO #endif
883146cd1bcSHajimu UMEMOTO 		}
884146cd1bcSHajimu UMEMOTO 		aio[i].aio_dstscope = gai_addr2scopetype(sa);
885146cd1bcSHajimu UMEMOTO 		aio[i].aio_dstpolicy = match_addrselectpolicy(sa, &policyhead);
886146cd1bcSHajimu UMEMOTO 		set_source(&aio[i], &policyhead);
887146cd1bcSHajimu UMEMOTO 	}
888146cd1bcSHajimu UMEMOTO 
889146cd1bcSHajimu UMEMOTO 	/* perform sorting. */
890146cd1bcSHajimu UMEMOTO 	qsort(aio, n, sizeof(*aio), comp_dst);
891146cd1bcSHajimu UMEMOTO 
892146cd1bcSHajimu UMEMOTO 	/* reorder the h_addr_list. */
893146cd1bcSHajimu UMEMOTO 	for (i = 0; i < n; i++)
894146cd1bcSHajimu UMEMOTO 		hp->h_addr_list[i] = aio[i].aio_h_addr;
895146cd1bcSHajimu UMEMOTO 
896b8b31f33SHajimu UMEMOTO 	/* cleanup and return */
897146cd1bcSHajimu UMEMOTO 	free(aio);
898b8b31f33SHajimu UMEMOTO 	free_addrselectpolicy(&policyhead);
899b8b31f33SHajimu UMEMOTO 	return hp;
900b8b31f33SHajimu UMEMOTO }
901b8b31f33SHajimu UMEMOTO 
902b8b31f33SHajimu UMEMOTO static int
903b8b31f33SHajimu UMEMOTO get_addrselectpolicy(head)
904b8b31f33SHajimu UMEMOTO 	struct policyhead *head;
905b8b31f33SHajimu UMEMOTO {
906b8b31f33SHajimu UMEMOTO #ifdef INET6
907b8b31f33SHajimu UMEMOTO 	int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY };
908b8b31f33SHajimu UMEMOTO 	size_t l;
909b8b31f33SHajimu UMEMOTO 	char *buf;
910b8b31f33SHajimu UMEMOTO 	struct in6_addrpolicy *pol, *ep;
911b8b31f33SHajimu UMEMOTO 
912b8b31f33SHajimu UMEMOTO 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0)
913b8b31f33SHajimu UMEMOTO 		return (0);
914b8b31f33SHajimu UMEMOTO 	if ((buf = malloc(l)) == NULL)
915b8b31f33SHajimu UMEMOTO 		return (0);
916b8b31f33SHajimu UMEMOTO 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
917b8b31f33SHajimu UMEMOTO 		free(buf);
918b8b31f33SHajimu UMEMOTO 		return (0);
919b8b31f33SHajimu UMEMOTO 	}
920b8b31f33SHajimu UMEMOTO 
921b8b31f33SHajimu UMEMOTO 	ep = (struct in6_addrpolicy *)(buf + l);
922b8b31f33SHajimu UMEMOTO 	for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) {
923b8b31f33SHajimu UMEMOTO 		struct policyqueue *new;
924b8b31f33SHajimu UMEMOTO 
925b8b31f33SHajimu UMEMOTO 		if ((new = malloc(sizeof(*new))) == NULL) {
926b8b31f33SHajimu UMEMOTO 			free_addrselectpolicy(head); /* make the list empty */
927b8b31f33SHajimu UMEMOTO 			break;
928b8b31f33SHajimu UMEMOTO 		}
929b8b31f33SHajimu UMEMOTO 		new->pc_policy = *pol;
930b8b31f33SHajimu UMEMOTO 		TAILQ_INSERT_TAIL(head, new, pc_entry);
931b8b31f33SHajimu UMEMOTO 	}
932b8b31f33SHajimu UMEMOTO 
933b8b31f33SHajimu UMEMOTO 	free(buf);
934b8b31f33SHajimu UMEMOTO 	return (1);
935b8b31f33SHajimu UMEMOTO #else
936b8b31f33SHajimu UMEMOTO 	return (0);
937b8b31f33SHajimu UMEMOTO #endif
938b8b31f33SHajimu UMEMOTO }
939b8b31f33SHajimu UMEMOTO 
940b8b31f33SHajimu UMEMOTO static void
941b8b31f33SHajimu UMEMOTO free_addrselectpolicy(head)
942b8b31f33SHajimu UMEMOTO 	struct policyhead *head;
943b8b31f33SHajimu UMEMOTO {
944b8b31f33SHajimu UMEMOTO 	struct policyqueue *ent, *nent;
945b8b31f33SHajimu UMEMOTO 
946b8b31f33SHajimu UMEMOTO 	for (ent = TAILQ_FIRST(head); ent; ent = nent) {
947b8b31f33SHajimu UMEMOTO 		nent = TAILQ_NEXT(ent, pc_entry);
948b8b31f33SHajimu UMEMOTO 		TAILQ_REMOVE(head, ent, pc_entry);
949b8b31f33SHajimu UMEMOTO 		free(ent);
950b8b31f33SHajimu UMEMOTO 	}
951b8b31f33SHajimu UMEMOTO }
952b8b31f33SHajimu UMEMOTO 
953b8b31f33SHajimu UMEMOTO static struct policyqueue *
954b8b31f33SHajimu UMEMOTO match_addrselectpolicy(addr, head)
955b8b31f33SHajimu UMEMOTO 	struct sockaddr *addr;
956b8b31f33SHajimu UMEMOTO 	struct policyhead *head;
957b8b31f33SHajimu UMEMOTO {
958b8b31f33SHajimu UMEMOTO #ifdef INET6
959b8b31f33SHajimu UMEMOTO 	struct policyqueue *ent, *bestent = NULL;
960b8b31f33SHajimu UMEMOTO 	struct in6_addrpolicy *pol;
961b8b31f33SHajimu UMEMOTO 	int matchlen, bestmatchlen = -1;
962b8b31f33SHajimu UMEMOTO 	u_char *mp, *ep, *k, *p, m;
963b8b31f33SHajimu UMEMOTO 	struct sockaddr_in6 key;
964b8b31f33SHajimu UMEMOTO 
965b8b31f33SHajimu UMEMOTO 	switch(addr->sa_family) {
966b8b31f33SHajimu UMEMOTO 	case AF_INET6:
967b8b31f33SHajimu UMEMOTO 		key = *(struct sockaddr_in6 *)addr;
968b8b31f33SHajimu UMEMOTO 		break;
969b8b31f33SHajimu UMEMOTO 	case AF_INET:
970b8b31f33SHajimu UMEMOTO 		/* convert the address into IPv4-mapped IPv6 address. */
971b8b31f33SHajimu UMEMOTO 		memset(&key, 0, sizeof(key));
972b8b31f33SHajimu UMEMOTO 		key.sin6_family = AF_INET6;
973b8b31f33SHajimu UMEMOTO 		key.sin6_len = sizeof(key);
974b8b31f33SHajimu UMEMOTO 		key.sin6_addr.s6_addr[10] = 0xff;
975b8b31f33SHajimu UMEMOTO 		key.sin6_addr.s6_addr[11] = 0xff;
976b8b31f33SHajimu UMEMOTO 		memcpy(&key.sin6_addr.s6_addr[12],
977b8b31f33SHajimu UMEMOTO 		       &((struct sockaddr_in *)addr)->sin_addr, 4);
978b8b31f33SHajimu UMEMOTO 		break;
979b8b31f33SHajimu UMEMOTO 	default:
980b8b31f33SHajimu UMEMOTO 		return(NULL);
981b8b31f33SHajimu UMEMOTO 	}
982b8b31f33SHajimu UMEMOTO 
983b8b31f33SHajimu UMEMOTO 	for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) {
984b8b31f33SHajimu UMEMOTO 		pol = &ent->pc_policy;
985b8b31f33SHajimu UMEMOTO 		matchlen = 0;
986b8b31f33SHajimu UMEMOTO 
987b8b31f33SHajimu UMEMOTO 		mp = (u_char *)&pol->addrmask.sin6_addr;
988b8b31f33SHajimu UMEMOTO 		ep = mp + 16;	/* XXX: scope field? */
989b8b31f33SHajimu UMEMOTO 		k = (u_char *)&key.sin6_addr;
990b8b31f33SHajimu UMEMOTO 		p = (u_char *)&pol->addr.sin6_addr;
991b8b31f33SHajimu UMEMOTO 		for (; mp < ep && *mp; mp++, k++, p++) {
992b8b31f33SHajimu UMEMOTO 			m = *mp;
993b8b31f33SHajimu UMEMOTO 			if ((*k & m) != *p)
994b8b31f33SHajimu UMEMOTO 				goto next; /* not match */
995b8b31f33SHajimu UMEMOTO 			if (m == 0xff) /* short cut for a typical case */
996b8b31f33SHajimu UMEMOTO 				matchlen += 8;
997b8b31f33SHajimu UMEMOTO 			else {
998b8b31f33SHajimu UMEMOTO 				while (m >= 0x80) {
999b8b31f33SHajimu UMEMOTO 					matchlen++;
1000b8b31f33SHajimu UMEMOTO 					m <<= 1;
1001b8b31f33SHajimu UMEMOTO 				}
1002b8b31f33SHajimu UMEMOTO 			}
1003b8b31f33SHajimu UMEMOTO 		}
1004b8b31f33SHajimu UMEMOTO 
1005b8b31f33SHajimu UMEMOTO 		/* matched.  check if this is better than the current best. */
1006b8b31f33SHajimu UMEMOTO 		if (matchlen > bestmatchlen) {
1007b8b31f33SHajimu UMEMOTO 			bestent = ent;
1008b8b31f33SHajimu UMEMOTO 			bestmatchlen = matchlen;
1009b8b31f33SHajimu UMEMOTO 		}
1010b8b31f33SHajimu UMEMOTO 
1011b8b31f33SHajimu UMEMOTO 	  next:
1012b8b31f33SHajimu UMEMOTO 		continue;
1013b8b31f33SHajimu UMEMOTO 	}
1014b8b31f33SHajimu UMEMOTO 
1015b8b31f33SHajimu UMEMOTO 	return(bestent);
1016b8b31f33SHajimu UMEMOTO #else
1017b8b31f33SHajimu UMEMOTO 	return(NULL);
1018b8b31f33SHajimu UMEMOTO #endif
1019b8b31f33SHajimu UMEMOTO 
1020b8b31f33SHajimu UMEMOTO }
1021b8b31f33SHajimu UMEMOTO 
1022146cd1bcSHajimu UMEMOTO static void
1023146cd1bcSHajimu UMEMOTO set_source(aio, ph)
1024146cd1bcSHajimu UMEMOTO 	struct hp_order *aio;
1025146cd1bcSHajimu UMEMOTO 	struct policyhead *ph;
1026146cd1bcSHajimu UMEMOTO {
1027146cd1bcSHajimu UMEMOTO 	struct sockaddr_storage ss = aio->aio_un.aiou_ss;
1028146cd1bcSHajimu UMEMOTO 	int s, srclen;
1029146cd1bcSHajimu UMEMOTO 
1030146cd1bcSHajimu UMEMOTO 	/* set unspec ("no source is available"), just in case */
1031146cd1bcSHajimu UMEMOTO 	aio->aio_srcsa.sa_family = AF_UNSPEC;
1032146cd1bcSHajimu UMEMOTO 	aio->aio_srcscope = -1;
1033146cd1bcSHajimu UMEMOTO 
1034146cd1bcSHajimu UMEMOTO 	switch(ss.ss_family) {
1035146cd1bcSHajimu UMEMOTO 	case AF_INET:
1036146cd1bcSHajimu UMEMOTO 		((struct sockaddr_in *)&ss)->sin_port = htons(1);
1037146cd1bcSHajimu UMEMOTO 		break;
1038146cd1bcSHajimu UMEMOTO #ifdef INET6
1039146cd1bcSHajimu UMEMOTO 	case AF_INET6:
1040146cd1bcSHajimu UMEMOTO 		((struct sockaddr_in6 *)&ss)->sin6_port = htons(1);
1041146cd1bcSHajimu UMEMOTO 		break;
1042146cd1bcSHajimu UMEMOTO #endif
1043146cd1bcSHajimu UMEMOTO 	default:		/* ignore unsupported AFs explicitly */
1044146cd1bcSHajimu UMEMOTO 		return;
1045146cd1bcSHajimu UMEMOTO 	}
1046146cd1bcSHajimu UMEMOTO 
1047146cd1bcSHajimu UMEMOTO 	/* open a socket to get the source address for the given dst */
1048146cd1bcSHajimu UMEMOTO 	if ((s = _socket(ss.ss_family, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1049146cd1bcSHajimu UMEMOTO 		return;		/* give up */
1050146cd1bcSHajimu UMEMOTO 	if (_connect(s, (struct sockaddr *)&ss, ss.ss_len) < 0)
1051146cd1bcSHajimu UMEMOTO 		goto cleanup;
1052146cd1bcSHajimu UMEMOTO 	srclen = ss.ss_len;
1053146cd1bcSHajimu UMEMOTO 	if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) {
1054146cd1bcSHajimu UMEMOTO 		aio->aio_srcsa.sa_family = AF_UNSPEC;
1055146cd1bcSHajimu UMEMOTO 		goto cleanup;
1056146cd1bcSHajimu UMEMOTO 	}
1057146cd1bcSHajimu UMEMOTO 	aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa);
1058146cd1bcSHajimu UMEMOTO 	aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph);
1059146cd1bcSHajimu UMEMOTO 	aio->aio_matchlen = matchlen(&aio->aio_srcsa, (struct sockaddr *)&ss);
1060146cd1bcSHajimu UMEMOTO #ifdef INET6
1061146cd1bcSHajimu UMEMOTO 	if (ss.ss_family == AF_INET6) {
1062146cd1bcSHajimu UMEMOTO 		struct in6_ifreq ifr6;
1063146cd1bcSHajimu UMEMOTO 		u_int32_t flags6;
1064146cd1bcSHajimu UMEMOTO 
1065146cd1bcSHajimu UMEMOTO 		/* XXX: interface name should not be hardcoded */
1066146cd1bcSHajimu UMEMOTO 		strncpy(ifr6.ifr_name, "lo0", sizeof(ifr6.ifr_name));
1067146cd1bcSHajimu UMEMOTO 		memset(&ifr6, 0, sizeof(ifr6));
1068146cd1bcSHajimu UMEMOTO 		memcpy(&ifr6.ifr_addr, &ss, ss.ss_len);
1069146cd1bcSHajimu UMEMOTO 		if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) {
1070146cd1bcSHajimu UMEMOTO 			flags6 = ifr6.ifr_ifru.ifru_flags6;
1071146cd1bcSHajimu UMEMOTO 			if ((flags6 & IN6_IFF_DEPRECATED))
1072146cd1bcSHajimu UMEMOTO 				aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED;
1073146cd1bcSHajimu UMEMOTO 		}
1074146cd1bcSHajimu UMEMOTO 	}
1075146cd1bcSHajimu UMEMOTO #endif
1076146cd1bcSHajimu UMEMOTO 
1077146cd1bcSHajimu UMEMOTO   cleanup:
1078146cd1bcSHajimu UMEMOTO 	_close(s);
1079146cd1bcSHajimu UMEMOTO 	return;
1080146cd1bcSHajimu UMEMOTO }
1081146cd1bcSHajimu UMEMOTO 
1082146cd1bcSHajimu UMEMOTO static int
1083146cd1bcSHajimu UMEMOTO matchlen(src, dst)
1084146cd1bcSHajimu UMEMOTO 	struct sockaddr *src, *dst;
1085146cd1bcSHajimu UMEMOTO {
1086146cd1bcSHajimu UMEMOTO 	int match = 0;
1087146cd1bcSHajimu UMEMOTO 	u_char *s, *d;
1088146cd1bcSHajimu UMEMOTO 	u_char *lim, r;
1089146cd1bcSHajimu UMEMOTO 	int addrlen;
1090146cd1bcSHajimu UMEMOTO 
1091146cd1bcSHajimu UMEMOTO 	switch (src->sa_family) {
1092146cd1bcSHajimu UMEMOTO #ifdef INET6
1093146cd1bcSHajimu UMEMOTO 	case AF_INET6:
1094146cd1bcSHajimu UMEMOTO 		s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr;
1095146cd1bcSHajimu UMEMOTO 		d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr;
1096146cd1bcSHajimu UMEMOTO 		addrlen = sizeof(struct in6_addr);
1097146cd1bcSHajimu UMEMOTO 		lim = s + addrlen;
1098146cd1bcSHajimu UMEMOTO 		break;
1099146cd1bcSHajimu UMEMOTO #endif
1100146cd1bcSHajimu UMEMOTO 	case AF_INET:
1101146cd1bcSHajimu UMEMOTO 		s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr;
1102146cd1bcSHajimu UMEMOTO 		d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr;
1103146cd1bcSHajimu UMEMOTO 		addrlen = sizeof(struct in_addr);
1104146cd1bcSHajimu UMEMOTO 		lim = s + addrlen;
1105146cd1bcSHajimu UMEMOTO 		break;
1106146cd1bcSHajimu UMEMOTO 	default:
1107146cd1bcSHajimu UMEMOTO 		return(0);
1108146cd1bcSHajimu UMEMOTO 	}
1109146cd1bcSHajimu UMEMOTO 
1110146cd1bcSHajimu UMEMOTO 	while (s < lim)
1111146cd1bcSHajimu UMEMOTO 		if ((r = (*d++ ^ *s++)) != 0) {
1112146cd1bcSHajimu UMEMOTO 			while (r < addrlen * 8) {
1113146cd1bcSHajimu UMEMOTO 				match++;
1114146cd1bcSHajimu UMEMOTO 				r <<= 1;
1115146cd1bcSHajimu UMEMOTO 			}
1116146cd1bcSHajimu UMEMOTO 			break;
1117146cd1bcSHajimu UMEMOTO 		} else
1118146cd1bcSHajimu UMEMOTO 			match += 8;
1119146cd1bcSHajimu UMEMOTO 	return(match);
1120146cd1bcSHajimu UMEMOTO }
1121146cd1bcSHajimu UMEMOTO 
1122146cd1bcSHajimu UMEMOTO static int
1123146cd1bcSHajimu UMEMOTO comp_dst(arg1, arg2)
1124146cd1bcSHajimu UMEMOTO 	const void *arg1, *arg2;
1125146cd1bcSHajimu UMEMOTO {
1126146cd1bcSHajimu UMEMOTO 	const struct hp_order *dst1 = arg1, *dst2 = arg2;
1127146cd1bcSHajimu UMEMOTO 
1128146cd1bcSHajimu UMEMOTO 	/*
1129146cd1bcSHajimu UMEMOTO 	 * Rule 1: Avoid unusable destinations.
1130146cd1bcSHajimu UMEMOTO 	 * XXX: we currently do not consider if an appropriate route exists.
1131146cd1bcSHajimu UMEMOTO 	 */
1132146cd1bcSHajimu UMEMOTO 	if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
1133146cd1bcSHajimu UMEMOTO 	    dst2->aio_srcsa.sa_family == AF_UNSPEC) {
1134146cd1bcSHajimu UMEMOTO 		return(-1);
1135146cd1bcSHajimu UMEMOTO 	}
1136146cd1bcSHajimu UMEMOTO 	if (dst1->aio_srcsa.sa_family == AF_UNSPEC &&
1137146cd1bcSHajimu UMEMOTO 	    dst2->aio_srcsa.sa_family != AF_UNSPEC) {
1138146cd1bcSHajimu UMEMOTO 		return(1);
1139146cd1bcSHajimu UMEMOTO 	}
1140146cd1bcSHajimu UMEMOTO 
1141146cd1bcSHajimu UMEMOTO 	/* Rule 2: Prefer matching scope. */
1142146cd1bcSHajimu UMEMOTO 	if (dst1->aio_dstscope == dst1->aio_srcscope &&
1143146cd1bcSHajimu UMEMOTO 	    dst2->aio_dstscope != dst2->aio_srcscope) {
1144146cd1bcSHajimu UMEMOTO 		return(-1);
1145146cd1bcSHajimu UMEMOTO 	}
1146146cd1bcSHajimu UMEMOTO 	if (dst1->aio_dstscope != dst1->aio_srcscope &&
1147146cd1bcSHajimu UMEMOTO 	    dst2->aio_dstscope == dst2->aio_srcscope) {
1148146cd1bcSHajimu UMEMOTO 		return(1);
1149146cd1bcSHajimu UMEMOTO 	}
1150146cd1bcSHajimu UMEMOTO 
1151146cd1bcSHajimu UMEMOTO 	/* Rule 3: Avoid deprecated addresses. */
1152146cd1bcSHajimu UMEMOTO 	if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
1153146cd1bcSHajimu UMEMOTO 	    dst2->aio_srcsa.sa_family != AF_UNSPEC) {
1154146cd1bcSHajimu UMEMOTO 		if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
1155146cd1bcSHajimu UMEMOTO 		    (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
1156146cd1bcSHajimu UMEMOTO 			return(-1);
1157146cd1bcSHajimu UMEMOTO 		}
1158146cd1bcSHajimu UMEMOTO 		if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
1159146cd1bcSHajimu UMEMOTO 		    !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
1160146cd1bcSHajimu UMEMOTO 			return(1);
1161146cd1bcSHajimu UMEMOTO 		}
1162146cd1bcSHajimu UMEMOTO 	}
1163146cd1bcSHajimu UMEMOTO 
1164146cd1bcSHajimu UMEMOTO 	/* Rule 4: Prefer home addresses. */
1165146cd1bcSHajimu UMEMOTO 	/* XXX: not implemented yet */
1166146cd1bcSHajimu UMEMOTO 
1167146cd1bcSHajimu UMEMOTO 	/* Rule 5: Prefer matching label. */
1168146cd1bcSHajimu UMEMOTO #ifdef INET6
1169146cd1bcSHajimu UMEMOTO 	if (dst1->aio_srcpolicy && dst1->aio_dstpolicy &&
1170146cd1bcSHajimu UMEMOTO 	    dst1->aio_srcpolicy->pc_policy.label ==
1171146cd1bcSHajimu UMEMOTO 	    dst1->aio_dstpolicy->pc_policy.label &&
1172146cd1bcSHajimu UMEMOTO 	    (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL ||
1173146cd1bcSHajimu UMEMOTO 	     dst2->aio_srcpolicy->pc_policy.label !=
1174146cd1bcSHajimu UMEMOTO 	     dst2->aio_dstpolicy->pc_policy.label)) {
1175146cd1bcSHajimu UMEMOTO 		return(-1);
1176146cd1bcSHajimu UMEMOTO 	}
1177146cd1bcSHajimu UMEMOTO 	if (dst2->aio_srcpolicy && dst2->aio_dstpolicy &&
1178146cd1bcSHajimu UMEMOTO 	    dst2->aio_srcpolicy->pc_policy.label ==
1179146cd1bcSHajimu UMEMOTO 	    dst2->aio_dstpolicy->pc_policy.label &&
1180146cd1bcSHajimu UMEMOTO 	    (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL ||
1181146cd1bcSHajimu UMEMOTO 	     dst1->aio_srcpolicy->pc_policy.label !=
1182146cd1bcSHajimu UMEMOTO 	     dst1->aio_dstpolicy->pc_policy.label)) {
1183146cd1bcSHajimu UMEMOTO 		return(1);
1184146cd1bcSHajimu UMEMOTO 	}
1185146cd1bcSHajimu UMEMOTO #endif
1186146cd1bcSHajimu UMEMOTO 
1187146cd1bcSHajimu UMEMOTO 	/* Rule 6: Prefer higher precedence. */
1188146cd1bcSHajimu UMEMOTO #ifdef INET6
1189146cd1bcSHajimu UMEMOTO 	if (dst1->aio_dstpolicy &&
1190146cd1bcSHajimu UMEMOTO 	    (dst2->aio_dstpolicy == NULL ||
1191146cd1bcSHajimu UMEMOTO 	     dst1->aio_dstpolicy->pc_policy.preced >
1192146cd1bcSHajimu UMEMOTO 	     dst2->aio_dstpolicy->pc_policy.preced)) {
1193146cd1bcSHajimu UMEMOTO 		return(-1);
1194146cd1bcSHajimu UMEMOTO 	}
1195146cd1bcSHajimu UMEMOTO 	if (dst2->aio_dstpolicy &&
1196146cd1bcSHajimu UMEMOTO 	    (dst1->aio_dstpolicy == NULL ||
1197146cd1bcSHajimu UMEMOTO 	     dst2->aio_dstpolicy->pc_policy.preced >
1198146cd1bcSHajimu UMEMOTO 	     dst1->aio_dstpolicy->pc_policy.preced)) {
1199146cd1bcSHajimu UMEMOTO 		return(1);
1200146cd1bcSHajimu UMEMOTO 	}
1201146cd1bcSHajimu UMEMOTO #endif
1202146cd1bcSHajimu UMEMOTO 
1203146cd1bcSHajimu UMEMOTO 	/* Rule 7: Prefer native transport. */
1204146cd1bcSHajimu UMEMOTO 	/* XXX: not implemented yet */
1205146cd1bcSHajimu UMEMOTO 
1206146cd1bcSHajimu UMEMOTO 	/* Rule 8: Prefer smaller scope. */
1207146cd1bcSHajimu UMEMOTO 	if (dst1->aio_dstscope >= 0 &&
1208146cd1bcSHajimu UMEMOTO 	    dst1->aio_dstscope < dst2->aio_dstscope) {
1209146cd1bcSHajimu UMEMOTO 		return(-1);
1210146cd1bcSHajimu UMEMOTO 	}
1211146cd1bcSHajimu UMEMOTO 	if (dst2->aio_dstscope >= 0 &&
1212146cd1bcSHajimu UMEMOTO 	    dst2->aio_dstscope < dst1->aio_dstscope) {
1213146cd1bcSHajimu UMEMOTO 		return(1);
1214146cd1bcSHajimu UMEMOTO 	}
1215146cd1bcSHajimu UMEMOTO 
1216146cd1bcSHajimu UMEMOTO 	/*
1217146cd1bcSHajimu UMEMOTO 	 * Rule 9: Use longest matching prefix.
1218146cd1bcSHajimu UMEMOTO 	 * We compare the match length in a same AF only.
1219146cd1bcSHajimu UMEMOTO 	 */
1220146cd1bcSHajimu UMEMOTO 	if (dst1->aio_sa.sa_family == dst2->aio_sa.sa_family) {
1221146cd1bcSHajimu UMEMOTO 		if (dst1->aio_matchlen > dst2->aio_matchlen) {
1222146cd1bcSHajimu UMEMOTO 			return(-1);
1223146cd1bcSHajimu UMEMOTO 		}
1224146cd1bcSHajimu UMEMOTO 		if (dst1->aio_matchlen < dst2->aio_matchlen) {
1225146cd1bcSHajimu UMEMOTO 			return(1);
1226146cd1bcSHajimu UMEMOTO 		}
1227146cd1bcSHajimu UMEMOTO 	}
1228146cd1bcSHajimu UMEMOTO 
1229146cd1bcSHajimu UMEMOTO 	/* Rule 10: Otherwise, leave the order unchanged. */
1230146cd1bcSHajimu UMEMOTO 	return(-1);
1231146cd1bcSHajimu UMEMOTO }
1232146cd1bcSHajimu UMEMOTO 
1233146cd1bcSHajimu UMEMOTO /*
1234146cd1bcSHajimu UMEMOTO  * Copy from scope.c.
1235146cd1bcSHajimu UMEMOTO  * XXX: we should standardize the functions and link them as standard
1236146cd1bcSHajimu UMEMOTO  * library.
1237146cd1bcSHajimu UMEMOTO  */
1238146cd1bcSHajimu UMEMOTO static int
1239146cd1bcSHajimu UMEMOTO gai_addr2scopetype(sa)
1240146cd1bcSHajimu UMEMOTO 	struct sockaddr *sa;
1241146cd1bcSHajimu UMEMOTO {
1242146cd1bcSHajimu UMEMOTO #ifdef INET6
1243146cd1bcSHajimu UMEMOTO 	struct sockaddr_in6 *sa6;
1244146cd1bcSHajimu UMEMOTO #endif
1245146cd1bcSHajimu UMEMOTO 	struct sockaddr_in *sa4;
1246146cd1bcSHajimu UMEMOTO 
1247146cd1bcSHajimu UMEMOTO 	switch(sa->sa_family) {
1248146cd1bcSHajimu UMEMOTO #ifdef INET6
1249146cd1bcSHajimu UMEMOTO 	case AF_INET6:
1250146cd1bcSHajimu UMEMOTO 		sa6 = (struct sockaddr_in6 *)sa;
1251146cd1bcSHajimu UMEMOTO 		if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
1252146cd1bcSHajimu UMEMOTO 			/* just use the scope field of the multicast address */
1253146cd1bcSHajimu UMEMOTO 			return(sa6->sin6_addr.s6_addr[2] & 0x0f);
1254146cd1bcSHajimu UMEMOTO 		}
1255146cd1bcSHajimu UMEMOTO 		/*
1256146cd1bcSHajimu UMEMOTO 		 * Unicast addresses: map scope type to corresponding scope
1257146cd1bcSHajimu UMEMOTO 		 * value defined for multcast addresses.
1258146cd1bcSHajimu UMEMOTO 		 * XXX: hardcoded scope type values are bad...
1259146cd1bcSHajimu UMEMOTO 		 */
1260146cd1bcSHajimu UMEMOTO 		if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr))
1261146cd1bcSHajimu UMEMOTO 			return(1); /* node local scope */
1262146cd1bcSHajimu UMEMOTO 		if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr))
1263146cd1bcSHajimu UMEMOTO 			return(2); /* link-local scope */
1264146cd1bcSHajimu UMEMOTO 		if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr))
1265146cd1bcSHajimu UMEMOTO 			return(5); /* site-local scope */
1266146cd1bcSHajimu UMEMOTO 		return(14);	/* global scope */
1267146cd1bcSHajimu UMEMOTO 		break;
1268146cd1bcSHajimu UMEMOTO #endif
1269146cd1bcSHajimu UMEMOTO 	case AF_INET:
1270146cd1bcSHajimu UMEMOTO 		/*
1271146cd1bcSHajimu UMEMOTO 		 * IPv4 pseudo scoping according to RFC 3484.
1272146cd1bcSHajimu UMEMOTO 		 */
1273146cd1bcSHajimu UMEMOTO 		sa4 = (struct sockaddr_in *)sa;
1274146cd1bcSHajimu UMEMOTO 		/* IPv4 autoconfiguration addresses have link-local scope. */
1275146cd1bcSHajimu UMEMOTO 		if (((u_char *)&sa4->sin_addr)[0] == 169 &&
1276146cd1bcSHajimu UMEMOTO 		    ((u_char *)&sa4->sin_addr)[1] == 254)
1277146cd1bcSHajimu UMEMOTO 			return(2);
1278146cd1bcSHajimu UMEMOTO 		/* Private addresses have site-local scope. */
1279146cd1bcSHajimu UMEMOTO 		if (((u_char *)&sa4->sin_addr)[0] == 10 ||
1280146cd1bcSHajimu UMEMOTO 		    (((u_char *)&sa4->sin_addr)[0] == 172 &&
1281146cd1bcSHajimu UMEMOTO 		     (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) ||
1282146cd1bcSHajimu UMEMOTO 		    (((u_char *)&sa4->sin_addr)[0] == 192 &&
1283146cd1bcSHajimu UMEMOTO 		     ((u_char *)&sa4->sin_addr)[1] == 168))
1284146cd1bcSHajimu UMEMOTO 			return(14);	/* XXX: It should be 5 unless NAT */
1285146cd1bcSHajimu UMEMOTO 		/* Loopback addresses have link-local scope. */
1286146cd1bcSHajimu UMEMOTO 		if (((u_char *)&sa4->sin_addr)[0] == 127)
1287146cd1bcSHajimu UMEMOTO 			return(2);
1288146cd1bcSHajimu UMEMOTO 		return(14);
1289146cd1bcSHajimu UMEMOTO 		break;
1290146cd1bcSHajimu UMEMOTO 	default:
1291146cd1bcSHajimu UMEMOTO 		errno = EAFNOSUPPORT; /* is this a good error? */
1292146cd1bcSHajimu UMEMOTO 		return(-1);
1293146cd1bcSHajimu UMEMOTO 	}
1294146cd1bcSHajimu UMEMOTO }
1295146cd1bcSHajimu UMEMOTO 
1296b8b31f33SHajimu UMEMOTO /*
12977d56d374SYoshinobu Inoue  * FILES (/etc/hosts)
12987d56d374SYoshinobu Inoue  */
12997d56d374SYoshinobu Inoue 
13007d56d374SYoshinobu Inoue static FILE *
13017d56d374SYoshinobu Inoue _files_open(int *errp)
13027d56d374SYoshinobu Inoue {
13037d56d374SYoshinobu Inoue 	FILE *fp;
13047d56d374SYoshinobu Inoue 	fp = fopen(_PATH_HOSTS, "r");
13057d56d374SYoshinobu Inoue 	if (fp == NULL)
13067d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
13077d56d374SYoshinobu Inoue 	return fp;
13087d56d374SYoshinobu Inoue }
13097d56d374SYoshinobu Inoue 
1310248aee62SJacques Vidrine static int
1311248aee62SJacques Vidrine _files_ghbyname(void *rval, void *cb_data, va_list ap)
13127d56d374SYoshinobu Inoue {
1313248aee62SJacques Vidrine 	const char *name;
1314248aee62SJacques Vidrine 	int af;
1315248aee62SJacques Vidrine 	int *errp;
13167d56d374SYoshinobu Inoue 	int match, nalias;
13177d56d374SYoshinobu Inoue 	char *p, *line, *addrstr, *cname;
13187d56d374SYoshinobu Inoue 	FILE *fp;
13197d56d374SYoshinobu Inoue 	struct hostent *rethp, *hp, hpbuf;
13207d56d374SYoshinobu Inoue 	char *aliases[MAXALIASES + 1], *addrs[2];
13217d56d374SYoshinobu Inoue 	union inx_addr addrbuf;
13227d56d374SYoshinobu Inoue 	char buf[BUFSIZ];
1323cb0600bdSJacques Vidrine 	int af0;
13247d56d374SYoshinobu Inoue 
1325248aee62SJacques Vidrine 	name = va_arg(ap, const char *);
1326248aee62SJacques Vidrine 	af = va_arg(ap, int);
1327248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
1328248aee62SJacques Vidrine 
1329248aee62SJacques Vidrine 	*(struct hostent **)rval = NULL;
1330248aee62SJacques Vidrine 
13317d56d374SYoshinobu Inoue 	if ((fp = _files_open(errp)) == NULL)
1332248aee62SJacques Vidrine 		return NS_UNAVAIL;
13337d56d374SYoshinobu Inoue 	rethp = hp = NULL;
13347d56d374SYoshinobu Inoue 
1335cb0600bdSJacques Vidrine 	af0 = af;
13367d56d374SYoshinobu Inoue 	while (fgets(buf, sizeof(buf), fp)) {
13377d56d374SYoshinobu Inoue 		line = buf;
13387d56d374SYoshinobu Inoue 		if ((addrstr = _hgetword(&line)) == NULL
13397d56d374SYoshinobu Inoue 		||  (cname = _hgetword(&line)) == NULL)
13407d56d374SYoshinobu Inoue 			continue;
13417d56d374SYoshinobu Inoue 		match = (strcasecmp(cname, name) == 0);
13427d56d374SYoshinobu Inoue 		nalias = 0;
13437d56d374SYoshinobu Inoue 		while ((p = _hgetword(&line)) != NULL) {
13447d56d374SYoshinobu Inoue 			if (!match)
13457d56d374SYoshinobu Inoue 				match = (strcasecmp(p, name) == 0);
13467d56d374SYoshinobu Inoue 			if (nalias < MAXALIASES)
13477d56d374SYoshinobu Inoue 				aliases[nalias++] = p;
13487d56d374SYoshinobu Inoue 		}
13497d56d374SYoshinobu Inoue 		if (!match)
13507d56d374SYoshinobu Inoue 			continue;
1351e6f35403SYoshinobu Inoue 		switch (af0) {
1352e6f35403SYoshinobu Inoue 		case AF_INET:
1353e6f35403SYoshinobu Inoue 			if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
1354e6f35403SYoshinobu Inoue 			    != 1) {
13557d56d374SYoshinobu Inoue 				*errp = NO_DATA;	/* name found */
13567d56d374SYoshinobu Inoue 				continue;
13577d56d374SYoshinobu Inoue 			}
1358e6f35403SYoshinobu Inoue 			af = af0;
1359e6f35403SYoshinobu Inoue 			break;
1360e6f35403SYoshinobu Inoue #ifdef INET6
1361e6f35403SYoshinobu Inoue 		case AF_INET6:
1362e6f35403SYoshinobu Inoue 			if (inet_pton(af, addrstr, &addrbuf) != 1) {
1363e6f35403SYoshinobu Inoue 				*errp = NO_DATA;	/* name found */
1364e6f35403SYoshinobu Inoue 				continue;
1365e6f35403SYoshinobu Inoue 			}
1366e6f35403SYoshinobu Inoue 			af = af0;
1367e6f35403SYoshinobu Inoue 			break;
1368e6f35403SYoshinobu Inoue #endif
1369e6f35403SYoshinobu Inoue 		case AF_UNSPEC:
1370e6f35403SYoshinobu Inoue 			if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
1371e6f35403SYoshinobu Inoue 			    == 1) {
1372e6f35403SYoshinobu Inoue 				af = AF_INET;
1373e6f35403SYoshinobu Inoue 				break;
1374e6f35403SYoshinobu Inoue 			}
1375e6f35403SYoshinobu Inoue #ifdef INET6
1376e6f35403SYoshinobu Inoue 			if (inet_pton(AF_INET6, addrstr, &addrbuf) == 1) {
1377e6f35403SYoshinobu Inoue 				af = AF_INET6;
1378e6f35403SYoshinobu Inoue 				break;
1379e6f35403SYoshinobu Inoue 			}
1380e6f35403SYoshinobu Inoue #endif
1381e6f35403SYoshinobu Inoue 			*errp = NO_DATA;	/* name found */
1382e6f35403SYoshinobu Inoue 			continue;
1383e6f35403SYoshinobu Inoue 			/* NOTREACHED */
1384e6f35403SYoshinobu Inoue 		}
13857d56d374SYoshinobu Inoue 		hp = &hpbuf;
13867d56d374SYoshinobu Inoue 		hp->h_name = cname;
13877d56d374SYoshinobu Inoue 		hp->h_aliases = aliases;
13887d56d374SYoshinobu Inoue 		aliases[nalias] = NULL;
13897d56d374SYoshinobu Inoue 		hp->h_addrtype = af;
13907d56d374SYoshinobu Inoue 		hp->h_length = ADDRLEN(af);
13917d56d374SYoshinobu Inoue 		hp->h_addr_list = addrs;
13927d56d374SYoshinobu Inoue 		addrs[0] = (char *)&addrbuf;
13937d56d374SYoshinobu Inoue 		addrs[1] = NULL;
13947d56d374SYoshinobu Inoue 		hp = _hpcopy(hp, errp);
13957d56d374SYoshinobu Inoue 		rethp = _hpmerge(rethp, hp, errp);
13967d56d374SYoshinobu Inoue 	}
13977d56d374SYoshinobu Inoue 	fclose(fp);
1398248aee62SJacques Vidrine 	*(struct hostent **)rval = rethp;
1399248aee62SJacques Vidrine 	return (rethp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
14007d56d374SYoshinobu Inoue }
14017d56d374SYoshinobu Inoue 
1402248aee62SJacques Vidrine static int
1403248aee62SJacques Vidrine _files_ghbyaddr(void *rval, void *cb_data, va_list ap)
14047d56d374SYoshinobu Inoue {
1405248aee62SJacques Vidrine 	const void *addr;
1406248aee62SJacques Vidrine 	int addrlen;
1407248aee62SJacques Vidrine 	int af;
1408248aee62SJacques Vidrine 	int *errp;
14097d56d374SYoshinobu Inoue 	int nalias;
14107d56d374SYoshinobu Inoue 	char *p, *line;
14117d56d374SYoshinobu Inoue 	FILE *fp;
14127d56d374SYoshinobu Inoue 	struct hostent *hp, hpbuf;
14137d56d374SYoshinobu Inoue 	char *aliases[MAXALIASES + 1], *addrs[2];
14147d56d374SYoshinobu Inoue 	union inx_addr addrbuf;
14157d56d374SYoshinobu Inoue 	char buf[BUFSIZ];
14167d56d374SYoshinobu Inoue 
1417248aee62SJacques Vidrine 	addr = va_arg(ap, const void *);
1418248aee62SJacques Vidrine 	addrlen = va_arg(ap, int);
1419248aee62SJacques Vidrine 	af = va_arg(ap, int);
1420248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
1421248aee62SJacques Vidrine 
1422248aee62SJacques Vidrine 	*(struct hostent**)rval = NULL;
1423248aee62SJacques Vidrine 
14247d56d374SYoshinobu Inoue 	if ((fp = _files_open(errp)) == NULL)
1425248aee62SJacques Vidrine 		return NS_UNAVAIL;
14267d56d374SYoshinobu Inoue 	hp = NULL;
14277d56d374SYoshinobu Inoue 	while (fgets(buf, sizeof(buf), fp)) {
14287d56d374SYoshinobu Inoue 		line = buf;
14297d56d374SYoshinobu Inoue 		if ((p = _hgetword(&line)) == NULL
1430be26adb5SYoshinobu Inoue 		||  (af == AF_INET
1431be26adb5SYoshinobu Inoue 		     ? inet_aton(p, (struct in_addr *)&addrbuf)
1432be26adb5SYoshinobu Inoue 		     : inet_pton(af, p, &addrbuf)) != 1
14337d56d374SYoshinobu Inoue 		||  memcmp(addr, &addrbuf, addrlen) != 0
14347d56d374SYoshinobu Inoue 		||  (p = _hgetword(&line)) == NULL)
14357d56d374SYoshinobu Inoue 			continue;
14367d56d374SYoshinobu Inoue 		hp = &hpbuf;
14377d56d374SYoshinobu Inoue 		hp->h_name = p;
14387d56d374SYoshinobu Inoue 		hp->h_aliases = aliases;
14397d56d374SYoshinobu Inoue 		nalias = 0;
14407d56d374SYoshinobu Inoue 		while ((p = _hgetword(&line)) != NULL) {
14417d56d374SYoshinobu Inoue 			if (nalias < MAXALIASES)
14427d56d374SYoshinobu Inoue 				aliases[nalias++] = p;
14437d56d374SYoshinobu Inoue 		}
14447d56d374SYoshinobu Inoue 		aliases[nalias] = NULL;
14457d56d374SYoshinobu Inoue 		hp->h_addrtype = af;
14467d56d374SYoshinobu Inoue 		hp->h_length = addrlen;
14477d56d374SYoshinobu Inoue 		hp->h_addr_list = addrs;
14487d56d374SYoshinobu Inoue 		addrs[0] = (char *)&addrbuf;
14497d56d374SYoshinobu Inoue 		addrs[1] = NULL;
14507d56d374SYoshinobu Inoue 		hp = _hpcopy(hp, errp);
14517d56d374SYoshinobu Inoue 		break;
14527d56d374SYoshinobu Inoue 	}
14537d56d374SYoshinobu Inoue 	fclose(fp);
1454248aee62SJacques Vidrine 	*(struct hostent **)rval = hp;
1455248aee62SJacques Vidrine 	return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
14567d56d374SYoshinobu Inoue }
14577d56d374SYoshinobu Inoue 
145873b30f0cSJun-ichiro itojun Hagino #ifdef YP
145963858012SJonathan Lemon /*
146063858012SJonathan Lemon  * NIS
146163858012SJonathan Lemon  *
146263858012SJonathan Lemon  * XXX actually a hack, these are INET4 specific.
146363858012SJonathan Lemon  */
1464248aee62SJacques Vidrine static int
1465248aee62SJacques Vidrine _nis_ghbyname(void *rval, void *cb_data, va_list ap)
146663858012SJonathan Lemon {
1467248aee62SJacques Vidrine 	const char *name;
1468248aee62SJacques Vidrine 	int af;
1469248aee62SJacques Vidrine 	int *errp;
147038775c5eSJonathan Lemon 	struct hostent *hp = NULL;
147163858012SJonathan Lemon 
1472248aee62SJacques Vidrine 	name = va_arg(ap, const char *);
1473248aee62SJacques Vidrine 	af = va_arg(ap, int);
1474248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
1475248aee62SJacques Vidrine 
1476e6f35403SYoshinobu Inoue 	if (af == AF_UNSPEC)
1477e6f35403SYoshinobu Inoue 		af = AF_INET;
147863858012SJonathan Lemon 	if (af == AF_INET) {
147933dee819SBrian Feldman 		THREAD_LOCK();
148063858012SJonathan Lemon 		hp = _gethostbynisname(name, af);
148163858012SJonathan Lemon 		if (hp != NULL)
148263858012SJonathan Lemon 			hp = _hpcopy(hp, errp);
148333dee819SBrian Feldman 		THREAD_UNLOCK();
148463858012SJonathan Lemon 	}
1485248aee62SJacques Vidrine 
1486248aee62SJacques Vidrine 	*(struct hostent **)rval = hp;
1487248aee62SJacques Vidrine 	return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
148863858012SJonathan Lemon 
148963858012SJonathan Lemon }
149063858012SJonathan Lemon 
1491248aee62SJacques Vidrine static int
1492248aee62SJacques Vidrine _nis_ghbyaddr(void *rval, void *cb_data, va_list ap)
149363858012SJonathan Lemon {
1494248aee62SJacques Vidrine 	const void *addr;
1495248aee62SJacques Vidrine 	int addrlen;
1496248aee62SJacques Vidrine 	int af;
1497248aee62SJacques Vidrine 	int *errp;
149863858012SJonathan Lemon 	struct hostent *hp = NULL;
149963858012SJonathan Lemon 
1500248aee62SJacques Vidrine 	addr = va_arg(ap, const void *);
1501248aee62SJacques Vidrine 	addrlen = va_arg(ap, int);
1502248aee62SJacques Vidrine 	af = va_arg(ap, int);
1503248aee62SJacques Vidrine 
150463858012SJonathan Lemon 	if (af == AF_INET) {
150533dee819SBrian Feldman 		THREAD_LOCK();
150663858012SJonathan Lemon 		hp = _gethostbynisaddr(addr, addrlen, af);
150763858012SJonathan Lemon 		if (hp != NULL)
150863858012SJonathan Lemon 			hp = _hpcopy(hp, errp);
150933dee819SBrian Feldman 		THREAD_UNLOCK();
151063858012SJonathan Lemon 	}
1511248aee62SJacques Vidrine 	*(struct hostent **)rval = hp;
1512248aee62SJacques Vidrine 	return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
151363858012SJonathan Lemon }
15147d56d374SYoshinobu Inoue #endif
15157d56d374SYoshinobu Inoue 
1516e6f35403SYoshinobu Inoue struct __res_type_list {
1517e3975643SJake Burkholder         SLIST_ENTRY(__res_type_list) rtl_entry;
1518e6f35403SYoshinobu Inoue         int     rtl_type;
1519e6f35403SYoshinobu Inoue };
1520e6f35403SYoshinobu Inoue 
15219832619cSHajimu UMEMOTO #define	MAXPACKET	(64*1024)
152273b30f0cSJun-ichiro itojun Hagino 
152373b30f0cSJun-ichiro itojun Hagino typedef union {
152473b30f0cSJun-ichiro itojun Hagino 	HEADER hdr;
152573b30f0cSJun-ichiro itojun Hagino 	u_char buf[MAXPACKET];
152673b30f0cSJun-ichiro itojun Hagino } querybuf;
152773b30f0cSJun-ichiro itojun Hagino 
15281372519bSDavid E. O'Brien static struct hostent *getanswer(const querybuf *, int, const char *, int,
15291372519bSDavid E. O'Brien 	    struct hostent *, int *);
153073b30f0cSJun-ichiro itojun Hagino 
153173b30f0cSJun-ichiro itojun Hagino /*
153273b30f0cSJun-ichiro itojun Hagino  * we don't need to take care about sorting, nor IPv4 mapped address here.
153373b30f0cSJun-ichiro itojun Hagino  */
15347d56d374SYoshinobu Inoue static struct hostent *
153573b30f0cSJun-ichiro itojun Hagino getanswer(answer, anslen, qname, qtype, template, errp)
153673b30f0cSJun-ichiro itojun Hagino 	const querybuf *answer;
1537e6f35403SYoshinobu Inoue 	int anslen;
153873b30f0cSJun-ichiro itojun Hagino 	const char *qname;
1539e6f35403SYoshinobu Inoue 	int qtype;
154073b30f0cSJun-ichiro itojun Hagino 	struct hostent *template;
1541e6f35403SYoshinobu Inoue 	int *errp;
15427d56d374SYoshinobu Inoue {
15438fb3f3f6SDavid E. O'Brien 	const HEADER *hp;
15448fb3f3f6SDavid E. O'Brien 	const u_char *cp;
15458fb3f3f6SDavid E. O'Brien 	int n;
154673b30f0cSJun-ichiro itojun Hagino 	const u_char *eom, *erdata;
1547d6af58f5SWarner Losh 	char *bp, *ep, **ap, **hap;
1548d6af58f5SWarner Losh 	int type, class, ancount, qdcount;
154973b30f0cSJun-ichiro itojun Hagino 	int haveanswer, had_error;
155073b30f0cSJun-ichiro itojun Hagino 	char tbuf[MAXDNAME];
155173b30f0cSJun-ichiro itojun Hagino 	const char *tname;
1552c05ac53bSDavid E. O'Brien 	int (*name_ok)(const char *);
155373b30f0cSJun-ichiro itojun Hagino 	static char *h_addr_ptrs[MAXADDRS + 1];
155473b30f0cSJun-ichiro itojun Hagino 	static char *host_aliases[MAXALIASES];
155573b30f0cSJun-ichiro itojun Hagino 	static char hostbuf[8*1024];
15567d56d374SYoshinobu Inoue 
155773b30f0cSJun-ichiro itojun Hagino #define BOUNDED_INCR(x) \
155873b30f0cSJun-ichiro itojun Hagino 	do { \
155973b30f0cSJun-ichiro itojun Hagino 		cp += x; \
156073b30f0cSJun-ichiro itojun Hagino 		if (cp > eom) { \
156173b30f0cSJun-ichiro itojun Hagino 			*errp = NO_RECOVERY; \
156273b30f0cSJun-ichiro itojun Hagino 			return (NULL); \
156373b30f0cSJun-ichiro itojun Hagino 		} \
156473b30f0cSJun-ichiro itojun Hagino 	} while (0)
15657d56d374SYoshinobu Inoue 
156673b30f0cSJun-ichiro itojun Hagino #define BOUNDS_CHECK(ptr, count) \
156773b30f0cSJun-ichiro itojun Hagino 	do { \
156873b30f0cSJun-ichiro itojun Hagino 		if ((ptr) + (count) > eom) { \
156973b30f0cSJun-ichiro itojun Hagino 			*errp = NO_RECOVERY; \
157073b30f0cSJun-ichiro itojun Hagino 			return (NULL); \
157173b30f0cSJun-ichiro itojun Hagino 		} \
157273b30f0cSJun-ichiro itojun Hagino 	} while (0)
157373b30f0cSJun-ichiro itojun Hagino 
15743f587e57SKris Kennaway /* XXX do {} while (0) cannot be put here */
157573b30f0cSJun-ichiro itojun Hagino #define DNS_ASSERT(x) \
15763f587e57SKris Kennaway 	{				\
157773b30f0cSJun-ichiro itojun Hagino 		if (!(x)) {		\
157873b30f0cSJun-ichiro itojun Hagino 			cp += n;	\
157973b30f0cSJun-ichiro itojun Hagino 			continue;	\
158073b30f0cSJun-ichiro itojun Hagino 		}			\
15813f587e57SKris Kennaway 	}
158273b30f0cSJun-ichiro itojun Hagino 
15833f587e57SKris Kennaway /* XXX do {} while (0) cannot be put here */
158473b30f0cSJun-ichiro itojun Hagino #define DNS_FATAL(x) \
15853f587e57SKris Kennaway 	{				\
158673b30f0cSJun-ichiro itojun Hagino 		if (!(x)) {		\
158773b30f0cSJun-ichiro itojun Hagino 			had_error++;	\
158873b30f0cSJun-ichiro itojun Hagino 			continue;	\
158973b30f0cSJun-ichiro itojun Hagino 		}			\
15903f587e57SKris Kennaway 	}
159173b30f0cSJun-ichiro itojun Hagino 
159273b30f0cSJun-ichiro itojun Hagino 	tname = qname;
159373b30f0cSJun-ichiro itojun Hagino 	template->h_name = NULL;
159473b30f0cSJun-ichiro itojun Hagino 	eom = answer->buf + anslen;
159573b30f0cSJun-ichiro itojun Hagino 	switch (qtype) {
15967d56d374SYoshinobu Inoue 	case T_A:
15977d56d374SYoshinobu Inoue 	case T_AAAA:
159873b30f0cSJun-ichiro itojun Hagino 		name_ok = res_hnok;
159973b30f0cSJun-ichiro itojun Hagino 		break;
160073b30f0cSJun-ichiro itojun Hagino 	case T_PTR:
160173b30f0cSJun-ichiro itojun Hagino 		name_ok = res_dnok;
16027d56d374SYoshinobu Inoue 		break;
16037d56d374SYoshinobu Inoue 	default:
160473b30f0cSJun-ichiro itojun Hagino 		return (NULL);	/* XXX should be abort(); */
160573b30f0cSJun-ichiro itojun Hagino 	}
160673b30f0cSJun-ichiro itojun Hagino 	/*
160773b30f0cSJun-ichiro itojun Hagino 	 * find first satisfactory answer
160873b30f0cSJun-ichiro itojun Hagino 	 */
160973b30f0cSJun-ichiro itojun Hagino 	hp = &answer->hdr;
161073b30f0cSJun-ichiro itojun Hagino 	ancount = ntohs(hp->ancount);
161173b30f0cSJun-ichiro itojun Hagino 	qdcount = ntohs(hp->qdcount);
161273b30f0cSJun-ichiro itojun Hagino 	bp = hostbuf;
1613d6af58f5SWarner Losh 	ep = hostbuf + sizeof hostbuf;
161473b30f0cSJun-ichiro itojun Hagino 	cp = answer->buf;
161573b30f0cSJun-ichiro itojun Hagino 	BOUNDED_INCR(HFIXEDSZ);
161673b30f0cSJun-ichiro itojun Hagino 	if (qdcount != 1) {
161773b30f0cSJun-ichiro itojun Hagino 		*errp = NO_RECOVERY;
161873b30f0cSJun-ichiro itojun Hagino 		return (NULL);
161973b30f0cSJun-ichiro itojun Hagino 	}
1620d6af58f5SWarner Losh 	n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
162173b30f0cSJun-ichiro itojun Hagino 	if ((n < 0) || !(*name_ok)(bp)) {
162273b30f0cSJun-ichiro itojun Hagino 		*errp = NO_RECOVERY;
162373b30f0cSJun-ichiro itojun Hagino 		return (NULL);
162473b30f0cSJun-ichiro itojun Hagino 	}
162573b30f0cSJun-ichiro itojun Hagino 	BOUNDED_INCR(n + QFIXEDSZ);
162673b30f0cSJun-ichiro itojun Hagino 	if (qtype == T_A || qtype == T_AAAA) {
162773b30f0cSJun-ichiro itojun Hagino 		/* res_send() has already verified that the query name is the
162873b30f0cSJun-ichiro itojun Hagino 		 * same as the one we sent; this just gets the expanded name
162973b30f0cSJun-ichiro itojun Hagino 		 * (i.e., with the succeeding search-domain tacked on).
163073b30f0cSJun-ichiro itojun Hagino 		 */
163173b30f0cSJun-ichiro itojun Hagino 		n = strlen(bp) + 1;		/* for the \0 */
163273b30f0cSJun-ichiro itojun Hagino 		if (n >= MAXHOSTNAMELEN) {
163373b30f0cSJun-ichiro itojun Hagino 			*errp = NO_RECOVERY;
163473b30f0cSJun-ichiro itojun Hagino 			return (NULL);
163573b30f0cSJun-ichiro itojun Hagino 		}
163673b30f0cSJun-ichiro itojun Hagino 		template->h_name = bp;
163773b30f0cSJun-ichiro itojun Hagino 		bp += n;
163873b30f0cSJun-ichiro itojun Hagino 		/* The qname can be abbreviated, but h_name is now absolute. */
163973b30f0cSJun-ichiro itojun Hagino 		qname = template->h_name;
164073b30f0cSJun-ichiro itojun Hagino 	}
164173b30f0cSJun-ichiro itojun Hagino 	ap = host_aliases;
164273b30f0cSJun-ichiro itojun Hagino 	*ap = NULL;
164373b30f0cSJun-ichiro itojun Hagino 	template->h_aliases = host_aliases;
164473b30f0cSJun-ichiro itojun Hagino 	hap = h_addr_ptrs;
164573b30f0cSJun-ichiro itojun Hagino 	*hap = NULL;
164673b30f0cSJun-ichiro itojun Hagino 	template->h_addr_list = h_addr_ptrs;
164773b30f0cSJun-ichiro itojun Hagino 	haveanswer = 0;
164873b30f0cSJun-ichiro itojun Hagino 	had_error = 0;
164973b30f0cSJun-ichiro itojun Hagino 	while (ancount-- > 0 && cp < eom && !had_error) {
1650d6af58f5SWarner Losh 		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
165173b30f0cSJun-ichiro itojun Hagino 		DNS_FATAL(n >= 0);
165273b30f0cSJun-ichiro itojun Hagino 		DNS_FATAL((*name_ok)(bp));
165373b30f0cSJun-ichiro itojun Hagino 		cp += n;			/* name */
165473b30f0cSJun-ichiro itojun Hagino 		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
165573b30f0cSJun-ichiro itojun Hagino 		type = _getshort(cp);
165673b30f0cSJun-ichiro itojun Hagino  		cp += INT16SZ;			/* type */
165773b30f0cSJun-ichiro itojun Hagino 		class = _getshort(cp);
165873b30f0cSJun-ichiro itojun Hagino  		cp += INT16SZ + INT32SZ;	/* class, TTL */
165973b30f0cSJun-ichiro itojun Hagino 		n = _getshort(cp);
166073b30f0cSJun-ichiro itojun Hagino 		cp += INT16SZ;			/* len */
166173b30f0cSJun-ichiro itojun Hagino 		BOUNDS_CHECK(cp, n);
166273b30f0cSJun-ichiro itojun Hagino 		erdata = cp + n;
166373b30f0cSJun-ichiro itojun Hagino 		DNS_ASSERT(class == C_IN);
166473b30f0cSJun-ichiro itojun Hagino 		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
166573b30f0cSJun-ichiro itojun Hagino 			if (ap >= &host_aliases[MAXALIASES-1])
166673b30f0cSJun-ichiro itojun Hagino 				continue;
166773b30f0cSJun-ichiro itojun Hagino 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
166873b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n >= 0);
166973b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL((*name_ok)(tbuf));
16707d56d374SYoshinobu Inoue 			cp += n;
167173b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
167273b30f0cSJun-ichiro itojun Hagino 				*errp = NO_RECOVERY;
167373b30f0cSJun-ichiro itojun Hagino 				return (NULL);
167473b30f0cSJun-ichiro itojun Hagino 			}
167573b30f0cSJun-ichiro itojun Hagino 			/* Store alias. */
167673b30f0cSJun-ichiro itojun Hagino 			*ap++ = bp;
167773b30f0cSJun-ichiro itojun Hagino 			n = strlen(bp) + 1;	/* for the \0 */
167873b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n < MAXHOSTNAMELEN);
167973b30f0cSJun-ichiro itojun Hagino 			bp += n;
168073b30f0cSJun-ichiro itojun Hagino 			/* Get canonical name. */
168173b30f0cSJun-ichiro itojun Hagino 			n = strlen(tbuf) + 1;	/* for the \0 */
1682d6af58f5SWarner Losh 			DNS_FATAL(n <= ep - bp);
168373b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n < MAXHOSTNAMELEN);
168473b30f0cSJun-ichiro itojun Hagino 			strcpy(bp, tbuf);
168573b30f0cSJun-ichiro itojun Hagino 			template->h_name = bp;
168673b30f0cSJun-ichiro itojun Hagino 			bp += n;
168773b30f0cSJun-ichiro itojun Hagino 			continue;
168873b30f0cSJun-ichiro itojun Hagino 		}
168973b30f0cSJun-ichiro itojun Hagino 		if (qtype == T_PTR && type == T_CNAME) {
169073b30f0cSJun-ichiro itojun Hagino 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
169173b30f0cSJun-ichiro itojun Hagino 			if (n < 0 || !res_dnok(tbuf)) {
169273b30f0cSJun-ichiro itojun Hagino 				had_error++;
169373b30f0cSJun-ichiro itojun Hagino 				continue;
169473b30f0cSJun-ichiro itojun Hagino 			}
169573b30f0cSJun-ichiro itojun Hagino 			cp += n;
169673b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
169773b30f0cSJun-ichiro itojun Hagino 				*errp = NO_RECOVERY;
169873b30f0cSJun-ichiro itojun Hagino 				return (NULL);
169973b30f0cSJun-ichiro itojun Hagino 			}
170073b30f0cSJun-ichiro itojun Hagino 			/* Get canonical name. */
170173b30f0cSJun-ichiro itojun Hagino 			n = strlen(tbuf) + 1;	/* for the \0 */
1702d6af58f5SWarner Losh 			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
170373b30f0cSJun-ichiro itojun Hagino 				had_error++;
170473b30f0cSJun-ichiro itojun Hagino 				continue;
170573b30f0cSJun-ichiro itojun Hagino 			}
170673b30f0cSJun-ichiro itojun Hagino 			strcpy(bp, tbuf);
17073f587e57SKris Kennaway 			tname = bp;
170873b30f0cSJun-ichiro itojun Hagino 			bp += n;
170973b30f0cSJun-ichiro itojun Hagino 			continue;
171073b30f0cSJun-ichiro itojun Hagino 		}
171173b30f0cSJun-ichiro itojun Hagino 		DNS_ASSERT(type == qtype);
171273b30f0cSJun-ichiro itojun Hagino 		switch (type) {
171373b30f0cSJun-ichiro itojun Hagino 		case T_PTR:
171473b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(strcasecmp(tname, bp) == 0);
1715d6af58f5SWarner Losh 			n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
171673b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n >= 0);
171773b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(res_hnok(bp));
171873b30f0cSJun-ichiro itojun Hagino #if MULTI_PTRS_ARE_ALIASES
171973b30f0cSJun-ichiro itojun Hagino 			cp += n;
172073b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
172173b30f0cSJun-ichiro itojun Hagino 				*errp = NO_RECOVERY;
172273b30f0cSJun-ichiro itojun Hagino 				return (NULL);
172373b30f0cSJun-ichiro itojun Hagino 			}
172473b30f0cSJun-ichiro itojun Hagino 			if (!haveanswer)
172573b30f0cSJun-ichiro itojun Hagino 				template->h_name = bp;
172673b30f0cSJun-ichiro itojun Hagino 			else if (ap < &host_aliases[MAXALIASES-1])
172773b30f0cSJun-ichiro itojun Hagino 				*ap++ = bp;
172873b30f0cSJun-ichiro itojun Hagino 			else
172973b30f0cSJun-ichiro itojun Hagino 				n = -1;
173073b30f0cSJun-ichiro itojun Hagino 			if (n != -1) {
173173b30f0cSJun-ichiro itojun Hagino 				n = strlen(bp) + 1;	/* for the \0 */
173273b30f0cSJun-ichiro itojun Hagino 				if (n >= MAXHOSTNAMELEN) {
173373b30f0cSJun-ichiro itojun Hagino 					had_error++;
17347d56d374SYoshinobu Inoue 					break;
17357d56d374SYoshinobu Inoue 				}
173673b30f0cSJun-ichiro itojun Hagino 				bp += n;
17377d56d374SYoshinobu Inoue 			}
173873b30f0cSJun-ichiro itojun Hagino 			break;
173973b30f0cSJun-ichiro itojun Hagino #else
174073b30f0cSJun-ichiro itojun Hagino 			template->h_name = bp;
174173b30f0cSJun-ichiro itojun Hagino 			*errp = NETDB_SUCCESS;
174273b30f0cSJun-ichiro itojun Hagino 			return (template);
174373b30f0cSJun-ichiro itojun Hagino #endif
174473b30f0cSJun-ichiro itojun Hagino 		case T_A:
174573b30f0cSJun-ichiro itojun Hagino 		case T_AAAA:
174673b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(strcasecmp(template->h_name, bp) == 0);
174773b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(n == template->h_length);
174873b30f0cSJun-ichiro itojun Hagino 			if (!haveanswer) {
17498fb3f3f6SDavid E. O'Brien 				int nn;
175073b30f0cSJun-ichiro itojun Hagino 
175173b30f0cSJun-ichiro itojun Hagino 				template->h_name = bp;
175273b30f0cSJun-ichiro itojun Hagino 				nn = strlen(bp) + 1;	/* for the \0 */
175373b30f0cSJun-ichiro itojun Hagino 				bp += nn;
175473b30f0cSJun-ichiro itojun Hagino 			}
175573b30f0cSJun-ichiro itojun Hagino 			bp = (char *)ALIGN(bp);
175673b30f0cSJun-ichiro itojun Hagino 
1757d6af58f5SWarner Losh 			DNS_FATAL(bp + n < ep);
175873b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(hap < &h_addr_ptrs[MAXADDRS-1]);
175973b30f0cSJun-ichiro itojun Hagino #ifdef FILTER_V4MAPPED
176073b30f0cSJun-ichiro itojun Hagino 			if (type == T_AAAA) {
176173b30f0cSJun-ichiro itojun Hagino 				struct in6_addr in6;
176273b30f0cSJun-ichiro itojun Hagino 				memcpy(&in6, cp, sizeof(in6));
176373b30f0cSJun-ichiro itojun Hagino 				DNS_ASSERT(IN6_IS_ADDR_V4MAPPED(&in6) == 0);
176473b30f0cSJun-ichiro itojun Hagino 			}
176573b30f0cSJun-ichiro itojun Hagino #endif
176673b30f0cSJun-ichiro itojun Hagino 			bcopy(cp, *hap++ = bp, n);
176773b30f0cSJun-ichiro itojun Hagino 			bp += n;
176873b30f0cSJun-ichiro itojun Hagino 			cp += n;
176973b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
17707d56d374SYoshinobu Inoue 				*errp = NO_RECOVERY;
177173b30f0cSJun-ichiro itojun Hagino 				return (NULL);
17727d56d374SYoshinobu Inoue 			}
177373b30f0cSJun-ichiro itojun Hagino 			break;
177473b30f0cSJun-ichiro itojun Hagino 		default:
177573b30f0cSJun-ichiro itojun Hagino 			abort();
177673b30f0cSJun-ichiro itojun Hagino 		}
177773b30f0cSJun-ichiro itojun Hagino 		if (!had_error)
177873b30f0cSJun-ichiro itojun Hagino 			haveanswer++;
177973b30f0cSJun-ichiro itojun Hagino 	}
178073b30f0cSJun-ichiro itojun Hagino 	if (haveanswer) {
178173b30f0cSJun-ichiro itojun Hagino 		*ap = NULL;
178273b30f0cSJun-ichiro itojun Hagino 		*hap = NULL;
178373b30f0cSJun-ichiro itojun Hagino 		if (!template->h_name) {
178473b30f0cSJun-ichiro itojun Hagino 			n = strlen(qname) + 1;	/* for the \0 */
1785d6af58f5SWarner Losh 			if (n > ep - bp || n >= MAXHOSTNAMELEN)
178673b30f0cSJun-ichiro itojun Hagino 				goto no_recovery;
178773b30f0cSJun-ichiro itojun Hagino 			strcpy(bp, qname);
178873b30f0cSJun-ichiro itojun Hagino 			template->h_name = bp;
178973b30f0cSJun-ichiro itojun Hagino 			bp += n;
179073b30f0cSJun-ichiro itojun Hagino 		}
179173b30f0cSJun-ichiro itojun Hagino 		*errp = NETDB_SUCCESS;
179273b30f0cSJun-ichiro itojun Hagino 		return (template);
179373b30f0cSJun-ichiro itojun Hagino 	}
179473b30f0cSJun-ichiro itojun Hagino  no_recovery:
179573b30f0cSJun-ichiro itojun Hagino 	*errp = NO_RECOVERY;
179673b30f0cSJun-ichiro itojun Hagino 	return (NULL);
179773b30f0cSJun-ichiro itojun Hagino 
179873b30f0cSJun-ichiro itojun Hagino #undef BOUNDED_INCR
179973b30f0cSJun-ichiro itojun Hagino #undef BOUNDS_CHECK
180073b30f0cSJun-ichiro itojun Hagino #undef DNS_ASSERT
180173b30f0cSJun-ichiro itojun Hagino #undef DNS_FATAL
18027d56d374SYoshinobu Inoue }
18037d56d374SYoshinobu Inoue 
1804e6f35403SYoshinobu Inoue /* res_search() variant with multiple query support. */
1805e6f35403SYoshinobu Inoue static struct hostent *
1806e6f35403SYoshinobu Inoue _res_search_multi(name, rtl, errp)
1807e6f35403SYoshinobu Inoue 	const char *name;	/* domain name */
1808e6f35403SYoshinobu Inoue 	struct	__res_type_list *rtl; /* list of query types */
1809e6f35403SYoshinobu Inoue 	int *errp;
1810e6f35403SYoshinobu Inoue {
1811e6f35403SYoshinobu Inoue 	const char *cp, * const *domain;
1812e6f35403SYoshinobu Inoue 	struct hostent *hp0 = NULL, *hp;
181373b30f0cSJun-ichiro itojun Hagino 	struct hostent hpbuf;
1814e6f35403SYoshinobu Inoue 	u_int dots;
1815e6f35403SYoshinobu Inoue 	int trailing_dot, ret, saved_herrno;
1816e6f35403SYoshinobu Inoue 	int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1817e6f35403SYoshinobu Inoue 	struct __res_type_list *rtl0 = rtl;
18189832619cSHajimu UMEMOTO 	querybuf *buf;
1819e6f35403SYoshinobu Inoue 
1820e6f35403SYoshinobu Inoue 	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
1821e6f35403SYoshinobu Inoue 		*errp = NETDB_INTERNAL;
1822e6f35403SYoshinobu Inoue 		return (NULL);
1823e6f35403SYoshinobu Inoue 	}
1824e6f35403SYoshinobu Inoue 	dots = 0;
1825e6f35403SYoshinobu Inoue 	for (cp = name; *cp; cp++)
1826e6f35403SYoshinobu Inoue 		dots += (*cp == '.');
1827e6f35403SYoshinobu Inoue 	trailing_dot = 0;
1828e6f35403SYoshinobu Inoue 	if (cp > name && *--cp == '.')
1829e6f35403SYoshinobu Inoue 		trailing_dot++;
1830e6f35403SYoshinobu Inoue 
18319832619cSHajimu UMEMOTO 	buf = malloc(sizeof(*buf));
18329832619cSHajimu UMEMOTO 	if (buf == NULL) {
18339832619cSHajimu UMEMOTO 		*errp = NETDB_INTERNAL;
18349832619cSHajimu UMEMOTO 		return NULL;
18359832619cSHajimu UMEMOTO 	}
18369832619cSHajimu UMEMOTO 
1837e6f35403SYoshinobu Inoue 	/* If there aren't any dots, it could be a user-level alias */
1838e6f35403SYoshinobu Inoue 	if (!dots && (cp = hostalias(name)) != NULL) {
1839e6f35403SYoshinobu Inoue 		for(rtl = rtl0; rtl != NULL;
1840e6f35403SYoshinobu Inoue 		    rtl = SLIST_NEXT(rtl, rtl_entry)) {
18419832619cSHajimu UMEMOTO 			ret = res_query(cp, C_IN, rtl->rtl_type, buf->buf,
18429832619cSHajimu UMEMOTO 					     sizeof(buf->buf));
18439832619cSHajimu UMEMOTO 			if (ret > 0 && ret < sizeof(buf->buf)) {
184473b30f0cSJun-ichiro itojun Hagino 				hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
184573b30f0cSJun-ichiro itojun Hagino 				    ? AF_INET6 : AF_INET;
184673b30f0cSJun-ichiro itojun Hagino 				hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
18479832619cSHajimu UMEMOTO 				hp = getanswer(buf, ret, name, rtl->rtl_type,
184873b30f0cSJun-ichiro itojun Hagino 						    &hpbuf, errp);
18493f587e57SKris Kennaway 				if (!hp)
18503f587e57SKris Kennaway 					continue;
185173b30f0cSJun-ichiro itojun Hagino 				hp = _hpcopy(&hpbuf, errp);
1852e6f35403SYoshinobu Inoue 				hp0 = _hpmerge(hp0, hp, errp);
185354846c9fSPierre Beyssac 			} else
185454846c9fSPierre Beyssac 				*errp = h_errno;
1855e6f35403SYoshinobu Inoue 		}
18569832619cSHajimu UMEMOTO 		free(buf);
1857e6f35403SYoshinobu Inoue 		return (hp0);
1858e6f35403SYoshinobu Inoue 	}
1859e6f35403SYoshinobu Inoue 
1860e6f35403SYoshinobu Inoue 	/*
1861e6f35403SYoshinobu Inoue 	 * If there are dots in the name already, let's just give it a try
1862e6f35403SYoshinobu Inoue 	 * 'as is'.  The threshold can be set with the "ndots" option.
1863e6f35403SYoshinobu Inoue 	 */
1864e6f35403SYoshinobu Inoue 	saved_herrno = -1;
1865e6f35403SYoshinobu Inoue 	if (dots >= _res.ndots) {
1866e6f35403SYoshinobu Inoue 		for(rtl = rtl0; rtl != NULL;
1867e6f35403SYoshinobu Inoue 		    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1868e6f35403SYoshinobu Inoue 			ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type,
18699832619cSHajimu UMEMOTO 					      buf->buf, sizeof(buf->buf));
18709832619cSHajimu UMEMOTO 			if (ret > 0 && ret < sizeof(buf->buf)) {
187173b30f0cSJun-ichiro itojun Hagino 				hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
187273b30f0cSJun-ichiro itojun Hagino 				    ? AF_INET6 : AF_INET;
187373b30f0cSJun-ichiro itojun Hagino 				hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
18749832619cSHajimu UMEMOTO 				hp = getanswer(buf, ret, name, rtl->rtl_type,
187573b30f0cSJun-ichiro itojun Hagino 						    &hpbuf, errp);
18763f587e57SKris Kennaway 				if (!hp)
18773f587e57SKris Kennaway 					continue;
187873b30f0cSJun-ichiro itojun Hagino 				hp = _hpcopy(&hpbuf, errp);
1879e6f35403SYoshinobu Inoue 				hp0 = _hpmerge(hp0, hp, errp);
1880e651d83aSPierre Beyssac 			} else
1881e651d83aSPierre Beyssac 				*errp = h_errno;
1882e6f35403SYoshinobu Inoue 		}
18839832619cSHajimu UMEMOTO 		if (hp0 != NULL) {
18849832619cSHajimu UMEMOTO 			free(buf);
1885e6f35403SYoshinobu Inoue 			return (hp0);
18869832619cSHajimu UMEMOTO 		}
1887e6f35403SYoshinobu Inoue 		saved_herrno = *errp;
1888e6f35403SYoshinobu Inoue 		tried_as_is++;
1889e6f35403SYoshinobu Inoue 	}
1890e6f35403SYoshinobu Inoue 
1891e6f35403SYoshinobu Inoue 	/*
1892e6f35403SYoshinobu Inoue 	 * We do at least one level of search if
1893e6f35403SYoshinobu Inoue 	 *	- there is no dot and RES_DEFNAME is set, or
1894e6f35403SYoshinobu Inoue 	 *	- there is at least one dot, there is no trailing dot,
1895e6f35403SYoshinobu Inoue 	 *	  and RES_DNSRCH is set.
1896e6f35403SYoshinobu Inoue 	 */
1897e6f35403SYoshinobu Inoue 	if ((!dots && (_res.options & RES_DEFNAMES)) ||
1898e6f35403SYoshinobu Inoue 	    (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
1899e6f35403SYoshinobu Inoue 		int done = 0;
1900e6f35403SYoshinobu Inoue 
1901e6f35403SYoshinobu Inoue 		for (domain = (const char * const *)_res.dnsrch;
1902e6f35403SYoshinobu Inoue 		     *domain && !done;
1903e6f35403SYoshinobu Inoue 		     domain++) {
1904e6f35403SYoshinobu Inoue 
1905e6f35403SYoshinobu Inoue 			for(rtl = rtl0; rtl != NULL;
1906e6f35403SYoshinobu Inoue 			    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1907e6f35403SYoshinobu Inoue 				ret = res_querydomain(name, *domain, C_IN,
1908e6f35403SYoshinobu Inoue 						      rtl->rtl_type,
19099832619cSHajimu UMEMOTO 						      buf->buf, sizeof(buf->buf));
19109832619cSHajimu UMEMOTO 				if (ret > 0 && ret < sizeof(buf->buf)) {
191173b30f0cSJun-ichiro itojun Hagino 					hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
191273b30f0cSJun-ichiro itojun Hagino 					    ? AF_INET6 : AF_INET;
191373b30f0cSJun-ichiro itojun Hagino 					hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
19149832619cSHajimu UMEMOTO 					hp = getanswer(buf, ret, name,
191573b30f0cSJun-ichiro itojun Hagino 					    rtl->rtl_type, &hpbuf, errp);
19163f587e57SKris Kennaway 					if (!hp)
19173f587e57SKris Kennaway 						continue;
191873b30f0cSJun-ichiro itojun Hagino 					hp = _hpcopy(&hpbuf, errp);
1919e6f35403SYoshinobu Inoue 					hp0 = _hpmerge(hp0, hp, errp);
1920e651d83aSPierre Beyssac 				} else
1921e651d83aSPierre Beyssac 					*errp = h_errno;
1922e6f35403SYoshinobu Inoue 			}
19239832619cSHajimu UMEMOTO 			if (hp0 != NULL) {
19249832619cSHajimu UMEMOTO 				free(buf);
1925e6f35403SYoshinobu Inoue 				return (hp0);
19269832619cSHajimu UMEMOTO 			}
1927e6f35403SYoshinobu Inoue 
1928e6f35403SYoshinobu Inoue 			/*
1929e6f35403SYoshinobu Inoue 			 * If no server present, give up.
1930e6f35403SYoshinobu Inoue 			 * If name isn't found in this domain,
1931e6f35403SYoshinobu Inoue 			 * keep trying higher domains in the search list
1932e6f35403SYoshinobu Inoue 			 * (if that's enabled).
1933e6f35403SYoshinobu Inoue 			 * On a NO_DATA error, keep trying, otherwise
1934e6f35403SYoshinobu Inoue 			 * a wildcard entry of another type could keep us
1935e6f35403SYoshinobu Inoue 			 * from finding this entry higher in the domain.
1936e6f35403SYoshinobu Inoue 			 * If we get some other error (negative answer or
1937e6f35403SYoshinobu Inoue 			 * server failure), then stop searching up,
1938e6f35403SYoshinobu Inoue 			 * but try the input name below in case it's
1939e6f35403SYoshinobu Inoue 			 * fully-qualified.
1940e6f35403SYoshinobu Inoue 			 */
1941e6f35403SYoshinobu Inoue 			if (errno == ECONNREFUSED) {
19429832619cSHajimu UMEMOTO 				free(buf);
1943e6f35403SYoshinobu Inoue 				*errp = TRY_AGAIN;
1944e6f35403SYoshinobu Inoue 				return (NULL);
1945e6f35403SYoshinobu Inoue 			}
1946e6f35403SYoshinobu Inoue 
1947e6f35403SYoshinobu Inoue 			switch (*errp) {
1948e6f35403SYoshinobu Inoue 			case NO_DATA:
1949e6f35403SYoshinobu Inoue 				got_nodata++;
1950e6f35403SYoshinobu Inoue 				/* FALLTHROUGH */
1951e6f35403SYoshinobu Inoue 			case HOST_NOT_FOUND:
1952e6f35403SYoshinobu Inoue 				/* keep trying */
1953e6f35403SYoshinobu Inoue 				break;
1954e6f35403SYoshinobu Inoue 			case TRY_AGAIN:
19559832619cSHajimu UMEMOTO 				if (buf->hdr.rcode == SERVFAIL) {
1956e6f35403SYoshinobu Inoue 					/* try next search element, if any */
1957e6f35403SYoshinobu Inoue 					got_servfail++;
1958e6f35403SYoshinobu Inoue 					break;
1959e6f35403SYoshinobu Inoue 				}
1960e6f35403SYoshinobu Inoue 				/* FALLTHROUGH */
1961e6f35403SYoshinobu Inoue 			default:
1962e6f35403SYoshinobu Inoue 				/* anything else implies that we're done */
1963e6f35403SYoshinobu Inoue 				done++;
1964e6f35403SYoshinobu Inoue 			}
1965e6f35403SYoshinobu Inoue 
1966e6f35403SYoshinobu Inoue 			/* if we got here for some reason other than DNSRCH,
1967e6f35403SYoshinobu Inoue 			 * we only wanted one iteration of the loop, so stop.
1968e6f35403SYoshinobu Inoue 			 */
1969e6f35403SYoshinobu Inoue 			if (!(_res.options & RES_DNSRCH))
1970e6f35403SYoshinobu Inoue 				done++;
1971e6f35403SYoshinobu Inoue 		}
1972e6f35403SYoshinobu Inoue 	}
1973e6f35403SYoshinobu Inoue 
1974e6f35403SYoshinobu Inoue 	/*
1975e6f35403SYoshinobu Inoue 	 * If we have not already tried the name "as is", do that now.
1976e6f35403SYoshinobu Inoue 	 * note that we do this regardless of how many dots were in the
1977e6f35403SYoshinobu Inoue 	 * name or whether it ends with a dot unless NOTLDQUERY is set.
1978e6f35403SYoshinobu Inoue 	 */
1979e6f35403SYoshinobu Inoue 	if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) {
1980e6f35403SYoshinobu Inoue 		for(rtl = rtl0; rtl != NULL;
1981e6f35403SYoshinobu Inoue 		    rtl = SLIST_NEXT(rtl, rtl_entry)) {
1982e6f35403SYoshinobu Inoue 			ret = res_querydomain(name, NULL, C_IN, rtl->rtl_type,
19839832619cSHajimu UMEMOTO 					      buf->buf, sizeof(buf->buf));
19849832619cSHajimu UMEMOTO 			if (ret > 0 && ret < sizeof(buf->buf)) {
198573b30f0cSJun-ichiro itojun Hagino 				hpbuf.h_addrtype = (rtl->rtl_type == T_AAAA)
198673b30f0cSJun-ichiro itojun Hagino 				    ? AF_INET6 : AF_INET;
198773b30f0cSJun-ichiro itojun Hagino 				hpbuf.h_length = ADDRLEN(hpbuf.h_addrtype);
19889832619cSHajimu UMEMOTO 				hp = getanswer(buf, ret, name, rtl->rtl_type,
198973b30f0cSJun-ichiro itojun Hagino 				    &hpbuf, errp);
19903f587e57SKris Kennaway 				if (!hp)
19913f587e57SKris Kennaway 					continue;
199273b30f0cSJun-ichiro itojun Hagino 				hp = _hpcopy(&hpbuf, errp);
1993e6f35403SYoshinobu Inoue 				hp0 = _hpmerge(hp0, hp, errp);
1994e651d83aSPierre Beyssac 			} else
1995e651d83aSPierre Beyssac 				*errp = h_errno;
1996e6f35403SYoshinobu Inoue 		}
19979832619cSHajimu UMEMOTO 		if (hp0 != NULL) {
19989832619cSHajimu UMEMOTO 			free(buf);
1999e6f35403SYoshinobu Inoue 			return (hp0);
2000e6f35403SYoshinobu Inoue 		}
20019832619cSHajimu UMEMOTO 	}
20029832619cSHajimu UMEMOTO 
20039832619cSHajimu UMEMOTO 	free(buf);
2004e6f35403SYoshinobu Inoue 
2005e6f35403SYoshinobu Inoue 	/* if we got here, we didn't satisfy the search.
2006e6f35403SYoshinobu Inoue 	 * if we did an initial full query, return that query's h_errno
2007e6f35403SYoshinobu Inoue 	 * (note that we wouldn't be here if that query had succeeded).
2008e6f35403SYoshinobu Inoue 	 * else if we ever got a nodata, send that back as the reason.
2009e6f35403SYoshinobu Inoue 	 * else send back meaningless h_errno, that being the one from
2010e6f35403SYoshinobu Inoue 	 * the last DNSRCH we did.
2011e6f35403SYoshinobu Inoue 	 */
2012e6f35403SYoshinobu Inoue 	if (saved_herrno != -1)
2013e6f35403SYoshinobu Inoue 		*errp = saved_herrno;
2014e6f35403SYoshinobu Inoue 	else if (got_nodata)
2015e6f35403SYoshinobu Inoue 		*errp = NO_DATA;
2016e6f35403SYoshinobu Inoue 	else if (got_servfail)
2017e6f35403SYoshinobu Inoue 		*errp = TRY_AGAIN;
2018e6f35403SYoshinobu Inoue 	return (NULL);
2019e6f35403SYoshinobu Inoue }
2020e6f35403SYoshinobu Inoue 
2021248aee62SJacques Vidrine static int
2022248aee62SJacques Vidrine _dns_ghbyname(void *rval, void *cb_data, va_list ap)
2023e6f35403SYoshinobu Inoue {
2024248aee62SJacques Vidrine 	const char *name;
2025248aee62SJacques Vidrine 	int af;
2026248aee62SJacques Vidrine 	int *errp;
2027e6f35403SYoshinobu Inoue 	struct __res_type_list *rtl, rtl4;
2028e6f35403SYoshinobu Inoue #ifdef INET6
2029e6f35403SYoshinobu Inoue 	struct __res_type_list rtl6;
2030e6f35403SYoshinobu Inoue #endif
2031e6f35403SYoshinobu Inoue 
2032248aee62SJacques Vidrine 	name = va_arg(ap, const char *);
2033248aee62SJacques Vidrine 	af = va_arg(ap, int);
2034248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
2035248aee62SJacques Vidrine 
2036e6f35403SYoshinobu Inoue #ifdef INET6
2037e6f35403SYoshinobu Inoue 	switch (af) {
2038e6f35403SYoshinobu Inoue 	case AF_UNSPEC:
2039e6f35403SYoshinobu Inoue 		SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
2040e6f35403SYoshinobu Inoue 		SLIST_NEXT(&rtl6, rtl_entry) = &rtl4; rtl6.rtl_type = T_AAAA;
2041e6f35403SYoshinobu Inoue 		rtl = &rtl6;
2042e6f35403SYoshinobu Inoue 		break;
2043e6f35403SYoshinobu Inoue 	case AF_INET6:
2044e6f35403SYoshinobu Inoue 		SLIST_NEXT(&rtl6, rtl_entry) = NULL; rtl6.rtl_type = T_AAAA;
2045e6f35403SYoshinobu Inoue 		rtl = &rtl6;
2046e6f35403SYoshinobu Inoue 		break;
2047e6f35403SYoshinobu Inoue 	case AF_INET:
2048e6f35403SYoshinobu Inoue 		SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
2049e6f35403SYoshinobu Inoue 		rtl = &rtl4;
2050e6f35403SYoshinobu Inoue 		break;
2051e6f35403SYoshinobu Inoue 	}
2052e6f35403SYoshinobu Inoue #else
2053e6f35403SYoshinobu Inoue 	SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
2054e6f35403SYoshinobu Inoue 	rtl = &rtl4;
2055e6f35403SYoshinobu Inoue #endif
2056248aee62SJacques Vidrine 	*(struct hostent **)rval = _res_search_multi(name, rtl, errp);
2057e651d83aSPierre Beyssac 	if (*(struct hostent **)rval != NULL)
2058e651d83aSPierre Beyssac 		return NS_SUCCESS;
2059e651d83aSPierre Beyssac 	else if (*errp == TRY_AGAIN)
2060e651d83aSPierre Beyssac 		return NS_TRYAGAIN;
2061e651d83aSPierre Beyssac 	else
2062e651d83aSPierre Beyssac 		return NS_NOTFOUND;
2063e6f35403SYoshinobu Inoue }
2064e6f35403SYoshinobu Inoue 
2065248aee62SJacques Vidrine static int
2066248aee62SJacques Vidrine _dns_ghbyaddr(void *rval, void *cb_data, va_list ap)
20677d56d374SYoshinobu Inoue {
2068248aee62SJacques Vidrine 	const void *addr;
2069248aee62SJacques Vidrine 	int addrlen;
2070248aee62SJacques Vidrine 	int af;
2071248aee62SJacques Vidrine 	int *errp;
20727d56d374SYoshinobu Inoue 	int n;
2073aadad922SHajimu UMEMOTO 	int err;
207473b30f0cSJun-ichiro itojun Hagino 	struct hostent *hp;
207573b30f0cSJun-ichiro itojun Hagino 	u_char c, *cp;
20767d56d374SYoshinobu Inoue 	char *bp;
20777d56d374SYoshinobu Inoue 	struct hostent hbuf;
20787d56d374SYoshinobu Inoue 	int na;
20797d56d374SYoshinobu Inoue #ifdef INET6
20807d56d374SYoshinobu Inoue 	static const char hex[] = "0123456789abcdef";
20817d56d374SYoshinobu Inoue #endif
20829832619cSHajimu UMEMOTO 	querybuf *buf;
208373b30f0cSJun-ichiro itojun Hagino 	char qbuf[MAXDNAME+1];
208473b30f0cSJun-ichiro itojun Hagino 	char *hlist[2];
2085aadad922SHajimu UMEMOTO 	char *tld6[] = { "ip6.arpa", "ip6.int", NULL };
2086aadad922SHajimu UMEMOTO 	char *tld4[] = { "in-addr.arpa", NULL };
2087aadad922SHajimu UMEMOTO 	char **tld;
20887d56d374SYoshinobu Inoue 
2089248aee62SJacques Vidrine 	addr = va_arg(ap, const void *);
2090248aee62SJacques Vidrine 	addrlen = va_arg(ap, int);
2091248aee62SJacques Vidrine 	af = va_arg(ap, int);
2092248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
2093248aee62SJacques Vidrine 
2094248aee62SJacques Vidrine 	*(struct hostent **)rval = NULL;
2095248aee62SJacques Vidrine 
20967d56d374SYoshinobu Inoue #ifdef INET6
20977d56d374SYoshinobu Inoue 	/* XXX */
20987d56d374SYoshinobu Inoue 	if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
2099248aee62SJacques Vidrine 		return NS_NOTFOUND;
21007d56d374SYoshinobu Inoue #endif
21017d56d374SYoshinobu Inoue 
2102aadad922SHajimu UMEMOTO 	switch (af) {
2103aadad922SHajimu UMEMOTO #ifdef INET6
2104aadad922SHajimu UMEMOTO 	case AF_INET6:
2105aadad922SHajimu UMEMOTO 		tld = tld6;
2106aadad922SHajimu UMEMOTO 		break;
2107aadad922SHajimu UMEMOTO #endif
2108aadad922SHajimu UMEMOTO 	case AF_INET:
2109aadad922SHajimu UMEMOTO 		tld = tld4;
2110aadad922SHajimu UMEMOTO 		break;
2111aadad922SHajimu UMEMOTO 	default:
2112aadad922SHajimu UMEMOTO 		return NS_NOTFOUND;
2113aadad922SHajimu UMEMOTO 	}
2114aadad922SHajimu UMEMOTO 
21157d56d374SYoshinobu Inoue 	if ((_res.options & RES_INIT) == 0) {
21167d56d374SYoshinobu Inoue 		if (res_init() < 0) {
21177d56d374SYoshinobu Inoue 			*errp = h_errno;
2118248aee62SJacques Vidrine 			return NS_UNAVAIL;
21197d56d374SYoshinobu Inoue 		}
21207d56d374SYoshinobu Inoue 	}
212173b30f0cSJun-ichiro itojun Hagino 	memset(&hbuf, 0, sizeof(hbuf));
21227d56d374SYoshinobu Inoue 	hbuf.h_name = NULL;
21237d56d374SYoshinobu Inoue 	hbuf.h_addrtype = af;
21247d56d374SYoshinobu Inoue 	hbuf.h_length = addrlen;
21257d56d374SYoshinobu Inoue 	na = 0;
21267d56d374SYoshinobu Inoue 
2127aadad922SHajimu UMEMOTO 	buf = malloc(sizeof(*buf));
2128aadad922SHajimu UMEMOTO 	if (buf == NULL) {
2129aadad922SHajimu UMEMOTO 		*errp = NETDB_INTERNAL;
2130aadad922SHajimu UMEMOTO 		return NS_UNAVAIL;
2131aadad922SHajimu UMEMOTO 	}
2132aadad922SHajimu UMEMOTO 	err = NS_SUCCESS;
2133aadad922SHajimu UMEMOTO 	for (/* nothing */; *tld; tld++) {
2134aadad922SHajimu UMEMOTO 		/*
2135aadad922SHajimu UMEMOTO 		 * XXX assumes that MAXDNAME is big enough - error checks
2136aadad922SHajimu UMEMOTO 		 * has been made by callers
2137aadad922SHajimu UMEMOTO 		 */
21387d56d374SYoshinobu Inoue 		n = 0;
213973b30f0cSJun-ichiro itojun Hagino 		bp = qbuf;
21407d56d374SYoshinobu Inoue 		cp = (u_char *)addr+addrlen-1;
21417d56d374SYoshinobu Inoue 		switch (af) {
21427d56d374SYoshinobu Inoue #ifdef INET6
21437d56d374SYoshinobu Inoue 		case AF_INET6:
21447d56d374SYoshinobu Inoue 			for (; n < addrlen; n++, cp--) {
21457d56d374SYoshinobu Inoue 				c = *cp;
21467d56d374SYoshinobu Inoue 				*bp++ = hex[c & 0xf];
21477d56d374SYoshinobu Inoue 				*bp++ = '.';
21487d56d374SYoshinobu Inoue 				*bp++ = hex[c >> 4];
21497d56d374SYoshinobu Inoue 				*bp++ = '.';
21507d56d374SYoshinobu Inoue 			}
2151aadad922SHajimu UMEMOTO 			strcpy(bp, *tld);
21527d56d374SYoshinobu Inoue 			break;
21537d56d374SYoshinobu Inoue #endif
2154aadad922SHajimu UMEMOTO 		case AF_INET:
21557d56d374SYoshinobu Inoue 			for (; n < addrlen; n++, cp--) {
21567d56d374SYoshinobu Inoue 				c = *cp;
21577d56d374SYoshinobu Inoue 				if (c >= 100)
21587d56d374SYoshinobu Inoue 					*bp++ = '0' + c / 100;
21597d56d374SYoshinobu Inoue 				if (c >= 10)
21607d56d374SYoshinobu Inoue 					*bp++ = '0' + (c % 100) / 10;
21617d56d374SYoshinobu Inoue 				*bp++ = '0' + c % 10;
21627d56d374SYoshinobu Inoue 				*bp++ = '.';
21637d56d374SYoshinobu Inoue 			}
2164aadad922SHajimu UMEMOTO 			strcpy(bp, *tld);
21657d56d374SYoshinobu Inoue 			break;
21667d56d374SYoshinobu Inoue 		}
21677d56d374SYoshinobu Inoue 
21689832619cSHajimu UMEMOTO 		n = res_query(qbuf, C_IN, T_PTR, buf->buf, sizeof buf->buf);
21697d56d374SYoshinobu Inoue 		if (n < 0) {
21707d56d374SYoshinobu Inoue 			*errp = h_errno;
2171aadad922SHajimu UMEMOTO 			err = NS_UNAVAIL;
2172aadad922SHajimu UMEMOTO 			continue;
21739832619cSHajimu UMEMOTO 		} else if (n > sizeof(buf->buf)) {
217454384cf3SJacques Vidrine #if 0
217554384cf3SJacques Vidrine 			errno = ERANGE; /* XXX is it OK to set errno here? */
217654384cf3SJacques Vidrine #endif
217754384cf3SJacques Vidrine 			*errp = NETDB_INTERNAL;
2178aadad922SHajimu UMEMOTO 			err = NS_UNAVAIL;
2179aadad922SHajimu UMEMOTO 			continue;
21807d56d374SYoshinobu Inoue 		}
21819832619cSHajimu UMEMOTO 		hp = getanswer(buf, n, qbuf, T_PTR, &hbuf, errp);
2182aadad922SHajimu UMEMOTO 		if (!hp) {
2183aadad922SHajimu UMEMOTO 			err = NS_NOTFOUND;
2184aadad922SHajimu UMEMOTO 			continue;
2185aadad922SHajimu UMEMOTO 		}
21869832619cSHajimu UMEMOTO 		free(buf);
218773b30f0cSJun-ichiro itojun Hagino 		hbuf.h_addrtype = af;
218873b30f0cSJun-ichiro itojun Hagino 		hbuf.h_length = addrlen;
218973b30f0cSJun-ichiro itojun Hagino 		hbuf.h_addr_list = hlist;
219073b30f0cSJun-ichiro itojun Hagino 		hlist[0] = (char *)addr;
219173b30f0cSJun-ichiro itojun Hagino 		hlist[1] = NULL;
2192248aee62SJacques Vidrine 		*(struct hostent **)rval = _hpcopy(&hbuf, errp);
2193248aee62SJacques Vidrine 		return NS_SUCCESS;
21947d56d374SYoshinobu Inoue 	}
2195aadad922SHajimu UMEMOTO 	free(buf);
2196aadad922SHajimu UMEMOTO 	return err;
2197aadad922SHajimu UMEMOTO }
21987d56d374SYoshinobu Inoue 
219973b30f0cSJun-ichiro itojun Hagino static void
220073b30f0cSJun-ichiro itojun Hagino _dns_shent(int stayopen)
220173b30f0cSJun-ichiro itojun Hagino {
220273b30f0cSJun-ichiro itojun Hagino 	if ((_res.options & RES_INIT) == 0) {
220373b30f0cSJun-ichiro itojun Hagino 		if (res_init() < 0)
220473b30f0cSJun-ichiro itojun Hagino 			return;
220573b30f0cSJun-ichiro itojun Hagino 	}
220673b30f0cSJun-ichiro itojun Hagino 	if (stayopen)
220773b30f0cSJun-ichiro itojun Hagino 		_res.options |= RES_STAYOPEN | RES_USEVC;
220873b30f0cSJun-ichiro itojun Hagino }
220973b30f0cSJun-ichiro itojun Hagino 
221073b30f0cSJun-ichiro itojun Hagino static void
221173b30f0cSJun-ichiro itojun Hagino _dns_ehent(void)
221273b30f0cSJun-ichiro itojun Hagino {
221373b30f0cSJun-ichiro itojun Hagino 	_res.options &= ~(RES_STAYOPEN | RES_USEVC);
221473b30f0cSJun-ichiro itojun Hagino 	res_close();
221573b30f0cSJun-ichiro itojun Hagino }
221673b30f0cSJun-ichiro itojun Hagino 
22177d56d374SYoshinobu Inoue #ifdef ICMPNL
22187d56d374SYoshinobu Inoue 
22197d56d374SYoshinobu Inoue /*
22207d56d374SYoshinobu Inoue  * experimental:
22217d56d374SYoshinobu Inoue  *	draft-ietf-ipngwg-icmp-namelookups-02.txt
22227d56d374SYoshinobu Inoue  *	ifindex is assumed to be encoded in addr.
22237d56d374SYoshinobu Inoue  */
22247d56d374SYoshinobu Inoue #include <sys/uio.h>
22257d56d374SYoshinobu Inoue #include <netinet/ip6.h>
22267d56d374SYoshinobu Inoue #include <netinet/icmp6.h>
22277d56d374SYoshinobu Inoue 
22287d56d374SYoshinobu Inoue struct _icmp_host_cache {
22297d56d374SYoshinobu Inoue 	struct _icmp_host_cache *hc_next;
22307d56d374SYoshinobu Inoue 	int hc_ifindex;
22317d56d374SYoshinobu Inoue 	struct in6_addr hc_addr;
22327d56d374SYoshinobu Inoue 	char *hc_name;
22337d56d374SYoshinobu Inoue };
22347d56d374SYoshinobu Inoue 
22357d56d374SYoshinobu Inoue static char *
22367d56d374SYoshinobu Inoue _icmp_fqdn_query(const struct in6_addr *addr, int ifindex)
22377d56d374SYoshinobu Inoue {
22387d56d374SYoshinobu Inoue 	int s;
22397d56d374SYoshinobu Inoue 	struct icmp6_filter filter;
22407d56d374SYoshinobu Inoue 	struct msghdr msg;
22417d56d374SYoshinobu Inoue 	struct cmsghdr *cmsg;
22427d56d374SYoshinobu Inoue 	struct in6_pktinfo *pkt;
22437d56d374SYoshinobu Inoue 	char cbuf[256];
22447d56d374SYoshinobu Inoue 	char buf[1024];
22457d56d374SYoshinobu Inoue 	int cc;
22467d56d374SYoshinobu Inoue 	struct icmp6_fqdn_query *fq;
22477d56d374SYoshinobu Inoue 	struct icmp6_fqdn_reply *fr;
22487d56d374SYoshinobu Inoue 	struct _icmp_host_cache *hc;
22497d56d374SYoshinobu Inoue 	struct sockaddr_in6 sin6;
22507d56d374SYoshinobu Inoue 	struct iovec iov;
22517d56d374SYoshinobu Inoue 	fd_set s_fds, fds;
22527d56d374SYoshinobu Inoue 	struct timeval tout;
22537d56d374SYoshinobu Inoue 	int len;
22547d56d374SYoshinobu Inoue 	char *name;
22557d56d374SYoshinobu Inoue 	static struct _icmp_host_cache *hc_head;
22567d56d374SYoshinobu Inoue 
225733dee819SBrian Feldman 	THREAD_LOCK();
22587d56d374SYoshinobu Inoue 	for (hc = hc_head; hc; hc = hc->hc_next) {
22597d56d374SYoshinobu Inoue 		if (hc->hc_ifindex == ifindex
226033dee819SBrian Feldman 		&&  IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr)) {
226133dee819SBrian Feldman 			THREAD_UNLOCK();
226233dee819SBrian Feldman 			return hc->hc_name;	/* XXX: never freed */
22637d56d374SYoshinobu Inoue 		}
226433dee819SBrian Feldman 	}
22657d56d374SYoshinobu Inoue 
22667d56d374SYoshinobu Inoue 	ICMP6_FILTER_SETBLOCKALL(&filter);
22677d56d374SYoshinobu Inoue 	ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter);
22687d56d374SYoshinobu Inoue 
22697d56d374SYoshinobu Inoue 	FD_ZERO(&s_fds);
22707d56d374SYoshinobu Inoue 	tout.tv_sec = 0;
22717d56d374SYoshinobu Inoue 	tout.tv_usec = 200000;	/*XXX: 200ms*/
22727d56d374SYoshinobu Inoue 
22737d56d374SYoshinobu Inoue 	fq = (struct icmp6_fqdn_query *)buf;
22747d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY;
22757d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_code = 0;
22767d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_cksum = 0;
227733dee819SBrian Feldman 	fq->icmp6_fqdn_id = (u_short)getpid();
22787d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_unused = 0;
22797d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_cookie[0] = 0;
22807d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_cookie[1] = 0;
22817d56d374SYoshinobu Inoue 
22827d56d374SYoshinobu Inoue 	memset(&sin6, 0, sizeof(sin6));
22837d56d374SYoshinobu Inoue 	sin6.sin6_family = AF_INET6;
22847d56d374SYoshinobu Inoue 	sin6.sin6_addr = *addr;
22857d56d374SYoshinobu Inoue 
22867d56d374SYoshinobu Inoue 	memset(&msg, 0, sizeof(msg));
22877d56d374SYoshinobu Inoue 	msg.msg_name = (caddr_t)&sin6;
22887d56d374SYoshinobu Inoue 	msg.msg_namelen = sizeof(sin6);
22897d56d374SYoshinobu Inoue 	msg.msg_iov = &iov;
22907d56d374SYoshinobu Inoue 	msg.msg_iovlen = 1;
22917d56d374SYoshinobu Inoue 	msg.msg_control = NULL;
22927d56d374SYoshinobu Inoue 	msg.msg_controllen = 0;
22937d56d374SYoshinobu Inoue 	iov.iov_base = (caddr_t)buf;
22947d56d374SYoshinobu Inoue 	iov.iov_len = sizeof(struct icmp6_fqdn_query);
22957d56d374SYoshinobu Inoue 
22967d56d374SYoshinobu Inoue 	if (ifindex) {
22977d56d374SYoshinobu Inoue 		msg.msg_control = cbuf;
22987d56d374SYoshinobu Inoue 		msg.msg_controllen = sizeof(cbuf);
22997d56d374SYoshinobu Inoue 		cmsg = CMSG_FIRSTHDR(&msg);
23007d56d374SYoshinobu Inoue 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
23017d56d374SYoshinobu Inoue 		cmsg->cmsg_level = IPPROTO_IPV6;
23027d56d374SYoshinobu Inoue 		cmsg->cmsg_type = IPV6_PKTINFO;
23037d56d374SYoshinobu Inoue 		pkt = (struct in6_pktinfo *)&cmsg[1];
23047d56d374SYoshinobu Inoue 		memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
23057d56d374SYoshinobu Inoue 		pkt->ipi6_ifindex = ifindex;
23067d56d374SYoshinobu Inoue 		cmsg = CMSG_NXTHDR(&msg, cmsg);
23077d56d374SYoshinobu Inoue 		msg.msg_controllen = (char *)cmsg - cbuf;
23087d56d374SYoshinobu Inoue 	}
23097d56d374SYoshinobu Inoue 
2310d201fe46SDaniel Eischen 	if ((s = _socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
23117d56d374SYoshinobu Inoue 		return NULL;
2312d201fe46SDaniel Eischen 	(void)_setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
23137d56d374SYoshinobu Inoue 			 (char *)&filter, sizeof(filter));
2314d201fe46SDaniel Eischen 	cc = _sendmsg(s, &msg, 0);
23157d56d374SYoshinobu Inoue 	if (cc < 0) {
23169233c4d9SJason Evans 		_close(s);
23177d56d374SYoshinobu Inoue 		return NULL;
23187d56d374SYoshinobu Inoue 	}
23197d56d374SYoshinobu Inoue 	FD_SET(s, &s_fds);
23207d56d374SYoshinobu Inoue 	for (;;) {
23217d56d374SYoshinobu Inoue 		fds = s_fds;
2322d201fe46SDaniel Eischen 		if (_select(s + 1, &fds, NULL, NULL, &tout) <= 0) {
23239233c4d9SJason Evans 			_close(s);
23247d56d374SYoshinobu Inoue 			return NULL;
23257d56d374SYoshinobu Inoue 		}
23267d56d374SYoshinobu Inoue 		len = sizeof(sin6);
2327d201fe46SDaniel Eischen 		cc = _recvfrom(s, buf, sizeof(buf), 0,
23287d56d374SYoshinobu Inoue 			      (struct sockaddr *)&sin6, &len);
23297d56d374SYoshinobu Inoue 		if (cc <= 0) {
23309233c4d9SJason Evans 			_close(s);
23317d56d374SYoshinobu Inoue 			return NULL;
23327d56d374SYoshinobu Inoue 		}
23337d56d374SYoshinobu Inoue 		if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
23347d56d374SYoshinobu Inoue 			continue;
23357d56d374SYoshinobu Inoue 		if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr))
23367d56d374SYoshinobu Inoue 			continue;
23377d56d374SYoshinobu Inoue 		fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr));
23387d56d374SYoshinobu Inoue 		if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY)
23397d56d374SYoshinobu Inoue 			break;
23407d56d374SYoshinobu Inoue 	}
23419233c4d9SJason Evans 	_close(s);
23427d56d374SYoshinobu Inoue 	if (fr->icmp6_fqdn_cookie[1] != 0) {
23437d56d374SYoshinobu Inoue 		/* rfc1788 type */
23447d56d374SYoshinobu Inoue 		name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4;
23457d56d374SYoshinobu Inoue 		len = (buf + cc) - name;
23467d56d374SYoshinobu Inoue 	} else {
23477d56d374SYoshinobu Inoue 		len = fr->icmp6_fqdn_namelen;
23487d56d374SYoshinobu Inoue 		name = fr->icmp6_fqdn_name;
23497d56d374SYoshinobu Inoue 	}
23507d56d374SYoshinobu Inoue 	if (len <= 0)
23517d56d374SYoshinobu Inoue 		return NULL;
23527d56d374SYoshinobu Inoue 	name[len] = 0;
23537d56d374SYoshinobu Inoue 
23547d56d374SYoshinobu Inoue 	if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL)
23557d56d374SYoshinobu Inoue 		return NULL;
23567d56d374SYoshinobu Inoue 	/* XXX: limit number of cached entries */
23577d56d374SYoshinobu Inoue 	hc->hc_ifindex = ifindex;
23587d56d374SYoshinobu Inoue 	hc->hc_addr = *addr;
23597d56d374SYoshinobu Inoue 	hc->hc_name = strdup(name);
236033dee819SBrian Feldman 	THREAD_LOCK();
23617d56d374SYoshinobu Inoue 	hc->hc_next = hc_head;
23627d56d374SYoshinobu Inoue 	hc_head = hc;
236333dee819SBrian Feldman 	THREAD_UNLOCK();
23647d56d374SYoshinobu Inoue 	return hc->hc_name;
23657d56d374SYoshinobu Inoue }
23667d56d374SYoshinobu Inoue 
23677d56d374SYoshinobu Inoue static struct hostent *
23687d56d374SYoshinobu Inoue _icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
23697d56d374SYoshinobu Inoue {
23707d56d374SYoshinobu Inoue 	char *hname;
23717d56d374SYoshinobu Inoue 	int ifindex;
23727d56d374SYoshinobu Inoue 	struct in6_addr addr6;
23737d56d374SYoshinobu Inoue 
23747d56d374SYoshinobu Inoue 	if (af != AF_INET6) {
23757d56d374SYoshinobu Inoue 		/*
23767d56d374SYoshinobu Inoue 		 * Note: rfc1788 defines Who Are You for IPv4,
23777d56d374SYoshinobu Inoue 		 * but no one implements it.
23787d56d374SYoshinobu Inoue 		 */
23797d56d374SYoshinobu Inoue 		return NULL;
23807d56d374SYoshinobu Inoue 	}
23817d56d374SYoshinobu Inoue 
23827d56d374SYoshinobu Inoue 	memcpy(&addr6, addr, addrlen);
23837d56d374SYoshinobu Inoue 	ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
23847d56d374SYoshinobu Inoue 	addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
23857d56d374SYoshinobu Inoue 
23867d56d374SYoshinobu Inoue 	if (!IN6_IS_ADDR_LINKLOCAL(&addr6))
23877d56d374SYoshinobu Inoue 		return NULL;	/*XXX*/
23887d56d374SYoshinobu Inoue 
23897d56d374SYoshinobu Inoue 	if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL)
23907d56d374SYoshinobu Inoue 		return NULL;
23917d56d374SYoshinobu Inoue 	return _hpaddr(af, hname, &addr6, errp);
23927d56d374SYoshinobu Inoue }
23937d56d374SYoshinobu Inoue #endif /* ICMPNL */
2394