diff options
Diffstat (limited to 'lib/proxy.c')
| -rw-r--r-- | lib/proxy.c | 187 | 
1 files changed, 104 insertions, 83 deletions
| diff --git a/lib/proxy.c b/lib/proxy.c index e52837fe..e7d35351 100644 --- a/lib/proxy.c +++ b/lib/proxy.c @@ -48,6 +48,11 @@ int proxytype = PROXY_NONE;  char proxyuser[128] = "";  char proxypass[128] = ""; +/* Some systems don't know this one. It's not essential, so set it to 0 then. */ +#ifndef AI_NUMERICSERV +#define AI_NUMERICSERV 0 +#endif +  struct PHB {  	b_event_handler func, proxy_func;  	gpointer data, proxy_data; @@ -55,28 +60,10 @@ struct PHB {  	int port;  	int fd;  	gint inpa; +	struct addrinfo *gai, *gai_cur;  }; - - -static struct sockaddr_in *gaim_gethostbyname(const char *host, int port) -{ -	static struct sockaddr_in sin; - -	if (!inet_aton(host, &sin.sin_addr)) { -		struct hostent *hp; -		if (!(hp = gethostbyname(host))) { -			return NULL; -		} -		memset(&sin, 0, sizeof(struct sockaddr_in)); -		memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); -		sin.sin_family = hp->h_addrtype; -	} else -		sin.sin_family = AF_INET; -	sin.sin_port = htons(port); - -	return &sin; -} +static int proxy_connect_none(const char *host, unsigned short port_, struct PHB *phb);  static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition cond)  { @@ -86,71 +73,105 @@ static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition  	len = sizeof(error);  #ifndef _WIN32 -	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { +	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error) { +		if ((phb->gai_cur = phb->gai_cur->ai_next)) { +			int new_fd; +			b_event_remove(phb->inpa); +			if ((new_fd = proxy_connect_none(NULL, 0, phb))) { +				b_event_remove(phb->inpa); +				closesocket(source); +				dup2(new_fd, source); +				phb->inpa = b_input_add(source, B_EV_IO_WRITE, gaim_io_connected, phb); +				return FALSE; +			} +		} +		freeaddrinfo(phb->gai);  		closesocket(source);  		b_event_remove(phb->inpa);  		if( phb->proxy_func ) -			phb->proxy_func(phb->proxy_data, -1, GAIM_INPUT_READ); +			phb->proxy_func(phb->proxy_data, -1, B_EV_IO_READ);  		else { -			phb->func(phb->data, -1, GAIM_INPUT_READ); +			phb->func(phb->data, -1, B_EV_IO_READ);  			g_free(phb);  		}  		return FALSE;  	}  #endif +	freeaddrinfo(phb->gai);  	sock_make_blocking(source);  	b_event_remove(phb->inpa);  	if( phb->proxy_func ) -		phb->proxy_func(phb->proxy_data, source, GAIM_INPUT_READ); +		phb->proxy_func(phb->proxy_data, source, B_EV_IO_READ);  	else { -		phb->func(phb->data, source, GAIM_INPUT_READ); +		phb->func(phb->data, source, B_EV_IO_READ);  		g_free(phb);  	}  	return FALSE;  } -static int proxy_connect_none(const char *host, unsigned short port, struct PHB *phb) +static int proxy_connect_none(const char *host, unsigned short port_, struct PHB *phb)  { -	struct sockaddr_in *sin;  	struct sockaddr_in me;  	int fd = -1; - -	if (!(sin = gaim_gethostbyname(host, port))) { -		g_free(phb); -		return -1; +	 +	if (phb->gai_cur == NULL) +	{ +		int ret; +		char port[6]; +		struct addrinfo hints; +	 +		g_snprintf(port, sizeof(port), "%d", port_); +	 +		memset(&hints, 0, sizeof(struct addrinfo)); +		hints.ai_family = AF_UNSPEC; +		hints.ai_socktype = SOCK_STREAM; +		hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; +	 +		if (!(ret = getaddrinfo(host, port, &hints, &phb->gai))) +			phb->gai_cur = phb->gai; +		else +			event_debug("gai(): %s\n", gai_strerror(ret));  	} +	 +	for (; phb->gai_cur; phb->gai_cur = phb->gai_cur->ai_next) +	{ +		if ((fd = socket(phb->gai_cur->ai_family, phb->gai_cur->ai_socktype, phb->gai_cur->ai_protocol)) < 0) { +			event_debug( "socket failed: %d\n", errno); +			continue; +		} -	if ((fd = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) { -		g_free(phb); -		return -1; -	} +		sock_make_nonblocking(fd); + +		if (global.conf->iface_out) +		{ +			me.sin_family = AF_INET; +			me.sin_port = 0; +			me.sin_addr.s_addr = inet_addr( global.conf->iface_out ); +				 +			if (bind(fd, (struct sockaddr *) &me, sizeof(me)) != 0) +				event_debug("bind( %d, \"%s\" ) failure\n", fd, global.conf->iface_out); +		} -	sock_make_nonblocking(fd); +		event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd); -	if( global.conf->iface_out ) -	{ -		me.sin_family = AF_INET; -		me.sin_port = 0; -		me.sin_addr.s_addr = inet_addr( global.conf->iface_out ); -		 -		if( bind( fd, (struct sockaddr *) &me, sizeof( me ) ) != 0 ) -			event_debug( "bind( %d, \"%s\" ) failure\n", fd, global.conf->iface_out ); +		if (connect(fd, phb->gai_cur->ai_addr, phb->gai_cur->ai_addrlen) < 0 && !sockerr_again()) { +			event_debug( "connect failed: %s\n", strerror(errno)); +			closesocket(fd); +			fd = -1; +			continue; +		} else { +			phb->inpa = b_input_add(fd, B_EV_IO_WRITE, gaim_io_connected, phb); +			phb->fd = fd; +			 +			break; +		}  	} -	event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd); -	 -	if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0 && !sockerr_again()) { -		closesocket(fd); +	if(fd < 0 && host)  		g_free(phb); -		 -		return -1; -	} else { -		phb->inpa = b_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb); -		phb->fd = fd; -		 -		return fd; -	} + +	return fd;  } @@ -178,14 +199,14 @@ static gboolean http_canread(gpointer data, gint source, b_input_condition cond)  	if ((memcmp(HTTP_GOODSTRING, inputline, strlen(HTTP_GOODSTRING)) == 0) ||  	    (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) { -		phb->func(phb->data, source, GAIM_INPUT_READ); +		phb->func(phb->data, source, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE;  	}  	close(source); -	phb->func(phb->data, -1, GAIM_INPUT_READ); +	phb->func(phb->data, -1, B_EV_IO_READ);  	g_free(phb->host);  	g_free(phb); @@ -203,7 +224,7 @@ static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond  	len = sizeof(error);  	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -214,7 +235,7 @@ static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond  		   phb->host, phb->port);  	if (send(source, cmd, strlen(cmd), 0) < 0) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -229,7 +250,7 @@ static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond  		g_free(t2);  		if (send(source, cmd, strlen(cmd), 0) < 0) {  			close(source); -			phb->func(phb->data, -1, GAIM_INPUT_READ); +			phb->func(phb->data, -1, B_EV_IO_READ);  			g_free(phb->host);  			g_free(phb);  			return FALSE; @@ -239,13 +260,13 @@ static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond  	g_snprintf(cmd, sizeof(cmd), "\r\n");  	if (send(source, cmd, strlen(cmd), 0) < 0) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE;  	} -	phb->inpa = b_input_add(source, GAIM_INPUT_READ, http_canread, phb); +	phb->inpa = b_input_add(source, B_EV_IO_READ, http_canread, phb);  	return FALSE;  } @@ -272,14 +293,14 @@ static gboolean s4_canread(gpointer data, gint source, b_input_condition cond)  	memset(packet, 0, sizeof(packet));  	if (read(source, packet, 9) >= 4 && packet[1] == 90) { -		phb->func(phb->data, source, GAIM_INPUT_READ); +		phb->func(phb->data, source, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE;  	}  	close(source); -	phb->func(phb->data, -1, GAIM_INPUT_READ); +	phb->func(phb->data, -1, B_EV_IO_READ);  	g_free(phb->host);  	g_free(phb); @@ -298,7 +319,7 @@ static gboolean s4_canwrite(gpointer data, gint source, b_input_condition cond)  	len = sizeof(error);  	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -308,7 +329,7 @@ static gboolean s4_canwrite(gpointer data, gint source, b_input_condition cond)  	/* XXX does socks4 not support host name lookups by the proxy? */  	if (!(hp = gethostbyname(phb->host))) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -325,13 +346,13 @@ static gboolean s4_canwrite(gpointer data, gint source, b_input_condition cond)  	packet[8] = 0;  	if (write(source, packet, 9) != 9) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE;  	} -	phb->inpa = b_input_add(source, GAIM_INPUT_READ, s4_canread, phb); +	phb->inpa = b_input_add(source, B_EV_IO_READ, s4_canread, phb);  	return FALSE;  } @@ -358,20 +379,20 @@ static gboolean s5_canread_again(gpointer data, gint source, b_input_condition c  	if (read(source, buf, 10) < 10) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE;  	}  	if ((buf[0] != 0x05) || (buf[1] != 0x00)) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE;  	} -	phb->func(phb->data, source, GAIM_INPUT_READ); +	phb->func(phb->data, source, B_EV_IO_READ);  	g_free(phb->host);  	g_free(phb); @@ -395,13 +416,13 @@ static void s5_sendconnect(gpointer data, gint source)  	if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return;  	} -	phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb); +	phb->inpa = b_input_add(source, B_EV_IO_READ, s5_canread_again, phb);  }  static gboolean s5_readauth(gpointer data, gint source, b_input_condition cond) @@ -413,7 +434,7 @@ static gboolean s5_readauth(gpointer data, gint source, b_input_condition cond)  	if (read(source, buf, 2) < 2) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -421,7 +442,7 @@ static gboolean s5_readauth(gpointer data, gint source, b_input_condition cond)  	if ((buf[0] != 0x01) || (buf[1] != 0x00)) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -441,7 +462,7 @@ static gboolean s5_canread(gpointer data, gint source, b_input_condition cond)  	if (read(source, buf, 2) < 2) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -449,7 +470,7 @@ static gboolean s5_canread(gpointer data, gint source, b_input_condition cond)  	if ((buf[0] != 0x05) || (buf[1] == 0xff)) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -464,13 +485,13 @@ static gboolean s5_canread(gpointer data, gint source, b_input_condition cond)  		memcpy(buf + 2 + i + 1, proxypass, j);  		if (write(source, buf, 3 + i + j) < 3 + i + j) {  			close(source); -			phb->func(phb->data, -1, GAIM_INPUT_READ); +			phb->func(phb->data, -1, B_EV_IO_READ);  			g_free(phb->host);  			g_free(phb);  			return FALSE;  		} -		phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_readauth, phb); +		phb->inpa = b_input_add(source, B_EV_IO_READ, s5_readauth, phb);  	} else {  		s5_sendconnect(phb, source);  	} @@ -490,7 +511,7 @@ static gboolean s5_canwrite(gpointer data, gint source, b_input_condition cond)  	len = sizeof(error);  	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -512,13 +533,13 @@ static gboolean s5_canwrite(gpointer data, gint source, b_input_condition cond)  	if (write(source, buf, i) < i) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE;  	} -	phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread, phb); +	phb->inpa = b_input_add(source, B_EV_IO_READ, s5_canread, phb);  	return FALSE;  } | 
