talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

commit 8f4236e282d3252ecf9f3920e2e5c312d2cf50fc
parent 1b32cc6794190c9fb6124b6de5b6f23e3007eec9
Author: Andrej Kacian <ticho@claws-mail.org>
Date:   Wed,  1 Oct 2014 22:00:06 +0200

Use getaddrinfo() instead of gethostbyname() in socket.c.

Closes bug #3253, as we're trying all resolved addresses.
This should also make IPv6 work on Windows, bug #3495.

Diffstat:
Msrc/common/socket.c | 195++++++++++---------------------------------------------------------------------
Msrc/common/socket.h | 2--
Msrc/common/utils.c | 21++++++++++++++-------
3 files changed, 37 insertions(+), 181 deletions(-)

diff --git a/src/common/socket.c b/src/common/socket.c @@ -151,14 +151,8 @@ static gint sock_connect_with_timeout (gint sock, gint addrlen, guint timeout_secs); -#ifndef INET6 -static gint sock_connect_by_hostname (gint sock, - const gchar *hostname, - gushort port); -#else static gint sock_connect_by_getaddrinfo (const gchar *hostname, gushort port); -#endif static SockInfo *sockinfo_from_fd(const gchar *hostname, gushort port, @@ -615,98 +609,6 @@ static gint sock_connect_with_timeout(gint sock, return ret; } -struct hostent *my_gethostbyname(const gchar *hostname) -{ - struct hostent *hp; -#ifdef G_OS_UNIX - void (*prev_handler)(gint); - - alarm(0); - prev_handler = signal(SIGALRM, timeout_handler); - if (sigsetjmp(jmpenv, 1)) { - alarm(0); - signal(SIGALRM, prev_handler); - g_printerr("%s: host lookup timed out.\n", hostname); - log_error(LOG_PROTOCOL, _("%s: host lookup timed out.\n"), hostname); - errno = 0; - return NULL; - } - alarm(io_timeout); -#endif - - if ((hp = gethostbyname(hostname)) == NULL) { -#ifdef G_OS_UNIX - alarm(0); - signal(SIGALRM, prev_handler); -#endif - g_printerr("%s: unknown host.\n", hostname); - log_error(LOG_PROTOCOL, _("%s: unknown host.\n"), hostname); - errno = 0; - return NULL; - } - -#ifdef G_OS_UNIX - alarm(0); - signal(SIGALRM, prev_handler); -#endif - - return hp; -} - -#ifndef INET6 -static gint my_inet_aton(const gchar *hostname, struct in_addr *inp) -{ -#if HAVE_INET_ATON - return inet_aton(hostname, inp); -#else -#if HAVE_INET_ADDR - guint32 inaddr; - - inaddr = inet_addr(hostname); - if (inaddr != -1) { - memcpy(inp, &inaddr, sizeof(inaddr)); - return 1; - } else - return 0; -#else - return 0; -#endif -#endif /* HAVE_INET_ATON */ -} - -static gint sock_connect_by_hostname(gint sock, const gchar *hostname, - gushort port) -{ - struct hostent *hp; - struct sockaddr_in ad; - - memset(&ad, 0, sizeof(ad)); - ad.sin_family = AF_INET; - ad.sin_port = htons(port); - - refresh_resolvers(); - - if (!my_inet_aton(hostname, &ad.sin_addr)) { - if ((hp = my_gethostbyname(hostname)) == NULL) { - g_printerr("%s: unknown host.\n", hostname); - errno = 0; - return -1; - } - - if (hp->h_length != 4 && hp->h_length != 8) { - g_printerr("illegal address length received for host %s\n", hostname); - errno = 0; - return -1; - } - - memcpy(&ad.sin_addr, hp->h_addr, hp->h_length); - } - - return sock_connect_with_timeout(sock, (struct sockaddr *)&ad, - sizeof(ad), io_timeout); -} - -#else /* INET6 */ static gint sock_connect_by_getaddrinfo(const gchar *hostname, gushort port) { gint sock = -1, gai_error; @@ -716,8 +618,14 @@ static gint sock_connect_by_getaddrinfo(const gchar *hostname, gushort port) refresh_resolvers(); memset(&hints, 0, sizeof(hints)); - /* hints.ai_flags = AI_CANONNAME; */ + hints.ai_flags = AI_ADDRCONFIG; + +#ifdef INET6 hints.ai_family = AF_UNSPEC; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; @@ -731,9 +639,18 @@ static gint sock_connect_by_getaddrinfo(const gchar *hostname, gushort port) } for (ai = res; ai != NULL; ai = ai->ai_next) { +#ifndef INET6 + if (ai->ai_family == AF_INET6) + continue; +#endif + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (sock < 0) + if (sock < 0 ) + continue; +#ifdef G_OS_WIN32 + if (sock == INVALID_SOCKET) continue; +#endif if (sock_connect_with_timeout (sock, ai->ai_addr, ai->ai_addrlen, io_timeout) == 0) @@ -750,7 +667,6 @@ static gint sock_connect_by_getaddrinfo(const gchar *hostname, gushort port) return sock; } -#endif /* !INET6 */ SockInfo *sock_connect(const gchar *hostname, gushort port) { @@ -760,27 +676,10 @@ SockInfo *sock_connect(const gchar *hostname, gushort port) gint sock; #endif -#ifdef INET6 - if ((sock = sock_connect_by_getaddrinfo(hostname, port)) < 0) - return NULL; -#else -#ifdef G_OS_WIN32 - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { - g_warning("socket() failed: %d\n", WSAGetLastError()); -#else - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("socket"); -#endif /* G_OS_WIN32 */ + if ((sock = sock_connect_by_getaddrinfo(hostname, port)) < 0) { return NULL; } - if (sock_connect_by_hostname(sock, hostname, port) < 0) { - if (errno != 0) perror("connect"); - close(sock); - return NULL; - } -#endif /* INET6 */ - return sockinfo_from_fd(hostname, port, sock); } @@ -1133,15 +1032,9 @@ static gboolean sock_get_address_info_async_cb(GIOChannel *source, static void address_info_async_child(void *opaque) { SockLookupData *parm = opaque; -#ifdef INET6 gint gai_err; struct addrinfo hints, *res, *ai; gchar port_str[6]; -#else /* !INET6 */ - struct hostent *hp; - gchar **addr_list_p; - struct sockaddr_in ad; -#endif /* INET6 */ gint ai_member[4] = {AF_UNSPEC, 0, 0, 0}; #ifndef G_OS_WIN32 @@ -1149,10 +1042,13 @@ static void address_info_async_child(void *opaque) parm->pipe_fds[0] = -1; #endif -#ifdef INET6 memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; + hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; +#ifdef INET6 hints.ai_family = AF_UNSPEC; +#else + hints.ai_family = AF_INET; +#endif hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; @@ -1210,51 +1106,6 @@ static void address_info_async_child(void *opaque) if (res != NULL) freeaddrinfo(res); -#else /* !INET6 */ - hp = my_gethostbyname(parm->hostname); - if (hp == NULL || hp->h_addrtype != AF_INET) { - gchar len = 0; - fd_write_all(parm->pipe_fds[1], &len, - sizeof(len)); - fd_write_all(parm->pipe_fds[1], (gchar *)ai_member, - sizeof(ai_member)); - close(parm->pipe_fds[1]); - parm->pipe_fds[1] = -1; -#ifdef G_OS_WIN32 - _endthread(); -#else - _exit(1); -#endif - } - - ai_member[0] = AF_INET; - ai_member[1] = SOCK_STREAM; - ai_member[2] = IPPROTO_TCP; - ai_member[3] = sizeof(ad); - - memset(&ad, 0, sizeof(ad)); - ad.sin_family = AF_INET; - ad.sin_port = htons(parm->port); - - if (hp->h_name && strlen(hp->h_name) < 255) { - gchar len = strlen(hp->h_name); - fd_write_all(parm->pipe_fds[1], &len, - sizeof(len)); - fd_write_all(parm->pipe_fds[1], hp->h_name, - len); - } else { - gchar len = 0; - fd_write_all(parm->pipe_fds[1], &len, - sizeof(len)); - } - for (addr_list_p = hp->h_addr_list; *addr_list_p != NULL; - addr_list_p++) { - memcpy(&ad.sin_addr, *addr_list_p, hp->h_length); - fd_write_all(parm->pipe_fds[1], (gchar *)ai_member, - sizeof(ai_member)); - fd_write_all(parm->pipe_fds[1], (gchar *)&ad, sizeof(ad)); - } -#endif /* INET6 */ close(parm->pipe_fds[1]); parm->pipe_fds[1] = -1; diff --git a/src/common/socket.h b/src/common/socket.h @@ -94,8 +94,6 @@ gboolean sock_is_nonblocking_mode (SockInfo *sock); guint sock_add_watch (SockInfo *sock, GIOCondition condition, SockFunc func, gpointer data); -struct hostent *my_gethostbyname (const gchar *hostname); - SockInfo *sock_connect (const gchar *hostname, gushort port); gint sock_connect_async (const gchar *hostname, gushort port, SockConnectFunc func, gpointer data); diff --git a/src/common/utils.c b/src/common/utils.c @@ -1976,21 +1976,28 @@ const gchar *get_domain_name(void) { #ifdef G_OS_UNIX static gchar *domain_name = NULL; + struct addrinfo hints, *res; + char hostname[256]; + int s; if (!domain_name) { - struct hostent *hp; - char hostname[256]; - if (gethostname(hostname, sizeof(hostname)) != 0) { perror("gethostname"); domain_name = "localhost"; } else { - hostname[sizeof(hostname) - 1] = '\0'; - if ((hp = my_gethostbyname(hostname)) == NULL) { - perror("gethostbyname"); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = 0; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = 0; + + s = getaddrinfo(hostname, NULL, &hints, &res); + if (s != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); domain_name = g_strdup(hostname); } else { - domain_name = g_strdup(hp->h_name); + domain_name = g_strdup(res->ai_canonname); + freeaddrinfo(res); } } debug_print("domain name = %s\n", domain_name);