From 8c2dad28280f842b9430b1e950ac1ba1090d542a Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Mon, 17 Nov 2008 02:40:05 +0000 Subject: resolver: fix some previous TODOs, add new ones. --- libc/inet/resolv.c | 377 ++++++++++++++++++++++++++++------------------------- 1 file changed, 198 insertions(+), 179 deletions(-) (limited to 'libc/inet') 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; -- cgit v1.2.3