1 /* $USAGI: getaddrinfo.c,v 1.16 2001/10/04 09:52:03 sekiya Exp $ */
2 
3 /* The Inner Net License, Version 2.00
4 
5   The author(s) grant permission for redistribution and use in source and
6 binary forms, with or without modification, of the software and documentation
7 provided that the following conditions are met:
8 
9 0. If you receive a version of the software that is specifically labelled
10    as not being for redistribution (check the version message and/or README),
11    you are not permitted to redistribute that version of the software in any
12    way or form.
13 1. All terms of the all other applicable copyrights and licenses must be
14    followed.
15 2. Redistributions of source code must retain the authors' copyright
16    notice(s), this list of conditions, and the following disclaimer.
17 3. Redistributions in binary form must reproduce the authors' copyright
18    notice(s), this list of conditions, and the following disclaimer in the
19    documentation and/or other materials provided with the distribution.
20 4. All advertising materials mentioning features or use of this software
21    must display the following acknowledgement with the name(s) of the
22    authors as specified in the copyright notice(s) substituted where
23    indicated:
24 
25 	This product includes software developed by <name(s)>, The Inner
26 	Net, and other contributors.
27 
28 5. Neither the name(s) of the author(s) nor the names of its contributors
29    may be used to endorse or promote products derived from this software
30    without specific prior written permission.
31 
32 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
33 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
39 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 
43   If these license terms cause you a real problem, contact the author.  */
44 
45 /* This software is Copyright 1996 by Craig Metz, All Rights Reserved.  */
46 
47 #include <config.h>
48 #include "owfs_config.h"
49 
50 #ifdef HAVE_PTHREAD
51 #include <pthread.h>
52 #endif
53 
54 #ifndef HAVE_GETADDRINFO
55 
56 #define _GNU_SOURCE 1
57 #define __FORCE_GLIBC
58 #ifdef HAVE_FEATURES_H
59 #include <features.h>
60 #endif
61 #include <assert.h>
62 #include <errno.h>
63 #include <netdb.h>
64 #include "compat_netdb.h"
65 
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include <unistd.h>
70 #include <arpa/inet.h>
71 #include <sys/socket.h>
72 #include <netinet/in.h>
73 #include <sys/types.h>
74 #include <sys/un.h>
75 #include <sys/utsname.h>
76 #include <net/if.h>
77 
78 #ifdef HAVE_RESOLV_H
79 #include <resolv.h>
80 #endif
81 
82 #include "ow_debug.h"
83 
84 
85 /* The following declarations and definitions have been removed from
86  *    the public header since we don't want people to use them.  */
87 #define AI_V4MAPPED     0x0008	/* IPv4-mapped addresses are acceptable.  */
88 #define AI_ALL          0x0010	/* Return both IPv4 and IPv6 addresses.  */
89 #define AI_ADDRCONFIG   0x0020	/* Use configuration of this host to choose
90 								   returned address type.  */
91 #define AI_DEFAULT    (AI_V4MAPPED | AI_ADDRCONFIG)
92 
93 
94 #define GAIH_OKIFUNSPEC 0x0100
95 #define GAIH_EAI        ~(GAIH_OKIFUNSPEC)
96 
97 struct gaih_service {
98 	const char *name;
99 	int num;
100 };
101 
102 struct gaih_servtuple {
103 	struct gaih_servtuple *next;
104 	int socktype;
105 	int protocol;
106 	int port;
107 };
108 
109 static const struct gaih_servtuple nullserv;
110 
111 struct gaih_addrtuple {
112 	struct gaih_addrtuple *next;
113 	int family;
114 	char addr[16];
115 	uint32_t scopeid;
116 };
117 
118 struct gaih_typeproto {
119 	int socktype;
120 	int protocol;
121 	char name[4];
122 	int protoflag;
123 };
124 
125 /* Values for `protoflag'.  */
126 #define GAI_PROTO_NOSERVICE	1
127 #define GAI_PROTO_PROTOANY	2
128 
129 static const struct gaih_typeproto gaih_inet_typeproto[] = {
130 	{0, 0, "", 0},
131 	{SOCK_STREAM, IPPROTO_TCP, "tcp", 0},
132 	{SOCK_DGRAM, IPPROTO_UDP, "udp", 0},
133 	{SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY | GAI_PROTO_NOSERVICE},
134 	{0, 0, "", 0}
135 };
136 
137 struct gaih {
138 	int family;
139 	int (*gaih) (const char *name, const struct gaih_service * service, const struct addrinfo * req, struct addrinfo ** pai);
140 };
141 
142 #if PF_UNSPEC == 0
143 static const struct addrinfo default_hints;
144 #else
145 static const struct addrinfo default_hints = { 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
146 #endif
147 
148 
addrconfig(sa_family_t af)149 static int addrconfig(sa_family_t af)
150 {
151 	int s;
152 	int ret;
153 	int saved_errno = errno;
154 	s = socket(af, SOCK_DGRAM, 0);
155 	if (s < 0)
156 		ret = (errno == EMFILE) ? 1 : 0;
157 	else {
158 		close(s);
159 		ret = 1;
160 	}
161 	__set_errno(saved_errno);
162 	return ret;
163 }
164 
165 #if 0
166 #ifndef UNIX_PATH_MAX
167 #define UNIX_PATH_MAX  108
168 #endif
169 
170 /* Using Unix sockets this way is a security risk.  */
171 static int gaih_local(const char *name, const struct gaih_service *service, const struct addrinfo *req, struct addrinfo **pai)
172 {
173 	struct utsname utsname;
174 
175 	if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
176 		return GAIH_OKIFUNSPEC | -EAI_NONAME;
177 
178 	if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
179 		if (uname(&utsname) < 0)
180 			return -EAI_SYSTEM;
181 
182 	if (name != NULL) {
183 		if (strcmp(name, "localhost") && strcmp(name, "local") && strcmp(name, "unix") && strcmp(name, utsname.nodename))
184 			return GAIH_OKIFUNSPEC | -EAI_NONAME;
185 	}
186 
187 	if (req->ai_protocol || req->ai_socktype) {
188 		const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
189 
190 		while (tp->name[0]
191 			   && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
192 				   || (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY)
193 					   && req->ai_protocol != tp->protocol)))
194 			++tp;
195 
196 		if (!tp->name[0]) {
197 			if (req->ai_socktype)
198 				return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
199 			else
200 				return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
201 		}
202 	}
203 
204 	*pai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_un)
205 				  + ((req->ai_flags & AI_CANONNAME)
206 					 ? (strlen(utsname.nodename) + 1) : 0));
207 	if (*pai == NULL)
208 		return -EAI_MEMORY;
209 
210 	(*pai)->ai_next = NULL;
211 	(*pai)->ai_flags = req->ai_flags;
212 	(*pai)->ai_family = AF_LOCAL;
213 	(*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
214 	(*pai)->ai_protocol = req->ai_protocol;
215 	(*pai)->ai_addrlen = sizeof(struct sockaddr_un);
216 	(*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
217 
218 #ifdef HAVE_SA_LEN
219 	((struct sockaddr_un *) (*pai)->ai_addr)->sun_len = sizeof(struct sockaddr_un);
220 #endif							/* HAVE_SA_LEN */
221 
222 	((struct sockaddr_un *) (*pai)->ai_addr)->sun_family = AF_LOCAL;
223 	memset(((struct sockaddr_un *) (*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
224 
225 	if (service) {
226 		struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
227 
228 		if (strchr(service->name, '/') != NULL) {
229 			if (strlen(service->name) >= sizeof(sunp->sun_path))
230 				return GAIH_OKIFUNSPEC | -EAI_SERVICE;
231 
232 			strcpy(sunp->sun_path, service->name);
233 		} else {
234 			if (strlen(P_tmpdir "/") + 1 + strlen(service->name) >= sizeof(sunp->sun_path))
235 				return GAIH_OKIFUNSPEC | -EAI_SERVICE;
236 
237 			__stpcpy(__stpcpy(sunp->sun_path, P_tmpdir "/"), service->name);
238 		}
239 	} else {
240 		/* This is a dangerous use of the interface since there is a time
241 		   window between the test for the file and the actual creation
242 		   (done by the caller) in which a file with the same name could
243 		   be created.  */
244 		char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
245 
246 		if (__builtin_expect(__path_search(buf, L_tmpnam, NULL, NULL, 0), 0) != 0 || __builtin_expect(__gen_tempname(buf, __GT_NOCREATE), 0) != 0)
247 			return -EAI_SYSTEM;
248 	}
249 
250 	if (req->ai_flags & AI_CANONNAME)
251 		(*pai)->ai_canonname = strcpy((char *) *pai + sizeof(struct addrinfo)
252 									  + sizeof(struct sockaddr_un), utsname.nodename);
253 	else
254 		(*pai)->ai_canonname = NULL;
255 	return 0;
256 }
257 #endif							/* 0 */
258 
259 #ifndef HAVE_GETHOSTBYNAME_R
gethostbyname_r(const char * name,struct hostent * result,char * buf,size_t buflen,int * h_errnop)260 struct hostent *gethostbyname_r(const char *name, struct hostent *result, char *buf, size_t buflen, int *h_errnop)
261 {
262 #ifdef HAVE_PTHREAD
263 	static pthread_mutex_t gethostbyname_lock = PTHREAD_MUTEX_INITIALIZER;
264 #endif
265 	struct hostent *res;
266 	(void) buf;					// not used
267 	(void) buflen;				// not used
268 
269 #ifdef HAVE_PTHREAD
270 	pthread_mutex_lock(&gethostbyname_lock);
271 #endif
272 	res = gethostbyname(name);
273 	if (res) {
274 		memcpy(result, res, sizeof(struct hostent));
275 	} else {
276 		*h_errnop = errno;
277 	}
278 #ifdef HAVE_PTHREAD
279 	pthread_mutex_unlock(&gethostbyname_lock);
280 #endif
281 	return res;
282 }
283 #endif
284 
285 #ifndef HAVE_GETSERVBYNAME_R
getservbyname_r(const char * name,const char * proto,struct servent * result,char * buf,size_t buflen)286 struct servent *getservbyname_r(const char *name, const char *proto, struct servent *result, char *buf, size_t buflen)
287 {
288 #ifdef HAVE_PTHREAD
289 	static pthread_mutex_t getservbyname_lock = PTHREAD_MUTEX_INITIALIZER;
290 #endif
291 	struct servent *res;
292 	(void) buf;					// not used
293 	(void) buflen;				// not used
294 
295 #ifdef HAVE_PTHREAD
296 	pthread_mutex_lock(&getservbyname_lock);
297 #endif
298 	res = getservbyname(name, proto);
299 	if (res)
300 		memcpy(result, res, sizeof(struct servent));
301 #ifdef HAVE_PTHREAD
302 	pthread_mutex_unlock(&getservbyname_lock);
303 #endif
304 	return res;
305 }
306 #endif
307 
308 
309 
310 
311 
gaih_inet_serv(const char * servicename,const struct gaih_typeproto * tp,const struct addrinfo * req,struct gaih_servtuple * st)312 static int gaih_inet_serv(const char *servicename, const struct gaih_typeproto *tp, const struct addrinfo *req, struct gaih_servtuple *st)
313 {
314 	struct servent *s;
315 	size_t tmpbuflen = 1024;
316 	struct servent ts;
317 	char *tmpbuf;
318 	int r;
319 
320 	do {
321 		tmpbuf = alloca(tmpbuflen);
322 #if 0
323 		r = getservbyname_r(servicename, tp->name, &ts, tmpbuf, tmpbuflen, &s);
324 		if (!s)
325 			r = errno;
326 		if (r != 0 || s == NULL) {
327 			if (r == ERANGE)
328 				tmpbuflen *= 2;
329 			else
330 				return GAIH_OKIFUNSPEC | -EAI_SERVICE;
331 		}
332 #else
333 		s = getservbyname_r(servicename, tp->name, &ts, tmpbuf, tmpbuflen);
334 		if (s == NULL) {
335 			r = errno;
336 			if (r == ERANGE)
337 				tmpbuflen *= 2;
338 			else
339 				return GAIH_OKIFUNSPEC | -EAI_SERVICE;
340 		} else {
341 			r = 0;
342 		}
343 #endif
344 	}
345 	while (r);
346 
347 	st->next = NULL;
348 	st->socktype = tp->socktype;
349 	st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
350 					? req->ai_protocol : tp->protocol);
351 	st->port = s->s_port;
352 
353 	return 0;
354 }
355 
356 #define gethosts(_family, _type)					\
357 {									\
358     int i, herrno;							\
359     size_t tmpbuflen;							\
360     struct hostent th;							\
361     char *tmpbuf;							\
362     tmpbuflen = 512;							\
363     no_data = 0;							\
364     do {								\
365 	tmpbuflen *= 2;							\
366 	tmpbuf = alloca (tmpbuflen);					\
367         rc = 0;								\
368 	h = gethostbyname_r (name, &th, tmpbuf,				\
369 			       tmpbuflen, &herrno);			\
370         if(!h) rc = errno;						\
371     } while (rc == ERANGE && herrno == NETDB_INTERNAL);			\
372     if (rc != 0)							\
373     {									\
374 	if (herrno == NETDB_INTERNAL)					\
375 	{								\
376 	    __set_h_errno (herrno);					\
377 		return -EAI_SYSTEM;					\
378 	}								\
379 	if (herrno == TRY_AGAIN)					\
380 	    no_data = EAI_AGAIN;					\
381 	else								\
382 	    no_data = herrno == NO_DATA;				\
383     }									\
384     else if (h != NULL)							\
385     {									\
386 	for (i = 0; h->h_addr_list[i]; i++)				\
387 	{								\
388 	    if (*pat == NULL) {						\
389 		*pat = alloca (sizeof(struct gaih_addrtuple));		\
390 		    (*pat)->scopeid = 0;				\
391 	    }								\
392 	    (*pat)->next = NULL;					\
393 		(*pat)->family = _family;				\
394 		memcpy ((*pat)->addr, h->h_addr_list[i],		\
395 			sizeof(_type));					\
396 		pat = &((*pat)->next);					\
397 	}								\
398     }									\
399 }
400 
401 #ifndef HAVE_GETHOSTBYNAME2_R
gethostbyname2_r(const char * name,int af,struct hostent * ret,char * buf,size_t buflen,struct hostent ** result,int * h_errnop)402 struct hostenv *gethostbyname2_r(const char *name, int af, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop)
403 {
404 	/* Don't support this if it doesn't exists...
405 	   (eg. IPV6 will fail on cygwin for example) */
406 	(void) name;
407 	(void) af;
408 	(void) ret;
409 	(void) buf;
410 	(void) buflen;
411 	(void) result;
412 	(void) h_errnop;
413 	return NULL;
414 }
415 #endif
416 
417 
418 #if __HAS_IPV6__
419 #define gethosts2(_family, _type)					\
420 {									\
421     int i, herrno;							\
422     size_t tmpbuflen;							\
423     struct hostent th;							\
424     char *tmpbuf;							\
425     tmpbuflen = 512;							\
426     no_data = 0;							\
427     do {								\
428 	tmpbuflen *= 2;							\
429 	tmpbuf = alloca (tmpbuflen);					\
430 	rc = gethostbyname2_r (name, _family, &th, tmpbuf,		\
431 			       tmpbuflen, &h, &herrno);			\
432     } while (rc == ERANGE && herrno == NETDB_INTERNAL);			\
433     if (rc != 0)							\
434     {									\
435 	if (herrno == NETDB_INTERNAL)					\
436 	{								\
437 	    __set_h_errno (herrno);					\
438 		return -EAI_SYSTEM;					\
439 	}								\
440 	if (herrno == TRY_AGAIN)					\
441 	    no_data = EAI_AGAIN;					\
442 	else								\
443 	    no_data = herrno == NO_DATA;				\
444     }									\
445     else if (h != NULL)							\
446     {									\
447 	for (i = 0; h->h_addr_list[i]; i++)				\
448 	{								\
449 	    if (*pat == NULL) {						\
450 		*pat = alloca (sizeof(struct gaih_addrtuple));		\
451 		    (*pat)->scopeid = 0;				\
452 	    }								\
453 	    (*pat)->next = NULL;					\
454 		(*pat)->family = _family;				\
455 		memcpy ((*pat)->addr, h->h_addr_list[i],		\
456 			sizeof(_type));					\
457 		pat = &((*pat)->next);					\
458 	}								\
459     }									\
460 }
461 #endif
462 
463 #ifndef HAVE_GETHOSTBYADDR_R
gethostbyaddr_r(const char * name,int len,int type,struct hostent * result,char * buf,size_t buflen,int * h_errnop)464 struct hostent *gethostbyaddr_r(const char *name, int len, int type, struct hostent *result, char *buf, size_t buflen, int *h_errnop)
465 {
466 #ifdef HAVE_PTHREAD
467 	static pthread_mutex_t gethostbyaddr_lock = PTHREAD_MUTEX_INITIALIZER;
468 #endif
469 	struct hostent *res;
470 	(void) buf;					// not used
471 	(void) buflen;				// not used
472 
473 #ifdef HAVE_PTHREAD
474 	pthread_mutex_lock(&gethostbyaddr_lock);
475 #endif
476 	res = gethostbyaddr(name, len, type);
477 	if (res) {
478 		memcpy(result, res, sizeof(struct hostent));
479 	} else {
480 		*h_errnop = errno;
481 	}
482 #ifdef HAVE_PTHREAD
483 	pthread_mutex_unlock(&gethostbyaddr_lock);
484 #endif
485 	return res;
486 }
487 #endif
488 
gaih_inet(const char * name,const struct gaih_service * service,const struct addrinfo * req,struct addrinfo ** pai)489 static int gaih_inet(const char *name, const struct gaih_service *service, const struct addrinfo *req, struct addrinfo **pai)
490 {
491 	const struct gaih_typeproto *tp = gaih_inet_typeproto;
492 	struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
493 	struct gaih_addrtuple *at = NULL;
494 	int rc;
495 	int v4mapped = (req->ai_family == PF_UNSPEC
496 #if __HAS_IPV6__
497 					|| req->ai_family == PF_INET6
498 #endif
499 		) && (req->ai_flags & AI_V4MAPPED);
500 
501 	if (req->ai_protocol || req->ai_socktype) {
502 		++tp;
503 
504 		while (tp->name[0]
505 			   && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
506 				   || (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY)
507 					   && req->ai_protocol != tp->protocol)))
508 			++tp;
509 
510 		if (!tp->name[0]) {
511 			if (req->ai_socktype)
512 				return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
513 			else
514 				return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
515 		}
516 	}
517 
518 	if (service != NULL) {
519 		if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
520 			return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
521 
522 		if (service->num < 0) {
523 			if (tp->name[0]) {
524 				st = (struct gaih_servtuple *)
525 					alloca(sizeof(struct gaih_servtuple));
526 
527 				if ((rc = gaih_inet_serv(service->name, tp, req, st)))
528 					return rc;
529 			} else {
530 				struct gaih_servtuple **pst = &st;
531 				for (tp++; tp->name[0]; tp++) {
532 					struct gaih_servtuple *newp;
533 
534 					if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
535 						continue;
536 
537 					if (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
538 						continue;
539 					if (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY)
540 						&& req->ai_protocol != tp->protocol)
541 						continue;
542 
543 					newp = (struct gaih_servtuple *)
544 						alloca(sizeof(struct gaih_servtuple));
545 
546 					if ((rc = gaih_inet_serv(service->name, tp, req, newp))) {
547 						if (rc & GAIH_OKIFUNSPEC)
548 							continue;
549 						return rc;
550 					}
551 
552 					*pst = newp;
553 					pst = &(newp->next);
554 				}
555 				if (st == (struct gaih_servtuple *) &nullserv)
556 					return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
557 			}
558 		} else {
559 			st = alloca(sizeof(struct gaih_servtuple));
560 			st->next = NULL;
561 			st->socktype = tp->socktype;
562 			st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
563 							? req->ai_protocol : tp->protocol);
564 			st->port = htons(service->num);
565 		}
566 	} else if (req->ai_socktype || req->ai_protocol) {
567 		st = alloca(sizeof(struct gaih_servtuple));
568 		st->next = NULL;
569 		st->socktype = tp->socktype;
570 		st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
571 						? req->ai_protocol : tp->protocol);
572 		st->port = 0;
573 	} else {
574 		/*
575 		 * Neither socket type nor protocol is set.  Return all socket types
576 		 * we know about.
577 		 */
578 		struct gaih_servtuple **lastp = &st;
579 		for (++tp; tp->name[0]; ++tp) {
580 			struct gaih_servtuple *newp;
581 
582 			newp = alloca(sizeof(struct gaih_servtuple));
583 			newp->next = NULL;
584 			newp->socktype = tp->socktype;
585 			newp->protocol = tp->protocol;
586 			newp->port = 0;
587 
588 			*lastp = newp;
589 			lastp = &newp->next;
590 		}
591 	}
592 
593 	if (name != NULL) {
594 		at = alloca(sizeof(struct gaih_addrtuple));
595 
596 		at->family = AF_UNSPEC;
597 		at->scopeid = 0;
598 		at->next = NULL;
599 
600 		if (inet_pton(AF_INET, name, at->addr) > 0) {
601 			if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped)
602 				at->family = AF_INET;
603 			else
604 				return -EAI_FAMILY;
605 		}
606 #if __HAS_IPV6__
607 		if (at->family == AF_UNSPEC) {
608 			char *namebuf = strdupa(name);
609 			char *scope_delim;
610 
611 			scope_delim = strchr(namebuf, SCOPE_DELIMITER);
612 			if (scope_delim != NULL)
613 				*scope_delim = '\0';
614 
615 			if (inet_pton(AF_INET6, namebuf, at->addr) > 0) {
616 				if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
617 					at->family = AF_INET6;
618 				else
619 					return -EAI_FAMILY;
620 
621 				if (scope_delim != NULL) {
622 					int try_numericscope = 0;
623 					if (IN6_IS_ADDR_LINKLOCAL(at->addr)
624 						|| IN6_IS_ADDR_MC_LINKLOCAL(at->addr)) {
625 						at->scopeid = if_nametoindex(scope_delim + 1);
626 						if (at->scopeid == 0)
627 							try_numericscope = 1;
628 					} else
629 						try_numericscope = 1;
630 
631 					if (try_numericscope != 0) {
632 						char *end;
633 						assert(sizeof(uint32_t) <= sizeof(unsigned long));
634 						at->scopeid = (uint32_t) strtoul(scope_delim + 1, &end, 10);
635 						if (*end != '\0')
636 							return GAIH_OKIFUNSPEC | -EAI_NONAME;
637 					}
638 				}
639 			}
640 		}
641 #endif
642 
643 		if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0) {
644 			struct hostent *h;
645 			struct gaih_addrtuple **pat = &at;
646 			int no_data = 0;
647 			int no_inet6_data;
648 
649 			/*
650 			 * If we are looking for both IPv4 and IPv6 address we don't want
651 			 * the lookup functions to automatically promote IPv4 addresses to
652 			 * IPv6 addresses.
653 			 */
654 
655 #if __HAS_IPV6__
656 			if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
657 				gethosts(AF_INET6, struct in6_addr);
658 #endif
659 			no_inet6_data = no_data;
660 
661 			if (req->ai_family == AF_INET ||
662 				(!v4mapped && req->ai_family == AF_UNSPEC) || (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL))))
663 #if __HAS_IPV6__
664 				gethosts2(AF_INET, struct in_addr);
665 #else
666 				gethosts(AF_INET, struct in_addr);
667 #endif
668 			if (no_data != 0 && no_inet6_data != 0) {
669 				/* If both requests timed out report this. */
670 				if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
671 					return -EAI_AGAIN;
672 
673 				/*
674 				 * We made requests but they turned out no data.
675 				 * The name is known, though.
676 				 */
677 				return (GAIH_OKIFUNSPEC | -EAI_AGAIN);
678 			}
679 		}
680 
681 		if (at->family == AF_UNSPEC)
682 			return (GAIH_OKIFUNSPEC | -EAI_NONAME);
683 	} else {
684 		struct gaih_addrtuple *atr;
685 		atr = at = alloca(sizeof(struct gaih_addrtuple));
686 		memset(at, '\0', sizeof(struct gaih_addrtuple));
687 
688 		if (req->ai_family == 0) {
689 			at->next = alloca(sizeof(struct gaih_addrtuple));
690 			memset(at->next, '\0', sizeof(struct gaih_addrtuple));
691 		}
692 #if __HAS_IPV6__
693 		if (req->ai_family == 0 || req->ai_family == AF_INET6) {
694 			extern const struct in6_addr __in6addr_loopback;
695 			at->family = AF_INET6;
696 			if ((req->ai_flags & AI_PASSIVE) == 0)
697 				memcpy(at->addr, &__in6addr_loopback, sizeof(struct in6_addr));
698 			atr = at->next;
699 		}
700 #endif
701 
702 		if (req->ai_family == 0 || req->ai_family == AF_INET) {
703 			atr->family = AF_INET;
704 			if ((req->ai_flags & AI_PASSIVE) == 0)
705 				*(uint32_t *) atr->addr = htonl(INADDR_LOOPBACK);
706 		}
707 	}
708 
709 	if (pai == NULL)
710 		return 0;
711 
712 	{
713 		const char *c = NULL;
714 		struct gaih_servtuple *st2;
715 		struct gaih_addrtuple *at2 = at;
716 		size_t socklen, namelen;
717 		sa_family_t family;
718 
719 		/*
720 		 * buffer is the size of an unformatted IPv6 address in
721 		 * printable format.
722 		 */
723 		char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
724 
725 		while (at2 != NULL) {
726 			if (req->ai_flags & AI_CANONNAME) {
727 				struct hostent *h = NULL;
728 
729 				int herrno;
730 				struct hostent th;
731 				size_t tmpbuflen = 512;
732 				char *tmpbuf;
733 
734 				do {
735 					tmpbuflen *= 2;
736 					tmpbuf = alloca(tmpbuflen);
737 
738 					if (tmpbuf == NULL)
739 						return -EAI_MEMORY;
740 
741 					rc = 0;
742 					h = gethostbyaddr_r(at2->addr,
743 #if __HAS_IPV6__
744 										((at2->family == AF_INET6)
745 										 ? sizeof(struct in6_addr)
746 										 : sizeof(struct in_addr)),
747 #else
748 										sizeof(struct in_addr),
749 #endif
750 										at2->family, &th, tmpbuf, tmpbuflen, &herrno);
751 
752 					if (!h)
753 						rc = errno;
754 				}
755 				while (rc == errno && herrno == NETDB_INTERNAL);
756 
757 				if (rc != 0 && herrno == NETDB_INTERNAL) {
758 					__set_h_errno(herrno);
759 					return -EAI_SYSTEM;
760 				}
761 
762 				if (h == NULL)
763 					c = inet_ntop(at2->family, at2->addr, buffer, sizeof(buffer));
764 				else
765 					c = h->h_name;
766 
767 				if (c == NULL)
768 					return GAIH_OKIFUNSPEC | -EAI_NONAME;
769 
770 				namelen = strlen(c) + 1;
771 			} else
772 				namelen = 0;
773 
774 #if __HAS_IPV6__
775 			if (at2->family == AF_INET6 || v4mapped) {
776 				family = AF_INET6;
777 				socklen = sizeof(struct sockaddr_in6);
778 			} else
779 #endif
780 			{
781 				family = AF_INET;
782 				socklen = sizeof(struct sockaddr_in);
783 			}
784 
785 			for (st2 = st; st2 != NULL; st2 = st2->next) {
786 				*pai = malloc(sizeof(struct addrinfo) + socklen + namelen);
787 				if (*pai == NULL)
788 					return -EAI_MEMORY;
789 
790 				(*pai)->ai_flags = req->ai_flags;
791 				(*pai)->ai_family = family;
792 				(*pai)->ai_socktype = st2->socktype;
793 				(*pai)->ai_protocol = st2->protocol;
794 				(*pai)->ai_addrlen = socklen;
795 				(*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
796 #ifdef HAVE_SA_LEN
797 				(*pai)->ai_addr->sa_len = socklen;
798 #endif							/* HAVE_SA_LEN */
799 				(*pai)->ai_addr->sa_family = family;
800 
801 #if __HAS_IPV6__
802 				if (family == AF_INET6) {
803 					struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *) (*pai)->ai_addr;
804 
805 					sin6p->sin6_flowinfo = 0;
806 					if (at2->family == AF_INET6) {
807 						memcpy(&sin6p->sin6_addr, at2->addr, sizeof(struct in6_addr));
808 					} else {
809 						sin6p->sin6_addr.s6_addr32[0] = 0;
810 						sin6p->sin6_addr.s6_addr32[1] = 0;
811 						sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
812 						memcpy(&sin6p->sin6_addr.s6_addr32[3], at2->addr, sizeof(sin6p->sin6_addr.s6_addr32[3]));
813 					}
814 					sin6p->sin6_port = st2->port;
815 					sin6p->sin6_scope_id = at2->scopeid;
816 				} else
817 #endif
818 				{
819 					struct sockaddr_in *sinp = (struct sockaddr_in *) (*pai)->ai_addr;
820 
821 					memcpy(&sinp->sin_addr, at2->addr, sizeof(struct in_addr));
822 					sinp->sin_port = st2->port;
823 					memset(sinp->sin_zero, '\0', sizeof(sinp->sin_zero));
824 				}
825 
826 				if (c) {
827 					(*pai)->ai_canonname = ((void *) (*pai) + sizeof(struct addrinfo) + socklen);
828 					strcpy((*pai)->ai_canonname, c);
829 				} else
830 					(*pai)->ai_canonname = NULL;
831 
832 				(*pai)->ai_next = NULL;
833 				pai = &((*pai)->ai_next);
834 			}
835 
836 			at2 = at2->next;
837 		}
838 	}
839 	return 0;
840 }
841 
842 static struct gaih gaih[] = {
843 #if __HAS_IPV6__
844 	{PF_INET6, gaih_inet},
845 #endif
846 	{PF_INET, gaih_inet},
847 #if 0
848 	{PF_LOCAL, gaih_local},
849 #endif
850 	{PF_UNSPEC, NULL}
851 };
852 
getaddrinfo(const char * name,const char * service,const struct addrinfo * hints,struct addrinfo ** pai)853 int getaddrinfo(const char *name, const char *service, const struct addrinfo *hints, struct addrinfo **pai)
854 {
855 	int i = 0, j = 0, last_i = 0;
856 	struct addrinfo *p = NULL, **end;
857 	struct gaih *g = gaih, *pg = NULL;
858 	struct gaih_service gaih_service, *pservice;
859 
860 	if (name != NULL && name[0] == '*' && name[1] == 0)
861 		name = NULL;
862 
863 	if (service != NULL && service[0] == '*' && service[1] == 0)
864 		service = NULL;
865 
866 	if (name == NULL && service == NULL)
867 		return EAI_NONAME;
868 
869 	if (hints == NULL)
870 		hints = &default_hints;
871 
872 	if (hints->ai_flags & ~(AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_ADDRCONFIG | AI_V4MAPPED | AI_ALL))
873 		return EAI_BADFLAGS;
874 
875 	if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
876 		return EAI_BADFLAGS;
877 
878 	if (service && service[0]) {
879 		char *c;
880 		gaih_service.name = service;
881 		gaih_service.num = strtoul(gaih_service.name, &c, 10);
882 		if (*c)
883 			gaih_service.num = -1;
884 		else
885 			/*
886 			 * Can't specify a numerical socket unless a protocol
887 			 * family was given.
888 			 */
889 		if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
890 			return EAI_SERVICE;
891 		pservice = &gaih_service;
892 	} else
893 		pservice = NULL;
894 
895 	if (pai)
896 		end = &p;
897 	else
898 		end = NULL;
899 
900 	while (g->gaih) {
901 		if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC) {
902 			if ((hints->ai_flags & AI_ADDRCONFIG)
903 				&& !addrconfig(g->family))
904 				continue;
905 			j++;
906 			if (pg == NULL || pg->gaih != g->gaih) {
907 				pg = g;
908 				i = g->gaih(name, pservice, hints, end);
909 				if (i != 0) {
910 					last_i = i;
911 
912 					if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
913 						continue;
914 
915 					if (p)
916 						freeaddrinfo(p);
917 
918 					return -(i & GAIH_EAI);
919 				}
920 				if (end)
921 					while (*end)
922 						end = &((*end)->ai_next);
923 			}
924 		}
925 		++g;
926 	}
927 
928 	if (j == 0)
929 		return EAI_FAMILY;
930 
931 	if (p) {
932 		*pai = p;
933 		return 0;
934 	}
935 
936 	if (pai == NULL && last_i == 0)
937 		return 0;
938 
939 	if (p)
940 		freeaddrinfo(p);
941 
942 	return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
943 }
944 
freeaddrinfo(struct addrinfo * ai)945 void freeaddrinfo(struct addrinfo *ai)
946 {
947 	struct addrinfo *p;
948 
949 	while (ai != NULL) {
950 		p = ai;
951 		ai = ai->ai_next;
952 		free(p);
953 	}
954 }
955 
956 #define N_(x) x
957 static struct {
958 	int code;
959 	const char *msg;
960 } values[] = {
961 	{
962 	EAI_ADDRFAMILY, N_("Address family for hostname not supported")}, {
963 	EAI_AGAIN, N_("Temporary failure in name resolution")}, {
964 	EAI_BADFLAGS, N_("Bad value for ai_flags")}, {
965 	EAI_FAIL, N_("Non-recoverable failure in name resolution")}, {
966 	EAI_FAMILY, N_("ai_family not supported")}, {
967 	EAI_MEMORY, N_("Memory allocation failure")}, {
968 	EAI_NODATA, N_("No address associated with hostname")}, {
969 	EAI_NONAME, N_("Name or service not known")}, {
970 	EAI_SERVICE, N_("Servname not supported for ai_socktype")}, {
971 	EAI_SOCKTYPE, N_("ai_socktype not supported")}, {
972 	EAI_SYSTEM, N_("System error")}, {
973 	EAI_INPROGRESS, N_("Processing request in progress")}, {
974 	EAI_CANCELED, N_("Request canceled")}, {
975 	EAI_NOTCANCELED, N_("Request not canceled")}, {
976 	EAI_ALLDONE, N_("All requests done")}, {
977 	EAI_INTR, N_("Interrupted by a signal")}
978 };
979 
gai_strerror(int code)980 const char *gai_strerror(int code)
981 {
982 	size_t i;
983 	for (i = 0; i < sizeof(values) / sizeof(values[0]); ++i)
984 		if (values[i].code == code)
985 			return (values[i].msg);
986 
987 	return ("Unknown error");
988 }
989 
990 #endif							/* HAVE_GETADDRINFO */
991 
992 
993 
994 #ifndef HAVE_INET_NTOP
995 /* char *
996  * inet_ntop4(src, dst, size)
997  *      format an IPv4 address
998  * return:
999  *      `dst' (as a const)
1000  * notes:
1001  *      (1) uses no statics
1002  *      (2) takes a u_char* not an in_addr as input
1003  * author:
1004  *      Paul Vixie, 1996.
1005  */
inet_ntop4(const unsigned char * src,char * dst,size_t size)1006 static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size)
1007 {
1008 	char tmp[sizeof("255.255.255.255") + 1] = "\0";
1009 	int octet;
1010 	int i;
1011 
1012 	i = 0;
1013 	for (octet = 0; octet <= 3; octet++) {
1014 
1015 		if (src[octet] > 255) {
1016 			__set_errno(ENOSPC);
1017 			return (NULL);
1018 		}
1019 		tmp[i++] = '0' + src[octet] / 100;
1020 		if (tmp[i - 1] == '0') {
1021 			tmp[i - 1] = '0' + (src[octet] / 10 % 10);
1022 			if (tmp[i - 1] == '0')
1023 				i--;
1024 		} else {
1025 			tmp[i++] = '0' + (src[octet] / 10 % 10);
1026 		}
1027 		tmp[i++] = '0' + src[octet] % 10;
1028 		tmp[i++] = '.';
1029 	}
1030 	tmp[i - 1] = '\0';
1031 
1032 	if (strlen(tmp) > size) {
1033 		__set_errno(ENOSPC);
1034 		return (NULL);
1035 	}
1036 
1037 	return strcpy(dst, tmp);
1038 }
1039 
1040 /* char *
1041  * inet_ntop(af, src, dst, size)
1042  *      convert a network format address to presentation format.
1043  * return:
1044  *      pointer to presentation format address (`dst'), or NULL (see errno).
1045  * author:
1046  *      Paul Vixie, 1996.
1047  */
inet_ntop(af,src,dst,size)1048 const char *inet_ntop(af, src, dst, size)
1049 int af;
1050 const void *src;
1051 char *dst;
1052 socklen_t size;
1053 {
1054 	switch (af) {
1055 	case AF_INET:
1056 		return (inet_ntop4(src, dst, size));
1057 #if __HAS_IPV6__
1058 	case AF_INET6:
1059 		return (inet_ntop6(src, dst, size));
1060 #endif
1061 	default:
1062 		__set_errno(EAFNOSUPPORT);
1063 		return (NULL);
1064 	}
1065 	/* NOTREACHED */
1066 }
1067 #endif							/* HAVE_INET_NTOP */
1068 
1069 
1070 #ifndef HAVE_INET_PTON
1071 /* int
1072  * inet_pton4(src, dst)
1073  *      like inet_aton() but without all the hexadecimal and shorthand.
1074  * return:
1075  *      1 if `src' is a valid dotted quad, else 0.
1076  * notice:
1077  *      does not touch `dst' unless it's returning 1.
1078  * author:
1079  *      Paul Vixie, 1996.
1080  */
inet_pton4(const char * src,unsigned char * dst)1081 static int inet_pton4(const char *src, unsigned char *dst)
1082 {
1083 	int saw_digit, octets, ch;
1084 	unsigned char tmp[4], *tp;
1085 
1086 	saw_digit = 0;
1087 	octets = 0;
1088 	*(tp = tmp) = 0;
1089 	while ((ch = *src++) != '\0') {
1090 
1091 		if (ch >= '0' && ch <= '9') {
1092 			unsigned int new = *tp * 10 + (ch - '0');
1093 
1094 			if (new > 255)
1095 				return (0);
1096 			*tp = new;
1097 			if (!saw_digit) {
1098 				if (++octets > 4)
1099 					return (0);
1100 				saw_digit = 1;
1101 			}
1102 		} else if (ch == '.' && saw_digit) {
1103 			if (octets == 4)
1104 				return (0);
1105 			*++tp = 0;
1106 			saw_digit = 0;
1107 		} else
1108 			return (0);
1109 	}
1110 	if (octets < 4)
1111 		return (0);
1112 	memcpy(dst, tmp, 4);
1113 	return (1);
1114 }
1115 
1116 /* int
1117  * inet_pton(af, src, dst)
1118  *      convert from presentation format (which usually means ASCII printable)
1119  *      to network format (which is usually some kind of binary format).
1120  * return:
1121  *      1 if the address was valid for the specified address family
1122  *      0 if the address wasn't valid (`dst' is untouched in this case)
1123  *      -1 if some other error occurred (`dst' is untouched in this case, too)
1124  * author:
1125  *      Paul Vixie, 1996.
1126  */
inet_pton(af,src,dst)1127 int inet_pton(af, src, dst)
1128 int af;
1129 const char *src;
1130 void *dst;
1131 {
1132 	switch (af) {
1133 	case AF_INET:
1134 		return (inet_pton4(src, dst));
1135 #if __HAS_IPV6__
1136 	case AF_INET6:
1137 		return (inet_pton6(src, dst));
1138 #endif
1139 	default:
1140 		__set_errno(EAFNOSUPPORT);
1141 		return (-1);
1142 	}
1143 	/* NOTREACHED */
1144 }
1145 #endif							/* HAVE_INET_PTON */
1146