From owner-svn-src-head@freebsd.org Wed Oct 14 14:26:46 2015 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 28484A13514; Wed, 14 Oct 2015 14:26:46 +0000 (UTC) (envelope-from vangyzen@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id F336A19A5; Wed, 14 Oct 2015 14:26:45 +0000 (UTC) (envelope-from vangyzen@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id t9EEQjA9079422; Wed, 14 Oct 2015 14:26:45 GMT (envelope-from vangyzen@FreeBSD.org) Received: (from vangyzen@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id t9EEQiWX079418; Wed, 14 Oct 2015 14:26:44 GMT (envelope-from vangyzen@FreeBSD.org) Message-Id: <201510141426.t9EEQiWX079418@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: vangyzen set sender to vangyzen@FreeBSD.org using -f From: Eric van Gyzen Date: Wed, 14 Oct 2015 14:26:44 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r289315 - in head: include lib/libc/resolv share/man/man5 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 14 Oct 2015 14:26:46 -0000 Author: vangyzen Date: Wed Oct 14 14:26:44 2015 New Revision: 289315 URL: https://svnweb.freebsd.org/changeset/base/289315 Log: 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 Modified: head/include/resolv.h head/lib/libc/resolv/res_init.c head/lib/libc/resolv/res_state.c head/share/man/man5/resolver.5 Modified: head/include/resolv.h ============================================================================== --- head/include/resolv.h Wed Oct 14 12:46:05 2015 (r289314) +++ head/include/resolv.h Wed Oct 14 14:26:44 2015 (r289315) @@ -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; Modified: head/lib/libc/resolv/res_init.c ============================================================================== --- head/lib/libc/resolv/res_init.c Wed Oct 14 12:46:05 2015 (r289314) +++ head/lib/libc/resolv/res_init.c Wed Oct 14 14:26:44 2015 (r289315) @@ -78,6 +78,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -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 ch } 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)) { Modified: head/lib/libc/resolv/res_state.c ============================================================================== --- head/lib/libc/resolv/res_state.c Wed Oct 14 12:46:05 2015 (r289314) +++ head/lib/libc/resolv/res_state.c Wed Oct 14 14:26:44 2015 (r289315) @@ -26,6 +26,8 @@ */ #include +#include +#include #include #include #include @@ -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); Modified: head/share/man/man5/resolver.5 ============================================================================== --- head/share/man/man5/resolver.5 Wed Oct 14 12:46:05 2015 (r289314) +++ head/share/man/man5/resolver.5 Wed Oct 14 14:26:44 2015 (r289315) @@ -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 keywo 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