summaryrefslogtreecommitdiff
path: root/libc/inet
diff options
context:
space:
mode:
Diffstat (limited to 'libc/inet')
-rw-r--r--libc/inet/resolv.c377
1 files changed, 198 insertions, 179 deletions
diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c
index 4a1f97541..e6dac1ae3 100644
--- a/libc/inet/resolv.c
+++ b/libc/inet/resolv.c
@@ -239,7 +239,7 @@ libc_hidden_proto(__libc_getdomainname)
#define DPRINTF(X,args...) fprintf(stderr, X, ##args)
#else
#define DPRINTF(X,args...)
-#endif /* DEBUG */
+#endif
#undef ARRAY_SIZE
#define ARRAY_SIZE(v) (sizeof(v) / sizeof((v)[0]))
@@ -344,7 +344,7 @@ extern int __decode_dotted(const unsigned char * const message, int offset,
char * dest, int maxlen) attribute_hidden;
extern int __length_dotted(const unsigned char * const message, int offset) attribute_hidden;
extern int __encode_header(struct resolv_header * h, unsigned char * dest, int maxlen) attribute_hidden;
-extern int __decode_header(unsigned char * data, struct resolv_header * h) attribute_hidden;
+extern void __decode_header(unsigned char * data, struct resolv_header * h) attribute_hidden;
extern int __encode_question(const struct resolv_question * const q,
unsigned char * dest, int maxlen) attribute_hidden;
extern int __decode_question(const unsigned char * const message, int offset,
@@ -475,7 +475,7 @@ int attribute_hidden __encode_header(struct resolv_header *h, unsigned char *des
#ifdef L_decodeh
-int attribute_hidden __decode_header(unsigned char *data, struct resolv_header *h)
+void attribute_hidden __decode_header(unsigned char *data, struct resolv_header *h)
{
h->id = (data[0] << 8) | data[1];
h->qr = (data[2] & 0x80) ? 1 : 0;
@@ -489,8 +489,6 @@ int attribute_hidden __decode_header(unsigned char *data, struct resolv_header *
h->ancount = (data[6] << 8) | data[7];
h->nscount = (data[8] << 8) | data[9];
h->arcount = (data[10] << 8) | data[11];
-
- return HFIXEDSZ;
}
#endif
@@ -827,7 +825,8 @@ int __encode_packet(struct resolv_header *h,
int __decode_packet(unsigned char *data, struct resolv_header *h) attribute_hidden;
int __decode_packet(unsigned char *data, struct resolv_header *h)
{
- return __decode_header(data, h);
+ __decode_header(data, h);
+ return HFIXEDSZ;
}
#endif
@@ -1012,7 +1011,15 @@ void attribute_hidden __open_nameservers(void)
fclose(fp);
}
if (__nameservers == 0) {
- __nameserver = (void*) &__local_nameserver;
+ /* Have to handle malloc failure! What a mess...
+ * And it's not only here, we need to be careful
+ * to never write into __nameserver[0] if it points
+ * to constant __local_nameserver, or free it. */
+ __nameserver = malloc(sizeof(__nameserver[0]));
+ if (__nameserver)
+ memcpy(__nameserver, &__local_nameserver, sizeof(__local_nameserver));
+ else
+ __nameserver = (void*) &__local_nameserver;
__nameservers++;
}
if (__searchdomains == 0) {
@@ -1063,10 +1070,6 @@ void attribute_hidden __close_nameservers(void)
#ifdef L_dnslookup
-/* Protected by __resolv_lock */
-static int last_ns_num = 0;
-static uint16_t last_id = 1;
-
/* On entry:
* a.buf(len) = auxiliary buffer for IP addresses after first one
* a.add_count = how many additional addresses are there already
@@ -1087,6 +1090,10 @@ int attribute_hidden __dns_lookup(const char *name, int type,
unsigned char **outpacket,
struct resolv_answer *a)
{
+ /* Protected by __resolv_lock: */
+ static int last_ns_num = 0;
+ static uint16_t last_id = 1;
+
int i, j, len, fd, pos, rc;
int name_len;
#ifdef USE_SELECT
@@ -1099,7 +1106,7 @@ int attribute_hidden __dns_lookup(const char *name, int type,
struct resolv_question q;
struct resolv_answer ma;
bool first_answer = 1;
- unsigned retries = 0;
+ int retries_left;
unsigned char *packet = malloc(PACKETSZ);
char *lookup;
int variant = -1; /* search domain to append, -1: none */
@@ -1118,18 +1125,19 @@ int attribute_hidden __dns_lookup(const char *name, int type,
if (!packet || !lookup || !name[0])
goto fail;
ends_with_dot = (name[name_len - 1] == '.');
+ /* no strcpy! paranoia, user might change name[] under us */
+ memcpy(lookup, name, name_len);
+
DPRINTF("Looking up type %d answer for '%s'\n", type, name);
+ retries_left = 0; /* for compiler */
+ do {
+ unsigned reply_timeout;
- while (retries < MAX_RETRIES) {
if (fd != -1) {
close(fd);
fd = -1;
}
- /* no strcpy! paranoia, user might change name[] under us */
- memcpy(lookup, name, name_len);
- lookup[name_len] = '\0';
-
/* Mess with globals while under lock */
/* NB: even data *pointed to* by globals may vanish
* outside the locks. We should assume any and all
@@ -1142,27 +1150,26 @@ int attribute_hidden __dns_lookup(const char *name, int type,
__UCLIBC_MUTEX_LOCK(__resolv_lock);
__open_nameservers();
sdomains = __searchdomains;
+ lookup[name_len] = '\0';
if ((unsigned)variant < sdomains) {
/* lookup is name_len + 1 + MAXLEN_searchdomain + 1 long */
/* __searchdomain[] is not bigger than MAXLEN_searchdomain */
lookup[name_len] = '.';
strcpy(&lookup[name_len + 1], __searchdomain[variant]);
}
- if (local_ns_num < 0) { /* first time */
+ /* first time? pick starting server etc */
+ if (local_ns_num < 0) {
local_id = last_id;
//TODO: implement /etc/resolv.conf's "options rotate"
// (a.k.a. RES_ROTATE bit in _res.options)
// local_ns_num = 0;
// if (_res.options & RES_ROTATE)
local_ns_num = last_ns_num;
+ retries_left = __nameservers * MAX_RETRIES;
}
- if (local_ns_num >= __nameservers) {
+ retries_left--;
+ if (local_ns_num >= __nameservers)
local_ns_num = 0;
-//TODO: wrong method of retries++!
-// Should be if (local_ns_num == starting_ns_num) retries++;
- retries++;
- /* break if retries >= MAX_RETRIES - *after unlock*! */
- }
local_id++;
local_id &= 0xffff;
/* write new values back while still under lock */
@@ -1173,8 +1180,6 @@ int attribute_hidden __dns_lookup(const char *name, int type,
* is not safe to use outside of locks */
sa = __nameserver[local_ns_num];
__UCLIBC_MUTEX_UNLOCK(__resolv_lock);
- if (retries >= MAX_RETRIES)
- break;
memset(packet, 0, PACKETSZ);
memset(&h, 0, sizeof(h));
@@ -1200,29 +1205,30 @@ int attribute_hidden __dns_lookup(const char *name, int type,
/* send packet */
DPRINTF("On try %d, sending query to port %d\n",
- retries+1, NAMESERVER_PORT);
+ retries_left, NAMESERVER_PORT);
fd = socket(sa.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
- if (fd < 0) { /* paranoia */
- retries++;
- continue;
- }
+ if (fd < 0) /* paranoia */
+ goto try_next_server;
rc = connect(fd, &sa.sa, sizeof(sa));
if (rc < 0) {
- if (errno == ENETUNREACH) {
+ //if (errno == ENETUNREACH) {
/* routing error, presume not transient */
goto try_next_server;
- }
- /* retry */
- retries++;
- continue;
+ //}
+//For example, what transient error this can be? Can't think of any
+ ///* retry */
+ //continue;
}
DPRINTF("Xmit packet len:%d id:%d qr:%d\n", len, h.id, h.qr);
+ /* no error check - if it fails, we time out on recv */
send(fd, packet, len, 0);
#ifdef USE_SELECT
+ reply_timeout = REPLY_TIMEOUT;
+ wait_again:
FD_ZERO(&fds);
FD_SET(fd, &fds);
- tv.tv_sec = REPLY_TIMEOUT;
+ tv.tv_sec = reply_timeout;
tv.tv_usec = 0;
if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0) {
DPRINTF("Timeout\n");
@@ -1230,30 +1236,35 @@ int attribute_hidden __dns_lookup(const char *name, int type,
* to next nameserver */
goto try_next_server;
}
+ reply_timeout--;
#else
+ reply_timeout = REPLY_TIMEOUT * 1000;
+ wait_again:
fds.fd = fd;
fds.events = POLLIN;
- if (poll(&fds, 1, REPLY_TIMEOUT * 1000) <= 0) {
+ if (poll(&fds, 1, reply_timeout) <= 0) {
DPRINTF("Timeout\n");
/* timed out, so retry send and receive
* to next nameserver */
goto try_next_server;
}
+//TODO: better timeout accounting?
+ reply_timeout -= 1000;
#endif
len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
if (len < HFIXEDSZ) {
- /* too short! */
-//TODO: why next sdomain? it's just a bogus packet from somewhere,
-// we can as well wait more...
- goto try_next_sdomain;
+ /* too short!
+ * it's just a bogus packet from somewhere */
+ bogus_packet:
+ if (reply_timeout)
+ goto wait_again;
+ goto try_next_server;
}
-
__decode_header(packet, &h);
DPRINTF("id = %d, qr = %d\n", h.id, h.qr);
- if ((h.id != local_id) || (!h.qr)) {
+ if (h.id != local_id || !h.qr) {
/* unsolicited */
-//TODO: why next sdomain?...
- goto try_next_sdomain;
+ goto bogus_packet;
}
DPRINTF("Got response (i think)!\n");
@@ -1262,9 +1273,10 @@ int attribute_hidden __dns_lookup(const char *name, int type,
DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
h.opcode, h.aa, h.tc, h.rd, h.ra, h.rcode);
+ /* bug 660 says we treat negative response as an error
+ * and retry, which is, eh, an error. :)
+ * We were incurring long delays because of this. */
if (h.rcode == NXDOMAIN) {
-// bug 660 says we treat negative response as an error and retry
-// which is, eh, an error. :) We were incurring long delays because of this.
/* if possible, try next search domain */
if (!ends_with_dot) {
DPRINTF("variant:%d sdomains:%d\n", variant, sdomains);
@@ -1273,8 +1285,9 @@ int attribute_hidden __dns_lookup(const char *name, int type,
variant++;
continue;
}
+ /* no more search domains to try */
}
- /* this is not an error - don't goto again! */
+ /* dont loop, this is "no such host" situation */
h_errno = HOST_NOT_FOUND;
goto fail1;
}
@@ -1291,8 +1304,6 @@ int attribute_hidden __dns_lookup(const char *name, int type,
DPRINTF("Skipping question %d at %d\n", j, pos);
/* returns -1 only if packet == NULL (can't happen) */
i = __length_question(packet, pos);
- //if (i < 0)
- // goto try_next_sdomain;
DPRINTF("Length of question %d is %d\n", j, i);
pos += i;
}
@@ -1342,6 +1353,7 @@ int attribute_hidden __dns_lookup(const char *name, int type,
}
}
+ /* success! */
DPRINTF("Answer name = |%s|\n", a->dotted);
DPRINTF("Answer type = |%d|\n", a->atype);
if (fd != -1)
@@ -1351,8 +1363,11 @@ int attribute_hidden __dns_lookup(const char *name, int type,
else
free(packet);
free(lookup);
- return len; /* success! */
+ return len;
+//TODO: audit whether *any* "goto try_next_sdomain" is actually correct:
+//trying next search domain makes sense only if we got NXDOMAIN!
+//why we do it in other cases too?
try_next_sdomain:
/* if there are searchdomains, try them */
if (!ends_with_dot) {
@@ -1366,7 +1381,7 @@ int attribute_hidden __dns_lookup(const char *name, int type,
/* if there are other nameservers, try them */
local_ns_num++;
variant = -1;
- } /* while (retries < MAX_RETRIES) */
+ } while (retries_left > 0);
fail:
h_errno = NETDB_INTERNAL;
@@ -1386,12 +1401,11 @@ struct hostent *gethostbyname(const char *name)
{
static struct hostent h;
static char buf[sizeof(struct in_addr) +
- sizeof(struct in_addr *)*2 +
+ sizeof(struct in_addr *) * 2 +
sizeof(char *)*ALIAS_DIM + 384/*namebuffer*/ + 32/* margin */];
struct hostent *hp;
gethostbyname_r(name, &h, buf, sizeof(buf), &hp, &h_errno);
-
return hp;
}
libc_hidden_def(gethostbyname)
@@ -1404,17 +1418,16 @@ struct hostent *gethostbyname2(const char *name, int family)
{
#ifndef __UCLIBC_HAS_IPV6__
return family == AF_INET ? gethostbyname(name) : (struct hostent*)NULL;
-#else /* __UCLIBC_HAS_IPV6__ */
+#else
static struct hostent h;
static char buf[sizeof(struct in6_addr) +
- sizeof(struct in6_addr *)*2 +
+ sizeof(struct in6_addr *) * 2 +
sizeof(char *)*ALIAS_DIM + 384/*namebuffer*/ + 32/* margin */];
struct hostent *hp;
gethostbyname2_r(name, family, &h, buf, sizeof(buf), &hp, &h_errno);
-
return hp;
-#endif /* __UCLIBC_HAS_IPV6__ */
+#endif
}
#endif
@@ -1430,22 +1443,25 @@ static void res_sync_func(void)
struct __res_state *rp = &(_res);
int n;
- /* TODO:
- * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
- */
+ /* If we didn't get malloc failure earlier... */
+ if (__nameserver != (void*) &__local_nameserver) {
+ /* TODO:
+ * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
+ */
#ifdef __UCLIBC_HAS_IPV6__
- if (__nameservers > rp->_u._ext.nscount)
- __nameservers = rp->_u._ext.nscount;
- n = __nameservers;
- while (--n >= 0)
- __nameserver[n].sa6 = *rp->_u._ext.nsaddrs[n]; /* struct copy */
-#else /* __UCLIBC_HAS_IPV4__ */
- if (__nameservers > rp->nscount)
- __nameservers = rp->nscount;
- n = __nameservers;
- while (--n >= 0)
- __nameserver[n].sa4 = rp->nsaddr_list[n]; /* struct copy */
+ if (__nameservers > rp->_u._ext.nscount)
+ __nameservers = rp->_u._ext.nscount;
+ n = __nameservers;
+ while (--n >= 0)
+ __nameserver[n].sa6 = *rp->_u._ext.nsaddrs[n]; /* struct copy */
+#else /* IPv4 only */
+ if (__nameservers > rp->nscount)
+ __nameservers = rp->nscount;
+ n = __nameservers;
+ while (--n >= 0)
+ __nameserver[n].sa4 = rp->nsaddr_list[n]; /* struct copy */
#endif
+ }
/* Extend and comment what program is known
* to use which _res.XXX member(s).
*/
@@ -1521,7 +1537,7 @@ int res_init(void)
rp->_u._ext.nscount = m;
#endif
-#else /* if !__UCLIBC_HAS_IPV4__ (only IPV6) */
+#else /* IPv6 only */
while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs) && i < __nameservers) {
struct sockaddr_in6 *sa6 = malloc(sizeof(sa6));
if (sa6) {
@@ -1532,7 +1548,7 @@ int res_init(void)
i++;
}
rp->_u._ext.nscount = m;
-#endif /* !__UCLIBC_HAS_IPV4__ (only IPV6) */
+#endif
__UCLIBC_MUTEX_UNLOCK(__resolv_lock);
return 0;
@@ -1836,7 +1852,6 @@ struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type)
struct hostent *hp;
gethostbyaddr_r(addr, len, type, &h, buf, sizeof(buf), &hp, &h_errno);
-
return hp;
}
libc_hidden_def(gethostbyaddr)
@@ -1854,12 +1869,15 @@ FILE * __open_etc_hosts(void)
return fp;
}
-int attribute_hidden __read_etc_hosts_r(FILE * fp, const char * name, int type,
- enum etc_hosts_action action,
- struct hostent * result_buf,
- char * buf, size_t buflen,
- struct hostent ** result,
- int * h_errnop)
+int attribute_hidden __read_etc_hosts_r(
+ FILE * fp,
+ const char * name,
+ int type,
+ enum etc_hosts_action action,
+ struct hostent * result_buf,
+ char * buf, size_t buflen,
+ struct hostent ** result,
+ int * h_errnop)
{
struct in_addr *in = NULL;
struct in_addr **addr_list = NULL;
@@ -1879,11 +1897,11 @@ int attribute_hidden __read_etc_hosts_r(FILE * fp, const char * name, int type,
buflen -= i;
}
- if (buflen < sizeof(char *)*ALIAS_DIM)
+ if (buflen < sizeof(char *) * ALIAS_DIM)
return ERANGE;
alias = (char **)buf;
- buf += sizeof(char **)*ALIAS_DIM;
- buflen -= sizeof(char **)*ALIAS_DIM;
+ buf += sizeof(char **) * ALIAS_DIM;
+ buflen -= sizeof(char **) * ALIAS_DIM;
if (action != GETHOSTENT) {
#ifdef __UCLIBC_HAS_IPV6__
@@ -1897,10 +1915,10 @@ int attribute_hidden __read_etc_hosts_r(FILE * fp, const char * name, int type,
buf += sizeof(*in);
buflen -= sizeof(*in);
- if (buflen < sizeof(*addr_list)*2)
+ if (buflen < sizeof(*addr_list) * 2)
return ERANGE;
addr_list = (struct in_addr **)buf;
- buf += sizeof(*addr_list)*2;
+ buf += sizeof(*addr_list) * 2;
buflen -= sizeof(*addr_list)*2;
#ifdef __UCLIBC_HAS_IPV6__
@@ -1910,11 +1928,11 @@ int attribute_hidden __read_etc_hosts_r(FILE * fp, const char * name, int type,
p += sizeof(*in6);
len -= sizeof(*in6);
- if (len < sizeof(*addr_list6)*2)
+ if (len < sizeof(*addr_list6) * 2)
return ERANGE;
addr_list6 = (struct in6_addr**)p;
- p += sizeof(*addr_list6)*2;
- len -= sizeof(*addr_list6)*2;
+ p += sizeof(*addr_list6) * 2;
+ len -= sizeof(*addr_list6) * 2;
if (len < buflen) {
buflen = len;
@@ -1951,7 +1969,7 @@ int attribute_hidden __read_etc_hosts_r(FILE * fp, const char * name, int type,
while (*cp && !isspace(*cp))
cp++;
}
- alias[aliases] = 0;
+ alias[aliases] = NULL;
if (aliases < 2)
continue; /* syntax error really */
@@ -2075,17 +2093,18 @@ struct hostent *gethostent(void)
static struct hostent h;
static char buf[
#ifndef __UCLIBC_HAS_IPV6__
- sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
+ sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 +
#else
- sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
+ sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 +
#endif /* __UCLIBC_HAS_IPV6__ */
- sizeof(char *)*ALIAS_DIM +
+ sizeof(char *) * ALIAS_DIM +
80 /*namebuffer*/ + 2 /* margin */];
struct hostent *host;
- __UCLIBC_MUTEX_LOCK(mylock);
+//BUG: the lock is not recursive!
+// __UCLIBC_MUTEX_LOCK(mylock);
gethostent_r(&h, buf, sizeof(buf), &host, &h_errno);
- __UCLIBC_MUTEX_UNLOCK(mylock);
+// __UCLIBC_MUTEX_UNLOCK(mylock);
return host;
}
#endif
@@ -2184,31 +2203,31 @@ BAD_FAM:
case AF_INET:
#ifdef __UCLIBC_HAS_IPV6__
case AF_INET6:
-#endif /* __UCLIBC_HAS_IPV6__ */
+#endif
if (!(flags & NI_NUMERICHOST)) {
+ if (0) /* nothing */;
#ifdef __UCLIBC_HAS_IPV6__
- if (sa->sa_family == AF_INET6)
+ else if (sa->sa_family == AF_INET6)
h = gethostbyaddr((const void *)
&(((const struct sockaddr_in6 *) sa)->sin6_addr),
sizeof(struct in6_addr), AF_INET6);
-#endif /* __UCLIBC_HAS_IPV6__ */
-#if defined __UCLIBC_HAS_IPV6__ && defined __UCLIBC_HAS_IPV4__
- else
#endif
#ifdef __UCLIBC_HAS_IPV4__
+ else
h = gethostbyaddr((const void *)
&(((const struct sockaddr_in *)sa)->sin_addr),
sizeof(struct in_addr), AF_INET);
-#endif /* __UCLIBC_HAS_IPV4__ */
+#endif
if (h) {
char *c;
#undef min
#define min(x,y) (((x) > (y)) ? (y) : (x))
if ((flags & NI_NOFQDN)
- && (__libc_getdomainname(domain, sizeof(domain)) == 0)
- && (c = strstr (h->h_name, domain))
- && (c != h->h_name) && (*(--c) == '.')) {
+ && (__libc_getdomainname(domain, sizeof(domain)) == 0)
+ && (c = strstr(h->h_name, domain)) != NULL
+ && (c != h->h_name) && (*(--c) == '.')
+ ) {
strncpy(host, h->h_name,
min(hostlen, (size_t) (c - h->h_name)));
host[min(hostlen - 1, (size_t) (c - h->h_name))] = '\0';
@@ -2227,8 +2246,9 @@ BAD_FAM:
errno = serrno;
return EAI_NONAME;
}
+ if (0) /* nothing */;
#ifdef __UCLIBC_HAS_IPV6__
- if (sa->sa_family == AF_INET6) {
+ else if (sa->sa_family == AF_INET6) {
const struct sockaddr_in6 *sin6p;
sin6p = (const struct sockaddr_in6 *) sa;
@@ -2275,14 +2295,13 @@ BAD_FAM:
#endif
}
#endif /* __UCLIBC_HAS_IPV6__ */
-#if defined __UCLIBC_HAS_IPV6__ && defined __UCLIBC_HAS_IPV4__
- else
-#endif /* __UCLIBC_HAS_IPV6__ && defined __UCLIBC_HAS_IPV4__ */
#if defined __UCLIBC_HAS_IPV4__
+ else {
c = inet_ntop(AF_INET, (const void *)
&(((const struct sockaddr_in *) sa)->sin_addr),
host, hostlen);
-#endif /* __UCLIBC_HAS_IPV4__ */
+ }
+#endif
if (c == NULL) {
errno = serrno;
return EAI_SYSTEM;
@@ -2383,6 +2402,7 @@ int gethostbyname_r(const char * name,
unsigned char *packet;
struct resolv_answer a;
int i;
+ int wrong_af = 0;
*result = NULL;
if (!name)
@@ -2394,10 +2414,13 @@ int gethostbyname_r(const char * name,
__set_errno(0); /* to check for missing /etc/hosts. */
i = __get_hosts_byname_r(name, AF_INET, result_buf,
buf, buflen, result, h_errnop);
- if (i == 0)
+ if (i == NETDB_SUCCESS) {
+ __set_errno(old_errno);
return i;
+ }
switch (*h_errnop) {
case HOST_NOT_FOUND:
+ wrong_af = (i == TRY_AGAIN);
case NO_ADDRESS:
break;
case NETDB_INTERNAL:
@@ -2464,6 +2487,14 @@ int gethostbyname_r(const char * name,
}
}
+ /* what if /etc/hosts has it but it's not IPv4?
+ * F.e. "::1 localhost6". We don't do DNS query for such hosts -
+ * "ping localhost6" should be fast even if DNS server is down! */
+ if (wrong_af) {
+ *h_errnop = HOST_NOT_FOUND;
+ return TRY_AGAIN;
+ }
+
/* talk to DNS servers */
{
a.buf = buf;
@@ -2547,17 +2578,19 @@ libc_hidden_def(gethostbyname_r)
#ifdef L_gethostbyname2_r
-int gethostbyname2_r(const char *name, int family,
- struct hostent * result_buf,
- char * buf, size_t buflen,
- struct hostent ** result,
- int * h_errnop)
+int gethostbyname2_r(const char *name,
+ int family,
+ struct hostent * result_buf,
+ char * buf,
+ size_t buflen,
+ struct hostent ** result,
+ int * h_errnop)
{
#ifndef __UCLIBC_HAS_IPV6__
return family == (AF_INET)
? gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop)
: HOST_NOT_FOUND;
-#else /* __UCLIBC_HAS_IPV6__ */
+#else
struct in6_addr *in;
struct in6_addr **addr_list;
unsigned char *packet;
@@ -2584,7 +2617,7 @@ int gethostbyname2_r(const char *name, int family,
i = __get_hosts_byname_r(name, family, result_buf,
buf, buflen, result, h_errnop);
if (i == NETDB_SUCCESS) {
-//FIXME: restore errno?
+ __set_errno(old_errno);
return i;
}
switch (*h_errnop) {
@@ -2602,30 +2635,28 @@ int gethostbyname2_r(const char *name, int family,
}
__set_errno(old_errno);
}
-
DPRINTF("Nothing found in /etc/hosts\n");
*h_errnop = NETDB_INTERNAL;
- if (buflen < sizeof(*in))
- return ERANGE;
+
+ /* make sure pointer is aligned */
+ i = ALIGN_BUFFER_OFFSET(buf);
+ buf += i;
+ buflen -= i;
+
in = (struct in6_addr*)buf;
buf += sizeof(*in);
buflen -= sizeof(*in);
-
- if (buflen < sizeof(*addr_list)*2)
- return ERANGE;
addr_list = (struct in6_addr**)buf;
- buf += sizeof(*addr_list)*2;
- buflen -= sizeof(*addr_list)*2;
-
- addr_list[0] = in;
- addr_list[1] = 0;
-
- if (buflen < 256)
+ buf += sizeof(*addr_list) * 2;
+ buflen -= sizeof(*addr_list) * 2;
+ if ((ssize_t)buflen < 256)
return ERANGE;
+ addr_list[0] = in;
+ addr_list[1] = NULL;
strncpy(buf, name, buflen);
- /* First check if this is already an address */
+ /* maybe it is already an address? */
if (inet_pton(AF_INET6, name, in)) {
result_buf->h_name = buf;
result_buf->h_addrtype = AF_INET6;
@@ -2636,7 +2667,7 @@ int gethostbyname2_r(const char *name, int family,
return NETDB_SUCCESS;
}
- /* What if /etc/hosts has it but it's not IPv6?
+ /* 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) {
@@ -2644,8 +2675,9 @@ int gethostbyname2_r(const char *name, int family,
return TRY_AGAIN;
}
+ /* talk to DNS servers */
+// TODO: why it's so different from gethostbyname_r (IPv4 case)?
memset(&a, '\0', sizeof(a));
-
for (;;) {
i = __dns_lookup(buf, T_AAAA, &packet, &a);
@@ -2722,7 +2754,7 @@ int gethostbyaddr_r(const void *addr, socklen_t len, int type,
if (!addr)
return EINVAL;
- memset((char *) &a, '\0', sizeof(a));
+ memset(&a, '\0', sizeof(a));
switch (type) {
case AF_INET:
@@ -2752,49 +2784,42 @@ int gethostbyaddr_r(const void *addr, socklen_t len, int type,
return i;
}
+ *h_errnop = NETDB_INTERNAL;
+
+ /* make sure pointer is aligned */
+ i = ALIGN_BUFFER_OFFSET(buf);
+ buf += i;
+ buflen -= i;
+
#ifdef __UCLIBC_HAS_IPV6__
qp = buf;
plen = buflen;
-#endif /* __UCLIBC_HAS_IPV6__ */
-
- *h_errnop = NETDB_INTERNAL;
- if (buflen < sizeof(*in))
- return ERANGE;
+#endif
in = (struct in_addr*)buf;
buf += sizeof(*in);
buflen -= sizeof(*in);
-
- if (buflen < sizeof(*addr_list)*2)
- return ERANGE;
addr_list = (struct in_addr**)buf;
- buf += sizeof(*addr_list)*2;
- buflen -= sizeof(*addr_list)*2;
-
- if (buflen < sizeof(char *)*ALIAS_DIM)
- return ERANGE;
+ buf += sizeof(*addr_list) * 2;
+ buflen -= sizeof(*addr_list) * 2;
alias = (char **)buf;
- buf += sizeof(*alias)*ALIAS_DIM;
- buflen -= sizeof(*alias)*ALIAS_DIM;
-
-#ifdef __UCLIBC_HAS_IPV6__
- if (plen < sizeof(*in6))
+ buf += sizeof(*alias) * ALIAS_DIM;
+ buflen -= sizeof(*alias) * ALIAS_DIM;
+ if ((ssize_t)buflen < 0)
return ERANGE;
+#ifdef __UCLIBC_HAS_IPV6__
in6 = (struct in6_addr*)qp;
qp += sizeof(*in6);
plen -= sizeof(*in6);
-
- if (plen < sizeof(*addr_list6)*2)
- return ERANGE;
addr_list6 = (struct in6_addr**)qp;
- qp += sizeof(*addr_list6)*2;
- plen -= sizeof(*addr_list6)*2;
-
+ qp += sizeof(*addr_list6) * 2;
+ plen -= sizeof(*addr_list6) * 2;
+ if ((ssize_t)plen < 0)
+ return ERANGE;
if (plen < buflen) {
buflen = plen;
buf = qp;
}
-#endif /* __UCLIBC_HAS_IPV6__ */
-
+#endif
if (buflen < 256)
return ERANGE;
@@ -2802,30 +2827,27 @@ int gethostbyaddr_r(const void *addr, socklen_t len, int type,
unsigned char *tmp_addr = (unsigned char *)addr;
memcpy(&in->s_addr, addr, len);
-
addr_list[0] = in;
-
sprintf(buf, "%u.%u.%u.%u.in-addr.arpa",
tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0]);
+ }
#ifdef __UCLIBC_HAS_IPV6__
- } else {
+ else {
memcpy(in6->s6_addr, addr, len);
-
addr_list6[0] = in6;
qp = buf;
-
for (i = len - 1; i >= 0; i--) {
- qp += sprintf(qp, "%x.%x.", in6->s6_addr[i] & 0xf,
- (in6->s6_addr[i] >> 4) & 0xf);
+ qp += sprintf(qp, "%x.%x.",
+ in6->s6_addr[i] & 0xf,
+ (in6->s6_addr[i] >> 4) & 0xf);
}
strcpy(qp, "ip6.arpa");
-#endif /* __UCLIBC_HAS_IPV6__ */
}
-
- addr_list[1] = 0;
+#endif
+ addr_list[1] = NULL;
alias[0] = buf;
- alias[1] = 0;
+ alias[1] = NULL;
for (;;) {
i = __dns_lookup(buf, T_PTR, &packet, &a);
@@ -2838,7 +2860,7 @@ int gethostbyaddr_r(const void *addr, socklen_t len, int type,
strncpy(buf, a.dotted, buflen);
free(a.dotted);
- if (a.atype == T_CNAME) { /* CNAME */
+ if (a.atype == T_CNAME) { /* CNAME */
DPRINTF("Got a CNAME in gethostbyaddr()\n");
i = __decode_dotted(packet, a.rdoffset, buf, buflen);
free(packet);
@@ -2860,15 +2882,12 @@ int gethostbyaddr_r(const void *addr, socklen_t len, int type,
result_buf->h_name = buf;
result_buf->h_addrtype = type;
-
- if (type == AF_INET) {
+ if (type == AF_INET)
result_buf->h_length = sizeof(*in);
#ifdef __UCLIBC_HAS_IPV6__
- } else {
+ else
result_buf->h_length = sizeof(*in6);
-#endif /* __UCLIBC_HAS_IPV6__ */
- }
-
+#endif
result_buf->h_addr_list = (char **) addr_list;
result_buf->h_aliases = alias;
break;