From 346792d2a1494d3451837c205343c2ecbf5ee810 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Tue, 28 Oct 2008 00:12:25 +0000 Subject: make getaddrinfo to NOT query DNS for IPv6 address if host is in /etc/hosts and it has IPv4 address there. The most common example is "127.0.0.1 localhost". We don't want "ping localhost" to stall and time out on IPv6 queries to, say, inaccessible DNS server, right? - 655 0 0 655 28f libc/inet/gethostbyname2_r.o + 685 0 0 685 2ad libc/inet/gethostbyname2_r.o --- libc/inet/resolv.c | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) (limited to 'libc/inet') 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; -- cgit v1.2.3