diff options
Diffstat (limited to 'lib/libc/resolv/res_query.c')
-rw-r--r-- | lib/libc/resolv/res_query.c | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/lib/libc/resolv/res_query.c b/lib/libc/resolv/res_query.c index 5156ce8..e715b85 100644 --- a/lib/libc/resolv/res_query.c +++ b/lib/libc/resolv/res_query.c @@ -72,6 +72,8 @@ static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; static const char rcsid[] = "$Id: res_query.c,v 1.2.2.3.4.2 2004/03/16 12:34:19 marka Exp $"; #endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); #include "port_before.h" #include <sys/types.h> @@ -86,6 +88,7 @@ static const char rcsid[] = "$Id: res_query.c,v 1.2.2.3.4.2 2004/03/16 12:34:19 #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #include "port_after.h" /* Options. Leave them on. */ @@ -242,6 +245,21 @@ res_nsearch(res_state statp, answer, anslen); if (ret > 0 || trailing_dot) return (ret); + if (errno == ECONNREFUSED) { + RES_SET_H_ERRNO(statp, TRY_AGAIN); + return (-1); + } + switch (statp->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 = statp->res_h_errno; tried_as_is++; } @@ -265,6 +283,9 @@ res_nsearch(res_state statp, (domain[0][0] == '.' && domain[0][1] == '\0')) root_on_list++; + if (root_on_list && tried_as_is) + continue; + ret = res_nquerydomain(statp, name, *domain, class, type, answer, anslen); @@ -297,9 +318,26 @@ res_nsearch(res_state statp, /* keep trying */ break; case TRY_AGAIN: + /* + * This can occur due to a server failure + * (that is, all listed servers have failed), + * or all listed servers have timed out. + * ((HEADER *)answer)->rcode may not be set + * to SERVFAIL in the case of a timeout. + * + * Either way we must return TRY_AGAIN in + * order to avoid non-deterministic + * return codes. + * For example, loaded name servers or races + * against network startup/validation (dhcp, + * ppp, etc) can cause the search to timeout + * on one search element, e.g. 'fu.bar.com', + * and return a definitive failure on the + * next search element, e.g. 'fu.'. + */ + got_servfail++; if (hp->rcode == SERVFAIL) { /* try next search element, if any */ - got_servfail++; break; } /* FALLTHROUGH */ @@ -316,6 +354,18 @@ res_nsearch(res_state statp, } } + switch (statp->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. @@ -335,6 +385,7 @@ res_nsearch(res_state statp, * 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(statp, saved_herrno); else if (got_nodata) @@ -401,6 +452,8 @@ res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) { if (statp->options & RES_NOALIASES) return (NULL); + if (issetugid()) + return (NULL); file = getenv("HOSTALIASES"); if (file == NULL || (fp = fopen(file, "r")) == NULL) return (NULL); |