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/res_init.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/res_init.c')
-rw-r--r-- | resolv/res_init.c | 78 |
1 files changed, 48 insertions, 30 deletions
diff --git a/resolv/res_init.c b/resolv/res_init.c index 80a21fb90d..fa46ce7813 100644 --- a/resolv/res_init.c +++ b/resolv/res_init.c @@ -106,8 +106,6 @@ static uint32_t net_mask (struct in_addr); -unsigned long long int __res_initstamp; - int res_ninit (res_state statp) { @@ -164,6 +162,16 @@ struct resolv_conf_parser struct resolv_conf template; }; +/* Return true if *PREINIT contains actual preinitialization. */ +static bool +has_preinit_values (const struct __res_state *preinit) +{ + return (preinit->retrans != 0 && preinit->retrans != RES_TIMEOUT) + || (preinit->retry != 0 && preinit->retry != RES_DFLRETRY) + || (preinit->options != 0 + && (preinit->options & ~RES_INIT) != RES_DEFAULT); +} + static void resolv_conf_parser_init (struct resolv_conf_parser *parser, const struct __res_state *preinit) @@ -531,14 +539,8 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) return true; } -/* Set up default settings. If the /etc/resolv.conf configuration - file exist, the values there will have precedence. Otherwise, the - server address is set to INADDR_LOOPBACK and the default domain - name comes from gethostname. The RES_OPTIONS and LOCALDOMAIN - environment variables can be used to override some settings. - Return 0 if completes successfully, -1 on error. */ -int -__res_vinit (res_state statp, int preinit) +struct resolv_conf * +__resolv_conf_load (struct __res_state *preinit) { /* Ensure that /etc/hosts.conf has been loaded (once). */ _res_hconf_init (); @@ -559,20 +561,14 @@ __res_vinit (res_state statp, int preinit) default: /* Other errors refer to resource allocation problems and need to be handled by the application. */ - return -1; + return NULL; } struct resolv_conf_parser parser; - if (preinit) - { - resolv_conf_parser_init (&parser, statp); - statp->id = res_randomid (); - } - else - resolv_conf_parser_init (&parser, NULL); + resolv_conf_parser_init (&parser, preinit); - bool ok = res_vinit_1 (fp, &parser); - if (ok) + struct resolv_conf *conf = NULL; + if (res_vinit_1 (fp, &parser)) { parser.template.nameserver_list = nameserver_list_begin (&parser.nameserver_list); @@ -583,21 +579,42 @@ __res_vinit (res_state statp, int preinit) = search_list_size (&parser.search_list); parser.template.sort_list = sort_list_begin (&parser.sort_list); parser.template.sort_list_size = sort_list_size (&parser.sort_list); - struct resolv_conf *conf = __resolv_conf_allocate (&parser.template); - if (conf == NULL) - ok = false; - else - { - ok = __resolv_conf_attach (statp, conf); - __resolv_conf_put (conf); - } + conf = __resolv_conf_allocate (&parser.template); } resolv_conf_parser_free (&parser); - if (!ok) + return conf; +} + +/* Set up default settings. If the /etc/resolv.conf configuration + file exist, the values there will have precedence. Otherwise, the + server address is set to INADDR_LOOPBACK and the default domain + name comes from gethostname. The RES_OPTIONS and LOCALDOMAIN + environment variables can be used to override some settings. + Return 0 if completes successfully, -1 on error. */ +int +__res_vinit (res_state statp, int preinit) +{ + struct resolv_conf *conf; + if (preinit && has_preinit_values (statp)) + /* For the preinit case, we cannot use the cached configuration + because some settings could be different. */ + conf = __resolv_conf_load (statp); + else + conf = __resolv_conf_get_current (); + if (conf == NULL) return -1; + + bool ok = __resolv_conf_attach (statp, conf); + __resolv_conf_put (conf); + if (ok) + { + if (preinit) + statp->id = res_randomid (); + return 0; + } else - return 0; + return -1; } static void @@ -652,6 +669,7 @@ res_setoptions (struct resolv_conf_parser *parser, const char *options) { STRnLEN ("single-request"), 0, RES_SNGLKUP }, { STRnLEN ("no_tld_query"), 0, RES_NOTLDQUERY }, { STRnLEN ("no-tld-query"), 0, RES_NOTLDQUERY }, + { STRnLEN ("no-reload"), 0, RES_NORELOAD }, { STRnLEN ("use-vc"), 0, RES_USEVC } }; #define noptions (sizeof (options) / sizeof (options[0])) |