diff options
Diffstat (limited to 'libc/inet/resolv.c')
-rw-r--r-- | libc/inet/resolv.c | 78 |
1 files changed, 45 insertions, 33 deletions
diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c index 828ca1359..f73329a92 100644 --- a/libc/inet/resolv.c +++ b/libc/inet/resolv.c @@ -742,8 +742,25 @@ static int static_ns = 0; * rw data costs more. */ static uint16_t static_id = 1; -int attribute_hidden __dns_lookup(const char *name, int type, int nscount, char **nsip, - unsigned char **outpacket, struct resolv_answer *a) +/* On entry: + * a.buf(len) = auxiliary buffer for IP addresses after first one + * a.add_count = how many additional addresses are there already + * outpacket = where to save ptr to raw packet? can be NULL + * On exit: + * ret < 0: error, all other data is not valid + * a.add_count & a.buf: updated + * a.rdlength: length of addresses (4 bytes for IPv4) + * *outpacket: updated (packet is malloced, you need to free it) + * a.rdata: points into *outpacket to 1st IP addr + * NB: don't pass outpacket == NULL if you need to use a.rdata! + * a.atype: type of query? + * a.dotted: numeric IP as a string (malloced, may be NULL if strdup failed) + * (which one of potentially many??) + */ +int attribute_hidden __dns_lookup(const char *name, int type, + int nscount, char **nsip, + unsigned char **outpacket, + struct resolv_answer *a) { int i, j, len, fd, pos, rc; #ifdef USE_SELECT @@ -762,13 +779,15 @@ int attribute_hidden __dns_lookup(const char *name, int type, int nscount, char int variant = -1; /* search domain to append, -1 - none */ int local_ns = -1, local_id = -1; bool ends_with_dot; -#ifdef __UCLIBC_HAS_IPV6__ - bool v6; - struct sockaddr_in6 sa6; -#endif + union { + struct sockaddr sa; #ifdef __UCLIBC_HAS_IPV4__ - struct sockaddr_in sa; + struct sockaddr_in sa4; #endif +#ifdef __UCLIBC_HAS_IPV6__ + struct sockaddr_in6 sa6; +#endif + } sa; fd = -1; @@ -841,43 +860,38 @@ int attribute_hidden __dns_lookup(const char *name, int type, int nscount, char DPRINTF("On try %d, sending query to port %d of machine %s\n", retries+1, NAMESERVER_PORT, dns); + sa.sa.sa_family = AF_INET; #ifdef __UCLIBC_HAS_IPV6__ //__UCLIBC_MUTEX_LOCK(__resolv_lock); ///* 'dns' is really __nameserver[] which is a global that // needs to hold __resolv_lock before access!! */ - v6 = inet_pton(AF_INET6, dns, &sa6.sin6_addr) > 0; + if (inet_pton(AF_INET6, dns, &sa.sa6.sin6_addr) > 0) + sa.sa.sa_family = AF_INET6; //__UCLIBC_MUTEX_UNLOCK(__resolv_lock); - fd = socket(v6 ? AF_INET6 : AF_INET, SOCK_DGRAM, IPPROTO_UDP); -#else - fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); #endif - if (fd < 0) { - retries++; - continue; - } - /* Connect to the UDP socket so that asyncronous errors are returned */ #ifdef __UCLIBC_HAS_IPV6__ - if (v6) { - sa6.sin6_family = AF_INET6; - sa6.sin6_port = htons(NAMESERVER_PORT); + if (sa.sa.sa_family == AF_INET6) { + sa.sa6.sin6_port = htons(NAMESERVER_PORT); /* sa6.sin6_addr is already here */ - rc = connect(fd, (struct sockaddr *) &sa6, sizeof(sa6)); - } else { + } else #endif #ifdef __UCLIBC_HAS_IPV4__ - sa.sin_family = AF_INET; - sa.sin_port = htons(NAMESERVER_PORT); + { + sa.sa4.sin_port = htons(NAMESERVER_PORT); //__UCLIBC_MUTEX_LOCK(__resolv_lock); ///* 'dns' is really __nameserver[] which is a global that // needs to hold __resolv_lock before access!! */ - sa.sin_addr.s_addr = inet_addr(dns); + sa.sa4.sin_addr.s_addr = inet_addr(dns); //__UCLIBC_MUTEX_UNLOCK(__resolv_lock); - rc = connect(fd, (struct sockaddr *) &sa, sizeof(sa)); -#endif -#ifdef __UCLIBC_HAS_IPV6__ } #endif + fd = socket(sa.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + retries++; + continue; + } + rc = connect(fd, &sa.sa, sizeof(sa)); if (rc < 0) { if (errno == ENETUNREACH) { /* routing error, presume not transient */ @@ -900,7 +914,6 @@ int attribute_hidden __dns_lookup(const char *name, int type, int nscount, char tv.tv_usec = 0; if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0) { DPRINTF("Timeout\n"); - /* timed out, so retry send and receive, * to next nameserver on queue */ goto tryall; @@ -910,7 +923,6 @@ int attribute_hidden __dns_lookup(const char *name, int type, int nscount, char fds.events = POLLIN; if (poll(&fds, 1, REPLY_TIMEOUT * 1000) <= 0) { DPRINTF("Timeout\n"); - /* timed out, so retry send and receive, * to next nameserver on queue */ goto tryall; @@ -967,9 +979,8 @@ int attribute_hidden __dns_lookup(const char *name, int type, int nscount, char DPRINTF("Decoding answer at pos %d\n", pos); first_answer = 1; - for (j = 0; j < h.ancount && pos < len; j++, pos += i) { + for (j = 0; j < h.ancount && pos < len; j++) { i = __decode_answer(packet, pos, len, &ma); - if (i < 0) { DPRINTF("failed decode %d\n", i); /* if the message was truncated and we have @@ -978,13 +989,14 @@ int attribute_hidden __dns_lookup(const char *name, int type, int nscount, char break; goto again; } + pos += i; if (first_answer) { ma.buf = a->buf; ma.buflen = a->buflen; ma.add_count = a->add_count; memcpy(a, &ma, sizeof(ma)); - if (a->atype != T_SIG && (0 == a->buf || (type != T_A && type != T_AAAA))) + if (a->atype != T_SIG && (NULL == a->buf || (type != T_A && type != T_AAAA))) break; if (a->atype != type) { free(a->dotted); @@ -1288,7 +1300,7 @@ int res_query(const char *dname, int class, int type, unsigned char *answer, int anslen) { int i; - unsigned char * packet = 0; + unsigned char * packet = NULL; struct resolv_answer a; int __nameserversXX; char ** __nameserverXX; |