The branch, master has been updated via f34b454 rwrap: make use of res_{get,set}servers() for FreeBSD via 4eb4e25 rwrap: split out a rwrap_set_nameservers() function via 93702c8 rwrap: split out rwrap_{get,log}_nameservers() functions via be1a294 rwrap: split out a rwrap_reset_nameservers() function via e47b20d rwrap: let configure use define HAVE_RES_STATE_U_EXT_NSADDRS via 2cc5920 rwrap: fix resolv wrapper with ipv6 addresses and old glibc versions via 396e83a tests/test_res_init.c: avoid using public ipv6 addresses from google in tests from 3ab29a2 rwrap: improve logging messages by including getprogname()
https://git.samba.org/?p=resolv_wrapper.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit f34b4540fd1b860ecff38f9caaa6f4c48197a18a Author: Stefan Metzmacher <me...@samba.org> Date: Tue Mar 10 13:11:40 2020 +0100 rwrap: make use of res_{get,set}servers() for FreeBSD This way don't depend on the opaque structure on FreeBSD and have support for ipv6 nameservers. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit 4eb4e25b89bcd5a10b9f0e3e42c4181b65518adf Author: Stefan Metzmacher <me...@samba.org> Date: Tue Mar 10 13:07:25 2020 +0100 rwrap: split out a rwrap_set_nameservers() function This will make it easier to add support for ipv6 nameservers on FreeBSD in the next step. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit 93702c87726ac9f29df41e192c105e2f030d1d80 Author: Stefan Metzmacher <me...@samba.org> Date: Tue Mar 10 13:07:25 2020 +0100 rwrap: split out rwrap_{get,log}_nameservers() functions This will make it easier to add support for ipv6 nameservers on FreeBSD in the next step. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit be1a2940aff74edc7b6063b1772558f63eb82544 Author: Stefan Metzmacher <me...@samba.org> Date: Tue Mar 10 13:07:25 2020 +0100 rwrap: split out a rwrap_reset_nameservers() function This will make it easier to add support for ipv6 nameservers on FreeBSD in the following commits. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit e47b20d78b1d5ba9b66cb054659ed338d43f469e Author: Stefan Metzmacher <me...@samba.org> Date: Wed Mar 18 17:01:48 2020 +0100 rwrap: let configure use define HAVE_RES_STATE_U_EXT_NSADDRS The configure check should describe what it checked for. Let the code logic decide if that means we expect HAVE_RESOLV_IPV6_NSADDRS to be defined. We'll get another condition that sets HAVE_RESOLV_IPV6_NSADDRS in the following commits. Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit 2cc59200e35fe6251871d60a53f8a0886ec82fb5 Author: Stefan Metzmacher <me...@samba.org> Date: Thu Feb 14 15:46:22 2019 +0100 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 <sch...@suse.de> AuthorDate: Thu Feb 19 15:52:08 2015 +0100 Commit: Andreas Schwab <sch...@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 <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit 396e83a1537a6f5df1cbe8aa152180c36cd18764 Author: Stefan Metzmacher <me...@samba.org> Date: Fri Feb 15 17:24:57 2019 +0100 tests/test_res_init.c: avoid using public ipv6 addresses from google in tests Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> ----------------------------------------------------------------------- Summary of changes: ConfigureChecks.cmake | 10 +- config.h.cmake | 4 +- src/resolv_wrapper.c | 370 +++++++++++++++++++++++++++++++++++++------------- tests/test_res_init.c | 84 ++++++++---- 4 files changed, 347 insertions(+), 121 deletions(-) Changeset truncated at 500 lines: diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index ae9437b..8444232 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -173,7 +173,15 @@ int main(void) { return 0; }" HAVE_IPV6) -check_struct_has_member("struct __res_state" _u._ext.nsaddrs resolv.h HAVE_RESOLV_IPV6_NSADDRS) +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))); diff --git a/config.h.cmake b/config.h.cmake index 0c2fa35..8eba17b 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -55,7 +55,9 @@ /**************************** OPTIONS ****************************/ #cmakedefine HAVE_IPV6 1 -#cmakedefine HAVE_RESOLV_IPV6_NSADDRS 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 diff --git a/src/resolv_wrapper.c b/src/resolv_wrapper.c index cbca248..0d3f34c 100644 --- a/src/resolv_wrapper.c +++ b/src/resolv_wrapper.c @@ -52,6 +52,10 @@ #include <resolv.h> +#if defined(HAVE_RES_STATE_U_EXT_NSADDRS) || defined(HAVE_RES_SOCKADDR_UNION_SIN6) +#define HAVE_RESOLV_IPV6_NSADDRS 1 +#endif + /* GCC has printf type attribute check. */ #ifdef HAVE_ATTRIBUTE_PRINTF_FORMAT #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b))) @@ -173,6 +177,12 @@ static void rwrap_log(enum rwrap_dbglvl_e dbglvl, #define RWRAP_MAX_RECURSION 64 +union rwrap_sockaddr { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_in6 in6; +}; + /* Priority and weight can be omitted from the hosts file, but need to be part * of the output */ @@ -1602,12 +1612,235 @@ static int libc_res_nsearch(struct __res_state *state, * RES_HELPER ***************************************************************************/ +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); + + if (nserv > (size_t)state->nscount) { + nserv = (size_t)state->nscount; + } + + for (i = 0; i < nserv; i++) { +#ifdef HAVE_RES_STATE_U_EXT_NSADDRS + if (state->_u._ext.nsaddrs[i] != NULL) { + nsaddrs[i] = (union rwrap_sockaddr) { + .in6 = *state->_u._ext.nsaddrs[i], + }; + } else +#endif /* HAVE_RES_STATE_U_EXT_NSADDRS */ + { + nsaddrs[i] = (union rwrap_sockaddr) { + .in = state->nsaddr_list[i], + }; + } + } + + return nserv; +#endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */ +} + +static void rwrap_log_nameservers(enum rwrap_dbglvl_e dbglvl, + const char *func, + struct __res_state *state) +{ + union rwrap_sockaddr nsaddrs[MAXNS]; + size_t nserv = MAXNS; + size_t i; + + memset(nsaddrs, 0, sizeof(nsaddrs)); + nserv = rwrap_get_nameservers(state, nserv, nsaddrs); + for (i = 0; i < nserv; i++) { + char ip[INET6_ADDRSTRLEN]; + + switch (nsaddrs[i].sa.sa_family) { + case AF_INET: + inet_ntop(AF_INET, &(nsaddrs[i].in.sin_addr), + ip, sizeof(ip)); + break; + case AF_INET6: + inet_ntop(AF_INET6, &(nsaddrs[i].in6.sin6_addr), + ip, sizeof(ip)); + break; + default: + snprintf(ip, sizeof(ip), "<unknown sa_family=%d", + nsaddrs[i].sa.sa_family); + break; + } + + rwrap_log(dbglvl, func, + " nameserver: %s", + ip); + } +} + +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; + + for (i = 0; i < (size_t)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]); + } + memset(&state->_u._ext, 0, sizeof(state->_u._ext)); + for (i = 0; i < MAXNS; i++) { + state->_u._ext.nssocks[i] = -1; + state->_u._ext.nsmap[i] = MAXNS + 1; + } + state->ipv6_unavail = false; +#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) { + nserv = MAXNS; + } + rwrap_reset_nameservers(state); + + for (i = 0; i < nserv; i++) { + switch (nsaddrs[i].sa.sa_family) { + case AF_INET: + state->nsaddr_list[i] = nsaddrs[i].in; + break; +#ifdef HAVE_RES_STATE_U_EXT_NSADDRS + case AF_INET6: + state->_u._ext.nsaddrs[i] = malloc(sizeof(nsaddrs[i].in6)); + if (state->_u._ext.nsaddrs[i] == NULL) { + rwrap_reset_nameservers(state); + errno = ENOMEM; + return -1; + } + *state->_u._ext.nsaddrs[i] = nsaddrs[i].in6; + state->_u._ext.nssocks[i] = -1; + state->_u._ext.nsmap[i] = MAXNS + 1; + state->_u._ext.nscount6++; + break; +#endif + default: + RWRAP_LOG(RWRAP_LOG_ERROR, + "Internal error unhandled sa_family=%d", + nsaddrs[i].sa.sa_family); + rwrap_reset_nameservers(state); + errno = ENOSYS; + return -1; + } + } + + /* + * 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 = i; + + return 0; +#endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */ +} + static int rwrap_parse_resolv_conf(struct __res_state *state, const char *resolv_conf) { FILE *fp; char buf[BUFSIZ]; - int nserv = 0; + size_t nserv = 0; + union rwrap_sockaddr nsaddrs[MAXNS]; + + memset(nsaddrs, 0, sizeof(nsaddrs)); fp = fopen(resolv_conf, "r"); if (fp == NULL) { @@ -1627,6 +1860,7 @@ static int rwrap_parse_resolv_conf(struct __res_state *state, if (RESOLV_MATCH(buf, "nameserver") && nserv < MAXNS) { struct in_addr a; + struct in6_addr a6; char *q; int ok; @@ -1645,57 +1879,42 @@ 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) { - .sin_family = AF_INET, - .sin_addr = a, - .sin_port = htons(53), - .sin_zero = { 0 }, + nsaddrs[nserv] = (union rwrap_sockaddr) { + .in = { + .sin_family = AF_INET, + .sin_addr = a, + .sin_port = htons(53), + .sin_zero = { 0 }, + }, }; - state->nscount++; nserv++; - } else { + continue; + } + + ok = inet_pton(AF_INET6, p, &a6); + if (ok) { #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) { - fclose(fp); - 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; - } + nsaddrs[nserv] = (union rwrap_sockaddr) { + .in6 = { + + .sin6_family = AF_INET6, + .sin6_port = htons(53), + .sin6_flowinfo = 0, + .sin6_addr = a6, + }, + }; + nserv++; + 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; + continue; #endif } + + RWRAP_LOG(RWRAP_LOG_ERROR, "Malformed DNS server[%s]", p); continue; } /* TODO: match other keywords */ } @@ -1709,7 +1928,16 @@ static int rwrap_parse_resolv_conf(struct __res_state *state, } fclose(fp); - return 0; + + if (nserv == 0) { + RWRAP_LOG(RWRAP_LOG_ERROR, + "No usable nameservers found in %s", + resolv_conf); + errno = ESRCH; + return -1; + } + + return rwrap_set_nameservers(state, nserv, nsaddrs); } /**************************************************************************** @@ -1725,21 +1953,6 @@ static int rwrap_res_ninit(struct __res_state *state) const char *resolv_conf = getenv("RESOLV_WRAPPER_CONF"); if (resolv_conf != NULL) { - uint16_t i; - - (void)i; /* maybe unused */ - - /* Delete name servers */ - state->nscount = 0; - memset(state->nsaddr_list, 0, sizeof(state->nsaddr_list)); - -#ifdef HAVE_RESOLV_IPV6_NSADDRS - state->_u._ext.nscount = 0; - for (i = 0; i < state->_u._ext.nscount; i++) { - SAFE_FREE(state->_u._ext.nsaddrs[i]); - } -#endif - rc = rwrap_parse_resolv_conf(state, resolv_conf); } } @@ -1786,19 +1999,8 @@ int __res_init(void) static void rwrap_res_nclose(struct __res_state *state) { -#ifdef HAVE_RESOLV_IPV6_NSADDRS - int i; -#endif - + rwrap_reset_nameservers(state); 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) @@ -1841,23 +2043,11 @@ static int rwrap_res_nquery(struct __res_state *state, { int rc; const char *fake_hosts; -#ifndef NDEBUG - int i; -#endif RWRAP_LOG(RWRAP_LOG_TRACE, "Resolve the domain name [%s] - class=%d, type=%d", dname, class, type); -#ifndef NDEBUG - for (i = 0; i < state->nscount; i++) { - char ip[INET6_ADDRSTRLEN]; - - inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, ip, sizeof(ip)); - RWRAP_LOG(RWRAP_LOG_TRACE, - " nameserver: %s", - ip); - } -#endif + rwrap_log_nameservers(RWRAP_LOG_TRACE, __func__, state); fake_hosts = getenv("RESOLV_WRAPPER_HOSTS"); if (fake_hosts != NULL) { @@ -1950,23 +2140,11 @@ static int rwrap_res_nsearch(struct __res_state *state, { int rc; const char *fake_hosts; -#ifndef NDEBUG - int i; -#endif RWRAP_LOG(RWRAP_LOG_TRACE, "Resolve the domain name [%s] - class=%d, type=%d", dname, class, type); -#ifndef NDEBUG - for (i = 0; i < state->nscount; i++) { - char ip[INET6_ADDRSTRLEN]; - - inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, ip, sizeof(ip)); - RWRAP_LOG(RWRAP_LOG_TRACE, - " nameserver: %s", - ip); - } -#endif -- Resolv Wrapper Repository