xref: /freebsd/lib/libc/net/name6.c (revision d6fd3ed8)
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 
90333fc21eSDavid E. O'Brien #include <sys/cdefs.h>
91333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$");
92333fc21eSDavid E. O'Brien 
93d201fe46SDaniel Eischen #include "namespace.h"
94b8ab0f45SHajimu UMEMOTO #ifdef ICMPNL
952424b118SHajimu UMEMOTO #include "reentrant.h"
96e8ffd816SHajimu UMEMOTO #endif
977d56d374SYoshinobu Inoue #include <sys/param.h>
987d56d374SYoshinobu Inoue #include <sys/socket.h>
997d56d374SYoshinobu Inoue #include <sys/time.h>
100e6f35403SYoshinobu Inoue #include <sys/queue.h>
1017d56d374SYoshinobu Inoue #include <netinet/in.h>
102b8b31f33SHajimu UMEMOTO #ifdef INET6
103b8b31f33SHajimu UMEMOTO #include <net/if.h>
104b8b31f33SHajimu UMEMOTO #include <net/if_var.h>
105b8b31f33SHajimu UMEMOTO #include <sys/sysctl.h>
106146cd1bcSHajimu UMEMOTO #include <sys/ioctl.h>
107b8b31f33SHajimu UMEMOTO #include <netinet6/in6_var.h>	/* XXX */
108b8b31f33SHajimu UMEMOTO #endif
1097d56d374SYoshinobu Inoue 
1107d56d374SYoshinobu Inoue #include <arpa/inet.h>
1117d56d374SYoshinobu Inoue #include <arpa/nameser.h>
1127d56d374SYoshinobu Inoue 
113e6f35403SYoshinobu Inoue #include <errno.h>
1147d56d374SYoshinobu Inoue #include <netdb.h>
1157d56d374SYoshinobu Inoue #include <resolv.h>
1167d56d374SYoshinobu Inoue #include <stdio.h>
1177d56d374SYoshinobu Inoue #include <stdlib.h>
1187d56d374SYoshinobu Inoue #include <string.h>
119248aee62SJacques Vidrine #include <stdarg.h>
120248aee62SJacques Vidrine #include <nsswitch.h>
1217d56d374SYoshinobu Inoue #include <unistd.h>
122d201fe46SDaniel Eischen #include "un-namespace.h"
123bcb131aaSHajimu UMEMOTO #include "netdb_private.h"
1247d56d374SYoshinobu Inoue 
1257d56d374SYoshinobu Inoue #ifndef _PATH_HOSTS
1267d56d374SYoshinobu Inoue #define	_PATH_HOSTS	"/etc/hosts"
1277d56d374SYoshinobu Inoue #endif
1287d56d374SYoshinobu Inoue 
1297d56d374SYoshinobu Inoue #ifndef MAXALIASES
1307d56d374SYoshinobu Inoue #define	MAXALIASES	10
1317d56d374SYoshinobu Inoue #endif
1327d56d374SYoshinobu Inoue #ifndef	MAXADDRS
1337d56d374SYoshinobu Inoue #define	MAXADDRS	20
1347d56d374SYoshinobu Inoue #endif
1357d56d374SYoshinobu Inoue #ifndef MAXDNAME
1367d56d374SYoshinobu Inoue #define	MAXDNAME	1025
1377d56d374SYoshinobu Inoue #endif
1387d56d374SYoshinobu Inoue 
1397d56d374SYoshinobu Inoue #ifdef INET6
1407d56d374SYoshinobu Inoue #define	ADDRLEN(af)	((af) == AF_INET6 ? sizeof(struct in6_addr) : \
1417d56d374SYoshinobu Inoue 					    sizeof(struct in_addr))
1427d56d374SYoshinobu Inoue #else
1437d56d374SYoshinobu Inoue #define	ADDRLEN(af)	sizeof(struct in_addr)
1447d56d374SYoshinobu Inoue #endif
1457d56d374SYoshinobu Inoue 
1467d56d374SYoshinobu Inoue #define	MAPADDR(ab, ina) \
1477d56d374SYoshinobu Inoue do {									\
1487d56d374SYoshinobu Inoue 	memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr));		\
1497d56d374SYoshinobu Inoue 	memset((ab)->map_zero, 0, sizeof((ab)->map_zero));		\
1507d56d374SYoshinobu Inoue 	memset((ab)->map_one, 0xff, sizeof((ab)->map_one));		\
1517d56d374SYoshinobu Inoue } while (0)
1527d56d374SYoshinobu Inoue #define	MAPADDRENABLED(flags) \
1537d56d374SYoshinobu Inoue 	(((flags) & AI_V4MAPPED) || \
1547d56d374SYoshinobu Inoue 	 (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled()))
1557d56d374SYoshinobu Inoue 
1567d56d374SYoshinobu Inoue union inx_addr {
1577d56d374SYoshinobu Inoue 	struct in_addr	in_addr;
1587d56d374SYoshinobu Inoue #ifdef INET6
1597d56d374SYoshinobu Inoue 	struct in6_addr	in6_addr;
1607d56d374SYoshinobu Inoue #endif
1617d56d374SYoshinobu Inoue 	struct {
1627d56d374SYoshinobu Inoue 		u_char	mau_zero[10];
1637d56d374SYoshinobu Inoue 		u_char	mau_one[2];
1647d56d374SYoshinobu Inoue 		struct in_addr mau_inaddr;
1657d56d374SYoshinobu Inoue 	}		map_addr_un;
1667d56d374SYoshinobu Inoue #define	map_zero	map_addr_un.mau_zero
1677d56d374SYoshinobu Inoue #define	map_one		map_addr_un.mau_one
1687d56d374SYoshinobu Inoue #define	map_inaddr	map_addr_un.mau_inaddr
1697d56d374SYoshinobu Inoue };
1707d56d374SYoshinobu Inoue 
171b8b31f33SHajimu UMEMOTO struct policyqueue {
172b8b31f33SHajimu UMEMOTO 	TAILQ_ENTRY(policyqueue) pc_entry;
173b8b31f33SHajimu UMEMOTO #ifdef INET6
174b8b31f33SHajimu UMEMOTO 	struct in6_addrpolicy pc_policy;
175b8b31f33SHajimu UMEMOTO #endif
176b8b31f33SHajimu UMEMOTO };
177b8b31f33SHajimu UMEMOTO TAILQ_HEAD(policyhead, policyqueue);
178b8b31f33SHajimu UMEMOTO 
179146cd1bcSHajimu UMEMOTO #define AIO_SRCFLAG_DEPRECATED	0x1
180146cd1bcSHajimu UMEMOTO 
181146cd1bcSHajimu UMEMOTO struct hp_order {
182146cd1bcSHajimu UMEMOTO 	union {
183146cd1bcSHajimu UMEMOTO 		struct sockaddr_storage aiou_ss;
184146cd1bcSHajimu UMEMOTO 		struct sockaddr aiou_sa;
185146cd1bcSHajimu UMEMOTO 	} aio_src_un;
186146cd1bcSHajimu UMEMOTO #define aio_srcsa aio_src_un.aiou_sa
187146cd1bcSHajimu UMEMOTO 	u_int32_t aio_srcflag;
188146cd1bcSHajimu UMEMOTO 	int aio_srcscope;
189146cd1bcSHajimu UMEMOTO 	int aio_dstscope;
190146cd1bcSHajimu UMEMOTO 	struct policyqueue *aio_srcpolicy;
191146cd1bcSHajimu UMEMOTO 	struct policyqueue *aio_dstpolicy;
192146cd1bcSHajimu UMEMOTO 	union {
193146cd1bcSHajimu UMEMOTO 		struct sockaddr_storage aiou_ss;
194146cd1bcSHajimu UMEMOTO 		struct sockaddr aiou_sa;
195146cd1bcSHajimu UMEMOTO 	} aio_un;
196146cd1bcSHajimu UMEMOTO #define aio_sa aio_un.aiou_sa
197146cd1bcSHajimu UMEMOTO 	int aio_matchlen;
198d6fd3ed8SHajimu UMEMOTO 	char *aio_h_addr;
199146cd1bcSHajimu UMEMOTO };
200146cd1bcSHajimu UMEMOTO 
2017d56d374SYoshinobu Inoue static struct	 hostent *_hpcopy(struct hostent *hp, int *errp);
2027d56d374SYoshinobu Inoue static struct	 hostent *_hpaddr(int af, const char *name, void *addr, int *errp);
2037d56d374SYoshinobu Inoue static struct	 hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp);
2047d56d374SYoshinobu Inoue #ifdef INET6
2057d56d374SYoshinobu Inoue static struct	 hostent *_hpmapv6(struct hostent *hp, int *errp);
2067d56d374SYoshinobu Inoue #endif
2077d56d374SYoshinobu Inoue static struct	 hostent *_hpsort(struct hostent *hp);
2087d56d374SYoshinobu Inoue static struct	 hostent *_ghbyname(const char *name, int af, int flags, int *errp);
2097d56d374SYoshinobu Inoue static char	*_hgetword(char **pp);
2107d56d374SYoshinobu Inoue static int	 _mapped_addr_enabled(void);
2117d56d374SYoshinobu Inoue 
212b8b31f33SHajimu UMEMOTO static struct	 hostent *_hpreorder(struct hostent *hp);
213b8b31f33SHajimu UMEMOTO static int	 get_addrselectpolicy(struct policyhead *);
214b8b31f33SHajimu UMEMOTO static void	 free_addrselectpolicy(struct policyhead *);
215b8b31f33SHajimu UMEMOTO static struct	 policyqueue *match_addrselectpolicy(struct sockaddr *,
216b8b31f33SHajimu UMEMOTO 	struct policyhead *);
217146cd1bcSHajimu UMEMOTO static void	 set_source(struct hp_order *, struct policyhead *);
218146cd1bcSHajimu UMEMOTO static int	 matchlen(struct sockaddr *, struct sockaddr *);
219146cd1bcSHajimu UMEMOTO static int	 comp_dst(const void *, const void *);
220146cd1bcSHajimu UMEMOTO static int	 gai_addr2scopetype(struct sockaddr *);
221b8b31f33SHajimu UMEMOTO 
2227d56d374SYoshinobu Inoue static FILE	*_files_open(int *errp);
223248aee62SJacques Vidrine static int	 _files_ghbyname(void *, void *, va_list);
224248aee62SJacques Vidrine static int	 _files_ghbyaddr(void *, void *, va_list);
225f468e837SHajimu UMEMOTO #ifdef YP
226248aee62SJacques Vidrine static int	 _nis_ghbyname(void *, void *, va_list);
227248aee62SJacques Vidrine static int	 _nis_ghbyaddr(void *, void *, va_list);
228f468e837SHajimu UMEMOTO #endif
229248aee62SJacques Vidrine static int	 _dns_ghbyname(void *, void *, va_list);
230248aee62SJacques Vidrine static int	 _dns_ghbyaddr(void *, void *, va_list);
231e0554a53SJacques Vidrine static void	 _dns_shent(int stayopen) __unused;
232e0554a53SJacques Vidrine static void	 _dns_ehent(void) __unused;
2337d56d374SYoshinobu Inoue #ifdef ICMPNL
234248aee62SJacques Vidrine static int	 _icmp_ghbyaddr(void *, void *, va_list);
2357d56d374SYoshinobu Inoue #endif /* ICMPNL */
2367d56d374SYoshinobu Inoue 
237b8ab0f45SHajimu UMEMOTO #ifdef ICMPNL
2382424b118SHajimu UMEMOTO static mutex_t _getipnodeby_thread_lock = MUTEX_INITIALIZER;
2392424b118SHajimu UMEMOTO #define THREAD_LOCK()	mutex_lock(&_getipnodeby_thread_lock);
2402424b118SHajimu UMEMOTO #define THREAD_UNLOCK()	mutex_unlock(&_getipnodeby_thread_lock);
241e8ffd816SHajimu UMEMOTO #endif
24271918af6SHajimu UMEMOTO 
243248aee62SJacques Vidrine /* Host lookup order if nsswitch.conf is broken or nonexistant */
244248aee62SJacques Vidrine static const ns_src default_src[] = {
245248aee62SJacques Vidrine 	{ NSSRC_FILES, NS_SUCCESS },
246248aee62SJacques Vidrine 	{ NSSRC_DNS, NS_SUCCESS },
2477d56d374SYoshinobu Inoue #ifdef ICMPNL
248248aee62SJacques Vidrine #define NSSRC_ICMP "icmp"
249248aee62SJacques Vidrine 	{ NSSRC_ICMP, NS_SUCCESS },
25073b30f0cSJun-ichiro itojun Hagino #endif
251248aee62SJacques Vidrine 	{ 0 }
252248aee62SJacques Vidrine };
2537d56d374SYoshinobu Inoue 
2547d56d374SYoshinobu Inoue /*
2557d56d374SYoshinobu Inoue  * Check if kernel supports mapped address.
2567d56d374SYoshinobu Inoue  *	implementation dependent
2577d56d374SYoshinobu Inoue  */
2587d56d374SYoshinobu Inoue #ifdef __KAME__
2597d56d374SYoshinobu Inoue #include <sys/sysctl.h>
2607d56d374SYoshinobu Inoue #endif /* __KAME__ */
2617d56d374SYoshinobu Inoue 
2627d56d374SYoshinobu Inoue static int
2637d56d374SYoshinobu Inoue _mapped_addr_enabled(void)
2647d56d374SYoshinobu Inoue {
2657d56d374SYoshinobu Inoue 	/* implementation dependent check */
2667d56d374SYoshinobu Inoue #if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR)
2677d56d374SYoshinobu Inoue 	int mib[4];
2687d56d374SYoshinobu Inoue 	size_t len;
2697d56d374SYoshinobu Inoue 	int val;
2707d56d374SYoshinobu Inoue 
2717d56d374SYoshinobu Inoue 	mib[0] = CTL_NET;
2727d56d374SYoshinobu Inoue 	mib[1] = PF_INET6;
2737d56d374SYoshinobu Inoue 	mib[2] = IPPROTO_IPV6;
2747d56d374SYoshinobu Inoue 	mib[3] = IPV6CTL_MAPPED_ADDR;
2757d56d374SYoshinobu Inoue 	len = sizeof(val);
2767d56d374SYoshinobu Inoue 	if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0)
2777d56d374SYoshinobu Inoue 		return 1;
2787d56d374SYoshinobu Inoue #endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */
2797d56d374SYoshinobu Inoue 	return 0;
2807d56d374SYoshinobu Inoue }
2817d56d374SYoshinobu Inoue 
2827d56d374SYoshinobu Inoue /*
2837d56d374SYoshinobu Inoue  * Functions defined in RFC2553
28473b30f0cSJun-ichiro itojun Hagino  *	getipnodebyname, getipnodebyaddr, freehostent
2857d56d374SYoshinobu Inoue  */
2867d56d374SYoshinobu Inoue 
2877d56d374SYoshinobu Inoue static struct hostent *
2887d56d374SYoshinobu Inoue _ghbyname(const char *name, int af, int flags, int *errp)
2897d56d374SYoshinobu Inoue {
2907d56d374SYoshinobu Inoue 	struct hostent *hp;
291cb0600bdSJacques Vidrine 	int rval;
292248aee62SJacques Vidrine 
293248aee62SJacques Vidrine 	static const ns_dtab dtab[] = {
294248aee62SJacques Vidrine 		NS_FILES_CB(_files_ghbyname, NULL)
295248aee62SJacques Vidrine 		{ NSSRC_DNS, _dns_ghbyname, NULL },
296248aee62SJacques Vidrine 		NS_NIS_CB(_nis_ghbyname, NULL)
297248aee62SJacques Vidrine 		{ 0 }
298248aee62SJacques Vidrine 	};
2997d56d374SYoshinobu Inoue 
3007d56d374SYoshinobu Inoue 	if (flags & AI_ADDRCONFIG) {
3017d56d374SYoshinobu Inoue 		int s;
3027d56d374SYoshinobu Inoue 
3030fbf0979SHajimu UMEMOTO 		if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
3040fbf0979SHajimu UMEMOTO 			return NULL;
3057d56d374SYoshinobu Inoue 		/*
3067d56d374SYoshinobu Inoue 		 * TODO:
3077d56d374SYoshinobu Inoue 		 * Note that implementation dependent test for address
3087d56d374SYoshinobu Inoue 		 * configuration should be done everytime called
3097d56d374SYoshinobu Inoue 		 * (or apropriate interval),
3107d56d374SYoshinobu Inoue 		 * because addresses will be dynamically assigned or deleted.
3117d56d374SYoshinobu Inoue 		 */
3129233c4d9SJason Evans 		_close(s);
3137d56d374SYoshinobu Inoue 	}
3147d56d374SYoshinobu Inoue 
31520e0e084SJacques Vidrine 	rval = _nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyname", default_src,
316248aee62SJacques Vidrine 			  name, af, errp);
317248aee62SJacques Vidrine 	return (rval == NS_SUCCESS) ? hp : NULL;
3187d56d374SYoshinobu Inoue }
3197d56d374SYoshinobu Inoue 
3200fbf0979SHajimu UMEMOTO struct hostent *
3210fbf0979SHajimu UMEMOTO getipnodebyname(const char *name, int af, int flags, int *errp)
3227d56d374SYoshinobu Inoue {
3237d56d374SYoshinobu Inoue 	struct hostent *hp;
3247d56d374SYoshinobu Inoue 	union inx_addr addrbuf;
3257d56d374SYoshinobu Inoue 
326946e41f1SHajimu UMEMOTO 	switch (af) {
327946e41f1SHajimu UMEMOTO 	case AF_INET:
3287d56d374SYoshinobu Inoue #ifdef INET6
329946e41f1SHajimu UMEMOTO 	case AF_INET6:
3307d56d374SYoshinobu Inoue #endif
331946e41f1SHajimu UMEMOTO 		break;
332946e41f1SHajimu UMEMOTO 	default:
3337d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
3347d56d374SYoshinobu Inoue 		return NULL;
3357d56d374SYoshinobu Inoue 	}
3367d56d374SYoshinobu Inoue 
3377d56d374SYoshinobu Inoue #ifdef INET6
3387d56d374SYoshinobu Inoue 	/* special case for literal address */
3397d56d374SYoshinobu Inoue 	if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
3407d56d374SYoshinobu Inoue 		if (af != AF_INET6) {
3417d56d374SYoshinobu Inoue 			*errp = HOST_NOT_FOUND;
3427d56d374SYoshinobu Inoue 			return NULL;
3437d56d374SYoshinobu Inoue 		}
3447d56d374SYoshinobu Inoue 		return _hpaddr(af, name, &addrbuf, errp);
3457d56d374SYoshinobu Inoue 	}
3467d56d374SYoshinobu Inoue #endif
347be26adb5SYoshinobu Inoue 	if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) {
3487d56d374SYoshinobu Inoue 		if (af != AF_INET) {
3497d56d374SYoshinobu Inoue 			if (MAPADDRENABLED(flags)) {
3507d56d374SYoshinobu Inoue 				MAPADDR(&addrbuf, &addrbuf.in_addr);
3517d56d374SYoshinobu Inoue 			} else {
3527d56d374SYoshinobu Inoue 				*errp = HOST_NOT_FOUND;
3537d56d374SYoshinobu Inoue 				return NULL;
3547d56d374SYoshinobu Inoue 			}
3557d56d374SYoshinobu Inoue 		}
3567d56d374SYoshinobu Inoue 		return _hpaddr(af, name, &addrbuf, errp);
3577d56d374SYoshinobu Inoue 	}
3587d56d374SYoshinobu Inoue 
3597d56d374SYoshinobu Inoue 	*errp = HOST_NOT_FOUND;
3607d56d374SYoshinobu Inoue 	hp = _ghbyname(name, af, flags, errp);
3617d56d374SYoshinobu Inoue 
3627d56d374SYoshinobu Inoue #ifdef INET6
363946e41f1SHajimu UMEMOTO 	if (af == AF_INET6 && ((flags & AI_ALL) || hp == NULL) &&
364946e41f1SHajimu UMEMOTO 	    MAPADDRENABLED(flags)) {
3657d56d374SYoshinobu Inoue 		struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp);
3667d56d374SYoshinobu Inoue 		if (hp == NULL)
3677d56d374SYoshinobu Inoue 			hp = _hpmapv6(hp2, errp);
3687d56d374SYoshinobu Inoue 		else {
3697d56d374SYoshinobu Inoue 			if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) {
3707d56d374SYoshinobu Inoue 				freehostent(hp2);
3717d56d374SYoshinobu Inoue 				hp2 = NULL;
3727d56d374SYoshinobu Inoue 			}
3737d56d374SYoshinobu Inoue 			hp = _hpmerge(hp, hp2, errp);
3747d56d374SYoshinobu Inoue 		}
3757d56d374SYoshinobu Inoue 	}
3767d56d374SYoshinobu Inoue #endif
377b8b31f33SHajimu UMEMOTO 	return _hpreorder(_hpsort(hp));
3787d56d374SYoshinobu Inoue }
3797d56d374SYoshinobu Inoue 
3807d56d374SYoshinobu Inoue struct hostent *
3817d56d374SYoshinobu Inoue getipnodebyaddr(const void *src, size_t len, int af, int *errp)
3827d56d374SYoshinobu Inoue {
3837d56d374SYoshinobu Inoue 	struct hostent *hp;
384cb0600bdSJacques Vidrine 	int rval;
3857d56d374SYoshinobu Inoue #ifdef INET6
3867d56d374SYoshinobu Inoue 	struct in6_addr addrbuf;
3877d56d374SYoshinobu Inoue #else
3887d56d374SYoshinobu Inoue 	struct in_addr addrbuf;
3897d56d374SYoshinobu Inoue #endif
3907d56d374SYoshinobu Inoue 
391248aee62SJacques Vidrine 	static const ns_dtab dtab[] = {
392248aee62SJacques Vidrine 		NS_FILES_CB(_files_ghbyaddr, NULL)
393248aee62SJacques Vidrine 		{ NSSRC_DNS, _dns_ghbyaddr, NULL },
394248aee62SJacques Vidrine 		NS_NIS_CB(_nis_ghbyaddr, NULL)
395248aee62SJacques Vidrine #ifdef ICMPNL
396248aee62SJacques Vidrine 		{ NSSRC_ICMP, _icmp_ghbyaddr, NULL },
397248aee62SJacques Vidrine #endif
398248aee62SJacques Vidrine 		{ 0 }
399248aee62SJacques Vidrine 	};
400248aee62SJacques Vidrine 
4017d56d374SYoshinobu Inoue 	*errp = HOST_NOT_FOUND;
4027d56d374SYoshinobu Inoue 
4037d56d374SYoshinobu Inoue 	switch (af) {
4047d56d374SYoshinobu Inoue 	case AF_INET:
4057d56d374SYoshinobu Inoue 		if (len != sizeof(struct in_addr)) {
4067d56d374SYoshinobu Inoue 			*errp = NO_RECOVERY;
4077d56d374SYoshinobu Inoue 			return NULL;
4087d56d374SYoshinobu Inoue 		}
4097d56d374SYoshinobu Inoue 		if ((long)src & ~(sizeof(struct in_addr) - 1)) {
4107d56d374SYoshinobu Inoue 			memcpy(&addrbuf, src, len);
4117d56d374SYoshinobu Inoue 			src = &addrbuf;
4127d56d374SYoshinobu Inoue 		}
4137d56d374SYoshinobu Inoue 		if (((struct in_addr *)src)->s_addr == 0)
4147d56d374SYoshinobu Inoue 			return NULL;
4157d56d374SYoshinobu Inoue 		break;
4167d56d374SYoshinobu Inoue #ifdef INET6
4177d56d374SYoshinobu Inoue 	case AF_INET6:
4187d56d374SYoshinobu Inoue 		if (len != sizeof(struct in6_addr)) {
4197d56d374SYoshinobu Inoue 			*errp = NO_RECOVERY;
4207d56d374SYoshinobu Inoue 			return NULL;
4217d56d374SYoshinobu Inoue 		}
4227d56d374SYoshinobu Inoue 		if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) {	/*XXX*/
4237d56d374SYoshinobu Inoue 			memcpy(&addrbuf, src, len);
4247d56d374SYoshinobu Inoue 			src = &addrbuf;
4257d56d374SYoshinobu Inoue 		}
4263d670abcSYoshinobu Inoue 		if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src))
4273d670abcSYoshinobu Inoue 			return NULL;
4287d56d374SYoshinobu Inoue 		if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)
4297d56d374SYoshinobu Inoue 		||  IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) {
4307d56d374SYoshinobu Inoue 			src = (char *)src +
4317d56d374SYoshinobu Inoue 			    (sizeof(struct in6_addr) - sizeof(struct in_addr));
4327d56d374SYoshinobu Inoue 			af = AF_INET;
4337d56d374SYoshinobu Inoue 			len = sizeof(struct in_addr);
4347d56d374SYoshinobu Inoue 		}
4357d56d374SYoshinobu Inoue 		break;
4367d56d374SYoshinobu Inoue #endif
4377d56d374SYoshinobu Inoue 	default:
4387d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
4397d56d374SYoshinobu Inoue 		return NULL;
4407d56d374SYoshinobu Inoue 	}
4417d56d374SYoshinobu Inoue 
44220e0e084SJacques Vidrine 	rval = _nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyaddr", default_src,
443248aee62SJacques Vidrine 			  src, len, af, errp);
444248aee62SJacques Vidrine 	return (rval == NS_SUCCESS) ? hp : NULL;
4457d56d374SYoshinobu Inoue }
4467d56d374SYoshinobu Inoue 
4477d56d374SYoshinobu Inoue void
4487d56d374SYoshinobu Inoue freehostent(struct hostent *ptr)
4497d56d374SYoshinobu Inoue {
4507d56d374SYoshinobu Inoue 	free(ptr);
4517d56d374SYoshinobu Inoue }
4527d56d374SYoshinobu Inoue 
4537d56d374SYoshinobu Inoue /*
4547d56d374SYoshinobu Inoue  * Private utility functions
4557d56d374SYoshinobu Inoue  */
4567d56d374SYoshinobu Inoue 
4577d56d374SYoshinobu Inoue /*
4587d56d374SYoshinobu Inoue  * _hpcopy: allocate and copy hostent structure
4597d56d374SYoshinobu Inoue  */
4607d56d374SYoshinobu Inoue static struct hostent *
4617d56d374SYoshinobu Inoue _hpcopy(struct hostent *hp, int *errp)
4627d56d374SYoshinobu Inoue {
4637d56d374SYoshinobu Inoue 	struct hostent *nhp;
4647d56d374SYoshinobu Inoue 	char *cp, **pp;
4657d56d374SYoshinobu Inoue 	int size, addrsize;
4667d56d374SYoshinobu Inoue 	int nalias = 0, naddr = 0;
4677d56d374SYoshinobu Inoue 	int al_off;
4687d56d374SYoshinobu Inoue 	int i;
4697d56d374SYoshinobu Inoue 
4707d56d374SYoshinobu Inoue 	if (hp == NULL)
4717d56d374SYoshinobu Inoue 		return hp;
4727d56d374SYoshinobu Inoue 
4737d56d374SYoshinobu Inoue 	/* count size to be allocated */
4747d56d374SYoshinobu Inoue 	size = sizeof(struct hostent);
47505c36511SHajimu UMEMOTO 	if (hp->h_name != NULL)
4767d56d374SYoshinobu Inoue 		size += strlen(hp->h_name) + 1;
4777d56d374SYoshinobu Inoue 	if ((pp = hp->h_aliases) != NULL) {
4787d56d374SYoshinobu Inoue 		for (i = 0; *pp != NULL; i++, pp++) {
4797d56d374SYoshinobu Inoue 			if (**pp != '\0') {
4807d56d374SYoshinobu Inoue 				size += strlen(*pp) + 1;
4817d56d374SYoshinobu Inoue 				nalias++;
4827d56d374SYoshinobu Inoue 			}
4837d56d374SYoshinobu Inoue 		}
4847d56d374SYoshinobu Inoue 	}
4857d56d374SYoshinobu Inoue 	/* adjust alignment */
4867d56d374SYoshinobu Inoue 	size = ALIGN(size);
4877d56d374SYoshinobu Inoue 	al_off = size;
4887d56d374SYoshinobu Inoue 	size += sizeof(char *) * (nalias + 1);
4897d56d374SYoshinobu Inoue 	addrsize = ALIGN(hp->h_length);
4907d56d374SYoshinobu Inoue 	if ((pp = hp->h_addr_list) != NULL) {
4917d56d374SYoshinobu Inoue 		while (*pp++ != NULL)
4927d56d374SYoshinobu Inoue 			naddr++;
4937d56d374SYoshinobu Inoue 	}
4947d56d374SYoshinobu Inoue 	size += addrsize * naddr;
4957d56d374SYoshinobu Inoue 	size += sizeof(char *) * (naddr + 1);
4967d56d374SYoshinobu Inoue 
4977d56d374SYoshinobu Inoue 	/* copy */
4987d56d374SYoshinobu Inoue 	if ((nhp = (struct hostent *)malloc(size)) == NULL) {
4997d56d374SYoshinobu Inoue 		*errp = TRY_AGAIN;
5007d56d374SYoshinobu Inoue 		return NULL;
5017d56d374SYoshinobu Inoue 	}
5027d56d374SYoshinobu Inoue 	cp = (char *)&nhp[1];
50305c36511SHajimu UMEMOTO 	if (hp->h_name != NULL) {
5047d56d374SYoshinobu Inoue 		nhp->h_name = cp;
5057d56d374SYoshinobu Inoue 		strcpy(cp, hp->h_name);
5067d56d374SYoshinobu Inoue 		cp += strlen(cp) + 1;
5077d56d374SYoshinobu Inoue 	} else
5087d56d374SYoshinobu Inoue 		nhp->h_name = NULL;
5097d56d374SYoshinobu Inoue 	nhp->h_aliases = (char **)((char *)nhp + al_off);
5107d56d374SYoshinobu Inoue 	if ((pp = hp->h_aliases) != NULL) {
5117d56d374SYoshinobu Inoue 		for (i = 0; *pp != NULL; pp++) {
5127d56d374SYoshinobu Inoue 			if (**pp != '\0') {
5137d56d374SYoshinobu Inoue 				nhp->h_aliases[i++] = cp;
5147d56d374SYoshinobu Inoue 				strcpy(cp, *pp);
5157d56d374SYoshinobu Inoue 				cp += strlen(cp) + 1;
5167d56d374SYoshinobu Inoue 			}
5177d56d374SYoshinobu Inoue 		}
5187d56d374SYoshinobu Inoue 	}
5197d56d374SYoshinobu Inoue 	nhp->h_aliases[nalias] = NULL;
5207d56d374SYoshinobu Inoue 	cp = (char *)&nhp->h_aliases[nalias + 1];
5217d56d374SYoshinobu Inoue 	nhp->h_addrtype = hp->h_addrtype;
5227d56d374SYoshinobu Inoue 	nhp->h_length = hp->h_length;
5237d56d374SYoshinobu Inoue 	nhp->h_addr_list = (char **)cp;
5247d56d374SYoshinobu Inoue 	if ((pp = hp->h_addr_list) != NULL) {
5257d56d374SYoshinobu Inoue 		cp = (char *)&nhp->h_addr_list[naddr + 1];
5267d56d374SYoshinobu Inoue 		for (i = 0; *pp != NULL; pp++) {
5277d56d374SYoshinobu Inoue 			nhp->h_addr_list[i++] = cp;
5287d56d374SYoshinobu Inoue 			memcpy(cp, *pp, hp->h_length);
5297d56d374SYoshinobu Inoue 			cp += addrsize;
5307d56d374SYoshinobu Inoue 		}
5317d56d374SYoshinobu Inoue 	}
5327d56d374SYoshinobu Inoue 	nhp->h_addr_list[naddr] = NULL;
5337d56d374SYoshinobu Inoue 	return nhp;
5347d56d374SYoshinobu Inoue }
5357d56d374SYoshinobu Inoue 
5367d56d374SYoshinobu Inoue /*
5377d56d374SYoshinobu Inoue  * _hpaddr: construct hostent structure with one address
5387d56d374SYoshinobu Inoue  */
5397d56d374SYoshinobu Inoue static struct hostent *
5407d56d374SYoshinobu Inoue _hpaddr(int af, const char *name, void *addr, int *errp)
5417d56d374SYoshinobu Inoue {
5427d56d374SYoshinobu Inoue 	struct hostent *hp, hpbuf;
5437d56d374SYoshinobu Inoue 	char *addrs[2];
5447d56d374SYoshinobu Inoue 
5457d56d374SYoshinobu Inoue 	hp = &hpbuf;
5467d56d374SYoshinobu Inoue 	hp->h_name = (char *)name;
5477d56d374SYoshinobu Inoue 	hp->h_aliases = NULL;
5487d56d374SYoshinobu Inoue 	hp->h_addrtype = af;
5497d56d374SYoshinobu Inoue 	hp->h_length = ADDRLEN(af);
5507d56d374SYoshinobu Inoue 	hp->h_addr_list = addrs;
5517d56d374SYoshinobu Inoue 	addrs[0] = (char *)addr;
5527d56d374SYoshinobu Inoue 	addrs[1] = NULL;
5537d56d374SYoshinobu Inoue 	return _hpcopy(hp, errp);
5547d56d374SYoshinobu Inoue }
5557d56d374SYoshinobu Inoue 
5567d56d374SYoshinobu Inoue /*
5577d56d374SYoshinobu Inoue  * _hpmerge: merge 2 hostent structure, arguments will be freed
5587d56d374SYoshinobu Inoue  */
5597d56d374SYoshinobu Inoue static struct hostent *
5607d56d374SYoshinobu Inoue _hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp)
5617d56d374SYoshinobu Inoue {
5627d56d374SYoshinobu Inoue 	int i, j;
5637d56d374SYoshinobu Inoue 	int naddr, nalias;
5647d56d374SYoshinobu Inoue 	char **pp;
5657d56d374SYoshinobu Inoue 	struct hostent *hp, hpbuf;
5667d56d374SYoshinobu Inoue 	char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1];
5677d56d374SYoshinobu Inoue 	union inx_addr addrbuf[MAXADDRS];
5687d56d374SYoshinobu Inoue 
5697d56d374SYoshinobu Inoue 	if (hp1 == NULL)
5707d56d374SYoshinobu Inoue 		return hp2;
5717d56d374SYoshinobu Inoue 	if (hp2 == NULL)
5727d56d374SYoshinobu Inoue 		return hp1;
5737d56d374SYoshinobu Inoue 
5747d56d374SYoshinobu Inoue #define	HP(i)	(i == 1 ? hp1 : hp2)
5757d56d374SYoshinobu Inoue 	hp = &hpbuf;
5767d56d374SYoshinobu Inoue 	hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name);
5777d56d374SYoshinobu Inoue 	hp->h_aliases = aliases;
5787d56d374SYoshinobu Inoue 	nalias = 0;
5797d56d374SYoshinobu Inoue 	for (i = 1; i <= 2; i++) {
5807d56d374SYoshinobu Inoue 		if ((pp = HP(i)->h_aliases) == NULL)
5817d56d374SYoshinobu Inoue 			continue;
5827d56d374SYoshinobu Inoue 		for (; nalias < MAXALIASES && *pp != NULL; pp++) {
5837d56d374SYoshinobu Inoue 			/* check duplicates */
5847d56d374SYoshinobu Inoue 			for (j = 0; j < nalias; j++)
5857d56d374SYoshinobu Inoue 				if (strcasecmp(*pp, aliases[j]) == 0)
5867d56d374SYoshinobu Inoue 					break;
5877d56d374SYoshinobu Inoue 			if (j == nalias)
5887d56d374SYoshinobu Inoue 				aliases[nalias++] = *pp;
5897d56d374SYoshinobu Inoue 		}
5907d56d374SYoshinobu Inoue 	}
5917d56d374SYoshinobu Inoue 	aliases[nalias] = NULL;
5927d56d374SYoshinobu Inoue #ifdef INET6
5937d56d374SYoshinobu Inoue 	if (hp1->h_length != hp2->h_length) {
5947d56d374SYoshinobu Inoue 		hp->h_addrtype = AF_INET6;
5957d56d374SYoshinobu Inoue 		hp->h_length = sizeof(struct in6_addr);
5967d56d374SYoshinobu Inoue 	} else {
5977d56d374SYoshinobu Inoue #endif
5987d56d374SYoshinobu Inoue 		hp->h_addrtype = hp1->h_addrtype;
5997d56d374SYoshinobu Inoue 		hp->h_length = hp1->h_length;
6007d56d374SYoshinobu Inoue #ifdef INET6
6017d56d374SYoshinobu Inoue 	}
6027d56d374SYoshinobu Inoue #endif
6037d56d374SYoshinobu Inoue 	hp->h_addr_list = addrs;
6047d56d374SYoshinobu Inoue 	naddr = 0;
6057d56d374SYoshinobu Inoue 	for (i = 1; i <= 2; i++) {
6067d56d374SYoshinobu Inoue 		if ((pp = HP(i)->h_addr_list) == NULL)
6077d56d374SYoshinobu Inoue 			continue;
6087d56d374SYoshinobu Inoue 		if (HP(i)->h_length == hp->h_length) {
6097d56d374SYoshinobu Inoue 			while (naddr < MAXADDRS && *pp != NULL)
6107d56d374SYoshinobu Inoue 				addrs[naddr++] = *pp++;
6117d56d374SYoshinobu Inoue 		} else {
6127d56d374SYoshinobu Inoue 			/* copy IPv4 addr as mapped IPv6 addr */
6137d56d374SYoshinobu Inoue 			while (naddr < MAXADDRS && *pp != NULL) {
6147d56d374SYoshinobu Inoue 				MAPADDR(&addrbuf[naddr], *pp++);
6157d56d374SYoshinobu Inoue 				addrs[naddr] = (char *)&addrbuf[naddr];
6167d56d374SYoshinobu Inoue 				naddr++;
6177d56d374SYoshinobu Inoue 			}
6187d56d374SYoshinobu Inoue 		}
6197d56d374SYoshinobu Inoue 	}
6207d56d374SYoshinobu Inoue 	addrs[naddr] = NULL;
6217d56d374SYoshinobu Inoue 	hp = _hpcopy(hp, errp);
6227d56d374SYoshinobu Inoue 	freehostent(hp1);
6237d56d374SYoshinobu Inoue 	freehostent(hp2);
6247d56d374SYoshinobu Inoue 	return hp;
6257d56d374SYoshinobu Inoue }
6267d56d374SYoshinobu Inoue 
6277d56d374SYoshinobu Inoue /*
6287d56d374SYoshinobu Inoue  * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses
6297d56d374SYoshinobu Inoue  */
6307d56d374SYoshinobu Inoue #ifdef INET6
6317d56d374SYoshinobu Inoue static struct hostent *
6327d56d374SYoshinobu Inoue _hpmapv6(struct hostent *hp, int *errp)
6337d56d374SYoshinobu Inoue {
6347d56d374SYoshinobu Inoue 	struct hostent *hp6;
6357d56d374SYoshinobu Inoue 
6367d56d374SYoshinobu Inoue 	if (hp == NULL)
6377d56d374SYoshinobu Inoue 		return NULL;
6387d56d374SYoshinobu Inoue 	if (hp->h_addrtype == AF_INET6)
6397d56d374SYoshinobu Inoue 		return hp;
6407d56d374SYoshinobu Inoue 
6417d56d374SYoshinobu Inoue 	/* make dummy hostent to convert IPv6 address */
6427d56d374SYoshinobu Inoue 	if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) {
6437d56d374SYoshinobu Inoue 		*errp = TRY_AGAIN;
6447d56d374SYoshinobu Inoue 		return NULL;
6457d56d374SYoshinobu Inoue 	}
6467d56d374SYoshinobu Inoue 	hp6->h_name = NULL;
6477d56d374SYoshinobu Inoue 	hp6->h_aliases = NULL;
6487d56d374SYoshinobu Inoue 	hp6->h_addrtype = AF_INET6;
6497d56d374SYoshinobu Inoue 	hp6->h_length = sizeof(struct in6_addr);
6507d56d374SYoshinobu Inoue 	hp6->h_addr_list = NULL;
6517d56d374SYoshinobu Inoue 	return _hpmerge(hp6, hp, errp);
6527d56d374SYoshinobu Inoue }
6537d56d374SYoshinobu Inoue #endif
6547d56d374SYoshinobu Inoue 
6557d56d374SYoshinobu Inoue /*
6567d56d374SYoshinobu Inoue  * _hpsort: sort address by sortlist
6577d56d374SYoshinobu Inoue  */
6587d56d374SYoshinobu Inoue static struct hostent *
6597d56d374SYoshinobu Inoue _hpsort(struct hostent *hp)
6607d56d374SYoshinobu Inoue {
6617d56d374SYoshinobu Inoue 	int i, j, n;
6627d56d374SYoshinobu Inoue 	u_char *ap, *sp, *mp, **pp;
6637d56d374SYoshinobu Inoue 	char t;
6647d56d374SYoshinobu Inoue 	char order[MAXADDRS];
6657d56d374SYoshinobu Inoue 	int nsort = _res.nsort;
6667d56d374SYoshinobu Inoue 
6677d56d374SYoshinobu Inoue 	if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0)
6687d56d374SYoshinobu Inoue 		return hp;
6697d56d374SYoshinobu Inoue 	for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) {
6707d56d374SYoshinobu Inoue 		for (j = 0; j < nsort; j++) {
6717d56d374SYoshinobu Inoue #ifdef INET6
6727d56d374SYoshinobu Inoue 			if (_res_ext.sort_list[j].af != hp->h_addrtype)
6737d56d374SYoshinobu Inoue 				continue;
6747d56d374SYoshinobu Inoue 			sp = (u_char *)&_res_ext.sort_list[j].addr;
6757d56d374SYoshinobu Inoue 			mp = (u_char *)&_res_ext.sort_list[j].mask;
6767d56d374SYoshinobu Inoue #else
6777d56d374SYoshinobu Inoue 			sp = (u_char *)&_res.sort_list[j].addr;
6787d56d374SYoshinobu Inoue 			mp = (u_char *)&_res.sort_list[j].mask;
6797d56d374SYoshinobu Inoue #endif
6807d56d374SYoshinobu Inoue 			for (n = 0; n < hp->h_length; n++) {
6817d56d374SYoshinobu Inoue 				if ((ap[n] & mp[n]) != sp[n])
6827d56d374SYoshinobu Inoue 					break;
6837d56d374SYoshinobu Inoue 			}
6847d56d374SYoshinobu Inoue 			if (n == hp->h_length)
6857d56d374SYoshinobu Inoue 				break;
6867d56d374SYoshinobu Inoue 		}
6877d56d374SYoshinobu Inoue 		order[i] = j;
6887d56d374SYoshinobu Inoue 	}
6897d56d374SYoshinobu Inoue 	n = i;
6907d56d374SYoshinobu Inoue 	pp = (u_char **)hp->h_addr_list;
6917d56d374SYoshinobu Inoue 	for (i = 0; i < n - 1; i++) {
6927d56d374SYoshinobu Inoue 		for (j = i + 1; j < n; j++) {
6937d56d374SYoshinobu Inoue 			if (order[i] > order[j]) {
6947d56d374SYoshinobu Inoue 				ap = pp[i];
6957d56d374SYoshinobu Inoue 				pp[i] = pp[j];
6967d56d374SYoshinobu Inoue 				pp[j] = ap;
6977d56d374SYoshinobu Inoue 				t = order[i];
6987d56d374SYoshinobu Inoue 				order[i] = order[j];
6997d56d374SYoshinobu Inoue 				order[j] = t;
7007d56d374SYoshinobu Inoue 			}
7017d56d374SYoshinobu Inoue 		}
7027d56d374SYoshinobu Inoue 	}
7037d56d374SYoshinobu Inoue 	return hp;
7047d56d374SYoshinobu Inoue }
7057d56d374SYoshinobu Inoue 
7067d56d374SYoshinobu Inoue static char *
7077d56d374SYoshinobu Inoue _hgetword(char **pp)
7087d56d374SYoshinobu Inoue {
7097d56d374SYoshinobu Inoue 	char c, *p, *ret;
7107d56d374SYoshinobu Inoue 	const char *sp;
7117d56d374SYoshinobu Inoue 	static const char sep[] = "# \t\n";
7127d56d374SYoshinobu Inoue 
7137d56d374SYoshinobu Inoue 	ret = NULL;
7147d56d374SYoshinobu Inoue 	for (p = *pp; (c = *p) != '\0'; p++) {
7157d56d374SYoshinobu Inoue 		for (sp = sep; *sp != '\0'; sp++) {
7167d56d374SYoshinobu Inoue 			if (c == *sp)
7177d56d374SYoshinobu Inoue 				break;
7187d56d374SYoshinobu Inoue 		}
7197d56d374SYoshinobu Inoue 		if (c == '#')
7207d56d374SYoshinobu Inoue 			p[1] = '\0';	/* ignore rest of line */
7217d56d374SYoshinobu Inoue 		if (ret == NULL) {
7227d56d374SYoshinobu Inoue 			if (*sp == '\0')
7237d56d374SYoshinobu Inoue 				ret = p;
7247d56d374SYoshinobu Inoue 		} else {
7257d56d374SYoshinobu Inoue 			if (*sp != '\0') {
7267d56d374SYoshinobu Inoue 				*p++ = '\0';
7277d56d374SYoshinobu Inoue 				break;
7287d56d374SYoshinobu Inoue 			}
7297d56d374SYoshinobu Inoue 		}
7307d56d374SYoshinobu Inoue 	}
7317d56d374SYoshinobu Inoue 	*pp = p;
7327d56d374SYoshinobu Inoue 	if (ret == NULL || *ret == '\0')
7337d56d374SYoshinobu Inoue 		return NULL;
7347d56d374SYoshinobu Inoue 	return ret;
7357d56d374SYoshinobu Inoue }
7367d56d374SYoshinobu Inoue 
7377d56d374SYoshinobu Inoue /*
738b8b31f33SHajimu UMEMOTO  * _hpreorder: sort address by default address selection
739b8b31f33SHajimu UMEMOTO  */
740b8b31f33SHajimu UMEMOTO static struct hostent *
741b8b31f33SHajimu UMEMOTO _hpreorder(struct hostent *hp)
742b8b31f33SHajimu UMEMOTO {
743146cd1bcSHajimu UMEMOTO 	struct hp_order *aio;
744146cd1bcSHajimu UMEMOTO 	int i, n;
745d6fd3ed8SHajimu UMEMOTO 	char *ap;
746146cd1bcSHajimu UMEMOTO 	struct sockaddr *sa;
747b8b31f33SHajimu UMEMOTO 	struct policyhead policyhead;
748b8b31f33SHajimu UMEMOTO 
749146cd1bcSHajimu UMEMOTO 	if (hp == NULL)
750b8b31f33SHajimu UMEMOTO 		return hp;
751b8b31f33SHajimu UMEMOTO 
752b8b31f33SHajimu UMEMOTO 	switch (hp->h_addrtype) {
753b8b31f33SHajimu UMEMOTO 	case AF_INET:
754b8b31f33SHajimu UMEMOTO #ifdef INET6
755b8b31f33SHajimu UMEMOTO 	case AF_INET6:
756b8b31f33SHajimu UMEMOTO #endif
757146cd1bcSHajimu UMEMOTO 		break;
758b8b31f33SHajimu UMEMOTO 	default:
759b8b31f33SHajimu UMEMOTO 		free_addrselectpolicy(&policyhead);
760b8b31f33SHajimu UMEMOTO 		return hp;
761b8b31f33SHajimu UMEMOTO 	}
762b8b31f33SHajimu UMEMOTO 
763146cd1bcSHajimu UMEMOTO 	/* count the number of addrinfo elements for sorting. */
764146cd1bcSHajimu UMEMOTO 	for (n = 0; hp->h_addr_list[n] != NULL; n++)
765146cd1bcSHajimu UMEMOTO 		;
766146cd1bcSHajimu UMEMOTO 
767146cd1bcSHajimu UMEMOTO 	/*
768146cd1bcSHajimu UMEMOTO 	 * If the number is small enough, we can skip the reordering process.
769146cd1bcSHajimu UMEMOTO 	 */
770146cd1bcSHajimu UMEMOTO 	if (n <= 1)
771146cd1bcSHajimu UMEMOTO 		return hp;
772146cd1bcSHajimu UMEMOTO 
773146cd1bcSHajimu UMEMOTO 	/* allocate a temporary array for sort and initialization of it. */
774146cd1bcSHajimu UMEMOTO 	if ((aio = malloc(sizeof(*aio) * n)) == NULL)
775146cd1bcSHajimu UMEMOTO 		return hp;	/* give up reordering */
776146cd1bcSHajimu UMEMOTO 	memset(aio, 0, sizeof(*aio) * n);
777146cd1bcSHajimu UMEMOTO 
778146cd1bcSHajimu UMEMOTO 	/* retrieve address selection policy from the kernel */
779146cd1bcSHajimu UMEMOTO 	TAILQ_INIT(&policyhead);
780146cd1bcSHajimu UMEMOTO 	if (!get_addrselectpolicy(&policyhead)) {
781146cd1bcSHajimu UMEMOTO 		/* no policy is installed into kernel, we don't sort. */
782146cd1bcSHajimu UMEMOTO 		free(aio);
783146cd1bcSHajimu UMEMOTO 		return hp;
784b8b31f33SHajimu UMEMOTO 	}
785b8b31f33SHajimu UMEMOTO 
786146cd1bcSHajimu UMEMOTO 	for (i = 0; i < n; i++) {
787d6fd3ed8SHajimu UMEMOTO 		ap = hp->h_addr_list[i];
788146cd1bcSHajimu UMEMOTO 		aio[i].aio_h_addr = ap;
789146cd1bcSHajimu UMEMOTO 		sa = &aio[i].aio_sa;
790146cd1bcSHajimu UMEMOTO 		switch (hp->h_addrtype) {
791146cd1bcSHajimu UMEMOTO 		case AF_INET:
792146cd1bcSHajimu UMEMOTO 			sa->sa_family = AF_INET;
793146cd1bcSHajimu UMEMOTO 			sa->sa_len = sizeof(struct sockaddr_in);
794146cd1bcSHajimu UMEMOTO 			memcpy(&((struct sockaddr_in *)sa)->sin_addr, ap,
795146cd1bcSHajimu UMEMOTO 			    sizeof(struct in_addr));
796146cd1bcSHajimu UMEMOTO 			break;
797146cd1bcSHajimu UMEMOTO #ifdef INET6
798146cd1bcSHajimu UMEMOTO 		case AF_INET6:
799146cd1bcSHajimu UMEMOTO 			if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
800146cd1bcSHajimu UMEMOTO 				sa->sa_family = AF_INET;
801146cd1bcSHajimu UMEMOTO 				sa->sa_len = sizeof(struct sockaddr_in);
802146cd1bcSHajimu UMEMOTO 				memcpy(&((struct sockaddr_in *)sa)->sin_addr,
803146cd1bcSHajimu UMEMOTO 				    &ap[12], sizeof(struct in_addr));
804146cd1bcSHajimu UMEMOTO 			} else {
805146cd1bcSHajimu UMEMOTO 				sa->sa_family = AF_INET6;
806146cd1bcSHajimu UMEMOTO 				sa->sa_len = sizeof(struct sockaddr_in6);
807146cd1bcSHajimu UMEMOTO 				memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr,
808146cd1bcSHajimu UMEMOTO 				    ap, sizeof(struct in6_addr));
809146cd1bcSHajimu UMEMOTO 			}
810146cd1bcSHajimu UMEMOTO 			break;
811146cd1bcSHajimu UMEMOTO #endif
812146cd1bcSHajimu UMEMOTO 		}
813146cd1bcSHajimu UMEMOTO 		aio[i].aio_dstscope = gai_addr2scopetype(sa);
814146cd1bcSHajimu UMEMOTO 		aio[i].aio_dstpolicy = match_addrselectpolicy(sa, &policyhead);
815146cd1bcSHajimu UMEMOTO 		set_source(&aio[i], &policyhead);
816146cd1bcSHajimu UMEMOTO 	}
817146cd1bcSHajimu UMEMOTO 
818146cd1bcSHajimu UMEMOTO 	/* perform sorting. */
819146cd1bcSHajimu UMEMOTO 	qsort(aio, n, sizeof(*aio), comp_dst);
820146cd1bcSHajimu UMEMOTO 
821146cd1bcSHajimu UMEMOTO 	/* reorder the h_addr_list. */
822146cd1bcSHajimu UMEMOTO 	for (i = 0; i < n; i++)
823146cd1bcSHajimu UMEMOTO 		hp->h_addr_list[i] = aio[i].aio_h_addr;
824146cd1bcSHajimu UMEMOTO 
825b8b31f33SHajimu UMEMOTO 	/* cleanup and return */
826146cd1bcSHajimu UMEMOTO 	free(aio);
827b8b31f33SHajimu UMEMOTO 	free_addrselectpolicy(&policyhead);
828b8b31f33SHajimu UMEMOTO 	return hp;
829b8b31f33SHajimu UMEMOTO }
830b8b31f33SHajimu UMEMOTO 
831b8b31f33SHajimu UMEMOTO static int
832b8b31f33SHajimu UMEMOTO get_addrselectpolicy(head)
833b8b31f33SHajimu UMEMOTO 	struct policyhead *head;
834b8b31f33SHajimu UMEMOTO {
835b8b31f33SHajimu UMEMOTO #ifdef INET6
836b8b31f33SHajimu UMEMOTO 	int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY };
837b8b31f33SHajimu UMEMOTO 	size_t l;
838b8b31f33SHajimu UMEMOTO 	char *buf;
839b8b31f33SHajimu UMEMOTO 	struct in6_addrpolicy *pol, *ep;
840b8b31f33SHajimu UMEMOTO 
841b8b31f33SHajimu UMEMOTO 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0)
842b8b31f33SHajimu UMEMOTO 		return (0);
843b8b31f33SHajimu UMEMOTO 	if ((buf = malloc(l)) == NULL)
844b8b31f33SHajimu UMEMOTO 		return (0);
845b8b31f33SHajimu UMEMOTO 	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
846b8b31f33SHajimu UMEMOTO 		free(buf);
847b8b31f33SHajimu UMEMOTO 		return (0);
848b8b31f33SHajimu UMEMOTO 	}
849b8b31f33SHajimu UMEMOTO 
850b8b31f33SHajimu UMEMOTO 	ep = (struct in6_addrpolicy *)(buf + l);
851b8b31f33SHajimu UMEMOTO 	for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) {
852b8b31f33SHajimu UMEMOTO 		struct policyqueue *new;
853b8b31f33SHajimu UMEMOTO 
854b8b31f33SHajimu UMEMOTO 		if ((new = malloc(sizeof(*new))) == NULL) {
855b8b31f33SHajimu UMEMOTO 			free_addrselectpolicy(head); /* make the list empty */
856b8b31f33SHajimu UMEMOTO 			break;
857b8b31f33SHajimu UMEMOTO 		}
858b8b31f33SHajimu UMEMOTO 		new->pc_policy = *pol;
859b8b31f33SHajimu UMEMOTO 		TAILQ_INSERT_TAIL(head, new, pc_entry);
860b8b31f33SHajimu UMEMOTO 	}
861b8b31f33SHajimu UMEMOTO 
862b8b31f33SHajimu UMEMOTO 	free(buf);
863b8b31f33SHajimu UMEMOTO 	return (1);
864b8b31f33SHajimu UMEMOTO #else
865b8b31f33SHajimu UMEMOTO 	return (0);
866b8b31f33SHajimu UMEMOTO #endif
867b8b31f33SHajimu UMEMOTO }
868b8b31f33SHajimu UMEMOTO 
869b8b31f33SHajimu UMEMOTO static void
870b8b31f33SHajimu UMEMOTO free_addrselectpolicy(head)
871b8b31f33SHajimu UMEMOTO 	struct policyhead *head;
872b8b31f33SHajimu UMEMOTO {
873b8b31f33SHajimu UMEMOTO 	struct policyqueue *ent, *nent;
874b8b31f33SHajimu UMEMOTO 
875b8b31f33SHajimu UMEMOTO 	for (ent = TAILQ_FIRST(head); ent; ent = nent) {
876b8b31f33SHajimu UMEMOTO 		nent = TAILQ_NEXT(ent, pc_entry);
877b8b31f33SHajimu UMEMOTO 		TAILQ_REMOVE(head, ent, pc_entry);
878b8b31f33SHajimu UMEMOTO 		free(ent);
879b8b31f33SHajimu UMEMOTO 	}
880b8b31f33SHajimu UMEMOTO }
881b8b31f33SHajimu UMEMOTO 
882b8b31f33SHajimu UMEMOTO static struct policyqueue *
883b8b31f33SHajimu UMEMOTO match_addrselectpolicy(addr, head)
884b8b31f33SHajimu UMEMOTO 	struct sockaddr *addr;
885b8b31f33SHajimu UMEMOTO 	struct policyhead *head;
886b8b31f33SHajimu UMEMOTO {
887b8b31f33SHajimu UMEMOTO #ifdef INET6
888b8b31f33SHajimu UMEMOTO 	struct policyqueue *ent, *bestent = NULL;
889b8b31f33SHajimu UMEMOTO 	struct in6_addrpolicy *pol;
890b8b31f33SHajimu UMEMOTO 	int matchlen, bestmatchlen = -1;
891b8b31f33SHajimu UMEMOTO 	u_char *mp, *ep, *k, *p, m;
892b8b31f33SHajimu UMEMOTO 	struct sockaddr_in6 key;
893b8b31f33SHajimu UMEMOTO 
894b8b31f33SHajimu UMEMOTO 	switch(addr->sa_family) {
895b8b31f33SHajimu UMEMOTO 	case AF_INET6:
896b8b31f33SHajimu UMEMOTO 		key = *(struct sockaddr_in6 *)addr;
897b8b31f33SHajimu UMEMOTO 		break;
898b8b31f33SHajimu UMEMOTO 	case AF_INET:
899b8b31f33SHajimu UMEMOTO 		/* convert the address into IPv4-mapped IPv6 address. */
900b8b31f33SHajimu UMEMOTO 		memset(&key, 0, sizeof(key));
901b8b31f33SHajimu UMEMOTO 		key.sin6_family = AF_INET6;
902b8b31f33SHajimu UMEMOTO 		key.sin6_len = sizeof(key);
903b8b31f33SHajimu UMEMOTO 		key.sin6_addr.s6_addr[10] = 0xff;
904b8b31f33SHajimu UMEMOTO 		key.sin6_addr.s6_addr[11] = 0xff;
905b8b31f33SHajimu UMEMOTO 		memcpy(&key.sin6_addr.s6_addr[12],
906b8b31f33SHajimu UMEMOTO 		       &((struct sockaddr_in *)addr)->sin_addr, 4);
907b8b31f33SHajimu UMEMOTO 		break;
908b8b31f33SHajimu UMEMOTO 	default:
909b8b31f33SHajimu UMEMOTO 		return(NULL);
910b8b31f33SHajimu UMEMOTO 	}
911b8b31f33SHajimu UMEMOTO 
912b8b31f33SHajimu UMEMOTO 	for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) {
913b8b31f33SHajimu UMEMOTO 		pol = &ent->pc_policy;
914b8b31f33SHajimu UMEMOTO 		matchlen = 0;
915b8b31f33SHajimu UMEMOTO 
916b8b31f33SHajimu UMEMOTO 		mp = (u_char *)&pol->addrmask.sin6_addr;
917b8b31f33SHajimu UMEMOTO 		ep = mp + 16;	/* XXX: scope field? */
918b8b31f33SHajimu UMEMOTO 		k = (u_char *)&key.sin6_addr;
919b8b31f33SHajimu UMEMOTO 		p = (u_char *)&pol->addr.sin6_addr;
920b8b31f33SHajimu UMEMOTO 		for (; mp < ep && *mp; mp++, k++, p++) {
921b8b31f33SHajimu UMEMOTO 			m = *mp;
922b8b31f33SHajimu UMEMOTO 			if ((*k & m) != *p)
923b8b31f33SHajimu UMEMOTO 				goto next; /* not match */
924b8b31f33SHajimu UMEMOTO 			if (m == 0xff) /* short cut for a typical case */
925b8b31f33SHajimu UMEMOTO 				matchlen += 8;
926b8b31f33SHajimu UMEMOTO 			else {
927b8b31f33SHajimu UMEMOTO 				while (m >= 0x80) {
928b8b31f33SHajimu UMEMOTO 					matchlen++;
929b8b31f33SHajimu UMEMOTO 					m <<= 1;
930b8b31f33SHajimu UMEMOTO 				}
931b8b31f33SHajimu UMEMOTO 			}
932b8b31f33SHajimu UMEMOTO 		}
933b8b31f33SHajimu UMEMOTO 
934b8b31f33SHajimu UMEMOTO 		/* matched.  check if this is better than the current best. */
935b8b31f33SHajimu UMEMOTO 		if (matchlen > bestmatchlen) {
936b8b31f33SHajimu UMEMOTO 			bestent = ent;
937b8b31f33SHajimu UMEMOTO 			bestmatchlen = matchlen;
938b8b31f33SHajimu UMEMOTO 		}
939b8b31f33SHajimu UMEMOTO 
940b8b31f33SHajimu UMEMOTO 	  next:
941b8b31f33SHajimu UMEMOTO 		continue;
942b8b31f33SHajimu UMEMOTO 	}
943b8b31f33SHajimu UMEMOTO 
944b8b31f33SHajimu UMEMOTO 	return(bestent);
945b8b31f33SHajimu UMEMOTO #else
946b8b31f33SHajimu UMEMOTO 	return(NULL);
947b8b31f33SHajimu UMEMOTO #endif
948b8b31f33SHajimu UMEMOTO 
949b8b31f33SHajimu UMEMOTO }
950b8b31f33SHajimu UMEMOTO 
951146cd1bcSHajimu UMEMOTO static void
952146cd1bcSHajimu UMEMOTO set_source(aio, ph)
953146cd1bcSHajimu UMEMOTO 	struct hp_order *aio;
954146cd1bcSHajimu UMEMOTO 	struct policyhead *ph;
955146cd1bcSHajimu UMEMOTO {
956146cd1bcSHajimu UMEMOTO 	struct sockaddr_storage ss = aio->aio_un.aiou_ss;
957943db5a2SHajimu UMEMOTO 	socklen_t srclen;
958943db5a2SHajimu UMEMOTO 	int s;
959146cd1bcSHajimu UMEMOTO 
960146cd1bcSHajimu UMEMOTO 	/* set unspec ("no source is available"), just in case */
961146cd1bcSHajimu UMEMOTO 	aio->aio_srcsa.sa_family = AF_UNSPEC;
962146cd1bcSHajimu UMEMOTO 	aio->aio_srcscope = -1;
963146cd1bcSHajimu UMEMOTO 
964146cd1bcSHajimu UMEMOTO 	switch(ss.ss_family) {
965146cd1bcSHajimu UMEMOTO 	case AF_INET:
966146cd1bcSHajimu UMEMOTO 		((struct sockaddr_in *)&ss)->sin_port = htons(1);
967146cd1bcSHajimu UMEMOTO 		break;
968146cd1bcSHajimu UMEMOTO #ifdef INET6
969146cd1bcSHajimu UMEMOTO 	case AF_INET6:
970146cd1bcSHajimu UMEMOTO 		((struct sockaddr_in6 *)&ss)->sin6_port = htons(1);
971146cd1bcSHajimu UMEMOTO 		break;
972146cd1bcSHajimu UMEMOTO #endif
973146cd1bcSHajimu UMEMOTO 	default:		/* ignore unsupported AFs explicitly */
974146cd1bcSHajimu UMEMOTO 		return;
975146cd1bcSHajimu UMEMOTO 	}
976146cd1bcSHajimu UMEMOTO 
977146cd1bcSHajimu UMEMOTO 	/* open a socket to get the source address for the given dst */
978146cd1bcSHajimu UMEMOTO 	if ((s = _socket(ss.ss_family, SOCK_DGRAM, IPPROTO_UDP)) < 0)
979146cd1bcSHajimu UMEMOTO 		return;		/* give up */
980146cd1bcSHajimu UMEMOTO 	if (_connect(s, (struct sockaddr *)&ss, ss.ss_len) < 0)
981146cd1bcSHajimu UMEMOTO 		goto cleanup;
982146cd1bcSHajimu UMEMOTO 	srclen = ss.ss_len;
983146cd1bcSHajimu UMEMOTO 	if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) {
984146cd1bcSHajimu UMEMOTO 		aio->aio_srcsa.sa_family = AF_UNSPEC;
985146cd1bcSHajimu UMEMOTO 		goto cleanup;
986146cd1bcSHajimu UMEMOTO 	}
987146cd1bcSHajimu UMEMOTO 	aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa);
988146cd1bcSHajimu UMEMOTO 	aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph);
989146cd1bcSHajimu UMEMOTO 	aio->aio_matchlen = matchlen(&aio->aio_srcsa, (struct sockaddr *)&ss);
990146cd1bcSHajimu UMEMOTO #ifdef INET6
991146cd1bcSHajimu UMEMOTO 	if (ss.ss_family == AF_INET6) {
992146cd1bcSHajimu UMEMOTO 		struct in6_ifreq ifr6;
993146cd1bcSHajimu UMEMOTO 		u_int32_t flags6;
994146cd1bcSHajimu UMEMOTO 
995146cd1bcSHajimu UMEMOTO 		/* XXX: interface name should not be hardcoded */
996146cd1bcSHajimu UMEMOTO 		strncpy(ifr6.ifr_name, "lo0", sizeof(ifr6.ifr_name));
997146cd1bcSHajimu UMEMOTO 		memset(&ifr6, 0, sizeof(ifr6));
998146cd1bcSHajimu UMEMOTO 		memcpy(&ifr6.ifr_addr, &ss, ss.ss_len);
999146cd1bcSHajimu UMEMOTO 		if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) {
1000146cd1bcSHajimu UMEMOTO 			flags6 = ifr6.ifr_ifru.ifru_flags6;
1001146cd1bcSHajimu UMEMOTO 			if ((flags6 & IN6_IFF_DEPRECATED))
1002146cd1bcSHajimu UMEMOTO 				aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED;
1003146cd1bcSHajimu UMEMOTO 		}
1004146cd1bcSHajimu UMEMOTO 	}
1005146cd1bcSHajimu UMEMOTO #endif
1006146cd1bcSHajimu UMEMOTO 
1007146cd1bcSHajimu UMEMOTO   cleanup:
1008146cd1bcSHajimu UMEMOTO 	_close(s);
1009146cd1bcSHajimu UMEMOTO 	return;
1010146cd1bcSHajimu UMEMOTO }
1011146cd1bcSHajimu UMEMOTO 
1012146cd1bcSHajimu UMEMOTO static int
1013146cd1bcSHajimu UMEMOTO matchlen(src, dst)
1014146cd1bcSHajimu UMEMOTO 	struct sockaddr *src, *dst;
1015146cd1bcSHajimu UMEMOTO {
1016146cd1bcSHajimu UMEMOTO 	int match = 0;
1017146cd1bcSHajimu UMEMOTO 	u_char *s, *d;
1018146cd1bcSHajimu UMEMOTO 	u_char *lim, r;
1019146cd1bcSHajimu UMEMOTO 	int addrlen;
1020146cd1bcSHajimu UMEMOTO 
1021146cd1bcSHajimu UMEMOTO 	switch (src->sa_family) {
1022146cd1bcSHajimu UMEMOTO #ifdef INET6
1023146cd1bcSHajimu UMEMOTO 	case AF_INET6:
1024146cd1bcSHajimu UMEMOTO 		s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr;
1025146cd1bcSHajimu UMEMOTO 		d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr;
1026146cd1bcSHajimu UMEMOTO 		addrlen = sizeof(struct in6_addr);
1027146cd1bcSHajimu UMEMOTO 		lim = s + addrlen;
1028146cd1bcSHajimu UMEMOTO 		break;
1029146cd1bcSHajimu UMEMOTO #endif
1030146cd1bcSHajimu UMEMOTO 	case AF_INET:
1031fd57e549SGeorge V. Neville-Neil 		s = (u_char *)&((struct sockaddr_in *)src)->sin_addr;
1032fd57e549SGeorge V. Neville-Neil 		d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr;
1033146cd1bcSHajimu UMEMOTO 		addrlen = sizeof(struct in_addr);
1034146cd1bcSHajimu UMEMOTO 		lim = s + addrlen;
1035146cd1bcSHajimu UMEMOTO 		break;
1036146cd1bcSHajimu UMEMOTO 	default:
1037146cd1bcSHajimu UMEMOTO 		return(0);
1038146cd1bcSHajimu UMEMOTO 	}
1039146cd1bcSHajimu UMEMOTO 
1040146cd1bcSHajimu UMEMOTO 	while (s < lim)
1041146cd1bcSHajimu UMEMOTO 		if ((r = (*d++ ^ *s++)) != 0) {
1042146cd1bcSHajimu UMEMOTO 			while (r < addrlen * 8) {
1043146cd1bcSHajimu UMEMOTO 				match++;
1044146cd1bcSHajimu UMEMOTO 				r <<= 1;
1045146cd1bcSHajimu UMEMOTO 			}
1046146cd1bcSHajimu UMEMOTO 			break;
1047146cd1bcSHajimu UMEMOTO 		} else
1048146cd1bcSHajimu UMEMOTO 			match += 8;
1049146cd1bcSHajimu UMEMOTO 	return(match);
1050146cd1bcSHajimu UMEMOTO }
1051146cd1bcSHajimu UMEMOTO 
1052146cd1bcSHajimu UMEMOTO static int
1053146cd1bcSHajimu UMEMOTO comp_dst(arg1, arg2)
1054146cd1bcSHajimu UMEMOTO 	const void *arg1, *arg2;
1055146cd1bcSHajimu UMEMOTO {
1056146cd1bcSHajimu UMEMOTO 	const struct hp_order *dst1 = arg1, *dst2 = arg2;
1057146cd1bcSHajimu UMEMOTO 
1058146cd1bcSHajimu UMEMOTO 	/*
1059146cd1bcSHajimu UMEMOTO 	 * Rule 1: Avoid unusable destinations.
1060146cd1bcSHajimu UMEMOTO 	 * XXX: we currently do not consider if an appropriate route exists.
1061146cd1bcSHajimu UMEMOTO 	 */
1062146cd1bcSHajimu UMEMOTO 	if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
1063146cd1bcSHajimu UMEMOTO 	    dst2->aio_srcsa.sa_family == AF_UNSPEC) {
1064146cd1bcSHajimu UMEMOTO 		return(-1);
1065146cd1bcSHajimu UMEMOTO 	}
1066146cd1bcSHajimu UMEMOTO 	if (dst1->aio_srcsa.sa_family == AF_UNSPEC &&
1067146cd1bcSHajimu UMEMOTO 	    dst2->aio_srcsa.sa_family != AF_UNSPEC) {
1068146cd1bcSHajimu UMEMOTO 		return(1);
1069146cd1bcSHajimu UMEMOTO 	}
1070146cd1bcSHajimu UMEMOTO 
1071146cd1bcSHajimu UMEMOTO 	/* Rule 2: Prefer matching scope. */
1072146cd1bcSHajimu UMEMOTO 	if (dst1->aio_dstscope == dst1->aio_srcscope &&
1073146cd1bcSHajimu UMEMOTO 	    dst2->aio_dstscope != dst2->aio_srcscope) {
1074146cd1bcSHajimu UMEMOTO 		return(-1);
1075146cd1bcSHajimu UMEMOTO 	}
1076146cd1bcSHajimu UMEMOTO 	if (dst1->aio_dstscope != dst1->aio_srcscope &&
1077146cd1bcSHajimu UMEMOTO 	    dst2->aio_dstscope == dst2->aio_srcscope) {
1078146cd1bcSHajimu UMEMOTO 		return(1);
1079146cd1bcSHajimu UMEMOTO 	}
1080146cd1bcSHajimu UMEMOTO 
1081146cd1bcSHajimu UMEMOTO 	/* Rule 3: Avoid deprecated addresses. */
1082146cd1bcSHajimu UMEMOTO 	if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
1083146cd1bcSHajimu UMEMOTO 	    dst2->aio_srcsa.sa_family != AF_UNSPEC) {
1084146cd1bcSHajimu UMEMOTO 		if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
1085146cd1bcSHajimu UMEMOTO 		    (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
1086146cd1bcSHajimu UMEMOTO 			return(-1);
1087146cd1bcSHajimu UMEMOTO 		}
1088146cd1bcSHajimu UMEMOTO 		if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
1089146cd1bcSHajimu UMEMOTO 		    !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
1090146cd1bcSHajimu UMEMOTO 			return(1);
1091146cd1bcSHajimu UMEMOTO 		}
1092146cd1bcSHajimu UMEMOTO 	}
1093146cd1bcSHajimu UMEMOTO 
1094146cd1bcSHajimu UMEMOTO 	/* Rule 4: Prefer home addresses. */
1095146cd1bcSHajimu UMEMOTO 	/* XXX: not implemented yet */
1096146cd1bcSHajimu UMEMOTO 
1097146cd1bcSHajimu UMEMOTO 	/* Rule 5: Prefer matching label. */
1098146cd1bcSHajimu UMEMOTO #ifdef INET6
1099146cd1bcSHajimu UMEMOTO 	if (dst1->aio_srcpolicy && dst1->aio_dstpolicy &&
1100146cd1bcSHajimu UMEMOTO 	    dst1->aio_srcpolicy->pc_policy.label ==
1101146cd1bcSHajimu UMEMOTO 	    dst1->aio_dstpolicy->pc_policy.label &&
1102146cd1bcSHajimu UMEMOTO 	    (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL ||
1103146cd1bcSHajimu UMEMOTO 	     dst2->aio_srcpolicy->pc_policy.label !=
1104146cd1bcSHajimu UMEMOTO 	     dst2->aio_dstpolicy->pc_policy.label)) {
1105146cd1bcSHajimu UMEMOTO 		return(-1);
1106146cd1bcSHajimu UMEMOTO 	}
1107146cd1bcSHajimu UMEMOTO 	if (dst2->aio_srcpolicy && dst2->aio_dstpolicy &&
1108146cd1bcSHajimu UMEMOTO 	    dst2->aio_srcpolicy->pc_policy.label ==
1109146cd1bcSHajimu UMEMOTO 	    dst2->aio_dstpolicy->pc_policy.label &&
1110146cd1bcSHajimu UMEMOTO 	    (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL ||
1111146cd1bcSHajimu UMEMOTO 	     dst1->aio_srcpolicy->pc_policy.label !=
1112146cd1bcSHajimu UMEMOTO 	     dst1->aio_dstpolicy->pc_policy.label)) {
1113146cd1bcSHajimu UMEMOTO 		return(1);
1114146cd1bcSHajimu UMEMOTO 	}
1115146cd1bcSHajimu UMEMOTO #endif
1116146cd1bcSHajimu UMEMOTO 
1117146cd1bcSHajimu UMEMOTO 	/* Rule 6: Prefer higher precedence. */
1118146cd1bcSHajimu UMEMOTO #ifdef INET6
1119146cd1bcSHajimu UMEMOTO 	if (dst1->aio_dstpolicy &&
1120146cd1bcSHajimu UMEMOTO 	    (dst2->aio_dstpolicy == NULL ||
1121146cd1bcSHajimu UMEMOTO 	     dst1->aio_dstpolicy->pc_policy.preced >
1122146cd1bcSHajimu UMEMOTO 	     dst2->aio_dstpolicy->pc_policy.preced)) {
1123146cd1bcSHajimu UMEMOTO 		return(-1);
1124146cd1bcSHajimu UMEMOTO 	}
1125146cd1bcSHajimu UMEMOTO 	if (dst2->aio_dstpolicy &&
1126146cd1bcSHajimu UMEMOTO 	    (dst1->aio_dstpolicy == NULL ||
1127146cd1bcSHajimu UMEMOTO 	     dst2->aio_dstpolicy->pc_policy.preced >
1128146cd1bcSHajimu UMEMOTO 	     dst1->aio_dstpolicy->pc_policy.preced)) {
1129146cd1bcSHajimu UMEMOTO 		return(1);
1130146cd1bcSHajimu UMEMOTO 	}
1131146cd1bcSHajimu UMEMOTO #endif
1132146cd1bcSHajimu UMEMOTO 
1133146cd1bcSHajimu UMEMOTO 	/* Rule 7: Prefer native transport. */
1134146cd1bcSHajimu UMEMOTO 	/* XXX: not implemented yet */
1135146cd1bcSHajimu UMEMOTO 
1136146cd1bcSHajimu UMEMOTO 	/* Rule 8: Prefer smaller scope. */
1137146cd1bcSHajimu UMEMOTO 	if (dst1->aio_dstscope >= 0 &&
1138146cd1bcSHajimu UMEMOTO 	    dst1->aio_dstscope < dst2->aio_dstscope) {
1139146cd1bcSHajimu UMEMOTO 		return(-1);
1140146cd1bcSHajimu UMEMOTO 	}
1141146cd1bcSHajimu UMEMOTO 	if (dst2->aio_dstscope >= 0 &&
1142146cd1bcSHajimu UMEMOTO 	    dst2->aio_dstscope < dst1->aio_dstscope) {
1143146cd1bcSHajimu UMEMOTO 		return(1);
1144146cd1bcSHajimu UMEMOTO 	}
1145146cd1bcSHajimu UMEMOTO 
1146146cd1bcSHajimu UMEMOTO 	/*
1147146cd1bcSHajimu UMEMOTO 	 * Rule 9: Use longest matching prefix.
1148146cd1bcSHajimu UMEMOTO 	 * We compare the match length in a same AF only.
1149146cd1bcSHajimu UMEMOTO 	 */
1150146cd1bcSHajimu UMEMOTO 	if (dst1->aio_sa.sa_family == dst2->aio_sa.sa_family) {
1151146cd1bcSHajimu UMEMOTO 		if (dst1->aio_matchlen > dst2->aio_matchlen) {
1152146cd1bcSHajimu UMEMOTO 			return(-1);
1153146cd1bcSHajimu UMEMOTO 		}
1154146cd1bcSHajimu UMEMOTO 		if (dst1->aio_matchlen < dst2->aio_matchlen) {
1155146cd1bcSHajimu UMEMOTO 			return(1);
1156146cd1bcSHajimu UMEMOTO 		}
1157146cd1bcSHajimu UMEMOTO 	}
1158146cd1bcSHajimu UMEMOTO 
1159146cd1bcSHajimu UMEMOTO 	/* Rule 10: Otherwise, leave the order unchanged. */
1160146cd1bcSHajimu UMEMOTO 	return(-1);
1161146cd1bcSHajimu UMEMOTO }
1162146cd1bcSHajimu UMEMOTO 
1163146cd1bcSHajimu UMEMOTO /*
1164146cd1bcSHajimu UMEMOTO  * Copy from scope.c.
1165146cd1bcSHajimu UMEMOTO  * XXX: we should standardize the functions and link them as standard
1166146cd1bcSHajimu UMEMOTO  * library.
1167146cd1bcSHajimu UMEMOTO  */
1168146cd1bcSHajimu UMEMOTO static int
1169146cd1bcSHajimu UMEMOTO gai_addr2scopetype(sa)
1170146cd1bcSHajimu UMEMOTO 	struct sockaddr *sa;
1171146cd1bcSHajimu UMEMOTO {
1172146cd1bcSHajimu UMEMOTO #ifdef INET6
1173146cd1bcSHajimu UMEMOTO 	struct sockaddr_in6 *sa6;
1174146cd1bcSHajimu UMEMOTO #endif
1175146cd1bcSHajimu UMEMOTO 	struct sockaddr_in *sa4;
1176146cd1bcSHajimu UMEMOTO 
1177146cd1bcSHajimu UMEMOTO 	switch(sa->sa_family) {
1178146cd1bcSHajimu UMEMOTO #ifdef INET6
1179146cd1bcSHajimu UMEMOTO 	case AF_INET6:
1180146cd1bcSHajimu UMEMOTO 		sa6 = (struct sockaddr_in6 *)sa;
1181146cd1bcSHajimu UMEMOTO 		if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
1182146cd1bcSHajimu UMEMOTO 			/* just use the scope field of the multicast address */
1183146cd1bcSHajimu UMEMOTO 			return(sa6->sin6_addr.s6_addr[2] & 0x0f);
1184146cd1bcSHajimu UMEMOTO 		}
1185146cd1bcSHajimu UMEMOTO 		/*
1186146cd1bcSHajimu UMEMOTO 		 * Unicast addresses: map scope type to corresponding scope
1187146cd1bcSHajimu UMEMOTO 		 * value defined for multcast addresses.
1188146cd1bcSHajimu UMEMOTO 		 * XXX: hardcoded scope type values are bad...
1189146cd1bcSHajimu UMEMOTO 		 */
1190146cd1bcSHajimu UMEMOTO 		if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr))
1191146cd1bcSHajimu UMEMOTO 			return(1); /* node local scope */
1192146cd1bcSHajimu UMEMOTO 		if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr))
1193146cd1bcSHajimu UMEMOTO 			return(2); /* link-local scope */
1194146cd1bcSHajimu UMEMOTO 		if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr))
1195146cd1bcSHajimu UMEMOTO 			return(5); /* site-local scope */
1196146cd1bcSHajimu UMEMOTO 		return(14);	/* global scope */
1197146cd1bcSHajimu UMEMOTO 		break;
1198146cd1bcSHajimu UMEMOTO #endif
1199146cd1bcSHajimu UMEMOTO 	case AF_INET:
1200146cd1bcSHajimu UMEMOTO 		/*
1201146cd1bcSHajimu UMEMOTO 		 * IPv4 pseudo scoping according to RFC 3484.
1202146cd1bcSHajimu UMEMOTO 		 */
1203146cd1bcSHajimu UMEMOTO 		sa4 = (struct sockaddr_in *)sa;
1204146cd1bcSHajimu UMEMOTO 		/* IPv4 autoconfiguration addresses have link-local scope. */
1205146cd1bcSHajimu UMEMOTO 		if (((u_char *)&sa4->sin_addr)[0] == 169 &&
1206146cd1bcSHajimu UMEMOTO 		    ((u_char *)&sa4->sin_addr)[1] == 254)
1207146cd1bcSHajimu UMEMOTO 			return(2);
1208146cd1bcSHajimu UMEMOTO 		/* Private addresses have site-local scope. */
1209146cd1bcSHajimu UMEMOTO 		if (((u_char *)&sa4->sin_addr)[0] == 10 ||
1210146cd1bcSHajimu UMEMOTO 		    (((u_char *)&sa4->sin_addr)[0] == 172 &&
1211146cd1bcSHajimu UMEMOTO 		     (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) ||
1212146cd1bcSHajimu UMEMOTO 		    (((u_char *)&sa4->sin_addr)[0] == 192 &&
1213146cd1bcSHajimu UMEMOTO 		     ((u_char *)&sa4->sin_addr)[1] == 168))
1214146cd1bcSHajimu UMEMOTO 			return(14);	/* XXX: It should be 5 unless NAT */
1215146cd1bcSHajimu UMEMOTO 		/* Loopback addresses have link-local scope. */
1216146cd1bcSHajimu UMEMOTO 		if (((u_char *)&sa4->sin_addr)[0] == 127)
1217146cd1bcSHajimu UMEMOTO 			return(2);
1218146cd1bcSHajimu UMEMOTO 		return(14);
1219146cd1bcSHajimu UMEMOTO 		break;
1220146cd1bcSHajimu UMEMOTO 	default:
1221146cd1bcSHajimu UMEMOTO 		errno = EAFNOSUPPORT; /* is this a good error? */
1222146cd1bcSHajimu UMEMOTO 		return(-1);
1223146cd1bcSHajimu UMEMOTO 	}
1224146cd1bcSHajimu UMEMOTO }
1225146cd1bcSHajimu UMEMOTO 
1226b8b31f33SHajimu UMEMOTO /*
12277d56d374SYoshinobu Inoue  * FILES (/etc/hosts)
12287d56d374SYoshinobu Inoue  */
12297d56d374SYoshinobu Inoue 
12307d56d374SYoshinobu Inoue static FILE *
12317d56d374SYoshinobu Inoue _files_open(int *errp)
12327d56d374SYoshinobu Inoue {
12337d56d374SYoshinobu Inoue 	FILE *fp;
12347d56d374SYoshinobu Inoue 	fp = fopen(_PATH_HOSTS, "r");
12357d56d374SYoshinobu Inoue 	if (fp == NULL)
12367d56d374SYoshinobu Inoue 		*errp = NO_RECOVERY;
12377d56d374SYoshinobu Inoue 	return fp;
12387d56d374SYoshinobu Inoue }
12397d56d374SYoshinobu Inoue 
1240248aee62SJacques Vidrine static int
1241248aee62SJacques Vidrine _files_ghbyname(void *rval, void *cb_data, va_list ap)
12427d56d374SYoshinobu Inoue {
1243248aee62SJacques Vidrine 	const char *name;
1244248aee62SJacques Vidrine 	int af;
1245248aee62SJacques Vidrine 	int *errp;
12467d56d374SYoshinobu Inoue 	int match, nalias;
12477d56d374SYoshinobu Inoue 	char *p, *line, *addrstr, *cname;
12487d56d374SYoshinobu Inoue 	FILE *fp;
12497d56d374SYoshinobu Inoue 	struct hostent *rethp, *hp, hpbuf;
12507d56d374SYoshinobu Inoue 	char *aliases[MAXALIASES + 1], *addrs[2];
12517d56d374SYoshinobu Inoue 	union inx_addr addrbuf;
12527d56d374SYoshinobu Inoue 	char buf[BUFSIZ];
12537d56d374SYoshinobu Inoue 
1254248aee62SJacques Vidrine 	name = va_arg(ap, const char *);
1255248aee62SJacques Vidrine 	af = va_arg(ap, int);
1256248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
1257248aee62SJacques Vidrine 
1258248aee62SJacques Vidrine 	*(struct hostent **)rval = NULL;
1259248aee62SJacques Vidrine 
12607d56d374SYoshinobu Inoue 	if ((fp = _files_open(errp)) == NULL)
1261248aee62SJacques Vidrine 		return NS_UNAVAIL;
12627d56d374SYoshinobu Inoue 	rethp = hp = NULL;
12637d56d374SYoshinobu Inoue 
12647d56d374SYoshinobu Inoue 	while (fgets(buf, sizeof(buf), fp)) {
12657d56d374SYoshinobu Inoue 		line = buf;
12667d56d374SYoshinobu Inoue 		if ((addrstr = _hgetword(&line)) == NULL
12677d56d374SYoshinobu Inoue 		||  (cname = _hgetword(&line)) == NULL)
12687d56d374SYoshinobu Inoue 			continue;
12697d56d374SYoshinobu Inoue 		match = (strcasecmp(cname, name) == 0);
12707d56d374SYoshinobu Inoue 		nalias = 0;
12717d56d374SYoshinobu Inoue 		while ((p = _hgetword(&line)) != NULL) {
12727d56d374SYoshinobu Inoue 			if (!match)
12737d56d374SYoshinobu Inoue 				match = (strcasecmp(p, name) == 0);
12747d56d374SYoshinobu Inoue 			if (nalias < MAXALIASES)
12757d56d374SYoshinobu Inoue 				aliases[nalias++] = p;
12767d56d374SYoshinobu Inoue 		}
12777d56d374SYoshinobu Inoue 		if (!match)
12787d56d374SYoshinobu Inoue 			continue;
12790fbf0979SHajimu UMEMOTO 		switch (af) {
1280e6f35403SYoshinobu Inoue 		case AF_INET:
1281e6f35403SYoshinobu Inoue 			if (inet_aton(addrstr, (struct in_addr *)&addrbuf)
1282e6f35403SYoshinobu Inoue 			    != 1) {
12837d56d374SYoshinobu Inoue 				*errp = NO_DATA;	/* name found */
12847d56d374SYoshinobu Inoue 				continue;
12857d56d374SYoshinobu Inoue 			}
1286e6f35403SYoshinobu Inoue 			break;
1287e6f35403SYoshinobu Inoue #ifdef INET6
1288e6f35403SYoshinobu Inoue 		case AF_INET6:
1289e6f35403SYoshinobu Inoue 			if (inet_pton(af, addrstr, &addrbuf) != 1) {
1290e6f35403SYoshinobu Inoue 				*errp = NO_DATA;	/* name found */
1291e6f35403SYoshinobu Inoue 				continue;
1292e6f35403SYoshinobu Inoue 			}
1293e6f35403SYoshinobu Inoue 			break;
1294e6f35403SYoshinobu Inoue #endif
1295e6f35403SYoshinobu Inoue 		}
12967d56d374SYoshinobu Inoue 		hp = &hpbuf;
12977d56d374SYoshinobu Inoue 		hp->h_name = cname;
12987d56d374SYoshinobu Inoue 		hp->h_aliases = aliases;
12997d56d374SYoshinobu Inoue 		aliases[nalias] = NULL;
13007d56d374SYoshinobu Inoue 		hp->h_addrtype = af;
13017d56d374SYoshinobu Inoue 		hp->h_length = ADDRLEN(af);
13027d56d374SYoshinobu Inoue 		hp->h_addr_list = addrs;
13037d56d374SYoshinobu Inoue 		addrs[0] = (char *)&addrbuf;
13047d56d374SYoshinobu Inoue 		addrs[1] = NULL;
13057d56d374SYoshinobu Inoue 		hp = _hpcopy(hp, errp);
13067d56d374SYoshinobu Inoue 		rethp = _hpmerge(rethp, hp, errp);
13077d56d374SYoshinobu Inoue 	}
13087d56d374SYoshinobu Inoue 	fclose(fp);
1309248aee62SJacques Vidrine 	*(struct hostent **)rval = rethp;
1310248aee62SJacques Vidrine 	return (rethp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
13117d56d374SYoshinobu Inoue }
13127d56d374SYoshinobu Inoue 
1313248aee62SJacques Vidrine static int
1314248aee62SJacques Vidrine _files_ghbyaddr(void *rval, void *cb_data, va_list ap)
13157d56d374SYoshinobu Inoue {
1316248aee62SJacques Vidrine 	const void *addr;
1317248aee62SJacques Vidrine 	int addrlen;
1318248aee62SJacques Vidrine 	int af;
1319248aee62SJacques Vidrine 	int *errp;
13207d56d374SYoshinobu Inoue 	int nalias;
13217d56d374SYoshinobu Inoue 	char *p, *line;
13227d56d374SYoshinobu Inoue 	FILE *fp;
13237d56d374SYoshinobu Inoue 	struct hostent *hp, hpbuf;
13247d56d374SYoshinobu Inoue 	char *aliases[MAXALIASES + 1], *addrs[2];
13257d56d374SYoshinobu Inoue 	union inx_addr addrbuf;
13267d56d374SYoshinobu Inoue 	char buf[BUFSIZ];
13277d56d374SYoshinobu Inoue 
1328248aee62SJacques Vidrine 	addr = va_arg(ap, const void *);
1329248aee62SJacques Vidrine 	addrlen = va_arg(ap, int);
1330248aee62SJacques Vidrine 	af = va_arg(ap, int);
1331248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
1332248aee62SJacques Vidrine 
1333248aee62SJacques Vidrine 	*(struct hostent**)rval = NULL;
1334248aee62SJacques Vidrine 
13357d56d374SYoshinobu Inoue 	if ((fp = _files_open(errp)) == NULL)
1336248aee62SJacques Vidrine 		return NS_UNAVAIL;
13377d56d374SYoshinobu Inoue 	hp = NULL;
13387d56d374SYoshinobu Inoue 	while (fgets(buf, sizeof(buf), fp)) {
13397d56d374SYoshinobu Inoue 		line = buf;
13407d56d374SYoshinobu Inoue 		if ((p = _hgetword(&line)) == NULL
1341be26adb5SYoshinobu Inoue 		||  (af == AF_INET
1342be26adb5SYoshinobu Inoue 		     ? inet_aton(p, (struct in_addr *)&addrbuf)
1343be26adb5SYoshinobu Inoue 		     : inet_pton(af, p, &addrbuf)) != 1
13447d56d374SYoshinobu Inoue 		||  memcmp(addr, &addrbuf, addrlen) != 0
13457d56d374SYoshinobu Inoue 		||  (p = _hgetword(&line)) == NULL)
13467d56d374SYoshinobu Inoue 			continue;
13477d56d374SYoshinobu Inoue 		hp = &hpbuf;
13487d56d374SYoshinobu Inoue 		hp->h_name = p;
13497d56d374SYoshinobu Inoue 		hp->h_aliases = aliases;
13507d56d374SYoshinobu Inoue 		nalias = 0;
13517d56d374SYoshinobu Inoue 		while ((p = _hgetword(&line)) != NULL) {
13527d56d374SYoshinobu Inoue 			if (nalias < MAXALIASES)
13537d56d374SYoshinobu Inoue 				aliases[nalias++] = p;
13547d56d374SYoshinobu Inoue 		}
13557d56d374SYoshinobu Inoue 		aliases[nalias] = NULL;
13567d56d374SYoshinobu Inoue 		hp->h_addrtype = af;
13577d56d374SYoshinobu Inoue 		hp->h_length = addrlen;
13587d56d374SYoshinobu Inoue 		hp->h_addr_list = addrs;
13597d56d374SYoshinobu Inoue 		addrs[0] = (char *)&addrbuf;
13607d56d374SYoshinobu Inoue 		addrs[1] = NULL;
13617d56d374SYoshinobu Inoue 		hp = _hpcopy(hp, errp);
13627d56d374SYoshinobu Inoue 		break;
13637d56d374SYoshinobu Inoue 	}
13647d56d374SYoshinobu Inoue 	fclose(fp);
1365248aee62SJacques Vidrine 	*(struct hostent **)rval = hp;
1366248aee62SJacques Vidrine 	return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
13677d56d374SYoshinobu Inoue }
13687d56d374SYoshinobu Inoue 
1369f468e837SHajimu UMEMOTO #ifdef YP
137063858012SJonathan Lemon /*
137163858012SJonathan Lemon  * NIS
137263858012SJonathan Lemon  *
13736bd1d1a1SHajimu UMEMOTO  * XXX actually a hack.
137463858012SJonathan Lemon  */
1375248aee62SJacques Vidrine static int
1376248aee62SJacques Vidrine _nis_ghbyname(void *rval, void *cb_data, va_list ap)
137763858012SJonathan Lemon {
1378248aee62SJacques Vidrine 	const char *name;
1379248aee62SJacques Vidrine 	int af;
1380248aee62SJacques Vidrine 	int *errp;
138138775c5eSJonathan Lemon 	struct hostent *hp = NULL;
138263858012SJonathan Lemon 
1383248aee62SJacques Vidrine 	name = va_arg(ap, const char *);
1384248aee62SJacques Vidrine 	af = va_arg(ap, int);
1385248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
1386248aee62SJacques Vidrine 
138763858012SJonathan Lemon 	hp = _gethostbynisname(name, af);
138863858012SJonathan Lemon 	if (hp != NULL)
138963858012SJonathan Lemon 		hp = _hpcopy(hp, errp);
1390248aee62SJacques Vidrine 
1391248aee62SJacques Vidrine 	*(struct hostent **)rval = hp;
1392248aee62SJacques Vidrine 	return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
139363858012SJonathan Lemon }
139463858012SJonathan Lemon 
1395248aee62SJacques Vidrine static int
1396248aee62SJacques Vidrine _nis_ghbyaddr(void *rval, void *cb_data, va_list ap)
139763858012SJonathan Lemon {
1398248aee62SJacques Vidrine 	const void *addr;
1399248aee62SJacques Vidrine 	int addrlen;
1400248aee62SJacques Vidrine 	int af;
1401248aee62SJacques Vidrine 	int *errp;
140263858012SJonathan Lemon 	struct hostent *hp = NULL;
140363858012SJonathan Lemon 
1404248aee62SJacques Vidrine 	addr = va_arg(ap, const void *);
1405248aee62SJacques Vidrine 	addrlen = va_arg(ap, int);
1406248aee62SJacques Vidrine 	af = va_arg(ap, int);
1407248aee62SJacques Vidrine 
140863858012SJonathan Lemon 	hp = _gethostbynisaddr(addr, addrlen, af);
140963858012SJonathan Lemon 	if (hp != NULL)
141063858012SJonathan Lemon 		hp = _hpcopy(hp, errp);
1411248aee62SJacques Vidrine 	*(struct hostent **)rval = hp;
1412248aee62SJacques Vidrine 	return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
14136bd1d1a1SHajimu UMEMOTO }
1414f468e837SHajimu UMEMOTO #endif
14157d56d374SYoshinobu Inoue 
14169832619cSHajimu UMEMOTO #define	MAXPACKET	(64*1024)
141773b30f0cSJun-ichiro itojun Hagino 
141873b30f0cSJun-ichiro itojun Hagino typedef union {
141973b30f0cSJun-ichiro itojun Hagino 	HEADER hdr;
142073b30f0cSJun-ichiro itojun Hagino 	u_char buf[MAXPACKET];
142173b30f0cSJun-ichiro itojun Hagino } querybuf;
142273b30f0cSJun-ichiro itojun Hagino 
14231372519bSDavid E. O'Brien static struct hostent *getanswer(const querybuf *, int, const char *, int,
14241372519bSDavid E. O'Brien 	    struct hostent *, int *);
142573b30f0cSJun-ichiro itojun Hagino 
142673b30f0cSJun-ichiro itojun Hagino /*
142773b30f0cSJun-ichiro itojun Hagino  * we don't need to take care about sorting, nor IPv4 mapped address here.
142873b30f0cSJun-ichiro itojun Hagino  */
14297d56d374SYoshinobu Inoue static struct hostent *
143073b30f0cSJun-ichiro itojun Hagino getanswer(answer, anslen, qname, qtype, template, errp)
143173b30f0cSJun-ichiro itojun Hagino 	const querybuf *answer;
1432e6f35403SYoshinobu Inoue 	int anslen;
143373b30f0cSJun-ichiro itojun Hagino 	const char *qname;
1434e6f35403SYoshinobu Inoue 	int qtype;
143573b30f0cSJun-ichiro itojun Hagino 	struct hostent *template;
1436e6f35403SYoshinobu Inoue 	int *errp;
14377d56d374SYoshinobu Inoue {
14388fb3f3f6SDavid E. O'Brien 	const HEADER *hp;
14398fb3f3f6SDavid E. O'Brien 	const u_char *cp;
14408fb3f3f6SDavid E. O'Brien 	int n;
144173b30f0cSJun-ichiro itojun Hagino 	const u_char *eom, *erdata;
1442d6af58f5SWarner Losh 	char *bp, *ep, **ap, **hap;
1443d6af58f5SWarner Losh 	int type, class, ancount, qdcount;
144473b30f0cSJun-ichiro itojun Hagino 	int haveanswer, had_error;
144573b30f0cSJun-ichiro itojun Hagino 	char tbuf[MAXDNAME];
144673b30f0cSJun-ichiro itojun Hagino 	const char *tname;
1447c05ac53bSDavid E. O'Brien 	int (*name_ok)(const char *);
144873b30f0cSJun-ichiro itojun Hagino 	static char *h_addr_ptrs[MAXADDRS + 1];
144973b30f0cSJun-ichiro itojun Hagino 	static char *host_aliases[MAXALIASES];
145073b30f0cSJun-ichiro itojun Hagino 	static char hostbuf[8*1024];
14517d56d374SYoshinobu Inoue 
145273b30f0cSJun-ichiro itojun Hagino #define BOUNDED_INCR(x) \
145373b30f0cSJun-ichiro itojun Hagino 	do { \
145473b30f0cSJun-ichiro itojun Hagino 		cp += x; \
145573b30f0cSJun-ichiro itojun Hagino 		if (cp > eom) { \
145673b30f0cSJun-ichiro itojun Hagino 			*errp = NO_RECOVERY; \
145773b30f0cSJun-ichiro itojun Hagino 			return (NULL); \
145873b30f0cSJun-ichiro itojun Hagino 		} \
145973b30f0cSJun-ichiro itojun Hagino 	} while (0)
14607d56d374SYoshinobu Inoue 
146173b30f0cSJun-ichiro itojun Hagino #define BOUNDS_CHECK(ptr, count) \
146273b30f0cSJun-ichiro itojun Hagino 	do { \
146373b30f0cSJun-ichiro itojun Hagino 		if ((ptr) + (count) > eom) { \
146473b30f0cSJun-ichiro itojun Hagino 			*errp = NO_RECOVERY; \
146573b30f0cSJun-ichiro itojun Hagino 			return (NULL); \
146673b30f0cSJun-ichiro itojun Hagino 		} \
146773b30f0cSJun-ichiro itojun Hagino 	} while (0)
146873b30f0cSJun-ichiro itojun Hagino 
14693f587e57SKris Kennaway /* XXX do {} while (0) cannot be put here */
147073b30f0cSJun-ichiro itojun Hagino #define DNS_ASSERT(x) \
14713f587e57SKris Kennaway 	{				\
147273b30f0cSJun-ichiro itojun Hagino 		if (!(x)) {		\
147373b30f0cSJun-ichiro itojun Hagino 			cp += n;	\
147473b30f0cSJun-ichiro itojun Hagino 			continue;	\
147573b30f0cSJun-ichiro itojun Hagino 		}			\
14763f587e57SKris Kennaway 	}
147773b30f0cSJun-ichiro itojun Hagino 
14783f587e57SKris Kennaway /* XXX do {} while (0) cannot be put here */
147973b30f0cSJun-ichiro itojun Hagino #define DNS_FATAL(x) \
14803f587e57SKris Kennaway 	{				\
148173b30f0cSJun-ichiro itojun Hagino 		if (!(x)) {		\
148273b30f0cSJun-ichiro itojun Hagino 			had_error++;	\
148373b30f0cSJun-ichiro itojun Hagino 			continue;	\
148473b30f0cSJun-ichiro itojun Hagino 		}			\
14853f587e57SKris Kennaway 	}
148673b30f0cSJun-ichiro itojun Hagino 
148773b30f0cSJun-ichiro itojun Hagino 	tname = qname;
148873b30f0cSJun-ichiro itojun Hagino 	template->h_name = NULL;
148973b30f0cSJun-ichiro itojun Hagino 	eom = answer->buf + anslen;
149073b30f0cSJun-ichiro itojun Hagino 	switch (qtype) {
14917d56d374SYoshinobu Inoue 	case T_A:
14927d56d374SYoshinobu Inoue 	case T_AAAA:
149373b30f0cSJun-ichiro itojun Hagino 		name_ok = res_hnok;
149473b30f0cSJun-ichiro itojun Hagino 		break;
149573b30f0cSJun-ichiro itojun Hagino 	case T_PTR:
149673b30f0cSJun-ichiro itojun Hagino 		name_ok = res_dnok;
14977d56d374SYoshinobu Inoue 		break;
14987d56d374SYoshinobu Inoue 	default:
149973b30f0cSJun-ichiro itojun Hagino 		return (NULL);	/* XXX should be abort(); */
150073b30f0cSJun-ichiro itojun Hagino 	}
150173b30f0cSJun-ichiro itojun Hagino 	/*
150273b30f0cSJun-ichiro itojun Hagino 	 * find first satisfactory answer
150373b30f0cSJun-ichiro itojun Hagino 	 */
150473b30f0cSJun-ichiro itojun Hagino 	hp = &answer->hdr;
150573b30f0cSJun-ichiro itojun Hagino 	ancount = ntohs(hp->ancount);
150673b30f0cSJun-ichiro itojun Hagino 	qdcount = ntohs(hp->qdcount);
150773b30f0cSJun-ichiro itojun Hagino 	bp = hostbuf;
1508d6af58f5SWarner Losh 	ep = hostbuf + sizeof hostbuf;
150973b30f0cSJun-ichiro itojun Hagino 	cp = answer->buf;
151073b30f0cSJun-ichiro itojun Hagino 	BOUNDED_INCR(HFIXEDSZ);
151173b30f0cSJun-ichiro itojun Hagino 	if (qdcount != 1) {
151273b30f0cSJun-ichiro itojun Hagino 		*errp = NO_RECOVERY;
151373b30f0cSJun-ichiro itojun Hagino 		return (NULL);
151473b30f0cSJun-ichiro itojun Hagino 	}
1515d6af58f5SWarner Losh 	n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
151673b30f0cSJun-ichiro itojun Hagino 	if ((n < 0) || !(*name_ok)(bp)) {
151773b30f0cSJun-ichiro itojun Hagino 		*errp = NO_RECOVERY;
151873b30f0cSJun-ichiro itojun Hagino 		return (NULL);
151973b30f0cSJun-ichiro itojun Hagino 	}
152073b30f0cSJun-ichiro itojun Hagino 	BOUNDED_INCR(n + QFIXEDSZ);
152173b30f0cSJun-ichiro itojun Hagino 	if (qtype == T_A || qtype == T_AAAA) {
152273b30f0cSJun-ichiro itojun Hagino 		/* res_send() has already verified that the query name is the
152373b30f0cSJun-ichiro itojun Hagino 		 * same as the one we sent; this just gets the expanded name
152473b30f0cSJun-ichiro itojun Hagino 		 * (i.e., with the succeeding search-domain tacked on).
152573b30f0cSJun-ichiro itojun Hagino 		 */
152673b30f0cSJun-ichiro itojun Hagino 		n = strlen(bp) + 1;		/* for the \0 */
152773b30f0cSJun-ichiro itojun Hagino 		if (n >= MAXHOSTNAMELEN) {
152873b30f0cSJun-ichiro itojun Hagino 			*errp = NO_RECOVERY;
152973b30f0cSJun-ichiro itojun Hagino 			return (NULL);
153073b30f0cSJun-ichiro itojun Hagino 		}
153173b30f0cSJun-ichiro itojun Hagino 		template->h_name = bp;
153273b30f0cSJun-ichiro itojun Hagino 		bp += n;
153373b30f0cSJun-ichiro itojun Hagino 		/* The qname can be abbreviated, but h_name is now absolute. */
153473b30f0cSJun-ichiro itojun Hagino 		qname = template->h_name;
153573b30f0cSJun-ichiro itojun Hagino 	}
153673b30f0cSJun-ichiro itojun Hagino 	ap = host_aliases;
153773b30f0cSJun-ichiro itojun Hagino 	*ap = NULL;
153873b30f0cSJun-ichiro itojun Hagino 	template->h_aliases = host_aliases;
153973b30f0cSJun-ichiro itojun Hagino 	hap = h_addr_ptrs;
154073b30f0cSJun-ichiro itojun Hagino 	*hap = NULL;
154173b30f0cSJun-ichiro itojun Hagino 	template->h_addr_list = h_addr_ptrs;
154273b30f0cSJun-ichiro itojun Hagino 	haveanswer = 0;
154373b30f0cSJun-ichiro itojun Hagino 	had_error = 0;
154473b30f0cSJun-ichiro itojun Hagino 	while (ancount-- > 0 && cp < eom && !had_error) {
1545d6af58f5SWarner Losh 		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
154673b30f0cSJun-ichiro itojun Hagino 		DNS_FATAL(n >= 0);
154773b30f0cSJun-ichiro itojun Hagino 		DNS_FATAL((*name_ok)(bp));
154873b30f0cSJun-ichiro itojun Hagino 		cp += n;			/* name */
154973b30f0cSJun-ichiro itojun Hagino 		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
155073b30f0cSJun-ichiro itojun Hagino 		type = _getshort(cp);
155173b30f0cSJun-ichiro itojun Hagino  		cp += INT16SZ;			/* type */
155273b30f0cSJun-ichiro itojun Hagino 		class = _getshort(cp);
155373b30f0cSJun-ichiro itojun Hagino  		cp += INT16SZ + INT32SZ;	/* class, TTL */
155473b30f0cSJun-ichiro itojun Hagino 		n = _getshort(cp);
155573b30f0cSJun-ichiro itojun Hagino 		cp += INT16SZ;			/* len */
155673b30f0cSJun-ichiro itojun Hagino 		BOUNDS_CHECK(cp, n);
155773b30f0cSJun-ichiro itojun Hagino 		erdata = cp + n;
155873b30f0cSJun-ichiro itojun Hagino 		DNS_ASSERT(class == C_IN);
155973b30f0cSJun-ichiro itojun Hagino 		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
156073b30f0cSJun-ichiro itojun Hagino 			if (ap >= &host_aliases[MAXALIASES-1])
156173b30f0cSJun-ichiro itojun Hagino 				continue;
156273b30f0cSJun-ichiro itojun Hagino 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
156373b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n >= 0);
156473b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL((*name_ok)(tbuf));
15657d56d374SYoshinobu Inoue 			cp += n;
156673b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
156773b30f0cSJun-ichiro itojun Hagino 				*errp = NO_RECOVERY;
156873b30f0cSJun-ichiro itojun Hagino 				return (NULL);
156973b30f0cSJun-ichiro itojun Hagino 			}
157073b30f0cSJun-ichiro itojun Hagino 			/* Store alias. */
157173b30f0cSJun-ichiro itojun Hagino 			*ap++ = bp;
157273b30f0cSJun-ichiro itojun Hagino 			n = strlen(bp) + 1;	/* for the \0 */
157373b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n < MAXHOSTNAMELEN);
157473b30f0cSJun-ichiro itojun Hagino 			bp += n;
157573b30f0cSJun-ichiro itojun Hagino 			/* Get canonical name. */
157673b30f0cSJun-ichiro itojun Hagino 			n = strlen(tbuf) + 1;	/* for the \0 */
1577d6af58f5SWarner Losh 			DNS_FATAL(n <= ep - bp);
157873b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n < MAXHOSTNAMELEN);
157973b30f0cSJun-ichiro itojun Hagino 			strcpy(bp, tbuf);
158073b30f0cSJun-ichiro itojun Hagino 			template->h_name = bp;
158173b30f0cSJun-ichiro itojun Hagino 			bp += n;
158273b30f0cSJun-ichiro itojun Hagino 			continue;
158373b30f0cSJun-ichiro itojun Hagino 		}
158473b30f0cSJun-ichiro itojun Hagino 		if (qtype == T_PTR && type == T_CNAME) {
158573b30f0cSJun-ichiro itojun Hagino 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
158673b30f0cSJun-ichiro itojun Hagino 			if (n < 0 || !res_dnok(tbuf)) {
158773b30f0cSJun-ichiro itojun Hagino 				had_error++;
158873b30f0cSJun-ichiro itojun Hagino 				continue;
158973b30f0cSJun-ichiro itojun Hagino 			}
159073b30f0cSJun-ichiro itojun Hagino 			cp += n;
159173b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
159273b30f0cSJun-ichiro itojun Hagino 				*errp = NO_RECOVERY;
159373b30f0cSJun-ichiro itojun Hagino 				return (NULL);
159473b30f0cSJun-ichiro itojun Hagino 			}
159573b30f0cSJun-ichiro itojun Hagino 			/* Get canonical name. */
159673b30f0cSJun-ichiro itojun Hagino 			n = strlen(tbuf) + 1;	/* for the \0 */
1597d6af58f5SWarner Losh 			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
159873b30f0cSJun-ichiro itojun Hagino 				had_error++;
159973b30f0cSJun-ichiro itojun Hagino 				continue;
160073b30f0cSJun-ichiro itojun Hagino 			}
160173b30f0cSJun-ichiro itojun Hagino 			strcpy(bp, tbuf);
16023f587e57SKris Kennaway 			tname = bp;
160373b30f0cSJun-ichiro itojun Hagino 			bp += n;
160473b30f0cSJun-ichiro itojun Hagino 			continue;
160573b30f0cSJun-ichiro itojun Hagino 		}
160673b30f0cSJun-ichiro itojun Hagino 		DNS_ASSERT(type == qtype);
160773b30f0cSJun-ichiro itojun Hagino 		switch (type) {
160873b30f0cSJun-ichiro itojun Hagino 		case T_PTR:
160973b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(strcasecmp(tname, bp) == 0);
1610d6af58f5SWarner Losh 			n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
161173b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(n >= 0);
161273b30f0cSJun-ichiro itojun Hagino 			DNS_FATAL(res_hnok(bp));
161373b30f0cSJun-ichiro itojun Hagino #if MULTI_PTRS_ARE_ALIASES
161473b30f0cSJun-ichiro itojun Hagino 			cp += n;
161573b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
161673b30f0cSJun-ichiro itojun Hagino 				*errp = NO_RECOVERY;
161773b30f0cSJun-ichiro itojun Hagino 				return (NULL);
161873b30f0cSJun-ichiro itojun Hagino 			}
161973b30f0cSJun-ichiro itojun Hagino 			if (!haveanswer)
162073b30f0cSJun-ichiro itojun Hagino 				template->h_name = bp;
162173b30f0cSJun-ichiro itojun Hagino 			else if (ap < &host_aliases[MAXALIASES-1])
162273b30f0cSJun-ichiro itojun Hagino 				*ap++ = bp;
162373b30f0cSJun-ichiro itojun Hagino 			else
162473b30f0cSJun-ichiro itojun Hagino 				n = -1;
162573b30f0cSJun-ichiro itojun Hagino 			if (n != -1) {
162673b30f0cSJun-ichiro itojun Hagino 				n = strlen(bp) + 1;	/* for the \0 */
162773b30f0cSJun-ichiro itojun Hagino 				if (n >= MAXHOSTNAMELEN) {
162873b30f0cSJun-ichiro itojun Hagino 					had_error++;
16297d56d374SYoshinobu Inoue 					break;
16307d56d374SYoshinobu Inoue 				}
163173b30f0cSJun-ichiro itojun Hagino 				bp += n;
16327d56d374SYoshinobu Inoue 			}
163373b30f0cSJun-ichiro itojun Hagino 			break;
163473b30f0cSJun-ichiro itojun Hagino #else
163573b30f0cSJun-ichiro itojun Hagino 			template->h_name = bp;
163673b30f0cSJun-ichiro itojun Hagino 			*errp = NETDB_SUCCESS;
163773b30f0cSJun-ichiro itojun Hagino 			return (template);
163873b30f0cSJun-ichiro itojun Hagino #endif
163973b30f0cSJun-ichiro itojun Hagino 		case T_A:
164073b30f0cSJun-ichiro itojun Hagino 		case T_AAAA:
164173b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(strcasecmp(template->h_name, bp) == 0);
164273b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(n == template->h_length);
164373b30f0cSJun-ichiro itojun Hagino 			if (!haveanswer) {
16448fb3f3f6SDavid E. O'Brien 				int nn;
164573b30f0cSJun-ichiro itojun Hagino 
164673b30f0cSJun-ichiro itojun Hagino 				template->h_name = bp;
164773b30f0cSJun-ichiro itojun Hagino 				nn = strlen(bp) + 1;	/* for the \0 */
164873b30f0cSJun-ichiro itojun Hagino 				bp += nn;
164973b30f0cSJun-ichiro itojun Hagino 			}
165073b30f0cSJun-ichiro itojun Hagino 			bp = (char *)ALIGN(bp);
165173b30f0cSJun-ichiro itojun Hagino 
1652d6af58f5SWarner Losh 			DNS_FATAL(bp + n < ep);
165373b30f0cSJun-ichiro itojun Hagino 			DNS_ASSERT(hap < &h_addr_ptrs[MAXADDRS-1]);
165473b30f0cSJun-ichiro itojun Hagino #ifdef FILTER_V4MAPPED
165573b30f0cSJun-ichiro itojun Hagino 			if (type == T_AAAA) {
165673b30f0cSJun-ichiro itojun Hagino 				struct in6_addr in6;
165773b30f0cSJun-ichiro itojun Hagino 				memcpy(&in6, cp, sizeof(in6));
165873b30f0cSJun-ichiro itojun Hagino 				DNS_ASSERT(IN6_IS_ADDR_V4MAPPED(&in6) == 0);
165973b30f0cSJun-ichiro itojun Hagino 			}
166073b30f0cSJun-ichiro itojun Hagino #endif
166173b30f0cSJun-ichiro itojun Hagino 			bcopy(cp, *hap++ = bp, n);
166273b30f0cSJun-ichiro itojun Hagino 			bp += n;
166373b30f0cSJun-ichiro itojun Hagino 			cp += n;
166473b30f0cSJun-ichiro itojun Hagino 			if (cp != erdata) {
16657d56d374SYoshinobu Inoue 				*errp = NO_RECOVERY;
166673b30f0cSJun-ichiro itojun Hagino 				return (NULL);
16677d56d374SYoshinobu Inoue 			}
166873b30f0cSJun-ichiro itojun Hagino 			break;
166973b30f0cSJun-ichiro itojun Hagino 		default:
167073b30f0cSJun-ichiro itojun Hagino 			abort();
167173b30f0cSJun-ichiro itojun Hagino 		}
167273b30f0cSJun-ichiro itojun Hagino 		if (!had_error)
167373b30f0cSJun-ichiro itojun Hagino 			haveanswer++;
167473b30f0cSJun-ichiro itojun Hagino 	}
167573b30f0cSJun-ichiro itojun Hagino 	if (haveanswer) {
167673b30f0cSJun-ichiro itojun Hagino 		*ap = NULL;
167773b30f0cSJun-ichiro itojun Hagino 		*hap = NULL;
167873b30f0cSJun-ichiro itojun Hagino 		if (!template->h_name) {
167973b30f0cSJun-ichiro itojun Hagino 			n = strlen(qname) + 1;	/* for the \0 */
1680d6af58f5SWarner Losh 			if (n > ep - bp || n >= MAXHOSTNAMELEN)
168173b30f0cSJun-ichiro itojun Hagino 				goto no_recovery;
168273b30f0cSJun-ichiro itojun Hagino 			strcpy(bp, qname);
168373b30f0cSJun-ichiro itojun Hagino 			template->h_name = bp;
168473b30f0cSJun-ichiro itojun Hagino 			bp += n;
168573b30f0cSJun-ichiro itojun Hagino 		}
168673b30f0cSJun-ichiro itojun Hagino 		*errp = NETDB_SUCCESS;
168773b30f0cSJun-ichiro itojun Hagino 		return (template);
168873b30f0cSJun-ichiro itojun Hagino 	}
168973b30f0cSJun-ichiro itojun Hagino  no_recovery:
169073b30f0cSJun-ichiro itojun Hagino 	*errp = NO_RECOVERY;
169173b30f0cSJun-ichiro itojun Hagino 	return (NULL);
169273b30f0cSJun-ichiro itojun Hagino 
169373b30f0cSJun-ichiro itojun Hagino #undef BOUNDED_INCR
169473b30f0cSJun-ichiro itojun Hagino #undef BOUNDS_CHECK
169573b30f0cSJun-ichiro itojun Hagino #undef DNS_ASSERT
169673b30f0cSJun-ichiro itojun Hagino #undef DNS_FATAL
16977d56d374SYoshinobu Inoue }
16987d56d374SYoshinobu Inoue 
1699248aee62SJacques Vidrine static int
1700248aee62SJacques Vidrine _dns_ghbyname(void *rval, void *cb_data, va_list ap)
1701e6f35403SYoshinobu Inoue {
1702248aee62SJacques Vidrine 	const char *name;
1703248aee62SJacques Vidrine 	int af;
1704248aee62SJacques Vidrine 	int *errp;
17050fbf0979SHajimu UMEMOTO 	int n;
17060fbf0979SHajimu UMEMOTO 	struct hostent *hp;
17070fbf0979SHajimu UMEMOTO 	int qtype;
17080fbf0979SHajimu UMEMOTO 	struct hostent hbuf;
17090fbf0979SHajimu UMEMOTO 	querybuf *buf;
1710e6f35403SYoshinobu Inoue 
1711248aee62SJacques Vidrine 	name = va_arg(ap, const char *);
1712248aee62SJacques Vidrine 	af = va_arg(ap, int);
1713248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
1714248aee62SJacques Vidrine 
17150fbf0979SHajimu UMEMOTO 	if ((_res.options & RES_INIT) == 0) {
17160fbf0979SHajimu UMEMOTO 		if (res_init() < 0) {
17170fbf0979SHajimu UMEMOTO 			*errp = h_errno;
17180fbf0979SHajimu UMEMOTO 			return NS_UNAVAIL;
1719e6f35403SYoshinobu Inoue 		}
17200fbf0979SHajimu UMEMOTO 	}
17210fbf0979SHajimu UMEMOTO 	memset(&hbuf, 0, sizeof(hbuf));
17220fbf0979SHajimu UMEMOTO 	hbuf.h_addrtype = af;
17230fbf0979SHajimu UMEMOTO 	hbuf.h_length = ADDRLEN(af);
17240fbf0979SHajimu UMEMOTO 
17250fbf0979SHajimu UMEMOTO 	switch (af) {
17260fbf0979SHajimu UMEMOTO #ifdef INET6
17270fbf0979SHajimu UMEMOTO 	case AF_INET6:
17280fbf0979SHajimu UMEMOTO 		qtype = T_AAAA;
17290fbf0979SHajimu UMEMOTO 		break;
1730e6f35403SYoshinobu Inoue #endif
17310fbf0979SHajimu UMEMOTO 	case AF_INET:
17320fbf0979SHajimu UMEMOTO 		qtype = T_A;
17330fbf0979SHajimu UMEMOTO 		break;
17340fbf0979SHajimu UMEMOTO 	default:
17350fbf0979SHajimu UMEMOTO 		*errp = NO_RECOVERY;
17360fbf0979SHajimu UMEMOTO 		return NS_NOTFOUND;
17370fbf0979SHajimu UMEMOTO 	}
17380fbf0979SHajimu UMEMOTO 	buf = malloc(sizeof(*buf));
17390fbf0979SHajimu UMEMOTO 	if (buf == NULL) {
17400fbf0979SHajimu UMEMOTO 		*errp = NETDB_INTERNAL;
17410fbf0979SHajimu UMEMOTO 		return NS_UNAVAIL;
17420fbf0979SHajimu UMEMOTO 	}
17430fbf0979SHajimu UMEMOTO 	n = res_search(name, C_IN, qtype, buf->buf, sizeof(buf->buf));
17440fbf0979SHajimu UMEMOTO 	if (n < 0) {
17450fbf0979SHajimu UMEMOTO 		free(buf);
17460fbf0979SHajimu UMEMOTO 		*errp = h_errno;
17470fbf0979SHajimu UMEMOTO 		return NS_UNAVAIL;
17480fbf0979SHajimu UMEMOTO 	}
17490fbf0979SHajimu UMEMOTO 	hp = getanswer(buf, n, name, qtype, &hbuf, errp);
17500fbf0979SHajimu UMEMOTO 	free(buf);
17510fbf0979SHajimu UMEMOTO 	if (!hp) {
17520fbf0979SHajimu UMEMOTO 		*errp = NO_RECOVERY;
17530fbf0979SHajimu UMEMOTO 		return NS_NOTFOUND;
17540fbf0979SHajimu UMEMOTO 	}
17550fbf0979SHajimu UMEMOTO 	*(struct hostent **)rval = _hpcopy(&hbuf, errp);
1756e651d83aSPierre Beyssac 	if (*(struct hostent **)rval != NULL)
1757e651d83aSPierre Beyssac 		return NS_SUCCESS;
1758e651d83aSPierre Beyssac 	else if (*errp == TRY_AGAIN)
1759e651d83aSPierre Beyssac 		return NS_TRYAGAIN;
1760e651d83aSPierre Beyssac 	else
1761e651d83aSPierre Beyssac 		return NS_NOTFOUND;
1762e6f35403SYoshinobu Inoue }
1763e6f35403SYoshinobu Inoue 
1764248aee62SJacques Vidrine static int
1765248aee62SJacques Vidrine _dns_ghbyaddr(void *rval, void *cb_data, va_list ap)
17667d56d374SYoshinobu Inoue {
1767248aee62SJacques Vidrine 	const void *addr;
1768248aee62SJacques Vidrine 	int addrlen;
1769248aee62SJacques Vidrine 	int af;
1770248aee62SJacques Vidrine 	int *errp;
17717d56d374SYoshinobu Inoue 	int n;
1772aadad922SHajimu UMEMOTO 	int err;
177373b30f0cSJun-ichiro itojun Hagino 	struct hostent *hp;
177473b30f0cSJun-ichiro itojun Hagino 	u_char c, *cp;
17757d56d374SYoshinobu Inoue 	char *bp;
17767d56d374SYoshinobu Inoue 	struct hostent hbuf;
17777d56d374SYoshinobu Inoue #ifdef INET6
17787d56d374SYoshinobu Inoue 	static const char hex[] = "0123456789abcdef";
17797d56d374SYoshinobu Inoue #endif
17809832619cSHajimu UMEMOTO 	querybuf *buf;
178173b30f0cSJun-ichiro itojun Hagino 	char qbuf[MAXDNAME+1];
178273b30f0cSJun-ichiro itojun Hagino 	char *hlist[2];
17830def575fSHajimu UMEMOTO 	char *tld6[] = { "ip6.arpa", NULL };
1784aadad922SHajimu UMEMOTO 	char *tld4[] = { "in-addr.arpa", NULL };
1785aadad922SHajimu UMEMOTO 	char **tld;
17867d56d374SYoshinobu Inoue 
1787248aee62SJacques Vidrine 	addr = va_arg(ap, const void *);
1788248aee62SJacques Vidrine 	addrlen = va_arg(ap, int);
1789248aee62SJacques Vidrine 	af = va_arg(ap, int);
1790248aee62SJacques Vidrine 	errp = va_arg(ap, int *);
1791248aee62SJacques Vidrine 
1792248aee62SJacques Vidrine 	*(struct hostent **)rval = NULL;
1793248aee62SJacques Vidrine 
17947d56d374SYoshinobu Inoue #ifdef INET6
17957d56d374SYoshinobu Inoue 	/* XXX */
17967d56d374SYoshinobu Inoue 	if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
1797248aee62SJacques Vidrine 		return NS_NOTFOUND;
17987d56d374SYoshinobu Inoue #endif
17997d56d374SYoshinobu Inoue 
1800aadad922SHajimu UMEMOTO 	switch (af) {
1801aadad922SHajimu UMEMOTO #ifdef INET6
1802aadad922SHajimu UMEMOTO 	case AF_INET6:
1803aadad922SHajimu UMEMOTO 		tld = tld6;
1804aadad922SHajimu UMEMOTO 		break;
1805aadad922SHajimu UMEMOTO #endif
1806aadad922SHajimu UMEMOTO 	case AF_INET:
1807aadad922SHajimu UMEMOTO 		tld = tld4;
1808aadad922SHajimu UMEMOTO 		break;
1809aadad922SHajimu UMEMOTO 	default:
1810aadad922SHajimu UMEMOTO 		return NS_NOTFOUND;
1811aadad922SHajimu UMEMOTO 	}
1812aadad922SHajimu UMEMOTO 
18137d56d374SYoshinobu Inoue 	if ((_res.options & RES_INIT) == 0) {
18147d56d374SYoshinobu Inoue 		if (res_init() < 0) {
18157d56d374SYoshinobu Inoue 			*errp = h_errno;
1816248aee62SJacques Vidrine 			return NS_UNAVAIL;
18177d56d374SYoshinobu Inoue 		}
18187d56d374SYoshinobu Inoue 	}
181973b30f0cSJun-ichiro itojun Hagino 	memset(&hbuf, 0, sizeof(hbuf));
18207d56d374SYoshinobu Inoue 	hbuf.h_name = NULL;
18217d56d374SYoshinobu Inoue 	hbuf.h_addrtype = af;
18227d56d374SYoshinobu Inoue 	hbuf.h_length = addrlen;
18237d56d374SYoshinobu Inoue 
1824aadad922SHajimu UMEMOTO 	buf = malloc(sizeof(*buf));
1825aadad922SHajimu UMEMOTO 	if (buf == NULL) {
1826aadad922SHajimu UMEMOTO 		*errp = NETDB_INTERNAL;
1827aadad922SHajimu UMEMOTO 		return NS_UNAVAIL;
1828aadad922SHajimu UMEMOTO 	}
1829aadad922SHajimu UMEMOTO 	err = NS_SUCCESS;
1830aadad922SHajimu UMEMOTO 	for (/* nothing */; *tld; tld++) {
1831aadad922SHajimu UMEMOTO 		/*
1832aadad922SHajimu UMEMOTO 		 * XXX assumes that MAXDNAME is big enough - error checks
1833aadad922SHajimu UMEMOTO 		 * has been made by callers
1834aadad922SHajimu UMEMOTO 		 */
18357d56d374SYoshinobu Inoue 		n = 0;
183673b30f0cSJun-ichiro itojun Hagino 		bp = qbuf;
18377d56d374SYoshinobu Inoue 		cp = (u_char *)addr+addrlen-1;
18387d56d374SYoshinobu Inoue 		switch (af) {
18397d56d374SYoshinobu Inoue #ifdef INET6
18407d56d374SYoshinobu Inoue 		case AF_INET6:
18417d56d374SYoshinobu Inoue 			for (; n < addrlen; n++, cp--) {
18427d56d374SYoshinobu Inoue 				c = *cp;
18437d56d374SYoshinobu Inoue 				*bp++ = hex[c & 0xf];
18447d56d374SYoshinobu Inoue 				*bp++ = '.';
18457d56d374SYoshinobu Inoue 				*bp++ = hex[c >> 4];
18467d56d374SYoshinobu Inoue 				*bp++ = '.';
18477d56d374SYoshinobu Inoue 			}
1848aadad922SHajimu UMEMOTO 			strcpy(bp, *tld);
18497d56d374SYoshinobu Inoue 			break;
18507d56d374SYoshinobu Inoue #endif
1851aadad922SHajimu UMEMOTO 		case AF_INET:
18527d56d374SYoshinobu Inoue 			for (; n < addrlen; n++, cp--) {
18537d56d374SYoshinobu Inoue 				c = *cp;
18547d56d374SYoshinobu Inoue 				if (c >= 100)
18557d56d374SYoshinobu Inoue 					*bp++ = '0' + c / 100;
18567d56d374SYoshinobu Inoue 				if (c >= 10)
18577d56d374SYoshinobu Inoue 					*bp++ = '0' + (c % 100) / 10;
18587d56d374SYoshinobu Inoue 				*bp++ = '0' + c % 10;
18597d56d374SYoshinobu Inoue 				*bp++ = '.';
18607d56d374SYoshinobu Inoue 			}
1861aadad922SHajimu UMEMOTO 			strcpy(bp, *tld);
18627d56d374SYoshinobu Inoue 			break;
18637d56d374SYoshinobu Inoue 		}
18647d56d374SYoshinobu Inoue 
18659832619cSHajimu UMEMOTO 		n = res_query(qbuf, C_IN, T_PTR, buf->buf, sizeof buf->buf);
18667d56d374SYoshinobu Inoue 		if (n < 0) {
18677d56d374SYoshinobu Inoue 			*errp = h_errno;
1868aadad922SHajimu UMEMOTO 			err = NS_UNAVAIL;
1869aadad922SHajimu UMEMOTO 			continue;
18709832619cSHajimu UMEMOTO 		} else if (n > sizeof(buf->buf)) {
187154384cf3SJacques Vidrine #if 0
187254384cf3SJacques Vidrine 			errno = ERANGE; /* XXX is it OK to set errno here? */
187354384cf3SJacques Vidrine #endif
187454384cf3SJacques Vidrine 			*errp = NETDB_INTERNAL;
1875aadad922SHajimu UMEMOTO 			err = NS_UNAVAIL;
1876aadad922SHajimu UMEMOTO 			continue;
18777d56d374SYoshinobu Inoue 		}
18789832619cSHajimu UMEMOTO 		hp = getanswer(buf, n, qbuf, T_PTR, &hbuf, errp);
1879aadad922SHajimu UMEMOTO 		if (!hp) {
1880aadad922SHajimu UMEMOTO 			err = NS_NOTFOUND;
1881aadad922SHajimu UMEMOTO 			continue;
1882aadad922SHajimu UMEMOTO 		}
18839832619cSHajimu UMEMOTO 		free(buf);
188473b30f0cSJun-ichiro itojun Hagino 		hbuf.h_addrtype = af;
188573b30f0cSJun-ichiro itojun Hagino 		hbuf.h_length = addrlen;
188673b30f0cSJun-ichiro itojun Hagino 		hbuf.h_addr_list = hlist;
188773b30f0cSJun-ichiro itojun Hagino 		hlist[0] = (char *)addr;
188873b30f0cSJun-ichiro itojun Hagino 		hlist[1] = NULL;
1889248aee62SJacques Vidrine 		*(struct hostent **)rval = _hpcopy(&hbuf, errp);
1890248aee62SJacques Vidrine 		return NS_SUCCESS;
18917d56d374SYoshinobu Inoue 	}
1892aadad922SHajimu UMEMOTO 	free(buf);
1893aadad922SHajimu UMEMOTO 	return err;
1894aadad922SHajimu UMEMOTO }
18957d56d374SYoshinobu Inoue 
189673b30f0cSJun-ichiro itojun Hagino static void
189773b30f0cSJun-ichiro itojun Hagino _dns_shent(int stayopen)
189873b30f0cSJun-ichiro itojun Hagino {
189973b30f0cSJun-ichiro itojun Hagino 	if ((_res.options & RES_INIT) == 0) {
190073b30f0cSJun-ichiro itojun Hagino 		if (res_init() < 0)
190173b30f0cSJun-ichiro itojun Hagino 			return;
190273b30f0cSJun-ichiro itojun Hagino 	}
190373b30f0cSJun-ichiro itojun Hagino 	if (stayopen)
190473b30f0cSJun-ichiro itojun Hagino 		_res.options |= RES_STAYOPEN | RES_USEVC;
190573b30f0cSJun-ichiro itojun Hagino }
190673b30f0cSJun-ichiro itojun Hagino 
190773b30f0cSJun-ichiro itojun Hagino static void
190873b30f0cSJun-ichiro itojun Hagino _dns_ehent(void)
190973b30f0cSJun-ichiro itojun Hagino {
191073b30f0cSJun-ichiro itojun Hagino 	_res.options &= ~(RES_STAYOPEN | RES_USEVC);
191173b30f0cSJun-ichiro itojun Hagino 	res_close();
191273b30f0cSJun-ichiro itojun Hagino }
191373b30f0cSJun-ichiro itojun Hagino 
19147d56d374SYoshinobu Inoue #ifdef ICMPNL
19157d56d374SYoshinobu Inoue 
19167d56d374SYoshinobu Inoue /*
19177d56d374SYoshinobu Inoue  * experimental:
19187d56d374SYoshinobu Inoue  *	draft-ietf-ipngwg-icmp-namelookups-02.txt
19197d56d374SYoshinobu Inoue  *	ifindex is assumed to be encoded in addr.
19207d56d374SYoshinobu Inoue  */
19217d56d374SYoshinobu Inoue #include <sys/uio.h>
19227d56d374SYoshinobu Inoue #include <netinet/ip6.h>
19237d56d374SYoshinobu Inoue #include <netinet/icmp6.h>
19247d56d374SYoshinobu Inoue 
19257d56d374SYoshinobu Inoue struct _icmp_host_cache {
19267d56d374SYoshinobu Inoue 	struct _icmp_host_cache *hc_next;
19277d56d374SYoshinobu Inoue 	int hc_ifindex;
19287d56d374SYoshinobu Inoue 	struct in6_addr hc_addr;
19297d56d374SYoshinobu Inoue 	char *hc_name;
19307d56d374SYoshinobu Inoue };
19317d56d374SYoshinobu Inoue 
19327d56d374SYoshinobu Inoue static char *
19337d56d374SYoshinobu Inoue _icmp_fqdn_query(const struct in6_addr *addr, int ifindex)
19347d56d374SYoshinobu Inoue {
19357d56d374SYoshinobu Inoue 	int s;
19367d56d374SYoshinobu Inoue 	struct icmp6_filter filter;
19377d56d374SYoshinobu Inoue 	struct msghdr msg;
19387d56d374SYoshinobu Inoue 	struct cmsghdr *cmsg;
19397d56d374SYoshinobu Inoue 	struct in6_pktinfo *pkt;
19407d56d374SYoshinobu Inoue 	char cbuf[256];
19417d56d374SYoshinobu Inoue 	char buf[1024];
19427d56d374SYoshinobu Inoue 	int cc;
19437d56d374SYoshinobu Inoue 	struct icmp6_fqdn_query *fq;
19447d56d374SYoshinobu Inoue 	struct icmp6_fqdn_reply *fr;
19457d56d374SYoshinobu Inoue 	struct _icmp_host_cache *hc;
19467d56d374SYoshinobu Inoue 	struct sockaddr_in6 sin6;
19477d56d374SYoshinobu Inoue 	struct iovec iov;
19487d56d374SYoshinobu Inoue 	fd_set s_fds, fds;
19497d56d374SYoshinobu Inoue 	struct timeval tout;
19507d56d374SYoshinobu Inoue 	int len;
19517d56d374SYoshinobu Inoue 	char *name;
19527d56d374SYoshinobu Inoue 	static struct _icmp_host_cache *hc_head;
19537d56d374SYoshinobu Inoue 
195433dee819SBrian Feldman 	THREAD_LOCK();
19557d56d374SYoshinobu Inoue 	for (hc = hc_head; hc; hc = hc->hc_next) {
19567d56d374SYoshinobu Inoue 		if (hc->hc_ifindex == ifindex
195733dee819SBrian Feldman 		&&  IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr)) {
195833dee819SBrian Feldman 			THREAD_UNLOCK();
195933dee819SBrian Feldman 			return hc->hc_name;	/* XXX: never freed */
19607d56d374SYoshinobu Inoue 		}
196133dee819SBrian Feldman 	}
196278ebcde8SHajimu UMEMOTO 	THREAD_UNLOCK();
19637d56d374SYoshinobu Inoue 
19647d56d374SYoshinobu Inoue 	ICMP6_FILTER_SETBLOCKALL(&filter);
19657d56d374SYoshinobu Inoue 	ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter);
19667d56d374SYoshinobu Inoue 
19677d56d374SYoshinobu Inoue 	FD_ZERO(&s_fds);
19687d56d374SYoshinobu Inoue 	tout.tv_sec = 0;
19697d56d374SYoshinobu Inoue 	tout.tv_usec = 200000;	/*XXX: 200ms*/
19707d56d374SYoshinobu Inoue 
19717d56d374SYoshinobu Inoue 	fq = (struct icmp6_fqdn_query *)buf;
19727d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY;
19737d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_code = 0;
19747d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_cksum = 0;
197533dee819SBrian Feldman 	fq->icmp6_fqdn_id = (u_short)getpid();
19767d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_unused = 0;
19777d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_cookie[0] = 0;
19787d56d374SYoshinobu Inoue 	fq->icmp6_fqdn_cookie[1] = 0;
19797d56d374SYoshinobu Inoue 
19807d56d374SYoshinobu Inoue 	memset(&sin6, 0, sizeof(sin6));
19817d56d374SYoshinobu Inoue 	sin6.sin6_family = AF_INET6;
19827d56d374SYoshinobu Inoue 	sin6.sin6_addr = *addr;
19837d56d374SYoshinobu Inoue 
19847d56d374SYoshinobu Inoue 	memset(&msg, 0, sizeof(msg));
19857d56d374SYoshinobu Inoue 	msg.msg_name = (caddr_t)&sin6;
19867d56d374SYoshinobu Inoue 	msg.msg_namelen = sizeof(sin6);
19877d56d374SYoshinobu Inoue 	msg.msg_iov = &iov;
19887d56d374SYoshinobu Inoue 	msg.msg_iovlen = 1;
19897d56d374SYoshinobu Inoue 	msg.msg_control = NULL;
19907d56d374SYoshinobu Inoue 	msg.msg_controllen = 0;
19917d56d374SYoshinobu Inoue 	iov.iov_base = (caddr_t)buf;
19927d56d374SYoshinobu Inoue 	iov.iov_len = sizeof(struct icmp6_fqdn_query);
19937d56d374SYoshinobu Inoue 
19947d56d374SYoshinobu Inoue 	if (ifindex) {
19957d56d374SYoshinobu Inoue 		msg.msg_control = cbuf;
19967d56d374SYoshinobu Inoue 		msg.msg_controllen = sizeof(cbuf);
19977d56d374SYoshinobu Inoue 		cmsg = CMSG_FIRSTHDR(&msg);
19987d56d374SYoshinobu Inoue 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
19997d56d374SYoshinobu Inoue 		cmsg->cmsg_level = IPPROTO_IPV6;
20007d56d374SYoshinobu Inoue 		cmsg->cmsg_type = IPV6_PKTINFO;
20017d56d374SYoshinobu Inoue 		pkt = (struct in6_pktinfo *)&cmsg[1];
20027d56d374SYoshinobu Inoue 		memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
20037d56d374SYoshinobu Inoue 		pkt->ipi6_ifindex = ifindex;
20047d56d374SYoshinobu Inoue 		cmsg = CMSG_NXTHDR(&msg, cmsg);
20057d56d374SYoshinobu Inoue 		msg.msg_controllen = (char *)cmsg - cbuf;
20067d56d374SYoshinobu Inoue 	}
20077d56d374SYoshinobu Inoue 
2008d201fe46SDaniel Eischen 	if ((s = _socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
20097d56d374SYoshinobu Inoue 		return NULL;
2010d201fe46SDaniel Eischen 	(void)_setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
20117d56d374SYoshinobu Inoue 			 (char *)&filter, sizeof(filter));
2012d201fe46SDaniel Eischen 	cc = _sendmsg(s, &msg, 0);
20137d56d374SYoshinobu Inoue 	if (cc < 0) {
20149233c4d9SJason Evans 		_close(s);
20157d56d374SYoshinobu Inoue 		return NULL;
20167d56d374SYoshinobu Inoue 	}
20177d56d374SYoshinobu Inoue 	FD_SET(s, &s_fds);
20187d56d374SYoshinobu Inoue 	for (;;) {
20197d56d374SYoshinobu Inoue 		fds = s_fds;
2020d201fe46SDaniel Eischen 		if (_select(s + 1, &fds, NULL, NULL, &tout) <= 0) {
20219233c4d9SJason Evans 			_close(s);
20227d56d374SYoshinobu Inoue 			return NULL;
20237d56d374SYoshinobu Inoue 		}
20247d56d374SYoshinobu Inoue 		len = sizeof(sin6);
2025d201fe46SDaniel Eischen 		cc = _recvfrom(s, buf, sizeof(buf), 0,
20267d56d374SYoshinobu Inoue 			      (struct sockaddr *)&sin6, &len);
20277d56d374SYoshinobu Inoue 		if (cc <= 0) {
20289233c4d9SJason Evans 			_close(s);
20297d56d374SYoshinobu Inoue 			return NULL;
20307d56d374SYoshinobu Inoue 		}
20317d56d374SYoshinobu Inoue 		if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
20327d56d374SYoshinobu Inoue 			continue;
20337d56d374SYoshinobu Inoue 		if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr))
20347d56d374SYoshinobu Inoue 			continue;
20357d56d374SYoshinobu Inoue 		fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr));
20367d56d374SYoshinobu Inoue 		if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY)
20377d56d374SYoshinobu Inoue 			break;
20387d56d374SYoshinobu Inoue 	}
20399233c4d9SJason Evans 	_close(s);
20407d56d374SYoshinobu Inoue 	if (fr->icmp6_fqdn_cookie[1] != 0) {
20417d56d374SYoshinobu Inoue 		/* rfc1788 type */
20427d56d374SYoshinobu Inoue 		name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4;
20437d56d374SYoshinobu Inoue 		len = (buf + cc) - name;
20447d56d374SYoshinobu Inoue 	} else {
20457d56d374SYoshinobu Inoue 		len = fr->icmp6_fqdn_namelen;
20467d56d374SYoshinobu Inoue 		name = fr->icmp6_fqdn_name;
20477d56d374SYoshinobu Inoue 	}
20487d56d374SYoshinobu Inoue 	if (len <= 0)
20497d56d374SYoshinobu Inoue 		return NULL;
20507d56d374SYoshinobu Inoue 	name[len] = 0;
20517d56d374SYoshinobu Inoue 
20527d56d374SYoshinobu Inoue 	if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL)
20537d56d374SYoshinobu Inoue 		return NULL;
20547d56d374SYoshinobu Inoue 	/* XXX: limit number of cached entries */
20557d56d374SYoshinobu Inoue 	hc->hc_ifindex = ifindex;
20567d56d374SYoshinobu Inoue 	hc->hc_addr = *addr;
20577d56d374SYoshinobu Inoue 	hc->hc_name = strdup(name);
205833dee819SBrian Feldman 	THREAD_LOCK();
20597d56d374SYoshinobu Inoue 	hc->hc_next = hc_head;
20607d56d374SYoshinobu Inoue 	hc_head = hc;
206133dee819SBrian Feldman 	THREAD_UNLOCK();
20627d56d374SYoshinobu Inoue 	return hc->hc_name;
20637d56d374SYoshinobu Inoue }
20647d56d374SYoshinobu Inoue 
20657d56d374SYoshinobu Inoue static struct hostent *
20667d56d374SYoshinobu Inoue _icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
20677d56d374SYoshinobu Inoue {
20687d56d374SYoshinobu Inoue 	char *hname;
20697d56d374SYoshinobu Inoue 	int ifindex;
20707d56d374SYoshinobu Inoue 	struct in6_addr addr6;
20717d56d374SYoshinobu Inoue 
20727d56d374SYoshinobu Inoue 	if (af != AF_INET6) {
20737d56d374SYoshinobu Inoue 		/*
20747d56d374SYoshinobu Inoue 		 * Note: rfc1788 defines Who Are You for IPv4,
20757d56d374SYoshinobu Inoue 		 * but no one implements it.
20767d56d374SYoshinobu Inoue 		 */
20777d56d374SYoshinobu Inoue 		return NULL;
20787d56d374SYoshinobu Inoue 	}
20797d56d374SYoshinobu Inoue 
20807d56d374SYoshinobu Inoue 	memcpy(&addr6, addr, addrlen);
20817d56d374SYoshinobu Inoue 	ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3];
20827d56d374SYoshinobu Inoue 	addr6.s6_addr[2] = addr6.s6_addr[3] = 0;
20837d56d374SYoshinobu Inoue 
20847d56d374SYoshinobu Inoue 	if (!IN6_IS_ADDR_LINKLOCAL(&addr6))
20857d56d374SYoshinobu Inoue 		return NULL;	/*XXX*/
20867d56d374SYoshinobu Inoue 
20877d56d374SYoshinobu Inoue 	if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL)
20887d56d374SYoshinobu Inoue 		return NULL;
20897d56d374SYoshinobu Inoue 	return _hpaddr(af, hname, &addr6, errp);
20907d56d374SYoshinobu Inoue }
20917d56d374SYoshinobu Inoue #endif /* ICMPNL */
2092