getaddrinfo.c revision 56627
1155192Srwatson/*
2155192Srwatson * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3155192Srwatson * All rights reserved.
4155192Srwatson *
5155192Srwatson * Redistribution and use in source and binary forms, with or without
6155192Srwatson * modification, are permitted provided that the following conditions
7155192Srwatson * are met:
8155192Srwatson * 1. Redistributions of source code must retain the above copyright
9155192Srwatson *    notice, this list of conditions and the following disclaimer.
10155192Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11155192Srwatson *    notice, this list of conditions and the following disclaimer in the
12155192Srwatson *    documentation and/or other materials provided with the distribution.
13155192Srwatson * 3. Neither the name of the project nor the names of its contributors
14155192Srwatson *    may be used to endorse or promote products derived from this software
15155192Srwatson *    without specific prior written permission.
16155192Srwatson *
17155192Srwatson * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18155192Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19155192Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20155192Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21155192Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22155192Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23155192Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24155192Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25155192Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26155192Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27155192Srwatson * SUCH DAMAGE.
28155192Srwatson *
29155192Srwatson * $FreeBSD: head/lib/libc/net/getaddrinfo.c 56627 2000-01-26 08:37:29Z shin $
30155192Srwatson */
31155192Srwatson
32168933Srwatson/*
33168933Srwatson * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
34155192Srwatson *
35159318Srwatson * Issues to be discussed:
36155192Srwatson * - Thread safe-ness must be checked.
37164033Srwatson * - Return values.  There are nonstandard return values defined and used
38155192Srwatson *   in the source code.  This is because RFC2553 is silent about which error
39155192Srwatson *   code must be returned for which situation.
40155192Srwatson * Note:
41155192Srwatson * - We use getipnodebyname() just for thread-safeness.  There's no intent
42163207Scsjp *   to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
43155192Srwatson *   getipnodebyname().
44155192Srwatson * - The code filters out AFs that are not supported by the kernel,
45155192Srwatson *   when globbing NULL hostname (to loopback, or wildcard).  Is it the right
46168933Srwatson *   thing to do?  What is the relationship with post-RFC2553 AI_ADDRCONFIG
47155192Srwatson *   in ai_flags?
48155192Srwatson */
49168933Srwatson
50155192Srwatson#include <sys/types.h>
51155192Srwatson#include <sys/param.h>
52155192Srwatson#include <sys/socket.h>
53155192Srwatson#include <net/if.h>
54156889Srwatson#include <netinet/in.h>
55170127Srwatson#include <arpa/inet.h>
56156889Srwatson#include <arpa/nameser.h>
57155192Srwatson#include <netdb.h>
58156889Srwatson#include <resolv.h>
59156889Srwatson#include <string.h>
60156889Srwatson#include <stdlib.h>
61155192Srwatson#include <stddef.h>
62155192Srwatson#include <ctype.h>
63155192Srwatson#include <unistd.h>
64155192Srwatson#include <stdio.h>
65155192Srwatson
66155192Srwatson#if defined(__KAME__) && defined(INET6)
67155192Srwatson# define FAITH
68155192Srwatson#endif
69155192Srwatson
70163207Scsjp#define	SUCCESS 0
71163207Scsjp#define	ANY 0
72164033Srwatson#define	YES 1
73155192Srwatson#define	NO  0
74155192Srwatson
75155192Srwatsonstatic const char in_addrany[] = { 0, 0, 0, 0 };
76155192Srwatsonstatic const char in6_addrany[] = {
77155192Srwatson	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
78155192Srwatson};
79155192Srwatsonstatic const char in_loopback[] = { 127, 0, 0, 1 };
80155192Srwatsonstatic const char in6_loopback[] = {
81156889Srwatson	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
82156889Srwatson};
83155192Srwatson
84155192Srwatsonstatic const struct afd {
85155192Srwatson	int a_af;
86155192Srwatson	int a_addrlen;
87156889Srwatson	int a_socklen;
88156889Srwatson	int a_off;
89156889Srwatson	const char *a_addrany;
90156889Srwatson	const char *a_loopback;
91155192Srwatson	int a_scoped;
92155192Srwatson} afdl [] = {
93155192Srwatson#ifdef INET6
94155192Srwatson#define	N_INET6 0
95155192Srwatson	{PF_INET6, sizeof(struct in6_addr),
96155192Srwatson	 sizeof(struct sockaddr_in6),
97155192Srwatson	 offsetof(struct sockaddr_in6, sin6_addr),
98155192Srwatson	 in6_addrany, in6_loopback, 1},
99155192Srwatson#define	N_INET 1
100155192Srwatson#else
101156889Srwatson#define	N_INET 0
102155192Srwatson#endif
103155192Srwatson	{PF_INET, sizeof(struct in_addr),
104155192Srwatson	 sizeof(struct sockaddr_in),
105155192Srwatson	 offsetof(struct sockaddr_in, sin_addr),
106155192Srwatson	 in_addrany, in_loopback, 0},
107155192Srwatson	{0, 0, 0, 0, NULL, NULL, 0},
108155192Srwatson};
109155192Srwatson
110156889Srwatsonstruct explore {
111155192Srwatson	int e_af;
112155192Srwatson	int e_socktype;
113155192Srwatson	int e_protocol;
114155192Srwatson	const char *e_protostr;
115155192Srwatson	int e_wild;
116168933Srwatson#define	WILD_AF(ex)		((ex)->e_wild & 0x01)
117172930Srwatson#define	WILD_SOCKTYPE(ex)	((ex)->e_wild & 0x02)
118168933Srwatson#define	WILD_PROTOCOL(ex)	((ex)->e_wild & 0x04)
119168933Srwatson};
120168933Srwatson
121168933Srwatsonstatic const struct explore explore[] = {
122156889Srwatson#ifdef INET6
123170127Srwatson	{ PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
124155192Srwatson	{ PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
125155192Srwatson	{ PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
126155192Srwatson#endif
127155192Srwatson	{ PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
128155192Srwatson	{ PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
129155192Srwatson	{ PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
130155192Srwatson	{ -1, 0, 0, NULL, 0 },
131155192Srwatson};
132155192Srwatson
133162380Scsjp#ifdef INET6
134162380Scsjp#define	PTON_MAX	16
135162380Scsjp#else
136170127Srwatson#define	PTON_MAX	4
137162380Scsjp#endif
138162380Scsjp
139162380Scsjp
140162380Scsjpstatic int str_isnumber __P((const char *));
141155192Srwatsonstatic int explore_fqdn __P((const struct addrinfo *, const char *,
142155192Srwatson	const char *, struct addrinfo **));
143155192Srwatsonstatic int explore_null __P((const struct addrinfo *, const char *,
144156889Srwatson	const char *, struct addrinfo **));
145156889Srwatsonstatic int explore_numeric __P((const struct addrinfo *, const char *,
146156889Srwatson	const char *, struct addrinfo **));
147155192Srwatsonstatic int explore_numeric_scope __P((const struct addrinfo *, const char *,
148155192Srwatson	const char *, struct addrinfo **));
149155192Srwatsonstatic int get_canonname __P((const struct addrinfo *,
150155192Srwatson	struct addrinfo *, const char *));
151155192Srwatsonstatic struct addrinfo *get_ai __P((const struct addrinfo *,
152155192Srwatson	const struct afd *, const char *));
153155192Srwatsonstatic int get_portmatch __P((const struct addrinfo *, const char *));
154155192Srwatsonstatic int get_port __P((struct addrinfo *, const char *, int));
155155192Srwatsonstatic const struct afd *find_afd __P((int));
156155192Srwatson
157155192Srwatsonstatic char *ai_errlist[] = {
158155192Srwatson	"Success",
159170407Srwatson	"Address family for hostname not supported",	/* EAI_ADDRFAMILY */
160155192Srwatson	"Temporary failure in name resolution",		/* EAI_AGAIN      */
161155192Srwatson	"Invalid value for ai_flags",		       	/* EAI_BADFLAGS   */
162155192Srwatson	"Non-recoverable failure in name resolution", 	/* EAI_FAIL       */
163155192Srwatson	"ai_family not supported",			/* EAI_FAMILY     */
164163207Scsjp	"Memory allocation failure", 			/* EAI_MEMORY     */
165163207Scsjp	"No address associated with hostname", 		/* EAI_NODATA     */
166155192Srwatson	"hostname nor servname provided, or not known",	/* EAI_NONAME     */
167168933Srwatson	"servname not supported for ai_socktype",	/* EAI_SERVICE    */
168168933Srwatson	"ai_socktype not supported", 			/* EAI_SOCKTYPE   */
169172930Srwatson	"System error returned in errno", 		/* EAI_SYSTEM     */
170168933Srwatson	"Invalid value for hints",			/* EAI_BADHINTS	  */
171168933Srwatson	"Resolved protocol is unknown",			/* EAI_PROTOCOL   */
172168933Srwatson	"Argument res is NULL",				/* EAI_RESNULL	  */
173168933Srwatson	"Unknown error", 				/* EAI_MAX        */
174164033Srwatson};
175155192Srwatson
176155192Srwatson/* XXX macros that make external reference is BAD. */
177155192Srwatson
178155192Srwatson#define	GET_AI(ai, afd, addr) \
179155192Srwatsondo { \
180155192Srwatson	/* external reference: pai, error, and label free */ \
181155192Srwatson	(ai) = get_ai(pai, (afd), (addr)); \
182155192Srwatson	if ((ai) == NULL) { \
183156889Srwatson		error = EAI_MEMORY; \
184156889Srwatson		goto free; \
185156889Srwatson	} \
186155192Srwatson} while (0)
187155192Srwatson
188155192Srwatson#define	GET_PORT(ai, serv) \
189155192Srwatsondo { \
190155192Srwatson	/* external reference: error and label free */ \
191155192Srwatson	error = get_port((ai), (serv), 0); \
192155192Srwatson	if (error != 0) \
193155192Srwatson		goto free; \
194155192Srwatson} while (0)
195155192Srwatson
196155192Srwatson#define	GET_CANONNAME(ai, str) \
197155192Srwatsondo { \
198155192Srwatson	/* external reference: pai, error and label free */ \
199155192Srwatson	error = get_canonname(pai, (ai), (str)); \
200155192Srwatson	if (error != 0) \
201155192Srwatson		goto free; \
202155192Srwatson} while (0)
203155192Srwatson
204155192Srwatson#define	ERR(err) \
205155192Srwatsondo { \
206155192Srwatson	/* external reference: error, and label bad */ \
207155192Srwatson	error = (err); \
208155192Srwatson	goto bad; \
209156889Srwatson} while (0)
210155192Srwatson
211155192Srwatson#define	MATCH_FAMILY(x, y, w) \
212155192Srwatson	((x) == (y) || ((w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
213155192Srwatson#define	MATCH(x, y, w) \
214155192Srwatson	((x) == (y) || ((w) && ((x) == ANY || (y) == ANY)))
215155192Srwatson
216155192Srwatsonchar *
217155192Srwatsongai_strerror(ecode)
218161813Swsalamon	int ecode;
219161813Swsalamon{
220161813Swsalamon	if (ecode < 0 || ecode > EAI_MAX)
221161813Swsalamon		ecode = EAI_MAX;
222155192Srwatson	return ai_errlist[ecode];
223155192Srwatson}
224155192Srwatson
225161813Swsalamonvoid
226161813Swsalamonfreeaddrinfo(ai)
227155192Srwatson	struct addrinfo *ai;
228155192Srwatson{
229155192Srwatson	struct addrinfo *next;
230155192Srwatson
231155192Srwatson	do {
232155192Srwatson		next = ai->ai_next;
233161813Swsalamon		if (ai->ai_canonname)
234161813Swsalamon			free(ai->ai_canonname);
235155192Srwatson		/* no need to free(ai->ai_addr) */
236155192Srwatson		free(ai);
237155192Srwatson	} while ((ai = next) != NULL);
238155192Srwatson}
239155192Srwatson
240155192Srwatsonstatic int
241155192Srwatsonstr_isnumber(p)
242155192Srwatson	const char *p;
243155192Srwatson{
244155192Srwatson	char *q = (char *)p;
245155192Srwatson	while (*q) {
246155192Srwatson		if (! isdigit(*q))
247155192Srwatson			return NO;
248155192Srwatson		q++;
249155192Srwatson	}
250155192Srwatson	return YES;
251155192Srwatson}
252155192Srwatson
253155192Srwatsonint
254155192Srwatsongetaddrinfo(hostname, servname, hints, res)
255155192Srwatson	const char *hostname, *servname;
256155192Srwatson	const struct addrinfo *hints;
257155192Srwatson	struct addrinfo **res;
258155192Srwatson{
259155192Srwatson	struct addrinfo sentinel;
260155192Srwatson	struct addrinfo *cur;
261155192Srwatson	int error = 0;
262155192Srwatson	struct addrinfo ai;
263155192Srwatson	struct addrinfo ai0;
264155192Srwatson	struct addrinfo *pai;
265155192Srwatson	const struct afd *afd;
266155192Srwatson	const struct explore *ex;
267155192Srwatson
268155192Srwatson	sentinel.ai_next = NULL;
269155192Srwatson	cur = &sentinel;
270155192Srwatson	pai = &ai;
271155192Srwatson	pai->ai_flags = 0;
272155192Srwatson	pai->ai_family = PF_UNSPEC;
273155192Srwatson	pai->ai_socktype = ANY;
274155192Srwatson	pai->ai_protocol = ANY;
275155192Srwatson	pai->ai_addrlen = 0;
276155192Srwatson	pai->ai_canonname = NULL;
277155192Srwatson	pai->ai_addr = NULL;
278155192Srwatson	pai->ai_next = NULL;
279155192Srwatson
280155192Srwatson	if (hostname == NULL && servname == NULL)
281155192Srwatson		return EAI_NONAME;
282155192Srwatson	if (res == NULL)
283155192Srwatson		return EAI_RESNULL; /* xxx */
284155192Srwatson	if (hints) {
285155192Srwatson		/* error check for hints */
286155192Srwatson		if (hints->ai_addrlen || hints->ai_canonname ||
287155192Srwatson		    hints->ai_addr || hints->ai_next)
288155192Srwatson			ERR(EAI_BADHINTS); /* xxx */
289155192Srwatson		if (hints->ai_flags & ~AI_MASK)
290155192Srwatson			ERR(EAI_BADFLAGS);
291155192Srwatson		switch (hints->ai_family) {
292155192Srwatson		case PF_UNSPEC:
293155192Srwatson		case PF_INET:
294156889Srwatson#ifdef INET6
295155192Srwatson		case PF_INET6:
296156889Srwatson#endif
297155192Srwatson			break;
298155192Srwatson		default:
299155192Srwatson			ERR(EAI_FAMILY);
300155192Srwatson		}
301155192Srwatson		memcpy(pai, hints, sizeof(*pai));
302155192Srwatson
303155192Srwatson		/*
304155192Srwatson		 * if both socktype/protocol are specified, check if they
305156889Srwatson		 * are meaningful combination.
306156889Srwatson		 */
307155192Srwatson		if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
308155192Srwatson			int matched = 0;
309155192Srwatson
310155192Srwatson			for (ex = explore; ex->e_af >= 0; ex++) {
311156889Srwatson				if (pai->ai_family != ex->e_af)
312155192Srwatson					continue;
313155192Srwatson				if (ex->e_socktype == ANY)
314155192Srwatson					continue;
315156889Srwatson				if (ex->e_protocol == ANY)
316155192Srwatson					continue;
317155192Srwatson				if (pai->ai_socktype == ex->e_socktype
318155192Srwatson				 && pai->ai_protocol == ex->e_protocol)
319165624Srwatson					matched = 1;
320165624Srwatson				else
321165624Srwatson					continue;
322165624Srwatson				if (matched == 0)
323170407Srwatson					ERR(EAI_BADHINTS);
324168688Scsjp			}
325168688Scsjp		}
326168688Scsjp	}
327170407Srwatson
328170407Srwatson	/* backup original pai contents */
329156889Srwatson	ai0 = *pai;
330170407Srwatson
331156889Srwatson	/*
332170407Srwatson	 * special cases check for inet and inet6 sockets.
333156889Srwatson	 * (1) servname is disallowed for raw sockets.
334170407Srwatson	 * (2) numeric servname is disallowed if socktype/protocol is left
335168688Scsjp	 *     unspecified.
336170407Srwatson	 */
337170407Srwatson	if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
338170407Srwatson#ifdef INET6
339155192Srwatson	    || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
340155192Srwatson#endif
341155192Srwatson	    ) {
342155192Srwatson		*pai = ai0;
343156889Srwatson
344155192Srwatson		if (pai->ai_family == PF_UNSPEC)
345170407Srwatson#ifdef INET6
346170407Srwatson			pai->ai_family = PF_INET6;
347170407Srwatson#else
348155192Srwatson			pai->ai_family = PF_INET;
349170407Srwatson#endif
350165624Srwatson		error = get_portmatch(pai, servname);
351165624Srwatson		if (error)
352170407Srwatson			ERR(error);
353165624Srwatson	}
354165624Srwatson
355170407Srwatson	/* NULL hostname, or numeric hostname */
356170407Srwatson	for (ex = explore; ex->e_af >= 0; ex++) {
357170407Srwatson		*pai = ai0;
358156889Srwatson
359170407Srwatson		if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
360156889Srwatson			continue;
361170407Srwatson		if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
362155192Srwatson			continue;
363170407Srwatson		if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
364155192Srwatson			continue;
365155192Srwatson
366155192Srwatson		if (pai->ai_family == PF_UNSPEC)
367155192Srwatson			pai->ai_family = ex->e_af;
368155192Srwatson		if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
369155192Srwatson			pai->ai_socktype = ex->e_socktype;
370155192Srwatson		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
371155192Srwatson			pai->ai_protocol = ex->e_protocol;
372155192Srwatson
373155192Srwatson		if (hostname == NULL)
374155192Srwatson			error = explore_null(pai, hostname, servname, &cur->ai_next);
375155192Srwatson		else
376155192Srwatson			error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
377155192Srwatson
378155192Srwatson		if (error)
379168688Scsjp			goto free;
380168688Scsjp
381168688Scsjp		while (cur && cur->ai_next)
382168688Scsjp			cur = cur->ai_next;
383170407Srwatson	}
384170407Srwatson
385168688Scsjp	/*
386170407Srwatson	 * XXX
387168688Scsjp	 * If numreic representation of AF1 can be interpreted as FQDN
388170407Srwatson	 * representation of AF2, we need to think again about the code below.
389170407Srwatson	 */
390170407Srwatson	if (sentinel.ai_next)
391170407Srwatson		goto good;
392170407Srwatson
393168688Scsjp	if (pai->ai_flags & AI_NUMERICHOST)
394155192Srwatson		ERR(EAI_NONAME);
395155192Srwatson	if (hostname == NULL)
396155192Srwatson		ERR(EAI_NONAME);
397155192Srwatson
398155192Srwatson	/*
399155192Srwatson	 * hostname as alphabetical name.
400155192Srwatson	 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
401155192Srwatson	 * outer loop by AFs.
402155192Srwatson	 */
403155192Srwatson	for (afd = afdl; afd->a_af; afd++) {
404155192Srwatson		*pai = ai0;
405155192Srwatson
406155192Srwatson		if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1))
407155192Srwatson			continue;
408156845Srwatson
409155192Srwatson		for (ex = explore; ex->e_af >= 0; ex++) {
410156889Srwatson			*pai = ai0;
411156889Srwatson
412156889Srwatson			if (pai->ai_family == PF_UNSPEC)
413156889Srwatson				pai->ai_family = afd->a_af;
414155192Srwatson
415155192Srwatson			if (!MATCH_FAMILY(pai->ai_family, ex->e_af,
416155192Srwatson					  WILD_AF(ex)))
417155192Srwatson				continue;
418155192Srwatson			if (!MATCH(pai->ai_socktype, ex->e_socktype,
419155192Srwatson					WILD_SOCKTYPE(ex))) {
420155192Srwatson				continue;
421155192Srwatson			}
422155192Srwatson			if (!MATCH(pai->ai_protocol, ex->e_protocol,
423155192Srwatson					WILD_PROTOCOL(ex))) {
424155192Srwatson				continue;
425155192Srwatson			}
426155192Srwatson
427155192Srwatson			if (pai->ai_family == PF_UNSPEC)
428155192Srwatson				pai->ai_family = ex->e_af;
429155192Srwatson			if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
430155192Srwatson				pai->ai_socktype = ex->e_socktype;
431155192Srwatson			if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
432155192Srwatson				pai->ai_protocol = ex->e_protocol;
433155192Srwatson
434155192Srwatson			error = explore_fqdn(pai, hostname, servname,
435155192Srwatson				&cur->ai_next);
436156889Srwatson
437155192Srwatson			while (cur && cur->ai_next)
438155192Srwatson				cur = cur->ai_next;
439155192Srwatson		}
440155192Srwatson	}
441155192Srwatson
442155192Srwatson	/* XXX: if any addrinfo found, SUCCESS return even if (error != 0) */
443155192Srwatson	if (sentinel.ai_next) {
444155192Srwatson good:
445163207Scsjp		*res = sentinel.ai_next;
446163207Scsjp		return SUCCESS;
447164033Srwatson	}
448155192Srwatson	/* else, failed */
449155192Srwatson free:
450170407Srwatson bad:
451170407Srwatson	if (error == 0)
452155192Srwatson		error = EAI_FAIL;
453155192Srwatson	if (sentinel.ai_next)
454155192Srwatson		freeaddrinfo(sentinel.ai_next);
455155192Srwatson	*res = NULL;
456155192Srwatson	return error;
457155192Srwatson}
458170407Srwatson
459170407Srwatson/*
460155192Srwatson * FQDN hostname, DNS lookup
461155192Srwatson */
462163207Scsjpstatic int
463163207Scsjpexplore_fqdn(pai, hostname, servname, res)
464155192Srwatson	const struct addrinfo *pai;
465155192Srwatson	const char *hostname;
466155192Srwatson	const char *servname;
467155192Srwatson	struct addrinfo **res;
468170407Srwatson{
469170407Srwatson	struct hostent *hp;
470170407Srwatson	int h_error;
471170407Srwatson	int af;
472168933Srwatson	char *ap;
473172930Srwatson	struct addrinfo sentinel, *cur;
474168933Srwatson	int i;
475170407Srwatson	const struct afd *afd;
476168933Srwatson	int error;
477170407Srwatson
478170407Srwatson	*res = NULL;
479170407Srwatson	sentinel.ai_next = NULL;
480170407Srwatson	cur = &sentinel;
481170407Srwatson
482155192Srwatson	/*
483170407Srwatson	 * if the servname does not match socktype/protocol, ignore it.
484155192Srwatson	 */
485170407Srwatson	if (get_portmatch(pai, servname) != 0)
486170407Srwatson		return 0;
487170407Srwatson
488170407Srwatson	afd = find_afd(pai->ai_family);
489155192Srwatson	if (afd == NULL)
490155192Srwatson		return 0;
491155192Srwatson
492156889Srwatson	hp = getipnodebyname(hostname, pai->ai_family, AI_ADDRCONFIG,
493155192Srwatson			     &h_error);
494155192Srwatson	if (hp == NULL) {
495155192Srwatson		switch (h_error) {
496155192Srwatson		case HOST_NOT_FOUND:
497155192Srwatson		case NO_DATA:
498155192Srwatson			error = EAI_NODATA;
499155192Srwatson			break;
500155192Srwatson		case TRY_AGAIN:
501163207Scsjp			error = EAI_AGAIN;
502163207Scsjp			break;
503164033Srwatson		case NO_RECOVERY:
504155192Srwatson		case NETDB_INTERNAL:
505155192Srwatson		default:
506171066Scsjp			error = EAI_FAIL;
507171066Scsjp			break;
508168688Scsjp		}
509170407Srwatson	} else if ((hp->h_name == NULL) || (hp->h_name[0] == 0)
510170407Srwatson			|| (hp->h_addr_list[0] == NULL)) {
511170407Srwatson		freehostent(hp);
512170407Srwatson		hp = NULL;
513170407Srwatson		error = EAI_FAIL;
514171066Scsjp	}
515155192Srwatson
516155192Srwatson	if (hp == NULL)
517155192Srwatson		goto free;
518155192Srwatson
519155192Srwatson	for (i = 0; hp->h_addr_list[i] != NULL; i++) {
520155192Srwatson		af = hp->h_addrtype;
521170407Srwatson		ap = hp->h_addr_list[i];
522155192Srwatson
523155192Srwatson		if (af != pai->ai_family)
524155192Srwatson			continue;
525163207Scsjp
526163207Scsjp		GET_AI(cur->ai_next, afd, ap);
527155192Srwatson		GET_PORT(cur->ai_next, servname);
528155192Srwatson		if ((pai->ai_flags & AI_CANONNAME) != 0) {
529155192Srwatson			/*
530155192Srwatson			 * RFC2553 says that ai_canonname will be set only for
531170407Srwatson			 * the first element.  we do it for all the elements,
532170407Srwatson			 * just for convenience.
533170407Srwatson			 */
534170407Srwatson			GET_CANONNAME(cur->ai_next, hp->h_name);
535168933Srwatson		}
536172930Srwatson
537168933Srwatson		while (cur && cur->ai_next)
538170407Srwatson			cur = cur->ai_next;
539168933Srwatson	}
540170407Srwatson
541170407Srwatson	*res = sentinel.ai_next;
542170407Srwatson	return 0;
543170407Srwatson
544170407Srwatsonfree:
545170407Srwatson	if (hp)
546170407Srwatson		freehostent(hp);
547170407Srwatson	if (sentinel.ai_next)
548170407Srwatson		freeaddrinfo(sentinel.ai_next);
549170407Srwatson	return error;
550170407Srwatson}
551155192Srwatson
552170407Srwatson/*
553155192Srwatson * hostname == NULL.
554170407Srwatson * passive socket -> anyaddr (0.0.0.0 or ::)
555170407Srwatson * non-passive socket -> localhost (127.0.0.1 or ::1)
556170407Srwatson */
557170407Srwatsonstatic int
558155192Srwatsonexplore_null(pai, hostname, servname, res)
559155192Srwatson	const struct addrinfo *pai;
560155192Srwatson	const char *hostname;
561155192Srwatson	const char *servname;
562155192Srwatson	struct addrinfo **res;
563155192Srwatson{
564155192Srwatson	int s;
565155192Srwatson	const struct afd *afd;
566163207Scsjp	struct addrinfo *cur;
567163207Scsjp	struct addrinfo sentinel;
568170407Srwatson	int error;
569170407Srwatson
570164033Srwatson	*res = NULL;
571155192Srwatson	sentinel.ai_next = NULL;
572155192Srwatson	cur = &sentinel;
573170407Srwatson
574170407Srwatson	/*
575155192Srwatson	 * filter out AFs that are not supported by the kernel
576155192Srwatson	 * XXX errno?
577155192Srwatson	 */
578155192Srwatson	s = socket(pai->ai_family, SOCK_DGRAM, 0);
579155192Srwatson	if (s < 0)
580155192Srwatson		return 0;
581170407Srwatson	_libc_close(s);
582168688Scsjp	afd = find_afd(pai->ai_family);
583155192Srwatson	if (afd == NULL)
584155192Srwatson		return 0;
585163207Scsjp
586163207Scsjp	GET_AI(cur->ai_next, afd,
587170407Srwatson	       (pai->ai_flags & AI_PASSIVE) ? afd->a_addrany : afd->a_loopback
588155192Srwatson	       );
589155192Srwatson	/* xxx meaningless?
590171066Scsjp	 * GET_CANONNAME(cur->ai_next, "anyaddr");
591171066Scsjp	 * or
592171066Scsjp	 * GET_CANONNAME(cur->ai_next, "localhost");
593171066Scsjp	 */
594170407Srwatson	/* if the servname does not match socktype/protocol, ignored */
595170407Srwatson	GET_PORT(cur->ai_next, servname);
596170407Srwatson
597170407Srwatson	*res = sentinel.ai_next;
598168933Srwatson	return 0;
599172930Srwatson
600168933Srwatsonfree:
601170407Srwatson	if (sentinel.ai_next)
602168933Srwatson		freeaddrinfo(sentinel.ai_next);
603170407Srwatson	return error;
604168688Scsjp}
605170407Srwatson
606170407Srwatson/*
607170407Srwatson * numeric hostname
608168688Scsjp */
609170407Srwatsonstatic int
610170407Srwatsonexplore_numeric(pai, hostname, servname, res)
611170407Srwatson	const struct addrinfo *pai;
612170777Srwatson	const char *hostname;
613170407Srwatson	const char *servname;
614168688Scsjp	struct addrinfo **res;
615155192Srwatson{
616155192Srwatson	const struct afd *afd;
617155192Srwatson	struct addrinfo *cur;
618155192Srwatson	struct addrinfo sentinel;
619155192Srwatson	int error;
620155192Srwatson	char pton[PTON_MAX];
621155192Srwatson	int flags;
622155192Srwatson
623155192Srwatson	*res = NULL;
624155192Srwatson	sentinel.ai_next = NULL;
625155192Srwatson	cur = &sentinel;
626155192Srwatson
627155192Srwatson	/*
628159318Srwatson	 * if the servname does not match socktype/protocol, ignore it.
629155192Srwatson	 */
630163207Scsjp	if (get_portmatch(pai, servname) != 0)
631163207Scsjp		return 0;
632164033Srwatson
633155192Srwatson	afd = find_afd(pai->ai_family);
634155192Srwatson	if (afd == NULL)
635155192Srwatson		return 0;
636155192Srwatson	flags = pai->ai_flags;
637155192Srwatson
638155192Srwatson	if (inet_pton(afd->a_af, hostname, pton) == 1) {
639155192Srwatson		if (pai->ai_family == afd->a_af ||
640155192Srwatson		    pai->ai_family == PF_UNSPEC /*?*/) {
641155192Srwatson			GET_AI(cur->ai_next, afd, pton);
642155192Srwatson			GET_PORT(cur->ai_next, servname);
643155192Srwatson			while (cur && cur->ai_next)
644165624Srwatson				cur = cur->ai_next;
645155192Srwatson		} else
646155192Srwatson			ERR(EAI_FAMILY);	/*xxx*/
647155192Srwatson	}
648155192Srwatson
649162944Srwatson	*res = sentinel.ai_next;
650162944Srwatson	return 0;
651155192Srwatson
652170183Skibfree:
653159318Srwatsonbad:
654159318Srwatson	if (sentinel.ai_next)
655159318Srwatson		freeaddrinfo(sentinel.ai_next);
656155192Srwatson	return error;
657168933Srwatson}
658172930Srwatson
659175294Sattilio/*
660168933Srwatson * numeric hostname with scope
661168933Srwatson */
662168933Srwatsonstatic int
663168933Srwatsonexplore_numeric_scope(pai, hostname, servname, res)
664168933Srwatson	const struct addrinfo *pai;
665168933Srwatson	const char *hostname;
666175294Sattilio	const char *servname;
667168933Srwatson	struct addrinfo **res;
668162944Srwatson{
669155192Srwatson#ifndef SCOPE_DELIMITER
670155192Srwatson	return explore_numeric(pai, hostname, servname, res);
671159318Srwatson#else
672159318Srwatson	const struct afd *afd;
673155192Srwatson	struct addrinfo *cur;
674159318Srwatson	int error;
675155192Srwatson	char *cp, *hostname2 = NULL;
676155192Srwatson	int scope;
677155192Srwatson#ifdef INET6
678155192Srwatson	struct sockaddr_in6 *sin6;
679155192Srwatson#endif
680155192Srwatson
681155192Srwatson	/*
682155192Srwatson	 * if the servname does not match socktype/protocol, ignore it.
683155192Srwatson	 */
684155192Srwatson	if (get_portmatch(pai, servname) != 0)
685155192Srwatson		return 0;
686155192Srwatson
687155192Srwatson	afd = find_afd(pai->ai_family);
688155192Srwatson	if (afd == NULL)
689155192Srwatson		return 0;
690155192Srwatson	if (!afd->a_scoped)
691155192Srwatson		return explore_numeric(pai, hostname, servname, res);
692155192Srwatson
693155192Srwatson	cp = strchr(hostname, SCOPE_DELIMITER);
694155192Srwatson	if (cp == NULL)
695155192Srwatson		return explore_numeric(pai, hostname, servname, res);
696155192Srwatson
697155192Srwatson	/*
698155192Srwatson	 * Handle special case of <scoped_address><delimiter><scope id>
699155192Srwatson	 */
700155192Srwatson	hostname2 = strdup(hostname);
701155192Srwatson	if (hostname2 == NULL)
702155192Srwatson		return EAI_MEMORY;
703155192Srwatson	/* terminate at the delimiter */
704155192Srwatson	hostname2[cp - hostname] = '\0';
705155192Srwatson
706155192Srwatson	cp++;
707155192Srwatson	switch (pai->ai_family) {
708155192Srwatson#ifdef INET6
709155192Srwatson	case AF_INET6:
710155192Srwatson		scope = if_nametoindex(cp);
711155192Srwatson		if (scope == 0) {
712155192Srwatson			error = EAI_SYSTEM;
713155192Srwatson			goto free;
714155192Srwatson		}
715155192Srwatson		break;
716155192Srwatson#endif
717155192Srwatson	}
718155192Srwatson
719155192Srwatson	error = explore_numeric(pai, hostname2, servname, res);
720155192Srwatson	if (error == 0) {
721155192Srwatson		for (cur = *res; cur; cur = cur->ai_next) {
722155192Srwatson#ifdef INET6
723155192Srwatson			if (cur->ai_family != AF_INET6)
724155192Srwatson				continue;
725155192Srwatson			sin6 = (struct sockaddr_in6 *)cur->ai_addr;
726155192Srwatson			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
727155192Srwatson			    IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr))
728155192Srwatson				sin6->sin6_scope_id = scope;
729155192Srwatson#endif
730155192Srwatson		}
731155192Srwatson	}
732155192Srwatson
733155192Srwatson#ifdef INET6
734155192Srwatsonfree:
735155192Srwatson#endif
736155192Srwatson	free(hostname2);
737155192Srwatson
738155192Srwatson	return error;
739155192Srwatson#endif
740155192Srwatson}
741155192Srwatson
742155192Srwatsonstatic int
743155192Srwatsonget_canonname(pai, ai, str)
744155192Srwatson	const struct addrinfo *pai;
745155192Srwatson	struct addrinfo *ai;
746155192Srwatson	const char *str;
747155192Srwatson{
748155192Srwatson	if ((pai->ai_flags & AI_CANONNAME) != 0) {
749155192Srwatson		ai->ai_canonname = (char *)malloc(strlen(str) + 1);
750155192Srwatson		if (ai->ai_canonname == NULL)
751155192Srwatson			return EAI_MEMORY;
752155192Srwatson		strcpy(ai->ai_canonname, str);
753155192Srwatson	}
754	return 0;
755}
756
757static struct addrinfo *
758get_ai(pai, afd, addr)
759	const struct addrinfo *pai;
760	const struct afd *afd;
761	const char *addr;
762{
763	char *p;
764	struct addrinfo *ai;
765#ifdef FAITH
766	struct in6_addr faith_prefix;
767	char *fp_str;
768	int translate = 0;
769#endif
770
771#ifdef FAITH
772	/*
773	 * Transfrom an IPv4 addr into a special IPv6 addr format for
774	 * IPv6->IPv4 translation gateway. (only TCP is supported now)
775	 *
776	 * +-----------------------------------+------------+
777	 * | faith prefix part (12 bytes)      | embedded   |
778	 * |                                   | IPv4 addr part (4 bytes)
779	 * +-----------------------------------+------------+
780	 *
781	 * faith prefix part is specified as ascii IPv6 addr format
782	 * in environmental variable GAI.
783	 * For FAITH to work correctly, routing to faith prefix must be
784	 * setup toward a machine where a FAITH daemon operates.
785	 * Also, the machine must enable some mechanizm
786	 * (e.g. faith interface hack) to divert those packet with
787	 * faith prefixed destination addr to user-land FAITH daemon.
788	 */
789	fp_str = getenv("GAI");
790	if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 &&
791	    afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) {
792		u_int32_t v4a;
793		u_int8_t v4a_top;
794
795		memcpy(&v4a, addr, sizeof v4a);
796		v4a_top = v4a >> IN_CLASSA_NSHIFT;
797		if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) &&
798		    v4a_top != 0 && v4a != IN_LOOPBACKNET) {
799			afd = &afdl[N_INET6];
800			memcpy(&faith_prefix.s6_addr[12], addr,
801			       sizeof(struct in_addr));
802			translate = 1;
803		}
804	}
805#endif
806
807	ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
808		+ (afd->a_socklen));
809	if (ai == NULL)
810		return NULL;
811
812	memcpy(ai, pai, sizeof(struct addrinfo));
813	ai->ai_addr = (struct sockaddr *)(ai + 1);
814	memset(ai->ai_addr, 0, afd->a_socklen);
815	ai->ai_addr->sa_len = afd->a_socklen;
816	ai->ai_addrlen = afd->a_socklen;
817	ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
818	p = (char *)(ai->ai_addr);
819#ifdef FAITH
820	if (translate == 1)
821		memcpy(p + afd->a_off, &faith_prefix, afd->a_addrlen);
822	else
823#endif
824	memcpy(p + afd->a_off, addr, afd->a_addrlen);
825
826	return ai;
827}
828
829static int
830get_portmatch(ai, servname)
831	const struct addrinfo *ai;
832	const char *servname;
833{
834	/* get_port does not touch first argument. when matchonly == 1. */
835	return get_port((struct addrinfo *)ai, servname, 1);
836}
837
838static int
839get_port(ai, servname, matchonly)
840	struct addrinfo *ai;
841	const char *servname;
842	int matchonly;
843{
844	const char *proto;
845	struct servent *sp;
846	int port;
847	int allownumeric;
848
849	if (servname == NULL)
850		return 0;
851	if (ai->ai_family != AF_INET
852#ifdef INET6
853	    && ai->ai_family != AF_INET6
854#endif
855	    )
856		return 0;
857
858	switch (ai->ai_socktype) {
859	case SOCK_RAW:
860		return EAI_SERVICE;
861	case SOCK_DGRAM:
862	case SOCK_STREAM:
863		allownumeric = 1;
864		break;
865	case ANY:
866		allownumeric = 0;
867		break;
868	default:
869		return EAI_SOCKTYPE;
870	}
871
872	if (str_isnumber(servname)) {
873		if (!allownumeric)
874			return EAI_SERVICE;
875		port = htons(atoi(servname));
876		if (port < 0 || port > 65535)
877			return EAI_SERVICE;
878	} else {
879		switch (ai->ai_socktype) {
880		case SOCK_DGRAM:
881			proto = "udp";
882			break;
883		case SOCK_STREAM:
884			proto = "tcp";
885			break;
886		default:
887			proto = NULL;
888			break;
889		}
890
891		if ((sp = getservbyname(servname, proto)) == NULL)
892			return EAI_SERVICE;
893		port = sp->s_port;
894	}
895
896	if (!matchonly) {
897		switch (ai->ai_family) {
898		case AF_INET:
899			((struct sockaddr_in *)ai->ai_addr)->sin_port = port;
900			break;
901#ifdef INET6
902		case AF_INET6:
903			((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port;
904			break;
905#endif
906		}
907	}
908
909	return 0;
910}
911
912static const struct afd *
913find_afd(af)
914	int af;
915{
916	const struct afd *afd;
917
918	if (af == PF_UNSPEC)
919		return NULL;
920	for (afd = afdl; afd->a_af; afd++) {
921		if (afd->a_af == af)
922			return afd;
923	}
924	return NULL;
925}
926