1/*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 *
4 * Changes Copyright (C) 2001 Martin Pool <mbp@samba.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the project nor the names of its contributors
15 *    may be used to endorse or promote products derived from this software
16 *    without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31/*
32 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
33 *
34 * Issues to be discussed:
35 * - Thread safe-ness must be checked.
36 * - Return values.  There are nonstandard return values defined and used
37 *   in the source code.  This is because RFC2133 is silent about which error
38 *   code must be returned for which situation.
39 * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag.
40 */
41
42#include <rsync.h>
43
44#if defined(__KAME__) && defined(INET6)
45# define FAITH
46#endif
47
48#define SUCCESS 0
49#define ANY 0
50#define YES 1
51#define NO  0
52
53#ifdef FAITH
54static int translate = NO;
55static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT;
56#endif /* FAITH */
57
58/* Amdahl's UTS 2.1.2 defines NO_ADDRESS instead of NO_DATA. */
59
60#ifndef NO_DATA
61#ifdef NO_ADDRESS
62#define NO_DATA NO_ADDRESS
63#endif
64#endif /* ndef NO_DATA */
65
66static const char in_addrany[] = { 0, 0, 0, 0 };
67static const char in_loopback[] = { 127, 0, 0, 1 };
68#ifdef INET6
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 in6_loopback[] = {
73	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
74};
75#endif
76
77struct sockinet {
78	u_char	si_len;
79	u_char	si_family;
80	u_short	si_port;
81};
82
83static struct afd {
84	int a_af;
85	int a_addrlen;
86	int a_socklen;
87	int a_off;
88	const char *a_addrany;
89	const char *a_loopback;
90} afdl [] = {
91#ifdef INET6
92#define N_INET6 0
93	{PF_INET6, sizeof(struct in6_addr),
94	 sizeof(struct sockaddr_in6),
95	 offsetof(struct sockaddr_in6, sin6_addr),
96	 in6_addrany, in6_loopback},
97#define N_INET  1
98#else
99#define N_INET  0
100#endif
101	{PF_INET, sizeof(struct in_addr),
102	 sizeof(struct sockaddr_in),
103	 offsetof(struct sockaddr_in, sin_addr),
104	 in_addrany, in_loopback},
105	{0, 0, 0, 0, NULL, NULL},
106};
107
108#ifdef INET6
109#define PTON_MAX	16
110#else
111#define PTON_MAX	4
112#endif
113
114
115static int get_name (const char *, struct afd *,
116		     struct addrinfo **, char *, struct addrinfo *,
117		     int);
118static int get_addr (const char *, int, struct addrinfo **,
119			struct addrinfo *, int);
120static int str_isnumber (const char *);
121
122static char *ai_errlist[] = {
123	"success.",
124	"address family for hostname not supported.",	/* EAI_ADDRFAMILY */
125	"temporary failure in name resolution.",	/* EAI_AGAIN      */
126	"invalid value for ai_flags.",		       	/* EAI_BADFLAGS   */
127	"non-recoverable failure in name resolution.", 	/* EAI_FAIL       */
128	"ai_family not supported.",			/* EAI_FAMILY     */
129	"memory allocation failure.", 			/* EAI_MEMORY     */
130	"no address associated with hostname.", 	/* EAI_NODATA     */
131	"hostname nor servname provided, or not known.",/* EAI_NONAME     */
132	"servname not supported for ai_socktype.",	/* EAI_SERVICE    */
133	"ai_socktype not supported.", 			/* EAI_SOCKTYPE   */
134	"system error returned in errno.", 		/* EAI_SYSTEM     */
135	"invalid value for hints.",			/* EAI_BADHINTS	  */
136	"resolved protocol is unknown.",		/* EAI_PROTOCOL   */
137	"unknown error.", 				/* EAI_MAX        */
138};
139
140#define GET_CANONNAME(ai, str) \
141if (pai->ai_flags & AI_CANONNAME) {\
142	int name_size = strlen(str) + 1;\
143	if (((ai)->ai_canonname = (char *)malloc(name_size)) != NULL) {\
144		memcpy((ai)->ai_canonname, (str), name_size);\
145	} else {\
146		error = EAI_MEMORY;\
147		goto free;\
148	}\
149}
150
151
152static int get_ai(struct addrinfo ** to_ai,
153		   struct addrinfo const * pai,
154		   struct afd *afd,
155		   const char *addr,
156		   short port)
157{
158	char *p;
159	if ((*to_ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) +
160					      ((afd)->a_socklen)))
161	    == NULL)
162		return 0;
163	memcpy(*to_ai, pai, sizeof(struct addrinfo));
164	(*to_ai)->ai_addr = (struct sockaddr *)((*to_ai) + 1);
165	memset((*to_ai)->ai_addr, 0, (afd)->a_socklen);
166	(*to_ai)->ai_addrlen = (afd)->a_socklen;
167#ifdef HAVE_SOCKADDR_LEN
168	(*to_ai)->ai_addr->sa_len = (afd)->a_socklen;
169#endif
170	(*to_ai)->ai_addr->sa_family = (*to_ai)->ai_family = (afd)->a_af;
171	((struct sockinet *)(*to_ai)->ai_addr)->si_port = port;
172	p = (char *)((*to_ai)->ai_addr);
173	memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);
174	return 1;
175}
176
177#define ERR(err) do { error = (err); if (1) goto bad; } while (0)
178
179char *
180gai_strerror(ecode)
181	int ecode;
182{
183	if (ecode < 0 || ecode > EAI_MAX)
184		ecode = EAI_MAX;
185	return ai_errlist[ecode];
186}
187
188void
189freeaddrinfo(ai)
190	struct addrinfo *ai;
191{
192	struct addrinfo *next;
193
194	do {
195		next = ai->ai_next;
196		if (ai->ai_canonname)
197			free(ai->ai_canonname);
198		/* no need to free(ai->ai_addr) */
199		free(ai);
200	} while ((ai = next) != NULL);
201}
202
203static int
204str_isnumber(p)
205	const char *p;
206{
207	char *q = (char *)p;
208	while (*q) {
209		if (! isdigit(*q))
210			return NO;
211		q++;
212	}
213	return YES;
214}
215
216int
217getaddrinfo(hostname, servname, hints, res)
218	const char *hostname, *servname;
219	const struct addrinfo *hints;
220	struct addrinfo **res;
221{
222	struct addrinfo sentinel;
223	struct addrinfo *top = NULL;
224	struct addrinfo *cur;
225	int i, error = 0;
226	char pton[PTON_MAX];
227	struct addrinfo ai;
228	struct addrinfo *pai;
229	u_short port;
230
231#ifdef FAITH
232	static int firsttime = 1;
233
234	if (firsttime) {
235		/* translator hack */
236		{
237			char *q = getenv("GAI");
238			if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
239				translate = YES;
240		}
241		firsttime = 0;
242	}
243#endif
244
245	/* initialize file static vars */
246	sentinel.ai_next = NULL;
247	cur = &sentinel;
248	pai = &ai;
249	pai->ai_flags = 0;
250	pai->ai_family = PF_UNSPEC;
251	pai->ai_socktype = ANY;
252	pai->ai_protocol = ANY;
253	pai->ai_addrlen = 0;
254	pai->ai_canonname = NULL;
255	pai->ai_addr = NULL;
256	pai->ai_next = NULL;
257	port = ANY;
258
259	if (hostname == NULL && servname == NULL)
260		return EAI_NONAME;
261	if (hints) {
262		/* error check for hints */
263		if (hints->ai_addrlen || hints->ai_canonname ||
264		    hints->ai_addr || hints->ai_next)
265			ERR(EAI_BADHINTS); /* xxx */
266		if (hints->ai_flags & ~AI_MASK)
267			ERR(EAI_BADFLAGS);
268		switch (hints->ai_family) {
269		case PF_UNSPEC:
270		case PF_INET:
271#ifdef INET6
272		case PF_INET6:
273#endif
274			break;
275		default:
276			ERR(EAI_FAMILY);
277		}
278		memcpy(pai, hints, sizeof(*pai));
279		switch (pai->ai_socktype) {
280		case ANY:
281			switch (pai->ai_protocol) {
282			case ANY:
283				break;
284			case IPPROTO_UDP:
285				pai->ai_socktype = SOCK_DGRAM;
286				break;
287			case IPPROTO_TCP:
288				pai->ai_socktype = SOCK_STREAM;
289				break;
290			default:
291				pai->ai_socktype = SOCK_RAW;
292				break;
293			}
294			break;
295		case SOCK_RAW:
296			break;
297		case SOCK_DGRAM:
298			if (pai->ai_protocol != IPPROTO_UDP &&
299			    pai->ai_protocol != ANY)
300				ERR(EAI_BADHINTS);	/*xxx*/
301			pai->ai_protocol = IPPROTO_UDP;
302			break;
303		case SOCK_STREAM:
304			if (pai->ai_protocol != IPPROTO_TCP &&
305			    pai->ai_protocol != ANY)
306				ERR(EAI_BADHINTS);	/*xxx*/
307			pai->ai_protocol = IPPROTO_TCP;
308			break;
309		default:
310			ERR(EAI_SOCKTYPE);
311			break;
312		}
313	}
314
315	/*
316	 * service port
317	 */
318	if (servname) {
319		if (str_isnumber(servname)) {
320			if (pai->ai_socktype == ANY) {
321				/* caller accept *ANY* socktype */
322				pai->ai_socktype = SOCK_DGRAM;
323				pai->ai_protocol = IPPROTO_UDP;
324			}
325			port = htons(atoi(servname));
326		} else {
327			struct servent *sp;
328			char *proto;
329
330			proto = NULL;
331			switch (pai->ai_socktype) {
332			case ANY:
333				proto = NULL;
334				break;
335			case SOCK_DGRAM:
336				proto = "udp";
337				break;
338			case SOCK_STREAM:
339				proto = "tcp";
340				break;
341			default:
342				fprintf(stderr, "panic!\n");
343				break;
344			}
345			if ((sp = getservbyname(servname, proto)) == NULL)
346				ERR(EAI_SERVICE);
347			port = sp->s_port;
348			if (pai->ai_socktype == ANY) {
349				if (strcmp(sp->s_proto, "udp") == 0) {
350					pai->ai_socktype = SOCK_DGRAM;
351					pai->ai_protocol = IPPROTO_UDP;
352				} else if (strcmp(sp->s_proto, "tcp") == 0) {
353					pai->ai_socktype = SOCK_STREAM;
354					pai->ai_protocol = IPPROTO_TCP;
355				} else
356					ERR(EAI_PROTOCOL);	/*xxx*/
357			}
358		}
359	}
360
361	/*
362	 * hostname == NULL.
363	 * passive socket -> anyaddr (0.0.0.0 or ::)
364	 * non-passive socket -> localhost (127.0.0.1 or ::1)
365	 */
366	if (hostname == NULL) {
367		struct afd *afd;
368
369		for (afd = &afdl[0]; afd->a_af; afd++) {
370			if (!(pai->ai_family == PF_UNSPEC
371			   || pai->ai_family == afd->a_af)) {
372				continue;
373			}
374
375			if (pai->ai_flags & AI_PASSIVE) {
376				if (!get_ai(&cur->ai_next, pai, afd, afd->a_addrany, port))
377					goto free;
378				/* xxx meaningless?
379				 * GET_CANONNAME(cur->ai_next, "anyaddr");
380				 */
381			} else {
382				if (!get_ai(&cur->ai_next, pai, afd, afd->a_loopback,
383					port))
384					goto free;
385				/* xxx meaningless?
386				 * GET_CANONNAME(cur->ai_next, "localhost");
387				 */
388			}
389			cur = cur->ai_next;
390		}
391		top = sentinel.ai_next;
392		if (top)
393			goto good;
394		else
395			ERR(EAI_FAMILY);
396	}
397
398	/* hostname as numeric name */
399	for (i = 0; afdl[i].a_af; i++) {
400		if (inet_pton(afdl[i].a_af, hostname, pton)) {
401			u_long v4a;
402
403			switch (afdl[i].a_af) {
404			case AF_INET:
405				v4a = ((struct in_addr *)pton)->s_addr;
406				if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
407					pai->ai_flags &= ~AI_CANONNAME;
408				v4a >>= IN_CLASSA_NSHIFT;
409				if (v4a == 0 || v4a == IN_LOOPBACKNET)
410					pai->ai_flags &= ~AI_CANONNAME;
411				break;
412#ifdef INET6
413			case AF_INET6:
414			{
415				u_char pfx;
416				pfx = ((struct in6_addr *)pton)->s6_addr[0];
417				if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
418					pai->ai_flags &= ~AI_CANONNAME;
419				break;
420			}
421#endif
422			}
423
424			if (pai->ai_family == afdl[i].a_af ||
425			    pai->ai_family == PF_UNSPEC) {
426				if (! (pai->ai_flags & AI_CANONNAME)) {
427					if (get_ai(&top, pai, &afdl[i], pton, port))
428						goto good;
429					else
430						goto free;
431				}
432				/*
433				 * if AI_CANONNAME and if reverse lookup
434				 * fail, return ai anyway to pacify
435				 * calling application.
436				 *
437				 * XXX getaddrinfo() is a name->address
438				 * translation function, and it looks strange
439				 * that we do addr->name translation here.
440				 */
441				get_name(pton, &afdl[i], &top, pton, pai, port);
442				goto good;
443			} else
444				ERR(EAI_FAMILY);	/*xxx*/
445		}
446	}
447
448	if (pai->ai_flags & AI_NUMERICHOST)
449		ERR(EAI_NONAME);
450
451	/* hostname as alphabetical name */
452	error = get_addr(hostname, pai->ai_family, &top, pai, port);
453	if (error == 0) {
454		if (top) {
455 good:
456			*res = top;
457			return SUCCESS;
458		} else
459			error = EAI_FAIL;
460	}
461 free:
462	if (top)
463		freeaddrinfo(top);
464 bad:
465	*res = NULL;
466	return error;
467}
468
469static int
470get_name(addr, afd, res, numaddr, pai, port0)
471	const char *addr;
472	struct afd *afd;
473	struct addrinfo **res;
474	char *numaddr;
475	struct addrinfo *pai;
476	int port0;
477{
478	u_short port = port0 & 0xffff;
479	struct hostent *hp;
480	struct addrinfo *cur;
481	int error = 0;
482
483#ifdef INET6
484	{
485		int h_error;
486		hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
487	}
488#else
489	hp = gethostbyaddr(addr, afd->a_addrlen, AF_INET);
490#endif
491	if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
492		if (!get_ai(&cur, pai, afd, hp->h_addr_list[0], port))
493			goto free;
494		GET_CANONNAME(cur, hp->h_name);
495	} else {
496		if (!get_ai(&cur, pai, afd, numaddr, port))
497			goto free;
498	}
499
500#ifdef INET6
501	if (hp)
502		freehostent(hp);
503#endif
504	*res = cur;
505	return SUCCESS;
506 free:
507	if (cur)
508		freeaddrinfo(cur);
509#ifdef INET6
510	if (hp)
511		freehostent(hp);
512#endif
513 /* bad: */
514	*res = NULL;
515	return error;
516}
517
518static int
519get_addr(hostname, af, res, pai, port0)
520	const char *hostname;
521	int af;
522	struct addrinfo **res;
523	struct addrinfo *pai;
524	int port0;
525{
526	u_short port = port0 & 0xffff;
527	struct addrinfo sentinel;
528	struct hostent *hp;
529	struct addrinfo *top, *cur;
530	struct afd *afd;
531	int i, error = 0, h_error;
532	char *ap;
533#ifndef INET6
534	extern int h_errno;
535#endif
536
537	top = NULL;
538	sentinel.ai_next = NULL;
539	cur = &sentinel;
540#ifdef INET6
541	if (af == AF_UNSPEC) {
542		hp = getipnodebyname(hostname, AF_INET6,
543				AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
544	} else
545		hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
546#else
547	hp = gethostbyname(hostname);
548	h_error = h_errno;
549#endif
550	if (hp == NULL) {
551		switch (h_error) {
552		case HOST_NOT_FOUND:
553		case NO_DATA:
554			error = EAI_NODATA;
555			break;
556		case TRY_AGAIN:
557			error = EAI_AGAIN;
558			break;
559		case NO_RECOVERY:
560		default:
561			error = EAI_FAIL;
562			break;
563		}
564		goto bad;
565	}
566
567	if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
568	    (hp->h_addr_list[0] == NULL))
569		ERR(EAI_FAIL);
570
571	for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
572		switch (af) {
573#ifdef INET6
574		case AF_INET6:
575			afd = &afdl[N_INET6];
576			break;
577#endif
578#ifndef INET6
579		default:	/* AF_UNSPEC */
580#endif
581		case AF_INET:
582			afd = &afdl[N_INET];
583			break;
584#ifdef INET6
585		default:	/* AF_UNSPEC */
586			if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
587				ap += sizeof(struct in6_addr) -
588					sizeof(struct in_addr);
589				afd = &afdl[N_INET];
590			} else
591				afd = &afdl[N_INET6];
592			break;
593#endif
594		}
595#ifdef FAITH
596		if (translate && afd->a_af == AF_INET) {
597			struct in6_addr *in6;
598
599			if (!get_ai(&cur->ai_next, pai, &afdl[N_INET6], ap, port))
600				goto free;
601			in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
602			memcpy(&in6->s6_addr32[0], &faith_prefix,
603			    sizeof(struct in6_addr) - sizeof(struct in_addr));
604			memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
605		} else
606#endif /* FAITH */
607		if (!get_ai(&cur->ai_next, pai, afd, ap, port))
608			goto free;
609		if (cur == &sentinel) {
610			top = cur->ai_next;
611			GET_CANONNAME(top, hp->h_name);
612		}
613		cur = cur->ai_next;
614	}
615#ifdef INET6
616	freehostent(hp);
617#endif
618	*res = top;
619	return SUCCESS;
620 free:
621	if (top)
622		freeaddrinfo(top);
623#ifdef INET6
624	if (hp)
625		freehostent(hp);
626#endif
627 bad:
628	*res = NULL;
629	return error;
630}
631