From 352f4ff9a268b81ef5d4b2413f582565806e4790 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 30 Jun 2017 21:10:23 +0200 Subject: 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. --- resolv/res_query.c | 298 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 172 insertions(+), 126 deletions(-) (limited to 'resolv/res_query.c') diff --git a/resolv/res_query.c b/resolv/res_query.c index 760bf32..33249e3 100644 --- a/resolv/res_query.c +++ b/resolv/res_query.c @@ -75,6 +75,7 @@ #include #include #include +#include #include #include #include @@ -89,33 +90,28 @@ #define QUERYSIZE (HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1) static int -__libc_res_nquerydomain(res_state statp, const char *name, const char *domain, - int class, int type, u_char *answer, int anslen, - u_char **answerp, u_char **answerp2, int *nanswerp2, - int *resplen2, int *answerp2_malloced); - -/* - * Formulate a normal query, send, and await answer. - * Returned answer is placed in supplied buffer "answer". - * Perform preliminary check of answer, returning success only - * if no error is indicated and the answer count is nonzero. - * Return the size of the response on success, -1 on error. - * Error number is left in H_ERRNO. - * - * Caller must parse answer and determine whether it answers the question. - */ +__res_context_querydomain (struct resolv_context *, + const char *name, const char *domain, + int class, int type, unsigned char *answer, int anslen, + unsigned char **answerp, unsigned char **answerp2, int *nanswerp2, + int *resplen2, int *answerp2_malloced); + +/* Formulate a normal query, send, and await answer. Returned answer + is placed in supplied buffer ANSWER. Perform preliminary check of + answer, returning success only if no error is indicated and the + answer count is nonzero. Return the size of the response on + success, -1 on error. Error number is left in h_errno. + + Caller must parse answer and determine whether it answers the + question. */ int -__libc_res_nquery(res_state statp, - const char *name, /* domain name */ - int class, int type, /* class and type of query */ - u_char *answer, /* buffer to put answer */ - int anslen, /* size of answer buffer */ - u_char **answerp, /* if buffer needs to be enlarged */ - u_char **answerp2, - int *nanswerp2, - int *resplen2, - int *answerp2_malloced) +__res_context_query (struct resolv_context *ctx, const char *name, + int class, int type, + unsigned char *answer, int anslen, + unsigned char **answerp, unsigned char **answerp2, + int *nanswerp2, int *resplen2, int *answerp2_malloced) { + struct __res_state *statp = ctx->resp; HEADER *hp = (HEADER *) answer; HEADER *hp2; int n, use_malloc = 0; @@ -132,15 +128,15 @@ __libc_res_nquery(res_state statp, if (type == T_QUERY_A_AND_AAAA) { - n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL, - query1, bufsize); + n = __res_context_mkquery (ctx, QUERY, name, class, T_A, NULL, + query1, bufsize); if (n > 0) { if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) { /* Use RESOLV_EDNS_BUFFER_SIZE because the receive buffer can be reallocated. */ - n = __res_nopt (statp, n, query1, bufsize, + n = __res_nopt (ctx, n, query1, bufsize, RESOLV_EDNS_BUFFER_SIZE); if (n < 0) goto unspec_nomem; @@ -157,13 +153,13 @@ __libc_res_nquery(res_state statp, } int nused = n + npad; query2 = buf + nused; - n = res_nmkquery(statp, QUERY, name, class, T_AAAA, NULL, 0, - NULL, query2, bufsize - nused); + n = __res_context_mkquery (ctx, QUERY, name, class, T_AAAA, + NULL, query2, bufsize - nused); if (n > 0 && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) /* Use RESOLV_EDNS_BUFFER_SIZE because the receive buffer can be reallocated. */ - n = __res_nopt (statp, n, query2, bufsize, + n = __res_nopt (ctx, n, query2, bufsize, RESOLV_EDNS_BUFFER_SIZE); nquery2 = n; } @@ -172,8 +168,8 @@ __libc_res_nquery(res_state statp, } else { - n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL, - query1, bufsize); + n = __res_context_mkquery (ctx, QUERY, name, class, type, NULL, + query1, bufsize); if (n > 0 && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) @@ -185,7 +181,7 @@ __libc_res_nquery(res_state statp, advertise = anslen; else advertise = RESOLV_EDNS_BUFFER_SIZE; - n = __res_nopt (statp, n, query1, bufsize, advertise); + n = __res_nopt (ctx, n, query1, bufsize, advertise); } nquery1 = n; @@ -209,9 +205,9 @@ __libc_res_nquery(res_state statp, return (n); } assert (answerp == NULL || (void *) *answerp == (void *) answer); - n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer, - anslen, answerp, answerp2, nanswerp2, resplen2, - answerp2_malloced); + n = __res_context_send (ctx, query1, nquery1, query2, nquery2, answer, + anslen, answerp, answerp2, nanswerp2, resplen2, + answerp2_malloced); if (use_malloc) free (buf); if (n < 0) { @@ -220,7 +216,7 @@ __libc_res_nquery(res_state statp, } if (answerp != NULL) - /* __libc_res_nsend might have reallocated the buffer. */ + /* __res_context_send might have reallocated the buffer. */ hp = (HEADER *) *answerp; /* We simplify the following tests by assigning HP to HP2 or @@ -280,7 +276,24 @@ __libc_res_nquery(res_state statp, success: return (n); } -libresolv_hidden_def (__libc_res_nquery) +libresolv_hidden_def (__res_context_query) + +/* Common part of res_nquery and res_query. */ +static int +context_query_common (struct resolv_context *ctx, + const char *name, int class, int type, + unsigned char *answer, int anslen) +{ + if (ctx == NULL) + { + RES_SET_H_ERRNO (&_res, NETDB_INTERNAL); + return -1; + } + int result = __res_context_query (ctx, name, class, type, answer, anslen, + NULL, NULL, NULL, NULL, NULL); + __resolv_context_put (ctx); + return result; +} int res_nquery(res_state statp, @@ -289,41 +302,30 @@ res_nquery(res_state statp, u_char *answer, /* buffer to put answer */ int anslen) /* size of answer buffer */ { - return __libc_res_nquery(statp, name, class, type, answer, anslen, - NULL, NULL, NULL, NULL, NULL); + return context_query_common + (__resolv_context_get_override (statp), name, class, type, answer, anslen); } -libresolv_hidden_def (res_nquery) int res_query (const char *name, int class, int type, unsigned char *answer, int anslen) { - if (__res_maybe_init (&_res, 1) == -1) - { - RES_SET_H_ERRNO (&_res, NETDB_INTERNAL); - return -1; - } - return res_nquery (&_res, name, class, type, answer, anslen); + return context_query_common + (__resolv_context_get (), name, class, type, answer, anslen); } -/* - * Formulate a normal query, send, and retrieve answer in supplied buffer. - * Return the size of the response on success, -1 on error. - * If enabled, implement search rules until answer or unrecoverable failure - * is detected. Error code, if any, is left in H_ERRNO. - */ +/* Formulate a normal query, send, and retrieve answer in supplied + buffer. Return the size of the response on success, -1 on error. + If enabled, implement search rules until answer or unrecoverable + failure is detected. Error code, if any, is left in h_errno. */ int -__libc_res_nsearch(res_state statp, - const char *name, /* domain name */ - int class, int type, /* class and type of query */ - u_char *answer, /* buffer to put answer */ - int anslen, /* size of answer */ - u_char **answerp, - u_char **answerp2, - int *nanswerp2, - int *resplen2, - int *answerp2_malloced) +__res_context_search (struct resolv_context *ctx, + const char *name, int class, int type, + unsigned char *answer, int anslen, + unsigned char **answerp, unsigned char **answerp2, + int *nanswerp2, int *resplen2, int *answerp2_malloced) { + struct __res_state *statp = ctx->resp; const char *cp, * const *domain; HEADER *hp = (HEADER *) answer; char tmp[NS_MAXDNAME]; @@ -344,10 +346,11 @@ __libc_res_nsearch(res_state statp, trailing_dot++; /* If there aren't any dots, it could be a user-level alias. */ - if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL) - return (__libc_res_nquery(statp, cp, class, type, answer, - anslen, answerp, answerp2, - nanswerp2, resplen2, answerp2_malloced)); + if (!dots && (cp = __res_context_hostalias + (ctx, name, tmp, sizeof tmp))!= NULL) + return __res_context_query (ctx, cp, class, type, answer, + anslen, answerp, answerp2, + nanswerp2, resplen2, answerp2_malloced); /* * If there are enough dots in the name, let's just give it a @@ -356,10 +359,10 @@ __libc_res_nsearch(res_state statp, */ saved_herrno = -1; if (dots >= statp->ndots || trailing_dot) { - ret = __libc_res_nquerydomain(statp, name, NULL, class, type, - answer, anslen, answerp, - answerp2, nanswerp2, resplen2, - answerp2_malloced); + ret = __res_context_querydomain (ctx, name, NULL, class, type, + answer, anslen, answerp, + answerp2, nanswerp2, resplen2, + answerp2_malloced); if (ret > 0 || trailing_dot /* If the second response is valid then we use that. */ || (ret == 0 && resplen2 != NULL && *resplen2 > 0)) @@ -395,7 +398,7 @@ __libc_res_nsearch(res_state statp, const char *dname = domain[0]; searched = 1; - /* __libc_res_nquerydoman concatenates name + /* __res_context_querydoman concatenates name with dname with a "." in between. If we pass it in dname the "." we got from the configured default search path, we'll end @@ -409,11 +412,10 @@ __libc_res_nsearch(res_state statp, if (dname[0] == '\0') root_on_list++; - ret = __libc_res_nquerydomain(statp, name, dname, - class, type, - answer, anslen, answerp, - answerp2, nanswerp2, - resplen2, answerp2_malloced); + ret = __res_context_querydomain + (ctx, name, dname, class, type, + answer, anslen, answerp, answerp2, nanswerp2, + resplen2, answerp2_malloced); if (ret > 0 || (ret == 0 && resplen2 != NULL && *resplen2 > 0)) return (ret); @@ -481,10 +483,10 @@ __libc_res_nsearch(res_state statp, */ if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0) && !(tried_as_is || root_on_list)) { - ret = __libc_res_nquerydomain(statp, name, NULL, class, type, - answer, anslen, answerp, - answerp2, nanswerp2, resplen2, - answerp2_malloced); + ret = __res_context_querydomain + (ctx, name, NULL, class, type, + answer, anslen, answerp, answerp2, nanswerp2, + resplen2, answerp2_malloced); if (ret > 0 || (ret == 0 && resplen2 != NULL && *resplen2 > 0)) return (ret); @@ -512,7 +514,24 @@ __libc_res_nsearch(res_state statp, RES_SET_H_ERRNO(statp, TRY_AGAIN); return (-1); } -libresolv_hidden_def (__libc_res_nsearch) +libresolv_hidden_def (__res_context_search) + +/* Common part of res_nsearch and res_search. */ +static int +context_search_common (struct resolv_context *ctx, + const char *name, int class, int type, + unsigned char *answer, int anslen) +{ + if (ctx == NULL) + { + RES_SET_H_ERRNO (&_res, NETDB_INTERNAL); + return -1; + } + int result = __res_context_search (ctx, name, class, type, answer, anslen, + NULL, NULL, NULL, NULL, NULL); + __resolv_context_put (ctx); + return result; +} int res_nsearch(res_state statp, @@ -521,40 +540,30 @@ res_nsearch(res_state statp, u_char *answer, /* buffer to put answer */ int anslen) /* size of answer */ { - return __libc_res_nsearch(statp, name, class, type, answer, - anslen, NULL, NULL, NULL, NULL, NULL); + return context_search_common + (__resolv_context_get_override (statp), name, class, type, answer, anslen); } -libresolv_hidden_def (res_nsearch) int res_search (const char *name, int class, int type, unsigned char *answer, int anslen) { - if (__res_maybe_init (&_res, 1) == -1) - { - RES_SET_H_ERRNO (&_res, NETDB_INTERNAL); - return -1; - } - - return res_nsearch (&_res, name, class, type, answer, anslen); + return context_search_common + (__resolv_context_get (), name, class, type, answer, anslen); } -/* - * Perform a call on res_query on the concatenation of name and domain. - */ +/* Perform a call on res_query on the concatenation of name and + domain. */ static int -__libc_res_nquerydomain(res_state statp, - const char *name, - const char *domain, - int class, int type, /* class and type of query */ - u_char *answer, /* buffer to put answer */ - int anslen, /* size of answer */ - u_char **answerp, - u_char **answerp2, - int *nanswerp2, - int *resplen2, - int *answerp2_malloced) +__res_context_querydomain (struct resolv_context *ctx, + const char *name, const char *domain, + int class, int type, + unsigned char *answer, int anslen, + unsigned char **answerp, unsigned char **answerp2, + int *nanswerp2, int *resplen2, + int *answerp2_malloced) { + struct __res_state *statp = ctx->resp; char nbuf[MAXDNAME]; const char *longname = nbuf; size_t n, d; @@ -580,9 +589,28 @@ __libc_res_nquerydomain(res_state statp, } sprintf(nbuf, "%s.%s", name, domain); } - return (__libc_res_nquery(statp, longname, class, type, answer, - anslen, answerp, answerp2, nanswerp2, - resplen2, answerp2_malloced)); + return __res_context_query (ctx, longname, class, type, answer, + anslen, answerp, answerp2, nanswerp2, + resplen2, answerp2_malloced); +} + +/* Common part of res_nquerydomain and res_querydomain. */ +static int +context_querydomain_common (struct resolv_context *ctx, + const char *name, const char *domain, + int class, int type, + unsigned char *answer, int anslen) +{ + if (ctx == NULL) + { + RES_SET_H_ERRNO (&_res, NETDB_INTERNAL); + return -1; + } + int result = __res_context_querydomain (ctx, name, domain, class, type, + answer, anslen, + NULL, NULL, NULL, NULL, NULL); + __resolv_context_put (ctx); + return result; } int @@ -593,32 +621,28 @@ res_nquerydomain(res_state statp, u_char *answer, /* buffer to put answer */ int anslen) /* size of answer */ { - return __libc_res_nquerydomain(statp, name, domain, class, type, - answer, anslen, NULL, NULL, NULL, NULL, - NULL); + return context_querydomain_common + (__resolv_context_get_override (statp), + name, domain, class, type, answer, anslen); } -libresolv_hidden_def (res_nquerydomain) int res_querydomain (const char *name, const char *domain, int class, int type, unsigned char *answer, int anslen) { - if (__res_maybe_init (&_res, 1) == -1) - { - RES_SET_H_ERRNO (&_res, NETDB_INTERNAL); - return -1; - } - - return res_nquerydomain (&_res, name, domain, class, type, answer, anslen); + return context_querydomain_common + (__resolv_context_get (), name, domain, class, type, answer, anslen); } const char * -res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) { +__res_context_hostalias (struct resolv_context *ctx, + const char *name, char *dst, size_t siz) +{ char *file, *cp1, *cp2; char buf[BUFSIZ]; FILE *fp; - if (statp->options & RES_NOALIASES) + if (ctx->resp->options & RES_NOALIASES) return (NULL); file = getenv("HOSTALIASES"); if (file == NULL || (fp = fopen(file, "rce")) == NULL) @@ -648,15 +672,37 @@ res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) { fclose(fp); return (NULL); } -libresolv_hidden_def (res_hostalias) +libresolv_hidden_def (__res_context_hostalias) + +/* Common part of res_hostalias and hostalias. */ +static const char * +context_hostalias_common (struct resolv_context *ctx, + const char *name, char *dst, size_t siz) +{ + if (ctx == NULL) + { + RES_SET_H_ERRNO (&_res, NETDB_INTERNAL); + return NULL; + } + const char *result = __res_context_hostalias (ctx, name, dst, siz); + __resolv_context_put (ctx); + return result; +} + +const char * +res_hostalias (res_state statp, const char *name, char *dst, size_t siz) +{ + return context_hostalias_common + (__resolv_context_get_override (statp), name, dst, siz); +} const char * hostalias (const char *name) { static char abuf[MAXDNAME]; - return res_hostalias (&_res, name, abuf, sizeof abuf); + return context_hostalias_common + (__resolv_context_get (), name, abuf, sizeof (abuf)); } -libresolv_hidden_def (hostalias) #if SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_2) # undef res_query -- cgit v1.1