mirror of
				https://github.com/osmarks/ngircd.git
				synced 2025-10-30 21:42:59 +00:00 
			
		
		
		
	IPv6 support.
all references to struct sockaddr/in_addr have been removed from src/ngircd. libngipaddr (in src/ipaddr/) hides all the gory details. See src/ipaddr/ng_ipaddr.h for API description.
This commit is contained in:
		| @@ -8,10 +8,10 @@ | ||||
| # (at your option) any later version. | ||||
| # Please read the file COPYING, README and AUTHORS for more information. | ||||
| # | ||||
| # $Id: Makefile.am,v 1.7 2005/07/22 21:01:03 alex Exp $ | ||||
| # $Id: Makefile.am,v 1.8 2008/02/26 22:04:15 fw Exp $ | ||||
| # | ||||
|  | ||||
| SUBDIRS = portab tool ngircd testsuite | ||||
| SUBDIRS = portab tool ipaddr ngircd testsuite | ||||
|  | ||||
| maintainer-clean-local: | ||||
| 	rm -f Makefile Makefile.in config.h config.h.in stamp-h.in | ||||
|   | ||||
							
								
								
									
										3
									
								
								src/ipaddr/.cvsignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/ipaddr/.cvsignore
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| Makefile | ||||
| Makefile.in | ||||
| .deps | ||||
							
								
								
									
										14
									
								
								src/ipaddr/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/ipaddr/Makefile.am
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| AUTOMAKE_OPTIONS = ansi2knr | ||||
|  | ||||
| INCLUDES = -I$(srcdir)/../portab | ||||
|  | ||||
| noinst_LIBRARIES = libngipaddr.a | ||||
|  | ||||
| libngipaddr_a_SOURCES = ng_ipaddr.c | ||||
|  | ||||
| noinst_HEADERS = ng_ipaddr.h | ||||
|  | ||||
| maintainer-clean-local: | ||||
| 	rm -f Makefile Makefile.in | ||||
|  | ||||
| # -eof- | ||||
							
								
								
									
										170
									
								
								src/ipaddr/ng_ipaddr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								src/ipaddr/ng_ipaddr.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,170 @@ | ||||
| /* | ||||
|  * Functions for AF_ agnostic ipv4/ipv6 handling. | ||||
|  * | ||||
|  * (c) 2008 Florian Westphal <fw@strlen.de>, public domain. | ||||
|  */ | ||||
|  | ||||
| #include "portab.h" | ||||
|  | ||||
| #include <assert.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #ifdef HAVE_GETADDRINFO | ||||
| #include <netdb.h> | ||||
| #include <sys/types.h> | ||||
| #endif | ||||
| #include <sys/socket.h> | ||||
|  | ||||
| #include <netinet/in.h> | ||||
|  | ||||
| #include "ng_ipaddr.h" | ||||
|  | ||||
| GLOBAL bool | ||||
| ng_ipaddr_init(ng_ipaddr_t *addr, const char *ip_str, UINT16 port) | ||||
| { | ||||
| #ifdef HAVE_GETADDRINFO | ||||
| 	int ret; | ||||
| 	char portstr[64]; | ||||
| 	struct addrinfo *res0; | ||||
| 	struct addrinfo hints = { | ||||
| #ifndef WANT_IPV6	/* only accept v4 addresses */ | ||||
| 		.ai_family = AF_INET, | ||||
| #endif | ||||
| 		.ai_flags = AI_NUMERICHOST | ||||
| 	}; | ||||
|  | ||||
| 	if (ip_str == NULL) | ||||
| 		hints.ai_flags |= AI_PASSIVE; | ||||
|  | ||||
| 	/* silly, but ngircd stores UINT16 in server config, not string */ | ||||
| 	snprintf(portstr, sizeof(portstr), "%u", (unsigned int) port); | ||||
| 	ret = getaddrinfo(ip_str, portstr, &hints, &res0); | ||||
| 	assert(ret == 0); | ||||
| 	if (ret != 0) | ||||
| 		return false; | ||||
|  | ||||
| 	assert(sizeof(*addr) >= res0->ai_addrlen); | ||||
| 	if (sizeof(*addr) >= res0->ai_addrlen) | ||||
| 		memcpy(addr, res0->ai_addr, res0->ai_addrlen); | ||||
| 	else | ||||
| 		ret = -1; | ||||
| 	freeaddrinfo(res0); | ||||
| 	return ret == 0; | ||||
| #else /* HAVE_GETADDRINFO */ | ||||
| 	if (ip_str == NULL) | ||||
| 		ip_str = "0.0.0.0"; | ||||
| 	addr->sin4.sin_family = AF_INET; | ||||
| # ifdef HAVE_INET_ATON | ||||
| 	if (inet_aton(ip_str, &addr->sin4.sin_addr) == 0) | ||||
| 		return false; | ||||
| # else | ||||
| 	addr->sin4.sin_addr.s_addr = inet_addr(ip_str); | ||||
| 	if (addr->sin4.sin_addr.s_addr == (unsigned) -1) | ||||
| 		return false; | ||||
| # endif | ||||
| 	ng_ipaddr_setport(addr, port); | ||||
| 	return true; | ||||
| #endif /* HAVE_GETADDRINFO */ | ||||
| } | ||||
|  | ||||
|  | ||||
| GLOBAL void | ||||
| ng_ipaddr_setport(ng_ipaddr_t *a, UINT16 port) | ||||
| { | ||||
| #ifdef WANT_IPV6 | ||||
| 	int af; | ||||
|  | ||||
| 	assert(a != NULL); | ||||
|  | ||||
| 	af = a->sa.sa_family; | ||||
|  | ||||
| 	assert(af == AF_INET || af == AF_INET6); | ||||
|  | ||||
| 	switch (af) { | ||||
| 	case AF_INET: | ||||
| 		a->sin4.sin_port = htons(port); | ||||
| 		break; | ||||
| 	case AF_INET6: | ||||
| 		a->sin6.sin6_port = htons(port); | ||||
| 		break; | ||||
| 	} | ||||
| #else /* WANT_IPV6 */ | ||||
| 	assert(a != NULL); | ||||
| 	assert(a->sin4.sin_family == AF_INET); | ||||
| 	a->sin4.sin_port = htons(port); | ||||
| #endif /* WANT_IPV6 */ | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| GLOBAL bool | ||||
| ng_ipaddr_ipequal(const ng_ipaddr_t *a, const ng_ipaddr_t *b) | ||||
| { | ||||
| 	assert(a != NULL); | ||||
| 	assert(b != NULL); | ||||
| #ifdef WANT_IPV6 | ||||
| 	if (a->sa.sa_family != b->sa.sa_family) | ||||
| 		return false; | ||||
| 	assert(ng_ipaddr_salen(a) == ng_ipaddr_salen(b)); | ||||
| 	switch (a->sa.sa_family) { | ||||
| 	case AF_INET6: | ||||
| 		return IN6_ARE_ADDR_EQUAL(&a->sin6.sin6_addr, &b->sin6.sin6_addr); | ||||
| 	case AF_INET: | ||||
| 		return memcmp(&a->sin4.sin_addr, &b->sin4.sin_addr, sizeof(a->sin4.sin_addr)) == 0; | ||||
| 	} | ||||
| 	return false; | ||||
| #else | ||||
| 	assert(a->sin4.sin_family == AF_INET); | ||||
| 	assert(b->sin4.sin_family == AF_INET); | ||||
| 	return memcmp(&a->sin4.sin_addr, &b->sin4.sin_addr, sizeof(a->sin4.sin_addr)) == 0; | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| #ifdef WANT_IPV6 | ||||
| GLOBAL const char * | ||||
| ng_ipaddr_tostr(const ng_ipaddr_t *addr) | ||||
| { | ||||
| 	static char strbuf[NG_INET_ADDRSTRLEN]; | ||||
|  | ||||
| 	strbuf[0] = 0; | ||||
|  | ||||
| 	ng_ipaddr_tostr_r(addr, strbuf); | ||||
| 	return strbuf; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* str must be at least NG_INET_ADDRSTRLEN bytes long */ | ||||
| GLOBAL bool | ||||
| ng_ipaddr_tostr_r(const ng_ipaddr_t *addr, char *str) | ||||
| { | ||||
| #ifdef HAVE_GETNAMEINFO | ||||
| 	const struct sockaddr *sa = (const struct sockaddr *) addr; | ||||
| 	int ret; | ||||
|  | ||||
| 	*str = 0; | ||||
|  | ||||
| 	ret = getnameinfo(sa, ng_ipaddr_salen(addr), | ||||
| 			str, NG_INET_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST); | ||||
| 	/* | ||||
| 	 * avoid leading ':'. | ||||
| 	 * causes mis-interpretation of client host in e.g. /WHOIS | ||||
| 	 */ | ||||
| 	if (*str == ':') { | ||||
| 		char tmp[NG_INET_ADDRSTRLEN] = "0"; | ||||
| 		ret = getnameinfo(sa, ng_ipaddr_salen(addr), | ||||
| 				tmp+1, sizeof(tmp) -1, NULL, 0, NI_NUMERICHOST); | ||||
| 		if (ret == 0) | ||||
| 			strlcpy(str, tmp, NG_INET_ADDRSTRLEN); | ||||
| 	} | ||||
| 	assert (ret == 0); | ||||
| 	return ret == 0; | ||||
| #else | ||||
| 	abort(); /* WANT_IPV6 depends on HAVE_GETNAMEINFO */ | ||||
| #endif | ||||
| } | ||||
|  | ||||
| #endif /* WANT_IPV6 */ | ||||
|  | ||||
| /* -eof- */ | ||||
							
								
								
									
										115
									
								
								src/ipaddr/ng_ipaddr.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								src/ipaddr/ng_ipaddr.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | ||||
| /* | ||||
|  * Functions for AF_ agnostic ipv4/ipv6 handling. | ||||
|  * | ||||
|  * (c) 2008 Florian Westphal <fw@strlen.de>, public domain. | ||||
|  */ | ||||
|  | ||||
| #ifndef NG_IPADDR_HDR | ||||
| #define NG_IPADDR_HDR | ||||
| #include "portab.h" | ||||
|  | ||||
| #ifdef HAVE_ARPA_INET_H | ||||
| # include <arpa/inet.h> | ||||
| #else | ||||
| # define PF_INET AF_INET | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #ifdef WANT_IPV6 | ||||
| #define NG_INET_ADDRSTRLEN	INET6_ADDRSTRLEN | ||||
| #else | ||||
| #define NG_INET_ADDRSTRLEN	16 | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #ifdef WANT_IPV6 | ||||
| typedef union { | ||||
| 	struct sockaddr sa; | ||||
| 	struct sockaddr_in sin4; | ||||
| 	struct sockaddr_in6 sin6; | ||||
| } ng_ipaddr_t; | ||||
| #else | ||||
| /* assume compiler can't deal with typedef struct {... */ | ||||
| struct NG_IP_ADDR_DONTUSE { | ||||
| 	struct sockaddr_in sin4; | ||||
| }; | ||||
| typedef struct NG_IP_ADDR_DONTUSE ng_ipaddr_t; | ||||
| #endif | ||||
|  | ||||
|  | ||||
| static inline int | ||||
| ng_ipaddr_af(const ng_ipaddr_t *a) | ||||
| { | ||||
| #ifdef WANT_IPV6 | ||||
| 	return a->sa.sa_family; | ||||
| #else | ||||
| 	assert(a->sin4.sin_family == 0 || a->sin4.sin_family == AF_INET); | ||||
| 	return a->sin4.sin_family; | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| static inline socklen_t | ||||
| ng_ipaddr_salen(const ng_ipaddr_t *a) | ||||
| { | ||||
| #ifdef WANT_IPV6 | ||||
| 	assert(a->sa.sa_family == AF_INET || a->sa.sa_family == AF_INET6); | ||||
| 	if (a->sa.sa_family == AF_INET6) | ||||
| 		return sizeof(a->sin6); | ||||
| #endif | ||||
| 	assert(a->sin4.sin_family == AF_INET); | ||||
| 	return sizeof(a->sin4); | ||||
| } | ||||
|  | ||||
|  | ||||
| static inline UINT16 | ||||
| ng_ipaddr_getport(const ng_ipaddr_t *a) | ||||
| { | ||||
| #ifdef WANT_IPV6 | ||||
| 	int af = a->sa.sa_family; | ||||
|  | ||||
| 	assert(af == AF_INET || af == AF_INET6); | ||||
|  | ||||
| 	if (af == AF_INET6) | ||||
| 		return ntohs(a->sin6.sin6_port); | ||||
| #endif /* WANT_IPV6 */ | ||||
| 	assert(a->sin4.sin_family == AF_INET); | ||||
| 	return ntohs(a->sin4.sin_port); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * init a ng_ipaddr_t object. | ||||
|  * @param addr: pointer to ng_ipaddr_t to initialize. | ||||
|  * @param ip_str: ip address in dotted-decimal (ipv4) or hexadecimal (ipv6) notation | ||||
|  *                if ip_str is NULL it is treated as 0.0.0.0/[::] | ||||
|  * @param port: transport layer port number to use. | ||||
|  */ | ||||
| GLOBAL bool ng_ipaddr_init PARAMS((ng_ipaddr_t *addr, const char *ip_str, UINT16 port)); | ||||
|  | ||||
| /* set sin4/sin6_port, depending on a->sa_family */ | ||||
| GLOBAL void ng_ipaddr_setport PARAMS((ng_ipaddr_t *a, UINT16 port)); | ||||
|  | ||||
| /* return true if a and b have the same IP address. If a and b have different AF, return false. */ | ||||
| GLOBAL bool ng_ipaddr_ipequal PARAMS((const ng_ipaddr_t *a, const ng_ipaddr_t *b)); | ||||
|  | ||||
|  | ||||
| #ifdef WANT_IPV6 | ||||
| /* convert struct sockaddr to string, returns pointer to static buffer */ | ||||
| GLOBAL const char *ng_ipaddr_tostr PARAMS((const ng_ipaddr_t *addr)); | ||||
|  | ||||
| /* convert struct sockaddr to string. dest must be NG_INET_ADDRSTRLEN bytes long */ | ||||
| GLOBAL bool ng_ipaddr_tostr_r PARAMS((const ng_ipaddr_t *addr, char *dest)); | ||||
| #else | ||||
| static inline const char * | ||||
| ng_ipaddr_tostr(const ng_ipaddr_t *addr) { return inet_ntoa(addr->sin4.sin_addr); } | ||||
|  | ||||
| static inline bool | ||||
| ng_ipaddr_tostr_r(const ng_ipaddr_t *addr, char *d) | ||||
| { | ||||
| 	strlcpy(d, inet_ntoa(addr->sin4.sin_addr), NG_INET_ADDRSTRLEN); | ||||
| 	return true; | ||||
| } | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| /* -eof- */ | ||||
| @@ -8,12 +8,12 @@ | ||||
| # (at your option) any later version. | ||||
| # Please read the file COPYING, README and AUTHORS for more information. | ||||
| # | ||||
| # $Id: Makefile.am,v 1.50 2007/11/21 12:16:36 alex Exp $ | ||||
| # $Id: Makefile.am,v 1.51 2008/02/26 22:04:17 fw Exp $ | ||||
| # | ||||
|  | ||||
| AUTOMAKE_OPTIONS = ../portab/ansi2knr | ||||
|  | ||||
| INCLUDES = -I$(srcdir)/../portab -I$(srcdir)/../tool | ||||
| INCLUDES = -I$(srcdir)/../portab -I$(srcdir)/../tool -I$(srcdir)/../ipaddr | ||||
|  | ||||
| LINTARGS = -weak -warnunixlib +unixlib -booltype BOOLEAN \ | ||||
|  -varuse -retvalother -emptyret -unrecog | ||||
| @@ -25,9 +25,9 @@ ngircd_SOURCES = ngircd.c array.c channel.c client.c conf.c conn.c conn-func.c \ | ||||
| 	irc-mode.c irc-op.c irc-oper.c irc-server.c irc-write.c lists.c log.c \ | ||||
| 	match.c numeric.c parse.c rendezvous.c resolve.c | ||||
|  | ||||
| ngircd_LDFLAGS = -L../portab -L../tool | ||||
| ngircd_LDFLAGS = -L../portab -L../tool -L../ipaddr | ||||
|  | ||||
| ngircd_LDADD = -lngportab -lngtool | ||||
| ngircd_LDADD = -lngportab -lngtool -lngipaddr | ||||
|  | ||||
| noinst_HEADERS = ngircd.h array.h channel.h client.h conf.h conn.h conn-func.h \ | ||||
| 	conn-zip.h hash.h io.h irc.h irc-channel.h irc-info.h irc-login.h \ | ||||
|   | ||||
| @@ -14,7 +14,7 @@ | ||||
|  | ||||
| #include "portab.h" | ||||
|  | ||||
| static char UNUSED id[] = "$Id: conf.c,v 1.103 2007/11/23 16:26:04 fw Exp $"; | ||||
| static char UNUSED id[] = "$Id: conf.c,v 1.104 2008/02/26 22:04:17 fw Exp $"; | ||||
|  | ||||
| #include "imp.h" | ||||
| #include <assert.h> | ||||
| @@ -938,7 +938,7 @@ Handle_SERVER( int Line, char *Var, char *Arg ) | ||||
| 		return; | ||||
| 	} | ||||
| 	if (strcasecmp(Var, "Bind") == 0) { | ||||
| 		if (ngt_IPStrToBin(Arg, &New_Server.bind_addr)) | ||||
| 		if (ng_ipaddr_init(&New_Server.bind_addr, Arg, 0)) | ||||
| 			return; | ||||
|  | ||||
| 		Config_Error(LOG_ERR, "%s, line %d (section \"Server\"): Can't parse IP address \"%s\"", | ||||
| @@ -1213,7 +1213,7 @@ Init_Server_Struct( CONF_SERVER *Server ) | ||||
|  | ||||
| 	Resolve_Init(&Server->res_stat); | ||||
| 	Server->conn_id = NONE; | ||||
| 	Server->bind_addr.s_addr = htonl(INADDR_ANY); | ||||
| 	memset(&Server->bind_addr, 0, sizeof(&Server->bind_addr)); | ||||
| } /* Init_Server_Struct */ | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
|  * (at your option) any later version. | ||||
|  * Please read the file COPYING, README and AUTHORS for more information. | ||||
|  * | ||||
|  * $Id: conf.h,v 1.47 2007/11/23 16:28:37 fw Exp $ | ||||
|  * $Id: conf.h,v 1.48 2008/02/26 22:04:17 fw Exp $ | ||||
|  * | ||||
|  * Configuration management (header) | ||||
|  */ | ||||
| @@ -22,6 +22,8 @@ | ||||
| #include "defines.h" | ||||
| #include "array.h" | ||||
| #include "portab.h" | ||||
| #include "tool.h" | ||||
| #include "ng_ipaddr.h" | ||||
|  | ||||
| typedef struct _Conf_Oper | ||||
| { | ||||
| @@ -42,7 +44,8 @@ typedef struct _Conf_Server | ||||
| 	RES_STAT res_stat;		/* Status of the resolver */ | ||||
| 	int flags;			/* Flags */ | ||||
| 	CONN_ID conn_id;		/* ID of server connection or NONE */ | ||||
| 	struct in_addr bind_addr;	/* source address to use for outgoing connections */ | ||||
| 	ng_ipaddr_t bind_addr;		/* source address to use for outgoing connections */ | ||||
| 	ng_ipaddr_t dst_addr[2];	/* list of addresses to connect to */ | ||||
| } CONF_SERVER; | ||||
|  | ||||
| typedef struct _Conf_Channel | ||||
| @@ -121,6 +124,12 @@ GLOBAL bool Conf_OperCanMode; | ||||
| /* Disable all DNS functions? */ | ||||
| GLOBAL bool Conf_NoDNS; | ||||
|  | ||||
| /* don't listen for incoming ipv6 connections, even if OS supports it? */ | ||||
| GLOBAL bool Conf_NoListenIpv6; | ||||
|  | ||||
| /* don't connect to remote systems unsign ipv6? */ | ||||
| GLOBAL bool Conf_NoConnectIpv6; | ||||
|  | ||||
| /* If an IRC op gives chanop privileges without being a chanop, | ||||
|  * ircd2 will ignore the command. This enables a workaround: | ||||
|  * It masks the command as coming from the server */ | ||||
|   | ||||
| @@ -17,7 +17,7 @@ | ||||
| #include "portab.h" | ||||
| #include "io.h" | ||||
|  | ||||
| static char UNUSED id[] = "$Id: conn.c,v 1.220 2007/12/13 01:30:16 fw Exp $"; | ||||
| static char UNUSED id[] = "$Id: conn.c,v 1.221 2008/02/26 22:04:17 fw Exp $"; | ||||
|  | ||||
| #include "imp.h" | ||||
| #include <assert.h> | ||||
| @@ -86,10 +86,9 @@ static void Check_Connections PARAMS(( void )); | ||||
| static void Check_Servers PARAMS(( void )); | ||||
| static void Init_Conn_Struct PARAMS(( CONN_ID Idx )); | ||||
| static bool Init_Socket PARAMS(( int Sock )); | ||||
| static void New_Server PARAMS(( int Server, struct in_addr *dest)); | ||||
| static void New_Server PARAMS(( int Server, ng_ipaddr_t *dest )); | ||||
| static void Simple_Message PARAMS(( int Sock, const char *Msg )); | ||||
| static int Count_Connections PARAMS(( struct sockaddr_in addr )); | ||||
| static int NewListener PARAMS(( const UINT16 Port )); | ||||
| static int NewListener PARAMS(( int af, const UINT16 Port )); | ||||
|  | ||||
| static array My_Listeners; | ||||
| static array My_ConnArray; | ||||
| @@ -144,10 +143,28 @@ cb_connserver(int sock, UNUSED short what) | ||||
|  			    Conf_Server[Conf_GetServer(idx)].port, | ||||
|  			    idx, strerror(err)); | ||||
|  | ||||
| 		res = Conf_GetServer(idx); | ||||
| 		assert(res >= 0); | ||||
|  | ||||
| 		Conn_Close(idx, "Can't connect!", NULL, false); | ||||
|  | ||||
| 		if (res < 0) | ||||
| 			return; | ||||
| 		if (ng_ipaddr_af(&Conf_Server[res].dst_addr[0])) { | ||||
| 			/* more addresses to try... */ | ||||
| 			New_Server(res, &Conf_Server[res].dst_addr[0]); | ||||
| 			/* connection to dst_addr[0] in progress, remove this address... */ | ||||
| 			Conf_Server[res].dst_addr[0] = Conf_Server[res].dst_addr[1]; | ||||
|  | ||||
| 			memset(&Conf_Server[res].dst_addr[1], 0, sizeof(&Conf_Server[res].dst_addr[1])); | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	res = Conf_GetServer(idx); | ||||
| 	assert(res >= 0); | ||||
| 	if (res >= 0) /* connect succeeded, remove all additional addresses */ | ||||
| 		memset(&Conf_Server[res].dst_addr, 0, sizeof(&Conf_Server[res].dst_addr)); | ||||
| 	Conn_OPTION_DEL( &My_Connections[idx], CONN_ISCONNECTING ); | ||||
| 	server_login(idx); | ||||
| } | ||||
| @@ -255,7 +272,7 @@ Conn_Exit( void ) | ||||
|  | ||||
|  | ||||
| static unsigned int | ||||
| ports_initlisteners(array *a, void (*func)(int,short)) | ||||
| ports_initlisteners(array *a, int af, void (*func)(int,short)) | ||||
| { | ||||
| 	unsigned int created = 0; | ||||
| 	size_t len; | ||||
| @@ -265,7 +282,7 @@ ports_initlisteners(array *a, void (*func)(int,short)) | ||||
| 	len = array_length(a, sizeof (UINT16)); | ||||
| 	port = array_start(a); | ||||
| 	while(len--) { | ||||
| 		fd = NewListener( *port ); | ||||
| 		fd = NewListener(af, *port); | ||||
| 		if (fd < 0) { | ||||
| 			port++; | ||||
| 			continue; | ||||
| @@ -290,14 +307,18 @@ Conn_InitListeners( void ) | ||||
| { | ||||
| 	/* Initialize ports on which the server should accept connections */ | ||||
|  | ||||
| 	unsigned int created; | ||||
| 	unsigned int created = 0; | ||||
|  | ||||
| 	if (!io_library_init(CONNECTION_POOL)) { | ||||
| 		Log(LOG_EMERG, "Cannot initialize IO routines: %s", strerror(errno)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	created = ports_initlisteners(&Conf_ListenPorts, cb_listen); | ||||
| #ifdef WANT_IPV6 | ||||
| 	if (!Conf_NoListenIpv6) | ||||
| 		created = ports_initlisteners(&Conf_ListenPorts, AF_INET6, cb_listen); | ||||
| #endif | ||||
| 	created += ports_initlisteners(&Conf_ListenPorts, AF_INET, cb_listen); | ||||
|  | ||||
| 	return created; | ||||
| } /* Conn_InitListeners */ | ||||
| @@ -327,68 +348,75 @@ Conn_ExitListeners( void ) | ||||
| } /* Conn_ExitListeners */ | ||||
|  | ||||
|  | ||||
| static void | ||||
| InitSinaddr(struct sockaddr_in *addr, UINT16 Port) | ||||
| static bool | ||||
| InitSinaddrListenAddr(int af, ng_ipaddr_t *addr, UINT16 Port) | ||||
| { | ||||
| 	struct in_addr inaddr; | ||||
| 	bool ret; | ||||
| 	const char *listen_addrstr = NULL; | ||||
| #ifdef WANT_IPV6 | ||||
| 	if (af == AF_INET) | ||||
| 		listen_addrstr = "0.0.0.0"; | ||||
| #else | ||||
| 	(void)af; | ||||
| #endif | ||||
| 	if (Conf_ListenAddress[0]) /* overrides V4/V6 atm */ | ||||
| 		listen_addrstr = Conf_ListenAddress; | ||||
|  | ||||
| 	memset(addr, 0, sizeof(*addr)); | ||||
| 	memset( &inaddr, 0, sizeof(inaddr)); | ||||
|  | ||||
| 	addr->sin_family = AF_INET; | ||||
| 	addr->sin_port = htons(Port); | ||||
| 	inaddr.s_addr = htonl(INADDR_ANY); | ||||
| 	addr->sin_addr = inaddr; | ||||
| 	ret = ng_ipaddr_init(addr, listen_addrstr, Port); | ||||
| 	if (!ret) { | ||||
| 		if (!listen_addrstr) | ||||
| 			listen_addrstr = ""; | ||||
| 		Log(LOG_CRIT, "Can't bind to %s:%u: can't convert ip address \"%s\"", | ||||
| 					listen_addrstr, Port, listen_addrstr); | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
|  | ||||
| static bool | ||||
| InitSinaddrListenAddr(struct sockaddr_in *addr, UINT16 Port) | ||||
| static void | ||||
| set_v6_only(int af, int sock) | ||||
| { | ||||
| 	struct in_addr inaddr; | ||||
| #if defined(IPV6_V6ONLY) && defined(WANT_IPV6) | ||||
| 	int on = 1; | ||||
|  | ||||
| 	InitSinaddr(addr, Port); | ||||
| 	if (af != AF_INET6) | ||||
| 		return; | ||||
|  | ||||
| 	if (!Conf_ListenAddress[0]) | ||||
| 		return true; | ||||
|  | ||||
| 	if (!ngt_IPStrToBin(Conf_ListenAddress, &inaddr)) { | ||||
| 		Log( LOG_CRIT, "Can't bind to %s:%u: can't convert ip address \"%s\"", | ||||
| 				Conf_ListenAddress, Port, Conf_ListenAddress); | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	addr->sin_addr = inaddr; | ||||
| 	return true; | ||||
| 	if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) | ||||
| 		Log(LOG_ERR, "Could not set IPV6_V6ONLY: %s", strerror(errno)); | ||||
| #else | ||||
| 	(void)af; | ||||
| 	(void)sock; | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| /* return new listening port file descriptor or -1 on failure */ | ||||
| static int | ||||
| NewListener( const UINT16 Port ) | ||||
| NewListener(int af, const UINT16 Port) | ||||
| { | ||||
| 	/* Create new listening socket on specified port */ | ||||
|  | ||||
| 	struct sockaddr_in addr; | ||||
| 	ng_ipaddr_t addr; | ||||
| 	int sock; | ||||
| #ifdef ZEROCONF | ||||
| 	char name[CLIENT_ID_LEN], *info; | ||||
| #endif | ||||
| 	if (!InitSinaddrListenAddr(af, &addr, Port)) | ||||
| 		return -1; | ||||
|  | ||||
| 	InitSinaddrListenAddr(&addr, Port); | ||||
|  | ||||
| 	addr.sin_family = AF_INET; | ||||
| 	addr.sin_port = htons( Port ); | ||||
|  | ||||
| 	sock = socket( PF_INET, SOCK_STREAM, 0); | ||||
| 	sock = socket(ng_ipaddr_af(&addr), SOCK_STREAM, 0); | ||||
| 	if( sock < 0 ) { | ||||
| 		Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno )); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	af = ng_ipaddr_af(&addr); | ||||
|  | ||||
| 	set_v6_only(af, sock); | ||||
|  | ||||
| 	if( ! Init_Socket( sock )) return -1; | ||||
|  | ||||
| 	if (bind(sock, (struct sockaddr *)&addr, (socklen_t)sizeof(addr)) != 0) { | ||||
| 	if (bind(sock, (struct sockaddr *)&addr, ng_ipaddr_salen(&addr)) != 0) { | ||||
| 		Log( LOG_CRIT, "Can't bind socket (port %d) : %s!", Port, strerror( errno )); | ||||
| 		close( sock ); | ||||
| 		return -1; | ||||
| @@ -407,8 +435,12 @@ NewListener( const UINT16 Port ) | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if( Conf_ListenAddress[0]) Log( LOG_INFO, "Now listening on %s:%d (socket %d).", Conf_ListenAddress, Port, sock ); | ||||
| 	else Log( LOG_INFO, "Now listening on 0.0.0.0:%d (socket %d).", Port, sock ); | ||||
| #ifdef WANT_IPV6 | ||||
| 	if (af == AF_INET6) | ||||
| 		Log(LOG_INFO, "Now listening on [%s]:%d (socket %d).", ng_ipaddr_tostr(&addr), Port, sock); | ||||
| 	else | ||||
| #endif | ||||
| 		Log(LOG_INFO, "Now listening on %s:%d (socket %d).", ng_ipaddr_tostr(&addr), Port, sock); | ||||
|  | ||||
| #ifdef ZEROCONF | ||||
| 	/* Get best server description text */ | ||||
| @@ -709,6 +741,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient ) | ||||
| 	CLIENT *c; | ||||
| 	char *txt; | ||||
| 	double in_k, out_k; | ||||
| 	UINT16 port; | ||||
| #ifdef ZLIB | ||||
| 	double in_z_k, out_z_k; | ||||
| 	int in_p, out_p; | ||||
| @@ -736,9 +769,9 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient ) | ||||
| 	if (! txt) | ||||
| 		txt = "Reason unknown"; | ||||
|  | ||||
| 	port = ng_ipaddr_getport(&My_Connections[Idx].addr); | ||||
| 	Log(LOG_INFO, "Shutting down connection %d (%s) with %s:%d ...", Idx, | ||||
| 	    LogMsg ? LogMsg : FwdMsg, My_Connections[Idx].host, | ||||
| 	    ntohs(My_Connections[Idx].addr.sin_port)); | ||||
| 	    LogMsg ? LogMsg : FwdMsg, My_Connections[Idx].host, port); | ||||
|  | ||||
| 	/* Search client, if any */ | ||||
| 	c = Conn_GetClient( Idx ); | ||||
| @@ -778,7 +811,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient ) | ||||
| 		Log(LOG_CRIT, | ||||
| 		    "Error closing connection %d (socket %d) with %s:%d - %s! (ignored)", | ||||
| 		    Idx, My_Connections[Idx].sock, My_Connections[Idx].host, | ||||
| 		    ntohs(My_Connections[Idx].addr.sin_port), strerror(errno)); | ||||
| 		    port, strerror(errno)); | ||||
| 	} | ||||
|  | ||||
| 	/* Mark socket as invalid: */ | ||||
| @@ -807,8 +840,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient ) | ||||
| 		out_p = (int)(( out_k * 100 ) / out_z_k ); | ||||
| 		Log(LOG_INFO, | ||||
| 		    "Connection %d with %s:%d closed (in: %.1fk/%.1fk/%d%%, out: %.1fk/%.1fk/%d%%).", | ||||
| 		    Idx, My_Connections[Idx].host, | ||||
| 		    ntohs(My_Connections[Idx].addr.sin_port), | ||||
| 		    Idx, My_Connections[Idx].host, port, | ||||
| 		    in_k, in_z_k, in_p, out_k, out_z_k, out_p); | ||||
| 	} | ||||
| 	else | ||||
| @@ -816,8 +848,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient ) | ||||
| 	{ | ||||
| 		Log(LOG_INFO, | ||||
| 		    "Connection %d with %s:%d closed (in: %.1fk, out: %.1fk).", | ||||
| 		    Idx, My_Connections[Idx].host, | ||||
| 		    ntohs(My_Connections[Idx].addr.sin_port), | ||||
| 		    Idx, My_Connections[Idx].host, port, | ||||
| 		    in_k, out_k); | ||||
| 	} | ||||
|  | ||||
| @@ -940,6 +971,22 @@ Handle_Write( CONN_ID Idx ) | ||||
| } /* Handle_Write */ | ||||
|  | ||||
|  | ||||
| static int | ||||
| Count_Connections(ng_ipaddr_t *a) | ||||
| { | ||||
| 	int i, cnt; | ||||
|  | ||||
| 	cnt = 0; | ||||
| 	for (i = 0; i < Pool_Size; i++) { | ||||
| 		if (My_Connections[i].sock <= NONE) | ||||
| 			continue; | ||||
| 		if (ng_ipaddr_ipequal(&My_Connections[i].addr, a)) | ||||
| 			cnt++; | ||||
| 	} | ||||
| 	return cnt; | ||||
| } /* Count_Connections */ | ||||
|  | ||||
|  | ||||
| static int | ||||
| New_Connection( int Sock ) | ||||
| { | ||||
| @@ -949,14 +996,16 @@ New_Connection( int Sock ) | ||||
| #ifdef TCPWRAP | ||||
| 	struct request_info req; | ||||
| #endif | ||||
| 	struct sockaddr_in new_addr; | ||||
| 	ng_ipaddr_t new_addr; | ||||
| 	char ip_str[NG_INET_ADDRSTRLEN]; | ||||
| 	int new_sock, new_sock_len, new_Pool_Size; | ||||
| 	CLIENT *c; | ||||
| 	long cnt; | ||||
|  | ||||
| 	assert( Sock > NONE ); | ||||
| 	/* Connection auf Listen-Socket annehmen */ | ||||
| 	new_sock_len = (int)sizeof new_addr; | ||||
| 	new_sock_len = (int)sizeof(new_addr); | ||||
|  | ||||
| 	new_sock = accept(Sock, (struct sockaddr *)&new_addr, | ||||
| 			  (socklen_t *)&new_sock_len); | ||||
| 	if (new_sock < 0) { | ||||
| @@ -964,14 +1013,18 @@ New_Connection( int Sock ) | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (!ng_ipaddr_tostr_r(&new_addr, ip_str)) { | ||||
| 		Log(LOG_CRIT, "fd %d: Can't convert IP address!", new_sock); | ||||
| 		Simple_Message(new_sock, "ERROR :Internal Server Error"); | ||||
| 		close(new_sock); | ||||
| 	} | ||||
|  | ||||
| #ifdef TCPWRAP | ||||
| 	/* Validate socket using TCP Wrappers */ | ||||
| 	request_init( &req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock, RQ_CLIENT_SIN, &new_addr, NULL ); | ||||
| 	fromhost(&req); | ||||
| 	if( ! hosts_access( &req )) | ||||
| 	{ | ||||
| 		/* Access denied! */ | ||||
| 		Log( deny_severity, "Refused connection from %s (by TCP Wrappers)!", inet_ntoa( new_addr.sin_addr )); | ||||
| 	if (!hosts_access(&req)) { | ||||
| 		Log (deny_severity, "Refused connection from %s (by TCP Wrappers)!", ip_str); | ||||
| 		Simple_Message( new_sock, "ERROR :Connection refused" ); | ||||
| 		close( new_sock ); | ||||
| 		return -1; | ||||
| @@ -981,13 +1034,12 @@ New_Connection( int Sock ) | ||||
| 	/* Socket initialisieren */ | ||||
| 	if (!Init_Socket( new_sock )) | ||||
| 		return -1; | ||||
| 	 | ||||
|  | ||||
| 	/* Check IP-based connection limit */ | ||||
| 	cnt = Count_Connections( new_addr ); | ||||
| 	if(( Conf_MaxConnectionsIP > 0 ) && ( cnt >= Conf_MaxConnectionsIP )) | ||||
| 	{ | ||||
| 	cnt = Count_Connections(&new_addr); | ||||
| 	if ((Conf_MaxConnectionsIP > 0) && (cnt >= Conf_MaxConnectionsIP)) { | ||||
| 		/* Access denied, too many connections from this IP address! */ | ||||
| 		Log( LOG_ERR, "Refused connection from %s: too may connections (%ld) from this IP address!", inet_ntoa( new_addr.sin_addr ), cnt); | ||||
| 		Log( LOG_ERR, "Refused connection from %s: too may connections (%ld) from this IP address!", ip_str, cnt); | ||||
| 		Simple_Message( new_sock, "ERROR :Connection refused, too many connections from your IP address!" ); | ||||
| 		close( new_sock ); | ||||
| 		return -1; | ||||
| @@ -1029,7 +1081,7 @@ New_Connection( int Sock ) | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	c = Client_NewLocal( new_sock, inet_ntoa( new_addr.sin_addr ), CLIENT_UNKNOWN, false ); | ||||
| 	c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWN, false ); | ||||
| 	if( ! c ) { | ||||
| 		Log(LOG_ALERT, "Can't accept connection: can't create client structure!"); | ||||
| 		Simple_Message(new_sock, "ERROR :Internal error"); | ||||
| @@ -1043,13 +1095,12 @@ New_Connection( int Sock ) | ||||
| 	My_Connections[new_sock].client = c; | ||||
|  | ||||
| 	Log( LOG_INFO, "Accepted connection %d from %s:%d on socket %d.", new_sock, | ||||
| 			inet_ntoa( new_addr.sin_addr ), ntohs( new_addr.sin_port), Sock ); | ||||
| 			ip_str, ng_ipaddr_getport(&new_addr), Sock); | ||||
|  | ||||
| 	/* Hostnamen ermitteln */ | ||||
| 	strlcpy( My_Connections[new_sock].host, inet_ntoa( new_addr.sin_addr ), | ||||
| 						sizeof( My_Connections[new_sock].host )); | ||||
| 	strlcpy(My_Connections[new_sock].host, ip_str, sizeof(My_Connections[new_sock].host)); | ||||
|  | ||||
| 	Client_SetHostname( c, My_Connections[new_sock].host ); | ||||
| 	Client_SetHostname(c, My_Connections[new_sock].host); | ||||
|  | ||||
| 	if (!Conf_NoDNS) | ||||
| 		Resolve_Addr(&My_Connections[new_sock].res_stat, &new_addr, | ||||
| @@ -1107,10 +1158,10 @@ Read_Request( CONN_ID Idx ) | ||||
|  | ||||
| 	len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf)); | ||||
| 	if (len == 0) { | ||||
| 		Log(LOG_INFO, "%s:%d (%s) is closing the connection ...", | ||||
| 		    My_Connections[Idx].host, | ||||
| 		    ntohs(My_Connections[Idx].addr.sin_port), | ||||
| 		    inet_ntoa( My_Connections[Idx].addr.sin_addr)); | ||||
| 		Log(LOG_INFO, "%s:%u (%s) is closing the connection ...", | ||||
| 				My_Connections[Idx].host, | ||||
| 				(unsigned int) ng_ipaddr_getport(&My_Connections[Idx].addr), | ||||
| 				ng_ipaddr_tostr(&My_Connections[Idx].addr)); | ||||
| 		Conn_Close(Idx, | ||||
| 			   "Socket closed!", "Client closed connection", | ||||
| 			   false); | ||||
| @@ -1367,37 +1418,44 @@ Check_Servers( void ) | ||||
|  | ||||
|  | ||||
| static void | ||||
| New_Server( int Server , struct in_addr *dest) | ||||
| New_Server( int Server , ng_ipaddr_t *dest) | ||||
| { | ||||
| 	/* Establish new server link */ | ||||
| 	struct sockaddr_in local_addr; | ||||
| 	struct sockaddr_in new_addr; | ||||
| 	int res, new_sock; | ||||
| 	char ip_str[NG_INET_ADDRSTRLEN]; | ||||
| 	int af_dest, res, new_sock; | ||||
| 	CLIENT *c; | ||||
|  | ||||
| 	assert( Server > NONE ); | ||||
|  | ||||
| 	memset(&new_addr, 0, sizeof( new_addr )); | ||||
| 	new_addr.sin_family = AF_INET; | ||||
| 	new_addr.sin_addr = *dest; | ||||
| 	new_addr.sin_port = htons( Conf_Server[Server].port ); | ||||
| 	if (!ng_ipaddr_tostr_r(dest, ip_str)) { | ||||
| 		Log(LOG_WARNING, "New_Server: Could not convert IP to string"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	new_sock = socket( PF_INET, SOCK_STREAM, 0 ); | ||||
| 	if ( new_sock < 0 ) { | ||||
| 	Log( LOG_INFO, "Establishing connection to \"%s\", %s, port %d ... ", | ||||
| 			Conf_Server[Server].host, ip_str, Conf_Server[Server].port ); | ||||
|  | ||||
| 	af_dest = ng_ipaddr_af(dest); | ||||
| 	new_sock = socket(af_dest, SOCK_STREAM, 0); | ||||
| 	if (new_sock < 0) { | ||||
| 		Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno )); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if( ! Init_Socket( new_sock )) return; | ||||
| 	if (!Init_Socket(new_sock)) | ||||
| 		return; | ||||
|  | ||||
| 	/* if we fail to bind, just continue and let connect() pick a source address */ | ||||
| 	InitSinaddr(&local_addr, 0); | ||||
| 	local_addr.sin_addr = Conf_Server[Server].bind_addr; | ||||
| 	if (bind(new_sock, (struct sockaddr *)&local_addr, (socklen_t)sizeof(local_addr))) | ||||
| 		Log(LOG_WARNING, "Can't bind socket to %s: %s!", inet_ntoa(Conf_Server[Server].bind_addr), strerror( errno )); | ||||
|  | ||||
| 	res = connect(new_sock, (struct sockaddr *)&new_addr, | ||||
| 			(socklen_t)sizeof(new_addr)); | ||||
| 	/* is a bind address configured? */ | ||||
| 	res = ng_ipaddr_af(&Conf_Server[Server].bind_addr); | ||||
| 	/* if yes, bind now. If it fails, warn and let connect() pick a source address */ | ||||
| 	if (res && bind(new_sock, (struct sockaddr *) &Conf_Server[Server].bind_addr, | ||||
| 				ng_ipaddr_salen(&Conf_Server[Server].bind_addr))) | ||||
| 	{ | ||||
| 		ng_ipaddr_tostr_r(&Conf_Server[Server].bind_addr, ip_str); | ||||
| 		Log(LOG_WARNING, "Can't bind socket to %s: %s!", ip_str, strerror(errno)); | ||||
| 	} | ||||
| 	ng_ipaddr_setport(dest, Conf_Server[Server].port); | ||||
| 	res = connect(new_sock, (struct sockaddr *) dest, ng_ipaddr_salen(dest)); | ||||
| 	if(( res != 0 ) && ( errno != EINPROGRESS )) { | ||||
| 		Log( LOG_CRIT, "Can't connect socket: %s!", strerror( errno )); | ||||
| 		close( new_sock ); | ||||
| @@ -1418,8 +1476,9 @@ New_Server( int Server , struct in_addr *dest) | ||||
|  | ||||
| 	Init_Conn_Struct(new_sock); | ||||
|  | ||||
| 	c = Client_NewLocal( new_sock, inet_ntoa( new_addr.sin_addr ), CLIENT_UNKNOWNSERVER, false ); | ||||
| 	if( ! c ) { | ||||
| 	ng_ipaddr_tostr_r(dest, ip_str); | ||||
| 	c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWNSERVER, false); | ||||
| 	if (!c) { | ||||
| 		Log( LOG_ALERT, "Can't establish connection: can't create client structure!" ); | ||||
| 		close( new_sock ); | ||||
| 		return; | ||||
| @@ -1431,7 +1490,7 @@ New_Server( int Server , struct in_addr *dest) | ||||
| 	/* Register connection */ | ||||
| 	Conf_Server[Server].conn_id = new_sock; | ||||
| 	My_Connections[new_sock].sock = new_sock; | ||||
| 	My_Connections[new_sock].addr = new_addr; | ||||
| 	My_Connections[new_sock].addr = *dest; | ||||
| 	My_Connections[new_sock].client = c; | ||||
| 	strlcpy( My_Connections[new_sock].host, Conf_Server[Server].host, | ||||
| 				sizeof(My_Connections[new_sock].host )); | ||||
| @@ -1510,8 +1569,9 @@ cb_Connect_to_Server(int fd, UNUSED short events) | ||||
| 	/* Read result of resolver sub-process from pipe and start connection */ | ||||
| 	int i; | ||||
| 	size_t len; | ||||
| 	struct in_addr dest_addr; | ||||
| 	char readbuf[HOST_LEN + 1]; | ||||
| 	ng_ipaddr_t dest_addrs[4];	/* we can handle at most 3; but we read up to | ||||
| 					   four so we can log the 'more than we can handle' | ||||
| 					   condition */ | ||||
|  | ||||
| 	LogDebug("Resolver: Got forward lookup callback on fd %d, events %d", fd, events); | ||||
|  | ||||
| @@ -1528,23 +1588,28 @@ cb_Connect_to_Server(int fd, UNUSED short events) | ||||
| 	} | ||||
|  | ||||
| 	/* Read result from pipe */ | ||||
| 	len = Resolve_Read(&Conf_Server[i].res_stat, readbuf, sizeof(readbuf)-1); | ||||
| 	len = Resolve_Read(&Conf_Server[i].res_stat, dest_addrs, sizeof(dest_addrs)); | ||||
| 	if (len == 0) | ||||
| 		return; | ||||
|  | ||||
| 	readbuf[len] = '\0'; | ||||
| 	LogDebug("Got result from resolver: \"%s\" (%u bytes read).", readbuf, len); | ||||
| 	assert((len % sizeof(ng_ipaddr_t)) == 0); | ||||
|  | ||||
| 	if (!ngt_IPStrToBin(readbuf, &dest_addr)) { | ||||
| 		Log(LOG_ERR, "Can't connect to \"%s\": can't convert ip address %s!", | ||||
| 						Conf_Server[i].host, readbuf); | ||||
| 		return; | ||||
| 	LogDebug("Got result from resolver: %u structs (%u bytes).", len/sizeof(ng_ipaddr_t), len); | ||||
|  | ||||
| 	memset(&Conf_Server[i].dst_addr, 0, sizeof(&Conf_Server[i].dst_addr)); | ||||
| 	if (len > sizeof(ng_ipaddr_t)) { | ||||
| 		/* more than one address for this hostname, remember them | ||||
| 		 * in case first address is unreachable/not available */ | ||||
| 		len -= sizeof(ng_ipaddr_t); | ||||
| 		if (len > sizeof(&Conf_Server[i].dst_addr)) { | ||||
| 			len = sizeof(&Conf_Server[i].dst_addr); | ||||
| 			Log(LOG_NOTICE, "Notice: Resolver returned more IP Addresses for host than we can handle," | ||||
| 					" additional addresses dropped"); | ||||
| 		} | ||||
| 		memcpy(&Conf_Server[i].dst_addr, &dest_addrs[1], len); | ||||
| 	} | ||||
|  | ||||
| 	Log( LOG_INFO, "Establishing connection to \"%s\", %s, port %d ... ", | ||||
| 			Conf_Server[i].host, readbuf, Conf_Server[i].port ); | ||||
| 	/* connect() */ | ||||
| 	New_Server(i, &dest_addr); | ||||
| 	New_Server(i, dest_addrs); | ||||
| } /* cb_Read_Forward_Lookup */ | ||||
|  | ||||
|  | ||||
| @@ -1643,19 +1708,6 @@ Simple_Message( int Sock, const char *Msg ) | ||||
| } /* Simple_Error */ | ||||
|  | ||||
|  | ||||
| static int | ||||
| Count_Connections( struct sockaddr_in addr_in ) | ||||
| { | ||||
| 	int i, cnt; | ||||
| 	 | ||||
| 	cnt = 0; | ||||
| 	for( i = 0; i < Pool_Size; i++ ) { | ||||
| 		if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].addr.sin_addr.s_addr == addr_in.sin_addr.s_addr )) cnt++; | ||||
| 	} | ||||
| 	return cnt; | ||||
| } /* Count_Connections */ | ||||
|  | ||||
|  | ||||
| GLOBAL CLIENT * | ||||
| Conn_GetClient( CONN_ID Idx )  | ||||
| { | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
|  * (at your option) any later version. | ||||
|  * Please read the file COPYING, README and AUTHORS for more information. | ||||
|  * | ||||
|  * $Id: conn.h,v 1.45 2007/10/04 15:03:56 alex Exp $ | ||||
|  * $Id: conn.h,v 1.46 2008/02/26 22:04:17 fw Exp $ | ||||
|  * | ||||
|  * Connection management (header) | ||||
|  */ | ||||
| @@ -38,6 +38,8 @@ typedef int CONN_ID; | ||||
| #include "defines.h" | ||||
| #include "resolve.h" | ||||
| #include "array.h" | ||||
| #include "tool.h" | ||||
| #include "ng_ipaddr.h" | ||||
|  | ||||
| #ifdef ZLIB | ||||
| #include <zlib.h> | ||||
| @@ -54,7 +56,7 @@ typedef struct _ZipData | ||||
| typedef struct _Connection | ||||
| { | ||||
| 	int sock;			/* Socket handle */ | ||||
| 	struct sockaddr_in addr;	/* Client address */ | ||||
| 	ng_ipaddr_t addr;		/* Client address */ | ||||
| 	RES_STAT res_stat;		/* Status of resolver process */ | ||||
| 	char host[HOST_LEN];		/* Hostname */ | ||||
| 	array rbuf;			/* Read buffer */ | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
|  | ||||
| #include "portab.h" | ||||
|  | ||||
| static char UNUSED id[] = "$Id: ngircd.c,v 1.117 2007/11/21 12:16:36 alex Exp $"; | ||||
| static char UNUSED id[] = "$Id: ngircd.c,v 1.118 2008/02/26 22:04:17 fw Exp $"; | ||||
|  | ||||
| /** | ||||
|  * @file | ||||
| @@ -397,7 +397,12 @@ Fill_Version( void ) | ||||
|  | ||||
| 	strlcat( NGIRCd_VersionAddition, "IRCPLUS", sizeof NGIRCd_VersionAddition ); | ||||
| #endif | ||||
| #ifdef WANT_IPV6 | ||||
| 	if (NGIRCd_VersionAddition[0]) | ||||
| 		strlcat(NGIRCd_VersionAddition, "+", sizeof(NGIRCd_VersionAddition)); | ||||
|  | ||||
| 	strlcat(NGIRCd_VersionAddition, "IPv6", sizeof(NGIRCd_VersionAddition)); | ||||
| #endif | ||||
| 	if( NGIRCd_VersionAddition[0] ) | ||||
| 		strlcat( NGIRCd_VersionAddition, "-", sizeof( NGIRCd_VersionAddition )); | ||||
|  | ||||
|   | ||||
| @@ -14,7 +14,7 @@ | ||||
|  | ||||
| #include "portab.h" | ||||
|  | ||||
| static char UNUSED id[] = "$Id: resolve.c,v 1.28 2008/01/02 11:03:29 fw Exp $"; | ||||
| static char UNUSED id[] = "$Id: resolve.c,v 1.29 2008/02/26 22:04:17 fw Exp $"; | ||||
|  | ||||
| #include "imp.h" | ||||
| #include <assert.h> | ||||
| @@ -35,20 +35,16 @@ static char UNUSED id[] = "$Id: resolve.c,v 1.28 2008/01/02 11:03:29 fw Exp $"; | ||||
| #include "conn.h" | ||||
| #include "defines.h" | ||||
| #include "log.h" | ||||
| #include "tool.h" | ||||
|  | ||||
| #include "exp.h" | ||||
| #include "resolve.h" | ||||
| #include "io.h" | ||||
|  | ||||
|  | ||||
| static void Do_ResolveAddr PARAMS(( struct sockaddr_in *Addr, int Sock, int w_fd )); | ||||
| static void Do_ResolveAddr PARAMS(( const ng_ipaddr_t *Addr, int Sock, int w_fd )); | ||||
| static void Do_ResolveName PARAMS(( const char *Host, int w_fd )); | ||||
| static bool register_callback PARAMS((RES_STAT *s, void (*cbfunc)(int, short))); | ||||
|  | ||||
| #ifdef h_errno | ||||
| static char *Get_Error PARAMS(( int H_Error )); | ||||
| #endif | ||||
|  | ||||
| static pid_t | ||||
| Resolver_fork(int *pipefds) | ||||
| @@ -82,7 +78,7 @@ Resolver_fork(int *pipefds) | ||||
|  * Resolve IP (asynchronous!). | ||||
|  */ | ||||
| GLOBAL bool | ||||
| Resolve_Addr(RES_STAT * s, struct sockaddr_in *Addr, int identsock, | ||||
| Resolve_Addr(RES_STAT * s, const ng_ipaddr_t *Addr, int identsock, | ||||
| 	     void (*cbfunc) (int, short)) | ||||
| { | ||||
| 	int pipefd[2]; | ||||
| @@ -92,9 +88,8 @@ Resolve_Addr(RES_STAT * s, struct sockaddr_in *Addr, int identsock, | ||||
|  | ||||
| 	pid = Resolver_fork(pipefd); | ||||
| 	if (pid > 0) { | ||||
| #ifdef DEBUG | ||||
| 		Log( LOG_DEBUG, "Resolver for %s created (PID %d).", inet_ntoa( Addr->sin_addr ), pid ); | ||||
| #endif | ||||
| 		Log(LOG_DEBUG, "Resolver for %s created (PID %d).", ng_ipaddr_tostr(Addr), pid); | ||||
|  | ||||
| 		s->pid = pid; | ||||
| 		s->resolver_fd = pipefd[0]; | ||||
| 		return register_callback(s, cbfunc); | ||||
| @@ -147,92 +142,294 @@ Resolve_Init(RES_STAT *s) | ||||
| } | ||||
|  | ||||
|  | ||||
| #ifndef WANT_IPV6 | ||||
| #ifdef h_errno | ||||
| static char * | ||||
| Get_Error( int H_Error ) | ||||
| { | ||||
| 	/* Get error message for H_Error */ | ||||
| 	switch( H_Error ) { | ||||
| 	case HOST_NOT_FOUND: | ||||
| 		return "host not found"; | ||||
| 	case NO_DATA: | ||||
| 		return "name valid but no IP address defined"; | ||||
| 	case NO_RECOVERY: | ||||
| 		return "name server error"; | ||||
| 	case TRY_AGAIN: | ||||
| 		return "name server temporary not available"; | ||||
| 	} | ||||
| 	return "unknown error"; | ||||
| } | ||||
| #endif /* h_errno */ | ||||
| #endif /* WANT_IPV6 */ | ||||
|  | ||||
|  | ||||
| /* Do "IDENT" (aka "AUTH") lookup and append result to resolved_addr array */ | ||||
| static void | ||||
| Do_ResolveAddr( struct sockaddr_in *Addr, int identsock, int w_fd ) | ||||
| Do_IdentQuery(int identsock, array *resolved_addr) | ||||
| { | ||||
| #ifdef IDENTAUTH | ||||
| 	char *res; | ||||
|  | ||||
| 	assert(identsock >= 0); | ||||
|  | ||||
| #ifdef DEBUG | ||||
| 	Log_Resolver(LOG_DEBUG, "Doing IDENT lookup on socket %d ...", identsock); | ||||
| #endif | ||||
| 	if (identsock < 0) | ||||
| 		return; | ||||
| 	res = ident_id( identsock, 10 ); | ||||
| #ifdef DEBUG | ||||
| 	Log_Resolver(LOG_DEBUG, "Ok, IDENT lookup on socket %d done: \"%s\"", | ||||
| 						identsock, res ? res : "(NULL)" ); | ||||
| #endif | ||||
| 	if (!res) /* no result */ | ||||
| 		return; | ||||
| 	if (!array_cats(resolved_addr, res)) | ||||
| 		Log_Resolver(LOG_WARNING, "Resolver: Cannot copy IDENT result: %s!", strerror(errno)); | ||||
|  | ||||
| 	free(res); | ||||
| #else | ||||
| 	(void) identsock; | ||||
| 	(void) resolved_addr; | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * perform reverse DNS lookup and put result string into resbuf. | ||||
|  * If no hostname could be obtained, this function stores the string representation of | ||||
|  * the IP address in resbuf and returns false. | ||||
|  * @param IpAddr ip address to resolve | ||||
|  * @param resbuf result buffer to store DNS name/string representation of ip address | ||||
|  * @reslen size of result buffer (must be >= NGT_INET_ADDRSTRLEN) | ||||
|  * @return true if reverse lookup successful, false otherwise | ||||
|  */ | ||||
| static bool | ||||
| ReverseLookup(const ng_ipaddr_t *IpAddr, char *resbuf, size_t reslen) | ||||
| { | ||||
| 	char tmp_ip_str[NG_INET_ADDRSTRLEN]; | ||||
| 	const char *errmsg; | ||||
| #ifdef HAVE_GETNAMEINFO | ||||
| 	static const char funcname[]="getnameinfo"; | ||||
| 	int res; | ||||
|  | ||||
| 	*resbuf = 0; | ||||
|  | ||||
| 	res = getnameinfo((struct sockaddr *) IpAddr, ng_ipaddr_salen(IpAddr), | ||||
| 				resbuf, reslen, NULL, 0, NI_NAMEREQD); | ||||
| 	if (res == 0) | ||||
| 		return true; | ||||
|  | ||||
| 	if (res == EAI_SYSTEM) | ||||
| 		errmsg = strerror(errno); | ||||
| 	else | ||||
| 		errmsg = gai_strerror(res); | ||||
| #else | ||||
| 	const struct sockaddr_in *Addr = (const struct sockaddr_in *) IpAddr; | ||||
| 	struct hostent *h; | ||||
| 	static const char funcname[]="gethostbyaddr"; | ||||
|  | ||||
| 	h = gethostbyaddr((char *)&Addr->sin_addr, sizeof(Addr->sin_addr), AF_INET); | ||||
| 	if (h) { | ||||
| 		if (strlcpy(resbuf, h->h_name, reslen) < reslen) | ||||
| 			return true; | ||||
| 		errmsg = "hostname too long"; | ||||
| 	} else { | ||||
| # ifdef h_errno | ||||
| 		errmsg = Get_Error(h_errno); | ||||
| # else | ||||
| 		errmsg = "unknown error"; | ||||
| # endif /* h_errno */ | ||||
| 	} | ||||
| #endif	/* HAVE_GETNAMEINFO */ | ||||
|  | ||||
| 	assert(errmsg); | ||||
| 	assert(reslen >= NG_INET_ADDRSTRLEN); | ||||
| 	ng_ipaddr_tostr_r(IpAddr, tmp_ip_str); | ||||
|  | ||||
| 	Log_Resolver(LOG_WARNING, "%s: Can't resolve address \"%s\": %s", | ||||
| 				funcname, tmp_ip_str, errmsg); | ||||
| 	strlcpy(resbuf, tmp_ip_str, reslen); | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * perform DNS lookup of given host name and fill IpAddr with a list of | ||||
|  * ip addresses associated with that name. | ||||
|  * ip addresses found are stored in the "array *IpAddr" argument (type ng_ipaddr_t) | ||||
|  * @param hostname The domain name to look up. | ||||
|  * @param IpAddr pointer to empty and initialized array to store results | ||||
|  * @return true if lookup successful, false if domain name not found | ||||
|  */ | ||||
| static bool | ||||
| ForwardLookup(const char *hostname, array *IpAddr) | ||||
| { | ||||
| 	ng_ipaddr_t addr; | ||||
| #ifdef HAVE_GETADDRINFO | ||||
| 	int res; | ||||
| 	struct addrinfo *a, *ai_results; | ||||
| 	static const struct addrinfo hints = { | ||||
| #ifndef WANT_IPV6 | ||||
| 		.ai_family = AF_INET, | ||||
| #endif | ||||
| #ifdef AI_ADDRCONFIG	/* glibc has this, but not e.g. netbsd 4.0 */ | ||||
| 		.ai_flags = AI_ADDRCONFIG, | ||||
| #endif | ||||
| 		.ai_socktype = SOCK_STREAM, | ||||
| 		.ai_protocol = IPPROTO_TCP | ||||
| 	}; | ||||
| 	res = getaddrinfo(hostname, NULL, &hints, &ai_results); | ||||
| 	switch (res) { | ||||
| 	case 0:	break; | ||||
| 	case EAI_SYSTEM: | ||||
| 		Log_Resolver(LOG_WARNING, "Can't resolve \"%s\": %s", hostname, strerror(errno)); | ||||
| 		return false; | ||||
| 	default: | ||||
| 		Log_Resolver(LOG_WARNING, "Can't resolve \"%s\": %s", hostname, gai_strerror(res)); | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	for (a = ai_results; a != NULL; a = a->ai_next) { | ||||
| 		assert(a->ai_addrlen <= sizeof(addr)); | ||||
|  | ||||
| 		if (a->ai_addrlen > sizeof(addr)) | ||||
| 			continue; | ||||
|  | ||||
| 		memcpy(&addr, a->ai_addr, a->ai_addrlen); | ||||
|  | ||||
| 		if (!array_catb(IpAddr, (char *)&addr, sizeof(addr))) | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| 	freeaddrinfo(ai_results); | ||||
| 	return a == NULL; | ||||
| #else | ||||
| 	struct hostent *h = gethostbyname(hostname); | ||||
|  | ||||
| 	if (!h) { | ||||
| #ifdef h_errno | ||||
| 		Log_Resolver(LOG_WARNING, "Can't resolve \"%s\": %s", hostname, Get_Error(h_errno)); | ||||
| #else | ||||
| 		Log_Resolver(LOG_WARNING, "Can't resolve \"%s\"", hostname); | ||||
| #endif | ||||
| 		return false; | ||||
| 	} | ||||
| 	memset(&addr, 0, sizeof(addr)); | ||||
|  | ||||
| 	addr.sin4.sin_family = AF_INET; | ||||
| 	memcpy(&addr.sin4.sin_addr, h->h_addr, sizeof(struct in_addr)); | ||||
|  | ||||
| 	return array_copyb(IpAddr, (char *)&addr, sizeof(addr)); | ||||
| #endif /* HAVE_GETADDRINFO */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static bool | ||||
| Addr_in_list(const array *resolved_addr, const ng_ipaddr_t *Addr) | ||||
| { | ||||
| 	char tmp_ip_str[NG_INET_ADDRSTRLEN]; | ||||
| 	const ng_ipaddr_t *tmpAddrs = array_start(resolved_addr); | ||||
| 	size_t len = array_length(resolved_addr, sizeof(*tmpAddrs)); | ||||
|  | ||||
| 	assert(len > 0); | ||||
| 	assert(tmpAddrs); | ||||
|  | ||||
| 	while (len > 0) { | ||||
| 		if (ng_ipaddr_ipequal(Addr, tmpAddrs)) | ||||
| 			return true; | ||||
| 		tmpAddrs++; | ||||
| 		len--; | ||||
| 	} | ||||
| 	/* failed; print list of addresses */ | ||||
| 	ng_ipaddr_tostr_r(Addr, tmp_ip_str); | ||||
| 	len = array_length(resolved_addr, sizeof(*tmpAddrs)); | ||||
| 	tmpAddrs = array_start(resolved_addr); | ||||
|  | ||||
| 	while (len > 0) { | ||||
| 		Log_Resolver(LOG_WARNING, "Address mismatch: %s != %s", | ||||
| 			tmp_ip_str, ng_ipaddr_tostr(tmpAddrs)); | ||||
| 		tmpAddrs++; | ||||
| 		len--; | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void | ||||
| Log_Forgery_NoIP(const char *ip, const char *host) | ||||
| { | ||||
| 	Log_Resolver(LOG_WARNING, "Possible forgery: %s resolved to %s " | ||||
| 		"(which has no ip address)", ip, host); | ||||
| } | ||||
|  | ||||
| static void | ||||
| Log_Forgery_WrongIP(const char *ip, const char *host) | ||||
| { | ||||
| 	Log_Resolver(LOG_WARNING,"Possible forgery: %s resolved to %s " | ||||
| 		"(which points to different address)", ip, host); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void | ||||
| ArrayWrite(int fd, const array *a) | ||||
| { | ||||
| 	size_t len = array_bytes(a); | ||||
| 	const char *data = array_start(a); | ||||
|  | ||||
| 	assert(data); | ||||
|  | ||||
| 	if( (size_t)write(fd, data, len) != len ) | ||||
| 		Log_Resolver( LOG_CRIT, "Resolver: Can't write to parent: %s!", | ||||
| 							strerror(errno)); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void | ||||
| Do_ResolveAddr(const ng_ipaddr_t *Addr, int identsock, int w_fd) | ||||
| { | ||||
| 	/* Resolver sub-process: resolve IP address and write result into | ||||
| 	 * pipe to parent. */ | ||||
|  | ||||
| 	char hostname[CLIENT_HOST_LEN]; | ||||
| 	char ipstr[CLIENT_HOST_LEN]; | ||||
| 	struct hostent *h; | ||||
| 	char tmp_ip_str[NG_INET_ADDRSTRLEN]; | ||||
| 	size_t len; | ||||
| 	struct in_addr *addr; | ||||
| 	char *ntoaptr; | ||||
| 	array resolved_addr; | ||||
| #ifdef IDENTAUTH | ||||
| 	char *res; | ||||
| #endif | ||||
|  | ||||
| 	array_init(&resolved_addr); | ||||
| 	/* Resolve IP address */ | ||||
| 	ng_ipaddr_tostr_r(Addr, tmp_ip_str); | ||||
| #ifdef DEBUG | ||||
| 	Log_Resolver( LOG_DEBUG, "Now resolving %s ...", inet_ntoa( Addr->sin_addr )); | ||||
| 	Log_Resolver(LOG_DEBUG, "Now resolving %s ...", tmp_ip_str); | ||||
| #endif | ||||
| 	h = gethostbyaddr( (char *)&Addr->sin_addr, sizeof( Addr->sin_addr ), AF_INET ); | ||||
| 	if (!h || strlen(h->h_name) >= sizeof(hostname)) { | ||||
| #ifdef h_errno | ||||
| 		Log_Resolver( LOG_WARNING, "Can't resolve address \"%s\": %s!", inet_ntoa( Addr->sin_addr ), Get_Error( h_errno )); | ||||
| #else | ||||
| 		Log_Resolver( LOG_WARNING, "Can't resolve address \"%s\"!", inet_ntoa( Addr->sin_addr )); | ||||
| #endif	 | ||||
| 		strlcpy( hostname, inet_ntoa( Addr->sin_addr ), sizeof( hostname )); | ||||
| 	} else { | ||||
|  		strlcpy( hostname, h->h_name, sizeof( hostname )); | ||||
| 	if (!ReverseLookup(Addr, hostname, sizeof(hostname))) | ||||
| 		goto dns_done; | ||||
|  | ||||
| 		h = gethostbyname( hostname ); | ||||
| 		if ( h ) { | ||||
| 			if (memcmp(h->h_addr, &Addr->sin_addr, sizeof (struct in_addr))) { | ||||
| 				addr = (struct in_addr*) h->h_addr; | ||||
| 				strlcpy(ipstr, inet_ntoa(*addr), sizeof ipstr);  | ||||
| 				ntoaptr = inet_ntoa( Addr->sin_addr ); | ||||
| 				Log(LOG_WARNING,"Possible forgery: %s resolved to %s (which is at ip %s!)", | ||||
| 										ntoaptr, hostname, ipstr); | ||||
| 				strlcpy( hostname, ntoaptr, sizeof hostname); | ||||
| 			} | ||||
| 		} else { | ||||
| 			ntoaptr = inet_ntoa( Addr->sin_addr ); | ||||
| 			Log(LOG_WARNING, "Possible forgery: %s resolved to %s (which has no ip address)", | ||||
| 											ntoaptr, hostname); | ||||
| 			strlcpy( hostname, ntoaptr, sizeof hostname); | ||||
| 	if (ForwardLookup(hostname, &resolved_addr)) { | ||||
| 		if (!Addr_in_list(&resolved_addr, Addr)) { | ||||
| 			Log_Forgery_WrongIP(tmp_ip_str, hostname); | ||||
| 			strlcpy(hostname, tmp_ip_str, sizeof(hostname)); | ||||
| 		} | ||||
| 	} else { | ||||
| 		Log_Forgery_NoIP(tmp_ip_str, hostname); | ||||
| 		strlcpy(hostname, tmp_ip_str, sizeof(hostname)); | ||||
| 	} | ||||
| 	Log_Resolver( LOG_DEBUG, "Ok, translated %s to \"%s\".", inet_ntoa( Addr->sin_addr ), hostname ); | ||||
|  | ||||
| 	len = strlen( hostname );  | ||||
| 	hostname[len] = '\n'; len++; | ||||
| 	if (!array_copyb(&resolved_addr, hostname, len )) { | ||||
| 		Log_Resolver( LOG_CRIT, "Resolver: Can't copy resolved name: %s!", strerror( errno )); | ||||
| 		close( w_fd ); | ||||
| #ifdef DEBUG | ||||
| 	Log_Resolver(LOG_DEBUG, "Ok, translated %s to \"%s\".", tmp_ip_str, hostname); | ||||
| #endif | ||||
|  dns_done: | ||||
| 	len = strlen(hostname); | ||||
| 	hostname[len] = '\n'; | ||||
| 	if (!array_copyb(&resolved_addr, hostname, ++len)) { | ||||
| 		Log_Resolver(LOG_CRIT, "Resolver: Can't copy resolved name: %s!", strerror(errno)); | ||||
| 		array_free(&resolved_addr); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| #ifdef IDENTAUTH | ||||
| 	assert(identsock >= 0); | ||||
| 	if (identsock >= 0) { | ||||
| 		/* Do "IDENT" (aka "AUTH") lookup and append result to resolved_addr array */ | ||||
| #ifdef DEBUG | ||||
| 		Log_Resolver( LOG_DEBUG, "Doing IDENT lookup on socket %d ...", identsock ); | ||||
| #endif | ||||
| 		res = ident_id( identsock, 10 ); | ||||
| #ifdef DEBUG | ||||
| 		Log_Resolver(LOG_DEBUG, "Ok, IDENT lookup on socket %d done: \"%s\"", | ||||
| 							identsock, res ? res : "(NULL)" ); | ||||
| #endif | ||||
| 		if (res && !array_cats(&resolved_addr, res)) { | ||||
| 			Log_Resolver(LOG_WARNING, "Resolver: Cannot copy IDENT result: %s!", strerror(errno)); | ||||
| 			/* omit ident and return hostname only */  | ||||
| 		} | ||||
| 	Do_IdentQuery(identsock, &resolved_addr); | ||||
|  | ||||
| 		if (res) free(res); | ||||
| 	} | ||||
| #else | ||||
| 	(void)identsock; | ||||
| #endif | ||||
| 	len = array_bytes(&resolved_addr); | ||||
| 	if( (size_t)write( w_fd, array_start(&resolved_addr), len) != len ) | ||||
| 		Log_Resolver( LOG_CRIT, "Resolver: Can't write result to parent: %s!", strerror( errno )); | ||||
| 	ArrayWrite(w_fd, &resolved_addr); | ||||
|  | ||||
| 	close(w_fd); | ||||
| 	array_free(&resolved_addr); | ||||
| } /* Do_ResolveAddr */ | ||||
|  | ||||
| @@ -242,65 +439,36 @@ Do_ResolveName( const char *Host, int w_fd ) | ||||
| { | ||||
| 	/* Resolver sub-process: resolve name and write result into pipe | ||||
| 	 * to parent. */ | ||||
|  | ||||
| 	char ip[16]; | ||||
| 	struct hostent *h; | ||||
| 	struct in_addr *addr; | ||||
| 	array IpAddrs; | ||||
| #ifdef DEBUG | ||||
| 	ng_ipaddr_t *addr; | ||||
| 	size_t len; | ||||
|  | ||||
| 	Log_Resolver( LOG_DEBUG, "Now resolving \"%s\" ...", Host ); | ||||
|  | ||||
| 	/* Resolve hostname */ | ||||
| 	h = gethostbyname( Host ); | ||||
| 	if( h ) { | ||||
| 		addr = (struct in_addr *)h->h_addr; | ||||
| 		strlcpy( ip, inet_ntoa( *addr ), sizeof( ip )); | ||||
| 	} else { | ||||
| #ifdef h_errno | ||||
| 		Log_Resolver( LOG_WARNING, "Can't resolve \"%s\": %s!", Host, Get_Error( h_errno )); | ||||
| #else | ||||
| 		Log_Resolver( LOG_WARNING, "Can't resolve \"%s\"!", Host ); | ||||
| #endif | ||||
| 	Log_Resolver(LOG_DEBUG, "Now resolving \"%s\" ...", Host); | ||||
|  | ||||
| 	array_init(&IpAddrs); | ||||
| 	/* Resolve hostname */ | ||||
| 	if (!ForwardLookup(Host, &IpAddrs)) { | ||||
| 		close(w_fd); | ||||
| 		return; | ||||
| 	} | ||||
| #ifdef DEBUG | ||||
| 	Log_Resolver( LOG_DEBUG, "Ok, translated \"%s\" to %s.", Host, ip ); | ||||
| 	len = array_length(&IpAddrs, sizeof(*addr)); | ||||
| 	assert(len > 0); | ||||
| 	addr = array_start(&IpAddrs); | ||||
| 	assert(addr); | ||||
| 	for (; len > 0; --len,addr++) { | ||||
| 		Log_Resolver(LOG_DEBUG, "translated \"%s\" to %s.", | ||||
| 					Host, ng_ipaddr_tostr(addr)); | ||||
| 	} | ||||
| #endif | ||||
| 	/* Write result into pipe to parent */ | ||||
| 	len = strlen( ip ); | ||||
| 	if ((size_t)write( w_fd, ip, len ) != len) { | ||||
| 		Log_Resolver( LOG_CRIT, "Resolver: Can't write to parent: %s!", strerror( errno )); | ||||
| 		close( w_fd ); | ||||
| 	} | ||||
| 	ArrayWrite(w_fd, &IpAddrs); | ||||
|  | ||||
| 	array_free(&IpAddrs); | ||||
| } /* Do_ResolveName */ | ||||
|  | ||||
|  | ||||
| #ifdef h_errno | ||||
|  | ||||
| static char * | ||||
| Get_Error( int H_Error ) | ||||
| { | ||||
| 	/* Get error message for H_Error */ | ||||
|  | ||||
| 	switch( H_Error ) | ||||
| 	{ | ||||
| 		case HOST_NOT_FOUND: | ||||
| 			return "host not found"; | ||||
| 		case NO_DATA: | ||||
| 			return "name valid but no IP address defined"; | ||||
| 		case NO_RECOVERY: | ||||
| 			return "name server error"; | ||||
| 		case TRY_AGAIN: | ||||
| 			return "name server temporary not available"; | ||||
| 		default: | ||||
| 			return "unknown error"; | ||||
| 	} | ||||
| } /* Get_Error */ | ||||
|  | ||||
| #endif | ||||
|  | ||||
|  | ||||
| static bool | ||||
| register_callback( RES_STAT *s, void (*cbfunc)(int, short)) | ||||
| { | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
|  * (at your option) any later version. | ||||
|  * Please read the file COPYING, README and AUTHORS for more information. | ||||
|  * | ||||
|  * $Id: resolve.h,v 1.13 2006/05/10 21:24:02 alex Exp $ | ||||
|  * $Id: resolve.h,v 1.14 2008/02/26 22:04:17 fw Exp $ | ||||
|  * | ||||
|  * Asynchronous resolver (header) | ||||
|  */ | ||||
| @@ -18,6 +18,8 @@ | ||||
| #define __resolve_h__ | ||||
|  | ||||
| #include "array.h" | ||||
| #include "tool.h" | ||||
| #include "ng_ipaddr.h" | ||||
| #include <netinet/in.h> | ||||
|  | ||||
| /* This struct must not be accessed directly */ | ||||
| @@ -30,7 +32,7 @@ typedef struct _Res_Stat { | ||||
| #define Resolve_Getfd(x)		((x)->resolver_fd) | ||||
| #define Resolve_INPROGRESS(x)		((x)->resolver_fd >= 0) | ||||
|  | ||||
| GLOBAL bool Resolve_Addr PARAMS(( RES_STAT *s, struct sockaddr_in *Addr, int identsock, void (*cbfunc)(int, short))); | ||||
| GLOBAL bool Resolve_Addr PARAMS(( RES_STAT *s, const ng_ipaddr_t *Addr, int identsock, void (*cbfunc)(int, short))); | ||||
| GLOBAL bool Resolve_Name PARAMS(( RES_STAT *s, const char *Host, void (*cbfunc)(int, short) )); | ||||
| GLOBAL size_t Resolve_Read PARAMS(( RES_STAT *s, void *buf, size_t buflen)); | ||||
| GLOBAL void Resolve_Init PARAMS(( RES_STAT *s)); | ||||
|   | ||||
| @@ -14,7 +14,7 @@ | ||||
|  | ||||
| #include "portab.h" | ||||
|  | ||||
| static char UNUSED id[] = "$Id: tool.c,v 1.8 2007/11/25 18:42:38 fw Exp $"; | ||||
| static char UNUSED id[] = "$Id: tool.c,v 1.9 2008/02/26 22:04:18 fw Exp $"; | ||||
|  | ||||
| #include "imp.h" | ||||
| #include <assert.h> | ||||
| @@ -106,23 +106,4 @@ ngt_TrimLastChr( char *String, const char Chr) | ||||
| 	if( String[len] == Chr ) String[len] = '\0'; | ||||
| } /* ngt_TrimLastChr */ | ||||
|  | ||||
|  | ||||
| GLOBAL bool | ||||
| ngt_IPStrToBin(const char *ip_str, struct in_addr *inaddr) | ||||
| { | ||||
| 	/* AF is always AF_INET for now */ | ||||
| #ifdef HAVE_INET_ATON | ||||
| 	if (inet_aton(ip_str, inaddr) == 0) | ||||
| 		return false; | ||||
| #else | ||||
| 	inaddr->s_addr = inet_addr(ip_str); | ||||
| 	if (inaddr->s_addr == (unsigned)-1) | ||||
| 		return false; | ||||
| #endif | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| /* -eof- */ | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
|  * (at your option) any later version. | ||||
|  * Please read the file COPYING, README and AUTHORS for more information. | ||||
|  * | ||||
|  * $Id: tool.h,v 1.5 2007/11/25 18:42:38 fw Exp $ | ||||
|  * $Id: tool.h,v 1.6 2008/02/26 22:04:18 fw Exp $ | ||||
|  * | ||||
|  * Tool functions (Header) | ||||
|  */ | ||||
| @@ -29,8 +29,6 @@ GLOBAL void ngt_TrimLastChr PARAMS((char *String, const char Chr )); | ||||
| GLOBAL void ngt_TrimStr PARAMS((char *String )); | ||||
|  | ||||
| GLOBAL char *ngt_LowerStr PARAMS((char *String )); | ||||
|  | ||||
| GLOBAL bool ngt_IPStrToBin PARAMS((const char *ip_str, struct in_addr *inaddr)); | ||||
| #endif | ||||
|  | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Florian Westphal
					Florian Westphal