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; } |