diff options
author | Stefan Metzmacher <metze@samba.org> | 2019-02-14 15:46:22 +0100 |
---|---|---|
committer | Andreas Schneider <asn@samba.org> | 2020-03-20 13:20:57 +0100 |
commit | 2cc59200e35fe6251871d60a53f8a0886ec82fb5 (patch) | |
tree | a4d7da7d190b7e276f36f5574fb76cd09c403333 | |
parent | 396e83a1537a6f5df1cbe8aa152180c36cd18764 (diff) | |
download | resolv_wrapper-2cc59200e35fe6251871d60a53f8a0886ec82fb5.tar.gz resolv_wrapper-2cc59200e35fe6251871d60a53f8a0886ec82fb5.tar.xz resolv_wrapper-2cc59200e35fe6251871d60a53f8a0886ec82fb5.zip |
rwrap: fix resolv wrapper with ipv6 addresses and old glibc versions
The handling of __res_state._u._ext was different before
this glibc commit (e.g. glibc-2.19):
commit 2212c1420c92a33b0e0bd9a34938c9814a56c0f7
Author: Andreas Schwab <schwab@suse.de>
AuthorDate: Thu Feb 19 15:52:08 2015 +0100
Commit: Andreas Schwab <schwab@suse.de>
CommitDate: Thu May 21 15:16:37 2015 +0200
Simplify handling of nameserver configuration in resolver
Remove use of ext.nsmap member of struct __res_state and always use
an identity mapping betwen the nsaddr_list array and the ext.nsaddrs
array. The fact that a nameserver has an IPv6 address is signalled by
setting nsaddr_list[].sin_family to zero.
As a result of fixing this, it's now possible to run 'test_res_init'
even without using resolv_wrapper.
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
-rw-r--r-- | src/resolv_wrapper.c | 53 | ||||
-rw-r--r-- | tests/test_res_init.c | 26 |
2 files changed, 43 insertions, 36 deletions
diff --git a/src/resolv_wrapper.c b/src/resolv_wrapper.c index cbca248..20ba2d1 100644 --- a/src/resolv_wrapper.c +++ b/src/resolv_wrapper.c @@ -1645,14 +1645,13 @@ static int rwrap_parse_resolv_conf(struct __res_state *state, ok = inet_pton(AF_INET, p, &a); if (ok) { - state->nsaddr_list[state->nscount] = (struct sockaddr_in) { + state->nsaddr_list[nserv] = (struct sockaddr_in) { .sin_family = AF_INET, .sin_addr = a, .sin_port = htons(53), .sin_zero = { 0 }, }; - state->nscount++; nserv++; } else { #ifdef HAVE_RESOLV_IPV6_NSADDRS @@ -1673,11 +1672,11 @@ static int rwrap_parse_resolv_conf(struct __res_state *state, 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.nsaddrs[nserv] = sa6; + state->_u._ext.nssocks[nserv] = -1; + state->_u._ext.nsmap[nserv] = MAXNS + 1; - state->_u._ext.nscount++; + state->_u._ext.nscount6++; nserv++; } else { RWRAP_LOG(RWRAP_LOG_ERROR, @@ -1700,6 +1699,13 @@ static int rwrap_parse_resolv_conf(struct __res_state *state, } /* TODO: match other keywords */ } + /* + * note that state->_u._ext.nscount is left as 0, + * this matches glibc and allows resolv wrapper + * to work with most (maybe all) glibc versions. + */ + state->nscount = nserv; + if (ferror(fp)) { RWRAP_LOG(RWRAP_LOG_ERROR, "Reading from %s failed", @@ -1725,21 +1731,36 @@ static int rwrap_res_ninit(struct __res_state *state) const char *resolv_conf = getenv("RESOLV_WRAPPER_CONF"); if (resolv_conf != NULL) { + /* Delete name servers */ +#ifdef HAVE_RESOLV_IPV6_NSADDRS uint16_t i; - (void)i; /* maybe unused */ + for (i = 0; i < state->nscount; i++) { + if (state->_u._ext.nssocks[i] != -1) { + close(state->_u._ext.nssocks[i]); + state->_u._ext.nssocks[i] = -1; + } + + SAFE_FREE(state->_u._ext.nsaddrs[i]); + } +#endif - /* Delete name servers */ state->nscount = 0; memset(state->nsaddr_list, 0, sizeof(state->nsaddr_list)); #ifdef HAVE_RESOLV_IPV6_NSADDRS + state->ipv6_unavail = false; + state->_u._ext.nsinit = 0; state->_u._ext.nscount = 0; - for (i = 0; i < state->_u._ext.nscount; i++) { - SAFE_FREE(state->_u._ext.nsaddrs[i]); + state->_u._ext.nscount6 = 0; + for (i = 0; i < MAXNS; i++) { + state->_u._ext.nsaddrs[i] = NULL; + state->_u._ext.nssocks[i] = -1; + state->_u._ext.nsmap[i] = MAXNS; } #endif + /* And parse the new name servers */ rc = rwrap_parse_resolv_conf(state, resolv_conf); } } @@ -1786,19 +1807,7 @@ int __res_init(void) static void rwrap_res_nclose(struct __res_state *state) { -#ifdef HAVE_RESOLV_IPV6_NSADDRS - int i; -#endif - libc_res_nclose(state); - -#ifdef HAVE_RESOLV_IPV6_NSADDRS - if (state != NULL) { - for (i = 0; i < state->_u._ext.nscount; i++) { - SAFE_FREE(state->_u._ext.nsaddrs[i]); - } - } -#endif } #if !defined(res_nclose) && defined(HAVE_RES_NCLOSE) diff --git a/tests/test_res_init.c b/tests/test_res_init.c index 7f73378..f0cd2ee 100644 --- a/tests/test_res_init.c +++ b/tests/test_res_init.c @@ -121,26 +121,17 @@ static void test_res_ninit(void **state) /* * Validate the number of parsed name servers. - */ - - assert_int_equal(dnsstate.nscount + dnsstate._u._ext.nscount, MAXNS); - -#ifndef HAVE_RESOLV_IPV6_NSADDRS - /* + * * On platforms that don't support IPv6, the v6 address is skipped * and we end up reading three v4 addresses. - */ - assert_int_equal(dnsstate.nscount, MAXNS); -#else - /* + * * test we have two v4 and one v6 server * * Note: This test assumes MAXNS == 3, which is the * case on all systems encountered so far. */ - assert_int_equal(dnsstate.nscount, 2); - assert_int_equal(dnsstate._u._ext.nscount, 1); -#endif /* HAVE_RESOLV_IPV6_NSADDRS */ + assert_int_equal(MAXNS, 3); + assert_int_equal(dnsstate.nscount, MAXNS); /* Validate the servers. */ @@ -150,12 +141,18 @@ static void test_res_ninit(void **state) inet_ntop(AF_INET, &(dnsstate.nsaddr_list[0].sin_addr), straddr, INET6_ADDRSTRLEN); assert_string_equal(nameservers[0], straddr); +#ifdef HAVE_RESOLV_IPV6_NSADDRS + assert_null(dnsstate._u._ext.nsaddrs[0]); +#endif assert_int_equal(dnsstate.nsaddr_list[1].sin_family, AF_INET); assert_int_equal(dnsstate.nsaddr_list[1].sin_port, htons(53)); inet_ntop(AF_INET, &(dnsstate.nsaddr_list[1].sin_addr), straddr, INET6_ADDRSTRLEN); assert_string_equal(nameservers[1], straddr); +#ifdef HAVE_RESOLV_IPV6_NSADDRS + assert_null(dnsstate._u._ext.nsaddrs[1]); +#endif #ifndef HAVE_RESOLV_IPV6_NSADDRS /* @@ -169,7 +166,8 @@ static void test_res_ninit(void **state) assert_string_equal(nameservers[3], straddr); #else /* IPv6 */ - sa6 = dnsstate._u._ext.nsaddrs[0]; + assert_non_null(dnsstate._u._ext.nsaddrs[2]); + sa6 = dnsstate._u._ext.nsaddrs[2]; assert_int_equal(sa6->sin6_family, AF_INET6); assert_int_equal(sa6->sin6_port, htons(53)); inet_ntop(AF_INET6, &(sa6->sin6_addr), straddr, INET6_ADDRSTRLEN); |