xref: /minix3/external/bsd/libpcap/dist/Win32/Src/getaddrinfo.c (revision d56f51ea7d8b9045e5c8e2028422523d3f9a5840)
1*d56f51eaSDavid van Moolenbroek /*
2*d56f51eaSDavid van Moolenbroek  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3*d56f51eaSDavid van Moolenbroek  * All rights reserved.
4*d56f51eaSDavid van Moolenbroek  *
5*d56f51eaSDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
6*d56f51eaSDavid van Moolenbroek  * modification, are permitted provided that the following conditions
7*d56f51eaSDavid van Moolenbroek  * are met:
8*d56f51eaSDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
9*d56f51eaSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
10*d56f51eaSDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
11*d56f51eaSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
12*d56f51eaSDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
13*d56f51eaSDavid van Moolenbroek  * 3. Neither the name of the project nor the names of its contributors
14*d56f51eaSDavid van Moolenbroek  *    may be used to endorse or promote products derived from this software
15*d56f51eaSDavid van Moolenbroek  *    without specific prior written permission.
16*d56f51eaSDavid van Moolenbroek  *
17*d56f51eaSDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18*d56f51eaSDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*d56f51eaSDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*d56f51eaSDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21*d56f51eaSDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*d56f51eaSDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*d56f51eaSDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*d56f51eaSDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*d56f51eaSDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*d56f51eaSDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*d56f51eaSDavid van Moolenbroek  * SUCH DAMAGE.
28*d56f51eaSDavid van Moolenbroek  */
29*d56f51eaSDavid van Moolenbroek 
30*d56f51eaSDavid van Moolenbroek /*
31*d56f51eaSDavid van Moolenbroek  * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
32*d56f51eaSDavid van Moolenbroek  *
33*d56f51eaSDavid van Moolenbroek  * Issues to be discussed:
34*d56f51eaSDavid van Moolenbroek  * - Thread safe-ness must be checked.
35*d56f51eaSDavid van Moolenbroek  * - Return values.  There are nonstandard return values defined and used
36*d56f51eaSDavid van Moolenbroek  *   in the source code.  This is because RFC2553 is silent about which error
37*d56f51eaSDavid van Moolenbroek  *   code must be returned for which situation.
38*d56f51eaSDavid van Moolenbroek  * Note:
39*d56f51eaSDavid van Moolenbroek  * - We use getipnodebyname() just for thread-safeness.  There's no intent
40*d56f51eaSDavid van Moolenbroek  *   to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
41*d56f51eaSDavid van Moolenbroek  *   getipnodebyname().
42*d56f51eaSDavid van Moolenbroek  * - The code filters out AFs that are not supported by the kernel,
43*d56f51eaSDavid van Moolenbroek  *   when globbing NULL hostname (to loopback, or wildcard).  Is it the right
44*d56f51eaSDavid van Moolenbroek  *   thing to do?  What is the relationship with post-RFC2553 AI_ADDRCONFIG
45*d56f51eaSDavid van Moolenbroek  *   in ai_flags?
46*d56f51eaSDavid van Moolenbroek  */
47*d56f51eaSDavid van Moolenbroek 
48*d56f51eaSDavid van Moolenbroek /*
49*d56f51eaSDavid van Moolenbroek  * Mingw64 has its own implementation of getaddrinfo, mingw32 no
50*d56f51eaSDavid van Moolenbroek  */
51*d56f51eaSDavid van Moolenbroek #ifndef __MINGW64__
52*d56f51eaSDavid van Moolenbroek 
53*d56f51eaSDavid van Moolenbroek 
54*d56f51eaSDavid van Moolenbroek #ifdef HAVE_CONFIG_H
55*d56f51eaSDavid van Moolenbroek #include <config.h>
56*d56f51eaSDavid van Moolenbroek #endif
57*d56f51eaSDavid van Moolenbroek 
58*d56f51eaSDavid van Moolenbroek #include <pcap-stdinc.h>
59*d56f51eaSDavid van Moolenbroek #if 0
60*d56f51eaSDavid van Moolenbroek #include <sys/sysctl.h>
61*d56f51eaSDavid van Moolenbroek #endif
62*d56f51eaSDavid van Moolenbroek #ifndef __MINGW32__
63*d56f51eaSDavid van Moolenbroek #include <arpa/nameser.h>
64*d56f51eaSDavid van Moolenbroek #endif
65*d56f51eaSDavid van Moolenbroek #include <string.h>
66*d56f51eaSDavid van Moolenbroek #include <stdlib.h>
67*d56f51eaSDavid van Moolenbroek #include <stddef.h>
68*d56f51eaSDavid van Moolenbroek #include <ctype.h>
69*d56f51eaSDavid van Moolenbroek #include <stdio.h>
70*d56f51eaSDavid van Moolenbroek #include <errno.h>
71*d56f51eaSDavid van Moolenbroek 
72*d56f51eaSDavid van Moolenbroek #ifndef HAVE_PORTABLE_PROTOTYPE
73*d56f51eaSDavid van Moolenbroek #include "cdecl_ext.h"
74*d56f51eaSDavid van Moolenbroek #endif
75*d56f51eaSDavid van Moolenbroek 
76*d56f51eaSDavid van Moolenbroek #ifndef HAVE_U_INT32_T
77*d56f51eaSDavid van Moolenbroek #include "bittypes.h"
78*d56f51eaSDavid van Moolenbroek #endif
79*d56f51eaSDavid van Moolenbroek 
80*d56f51eaSDavid van Moolenbroek #ifndef HAVE_SOCKADDR_STORAGE
81*d56f51eaSDavid van Moolenbroek #ifndef __MINGW32__
82*d56f51eaSDavid van Moolenbroek #include "sockstorage.h"
83*d56f51eaSDavid van Moolenbroek #endif
84*d56f51eaSDavid van Moolenbroek #endif
85*d56f51eaSDavid van Moolenbroek 
86*d56f51eaSDavid van Moolenbroek #ifdef NEED_ADDRINFO_H
87*d56f51eaSDavid van Moolenbroek #include "addrinfo.h"
88*d56f51eaSDavid van Moolenbroek #ifdef WIN32
89*d56f51eaSDavid van Moolenbroek #include "ip6_misc.h"
90*d56f51eaSDavid van Moolenbroek #endif
91*d56f51eaSDavid van Moolenbroek #endif
92*d56f51eaSDavid van Moolenbroek 
93*d56f51eaSDavid van Moolenbroek 
94*d56f51eaSDavid van Moolenbroek #if defined(__KAME__) && defined(INET6)
95*d56f51eaSDavid van Moolenbroek # define FAITH
96*d56f51eaSDavid van Moolenbroek #endif
97*d56f51eaSDavid van Moolenbroek 
98*d56f51eaSDavid van Moolenbroek #define SUCCESS 0
99*d56f51eaSDavid van Moolenbroek #define ANY 0
100*d56f51eaSDavid van Moolenbroek #define YES 1
101*d56f51eaSDavid van Moolenbroek #define NO  0
102*d56f51eaSDavid van Moolenbroek 
103*d56f51eaSDavid van Moolenbroek #ifdef FAITH
104*d56f51eaSDavid van Moolenbroek static int translate = NO;
105*d56f51eaSDavid van Moolenbroek static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT;
106*d56f51eaSDavid van Moolenbroek #endif
107*d56f51eaSDavid van Moolenbroek 
108*d56f51eaSDavid van Moolenbroek static const char in_addrany[] = { 0, 0, 0, 0 };
109*d56f51eaSDavid van Moolenbroek static const char in6_addrany[] = {
110*d56f51eaSDavid van Moolenbroek 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
111*d56f51eaSDavid van Moolenbroek };
112*d56f51eaSDavid van Moolenbroek static const char in_loopback[] = { 127, 0, 0, 1 };
113*d56f51eaSDavid van Moolenbroek static const char in6_loopback[] = {
114*d56f51eaSDavid van Moolenbroek 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
115*d56f51eaSDavid van Moolenbroek };
116*d56f51eaSDavid van Moolenbroek 
117*d56f51eaSDavid van Moolenbroek struct sockinet {
118*d56f51eaSDavid van Moolenbroek 	u_char	si_len;
119*d56f51eaSDavid van Moolenbroek 	u_char	si_family;
120*d56f51eaSDavid van Moolenbroek 	u_short	si_port;
121*d56f51eaSDavid van Moolenbroek 	u_int32_t si_scope_id;
122*d56f51eaSDavid van Moolenbroek };
123*d56f51eaSDavid van Moolenbroek 
124*d56f51eaSDavid van Moolenbroek static const struct afd {
125*d56f51eaSDavid van Moolenbroek 	int a_af;
126*d56f51eaSDavid van Moolenbroek 	int a_addrlen;
127*d56f51eaSDavid van Moolenbroek 	int a_socklen;
128*d56f51eaSDavid van Moolenbroek 	int a_off;
129*d56f51eaSDavid van Moolenbroek 	const char *a_addrany;
130*d56f51eaSDavid van Moolenbroek 	const char *a_loopback;
131*d56f51eaSDavid van Moolenbroek 	int a_scoped;
132*d56f51eaSDavid van Moolenbroek } afdl [] = {
133*d56f51eaSDavid van Moolenbroek #ifdef INET6
134*d56f51eaSDavid van Moolenbroek 	{PF_INET6, sizeof(struct in6_addr),
135*d56f51eaSDavid van Moolenbroek 	 sizeof(struct sockaddr_in6),
136*d56f51eaSDavid van Moolenbroek 	 offsetof(struct sockaddr_in6, sin6_addr),
137*d56f51eaSDavid van Moolenbroek 	 in6_addrany, in6_loopback, 1},
138*d56f51eaSDavid van Moolenbroek #endif
139*d56f51eaSDavid van Moolenbroek 	{PF_INET, sizeof(struct in_addr),
140*d56f51eaSDavid van Moolenbroek 	 sizeof(struct sockaddr_in),
141*d56f51eaSDavid van Moolenbroek 	 offsetof(struct sockaddr_in, sin_addr),
142*d56f51eaSDavid van Moolenbroek 	 in_addrany, in_loopback, 0},
143*d56f51eaSDavid van Moolenbroek 	{0, 0, 0, 0, NULL, NULL, 0},
144*d56f51eaSDavid van Moolenbroek };
145*d56f51eaSDavid van Moolenbroek 
146*d56f51eaSDavid van Moolenbroek struct explore {
147*d56f51eaSDavid van Moolenbroek 	int e_af;
148*d56f51eaSDavid van Moolenbroek 	int e_socktype;
149*d56f51eaSDavid van Moolenbroek 	int e_protocol;
150*d56f51eaSDavid van Moolenbroek 	const char *e_protostr;
151*d56f51eaSDavid van Moolenbroek 	int e_wild;
152*d56f51eaSDavid van Moolenbroek #define WILD_AF(ex)		((ex)->e_wild & 0x01)
153*d56f51eaSDavid van Moolenbroek #define WILD_SOCKTYPE(ex)	((ex)->e_wild & 0x02)
154*d56f51eaSDavid van Moolenbroek #define WILD_PROTOCOL(ex)	((ex)->e_wild & 0x04)
155*d56f51eaSDavid van Moolenbroek };
156*d56f51eaSDavid van Moolenbroek 
157*d56f51eaSDavid van Moolenbroek static const struct explore explore[] = {
158*d56f51eaSDavid van Moolenbroek #if 0
159*d56f51eaSDavid van Moolenbroek 	{ PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
160*d56f51eaSDavid van Moolenbroek #endif
161*d56f51eaSDavid van Moolenbroek #ifdef INET6
162*d56f51eaSDavid van Moolenbroek 	{ PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
163*d56f51eaSDavid van Moolenbroek 	{ PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
164*d56f51eaSDavid van Moolenbroek 	{ PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
165*d56f51eaSDavid van Moolenbroek #endif
166*d56f51eaSDavid van Moolenbroek 	{ PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
167*d56f51eaSDavid van Moolenbroek 	{ PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
168*d56f51eaSDavid van Moolenbroek 	{ PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
169*d56f51eaSDavid van Moolenbroek 	{ -1, 0, 0, NULL, 0 },
170*d56f51eaSDavid van Moolenbroek };
171*d56f51eaSDavid van Moolenbroek 
172*d56f51eaSDavid van Moolenbroek #ifdef INET6
173*d56f51eaSDavid van Moolenbroek #define PTON_MAX	16
174*d56f51eaSDavid van Moolenbroek #else
175*d56f51eaSDavid van Moolenbroek #define PTON_MAX	4
176*d56f51eaSDavid van Moolenbroek #endif
177*d56f51eaSDavid van Moolenbroek 
178*d56f51eaSDavid van Moolenbroek 
179*d56f51eaSDavid van Moolenbroek static int str_isnumber __P((const char *));
180*d56f51eaSDavid van Moolenbroek static int explore_fqdn __P((const struct addrinfo *, const char *,
181*d56f51eaSDavid van Moolenbroek 	const char *, struct addrinfo **));
182*d56f51eaSDavid van Moolenbroek static int explore_null __P((const struct addrinfo *, const char *,
183*d56f51eaSDavid van Moolenbroek 	const char *, struct addrinfo **));
184*d56f51eaSDavid van Moolenbroek static int explore_numeric __P((const struct addrinfo *, const char *,
185*d56f51eaSDavid van Moolenbroek 	const char *, struct addrinfo **));
186*d56f51eaSDavid van Moolenbroek static int explore_numeric_scope __P((const struct addrinfo *, const char *,
187*d56f51eaSDavid van Moolenbroek 	const char *, struct addrinfo **));
188*d56f51eaSDavid van Moolenbroek static int get_name __P((const char *, const struct afd *, struct addrinfo **,
189*d56f51eaSDavid van Moolenbroek 	char *, const struct addrinfo *, const char *));
190*d56f51eaSDavid van Moolenbroek static int get_canonname __P((const struct addrinfo *,
191*d56f51eaSDavid van Moolenbroek 	struct addrinfo *, const char *));
192*d56f51eaSDavid van Moolenbroek static struct addrinfo *get_ai __P((const struct addrinfo *,
193*d56f51eaSDavid van Moolenbroek 	const struct afd *, const char *));
194*d56f51eaSDavid van Moolenbroek static int get_portmatch __P((const struct addrinfo *, const char *));
195*d56f51eaSDavid van Moolenbroek static int get_port __P((struct addrinfo *, const char *, int));
196*d56f51eaSDavid van Moolenbroek static const struct afd *find_afd __P((int));
197*d56f51eaSDavid van Moolenbroek 
198*d56f51eaSDavid van Moolenbroek static char *ai_errlist[] = {
199*d56f51eaSDavid van Moolenbroek 	"Success",
200*d56f51eaSDavid van Moolenbroek 	"Address family for hostname not supported",	/* EAI_ADDRFAMILY */
201*d56f51eaSDavid van Moolenbroek 	"Temporary failure in name resolution",		/* EAI_AGAIN      */
202*d56f51eaSDavid van Moolenbroek 	"Invalid value for ai_flags",		       	/* EAI_BADFLAGS   */
203*d56f51eaSDavid van Moolenbroek 	"Non-recoverable failure in name resolution", 	/* EAI_FAIL       */
204*d56f51eaSDavid van Moolenbroek 	"ai_family not supported",			/* EAI_FAMILY     */
205*d56f51eaSDavid van Moolenbroek 	"Memory allocation failure", 			/* EAI_MEMORY     */
206*d56f51eaSDavid van Moolenbroek 	"No address associated with hostname", 		/* EAI_NODATA     */
207*d56f51eaSDavid van Moolenbroek 	"hostname nor servname provided, or not known",	/* EAI_NONAME     */
208*d56f51eaSDavid van Moolenbroek 	"servname not supported for ai_socktype",	/* EAI_SERVICE    */
209*d56f51eaSDavid van Moolenbroek 	"ai_socktype not supported", 			/* EAI_SOCKTYPE   */
210*d56f51eaSDavid van Moolenbroek 	"System error returned in errno", 		/* EAI_SYSTEM     */
211*d56f51eaSDavid van Moolenbroek 	"Invalid value for hints",			/* EAI_BADHINTS	  */
212*d56f51eaSDavid van Moolenbroek 	"Resolved protocol is unknown",			/* EAI_PROTOCOL   */
213*d56f51eaSDavid van Moolenbroek 	"Unknown error", 				/* EAI_MAX        */
214*d56f51eaSDavid van Moolenbroek };
215*d56f51eaSDavid van Moolenbroek 
216*d56f51eaSDavid van Moolenbroek /* XXX macros that make external reference is BAD. */
217*d56f51eaSDavid van Moolenbroek 
218*d56f51eaSDavid van Moolenbroek #define GET_AI(ai, afd, addr) \
219*d56f51eaSDavid van Moolenbroek do { \
220*d56f51eaSDavid van Moolenbroek 	/* external reference: pai, error, and label free */ \
221*d56f51eaSDavid van Moolenbroek 	(ai) = get_ai(pai, (afd), (addr)); \
222*d56f51eaSDavid van Moolenbroek 	if ((ai) == NULL) { \
223*d56f51eaSDavid van Moolenbroek 		error = EAI_MEMORY; \
224*d56f51eaSDavid van Moolenbroek 		goto free; \
225*d56f51eaSDavid van Moolenbroek 	} \
226*d56f51eaSDavid van Moolenbroek } while (0)
227*d56f51eaSDavid van Moolenbroek 
228*d56f51eaSDavid van Moolenbroek #define GET_PORT(ai, serv) \
229*d56f51eaSDavid van Moolenbroek do { \
230*d56f51eaSDavid van Moolenbroek 	/* external reference: error and label free */ \
231*d56f51eaSDavid van Moolenbroek 	error = get_port((ai), (serv), 0); \
232*d56f51eaSDavid van Moolenbroek 	if (error != 0) \
233*d56f51eaSDavid van Moolenbroek 		goto free; \
234*d56f51eaSDavid van Moolenbroek } while (0)
235*d56f51eaSDavid van Moolenbroek 
236*d56f51eaSDavid van Moolenbroek #define GET_CANONNAME(ai, str) \
237*d56f51eaSDavid van Moolenbroek do { \
238*d56f51eaSDavid van Moolenbroek 	/* external reference: pai, error and label free */ \
239*d56f51eaSDavid van Moolenbroek 	error = get_canonname(pai, (ai), (str)); \
240*d56f51eaSDavid van Moolenbroek 	if (error != 0) \
241*d56f51eaSDavid van Moolenbroek 		goto free; \
242*d56f51eaSDavid van Moolenbroek } while (0)
243*d56f51eaSDavid van Moolenbroek 
244*d56f51eaSDavid van Moolenbroek #define ERR(err) \
245*d56f51eaSDavid van Moolenbroek do { \
246*d56f51eaSDavid van Moolenbroek 	/* external reference: error, and label bad */ \
247*d56f51eaSDavid van Moolenbroek 	error = (err); \
248*d56f51eaSDavid van Moolenbroek 	goto bad; \
249*d56f51eaSDavid van Moolenbroek } while (0)
250*d56f51eaSDavid van Moolenbroek 
251*d56f51eaSDavid van Moolenbroek #define MATCH_FAMILY(x, y, w) \
252*d56f51eaSDavid van Moolenbroek 	((x) == (y) || ((w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
253*d56f51eaSDavid van Moolenbroek #define MATCH(x, y, w) \
254*d56f51eaSDavid van Moolenbroek 	((x) == (y) || ((w) && ((x) == ANY || (y) == ANY)))
255*d56f51eaSDavid van Moolenbroek 
256*d56f51eaSDavid van Moolenbroek #if  defined(DEFINE_ADDITIONAL_IPV6_STUFF)
257*d56f51eaSDavid van Moolenbroek char *
gai_strerror(ecode)258*d56f51eaSDavid van Moolenbroek gai_strerror(ecode)
259*d56f51eaSDavid van Moolenbroek 	int ecode;
260*d56f51eaSDavid van Moolenbroek {
261*d56f51eaSDavid van Moolenbroek 	if (ecode < 0 || ecode > EAI_MAX)
262*d56f51eaSDavid van Moolenbroek 		ecode = EAI_MAX;
263*d56f51eaSDavid van Moolenbroek 	return ai_errlist[ecode];
264*d56f51eaSDavid van Moolenbroek }
265*d56f51eaSDavid van Moolenbroek #endif
266*d56f51eaSDavid van Moolenbroek 
267*d56f51eaSDavid van Moolenbroek void
freeaddrinfo(ai)268*d56f51eaSDavid van Moolenbroek freeaddrinfo(ai)
269*d56f51eaSDavid van Moolenbroek 	struct addrinfo *ai;
270*d56f51eaSDavid van Moolenbroek {
271*d56f51eaSDavid van Moolenbroek 	struct addrinfo *next;
272*d56f51eaSDavid van Moolenbroek 
273*d56f51eaSDavid van Moolenbroek 	do {
274*d56f51eaSDavid van Moolenbroek 		next = ai->ai_next;
275*d56f51eaSDavid van Moolenbroek 		if (ai->ai_canonname)
276*d56f51eaSDavid van Moolenbroek 			free(ai->ai_canonname);
277*d56f51eaSDavid van Moolenbroek 		/* no need to free(ai->ai_addr) */
278*d56f51eaSDavid van Moolenbroek 		free(ai);
279*d56f51eaSDavid van Moolenbroek 	} while ((ai = next) != NULL);
280*d56f51eaSDavid van Moolenbroek }
281*d56f51eaSDavid van Moolenbroek 
282*d56f51eaSDavid van Moolenbroek static int
str_isnumber(p)283*d56f51eaSDavid van Moolenbroek str_isnumber(p)
284*d56f51eaSDavid van Moolenbroek 	const char *p;
285*d56f51eaSDavid van Moolenbroek {
286*d56f51eaSDavid van Moolenbroek 	char *q = (char *)p;
287*d56f51eaSDavid van Moolenbroek 	while (*q) {
288*d56f51eaSDavid van Moolenbroek 		if (! isdigit(*q))
289*d56f51eaSDavid van Moolenbroek 			return NO;
290*d56f51eaSDavid van Moolenbroek 		q++;
291*d56f51eaSDavid van Moolenbroek 	}
292*d56f51eaSDavid van Moolenbroek 	return YES;
293*d56f51eaSDavid van Moolenbroek }
294*d56f51eaSDavid van Moolenbroek 
295*d56f51eaSDavid van Moolenbroek int
getaddrinfo(hostname,servname,hints,res)296*d56f51eaSDavid van Moolenbroek getaddrinfo(hostname, servname, hints, res)
297*d56f51eaSDavid van Moolenbroek 	const char *hostname, *servname;
298*d56f51eaSDavid van Moolenbroek 	const struct addrinfo *hints;
299*d56f51eaSDavid van Moolenbroek 	struct addrinfo **res;
300*d56f51eaSDavid van Moolenbroek {
301*d56f51eaSDavid van Moolenbroek 	struct addrinfo sentinel;
302*d56f51eaSDavid van Moolenbroek 	struct addrinfo *cur;
303*d56f51eaSDavid van Moolenbroek 	int error = 0;
304*d56f51eaSDavid van Moolenbroek 	struct addrinfo ai;
305*d56f51eaSDavid van Moolenbroek 	struct addrinfo ai0;
306*d56f51eaSDavid van Moolenbroek 	struct addrinfo *pai;
307*d56f51eaSDavid van Moolenbroek 	const struct afd *afd;
308*d56f51eaSDavid van Moolenbroek 	const struct explore *ex;
309*d56f51eaSDavid van Moolenbroek 
310*d56f51eaSDavid van Moolenbroek #ifdef FAITH
311*d56f51eaSDavid van Moolenbroek 	static int firsttime = 1;
312*d56f51eaSDavid van Moolenbroek 
313*d56f51eaSDavid van Moolenbroek 	if (firsttime) {
314*d56f51eaSDavid van Moolenbroek 		/* translator hack */
315*d56f51eaSDavid van Moolenbroek 		char *q = getenv("GAI");
316*d56f51eaSDavid van Moolenbroek 		if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
317*d56f51eaSDavid van Moolenbroek 			translate = YES;
318*d56f51eaSDavid van Moolenbroek 		firsttime = 0;
319*d56f51eaSDavid van Moolenbroek 	}
320*d56f51eaSDavid van Moolenbroek #endif
321*d56f51eaSDavid van Moolenbroek 
322*d56f51eaSDavid van Moolenbroek 	sentinel.ai_next = NULL;
323*d56f51eaSDavid van Moolenbroek 	cur = &sentinel;
324*d56f51eaSDavid van Moolenbroek 	pai = &ai;
325*d56f51eaSDavid van Moolenbroek 	pai->ai_flags = 0;
326*d56f51eaSDavid van Moolenbroek 	pai->ai_family = PF_UNSPEC;
327*d56f51eaSDavid van Moolenbroek 	pai->ai_socktype = ANY;
328*d56f51eaSDavid van Moolenbroek 	pai->ai_protocol = ANY;
329*d56f51eaSDavid van Moolenbroek 	pai->ai_addrlen = 0;
330*d56f51eaSDavid van Moolenbroek 	pai->ai_canonname = NULL;
331*d56f51eaSDavid van Moolenbroek 	pai->ai_addr = NULL;
332*d56f51eaSDavid van Moolenbroek 	pai->ai_next = NULL;
333*d56f51eaSDavid van Moolenbroek 
334*d56f51eaSDavid van Moolenbroek 	if (hostname == NULL && servname == NULL)
335*d56f51eaSDavid van Moolenbroek 		return EAI_NONAME;
336*d56f51eaSDavid van Moolenbroek 	if (hints) {
337*d56f51eaSDavid van Moolenbroek 		/* error check for hints */
338*d56f51eaSDavid van Moolenbroek 		if (hints->ai_addrlen || hints->ai_canonname ||
339*d56f51eaSDavid van Moolenbroek 		    hints->ai_addr || hints->ai_next)
340*d56f51eaSDavid van Moolenbroek 			ERR(EAI_BADHINTS); /* xxx */
341*d56f51eaSDavid van Moolenbroek 		if (hints->ai_flags & ~AI_MASK)
342*d56f51eaSDavid van Moolenbroek 			ERR(EAI_BADFLAGS);
343*d56f51eaSDavid van Moolenbroek 		switch (hints->ai_family) {
344*d56f51eaSDavid van Moolenbroek 		case PF_UNSPEC:
345*d56f51eaSDavid van Moolenbroek 		case PF_INET:
346*d56f51eaSDavid van Moolenbroek #ifdef INET6
347*d56f51eaSDavid van Moolenbroek 		case PF_INET6:
348*d56f51eaSDavid van Moolenbroek #endif
349*d56f51eaSDavid van Moolenbroek 			break;
350*d56f51eaSDavid van Moolenbroek 		default:
351*d56f51eaSDavid van Moolenbroek 			ERR(EAI_FAMILY);
352*d56f51eaSDavid van Moolenbroek 		}
353*d56f51eaSDavid van Moolenbroek 		memcpy(pai, hints, sizeof(*pai));
354*d56f51eaSDavid van Moolenbroek 
355*d56f51eaSDavid van Moolenbroek 		/*
356*d56f51eaSDavid van Moolenbroek 		 * if both socktype/protocol are specified, check if they
357*d56f51eaSDavid van Moolenbroek 		 * are meaningful combination.
358*d56f51eaSDavid van Moolenbroek 		 */
359*d56f51eaSDavid van Moolenbroek 		if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
360*d56f51eaSDavid van Moolenbroek 			for (ex = explore; ex->e_af >= 0; ex++) {
361*d56f51eaSDavid van Moolenbroek 				if (pai->ai_family != ex->e_af)
362*d56f51eaSDavid van Moolenbroek 					continue;
363*d56f51eaSDavid van Moolenbroek 				if (ex->e_socktype == ANY)
364*d56f51eaSDavid van Moolenbroek 					continue;
365*d56f51eaSDavid van Moolenbroek 				if (ex->e_protocol == ANY)
366*d56f51eaSDavid van Moolenbroek 					continue;
367*d56f51eaSDavid van Moolenbroek 				if (pai->ai_socktype == ex->e_socktype
368*d56f51eaSDavid van Moolenbroek 				 && pai->ai_protocol != ex->e_protocol) {
369*d56f51eaSDavid van Moolenbroek 					ERR(EAI_BADHINTS);
370*d56f51eaSDavid van Moolenbroek 				}
371*d56f51eaSDavid van Moolenbroek 			}
372*d56f51eaSDavid van Moolenbroek 		}
373*d56f51eaSDavid van Moolenbroek 	}
374*d56f51eaSDavid van Moolenbroek 
375*d56f51eaSDavid van Moolenbroek 	/*
376*d56f51eaSDavid van Moolenbroek 	 * check for special cases.  (1) numeric servname is disallowed if
377*d56f51eaSDavid van Moolenbroek 	 * socktype/protocol are left unspecified. (2) servname is disallowed
378*d56f51eaSDavid van Moolenbroek 	 * for raw and other inet{,6} sockets.
379*d56f51eaSDavid van Moolenbroek 	 */
380*d56f51eaSDavid van Moolenbroek 	if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
381*d56f51eaSDavid van Moolenbroek #ifdef PF_INET6
382*d56f51eaSDavid van Moolenbroek 	 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
383*d56f51eaSDavid van Moolenbroek #endif
384*d56f51eaSDavid van Moolenbroek 	    ) {
385*d56f51eaSDavid van Moolenbroek 		ai0 = *pai;
386*d56f51eaSDavid van Moolenbroek 
387*d56f51eaSDavid van Moolenbroek 		if (pai->ai_family == PF_UNSPEC) {
388*d56f51eaSDavid van Moolenbroek #ifdef PF_INET6
389*d56f51eaSDavid van Moolenbroek 			pai->ai_family = PF_INET6;
390*d56f51eaSDavid van Moolenbroek #else
391*d56f51eaSDavid van Moolenbroek 			pai->ai_family = PF_INET;
392*d56f51eaSDavid van Moolenbroek #endif
393*d56f51eaSDavid van Moolenbroek 		}
394*d56f51eaSDavid van Moolenbroek 		error = get_portmatch(pai, servname);
395*d56f51eaSDavid van Moolenbroek 		if (error)
396*d56f51eaSDavid van Moolenbroek 			ERR(error);
397*d56f51eaSDavid van Moolenbroek 
398*d56f51eaSDavid van Moolenbroek 		*pai = ai0;
399*d56f51eaSDavid van Moolenbroek 	}
400*d56f51eaSDavid van Moolenbroek 
401*d56f51eaSDavid van Moolenbroek 	ai0 = *pai;
402*d56f51eaSDavid van Moolenbroek 
403*d56f51eaSDavid van Moolenbroek 	/* NULL hostname, or numeric hostname */
404*d56f51eaSDavid van Moolenbroek 	for (ex = explore; ex->e_af >= 0; ex++) {
405*d56f51eaSDavid van Moolenbroek 		*pai = ai0;
406*d56f51eaSDavid van Moolenbroek 
407*d56f51eaSDavid van Moolenbroek 		if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
408*d56f51eaSDavid van Moolenbroek 			continue;
409*d56f51eaSDavid van Moolenbroek 		if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
410*d56f51eaSDavid van Moolenbroek 			continue;
411*d56f51eaSDavid van Moolenbroek 		if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
412*d56f51eaSDavid van Moolenbroek 			continue;
413*d56f51eaSDavid van Moolenbroek 
414*d56f51eaSDavid van Moolenbroek 		if (pai->ai_family == PF_UNSPEC)
415*d56f51eaSDavid van Moolenbroek 			pai->ai_family = ex->e_af;
416*d56f51eaSDavid van Moolenbroek 		if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
417*d56f51eaSDavid van Moolenbroek 			pai->ai_socktype = ex->e_socktype;
418*d56f51eaSDavid van Moolenbroek 		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
419*d56f51eaSDavid van Moolenbroek 			pai->ai_protocol = ex->e_protocol;
420*d56f51eaSDavid van Moolenbroek 
421*d56f51eaSDavid van Moolenbroek 		if (hostname == NULL)
422*d56f51eaSDavid van Moolenbroek 			error = explore_null(pai, hostname, servname, &cur->ai_next);
423*d56f51eaSDavid van Moolenbroek 		else
424*d56f51eaSDavid van Moolenbroek 			error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
425*d56f51eaSDavid van Moolenbroek 
426*d56f51eaSDavid van Moolenbroek 		if (error)
427*d56f51eaSDavid van Moolenbroek 			goto free;
428*d56f51eaSDavid van Moolenbroek 
429*d56f51eaSDavid van Moolenbroek 		while (cur && cur->ai_next)
430*d56f51eaSDavid van Moolenbroek 			cur = cur->ai_next;
431*d56f51eaSDavid van Moolenbroek 	}
432*d56f51eaSDavid van Moolenbroek 
433*d56f51eaSDavid van Moolenbroek 	/*
434*d56f51eaSDavid van Moolenbroek 	 * XXX
435*d56f51eaSDavid van Moolenbroek 	 * If numreic representation of AF1 can be interpreted as FQDN
436*d56f51eaSDavid van Moolenbroek 	 * representation of AF2, we need to think again about the code below.
437*d56f51eaSDavid van Moolenbroek 	 */
438*d56f51eaSDavid van Moolenbroek 	if (sentinel.ai_next)
439*d56f51eaSDavid van Moolenbroek 		goto good;
440*d56f51eaSDavid van Moolenbroek 
441*d56f51eaSDavid van Moolenbroek 	if (pai->ai_flags & AI_NUMERICHOST)
442*d56f51eaSDavid van Moolenbroek 		ERR(EAI_NONAME);
443*d56f51eaSDavid van Moolenbroek 	if (hostname == NULL)
444*d56f51eaSDavid van Moolenbroek 		ERR(EAI_NONAME);
445*d56f51eaSDavid van Moolenbroek 
446*d56f51eaSDavid van Moolenbroek 	/*
447*d56f51eaSDavid van Moolenbroek 	 * hostname as alphabetical name.
448*d56f51eaSDavid van Moolenbroek 	 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
449*d56f51eaSDavid van Moolenbroek 	 * outer loop by AFs.
450*d56f51eaSDavid van Moolenbroek 	 */
451*d56f51eaSDavid van Moolenbroek 	for (afd = afdl; afd->a_af; afd++) {
452*d56f51eaSDavid van Moolenbroek 		*pai = ai0;
453*d56f51eaSDavid van Moolenbroek 
454*d56f51eaSDavid van Moolenbroek 		if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1))
455*d56f51eaSDavid van Moolenbroek 			continue;
456*d56f51eaSDavid van Moolenbroek 
457*d56f51eaSDavid van Moolenbroek 		for (ex = explore; ex->e_af >= 0; ex++) {
458*d56f51eaSDavid van Moolenbroek 			*pai = ai0;
459*d56f51eaSDavid van Moolenbroek 
460*d56f51eaSDavid van Moolenbroek 			if (pai->ai_family == PF_UNSPEC)
461*d56f51eaSDavid van Moolenbroek 				pai->ai_family = afd->a_af;
462*d56f51eaSDavid van Moolenbroek 
463*d56f51eaSDavid van Moolenbroek 			if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
464*d56f51eaSDavid van Moolenbroek 				continue;
465*d56f51eaSDavid van Moolenbroek 			if (!MATCH(pai->ai_socktype, ex->e_socktype,
466*d56f51eaSDavid van Moolenbroek 					WILD_SOCKTYPE(ex))) {
467*d56f51eaSDavid van Moolenbroek 				continue;
468*d56f51eaSDavid van Moolenbroek 			}
469*d56f51eaSDavid van Moolenbroek 			if (!MATCH(pai->ai_protocol, ex->e_protocol,
470*d56f51eaSDavid van Moolenbroek 					WILD_PROTOCOL(ex))) {
471*d56f51eaSDavid van Moolenbroek 				continue;
472*d56f51eaSDavid van Moolenbroek 			}
473*d56f51eaSDavid van Moolenbroek 
474*d56f51eaSDavid van Moolenbroek 			if (pai->ai_family == PF_UNSPEC)
475*d56f51eaSDavid van Moolenbroek 				pai->ai_family = ex->e_af;
476*d56f51eaSDavid van Moolenbroek 			if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
477*d56f51eaSDavid van Moolenbroek 				pai->ai_socktype = ex->e_socktype;
478*d56f51eaSDavid van Moolenbroek 			if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
479*d56f51eaSDavid van Moolenbroek 				pai->ai_protocol = ex->e_protocol;
480*d56f51eaSDavid van Moolenbroek 
481*d56f51eaSDavid van Moolenbroek 			error = explore_fqdn(pai, hostname, servname,
482*d56f51eaSDavid van Moolenbroek 				&cur->ai_next);
483*d56f51eaSDavid van Moolenbroek 
484*d56f51eaSDavid van Moolenbroek 			while (cur && cur->ai_next)
485*d56f51eaSDavid van Moolenbroek 				cur = cur->ai_next;
486*d56f51eaSDavid van Moolenbroek 		}
487*d56f51eaSDavid van Moolenbroek 	}
488*d56f51eaSDavid van Moolenbroek 
489*d56f51eaSDavid van Moolenbroek 	/* XXX */
490*d56f51eaSDavid van Moolenbroek 	if (sentinel.ai_next)
491*d56f51eaSDavid van Moolenbroek 		error = 0;
492*d56f51eaSDavid van Moolenbroek 
493*d56f51eaSDavid van Moolenbroek 	if (error)
494*d56f51eaSDavid van Moolenbroek 		goto free;
495*d56f51eaSDavid van Moolenbroek 	if (error == 0) {
496*d56f51eaSDavid van Moolenbroek 		if (sentinel.ai_next) {
497*d56f51eaSDavid van Moolenbroek  good:
498*d56f51eaSDavid van Moolenbroek 			*res = sentinel.ai_next;
499*d56f51eaSDavid van Moolenbroek 			return SUCCESS;
500*d56f51eaSDavid van Moolenbroek 		} else
501*d56f51eaSDavid van Moolenbroek 			error = EAI_FAIL;
502*d56f51eaSDavid van Moolenbroek 	}
503*d56f51eaSDavid van Moolenbroek  free:
504*d56f51eaSDavid van Moolenbroek  bad:
505*d56f51eaSDavid van Moolenbroek 	if (sentinel.ai_next)
506*d56f51eaSDavid van Moolenbroek 		freeaddrinfo(sentinel.ai_next);
507*d56f51eaSDavid van Moolenbroek 	*res = NULL;
508*d56f51eaSDavid van Moolenbroek 	return error;
509*d56f51eaSDavid van Moolenbroek }
510*d56f51eaSDavid van Moolenbroek 
511*d56f51eaSDavid van Moolenbroek /*
512*d56f51eaSDavid van Moolenbroek  * FQDN hostname, DNS lookup
513*d56f51eaSDavid van Moolenbroek  */
514*d56f51eaSDavid van Moolenbroek static int
explore_fqdn(pai,hostname,servname,res)515*d56f51eaSDavid van Moolenbroek explore_fqdn(pai, hostname, servname, res)
516*d56f51eaSDavid van Moolenbroek 	const struct addrinfo *pai;
517*d56f51eaSDavid van Moolenbroek 	const char *hostname;
518*d56f51eaSDavid van Moolenbroek 	const char *servname;
519*d56f51eaSDavid van Moolenbroek 	struct addrinfo **res;
520*d56f51eaSDavid van Moolenbroek {
521*d56f51eaSDavid van Moolenbroek 	struct hostent *hp;
522*d56f51eaSDavid van Moolenbroek 	int h_error;
523*d56f51eaSDavid van Moolenbroek 	int af;
524*d56f51eaSDavid van Moolenbroek 	char **aplist = NULL, *apbuf = NULL;
525*d56f51eaSDavid van Moolenbroek 	char *ap;
526*d56f51eaSDavid van Moolenbroek 	struct addrinfo sentinel, *cur;
527*d56f51eaSDavid van Moolenbroek 	int i;
528*d56f51eaSDavid van Moolenbroek #ifndef USE_GETIPNODEBY
529*d56f51eaSDavid van Moolenbroek 	int naddrs;
530*d56f51eaSDavid van Moolenbroek #endif
531*d56f51eaSDavid van Moolenbroek 	const struct afd *afd;
532*d56f51eaSDavid van Moolenbroek 	int error;
533*d56f51eaSDavid van Moolenbroek 
534*d56f51eaSDavid van Moolenbroek 	*res = NULL;
535*d56f51eaSDavid van Moolenbroek 	sentinel.ai_next = NULL;
536*d56f51eaSDavid van Moolenbroek 	cur = &sentinel;
537*d56f51eaSDavid van Moolenbroek 
538*d56f51eaSDavid van Moolenbroek 	/*
539*d56f51eaSDavid van Moolenbroek 	 * Do not filter unsupported AFs here.  We need to honor content of
540*d56f51eaSDavid van Moolenbroek 	 * databases (/etc/hosts, DNS and others).  Otherwise we cannot
541*d56f51eaSDavid van Moolenbroek 	 * replace gethostbyname() by getaddrinfo().
542*d56f51eaSDavid van Moolenbroek 	 */
543*d56f51eaSDavid van Moolenbroek 
544*d56f51eaSDavid van Moolenbroek 	/*
545*d56f51eaSDavid van Moolenbroek 	 * if the servname does not match socktype/protocol, ignore it.
546*d56f51eaSDavid van Moolenbroek 	 */
547*d56f51eaSDavid van Moolenbroek 	if (get_portmatch(pai, servname) != 0)
548*d56f51eaSDavid van Moolenbroek 		return 0;
549*d56f51eaSDavid van Moolenbroek 
550*d56f51eaSDavid van Moolenbroek 	afd = find_afd(pai->ai_family);
551*d56f51eaSDavid van Moolenbroek 
552*d56f51eaSDavid van Moolenbroek 	/*
553*d56f51eaSDavid van Moolenbroek 	 * post-RFC2553: should look at (pai->ai_flags & AI_ADDRCONFIG)
554*d56f51eaSDavid van Moolenbroek 	 * rather than hardcoding it.  we may need to add AI_ADDRCONFIG
555*d56f51eaSDavid van Moolenbroek 	 * handling code by ourselves in case we don't have getipnodebyname().
556*d56f51eaSDavid van Moolenbroek 	 */
557*d56f51eaSDavid van Moolenbroek #ifdef USE_GETIPNODEBY
558*d56f51eaSDavid van Moolenbroek 	hp = getipnodebyname(hostname, pai->ai_family, AI_ADDRCONFIG, &h_error);
559*d56f51eaSDavid van Moolenbroek #else
560*d56f51eaSDavid van Moolenbroek #ifdef HAVE_GETHOSTBYNAME2
561*d56f51eaSDavid van Moolenbroek 	hp = gethostbyname2(hostname, pai->ai_family);
562*d56f51eaSDavid van Moolenbroek #else
563*d56f51eaSDavid van Moolenbroek 	if (pai->ai_family != AF_INET)
564*d56f51eaSDavid van Moolenbroek 		return 0;
565*d56f51eaSDavid van Moolenbroek 	hp = gethostbyname(hostname);
566*d56f51eaSDavid van Moolenbroek #ifdef HAVE_H_ERRNO
567*d56f51eaSDavid van Moolenbroek 	h_error = h_errno;
568*d56f51eaSDavid van Moolenbroek #else
569*d56f51eaSDavid van Moolenbroek 	h_error = EINVAL;
570*d56f51eaSDavid van Moolenbroek #endif
571*d56f51eaSDavid van Moolenbroek #endif /*HAVE_GETHOSTBYNAME2*/
572*d56f51eaSDavid van Moolenbroek #endif /*USE_GETIPNODEBY*/
573*d56f51eaSDavid van Moolenbroek 
574*d56f51eaSDavid van Moolenbroek 	if (hp == NULL) {
575*d56f51eaSDavid van Moolenbroek 		switch (h_error) {
576*d56f51eaSDavid van Moolenbroek 		case HOST_NOT_FOUND:
577*d56f51eaSDavid van Moolenbroek 		case NO_DATA:
578*d56f51eaSDavid van Moolenbroek 			error = EAI_NODATA;
579*d56f51eaSDavid van Moolenbroek 			break;
580*d56f51eaSDavid van Moolenbroek 		case TRY_AGAIN:
581*d56f51eaSDavid van Moolenbroek 			error = EAI_AGAIN;
582*d56f51eaSDavid van Moolenbroek 			break;
583*d56f51eaSDavid van Moolenbroek 		case NO_RECOVERY:
584*d56f51eaSDavid van Moolenbroek 		case NETDB_INTERNAL:
585*d56f51eaSDavid van Moolenbroek 		default:
586*d56f51eaSDavid van Moolenbroek 			error = EAI_FAIL;
587*d56f51eaSDavid van Moolenbroek 			break;
588*d56f51eaSDavid van Moolenbroek 		}
589*d56f51eaSDavid van Moolenbroek 	} else if ((hp->h_name == NULL) || (hp->h_name[0] == 0)
590*d56f51eaSDavid van Moolenbroek 			|| (hp->h_addr_list[0] == NULL)) {
591*d56f51eaSDavid van Moolenbroek #ifdef USE_GETIPNODEBY
592*d56f51eaSDavid van Moolenbroek 		freehostent(hp);
593*d56f51eaSDavid van Moolenbroek #endif
594*d56f51eaSDavid van Moolenbroek 		hp = NULL;
595*d56f51eaSDavid van Moolenbroek 		error = EAI_FAIL;
596*d56f51eaSDavid van Moolenbroek 	}
597*d56f51eaSDavid van Moolenbroek 
598*d56f51eaSDavid van Moolenbroek 	if (hp == NULL)
599*d56f51eaSDavid van Moolenbroek 		goto free;
600*d56f51eaSDavid van Moolenbroek 
601*d56f51eaSDavid van Moolenbroek #ifdef USE_GETIPNODEBY
602*d56f51eaSDavid van Moolenbroek 	aplist = hp->h_addr_list;
603*d56f51eaSDavid van Moolenbroek #else
604*d56f51eaSDavid van Moolenbroek 	/*
605*d56f51eaSDavid van Moolenbroek 	 * hp will be overwritten if we use gethostbyname2().
606*d56f51eaSDavid van Moolenbroek 	 * always deep copy for simplification.
607*d56f51eaSDavid van Moolenbroek 	 */
608*d56f51eaSDavid van Moolenbroek 	for (naddrs = 0; hp->h_addr_list[naddrs] != NULL; naddrs++)
609*d56f51eaSDavid van Moolenbroek 		;
610*d56f51eaSDavid van Moolenbroek 	naddrs++;
611*d56f51eaSDavid van Moolenbroek 	aplist = (char **)malloc(sizeof(aplist[0]) * naddrs);
612*d56f51eaSDavid van Moolenbroek 	apbuf = (char *)malloc(hp->h_length * naddrs);
613*d56f51eaSDavid van Moolenbroek 	if (aplist == NULL || apbuf == NULL) {
614*d56f51eaSDavid van Moolenbroek 		error = EAI_MEMORY;
615*d56f51eaSDavid van Moolenbroek 		goto free;
616*d56f51eaSDavid van Moolenbroek 	}
617*d56f51eaSDavid van Moolenbroek 	memset(aplist, 0, sizeof(aplist[0]) * naddrs);
618*d56f51eaSDavid van Moolenbroek 	for (i = 0; i < naddrs; i++) {
619*d56f51eaSDavid van Moolenbroek 		if (hp->h_addr_list[i] == NULL) {
620*d56f51eaSDavid van Moolenbroek 			aplist[i] = NULL;
621*d56f51eaSDavid van Moolenbroek 			continue;
622*d56f51eaSDavid van Moolenbroek 		}
623*d56f51eaSDavid van Moolenbroek 		memcpy(&apbuf[i * hp->h_length], hp->h_addr_list[i],
624*d56f51eaSDavid van Moolenbroek 			hp->h_length);
625*d56f51eaSDavid van Moolenbroek 		aplist[i] = &apbuf[i * hp->h_length];
626*d56f51eaSDavid van Moolenbroek 	}
627*d56f51eaSDavid van Moolenbroek #endif
628*d56f51eaSDavid van Moolenbroek 
629*d56f51eaSDavid van Moolenbroek 	for (i = 0; aplist[i] != NULL; i++) {
630*d56f51eaSDavid van Moolenbroek 		af = hp->h_addrtype;
631*d56f51eaSDavid van Moolenbroek 		ap = aplist[i];
632*d56f51eaSDavid van Moolenbroek #ifdef AF_INET6
633*d56f51eaSDavid van Moolenbroek 		if (af == AF_INET6
634*d56f51eaSDavid van Moolenbroek 		 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
635*d56f51eaSDavid van Moolenbroek 			af = AF_INET;
636*d56f51eaSDavid van Moolenbroek 			ap = ap + sizeof(struct in6_addr)
637*d56f51eaSDavid van Moolenbroek 				- sizeof(struct in_addr);
638*d56f51eaSDavid van Moolenbroek 		}
639*d56f51eaSDavid van Moolenbroek #endif
640*d56f51eaSDavid van Moolenbroek 
641*d56f51eaSDavid van Moolenbroek 		if (af != pai->ai_family)
642*d56f51eaSDavid van Moolenbroek 			continue;
643*d56f51eaSDavid van Moolenbroek 
644*d56f51eaSDavid van Moolenbroek 		if ((pai->ai_flags & AI_CANONNAME) == 0) {
645*d56f51eaSDavid van Moolenbroek 			GET_AI(cur->ai_next, afd, ap);
646*d56f51eaSDavid van Moolenbroek 			GET_PORT(cur->ai_next, servname);
647*d56f51eaSDavid van Moolenbroek 		} else {
648*d56f51eaSDavid van Moolenbroek 			/*
649*d56f51eaSDavid van Moolenbroek 			 * if AI_CANONNAME and if reverse lookup
650*d56f51eaSDavid van Moolenbroek 			 * fail, return ai anyway to pacify
651*d56f51eaSDavid van Moolenbroek 			 * calling application.
652*d56f51eaSDavid van Moolenbroek 			 *
653*d56f51eaSDavid van Moolenbroek 			 * XXX getaddrinfo() is a name->address
654*d56f51eaSDavid van Moolenbroek 			 * translation function, and it looks
655*d56f51eaSDavid van Moolenbroek 			 * strange that we do addr->name
656*d56f51eaSDavid van Moolenbroek 			 * translation here.
657*d56f51eaSDavid van Moolenbroek 			 */
658*d56f51eaSDavid van Moolenbroek 			get_name(ap, afd, &cur->ai_next,
659*d56f51eaSDavid van Moolenbroek 				ap, pai, servname);
660*d56f51eaSDavid van Moolenbroek 		}
661*d56f51eaSDavid van Moolenbroek 
662*d56f51eaSDavid van Moolenbroek 		while (cur && cur->ai_next)
663*d56f51eaSDavid van Moolenbroek 			cur = cur->ai_next;
664*d56f51eaSDavid van Moolenbroek 	}
665*d56f51eaSDavid van Moolenbroek 
666*d56f51eaSDavid van Moolenbroek 	*res = sentinel.ai_next;
667*d56f51eaSDavid van Moolenbroek 	return 0;
668*d56f51eaSDavid van Moolenbroek 
669*d56f51eaSDavid van Moolenbroek free:
670*d56f51eaSDavid van Moolenbroek #ifdef USE_GETIPNODEBY
671*d56f51eaSDavid van Moolenbroek 	if (hp)
672*d56f51eaSDavid van Moolenbroek 		freehostent(hp);
673*d56f51eaSDavid van Moolenbroek #endif
674*d56f51eaSDavid van Moolenbroek 	if (aplist)
675*d56f51eaSDavid van Moolenbroek 		free(aplist);
676*d56f51eaSDavid van Moolenbroek 	if (apbuf)
677*d56f51eaSDavid van Moolenbroek 		free(apbuf);
678*d56f51eaSDavid van Moolenbroek 	if (sentinel.ai_next)
679*d56f51eaSDavid van Moolenbroek 		freeaddrinfo(sentinel.ai_next);
680*d56f51eaSDavid van Moolenbroek 	return error;
681*d56f51eaSDavid van Moolenbroek }
682*d56f51eaSDavid van Moolenbroek 
683*d56f51eaSDavid van Moolenbroek /*
684*d56f51eaSDavid van Moolenbroek  * hostname == NULL.
685*d56f51eaSDavid van Moolenbroek  * passive socket -> anyaddr (0.0.0.0 or ::)
686*d56f51eaSDavid van Moolenbroek  * non-passive socket -> localhost (127.0.0.1 or ::1)
687*d56f51eaSDavid van Moolenbroek  */
688*d56f51eaSDavid van Moolenbroek static int
explore_null(pai,hostname,servname,res)689*d56f51eaSDavid van Moolenbroek explore_null(pai, hostname, servname, res)
690*d56f51eaSDavid van Moolenbroek 	const struct addrinfo *pai;
691*d56f51eaSDavid van Moolenbroek 	const char *hostname;
692*d56f51eaSDavid van Moolenbroek 	const char *servname;
693*d56f51eaSDavid van Moolenbroek 	struct addrinfo **res;
694*d56f51eaSDavid van Moolenbroek {
695*d56f51eaSDavid van Moolenbroek 	int s;
696*d56f51eaSDavid van Moolenbroek 	const struct afd *afd;
697*d56f51eaSDavid van Moolenbroek 	struct addrinfo *cur;
698*d56f51eaSDavid van Moolenbroek 	struct addrinfo sentinel;
699*d56f51eaSDavid van Moolenbroek 	int error;
700*d56f51eaSDavid van Moolenbroek 
701*d56f51eaSDavid van Moolenbroek 	*res = NULL;
702*d56f51eaSDavid van Moolenbroek 	sentinel.ai_next = NULL;
703*d56f51eaSDavid van Moolenbroek 	cur = &sentinel;
704*d56f51eaSDavid van Moolenbroek 
705*d56f51eaSDavid van Moolenbroek 	/*
706*d56f51eaSDavid van Moolenbroek 	 * filter out AFs that are not supported by the kernel
707*d56f51eaSDavid van Moolenbroek 	 * XXX errno?
708*d56f51eaSDavid van Moolenbroek 	 */
709*d56f51eaSDavid van Moolenbroek 	s = socket(pai->ai_family, SOCK_DGRAM, 0);
710*d56f51eaSDavid van Moolenbroek 	if (s < 0) {
711*d56f51eaSDavid van Moolenbroek 		if (errno != EMFILE)
712*d56f51eaSDavid van Moolenbroek 			return 0;
713*d56f51eaSDavid van Moolenbroek 	} else
714*d56f51eaSDavid van Moolenbroek 		close(s);
715*d56f51eaSDavid van Moolenbroek 
716*d56f51eaSDavid van Moolenbroek 	/*
717*d56f51eaSDavid van Moolenbroek 	 * if the servname does not match socktype/protocol, ignore it.
718*d56f51eaSDavid van Moolenbroek 	 */
719*d56f51eaSDavid van Moolenbroek 	if (get_portmatch(pai, servname) != 0)
720*d56f51eaSDavid van Moolenbroek 		return 0;
721*d56f51eaSDavid van Moolenbroek 
722*d56f51eaSDavid van Moolenbroek 	afd = find_afd(pai->ai_family);
723*d56f51eaSDavid van Moolenbroek 
724*d56f51eaSDavid van Moolenbroek 	if (pai->ai_flags & AI_PASSIVE) {
725*d56f51eaSDavid van Moolenbroek 		GET_AI(cur->ai_next, afd, afd->a_addrany);
726*d56f51eaSDavid van Moolenbroek 		/* xxx meaningless?
727*d56f51eaSDavid van Moolenbroek 		 * GET_CANONNAME(cur->ai_next, "anyaddr");
728*d56f51eaSDavid van Moolenbroek 		 */
729*d56f51eaSDavid van Moolenbroek 		GET_PORT(cur->ai_next, servname);
730*d56f51eaSDavid van Moolenbroek 	} else {
731*d56f51eaSDavid van Moolenbroek 		GET_AI(cur->ai_next, afd, afd->a_loopback);
732*d56f51eaSDavid van Moolenbroek 		/* xxx meaningless?
733*d56f51eaSDavid van Moolenbroek 		 * GET_CANONNAME(cur->ai_next, "localhost");
734*d56f51eaSDavid van Moolenbroek 		 */
735*d56f51eaSDavid van Moolenbroek 		GET_PORT(cur->ai_next, servname);
736*d56f51eaSDavid van Moolenbroek 	}
737*d56f51eaSDavid van Moolenbroek 	cur = cur->ai_next;
738*d56f51eaSDavid van Moolenbroek 
739*d56f51eaSDavid van Moolenbroek 	*res = sentinel.ai_next;
740*d56f51eaSDavid van Moolenbroek 	return 0;
741*d56f51eaSDavid van Moolenbroek 
742*d56f51eaSDavid van Moolenbroek free:
743*d56f51eaSDavid van Moolenbroek 	if (sentinel.ai_next)
744*d56f51eaSDavid van Moolenbroek 		freeaddrinfo(sentinel.ai_next);
745*d56f51eaSDavid van Moolenbroek 	return error;
746*d56f51eaSDavid van Moolenbroek }
747*d56f51eaSDavid van Moolenbroek 
748*d56f51eaSDavid van Moolenbroek /*
749*d56f51eaSDavid van Moolenbroek  * numeric hostname
750*d56f51eaSDavid van Moolenbroek  */
751*d56f51eaSDavid van Moolenbroek static int
explore_numeric(pai,hostname,servname,res)752*d56f51eaSDavid van Moolenbroek explore_numeric(pai, hostname, servname, res)
753*d56f51eaSDavid van Moolenbroek 	const struct addrinfo *pai;
754*d56f51eaSDavid van Moolenbroek 	const char *hostname;
755*d56f51eaSDavid van Moolenbroek 	const char *servname;
756*d56f51eaSDavid van Moolenbroek 	struct addrinfo **res;
757*d56f51eaSDavid van Moolenbroek {
758*d56f51eaSDavid van Moolenbroek 	const struct afd *afd;
759*d56f51eaSDavid van Moolenbroek 	struct addrinfo *cur;
760*d56f51eaSDavid van Moolenbroek 	struct addrinfo sentinel;
761*d56f51eaSDavid van Moolenbroek 	int error;
762*d56f51eaSDavid van Moolenbroek 	char pton[PTON_MAX];
763*d56f51eaSDavid van Moolenbroek 	int flags;
764*d56f51eaSDavid van Moolenbroek 
765*d56f51eaSDavid van Moolenbroek 	*res = NULL;
766*d56f51eaSDavid van Moolenbroek 	sentinel.ai_next = NULL;
767*d56f51eaSDavid van Moolenbroek 	cur = &sentinel;
768*d56f51eaSDavid van Moolenbroek 
769*d56f51eaSDavid van Moolenbroek 	/*
770*d56f51eaSDavid van Moolenbroek 	 * if the servname does not match socktype/protocol, ignore it.
771*d56f51eaSDavid van Moolenbroek 	 */
772*d56f51eaSDavid van Moolenbroek 	if (get_portmatch(pai, servname) != 0)
773*d56f51eaSDavid van Moolenbroek 		return 0;
774*d56f51eaSDavid van Moolenbroek 
775*d56f51eaSDavid van Moolenbroek 	afd = find_afd(pai->ai_family);
776*d56f51eaSDavid van Moolenbroek 	flags = pai->ai_flags;
777*d56f51eaSDavid van Moolenbroek 
778*d56f51eaSDavid van Moolenbroek 	if (inet_pton(afd->a_af, hostname, pton) == 1) {
779*d56f51eaSDavid van Moolenbroek 		u_int32_t v4a;
780*d56f51eaSDavid van Moolenbroek #ifdef INET6
781*d56f51eaSDavid van Moolenbroek 		u_char pfx;
782*d56f51eaSDavid van Moolenbroek #endif
783*d56f51eaSDavid van Moolenbroek 
784*d56f51eaSDavid van Moolenbroek 		switch (afd->a_af) {
785*d56f51eaSDavid van Moolenbroek 		case AF_INET:
786*d56f51eaSDavid van Moolenbroek 			v4a = (u_int32_t)ntohl(((struct in_addr *)pton)->s_addr);
787*d56f51eaSDavid van Moolenbroek 			if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
788*d56f51eaSDavid van Moolenbroek 				flags &= ~AI_CANONNAME;
789*d56f51eaSDavid van Moolenbroek 			v4a >>= IN_CLASSA_NSHIFT;
790*d56f51eaSDavid van Moolenbroek 			if (v4a == 0 || v4a == IN_LOOPBACKNET)
791*d56f51eaSDavid van Moolenbroek 				flags &= ~AI_CANONNAME;
792*d56f51eaSDavid van Moolenbroek 			break;
793*d56f51eaSDavid van Moolenbroek #ifdef INET6
794*d56f51eaSDavid van Moolenbroek 		case AF_INET6:
795*d56f51eaSDavid van Moolenbroek 			pfx = ((struct in6_addr *)pton)->s6_addr[0];
796*d56f51eaSDavid van Moolenbroek 			if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
797*d56f51eaSDavid van Moolenbroek 				flags &= ~AI_CANONNAME;
798*d56f51eaSDavid van Moolenbroek 			break;
799*d56f51eaSDavid van Moolenbroek #endif
800*d56f51eaSDavid van Moolenbroek 		}
801*d56f51eaSDavid van Moolenbroek 
802*d56f51eaSDavid van Moolenbroek 		if (pai->ai_family == afd->a_af ||
803*d56f51eaSDavid van Moolenbroek 		    pai->ai_family == PF_UNSPEC /*?*/) {
804*d56f51eaSDavid van Moolenbroek 			if ((flags & AI_CANONNAME) == 0) {
805*d56f51eaSDavid van Moolenbroek 				GET_AI(cur->ai_next, afd, pton);
806*d56f51eaSDavid van Moolenbroek 				GET_PORT(cur->ai_next, servname);
807*d56f51eaSDavid van Moolenbroek 			} else {
808*d56f51eaSDavid van Moolenbroek 				/*
809*d56f51eaSDavid van Moolenbroek 				 * if AI_CANONNAME and if reverse lookup
810*d56f51eaSDavid van Moolenbroek 				 * fail, return ai anyway to pacify
811*d56f51eaSDavid van Moolenbroek 				 * calling application.
812*d56f51eaSDavid van Moolenbroek 				 *
813*d56f51eaSDavid van Moolenbroek 				 * XXX getaddrinfo() is a name->address
814*d56f51eaSDavid van Moolenbroek 				 * translation function, and it looks
815*d56f51eaSDavid van Moolenbroek 				 * strange that we do addr->name
816*d56f51eaSDavid van Moolenbroek 				 * translation here.
817*d56f51eaSDavid van Moolenbroek 				 */
818*d56f51eaSDavid van Moolenbroek 				get_name(pton, afd, &cur->ai_next,
819*d56f51eaSDavid van Moolenbroek 					pton, pai, servname);
820*d56f51eaSDavid van Moolenbroek 			}
821*d56f51eaSDavid van Moolenbroek 			while (cur && cur->ai_next)
822*d56f51eaSDavid van Moolenbroek 				cur = cur->ai_next;
823*d56f51eaSDavid van Moolenbroek 		} else
824*d56f51eaSDavid van Moolenbroek 			ERR(EAI_FAMILY);	/*xxx*/
825*d56f51eaSDavid van Moolenbroek 	}
826*d56f51eaSDavid van Moolenbroek 
827*d56f51eaSDavid van Moolenbroek 	*res = sentinel.ai_next;
828*d56f51eaSDavid van Moolenbroek 	return 0;
829*d56f51eaSDavid van Moolenbroek 
830*d56f51eaSDavid van Moolenbroek free:
831*d56f51eaSDavid van Moolenbroek bad:
832*d56f51eaSDavid van Moolenbroek 	if (sentinel.ai_next)
833*d56f51eaSDavid van Moolenbroek 		freeaddrinfo(sentinel.ai_next);
834*d56f51eaSDavid van Moolenbroek 	return error;
835*d56f51eaSDavid van Moolenbroek }
836*d56f51eaSDavid van Moolenbroek 
837*d56f51eaSDavid van Moolenbroek /*
838*d56f51eaSDavid van Moolenbroek  * numeric hostname with scope
839*d56f51eaSDavid van Moolenbroek  */
840*d56f51eaSDavid van Moolenbroek static int
explore_numeric_scope(pai,hostname,servname,res)841*d56f51eaSDavid van Moolenbroek explore_numeric_scope(pai, hostname, servname, res)
842*d56f51eaSDavid van Moolenbroek 	const struct addrinfo *pai;
843*d56f51eaSDavid van Moolenbroek 	const char *hostname;
844*d56f51eaSDavid van Moolenbroek 	const char *servname;
845*d56f51eaSDavid van Moolenbroek 	struct addrinfo **res;
846*d56f51eaSDavid van Moolenbroek {
847*d56f51eaSDavid van Moolenbroek #ifndef SCOPE_DELIMITER
848*d56f51eaSDavid van Moolenbroek 	return explore_numeric(pai, hostname, servname, res);
849*d56f51eaSDavid van Moolenbroek #else
850*d56f51eaSDavid van Moolenbroek 	const struct afd *afd;
851*d56f51eaSDavid van Moolenbroek 	struct addrinfo *cur;
852*d56f51eaSDavid van Moolenbroek 	int error;
853*d56f51eaSDavid van Moolenbroek 	char *cp, *hostname2 = NULL;
854*d56f51eaSDavid van Moolenbroek 	int scope;
855*d56f51eaSDavid van Moolenbroek 	struct sockaddr_in6 *sin6;
856*d56f51eaSDavid van Moolenbroek 
857*d56f51eaSDavid van Moolenbroek 	/*
858*d56f51eaSDavid van Moolenbroek 	 * if the servname does not match socktype/protocol, ignore it.
859*d56f51eaSDavid van Moolenbroek 	 */
860*d56f51eaSDavid van Moolenbroek 	if (get_portmatch(pai, servname) != 0)
861*d56f51eaSDavid van Moolenbroek 		return 0;
862*d56f51eaSDavid van Moolenbroek 
863*d56f51eaSDavid van Moolenbroek 	afd = find_afd(pai->ai_family);
864*d56f51eaSDavid van Moolenbroek 	if (!afd->a_scoped)
865*d56f51eaSDavid van Moolenbroek 		return explore_numeric(pai, hostname, servname, res);
866*d56f51eaSDavid van Moolenbroek 
867*d56f51eaSDavid van Moolenbroek 	cp = strchr(hostname, SCOPE_DELIMITER);
868*d56f51eaSDavid van Moolenbroek 	if (cp == NULL)
869*d56f51eaSDavid van Moolenbroek 		return explore_numeric(pai, hostname, servname, res);
870*d56f51eaSDavid van Moolenbroek 
871*d56f51eaSDavid van Moolenbroek 	/*
872*d56f51eaSDavid van Moolenbroek 	 * Handle special case of <scoped_address><delimiter><scope id>
873*d56f51eaSDavid van Moolenbroek 	 */
874*d56f51eaSDavid van Moolenbroek 	hostname2 = strdup(hostname);
875*d56f51eaSDavid van Moolenbroek 	if (hostname2 == NULL)
876*d56f51eaSDavid van Moolenbroek 		return EAI_MEMORY;
877*d56f51eaSDavid van Moolenbroek 	/* terminate at the delimiter */
878*d56f51eaSDavid van Moolenbroek 	hostname2[cp - hostname] = '\0';
879*d56f51eaSDavid van Moolenbroek 
880*d56f51eaSDavid van Moolenbroek 	cp++;
881*d56f51eaSDavid van Moolenbroek 	switch (pai->ai_family) {
882*d56f51eaSDavid van Moolenbroek #ifdef INET6
883*d56f51eaSDavid van Moolenbroek 	case AF_INET6:
884*d56f51eaSDavid van Moolenbroek 		scope = if_nametoindex(cp);
885*d56f51eaSDavid van Moolenbroek 		if (scope == 0) {
886*d56f51eaSDavid van Moolenbroek 			free(hostname2);
887*d56f51eaSDavid van Moolenbroek 			return (EAI_NONAME);
888*d56f51eaSDavid van Moolenbroek 		}
889*d56f51eaSDavid van Moolenbroek 		break;
890*d56f51eaSDavid van Moolenbroek #endif
891*d56f51eaSDavid van Moolenbroek 	}
892*d56f51eaSDavid van Moolenbroek 
893*d56f51eaSDavid van Moolenbroek 	error = explore_numeric(pai, hostname2, servname, res);
894*d56f51eaSDavid van Moolenbroek 	if (error == 0) {
895*d56f51eaSDavid van Moolenbroek 		for (cur = *res; cur; cur = cur->ai_next) {
896*d56f51eaSDavid van Moolenbroek 			if (cur->ai_family != AF_INET6)
897*d56f51eaSDavid van Moolenbroek 				continue;
898*d56f51eaSDavid van Moolenbroek 			sin6 = (struct sockaddr_in6 *)cur->ai_addr;
899*d56f51eaSDavid van Moolenbroek 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
900*d56f51eaSDavid van Moolenbroek 			    IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr))
901*d56f51eaSDavid van Moolenbroek 				sin6->sin6_scope_id = scope;
902*d56f51eaSDavid van Moolenbroek 		}
903*d56f51eaSDavid van Moolenbroek 	}
904*d56f51eaSDavid van Moolenbroek 
905*d56f51eaSDavid van Moolenbroek 	free(hostname2);
906*d56f51eaSDavid van Moolenbroek 
907*d56f51eaSDavid van Moolenbroek 	return error;
908*d56f51eaSDavid van Moolenbroek #endif
909*d56f51eaSDavid van Moolenbroek }
910*d56f51eaSDavid van Moolenbroek 
911*d56f51eaSDavid van Moolenbroek static int
get_name(addr,afd,res,numaddr,pai,servname)912*d56f51eaSDavid van Moolenbroek get_name(addr, afd, res, numaddr, pai, servname)
913*d56f51eaSDavid van Moolenbroek 	const char *addr;
914*d56f51eaSDavid van Moolenbroek 	const struct afd *afd;
915*d56f51eaSDavid van Moolenbroek 	struct addrinfo **res;
916*d56f51eaSDavid van Moolenbroek 	char *numaddr;
917*d56f51eaSDavid van Moolenbroek 	const struct addrinfo *pai;
918*d56f51eaSDavid van Moolenbroek 	const char *servname;
919*d56f51eaSDavid van Moolenbroek {
920*d56f51eaSDavid van Moolenbroek 	struct hostent *hp = NULL;
921*d56f51eaSDavid van Moolenbroek 	struct addrinfo *cur = NULL;
922*d56f51eaSDavid van Moolenbroek 	int error = 0;
923*d56f51eaSDavid van Moolenbroek 	char *ap = NULL, *cn = NULL;
924*d56f51eaSDavid van Moolenbroek #ifdef USE_GETIPNODEBY
925*d56f51eaSDavid van Moolenbroek 	int h_error;
926*d56f51eaSDavid van Moolenbroek 
927*d56f51eaSDavid van Moolenbroek 	hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
928*d56f51eaSDavid van Moolenbroek #else
929*d56f51eaSDavid van Moolenbroek 	hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
930*d56f51eaSDavid van Moolenbroek #endif
931*d56f51eaSDavid van Moolenbroek 	if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
932*d56f51eaSDavid van Moolenbroek #ifdef USE_GETIPNODEBY
933*d56f51eaSDavid van Moolenbroek 		GET_AI(cur, afd, hp->h_addr_list[0]);
934*d56f51eaSDavid van Moolenbroek 		GET_PORT(cur, servname);
935*d56f51eaSDavid van Moolenbroek 		GET_CANONNAME(cur, hp->h_name);
936*d56f51eaSDavid van Moolenbroek #else
937*d56f51eaSDavid van Moolenbroek 		/* hp will be damaged if we use gethostbyaddr() */
938*d56f51eaSDavid van Moolenbroek 		if ((ap = (char *)malloc(hp->h_length)) == NULL) {
939*d56f51eaSDavid van Moolenbroek 			error = EAI_MEMORY;
940*d56f51eaSDavid van Moolenbroek 			goto free;
941*d56f51eaSDavid van Moolenbroek 		}
942*d56f51eaSDavid van Moolenbroek 		memcpy(ap, hp->h_addr_list[0], hp->h_length);
943*d56f51eaSDavid van Moolenbroek 		if ((cn = strdup(hp->h_name)) == NULL) {
944*d56f51eaSDavid van Moolenbroek 			error = EAI_MEMORY;
945*d56f51eaSDavid van Moolenbroek 			goto free;
946*d56f51eaSDavid van Moolenbroek 		}
947*d56f51eaSDavid van Moolenbroek 
948*d56f51eaSDavid van Moolenbroek 		GET_AI(cur, afd, ap);
949*d56f51eaSDavid van Moolenbroek 		GET_PORT(cur, servname);
950*d56f51eaSDavid van Moolenbroek 		GET_CANONNAME(cur, cn);
951*d56f51eaSDavid van Moolenbroek 		free(ap); ap = NULL;
952*d56f51eaSDavid van Moolenbroek 		free(cn); cn = NULL;
953*d56f51eaSDavid van Moolenbroek #endif
954*d56f51eaSDavid van Moolenbroek 	} else {
955*d56f51eaSDavid van Moolenbroek 		GET_AI(cur, afd, numaddr);
956*d56f51eaSDavid van Moolenbroek 		GET_PORT(cur, servname);
957*d56f51eaSDavid van Moolenbroek 	}
958*d56f51eaSDavid van Moolenbroek 
959*d56f51eaSDavid van Moolenbroek #ifdef USE_GETIPNODEBY
960*d56f51eaSDavid van Moolenbroek 	if (hp)
961*d56f51eaSDavid van Moolenbroek 		freehostent(hp);
962*d56f51eaSDavid van Moolenbroek #endif
963*d56f51eaSDavid van Moolenbroek 	*res = cur;
964*d56f51eaSDavid van Moolenbroek 	return SUCCESS;
965*d56f51eaSDavid van Moolenbroek  free:
966*d56f51eaSDavid van Moolenbroek 	if (cur)
967*d56f51eaSDavid van Moolenbroek 		freeaddrinfo(cur);
968*d56f51eaSDavid van Moolenbroek 	if (ap)
969*d56f51eaSDavid van Moolenbroek 		free(ap);
970*d56f51eaSDavid van Moolenbroek 	if (cn)
971*d56f51eaSDavid van Moolenbroek 		free(cn);
972*d56f51eaSDavid van Moolenbroek #ifdef USE_GETIPNODEBY
973*d56f51eaSDavid van Moolenbroek 	if (hp)
974*d56f51eaSDavid van Moolenbroek 		freehostent(hp);
975*d56f51eaSDavid van Moolenbroek #endif
976*d56f51eaSDavid van Moolenbroek 	*res = NULL;
977*d56f51eaSDavid van Moolenbroek 	return error;
978*d56f51eaSDavid van Moolenbroek }
979*d56f51eaSDavid van Moolenbroek 
980*d56f51eaSDavid van Moolenbroek static int
get_canonname(pai,ai,str)981*d56f51eaSDavid van Moolenbroek get_canonname(pai, ai, str)
982*d56f51eaSDavid van Moolenbroek 	const struct addrinfo *pai;
983*d56f51eaSDavid van Moolenbroek 	struct addrinfo *ai;
984*d56f51eaSDavid van Moolenbroek 	const char *str;
985*d56f51eaSDavid van Moolenbroek {
986*d56f51eaSDavid van Moolenbroek 	if ((pai->ai_flags & AI_CANONNAME) != 0) {
987*d56f51eaSDavid van Moolenbroek 		ai->ai_canonname = strdup(str);
988*d56f51eaSDavid van Moolenbroek 		if (ai->ai_canonname == NULL)
989*d56f51eaSDavid van Moolenbroek 			return EAI_MEMORY;
990*d56f51eaSDavid van Moolenbroek 	}
991*d56f51eaSDavid van Moolenbroek 	return 0;
992*d56f51eaSDavid van Moolenbroek }
993*d56f51eaSDavid van Moolenbroek 
994*d56f51eaSDavid van Moolenbroek static struct addrinfo *
get_ai(pai,afd,addr)995*d56f51eaSDavid van Moolenbroek get_ai(pai, afd, addr)
996*d56f51eaSDavid van Moolenbroek 	const struct addrinfo *pai;
997*d56f51eaSDavid van Moolenbroek 	const struct afd *afd;
998*d56f51eaSDavid van Moolenbroek 	const char *addr;
999*d56f51eaSDavid van Moolenbroek {
1000*d56f51eaSDavid van Moolenbroek 	char *p;
1001*d56f51eaSDavid van Moolenbroek 	struct addrinfo *ai;
1002*d56f51eaSDavid van Moolenbroek 
1003*d56f51eaSDavid van Moolenbroek 	ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
1004*d56f51eaSDavid van Moolenbroek 		+ (afd->a_socklen));
1005*d56f51eaSDavid van Moolenbroek 	if (ai == NULL)
1006*d56f51eaSDavid van Moolenbroek 		return NULL;
1007*d56f51eaSDavid van Moolenbroek 
1008*d56f51eaSDavid van Moolenbroek 	memcpy(ai, pai, sizeof(struct addrinfo));
1009*d56f51eaSDavid van Moolenbroek 	ai->ai_addr = (struct sockaddr *)(ai + 1);
1010*d56f51eaSDavid van Moolenbroek 	memset(ai->ai_addr, 0, afd->a_socklen);
1011*d56f51eaSDavid van Moolenbroek #ifdef HAVE_SOCKADDR_SA_LEN
1012*d56f51eaSDavid van Moolenbroek 	ai->ai_addr->sa_len = afd->a_socklen;
1013*d56f51eaSDavid van Moolenbroek #endif
1014*d56f51eaSDavid van Moolenbroek 	ai->ai_addrlen = afd->a_socklen;
1015*d56f51eaSDavid van Moolenbroek 	ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
1016*d56f51eaSDavid van Moolenbroek 	p = (char *)(ai->ai_addr);
1017*d56f51eaSDavid van Moolenbroek 	memcpy(p + afd->a_off, addr, afd->a_addrlen);
1018*d56f51eaSDavid van Moolenbroek 	return ai;
1019*d56f51eaSDavid van Moolenbroek }
1020*d56f51eaSDavid van Moolenbroek 
1021*d56f51eaSDavid van Moolenbroek static int
get_portmatch(ai,servname)1022*d56f51eaSDavid van Moolenbroek get_portmatch(ai, servname)
1023*d56f51eaSDavid van Moolenbroek 	const struct addrinfo *ai;
1024*d56f51eaSDavid van Moolenbroek 	const char *servname;
1025*d56f51eaSDavid van Moolenbroek {
1026*d56f51eaSDavid van Moolenbroek 
1027*d56f51eaSDavid van Moolenbroek 	/* get_port does not touch first argument. when matchonly == 1. */
1028*d56f51eaSDavid van Moolenbroek 	return get_port((struct addrinfo *)ai, servname, 1);
1029*d56f51eaSDavid van Moolenbroek }
1030*d56f51eaSDavid van Moolenbroek 
1031*d56f51eaSDavid van Moolenbroek static int
get_port(ai,servname,matchonly)1032*d56f51eaSDavid van Moolenbroek get_port(ai, servname, matchonly)
1033*d56f51eaSDavid van Moolenbroek 	struct addrinfo *ai;
1034*d56f51eaSDavid van Moolenbroek 	const char *servname;
1035*d56f51eaSDavid van Moolenbroek 	int matchonly;
1036*d56f51eaSDavid van Moolenbroek {
1037*d56f51eaSDavid van Moolenbroek 	const char *proto;
1038*d56f51eaSDavid van Moolenbroek 	struct servent *sp;
1039*d56f51eaSDavid van Moolenbroek 	int port;
1040*d56f51eaSDavid van Moolenbroek 	int allownumeric;
1041*d56f51eaSDavid van Moolenbroek 
1042*d56f51eaSDavid van Moolenbroek 	if (servname == NULL)
1043*d56f51eaSDavid van Moolenbroek 		return 0;
1044*d56f51eaSDavid van Moolenbroek 	switch (ai->ai_family) {
1045*d56f51eaSDavid van Moolenbroek 	case AF_INET:
1046*d56f51eaSDavid van Moolenbroek #ifdef AF_INET6
1047*d56f51eaSDavid van Moolenbroek 	case AF_INET6:
1048*d56f51eaSDavid van Moolenbroek #endif
1049*d56f51eaSDavid van Moolenbroek 		break;
1050*d56f51eaSDavid van Moolenbroek 	default:
1051*d56f51eaSDavid van Moolenbroek 		return 0;
1052*d56f51eaSDavid van Moolenbroek 	}
1053*d56f51eaSDavid van Moolenbroek 
1054*d56f51eaSDavid van Moolenbroek 	switch (ai->ai_socktype) {
1055*d56f51eaSDavid van Moolenbroek 	case SOCK_RAW:
1056*d56f51eaSDavid van Moolenbroek 		return EAI_SERVICE;
1057*d56f51eaSDavid van Moolenbroek 	case SOCK_DGRAM:
1058*d56f51eaSDavid van Moolenbroek 	case SOCK_STREAM:
1059*d56f51eaSDavid van Moolenbroek 		allownumeric = 1;
1060*d56f51eaSDavid van Moolenbroek 		break;
1061*d56f51eaSDavid van Moolenbroek 	case ANY:
1062*d56f51eaSDavid van Moolenbroek 		allownumeric = 0;
1063*d56f51eaSDavid van Moolenbroek 		break;
1064*d56f51eaSDavid van Moolenbroek 	default:
1065*d56f51eaSDavid van Moolenbroek 		return EAI_SOCKTYPE;
1066*d56f51eaSDavid van Moolenbroek 	}
1067*d56f51eaSDavid van Moolenbroek 
1068*d56f51eaSDavid van Moolenbroek 	if (str_isnumber(servname)) {
1069*d56f51eaSDavid van Moolenbroek 		if (!allownumeric)
1070*d56f51eaSDavid van Moolenbroek 			return EAI_SERVICE;
1071*d56f51eaSDavid van Moolenbroek 		port = htons(atoi(servname));
1072*d56f51eaSDavid van Moolenbroek 		if (port < 0 || port > 65535)
1073*d56f51eaSDavid van Moolenbroek 			return EAI_SERVICE;
1074*d56f51eaSDavid van Moolenbroek 	} else {
1075*d56f51eaSDavid van Moolenbroek 		switch (ai->ai_socktype) {
1076*d56f51eaSDavid van Moolenbroek 		case SOCK_DGRAM:
1077*d56f51eaSDavid van Moolenbroek 			proto = "udp";
1078*d56f51eaSDavid van Moolenbroek 			break;
1079*d56f51eaSDavid van Moolenbroek 		case SOCK_STREAM:
1080*d56f51eaSDavid van Moolenbroek 			proto = "tcp";
1081*d56f51eaSDavid van Moolenbroek 			break;
1082*d56f51eaSDavid van Moolenbroek 		default:
1083*d56f51eaSDavid van Moolenbroek 			proto = NULL;
1084*d56f51eaSDavid van Moolenbroek 			break;
1085*d56f51eaSDavid van Moolenbroek 		}
1086*d56f51eaSDavid van Moolenbroek 
1087*d56f51eaSDavid van Moolenbroek 		if ((sp = getservbyname(servname, proto)) == NULL)
1088*d56f51eaSDavid van Moolenbroek 			return EAI_SERVICE;
1089*d56f51eaSDavid van Moolenbroek 		port = sp->s_port;
1090*d56f51eaSDavid van Moolenbroek 	}
1091*d56f51eaSDavid van Moolenbroek 
1092*d56f51eaSDavid van Moolenbroek 	if (!matchonly) {
1093*d56f51eaSDavid van Moolenbroek 		switch (ai->ai_family) {
1094*d56f51eaSDavid van Moolenbroek 		case AF_INET:
1095*d56f51eaSDavid van Moolenbroek 			((struct sockaddr_in *)ai->ai_addr)->sin_port = port;
1096*d56f51eaSDavid van Moolenbroek 			break;
1097*d56f51eaSDavid van Moolenbroek #ifdef INET6
1098*d56f51eaSDavid van Moolenbroek 		case AF_INET6:
1099*d56f51eaSDavid van Moolenbroek 			((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port;
1100*d56f51eaSDavid van Moolenbroek 			break;
1101*d56f51eaSDavid van Moolenbroek #endif
1102*d56f51eaSDavid van Moolenbroek 		}
1103*d56f51eaSDavid van Moolenbroek 	}
1104*d56f51eaSDavid van Moolenbroek 
1105*d56f51eaSDavid van Moolenbroek 	return 0;
1106*d56f51eaSDavid van Moolenbroek }
1107*d56f51eaSDavid van Moolenbroek 
1108*d56f51eaSDavid van Moolenbroek static const struct afd *
find_afd(af)1109*d56f51eaSDavid van Moolenbroek find_afd(af)
1110*d56f51eaSDavid van Moolenbroek 	int af;
1111*d56f51eaSDavid van Moolenbroek {
1112*d56f51eaSDavid van Moolenbroek 	const struct afd *afd;
1113*d56f51eaSDavid van Moolenbroek 
1114*d56f51eaSDavid van Moolenbroek 	if (af == PF_UNSPEC)
1115*d56f51eaSDavid van Moolenbroek 		return NULL;
1116*d56f51eaSDavid van Moolenbroek 	for (afd = afdl; afd->a_af; afd++) {
1117*d56f51eaSDavid van Moolenbroek 		if (afd->a_af == af)
1118*d56f51eaSDavid van Moolenbroek 			return afd;
1119*d56f51eaSDavid van Moolenbroek 	}
1120*d56f51eaSDavid van Moolenbroek 	return NULL;
1121*d56f51eaSDavid van Moolenbroek }
1122*d56f51eaSDavid van Moolenbroek 
1123*d56f51eaSDavid van Moolenbroek 
1124*d56f51eaSDavid van Moolenbroek #endif /*__MING64__*/
1125