summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorvangyzen <vangyzen@FreeBSD.org>2015-10-14 14:26:44 +0000
committervangyzen <vangyzen@FreeBSD.org>2015-10-14 14:26:44 +0000
commit60458e70da25850f61b9877b8eae858c8ebe875d (patch)
tree898ee83d1d591faf4a93dd91b88fc597457060f4 /lib
parentb800f004107ceb768773500aa53149cd9cc29f77 (diff)
downloadFreeBSD-src-60458e70da25850f61b9877b8eae858c8ebe875d.zip
FreeBSD-src-60458e70da25850f61b9877b8eae858c8ebe875d.tar.gz
resolver: automatically reload /etc/resolv.conf
On each resolver query, use stat(2) to see if the modification time of /etc/resolv.conf has changed. If so, reload the file and reinitialize the resolver library. However, only call stat(2) if at least two seconds have passed since the last call to stat(2), since calling it on every query could kill performance. This new behavior is enabled by default. Add a "reload-period" option to disable it or change the period of the test. Document this behavior and option in resolv.conf(5). Polish the man page just enough to appease igor. https://lists.freebsd.org/pipermail/freebsd-arch/2015-October/017342.html Reviewed by: kp, wblock Discussed with: jilles, imp, alfred MFC after: 1 month Relnotes: yes Sponsored by: Dell Inc. Differential Revision: https://reviews.freebsd.org/D3867
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/resolv/res_init.c22
-rw-r--r--lib/libc/resolv/res_state.c31
2 files changed, 51 insertions, 2 deletions
diff --git a/lib/libc/resolv/res_init.c b/lib/libc/resolv/res_init.c
index 4dbd6d1..087e6a8 100644
--- a/lib/libc/resolv/res_init.c
+++ b/lib/libc/resolv/res_init.c
@@ -78,6 +78,7 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/time.h>
#include <netinet/in.h>
@@ -227,6 +228,7 @@ __res_vinit(res_state statp, int preinit) {
statp->pfcode = 0;
statp->_vcsock = -1;
statp->_flags = 0;
+ statp->reload_period = 2;
statp->qhook = NULL;
statp->rhook = NULL;
statp->_u._ext.nscount = 0;
@@ -321,6 +323,22 @@ __res_vinit(res_state statp, int preinit) {
nserv = 0;
if ((fp = fopen(_PATH_RESCONF, "re")) != NULL) {
+ struct stat sb;
+ struct timespec now;
+
+ if (_fstat(fileno(fp), &sb) == 0) {
+ statp->conf_mtim = sb.st_mtim;
+ if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) == 0) {
+ statp->conf_stat = now.tv_sec;
+ } else {
+ statp->conf_stat = 0;
+ }
+ } else {
+ statp->conf_mtim.tv_sec = 0;
+ statp->conf_mtim.tv_nsec = 0;
+ statp->conf_stat = 0;
+ }
+
/* read the config file */
while (fgets(buf, sizeof(buf), fp) != NULL) {
/* skip comments */
@@ -666,6 +684,10 @@ res_setoptions(res_state statp, const char *options, const char *source)
} else if (!strncmp(cp, "no-check-names",
sizeof("no-check-names") - 1)) {
statp->options |= RES_NOCHECKNAME;
+ } else if (!strncmp(cp, "reload-period:",
+ sizeof("reload-period:") - 1)) {
+ statp->reload_period = (u_short)
+ atoi(cp + sizeof("reload-period:") - 1);
}
#ifdef RES_USE_EDNS0
else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
diff --git a/lib/libc/resolv/res_state.c b/lib/libc/resolv/res_state.c
index 59c9430..87643422 100644
--- a/lib/libc/resolv/res_state.c
+++ b/lib/libc/resolv/res_state.c
@@ -26,6 +26,8 @@
*/
#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
@@ -59,13 +61,38 @@ res_keycreate(void)
res_thr_keycreated = thr_keycreate(&res_key, free_res) == 0;
}
+static res_state
+res_check_reload(res_state statp)
+{
+ struct timespec now;
+ struct stat sb;
+
+ if ((statp->options & RES_INIT) == 0 || statp->reload_period == 0) {
+ return (statp);
+ }
+
+ if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) != 0 ||
+ (now.tv_sec - statp->conf_stat) < statp->reload_period) {
+ return (statp);
+ }
+
+ statp->conf_stat = now.tv_sec;
+ if (stat(_PATH_RESCONF, &sb) == 0 &&
+ (sb.st_mtim.tv_sec != statp->conf_mtim.tv_sec ||
+ sb.st_mtim.tv_nsec != statp->conf_mtim.tv_nsec)) {
+ statp->options &= ~RES_INIT;
+ }
+
+ return (statp);
+}
+
res_state
__res_state(void)
{
res_state statp;
if (thr_main() != 0)
- return (&_res);
+ return res_check_reload(&_res);
if (thr_once(&res_init_once, res_keycreate) != 0 ||
!res_thr_keycreated)
@@ -73,7 +100,7 @@ __res_state(void)
statp = thr_getspecific(res_key);
if (statp != NULL)
- return (statp);
+ return res_check_reload(statp);
statp = calloc(1, sizeof(*statp));
if (statp == NULL)
return (&_res);
OpenPOWER on IntegriCloud