From affc63cba875df11daade6f6767cb06e013ac6c3 Mon Sep 17 00:00:00 2001 From: Gregor Jasny Date: Wed, 25 Nov 2015 15:03:26 +0100 Subject: [PATCH] Use libresolv to initialize cares on iPhone targets On iPhone targets like iOS, watchOS or tvOS the file /etc/resolv.conf cannot be used to configure cares. Instead the resolver library is queried for configuration values. CC: Yury Kirpichev --- ares_init.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++---- configure.ac | 24 +++++++++++++++++ 2 files changed, 94 insertions(+), 5 deletions(-) diff --git a/ares_init.c b/ares_init.c index b698a15..6555ce0 100644 --- a/ares_init.c +++ b/ares_init.c @@ -49,6 +49,10 @@ #define MAX_DNS_PROPERTIES 8 #endif +#if defined(CARES_USE_LIBRESOLV) +#include +#endif + #include "ares.h" #include "ares_inet_net_pton.h" #include "ares_library_init.h" @@ -77,7 +81,7 @@ static const char *try_option(const char *p, const char *q, const char *opt); static int init_id_key(rc4_key* key,int key_data_len); #if !defined(WIN32) && !defined(WATT32) && \ - !defined(ANDROID) && !defined(__ANDROID__) + !defined(ANDROID) && !defined(__ANDROID__) && !defined(CARES_USE_LIBRESOLV) static int sortlist_alloc(struct apattern **sortlist, int *nsort, struct apattern *pat); static int ip_addr(const char *s, ssize_t len, struct in_addr *addr); @@ -1067,7 +1071,8 @@ static int get_DNS_Windows(char **outptr) static int init_by_resolv_conf(ares_channel channel) { -#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(WATT32) +#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(WATT32) && \ + !defined(CARES_USE_LIBRESOLV) char *line = NULL; #endif int status = -1, nservers = 0, nsort = 0; @@ -1159,6 +1164,65 @@ static int init_by_resolv_conf(ares_channel channel) break; status = ARES_EOF; } +#elif defined(CARES_USE_LIBRESOLV) + struct __res_state res; + memset(&res, 0, sizeof(res)); + int result = res_ninit(&res); + if (result == 0 && (res.options & RES_INIT)) { + status = ARES_EOF; + + if (channel->nservers == -1) { + union res_sockaddr_union addr[MAXNS]; + int nscount = res_getservers(&res, addr, MAXNS); + for (int i = 0; i < nscount; ++i) { + char str[INET6_ADDRSTRLEN]; + int config_status; + sa_family_t family = addr[i].sin.sin_family; + if (family == AF_INET) { + ares_inet_ntop(family, &addr[i].sin.sin_addr, str, sizeof(str)); + } else if (family == AF_INET6) { + ares_inet_ntop(family, &addr[i].sin6.sin6_addr, str, sizeof(str)); + } else { + continue; + } + + config_status = config_nameserver(&servers, &nservers, str); + if (config_status != ARES_SUCCESS) { + status = config_status; + break; + } + } + } + if (channel->ndomains == -1) { + int entries = 0; + while ((entries < MAXDNSRCH) && res.dnsrch[entries]) + entries++; + + channel->domains = malloc(entries * sizeof(char *)); + if (!channel->domains) { + status = ARES_ENOMEM; + } else { + channel->ndomains = entries; + for (int i = 0; i < channel->ndomains; ++i) { + channel->domains[i] = strdup(res.dnsrch[i]); + if (!channel->domains[i]) { + status = ARES_ENOMEM; + break; + } + } + } + } + if (channel->ndots == -1) + channel->ndots = res.ndots; + if (channel->tries == -1) + channel->tries = res.retry; + if (channel->rotate == -1) + channel->rotate = res.options & RES_ROTATE; + if (channel->timeout == -1) + channel->timeout = res.retrans * 1000; + + res_ndestroy(&res); + } #else { char *p; @@ -1479,7 +1543,7 @@ static int init_by_defaults(ares_channel channel) } #if !defined(WIN32) && !defined(WATT32) && \ - !defined(ANDROID) && !defined(__ANDROID__) + !defined(ANDROID) && !defined(__ANDROID__) && !defined(CARES_USE_LIBRESOLV) static int config_domain(ares_channel channel, char *str) { char *q; @@ -1592,7 +1656,8 @@ static int config_nameserver(struct server_state **servers, int *nservers, return ARES_SUCCESS; } -#if !defined(WIN32) && !defined(ANDROID) && !defined(__ANDROID__) +#if !defined(WIN32) && !defined(ANDROID) && !defined(__ANDROID__) && \ + !defined(CARES_USE_LIBRESOLV) static int config_sortlist(struct apattern **sortlist, int *nsort, const char *str) { @@ -1773,7 +1838,7 @@ static const char *try_option(const char *p, const char *q, const char *opt) } #if !defined(WIN32) && !defined(WATT32) && \ - !defined(ANDROID) && !defined(__ANDROID__) + !defined(ANDROID) && !defined(__ANDROID__) && !defined(CARES_USE_LIBRESOLV) static char *try_config(char *s, const char *opt, char scc) { size_t len; diff --git a/configure.ac b/configure.ac index 0ef8bd4..61c8e77 100644 --- a/configure.ac +++ b/configure.ac @@ -346,6 +346,30 @@ if test "$HAVE_GETHOSTBYNAME" != "1"; then AC_MSG_ERROR([couldn't find libraries for gethostbyname()]) fi +dnl resolv lib for iPhone +AS_IF([test "x$host_vendor" = "xapple"], [ + AC_MSG_CHECKING([for iPhone target]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ +#include "TargetConditionals.h" + ]], [[ +#if TARGET_OS_IPHONE == 0 +#error Not an iPhone target +#endif +return 0; + ]]) + ],[ + AC_MSG_RESULT([yes]) + AC_SEARCH_LIBS([res_servicename], [resolv], [ + AC_DEFINE([CARES_USE_LIBRESOLV], [1], [Use resolver library to configure cares]) + ], [ + AC_MSG_ERROR([Unable to find libresolv which is required for iPhone targets]) + ]) + ],[ + AC_MSG_RESULT([no]) + ]) +]) + dnl resolve lib? AC_CHECK_FUNC(strcasecmp, , [ AC_CHECK_LIB(resolve, strcasecmp) ])