diff options
author | Florian Weimer <fweimer@redhat.com> | 2017-07-03 21:06:23 +0200 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2017-07-03 21:06:23 +0200 |
commit | aef16cc8a4c670036d45590877d411a97f01e0cd (patch) | |
tree | 4403f1962170ce92087a6e1af62dbb92e15d27f6 /resolv/resolv_context.c | |
parent | a1c4eb8794e789b5055d7ceb13b2b3231abf5e26 (diff) | |
download | glibc-aef16cc8a4c670036d45590877d411a97f01e0cd.tar.gz glibc-aef16cc8a4c670036d45590877d411a97f01e0cd.tar.xz glibc-aef16cc8a4c670036d45590877d411a97f01e0cd.zip |
resolv: Automatically reload a changed /etc/resolv.conf file [BZ #984]
This commit enhances the stub resolver to reload the configuration in the per-thread _res object if the /etc/resolv.conf file has changed. The resolver checks whether the application has modified _res and will not overwrite the _res object in that case. The struct resolv_context mechanism is used to check the configuration file only once per name lookup.
Diffstat (limited to 'resolv/resolv_context.c')
-rw-r--r-- | resolv/resolv_context.c | 53 |
1 files changed, 38 insertions, 15 deletions
diff --git a/resolv/resolv_context.c b/resolv/resolv_context.c index 0ee2184055..35d4b3d41d 100644 --- a/resolv/resolv_context.c +++ b/resolv/resolv_context.c @@ -51,6 +51,20 @@ 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 @@ -59,27 +73,36 @@ 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 && ctx->conf->initstamp != __res_initstamp) + if (ctx->conf != NULL && replicated_configuration_matches (ctx)) { - if (resp->nscount > 0) - /* This call will detach the extended resolver state. */ - __res_iclose (resp, true); - /* And this call will attach it again. */ - if (__res_vinit (resp, 1) < 0) + struct resolv_conf *current = __resolv_conf_get_current (); + if (current == NULL) + return false; + + /* Check if the configuration changed. */ + if (current != ctx->conf) { - /* The configuration no longer matches after failed - initialization. */ - __resolv_conf_put (ctx->conf); - ctx->conf = NULL; - return false; + /* 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; + } } - /* Delay the release of the old configuration until this - point, so that __res_vinit can reuse it if possible. */ - __resolv_conf_put (ctx->conf); - ctx->conf = __resolv_conf_get (ctx->resp); + else + /* No change. Drop the reference count for current. */ + __resolv_conf_put (current); } return true; } |