diff --git a/libnetutil/netutil.cc b/libnetutil/netutil.cc index 974440e6d..6becdbacd 100644 --- a/libnetutil/netutil.cc +++ b/libnetutil/netutil.cc @@ -138,6 +138,7 @@ typedef unsigned __int8 u_int8_t; #endif #include +#include #define NBASE_MAX_ERR_STR_LEN 1024 /* Max length of an error message */ @@ -351,25 +352,34 @@ after: return(d - data); } -/* Internal helper for resolve and resolve_numeric. addl_flags is ored into - hints.ai_flags, so you can add AI_NUMERICHOST. */ -static int resolve_internal(const char *hostname, unsigned short port, - struct sockaddr_storage *ss, size_t *sslen, int af, int addl_flags) { +/* Tries to resolve the given name (or literal IP) into a sockaddr structure. + This function calls getaddrinfo and returns the same addrinfo linked list + that getaddrinfo produces. Returns NULL for any error or failure to resolve. + You need to call freeaddrinfo on the result if non-NULL. */ +static addrinfo *resolve_all_internal(const char *hostname, unsigned short port, + int af, int addl_flags) { struct addrinfo hints; struct addrinfo *result; char portbuf[16]; char *servname = NULL; int rc; - assert(hostname); - assert(ss); - assert(sslen); - memset(&hints, 0, sizeof(hints)); hints.ai_family = af; + /* Otherwise we get multiple identical addresses with different socktypes. */ hints.ai_socktype = SOCK_DGRAM; hints.ai_flags |= addl_flags; +#ifdef AI_IDN + /* Try resolving internationalized domain names */ + locale_t env_locale = newlocale(LC_CTYPE_MASK, "", (locale_t)0); + hints.ai_flags |= AI_IDN; + locale_t old_locale = (locale_t)0; + if (env_locale != old_locale) { + old_locale = uselocale(env_locale); + } +#endif + /* Make the port number a string to give to getaddrinfo. */ if (port != 0) { rc = Snprintf(portbuf, sizeof(portbuf), "%hu", port); @@ -378,8 +388,36 @@ static int resolve_internal(const char *hostname, unsigned short port, } rc = getaddrinfo(hostname, servname, &hints, &result); - if (rc != 0) - return rc; + +#ifdef AI_IDN + if (env_locale != (locale_t)0) { + // Restore the thread's previous locale configuration + uselocale(old_locale); + // Free the allocated memory for the temporary locale + freelocale(env_locale); + } +#endif + + if (rc != 0){ + if ((AI_NUMERICHOST & addl_flags) == 0) + netutil_error("Error resolving %s: %s", hostname, gai_strerror(rc)); + return NULL; + } + + return result; +} + +/* Internal helper for resolve and resolve_numeric. addl_flags is ored into + hints.ai_flags, so you can add AI_NUMERICHOST. */ +static int resolve_internal(const char *hostname, unsigned short port, + struct sockaddr_storage *ss, size_t *sslen, int af, int addl_flags) { + struct addrinfo *result; + + assert(hostname); + assert(ss); + assert(sslen); + + result = resolve_all_internal(hostname, port, af, addl_flags); if (result == NULL) return EAI_NONAME; assert(result->ai_addrlen > 0 && result->ai_addrlen <= (int) sizeof(struct sockaddr_storage)); @@ -409,6 +447,10 @@ int resolve_numeric(const char *ip, unsigned short port, return resolve_internal(ip, port, ss, sslen, af, AI_NUMERICHOST); } +struct addrinfo *resolve_all(const char *hostname, int pf) { + return resolve_all_internal(hostname, 0, pf, 0); +} + /* * Returns 1 if this is a reserved IP address, where "reserved" means * either a private address, non-routable address, or even a non-reserved diff --git a/libnetutil/netutil.h b/libnetutil/netutil.h index 9deccfbbb..7a4df69f2 100644 --- a/libnetutil/netutil.h +++ b/libnetutil/netutil.h @@ -146,6 +146,12 @@ int resolve(const char *hostname, unsigned short port, int resolve_numeric(const char *ip, unsigned short port, struct sockaddr_storage *ss, size_t *sslen, int af); +/* Tries to resolve the given name (or literal IP) into a sockaddr + structure. This function calls getaddrinfo and returns the same + addrinfo linked list that getaddrinfo produces. Returns NULL for any + error or failure to resolve. */ +struct addrinfo *resolve_all(const char *hostname, int pf); + /* * Returns 1 if this is a reserved IP address, where "reserved" means * either a private address, non-routable address, or even a non-reserved diff --git a/tcpip.cc b/tcpip.cc index 67020c85a..717836ed7 100644 --- a/tcpip.cc +++ b/tcpip.cc @@ -381,37 +381,6 @@ const char *inet_socktop(const struct sockaddr_storage *ss) { return buf; } -/* Tries to resolve the given name (or literal IP) into a sockaddr structure. - This function calls getaddrinfo and returns the same addrinfo linked list - that getaddrinfo produces. Returns NULL for any error or failure to resolve. - You need to call freeaddrinfo on the result if non-NULL. */ -struct addrinfo *resolve_all(const char *hostname, int pf) { - struct addrinfo hints; - struct addrinfo *result; - int rc; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = pf; - /* Otherwise we get multiple identical addresses with different socktypes. */ - hints.ai_socktype = SOCK_DGRAM; -#ifdef AI_IDN - /* Try resolving internationalized domain names */ - hints.ai_flags = AI_IDN; - setlocale(LC_CTYPE, ""); -#endif - rc = getaddrinfo(hostname, NULL, &hints, &result); -#ifdef AI_IDN - setlocale(LC_CTYPE, o.locale); -#endif - if (rc != 0){ - if (o.debugging > 1) - error("Error resolving %s: %s", hostname, gai_strerror(rc)); - return NULL; - } - - return result; -} - /* Send a pre-built IPv4 packet. Handles fragmentation and whether to send with an ethernet handle or a socket. */ diff --git a/tcpip.h b/tcpip.h index 8b9e68c4f..067f77d9e 100644 --- a/tcpip.h +++ b/tcpip.h @@ -137,12 +137,6 @@ class PacketCounter { */ const char *inet_socktop(const struct sockaddr_storage *ss); -/* Tries to resolve the given name (or literal IP) into a sockaddr - structure. This function calls getaddrinfo and returns the same - addrinfo linked list that getaddrinfo produces. Returns NULL for any - error or failure to resolve. */ -struct addrinfo *resolve_all(const char *hostname, int pf); - /* Takes a destination address (dst) and tries to determine the source address and interface necessary to route to this address. If no route is found, false is returned and rnfo is undefined. If