rwrap: make use of res_{get,set}servers() for FreeBSD
authorStefan Metzmacher <metze@samba.org>
Tue, 10 Mar 2020 12:11:40 +0000 (13:11 +0100)
committerAndreas Schneider <asn@samba.org>
Fri, 20 Mar 2020 12:20:57 +0000 (13:20 +0100)
This way don't depend on the opaque structure on FreeBSD
and have support for ipv6 nameservers.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
ConfigureChecks.cmake
config.h.cmake
src/resolv_wrapper.c
tests/test_res_init.c

index 4752cd441233e90219215f36e55e6baea85c62f3..84442321127b76134b11517e517588ad3c2261f8 100644 (file)
@@ -176,6 +176,12 @@ int main(void) {
 check_struct_has_member("struct __res_state" _u._ext.nsaddrs
                         "sys/socket.h;netinet/in.h;resolv.h"
                         HAVE_RES_STATE_U_EXT_NSADDRS)
+check_struct_has_member("union res_sockaddr_union" sin
+                        "sys/socket.h;netinet/in.h;resolv.h"
+                        HAVE_RES_SOCKADDR_UNION_SIN)
+check_struct_has_member("union res_sockaddr_union" sin6
+                        "sys/socket.h;netinet/in.h;resolv.h"
+                        HAVE_RES_SOCKADDR_UNION_SIN6)
 
 check_c_source_compiles("
 void log_fn(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
index 75e6902def71d6e8d1f3d2c7e28224257262d249..8eba17bd735de943c8e8e32539ebb1c34d986786 100644 (file)
@@ -56,6 +56,8 @@
 
 #cmakedefine HAVE_IPV6 1
 #cmakedefine HAVE_RES_STATE_U_EXT_NSADDRS 1
+#cmakedefine HAVE_RES_SOCKADDR_UNION_SIN 1
+#cmakedefine HAVE_RES_SOCKADDR_UNION_SIN6 1
 
 #cmakedefine HAVE_ATTRIBUTE_PRINTF_FORMAT 1
 #cmakedefine HAVE_DESTRUCTOR_ATTRIBUTE 1
index e1903c922d3d089908a826d78018d49073b4c578..0d3f34ce5910e3d81dc960774355336ece3d78bd 100644 (file)
@@ -52,7 +52,7 @@
 
 #include <resolv.h>
 
-#ifdef HAVE_RES_STATE_U_EXT_NSADDRS
+#if defined(HAVE_RES_STATE_U_EXT_NSADDRS) || defined(HAVE_RES_SOCKADDR_UNION_SIN6)
 #define HAVE_RESOLV_IPV6_NSADDRS 1
 #endif
 
@@ -1616,6 +1616,45 @@ static size_t rwrap_get_nameservers(struct __res_state *state,
                                    size_t nserv,
                                    union rwrap_sockaddr *nsaddrs)
 {
+#ifdef HAVE_RES_SOCKADDR_UNION_SIN
+       union res_sockaddr_union set[MAXNS];
+       size_t i;
+       int rc;
+
+       memset(set, 0, sizeof(set));
+       memset(nsaddrs, 0, sizeof(*nsaddrs) * nserv);
+
+       if (nserv > MAXNS) {
+               nserv = MAXNS;
+       }
+
+       rc = res_getservers(state, set, nserv);
+       if (rc <= 0) {
+               return 0;
+       }
+       if (rc < nserv) {
+               nserv = rc;
+       }
+
+       for (i = 0; i < nserv; i++) {
+               switch (set[i].sin.sin_family) {
+               case AF_INET:
+                       nsaddrs[i] = (union rwrap_sockaddr) {
+                               .in = set[i].sin,
+                       };
+                       break;
+#ifdef HAVE_RES_SOCKADDR_UNION_SIN6
+               case AF_INET6:
+                       nsaddrs[i] = (union rwrap_sockaddr) {
+                               .in6 = set[i].sin6,
+                       };
+                       break;
+#endif
+               }
+       }
+
+       return nserv;
+#else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
        size_t i;
 
        memset(nsaddrs, 0, sizeof(*nsaddrs) * nserv);
@@ -1640,6 +1679,7 @@ static size_t rwrap_get_nameservers(struct __res_state *state,
        }
 
        return nserv;
+#endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
 }
 
 static void rwrap_log_nameservers(enum rwrap_dbglvl_e dbglvl,
@@ -1678,6 +1718,9 @@ static void rwrap_log_nameservers(enum rwrap_dbglvl_e dbglvl,
 
 static void rwrap_reset_nameservers(struct __res_state *state)
 {
+#ifdef HAVE_RES_SOCKADDR_UNION_SIN
+       res_setservers(state, NULL, 0);
+#else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
        size_t i;
 
@@ -1697,12 +1740,51 @@ static void rwrap_reset_nameservers(struct __res_state *state)
 #endif
        memset(state->nsaddr_list, 0, sizeof(state->nsaddr_list));
        state->nscount = 0;
+#endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
 }
 
 static int rwrap_set_nameservers(struct __res_state *state,
                                 size_t nserv,
                                 const union rwrap_sockaddr *nsaddrs)
 {
+#ifdef HAVE_RES_SOCKADDR_UNION_SIN
+       union res_sockaddr_union set[MAXNS];
+       size_t i;
+
+       memset(set, 0, sizeof(set));
+
+       if (nserv > MAXNS) {
+               nserv = MAXNS;
+       }
+
+       rwrap_reset_nameservers(state);
+
+       for (i = 0; i < nserv; i++) {
+               switch (nsaddrs[i].sa.sa_family) {
+               case AF_INET:
+                       set[i] = (union res_sockaddr_union) {
+                               .sin = nsaddrs[i].in,
+                       };
+                       break;
+#ifdef HAVE_RES_SOCKADDR_UNION_SIN6
+               case AF_INET6:
+                       set[i] = (union res_sockaddr_union) {
+                               .sin6 = nsaddrs[i].in6,
+                       };
+                       break;
+#endif
+               default:
+                       RWRAP_LOG(RWRAP_LOG_ERROR,
+                                 "Internal error unhandled sa_family=%d",
+                                 nsaddrs[i].sa.sa_family);
+                       errno = ENOSYS;
+                       return -1;
+               }
+       }
+
+       res_setservers(state, set, nserv);
+       return 0;
+#else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
        size_t i;
 
        if (nserv > MAXNS) {
@@ -1747,6 +1829,7 @@ static int rwrap_set_nameservers(struct __res_state *state,
        state->nscount = i;
 
        return 0;
+#endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
 }
 
 static int rwrap_parse_resolv_conf(struct __res_state *state,
index eb0eee716eef0f29522db4a18a2585003c79a255..b79e28cfeca3c2ecc7150b6e0c8e067ef7365213 100644 (file)
@@ -92,6 +92,9 @@ static void test_res_ninit(void **state)
        int i;
        int rv;
        char straddr[INET6_ADDRSTRLEN] = { '\0' };
+#ifdef HAVE_RES_SOCKADDR_UNION_SIN
+       union res_sockaddr_union set[MAXNS*5];
+#endif
 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
        struct sockaddr_in6 *sa6;
 #endif
@@ -131,6 +134,41 @@ static void test_res_ninit(void **state)
         * case on all systems encountered so far.
         */
        assert_int_equal(MAXNS, 3);
+#ifdef HAVE_RES_SOCKADDR_UNION_SIN
+       memset(set, 0, sizeof(set));
+       rv = res_getservers(&dnsstate, set, MAXNS+5);
+       assert_int_equal(rv, MAXNS);
+
+       /* IPv4 */
+       assert_int_equal(set[0].sin.sin_family, AF_INET);
+       assert_int_equal(set[0].sin.sin_port, htons(53));
+       inet_ntop(AF_INET, &(set[0].sin.sin_addr),
+                 straddr, INET6_ADDRSTRLEN);
+       assert_string_equal(nameservers[0], straddr);
+
+       assert_int_equal(set[1].sin.sin_family, AF_INET);
+       assert_int_equal(set[1].sin.sin_port, htons(53));
+       inet_ntop(AF_INET, &(set[1].sin.sin_addr), straddr, INET6_ADDRSTRLEN);
+       assert_string_equal(nameservers[1], straddr);
+
+#ifdef HAVE_RES_SOCKADDR_UNION_SIN6
+       /* IPv6 */
+       assert_int_equal(set[2].sin6.sin6_family, AF_INET6);
+       assert_int_equal(set[2].sin6.sin6_port, htons(53));
+       inet_ntop(AF_INET6, &(set[2].sin6.sin6_addr), straddr, INET6_ADDRSTRLEN);
+       assert_string_equal(nameservers[2], straddr);
+#else /* ! HAVE_RES_SOCKADDR_UNION_SIN6 */
+       /*
+        * On platforms that don't support IPv6, the v6 address is skipped
+        * and we end up reading three v4 addresses.
+        */
+       assert_int_equal(set[2].sin.sin_family, AF_INET);
+       assert_int_equal(set[2].sin.sin_port, htons(53));
+       inet_ntop(AF_INET, &(set[2].sin.sin_addr), straddr, INET6_ADDRSTRLEN);
+       assert_string_equal(nameservers[3], straddr);
+#endif /* ! HAVE_RES_SOCKADDR_UNION_SIN6 */
+
+#else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
        assert_int_equal(dnsstate.nscount, MAXNS);
 
        /* Validate the servers. */
@@ -174,6 +212,8 @@ static void test_res_ninit(void **state)
        assert_string_equal(nameservers[3], straddr);
 #endif
 
+#endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
+
        res_nclose(&dnsstate);
 }