diff options
| author | Florian Weimer <fweimer@redhat.com> | 2017-06-30 21:10:23 +0200 |
|---|---|---|
| committer | Florian Weimer <fweimer@redhat.com> | 2017-07-03 20:52:59 +0200 |
| commit | 352f4ff9a268b81ef5d4b2413f582565806e4790 (patch) | |
| tree | fb27056dfdeafe43c021f6127c9544c016e78019 /resolv | |
| parent | 4e45d83c92dbb5b8dc20654f32395108d18cf739 (diff) | |
| download | glibc-352f4ff9a268b81ef5d4b2413f582565806e4790.tar.xz glibc-352f4ff9a268b81ef5d4b2413f582565806e4790.zip | |
resolv: Introduce struct resolv_context [BZ #21668]
struct resolv_context objects provide a temporary resolver context
which does not change during a name lookup operation. Only when the
outmost context is created, the stub resolver configuration is
verified to be current (at present, only against previous res_init
calls). Subsequent attempts to obtain the context will reuse the
result of the initial verification operation.
struct resolv_context can also be extended in the future to store
data which needs to be deallocated during thread cancellation.
Diffstat (limited to 'resolv')
| -rw-r--r-- | resolv/Makefile | 3 | ||||
| -rw-r--r-- | resolv/Versions | 10 | ||||
| -rw-r--r-- | resolv/compat-gethnamaddr.c | 95 | ||||
| -rw-r--r-- | resolv/nss_dns/dns-canon.c | 19 | ||||
| -rw-r--r-- | resolv/nss_dns/dns-host.c | 104 | ||||
| -rw-r--r-- | resolv/nss_dns/dns-network.c | 21 | ||||
| -rw-r--r-- | resolv/res-close.c | 3 | ||||
| -rw-r--r-- | resolv/res_libc.c | 31 | ||||
| -rw-r--r-- | resolv/res_mkquery.c | 92 | ||||
| -rw-r--r-- | resolv/res_query.c | 298 | ||||
| -rw-r--r-- | resolv/res_send.c | 44 | ||||
| -rw-r--r-- | resolv/res_use_inet6.h | 49 | ||||
| -rw-r--r-- | resolv/resolv-internal.h | 36 | ||||
| -rw-r--r-- | resolv/resolv_context.c | 201 | ||||
| -rw-r--r-- | resolv/resolv_context.h | 95 |
15 files changed, 810 insertions, 291 deletions
diff --git a/resolv/Makefile b/resolv/Makefile index bab1ac24a6..126da0736a 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -28,7 +28,8 @@ headers := resolv.h bits/types/res_state.h \ sys/bitypes.h routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \ - res_hconf res_libc res-state res_randomid res-close + res_hconf res_libc res-state res_randomid res-close \ + resolv_context tests = tst-aton tst-leaks tst-inet_ntop xtests = tst-leaks2 diff --git a/resolv/Versions b/resolv/Versions index f528ed51e8..b05778d965 100644 --- a/resolv/Versions +++ b/resolv/Versions @@ -26,8 +26,12 @@ libc { __h_errno; __resp; - __res_maybe_init; __res_iclose; + __res_iclose; __inet_pton_length; + __resolv_context_get; + __resolv_context_get_preinit; + __resolv_context_get_override; + __resolv_context_put; } } @@ -79,7 +83,9 @@ libresolv { # Needed in libnss_dns. __ns_name_unpack; __ns_name_ntop; __ns_get16; __ns_get32; - __libc_res_nquery; __libc_res_nsearch; + __res_context_query; + __res_context_search; + __res_context_hostalias; } } diff --git a/resolv/compat-gethnamaddr.c b/resolv/compat-gethnamaddr.c index 813c7d4e85..259378b2be 100644 --- a/resolv/compat-gethnamaddr.c +++ b/resolv/compat-gethnamaddr.c @@ -67,6 +67,7 @@ # include <stdio.h> # include <netdb.h> # include <resolv/resolv-internal.h> +# include <resolv/resolv_context.h> # include <ctype.h> # include <errno.h> # include <stdlib.h> @@ -84,6 +85,9 @@ static u_char host_addr[16]; /* IPv4 or IPv6 */ static FILE *hostf = NULL; static int stayopen = 0; +static struct hostent *res_gethostbyname2_context (struct resolv_context *, + const char *name, int af); + static void map_v4v6_address (const char *src, char *dst) __THROW; static void map_v4v6_hostent (struct hostent *hp, char **bp, int *len) __THROW; @@ -428,23 +432,31 @@ libresolv_hidden_proto (res_gethostbyname2) struct hostent * res_gethostbyname (const char *name) { - struct hostent *hp; - - if (__res_maybe_init (&_res, 0) == -1) { - __set_h_errno (NETDB_INTERNAL); - return (NULL); - } - if (res_use_inet6 ()) { - hp = res_gethostbyname2(name, AF_INET6); - if (hp) - return (hp); + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) + { + __set_h_errno (NETDB_INTERNAL); + return NULL; + } + + if (res_use_inet6 ()) + { + struct hostent *hp = res_gethostbyname2_context (ctx, name, AF_INET6); + if (hp != NULL) + { + __resolv_context_put (ctx); + return hp; } - return (res_gethostbyname2(name, AF_INET)); + } + struct hostent *hp = res_gethostbyname2_context (ctx, name, AF_INET); + __resolv_context_put (ctx); + return hp; } compat_symbol (libresolv, res_gethostbyname, res_gethostbyname, GLIBC_2_0); -struct hostent * -res_gethostbyname2 (const char *name, int af) +static struct hostent * +res_gethostbyname2_context (struct resolv_context *ctx, + const char *name, int af) { union { @@ -457,11 +469,6 @@ res_gethostbyname2 (const char *name, int af) int n, size, type, len; struct hostent *ret; - if (__res_maybe_init (&_res, 0) == -1) { - __set_h_errno (NETDB_INTERNAL); - return (NULL); - } - switch (af) { case AF_INET: size = INADDRSZ; @@ -485,8 +492,10 @@ res_gethostbyname2 (const char *name, int af) * this is also done in res_query() since we are not the only * function that looks up host names. */ - if (!strchr(name, '.') && (cp = __hostalias(name))) - name = cp; + char abuf[MAXDNAME]; + if (strchr (name, '.') != NULL + && (cp = __res_context_hostalias (ctx, name, abuf, sizeof (abuf)))) + name = cp; /* * disallow names consisting only of digits/dots, unless @@ -558,8 +567,9 @@ res_gethostbyname2 (const char *name, int af) buf.buf = origbuf = (querybuf *) alloca (1024); - if ((n = __libc_res_nsearch(&_res, name, C_IN, type, buf.buf->buf, 1024, - &buf.ptr, NULL, NULL, NULL, NULL)) < 0) { + if ((n = __res_context_search + (ctx, name, C_IN, type, buf.buf->buf, 1024, + &buf.ptr, NULL, NULL, NULL, NULL)) < 0) { if (buf.buf != origbuf) free (buf.buf); Dprintf("res_nsearch failed (%d)\n", n); @@ -572,11 +582,26 @@ res_gethostbyname2 (const char *name, int af) free (buf.buf); return ret; } + +struct hostent * +res_gethostbyname2 (const char *name, int af) +{ + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) + { + __set_h_errno (NETDB_INTERNAL); + return NULL; + } + struct hostent *hp = res_gethostbyname2_context (ctx, name, AF_INET); + __resolv_context_put (ctx); + return hp; +} libresolv_hidden_def (res_gethostbyname2) compat_symbol (libresolv, res_gethostbyname2, res_gethostbyname2, GLIBC_2_0); -struct hostent * -res_gethostbyaddr (const void *addr, socklen_t len, int af) +static struct hostent * +res_gethostbyaddr_context (struct resolv_context *ctx, + const void *addr, socklen_t len, int af) { const u_char *uaddr = (const u_char *)addr; static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff }; @@ -592,10 +617,6 @@ res_gethostbyaddr (const void *addr, socklen_t len, int af) struct hostent *hp; char qbuf[MAXDNAME+1], *qp = NULL; - if (__res_maybe_init (&_res, 0) == -1) { - __set_h_errno (NETDB_INTERNAL); - return (NULL); - } if (af == AF_INET6 && len == IN6ADDRSZ && (!memcmp(uaddr, mapped, sizeof mapped) || !memcmp(uaddr, tunnelled, sizeof tunnelled))) { @@ -645,8 +666,8 @@ res_gethostbyaddr (const void *addr, socklen_t len, int af) buf.buf = orig_buf = (querybuf *) alloca (1024); - n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf, 1024, - &buf.ptr, NULL, NULL, NULL, NULL); + n = __res_context_query (ctx, qbuf, C_IN, T_PTR, buf.buf->buf, 1024, + &buf.ptr, NULL, NULL, NULL, NULL); if (n < 0) { if (buf.buf != orig_buf) free (buf.buf); @@ -673,6 +694,20 @@ res_gethostbyaddr (const void *addr, socklen_t len, int af) __set_h_errno (NETDB_SUCCESS); return (hp); } + +struct hostent * +res_gethostbyaddr (const void *addr, socklen_t len, int af) +{ + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) + { + __set_h_errno (NETDB_INTERNAL); + return NULL; + } + struct hostent *hp = res_gethostbyaddr_context (ctx, addr, len, af); + __resolv_context_put (ctx); + return hp; +} compat_symbol (libresolv, res_gethostbyaddr, res_gethostbyaddr, GLIBC_2_0); void diff --git a/resolv/nss_dns/dns-canon.c b/resolv/nss_dns/dns-canon.c index 4276eb6542..7a5c39dc20 100644 --- a/resolv/nss_dns/dns-canon.c +++ b/resolv/nss_dns/dns-canon.c @@ -23,7 +23,8 @@ #include <stdint.h> #include <arpa/nameser.h> #include <nsswitch.h> - +#include <resolv/resolv_context.h> +#include <resolv/resolv-internal.h> #if PACKETSZ > 65536 # define MAXPACKET PACKETSZ @@ -58,11 +59,19 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen, } ansp = { .ptr = buf }; enum nss_status status = NSS_STATUS_UNAVAIL; + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) + { + *errnop = errno; + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } + for (int i = 0; i < nqtypes; ++i) { - int r = __libc_res_nquery (&_res, name, ns_c_in, qtypes[i], - buf, sizeof (buf), &ansp.ptr, NULL, NULL, - NULL, NULL); + int r = __res_context_query (ctx, name, ns_c_in, qtypes[i], + buf, sizeof (buf), &ansp.ptr, NULL, NULL, + NULL, NULL); if (r > 0) { /* We need to decode the response. Just one question record. @@ -168,6 +177,6 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen, if (ansp.ptr != buf) free (ansp.ptr); - + __resolv_context_put (ctx); return status; } diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c index 206924de86..9d7ceb1691 100644 --- a/resolv/nss_dns/dns-host.c +++ b/resolv/nss_dns/dns-host.c @@ -84,6 +84,7 @@ /* Get implementeation for some internal functions. */ #include <resolv/resolv-internal.h> +#include <resolv/resolv_context.h> #include <resolv/mapv4v6addr.h> #include <resolv/mapv4v6hostent.h> @@ -121,13 +122,13 @@ static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1, int *errnop, int *h_errnop, int32_t *ttlp); -extern enum nss_status _nss_dns_gethostbyname3_r (const char *name, int af, - struct hostent *result, - char *buffer, size_t buflen, - int *errnop, int *h_errnop, - int32_t *ttlp, - char **canonp); -hidden_proto (_nss_dns_gethostbyname3_r) +static enum nss_status gethostbyname3_context (struct resolv_context *ctx, + const char *name, int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp, + char **canonp); /* Return the expected RDATA length for an address record type (A or AAAA). */ @@ -145,11 +146,31 @@ rrtype_to_rdata_length (int type) } } + enum nss_status _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop, int32_t *ttlp, char **canonp) { + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) + { + *errnop = errno; + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } + enum nss_status status = gethostbyname3_context + (ctx, name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp); + __resolv_context_put (ctx); + return status; +} + +static enum nss_status +gethostbyname3_context (struct resolv_context *ctx, + const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *h_errnop, int32_t *ttlp, char **canonp) +{ union { querybuf *buf; @@ -163,13 +184,6 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result, int olderr = errno; enum nss_status status; - if (__res_maybe_init (&_res, 0) == -1) - { - *errnop = errno; - *h_errnop = NETDB_INTERNAL; - return NSS_STATUS_UNAVAIL; - } - switch (af) { case AF_INET: size = INADDRSZ; @@ -194,13 +208,13 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result, * function that looks up host names. */ if (strchr (name, '.') == NULL - && (cp = res_hostalias (&_res, name, tmp, sizeof (tmp))) != NULL) + && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL) name = cp; host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024); - n = __libc_res_nsearch (&_res, name, C_IN, type, host_buffer.buf->buf, - 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); + n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf, + 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); if (n < 0) { switch (errno) @@ -232,10 +246,10 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result, by having the RES_USE_INET6 bit in _res.options set, we try another lookup. */ if (af == AF_INET6 && res_use_inet6 ()) - n = __libc_res_nsearch (&_res, name, C_IN, T_A, host_buffer.buf->buf, - host_buffer.buf != orig_host_buffer - ? MAXPACKET : 1024, &host_buffer.ptr, - NULL, NULL, NULL, NULL); + n = __res_context_search (ctx, name, C_IN, T_A, host_buffer.buf->buf, + host_buffer.buf != orig_host_buffer + ? MAXPACKET : 1024, &host_buffer.ptr, + NULL, NULL, NULL, NULL); if (n < 0) { @@ -256,8 +270,6 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result, free (host_buffer.buf); return status; } -hidden_def (_nss_dns_gethostbyname3_r) - enum nss_status _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result, @@ -274,15 +286,21 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop) { + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) + { + *errnop = errno; + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } enum nss_status status = NSS_STATUS_NOTFOUND; - if (res_use_inet6 ()) - status = _nss_dns_gethostbyname3_r (name, AF_INET6, result, buffer, - buflen, errnop, h_errnop, NULL, NULL); + status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer, + buflen, errnop, h_errnop, NULL, NULL); if (status == NSS_STATUS_NOTFOUND) - status = _nss_dns_gethostbyname3_r (name, AF_INET, result, buffer, - buflen, errnop, h_errnop, NULL, NULL); - + status = gethostbyname3_context (ctx, name, AF_INET, result, buffer, + buflen, errnop, h_errnop, NULL, NULL); + __resolv_context_put (ctx); return status; } @@ -292,7 +310,8 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, char *buffer, size_t buflen, int *errnop, int *herrnop, int32_t *ttlp) { - if (__res_maybe_init (&_res, 0) == -1) + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) { *errnop = errno; *herrnop = NETDB_INTERNAL; @@ -307,7 +326,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, if (strchr (name, '.') == NULL) { char *tmp = alloca (NS_MAXDNAME); - const char *cp = res_hostalias (&_res, name, tmp, NS_MAXDNAME); + const char *cp = __res_context_hostalias (ctx, name, tmp, NS_MAXDNAME); if (cp != NULL) name = cp; } @@ -326,9 +345,9 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, int olderr = errno; enum nss_status status; - int n = __libc_res_nsearch (&_res, name, C_IN, T_QUERY_A_AND_AAAA, - host_buffer.buf->buf, 2048, &host_buffer.ptr, - &ans2p, &nans2p, &resplen2, &ans2p_malloced); + int n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA, + host_buffer.buf->buf, 2048, &host_buffer.ptr, + &ans2p, &nans2p, &resplen2, &ans2p_malloced); if (n >= 0) { status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p, @@ -371,6 +390,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, if (host_buffer.buf != orig_host_buffer) free (host_buffer.buf); + __resolv_context_put (ctx); return status; } @@ -423,7 +443,8 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, host_data = (struct host_data *) buffer; - if (__res_maybe_init (&_res, 0) == -1) + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) { *errnop = errno; *h_errnop = NETDB_INTERNAL; @@ -453,12 +474,14 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, default: *errnop = EAFNOSUPPORT; *h_errnop = NETDB_INTERNAL; + __resolv_context_put (ctx); return NSS_STATUS_UNAVAIL; } if (size > len) { *errnop = EAFNOSUPPORT; *h_errnop = NETDB_INTERNAL; + __resolv_context_put (ctx); return NSS_STATUS_UNAVAIL; } @@ -487,14 +510,15 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, break; } - n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf, - 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); + n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf, + 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); if (n < 0) { *h_errnop = h_errno; __set_errno (olderr); if (host_buffer.buf != orig_host_buffer) free (host_buffer.buf); + __resolv_context_put (ctx); return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; } @@ -503,7 +527,10 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, if (host_buffer.buf != orig_host_buffer) free (host_buffer.buf); if (status != NSS_STATUS_SUCCESS) - return status; + { + __resolv_context_put (ctx); + return status; + } result->h_addrtype = af; result->h_length = len; @@ -511,6 +538,7 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, host_data->h_addr_ptrs[0] = (char *) host_data->host_addr; host_data->h_addr_ptrs[1] = NULL; *h_errnop = NETDB_SUCCESS; + __resolv_context_put (ctx); return NSS_STATUS_SUCCESS; } hidden_def (_nss_dns_gethostbyaddr2_r) diff --git a/resolv/nss_dns/dns-network.c b/resolv/nss_dns/dns-network.c index dc1599b471..f190eb2225 100644 --- a/resolv/nss_dns/dns-network.c +++ b/resolv/nss_dns/dns-network.c @@ -67,6 +67,8 @@ #include "nsswitch.h" #include <arpa/inet.h> #include <arpa/nameser.h> +#include <resolv/resolv-internal.h> +#include <resolv/resolv_context.h> /* Maximum number of aliases we allow. */ #define MAX_NR_ALIASES 48 @@ -115,7 +117,8 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result, int anslen; enum nss_status status; - if (__res_maybe_init (&_res, 0) == -1) + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) { *errnop = errno; *herrnop = NETDB_INTERNAL; @@ -124,14 +127,16 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result, net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024); - anslen = __libc_res_nsearch (&_res, name, C_IN, T_PTR, net_buffer.buf->buf, - 1024, &net_buffer.ptr, NULL, NULL, NULL, NULL); + anslen = __res_context_search + (ctx, name, C_IN, T_PTR, net_buffer.buf->buf, + 1024, &net_buffer.ptr, NULL, NULL, NULL, NULL); if (anslen < 0) { /* Nothing found. */ *errnop = errno; if (net_buffer.buf != orig_net_buffer) free (net_buffer.buf); + __resolv_context_put (ctx); return (errno == ECONNREFUSED || errno == EPFNOSUPPORT || errno == EAFNOSUPPORT) @@ -142,6 +147,7 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result, errnop, herrnop, BYNAME); if (net_buffer.buf != orig_net_buffer) free (net_buffer.buf); + __resolv_context_put (ctx); return status; } @@ -169,7 +175,8 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result, if (type != AF_INET) return NSS_STATUS_UNAVAIL; - if (__res_maybe_init (&_res, 0) == -1) + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) { *errnop = errno; *herrnop = NETDB_INTERNAL; @@ -204,8 +211,8 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result, net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024); - anslen = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf, - 1024, &net_buffer.ptr, N |
