Index: include/resolv.h =================================================================== --- include/resolv.h +++ include/resolv.h @@ -188,6 +188,8 @@ } _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; @@ -243,6 +245,7 @@ #define RES_KEEPTSIG 0x00010000 /*%< do not strip TSIG records */ #define RES_BLAST 0x00020000 /*%< blast all recursive servers */ #define RES_NSID 0x00040000 /*%< request name server ID */ +#define RES_NO_RELOAD 0x00080000 /*%< no auto reload of resolv.conf */ #define RES_NOTLDQUERY 0x00100000 /*%< don't unqualified name as a tld */ #define RES_USE_DNSSEC 0x00200000 /*%< use DNSSEC using OK bit in OPT */ /* #define RES_DEBUG2 0x00400000 */ /* nslookup internal */ Index: lib/libc/resolv/res_init.c =================================================================== --- lib/libc/resolv/res_init.c +++ lib/libc/resolv/res_init.c @@ -78,6 +78,7 @@ #include #include #include +#include #include #include @@ -321,6 +322,22 @@ 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,7 +683,9 @@ } else if (!strncmp(cp, "no-check-names", sizeof("no-check-names") - 1)) { statp->options |= RES_NOCHECKNAME; - } + } else if (!strncmp(cp, "no-reload", sizeof("no-reload") - 1)) { + statp->options |= RES_NO_RELOAD; + } #ifdef RES_USE_EDNS0 else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) { statp->options |= RES_USE_EDNS0; Index: lib/libc/resolv/res_state.c =================================================================== --- lib/libc/resolv/res_state.c +++ lib/libc/resolv/res_state.c @@ -26,6 +26,8 @@ */ #include +#include +#include #include #include #include @@ -37,6 +39,8 @@ #undef _res +#define RELOAD_INTERVAL 10 /* seconds */ + struct __res_state _res; static thread_key_t res_key; @@ -59,13 +63,35 @@ res_thr_keycreated = thr_keycreate(&res_key, free_res) == 0; } +static res_state +res_check_reload(res_state statp) +{ + if ((statp->options & (RES_INIT|RES_NO_RELOAD)) == RES_INIT) { + struct timespec now; + + if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) != 0 || + (now.tv_sec - statp->conf_stat) >= RELOAD_INTERVAL) { + struct stat sb; + + 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 +99,7 @@ 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); Index: share/man/man5/resolver.5 =================================================================== --- share/man/man5/resolver.5 +++ share/man/man5/resolver.5 @@ -28,7 +28,7 @@ .\" @(#)resolver.5 8.1 (Berkeley) 6/5/93 .\" $FreeBSD$ .\" -.Dd December 25, 2013 +.Dd October 9, 2015 .Dt RESOLVER 5 .Os .Sh NAME @@ -175,6 +175,14 @@ and .Sy search rules with the given name. +.It Sy no-reload +Do not automatically reload +.Pa /etc/resolv.conf +when the file changes. +By default, the resolver will notice modifications +within ten seconds and automatically reload the file. +Small or heavily loaded systems might use this option to disable +this behavior. .El .Pp Options may also be specified as a space or tab separated list using the @@ -191,7 +199,7 @@ the last instance will override. .Pp The keyword and value must appear on a single line, and the keyword -(e.g.\& +(e.g.,\& .Sy nameserver ) must start the line. The value follows the keyword, separated by white space.