638 lines · 15.5 KB · C
RawDownload
/* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. *  * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. *  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * GAI_ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR GAI_ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON GAI_ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN GAI_ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. * * Issues to be discussed: * - Thread safe-ness must be checked. * - Return values.  There are nonstandard return values defined and used *   in the source code.  This is because RFC2133 is silent about which error *   code must be returned for which situation. * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag. */ #if 0#include <sys/types.h>#include <sys/param.h>#include <sys/sysctl.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <arpa/nameser.h>#include <netdb.h>#include <resolv.h>#include <string.h>#include <stdlib.h>#include <stddef.h>#include <ctype.h>#include <unistd.h> #include "addrinfo.h"#endif #if defined(__KAME__) && defined(ENABLE_IPV6)# define FAITH#endif #define SUCCESS 0#define GAI_ANY 0#define YES 1#define NO  0 #ifdef FAITHstatic int translate = NO;static struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT;#endif static const char in_addrany[] = { 0, 0, 0, 0 };static const char in6_addrany[] = {	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};static const char in_loopback[] = { 127, 0, 0, 1 }; static const char in6_loopback[] = {	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; struct sockinet {	u_char	si_len;	u_char	si_family;	u_short	si_port;}; static struct gai_afd {	int a_af;	int a_addrlen;	int a_socklen;	int a_off;	const char *a_addrany;	const char *a_loopback;	} gai_afdl [] = {#ifdef ENABLE_IPV6#define N_INET6 0	{PF_INET6, sizeof(struct in6_addr),	 sizeof(struct sockaddr_in6),	 offsetof(struct sockaddr_in6, sin6_addr),	 in6_addrany, in6_loopback},#define N_INET  1#else#define N_INET  0#endif	{PF_INET, sizeof(struct in_addr),	 sizeof(struct sockaddr_in),	 offsetof(struct sockaddr_in, sin_addr),	 in_addrany, in_loopback},	{0, 0, 0, 0, NULL, NULL},}; #ifdef ENABLE_IPV6#define PTON_MAX	16#else#define PTON_MAX	4#endif #ifndef IN_MULTICAST#define IN_MULTICAST(i)	    (((i) & 0xf0000000U) == 0xe0000000U)#endif #ifndef IN_EXPERIMENTAL#define IN_EXPERIMENTAL(i)  (((i) & 0xe0000000U) == 0xe0000000U)#endif #ifndef IN_LOOPBACKNET#define IN_LOOPBACKNET	    127#endif static int get_name Py_PROTO((const char *, struct gai_afd *,			  struct addrinfo **, char *, struct addrinfo *,			  int));static int get_addr Py_PROTO((const char *, int, struct addrinfo **,			struct addrinfo *, int));static int str_isnumber Py_PROTO((const char *));	static char *ai_errlist[] = {	"success.",	"address family for hostname not supported.",	/* EAI_ADDRFAMILY */	"temporary failure in name resolution.",	/* EAI_AGAIN      */	"invalid value for ai_flags.",		       	/* EAI_BADFLAGS   */	"non-recoverable failure in name resolution.", 	/* EAI_FAIL       */	"ai_family not supported.",			/* EAI_FAMILY     */	"memory allocation failure.", 			/* EAI_MEMORY     */	"no address associated with hostname.", 	/* EAI_NODATA     */	"hostname nor servname provided, or not known.",/* EAI_NONAME     */	"servname not supported for ai_socktype.",	/* EAI_SERVICE    */	"ai_socktype not supported.", 			/* EAI_SOCKTYPE   */	"system error returned in errno.", 		/* EAI_SYSTEM     */	"invalid value for hints.",			/* EAI_BADHINTS	  */	"resolved protocol is unknown.",		/* EAI_PROTOCOL   */	"unknown error.", 				/* EAI_MAX        */}; #define GET_CANONNAME(ai, str) \if (pai->ai_flags & AI_CANONNAME) {\	if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\		strcpy((ai)->ai_canonname, (str));\	} else {\		error = EAI_MEMORY;\		goto free;\	}\} #ifdef HAVE_SOCKADDR_SA_LEN#define GET_AI(ai, gai_afd, addr, port) {\	char *p;\	if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\					      ((gai_afd)->a_socklen)))\	    == NULL) goto free;\	memcpy(ai, pai, sizeof(struct addrinfo));\	(ai)->ai_addr = (struct sockaddr *)((ai) + 1);\	memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\	(ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\	(ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\	((struct sockinet *)(ai)->ai_addr)->si_port = port;\	p = (char *)((ai)->ai_addr);\	memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\}#else#define GET_AI(ai, gai_afd, addr, port) {\	char *p;\	if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\					      ((gai_afd)->a_socklen)))\	    == NULL) goto free;\	memcpy(ai, pai, sizeof(struct addrinfo));\	(ai)->ai_addr = (struct sockaddr *)((ai) + 1);\	memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\	(ai)->ai_addrlen = (gai_afd)->a_socklen;\	(ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\	((struct sockinet *)(ai)->ai_addr)->si_port = port;\	p = (char *)((ai)->ai_addr);\	memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\}#endif #define ERR(err) { error = (err); goto bad; } char *gai_strerror(int ecode){	if (ecode < 0 || ecode > EAI_MAX)		ecode = EAI_MAX;	return ai_errlist[ecode];} voidfreeaddrinfo(struct addrinfo *ai){	struct addrinfo *next; 	do {		next = ai->ai_next;		if (ai->ai_canonname)			free(ai->ai_canonname);		/* no need to free(ai->ai_addr) */		free(ai);	} while ((ai = next) != NULL);} static intstr_isnumber(const char *p){	unsigned char *q = (unsigned char *)p;	while (*q) {		if (! isdigit(*q))			return NO;		q++;	}	return YES;} intgetaddrinfo(const char*hostname, const char*servname,            const struct addrinfo *hints, struct addrinfo **res){	struct addrinfo sentinel;	struct addrinfo *top = NULL;	struct addrinfo *cur;	int i, error = 0;	char pton[PTON_MAX];	struct addrinfo ai;	struct addrinfo *pai;	u_short port; #ifdef FAITH	static int firsttime = 1; 	if (firsttime) {		/* translator hack */		{			char *q = getenv("GAI");			if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)				translate = YES;		}		firsttime = 0;	}#endif 	/* initialize file static vars */	sentinel.ai_next = NULL;	cur = &sentinel;	pai = &ai;	pai->ai_flags = 0;	pai->ai_family = PF_UNSPEC;	pai->ai_socktype = GAI_ANY;	pai->ai_protocol = GAI_ANY;	pai->ai_addrlen = 0;	pai->ai_canonname = NULL;	pai->ai_addr = NULL;	pai->ai_next = NULL;	port = GAI_ANY;		if (hostname == NULL && servname == NULL)		return EAI_NONAME;	if (hints) {		/* error check for hints */		if (hints->ai_addrlen || hints->ai_canonname ||		    hints->ai_addr || hints->ai_next)			ERR(EAI_BADHINTS); /* xxx */		if (hints->ai_flags & ~AI_MASK)			ERR(EAI_BADFLAGS);		switch (hints->ai_family) {		case PF_UNSPEC:		case PF_INET:#ifdef ENABLE_IPV6		case PF_INET6:#endif			break;		default:			ERR(EAI_FAMILY);		}		memcpy(pai, hints, sizeof(*pai));		switch (pai->ai_socktype) {		case GAI_ANY:			switch (pai->ai_protocol) {			case GAI_ANY:				break;			case IPPROTO_UDP:				pai->ai_socktype = SOCK_DGRAM;				break;			case IPPROTO_TCP:				pai->ai_socktype = SOCK_STREAM;				break;			default:				pai->ai_socktype = SOCK_RAW;				break;			}			break;		case SOCK_RAW:			break;		case SOCK_DGRAM:			if (pai->ai_protocol != IPPROTO_UDP &&			    pai->ai_protocol != GAI_ANY)				ERR(EAI_BADHINTS);	/*xxx*/			pai->ai_protocol = IPPROTO_UDP;			break;		case SOCK_STREAM:			if (pai->ai_protocol != IPPROTO_TCP &&			    pai->ai_protocol != GAI_ANY)				ERR(EAI_BADHINTS);	/*xxx*/			pai->ai_protocol = IPPROTO_TCP;			break;		default:			ERR(EAI_SOCKTYPE);			/* unreachable */		}	} 	/*	 * service port	 */	if (servname) {		if (str_isnumber(servname)) {			if (pai->ai_socktype == GAI_ANY) {				/* caller accept *GAI_ANY* socktype */				pai->ai_socktype = SOCK_DGRAM;				pai->ai_protocol = IPPROTO_UDP;			}			port = htons((u_short)atoi(servname));		} else {			struct servent *sp;			char *proto; 			proto = NULL;			switch (pai->ai_socktype) {			case GAI_ANY:				proto = NULL;				break;			case SOCK_DGRAM:				proto = "udp";				break;			case SOCK_STREAM:				proto = "tcp";				break;			default:				fprintf(stderr, "panic!\n");				break;			}			if ((sp = getservbyname(servname, proto)) == NULL)				ERR(EAI_SERVICE);			port = sp->s_port;			if (pai->ai_socktype == GAI_ANY) {				if (strcmp(sp->s_proto, "udp") == 0) {					pai->ai_socktype = SOCK_DGRAM;					pai->ai_protocol = IPPROTO_UDP;				} else if (strcmp(sp->s_proto, "tcp") == 0) {                                        pai->ai_socktype = SOCK_STREAM;                                        pai->ai_protocol = IPPROTO_TCP;                                } else                                        ERR(EAI_PROTOCOL);	/*xxx*/                        }		}	}		/*	 * hostname == NULL.	 * passive socket -> anyaddr (0.0.0.0 or ::)	 * non-passive socket -> localhost (127.0.0.1 or ::1)	 */	if (hostname == NULL) {		struct gai_afd *gai_afd; 		for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) {			if (!(pai->ai_family == PF_UNSPEC			   || pai->ai_family == gai_afd->a_af)) {				continue;			} 			if (pai->ai_flags & AI_PASSIVE) {				GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port);				/* xxx meaningless?				 * GET_CANONNAME(cur->ai_next, "anyaddr");				 */			} else {				GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback,					port);				/* xxx meaningless?				 * GET_CANONNAME(cur->ai_next, "localhost");				 */			}			cur = cur->ai_next;		}		top = sentinel.ai_next;		if (top)			goto good;		else			ERR(EAI_FAMILY);	}		/* hostname as numeric name */	for (i = 0; gai_afdl[i].a_af; i++) {		if (inet_pton(gai_afdl[i].a_af, hostname, pton)) {			u_long v4a;#ifdef ENABLE_IPV6			u_char pfx;#endif 			switch (gai_afdl[i].a_af) {			case AF_INET:				v4a = ((struct in_addr *)pton)->s_addr;				v4a = ntohl(v4a);				if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))					pai->ai_flags &= ~AI_CANONNAME;				v4a >>= IN_CLASSA_NSHIFT;				if (v4a == 0 || v4a == IN_LOOPBACKNET)					pai->ai_flags &= ~AI_CANONNAME;				break;#ifdef ENABLE_IPV6			case AF_INET6:				pfx = ((struct in6_addr *)pton)->s6_addr8[0];				if (pfx == 0 || pfx == 0xfe || pfx == 0xff)					pai->ai_flags &= ~AI_CANONNAME;				break;#endif			}						if (pai->ai_family == gai_afdl[i].a_af ||			    pai->ai_family == PF_UNSPEC) {				if (! (pai->ai_flags & AI_CANONNAME)) {					GET_AI(top, &gai_afdl[i], pton, port);					goto good;				}				/*				 * if AI_CANONNAME and if reverse lookup				 * fail, return ai anyway to pacify				 * calling application.				 *				 * XXX getaddrinfo() is a name->address				 * translation function, and it looks strange				 * that we do addr->name translation here.				 */				get_name(pton, &gai_afdl[i], &top, pton, pai, port);				goto good;			} else 				ERR(EAI_FAMILY);	/*xxx*/		}	} 	if (pai->ai_flags & AI_NUMERICHOST)		ERR(EAI_NONAME); 	/* hostname as alphabetical name */	error = get_addr(hostname, pai->ai_family, &top, pai, port);	if (error == 0) {		if (top) { good:			*res = top;			return SUCCESS;		} else			error = EAI_FAIL;	} free:	if (top)		freeaddrinfo(top); bad:	*res = NULL;	return error;} static intget_name(addr, gai_afd, res, numaddr, pai, port0)	const char *addr;	struct gai_afd *gai_afd;	struct addrinfo **res;	char *numaddr;	struct addrinfo *pai;	int port0;{	u_short port = port0 & 0xffff;	struct hostent *hp;	struct addrinfo *cur;	int error = 0;#ifdef ENABLE_IPV6	int h_error;#endif	#ifdef ENABLE_IPV6

Lines 1–500 of 638.