Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 21 Aug 2005 00:37:56 +0100 (BST)
From:      Robert Watson <rwatson@FreeBSD.org>
To:        Hajimu UMEMOTO <ume@FreeBSD.org>
Cc:        arch@FreeBSD.org
Subject:   Re: [CFR] reflect resolv.conf update to running application
Message-ID:  <20050821003536.P14178@fledge.watson.org>
In-Reply-To: <ygefyt4yiaz.wl%ume@mahoroba.org>
References:  <ygefyt4yiaz.wl%ume@mahoroba.org>

next in thread | previous in thread | raw e-mail | index | archive | help

On Sat, 20 Aug 2005, Hajimu UMEMOTO wrote:

> Our resolver reads resolv.conf once, and never re-read it.  Recent 
> OpenBSD changed to re-read resolv.conf when it is updated.  I believe it 
> is useful specially for mobile environment.  So, I made a patch for our 
> resolver.  Please review it.

Two concerns:

(1) Has anyone characterized the significant of the cost of doing a stat()
     for every DNS lookup for a significant workload?  Does it matter?
     Most performance-critical network paths don't do name lookups in order
     to prevent indefinite stalls in lookup, but doing, say, 1,000
     additional stats a second is not a small issue.

(2) By reading the configuration file more frequently and more quickly
     after a change, we increase the chances of a race condition in which
     the resolve reads a partially written resolv.conf file during an
     update.  Does this happen in practice?  I've always been very leery of
     re-reading configuration files automatically based on a time-stamp, as
     updates to files are not atomic at all.

Robert N M Watson

>
> 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	Sat May 21 22:46:37 2005
> +++ lib/libc/net/getaddrinfo.c	Sat May 21 23:20:27 2005
> @@ -2443,7 +2443,7 @@ res_searchN(name, target)
> 	int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
> 	char abuf[MAXDNAME];
>
> -	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
> +	if (_res_init() == -1) {
> 		h_errno = NETDB_INTERNAL;
> 		return (-1);
> 	}
> Index: lib/libc/net/gethostbydns.c
> diff -u -p lib/libc/net/gethostbydns.c.orig lib/libc/net/gethostbydns.c
> --- lib/libc/net/gethostbydns.c.orig	Sat May 21 22:46:37 2005
> +++ lib/libc/net/gethostbydns.c	Sat May 21 23:20:27 2005
> @@ -538,10 +538,6 @@ _dns_gethostbyaddr(void *rval, void *cb_
> 	he = va_arg(ap, struct hostent *);
> 	hed = va_arg(ap, struct hostent_data *);
>
> -	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
> -		h_errno = NETDB_INTERNAL;
> -		return NS_UNAVAIL;
> -	}
> 	switch (af) {
> 	case AF_INET:
> 		(void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
> 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	Sat May 21 22:46:37 2005
> +++ lib/libc/net/gethostnamadr.c	Sat May 21 23:20:27 2005
> @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD: src/lib/libc/net/get
> #include <resolv.h>			/* XXX hack for _res */
> #include "un-namespace.h"
> #include "netdb_private.h"
> +#include "res_config.h"
>
> extern int _ht_gethostbyname(void *, void *, va_list);
> extern int _dns_gethostbyname(void *, void *, va_list);
> @@ -264,7 +265,7 @@ gethostbyaddr_r(const char *addr, int le
> 		{ 0 }
> 	};
>
> -	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
> +	if (_res_init() == -1) {
> 		h_errno = NETDB_INTERNAL;
> 		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	Sat May 21 22:46:37 2005
> +++ lib/libc/net/getnetbydns.c	Sat May 21 23:20:27 2005
> @@ -304,6 +304,10 @@ _dns_getnetbyaddr(void *rval, void *cb_d
> 		    netbr[1], netbr[0]);
> 		break;
> 	}
> +	if (_res_init() == -1) {
> +		h_errno = NETDB_INTERNAL;
> +		return NS_UNAVAIL;
> +	}
> 	if ((buf = malloc(sizeof(*buf))) == NULL) {
> 		h_errno = NETDB_INTERNAL;
> 		return NS_NOTFOUND;
> 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 May 21 22:46:38 2005
> +++ lib/libc/net/name6.c	Sat May 21 23:20:27 2005
> @@ -121,6 +121,7 @@ __FBSDID("$FreeBSD: src/lib/libc/net/nam
> #include <unistd.h>
> #include "un-namespace.h"
> #include "netdb_private.h"
> +#include "res_config.h"
>
> #ifndef _PATH_HOSTS
> #define	_PATH_HOSTS	"/etc/hosts"
> @@ -1810,11 +1811,9 @@ _dns_ghbyaddr(void *rval, void *cb_data,
> 		return NS_NOTFOUND;
> 	}
>
> -	if ((_res.options & RES_INIT) == 0) {
> -		if (res_init() < 0) {
> -			*errp = h_errno;
> -			return NS_UNAVAIL;
> -		}
> +	if (_res_init() < 0) {
> +		*errp = h_errno;
> +		return NS_UNAVAIL;
> 	}
> 	memset(&hbuf, 0, sizeof(hbuf));
> 	hbuf.h_name = NULL;
> Index: lib/libc/net/res_config.h
> diff -u lib/libc/net/res_config.h.orig lib/libc/net/res_config.h
> --- lib/libc/net/res_config.h.orig	Sat Mar 23 08:41:54 2002
> +++ lib/libc/net/res_config.h	Sat May 21 23:20:27 2005
> @@ -8,3 +8,5 @@
> #define MULTI_PTRS_ARE_ALIASES 1 /* fold multiple PTR records into aliases */
> #define	CHECK_SRVR_ADDR 1 /* confirm that the server requested sent the reply */
> #define BIND_UPDATE 1	/* update support */
> +
> +int _res_init(void);
> Index: lib/libc/net/res_init.c
> diff -u -p lib/libc/net/res_init.c.orig lib/libc/net/res_init.c
> --- lib/libc/net/res_init.c.orig	Thu Feb 26 06:03:45 2004
> +++ lib/libc/net/res_init.c	Sat May 21 23:20:27 2005
> @@ -78,11 +78,13 @@ __FBSDID("$FreeBSD: src/lib/libc/net/res
> #include <sys/types.h>
> #include <sys/param.h>
> #include <sys/socket.h>
> +#include <sys/stat.h>
> #include <sys/time.h>
> #include <netinet/in.h>
> #include <arpa/inet.h>
> #include <arpa/nameser.h>
> #include <ctype.h>
> +#include <errno.h>
> #include <limits.h>
> #include <resolv.h>
> #include <stdio.h>
> @@ -100,6 +102,7 @@ __FBSDID("$FreeBSD: src/lib/libc/net/res
> #undef h_errno
> extern int h_errno;
>
> +static void res_readconf(void);
> static void res_setoptions(char *, char *);
>
> #ifdef RESOLVSORT
> @@ -112,6 +115,18 @@ static u_int32_t net_mask(struct in_addr
> # define isascii(c) (!(c & 0200))
> #endif
>
> +#define	timespecclear(tvp)	((tvp)->tv_sec = (tvp)->tv_nsec = 0)
> +#define	timespeccmp(tvp, uvp, cmp)					\
> +	(((tvp)->tv_sec == (uvp)->tv_sec) ?				\
> +	    ((tvp)->tv_nsec cmp (uvp)->tv_nsec) :			\
> +	    ((tvp)->tv_sec cmp (uvp)->tv_sec))
> +
> +struct __res_conf_private {
> +	struct timespec mtimespec;
> +};
> +
> +static struct __res_conf_private *___res_conf_private(void);
> +
> /*
>  * Check structure for failed per-thread allocations.
>  */
> @@ -119,6 +134,7 @@ static struct res_per_thread {
> 	struct __res_state res_state;
> 	struct __res_state_ext res_state_ext;
> 	struct __res_send_private res_send_private;
> +	struct __res_conf_private res_conf_private;
> 	int h_errno;
> } _res_per_thread_bogus = { .res_send_private = { .s = -1 } }; /* socket */
>
> @@ -146,21 +162,8 @@ static struct res_per_thread {
> int
> res_init()
> {
> -	FILE *fp;
> 	struct __res_send_private *rsp;
> -	char *cp, **pp;
> -	int n;
> -	char buf[MAXDNAME];
> -	int nserv = 0;    /* number of nameserver records read from file */
> -	int haveenv = 0;
> -	int havesearch = 0;
> -#ifdef RESOLVSORT
> -	int nsort = 0;
> -	char *net;
> -#endif
> -#ifndef RFC1535
> -	int dots;
> -#endif
> +	char *cp;
>
> 	/*
> 	 * If allocation of memory for this thread's resolver has failed,
> @@ -208,6 +211,37 @@ res_init()
> 	if (!_res.id)
> 		_res.id = res_randomid();
>
> +	_res.pfcode = 0;
> +	res_readconf();
> +
> +	if (issetugid())
> +		_res.options |= RES_NOALIASES;
> +	else if ((cp = getenv("RES_OPTIONS")) != NULL)
> +		res_setoptions(cp, "env");
> +	_res.options |= RES_INIT;
> +	return (0);
> +}
> +
> +static void
> +res_readconf()
> +{
> +	struct __res_conf_private *rcp;
> +	FILE *fp;
> +	char *cp, **pp;
> +	int n;
> +	char buf[MAXDNAME];
> +	int nserv = 0;    /* number of nameserver records read from file */
> +	int haveenv = 0;
> +	int havesearch = 0;
> +#ifdef RESOLVSORT
> +	int nsort = 0;
> +	char *net;
> +#endif
> +#ifndef RFC1535
> +	int dots;
> +#endif
> +	struct stat sb;
> +
> #ifdef USELOOPBACK
> 	_res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
> #else
> @@ -220,7 +254,6 @@ res_init()
> 		memcpy(&_res_ext.nsaddr, &_res.nsaddr, _res.nsaddr.sin_len);
> 	_res.nscount = 1;
> 	_res.ndots = 1;
> -	_res.pfcode = 0;
>
> 	/* Allow user to override the local domain definition */
> 	if (issetugid() == 0 && (cp = getenv("LOCALDOMAIN")) != NULL) {
> @@ -262,7 +295,10 @@ res_init()
> 	(line[sizeof(name) - 1] == ' ' || \
> 	 line[sizeof(name) - 1] == '\t'))
>
> +	rcp = ___res_conf_private();
> 	if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
> +	    if (fstat(fileno(fp), &sb) == 0)
> +		rcp->mtimespec = sb.st_mtimespec;
> 	    /* read the config file */
> 	    while (fgets(buf, sizeof(buf), fp) != NULL) {
> 		/* skip comments */
> @@ -396,11 +432,11 @@ res_init()
> 				if (inet_aton(net, &a)) {
> 				    _res.sort_list[nsort].mask = a.s_addr;
> 				} else {
> -				    _res.sort_list[nsort].mask =
> +				    _res.sort_list[nsort].mask =
> 					net_mask(_res.sort_list[nsort].addr);
> 				}
> 			    } else {
> -				_res.sort_list[nsort].mask =
> +				_res.sort_list[nsort].mask =
> 				    net_mask(_res.sort_list[nsort].addr);
> 			    }
> 			    _res_ext.sort_list[nsort].af = AF_INET;
> @@ -465,13 +501,14 @@ res_init()
> 		    continue;
> 		}
> 	    }
> -	    if (nserv > 1)
> +	    if (nserv > 1)
> 		_res.nscount = nserv;
> #ifdef RESOLVSORT
> 	    _res.nsort = nsort;
> #endif
> 	    (void) fclose(fp);
> -	}
> +	} else
> +	    timespecclear(&rcp->mtimespec);
> 	if (_res.defdname[0] == 0 &&
> 	    gethostname(buf, sizeof(_res.defdname) - 1) == 0 &&
> 	    (cp = strchr(buf, '.')) != NULL)
> @@ -507,12 +544,27 @@ res_init()
> #endif
> #endif /* !RFC1535 */
> 	}
> +}
>
> -	if (issetugid())
> -		_res.options |= RES_NOALIASES;
> -	else if ((cp = getenv("RES_OPTIONS")) != NULL)
> -		res_setoptions(cp, "env");
> -	_res.options |= RES_INIT;
> +int
> +_res_init(void)
> +{
> +	struct __res_conf_private *rcp;
> +	struct stat sb;
> +
> +	if ((_res.options & RES_INIT) == 0)
> +		return (res_init());
> +
> +	if (stat(_PATH_RESCONF, &sb) == -1) {
> +		/*
> +		 * Lost the file, in chroot?
> +		 * Don' trash settings
> +		 */
> +		return (0);
> +	}
> +	rcp = ___res_conf_private();
> +	if (timespeccmp(&sb.st_mtimespec, &rcp->mtimespec, !=))
> +		res_readconf();
> 	return (0);
> }
>
> @@ -629,6 +681,7 @@ struct __res_state _res;
> #endif
> struct __res_state_ext _res_ext;
> static struct __res_send_private _res_send_private = { .s = -1 }; /* socket */
> +static struct __res_conf_private _res_conf_private;
>
> static thread_key_t res_key;
> static once_t res_init_once = ONCE_INITIALIZER;
> @@ -697,6 +750,14 @@ ___res_send_private(void)
> 	if (thr_main() != 0)
> 		return (&_res_send_private);
> 	return (&allocate_res()->res_send_private);
> +}
> +
> +struct __res_conf_private *
> +___res_conf_private(void)
> +{
> +	if (thr_main() != 0)
> +		return (&_res_conf_private);
> +	return (&allocate_res()->res_conf_private);
> }
>
> int *
> Index: lib/libc/net/res_query.c
> diff -u -p lib/libc/net/res_query.c.orig lib/libc/net/res_query.c
> --- lib/libc/net/res_query.c.orig	Sat May 21 22:46:39 2005
> +++ lib/libc/net/res_query.c	Sat May 21 23:20:27 2005
> @@ -200,7 +200,7 @@ res_search(name, class, type, answer, an
> 	int trailing_dot, ret, saved_herrno;
> 	int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
>
> -	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
> +	if (_res_init() == -1) {
> 		h_errno = NETDB_INTERNAL;
> 		return (-1);
> 	}
> Index: lib/libc/net/res_update.c
> diff -u -p lib/libc/net/res_update.c.orig lib/libc/net/res_update.c
> --- lib/libc/net/res_update.c.orig	Mon Sep 16 01:51:09 2002
> +++ lib/libc/net/res_update.c	Sat May 21 23:20:27 2005
> @@ -36,6 +36,8 @@ __FBSDID("$FreeBSD: src/lib/libc/net/res
> #include <stdlib.h>
> #include <string.h>
>
> +#include "res_config.h"
> +
> /*
>  * Separate a linked list of records into groups so that all records
>  * in a group will belong to a single zone on the nameserver.
> @@ -84,7 +86,7 @@ res_update(ns_updrec *rrecp_in) {
> 	u_int16_t dlen, class, qclass, type, qtype;
> 	u_int32_t ttl;
>
> -	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
> +	if (_res_init() == -1) {
> 		h_errno = NETDB_INTERNAL;
> 		return (-1);
> 	}
>
>
> Sincerely,
>
> --
> Hajimu UMEMOTO @ Internet Mutual Aid Society Yokohama, Japan
> ume@mahoroba.org  ume@{,jp.}FreeBSD.org
> http://www.imasy.org/~ume/
> _______________________________________________
> freebsd-arch@freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-arch
> To unsubscribe, send any mail to "freebsd-arch-unsubscribe@freebsd.org"
>



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20050821003536.P14178>