Index: lib/libc/net/getaddrinfo.c diff -u -p lib/libc/net/getaddrinfo.c.orig lib/libc/net/getaddrinfo.c --- lib/libc/net/getaddrinfo.c.orig Sun Dec 3 00:44:12 2006 +++ lib/libc/net/getaddrinfo.c Sat Dec 9 21:58:27 2006 @@ -90,6 +90,7 @@ __FBSDID("$FreeBSD: src/lib/libc/net/get #include #include "res_config.h" +#include "res_private.h" #ifdef DEBUG #include @@ -1976,7 +1977,7 @@ _dns_getaddrinfo(void *rv, void *cb_data } res = __res_state(); - if ((res->options & RES_INIT) == 0 && res_ninit(res) == -1) { + if (__res_initialize(res) == -1) { RES_SET_H_ERRNO(res, NETDB_INTERNAL); free(buf); free(buf2); Index: lib/libc/net/gethostnamadr.c diff -u -p lib/libc/net/gethostnamadr.c.orig lib/libc/net/gethostnamadr.c --- lib/libc/net/gethostnamadr.c.orig Mon Jul 17 20:36:55 2006 +++ lib/libc/net/gethostnamadr.c Sat Dec 9 21:59:10 2006 @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD: src/lib/libc/net/get #include /* XXX hack for _res */ #include "un-namespace.h" #include "netdb_private.h" +#include "res_private.h" extern int _ht_gethostbyname(void *, void *, va_list); extern int _dns_gethostbyname(void *, void *, va_list); @@ -208,7 +209,7 @@ gethostbyname_r(const char *name, struct res_state statp; statp = __res_state(); - if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) { + if (__res_initialize(statp) == -1) { RES_SET_H_ERRNO(statp, NETDB_INTERNAL); return (-1); } @@ -232,7 +233,7 @@ gethostbyname2_r(const char *name, int a res_state statp; statp = __res_state(); - if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) { + if (__res_initialize(statp) == -1) { RES_SET_H_ERRNO(statp, NETDB_INTERNAL); return (-1); } @@ -305,7 +306,7 @@ gethostbyaddr_r(const void *addr, sockle }; statp = __res_state(); - if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) { + if (__res_initialize(statp) == -1) { RES_SET_H_ERRNO(statp, NETDB_INTERNAL); *h_errnop = statp->res_h_errno; return (-1); Index: lib/libc/net/getnetbydns.c diff -u -p lib/libc/net/getnetbydns.c.orig lib/libc/net/getnetbydns.c --- lib/libc/net/getnetbydns.c.orig Mon Jul 17 20:36:55 2006 +++ lib/libc/net/getnetbydns.c Sat Dec 9 21:59:31 2006 @@ -84,6 +84,7 @@ __FBSDID("$FreeBSD: src/lib/libc/net/get #include "netdb_private.h" #include "res_config.h" +#include "res_private.h" #define BYADDR 0 #define BYNAME 1 @@ -289,7 +290,7 @@ _dns_getnetbyaddr(void *rval, void *cb_d h_errnop = va_arg(ap, int *); statp = __res_state(); - if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) { + if (__res_initialize(statp) == -1) { RES_SET_H_ERRNO(statp, NETDB_INTERNAL); *h_errnop = statp->res_h_errno; return (NS_UNAVAIL); @@ -391,7 +392,7 @@ _dns_getnetbyname(void *rval, void *cb_d h_errnop = va_arg(ap, int *); statp = __res_state(); - if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) { + if (__res_initialize(statp) == -1) { RES_SET_H_ERRNO(statp, NETDB_INTERNAL); *h_errnop = statp->res_h_errno; return (NS_UNAVAIL); Index: lib/libc/net/name6.c diff -u -p lib/libc/net/name6.c.orig lib/libc/net/name6.c --- lib/libc/net/name6.c.orig Sat Jul 29 13:26:09 2006 +++ lib/libc/net/name6.c Sat Dec 9 21:35:52 2006 @@ -351,11 +351,9 @@ getipnodebyname(const char *name, int af } statp = __res_state(); - if ((statp->options & RES_INIT) == 0) { - if (res_ninit(statp) < 0) { - *errp = NETDB_INTERNAL; - return NULL; - } + if (__res_initialize(statp) == -1) { + *errp = NETDB_INTERNAL; + return NULL; } *errp = HOST_NOT_FOUND; @@ -1798,11 +1796,9 @@ _dns_ghbyaddr(void *rval, void *cb_data, } statp = __res_state(); - if ((statp->options & RES_INIT) == 0) { - if (res_ninit(statp) < 0) { - *errp = NETDB_INTERNAL; - return NS_UNAVAIL; - } + if (__res_initialize(statp) == -1) { + *errp = NETDB_INTERNAL; + return NS_UNAVAIL; } memset(&hbuf, 0, sizeof(hbuf)); hbuf.h_name = NULL; Index: lib/libc/net/resolver.3 diff -u lib/libc/net/resolver.3.orig lib/libc/net/resolver.3 --- lib/libc/net/resolver.3.orig Sat Nov 11 14:34:01 2006 +++ lib/libc/net/resolver.3 Sat Dec 9 21:50:20 2006 @@ -399,6 +399,16 @@ .Fa src to a buffer pointed to by .Fa dst . +.Pp +Traditionally, the resolver reads the configuration file only once. +If +.Dq Ev res_checkconf_interval +.Xr kenv 2 +variable is set to the value larger than 0 or equal +to 0, the resolver checks if the configuration file is updated +at intervals of +.Dq Ev res_checkconf_interval +seconds, and re-read configuration file when it is updated. .Sh IMPLEMENTATION NOTES This implementation of the resolver is thread-safe, but it will not function properly if the programmer attempts to declare his or her own Index: lib/libc/resolv/res_data.c diff -u -p lib/libc/resolv/res_data.c.orig lib/libc/resolv/res_data.c --- lib/libc/resolv/res_data.c.orig Mon Jul 17 19:09:58 2006 +++ lib/libc/resolv/res_data.c Wed Dec 13 04:31:56 2006 @@ -76,10 +76,12 @@ const char *_res_sectioncodes[] = { /* Proto. */ int res_ourserver_p(const res_state, const struct sockaddr_in *); +int __res_initialize(res_state); int res_init(void) { extern int __res_vinit(res_state, int); + extern void __res_get_checkconf_interval(void); /* * These three fields used to be statically initialized. This made @@ -114,6 +116,7 @@ res_init(void) { if (!_res.id) _res.id = res_randomid(); + __res_get_checkconf_interval(); return (__res_vinit(&_res, 1)); } @@ -145,7 +148,7 @@ res_mkquery(int op, /* opcode of query u_char *buf, /* buffer to put query */ int buflen) /* size of buffer */ { - if ((_res.options & RES_INIT) == 0U && res_init() == -1) { + if (__res_initialize(&_res) == -1) { RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); return (-1); } @@ -156,7 +159,7 @@ res_mkquery(int op, /* opcode of query int res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { - if ((_res.options & RES_INIT) == 0U && res_init() == -1) { + if (__res_initialize(&_res) == -1) { RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); return (-1); } @@ -170,7 +173,7 @@ res_query(const char *name, /* domain na u_char *answer, /* buffer to put answer */ int anslen) /* size of answer buffer */ { - if ((_res.options & RES_INIT) == 0U && res_init() == -1) { + if (__res_initialize(&_res) == -1) { RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); return (-1); } @@ -196,7 +199,7 @@ res_isourserver(const struct sockaddr_in int res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { - if ((_res.options & RES_INIT) == 0U && res_init() == -1) { + if (__res_initialize(&_res) == -1) { /* errno should have been set by res_init() in this case. */ return (-1); } @@ -209,7 +212,7 @@ int res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key, u_char *ans, int anssiz) { - if ((_res.options & RES_INIT) == 0U && res_init() == -1) { + if (__res_initialize(&_res) == -1) { /* errno should have been set by res_init() in this case. */ return (-1); } @@ -225,7 +228,7 @@ res_close(void) { int res_update(ns_updrec *rrecp_in) { - if ((_res.options & RES_INIT) == 0U && res_init() == -1) { + if (__res_initialize(&_res) == -1) { RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); return (-1); } @@ -239,7 +242,7 @@ res_search(const char *name, /* domain n u_char *answer, /* buffer to put answer */ int anslen) /* size of answer */ { - if ((_res.options & RES_INIT) == 0U && res_init() == -1) { + if (__res_initialize(&_res) == -1) { RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); return (-1); } @@ -254,7 +257,7 @@ res_querydomain(const char *name, u_char *answer, /* buffer to put answer */ int anslen) /* size of answer */ { - if ((_res.options & RES_INIT) == 0U && res_init() == -1) { + if (__res_initialize(&_res) == -1) { RES_SET_H_ERRNO(&_res, NETDB_INTERNAL); return (-1); } Index: lib/libc/resolv/res_init.c diff -u -p lib/libc/resolv/res_init.c.orig lib/libc/resolv/res_init.c --- lib/libc/resolv/res_init.c.orig Tue Aug 8 04:12:26 2006 +++ lib/libc/resolv/res_init.c Wed Dec 13 04:31:20 2006 @@ -82,6 +82,7 @@ __FBSDID("$FreeBSD: src/lib/libc/resolv/ #include #include #include +#include #include #include @@ -89,6 +90,8 @@ __FBSDID("$FreeBSD: src/lib/libc/resolv/ #include #include +#include +#include #include #include #include @@ -102,6 +105,8 @@ __FBSDID("$FreeBSD: src/lib/libc/resolv/ /* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */ #include +#include + #include "res_private.h" /* Options. Should all be left alone. */ @@ -124,10 +129,26 @@ static u_int32_t net_mask(struct in_addr # define isascii(c) (!(c & 0200)) #endif +static time_t checkconf_interval = -1; + /* * Resolver state default settings. */ +void +__res_get_checkconf_interval() +{ + time_t interval; + char buf[6], *ep; + + if (kenv(KENV_GET, "res_checkconf_interval", buf, sizeof(buf)) == -1) + return; + errno = 0; + interval = (time_t)strtol(buf, &ep, 10); + if (errno == 0 && ep && *ep == '\0') + checkconf_interval = interval; +} + /* * Set up default settings. If the configuration file exist, the values * there will have precedence. Otherwise, the server address is set to @@ -153,6 +174,7 @@ int res_ninit(res_state statp) { extern int __res_vinit(res_state, int); + __res_get_checkconf_interval(); return (__res_vinit(statp, 0)); } @@ -172,6 +194,7 @@ __res_vinit(res_state statp, int preinit #endif int dots; union res_sockaddr_union u[2]; + time_t now; if (statp->_u._ext.ext != NULL) res_ndestroy(statp); @@ -300,6 +323,11 @@ __res_vinit(res_state statp, int preinit nserv = 0; if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { + struct stat sb; + + if (_fstat(fileno(fp), &sb) == 0) + statp->_u._ext.ext->mtimespec = sb.st_mtimespec; + /* read the config file */ while (fgets(buf, sizeof(buf), fp) != NULL) { /* skip comments */ @@ -545,13 +573,20 @@ __res_vinit(res_state statp, int preinit printf(";;\t..END..\n"); } #endif - } + } else + statp->_u._ext.ext->mtimespec = evConsTime(0, 0); if (issetugid()) statp->options |= RES_NOALIASES; else if ((cp = getenv("RES_OPTIONS")) != NULL) res_setoptions(statp, cp, "env"); statp->options |= RES_INIT; + + time(&now); + statp->_u._ext.ext->chktime = now; + if (checkconf_interval > 0) + statp->_u._ext.ext->chktime += checkconf_interval; + return (0); #ifdef SOLARIS2 @@ -562,6 +597,39 @@ __res_vinit(res_state statp, int preinit } return (-1); #endif +} + +int +__res_initialize(res_state statp) +{ + struct stat sb; + time_t now; + u_long options; + int rv; + + if ((statp->options & RES_INIT) == 0U) { + if (statp == &_res) + return (res_init()); + return (res_ninit(statp)); + } + + if (checkconf_interval < 0) + return (0); + time(&now); + if (now < statp->_u._ext.ext->chktime) + return (0); + + if (stat(_PATH_RESCONF, &sb) == -1) { + /* Lost the file, in chroot? Don' trash settings */ + return (0); + } + if (evCmpTime(sb.st_mtimespec, statp->_u._ext.ext->mtimespec) == 0) + return (0); + + options = statp->options; + rv = __res_vinit(statp, 1); + statp->options = options; + return (rv); } static void Index: lib/libc/resolv/res_private.h diff -u lib/libc/resolv/res_private.h.orig lib/libc/resolv/res_private.h --- lib/libc/resolv/res_private.h.orig Mon Jul 17 19:09:58 2006 +++ lib/libc/resolv/res_private.h Wed Dec 13 04:22:29 2006 @@ -14,9 +14,13 @@ } sort_list[MAXRESOLVSORT]; char nsuffix[64]; char nsuffix2[64]; + struct timespec mtimespec; + time_t chktime; }; extern int res_ourserver_p(const res_state statp, const struct sockaddr *sa); +extern int +__res_initialize(res_state); #endif