xref: /freebsd/lib/libc/net/name6.c (revision 0fbf0979)
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 
3130fbf0979SHajimu UMEMOTO 		if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
3140fbf0979SHajimu UMEMOTO 			return NULL;
3157d56d374SYoshinobu Inoue 		/*
3167d56d374SYoshinobu Inoue 		 * TODO:
3177d56d374SYoshinobu Inoue 		 * Note that implementation dependent test for address
3187d56d374SYoshinobu Inoue 		 * configuration should be done everytime called
3197d56d374SYoshinobu Inoue 		 * (or apropriate interval),
3207d56d374SYoshinobu Inoue 		 * because addresses will be dynamically assigned or deleted.
3217d56d374SYoshinobu Inoue 		 */
3229233c4d9SJason Evans 		_close(s);
3237d56d374SYoshinobu Inoue 	}
3247d56d374SYoshinobu Inoue 
32520e0e084SJacques Vidrine 	rval = _nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyname", default_src,
326248aee62SJacques Vidrine 			  name, af, errp);
327248aee62SJacques Vidrine 	return (rval == NS_SUCCESS) ? hp : NULL;
3287d56d374SYoshinobu Inoue }
3297d56d374SYoshinobu Inoue 
3300fbf0979SHajimu UMEMOTO struct hostent *
3310fbf0979SHajimu UMEMOTO getipnodebyname(const char *name, int af, int flags, int *errp)
3327d56d374SYoshinobu Inoue {
3337d56d374SYoshinobu Inoue 	struct hostent *hp;
3347d56d374SYoshinobu Inoue 	union inx_addr addrbuf;
3357d56d374SYoshinobu Inoue 
3367d56d374SYoshinobu Inoue 	if (af != AF_INET
3377d56d374SYoshinobu Inoue #ifdef INET6
3387d56d374SYoshinobu Inoue 	    && af != AF_INET6
3397d56d374SYoshinobu Inoue #endif
3407d56d374SYoshinobu Inoue 		)
3417d56d374SYoshinobu Inoue 	{
3427d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
3437d56d374SYoshinobu Inoue 		return NULL;
3447d56d374SYoshinobu Inoue 	}
3457d56d374SYoshinobu Inoue 
3467d56d374SYoshinobu Inoue #ifdef INET6
3477d56d374SYoshinobu Inoue 	/* special case for literal address */
3487d56d374SYoshinobu Inoue 	if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
3497d56d374SYoshinobu Inoue 		if (af != AF_INET6) {
3507d56d374SYoshinobu Inoue 			*errp = HOST_NOT_FOUND;
3517d56d374SYoshinobu Inoue 			return NULL;
3527d56d374SYoshinobu Inoue 		}
3537d56d374SYoshinobu Inoue 		return _hpaddr(af, name, &addrbuf, errp);
3547d56d374SYoshinobu Inoue 	}
3557d56d374SYoshinobu Inoue #endif
356be26adb5SYoshinobu Inoue 	if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) {
3577d56d374SYoshinobu Inoue 		if (af != AF_INET) {
3587d56d374SYoshinobu Inoue 			if (MAPADDRENABLED(flags)) {
3597d56d374SYoshinobu Inoue 				MAPADDR(&addrbuf, &addrbuf.in_addr);
3607d56d374SYoshinobu Inoue 			} else {
3617d56d374SYoshinobu Inoue 				*errp = HOST_NOT_FOUND;
3627d56d374SYoshinobu Inoue 				return NULL;
3637d56d374SYoshinobu Inoue 			}
3647d56d374SYoshinobu Inoue 		}
3657d56d374SYoshinobu Inoue 		return _hpaddr(af, name, &addrbuf, errp);
3667d56d374SYoshinobu Inoue 	}
3677d56d374SYoshinobu Inoue 
3687d56d374SYoshinobu Inoue 	*errp = HOST_NOT_FOUND;
3697d56d374SYoshinobu Inoue 	hp = _ghbyname(name, af, flags, errp);
3707d56d374SYoshinobu Inoue 
3717d56d374SYoshinobu Inoue #ifdef INET6
3727d56d374SYoshinobu Inoue 	if (af == AF_INET6
3737d56d374SYoshinobu Inoue 	&&  ((flags & AI_ALL) || hp == NULL)
3747d56d374SYoshinobu Inoue 	&&  (MAPADDRENABLED(flags))) {
3757d56d374SYoshinobu Inoue 		struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp);
3767d56d374SYoshinobu Inoue 		if (hp == NULL)
3777d56d374SYoshinobu Inoue 			hp = _hpmapv6(hp2, errp);
3787d56d374SYoshinobu Inoue 		else {
3797d56d374SYoshinobu Inoue 			if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) {
3807d56d374SYoshinobu Inoue 				freehostent(hp2);
3817d56d374SYoshinobu Inoue 				hp2 = NULL;
3827d56d374SYoshinobu Inoue 			}
3837d56d374SYoshinobu Inoue 			hp = _hpmerge(hp, hp2, errp);
3847d56d374SYoshinobu Inoue 		}
3857d56d374SYoshinobu Inoue 	}
3867d56d374SYoshinobu Inoue #endif
387b8b31f33SHajimu UMEMOTO 	return _hpreorder(_hpsort(hp));
3887d56d374SYoshinobu Inoue }
3897d56d374SYoshinobu Inoue 
3907d56d374SYoshinobu Inoue struct hostent *
3917d56d374SYoshinobu Inoue getipnodebyaddr(const void *src, size_t len, int af, int *errp)
3927d56d374SYoshinobu Inoue {
3937d56d374SYoshinobu Inoue 	struct hostent *hp;
394cb0600bdSJacques Vidrine 	int rval;
3957d56d374SYoshinobu Inoue #ifdef INET6
3967d56d374SYoshinobu Inoue 	struct in6_addr addrbuf;
3977d56d374SYoshinobu Inoue #else
3987d56d374SYoshinobu Inoue 	struct in_addr addrbuf;
3997d56d374SYoshinobu Inoue #endif
4007d56d374SYoshinobu Inoue 
401248aee62SJacques Vidrine 	static const ns_dtab dtab[] = {
402248aee62SJacques Vidrine 		NS_FILES_CB(_files_ghbyaddr, NULL)
403248aee62SJacques Vidrine 		{ NSSRC_DNS, _dns_ghbyaddr, NULL },
404248aee62SJacques Vidrine 		NS_NIS_CB(_nis_ghbyaddr, NULL)
405248aee62SJacques Vidrine #ifdef ICMPNL
406248aee62SJacques Vidrine 		{ NSSRC_ICMP, _icmp_ghbyaddr, NULL },
407248aee62SJacques Vidrine #endif
408248aee62SJacques Vidrine 		{ 0 }
409248aee62SJacques Vidrine 	};
410248aee62SJacques Vidrine 
4117d56d374SYoshinobu Inoue 	*errp = HOST_NOT_FOUND;
4127d56d374SYoshinobu Inoue 
4137d56d374SYoshinobu Inoue 	switch (af) {
4147d56d374SYoshinobu Inoue 	case AF_INET:
4157d56d374SYoshinobu Inoue 		if (len != sizeof(struct in_addr)) {
4167d56d374SYoshinobu Inoue 			*errp = NO_RECOVERY;
4177d56d374SYoshinobu Inoue 			return NULL;
4187d56d374SYoshinobu Inoue 		}
4197d56d374SYoshinobu Inoue 		if ((long)src & ~(sizeof(struct in_addr) - 1)) {
4207d56d374SYoshinobu Inoue 			memcpy(&addrbuf, src, len);
4217d56d374SYoshinobu Inoue 			src = &addrbuf;
4227d56d374SYoshinobu Inoue 		}
4237d56d374SYoshinobu Inoue 		if (((struct in_addr *)src)->s_addr == 0)
4247d56d374SYoshinobu Inoue 			return NULL;
4257d56d374SYoshinobu Inoue 		break;
4267d56d374SYoshinobu Inoue #ifdef INET6
4277d56d374SYoshinobu Inoue 	case AF_INET6:
4287d56d374SYoshinobu Inoue 		if (len != sizeof(struct in6_addr)) {
4297d56d374SYoshinobu Inoue 			*errp = NO_RECOVERY;
4307d56d374SYoshinobu Inoue 			return NULL;
4317d56d374SYoshinobu Inoue 		}
4327d56d374SYoshinobu Inoue 		if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) {	/*XXX*/
4337d56d374SYoshinobu Inoue 			memcpy(&addrbuf, src, len);
4347d56d374SYoshinobu Inoue 			src = &addrbuf;
4357d56d374SYoshinobu Inoue 		}
4363d670abcSYoshinobu Inoue 		if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src))
4373d670abcSYoshinobu Inoue 			return NULL;
4387d56d374SYoshinobu Inoue 		if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)
4397d56d374SYoshinobu Inoue 		||  IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) {
4407d56d374SYoshinobu Inoue 			src = (char *)src +
4417d56d374SYoshinobu Inoue 			    (sizeof(struct in6_addr) - sizeof(struct in_addr));
4427d56d374SYoshinobu Inoue 			af = AF_INET;
4437d56d374SYoshinobu Inoue 			len = sizeof(struct in_addr);
4447d56d374SYoshinobu Inoue 		}
4457d56d374SYoshinobu Inoue 		break;
4467d56d374SYoshinobu Inoue #endif
4477d56d374SYoshinobu Inoue 	default:
4487d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
4497d56d374SYoshinobu Inoue 		return NULL;
4507d56d374SYoshinobu Inoue 	}
4517d56d374SYoshinobu Inoue 
45220e0e084SJacques Vidrine 	rval = _nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyaddr", default_src,
453248aee62SJacques Vidrine 			  src, len, af, errp);
454248aee62SJacques Vidrine 	return (rval == NS_SUCCESS) ? hp : NULL;
4557d56d374SYoshinobu Inoue }
4567d56d374SYoshinobu Inoue 
4577d56d374SYoshinobu Inoue void
4587d56d374SYoshinobu Inoue freehostent(struct hostent *ptr)
4597d56d374SYoshinobu Inoue {
4607d56d374SYoshinobu Inoue 	free(ptr);
4617d56d374SYoshinobu Inoue }
4627d56d374SYoshinobu Inoue 
4637d56d374SYoshinobu Inoue #if 0
4647d56d374SYoshinobu Inoue 
4657d56d374SYoshinobu Inoue /* XXX: should be deprecated */
4667d56d374SYoshinobu Inoue struct hostent *
4677d56d374SYoshinobu Inoue getnodebyname(const char *name, int af, int flags)
4687d56d374SYoshinobu Inoue {
4697d56d374SYoshinobu Inoue 	return getipnodebyname(name, af, flags, &h_errno);
4707d56d374SYoshinobu Inoue }
4717d56d374SYoshinobu Inoue 
4727d56d374SYoshinobu Inoue #ifdef __warn_references
4737d56d374SYoshinobu Inoue __warn_references(getnodebyname,
4747d56d374SYoshinobu Inoue 	"warning: getnodebyname() deprecated, "
4757d56d374SYoshinobu Inoue 	"should use getaddrinfo() or getipnodebyname()");
4767d56d374SYoshinobu Inoue #endif
4777d56d374SYoshinobu Inoue 
4787d56d374SYoshinobu Inoue struct hostent *
4797d56d374SYoshinobu Inoue getnodebyaddr(const void *src, size_t len, int af)
4807d56d374SYoshinobu Inoue {
4817d56d374SYoshinobu Inoue 	return getipnodebyaddr(src, len, af, &h_errno);
4827d56d374SYoshinobu Inoue }
4837d56d374SYoshinobu Inoue 
4847d56d374SYoshinobu Inoue #ifdef __warn_references
4857d56d374SYoshinobu Inoue __warn_references(getnodebyaddr,
4867d56d374SYoshinobu Inoue 	"warning: getnodebyaddr() deprecated, "
4877d56d374SYoshinobu Inoue 	"should use getnameinfo() or getipnodebyaddr()");
4887d56d374SYoshinobu Inoue #endif
4897d56d374SYoshinobu Inoue 
4907d56d374SYoshinobu Inoue #endif
4917d56d374SYoshinobu Inoue 
4927d56d374SYoshinobu Inoue /*
4937d56d374SYoshinobu Inoue  * Private utility functions
4947d56d374SYoshinobu Inoue  */
4957d56d374SYoshinobu Inoue 
4967d56d374SYoshinobu Inoue /*
4977d56d374SYoshinobu Inoue  * _hpcopy: allocate and copy hostent structure
4987d56d374SYoshinobu Inoue  */
4997d56d374SYoshinobu Inoue static struct hostent *
5007d56d374SYoshinobu Inoue _hpcopy(struct hostent *hp, int *errp)
5017d56d374SYoshinobu Inoue {
5027d56d374SYoshinobu Inoue 	struct hostent *nhp;
5037d56d374SYoshinobu Inoue 	char *cp, **pp;
5047d56d374SYoshinobu Inoue 	int size, addrsize;
5057d56d374SYoshinobu Inoue 	int nalias = 0, naddr = 0;
5067d56d374SYoshinobu Inoue 	int al_off;
5077d56d374SYoshinobu Inoue 	int i;
5087d56d374SYoshinobu Inoue 
5097d56d374SYoshinobu Inoue 	if (hp == NULL)
5107d56d374SYoshinobu Inoue 		return hp;
5117d56d374SYoshinobu Inoue 
5127d56d374SYoshinobu Inoue 	/* count size to be allocated */
5137d56d374SYoshinobu Inoue 	size = sizeof(struct hostent);
51405c36511SHajimu UMEMOTO 	if (hp->h_name != NULL)
5157d56d374SYoshinobu Inoue 		size += strlen(hp->h_name) + 1;
5167d56d374SYoshinobu Inoue 	if ((pp = hp->h_aliases) != NULL) {
5177d56d374SYoshinobu Inoue 		for (i = 0; *pp != NULL; i++, pp++) {
5187d56d374SYoshinobu Inoue 			if (**pp != '\0') {
5197d56d374SYoshinobu Inoue 				size += strlen(*pp) + 1;
5207d56d374SYoshinobu Inoue 				nalias++;
5217d56d374SYoshinobu Inoue 			}
5227d56d374SYoshinobu Inoue 		}
5237d56d374SYoshinobu Inoue 	}
5247d56d374SYoshinobu Inoue 	/* adjust alignment */
5257d56d374SYoshinobu Inoue 	size = ALIGN(size);
5267d56d374SYoshinobu Inoue 	al_off = size;
5277d56d374SYoshinobu Inoue 	size += sizeof(char *) * (nalias + 1);
5287d56d374SYoshinobu Inoue 	addrsize = ALIGN(hp->h_length);
5297d56d374SYoshinobu Inoue 	if ((pp = hp->h_addr_list) != NULL) {
5307d56d374SYoshinobu Inoue 		while (*pp++ != NULL)
5317d56d374SYoshinobu Inoue 			naddr++;
5327d56d374SYoshinobu Inoue 	}
5337d56d374SYoshinobu Inoue 	size += addrsize * naddr;
5347d56d374SYoshinobu Inoue 	size += sizeof(char *) * (naddr + 1);
5357d56d374SYoshinobu Inoue 
5367d56d374SYoshinobu Inoue 	/* copy */
5377d56d374SYoshinobu Inoue 	if ((nhp = (struct hostent *)malloc(size)) == NULL) {
5387d56d374SYoshinobu Inoue 		*errp = TRY_AGAIN;
5397d56d374SYoshinobu Inoue 		return NULL;
5407d56d374SYoshinobu Inoue 	}
5417d56d374SYoshinobu Inoue 	cp = (char *)&nhp[1];
54205c36511SHajimu UMEMOTO 	if (hp->h_name != NULL) {
5437d56d374SYoshinobu Inoue 		nhp->h_name = cp;
5447d56d374SYoshinobu Inoue 		strcpy(cp, hp->h_name);
5457d56d374SYoshinobu Inoue 		cp += strlen(cp) + 1;
5467d56d374SYoshinobu Inoue 	} else
5477d56d374SYoshinobu Inoue 		nhp->h_name = NULL;
5487d56d374SYoshinobu Inoue 	nhp->h_aliases = (char **)((char *)nhp + al_off);
5497d56d374SYoshinobu Inoue 	if ((pp = hp->h_aliases) != NULL) {
5507d56d374SYoshinobu Inoue 		for (i = 0; *pp != NULL; pp++) {
5517d56d374SYoshinobu Inoue 			if (**pp != '\0') {
5527d56d374SYoshinobu Inoue 				nhp->h_aliases[i++] = cp;
5537d56d374SYoshinobu Inoue 				strcpy(cp, *pp);
5547d56d374SYoshinobu Inoue 				cp += strlen(cp) + 1;
5557d56d374SYoshinobu Inoue 			}
5567d56d374SYoshinobu Inoue 		}
5577d56d374SYoshinobu Inoue 	}
5587d56d374SYoshinobu Inoue 	nhp->h_aliases[nalias] = NULL;
5597d56d374SYoshinobu Inoue 	cp = (char *)&nhp->h_aliases[nalias + 1];
5607d56d374SYoshinobu Inoue 	nhp->h_addrtype = hp->h_addrtype;
5617d56d374SYoshinobu Inoue 	nhp->h_length = hp->h_length;
5627d56d374SYoshinobu Inoue 	nhp->h_addr_list = (char **)cp;
5637d56d374SYoshinobu Inoue 	if ((pp = hp->h_addr_list) != NULL) {
5647d56d374SYoshinobu Inoue 		cp = (char *)&nhp->h_addr_list[naddr + 1];
5657d56d374SYoshinobu Inoue 		for (i = 0; *pp != NULL; pp++) {
5667d56d374SYoshinobu Inoue 			nhp->h_addr_list[i++] = cp;
5677d56d374SYoshinobu Inoue 			memcpy(cp, *pp, hp->h_length);
5687d56d374SYoshinobu Inoue 			cp += addrsize;
5697d56d374SYoshinobu Inoue 		}
5707d56d374SYoshinobu Inoue 	}
5717d56d374SYoshinobu Inoue 	nhp->h_addr_list[naddr] = NULL;
5727d56d374SYoshinobu Inoue 	return nhp;
5737d56d374SYoshinobu Inoue }
5747d56d374SYoshinobu Inoue 
5757d56d374SYoshinobu Inoue /*
5767d56d374SYoshinobu Inoue  * _hpaddr: construct hostent structure with one address
5777d56d374SYoshinobu Inoue  */
5787d56d374SYoshinobu Inoue static struct hostent *
5797d56d374SYoshinobu Inoue _hpaddr(int af, const char *name, void *addr, int *errp)
5807d56d374SYoshinobu Inoue {
5817d56d374SYoshinobu Inoue 	struct hostent *hp, hpbuf;
5827d56d374SYoshinobu Inoue 	char *addrs[2];
5837d56d374SYoshinobu Inoue 
5847d56d374SYoshinobu Inoue 	hp = &hpbuf;
5857d56d374SYoshinobu Inoue 	hp->h_name = (char *)name;
5867d56d374SYoshinobu Inoue 	hp->h_aliases = NULL;
5877d56d374SYoshinobu Inoue 	hp->h_addrtype = af;
5887d56d374SYoshinobu Inoue 	hp->h_length = ADDRLEN(af);
5897d56d374SYoshinobu Inoue 	hp->h_addr_list = addrs;
5907d56d374SYoshinobu Inoue 	addrs[0] = (char *)addr;
5917d56d374SYoshinobu Inoue 	addrs[1] = NULL;
5927d56d374SYoshinobu Inoue 	return _hpcopy(hp, errp);
5937d56d374SYoshinobu Inoue }
5947d56d374SYoshinobu Inoue 
5957d56d374SYoshinobu Inoue /*
5967d56d374SYoshinobu Inoue  * _hpmerge: merge 2 hostent structure, arguments will be freed
5977d56d374SYoshinobu Inoue  */
5987d56d374SYoshinobu Inoue static struct hostent *
5997d56d374SYoshinobu Inoue _hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp)
6007d56d374SYoshinobu Inoue {
6017d56d374SYoshinobu Inoue 	int i, j;
6027d56d374SYoshinobu Inoue 	int naddr, nalias;
6037d56d374SYoshinobu Inoue 	char **pp;
6047d56d374SYoshinobu Inoue 	struct hostent *hp, hpbuf;
6057d56d374SYoshinobu Inoue 	char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1];
6067d56d374SYoshinobu Inoue 	union inx_addr addrbuf[MAXADDRS];
6077d56d374SYoshinobu Inoue 
6087d56d374SYoshinobu Inoue 	if (hp1 == NULL)
6097d56d374SYoshinobu Inoue 		return hp2;
6107d56d374SYoshinobu Inoue 	if (hp2 == NULL)
6117d56d374SYoshinobu Inoue 		return hp1;
6127d56d374SYoshinobu Inoue 
6137d56d374SYoshinobu Inoue #define	HP(i)	(i == 1 ? hp1 : hp2)
6147d56d374SYoshinobu Inoue 	hp = &hpbuf;
6157d56d374SYoshinobu Inoue 	hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name);
6167d56d374SYoshinobu Inoue 	hp->h_aliases = aliases;
6177d56d374SYoshinobu Inoue 	nalias = 0;
6187d56d374SYoshinobu Inoue 	for (i = 1; i <= 2; i++) {
6197d56d374SYoshinobu Inoue 		if ((pp = HP(i)->h_aliases) == NULL)
6207d56d374SYoshinobu Inoue 			continue;
6217d56d374SYoshinobu Inoue 		for (; nalias < MAXALIASES && *pp != NULL; pp++) {
6227d56d374SYoshinobu Inoue 			/* check duplicates */
6237d56d374SYoshinobu Inoue 			for (j = 0; j < nalias; j++)
6247d56d374SYoshinobu Inoue 				if (strcasecmp(*pp, aliases[j]) == 0)
6257d56d374SYoshinobu Inoue 					break;
6267d56d374SYoshinobu Inoue 			if (j == nalias)
6277d56d374SYoshinobu Inoue 				aliases[nalias++] = *pp;
6287d56d374SYoshinobu Inoue 		}
6297d56d374SYoshinobu Inoue 	}
6307d56d374SYoshinobu Inoue 	aliases[nalias] = NULL;
6317d56d374SYoshinobu Inoue #ifdef INET6
6327d56d374SYoshinobu Inoue 	if (hp1->h_length != hp2->h_length) {
6337d56d374SYoshinobu Inoue 		hp->h_addrtype = AF_INET6;
6347d56d374SYoshinobu Inoue 		hp->h_length = sizeof(struct in6_addr);
6357d56d374SYoshinobu Inoue 	} else {
6367d56d374SYoshinobu Inoue #endif
6377d56d374SYoshinobu Inoue 		hp->h_addrtype = hp1->h_addrtype;
6387d56d374SYoshinobu Inoue 		hp->h_length = hp1->h_length;
6397d56d374SYoshinobu Inoue #ifdef INET6
6407d56d374SYoshinobu Inoue 	}
6417d56d374SYoshinobu Inoue #endif
6427d56d374SYoshinobu Inoue 	hp->h_addr_list = addrs;
6437d56d374SYoshinobu Inoue 	naddr = 0;
6447d56d374SYoshinobu Inoue 	for (i = 1; i <= 2; i++) {
6457d56d374SYoshinobu Inoue 		if ((pp = HP(i)->h_addr_list) == NULL)
6467d56d374SYoshinobu Inoue 			continue;
6477d56d374SYoshinobu Inoue 		if (HP(i)->h_length == hp->h_length) {
6487d56d374SYoshinobu Inoue 			while (naddr < MAXADDRS && *pp != NULL)
6497d56d374SYoshinobu Inoue 				addrs[naddr++] = *pp++;
6507d56d374SYoshinobu Inoue 		} else {
6517d56d374SYoshinobu Inoue 			/* copy IPv4 addr as mapped IPv6 addr */
6527d56d374SYoshinobu Inoue 			while (naddr < MAXADDRS && *pp != NULL) {
6537d56d374SYoshinobu Inoue 				MAPADDR(&addrbuf[naddr], *pp++);
6547d56d374SYoshinobu Inoue 				addrs[naddr] = (char *)&addrbuf[naddr];
6557d56d374SYoshinobu Inoue 				naddr++;
6567d56d374SYoshinobu Inoue 			}
6577d56d374SYoshinobu Inoue 		}
6587d56d374SYoshinobu Inoue 	}
6597d56d374SYoshinobu Inoue 	addrs[naddr] = NULL;
6607d56d374SYoshinobu Inoue 	hp = _hpcopy(hp, errp);
6617d56d374SYoshinobu Inoue 	freehostent(hp1);
6627d56d374SYoshinobu Inoue 	freehostent(hp2);
6637d56d374SYoshinobu Inoue 	return hp;
6647d56d374SYoshinobu Inoue }
6657d56d374SYoshinobu Inoue 
6667d56d374SYoshinobu Inoue /*
6677d56d374SYoshinobu Inoue  * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses
6687d56d374SYoshinobu Inoue  */
6697d56d374SYoshinobu Inoue #ifdef INET6
6707d56d374SYoshinobu Inoue static struct hostent *
6717d56d374SYoshinobu Inoue _hpmapv6(struct hostent *hp, int *errp)
6727d56d374SYoshinobu Inoue {
6737d56d374SYoshinobu Inoue 	struct hostent *hp6;
6747d56d374SYoshinobu Inoue 
6757d56d374SYoshinobu Inoue 	if (hp == NULL)
6767d56d374SYoshinobu Inoue 		return NULL;
6777d56d374SYoshinobu Inoue 	if (hp->h_addrtype == AF_INET6)
6787d56d374SYoshinobu Inoue 		return hp;
6797d56d374SYoshinobu Inoue 
6807d56d374SYoshinobu Inoue 	/* make dummy hostent to convert IPv6 address */
6817d56d374SYoshinobu Inoue 	if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) {
6827d56d374SYoshinobu Inoue 		*errp = TRY_AGAIN;
6837d56d374SYoshinobu Inoue 		return NULL;
6847d56d374SYoshinobu Inoue 	}
6857d56d374SYoshinobu Inoue 	hp6->h_name = NULL;
6867d56d374SYoshinobu Inoue 	hp6->h_aliases = NULL;
6877d56d374SYoshinobu Inoue 	hp6->h_addrtype = AF_INET6;
6887d56d374SYoshinobu Inoue 	hp6->h_length = sizeof(struct in6_addr);
6897d56d374SYoshinobu Inoue 	hp6->h_addr_list = NULL;
6907d56d374SYoshinobu Inoue 	return _hpmerge(hp6, hp, errp);
6917d56d374SYoshinobu Inoue }
6927d56d374SYoshinobu Inoue #endif
6937d56d374SYoshinobu Inoue 
6947d56d374SYoshinobu Inoue /*
6957d56d374SYoshinobu Inoue  * _hpsort: sort address by sortlist
6967d56d374SYoshinobu Inoue  */
6977d56d374SYoshinobu Inoue static struct hostent *
6987d56d374SYoshinobu Inoue _hpsort(struct hostent *hp)
6997d56d374SYoshinobu Inoue {
7007d56d374SYoshinobu Inoue 	int i, j, n;
7017d56d374SYoshinobu Inoue 	u_char *ap, *sp, *mp, **pp;
7027d56d374SYoshinobu Inoue 	char t;
7037d56d374SYoshinobu Inoue 	char order[MAXADDRS];
7047d56d374SYoshinobu Inoue 	int nsort = _res.nsort;
7057d56d374SYoshinobu Inoue 
7067d56d374SYoshinobu Inoue 	if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0)
7077d56d374SYoshinobu Inoue 		return hp;
7087d56d374SYoshinobu Inoue 	for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) {
7097d56d374SYoshinobu Inoue 		for (j = 0; j < nsort; j++) {
7107d56d374SYoshinobu Inoue #ifdef INET6
7117d56d374SYoshinobu Inoue 			if (_res_ext.sort_list[j].af != hp->h_addrtype)
7127d56d374SYoshinobu Inoue 				continue;
7137d56d374SYoshinobu Inoue 			sp = (u_char *)&_res_ext.sort_list[j].addr;
7147d56d374SYoshinobu Inoue 			mp = (u_char *)&_res_ext.sort_list[j].mask;
7157d56d374SYoshinobu Inoue #else
7167d56d374SYoshinobu Inoue 			sp = (u_char *)&_res.sort_list[j].addr;
7177d56d374SYoshinobu Inoue 			mp = (u_char *)&_res.sort_list[j].mask;
7187d56d374SYoshinobu Inoue #endif
7197d56d374SYoshinobu Inoue 			for (n = 0; n < hp->h_length; n++) {
7207d56d374SYoshinobu Inoue 				if ((ap[n] & mp[n]) != sp[n])
7217d56d374SYoshinobu Inoue 					break;
7227d56d374SYoshinobu Inoue 			}
7237d56d374SYoshinobu Inoue 			if (n == hp->h_length)
7247d56d374SYoshinobu Inoue 				break;
7257d56d374SYoshinobu Inoue 		}
7267d56d374SYoshinobu Inoue 		order[i] = j;
7277d56d374SYoshinobu Inoue 	}
7287d56d374SYoshinobu Inoue 	n = i;
7297d56d374SYoshinobu Inoue 	pp = (u_char **)hp->h_addr_list;
7307d56d374SYoshinobu Inoue 	for (i = 0; i < n - 1; i++) {
7317d56d374SYoshinobu Inoue 		for (j = i + 1; j < n; j++) {
7327d56d374SYoshinobu Inoue 			if (order[i] > order[j]) {
7337d56d374SYoshinobu Inoue 				ap = pp[i];
7347d56d374SYoshinobu Inoue 				pp[i] = pp[j];
7357d56d374SYoshinobu Inoue 				pp[j] = ap;
7367d56d374SYoshinobu Inoue 				t = order[i];
7377d56d374SYoshinobu Inoue 				order[i] = order[j];
7387d56d374SYoshinobu Inoue 				order[j] = t;
7397d56d374SYoshinobu Inoue 			}
7407d56d374SYoshinobu Inoue 		}
7417d56d374SYoshinobu Inoue 	}
7427d56d374SYoshinobu Inoue 	return hp;
7437d56d374SYoshinobu Inoue }
7447d56d374SYoshinobu Inoue 
7457d56d374SYoshinobu Inoue static char *
7467d56d374SYoshinobu Inoue _hgetword(char **pp)
7477d56d374SYoshinobu Inoue {
7487d56d374SYoshinobu Inoue 	char c, *p, *ret;
7497d56d374SYoshinobu Inoue 	const char *sp;
7507d56d374SYoshinobu Inoue 	static const char sep[] = "# \t\n";
7517d56d374SYoshinobu Inoue 
7527d56d374SYoshinobu Inoue 	ret = NULL;
7537d56d374SYoshinobu Inoue 	for (p = *pp; (c = *p) != '\0'; p++) {
7547d56d374SYoshinobu Inoue 		for (sp = sep; *sp != '\0'; sp++) {
7557d56d374SYoshinobu Inoue 			if (c == *sp)
7567d56d374SYoshinobu Inoue 				break;
7577d56d374SYoshinobu Inoue 		}
7587d56d374SYoshinobu Inoue 		if (c == '#')
7597d56d374SYoshinobu Inoue 			p[1] = '\0';	/* ignore rest of line */
7607d56d374SYoshinobu Inoue 		if (ret == NULL) {
7617d56d374SYoshinobu Inoue 			if (*sp == '\0')
7627d56d374SYoshinobu Inoue 				ret = p;
7637d56d374SYoshinobu Inoue 		} else {
7647d56d374SYoshinobu Inoue 			if (*sp != '\0') {
7657d56d374SYoshinobu Inoue 				*p++ = '\0';
7667d56d374SYoshinobu Inoue 				break;
7677d56d374SYoshinobu Inoue 			}
7687d56d374SYoshinobu Inoue 		}
7697d56d374SYoshinobu Inoue 	}
7707d56d374SYoshinobu Inoue 	*pp = p;
7717d56d374SYoshinobu Inoue 	if (ret == NULL || *ret == '\0')
7727d56d374SYoshinobu Inoue 		return NULL;
7737d56d374SYoshinobu Inoue 	return ret;
7747d56d374SYoshinobu Inoue }
7757d56d374SYoshinobu Inoue 
7767d56d374SYoshinobu Inoue /*
777b8b31f33SHajimu UMEMOTO  * _hpreorder: sort address by default address selection
778b8b31f33SHajimu UMEMOTO  */
779b8b31f33SHajimu UMEMOTO static struct hostent *
780b8b31f33SHajimu UMEMOTO _hpreorder(struct hostent *hp)
781b8b31f33SHajimu UMEMOTO {
782146cd1bcSHajimu UMEMOTO 	struct hp_order *aio;
783146cd1bcSHajimu UMEMOTO 	int i, n;
784146cd1bcSHajimu UMEMOTO 	u_char *ap;
785146cd1bcSHajimu UMEMOTO 	struct sockaddr *sa;
786b8b31f33SHajimu UMEMOTO 	struct policyhead policyhead;
787b8b31f33SHajimu UMEMOTO 
788146cd1bcSHajimu UMEMOTO 	if (hp == NULL)
789b8b31f33SHajimu UMEMOTO 		return hp;
790b8b31f33SHajimu UMEMOTO 
791b8b31f33SHajimu UMEMOTO 	switch (hp->h_addrtype) {
792b8b31f33SHajimu UMEMOTO 	case AF_INET:
793b8b31f33SHajimu UMEMOTO #ifdef INET6
794b8b31f33SHajimu UMEMOTO 	case AF_INET6:
795b8b31f33SHajimu UMEMOTO #endif
796146cd1bcSHajimu UMEMOTO 		break;
797b8b31f33SHajimu UMEMOTO 	default:
798b8b31f33SHajimu UMEMOTO 		free_addrselectpolicy(&policyhead);
799b8b31f33SHajimu UMEMOTO 		return hp;
800b8b31f33SHajimu UMEMOTO 	}
801b8b31f33SHajimu UMEMOTO 
802146cd1bcSHajimu UMEMOTO 	/* count the number of addrinfo elements for sorting. */
803146cd1bcSHajimu UMEMOTO 	for (n = 0; hp->h_addr_list[n] != NULL; n++)
804146cd1bcSHajimu UMEMOTO 		;
805146cd1bcSHajimu UMEMOTO 
806146cd1bcSHajimu UMEMOTO 	/*
807146cd1bcSHajimu UMEMOTO 	 * If the number is small enough, we can skip the reordering process.
808146cd1bcSHajimu UMEMOTO 	 */
809146cd1bcSHajimu UMEMOTO 	if (n <= 1)
810146cd1bcSHajimu UMEMOTO 		return hp;
811146cd1bcSHajimu UMEMOTO 
812146cd1bcSHajimu UMEMOTO 	/* allocate a temporary array for sort and initialization of it. */
813146cd1bcSHajimu UMEMOTO 	if ((aio = malloc(sizeof(*aio) * n)) == NULL)
814146cd1bcSHajimu UMEMOTO 		return hp;	/* give up reordering */
815146cd1bcSHajimu UMEMOTO 	memset(aio, 0, sizeof(*aio) * n);
816146cd1bcSHajimu UMEMOTO 
817146cd1bcSHajimu UMEMOTO 	/* retrieve address selection policy from the kernel */
818146cd1bcSHajimu UMEMOTO 	TAILQ_INIT(&policyhead);
819146cd1bcSHajimu UMEMOTO 	if (!get_addrselectpolicy(&policyhead)) {
820146cd1bcSHajimu UMEMOTO 		/* no policy is installed into kernel, we don't sort. */
821146cd1bcSHajimu UMEMOTO 		free(aio);
822146cd1bcSHajimu UMEMOTO 		return hp;
823b8b31f33SHajimu UMEMOTO 	}
824b8b31f33SHajimu UMEMOTO 
825146cd1bcSHajimu UMEMOTO 	for (i = 0; i < n; i++) {
826146cd1bcSHajimu UMEMOTO 		ap = (u_char *)hp->h_addr_list[i];
827146cd1bcSHajimu UMEMOTO 		aio[i].aio_h_addr = ap;
828146cd1bcSHajimu UMEMOTO 		sa = &aio[i].aio_sa;
829146cd1bcSHajimu UMEMOTO 		switch (hp->h_addrtype) {
830146cd1bcSHajimu UMEMOTO 		case AF_INET:
831146cd1bcSHajimu UMEMOTO 			sa->sa_family = AF_INET;
832146cd1bcSHajimu UMEMOTO 			sa->sa_len = sizeof(struct sockaddr_in);
833146cd1bcSHajimu UMEMOTO 			memcpy(&((struct sockaddr_in *)sa)->sin_addr, ap,
834146cd1bcSHajimu UMEMOTO 			    sizeof(struct in_addr));
835146cd1bcSHajimu UMEMOTO 			break;
836146cd1bcSHajimu UMEMOTO #ifdef INET6
837146cd1bcSHajimu UMEMOTO 		case AF_INET6:
838146cd1bcSHajimu UMEMOTO 			if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
839146cd1bcSHajimu UMEMOTO 				sa->sa_family = AF_INET;
840146cd1bcSHajimu UMEMOTO 				sa->sa_len = sizeof(struct sockaddr_in);
841146cd1bcSHajimu UMEMOTO 				memcpy(&((struct sockaddr_in *)sa)->sin_addr,
842146cd1bcSHajimu UMEMOTO 				    &ap[12], sizeof(struct in_addr));
843146cd1bcSHajimu UMEMOTO 			} else {
844146cd1bcSHajimu UMEMOTO 				sa->sa_family = AF_INET6;
845146cd1bcSHajimu UMEMOTO 				sa->sa_len = sizeof(struct sockaddr_in6);
846146cd1bcSHajimu UMEMOTO 				memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr,
847146cd1bcSHajimu UMEMOTO 				    ap, sizeof(struct in6_addr));
848146cd1bcSHajimu UMEMOTO 			}
849146cd1bcSHajimu UMEMOTO 			break;
850146cd1bcSHajimu UMEMOTO #endif
851146cd1bcSHajimu UMEMOTO 		}
852146cd1bcSHajimu UMEMOTO 		aio[i].aio_dstscope = gai_addr2scopetype(sa);
853146cd1bcSHajimu UMEMOTO 		aio[i].aio_dstpolicy = match_addrselectpolicy(sa, &policyhead);
854146cd1bcSHajimu UMEMOTO 		set_source(&aio[i], &policyhead);
855146cd1bcSHajimu UMEMOTO 	}
856146cd1bcSHajimu UMEMOTO 
857146cd1bcSHajimu UMEMOTO 	/* perform sorting. */
858146cd1bcSHajimu UMEMOTO 	qsort(aio, n, sizeof(*aio), comp_dst);
859146cd1bcSHajimu UMEMOTO 
860146cd1bcSHajimu UMEMOTO 	/* reorder the h_addr_list. */
861146cd1bcSHajimu UMEMOTO 	for (i = 0; i < n; i++)
862146cd1bcSHajimu UMEMOTO 		hp->h_addr_list[i] = aio[i].aio_h_addr;
863146cd1bcSHajimu UMEMOTO 
864b8b31f33SHajimu UMEMOTO 	/* cleanup and return */
865146cd1bcSHajimu UMEMOTO 	free(aio);
866b8b31f33SHajimu UMEMOTO 	free_addrselectpolicy(&policyhead);
867b8b31f33SHajimu UMEMOTO 	return hp;
868b8b31f33SHajimu UMEMOTO }
869b8b31f33SHajimu UMEMOTO 
870b8b31f33SHajimu UMEMOTO static int
871b8b31f33SHajimu UMEMOTO get_addrselectpolicy(head)
872b8b31f33SHajimu UMEMOTO 	struct policyhead *head;
873b8b31f33SHajimu UMEMOTO {
874b8b31f33SHajimu UMEMOTO #ifdef INET6
875b8b31f33SHajimu UMEMOTO 	int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY };
876b8b31f33SHajimu UMEMOTO 	size_t l;
877b8b31f33SHajimu UMEMOTO 	char *buf;
878b8b31f33SHajimu UMEMOTO 	struct in6_addrpolicy *pol, *ep;
879b8b31f33SHajimu UMEMOTO 
880b8b31f33SHajimu UMEMOTO 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0)
881b8b31f33SHajimu UMEMOTO 		return (0);
882b8b31f33SHajimu UMEMOTO 	if ((buf = malloc(l)) == NULL)
883b8b31f33SHajimu UMEMOTO 		return (0);
884b8b31f33SHajimu UMEMOTO 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
885b8b31f33SHajimu UMEMOTO 		free(buf);
886b8b31f33SHajimu UMEMOTO 		return (0);
887b8b31f33SHajimu UMEMOTO 	}
888b8b31f33SHajimu UMEMOTO 
889b8b31f33SHajimu UMEMOTO 	ep = (struct in6_addrpolicy *)(buf + l);
890b8b31f33SHajimu UMEMOTO 	for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) {
891b8b31f33SHajimu UMEMOTO 		struct policyqueue *new;
892b8b31f33SHajimu UMEMOTO 
893b8b31f33SHajimu UMEMOTO 		if ((new = malloc(sizeof(*new))) == NULL) {
894b8b31f33SHajimu UMEMOTO 			free_addrselectpolicy(head); /* make the list empty */
895b8b31f33SHajimu UMEMOTO 			break;
896b8b31f33SHajimu UMEMOTO 		}
897b8b31f33SHajimu UMEMOTO 		new->pc_policy = *pol;
898b8b31f33SHajimu UMEMOTO 		TAILQ_INSERT_TAIL(head, new, pc_entry);
899b8b31f33SHajimu UMEMOTO 	}
900b8b31f33SHajimu UMEMOTO 
901b8b31f33SHajimu UMEMOTO 	free(buf);
902b8b31f33SHajimu UMEMOTO 	return (1);
903b8b31f33SHajimu UMEMOTO #else
904b8b31f33SHajimu UMEMOTO 	return (0);
905b8b31f33SHajimu UMEMOTO #endif
906b8b31f33SHajimu UMEMOTO }
907b8b31f33SHajimu UMEMOTO 
908b8b31f33SHajimu UMEMOTO static void
909b8b31f33SHajimu UMEMOTO free_addrselectpolicy(head)
910b8b31f33SHajimu UMEMOTO 	struct policyhead *head;
911b8b31f33SHajimu UMEMOTO {
912b8b31f33SHajimu UMEMOTO 	struct policyqueue *ent, *nent;
913b8b31f33SHajimu UMEMOTO 
914b8b31f33SHajimu UMEMOTO 	for (ent = TAILQ_FIRST(head); ent; ent = nent) {
915b8b31f33SHajimu UMEMOTO 		nent = TAILQ_NEXT(ent, pc_entry);
916b8b31f33SHajimu UMEMOTO 		TAILQ_REMOVE(head, ent, pc_entry);
917b8b31f33SHajimu UMEMOTO 		free(ent);
918b8b31f33SHajimu UMEMOTO 	}
919b8b31f33SHajimu UMEMOTO }
920b8b31f33SHajimu UMEMOTO 
921b8b31f33SHajimu UMEMOTO static struct policyqueue *
922b8b31f33SHajimu UMEMOTO match_addrselectpolicy(addr, head)
923b8b31f33SHajimu UMEMOTO 	struct sockaddr *addr;
924b8b31f33SHajimu UMEMOTO 	struct policyhead *head;
925b8b31f33SHajimu UMEMOTO {
926b8b31f33SHajimu UMEMOTO #ifdef INET6
927b8b31f33SHajimu UMEMOTO 	struct policyqueue *ent, *bestent = NULL;
928b8b31f33SHajimu UMEMOTO 	struct in6_addrpolicy *pol;
929b8b31f33SHajimu UMEMOTO 	int matchlen, bestmatchlen = -1;
930b8b31f33SHajimu UMEMOTO 	u_char *mp, *ep, *k, *p, m;
931b8b31f33SHajimu UMEMOTO 	struct sockaddr_in6 key;
932b8b31f33SHajimu UMEMOTO 
933b8b31f33SHajimu UMEMOTO 	switch(addr->sa_family) {
934b8b31f33SHajimu UMEMOTO 	case AF_INET6:
935b8b31f33SHajimu UMEMOTO 		key = *(struct sockaddr_in6 *)addr;
936b8b31f33SHajimu UMEMOTO 		break;
937b8b31f33SHajimu UMEMOTO 	case AF_INET:
938b8b31f33SHajimu UMEMOTO 		/* convert the address into IPv4-mapped IPv6 address. */
939b8b31f33SHajimu UMEMOTO 		memset(&key, 0, sizeof(key));
940b8b31f33SHajimu UMEMOTO 		key.sin6_family = AF_INET6;
941b8b31f33SHajimu UMEMOTO 		key.sin6_len = sizeof(key);
942b8b31f33SHajimu UMEMOTO 		key.sin6_addr.s6_addr[10] = 0xff;
943b8b31f33SHajimu UMEMOTO 		key.sin6_addr.s6_addr[11] = 0xff;
944b8b31f33SHajimu UMEMOTO 		memcpy(&key.sin6_addr.s6_addr[12],
945b8b31f33SHajimu UMEMOTO 		       &((struct sockaddr_in *)addr)->sin_addr, 4);
946b8b31f33SHajimu UMEMOTO 		break;
947b8b31f33SHajimu UMEMOTO 	default:
948b8b31f33SHajimu UMEMOTO 		return(NULL);
949b8b31f33SHajimu UMEMOTO 	}
950b8b31f33SHajimu UMEMOTO 
951b8b31f33SHajimu UMEMOTO 	for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) {
952b8b31f33SHajimu UMEMOTO 		pol = &ent->pc_policy;
953b8b31f33SHajimu UMEMOTO 		matchlen = 0;
954b8b31f33SHajimu UMEMOTO 
955b8b31f33SHajimu UMEMOTO 		mp = (u_char *)&pol->addrmask.sin6_addr;
956b8b31f33SHajimu UMEMOTO 		ep = mp + 16;	/* XXX: scope field? */
957b8b31f33SHajimu UMEMOTO 		k = (u_char *)&key.sin6_addr;
958b8b31f33SHajimu UMEMOTO 		p = (u_char *)&pol->addr.sin6_addr;
959b8b31f33SHajimu UMEMOTO 		for (; mp < ep && *mp; mp++, k++, p++) {
960b8b31f33SHajimu UMEMOTO 			m = *mp;
961b8b31f33SHajimu UMEMOTO 			if ((*k & m) != *p)
962b8b31f33SHajimu UMEMOTO 				goto next; /* not match */
963b8b31f33SHajimu UMEMOTO 			if (m == 0xff) /* short cut for a typical case */
964b8b31f33SHajimu UMEMOTO 				matchlen += 8;
965b8b31f33SHajimu UMEMOTO 			else {
966b8b31f33SHajimu UMEMOTO 				while (m >= 0x80) {
967b8b31f33SHajimu UMEMOTO 					matchlen++;
968b8b31f33SHajimu UMEMOTO 					m <<= 1;
969b8b31f33SHajimu UMEMOTO 				}
970b8b31f33SHajimu UMEMOTO 			}
971b8b31f33SHajimu UMEMOTO 		}
972b8b31f33SHajimu UMEMOTO 
973b8b31f33SHajimu UMEMOTO 		/* matched.  check if this is better than the current best. */
974b8b31f33SHajimu UMEMOTO 		if (matchlen > bestmatchlen) {
975b8b31f33SHajimu UMEMOTO 			bestent = ent;
976b8b31f33SHajimu UMEMOTO 			bestmatchlen = matchlen;
977b8b31f33SHajimu UMEMOTO 		}
978b8b31f33SHajimu UMEMOTO 
979b8b31f33SHajimu UMEMOTO 	  next:
980b8b31f33SHajimu UMEMOTO 		continue;
981b8b31f33SHajimu UMEMOTO 	}
982b8b31f33SHajimu UMEMOTO 
983b8b31f33SHajimu UMEMOTO 	return(bestent);
984b8b31f33SHajimu UMEMOTO #else
985b8b31f33SHajimu UMEMOTO 	return(NULL);
986b8b31f33SHajimu UMEMOTO #endif
987b8b31f33SHajimu UMEMOTO 
988b8b31f33SHajimu UMEMOTO }
989b8b31f33SHajimu UMEMOTO 
990146cd1bcSHajimu UMEMOTO static void
991146cd1bcSHajimu UMEMOTO set_source(aio, ph)
992146cd1bcSHajimu UMEMOTO 	struct hp_order *aio;
993146cd1bcSHajimu UMEMOTO 	struct policyhead *ph;
994146cd1bcSHajimu UMEMOTO {
995146cd1bcSHajimu UMEMOTO 	struct sockaddr_storage ss = aio->aio_un.aiou_ss;
996146cd1bcSHajimu UMEMOTO 	int s, srclen;
997146cd1bcSHajimu UMEMOTO 
998146cd1bcSHajimu UMEMOTO 	/* set unspec ("no source is available"), just in case */
999146cd1bcSHajimu UMEMOTO 	aio->aio_srcsa.sa_family = AF_UNSPEC;
1000146cd1bcSHajimu UMEMOTO 	aio->aio_srcscope = -1;
1001146cd1bcSHajimu UMEMOTO 
1002146cd1bcSHajimu UMEMOTO 	switch(ss.ss_family) {
1003146cd1bcSHajimu UMEMOTO 	case AF_INET:
1004146cd1bcSHajimu UMEMOTO 		((struct sockaddr_in *)&ss)->sin_port = htons(1);
1005146cd1bcSHajimu UMEMOTO 		break;
1006146cd1bcSHajimu UMEMOTO #ifdef INET6
1007146cd1bcSHajimu UMEMOTO 	case AF_INET6:
1008146cd1bcSHajimu UMEMOTO 		((struct sockaddr_in6 *)&ss)->sin6_port = htons(1);
1009146cd1bcSHajimu UMEMOTO 		break;
1010146cd1bcSHajimu UMEMOTO #endif
1011146cd1bcSHajimu UMEMOTO 	default:		/* ignore unsupported AFs explicitly */
1012146cd1bcSHajimu UMEMOTO 		return;
1013146cd1bcSHajimu UMEMOTO 	}
1014146cd1bcSHajimu UMEMOTO 
1015146cd1bcSHajimu UMEMOTO 	/* open a socket to get the source address for the given dst */
1016146cd1bcSHajimu UMEMOTO 	if ((s = _socket(ss.ss_family, SOCK_DGRAM, IPPROTO_UDP)) < 0)
1017146cd1bcSHajimu UMEMOTO 		return;		/* give up */
1018146cd1bcSHajimu UMEMOTO 	if (_connect(s, (struct sockaddr *)&ss, ss.ss_len) < 0)
1019146cd1bcSHajimu UMEMOTO 		goto cleanup;
1020146cd1bcSHajimu UMEMOTO 	srclen = ss.ss_len;
1021146cd1bcSHajimu UMEMOTO 	if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) {
1022146cd1bcSHajimu UMEMOTO 		aio->aio_srcsa.sa_family = AF_UNSPEC;
1023146cd1bcSHajimu UMEMOTO 		goto cleanup;
1024146cd1bcSHajimu UMEMOTO 	}
1025146cd1bcSHajimu UMEMOTO 	aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa);
1026146cd1bcSHajimu UMEMOTO 	aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph);
1027146cd1bcSHajimu UMEMOTO 	aio->aio_matchlen = matchlen(&aio->aio_srcsa, (struct sockaddr *)&ss);
1028146cd1bcSHajimu UMEMOTO #ifdef INET6
1029146cd1bcSHajimu UMEMOTO 	if (ss.ss_family == AF_INET6) {
1030146cd1bcSHajimu UMEMOTO 		struct in6_ifreq ifr6;
1031146cd1bcSHajimu UMEMOTO 		u_int32_t flags6;
1032146cd1bcSHajimu UMEMOTO 
1033146cd1bcSHajimu UMEMOTO 		/* XXX: interface name should not be hardcoded */
1034146cd1bcSHajimu UMEMOTO 		strncpy(ifr6.ifr_name, "lo0", sizeof(ifr6.ifr_name));
1035146cd1bcSHajimu UMEMOTO 		memset(&ifr6, 0, sizeof(ifr6));
1036146cd1bcSHajimu UMEMOTO 		memcpy(&ifr6.ifr_addr, &ss, ss.ss_len);
1037146cd1bcSHajimu UMEMOTO 		if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) {
1038146cd1bcSHajimu UMEMOTO 			flags6 = ifr6.ifr_ifru.ifru_flags6;
1039146cd1bcSHajimu UMEMOTO 			if ((flags6 & IN6_IFF_DEPRECATED))
1040146cd1bcSHajimu UMEMOTO 				aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED;
1041146cd1bcSHajimu UMEMOTO 		}
1042146cd1bcSHajimu UMEMOTO 	}
1043146cd1bcSHajimu UMEMOTO #endif
1044146cd1bcSHajimu UMEMOTO 
1045146cd1bcSHajimu UMEMOTO   cleanup:
1046146cd1bcSHajimu UMEMOTO 	_close(s);
1047146cd1bcSHajimu UMEMOTO 	return;
1048146cd1bcSHajimu UMEMOTO }
1049146cd1bcSHajimu UMEMOTO 
1050146cd1bcSHajimu UMEMOTO static int
1051146cd1bcSHajimu UMEMOTO matchlen(src, dst)
1052146cd1bcSHajimu UMEMOTO 	struct sockaddr *src, *dst;
1053146cd1bcSHajimu UMEMOTO {
1054146cd1bcSHajimu UMEMOTO 	int match = 0;
1055146cd1bcSHajimu UMEMOTO 	u_char *s, *d;
1056146cd1bcSHajimu UMEMOTO 	u_char *lim, r;
1057146cd1bcSHajimu UMEMOTO 	int addrlen;
1058146cd1bcSHajimu UMEMOTO 
1059146cd1bcSHajimu UMEMOTO 	switch (src->sa_family) {
1060146cd1bcSHajimu UMEMOTO #ifdef INET6
1061146cd1bcSHajimu UMEMOTO 	case AF_INET6:
1062146cd1bcSHajimu UMEMOTO 		s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr;
1063146cd1bcSHajimu UMEMOTO 		d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr;
1064146cd1bcSHajimu UMEMOTO 		addrlen = sizeof(struct in6_addr);
1065146cd1bcSHajimu UMEMOTO 		lim = s + addrlen;
1066146cd1bcSHajimu UMEMOTO 		break;
1067146cd1bcSHajimu UMEMOTO #endif
1068146cd1bcSHajimu UMEMOTO 	case AF_INET:
1069146cd1bcSHajimu UMEMOTO 		s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr;
1070146cd1bcSHajimu UMEMOTO 		d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr;
1071146cd1bcSHajimu UMEMOTO 		addrlen = sizeof(struct in_addr);
1072146cd1bcSHajimu UMEMOTO 		lim = s + addrlen;
1073146cd1bcSHajimu UMEMOTO 		break;
1074146cd1bcSHajimu UMEMOTO 	default:
1075146cd1bcSHajimu UMEMOTO 		return(0);
1076146cd1bcSHajimu UMEMOTO 	}
1077146cd1bcSHajimu UMEMOTO 
1078146cd1bcSHajimu UMEMOTO 	while (s < lim)
1079146cd1bcSHajimu UMEMOTO 		if ((r = (*d++ ^ *s++)) != 0) {
1080146cd1bcSHajimu UMEMOTO 			while (r < addrlen * 8) {
1081146cd1bcSHajimu UMEMOTO 				match++;
1082146cd1bcSHajimu UMEMOTO 				r <<= 1;
1083146cd1bcSHajimu UMEMOTO 			}
1084146cd1bcSHajimu UMEMOTO 			break;
1085146cd1bcSHajimu UMEMOTO 		} else
1086146cd1bcSHajimu UMEMOTO 			match += 8;
1087146cd1bcSHajimu UMEMOTO 	return(match);
1088146cd1bcSHajimu UMEMOTO }
1089146cd1bcSHajimu UMEMOTO 
1090146cd1bcSHajimu UMEMOTO static int
1091146cd1bcSHajimu UMEMOTO comp_dst(arg1, arg2)
1092146cd1bcSHajimu UMEMOTO 	const void *arg1, *arg2;
1093146cd1bcSHajimu UMEMOTO {
1094146cd1bcSHajimu UMEMOTO 	const struct hp_order *dst1 = arg1, *dst2 = arg2;
1095146cd1bcSHajimu UMEMOTO 
1096146cd1bcSHajimu UMEMOTO 	/*
1097146cd1bcSHajimu UMEMOTO 	 * Rule 1: Avoid unusable destinations.
1098146cd1bcSHajimu UMEMOTO 	 * XXX: we currently do not consider if an appropriate route exists.
1099146cd1bcSHajimu UMEMOTO 	 */
1100146cd1bcSHajimu UMEMOTO 	if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
1101146cd1bcSHajimu UMEMOTO 	    dst2->aio_srcsa.sa_family == AF_UNSPEC) {
1102146cd1bcSHajimu UMEMOTO 		return(-1);
1103146cd1bcSHajimu UMEMOTO 	}
1104146cd1bcSHajimu UMEMOTO 	if (dst1->aio_srcsa.sa_family == AF_UNSPEC &&
1105146cd1bcSHajimu UMEMOTO 	    dst2->aio_srcsa.sa_family != AF_UNSPEC) {
1106146cd1bcSHajimu UMEMOTO 		return(1);
1107146cd1bcSHajimu UMEMOTO 	}
1108146cd1bcSHajimu UMEMOTO 
1109146cd1bcSHajimu UMEMOTO 	/* Rule 2: Prefer matching scope. */
1110146cd1bcSHajimu UMEMOTO 	if (dst1->aio_dstscope == dst1->aio_srcscope &&
1111146cd1bcSHajimu UMEMOTO 	    dst2->aio_dstscope != dst2->aio_srcscope) {
1112146cd1bcSHajimu UMEMOTO 		return(-1);
1113146cd1bcSHajimu UMEMOTO 	}
1114146cd1bcSHajimu UMEMOTO 	if (dst1->aio_dstscope != dst1->aio_srcscope &&
1115146cd1bcSHajimu UMEMOTO 	    dst2->aio_dstscope == dst2->aio_srcscope) {
1116146cd1bcSHajimu UMEMOTO 		return(1);
1117146cd1bcSHajimu UMEMOTO 	}
1118146cd1bcSHajimu UMEMOTO 
1119146cd1bcSHajimu UMEMOTO 	/* Rule 3: Avoid deprecated addresses. */
1120146cd1bcSHajimu UMEMOTO 	if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
1121146cd1bcSHajimu UMEMOTO 	    dst2->aio_srcsa.sa_family != AF_UNSPEC) {
1122146cd1bcSHajimu UMEMOTO 		if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
1123146cd1bcSHajimu UMEMOTO 		    (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
1124146cd1bcSHajimu UMEMOTO 			return(-1);
1125146cd1bcSHajimu UMEMOTO 		}
1126146cd1bcSHajimu UMEMOTO 		if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
1127146cd1bcSHajimu UMEMOTO 		    !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
1128146cd1bcSHajimu UMEMOTO 			return(1);
1129146cd1bcSHajimu UMEMOTO 		}
1130146cd1bcSHajimu UMEMOTO 	}
1131146cd1bcSHajimu UMEMOTO 
1132146cd1bcSHajimu UMEMOTO 	/* Rule 4: Prefer home addresses. */
1133146cd1bcSHajimu UMEMOTO 	/* XXX: not implemented yet */
1134146cd1bcSHajimu UMEMOTO 
1135146cd1bcSHajimu UMEMOTO 	/* Rule 5: Prefer matching label. */
1136146cd1bcSHajimu UMEMOTO #ifdef INET6
1137146cd1bcSHajimu UMEMOTO 	if (dst1->aio_srcpolicy && dst1->aio_dstpolicy &&
1138146cd1bcSHajimu UMEMOTO 	    dst1->aio_srcpolicy->pc_policy.label ==
1139146cd1bcSHajimu UMEMOTO 	    dst1->aio_dstpolicy->pc_policy.label &&
1140146cd1bcSHajimu UMEMOTO 	    (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL ||
1141146cd1bcSHajimu UMEMOTO 	     dst2->aio_srcpolicy->pc_policy.label !=
1142146cd1bcSHajimu UMEMOTO 	     dst2->aio_dstpolicy->pc_policy.label)) {
1143146cd1bcSHajimu UMEMOTO 		return(-1);
1144146cd1bcSHajimu UMEMOTO 	}
1145146cd1bcSHajimu UMEMOTO 	if (dst2->aio_srcpolicy && dst2->aio_dstpolicy &&
1146146cd1bcSHajimu UMEMOTO 	    dst2->aio_srcpolicy->pc_policy.label ==
1147146cd1bcSHajimu UMEMOTO 	    dst2->aio_dstpolicy->pc_policy.label &&
1148146cd1bcSHajimu UMEMOTO 	    (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL ||
1149146cd1bcSHajimu UMEMOTO 	     dst1->aio_srcpolicy->pc_policy.label !=
1150146cd1bcSHajimu UMEMOTO 	     dst1->aio_dstpolicy->pc_policy.label)) {
1151146cd1bcSHajimu UMEMOTO 		return(1);
1152146cd1bcSHajimu UMEMOTO 	}
1153146cd1bcSHajimu UMEMOTO #endif
1154146cd1bcSHajimu UMEMOTO 
1155146cd1bcSHajimu UMEMOTO 	/* Rule 6: Prefer higher precedence. */
1156146cd1bcSHajimu UMEMOTO #ifdef INET6
1157146cd1bcSHajimu UMEMOTO 	if (dst1->aio_dstpolicy &&
1158146cd1bcSHajimu UMEMOTO 	    (dst2->aio_dstpolicy == NULL ||
1159146cd1bcSHajimu UMEMOTO 	     dst1->aio_dstpolicy->pc_policy.preced >
1160146cd1bcSHajimu UMEMOTO 	     dst2->aio_dstpolicy->pc_policy.preced)) {
1161146cd1bcSHajimu UMEMOTO 		return(-1);
1162146cd1bcSHajimu UMEMOTO 	}
1163146cd1bcSHajimu UMEMOTO 	if (dst2->aio_dstpolicy &&
1164146cd1bcSHajimu UMEMOTO 	    (dst1->aio_dstpolicy == NULL ||
1165146cd1bcSHajimu UMEMOTO 	     dst2->aio_dstpolicy->pc_policy.preced >
1166146cd1bcSHajimu UMEMOTO 	     dst1->aio_dstpolicy->pc_policy.preced)) {
1167146cd1bcSHajimu UMEMOTO 		return(1);
1168146cd1bcSHajimu UMEMOTO 	}
1169146cd1bcSHajimu UMEMOTO #endif
1170146cd1bcSHajimu UMEMOTO 
1171146cd1bcSHajimu UMEMOTO 	/* Rule 7: Prefer native transport. */
1172146cd1bcSHajimu UMEMOTO 	/* XXX: not implemented yet */
1173146cd1bcSHajimu UMEMOTO 
1174146cd1bcSHajimu UMEMOTO 	/* Rule 8: Prefer smaller scope. */
1175146cd1bcSHajimu UMEMOTO 	if (dst1->aio_dstscope >= 0 &&
1176146cd1bcSHajimu UMEMOTO 	    dst1->aio_dstscope < dst2->aio_dstscope) {
1177146cd1bcSHajimu UMEMOTO 		return(-1);
1178146cd1bcSHajimu UMEMOTO 	}
1179146cd1bcSHajimu UMEMOTO 	if (dst2->aio_dstscope >= 0 &&
1180146cd1bcSHajimu UMEMOTO 	    dst2->aio_dstscope < dst1->aio_dstscope) {
1181146cd1bcSHajimu UMEMOTO 		return(1);
1182146cd1bcSHajimu UMEMOTO 	}
1183146cd1bcSHajimu UMEMOTO 
1184146cd1bcSHajimu UMEMOTO 	/*
1185146cd1bcSHajimu UMEMOTO 	 * Rule 9: Use longest matching prefix.
1186146cd1bcSHajimu UMEMOTO 	 * We compare the match length in a same AF only.
1187146cd1bcSHajimu UMEMOTO 	 */
1188146cd1bcSHajimu UMEMOTO 	if (dst1->aio_sa.sa_family == dst2->aio_sa.sa_family) {
1189146cd1bcSHajimu UMEMOTO 		if (dst1->aio_matchlen > dst2->aio_matchlen) {
1190146cd1bcSHajimu UMEMOTO 			return(-1);
1191146cd1bcSHajimu UMEMOTO 		}
1192146cd1bcSHajimu UMEMOTO 		if (dst1->aio_matchlen < dst2->aio_matchlen) {
1193146cd1bcSHajimu UMEMOTO 			return(1);
1194146cd1bcSHajimu UMEMOTO 		}
1195146cd1bcSHajimu UMEMOTO 	}
1196146cd1bcSHajimu UMEMOTO 
1197146cd1bcSHajimu UMEMOTO 	/* Rule 10: Otherwise, leave the order unchanged. */
1198146cd1bcSHajimu UMEMOTO 	return(-1);
1199146cd1bcSHajimu UMEMOTO }
1200146cd1bcSHajimu UMEMOTO 
1201146cd1bcSHajimu UMEMOTO /*
1202146cd1bcSHajimu UMEMOTO  * Copy from scope.c.
1203146cd1bcSHajimu UMEMOTO  * XXX: we should standardize the functions and link them as standard
1204146cd1bcSHajimu UMEMOTO  * library.
1205146cd1bcSHajimu UMEMOTO  */
1206146cd1bcSHajimu UMEMOTO static int
1207146cd1bcSHajimu UMEMOTO gai_addr2scopetype(sa)
1208146cd1bcSHajimu UMEMOTO 	struct sockaddr *sa;
1209146cd1bcSHajimu UMEMOTO {
1210146cd1bcSHajimu UMEMOTO #ifdef INET6
1211146cd1bcSHajimu UMEMOTO 	struct sockaddr_in6 *sa6;
1212146cd1bcSHajimu UMEMOTO #endif
1213146cd1bcSHajimu UMEMOTO 	struct sockaddr_in *sa4;
1214146cd1bcSHajimu UMEMOTO 
1215146cd1bcSHajimu UMEMOTO 	switch(sa->sa_family) {
1216146cd1bcSHajimu UMEMOTO #ifdef INET6
1217146cd1bcSHajimu UMEMOTO 	case AF_INET6:
1218146cd1bcSHajimu UMEMOTO 		sa6 = (struct sockaddr_in6 *)sa;
1219146cd1bcSHajimu UMEMOTO 		if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
1220146cd1bcSHajimu UMEMOTO 			/* just use the scope field of the multicast address */
1221146cd1bcSHajimu UMEMOTO 			return(sa6->sin6_addr.s6_addr[2] & 0x0f);
1222146cd1bcSHajimu UMEMOTO 		}
1223146cd1bcSHajimu UMEMOTO 		/*
1224146cd1bcSHajimu UMEMOTO 		 * Unicast addresses: map scope type to corresponding scope
1225146cd1bcSHajimu UMEMOTO 		 * value defined for multcast addresses.
1226146cd1bcSHajimu UMEMOTO 		 * XXX: hardcoded scope type values are bad...
1227146cd1bcSHajimu UMEMOTO 		 */
1228146cd1bcSHajimu UMEMOTO 		if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr))
1229146cd1bcSHajimu UMEMOTO 			return(1); /* node local scope */
1230146cd1bcSHajimu UMEMOTO 		if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr))
1231146cd1bcSHajimu UMEMOTO 			return(2); /* link-local scope */
1232146cd1bcSHajimu UMEMOTO 		if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr))
1233146cd1bcSHajimu UMEMOTO 			return(5); /* site-local scope */
1234146cd1bcSHajimu UMEMOTO 		return(14);	/* global scope */
1235146cd1bcSHajimu UMEMOTO 		break;
1236146cd1bcSHajimu UMEMOTO #endif
1237146cd1bcSHajimu UMEMOTO 	case AF_INET:
1238146cd1bcSHajimu UMEMOTO 		/*
1239146cd1bcSHajimu UMEMOTO 		 * IPv4 pseudo scoping according to RFC 3484.
1240146cd1bcSHajimu UMEMOTO 		 */
1241146cd1bcSHajimu UMEMOTO 		sa4 = (struct sockaddr_in *)sa;
1242146cd1bcSHajimu UMEMOTO 		/* IPv4 autoconfiguration addresses have link-local scope. */
1243146cd1bcSHajimu UMEMOTO 		if (((u_char *)&sa4->sin_addr)[0] == 169 &&
1244146cd1bcSHajimu UMEMOTO 		    ((u_char *)&sa4->sin_addr)[1] == 254)
1245146cd1bcSHajimu UMEMOTO 			return(2);
1246146cd1bcSHajimu UMEMOTO 		/* Private addresses have site-local scope. */
1247146cd1bcSHajimu UMEMOTO 		if (((u_char *)&sa4->sin_addr)[0] == 10 ||
1248146cd1bcSHajimu UMEMOTO 		    (((u_char *)&sa4->sin_addr)[0] == 172 &&
1249146cd1bcSHajimu UMEMOTO 		     (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) ||
1250146cd1bcSHajimu UMEMOTO 		    (((u_char *)&sa4->sin_addr)[0] == 192 &&
1251146cd1bcSHajimu UMEMOTO 		     ((u_char *)&sa4->sin_addr)[1] == 168))
1252146cd1bcSHajimu UMEMOTO 			return(14);	/* XXX: It should be 5 unless NAT */
1253146cd1bcSHajimu UMEMOTO 		/* Loopback addresses have link-local scope. */
1254146cd1bcSHajimu UMEMOTO 		if (((u_char *)&sa4->sin_addr)[0] == 127)
1255146cd1bcSHajimu UMEMOTO 			return(2);
1256146cd1bcSHajimu UMEMOTO 		return(14);
1257146cd1bcSHajimu UMEMOTO 		break;
1258146cd1bcSHajimu UMEMOTO 	default:
1259146cd1bcSHajimu UMEMOTO 		errno = EAFNOSUPPORT; /* is this a good error? */
1260146cd1bcSHajimu UMEMOTO 		return(-1);
1261146cd1bcSHajimu UMEMOTO 	}
1262146cd1bcSHajimu UMEMOTO }
1263146cd1bcSHajimu UMEMOTO 
1264b8b31f33SHajimu UMEMOTO /*
12657d56d374SYoshinobu Inoue  * FILES (/etc/hosts)
12667d56d374SYoshinobu Inoue  */
12677d56d374SYoshinobu Inoue 
12687d56d374SYoshinobu Inoue static FILE *
12697d56d374SYoshinobu Inoue _files_open(int *errp)
12707d56d374SYoshinobu Inoue {
12717d56d374SYoshinobu Inoue 	FILE *fp;
12727d56d374SYoshinobu Inoue 	fp = fopen(_PATH_HOSTS, "r");
12737d56d374SYoshinobu Inoue 	if (fp == NULL)
12747d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
12757d56d374SYoshinobu Inoue 	return fp;
12767d56d374SYoshinobu Inoue }
12777d56d374SYoshinobu Inoue 
1278248aee62SJacques Vidrine static int
1279248aee62SJacques Vidrine _files_ghbyname(void *rval, void *cb_data, va_list ap)
12807d56d374SYoshinobu Inoue {
1281248aee62SJacques Vidrine 	const char *name;
1282248aee62SJacques Vidrine 	int af;
1283248aee62SJacques Vidrine 	int *errp;
12847d56d374SYoshinobu Inoue 	int match, nalias;
12857d56d374SYoshinobu Inoue 	char *p, *line, *addrstr, *cname;
12867d56d374SYoshinobu Inoue 	FILE *fp;
12877d56d374SYoshinobu Inoue 	struct hostent *rethp, *hp, hpbuf;
12887d56d374SYoshinobu Inoue 	char *aliases[MAXALIASES + 1], *addrs[2];
12897d56d374SYoshinobu Inoue 	union inx_addr addrbuf;
12907d56d374SYoshinobu Inoue 	char buf[BUFSIZ];
12917d56d374SYoshinobu Inoue 
1292248aee62SJacques Vidrine 	name = va_arg(ap, const char *);
1293248aee62SJacques Vidrine 	af = va_arg(ap, int);
1294248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
1295248aee62SJacques Vidrine 
1296248aee62SJacques Vidrine 	*(struct hostent **)rval = NULL;
1297248aee62SJacques Vidrine 
12987d56d374SYoshinobu Inoue 	if ((fp = _files_open(errp)) == NULL)
1299248aee62SJacques Vidrine 		return NS_UNAVAIL;
13007d56d374SYoshinobu Inoue 	rethp = hp = NULL;
13017d56d374SYoshinobu Inoue 
13027d56d374SYoshinobu Inoue 	while (fgets(buf, sizeof(buf), fp)) {
13037d56d374SYoshinobu Inoue 		line = buf;
13047d56d374SYoshinobu Inoue 		if ((addrstr = _hgetword(&line)) == NULL
13057d56d374SYoshinobu Inoue 		||  (cname = _hgetword(&line)) == NULL)
13067d56d374SYoshinobu Inoue 			continue;
13077d56d374SYoshinobu Inoue 		match = (strcasecmp(cname, name) == 0);
13087d56d374SYoshinobu Inoue 		nalias = 0;
13097d56d374SYoshinobu Inoue 		while ((p = _hgetword(&line)) != NULL) {
13107d56d374SYoshinobu Inoue 			if (!match)
13117d56d374SYoshinobu Inoue 				match = (strcasecmp(p, name) == 0);
13127d56d374SYoshinobu Inoue 			if (nalias < MAXALIASES)
13137d56d374SYoshinobu Inoue 				aliases[nalias++] = p;
13147d56d374SYoshinobu Inoue 		}
13157d56d374SYoshinobu Inoue 		if (!match)
13167d56d374SYoshinobu Inoue 			continue;
13170fbf0979SHajimu UMEMOTO 		switch (af) {
1318e6f35403SYoshinobu Inoue 		case AF_INET:
1319e6f35403SYoshinobu Inoue 			if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
1320e6f35403SYoshinobu Inoue 			    != 1) {
13217d56d374SYoshinobu Inoue 				*errp = NO_DATA;	/* name found */
13227d56d374SYoshinobu Inoue 				continue;
13237d56d374SYoshinobu Inoue 			}
1324e6f35403SYoshinobu Inoue 			break;
1325e6f35403SYoshinobu Inoue #ifdef INET6
1326e6f35403SYoshinobu Inoue 		case AF_INET6:
1327e6f35403SYoshinobu Inoue 			if (inet_pton(af, addrstr, &addrbuf) != 1) {
1328e6f35403SYoshinobu Inoue 				*errp = NO_DATA;	/* name found */
1329e6f35403SYoshinobu Inoue 				continue;
1330e6f35403SYoshinobu Inoue 			}
1331e6f35403SYoshinobu Inoue 			break;
1332e6f35403SYoshinobu Inoue #endif
1333e6f35403SYoshinobu Inoue 		}
13347d56d374SYoshinobu Inoue 		hp = &hpbuf;
13357d56d374SYoshinobu Inoue 		hp->h_name = cname;
13367d56d374SYoshinobu Inoue 		hp->h_aliases = aliases;
13377d56d374SYoshinobu Inoue 		aliases[nalias] = NULL;
13387d56d374SYoshinobu Inoue 		hp->h_addrtype = af;
13397d56d374SYoshinobu Inoue 		hp->h_length = ADDRLEN(af);
13407d56d374SYoshinobu Inoue 		hp->h_addr_list = addrs;
13417d56d374SYoshinobu Inoue 		addrs[0] = (char *)&addrbuf;
13427d56d374SYoshinobu Inoue 		addrs[1] = NULL;
13437d56d374SYoshinobu Inoue 		hp = _hpcopy(hp, errp);
13447d56d374SYoshinobu Inoue 		rethp = _hpmerge(rethp, hp, errp);
13457d56d374SYoshinobu Inoue 	}
13467d56d374SYoshinobu Inoue 	fclose(fp);
1347248aee62SJacques Vidrine 	*(struct hostent **)rval = rethp;
1348248aee62SJacques Vidrine 	return (rethp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
13497d56d374SYoshinobu Inoue }
13507d56d374SYoshinobu Inoue 
1351248aee62SJacques Vidrine static int
1352248aee62SJacques Vidrine _files_ghbyaddr(void *rval, void *cb_data, va_list ap)
13537d56d374SYoshinobu Inoue {
1354248aee62SJacques Vidrine 	const void *addr;
1355248aee62SJacques Vidrine 	int addrlen;
1356248aee62SJacques Vidrine 	int af;
1357248aee62SJacques Vidrine 	int *errp;
13587d56d374SYoshinobu Inoue 	int nalias;
13597d56d374SYoshinobu Inoue 	char *p, *line;
13607d56d374SYoshinobu Inoue 	FILE *fp;
13617d56d374SYoshinobu Inoue 	struct hostent *hp, hpbuf;
13627d56d374SYoshinobu Inoue 	char *aliases[MAXALIASES + 1], *addrs[2];
13637d56d374SYoshinobu Inoue 	union inx_addr addrbuf;
13647d56d374SYoshinobu Inoue 	char buf[BUFSIZ];
13657d56d374SYoshinobu Inoue 
1366248aee62SJacques Vidrine 	addr = va_arg(ap, const void *);
1367248aee62SJacques Vidrine 	addrlen = va_arg(ap, int);
1368248aee62SJacques Vidrine 	af = va_arg(ap, int);
1369248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
1370248aee62SJacques Vidrine 
1371248aee62SJacques Vidrine 	*(struct hostent**)rval = NULL;
1372248aee62SJacques Vidrine 
13737d56d374SYoshinobu Inoue 	if ((fp = _files_open(errp)) == NULL)
1374248aee62SJacques Vidrine 		return NS_UNAVAIL;
13757d56d374SYoshinobu Inoue 	hp = NULL;
13767d56d374SYoshinobu Inoue 	while (fgets(buf, sizeof(buf), fp)) {
13777d56d374SYoshinobu Inoue 		line = buf;
13787d56d374SYoshinobu Inoue 		if ((p = _hgetword(&line)) == NULL
1379be26adb5SYoshinobu Inoue 		||  (af == AF_INET
1380be26adb5SYoshinobu Inoue 		     ? inet_aton(p, (struct in_addr *)&addrbuf)
1381be26adb5SYoshinobu Inoue 		     : inet_pton(af, p, &addrbuf)) != 1
13827d56d374SYoshinobu Inoue 		||  memcmp(addr, &addrbuf, addrlen) != 0
13837d56d374SYoshinobu Inoue 		||  (p = _hgetword(&line)) == NULL)
13847d56d374SYoshinobu Inoue 			continue;
13857d56d374SYoshinobu Inoue 		hp = &hpbuf;
13867d56d374SYoshinobu Inoue 		hp->h_name = p;
13877d56d374SYoshinobu Inoue 		hp->h_aliases = aliases;
13887d56d374SYoshinobu Inoue 		nalias = 0;
13897d56d374SYoshinobu Inoue 		while ((p = _hgetword(&line)) != NULL) {
13907d56d374SYoshinobu Inoue 			if (nalias < MAXALIASES)
13917d56d374SYoshinobu Inoue 				aliases[nalias++] = p;
13927d56d374SYoshinobu Inoue 		}
13937d56d374SYoshinobu Inoue 		aliases[nalias] = NULL;
13947d56d374SYoshinobu Inoue 		hp->h_addrtype = af;
13957d56d374SYoshinobu Inoue 		hp->h_length = addrlen;
13967d56d374SYoshinobu Inoue 		hp->h_addr_list = addrs;
13977d56d374SYoshinobu Inoue 		addrs[0] = (char *)&addrbuf;
13987d56d374SYoshinobu Inoue 		addrs[1] = NULL;
13997d56d374SYoshinobu Inoue 		hp = _hpcopy(hp, errp);
14007d56d374SYoshinobu Inoue 		break;
14017d56d374SYoshinobu Inoue 	}
14027d56d374SYoshinobu Inoue 	fclose(fp);
1403248aee62SJacques Vidrine 	*(struct hostent **)rval = hp;
1404248aee62SJacques Vidrine 	return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
14057d56d374SYoshinobu Inoue }
14067d56d374SYoshinobu Inoue 
140773b30f0cSJun-ichiro itojun Hagino #ifdef YP
140863858012SJonathan Lemon /*
140963858012SJonathan Lemon  * NIS
141063858012SJonathan Lemon  *
141163858012SJonathan Lemon  * XXX actually a hack, these are INET4 specific.
141263858012SJonathan Lemon  */
1413248aee62SJacques Vidrine static int
1414248aee62SJacques Vidrine _nis_ghbyname(void *rval, void *cb_data, va_list ap)
141563858012SJonathan Lemon {
1416248aee62SJacques Vidrine 	const char *name;
1417248aee62SJacques Vidrine 	int af;
1418248aee62SJacques Vidrine 	int *errp;
141938775c5eSJonathan Lemon 	struct hostent *hp = NULL;
142063858012SJonathan Lemon 
1421248aee62SJacques Vidrine 	name = va_arg(ap, const char *);
1422248aee62SJacques Vidrine 	af = va_arg(ap, int);
1423248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
1424248aee62SJacques Vidrine 
142563858012SJonathan Lemon 	if (af == AF_INET) {
142633dee819SBrian Feldman 		THREAD_LOCK();
142763858012SJonathan Lemon 		hp = _gethostbynisname(name, af);
142863858012SJonathan Lemon 		if (hp != NULL)
142963858012SJonathan Lemon 			hp = _hpcopy(hp, errp);
143033dee819SBrian Feldman 		THREAD_UNLOCK();
143163858012SJonathan Lemon 	}
1432248aee62SJacques Vidrine 
1433248aee62SJacques Vidrine 	*(struct hostent **)rval = hp;
1434248aee62SJacques Vidrine 	return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
143563858012SJonathan Lemon 
143663858012SJonathan Lemon }
143763858012SJonathan Lemon 
1438248aee62SJacques Vidrine static int
1439248aee62SJacques Vidrine _nis_ghbyaddr(void *rval, void *cb_data, va_list ap)
144063858012SJonathan Lemon {
1441248aee62SJacques Vidrine 	const void *addr;
1442248aee62SJacques Vidrine 	int addrlen;
1443248aee62SJacques Vidrine 	int af;
1444248aee62SJacques Vidrine 	int *errp;
144563858012SJonathan Lemon 	struct hostent *hp = NULL;
144663858012SJonathan Lemon 
1447248aee62SJacques Vidrine 	addr = va_arg(ap, const void *);
1448248aee62SJacques Vidrine 	addrlen = va_arg(ap, int);
1449248aee62SJacques Vidrine 	af = va_arg(ap, int);
1450248aee62SJacques Vidrine 
145163858012SJonathan Lemon 	if (af == AF_INET) {
145233dee819SBrian Feldman 		THREAD_LOCK();
145363858012SJonathan Lemon 		hp = _gethostbynisaddr(addr, addrlen, af);
145463858012SJonathan Lemon 		if (hp != NULL)
145563858012SJonathan Lemon 			hp = _hpcopy(hp, errp);
145633dee819SBrian Feldman 		THREAD_UNLOCK();
145763858012SJonathan Lemon 	}
1458248aee62SJacques Vidrine 	*(struct hostent **)rval = hp;
1459248aee62SJacques Vidrine 	return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
146063858012SJonathan Lemon }
14617d56d374SYoshinobu Inoue #endif
14627d56d374SYoshinobu Inoue 
14639832619cSHajimu UMEMOTO #define	MAXPACKET	(64*1024)
146473b30f0cSJun-ichiro itojun Hagino 
146573b30f0cSJun-ichiro itojun Hagino typedef union {
146673b30f0cSJun-ichiro itojun Hagino 	HEADER hdr;
146773b30f0cSJun-ichiro itojun Hagino 	u_char buf[MAXPACKET];
146873b30f0cSJun-ichiro itojun Hagino } querybuf;
146973b30f0cSJun-ichiro itojun Hagino 
14701372519bSDavid E. O'Brien static struct hostent *getanswer(const querybuf *, int, const char *, int,
14711372519bSDavid E. O'Brien 	    struct hostent *, int *);
147273b30f0cSJun-ichiro itojun Hagino 
147373b30f0cSJun-ichiro itojun Hagino /*
147473b30f0cSJun-ichiro itojun Hagino  * we don't need to take care about sorting, nor IPv4 mapped address here.
147573b30f0cSJun-ichiro itojun Hagino  */
14767d56d374SYoshinobu Inoue static struct hostent *
147773b30f0cSJun-ichiro itojun Hagino getanswer(answer, anslen, qname, qtype, template, errp)
147873b30f0cSJun-ichiro itojun Hagino 	const querybuf *answer;
1479e6f35403SYoshinobu Inoue 	int anslen;
148073b30f0cSJun-ichiro itojun Hagino 	const char *qname;
1481e6f35403SYoshinobu Inoue 	int qtype;
148273b30f0cSJun-ichiro itojun Hagino 	struct hostent *template;
1483e6f35403SYoshinobu Inoue 	int *errp;
14847d56d374SYoshinobu Inoue {
14858fb3f3f6SDavid E. O'Brien 	const HEADER *hp;
14868fb3f3f6SDavid E. O'Brien 	const u_char *cp;
14878fb3f3f6SDavid E. O'Brien 	int n;
148873b30f0cSJun-ichiro itojun Hagino 	const u_char *eom, *erdata;
1489d6af58f5SWarner Losh 	char *bp, *ep, **ap, **hap;
1490d6af58f5SWarner Losh 	int type, class, ancount, qdcount;
149173b30f0cSJun-ichiro itojun Hagino 	int haveanswer, had_error;
149273b30f0cSJun-ichiro itojun Hagino 	char tbuf[MAXDNAME];
149373b30f0cSJun-ichiro itojun Hagino 	const char *tname;
1494c05ac53bSDavid E. O'Brien 	int (*name_ok)(const char *);
149573b30f0cSJun-ichiro itojun Hagino 	static char *h_addr_ptrs[MAXADDRS + 1];
149673b30f0cSJun-ichiro itojun Hagino 	static char *host_aliases[MAXALIASES];
149773b30f0cSJun-ichiro itojun Hagino 	static char hostbuf[8*1024];
14987d56d374SYoshinobu Inoue 
149973b30f0cSJun-ichiro itojun Hagino #define BOUNDED_INCR(x) \
150073b30f0cSJun-ichiro itojun Hagino 	do { \
150173b30f0cSJun-ichiro itojun Hagino 		cp += x; \
150273b30f0cSJun-ichiro itojun Hagino 		if (cp > eom) { \
150373b30f0cSJun-ichiro itojun Hagino 			*errp = NO_RECOVERY; \
150473b30f0cSJun-ichiro itojun Hagino 			return (NULL); \
150573b30f0cSJun-ichiro itojun Hagino 		} \
150673b30f0cSJun-ichiro itojun Hagino 	} while (0)
15077d56d374SYoshinobu Inoue 
150873b30f0cSJun-ichiro itojun Hagino #define BOUNDS_CHECK(ptr, count) \
150973b30f0cSJun-ichiro itojun Hagino 	do { \
151073b30f0cSJun-ichiro itojun Hagino 		if ((ptr) + (count) > eom) { \
151173b30f0cSJun-ichiro itojun Hagino 			*errp = NO_RECOVERY; \
151273b30f0cSJun-ichiro itojun Hagino 			return (NULL); \
151373b30f0cSJun-ichiro itojun Hagino 		} \
151473b30f0cSJun-ichiro itojun Hagino 	} while (0)
151573b30f0cSJun-ichiro itojun Hagino 
15163f587e57SKris Kennaway /* XXX do {} while (0) cannot be put here */
151773b30f0cSJun-ichiro itojun Hagino #define DNS_ASSERT(x) \
15183f587e57SKris Kennaway 	{				\
151973b30f0cSJun-ichiro itojun Hagino 		if (!(x)) {		\
152073b30f0cSJun-ichiro itojun Hagino 			cp += n;	\
152173b30f0cSJun-ichiro itojun Hagino 			continue;	\
152273b30f0cSJun-ichiro itojun Hagino 		}			\
15233f587e57SKris Kennaway 	}
152473b30f0cSJun-ichiro itojun Hagino 
15253f587e57SKris Kennaway /* XXX do {} while (0) cannot be put here */
152673b30f0cSJun-ichiro itojun Hagino #define DNS_FATAL(x) \
15273f587e57SKris Kennaway 	{				\
152873b30f0cSJun-ichiro itojun Hagino 		if (!(x)) {		\
152973b30f0cSJun-ichiro itojun Hagino 			had_error++;	\
153073b30f0cSJun-ichiro itojun Hagino 			continue;	\
153173b30f0cSJun-ichiro itojun Hagino 		}			\
15323f587e57SKris Kennaway 	}
153373b30f0cSJun-ichiro itojun Hagino 
153473b30f0cSJun-ichiro itojun Hagino 	tname = qname;
153573b30f0cSJun-ichiro itojun Hagino 	template->h_name = NULL;
153673b30f0cSJun-ichiro itojun Hagino 	eom = answer->buf + anslen;
153773b30f0cSJun-ichiro itojun Hagino 	switch (qtype) {
15387d56d374SYoshinobu Inoue 	case T_A:
15397d56d374SYoshinobu Inoue 	case T_AAAA:
154073b30f0cSJun-ichiro itojun Hagino 		name_ok = res_hnok;
154173b30f0cSJun-ichiro itojun Hagino 		break;
154273b30f0cSJun-ichiro itojun Hagino 	case T_PTR:
154373b30f0cSJun-ichiro itojun Hagino 		name_ok = res_dnok;
15447d56d374SYoshinobu Inoue 		break;
15457d56d374SYoshinobu Inoue 	default:
154673b30f0cSJun-ichiro itojun Hagino 		return (NULL);	/* XXX should be abort(); */
154773b30f0cSJun-ichiro itojun Hagino 	}
154873b30f0cSJun-ichiro itojun Hagino 	/*
154973b30f0cSJun-ichiro itojun Hagino 	 * find first satisfactory answer
155073b30f0cSJun-ichiro itojun Hagino 	 */
155173b30f0cSJun-ichiro itojun Hagino 	hp = &answer->hdr;
155273b30f0cSJun-ichiro itojun Hagino 	ancount = ntohs(hp->ancount);
155373b30f0cSJun-ichiro itojun Hagino 	qdcount = ntohs(hp->qdcount);
155473b30f0cSJun-ichiro itojun Hagino 	bp = hostbuf;
1555d6af58f5SWarner Losh 	ep = hostbuf + sizeof hostbuf;
155673b30f0cSJun-ichiro itojun Hagino 	cp = answer->buf;
155773b30f0cSJun-ichiro itojun Hagino 	BOUNDED_INCR(HFIXEDSZ);
155873b30f0cSJun-ichiro itojun Hagino 	if (qdcount != 1) {
155973b30f0cSJun-ichiro itojun Hagino 		*errp = NO_RECOVERY;
156073b30f0cSJun-ichiro itojun Hagino 		return (NULL);
156173b30f0cSJun-ichiro itojun Hagino 	}
1562d6af58f5SWarner Losh 	n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
156373b30f0cSJun-ichiro itojun Hagino 	if ((n < 0) || !(*name_ok)(bp)) {
156473b30f0cSJun-ichiro itojun Hagino 		*errp = NO_RECOVERY;
156573b30f0cSJun-ichiro itojun Hagino 		return (NULL);
156673b30f0cSJun-ichiro itojun Hagino 	}
156773b30f0cSJun-ichiro itojun Hagino 	BOUNDED_INCR(n + QFIXEDSZ);
156873b30f0cSJun-ichiro itojun Hagino 	if (qtype == T_A || qtype == T_AAAA) {
156973b30f0cSJun-ichiro itojun Hagino 		/* res_send() has already verified that the query name is the
157073b30f0cSJun-ichiro itojun Hagino 		 * same as the one we sent; this just gets the expanded name
157173b30f0cSJun-ichiro itojun Hagino 		 * (i.e., with the succeeding search-domain tacked on).
157273b30f0cSJun-ichiro itojun Hagino 		 */
157373b30f0cSJun-ichiro itojun Hagino 		n = strlen(bp) + 1;		/* for the \0 */
157473b30f0cSJun-ichiro itojun Hagino 		if (n >= MAXHOSTNAMELEN) {
157573b30f0cSJun-ichiro itojun Hagino 			*errp = NO_RECOVERY;
157673b30f0cSJun-ichiro itojun Hagino 			return (NULL);
157773b30f0cSJun-ichiro itojun Hagino 		}
157873b30f0cSJun-ichiro itojun Hagino 		template->h_name = bp;
157973b30f0cSJun-ichiro itojun Hagino 		bp += n;
158073b30f0cSJun-ichiro itojun Hagino 		/* The qname can be abbreviated, but h_name is now absolute. */
158173b30f0cSJun-ichiro itojun Hagino 		qname = template->h_name;
158273b30f0cSJun-ichiro itojun Hagino 	}
158373b30f0cSJun-ichiro itojun Hagino 	ap = host_aliases;
158473b30f0cSJun-ichiro itojun Hagino 	*ap = NULL;
158573b30f0cSJun-ichiro itojun Hagino 	template->h_aliases = host_aliases;
158673b30f0cSJun-ichiro itojun Hagino 	hap = h_addr_ptrs;
158773b30f0cSJun-ichiro itojun Hagino 	*hap = NULL;
158873b30f0cSJun-ichiro itojun Hagino 	template->h_addr_list = h_addr_ptrs;
158973b30f0cSJun-ichiro itojun Hagino 	haveanswer = 0;
159073b30f0cSJun-ichiro itojun Hagino 	had_error = 0;
159173b30f0cSJun-ichiro itojun Hagino 	while (ancount-- > 0 && cp < eom && !had_error) {
1592d6af58f5SWarner Losh 		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
159373b30f0cSJun-ichiro itojun Hagino 		DNS_FATAL(n >= 0);
159473b30f0cSJun-ichiro itojun Hagino 		DNS_FATAL((*name_ok)(bp));
159573b30f0cSJun-ichiro itojun Hagino 		cp += n;			/* name */
159673b30f0cSJun-ichiro itojun Hagino 		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
159773b30f0cSJun-ichiro itojun Hagino 		type = _getshort(cp);
159873b30f0cSJun-ichiro itojun Hagino  		cp += INT16SZ;			/* type */
159973b30f0cSJun-ichiro itojun Hagino 		class = _getshort(cp);
160073b30f0cSJun-ichiro itojun Hagino  		cp += INT16SZ + INT32SZ;	/* class, TTL */
160173b30f0cSJun-ichiro itojun Hagino 		n = _getshort(cp);
160273b30f0cSJun-ichiro itojun Hagino 		cp += INT16SZ;			/* len */
160373b30f0cSJun-ichiro itojun Hagino 		BOUNDS_CHECK(cp, n);
160473b30f0cSJun-ichiro itojun Hagino 		erdata = cp + n;
160573b30f0cSJun-ichiro itojun Hagino 		DNS_ASSERT(class == C_IN);
160673b30f0cSJun-ichiro itojun Hagino 		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
160773b30f0cSJun-ichiro itojun Hagino 			if (ap >= &host_aliases[MAXALIASES-1])
160873b30f0cSJun-ichiro itojun Hagino 				continue;
160973b30f0cSJun-ichiro itojun Hagino 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
161073b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n >= 0);
161173b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL((*name_ok)(tbuf));
16127d56d374SYoshinobu Inoue 			cp += n;
161373b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
161473b30f0cSJun-ichiro itojun Hagino 				*errp = NO_RECOVERY;
161573b30f0cSJun-ichiro itojun Hagino 				return (NULL);
161673b30f0cSJun-ichiro itojun Hagino 			}
161773b30f0cSJun-ichiro itojun Hagino 			/* Store alias. */
161873b30f0cSJun-ichiro itojun Hagino 			*ap++ = bp;
161973b30f0cSJun-ichiro itojun Hagino 			n = strlen(bp) + 1;	/* for the \0 */
162073b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n < MAXHOSTNAMELEN);
162173b30f0cSJun-ichiro itojun Hagino 			bp += n;
162273b30f0cSJun-ichiro itojun Hagino 			/* Get canonical name. */
162373b30f0cSJun-ichiro itojun Hagino 			n = strlen(tbuf) + 1;	/* for the \0 */
1624d6af58f5SWarner Losh 			DNS_FATAL(n <= ep - bp);
162573b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n < MAXHOSTNAMELEN);
162673b30f0cSJun-ichiro itojun Hagino 			strcpy(bp, tbuf);
162773b30f0cSJun-ichiro itojun Hagino 			template->h_name = bp;
162873b30f0cSJun-ichiro itojun Hagino 			bp += n;
162973b30f0cSJun-ichiro itojun Hagino 			continue;
163073b30f0cSJun-ichiro itojun Hagino 		}
163173b30f0cSJun-ichiro itojun Hagino 		if (qtype == T_PTR && type == T_CNAME) {
163273b30f0cSJun-ichiro itojun Hagino 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
163373b30f0cSJun-ichiro itojun Hagino 			if (n < 0 || !res_dnok(tbuf)) {
163473b30f0cSJun-ichiro itojun Hagino 				had_error++;
163573b30f0cSJun-ichiro itojun Hagino 				continue;
163673b30f0cSJun-ichiro itojun Hagino 			}
163773b30f0cSJun-ichiro itojun Hagino 			cp += n;
163873b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
163973b30f0cSJun-ichiro itojun Hagino 				*errp = NO_RECOVERY;
164073b30f0cSJun-ichiro itojun Hagino 				return (NULL);
164173b30f0cSJun-ichiro itojun Hagino 			}
164273b30f0cSJun-ichiro itojun Hagino 			/* Get canonical name. */
164373b30f0cSJun-ichiro itojun Hagino 			n = strlen(tbuf) + 1;	/* for the \0 */
1644d6af58f5SWarner Losh 			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
164573b30f0cSJun-ichiro itojun Hagino 				had_error++;
164673b30f0cSJun-ichiro itojun Hagino 				continue;
164773b30f0cSJun-ichiro itojun Hagino 			}
164873b30f0cSJun-ichiro itojun Hagino 			strcpy(bp, tbuf);
16493f587e57SKris Kennaway 			tname = bp;
165073b30f0cSJun-ichiro itojun Hagino 			bp += n;
165173b30f0cSJun-ichiro itojun Hagino 			continue;
165273b30f0cSJun-ichiro itojun Hagino 		}
165373b30f0cSJun-ichiro itojun Hagino 		DNS_ASSERT(type == qtype);
165473b30f0cSJun-ichiro itojun Hagino 		switch (type) {
165573b30f0cSJun-ichiro itojun Hagino 		case T_PTR:
165673b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(strcasecmp(tname, bp) == 0);
1657d6af58f5SWarner Losh 			n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
165873b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n >= 0);
165973b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(res_hnok(bp));
166073b30f0cSJun-ichiro itojun Hagino #if MULTI_PTRS_ARE_ALIASES
166173b30f0cSJun-ichiro itojun Hagino 			cp += n;
166273b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
166373b30f0cSJun-ichiro itojun Hagino 				*errp = NO_RECOVERY;
166473b30f0cSJun-ichiro itojun Hagino 				return (NULL);
166573b30f0cSJun-ichiro itojun Hagino 			}
166673b30f0cSJun-ichiro itojun Hagino 			if (!haveanswer)
166773b30f0cSJun-ichiro itojun Hagino 				template->h_name = bp;
166873b30f0cSJun-ichiro itojun Hagino 			else if (ap < &host_aliases[MAXALIASES-1])
166973b30f0cSJun-ichiro itojun Hagino 				*ap++ = bp;
167073b30f0cSJun-ichiro itojun Hagino 			else
167173b30f0cSJun-ichiro itojun Hagino 				n = -1;
167273b30f0cSJun-ichiro itojun Hagino 			if (n != -1) {
167373b30f0cSJun-ichiro itojun Hagino 				n = strlen(bp) + 1;	/* for the \0 */
167473b30f0cSJun-ichiro itojun Hagino 				if (n >= MAXHOSTNAMELEN) {
167573b30f0cSJun-ichiro itojun Hagino 					had_error++;
16767d56d374SYoshinobu Inoue 					break;
16777d56d374SYoshinobu Inoue 				}
167873b30f0cSJun-ichiro itojun Hagino 				bp += n;
16797d56d374SYoshinobu Inoue 			}
168073b30f0cSJun-ichiro itojun Hagino 			break;
168173b30f0cSJun-ichiro itojun Hagino #else
168273b30f0cSJun-ichiro itojun Hagino 			template->h_name = bp;
168373b30f0cSJun-ichiro itojun Hagino 			*errp = NETDB_SUCCESS;
168473b30f0cSJun-ichiro itojun Hagino 			return (template);
168573b30f0cSJun-ichiro itojun Hagino #endif
168673b30f0cSJun-ichiro itojun Hagino 		case T_A:
168773b30f0cSJun-ichiro itojun Hagino 		case T_AAAA:
168873b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(strcasecmp(template->h_name, bp) == 0);
168973b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(n == template->h_length);
169073b30f0cSJun-ichiro itojun Hagino 			if (!haveanswer) {
16918fb3f3f6SDavid E. O'Brien 				int nn;
169273b30f0cSJun-ichiro itojun Hagino 
169373b30f0cSJun-ichiro itojun Hagino 				template->h_name = bp;
169473b30f0cSJun-ichiro itojun Hagino 				nn = strlen(bp) + 1;	/* for the \0 */
169573b30f0cSJun-ichiro itojun Hagino 				bp += nn;
169673b30f0cSJun-ichiro itojun Hagino 			}
169773b30f0cSJun-ichiro itojun Hagino 			bp = (char *)ALIGN(bp);
169873b30f0cSJun-ichiro itojun Hagino 
1699d6af58f5SWarner Losh 			DNS_FATAL(bp + n < ep);
170073b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(hap < &h_addr_ptrs[MAXADDRS-1]);
170173b30f0cSJun-ichiro itojun Hagino #ifdef FILTER_V4MAPPED
170273b30f0cSJun-ichiro itojun Hagino 			if (type == T_AAAA) {
170373b30f0cSJun-ichiro itojun Hagino 				struct in6_addr in6;
170473b30f0cSJun-ichiro itojun Hagino 				memcpy(&in6, cp, sizeof(in6));
170573b30f0cSJun-ichiro itojun Hagino 				DNS_ASSERT(IN6_IS_ADDR_V4MAPPED(&in6) == 0);
170673b30f0cSJun-ichiro itojun Hagino 			}
170773b30f0cSJun-ichiro itojun Hagino #endif
170873b30f0cSJun-ichiro itojun Hagino 			bcopy(cp, *hap++ = bp, n);
170973b30f0cSJun-ichiro itojun Hagino 			bp += n;
171073b30f0cSJun-ichiro itojun Hagino 			cp += n;
171173b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
17127d56d374SYoshinobu Inoue 				*errp = NO_RECOVERY;
171373b30f0cSJun-ichiro itojun Hagino 				return (NULL);
17147d56d374SYoshinobu Inoue 			}
171573b30f0cSJun-ichiro itojun Hagino 			break;
171673b30f0cSJun-ichiro itojun Hagino 		default:
171773b30f0cSJun-ichiro itojun Hagino 			abort();
171873b30f0cSJun-ichiro itojun Hagino 		}
171973b30f0cSJun-ichiro itojun Hagino 		if (!had_error)
172073b30f0cSJun-ichiro itojun Hagino 			haveanswer++;
172173b30f0cSJun-ichiro itojun Hagino 	}
172273b30f0cSJun-ichiro itojun Hagino 	if (haveanswer) {
172373b30f0cSJun-ichiro itojun Hagino 		*ap = NULL;
172473b30f0cSJun-ichiro itojun Hagino 		*hap = NULL;
172573b30f0cSJun-ichiro itojun Hagino 		if (!template->h_name) {
172673b30f0cSJun-ichiro itojun Hagino 			n = strlen(qname) + 1;	/* for the \0 */
1727d6af58f5SWarner Losh 			if (n > ep - bp || n >= MAXHOSTNAMELEN)
172873b30f0cSJun-ichiro itojun Hagino 				goto no_recovery;
172973b30f0cSJun-ichiro itojun Hagino 			strcpy(bp, qname);
173073b30f0cSJun-ichiro itojun Hagino 			template->h_name = bp;
173173b30f0cSJun-ichiro itojun Hagino 			bp += n;
173273b30f0cSJun-ichiro itojun Hagino 		}
173373b30f0cSJun-ichiro itojun Hagino 		*errp = NETDB_SUCCESS;
173473b30f0cSJun-ichiro itojun Hagino 		return (template);
173573b30f0cSJun-ichiro itojun Hagino 	}
173673b30f0cSJun-ichiro itojun Hagino  no_recovery:
173773b30f0cSJun-ichiro itojun Hagino 	*errp = NO_RECOVERY;
173873b30f0cSJun-ichiro itojun Hagino 	return (NULL);
173973b30f0cSJun-ichiro itojun Hagino 
174073b30f0cSJun-ichiro itojun Hagino #undef BOUNDED_INCR
174173b30f0cSJun-ichiro itojun Hagino #undef BOUNDS_CHECK
174273b30f0cSJun-ichiro itojun Hagino #undef DNS_ASSERT
174373b30f0cSJun-ichiro itojun Hagino #undef DNS_FATAL
17447d56d374SYoshinobu Inoue }
17457d56d374SYoshinobu Inoue 
1746248aee62SJacques Vidrine static int
1747248aee62SJacques Vidrine _dns_ghbyname(void *rval, void *cb_data, va_list ap)
1748e6f35403SYoshinobu Inoue {
1749248aee62SJacques Vidrine 	const char *name;
1750248aee62SJacques Vidrine 	int af;
1751248aee62SJacques Vidrine 	int *errp;
17520fbf0979SHajimu UMEMOTO 	int n;
17530fbf0979SHajimu UMEMOTO 	struct hostent *hp;
17540fbf0979SHajimu UMEMOTO 	int qtype;
17550fbf0979SHajimu UMEMOTO 	struct hostent hbuf;
17560fbf0979SHajimu UMEMOTO 	querybuf *buf;
1757e6f35403SYoshinobu Inoue 
1758248aee62SJacques Vidrine 	name = va_arg(ap, const char *);
1759248aee62SJacques Vidrine 	af = va_arg(ap, int);
1760248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
1761248aee62SJacques Vidrine 
17620fbf0979SHajimu UMEMOTO 	if ((_res.options & RES_INIT) == 0) {
17630fbf0979SHajimu UMEMOTO 		if (res_init() < 0) {
17640fbf0979SHajimu UMEMOTO 			*errp = h_errno;
17650fbf0979SHajimu UMEMOTO 			return NS_UNAVAIL;
1766e6f35403SYoshinobu Inoue 		}
17670fbf0979SHajimu UMEMOTO 	}
17680fbf0979SHajimu UMEMOTO 	memset(&hbuf, 0, sizeof(hbuf));
17690fbf0979SHajimu UMEMOTO 	hbuf.h_addrtype = af;
17700fbf0979SHajimu UMEMOTO 	hbuf.h_length = ADDRLEN(af);
17710fbf0979SHajimu UMEMOTO 
17720fbf0979SHajimu UMEMOTO 	switch (af) {
17730fbf0979SHajimu UMEMOTO #ifdef INET6
17740fbf0979SHajimu UMEMOTO 	case AF_INET6:
17750fbf0979SHajimu UMEMOTO 		qtype = T_AAAA;
17760fbf0979SHajimu UMEMOTO 		break;
1777e6f35403SYoshinobu Inoue #endif
17780fbf0979SHajimu UMEMOTO 	case AF_INET:
17790fbf0979SHajimu UMEMOTO 		qtype = T_A;
17800fbf0979SHajimu UMEMOTO 		break;
17810fbf0979SHajimu UMEMOTO 	default:
17820fbf0979SHajimu UMEMOTO 		*errp = NO_RECOVERY;
17830fbf0979SHajimu UMEMOTO 		return NS_NOTFOUND;
17840fbf0979SHajimu UMEMOTO 	}
17850fbf0979SHajimu UMEMOTO 	buf = malloc(sizeof(*buf));
17860fbf0979SHajimu UMEMOTO 	if (buf == NULL) {
17870fbf0979SHajimu UMEMOTO 		*errp = NETDB_INTERNAL;
17880fbf0979SHajimu UMEMOTO 		return NS_UNAVAIL;
17890fbf0979SHajimu UMEMOTO 	}
17900fbf0979SHajimu UMEMOTO 	n = res_search(name, C_IN, qtype, buf->buf, sizeof(buf->buf));
17910fbf0979SHajimu UMEMOTO 	if (n < 0) {
17920fbf0979SHajimu UMEMOTO 		free(buf);
17930fbf0979SHajimu UMEMOTO 		*errp = h_errno;
17940fbf0979SHajimu UMEMOTO 		return NS_UNAVAIL;
17950fbf0979SHajimu UMEMOTO 	}
17960fbf0979SHajimu UMEMOTO 	hp = getanswer(buf, n, name, qtype, &hbuf, errp);
17970fbf0979SHajimu UMEMOTO 	free(buf);
17980fbf0979SHajimu UMEMOTO 	if (!hp) {
17990fbf0979SHajimu UMEMOTO 		*errp = NO_RECOVERY;
18000fbf0979SHajimu UMEMOTO 		return NS_NOTFOUND;
18010fbf0979SHajimu UMEMOTO 	}
18020fbf0979SHajimu UMEMOTO 	*(struct hostent **)rval = _hpcopy(&hbuf, errp);
1803e651d83aSPierre Beyssac 	if (*(struct hostent **)rval != NULL)
1804e651d83aSPierre Beyssac 		return NS_SUCCESS;
1805e651d83aSPierre Beyssac 	else if (*errp == TRY_AGAIN)
1806e651d83aSPierre Beyssac 		return NS_TRYAGAIN;
1807e651d83aSPierre Beyssac 	else
1808e651d83aSPierre Beyssac 		return NS_NOTFOUND;
1809e6f35403SYoshinobu Inoue }
1810e6f35403SYoshinobu Inoue 
1811248aee62SJacques Vidrine static int
1812248aee62SJacques Vidrine _dns_ghbyaddr(void *rval, void *cb_data, va_list ap)
18137d56d374SYoshinobu Inoue {
1814248aee62SJacques Vidrine 	const void *addr;
1815248aee62SJacques Vidrine 	int addrlen;
1816248aee62SJacques Vidrine 	int af;
1817248aee62SJacques Vidrine 	int *errp;
18187d56d374SYoshinobu Inoue 	int n;
1819aadad922SHajimu UMEMOTO 	int err;
182073b30f0cSJun-ichiro itojun Hagino 	struct hostent *hp;
182173b30f0cSJun-ichiro itojun Hagino 	u_char c, *cp;
18227d56d374SYoshinobu Inoue 	char *bp;
18237d56d374SYoshinobu Inoue 	struct hostent hbuf;
18247d56d374SYoshinobu Inoue 	int na;
18257d56d374SYoshinobu Inoue #ifdef INET6
18267d56d374SYoshinobu Inoue 	static const char hex[] = "0123456789abcdef";
18277d56d374SYoshinobu Inoue #endif
18289832619cSHajimu UMEMOTO 	querybuf *buf;
182973b30f0cSJun-ichiro itojun Hagino 	char qbuf[MAXDNAME+1];
183073b30f0cSJun-ichiro itojun Hagino 	char *hlist[2];
18310def575fSHajimu UMEMOTO 	char *tld6[] = { "ip6.arpa", NULL };
1832aadad922SHajimu UMEMOTO 	char *tld4[] = { "in-addr.arpa", NULL };
1833aadad922SHajimu UMEMOTO 	char **tld;
18347d56d374SYoshinobu Inoue 
1835248aee62SJacques Vidrine 	addr = va_arg(ap, const void *);
1836248aee62SJacques Vidrine 	addrlen = va_arg(ap, int);
1837248aee62SJacques Vidrine 	af = va_arg(ap, int);
1838248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
1839248aee62SJacques Vidrine 
1840248aee62SJacques Vidrine 	*(struct hostent **)rval = NULL;
1841248aee62SJacques Vidrine 
18427d56d374SYoshinobu Inoue #ifdef INET6
18437d56d374SYoshinobu Inoue 	/* XXX */
18447d56d374SYoshinobu Inoue 	if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
1845248aee62SJacques Vidrine 		return NS_NOTFOUND;
18467d56d374SYoshinobu Inoue #endif
18477d56d374SYoshinobu Inoue 
1848aadad922SHajimu UMEMOTO 	switch (af) {
1849aadad922SHajimu UMEMOTO #ifdef INET6
1850aadad922SHajimu UMEMOTO 	case AF_INET6:
1851aadad922SHajimu UMEMOTO 		tld = tld6;
1852aadad922SHajimu UMEMOTO 		break;
1853aadad922SHajimu UMEMOTO #endif
1854aadad922SHajimu UMEMOTO 	case AF_INET:
1855aadad922SHajimu UMEMOTO 		tld = tld4;
1856aadad922SHajimu UMEMOTO 		break;
1857aadad922SHajimu UMEMOTO 	default:
1858aadad922SHajimu UMEMOTO 		return NS_NOTFOUND;
1859aadad922SHajimu UMEMOTO 	}
1860aadad922SHajimu UMEMOTO 
18617d56d374SYoshinobu Inoue 	if ((_res.options & RES_INIT) == 0) {
18627d56d374SYoshinobu Inoue 		if (res_init() < 0) {
18637d56d374SYoshinobu Inoue 			*errp = h_errno;
1864248aee62SJacques Vidrine 			return NS_UNAVAIL;
18657d56d374SYoshinobu Inoue 		}
18667d56d374SYoshinobu Inoue 	}
186773b30f0cSJun-ichiro itojun Hagino 	memset(&hbuf, 0, sizeof(hbuf));
18687d56d374SYoshinobu Inoue 	hbuf.h_name = NULL;
18697d56d374SYoshinobu Inoue 	hbuf.h_addrtype = af;
18707d56d374SYoshinobu Inoue 	hbuf.h_length = addrlen;
18717d56d374SYoshinobu Inoue 	na = 0;
18727d56d374SYoshinobu Inoue 
1873aadad922SHajimu UMEMOTO 	buf = malloc(sizeof(*buf));
1874aadad922SHajimu UMEMOTO 	if (buf == NULL) {
1875aadad922SHajimu UMEMOTO 		*errp = NETDB_INTERNAL;
1876aadad922SHajimu UMEMOTO 		return NS_UNAVAIL;
1877aadad922SHajimu UMEMOTO 	}
1878aadad922SHajimu UMEMOTO 	err = NS_SUCCESS;
1879aadad922SHajimu UMEMOTO 	for (/* nothing */; *tld; tld++) {
1880aadad922SHajimu UMEMOTO 		/*
1881aadad922SHajimu UMEMOTO 		 * XXX assumes that MAXDNAME is big enough - error checks
1882aadad922SHajimu UMEMOTO 		 * has been made by callers
1883aadad922SHajimu UMEMOTO 		 */
18847d56d374SYoshinobu Inoue 		n = 0;
188573b30f0cSJun-ichiro itojun Hagino 		bp = qbuf;
18867d56d374SYoshinobu Inoue 		cp = (u_char *)addr+addrlen-1;
18877d56d374SYoshinobu Inoue 		switch (af) {
18887d56d374SYoshinobu Inoue #ifdef INET6
18897d56d374SYoshinobu Inoue 		case AF_INET6:
18907d56d374SYoshinobu Inoue 			for (; n < addrlen; n++, cp--) {
18917d56d374SYoshinobu Inoue 				c = *cp;
18927d56d374SYoshinobu Inoue 				*bp++ = hex[c & 0xf];
18937d56d374SYoshinobu Inoue 				*bp++ = '.';
18947d56d374SYoshinobu Inoue 				*bp++ = hex[c >> 4];
18957d56d374SYoshinobu Inoue 				*bp++ = '.';
18967d56d374SYoshinobu Inoue 			}
1897aadad922SHajimu UMEMOTO 			strcpy(bp, *tld);
18987d56d374SYoshinobu Inoue 			break;
18997d56d374SYoshinobu Inoue #endif
1900aadad922SHajimu UMEMOTO 		case AF_INET:
19017d56d374SYoshinobu Inoue 			for (; n < addrlen; n++, cp--) {
19027d56d374SYoshinobu Inoue 				c = *cp;
19037d56d374SYoshinobu Inoue 				if (c >= 100)
19047d56d374SYoshinobu Inoue 					*bp++ = '0' + c / 100;
19057d56d374SYoshinobu Inoue 				if (c >= 10)
19067d56d374SYoshinobu Inoue 					*bp++ = '0' + (c % 100) / 10;
19077d56d374SYoshinobu Inoue 				*bp++ = '0' + c % 10;
19087d56d374SYoshinobu Inoue 				*bp++ = '.';
19097d56d374SYoshinobu Inoue 			}
1910aadad922SHajimu UMEMOTO 			strcpy(bp, *tld);
19117d56d374SYoshinobu Inoue 			break;
19127d56d374SYoshinobu Inoue 		}
19137d56d374SYoshinobu Inoue 
19149832619cSHajimu UMEMOTO 		n = res_query(qbuf, C_IN, T_PTR, buf->buf, sizeof buf->buf);
19157d56d374SYoshinobu Inoue 		if (n < 0) {
19167d56d374SYoshinobu Inoue 			*errp = h_errno;
1917aadad922SHajimu UMEMOTO 			err = NS_UNAVAIL;
1918aadad922SHajimu UMEMOTO 			continue;
19199832619cSHajimu UMEMOTO 		} else if (n > sizeof(buf->buf)) {
192054384cf3SJacques Vidrine #if 0
192154384cf3SJacques Vidrine 			errno = ERANGE; /* XXX is it OK to set errno here? */
192254384cf3SJacques Vidrine #endif
192354384cf3SJacques Vidrine 			*errp = NETDB_INTERNAL;
1924aadad922SHajimu UMEMOTO 			err = NS_UNAVAIL;
1925aadad922SHajimu UMEMOTO 			continue;
19267d56d374SYoshinobu Inoue 		}
19279832619cSHajimu UMEMOTO 		hp = getanswer(buf, n, qbuf, T_PTR, &hbuf, errp);
1928aadad922SHajimu UMEMOTO 		if (!hp) {
1929aadad922SHajimu UMEMOTO 			err = NS_NOTFOUND;
1930aadad922SHajimu UMEMOTO 			continue;
1931aadad922SHajimu UMEMOTO 		}
19329832619cSHajimu UMEMOTO 		free(buf);
193373b30f0cSJun-ichiro itojun Hagino 		hbuf.h_addrtype = af;
193473b30f0cSJun-ichiro itojun Hagino 		hbuf.h_length = addrlen;
193573b30f0cSJun-ichiro itojun Hagino 		hbuf.h_addr_list = hlist;
193673b30f0cSJun-ichiro itojun Hagino 		hlist[0] = (char *)addr;
193773b30f0cSJun-ichiro itojun Hagino 		hlist[1] = NULL;
1938248aee62SJacques Vidrine 		*(struct hostent **)rval = _hpcopy(&hbuf, errp);
1939248aee62SJacques Vidrine 		return NS_SUCCESS;
19407d56d374SYoshinobu Inoue 	}
1941aadad922SHajimu UMEMOTO 	free(buf);
1942aadad922SHajimu UMEMOTO 	return err;
1943aadad922SHajimu UMEMOTO }
19447d56d374SYoshinobu Inoue 
194573b30f0cSJun-ichiro itojun Hagino static void
194673b30f0cSJun-ichiro itojun Hagino _dns_shent(int stayopen)
194773b30f0cSJun-ichiro itojun Hagino {
194873b30f0cSJun-ichiro itojun Hagino 	if ((_res.options & RES_INIT) == 0) {
194973b30f0cSJun-ichiro itojun Hagino 		if (res_init() < 0)
195073b30f0cSJun-ichiro itojun Hagino 			return;
195173b30f0cSJun-ichiro itojun Hagino 	}
195273b30f0cSJun-ichiro itojun Hagino 	if (stayopen)
195373b30f0cSJun-ichiro itojun Hagino 		_res.options |= RES_STAYOPEN | RES_USEVC;
195473b30f0cSJun-ichiro itojun Hagino }
195573b30f0cSJun-ichiro itojun Hagino 
195673b30f0cSJun-ichiro itojun Hagino static void
195773b30f0cSJun-ichiro itojun Hagino _dns_ehent(void)
195873b30f0cSJun-ichiro itojun Hagino {
195973b30f0cSJun-ichiro itojun Hagino 	_res.options &= ~(RES_STAYOPEN | RES_USEVC);
196073b30f0cSJun-ichiro itojun Hagino 	res_close();
196173b30f0cSJun-ichiro itojun Hagino }
196273b30f0cSJun-ichiro itojun Hagino 
19637d56d374SYoshinobu Inoue #ifdef ICMPNL
19647d56d374SYoshinobu Inoue 
19657d56d374SYoshinobu Inoue /*
19667d56d374SYoshinobu Inoue  * experimental:
19677d56d374SYoshinobu Inoue  *	draft-ietf-ipngwg-icmp-namelookups-02.txt
19687d56d374SYoshinobu Inoue  *	ifindex is assumed to be encoded in addr.
19697d56d374SYoshinobu Inoue  */
19707d56d374SYoshinobu Inoue #include <sys/uio.h>
19717d56d374SYoshinobu Inoue #include <netinet/ip6.h>
19727d56d374SYoshinobu Inoue #include <netinet/icmp6.h>
19737d56d374SYoshinobu Inoue 
19747d56d374SYoshinobu Inoue struct _icmp_host_cache {
19757d56d374SYoshinobu Inoue 	struct _icmp_host_cache *hc_next;
19767d56d374SYoshinobu Inoue 	int hc_ifindex;
19777d56d374SYoshinobu Inoue 	struct in6_addr hc_addr;
19787d56d374SYoshinobu Inoue 	char *hc_name;
19797d56d374SYoshinobu Inoue };
19807d56d374SYoshinobu Inoue 
19817d56d374SYoshinobu Inoue static char *
19827d56d374SYoshinobu Inoue _icmp_fqdn_query(const struct in6_addr *addr, int ifindex)
19837d56d374SYoshinobu Inoue {
19847d56d374SYoshinobu Inoue 	int s;
19857d56d374SYoshinobu Inoue 	struct icmp6_filter filter;
19867d56d374SYoshinobu Inoue 	struct msghdr msg;
19877d56d374SYoshinobu Inoue 	struct cmsghdr *cmsg;
19887d56d374SYoshinobu Inoue 	struct in6_pktinfo *pkt;
19897d56d374SYoshinobu Inoue 	char cbuf[256];
19907d56d374SYoshinobu Inoue 	char buf[1024];
19917d56d374SYoshinobu Inoue 	int cc;
19927d56d374SYoshinobu Inoue 	struct icmp6_fqdn_query *fq;
19937d56d374SYoshinobu Inoue 	struct icmp6_fqdn_reply *fr;
19947d56d374SYoshinobu Inoue 	struct _icmp_host_cache *hc;
19957d56d374SYoshinobu Inoue 	struct sockaddr_in6 sin6;
19967d56d374SYoshinobu Inoue 	struct iovec iov;
19977d56d374SYoshinobu Inoue 	fd_set s_fds, fds;
19987d56d374SYoshinobu Inoue 	struct timeval tout;
19997d56d374SYoshinobu Inoue 	int len;
20007d56d374SYoshinobu Inoue 	char *name;
20017d56d374SYoshinobu Inoue 	static struct _icmp_host_cache *hc_head;
20027d56d374SYoshinobu Inoue 
200333dee819SBrian Feldman 	THREAD_LOCK();
20047d56d374SYoshinobu Inoue 	for (hc = hc_head; hc; hc = hc->hc_next) {
20057d56d374SYoshinobu Inoue 		if (hc->hc_ifindex == ifindex
200633dee819SBrian Feldman 		&&  IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr)) {
200733dee819SBrian Feldman 			THREAD_UNLOCK();
200833dee819SBrian Feldman 			return hc->hc_name;	/* XXX: never freed */
20097d56d374SYoshinobu Inoue 		}
201033dee819SBrian Feldman 	}
20117d56d374SYoshinobu Inoue 
20127d56d374SYoshinobu Inoue 	ICMP6_FILTER_SETBLOCKALL(&filter);
20137d56d374SYoshinobu Inoue 	ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter);
20147d56d374SYoshinobu Inoue 
20157d56d374SYoshinobu Inoue 	FD_ZERO(&s_fds);
20167d56d374SYoshinobu Inoue 	tout.tv_sec = 0;
20177d56d374SYoshinobu Inoue 	tout.tv_usec = 200000;	/*XXX: 200ms*/
20187d56d374SYoshinobu Inoue 
20197d56d374SYoshinobu Inoue 	fq = (struct icmp6_fqdn_query *)buf;
20207d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY;
20217d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_code = 0;
20227d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_cksum = 0;
202333dee819SBrian Feldman 	fq->icmp6_fqdn_id = (u_short)getpid();
20247d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_unused = 0;
20257d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_cookie[0] = 0;
20267d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_cookie[1] = 0;
20277d56d374SYoshinobu Inoue 
20287d56d374SYoshinobu Inoue 	memset(&sin6, 0, sizeof(sin6));
20297d56d374SYoshinobu Inoue 	sin6.sin6_family = AF_INET6;
20307d56d374SYoshinobu Inoue 	sin6.sin6_addr = *addr;
20317d56d374SYoshinobu Inoue 
20327d56d374SYoshinobu Inoue 	memset(&msg, 0, sizeof(msg));
20337d56d374SYoshinobu Inoue 	msg.msg_name = (caddr_t)&sin6;
20347d56d374SYoshinobu Inoue 	msg.msg_namelen = sizeof(sin6);
20357d56d374SYoshinobu Inoue 	msg.msg_iov = &iov;
20367d56d374SYoshinobu Inoue 	msg.msg_iovlen = 1;
20377d56d374SYoshinobu Inoue 	msg.msg_control = NULL;
20387d56d374SYoshinobu Inoue 	msg.msg_controllen = 0;
20397d56d374SYoshinobu Inoue 	iov.iov_base = (caddr_t)buf;
20407d56d374SYoshinobu Inoue 	iov.iov_len = sizeof(struct icmp6_fqdn_query);
20417d56d374SYoshinobu Inoue 
20427d56d374SYoshinobu Inoue 	if (ifindex) {
20437d56d374SYoshinobu Inoue 		msg.msg_control = cbuf;
20447d56d374SYoshinobu Inoue 		msg.msg_controllen = sizeof(cbuf);
20457d56d374SYoshinobu Inoue 		cmsg = CMSG_FIRSTHDR(&msg);
20467d56d374SYoshinobu Inoue 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
20477d56d374SYoshinobu Inoue 		cmsg->cmsg_level = IPPROTO_IPV6;
20487d56d374SYoshinobu Inoue 		cmsg->cmsg_type = IPV6_PKTINFO;
20497d56d374SYoshinobu Inoue 		pkt = (struct in6_pktinfo *)&cmsg[1];
20507d56d374SYoshinobu Inoue 		memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
20517d56d374SYoshinobu Inoue 		pkt->ipi6_ifindex = ifindex;
20527d56d374SYoshinobu Inoue 		cmsg = CMSG_NXTHDR(&msg, cmsg);
20537d56d374SYoshinobu Inoue 		msg.msg_controllen = (char *)cmsg - cbuf;
20547d56d374SYoshinobu Inoue 	}
20557d56d374SYoshinobu Inoue 
2056d201fe46SDaniel Eischen 	if ((s = _socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
20577d56d374SYoshinobu Inoue 		return NULL;
2058d201fe46SDaniel Eischen 	(void)_setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
20597d56d374SYoshinobu Inoue 			 (char *)&filter, sizeof(filter));
2060d201fe46SDaniel Eischen 	cc = _sendmsg(s, &msg, 0);
20617d56d374SYoshinobu Inoue 	if (cc < 0) {
20629233c4d9SJason Evans 		_close(s);
20637d56d374SYoshinobu Inoue 		return NULL;
20647d56d374SYoshinobu Inoue 	}
20657d56d374SYoshinobu Inoue 	FD_SET(s, &s_fds);
20667d56d374SYoshinobu Inoue 	for (;;) {
20677d56d374SYoshinobu Inoue 		fds = s_fds;
2068d201fe46SDaniel Eischen 		if (_select(s + 1, &fds, NULL, NULL, &tout) <= 0) {
20699233c4d9SJason Evans 			_close(s);
20707d56d374SYoshinobu Inoue 			return NULL;
20717d56d374SYoshinobu Inoue 		}
20727d56d374SYoshinobu Inoue 		len = sizeof(sin6);
2073d201fe46SDaniel Eischen 		cc = _recvfrom(s, buf, sizeof(buf), 0,
20747d56d374SYoshinobu Inoue 			      (struct sockaddr *)&sin6, &len);
20757d56d374SYoshinobu Inoue 		if (cc <= 0) {
20769233c4d9SJason Evans 			_close(s);
20777d56d374SYoshinobu Inoue 			return NULL;
20787d56d374SYoshinobu Inoue 		}
20797d56d374SYoshinobu Inoue 		if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
20807d56d374SYoshinobu Inoue 			continue;
20817d56d374SYoshinobu Inoue 		if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr))
20827d56d374SYoshinobu Inoue 			continue;
20837d56d374SYoshinobu Inoue 		fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr));
20847d56d374SYoshinobu Inoue 		if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY)
20857d56d374SYoshinobu Inoue 			break;
20867d56d374SYoshinobu Inoue 	}
20879233c4d9SJason Evans 	_close(s);
20887d56d374SYoshinobu Inoue 	if (fr->icmp6_fqdn_cookie[1] != 0) {
20897d56d374SYoshinobu Inoue 		/* rfc1788 type */
20907d56d374SYoshinobu Inoue 		name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4;
20917d56d374SYoshinobu Inoue 		len = (buf + cc) - name;
20927d56d374SYoshinobu Inoue 	} else {
20937d56d374SYoshinobu Inoue 		len = fr->icmp6_fqdn_namelen;
20947d56d374SYoshinobu Inoue 		name = fr->icmp6_fqdn_name;
20957d56d374SYoshinobu Inoue 	}
20967d56d374SYoshinobu Inoue 	if (len <= 0)
20977d56d374SYoshinobu Inoue 		return NULL;
20987d56d374SYoshinobu Inoue 	name[len] = 0;
20997d56d374SYoshinobu Inoue 
21007d56d374SYoshinobu Inoue 	if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL)
21017d56d374SYoshinobu Inoue 		return NULL;
21027d56d374SYoshinobu Inoue 	/* XXX: limit number of cached entries */
21037d56d374SYoshinobu Inoue 	hc->hc_ifindex = ifindex;
21047d56d374SYoshinobu Inoue 	hc->hc_addr = *addr;
21057d56d374SYoshinobu Inoue 	hc->hc_name = strdup(name);
210633dee819SBrian Feldman 	THREAD_LOCK();
21077d56d374SYoshinobu Inoue 	hc->hc_next = hc_head;
21087d56d374SYoshinobu Inoue 	hc_head = hc;
210933dee819SBrian Feldman 	THREAD_UNLOCK();
21107d56d374SYoshinobu Inoue 	return hc->hc_name;
21117d56d374SYoshinobu Inoue }
21127d56d374SYoshinobu Inoue 
21137d56d374SYoshinobu Inoue static struct hostent *
21147d56d374SYoshinobu Inoue _icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
21157d56d374SYoshinobu Inoue {
21167d56d374SYoshinobu Inoue 	char *hname;
21177d56d374SYoshinobu Inoue 	int ifindex;
21187d56d374SYoshinobu Inoue 	struct in6_addr addr6;
21197d56d374SYoshinobu Inoue 
21207d56d374SYoshinobu Inoue 	if (af != AF_INET6) {
21217d56d374SYoshinobu Inoue 		/*
21227d56d374SYoshinobu Inoue 		 * Note: rfc1788 defines Who Are You for IPv4,
21237d56d374SYoshinobu Inoue 		 * but no one implements it.
21247d56d374SYoshinobu Inoue 		 */
21257d56d374SYoshinobu Inoue 		return NULL;
21267d56d374SYoshinobu Inoue 	}
21277d56d374SYoshinobu Inoue 
21287d56d374SYoshinobu Inoue 	memcpy(&addr6, addr, addrlen);
21297d56d374SYoshinobu Inoue 	ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
21307d56d374SYoshinobu Inoue 	addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
21317d56d374SYoshinobu Inoue 
21327d56d374SYoshinobu Inoue 	if (!IN6_IS_ADDR_LINKLOCAL(&addr6))
21337d56d374SYoshinobu Inoue 		return NULL;	/*XXX*/
21347d56d374SYoshinobu Inoue 
21357d56d374SYoshinobu Inoue 	if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL)
21367d56d374SYoshinobu Inoue 		return NULL;
21377d56d374SYoshinobu Inoue 	return _hpaddr(af, hname, &addr6, errp);
21387d56d374SYoshinobu Inoue }
21397d56d374SYoshinobu Inoue #endif /* ICMPNL */
2140