| /* Temporary, thread-local resolver state. |
| Copyright (C) 2017-2018 Free Software Foundation, Inc. |
| 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 |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include <resolv_context.h> |
| #include <resolv_conf.h> |
| #include <resolv-internal.h> |
| |
| #include <assert.h> |
| #include <errno.h> |
| #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; |
| |
| /* The resolv_conf handling will gives us a ctx->conf pointer even if |
| these fields do not match because a mis-match does not cause a loss |
| 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; |
| } |
| |
| /* 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 |
| maybe_init (struct resolv_context *ctx, bool preinit) |
| { |
| struct __res_state *resp = ctx->resp; |
| if (resp->options & RES_INIT) |
| { |
| if (resp->options & RES_NORELOAD) |
| /* Configuration reloading was explicitly disabled. */ |
| return true; |
| |
| /* If there is no associated resolv_conf object despite the |
| initialization, something modified *ctx->resp. Do not |
| override those changes. */ |
| if (ctx->conf != NULL && replicated_configuration_matches (ctx)) |
| { |
| struct resolv_conf *current = __resolv_conf_get_current (); |
| if (current == NULL) |
| return false; |
| |
| /* Check if the configuration changed. */ |
| if (current != ctx->conf) |
| { |
| /* 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; |
| } |
| } |
| else |
| /* No change. Drop the reference count for current. */ |
| __resolv_conf_put (current); |
| } |
| return true; |
| } |
| |
| assert (ctx->conf == NULL); |
| 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 (); |
| } |
| |
| if (__res_vinit (resp, preinit) < 0) |
| return false; |
| ctx->conf = __resolv_conf_get (ctx->resp); |
| return true; |
| } |
| |
| /* 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; |
| ctx->conf = __resolv_conf_get (resp); |
| 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) |
| { |
| int error_code = errno; |
| current = ctx->__next; |
| __resolv_conf_put (ctx->conf); |
| free (ctx); |
| __set_errno (error_code); |
| } |
| |
| /* 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; |
| if (!maybe_init (ctx, preinit)) |
| { |
| 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; |
| } |
| } |