summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libc/inet/resolv.c999
1 files changed, 489 insertions, 510 deletions
diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c
index e6dac1ae3..5fe8a8ed7 100644
--- a/libc/inet/resolv.c
+++ b/libc/inet/resolv.c
@@ -198,6 +198,7 @@ libc_hidden_proto(printf)
libc_hidden_proto(sprintf)
libc_hidden_proto(snprintf)
libc_hidden_proto(fgets)
+libc_hidden_proto(getnameinfo)
libc_hidden_proto(gethostbyname)
libc_hidden_proto(gethostbyname_r)
libc_hidden_proto(gethostbyname2_r)
@@ -1395,469 +1396,6 @@ int attribute_hidden __dns_lookup(const char *name, int type,
#endif
-#ifdef L_gethostbyname
-
-struct hostent *gethostbyname(const char *name)
-{
- static struct hostent h;
- static char buf[sizeof(struct in_addr) +
- 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)
-#endif
-
-
-#ifdef L_gethostbyname2
-
-struct hostent *gethostbyname2(const char *name, int family)
-{
-#ifndef __UCLIBC_HAS_IPV6__
- return family == AF_INET ? gethostbyname(name) : (struct hostent*)NULL;
-#else
- static struct hostent h;
- static char buf[sizeof(struct in6_addr) +
- 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
-}
-#endif
-
-
-#ifdef L_res_init
-
-/* Protected by __resolv_lock */
-struct __res_state _res;
-
-/* Will be called under __resolv_lock. */
-static void res_sync_func(void)
-{
- struct __res_state *rp = &(_res);
- int n;
-
- /* 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 /* 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).
- */
- // __resolv_opts = rp->options;
- // ...
-}
-
-/* Our res_init never fails (always returns 0) */
-int res_init(void)
-{
- struct __res_state *rp = &(_res);
- int i;
- int n;
-#ifdef __UCLIBC_HAS_IPV6__
- int m = 0;
-#endif
-
- __UCLIBC_MUTEX_LOCK(__resolv_lock);
- __close_nameservers();
- __open_nameservers();
-
- __res_sync = res_sync_func;
-
- memset(rp, 0, sizeof(*rp));
- rp->options = RES_INIT;
-#ifdef __UCLIBC_HAS_COMPAT_RES_STATE__
- rp->retrans = RES_TIMEOUT;
- rp->retry = 4;
- rp->id = random();
-#endif
- rp->ndots = 1;
-#ifdef __UCLIBC_HAS_EXTRA_COMPAT_RES_STATE__
- rp->_vcsock = -1;
-#endif
-
- n = __searchdomains;
- if (n > ARRAY_SIZE(rp->dnsrch))
- n = ARRAY_SIZE(rp->dnsrch);
- for (i = 0; i < n; i++)
- rp->dnsrch[i] = __searchdomain[i];
-
- /* copy nameservers' addresses */
- i = 0;
-#ifdef __UCLIBC_HAS_IPV4__
- n = 0;
- while (n < ARRAY_SIZE(rp->nsaddr_list) && i < __nameservers) {
- if (__nameserver[i].sa.sa_family == AF_INET) {
- rp->nsaddr_list[n] = __nameserver[i].sa4; /* struct copy */
-#ifdef __UCLIBC_HAS_IPV6__
- if (m < ARRAY_SIZE(rp->_u._ext.nsaddrs)) {
- rp->_u._ext.nsaddrs[m] = (void*) &rp->nsaddr_list[n];
- m++;
- }
-#endif
- n++;
- }
-#ifdef __UCLIBC_HAS_IPV6__
- if (__nameserver[i].sa.sa_family == AF_INET6
- && m < ARRAY_SIZE(rp->_u._ext.nsaddrs)
- ) {
- struct sockaddr_in6 *sa6 = malloc(sizeof(sa6));
- if (sa6) {
- *sa6 = __nameserver[i].sa6; /* struct copy */
- rp->_u._ext.nsaddrs[m] = sa6;
- m++;
- }
- }
-#endif
- i++;
- }
- rp->nscount = n;
-#ifdef __UCLIBC_HAS_IPV6__
- rp->_u._ext.nscount = m;
-#endif
-
-#else /* IPv6 only */
- while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs) && i < __nameservers) {
- struct sockaddr_in6 *sa6 = malloc(sizeof(sa6));
- if (sa6) {
- *sa6 = __nameserver[i].sa6; /* struct copy */
- rp->_u._ext.nsaddrs[m] = sa6;
- m++;
- }
- i++;
- }
- rp->_u._ext.nscount = m;
-#endif
-
- __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
- return 0;
-}
-libc_hidden_def(res_init)
-
-#ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
-void res_close(void)
-{
- __UCLIBC_MUTEX_LOCK(__resolv_lock);
- __close_nameservers();
- __res_sync = NULL;
-#ifdef __UCLIBC_HAS_IPV6__
- {
- char *p1 = (char*) &(_res.nsaddr_list[0]);
- int m = 0;
- /* free nsaddrs[m] if they do not point to nsaddr_list[x] */
- while (m < ARRAY_SIZE(_res._u._ext.nsaddrs)) {
- char *p2 = (char*)(_res._u._ext.nsaddrs[m]);
- if (p2 < p1 || (p2 - p1) > sizeof(_res.nsaddr_list))
- free(p2);
- }
- }
-#endif
- memset(&_res, 0, sizeof(_res));
- __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
-}
-#endif
-#endif /* L_res_init */
-
-
-#ifdef L_res_query
-
-int res_query(const char *dname, int class, int type,
- unsigned char *answer, int anslen)
-{
- int i;
- unsigned char * packet = NULL;
- struct resolv_answer a;
-
- if (!dname || class != 1 /* CLASS_IN */) {
- h_errno = NO_RECOVERY;
- return -1;
- }
-
- memset(&a, '\0', sizeof(a));
- i = __dns_lookup(dname, type, &packet, &a);
-
- if (i < 0) {
- h_errno = TRY_AGAIN;
- return -1;
- }
-
- free(a.dotted);
-
- if (a.atype == type) { /* CNAME */
- if (i > anslen)
- i = anslen;
- memcpy(answer, packet, i);
- }
- free(packet);
- return i;
-}
-libc_hidden_def(res_query)
-
-/*
- * Formulate a normal query, send, and retrieve answer in supplied buffer.
- * Return the size of the response on success, -1 on error.
- * If enabled, implement search rules until answer or unrecoverable failure
- * is detected. Error code, if any, is left in h_errno.
- */
-#define __TRAILING_DOT (1<<0)
-#define __GOT_NODATA (1<<1)
-#define __GOT_SERVFAIL (1<<2)
-#define __TRIED_AS_IS (1<<3)
-int res_search(const char *name, int class, int type, u_char *answer,
- int anslen)
-{
- const char *cp, * const *domain;
- HEADER *hp = (HEADER *)(void *)answer;
- unsigned dots;
- unsigned state;
- int ret, saved_herrno;
- uint32_t _res_options;
- unsigned _res_ndots;
- char **_res_dnsrch;
-
- if (!name || !answer) {
- h_errno = NETDB_INTERNAL;
- return -1;
- }
-
- again:
- __UCLIBC_MUTEX_LOCK(__resolv_lock);
- _res_options = _res.options;
- _res_ndots = _res.ndots;
- _res_dnsrch = _res.dnsrch;
- __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
- if (!(_res_options & RES_INIT)) {
- res_init(); /* our res_init never fails */
- goto again;
- }
-
- state = 0;
- errno = 0;
- h_errno = HOST_NOT_FOUND; /* default, if we never query */
- dots = 0;
- for (cp = name; *cp; cp++)
- dots += (*cp == '.');
-
- if (cp > name && *--cp == '.')
- state |= __TRAILING_DOT;
-
- /*
- * If there are dots in the name already, let's just give it a try
- * 'as is'. The threshold can be set with the "ndots" option.
- */
- saved_herrno = -1;
- if (dots >= _res_ndots) {
- ret = res_querydomain(name, NULL, class, type, answer, anslen);
- if (ret > 0)
- return ret;
- saved_herrno = h_errno;
- state |= __TRIED_AS_IS;
- }
-
- /*
- * We do at least one level of search if
- * - there is no dot and RES_DEFNAME is set, or
- * - there is at least one dot, there is no trailing dot,
- * and RES_DNSRCH is set.
- */
- if ((!dots && (_res_options & RES_DEFNAMES))
- || (dots && !(state & __TRAILING_DOT) && (_res_options & RES_DNSRCH))
- ) {
- bool done = 0;
-
- for (domain = (const char * const *)_res_dnsrch;
- *domain && !done;
- domain++) {
-
- ret = res_querydomain(name, *domain, class, type,
- answer, anslen);
- if (ret > 0)
- return ret;
-
- /*
- * If no server present, give up.
- * If name isn't found in this domain,
- * keep trying higher domains in the search list
- * (if that's enabled).
- * On a NO_DATA error, keep trying, otherwise
- * a wildcard entry of another type could keep us
- * from finding this entry higher in the domain.
- * If we get some other error (negative answer or
- * server failure), then stop searching up,
- * but try the input name below in case it's
- * fully-qualified.
- */
- if (errno == ECONNREFUSED) {
- h_errno = TRY_AGAIN;
- return -1;
- }
-
- switch (h_errno) {
- case NO_DATA:
- state |= __GOT_NODATA;
- /* FALLTHROUGH */
- case HOST_NOT_FOUND:
- /* keep trying */
- break;
- case TRY_AGAIN:
- if (hp->rcode == SERVFAIL) {
- /* try next search element, if any */
- state |= __GOT_SERVFAIL;
- break;
- }
- /* FALLTHROUGH */
- default:
- /* anything else implies that we're done */
- done = 1;
- }
- /*
- * if we got here for some reason other than DNSRCH,
- * we only wanted one iteration of the loop, so stop.
- */
- if (!(_res_options & RES_DNSRCH))
- done = 1;
- }
- }
-
- /*
- * if we have not already tried the name "as is", do that now.
- * note that we do this regardless of how many dots were in the
- * name or whether it ends with a dot.
- */
- if (!(state & __TRIED_AS_IS)) {
- ret = res_querydomain(name, NULL, class, type, answer, anslen);
- if (ret > 0)
- return ret;
- }
-
- /*
- * if we got here, we didn't satisfy the search.
- * if we did an initial full query, return that query's h_errno
- * (note that we wouldn't be here if that query had succeeded).
- * else if we ever got a nodata, send that back as the reason.
- * else send back meaningless h_errno, that being the one from
- * the last DNSRCH we did.
- */
- if (saved_herrno != -1)
- h_errno = saved_herrno;
- else if (state & __GOT_NODATA)
- h_errno = NO_DATA;
- else if (state & __GOT_SERVFAIL)
- h_errno = TRY_AGAIN;
- return -1;
-}
-#undef __TRAILING_DOT
-#undef __GOT_NODATA
-#undef __GOT_SERVFAIL
-#undef __TRIED_AS_IS
-/*
- * Perform a call on res_query on the concatenation of name and domain,
- * removing a trailing dot from name if domain is NULL.
- */
-int res_querydomain(const char *name, const char *domain, int class, int type,
- u_char * answer, int anslen)
-{
- char nbuf[MAXDNAME];
- const char *longname = nbuf;
- size_t n, d;
-#ifdef DEBUG
- uint32_t _res_options;
-#endif
-
- if (!name || !answer) {
- h_errno = NETDB_INTERNAL;
- return -1;
- }
-
-#ifdef DEBUG
- again:
- __UCLIBC_MUTEX_LOCK(__resolv_lock);
- _res_options = _res.options;
- __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
- if (!(_res_options & RES_INIT)) {
- res_init(); /* our res_init never fails */
- goto again:
- }
- if (_res_options & RES_DEBUG)
- printf(";; res_querydomain(%s, %s, %d, %d)\n",
- name, (domain ? domain : "<Nil>"), class, type);
-#endif
- if (domain == NULL) {
- /*
- * Check for trailing '.';
- * copy without '.' if present.
- */
- n = strlen(name);
- if (n + 1 > sizeof(nbuf)) {
- h_errno = NO_RECOVERY;
- return -1;
- }
- if (n > 0 && name[--n] == '.') {
- strncpy(nbuf, name, n);
- nbuf[n] = '\0';
- } else
- longname = name;
- } else {
- n = strlen(name);
- d = strlen(domain);
- if (n + 1 + d + 1 > sizeof(nbuf)) {
- h_errno = NO_RECOVERY;
- return -1;
- }
- snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
- }
- return res_query(longname, class, type, answer, anslen);
-}
-libc_hidden_def(res_querydomain)
-/* res_mkquery */
-/* res_send */
-/* dn_comp */
-/* dn_expand */
-#endif
-
-
-#ifdef L_gethostbyaddr
-
-struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type)
-{
- static struct hostent h;
- static char buf[
-#ifndef __UCLIBC_HAS_IPV6__
- sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
-#else
- sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
-#endif /* __UCLIBC_HAS_IPV6__ */
- sizeof(char *)*ALIAS_DIM + 384 /*namebuffer*/ + 32 /* margin */];
- struct hostent *hp;
-
- gethostbyaddr_r(addr, len, type, &h, buf, sizeof(buf), &hp, &h_errno);
- return hp;
-}
-libc_hidden_def(gethostbyaddr)
-#endif
-
-
#ifdef L_read_etc_hosts_r
FILE * __open_etc_hosts(void)
@@ -1890,57 +1428,44 @@ int attribute_hidden __read_etc_hosts_r(
/* make sure user char * is aligned */
i = ALIGN_BUFFER_OFFSET(buf);
- if (unlikely(i)) {
- if (buflen < i)
- return ERANGE;
- buf += i;
- buflen -= i;
- }
+ buf += i;
+ buflen -= i;
- if (buflen < sizeof(char *) * ALIAS_DIM)
- return ERANGE;
alias = (char **)buf;
buf += sizeof(char **) * ALIAS_DIM;
buflen -= sizeof(char **) * ALIAS_DIM;
+ if ((ssize_t)buflen < 0)
+ return ERANGE;
if (action != GETHOSTENT) {
#ifdef __UCLIBC_HAS_IPV6__
char *p = buf;
size_t len = buflen;
-#endif /* __UCLIBC_HAS_IPV6__ */
+#endif
*h_errnop = NETDB_INTERNAL;
- if (buflen < sizeof(*in))
- return ERANGE;
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;
-
-#ifdef __UCLIBC_HAS_IPV6__
- if (len < sizeof(*in6))
+ buflen -= sizeof(*addr_list) * 2;
+ if ((ssize_t)buflen < 0)
return ERANGE;
+#ifdef __UCLIBC_HAS_IPV6__
in6 = (struct in6_addr*)p;
p += sizeof(*in6);
len -= sizeof(*in6);
-
- if (len < sizeof(*addr_list6) * 2)
- return ERANGE;
addr_list6 = (struct in6_addr**)p;
p += sizeof(*addr_list6) * 2;
len -= sizeof(*addr_list6) * 2;
-
+ if ((ssize_t)len < 0)
+ return ERANGE;
if (len < buflen) {
buflen = len;
buf = p;
}
-#endif /* __UCLIBC_HAS_IPV6__ */
-
- if (buflen < 80)
+#endif
+ if ((ssize_t)buflen < 80)
return ERANGE;
fp = __open_etc_hosts();
@@ -1993,7 +1518,7 @@ int attribute_hidden __read_etc_hosts_r(
if (type == AF_INET && inet_pton(AF_INET, alias[0], in) > 0) {
DPRINTF("Found INET\n");
addr_list[0] = in;
- addr_list[1] = 0;
+ addr_list[1] = NULL;
result_buf->h_name = alias[1];
result_buf->h_addrtype = AF_INET;
result_buf->h_length = sizeof(*in);
@@ -2001,11 +1526,12 @@ int attribute_hidden __read_etc_hosts_r(
result_buf->h_aliases = alias + 2;
*result = result_buf;
ret = NETDB_SUCCESS;
+ }
#ifdef __UCLIBC_HAS_IPV6__
- } else if (type == AF_INET6 && inet_pton(AF_INET6, alias[0], in6) > 0) {
+ else if (type == AF_INET6 && inet_pton(AF_INET6, alias[0], in6) > 0) {
DPRINTF("Found INET6\n");
addr_list6[0] = in6;
- addr_list6[1] = 0;
+ addr_list6[1] = NULL;
result_buf->h_name = alias[1];
result_buf->h_addrtype = AF_INET6;
result_buf->h_length = sizeof(*in6);
@@ -2013,8 +1539,9 @@ int attribute_hidden __read_etc_hosts_r(
result_buf->h_aliases = alias + 2;
*result = result_buf;
ret = NETDB_SUCCESS;
-#endif /* __UCLIBC_HAS_IPV6__ */
- } else {
+ }
+#endif
+ else {
/* continue parsing in the hope the user has multiple
* host types listed in the database like so:
* <ipv4 addr> host
@@ -2088,6 +1615,7 @@ DONE:
}
libc_hidden_def(gethostent_r)
+//TODO: move into separat .o file!
struct hostent *gethostent(void)
{
static struct hostent h;
@@ -2101,10 +1629,7 @@ struct hostent *gethostent(void)
80 /*namebuffer*/ + 2 /* margin */];
struct hostent *host;
-//BUG: the lock is not recursive!
-// __UCLIBC_MUTEX_LOCK(mylock);
gethostent_r(&h, buf, sizeof(buf), &host, &h_errno);
-// __UCLIBC_MUTEX_UNLOCK(mylock);
return host;
}
#endif
@@ -2161,9 +1686,66 @@ int attribute_hidden __get_hosts_byaddr_r(const char * addr, int len, int type,
#endif
+#ifdef L_gethostbyname
+
+struct hostent *gethostbyname(const char *name)
+{
+ static struct hostent h;
+ static char buf[sizeof(struct in_addr) +
+ 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)
+#endif
+
+
+#ifdef L_gethostbyname2
+
+struct hostent *gethostbyname2(const char *name, int family)
+{
+#ifndef __UCLIBC_HAS_IPV6__
+ return family == AF_INET ? gethostbyname(name) : (struct hostent*)NULL;
+#else
+ static struct hostent h;
+ static char buf[sizeof(struct in6_addr) +
+ 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
+}
+#endif
+
+
+#ifdef L_gethostbyaddr
+
+struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type)
+{
+ static struct hostent h;
+ static char buf[
+#ifndef __UCLIBC_HAS_IPV6__
+ sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
+#else
+ sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
+#endif /* __UCLIBC_HAS_IPV6__ */
+ sizeof(char *)*ALIAS_DIM + 384 /*namebuffer*/ + 32 /* margin */];
+ struct hostent *hp;
+
+ gethostbyaddr_r(addr, len, type, &h, buf, sizeof(buf), &hp, &h_errno);
+ return hp;
+}
+libc_hidden_def(gethostbyaddr)
+#endif
+
+
#ifdef L_getnameinfo
-libc_hidden_proto(getnameinfo)
int getnameinfo(const struct sockaddr *sa, socklen_t addrlen, char *host,
socklen_t hostlen, char *serv, socklen_t servlen,
unsigned int flags)
@@ -2929,24 +2511,15 @@ int __dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
#ifdef L_ns_name
-/*
- * printable(ch)
- * Thinking in noninternationalized USASCII (per the DNS spec),
- * is this character visible and not a space when printed ?
- * return:
- * boolean.
+/* Thinking in noninternationalized USASCII (per the DNS spec),
+ * is this character visible and not a space when printed ?
*/
static int printable(int ch)
{
return (ch > 0x20 && ch < 0x7f);
}
-
-/*
- * special(ch)
- * Thinking in noninternationalized USASCII (per the DNS spec),
- * is this characted special ("in need of quoting") ?
- * return:
- * boolean.
+/* Thinking in noninternationalized USASCII (per the DNS spec),
+ * is this characted special ("in need of quoting") ?
*/
static int special(int ch)
{
@@ -3144,4 +2717,410 @@ int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
}
libc_hidden_def(ns_name_unpack)
#endif /* L_ns_name */
+
+
+#ifdef L_res_init
+
+/* Protected by __resolv_lock */
+struct __res_state _res;
+
+/* Will be called under __resolv_lock. */
+static void res_sync_func(void)
+{
+ struct __res_state *rp = &(_res);
+ int n;
+
+ /* 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 /* 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).
+ */
+ // __resolv_opts = rp->options;
+ // ...
+}
+
+/* Our res_init never fails (always returns 0) */
+int res_init(void)
+{
+ struct __res_state *rp = &(_res);
+ int i;
+ int n;
+#ifdef __UCLIBC_HAS_IPV6__
+ int m = 0;
+#endif
+
+ __UCLIBC_MUTEX_LOCK(__resolv_lock);
+ __close_nameservers();
+ __open_nameservers();
+
+ __res_sync = res_sync_func;
+
+ memset(rp, 0, sizeof(*rp));
+ rp->options = RES_INIT;
+#ifdef __UCLIBC_HAS_COMPAT_RES_STATE__
+ rp->retrans = RES_TIMEOUT;
+ rp->retry = 4;
+ rp->id = random();
+#endif
+ rp->ndots = 1;
+#ifdef __UCLIBC_HAS_EXTRA_COMPAT_RES_STATE__
+ rp->_vcsock = -1;
+#endif
+
+ n = __searchdomains;
+ if (n > ARRAY_SIZE(rp->dnsrch))
+ n = ARRAY_SIZE(rp->dnsrch);
+ for (i = 0; i < n; i++)
+ rp->dnsrch[i] = __searchdomain[i];
+
+ /* copy nameservers' addresses */
+ i = 0;
+#ifdef __UCLIBC_HAS_IPV4__
+ n = 0;
+ while (n < ARRAY_SIZE(rp->nsaddr_list) && i < __nameservers) {
+ if (__nameserver[i].sa.sa_family == AF_INET) {
+ rp->nsaddr_list[n] = __nameserver[i].sa4; /* struct copy */
+#ifdef __UCLIBC_HAS_IPV6__
+ if (m < ARRAY_SIZE(rp->_u._ext.nsaddrs)) {
+ rp->_u._ext.nsaddrs[m] = (void*) &rp->nsaddr_list[n];
+ m++;
+ }
+#endif
+ n++;
+ }
+#ifdef __UCLIBC_HAS_IPV6__
+ if (__nameserver[i].sa.sa_family == AF_INET6
+ && m < ARRAY_SIZE(rp->_u._ext.nsaddrs)
+ ) {
+ struct sockaddr_in6 *sa6 = malloc(sizeof(sa6));
+ if (sa6) {
+ *sa6 = __nameserver[i].sa6; /* struct copy */
+ rp->_u._ext.nsaddrs[m] = sa6;
+ m++;
+ }
+ }
+#endif
+ i++;
+ }
+ rp->nscount = n;
+#ifdef __UCLIBC_HAS_IPV6__
+ rp->_u._ext.nscount = m;
+#endif
+
+#else /* IPv6 only */
+ while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs) && i < __nameservers) {
+ struct sockaddr_in6 *sa6 = malloc(sizeof(sa6));
+ if (sa6) {
+ *sa6 = __nameserver[i].sa6; /* struct copy */
+ rp->_u._ext.nsaddrs[m] = sa6;
+ m++;
+ }
+ i++;
+ }
+ rp->_u._ext.nscount = m;
+#endif
+
+ __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
+ return 0;
+}
+libc_hidden_def(res_init)
+
+#ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
+void res_close(void)
+{
+ __UCLIBC_MUTEX_LOCK(__resolv_lock);
+ __close_nameservers();
+ __res_sync = NULL;
+#ifdef __UCLIBC_HAS_IPV6__
+ {
+ char *p1 = (char*) &(_res.nsaddr_list[0]);
+ int m = 0;
+ /* free nsaddrs[m] if they do not point to nsaddr_list[x] */
+ while (m < ARRAY_SIZE(_res._u._ext.nsaddrs)) {
+ char *p2 = (char*)(_res._u._ext.nsaddrs[m]);
+ if (p2 < p1 || (p2 - p1) > sizeof(_res.nsaddr_list))
+ free(p2);
+ }
+ }
+#endif
+ memset(&_res, 0, sizeof(_res));
+ __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
+}
+#endif
+#endif /* L_res_init */
+
+
+#ifdef L_res_query
+
+int res_query(const char *dname, int class, int type,
+ unsigned char *answer, int anslen)
+{
+ int i;
+ unsigned char * packet = NULL;
+ struct resolv_answer a;
+
+ if (!dname || class != 1 /* CLASS_IN */) {
+ h_errno = NO_RECOVERY;
+ return -1;
+ }
+
+ memset(&a, '\0', sizeof(a));
+ i = __dns_lookup(dname, type, &packet, &a);
+
+ if (i < 0) {
+ h_errno = TRY_AGAIN;
+ return -1;
+ }
+
+ free(a.dotted);
+
+ if (a.atype == type) { /* CNAME */
+ if (i > anslen)
+ i = anslen;
+ memcpy(answer, packet, i);
+ }
+ free(packet);
+ return i;
+}
+libc_hidden_def(res_query)
+
+/*
+ * Formulate a normal query, send, and retrieve answer in supplied buffer.
+ * Return the size of the response on success, -1 on error.
+ * If enabled, implement search rules until answer or unrecoverable failure
+ * is detected. Error code, if any, is left in h_errno.
+ */
+#define __TRAILING_DOT (1<<0)
+#define __GOT_NODATA (1<<1)
+#define __GOT_SERVFAIL (1<<2)
+#define __TRIED_AS_IS (1<<3)
+int res_search(const char *name, int class, int type, u_char *answer,
+ int anslen)
+{
+ const char *cp, * const *domain;
+ HEADER *hp = (HEADER *)(void *)answer;
+ unsigned dots;
+ unsigned state;
+ int ret, saved_herrno;
+ uint32_t _res_options;
+ unsigned _res_ndots;
+ char **_res_dnsrch;
+
+ if (!name || !answer) {
+ h_errno = NETDB_INTERNAL;
+ return -1;
+ }
+
+ again:
+ __UCLIBC_MUTEX_LOCK(__resolv_lock);
+ _res_options = _res.options;
+ _res_ndots = _res.ndots;
+ _res_dnsrch = _res.dnsrch;
+ __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
+ if (!(_res_options & RES_INIT)) {
+ res_init(); /* our res_init never fails */
+ goto again;
+ }
+
+ state = 0;
+ errno = 0;
+ h_errno = HOST_NOT_FOUND; /* default, if we never query */
+ dots = 0;
+ for (cp = name; *cp; cp++)
+ dots += (*cp == '.');
+
+ if (cp > name && *--cp == '.')
+ state |= __TRAILING_DOT;
+
+ /*
+ * If there are dots in the name already, let's just give it a try
+ * 'as is'. The threshold can be set with the "ndots" option.
+ */
+ saved_herrno = -1;
+ if (dots >= _res_ndots) {
+ ret = res_querydomain(name, NULL, class, type, answer, anslen);
+ if (ret > 0)
+ return ret;
+ saved_herrno = h_errno;
+ state |= __TRIED_AS_IS;
+ }
+
+ /*
+ * We do at least one level of search if
+ * - there is no dot and RES_DEFNAME is set, or
+ * - there is at least one dot, there is no trailing dot,
+ * and RES_DNSRCH is set.
+ */
+ if ((!dots && (_res_options & RES_DEFNAMES))
+ || (dots && !(state & __TRAILING_DOT) && (_res_options & RES_DNSRCH))
+ ) {
+ bool done = 0;
+
+ for (domain = (const char * const *)_res_dnsrch;
+ *domain && !done;
+ domain++) {
+
+ ret = res_querydomain(name, *domain, class, type,
+ answer, anslen);
+ if (ret > 0)
+ return ret;
+
+ /*
+ * If no server present, give up.
+ * If name isn't found in this domain,
+ * keep trying higher domains in the search list
+ * (if that's enabled).
+ * On a NO_DATA error, keep trying, otherwise
+ * a wildcard entry of another type could keep us
+ * from finding this entry higher in the domain.
+ * If we get some other error (negative answer or
+ * server failure), then stop searching up,
+ * but try the input name below in case it's
+ * fully-qualified.
+ */
+ if (errno == ECONNREFUSED) {
+ h_errno = TRY_AGAIN;
+ return -1;
+ }
+
+ switch (h_errno) {
+ case NO_DATA:
+ state |= __GOT_NODATA;
+ /* FALLTHROUGH */
+ case HOST_NOT_FOUND:
+ /* keep trying */
+ break;
+ case TRY_AGAIN:
+ if (hp->rcode == SERVFAIL) {
+ /* try next search element, if any */
+ state |= __GOT_SERVFAIL;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ /* anything else implies that we're done */
+ done = 1;
+ }
+ /*
+ * if we got here for some reason other than DNSRCH,
+ * we only wanted one iteration of the loop, so stop.
+ */
+ if (!(_res_options & RES_DNSRCH))
+ done = 1;
+ }
+ }
+
+ /*
+ * if we have not already tried the name "as is", do that now.
+ * note that we do this regardless of how many dots were in the
+ * name or whether it ends with a dot.
+ */
+ if (!(state & __TRIED_AS_IS)) {
+ ret = res_querydomain(name, NULL, class, type, answer, anslen);
+ if (ret > 0)
+ return ret;
+ }
+
+ /*
+ * if we got here, we didn't satisfy the search.
+ * if we did an initial full query, return that query's h_errno
+ * (note that we wouldn't be here if that query had succeeded).
+ * else if we ever got a nodata, send that back as the reason.
+ * else send back meaningless h_errno, that being the one from
+ * the last DNSRCH we did.
+ */
+ if (saved_herrno != -1)
+ h_errno = saved_herrno;
+ else if (state & __GOT_NODATA)
+ h_errno = NO_DATA;
+ else if (state & __GOT_SERVFAIL)
+ h_errno = TRY_AGAIN;
+ return -1;
+}
+#undef __TRAILING_DOT
+#undef __GOT_NODATA
+#undef __GOT_SERVFAIL
+#undef __TRIED_AS_IS
+/*
+ * Perform a call on res_query on the concatenation of name and domain,
+ * removing a trailing dot from name if domain is NULL.
+ */
+int res_querydomain(const char *name, const char *domain, int class, int type,
+ u_char * answer, int anslen)
+{
+ char nbuf[MAXDNAME];
+ const char *longname = nbuf;
+ size_t n, d;
+#ifdef DEBUG
+ uint32_t _res_options;
+#endif
+
+ if (!name || !answer) {
+ h_errno = NETDB_INTERNAL;
+ return -1;
+ }
+
+#ifdef DEBUG
+ again:
+ __UCLIBC_MUTEX_LOCK(__resolv_lock);
+ _res_options = _res.options;
+ __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
+ if (!(_res_options & RES_INIT)) {
+ res_init(); /* our res_init never fails */
+ goto again:
+ }
+ if (_res_options & RES_DEBUG)
+ printf(";; res_querydomain(%s, %s, %d, %d)\n",
+ name, (domain ? domain : "<Nil>"), class, type);
+#endif
+ if (domain == NULL) {
+ /*
+ * Check for trailing '.';
+ * copy without '.' if present.
+ */
+ n = strlen(name);
+ if (n + 1 > sizeof(nbuf)) {
+ h_errno = NO_RECOVERY;
+ return -1;
+ }
+ if (n > 0 && name[--n] == '.') {
+ strncpy(nbuf, name, n);
+ nbuf[n] = '\0';
+ } else
+ longname = name;
+ } else {
+ n = strlen(name);
+ d = strlen(domain);
+ if (n + 1 + d + 1 > sizeof(nbuf)) {
+ h_errno = NO_RECOVERY;
+ return -1;
+ }
+ snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
+ }
+ return res_query(longname, class, type, answer, anslen);
+}
+libc_hidden_def(res_querydomain)
+/* res_mkquery */
+/* res_send */
+/* dn_comp */
+/* dn_expand */
+#endif
+
/* vi: set sw=4 ts=4: */