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:
@ -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
|
||||
|
Reference in New Issue
Block a user