1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-28 00:21:52 +03:00

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.
This commit is contained in:
Florian Weimer
2017-06-30 21:10:23 +02:00
parent 4e45d83c92
commit 352f4ff9a2
24 changed files with 1032 additions and 370 deletions

View File

@ -75,6 +75,7 @@
#include <netdb.h>
#include <resolv.h>
#include <resolv/resolv-internal.h>
#include <resolv/resolv_context.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -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);
__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.
*/
/* 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