Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 08 Nov 2008 17:39:52 +0900
From:      Hajimu UMEMOTO <ume@freebsd.org>
To:        Luigi Rizzo <rizzo@iet.unipi.it>
Cc:        net@freebsd.org
Subject:   Re: Two copies of resolver routines in libc ?
Message-ID:  <yge3ai2r4pz.wl%ume@mahoroba.org>
In-Reply-To: <20081106192103.GA46651@onelab2.iet.unipi.it>
References:  <20081106192103.GA46651@onelab2.iet.unipi.it>

next in thread | previous in thread | raw e-mail | index | archive | help
--Multipart_Sat_Nov__8_17:39:51_2008-1
Content-Type: text/plain; charset=US-ASCII

Hi,

>>>>> On Thu, 6 Nov 2008 20:21:03 +0100
>>>>> Luigi Rizzo <rizzo@iet.unipi.it> said:

rizzo> While looking for a workaround (attached, read later), i noticed
rizzo> that libc has two versions of the resolver routines: one is in

rizzo>         /usr/src/lib/libc/resolv/res_query.c

rizzo> the other one is embedded into
rizzo>         /usr/src/lib/libc/net/getaddrinfo.c

rizzo> which includes a slightly modified version of res_nquery, res_ndots,
rizzo> res_nquerydomain (all parts of the routines documented in resolver(3)).

Yes.

rizzo> If we are lucky, this is just replicated code.

No, the resolver functions in getaddrinfo.c has some addition of
functionality.  It was done for solving the query order problem.

rizzo> But i am not even sure they are the same, e.g. in the handling of
rizzo> options (in resolv.conf or the environment variable RES_OPTIONS).

The basic functionality including the handling of options are same.

rizzo> This is really annoying, because generally you don't know if an
rizzo> application uses getaddrinfo() or the traditional gethost*() routines
rizzo> (which in turn use resolver(3)), so it is hard to tell whether
rizzo> applications have a consistent behaviour.

You don't need to worry about it.

rizzo> If someone has time, it would be worthwhile trying to merge
rizzo> the two versions of the code into one (and i believe we should
rizzo> make getaddrinfo use the standard stuff in resolv/

When we tried to solve the query order problem, we decided to have a
modification code of the resolver into getaddrinfo.c.  Because:

  - Hide the internal functions from outside of libc.
  - Don't change the resolver as possible to ease further merge from
    ISC BIND.

Since we have the symbol versioning facility, we can hide the libc
internal functions from outside of libc, these days.  So, it may
better to merge the two.  I attached the proposed patch in this mail.
Please review it.

Sincerely,


--Multipart_Sat_Nov__8_17:39:51_2008-1
Content-Type: text/x-patch; type=patch; charset=US-ASCII
Content-Disposition: attachment; filename="resolver-multi.diff"
Content-Transfer-Encoding: 7bit

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	2007-09-06 03:08:14.000000000 +0900
+++ lib/libc/net/getaddrinfo.c	2008-11-07 16:06:49.000000000 +0900
@@ -94,6 +94,7 @@ __FBSDID("$FreeBSD: src/lib/libc/net/get
 #include <nsswitch.h>
 #include "un-namespace.h"
 #include "libc_private.h"
+#include "res_private.h"
 #ifdef NS_CACHING
 #include "nscache.h"
 #endif
@@ -210,15 +211,6 @@ static const ns_src default_dns_files[] 
 	{ 0 }
 };
 
-struct res_target {
-	struct res_target *next;
-	const char *name;	/* domain name */
-	int qclass, qtype;	/* class and type of query */
-	u_char *answer;		/* buffer to put answer */
-	int anslen;		/* size of answer buffer */
-	int n;			/* result length */
-};
-
 #define MAXPACKET	(64*1024)
 
 typedef union {
@@ -279,11 +271,6 @@ static int addrinfo_marshal_func(char *,
 static int addrinfo_unmarshal_func(char *, size_t, void *, va_list, void *);
 #endif
 
-static int res_queryN(const char *, struct res_target *, res_state);
-static int res_searchN(const char *, struct res_target *, res_state);
-static int res_querydomainN(const char *, const char *,
-	struct res_target *, res_state);
-
 /* XXX macros that make external reference is BAD. */
 
 #define GET_AI(ai, afd, addr) \
@@ -2117,7 +2104,7 @@ _dns_getaddrinfo(void *rv, void *cb_data
 		return NS_NOTFOUND;
 	}
 
-	if (res_searchN(hostname, &q, res) < 0) {
+	if (__res_nsearchN(res, hostname, &q) < 0) {
 		free(buf);
 		free(buf2);
 		return NS_NOTFOUND;
@@ -2407,355 +2394,3 @@ _yp_getaddrinfo(void *rv, void *cb_data,
 	return NS_SUCCESS;
 }
 #endif
-
-/* resolver logic */
-
-/*
- * Formulate a normal query, send, and await answer.
- * Returned answer is placed in supplied buffer "answer".
- * Perform preliminary check of answer, returning success only
- * if no error is indicated and the answer count is nonzero.
- * Return the size of the response on success, -1 on error.
- * Error number is left in h_errno.
- *
- * Caller must parse answer and determine whether it answers the question.
- */
-static int
-res_queryN(const char *name, struct res_target *target, res_state res)
-{
-	u_char *buf;
-	HEADER *hp;
-	int n;
-	u_int oflags;
-	struct res_target *t;
-	int rcode;
-	int ancount;
-
-	rcode = NOERROR;
-	ancount = 0;
-
-	buf = malloc(MAXPACKET);
-	if (!buf) {
-		RES_SET_H_ERRNO(res, NETDB_INTERNAL);
-		return -1;
-	}
-
-	for (t = target; t; t = t->next) {
-		int class, type;
-		u_char *answer;
-		int anslen;
-
-		hp = (HEADER *)(void *)t->answer;
-
-		/* make it easier... */
-		class = t->qclass;
-		type = t->qtype;
-		answer = t->answer;
-		anslen = t->anslen;
-
-		oflags = res->_flags;
-
-again:
-		hp->rcode = NOERROR;	/* default */
-
-#ifdef DEBUG
-		if (res->options & RES_DEBUG)
-			printf(";; res_query(%s, %d, %d)\n", name, class, type);
-#endif
-
-		n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL,
-		    buf, MAXPACKET);
-		if (n > 0 && (res->_flags & RES_F_EDNS0ERR) == 0 &&
-		    (res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U)
-			n = res_nopt(res, n, buf, MAXPACKET, anslen);
-		if (n <= 0) {
-#ifdef DEBUG
-			if (res->options & RES_DEBUG)
-				printf(";; res_query: mkquery failed\n");
-#endif
-			free(buf);
-			RES_SET_H_ERRNO(res, NO_RECOVERY);
-			return (n);
-		}
-		n = res_nsend(res, buf, n, answer, anslen);
-		if (n < 0) {
-			/*
-			 * if the query choked with EDNS0, retry
-			 * without EDNS0
-			 */
-			if ((res->options & (RES_USE_EDNS0|RES_USE_DNSSEC))
-			    != 0U &&
-			    ((oflags ^ res->_flags) & RES_F_EDNS0ERR) != 0) {
-				res->_flags |= RES_F_EDNS0ERR;
-				if (res->options & RES_DEBUG)
-					printf(";; res_nquery: retry without EDNS0\n");
-				goto again;
-			}
-			rcode = hp->rcode;	/* record most recent error */
-#ifdef DEBUG
-			if (res->options & RES_DEBUG)
-				printf(";; res_query: send error\n");
-#endif
-			continue;
-		}
-
-		if (n > anslen)
-			hp->rcode = FORMERR; /* XXX not very informative */
-		if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
-			rcode = hp->rcode;	/* record most recent error */
-#ifdef DEBUG
-			if (res->options & RES_DEBUG)
-				printf(";; rcode = %u, ancount=%u\n", hp->rcode,
-				    ntohs(hp->ancount));
-#endif
-			continue;
-		}
-
-		ancount += ntohs(hp->ancount);
-
-		t->n = n;
-	}
-
-	free(buf);
-
-	if (ancount == 0) {
-		switch (rcode) {
-		case NXDOMAIN:
-			RES_SET_H_ERRNO(res, HOST_NOT_FOUND);
-			break;
-		case SERVFAIL:
-			RES_SET_H_ERRNO(res, TRY_AGAIN);
-			break;
-		case NOERROR:
-			RES_SET_H_ERRNO(res, NO_DATA);
-			break;
-		case FORMERR:
-		case NOTIMP:
-		case REFUSED:
-		default:
-			RES_SET_H_ERRNO(res, NO_RECOVERY);
-			break;
-		}
-		return (-1);
-	}
-	return (ancount);
-}
-
-/*
- * Formulate a normal query, send, and retrieve answer in supplied buffer.
- * Return the size of the response on success, -1 on error.
- * If enabled, implement search rules until answer or unrecoverable failure
- * is detected.  Error code, if any, is left in h_errno.
- */
-static int
-res_searchN(const char *name, struct res_target *target, res_state res)
-{
-	const char *cp, * const *domain;
-	HEADER *hp = (HEADER *)(void *)target->answer;	/*XXX*/
-	u_int dots;
-	int trailing_dot, ret, saved_herrno;
-	int got_nodata = 0, got_servfail = 0, root_on_list = 0;
-	int tried_as_is = 0;
-	int searched = 0;
-	char abuf[MAXDNAME];
-
-	errno = 0;
-	RES_SET_H_ERRNO(res, HOST_NOT_FOUND); /* default, if we never query */
-	dots = 0;
-	for (cp = name; *cp; cp++)
-		dots += (*cp == '.');
-	trailing_dot = 0;
-	if (cp > name && *--cp == '.')
-		trailing_dot++;
-
-	/*
-	 * if there aren't any dots, it could be a user-level alias
-	 */
-	if (!dots &&
-	    (cp = res_hostalias(res, name, abuf, sizeof(abuf))) != NULL)
-		return (res_queryN(cp, target, res));
-
-	/*
-	 * If there are enough dots in the name, let's just give it a
-	 * try 'as is'. The threshold can be set with the "ndots" option.
-	 * Also, query 'as is', if there is a trailing dot in the name.
-	 */
-	saved_herrno = -1;
-	if (dots >= res->ndots || trailing_dot) {
-		ret = res_querydomainN(name, NULL, target, res);
-		if (ret > 0 || trailing_dot)
-			return (ret);
-		if (errno == ECONNREFUSED) {
-			RES_SET_H_ERRNO(res, TRY_AGAIN);
-			return (-1);
-		}
-		switch (res->res_h_errno) {
-		case NO_DATA:
-		case HOST_NOT_FOUND:
-			break;
-		case TRY_AGAIN:
-			if (hp->rcode == SERVFAIL)
-				break;
-			/* FALLTHROUGH */
-		default:
-			return (-1);
-		}
-		saved_herrno = res->res_h_errno;
-		tried_as_is++;
-	}
-
-	/*
-	 * We do at least one level of search if
-	 *	- there is no dot and RES_DEFNAME is set, or
-	 *	- there is at least one dot, there is no trailing dot,
-	 *	  and RES_DNSRCH is set.
-	 */
-	if ((!dots && (res->options & RES_DEFNAMES)) ||
-	    (dots && !trailing_dot && (res->options & RES_DNSRCH))) {
-		int done = 0;
-
-		for (domain = (const char * const *)res->dnsrch;
-		   *domain && !done;
-		   domain++) {
-			searched = 1;
-
-			if (domain[0][0] == '\0' ||
-			    (domain[0][0] == '.' && domain[0][1] == '\0'))
-				root_on_list++;
-
-			if (root_on_list && tried_as_is)
-				continue;
-
-			ret = res_querydomainN(name, *domain, target, res);
-			if (ret > 0)
-				return (ret);
-
-			/*
-			 * If no server present, give up.
-			 * If name isn't found in this domain,
-			 * keep trying higher domains in the search list
-			 * (if that's enabled).
-			 * On a NO_DATA error, keep trying, otherwise
-			 * a wildcard entry of another type could keep us
-			 * from finding this entry higher in the domain.
-			 * If we get some other error (negative answer or
-			 * server failure), then stop searching up,
-			 * but try the input name below in case it's
-			 * fully-qualified.
-			 */
-			if (errno == ECONNREFUSED) {
-				RES_SET_H_ERRNO(res, TRY_AGAIN);
-				return (-1);
-			}
-
-			switch (res->res_h_errno) {
-			case NO_DATA:
-				got_nodata++;
-				/* FALLTHROUGH */
-			case HOST_NOT_FOUND:
-				/* keep trying */
-				break;
-			case TRY_AGAIN:
-				got_servfail++;
-				if (hp->rcode == SERVFAIL) {
-					/* try next search element, if any */
-					break;
-				}
-				/* FALLTHROUGH */
-			default:
-				/* anything else implies that we're done */
-				done++;
-			}
-			/*
-			 * if we got here for some reason other than DNSRCH,
-			 * we only wanted one iteration of the loop, so stop.
-			 */
-			if (!(res->options & RES_DNSRCH))
-			        done++;
-		}
-	}
-
-	switch (res->res_h_errno) {
-	case NO_DATA:
-	case HOST_NOT_FOUND:
-		break;
-	case TRY_AGAIN:
-		if (hp->rcode == SERVFAIL)
-			break;
-		/* FALLTHROUGH */
-	default:
-		goto giveup;
-	}
-
-	/*
-	 * If the query has not already been tried as is then try it
-	 * unless RES_NOTLDQUERY is set and there were no dots.
-	 */
-	if ((dots || !searched || !(res->options & RES_NOTLDQUERY)) &&
-	    !(tried_as_is || root_on_list)) {
-		ret = res_querydomainN(name, NULL, target, res);
-		if (ret > 0)
-			return (ret);
-	}
-
-	/*
-	 * if we got here, we didn't satisfy the search.
-	 * if we did an initial full query, return that query's h_errno
-	 * (note that we wouldn't be here if that query had succeeded).
-	 * else if we ever got a nodata, send that back as the reason.
-	 * else send back meaningless h_errno, that being the one from
-	 * the last DNSRCH we did.
-	 */
-giveup:
-	if (saved_herrno != -1)
-		RES_SET_H_ERRNO(res, saved_herrno);
-	else if (got_nodata)
-		RES_SET_H_ERRNO(res, NO_DATA);
-	else if (got_servfail)
-		RES_SET_H_ERRNO(res, TRY_AGAIN);
-	return (-1);
-}
-
-/*
- * Perform a call on res_query on the concatenation of name and domain,
- * removing a trailing dot from name if domain is NULL.
- */
-static int
-res_querydomainN(const char *name, const char *domain,
-    struct res_target *target, res_state res)
-{
-	char nbuf[MAXDNAME];
-	const char *longname = nbuf;
-	size_t n, d;
-
-#ifdef DEBUG
-	if (res->options & RES_DEBUG)
-		printf(";; res_querydomain(%s, %s)\n",
-			name, domain?domain:"<Nil>");
-#endif
-	if (domain == NULL) {
-		/*
-		 * Check for trailing '.';
-		 * copy without '.' if present.
-		 */
-		n = strlen(name);
-		if (n >= MAXDNAME) {
-			RES_SET_H_ERRNO(res, NO_RECOVERY);
-			return (-1);
-		}
-		if (n > 0 && name[--n] == '.') {
-			strncpy(nbuf, name, n);
-			nbuf[n] = '\0';
-		} else
-			longname = name;
-	} else {
-		n = strlen(name);
-		d = strlen(domain);
-		if (n + d + 1 >= MAXDNAME) {
-			RES_SET_H_ERRNO(res, NO_RECOVERY);
-			return (-1);
-		}
-		snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
-	}
-	return (res_queryN(longname, target, res));
-}
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	2007-06-04 02:02:28.000000000 +0900
+++ lib/libc/resolv/res_private.h	2008-11-07 15:58:01.000000000 +0900
@@ -14,9 +14,21 @@
 	char nsuffix2[64];
 };
 
+struct res_target {
+	struct res_target *next;
+	const char *name;	/* domain name */
+	int qclass, qtype;	/* class and type of query */
+	u_char *answer;		/* buffer to put answer */
+	int anslen;		/* size of answer buffer */
+	int n;			/* result length */
+};
+
 extern int
 res_ourserver_p(const res_state statp, const struct sockaddr *sa);
 
+extern int
+__res_nsearchN(res_state, const char *, struct res_target *);
+
 #endif
 
 /*! \file */
Index: lib/libc/resolv/res_query.c
diff -u -p lib/libc/resolv/res_query.c.orig lib/libc/resolv/res_query.c
--- lib/libc/resolv/res_query.c.orig	2007-06-04 02:20:27.000000000 +0900
+++ lib/libc/resolv/res_query.c	2008-11-08 16:28:29.000000000 +0900
@@ -87,6 +87,8 @@ __FBSDID("$FreeBSD: src/lib/libc/resolv/
 #include <unistd.h>
 #include "port_after.h"
 
+#include "res_private.h"
+
 /* Options.  Leave them on. */
 #define DEBUG
 
@@ -96,6 +98,10 @@ __FBSDID("$FreeBSD: src/lib/libc/resolv/
 #define MAXPACKET	1024
 #endif
 
+static int res_nqueryN(res_state, const char *, struct res_target *);
+static int res_nquerydomainN(res_state, const char *, const char *,
+			     struct res_target *);
+
 /*%
  * Formulate a normal query, send, and await answer.
  * Returned answer is placed in supplied buffer "answer".
@@ -113,65 +119,117 @@ res_nquery(res_state statp,
 	   u_char *answer,	/*%< buffer to put answer */
 	   int anslen)		/*%< size of answer buffer */
 {
+	struct res_target q;
+	int n;
+
+	memset(&q, 0, sizeof(q));
+	q.name = name;
+	q.qclass = class;
+	q.qtype = type;
+	q.answer = answer;
+	q.anslen = anslen;
+	n = res_nqueryN(statp, name, &q);
+	return ((n < 0) ? n : q.n);
+}
+
+static int
+res_nqueryN(res_state statp, const char *name, struct res_target *target)
+{
 	u_char buf[MAXPACKET];
-	HEADER *hp = (HEADER *) answer;
+	HEADER *hp;
 	int n;
 	u_int oflags;
+	struct res_target *t;
+	int rcode;
+	int ancount;
+
+	rcode = NOERROR;
+	ancount = 0;
+
+	for (t = target; t; t = t->next) {
+		int class, type;
+		u_char *answer;
+		int anslen;
+
+		hp = (HEADER *)(void *) t->answer;
+
+		/* make it easier... */
+		class = t->qclass;
+		type = t->qtype;
+		answer = t->answer;
+		anslen = t->anslen;
 
-	oflags = statp->_flags;
+		oflags = statp->_flags;
 
 again:
-	hp->rcode = NOERROR;	/*%< default */
+		hp->rcode = NOERROR;	/*%< default */
 #ifdef DEBUG
-	if (statp->options & RES_DEBUG)
-		printf(";; res_query(%s, %d, %d)\n", name, class, type);
+		if (statp->options & RES_DEBUG)
+			printf(";; res_query(%s, %d, %d)\n", name, class,
+			       type);
 #endif
 
-	n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
-			 buf, sizeof(buf));
+		n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0,
+				 NULL, buf, sizeof(buf));
 #ifdef RES_USE_EDNS0
-	if (n > 0 && (statp->_flags & RES_F_EDNS0ERR) == 0 &&
-	    (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U)
-		n = res_nopt(statp, n, buf, sizeof(buf), anslen);
+		if (n > 0 && (statp->_flags & RES_F_EDNS0ERR) == 0 &&
+		    (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U)
+			n = res_nopt(statp, n, buf, sizeof(buf), anslen);
 #endif
-	if (n <= 0) {
+		if (n <= 0) {
 #ifdef DEBUG
-		if (statp->options & RES_DEBUG)
-			printf(";; res_query: mkquery failed\n");
-#endif
-		RES_SET_H_ERRNO(statp, NO_RECOVERY);
-		return (n);
-	}
-	n = res_nsend(statp, buf, n, answer, anslen);
-	if (n < 0) {
-#ifdef RES_USE_EDNS0
-		/* if the query choked with EDNS0, retry without EDNS0 */
-		if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U &&
-		    ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) {
-			statp->_flags |= RES_F_EDNS0ERR;
 			if (statp->options & RES_DEBUG)
-				printf(";; res_nquery: retry without EDNS0\n");
-			goto again;
+				printf(";; res_query: mkquery failed\n");
+#endif
+			RES_SET_H_ERRNO(statp, NO_RECOVERY);
+			return (n);
 		}
+		n = res_nsend(statp, buf, n, answer, anslen);
+		if (n < 0) {
+#ifdef RES_USE_EDNS0
+			/*
+			 * if the query choked with EDNS0, retry
+			 * without EDNS0
+			 */
+			if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC))
+			    != 0U &&
+			    ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) {
+				statp->_flags |= RES_F_EDNS0ERR;
+				if (statp->options & RES_DEBUG)
+					printf(";; res_nquery: retry without EDNS0\n");
+				goto again;
+			}
 #endif
+			rcode = hp->rcode;	/* record most recent error */
 #ifdef DEBUG
-		if (statp->options & RES_DEBUG)
-			printf(";; res_query: send error\n");
+			if (statp->options & RES_DEBUG)
+				printf(";; res_query: send error\n");
 #endif
-		RES_SET_H_ERRNO(statp, TRY_AGAIN);
-		return (n);
-	}
+			continue;
+		}
 
-	if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
+		if (n > anslen)
+			hp->rcode = FORMERR;	/* XXX not very informative */
+		if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
+			rcode = hp->rcode;	/* record most recent error */
 #ifdef DEBUG
-		if (statp->options & RES_DEBUG)
-			printf(";; rcode = (%s), counts = an:%d ns:%d ar:%d\n",
-			       p_rcode(hp->rcode),
-			       ntohs(hp->ancount),
-			       ntohs(hp->nscount),
-			       ntohs(hp->arcount));
+			if (statp->options & RES_DEBUG)
+				printf(";; rcode = (%s), counts = an:%d ns:%d ar:%d\n",
+				       p_rcode(hp->rcode),
+				       ntohs(hp->ancount),
+				       ntohs(hp->nscount),
+				       ntohs(hp->arcount));
 #endif
-		switch (hp->rcode) {
+			continue;
+		}
+
+		ancount += ntohs(hp->ancount);
+
+		t->n = n;
+	}
+
+	if (ancount == 0) {
+		switch (rcode) {
 		case NXDOMAIN:
 			RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
 			break;
@@ -190,7 +248,7 @@ again:
 		}
 		return (-1);
 	}
-	return (n);
+	return (ancount);
 }
 
 /*%
@@ -206,8 +264,24 @@ res_nsearch(res_state statp,
 	    u_char *answer,	/*%< buffer to put answer */
 	    int anslen)		/*%< size of answer */
 {
+	struct res_target q;
+	int n;
+
+	memset(&q, 0, sizeof(q));
+	q.name = name;
+	q.qclass = class;
+	q.qtype = type;
+	q.answer = answer;
+	q.anslen = anslen;
+	n = __res_nsearchN(statp, name, &q);
+	return ((n < 0) ? n : q.n);
+}
+
+int
+__res_nsearchN(res_state statp, const char *name, struct res_target *target)
+{
 	const char *cp, * const *domain;
-	HEADER *hp = (HEADER *) answer;
+	HEADER *hp = (HEADER *)(void *) target->answer;
 	char tmp[NS_MAXDNAME];
 	u_int dots;
 	int trailing_dot, ret, saved_herrno;
@@ -226,7 +300,7 @@ res_nsearch(res_state statp,
 
 	/* If there aren't any dots, it could be a user-level alias. */
 	if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
-		return (res_nquery(statp, cp, class, type, answer, anslen));
+		return (res_nqueryN(statp, cp, target));
 
 	/*
 	 * If there are enough dots in the name, let's just give it a
@@ -235,8 +309,7 @@ res_nsearch(res_state statp,
 	 */
 	saved_herrno = -1;
 	if (dots >= statp->ndots || trailing_dot) {
-		ret = res_nquerydomain(statp, name, NULL, class, type,
-					 answer, anslen);
+		ret = res_nquerydomainN(statp, name, NULL, target);
 		if (ret > 0 || trailing_dot)
 			return (ret);
 		if (errno == ECONNREFUSED) {
@@ -280,9 +353,7 @@ res_nsearch(res_state statp,
 			if (root_on_list && tried_as_is)
 				continue;
 
-			ret = res_nquerydomain(statp, name, *domain,
-					       class, type,
-					       answer, anslen);
+			ret = res_nquerydomainN(statp, name, *domain, target);
 			if (ret > 0)
 				return (ret);
 
@@ -366,8 +437,7 @@ res_nsearch(res_state statp,
 	 */
 	if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0U) &&
 	    !(tried_as_is || root_on_list)) {
-		ret = res_nquerydomain(statp, name, NULL, class, type,
-				       answer, anslen);
+		ret = res_nquerydomainN(statp, name, NULL, target);
 		if (ret > 0)
 			return (ret);
 	}
@@ -401,6 +471,23 @@ res_nquerydomain(res_state statp,
 	    u_char *answer,		/*%< buffer to put answer */
 	    int anslen)		/*%< size of answer */
 {
+	struct res_target q;
+	int n;
+
+	memset(&q, 0, sizeof(q));
+	q.name = name;
+	q.qclass = class;
+	q.qtype = type;
+	q.answer = answer;
+	q.anslen = anslen;
+	n = res_nquerydomainN(statp, name, domain, &q);
+	return ((n < 0) ? n : q.n);
+}
+
+static int
+res_nquerydomainN(res_state statp, const char *name, const char *domain,
+	    struct res_target *target)
+{
 	char nbuf[MAXDNAME];
 	const char *longname = nbuf;
 	int n, d;
@@ -408,7 +495,8 @@ res_nquerydomain(res_state statp,
 #ifdef DEBUG
 	if (statp->options & RES_DEBUG)
 		printf(";; res_nquerydomain(%s, %s, %d, %d)\n",
-		       name, domain?domain:"<Nil>", class, type);
+		       name, domain?domain:"<Nil>", target->qclass,
+		       target->qtype);
 #endif
 	if (domain == NULL) {
 		/*
@@ -433,9 +521,9 @@ res_nquerydomain(res_state statp,
 			RES_SET_H_ERRNO(statp, NO_RECOVERY);
 			return (-1);
 		}
-		sprintf(nbuf, "%s.%s", name, domain);
+		snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
 	}
-	return (res_nquery(statp, longname, class, type, answer, anslen));
+	return (res_nqueryN(statp, longname, target));
 }
 
 const char *

--Multipart_Sat_Nov__8_17:39:51_2008-1
Content-Type: text/plain; charset=US-ASCII


--
Hajimu UMEMOTO @ Internet Mutual Aid Society Yokohama, Japan
ume@mahoroba.org  ume@{,jp.}FreeBSD.org
http://www.imasy.org/~ume/

--Multipart_Sat_Nov__8_17:39:51_2008-1--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?yge3ai2r4pz.wl%ume>