summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorSebastien Helleu <flashcode@flashtux.org>2008-09-22 17:15:35 +0200
committerSebastien Helleu <flashcode@flashtux.org>2008-09-22 17:15:35 +0200
commitf67daef91408e4104ce219e2b823da556e2e1df8 (patch)
treef018b56e2b13c0e5d3a5c3c4dc5b5c8dc5a13fdb /src/core
parent87fd5c83ca21b2b1705b0ba57e0a6b532f6bd0c9 (diff)
downloadweechat-f67daef91408e4104ce219e2b823da556e2e1df8.zip
Fix network connection for hostnames resolving to several IPs: try all IPs in list until one succeeds (bug #21473, debian bug #498610)
Diffstat (limited to 'src/core')
-rw-r--r--src/core/wee-network.c135
1 files changed, 68 insertions, 67 deletions
diff --git a/src/core/wee-network.c b/src/core/wee-network.c
index 9f100a8ad..d87862d25 100644
--- a/src/core/wee-network.c
+++ b/src/core/wee-network.c
@@ -510,7 +510,7 @@ network_connect_to (int sock, unsigned long address, int port)
void
network_connect_child (struct t_hook *hook_connect)
{
- struct addrinfo hints, *res, *res_local;
+ struct addrinfo hints, *res, *res_local, *ptr_res;
char status_str[2], *ptr_address, *status_ok_with_address;
char ipv4_address[INET_ADDRSTRLEN + 1], ipv6_address[INET6_ADDRSTRLEN + 1];
char status_ok_without_address[1 + 5 + 1];
@@ -518,6 +518,7 @@ network_connect_child (struct t_hook *hook_connect)
res = NULL;
res_local = NULL;
+
status_str[1] = '\0';
if (CONFIG_BOOLEAN(config_proxy_use))
@@ -626,92 +627,92 @@ network_connect_child (struct t_hook *hook_connect)
write (HOOK_CONNECT(hook_connect, child_write), status_str, 1);
if (res)
freeaddrinfo (res);
- return;
- }
- if ((HOOK_CONNECT(hook_connect, ipv6) && (res->ai_family != AF_INET6))
- || ((!HOOK_CONNECT(hook_connect, ipv6) && (res->ai_family != AF_INET))))
- {
- /* IP address not found */
- status_str[0] = '0' + WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND;
- write (HOOK_CONNECT(hook_connect, child_write), status_str, 1);
- if (res)
- freeaddrinfo (res);
if (res_local)
freeaddrinfo (res_local);
return;
}
- /* connect to peer */
- if (HOOK_CONNECT(hook_connect, ipv6))
- ((struct sockaddr_in6 *)(res->ai_addr))->sin6_port =
- htons (HOOK_CONNECT(hook_connect, port));
- else
- ((struct sockaddr_in *)(res->ai_addr))->sin_port =
- htons (HOOK_CONNECT(hook_connect, port));
-
- if (connect (HOOK_CONNECT(hook_connect, sock),
- res->ai_addr, res->ai_addrlen) != 0)
+ status_str[0] = '0' + WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND;
+
+ /* try all IP addresses found, stop when connection is ok */
+ for (ptr_res = res; ptr_res; ptr_res = ptr_res->ai_next)
{
- /* connection refused */
- status_str[0] = '0' + WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED;
- write (HOOK_CONNECT(hook_connect, child_write), status_str, 1);
- if (res)
- freeaddrinfo (res);
- if (res_local)
- freeaddrinfo (res_local);
- return;
+ /* skip IP address if it's not good family */
+ if ((HOOK_CONNECT(hook_connect, ipv6) && (ptr_res->ai_family != AF_INET6))
+ || ((!HOOK_CONNECT(hook_connect, ipv6) && (ptr_res->ai_family != AF_INET))))
+ continue;
+
+ /* connect to peer */
+ if (HOOK_CONNECT(hook_connect, ipv6))
+ ((struct sockaddr_in6 *)(ptr_res->ai_addr))->sin6_port =
+ htons (HOOK_CONNECT(hook_connect, port));
+ else
+ ((struct sockaddr_in *)(ptr_res->ai_addr))->sin_port =
+ htons (HOOK_CONNECT(hook_connect, port));
+
+ if (connect (HOOK_CONNECT(hook_connect, sock),
+ ptr_res->ai_addr, ptr_res->ai_addrlen) == 0)
+ {
+ status_str[0] = '0' + WEECHAT_HOOK_CONNECT_OK;
+ break;
+ }
+ else
+ status_str[0] = '0' + WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED;
}
}
- /* connection ok */
- status_str[0] = '0' + WEECHAT_HOOK_CONNECT_OK;
-
- status_ok_with_address = NULL;
- ptr_address = NULL;
- if (HOOK_CONNECT(hook_connect, ipv6))
+ if (status_str[0] == '0' + WEECHAT_HOOK_CONNECT_OK)
{
- if (inet_ntop (AF_INET6,
- &((struct sockaddr_in6 *)(res->ai_addr))->sin6_addr,
- ipv6_address,
- INET6_ADDRSTRLEN))
+ status_ok_with_address = NULL;
+ ptr_address = NULL;
+ if (HOOK_CONNECT(hook_connect, ipv6))
{
- ptr_address = ipv6_address;
+ if (inet_ntop (AF_INET6,
+ &((struct sockaddr_in6 *)(res->ai_addr))->sin6_addr,
+ ipv6_address,
+ INET6_ADDRSTRLEN))
+ {
+ ptr_address = ipv6_address;
+ }
}
- }
- else
- {
- //ip = inet_ntoa (((struct sockaddr_in *)(res->ai_addr))->sin_addr);
- if (inet_ntop (AF_INET,
- &((struct sockaddr_in *)(res->ai_addr))->sin_addr,
- ipv4_address,
- INET_ADDRSTRLEN))
+ else
{
- ptr_address = ipv4_address;
+ if (inet_ntop (AF_INET,
+ &((struct sockaddr_in *)(res->ai_addr))->sin_addr,
+ ipv4_address,
+ INET_ADDRSTRLEN))
+ {
+ ptr_address = ipv4_address;
+ }
}
- }
- if (ptr_address)
- {
- length = strlen (status_str) + 5 + strlen (ptr_address) + 1;
- status_ok_with_address = malloc (length);
+ if (ptr_address)
+ {
+ length = strlen (status_str) + 5 + strlen (ptr_address) + 1;
+ status_ok_with_address = malloc (length);
+ if (status_ok_with_address)
+ {
+ snprintf (status_ok_with_address, length, "%s%05d%s",
+ status_str, strlen (ptr_address), ptr_address);
+ }
+ }
+
if (status_ok_with_address)
{
- snprintf (status_ok_with_address, length, "%s%05d%s",
- status_str, strlen (ptr_address), ptr_address);
+ write (HOOK_CONNECT(hook_connect, child_write),
+ status_ok_with_address, strlen (status_ok_with_address));
+ free (status_ok_with_address);
+ }
+ else
+ {
+ snprintf (status_ok_without_address, sizeof (status_ok_without_address),
+ "%s%05d", status_str, 0);
+ write (HOOK_CONNECT(hook_connect, child_write),
+ status_ok_without_address, strlen (status_ok_without_address));
}
- }
-
- if (status_ok_with_address)
- {
- write (HOOK_CONNECT(hook_connect, child_write),
- status_ok_with_address, strlen (status_ok_with_address));
- free (status_ok_with_address);
}
else
{
- snprintf (status_ok_without_address, sizeof (status_ok_without_address),
- "%s%05d", status_str, 0);
- write (HOOK_CONNECT(hook_connect, child_write),
- status_ok_without_address, strlen (status_ok_without_address));
+ write (HOOK_CONNECT(hook_connect, child_write), status_str, 1);
}
if (res)