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