From 9427b3db84888c24dc4b650bb22a62be6b0ca1de Mon Sep 17 00:00:00 2001 From: Kevin Easton Date: Tue, 8 Mar 2016 23:53:16 +1100 Subject: [PATCH] Try all addresses returned by getaddrinfo() until we find one that socket() is happy with Someone reported being unable to connect with the error "Address family not supported", which is probably being returned by socket(). It is likely a system where getaddrinfo() is returning AF_INET6 addresses, but socket() won't create AF_INET6 sockets. To handle this case, we loop over all the addresses returned by getaddrinfo() until we find one that socket() will accept. --- Changelog | 3 +++ source/network.c | 66 +++++++++++++++++++++++++++--------------------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/Changelog b/Changelog index 1db6adb..5687f22 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,8 @@ [Changes 1.2.2] +* If we can't create a socket for the first address returned by getaddrinfo(), + try the other returned addresses. (caf) + * Only show version once with -v option (reported by cpet). (caf) * Drop group privileges before droppping user privileges when execing. (caf) diff --git a/source/network.c b/source/network.c index 51c5427..182d8c2 100644 --- a/source/network.c +++ b/source/network.c @@ -509,13 +509,14 @@ int BX_connect_by_number(char *hostn, unsigned short *portnum, int service, int { struct sockaddr_foobar server; socklen_t server_len; - struct hostent *hp; #ifdef WINNT char buf[BIG_BUFFER_SIZE+1]; #endif #ifdef IPV6 - struct addrinfo hints, *res; + struct addrinfo hints = { 0 }; + struct addrinfo *res_list, *res; #else + struct hostent *hp; struct sockaddr_in localaddr; if (LocalHostName) { @@ -532,39 +533,46 @@ int BX_connect_by_number(char *hostn, unsigned short *portnum, int service, int #ifndef WINNT #ifdef IPV6 - memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_ADDRCONFIG; hints.ai_socktype = proto_type; - if (!getaddrinfo(hostn, NULL, &hints, &res) && res) - { - close(fd); - - if ((fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) - return -1; - set_socket_options (fd); - - memcpy(&server, res->ai_addr, res->ai_addrlen); - server_len = res->ai_addrlen; - server.sf_port = htons(*portnum); - - memset(&hints, 0, sizeof hints); - hints.ai_family = res->ai_family; - freeaddrinfo(res); - - if (LocalHostName && !getaddrinfo(LocalHostName, NULL, &hints, &res) && res) - { - int retval = bind(fd, (struct sockaddr *) res->ai_addr, res->ai_addrlen); - freeaddrinfo(res); - - if (retval) - return close(fd), -2; - } - } - else + if (getaddrinfo(hostn, NULL, &hints, &res_list) != 0) return close(fd), -6; + close(fd); + fd = -1; + + for (res = res_list; res; res = res->ai_next) + { + fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (fd >= 0) + break; + } + + if (fd < 0) + { + freeaddrinfo(res_list); + return -1; + } + set_socket_options(fd); + + memcpy(&server, res->ai_addr, res->ai_addrlen); + server_len = res->ai_addrlen; + server.sf_port = htons(*portnum); + + memset(&hints, 0, sizeof hints); + hints.ai_family = res->ai_family; + freeaddrinfo(res_list); + + if (LocalHostName && !getaddrinfo(LocalHostName, NULL, &hints, &res) && res) + { + int retval = bind(fd, (struct sockaddr *) res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + + if (retval) + return close(fd), -2; + } #else if (isdigit((unsigned char)hostn[strlen(hostn)-1])) inet_aton(hostn, (struct in_addr *)&server.sf_addr);