rwrap: Add support to read a resolv.conf.
authorJakub Hrozek <jakub.hrozek@gmail.com>
Wed, 3 Sep 2014 12:34:15 +0000 (14:34 +0200)
committerMichael Adam <obnox@samba.org>
Tue, 21 Oct 2014 11:39:39 +0000 (13:39 +0200)
For now, only "nameserver" entries are interpreted.

Pair-Programmed-With: Andreas Schneider <asn@samba.org>

Signed-off-by: Jakub Hrozek <jakub.hrozek@gmail.com>
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Michael Adam <obnox@samba.org>
ConfigureChecks.cmake
config.h.cmake
src/resolv_wrapper.c

index 44f053f1f8c91fd681173ff902bf49e63d1cd87f..7738179c8b990892712e2d0aa0c233c93abd1d96 100644 (file)
@@ -122,6 +122,8 @@ int main(void) {
     return 0;
 }" HAVE_IPV6)
 
+check_struct_has_member("struct __res_state" _u._ext.nsaddrs resolv.h HAVE_RESOLV_IPV6_NSADDRS)
+
 check_c_source_compiles("
 void log_fn(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
 
index 7022f7596b97fe8a5b616972ed27a349316b88dc..9d4dca001978eda369c4244ae83c12d968392924 100644 (file)
@@ -49,6 +49,7 @@
 /**************************** OPTIONS ****************************/
 
 #cmakedefine HAVE_IPV6 1
+#cmakedefine HAVE_RESOLV_IPV6_NSADDRS 1
 
 #cmakedefine HAVE_ATTRIBUTE_PRINTF_FORMAT 1
 #cmakedefine HAVE_DESTRUCTOR_ATTRIBUTE 1
index c5d7ba9b94c3b7de5a5cdf30f9d9a7ab35485b5c..b687551337f822e32fe9befa82b02b19e23b6f80 100644 (file)
@@ -33,7 +33,9 @@
 
 #include "config.h"
 
+#include <errno.h>
 #include <arpa/inet.h>
+#include <netinet/in.h>
 #include <sys/types.h>
 #include <stdarg.h>
 #include <stdlib.h>
@@ -41,6 +43,7 @@
 #include <stdbool.h>
 #include <string.h>
 #include <unistd.h>
+#include <ctype.h>
 
 #include <resolv.h>
 
@@ -401,6 +404,120 @@ static int libc_res_nsearch(struct __res_state *state,
 #endif
 }
 
+/****************************************************************************
+ *   RES_HELPER
+ ***************************************************************************/
+
+#define RESOLV_MATCH(line, name) \
+       (strncmp(line, name, sizeof(name) - 1) == 0 && \
+       (line[sizeof(name) - 1] == ' ' || \
+        line[sizeof(name) - 1] == '\t'))
+
+static int rwrap_parse_resolv_conf(struct __res_state *state,
+                                  const char *resolv_conf)
+{
+       FILE *fp;
+       char buf[BUFSIZ];
+       int nserv = 0;
+
+       fp = fopen(resolv_conf, "r");
+       if (fp == NULL) {
+               RWRAP_LOG(RWRAP_LOG_ERROR,
+                         "Opening %s failed: %s",
+                         resolv_conf, strerror(errno));
+               return -1;
+       }
+
+       while(fgets(buf, sizeof(buf), fp) != NULL) {
+               char *p;
+
+               /* Ignore comments */
+               if (buf[0] == '#' || buf[0] == ';') {
+                       continue;
+               }
+
+               if (RESOLV_MATCH(buf, "nameserver") && nserv < MAXNS) {
+                       struct in_addr a;
+                       char *q;
+                       int ok;
+
+                       p = buf + strlen("nameserver");
+
+                       /* Skip spaces and tabs */
+                       while(isblank((int)p[0])) {
+                               p++;
+                       }
+
+                       q = p;
+                       while(q[0] != '\n' && q[0] != '\0') {
+                               q++;
+                       }
+                       q[0] = '\0';
+
+                       ok = inet_pton(AF_INET, p, &a);
+                       if (ok) {
+                               state->nsaddr_list[state->nscount] = (struct sockaddr_in) {
+                                       .sin_family = AF_INET,
+                                       .sin_addr = a,
+                                       .sin_port = htons(53),
+                               };
+
+                               state->nscount++;
+                               nserv++;
+                       } else {
+#ifdef HAVE_RESOLV_IPV6_NSADDRS
+                               /* IPv6 */
+                               struct in6_addr a6;
+                               ok = inet_pton(AF_INET6, p, &a6);
+                               if (ok) {
+                                       struct sockaddr_in6 *sa6;
+
+                                       sa6 = malloc(sizeof(*sa6));
+                                       if (sa6 == NULL) {
+                                               return -1;
+                                       }
+
+                                       sa6->sin6_family = AF_INET6;
+                                       sa6->sin6_port = htons(53);
+                                       sa6->sin6_flowinfo = 0;
+                                       sa6->sin6_addr = a6;
+
+                                       state->_u._ext.nsaddrs[state->_u._ext.nscount] = sa6;
+                                       state->_u._ext.nssocks[state->_u._ext.nscount] = -1;
+                                       state->_u._ext.nsmap[state->_u._ext.nscount] = MAXNS + 1;
+
+                                       state->_u._ext.nscount++;
+                                       nserv++;
+                               } else {
+                                       RWRAP_LOG(RWRAP_LOG_ERROR,
+                                               "Malformed DNS server");
+                                       continue;
+                               }
+#else /* !HAVE_RESOLV_IPV6_NSADDRS */
+                               /*
+                                * BSD uses an opaque structure to store the
+                                * IPv6 addresses. So we can not simply store
+                                * these addresses the same way as above.
+                                */
+                               RWRAP_LOG(RWRAP_LOG_WARN,
+                                         "resolve_wrapper does not support "
+                                         "IPv6 on this platform");
+                                       continue;
+#endif
+                       }
+                       continue;
+               } /* TODO: match other keywords */
+       }
+
+       if (ferror(fp)) {
+               RWRAP_LOG(RWRAP_LOG_ERROR,
+                         "Reading from %s failed",
+                         resolv_conf);
+               return -1;
+       }
+
+       return 0;
+}
 
 /****************************************************************************
  *   RES_NINIT
@@ -412,31 +529,26 @@ static int rwrap_res_ninit(struct __res_state *state)
 
        rc = libc_res_ninit(state);
        if (rc == 0) {
-               const char *rwrap_ns_env = getenv("RESOLV_WRAPPER_NAMESERVER");
+               const char *resolv_conf = getenv("RESOLV_WRAPPER_CONF");
 
-               if (rwrap_ns_env != NULL) {
-                       int ok;
+               if (resolv_conf != NULL) {
+                       uint16_t i;
+
+                       (void)i; /* maybe unused */
 
                        /* Delete name servers */
-                       state->nscount = 1;
+                       state->nscount = 0;
                        memset(state->nsaddr_list, 0, sizeof(state->nsaddr_list));
 
-                       /* Simply zero the the padding array in the union */
-                       memset(state->_u.pad, 0, sizeof(state->_u.pad));
-
-                       state->nsaddr_list[0] = (struct sockaddr_in) {
-                               .sin_family = AF_INET,
-                               .sin_port = htons(53),
-                       };
-
-                       ok = inet_pton(AF_INET, rwrap_ns_env, &state->nsaddr_list[0].sin_addr);
-                       if (!ok) {
-                               return -1;
+                       state->_u._ext.nscount = 0;
+#ifdef HAVE_RESOLV_IPV6_NSADDRS
+                       for (i = 0; i < state->_u._ext.nscount; i++) {
+                               free(state->_u._ext.nsaddrs[i]);
+                               state->_u._ext.nssocks[i] = 0;
                        }
+#endif
 
-                       RWRAP_LOG(RWRAP_LOG_DEBUG,
-                                 "Using [%s] as new nameserver",
-                                 rwrap_ns_env);
+                       rc = rwrap_parse_resolv_conf(state, resolv_conf);
                }
        }