summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libc/inet/resolv.c48
1 files changed, 31 insertions, 17 deletions
diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c
index 1f12be9b9..e38c8bd67 100644
--- a/libc/inet/resolv.c
+++ b/libc/inet/resolv.c
@@ -1551,7 +1551,7 @@ int attribute_hidden __read_etc_hosts_r(FILE * fp, const char * name, int type,
struct in_addr **addr_list = NULL;
#ifdef __UCLIBC_HAS_IPV6__
struct in6_addr *in6 = NULL;
- struct in6_addr **addr_list6 =NULL;
+ struct in6_addr **addr_list6 = NULL;
#endif /* __UCLIBC_HAS_IPV6__ */
char *cp, **alias;
int aliases, i, ret = HOST_NOT_FOUND;
@@ -1613,14 +1613,15 @@ int attribute_hidden __read_etc_hosts_r(FILE * fp, const char * name, int type,
fp = __open_etc_hosts();
if (fp == NULL) {
- result = NULL;
+ *result = NULL;
return errno;
}
}
*h_errnop = HOST_NOT_FOUND;
while (fgets(buf, buflen, fp)) {
- if ((cp = strchr(buf, '#')))
+ cp = strchr(buf, '#');
+ if (cp)
*cp = '\0';
DPRINTF("Looking at: %s\n", buf);
aliases = 0;
@@ -1630,7 +1631,7 @@ int attribute_hidden __read_etc_hosts_r(FILE * fp, const char * name, int type,
while (*cp && isspace(*cp))
*cp++ = '\0';
if (!*cp)
- continue;
+ break;
if (aliases < (2+MAX_ALIASES))
alias[aliases++] = cp;
while (*cp && !isspace(*cp))
@@ -1644,7 +1645,8 @@ int attribute_hidden __read_etc_hosts_r(FILE * fp, const char * name, int type,
if (action == GETHOSTENT) {
/* Return whatever the next entry happens to be. */
break;
- } else if (action == GET_HOSTS_BYADDR) {
+ }
+ if (action == GET_HOSTS_BYADDR) {
if (strcmp(name, alias[0]) != 0)
continue;
} else {
@@ -1688,13 +1690,12 @@ int attribute_hidden __read_etc_hosts_r(FILE * fp, const char * name, int type,
* If looking for an IPv6 addr, don't bail when we got the IPv4
*/
DPRINTF("Error: Found host but diff network type\n");
+ /* NB: gethostbyname2_r depends on this feature
+ * to avoid looking for IPv6 addr of "localhost" etc */
ret = TRY_AGAIN;
continue;
}
-
- if (action != GETHOSTENT)
- fclose(fp);
- return ret;
+ break;
}
if (action != GETHOSTENT)
fclose(fp);
@@ -2206,6 +2207,7 @@ int gethostbyname2_r(const char *name, int family,
int nest = 0;
int __nameserversXX;
char ** __nameserverXX;
+ int wrong_af = 0;
if (family == AF_INET)
return gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop);
@@ -2223,11 +2225,15 @@ int gethostbyname2_r(const char *name, int family,
int old_errno = errno; /* Save the old errno and reset errno */
__set_errno(0); /* to check for missing /etc/hosts. */
- if ((i = __get_hosts_byname_r(name, family, result_buf,
- buf, buflen, result, h_errnop)) == 0)
+ i = __get_hosts_byname_r(name, family, result_buf,
+ buf, buflen, result, h_errnop);
+ if (i == NETDB_SUCCESS) {
+//FIXME: restore errno?
return i;
+ }
switch (*h_errnop) {
case HOST_NOT_FOUND:
+ wrong_af = (i == TRY_AGAIN);
case NO_ADDRESS:
break;
case NETDB_INTERNAL:
@@ -2274,7 +2280,15 @@ int gethostbyname2_r(const char *name, int family,
return NETDB_SUCCESS;
}
- memset((char *) &a, '\0', sizeof(a));
+ /* What if /etc/hosts has it but it's not IPv6?
+ * F.e. "127.0.0.1 localhost". We don't do DNS query for such hosts -
+ * "ping localhost" should be fast even if DNS server is down! */
+ if (wrong_af) {
+ *h_errnop = HOST_NOT_FOUND;
+ return TRY_AGAIN;
+ }
+
+ memset(&a, '\0', sizeof(a));
for (;;) {
__UCLIBC_MUTEX_LOCK(__resolv_lock);
@@ -2306,7 +2320,8 @@ int gethostbyname2_r(const char *name, int family,
return -1;
}
continue;
- } else if (a.atype == T_AAAA) { /* ADDRESS */
+ }
+ if (a.atype == T_AAAA) { /* ADDRESS */
memcpy(in, a.rdata, sizeof(*in));
result_buf->h_name = buf;
result_buf->h_addrtype = AF_INET6;
@@ -2314,11 +2329,10 @@ int gethostbyname2_r(const char *name, int family,
result_buf->h_addr_list = (char **) addr_list;
free(packet);
break;
- } else {
- free(packet);
- *h_errnop = HOST_NOT_FOUND;
- return TRY_AGAIN;
}
+ free(packet);
+ *h_errnop = HOST_NOT_FOUND;
+ return TRY_AGAIN;
}
*result = result_buf;