summaryrefslogtreecommitdiffstats
path: root/lib/libc/net/res_query.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/net/res_query.c')
-rw-r--r--lib/libc/net/res_query.c231
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);
}
OpenPOWER on IntegriCloud