Hello,

this is a reworked version of Yury Kirpichev's patch to add iOS support to cares. Compared to the former version the following has been added:

* IPv6 name server now work properly. The ones ones in nsaddr_list have
  their address family set to AF_UNSPEC. As a work-around we call
  res_getservers instead.

* More options like search domains, ndots, etc. are applied

* Added autoconf magic to detect iPhone (iOS, tvOS, and watchOS)
  presence and use libresolv there.

In theory we could use the libresolv code also on OSX. But to avoid possible regressions I decided against it for a start.

Patch is attached and also in this PR:
https://github.com/bagder/c-ares/pull/29

Thanks,
Gregor
From 4e30c6ed3f9513c493729ed426f1a8885baf04fa Mon Sep 17 00:00:00 2001
From: Gregor Jasny <gja...@googlemail.com>
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 <ykirpic...@yandex-team.ru>
---
 ares_init.c  | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 configure.ac | 24 ++++++++++++++++++++
 2 files changed, 90 insertions(+), 5 deletions(-)

diff --git a/ares_init.c b/ares_init.c
index 05bb941..f5aa49e 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 <resolv.h>
+#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);
@@ -1058,7 +1062,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;
@@ -1150,6 +1155,61 @@ 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->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;
@@ -1470,7 +1530,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;
@@ -1583,7 +1643,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)
 {
@@ -1764,7 +1825,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) ])
 
-- 
2.6.3

Reply via email to