summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libc/inet/resolv.c95
1 files changed, 49 insertions, 46 deletions
diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c
index 8781196c6..07dff18dd 100644
--- a/libc/inet/resolv.c
+++ b/libc/inet/resolv.c
@@ -456,7 +456,8 @@ extern int __read_etc_hosts_r(parser_t *parser,
extern int __dns_lookup(const char *name,
int type,
unsigned char **outpacket,
- struct resolv_answer *a) attribute_hidden;
+ struct resolv_answer *a,
+ int *h_errnop) attribute_hidden;
extern int __encode_dotted(const char *dotted,
unsigned char *dest,
int maxlen) attribute_hidden;
@@ -1233,7 +1234,8 @@ static int __decode_answer(const unsigned char *message, /* packet */
int attribute_hidden __dns_lookup(const char *name,
int type,
unsigned char **outpacket,
- struct resolv_answer *a)
+ struct resolv_answer *a,
+ int *h_errnop)
{
/* Protected by __resolv_lock: */
static int last_ns_num = 0;
@@ -1265,11 +1267,15 @@ int attribute_hidden __dns_lookup(const char *name,
fd = -1;
lookup = NULL;
name_len = strlen(name);
- if ((unsigned)name_len >= MAXDNAME - MAXLEN_searchdomain - 2)
- goto fail; /* paranoia */
+ if ((unsigned)name_len >= MAXDNAME - MAXLEN_searchdomain - 2) {
+ *h_errnop = NO_RECOVERY;
+ goto fail1; /* paranoia */
+ }
lookup = malloc(name_len + 1/*for '.'*/ + MAXLEN_searchdomain + 1);
- if (!packet || !lookup || !name[0])
- goto fail;
+ if (!packet || !lookup || !name[0]) {
+ *h_errnop = NO_RECOVERY;
+ goto fail1;
+ }
ends_with_dot = (name[name_len - 1] == '.');
/* no strcpy! paranoia, user might change name[] under us */
memcpy(lookup, name, name_len);
@@ -1337,8 +1343,10 @@ int attribute_hidden __dns_lookup(const char *name,
h.rd = 1;
DPRINTF("encoding header\n", h.rd);
i = __encode_header(&h, packet, PACKETSZ);
- if (i < 0)
- goto fail;
+ if (i < 0) {
+ *h_errnop = NO_RECOVERY;
+ goto fail1;
+ }
/* encode question */
DPRINTF("lookup name: %s\n", lookup);
@@ -1346,8 +1354,10 @@ int attribute_hidden __dns_lookup(const char *name,
q.qtype = type;
q.qclass = C_IN; /* CLASS_IN */
j = __encode_question(&q, packet+i, PACKETSZ-i);
- if (j < 0)
- goto fail;
+ if (j < 0) {
+ *h_errnop = NO_RECOVERY;
+ goto fail1;
+ }
packet_len = i + j;
/* send packet */
@@ -1473,7 +1483,7 @@ int attribute_hidden __dns_lookup(const char *name,
/* no more search domains to try */
}
/* dont loop, this is "no such host" situation */
- h_errno = HOST_NOT_FOUND;
+ *h_errnop = HOST_NOT_FOUND;
goto fail1;
}
/* Insert other non-fatal errors here, which do not warrant
@@ -1485,7 +1495,7 @@ int attribute_hidden __dns_lookup(const char *name,
/* Code below won't work correctly with h.ancount == 0, so... */
if (h.ancount <= 0) {
- h_errno = NO_DATA; /* [is this correct code to check for?] */
+ *h_errnop = NO_DATA; /* [is this correct code to check for?] */
goto fail1;
}
pos = HFIXEDSZ;
@@ -1564,8 +1574,7 @@ int attribute_hidden __dns_lookup(const char *name,
variant = -1;
} while (retries_left > 0);
- fail:
- h_errno = NETDB_INTERNAL;
+ *h_errnop = TRY_AGAIN;
fail1:
if (fd != -1)
close(fd);
@@ -2106,9 +2115,8 @@ int gethostbyname_r(const char *name,
* we'll need space of one in_addr + two addr_list[] elems */
a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in_addr)));
a.add_count = 0;
- packet_len = __dns_lookup(name, T_A, &packet, &a);
+ packet_len = __dns_lookup(name, T_A, &packet, &a, h_errnop);
if (packet_len < 0) {
- *h_errnop = HOST_NOT_FOUND;
DPRINTF("__dns_lookup returned < 0\n");
return TRY_AGAIN;
}
@@ -2292,9 +2300,8 @@ int gethostbyname2_r(const char *name,
int packet_len;
/* Hmm why we memset(a) to zeros only once? */
- packet_len = __dns_lookup(buf, T_AAAA, &packet, &a);
+ packet_len = __dns_lookup(buf, T_AAAA, &packet, &a, h_errnop);
if (packet_len < 0) {
- *h_errnop = HOST_NOT_FOUND;
return TRY_AGAIN;
}
strncpy(buf, a.dotted, buflen);
@@ -2450,9 +2457,8 @@ int gethostbyaddr_r(const void *addr, socklen_t addrlen,
memset(&a, '\0', sizeof(a));
for (;;) {
/* Hmm why we memset(a) to zeros only once? */
- packet_len = __dns_lookup(buf, T_PTR, &packet, &a);
+ packet_len = __dns_lookup(buf, T_PTR, &packet, &a, h_errnop);
if (packet_len < 0) {
- *h_errnop = HOST_NOT_FOUND;
return TRY_AGAIN;
}
@@ -3091,7 +3097,7 @@ int res_query(const char *dname, int class, int type,
}
memset(&a, '\0', sizeof(a));
- i = __dns_lookup(dname, type, &packet, &a);
+ i = __dns_lookup(dname, type, &packet, &a, &h_errno);
if (i < 0) {
if (!h_errno) /* TODO: can this ever happen? */
@@ -3117,14 +3123,13 @@ libc_hidden_def(res_query)
*/
#define __TRAILING_DOT (1<<0)
#define __GOT_NODATA (1<<1)
-#define __GOT_SERVFAIL (1<<2)
+#define __GOT_TRYAGAIN (1<<2)
#define __TRIED_AS_IS (1<<3)
int res_search(const char *name, int class, int type, u_char *answer,
int anslen)
{
const char *cp;
char **domain;
- HEADER *hp = (HEADER *)(void *)answer;
unsigned dots;
unsigned state;
int ret, saved_herrno;
@@ -3189,19 +3194,9 @@ int res_search(const char *name, int class, int type, u_char *answer,
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.
- */
+ /* our resolver refused to talk to us -
+ * no sense to retry, as the retry would likely
+ * fail too */
if (errno == ECONNREFUSED) {
h_errno = TRY_AGAIN;
return -1;
@@ -3209,21 +3204,29 @@ int res_search(const char *name, int class, int type, u_char *answer,
switch (h_errno) {
case NO_DATA:
+ /* Keep trying, otherwise a
+ * wildcard entry of another type
+ * could keep us from finding this
+ * entry from higher in the domain
+ * search. */
state |= __GOT_NODATA;
- /* FALLTHROUGH */
+ break;
case HOST_NOT_FOUND:
- /* keep trying */
+ /* Not found - keep trying higher
+ * domains in the search list. */
break;
case TRY_AGAIN:
- if (hp->rcode == SERVFAIL) {
- /* try next search element, if any */
- state |= __GOT_SERVFAIL;
- break;
- }
- /* FALLTHROUGH */
+ /* Server error or timeout. Could
+ * be caused by a problem in servers
+ * our resolver queried. Keep trying
+ * search, but remember that there
+ * was a temporary problem. */
+ state |= __GOT_TRYAGAIN;
+ break;
default:
/* anything else implies that we're done */
done = 1;
+ break;
}
/*
* if we got here for some reason other than DNSRCH,
@@ -3257,13 +3260,13 @@ int res_search(const char *name, int class, int type, u_char *answer,
h_errno = saved_herrno;
else if (state & __GOT_NODATA)
h_errno = NO_DATA;
- else if (state & __GOT_SERVFAIL)
+ else if (state & __GOT_TRYAGAIN)
h_errno = TRY_AGAIN;
return -1;
}
#undef __TRAILING_DOT
#undef __GOT_NODATA
-#undef __GOT_SERVFAIL
+#undef __GOT_TRYAGAIN
#undef __TRIED_AS_IS
/*
* Perform a call on res_query on the concatenation of name and domain,