2017-06-30 19:10:23 +00:00
|
|
|
/* Temporary, thread-local resolver state.
|
2024-01-01 18:12:26 +00:00
|
|
|
Copyright (C) 2017-2024 Free Software Foundation, Inc.
|
2017-06-30 19:10:23 +00:00
|
|
|
This file is part of the GNU C Library.
|
|
|
|
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with the GNU C Library; if not, see
|
Prefer https to http for gnu.org and fsf.org URLs
Also, change sources.redhat.com to sourceware.org.
This patch was automatically generated by running the following shell
script, which uses GNU sed, and which avoids modifying files imported
from upstream:
sed -ri '
s,(http|ftp)(://(.*\.)?(gnu|fsf|sourceware)\.org($|[^.]|\.[^a-z])),https\2,g
s,(http|ftp)(://(.*\.)?)sources\.redhat\.com($|[^.]|\.[^a-z]),https\2sourceware.org\4,g
' \
$(find $(git ls-files) -prune -type f \
! -name '*.po' \
! -name 'ChangeLog*' \
! -path COPYING ! -path COPYING.LIB \
! -path manual/fdl-1.3.texi ! -path manual/lgpl-2.1.texi \
! -path manual/texinfo.tex ! -path scripts/config.guess \
! -path scripts/config.sub ! -path scripts/install-sh \
! -path scripts/mkinstalldirs ! -path scripts/move-if-change \
! -path INSTALL ! -path locale/programs/charmap-kw.h \
! -path po/libc.pot ! -path sysdeps/gnu/errlist.c \
! '(' -name configure \
-execdir test -f configure.ac -o -f configure.in ';' ')' \
! '(' -name preconfigure \
-execdir test -f preconfigure.ac ';' ')' \
-print)
and then by running 'make dist-prepare' to regenerate files built
from the altered files, and then executing the following to cleanup:
chmod a+x sysdeps/unix/sysv/linux/riscv/configure
# Omit irrelevant whitespace and comment-only changes,
# perhaps from a slightly-different Autoconf version.
git checkout -f \
sysdeps/csky/configure \
sysdeps/hppa/configure \
sysdeps/riscv/configure \
sysdeps/unix/sysv/linux/csky/configure
# Omit changes that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/powerpc/powerpc64/ppc-mcount.S: trailing lines
git checkout -f \
sysdeps/powerpc/powerpc64/ppc-mcount.S \
sysdeps/unix/sysv/linux/s390/s390-64/syscall.S
# Omit change that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S: last line does not end in newline
git checkout -f sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S
2019-09-07 05:40:42 +00:00
|
|
|
<https://www.gnu.org/licenses/>. */
|
2017-06-30 19:10:23 +00:00
|
|
|
|
|
|
|
#include <resolv_context.h>
|
2017-07-03 18:31:23 +00:00
|
|
|
#include <resolv_conf.h>
|
2017-06-30 19:10:23 +00:00
|
|
|
#include <resolv-internal.h>
|
|
|
|
|
|
|
|
#include <assert.h>
|
2017-07-03 18:31:23 +00:00
|
|
|
#include <errno.h>
|
2017-06-30 19:10:23 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
/* Currently active struct resolv_context object. This pointer forms
|
|
|
|
the start of a single-linked list, using the __next member of
|
|
|
|
struct resolv_context. This list serves two purposes:
|
|
|
|
|
|
|
|
(a) A subsequent call to __resolv_context_get will only increment
|
|
|
|
the reference counter and will not allocate a new object. The
|
|
|
|
_res state freshness check is skipped in this case, too.
|
|
|
|
|
|
|
|
(b) The per-thread cleanup function defined by the resolver calls
|
|
|
|
__resolv_context_freeres, which will deallocate all the context
|
|
|
|
objects. This avoids the need for cancellation handlers and
|
|
|
|
the complexity they bring, but it requires heap allocation of
|
|
|
|
the context object because the per-thread cleanup functions run
|
|
|
|
only after the stack has been fully unwound (and all on-stack
|
|
|
|
objects have been deallocated at this point).
|
|
|
|
|
|
|
|
The TLS variable current is updated even in
|
|
|
|
__resolv_context_get_override, to support case (b) above. This does
|
|
|
|
not override the per-thread resolver state (as obtained by the
|
|
|
|
non-res_state function such as __resolv_context_get) in an
|
|
|
|
observable way because the wrapped context is only used to
|
|
|
|
implement the res_n* functions in the resolver, and those do not
|
|
|
|
call back into user code which could indirectly use the per-thread
|
|
|
|
resolver state. */
|
|
|
|
static __thread struct resolv_context *current attribute_tls_model_ie;
|
|
|
|
|
2017-07-03 19:06:23 +00:00
|
|
|
/* The resolv_conf handling will gives us a ctx->conf pointer even if
|
2023-05-20 13:37:47 +00:00
|
|
|
these fields do not match because a mismatch does not cause a loss
|
2017-07-03 19:06:23 +00:00
|
|
|
of state (_res objects can store the full information). This
|
|
|
|
function checks to ensure that there is a full patch, to prevent
|
|
|
|
overwriting a patched configuration. */
|
|
|
|
static bool
|
|
|
|
replicated_configuration_matches (const struct resolv_context *ctx)
|
|
|
|
{
|
|
|
|
return ctx->resp->options == ctx->conf->options
|
|
|
|
&& ctx->resp->retrans == ctx->conf->retrans
|
|
|
|
&& ctx->resp->retry == ctx->conf->retry
|
|
|
|
&& ctx->resp->ndots == ctx->conf->ndots;
|
|
|
|
}
|
|
|
|
|
2017-06-30 19:10:23 +00:00
|
|
|
/* Initialize *RESP if RES_INIT is not yet set in RESP->options, or if
|
|
|
|
res_init in some other thread requested re-initializing. */
|
|
|
|
static __attribute__ ((warn_unused_result)) bool
|
2017-07-03 18:31:23 +00:00
|
|
|
maybe_init (struct resolv_context *ctx, bool preinit)
|
2017-06-30 19:10:23 +00:00
|
|
|
{
|
2017-07-03 18:31:23 +00:00
|
|
|
struct __res_state *resp = ctx->resp;
|
2017-06-30 19:10:23 +00:00
|
|
|
if (resp->options & RES_INIT)
|
|
|
|
{
|
2017-07-03 19:06:23 +00:00
|
|
|
if (resp->options & RES_NORELOAD)
|
|
|
|
/* Configuration reloading was explicitly disabled. */
|
|
|
|
return true;
|
|
|
|
|
2017-07-03 18:31:23 +00:00
|
|
|
/* If there is no associated resolv_conf object despite the
|
|
|
|
initialization, something modified *ctx->resp. Do not
|
|
|
|
override those changes. */
|
2017-07-03 19:06:23 +00:00
|
|
|
if (ctx->conf != NULL && replicated_configuration_matches (ctx))
|
2017-06-30 19:10:23 +00:00
|
|
|
{
|
2017-07-03 19:06:23 +00:00
|
|
|
struct resolv_conf *current = __resolv_conf_get_current ();
|
|
|
|
if (current == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Check if the configuration changed. */
|
|
|
|
if (current != ctx->conf)
|
2017-07-03 18:31:23 +00:00
|
|
|
{
|
2017-07-03 19:06:23 +00:00
|
|
|
/* This call will detach the extended resolver state. */
|
|
|
|
if (resp->nscount > 0)
|
|
|
|
__res_iclose (resp, true);
|
|
|
|
/* Reattach the current configuration. */
|
|
|
|
if (__resolv_conf_attach (ctx->resp, current))
|
|
|
|
{
|
|
|
|
__resolv_conf_put (ctx->conf);
|
|
|
|
/* ctx takes ownership, so we do not release current. */
|
|
|
|
ctx->conf = current;
|
|
|
|
}
|
2017-07-03 18:31:23 +00:00
|
|
|
}
|
2017-07-03 19:06:23 +00:00
|
|
|
else
|
|
|
|
/* No change. Drop the reference count for current. */
|
|
|
|
__resolv_conf_put (current);
|
2017-06-30 19:10:23 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-07-03 18:31:23 +00:00
|
|
|
assert (ctx->conf == NULL);
|
2017-06-30 19:10:23 +00:00
|
|
|
if (preinit)
|
|
|
|
{
|
|
|
|
if (!resp->retrans)
|
|
|
|
resp->retrans = RES_TIMEOUT;
|
|
|
|
if (!resp->retry)
|
|
|
|
resp->retry = RES_DFLRETRY;
|
|
|
|
resp->options = RES_DEFAULT;
|
|
|
|
if (!resp->id)
|
|
|
|
resp->id = res_randomid ();
|
|
|
|
}
|
2017-07-03 18:31:23 +00:00
|
|
|
|
|
|
|
if (__res_vinit (resp, preinit) < 0)
|
|
|
|
return false;
|
|
|
|
ctx->conf = __resolv_conf_get (ctx->resp);
|
|
|
|
return true;
|
2017-06-30 19:10:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate a new context object and initialize it. The object is put
|
|
|
|
on the current list. */
|
|
|
|
static struct resolv_context *
|
|
|
|
context_alloc (struct __res_state *resp)
|
|
|
|
{
|
|
|
|
struct resolv_context *ctx = malloc (sizeof (*ctx));
|
|
|
|
if (ctx == NULL)
|
|
|
|
return NULL;
|
|
|
|
ctx->resp = resp;
|
2017-07-03 18:31:23 +00:00
|
|
|
ctx->conf = __resolv_conf_get (resp);
|
2017-06-30 19:10:23 +00:00
|
|
|
ctx->__refcount = 1;
|
|
|
|
ctx->__from_res = true;
|
|
|
|
ctx->__next = current;
|
|
|
|
current = ctx;
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Deallocate the context object and all the state within. */
|
|
|
|
static void
|
|
|
|
context_free (struct resolv_context *ctx)
|
|
|
|
{
|
2017-07-03 18:31:23 +00:00
|
|
|
int error_code = errno;
|
2017-06-30 19:10:23 +00:00
|
|
|
current = ctx->__next;
|
2017-07-03 18:31:23 +00:00
|
|
|
__resolv_conf_put (ctx->conf);
|
2017-06-30 19:10:23 +00:00
|
|
|
free (ctx);
|
2017-07-03 18:31:23 +00:00
|
|
|
__set_errno (error_code);
|
2017-06-30 19:10:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Reuse the current context object. */
|
|
|
|
static struct resolv_context *
|
|
|
|
context_reuse (void)
|
|
|
|
{
|
|
|
|
/* A context object created by __resolv_context_get_override cannot
|
|
|
|
be reused. */
|
|
|
|
assert (current->__from_res);
|
|
|
|
|
|
|
|
++current->__refcount;
|
|
|
|
|
|
|
|
/* Check for reference counter wraparound. This can only happen if
|
|
|
|
the get/put functions are not properly paired. */
|
|
|
|
assert (current->__refcount > 0);
|
|
|
|
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Backing function for the __resolv_context_get family of
|
|
|
|
functions. */
|
|
|
|
static struct resolv_context *
|
|
|
|
context_get (bool preinit)
|
|
|
|
{
|
|
|
|
if (current != NULL)
|
|
|
|
return context_reuse ();
|
|
|
|
|
|
|
|
struct resolv_context *ctx = context_alloc (&_res);
|
|
|
|
if (ctx == NULL)
|
|
|
|
return NULL;
|
2017-07-03 18:31:23 +00:00
|
|
|
if (!maybe_init (ctx, preinit))
|
2017-06-30 19:10:23 +00:00
|
|
|
{
|
|
|
|
context_free (ctx);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct resolv_context *
|
|
|
|
__resolv_context_get (void)
|
|
|
|
{
|
|
|
|
return context_get (false);
|
|
|
|
}
|
|
|
|
libc_hidden_def (__resolv_context_get)
|
|
|
|
|
|
|
|
struct resolv_context *
|
|
|
|
__resolv_context_get_preinit (void)
|
|
|
|
{
|
|
|
|
return context_get (true);
|
|
|
|
}
|
|
|
|
libc_hidden_def (__resolv_context_get_preinit)
|
|
|
|
|
|
|
|
struct resolv_context *
|
|
|
|
__resolv_context_get_override (struct __res_state *resp)
|
|
|
|
{
|
|
|
|
/* NB: As explained asbove, context_alloc will put the context on
|
|
|
|
the current list. */
|
|
|
|
struct resolv_context *ctx = context_alloc (resp);
|
|
|
|
if (ctx == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ctx->__from_res = false;
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
libc_hidden_def (__resolv_context_get_override)
|
|
|
|
|
|
|
|
void
|
|
|
|
__resolv_context_put (struct resolv_context *ctx)
|
|
|
|
{
|
|
|
|
if (ctx == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* NB: Callers assume that this function preserves errno and
|
|
|
|
h_errno. */
|
|
|
|
|
|
|
|
assert (current == ctx);
|
|
|
|
assert (ctx->__refcount > 0);
|
|
|
|
|
|
|
|
if (ctx->__from_res && --ctx->__refcount > 0)
|
|
|
|
/* Do not pop this context yet. */
|
|
|
|
return;
|
|
|
|
|
|
|
|
context_free (ctx);
|
|
|
|
}
|
|
|
|
libc_hidden_def (__resolv_context_put)
|
|
|
|
|
|
|
|
void
|
|
|
|
__resolv_context_freeres (void)
|
|
|
|
{
|
|
|
|
/* Deallocate the entire chain of context objects. */
|
|
|
|
struct resolv_context *ctx = current;
|
|
|
|
current = NULL;
|
|
|
|
while (ctx != NULL)
|
|
|
|
{
|
|
|
|
struct resolv_context *next = ctx->__next;
|
|
|
|
context_free (ctx);
|
|
|
|
ctx = next;
|
|
|
|
}
|
|
|
|
}
|