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
30/*
31 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
32 *
33 * Issues to be discussed:
34 * - Thread safe-ness must be checked.
35 * - Return values.  There are nonstandard return values defined and used
36 *   in the source code.  This is because RFC2553 is silent about which error
37 *   code must be returned for which situation.
38 * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag.
39 */
40
41#include <sys/types.h>
42#include <sys/param.h>
43#include <sys/sysctl.h>
44#include <sys/socket.h>
45#include <netinet/in.h>
46#include <arpa/inet.h>
47#include <arpa/nameser.h>
48#include <netdb.h>
49#include <resolv.h>
50#include <string.h>
51#include <stdlib.h>
52#include <stddef.h>
53#include <ctype.h>
54#include <unistd.h>
55
56#include "missing/addrinfo.h"
57
58#if defined(__KAME__) && defined(INET6)
59# define FAITH
60#endif
61
62#define SUCCESS 0
63#define ANY 0
64#define YES 1
65#define NO  0
66
67#ifdef FAITH
68static int translate = NO;
69static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT;
70#endif
71
72static const char in_addrany[] = { 0, 0, 0, 0 };
73static const char in6_addrany[] = {
74	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
75};
76static const char in_loopback[] = { 127, 0, 0, 1 };
77static const char in6_loopback[] = {
78	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
79};
80
81struct sockinet {
82	u_char	si_len;
83	u_char	si_family;
84	u_short	si_port;
85};
86
87static struct afd {
88	int a_af;
89	int a_addrlen;
90	int a_socklen;
91	int a_off;
92	const char *a_addrany;
93	const char *a_loopback;
94} afdl [] = {
95#ifdef INET6
96#define N_INET6 0
97	{PF_INET6, sizeof(struct in6_addr),
98	 sizeof(struct sockaddr_in6),
99	 offsetof(struct sockaddr_in6, sin6_addr),
100	 in6_addrany, in6_loopback},
101#define N_INET  1
102#else
103#define N_INET  0
104#endif
105	{PF_INET, sizeof(struct in_addr),
106	 sizeof(struct sockaddr_in),
107	 offsetof(struct sockaddr_in, sin_addr),
108	 in_addrany, in_loopback},
109	{0, 0, 0, 0, NULL, NULL},
110};
111
112#ifdef INET6
113#define PTON_MAX	16
114#else
115#define PTON_MAX	4
116#endif
117
118
119static int get_name __P((const char *, struct afd *,
120			  struct addrinfo **, char *, struct addrinfo *,
121			  int));
122static int get_addr __P((const char *, int, struct addrinfo **,
123			struct addrinfo *, int));
124static int get_addr0 __P((const char *, int, struct addrinfo **,
125			struct addrinfo *, int));
126static int str_isnumber __P((const char *));
127
128static char *ai_errlist[] = {
129	"Success",
130	"Address family for hostname not supported",	/* EAI_ADDRFAMILY */
131	"Temporary failure in name resolution",		/* EAI_AGAIN      */
132	"Invalid value for ai_flags",		       	/* EAI_BADFLAGS   */
133	"Non-recoverable failure in name resolution", 	/* EAI_FAIL       */
134	"ai_family not supported",			/* EAI_FAMILY     */
135	"Memory allocation failure", 			/* EAI_MEMORY     */
136	"No address associated with hostname", 		/* EAI_NODATA     */
137	"hostname nor servname provided, or not known",/* EAI_NONAME     */
138	"servname not supported for ai_socktype",	/* EAI_SERVICE    */
139	"ai_socktype not supported", 			/* EAI_SOCKTYPE   */
140	"System error returned in errno", 		/* EAI_SYSTEM     */
141	"Invalid value for hints",			/* EAI_BADHINTS	  */
142	"Resolved protocol is unknown",			/* EAI_PROTOCOL   */
143	"Unknown error", 				/* EAI_MAX        */
144};
145
146#define GET_CANONNAME(ai, str) \
147if (pai->ai_flags & AI_CANONNAME) {\
148	if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
149		strcpy((ai)->ai_canonname, (str));\
150	} else {\
151		error = EAI_MEMORY;\
152		goto free;\
153	}\
154}
155
156#define GET_AI(ai, afd, addr, port) {\
157	char *p;\
158	if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
159					      ((afd)->a_socklen)))\
160	    == NULL) {\
161		error = EAI_MEMORY;\
162		goto free;\
163	}\
164	memcpy(ai, pai, sizeof(struct addrinfo));\
165	(ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
166	memset((ai)->ai_addr, 0, (afd)->a_socklen);\
167	(ai)->ai_addr->sa_len = (ai)->ai_addrlen = (afd)->a_socklen;\
168	(ai)->ai_addr->sa_family = (ai)->ai_family = (afd)->a_af;\
169	((struct sockinet *)(ai)->ai_addr)->si_port = port;\
170	p = (char *)((ai)->ai_addr);\
171	memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);\
172}
173
174#define ERR(err) { error = (err); goto bad; }
175
176char *
177gai_strerror(ecode)
178	int ecode;
179{
180	if (ecode < 0 || ecode > EAI_MAX)
181		ecode = EAI_MAX;
182	return ai_errlist[ecode];
183}
184
185void
186freeaddrinfo(ai)
187	struct addrinfo *ai;
188{
189	struct addrinfo *next;
190
191	do {
192		next = ai->ai_next;
193		if (ai->ai_canonname)
194			free(ai->ai_canonname);
195		/* no need to free(ai->ai_addr) */
196		free(ai);
197	} while ((ai = next) != NULL);
198}
199
200static int
201str_isnumber(p)
202	const char *p;
203{
204	char *q = (char *)p;
205	while (*q) {
206		if (! isdigit(*q))
207			return NO;
208		q++;
209	}
210	return YES;
211}
212
213int
214getaddrinfo(hostname, servname, hints, res)
215	const char *hostname, *servname;
216	const struct addrinfo *hints;
217	struct addrinfo **res;
218{
219	struct addrinfo sentinel;
220	struct addrinfo *top = NULL;
221	struct addrinfo *cur;
222	int i, error = 0;
223	char pton[PTON_MAX];
224	struct addrinfo ai;
225	struct addrinfo *pai;
226	u_short port;
227
228#ifdef FAITH
229	static int firsttime = 1;
230
231	if (firsttime) {
232		/* translator hack */
233		{
234			char *q = getenv("GAI");
235			if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
236				translate = YES;
237		}
238		firsttime = 0;
239	}
240#endif
241
242	/* initialize file static vars */
243	sentinel.ai_next = NULL;
244	cur = &sentinel;
245	pai = &ai;
246	pai->ai_flags = 0;
247	pai->ai_family = PF_UNSPEC;
248	pai->ai_socktype = ANY;
249	pai->ai_protocol = ANY;
250	pai->ai_addrlen = 0;
251	pai->ai_canonname = NULL;
252	pai->ai_addr = NULL;
253	pai->ai_next = NULL;
254	port = ANY;
255
256	if (hostname == NULL && servname == NULL)
257		return EAI_NONAME;
258	if (hints) {
259		/* error check for hints */
260		if (hints->ai_addrlen || hints->ai_canonname ||
261		    hints->ai_addr || hints->ai_next)
262			ERR(EAI_BADHINTS);
263		if (hints->ai_flags & ~AI_MASK)
264			ERR(EAI_BADFLAGS);
265		switch (hints->ai_family) {
266		case PF_UNSPEC:
267		case PF_INET:
268#ifdef INET6
269		case PF_INET6:
270#endif
271			break;
272		default:
273			ERR(EAI_FAMILY);
274		}
275		memcpy(pai, hints, sizeof(*pai));
276		switch (pai->ai_socktype) {
277		case ANY:
278			switch (pai->ai_protocol) {
279			case ANY:
280				break;
281			case IPPROTO_UDP:
282				pai->ai_socktype = SOCK_DGRAM;
283				break;
284			case IPPROTO_TCP:
285				pai->ai_socktype = SOCK_STREAM;
286				break;
287			default:
288				pai->ai_socktype = SOCK_RAW;
289				break;
290			}
291			break;
292		case SOCK_RAW:
293			break;
294		case SOCK_DGRAM:
295			if (pai->ai_protocol != IPPROTO_UDP &&
296			    pai->ai_protocol != ANY)
297				ERR(EAI_BADHINTS);
298			pai->ai_protocol = IPPROTO_UDP;
299			break;
300		case SOCK_STREAM:
301			if (pai->ai_protocol != IPPROTO_TCP &&
302			    pai->ai_protocol != ANY)
303				ERR(EAI_BADHINTS);
304			pai->ai_protocol = IPPROTO_TCP;
305			break;
306		default:
307			ERR(EAI_SOCKTYPE);
308			break;
309		}
310	}
311
312	/*
313	 * service port
314	 */
315	if (servname) {
316		if (str_isnumber(servname)) {
317			if (pai->ai_socktype == ANY) {
318				/* caller accept *ANY* socktype */
319				pai->ai_socktype = SOCK_DGRAM;
320				pai->ai_protocol = IPPROTO_UDP;
321			}
322			port = htons(atoi(servname));
323		} else {
324			struct servent *sp;
325			char *proto;
326
327			proto = NULL;
328			switch (pai->ai_socktype) {
329			case ANY:
330				proto = NULL;
331				break;
332			case SOCK_DGRAM:
333				proto = "udp";
334				break;
335			case SOCK_STREAM:
336				proto = "tcp";
337				break;
338			default:
339				fprintf(stderr, "panic!\n");
340				break;
341			}
342			if ((sp = getservbyname(servname, proto)) == NULL)
343				ERR(EAI_SERVICE);
344			port = sp->s_port;
345			if (pai->ai_socktype == ANY) {
346				if (strcmp(sp->s_proto, "udp") == 0) {
347					pai->ai_socktype = SOCK_DGRAM;
348					pai->ai_protocol = IPPROTO_UDP;
349				} else if (strcmp(sp->s_proto, "tcp") == 0) {
350					pai->ai_socktype = SOCK_STREAM;
351					pai->ai_protocol = IPPROTO_TCP;
352				} else
353					ERR(EAI_PROTOCOL);
354			}
355		}
356	}
357
358	/*
359	 * hostname == NULL.
360	 * passive socket -> anyaddr (0.0.0.0 or ::)
361	 * non-passive socket -> localhost (127.0.0.1 or ::1)
362	 */
363	if (hostname == NULL) {
364		struct afd *afd;
365		int s;
366
367		for (afd = &afdl[0]; afd->a_af; afd++) {
368			if (!(pai->ai_family == PF_UNSPEC
369			   || pai->ai_family == afd->a_af)) {
370				continue;
371			}
372
373			s = socket(afd->a_af, SOCK_DGRAM, 0);
374			if (s < 0)
375				continue;
376			close(s);
377
378			if (pai->ai_flags & AI_PASSIVE) {
379				GET_AI(cur->ai_next, afd, afd->a_addrany, port);
380			} else {
381				GET_AI(cur->ai_next, afd, afd->a_loopback,
382					port);
383			}
384			cur = cur->ai_next;
385		}
386		top = sentinel.ai_next;
387		if (top)
388			goto good;
389		else
390			ERR(EAI_FAMILY);
391	}
392
393	/* hostname as numeric name */
394	for (i = 0; afdl[i].a_af; i++) {
395		if (inet_pton(afdl[i].a_af, hostname, pton) == 1) {
396			u_long v4a;
397			u_char pfx;
398
399			switch (afdl[i].a_af) {
400			case AF_INET:
401				v4a = ntohl(((struct in_addr *)pton)->s_addr);
402				if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
403					pai->ai_flags &= ~AI_CANONNAME;
404				v4a >>= IN_CLASSA_NSHIFT;
405				if (v4a == 0 || v4a == IN_LOOPBACKNET)
406					pai->ai_flags &= ~AI_CANONNAME;
407				break;
408#ifdef INET6
409			case AF_INET6:
410				pfx = ((struct in6_addr *)pton)->s6_addr[0];
411				if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
412					pai->ai_flags &= ~AI_CANONNAME;
413				break;
414#endif
415			}
416
417			if (pai->ai_family == afdl[i].a_af ||
418			    pai->ai_family == PF_UNSPEC) {
419				if (! (pai->ai_flags & AI_CANONNAME)) {
420					GET_AI(top, &afdl[i], pton, port);
421					goto good;
422				}
423				get_name(pton, &afdl[i], &top, pton, pai, port);
424				goto good;
425			} else
426				ERR(EAI_FAMILY);
427		}
428	}
429
430	if (pai->ai_flags & AI_NUMERICHOST)
431		ERR(EAI_NONAME);
432
433	/* hostname as alphabetical name */
434	error = get_addr(hostname, pai->ai_family, &top, pai, port);
435	if (error == 0) {
436		if (top) {
437 good:
438			*res = top;
439			return SUCCESS;
440		} else
441			error = EAI_FAIL;
442	}
443 free:
444	if (top)
445		freeaddrinfo(top);
446 bad:
447	*res = NULL;
448	return error;
449}
450
451static int
452get_name(addr, afd, res, numaddr, pai, port0)
453	const char *addr;
454	struct afd *afd;
455	struct addrinfo **res;
456	char *numaddr;
457	struct addrinfo *pai;
458	int port0;
459{
460	u_short port = port0 & 0xffff;
461	struct hostent *hp;
462	struct addrinfo *cur;
463	int error = 0;
464#ifdef USE_GETIPNODEBY
465	int h_error;
466
467	hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
468#else
469	hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
470#endif
471	if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
472		GET_AI(cur, afd, hp->h_addr_list[0], port);
473		GET_CANONNAME(cur, hp->h_name);
474	} else
475		GET_AI(cur, afd, numaddr, port);
476
477#ifdef USE_GETIPNODEBY
478	if (hp)
479		freehostent(hp);
480#endif
481	*res = cur;
482	return SUCCESS;
483 free:
484	if (cur)
485		freeaddrinfo(cur);
486#ifdef USE_GETIPNODEBY
487	if (hp)
488		freehostent(hp);
489#endif
490 /* bad: */
491	*res = NULL;
492	return error;
493}
494
495static int
496get_addr(hostname, af, res0, pai, port0)
497	const char *hostname;
498	int af;
499	struct addrinfo **res0;
500	struct addrinfo *pai;
501	int port0;
502{
503#ifdef USE_GETIPNODEBY
504	return get_addr0(hostname, af, res0, pai, port0);
505#else
506	int i, error, ekeep;
507	struct addrinfo *cur;
508	struct addrinfo **res;
509	int retry;
510	int s;
511
512	res = res0;
513	ekeep = 0;
514	error = 0;
515	for (i = 0; afdl[i].a_af; i++) {
516		retry = 0;
517		if (af == AF_UNSPEC) {
518			s = socket(afdl[i].a_af, SOCK_DGRAM, 0);
519			if (s < 0)
520				continue;
521			close(s);
522		} else {
523			if (af != afdl[i].a_af)
524				continue;
525		}
526		/* It is WRONG, we need getipnodebyname(). */
527again:
528		error = get_addr0(hostname, afdl[i].a_af, res, pai, port0);
529		switch (error) {
530		case EAI_AGAIN:
531			if (++retry < 3)
532				goto again;
533			/* FALL THROUGH*/
534		default:
535			if (ekeep == 0)
536				ekeep = error;
537			break;
538		}
539		if (*res) {
540			/* make chain of addrs */
541			for (cur = *res;
542			     cur && cur->ai_next;
543			     cur = cur->ai_next)
544				;
545			if (!cur)
546				return EAI_FAIL;
547			res = &cur->ai_next;
548		}
549	}
550
551	/* if we got something, it's okay */
552	if (*res0)
553		return 0;
554
555	return error ? error : ekeep;
556#endif
557}
558
559static int
560get_addr0(hostname, af, res, pai, port0)
561	const char *hostname;
562	int af;
563	struct addrinfo **res;
564	struct addrinfo *pai;
565	int port0;
566{
567	u_short port = port0 & 0xffff;
568	struct addrinfo sentinel;
569	struct hostent *hp;
570	struct addrinfo *top, *cur;
571	struct afd *afd;
572	int i, error = 0, h_error;
573	char *ap;
574#ifndef USE_GETIPNODEBY
575	extern int h_errno;
576#endif
577
578	top = NULL;
579	sentinel.ai_next = NULL;
580	cur = &sentinel;
581#ifdef USE_GETIPNODEBY
582	if (af == AF_UNSPEC) {
583		hp = getipnodebyname(hostname, AF_INET6,
584				AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
585	} else
586		hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
587#else
588	if (af == AF_UNSPEC) {
589		error = EAI_FAIL;
590		goto bad;
591	}
592	hp = gethostbyname2(hostname, af);
593	h_error = h_errno;
594#endif
595	if (hp == NULL) {
596		switch (h_error) {
597		case HOST_NOT_FOUND:
598		case NO_DATA:
599			error = EAI_NODATA;
600			break;
601		case TRY_AGAIN:
602			error = EAI_AGAIN;
603			break;
604		case NO_RECOVERY:
605		case NETDB_INTERNAL:
606		default:
607			error = EAI_FAIL;
608			break;
609		}
610		goto bad;
611	}
612
613	if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
614	    (hp->h_addr_list[0] == NULL))
615		ERR(EAI_FAIL);
616
617	for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
618		switch (af) {
619#ifdef INET6
620		case AF_INET6:
621			afd = &afdl[N_INET6];
622			break;
623#endif
624#ifndef INET6
625		default:	/* AF_UNSPEC */
626#endif
627		case AF_INET:
628			afd = &afdl[N_INET];
629			break;
630#ifdef INET6
631		default:	/* AF_UNSPEC */
632			if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
633				ap += sizeof(struct in6_addr) -
634					sizeof(struct in_addr);
635				afd = &afdl[N_INET];
636			} else
637				afd = &afdl[N_INET6];
638			break;
639#endif
640		}
641#ifdef FAITH
642		if (translate && afd->a_af == AF_INET) {
643			struct in6_addr *in6;
644
645			GET_AI(cur->ai_next, &afdl[N_INET6], ap, port);
646			in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
647			memcpy(&in6->s6_addr[0], &faith_prefix,
648			    sizeof(struct in6_addr) - sizeof(struct in_addr));
649			memcpy(&in6->s6_addr[12], ap, sizeof(struct in_addr));
650		} else
651#endif /* FAITH */
652		GET_AI(cur->ai_next, afd, ap, port);
653		if (cur == &sentinel) {
654			top = cur->ai_next;
655			GET_CANONNAME(top, hp->h_name);
656		}
657		cur = cur->ai_next;
658	}
659#ifdef USE_GETIPNODEBY
660	freehostent(hp);
661#endif
662	*res = top;
663	return SUCCESS;
664 free:
665	if (top)
666		freeaddrinfo(top);
667#ifdef USE_GETIPNODEBY
668	if (hp)
669		freehostent(hp);
670#endif
671 bad:
672	*res = NULL;
673	return error;
674}
675