diff options
-rw-r--r-- | include/resolv.h | 5 | ||||
-rw-r--r-- | lib/libc/resolv/res_init.c | 22 | ||||
-rw-r--r-- | lib/libc/resolv/res_state.c | 31 | ||||
-rw-r--r-- | share/man/man5/resolver.5 | 18 |
4 files changed, 70 insertions, 6 deletions
diff --git a/include/resolv.h b/include/resolv.h index e3d4fd1..78da374 100644 --- a/include/resolv.h +++ b/include/resolv.h @@ -176,7 +176,8 @@ struct __res_state { int res_h_errno; /*%< last one set for this context */ int _vcsock; /*%< PRIVATE: for res_send VC i/o */ u_int _flags; /*%< PRIVATE: see below */ - u_int _pad; /*%< make _u 64 bit aligned */ + u_short reload_period; /*%< seconds between stat(resolv.conf)*/ + u_short _pad; /*%< make _u 64 bit aligned */ union { /* On an 32-bit arch this means 512b total. */ char pad[72 - 4*sizeof (int) - 3*sizeof (void *)]; @@ -188,6 +189,8 @@ struct __res_state { } _ext; } _u; u_char *_rnd; /*%< PRIVATE: random state */ + struct timespec conf_mtim; /*%< mod time of loaded resolv.conf */ + time_t conf_stat; /*%< time of last stat(resolv.conf) */ }; typedef struct __res_state *res_state; 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); diff --git a/share/man/man5/resolver.5 b/share/man/man5/resolver.5 index 4116f23..a3c5e05 100644 --- a/share/man/man5/resolver.5 +++ b/share/man/man5/resolver.5 @@ -28,7 +28,7 @@ .\" @(#)resolver.5 8.1 (Berkeley) 6/5/93 .\" $FreeBSD$ .\" -.Dd December 25, 2013 +.Dd October 12, 2015 .Dt RESOLVER 5 .Os .Sh NAME @@ -175,6 +175,19 @@ the resolver from obeying the standard and .Sy search rules with the given name. +.It Sy reload-period: Ns Ar n +The resolver checks the modification time of +.Pa /etc/resolv.conf +every +.Ar n +seconds. +If +.Pa /etc/resolv.conf +has changed, it is automatically reloaded. +The default for +.Ar n +is two seconds. +Setting it to zero disables the file check. .El .Pp Options may also be specified as a space or tab separated list using the @@ -191,8 +204,7 @@ If more than one instance of these keywords is present, the last instance will override. .Pp The keyword and value must appear on a single line, and the keyword -(e.g.\& -.Sy nameserver ) +.Pq for example, Sy nameserver must start the line. The value follows the keyword, separated by white space. .Sh FILES |