diff options
Diffstat (limited to 'lib/libc/net/res_query.c')
-rw-r--r-- | lib/libc/net/res_query.c | 231 |
1 files changed, 154 insertions, 77 deletions
diff --git a/lib/libc/net/res_query.c b/lib/libc/net/res_query.c index 4980af1..17318b7 100644 --- a/lib/libc/net/res_query.c +++ b/lib/libc/net/res_query.c @@ -53,20 +53,29 @@ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; -static char rcsid[] = "$Id: res_query.c,v 1.1 1993/06/01 09:42:14 vixie Exp vixie $"; +static char rcsid[] = "$Id: res_query.c,v 4.9.1.13 1994/06/11 22:05:04 vixie Exp $"; #endif /* LIBC_SCCS and not lint */ #include <sys/param.h> #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> + +#include <stdio.h> #include <netdb.h> #include <resolv.h> -#include <stdio.h> #include <ctype.h> #include <errno.h> -#include <stdlib.h> -#include <string.h> +#if defined(BSD) && (BSD >= 199306) +# include <stdlib.h> +# include <string.h> +#else +# include "../conf/portability.h" +#endif + +#if defined(USE_OPTIONS_H) +# include <../conf/options.h> +#endif #if PACKETSZ > 1024 #define MAXPACKET PACKETSZ @@ -74,6 +83,7 @@ static char rcsid[] = "$Id: res_query.c,v 1.1 1993/06/01 09:42:14 vixie Exp vixi #define MAXPACKET 1024 #endif +char *__hostalias __P((const char *)); int h_errno; /* @@ -83,27 +93,31 @@ int h_errno; * 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. */ +int res_query(name, class, type, answer, anslen) - char *name; /* domain name */ + const char *name; /* domain name */ int class, type; /* class and type of query */ u_char *answer; /* buffer to put answer */ int anslen; /* size of answer buffer */ { - char buf[MAXPACKET]; - HEADER *hp; + u_char buf[MAXPACKET]; + register HEADER *hp = (HEADER *) answer; int n; + hp->rcode = NOERROR; /* default */ + if ((_res.options & RES_INIT) == 0 && res_init() == -1) return (-1); #ifdef DEBUG if (_res.options & RES_DEBUG) printf(";; res_query(%s, %d, %d)\n", name, class, type); #endif - n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL, - buf, sizeof(buf)); + n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, + buf, sizeof(buf)); if (n <= 0) { #ifdef DEBUG if (_res.options & RES_DEBUG) @@ -112,17 +126,16 @@ res_query(name, class, type, answer, anslen) h_errno = NO_RECOVERY; return (n); } - n = res_send(buf, n, (char *)answer, anslen); + n = res_send(buf, n, answer, anslen); if (n < 0) { #ifdef DEBUG if (_res.options & RES_DEBUG) printf(";; res_query: send error\n"); #endif h_errno = TRY_AGAIN; - return(n); + return (n); } - hp = (HEADER *) answer; if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { #ifdef DEBUG if (_res.options & RES_DEBUG) @@ -148,86 +161,148 @@ res_query(name, class, type, answer, anslen) } return (-1); } - return(n); + return (n); } /* * 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 number is left in h_errno. - * Only useful for queries in the same name hierarchy as the local host - * (not, for example, for host address-to-name lookups in domain in-addr.arpa). + * is detected. Error code, if any, is left in h_errno. */ int res_search(name, class, type, answer, anslen) - char *name; /* domain name */ + const char *name; /* domain name */ int class, type; /* class and type of query */ u_char *answer; /* buffer to put answer */ int anslen; /* size of answer */ { - register char *cp, **domain; - int n, ret, got_nodata = 0; - char *__hostalias(); + register const char *cp, * const *domain; + HEADER *hp = (HEADER *) answer; + u_int dots; + 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) return (-1); errno = 0; h_errno = HOST_NOT_FOUND; /* default, if we never query */ - for (cp = name, n = 0; *cp; cp++) - if (*cp == '.') - n++; - if (n == 0 && (cp = __hostalias(name))) + 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 = __hostalias(name))) return (res_query(cp, class, type, answer, anslen)); /* + * If there are dots in the name already, let's just give it a try + * 'as is'. The threshold can be set with the "ndots" option. + */ + saved_herrno = -1; + if (dots >= _res.ndots) { + ret = res_querydomain(name, NULL, class, type, answer, anslen); + if (ret > 0) + return (ret); + saved_herrno = 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 ((n == 0 && _res.options & RES_DEFNAMES) || - (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH)) - for (domain = _res.dnsrch; *domain; domain++) { - ret = res_querydomain(name, *domain, class, type, - answer, anslen); + 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++) { + + ret = res_querydomain(name, *domain, class, type, + answer, anslen); + 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) { + h_errno = TRY_AGAIN; + return (-1); + } + + switch (h_errno) { + case NO_DATA: + got_nodata++; + /* FALLTHROUGH */ + case HOST_NOT_FOUND: + /* keep trying */ + break; + case TRY_AGAIN: + if (hp->rcode == SERVFAIL) { + /* try next search element, if any */ + got_servfail++; + 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++; + } + } + + /* if we have not already tried the name "as is", do that now. + * note that we do this regardless of how many dots were in the + * name or whether it ends with a dot. + */ + if (!tried_as_is) { + ret = res_querydomain(name, NULL, class, type, answer, anslen); 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) { - h_errno = TRY_AGAIN; - return (-1); - } - if (h_errno == NO_DATA) - got_nodata++; - if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) || - (_res.options & RES_DNSRCH) == 0) - break; + saved_herrno = h_errno; } - /* - * If the search/default failed, try the name as fully-qualified, - * but only if it contained at least one dot (even trailing). - * This is purely a heuristic; we assume that any reasonable query - * about a top-level domain (for servers, SOA, etc) will not use - * res_search. + + /* 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. */ - if (n && (ret = res_querydomain(name, (char *)NULL, class, type, - answer, anslen)) > 0) - return (ret); - if (got_nodata) + if (saved_herrno != -1) + h_errno = saved_herrno; + else if (got_nodata) h_errno = NO_DATA; + else if (got_servfail) + h_errno = TRY_AGAIN; return (-1); } @@ -235,20 +310,21 @@ res_search(name, class, type, answer, anslen) * Perform a call on res_query on the concatenation of name and domain, * removing a trailing dot from name if domain is NULL. */ +int res_querydomain(name, domain, class, type, answer, anslen) - char *name, *domain; + const char *name, *domain; int class, type; /* class and type of query */ u_char *answer; /* buffer to put answer */ int anslen; /* size of answer */ { char nbuf[2*MAXDNAME+2]; - char *longname = nbuf; + const char *longname = nbuf; int n; #ifdef DEBUG if (_res.options & RES_DEBUG) printf(";; res_querydomain(%s, %s, %d, %d)\n", - name, domain, class, type); + name, domain?domain:"<Nil>", class, type); #endif if (domain == NULL) { /* @@ -256,14 +332,15 @@ res_querydomain(name, domain, class, type, answer, anslen) * copy without '.' if present. */ n = strlen(name) - 1; - if (name[n] == '.' && n < sizeof(nbuf) - 1) { + if (n != (0 - 1) && name[n] == '.' && n < sizeof(nbuf) - 1) { bcopy(name, nbuf, n); nbuf[n] = '\0'; } else longname = name; - } else - (void)sprintf(nbuf, "%.*s.%.*s", - MAXDNAME, name, MAXDNAME, domain); + } else { + sprintf(nbuf, "%.*s.%.*s", + MAXDNAME, name, MAXDNAME, domain); + } return (res_query(longname, class, type, answer, anslen)); } @@ -272,9 +349,9 @@ char * __hostalias(name) register const char *name; { - register char *C1, *C2; + register char *cp1, *cp2; FILE *fp; - char *file, *getenv(), *strcpy(), *strncpy(); + char *file; char buf[BUFSIZ]; static char abuf[MAXDNAME]; @@ -283,17 +360,17 @@ __hostalias(name) return (NULL); buf[sizeof(buf) - 1] = '\0'; while (fgets(buf, sizeof(buf), fp)) { - for (C1 = buf; *C1 && !isspace(*C1); ++C1); - if (!*C1) + for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1); + if (!*cp1) break; - *C1 = '\0'; + *cp1 = '\0'; if (!strcasecmp(buf, name)) { - while (isspace(*++C1)); - if (!*C1) + while (isspace(*++cp1)); + if (!*cp1) break; - for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2); - abuf[sizeof(abuf) - 1] = *C2 = '\0'; - (void)strncpy(abuf, C1, sizeof(abuf) - 1); + for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2); + abuf[sizeof(abuf) - 1] = *cp2 = '\0'; + (void)strncpy(abuf, cp1, sizeof(abuf) - 1); fclose(fp); return (abuf); } |