|
@@ -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,445 +1396,330 @@ 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 + 32];
|
|
|
- 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 + 32];
|
|
|
- struct hostent *hp;
|
|
|
-
|
|
|
- gethostbyname2_r(name, family, &h, buf, sizeof(buf), &hp, &h_errno);
|
|
|
- return hp;
|
|
|
-#endif
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
-
|
|
|
-#ifdef L_res_init
|
|
|
-
|
|
|
-
|
|
|
-struct __res_state _res;
|
|
|
+#ifdef L_read_etc_hosts_r
|
|
|
|
|
|
-
|
|
|
-static void res_sync_func(void)
|
|
|
+FILE * __open_etc_hosts(void)
|
|
|
{
|
|
|
- struct __res_state *rp = &(_res);
|
|
|
- int n;
|
|
|
-
|
|
|
-
|
|
|
- if (__nameserver != (void*) &__local_nameserver) {
|
|
|
-
|
|
|
- * 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];
|
|
|
-#else
|
|
|
- if (__nameservers > rp->nscount)
|
|
|
- __nameservers = rp->nscount;
|
|
|
- n = __nameservers;
|
|
|
- while (--n >= 0)
|
|
|
- __nameserver[n].sa4 = rp->nsaddr_list[n];
|
|
|
-#endif
|
|
|
+ FILE * fp;
|
|
|
+ if ((fp = fopen("/etc/hosts", "r")) == NULL) {
|
|
|
+ fp = fopen("/etc/config/hosts", "r");
|
|
|
}
|
|
|
-
|
|
|
- * to use which _res.XXX member(s).
|
|
|
- */
|
|
|
-
|
|
|
-
|
|
|
+ return fp;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-int res_init(void)
|
|
|
+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 __res_state *rp = &(_res);
|
|
|
- int i;
|
|
|
- int n;
|
|
|
+ struct in_addr *in = NULL;
|
|
|
+ struct in_addr **addr_list = NULL;
|
|
|
#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- int m = 0;
|
|
|
-#endif
|
|
|
-
|
|
|
- __UCLIBC_MUTEX_LOCK(__resolv_lock);
|
|
|
- __close_nameservers();
|
|
|
- __open_nameservers();
|
|
|
-
|
|
|
- __res_sync = res_sync_func;
|
|
|
+ struct in6_addr *in6 = NULL;
|
|
|
+ struct in6_addr **addr_list6 = NULL;
|
|
|
+#endif
|
|
|
+ char *cp, **alias;
|
|
|
+ int aliases, i, ret = HOST_NOT_FOUND;
|
|
|
|
|
|
- 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
|
|
|
+
|
|
|
+ i = ALIGN_BUFFER_OFFSET(buf);
|
|
|
+ buf += i;
|
|
|
+ buflen -= i;
|
|
|
|
|
|
- n = __searchdomains;
|
|
|
- if (n > ARRAY_SIZE(rp->dnsrch))
|
|
|
- n = ARRAY_SIZE(rp->dnsrch);
|
|
|
- for (i = 0; i < n; i++)
|
|
|
- rp->dnsrch[i] = __searchdomain[i];
|
|
|
+ alias = (char **)buf;
|
|
|
+ buf += sizeof(char **) * ALIAS_DIM;
|
|
|
+ buflen -= sizeof(char **) * ALIAS_DIM;
|
|
|
+ if ((ssize_t)buflen < 0)
|
|
|
+ return ERANGE;
|
|
|
|
|
|
-
|
|
|
- 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;
|
|
|
+ if (action != GETHOSTENT) {
|
|
|
#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- if (m < ARRAY_SIZE(rp->_u._ext.nsaddrs)) {
|
|
|
- rp->_u._ext.nsaddrs[m] = (void*) &rp->nsaddr_list[n];
|
|
|
- m++;
|
|
|
- }
|
|
|
+ char *p = buf;
|
|
|
+ size_t len = buflen;
|
|
|
#endif
|
|
|
- n++;
|
|
|
- }
|
|
|
+ *h_errnop = NETDB_INTERNAL;
|
|
|
+ in = (struct in_addr*)buf;
|
|
|
+ buf += sizeof(*in);
|
|
|
+ buflen -= sizeof(*in);
|
|
|
+ addr_list = (struct in_addr **)buf;
|
|
|
+ buf += sizeof(*addr_list) * 2;
|
|
|
+ buflen -= sizeof(*addr_list) * 2;
|
|
|
+ if ((ssize_t)buflen < 0)
|
|
|
+ return ERANGE;
|
|
|
#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;
|
|
|
- rp->_u._ext.nsaddrs[m] = sa6;
|
|
|
- m++;
|
|
|
- }
|
|
|
+ in6 = (struct in6_addr*)p;
|
|
|
+ p += sizeof(*in6);
|
|
|
+ len -= sizeof(*in6);
|
|
|
+ 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
|
|
|
- i++;
|
|
|
- }
|
|
|
- rp->nscount = n;
|
|
|
-#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- rp->_u._ext.nscount = m;
|
|
|
-#endif
|
|
|
+ if ((ssize_t)buflen < 80)
|
|
|
+ return ERANGE;
|
|
|
|
|
|
-#else
|
|
|
- while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs) && i < __nameservers) {
|
|
|
- struct sockaddr_in6 *sa6 = malloc(sizeof(sa6));
|
|
|
- if (sa6) {
|
|
|
- *sa6 = __nameserver[i].sa6;
|
|
|
- rp->_u._ext.nsaddrs[m] = sa6;
|
|
|
- m++;
|
|
|
+ fp = __open_etc_hosts();
|
|
|
+ if (fp == NULL) {
|
|
|
+ *result = NULL;
|
|
|
+ return errno;
|
|
|
}
|
|
|
- i++;
|
|
|
}
|
|
|
- rp->_u._ext.nscount = m;
|
|
|
-#endif
|
|
|
|
|
|
- __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-libc_hidden_def(res_init)
|
|
|
+ *h_errnop = HOST_NOT_FOUND;
|
|
|
+ while (fgets(buf, buflen, fp)) {
|
|
|
+ cp = strchr(buf, '#');
|
|
|
+ if (cp)
|
|
|
+ *cp = '\0';
|
|
|
+ DPRINTF("Looking at: %s\n", buf);
|
|
|
+ aliases = 0;
|
|
|
|
|
|
-#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;
|
|
|
-
|
|
|
- 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);
|
|
|
+ cp = buf;
|
|
|
+ while (*cp) {
|
|
|
+ while (*cp && isspace(*cp))
|
|
|
+ *cp++ = '\0';
|
|
|
+ if (!*cp)
|
|
|
+ break;
|
|
|
+ if (aliases < (2+MAX_ALIASES))
|
|
|
+ alias[aliases++] = cp;
|
|
|
+ while (*cp && !isspace(*cp))
|
|
|
+ cp++;
|
|
|
}
|
|
|
- }
|
|
|
-#endif
|
|
|
- memset(&_res, 0, sizeof(_res));
|
|
|
- __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
|
|
|
-}
|
|
|
-#endif
|
|
|
-#endif
|
|
|
+ alias[aliases] = NULL;
|
|
|
|
|
|
+ if (aliases < 2)
|
|
|
+ continue;
|
|
|
|
|
|
-#ifdef L_res_query
|
|
|
+ if (action == GETHOSTENT) {
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (action == GET_HOSTS_BYADDR) {
|
|
|
+ if (strcmp(name, alias[0]) != 0)
|
|
|
+ continue;
|
|
|
+ } else {
|
|
|
+
|
|
|
+ for (i = 1; i < aliases; i++)
|
|
|
+ if (strcasecmp(name, alias[i]) == 0)
|
|
|
+ break;
|
|
|
+ if (i >= aliases)
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
-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 ) {
|
|
|
- h_errno = NO_RECOVERY;
|
|
|
- return -1;
|
|
|
+ if (type == AF_INET && inet_pton(AF_INET, alias[0], in) > 0) {
|
|
|
+ DPRINTF("Found INET\n");
|
|
|
+ addr_list[0] = in;
|
|
|
+ addr_list[1] = NULL;
|
|
|
+ result_buf->h_name = alias[1];
|
|
|
+ result_buf->h_addrtype = AF_INET;
|
|
|
+ result_buf->h_length = sizeof(*in);
|
|
|
+ result_buf->h_addr_list = (char**) addr_list;
|
|
|
+ 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) {
|
|
|
+ DPRINTF("Found INET6\n");
|
|
|
+ addr_list6[0] = in6;
|
|
|
+ addr_list6[1] = NULL;
|
|
|
+ result_buf->h_name = alias[1];
|
|
|
+ result_buf->h_addrtype = AF_INET6;
|
|
|
+ result_buf->h_length = sizeof(*in6);
|
|
|
+ result_buf->h_addr_list = (char**) addr_list6;
|
|
|
+ result_buf->h_aliases = alias + 2;
|
|
|
+ *result = result_buf;
|
|
|
+ ret = NETDB_SUCCESS;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ else {
|
|
|
+
|
|
|
+ * host types listed in the database like so:
|
|
|
+ * <ipv4 addr> host
|
|
|
+ * <ipv6 addr> host
|
|
|
+ * If looking for an IPv6 addr, don't bail when we got the IPv4
|
|
|
+ */
|
|
|
+ DPRINTF("Error: Found host but diff network type\n");
|
|
|
+
|
|
|
+ * to avoid looking for IPv6 addr of "localhost" etc */
|
|
|
+ ret = TRY_AGAIN;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ break;
|
|
|
}
|
|
|
+ if (action != GETHOSTENT)
|
|
|
+ fclose(fp);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+#endif
|
|
|
|
|
|
- memset(&a, '\0', sizeof(a));
|
|
|
- i = __dns_lookup(dname, type, &packet, &a);
|
|
|
|
|
|
- if (i < 0) {
|
|
|
- h_errno = TRY_AGAIN;
|
|
|
- return -1;
|
|
|
- }
|
|
|
+#ifdef L_gethostent
|
|
|
|
|
|
- free(a.dotted);
|
|
|
+__UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
|
|
|
|
|
|
- if (a.atype == type) {
|
|
|
- if (i > anslen)
|
|
|
- i = anslen;
|
|
|
- memcpy(answer, packet, i);
|
|
|
+static smallint __stay_open;
|
|
|
+static FILE * __gethostent_fp;
|
|
|
+
|
|
|
+void endhostent(void)
|
|
|
+{
|
|
|
+ __UCLIBC_MUTEX_LOCK(mylock);
|
|
|
+ __stay_open = 0;
|
|
|
+ if (__gethostent_fp) {
|
|
|
+ fclose(__gethostent_fp);
|
|
|
+ __gethostent_fp = NULL;
|
|
|
}
|
|
|
- free(packet);
|
|
|
- return i;
|
|
|
+ __UCLIBC_MUTEX_UNLOCK(mylock);
|
|
|
}
|
|
|
-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)
|
|
|
+void sethostent(int stay_open)
|
|
|
{
|
|
|
- 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;
|
|
|
+ __UCLIBC_MUTEX_LOCK(mylock);
|
|
|
+ __stay_open = (stay_open != 0);
|
|
|
+ __UCLIBC_MUTEX_UNLOCK(mylock);
|
|
|
+}
|
|
|
|
|
|
- if (!name || !answer) {
|
|
|
- h_errno = NETDB_INTERNAL;
|
|
|
- return -1;
|
|
|
+int gethostent_r(struct hostent *result_buf, char *buf, size_t buflen,
|
|
|
+ struct hostent **result, int *h_errnop)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ __UCLIBC_MUTEX_LOCK(mylock);
|
|
|
+ if (__gethostent_fp == NULL) {
|
|
|
+ __gethostent_fp = __open_etc_hosts();
|
|
|
+ if (__gethostent_fp == NULL) {
|
|
|
+ *result = NULL;
|
|
|
+ ret = TRY_AGAIN;
|
|
|
+ goto DONE;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- 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();
|
|
|
- goto again;
|
|
|
+ ret = __read_etc_hosts_r(__gethostent_fp, NULL, AF_INET, GETHOSTENT,
|
|
|
+ result_buf, buf, buflen, result, h_errnop);
|
|
|
+ if (__stay_open == 0) {
|
|
|
+ fclose(__gethostent_fp);
|
|
|
+ __gethostent_fp = NULL;
|
|
|
}
|
|
|
+DONE:
|
|
|
+ __UCLIBC_MUTEX_UNLOCK(mylock);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+libc_hidden_def(gethostent_r)
|
|
|
|
|
|
- state = 0;
|
|
|
- errno = 0;
|
|
|
- h_errno = HOST_NOT_FOUND;
|
|
|
- dots = 0;
|
|
|
- for (cp = name; *cp; cp++)
|
|
|
- dots += (*cp == '.');
|
|
|
+
|
|
|
+struct hostent *gethostent(void)
|
|
|
+{
|
|
|
+ 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
|
|
|
+ sizeof(char *) * ALIAS_DIM +
|
|
|
+ 80 + 2 ];
|
|
|
+ struct hostent *host;
|
|
|
|
|
|
- if (cp > name && *--cp == '.')
|
|
|
- state |= __TRAILING_DOT;
|
|
|
+ gethostent_r(&h, buf, sizeof(buf), &host, &h_errno);
|
|
|
+ return host;
|
|
|
+}
|
|
|
+#endif
|
|
|
|
|
|
-
|
|
|
- * 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;
|
|
|
+
|
|
|
+#ifdef L_get_hosts_byname_r
|
|
|
+
|
|
|
+int attribute_hidden __get_hosts_byname_r(const char * name, int type,
|
|
|
+ struct hostent * result_buf,
|
|
|
+ char * buf, size_t buflen,
|
|
|
+ struct hostent ** result,
|
|
|
+ int * h_errnop)
|
|
|
+{
|
|
|
+ return __read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME,
|
|
|
+ result_buf, buf, buflen, result, h_errnop);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+#ifdef L_get_hosts_byaddr_r
|
|
|
+
|
|
|
+int attribute_hidden __get_hosts_byaddr_r(const char * addr, int len, int type,
|
|
|
+ struct hostent * result_buf,
|
|
|
+ char * buf, size_t buflen,
|
|
|
+ struct hostent ** result,
|
|
|
+ int * h_errnop)
|
|
|
+{
|
|
|
+#ifndef __UCLIBC_HAS_IPV6__
|
|
|
+ char ipaddr[INET_ADDRSTRLEN];
|
|
|
+#else
|
|
|
+ char ipaddr[INET6_ADDRSTRLEN];
|
|
|
+#endif
|
|
|
+
|
|
|
+ switch (type) {
|
|
|
+ case AF_INET:
|
|
|
+ if (len != sizeof(struct in_addr))
|
|
|
+ return 0;
|
|
|
+ break;
|
|
|
+#ifdef __UCLIBC_HAS_IPV6__
|
|
|
+ case AF_INET6:
|
|
|
+ if (len != sizeof(struct in6_addr))
|
|
|
+ return 0;
|
|
|
+ break;
|
|
|
+#endif
|
|
|
+ default:
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- * 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;
|
|
|
+ inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
|
|
|
|
|
|
- for (domain = (const char * const *)_res_dnsrch;
|
|
|
- *domain && !done;
|
|
|
- domain++) {
|
|
|
+ return __read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR,
|
|
|
+ result_buf, buf, buflen, result, h_errnop);
|
|
|
+}
|
|
|
+#endif
|
|
|
|
|
|
- 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;
|
|
|
- }
|
|
|
+#ifdef L_gethostbyname
|
|
|
|
|
|
- switch (h_errno) {
|
|
|
- case NO_DATA:
|
|
|
- state |= __GOT_NODATA;
|
|
|
-
|
|
|
- case HOST_NOT_FOUND:
|
|
|
-
|
|
|
- break;
|
|
|
- case TRY_AGAIN:
|
|
|
- if (hp->rcode == SERVFAIL) {
|
|
|
-
|
|
|
- state |= __GOT_SERVFAIL;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- default:
|
|
|
-
|
|
|
- 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;
|
|
|
- }
|
|
|
+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 + 32];
|
|
|
+ struct hostent *hp;
|
|
|
|
|
|
-
|
|
|
- * 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;
|
|
|
+ gethostbyname_r(name, &h, buf, sizeof(buf), &hp, &h_errno);
|
|
|
+ return hp;
|
|
|
}
|
|
|
-#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;
|
|
|
+libc_hidden_def(gethostbyname)
|
|
|
#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();
|
|
|
- goto again:
|
|
|
- }
|
|
|
- if (_res_options & RES_DEBUG)
|
|
|
- printf(";; res_querydomain(%s, %s, %d, %d)\n",
|
|
|
- name, (domain ? domain : "<Nil>"), class, type);
|
|
|
+#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 + 32];
|
|
|
+ struct hostent *hp;
|
|
|
+
|
|
|
+ gethostbyname2_r(name, family, &h, buf, sizeof(buf), &hp, &h_errno);
|
|
|
+ return hp;
|
|
|
#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)
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
#endif
|
|
|
|
|
|
|
|
@@ -1858,1290 +1744,1383 @@ libc_hidden_def(gethostbyaddr)
|
|
|
#endif
|
|
|
|
|
|
|
|
|
-#ifdef L_read_etc_hosts_r
|
|
|
-
|
|
|
-FILE * __open_etc_hosts(void)
|
|
|
-{
|
|
|
- FILE * fp;
|
|
|
- if ((fp = fopen("/etc/hosts", "r")) == NULL) {
|
|
|
- fp = fopen("/etc/config/hosts", "r");
|
|
|
- }
|
|
|
- return fp;
|
|
|
-}
|
|
|
+#ifdef L_getnameinfo
|
|
|
|
|
|
-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 getnameinfo(const struct sockaddr *sa, socklen_t addrlen, char *host,
|
|
|
+ socklen_t hostlen, char *serv, socklen_t servlen,
|
|
|
+ unsigned int flags)
|
|
|
{
|
|
|
- struct in_addr *in = NULL;
|
|
|
- struct in_addr **addr_list = NULL;
|
|
|
-#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- struct in6_addr *in6 = NULL;
|
|
|
- struct in6_addr **addr_list6 = NULL;
|
|
|
-#endif
|
|
|
- char *cp, **alias;
|
|
|
- int aliases, i, ret = HOST_NOT_FOUND;
|
|
|
+ int serrno = errno;
|
|
|
+ unsigned ok;
|
|
|
+ struct hostent *h = NULL;
|
|
|
+ char domain[256];
|
|
|
|
|
|
-
|
|
|
- i = ALIGN_BUFFER_OFFSET(buf);
|
|
|
- if (unlikely(i)) {
|
|
|
- if (buflen < i)
|
|
|
- return ERANGE;
|
|
|
- buf += i;
|
|
|
- buflen -= i;
|
|
|
- }
|
|
|
+ if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
|
|
|
+ return EAI_BADFLAGS;
|
|
|
|
|
|
- if (buflen < sizeof(char *) * ALIAS_DIM)
|
|
|
- return ERANGE;
|
|
|
- alias = (char **)buf;
|
|
|
- buf += sizeof(char **) * ALIAS_DIM;
|
|
|
- buflen -= sizeof(char **) * ALIAS_DIM;
|
|
|
+ if (sa == NULL || addrlen < sizeof(sa_family_t))
|
|
|
+ goto BAD_FAM;
|
|
|
|
|
|
- if (action != GETHOSTENT) {
|
|
|
+ ok = sa->sa_family;
|
|
|
+ if (ok == AF_LOCAL) ;
|
|
|
+#ifdef __UCLIBC_HAS_IPV4__
|
|
|
+ else if (ok == AF_INET) {
|
|
|
+ if (addrlen < sizeof(struct sockaddr_in))
|
|
|
+ goto BAD_FAM;
|
|
|
+ }
|
|
|
+#endif
|
|
|
#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- char *p = buf;
|
|
|
- size_t len = buflen;
|
|
|
+ else if (ok == AF_INET6) {
|
|
|
+ if (addrlen < sizeof(struct sockaddr_in6))
|
|
|
+ goto BAD_FAM;
|
|
|
+ }
|
|
|
#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;
|
|
|
+ else
|
|
|
+BAD_FAM:
|
|
|
+ return EAI_FAMILY;
|
|
|
|
|
|
+ ok = 0;
|
|
|
+ if (host != NULL && hostlen > 0)
|
|
|
+ switch (sa->sa_family) {
|
|
|
+ case AF_INET:
|
|
|
#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- if (len < sizeof(*in6))
|
|
|
- return ERANGE;
|
|
|
- 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 (len < buflen) {
|
|
|
- buflen = len;
|
|
|
- buf = p;
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
- if (buflen < 80)
|
|
|
- return ERANGE;
|
|
|
-
|
|
|
- fp = __open_etc_hosts();
|
|
|
- if (fp == NULL) {
|
|
|
- *result = NULL;
|
|
|
- return errno;
|
|
|
- }
|
|
|
- }
|
|
|
+ case AF_INET6:
|
|
|
+#endif
|
|
|
+ if (!(flags & NI_NUMERICHOST)) {
|
|
|
+ if (0) ;
|
|
|
+#ifdef __UCLIBC_HAS_IPV6__
|
|
|
+ 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
|
|
|
+#ifdef __UCLIBC_HAS_IPV4__
|
|
|
+ else
|
|
|
+ h = gethostbyaddr((const void *)
|
|
|
+ &(((const struct sockaddr_in *)sa)->sin_addr),
|
|
|
+ sizeof(struct in_addr), AF_INET);
|
|
|
+#endif
|
|
|
|
|
|
- *h_errnop = HOST_NOT_FOUND;
|
|
|
- while (fgets(buf, buflen, fp)) {
|
|
|
- cp = strchr(buf, '#');
|
|
|
- if (cp)
|
|
|
- *cp = '\0';
|
|
|
- DPRINTF("Looking at: %s\n", buf);
|
|
|
- aliases = 0;
|
|
|
+ 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)) != 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';
|
|
|
+ } else {
|
|
|
+ strncpy(host, h->h_name, hostlen);
|
|
|
+ }
|
|
|
+ ok = 1;
|
|
|
+#undef min
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- cp = buf;
|
|
|
- while (*cp) {
|
|
|
- while (*cp && isspace(*cp))
|
|
|
- *cp++ = '\0';
|
|
|
- if (!*cp)
|
|
|
- break;
|
|
|
- if (aliases < (2+MAX_ALIASES))
|
|
|
- alias[aliases++] = cp;
|
|
|
- while (*cp && !isspace(*cp))
|
|
|
- cp++;
|
|
|
- }
|
|
|
- alias[aliases] = NULL;
|
|
|
+ if (!ok) {
|
|
|
+ const char *c = NULL;
|
|
|
|
|
|
- if (aliases < 2)
|
|
|
- continue;
|
|
|
+ if (flags & NI_NAMEREQD) {
|
|
|
+ errno = serrno;
|
|
|
+ return EAI_NONAME;
|
|
|
+ }
|
|
|
+ if (0) ;
|
|
|
+#ifdef __UCLIBC_HAS_IPV6__
|
|
|
+ else if (sa->sa_family == AF_INET6) {
|
|
|
+ const struct sockaddr_in6 *sin6p;
|
|
|
|
|
|
- if (action == GETHOSTENT) {
|
|
|
-
|
|
|
+ sin6p = (const struct sockaddr_in6 *) sa;
|
|
|
+ c = inet_ntop(AF_INET6,
|
|
|
+ (const void *) &sin6p->sin6_addr,
|
|
|
+ host, hostlen);
|
|
|
+#if 0
|
|
|
+
|
|
|
+ uint32_t scopeid;
|
|
|
+ scopeid = sin6p->sin6_scope_id;
|
|
|
+ if (scopeid != 0) {
|
|
|
+
|
|
|
+ char scopebuf[IFNAMSIZ + 1];
|
|
|
+ char *scopeptr;
|
|
|
+ int ni_numericscope = 0;
|
|
|
+ size_t real_hostlen = strnlen(host, hostlen);
|
|
|
+ size_t scopelen = 0;
|
|
|
+
|
|
|
+ scopebuf[0] = SCOPE_DELIMITER;
|
|
|
+ scopebuf[1] = '\0';
|
|
|
+ scopeptr = &scopebuf[1];
|
|
|
+
|
|
|
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6p->sin6_addr)
|
|
|
+ || IN6_IS_ADDR_MC_LINKLOCAL(&sin6p->sin6_addr)) {
|
|
|
+ if (if_indextoname(scopeid, scopeptr) == NULL)
|
|
|
+ ++ni_numericscope;
|
|
|
+ else
|
|
|
+ scopelen = strlen(scopebuf);
|
|
|
+ } else {
|
|
|
+ ++ni_numericscope;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ni_numericscope)
|
|
|
+ scopelen = 1 + snprintf(scopeptr,
|
|
|
+ (scopebuf
|
|
|
+ + sizeof scopebuf
|
|
|
+ - scopeptr),
|
|
|
+ "%u", scopeid);
|
|
|
+
|
|
|
+ if (real_hostlen + scopelen + 1 > hostlen)
|
|
|
+ return EAI_SYSTEM;
|
|
|
+ memcpy(host + real_hostlen, scopebuf, scopelen + 1);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ }
|
|
|
+#endif
|
|
|
+#if defined __UCLIBC_HAS_IPV4__
|
|
|
+ else {
|
|
|
+ c = inet_ntop(AF_INET, (const void *)
|
|
|
+ &(((const struct sockaddr_in *) sa)->sin_addr),
|
|
|
+ host, hostlen);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ if (c == NULL) {
|
|
|
+ errno = serrno;
|
|
|
+ return EAI_SYSTEM;
|
|
|
+ }
|
|
|
+ ok = 1;
|
|
|
+ }
|
|
|
break;
|
|
|
- }
|
|
|
- if (action == GET_HOSTS_BYADDR) {
|
|
|
- if (strcmp(name, alias[0]) != 0)
|
|
|
- continue;
|
|
|
- } else {
|
|
|
-
|
|
|
- for (i = 1; i < aliases; i++)
|
|
|
- if (strcasecmp(name, alias[i]) == 0)
|
|
|
+
|
|
|
+ case AF_LOCAL:
|
|
|
+ if (!(flags & NI_NUMERICHOST)) {
|
|
|
+ struct utsname utsname;
|
|
|
+
|
|
|
+ if (!uname(&utsname)) {
|
|
|
+ strncpy(host, utsname.nodename, hostlen);
|
|
|
break;
|
|
|
- if (i >= aliases)
|
|
|
- continue;
|
|
|
- }
|
|
|
+ };
|
|
|
+ };
|
|
|
|
|
|
- if (type == AF_INET && inet_pton(AF_INET, alias[0], in) > 0) {
|
|
|
- DPRINTF("Found INET\n");
|
|
|
- addr_list[0] = in;
|
|
|
- addr_list[1] = 0;
|
|
|
- result_buf->h_name = alias[1];
|
|
|
- result_buf->h_addrtype = AF_INET;
|
|
|
- result_buf->h_length = sizeof(*in);
|
|
|
- result_buf->h_addr_list = (char**) addr_list;
|
|
|
- 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) {
|
|
|
- DPRINTF("Found INET6\n");
|
|
|
- addr_list6[0] = in6;
|
|
|
- addr_list6[1] = 0;
|
|
|
- result_buf->h_name = alias[1];
|
|
|
- result_buf->h_addrtype = AF_INET6;
|
|
|
- result_buf->h_length = sizeof(*in6);
|
|
|
- result_buf->h_addr_list = (char**) addr_list6;
|
|
|
- result_buf->h_aliases = alias + 2;
|
|
|
- *result = result_buf;
|
|
|
- ret = NETDB_SUCCESS;
|
|
|
-#endif
|
|
|
- } else {
|
|
|
-
|
|
|
- * host types listed in the database like so:
|
|
|
- * <ipv4 addr> host
|
|
|
- * <ipv6 addr> host
|
|
|
- * If looking for an IPv6 addr, don't bail when we got the IPv4
|
|
|
- */
|
|
|
- DPRINTF("Error: Found host but diff network type\n");
|
|
|
-
|
|
|
- * to avoid looking for IPv6 addr of "localhost" etc */
|
|
|
- ret = TRY_AGAIN;
|
|
|
- continue;
|
|
|
+ if (flags & NI_NAMEREQD) {
|
|
|
+ errno = serrno;
|
|
|
+ return EAI_NONAME;
|
|
|
+ }
|
|
|
+
|
|
|
+ strncpy(host, "localhost", hostlen);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return EAI_FAMILY;
|
|
|
+*/
|
|
|
+ }
|
|
|
+
|
|
|
+ if (serv && (servlen > 0)) {
|
|
|
+ if (sa->sa_family == AF_LOCAL) {
|
|
|
+ strncpy(serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
|
|
|
+ } else {
|
|
|
+ if (!(flags & NI_NUMERICSERV)) {
|
|
|
+ struct servent *s;
|
|
|
+ s = getservbyport(((const struct sockaddr_in *) sa)->sin_port,
|
|
|
+ ((flags & NI_DGRAM) ? "udp" : "tcp"));
|
|
|
+ if (s) {
|
|
|
+ strncpy(serv, s->s_name, servlen);
|
|
|
+ goto DONE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ snprintf(serv, servlen, "%d",
|
|
|
+ ntohs(((const struct sockaddr_in *) sa)->sin_port));
|
|
|
}
|
|
|
- break;
|
|
|
}
|
|
|
- if (action != GETHOSTENT)
|
|
|
- fclose(fp);
|
|
|
- return ret;
|
|
|
+DONE:
|
|
|
+ if (host && (hostlen > 0))
|
|
|
+ host[hostlen-1] = 0;
|
|
|
+ if (serv && (servlen > 0))
|
|
|
+ serv[servlen-1] = 0;
|
|
|
+ errno = serrno;
|
|
|
+ return 0;
|
|
|
}
|
|
|
+libc_hidden_def(getnameinfo)
|
|
|
#endif
|
|
|
|
|
|
|
|
|
-#ifdef L_gethostent
|
|
|
+#ifdef L_gethostbyname_r
|
|
|
|
|
|
-__UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
|
|
|
+
|
|
|
+ * "uClibc resolver's gethostbyname does not return the requested name
|
|
|
+ * as an alias, but instead returns the canonical name. glibc's
|
|
|
+ * gethostbyname has a similar bug where it returns the requested name
|
|
|
+ * with the search domain name appended (to make a FQDN) as an alias,
|
|
|
+ * but not the original name itself. Both contradict POSIX, which says
|
|
|
+ * that the name argument passed to gethostbyname must be in the alias list"
|
|
|
+ * This is fixed now, and we differ from glibc:
|
|
|
+ *
|
|
|
+ * $ ./gethostbyname_uclibc wer.google.com
|
|
|
+ * h_name:'c13-ss-2-lb.cnet.com'
|
|
|
+ * h_length:4
|
|
|
+ * h_addrtype:2 AF_INET
|
|
|
+ * alias:'wer.google.com' <===
|
|
|
+ * addr: 0x4174efd8 '216.239.116.65'
|
|
|
+ *
|
|
|
+ * $ ./gethostbyname_glibc wer.google.com
|
|
|
+ * h_name:'c13-ss-2-lb.cnet.com'
|
|
|
+ * h_length:4
|
|
|
+ * h_addrtype:2 AF_INET
|
|
|
+ * alias:'wer.google.com.com' <===
|
|
|
+ * addr:'216.239.116.65'
|
|
|
+ *
|
|
|
+ * When examples were run, /etc/resolv.conf contained "search com" line.
|
|
|
+ */
|
|
|
+int gethostbyname_r(const char * name,
|
|
|
+ struct hostent * result_buf,
|
|
|
+ char * buf,
|
|
|
+ size_t buflen,
|
|
|
+ struct hostent ** result,
|
|
|
+ int * h_errnop)
|
|
|
+{
|
|
|
+ struct in_addr **addr_list;
|
|
|
+ char **alias;
|
|
|
+ char *alias0;
|
|
|
+ unsigned char *packet;
|
|
|
+ struct resolv_answer a;
|
|
|
+ int i;
|
|
|
+ int wrong_af = 0;
|
|
|
|
|
|
-static smallint __stay_open;
|
|
|
-static FILE * __gethostent_fp;
|
|
|
+ *result = NULL;
|
|
|
+ if (!name)
|
|
|
+ return EINVAL;
|
|
|
|
|
|
-void endhostent(void)
|
|
|
-{
|
|
|
- __UCLIBC_MUTEX_LOCK(mylock);
|
|
|
- __stay_open = 0;
|
|
|
- if (__gethostent_fp) {
|
|
|
- fclose(__gethostent_fp);
|
|
|
- __gethostent_fp = NULL;
|
|
|
+
|
|
|
+ {
|
|
|
+ int old_errno = errno;
|
|
|
+ __set_errno(0);
|
|
|
+ i = __get_hosts_byname_r(name, AF_INET, result_buf,
|
|
|
+ buf, buflen, result, h_errnop);
|
|
|
+ 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:
|
|
|
+ if (errno == ENOENT) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ default:
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+ __set_errno(old_errno);
|
|
|
}
|
|
|
- __UCLIBC_MUTEX_UNLOCK(mylock);
|
|
|
-}
|
|
|
|
|
|
-void sethostent(int stay_open)
|
|
|
-{
|
|
|
- __UCLIBC_MUTEX_LOCK(mylock);
|
|
|
- __stay_open = (stay_open != 0);
|
|
|
- __UCLIBC_MUTEX_UNLOCK(mylock);
|
|
|
-}
|
|
|
+ DPRINTF("Nothing found in /etc/hosts\n");
|
|
|
+
|
|
|
+ *h_errnop = NETDB_INTERNAL;
|
|
|
+
|
|
|
+
|
|
|
+ i = strlen(name) + 1;
|
|
|
+ if ((ssize_t)buflen <= i)
|
|
|
+ return ERANGE;
|
|
|
+ strcpy(buf, name);
|
|
|
+ alias0 = buf;
|
|
|
+ buf += i;
|
|
|
+ buflen -= i;
|
|
|
+
|
|
|
+
|
|
|
+ i = ALIGN_BUFFER_OFFSET(buf);
|
|
|
+ buf += i;
|
|
|
+ buflen -= i;
|
|
|
+
|
|
|
+ alias = (char **)buf;
|
|
|
+ buf += sizeof(alias[0]) * 2;
|
|
|
+ buflen -= sizeof(alias[0]) * 2;
|
|
|
+
|
|
|
+ addr_list = (struct in_addr **)buf;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if ((ssize_t)buflen < 256)
|
|
|
+ return ERANGE;
|
|
|
|
|
|
-int gethostent_r(struct hostent *result_buf, char *buf, size_t buflen,
|
|
|
- struct hostent **result, int *h_errnop)
|
|
|
-{
|
|
|
- int ret;
|
|
|
+
|
|
|
+#ifdef __UCLIBC_MJN3_ONLY__
|
|
|
+#warning TODO -- generate the full list
|
|
|
+#endif
|
|
|
+ alias[0] = alias0;
|
|
|
+ alias[1] = NULL;
|
|
|
|
|
|
- __UCLIBC_MUTEX_LOCK(mylock);
|
|
|
- if (__gethostent_fp == NULL) {
|
|
|
- __gethostent_fp = __open_etc_hosts();
|
|
|
- if (__gethostent_fp == NULL) {
|
|
|
- *result = NULL;
|
|
|
- ret = TRY_AGAIN;
|
|
|
- goto DONE;
|
|
|
+
|
|
|
+ {
|
|
|
+ struct in_addr *in = (struct in_addr *)(buf + sizeof(addr_list[0]) * 2);
|
|
|
+ if (inet_aton(name, in)) {
|
|
|
+ addr_list[0] = in;
|
|
|
+ addr_list[1] = NULL;
|
|
|
+ result_buf->h_name = alias0;
|
|
|
+ result_buf->h_aliases = alias;
|
|
|
+ result_buf->h_addrtype = AF_INET;
|
|
|
+ result_buf->h_length = sizeof(struct in_addr);
|
|
|
+ result_buf->h_addr_list = (char **) addr_list;
|
|
|
+ *result = result_buf;
|
|
|
+ *h_errnop = NETDB_SUCCESS;
|
|
|
+ return NETDB_SUCCESS;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- ret = __read_etc_hosts_r(__gethostent_fp, NULL, AF_INET, GETHOSTENT,
|
|
|
- result_buf, buf, buflen, result, h_errnop);
|
|
|
- if (__stay_open == 0) {
|
|
|
- fclose(__gethostent_fp);
|
|
|
- __gethostent_fp = NULL;
|
|
|
+
|
|
|
+ * 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;
|
|
|
}
|
|
|
-DONE:
|
|
|
- __UCLIBC_MUTEX_UNLOCK(mylock);
|
|
|
- return ret;
|
|
|
-}
|
|
|
-libc_hidden_def(gethostent_r)
|
|
|
-
|
|
|
-struct hostent *gethostent(void)
|
|
|
-{
|
|
|
- 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
|
|
|
- sizeof(char *) * ALIAS_DIM +
|
|
|
- 80 + 2 ];
|
|
|
- struct hostent *host;
|
|
|
|
|
|
-
|
|
|
-
|
|
|
- gethostent_r(&h, buf, sizeof(buf), &host, &h_errno);
|
|
|
-
|
|
|
- return host;
|
|
|
-}
|
|
|
-#endif
|
|
|
+
|
|
|
+ {
|
|
|
+ a.buf = buf;
|
|
|
+
|
|
|
+ * we'll need space of one in_addr + two addr_list[] elems */
|
|
|
+ a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in_addr)));
|
|
|
+ a.add_count = 0;
|
|
|
+ i = __dns_lookup(name, T_A, &packet, &a);
|
|
|
+ if (i < 0) {
|
|
|
+ *h_errnop = HOST_NOT_FOUND;
|
|
|
+ DPRINTF("__dns_lookup returned < 0\n");
|
|
|
+ return TRY_AGAIN;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ if (a.atype == T_A) {
|
|
|
+
|
|
|
+
|
|
|
+ * another + 1 for NULL in last addr_list[]: */
|
|
|
+ int need_bytes = sizeof(addr_list[0]) * (a.add_count + 1 + 1)
|
|
|
+
|
|
|
+ + sizeof(struct in_addr);
|
|
|
+
|
|
|
+ int ips_len = a.add_count * a.rdlength;
|
|
|
|
|
|
-#ifdef L_get_hosts_byname_r
|
|
|
+ buflen -= (need_bytes + ips_len);
|
|
|
+ if ((ssize_t)buflen < 0) {
|
|
|
+ DPRINTF("buffer too small for all addresses\n");
|
|
|
+
|
|
|
+ i = ERANGE;
|
|
|
+ goto free_and_ret;
|
|
|
+ }
|
|
|
|
|
|
-int attribute_hidden __get_hosts_byname_r(const char * name, int type,
|
|
|
- struct hostent * result_buf,
|
|
|
- char * buf, size_t buflen,
|
|
|
- struct hostent ** result,
|
|
|
- int * h_errnop)
|
|
|
-{
|
|
|
- return __read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME,
|
|
|
- result_buf, buf, buflen, result, h_errnop);
|
|
|
-}
|
|
|
-#endif
|
|
|
+
|
|
|
+ * move them forward so that they are not destroyed */
|
|
|
+ DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a.add_count, a.rdlength, a.rdata);
|
|
|
+ memmove(buf + need_bytes, buf, ips_len);
|
|
|
|
|
|
+
|
|
|
+ buf += need_bytes - sizeof(struct in_addr);
|
|
|
+ memcpy(buf, a.rdata, sizeof(struct in_addr));
|
|
|
|
|
|
-#ifdef L_get_hosts_byaddr_r
|
|
|
+
|
|
|
+ for (i = 0; i <= a.add_count; i++) {
|
|
|
+ addr_list[i] = (struct in_addr*)buf;
|
|
|
+ buf += sizeof(struct in_addr);
|
|
|
+ }
|
|
|
+ addr_list[i] = NULL;
|
|
|
|
|
|
-int attribute_hidden __get_hosts_byaddr_r(const char * addr, int len, int type,
|
|
|
- struct hostent * result_buf,
|
|
|
- char * buf, size_t buflen,
|
|
|
- struct hostent ** result,
|
|
|
- int * h_errnop)
|
|
|
-{
|
|
|
-#ifndef __UCLIBC_HAS_IPV6__
|
|
|
- char ipaddr[INET_ADDRSTRLEN];
|
|
|
-#else
|
|
|
- char ipaddr[INET6_ADDRSTRLEN];
|
|
|
-#endif
|
|
|
+
|
|
|
+ * (it may contain search domains attached by __dns_lookup,
|
|
|
+ * or CNAME of the host if it is different from the name
|
|
|
+ * we used to find it) */
|
|
|
+ if (a.dotted && buflen > strlen(a.dotted)) {
|
|
|
+ strcpy(buf, a.dotted);
|
|
|
+ alias0 = buf;
|
|
|
+ }
|
|
|
|
|
|
- switch (type) {
|
|
|
- case AF_INET:
|
|
|
- if (len != sizeof(struct in_addr))
|
|
|
- return 0;
|
|
|
- break;
|
|
|
-#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- case AF_INET6:
|
|
|
- if (len != sizeof(struct in6_addr))
|
|
|
- return 0;
|
|
|
- break;
|
|
|
-#endif
|
|
|
- default:
|
|
|
- return 0;
|
|
|
+ result_buf->h_name = alias0;
|
|
|
+ result_buf->h_aliases = alias;
|
|
|
+ result_buf->h_addrtype = AF_INET;
|
|
|
+ result_buf->h_length = sizeof(struct in_addr);
|
|
|
+ result_buf->h_addr_list = (char **) addr_list;
|
|
|
+ *result = result_buf;
|
|
|
+ *h_errnop = NETDB_SUCCESS;
|
|
|
+ i = NETDB_SUCCESS;
|
|
|
+ goto free_and_ret;
|
|
|
}
|
|
|
|
|
|
- inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
|
|
|
+ *h_errnop = HOST_NOT_FOUND;
|
|
|
+ i = TRY_AGAIN;
|
|
|
|
|
|
- return __read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR,
|
|
|
- result_buf, buf, buflen, result, h_errnop);
|
|
|
+ free_and_ret:
|
|
|
+ free(a.dotted);
|
|
|
+ free(packet);
|
|
|
+ return i;
|
|
|
}
|
|
|
+libc_hidden_def(gethostbyname_r)
|
|
|
#endif
|
|
|
|
|
|
|
|
|
-#ifdef L_getnameinfo
|
|
|
+#ifdef L_gethostbyname2_r
|
|
|
|
|
|
-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)
|
|
|
+int gethostbyname2_r(const char *name,
|
|
|
+ int family,
|
|
|
+ struct hostent * result_buf,
|
|
|
+ char * buf,
|
|
|
+ size_t buflen,
|
|
|
+ struct hostent ** result,
|
|
|
+ int * h_errnop)
|
|
|
{
|
|
|
- int serrno = errno;
|
|
|
- unsigned ok;
|
|
|
- struct hostent *h = NULL;
|
|
|
- char domain[256];
|
|
|
-
|
|
|
- if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
|
|
|
- return EAI_BADFLAGS;
|
|
|
-
|
|
|
- if (sa == NULL || addrlen < sizeof(sa_family_t))
|
|
|
- goto BAD_FAM;
|
|
|
-
|
|
|
- ok = sa->sa_family;
|
|
|
- if (ok == AF_LOCAL) ;
|
|
|
-#ifdef __UCLIBC_HAS_IPV4__
|
|
|
- else if (ok == AF_INET) {
|
|
|
- if (addrlen < sizeof(struct sockaddr_in))
|
|
|
- goto BAD_FAM;
|
|
|
- }
|
|
|
-#endif
|
|
|
-#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- else if (ok == AF_INET6) {
|
|
|
- if (addrlen < sizeof(struct sockaddr_in6))
|
|
|
- goto BAD_FAM;
|
|
|
- }
|
|
|
-#endif
|
|
|
- else
|
|
|
-BAD_FAM:
|
|
|
- return EAI_FAMILY;
|
|
|
-
|
|
|
- ok = 0;
|
|
|
- if (host != NULL && hostlen > 0)
|
|
|
- switch (sa->sa_family) {
|
|
|
- case AF_INET:
|
|
|
-#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- case AF_INET6:
|
|
|
-#endif
|
|
|
- if (!(flags & NI_NUMERICHOST)) {
|
|
|
- if (0) ;
|
|
|
-#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- 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
|
|
|
-#ifdef __UCLIBC_HAS_IPV4__
|
|
|
- else
|
|
|
- h = gethostbyaddr((const void *)
|
|
|
- &(((const struct sockaddr_in *)sa)->sin_addr),
|
|
|
- sizeof(struct in_addr), AF_INET);
|
|
|
-#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)) != 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';
|
|
|
- } else {
|
|
|
- strncpy(host, h->h_name, hostlen);
|
|
|
- }
|
|
|
- ok = 1;
|
|
|
-#undef min
|
|
|
- }
|
|
|
- }
|
|
|
+#ifndef __UCLIBC_HAS_IPV6__
|
|
|
+ return family == (AF_INET)
|
|
|
+ ? gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop)
|
|
|
+ : HOST_NOT_FOUND;
|
|
|
+#else
|
|
|
+ struct in6_addr *in;
|
|
|
+ struct in6_addr **addr_list;
|
|
|
+ unsigned char *packet;
|
|
|
+ struct resolv_answer a;
|
|
|
+ int i;
|
|
|
+ int nest = 0;
|
|
|
+ int wrong_af = 0;
|
|
|
|
|
|
- if (!ok) {
|
|
|
- const char *c = NULL;
|
|
|
+ if (family == AF_INET)
|
|
|
+ return gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop);
|
|
|
|
|
|
- if (flags & NI_NAMEREQD) {
|
|
|
- errno = serrno;
|
|
|
- return EAI_NONAME;
|
|
|
+ if (family != AF_INET6)
|
|
|
+ return EINVAL;
|
|
|
+
|
|
|
+ *result = NULL;
|
|
|
+ if (!name)
|
|
|
+ return EINVAL;
|
|
|
+
|
|
|
+
|
|
|
+ {
|
|
|
+ int old_errno = errno;
|
|
|
+ __set_errno(0);
|
|
|
+
|
|
|
+ i = __get_hosts_byname_r(name, family, result_buf,
|
|
|
+ buf, buflen, result, h_errnop);
|
|
|
+ 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:
|
|
|
+ if (errno == ENOENT) {
|
|
|
+ break;
|
|
|
}
|
|
|
- if (0) ;
|
|
|
-#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- else if (sa->sa_family == AF_INET6) {
|
|
|
- const struct sockaddr_in6 *sin6p;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+ __set_errno(old_errno);
|
|
|
+ }
|
|
|
+ DPRINTF("Nothing found in /etc/hosts\n");
|
|
|
|
|
|
- sin6p = (const struct sockaddr_in6 *) sa;
|
|
|
- c = inet_ntop(AF_INET6,
|
|
|
- (const void *) &sin6p->sin6_addr,
|
|
|
- host, hostlen);
|
|
|
-#if 0
|
|
|
-
|
|
|
- uint32_t scopeid;
|
|
|
- scopeid = sin6p->sin6_scope_id;
|
|
|
- if (scopeid != 0) {
|
|
|
-
|
|
|
- char scopebuf[IFNAMSIZ + 1];
|
|
|
- char *scopeptr;
|
|
|
- int ni_numericscope = 0;
|
|
|
- size_t real_hostlen = strnlen(host, hostlen);
|
|
|
- size_t scopelen = 0;
|
|
|
+ *h_errnop = NETDB_INTERNAL;
|
|
|
|
|
|
- scopebuf[0] = SCOPE_DELIMITER;
|
|
|
- scopebuf[1] = '\0';
|
|
|
- scopeptr = &scopebuf[1];
|
|
|
+
|
|
|
+ i = ALIGN_BUFFER_OFFSET(buf);
|
|
|
+ buf += i;
|
|
|
+ buflen -= i;
|
|
|
|
|
|
- if (IN6_IS_ADDR_LINKLOCAL(&sin6p->sin6_addr)
|
|
|
- || IN6_IS_ADDR_MC_LINKLOCAL(&sin6p->sin6_addr)) {
|
|
|
- if (if_indextoname(scopeid, scopeptr) == NULL)
|
|
|
- ++ni_numericscope;
|
|
|
- else
|
|
|
- scopelen = strlen(scopebuf);
|
|
|
- } else {
|
|
|
- ++ni_numericscope;
|
|
|
- }
|
|
|
+ in = (struct in6_addr*)buf;
|
|
|
+ buf += sizeof(*in);
|
|
|
+ buflen -= sizeof(*in);
|
|
|
+ addr_list = (struct in6_addr**)buf;
|
|
|
+ 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);
|
|
|
|
|
|
- if (ni_numericscope)
|
|
|
- scopelen = 1 + snprintf(scopeptr,
|
|
|
- (scopebuf
|
|
|
- + sizeof scopebuf
|
|
|
- - scopeptr),
|
|
|
- "%u", scopeid);
|
|
|
+
|
|
|
+ if (inet_pton(AF_INET6, name, in)) {
|
|
|
+ result_buf->h_name = buf;
|
|
|
+ result_buf->h_addrtype = AF_INET6;
|
|
|
+ result_buf->h_length = sizeof(*in);
|
|
|
+ result_buf->h_addr_list = (char **) addr_list;
|
|
|
+ *result = result_buf;
|
|
|
+ *h_errnop = NETDB_SUCCESS;
|
|
|
+ return NETDB_SUCCESS;
|
|
|
+ }
|
|
|
|
|
|
- if (real_hostlen + scopelen + 1 > hostlen)
|
|
|
- return EAI_SYSTEM;
|
|
|
- memcpy(host + real_hostlen, scopebuf, scopelen + 1);
|
|
|
- }
|
|
|
-#endif
|
|
|
- }
|
|
|
-#endif
|
|
|
-#if defined __UCLIBC_HAS_IPV4__
|
|
|
- else {
|
|
|
- c = inet_ntop(AF_INET, (const void *)
|
|
|
- &(((const struct sockaddr_in *) sa)->sin_addr),
|
|
|
- host, hostlen);
|
|
|
- }
|
|
|
-#endif
|
|
|
- if (c == NULL) {
|
|
|
- errno = serrno;
|
|
|
- return EAI_SYSTEM;
|
|
|
- }
|
|
|
- ok = 1;
|
|
|
- }
|
|
|
- break;
|
|
|
+
|
|
|
+ * 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;
|
|
|
+ }
|
|
|
|
|
|
- case AF_LOCAL:
|
|
|
- if (!(flags & NI_NUMERICHOST)) {
|
|
|
- struct utsname utsname;
|
|
|
+
|
|
|
+
|
|
|
+ memset(&a, '\0', sizeof(a));
|
|
|
+ for (;;) {
|
|
|
+ i = __dns_lookup(buf, T_AAAA, &packet, &a);
|
|
|
|
|
|
- if (!uname(&utsname)) {
|
|
|
- strncpy(host, utsname.nodename, hostlen);
|
|
|
- break;
|
|
|
- };
|
|
|
- };
|
|
|
+ if (i < 0) {
|
|
|
+ *h_errnop = HOST_NOT_FOUND;
|
|
|
+ return TRY_AGAIN;
|
|
|
+ }
|
|
|
|
|
|
- if (flags & NI_NAMEREQD) {
|
|
|
- errno = serrno;
|
|
|
- return EAI_NONAME;
|
|
|
- }
|
|
|
+ strncpy(buf, a.dotted, buflen);
|
|
|
+ free(a.dotted);
|
|
|
|
|
|
- strncpy(host, "localhost", hostlen);
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- return EAI_FAMILY;
|
|
|
-*/
|
|
|
- }
|
|
|
+ if (a.atype == T_CNAME) {
|
|
|
+ DPRINTF("Got a CNAME in gethostbyname()\n");
|
|
|
+ i = __decode_dotted(packet, a.rdoffset, buf, buflen);
|
|
|
+ free(packet);
|
|
|
|
|
|
- if (serv && (servlen > 0)) {
|
|
|
- if (sa->sa_family == AF_LOCAL) {
|
|
|
- strncpy(serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
|
|
|
- } else {
|
|
|
- if (!(flags & NI_NUMERICSERV)) {
|
|
|
- struct servent *s;
|
|
|
- s = getservbyport(((const struct sockaddr_in *) sa)->sin_port,
|
|
|
- ((flags & NI_DGRAM) ? "udp" : "tcp"));
|
|
|
- if (s) {
|
|
|
- strncpy(serv, s->s_name, servlen);
|
|
|
- goto DONE;
|
|
|
- }
|
|
|
+ if (i < 0) {
|
|
|
+ *h_errnop = NO_RECOVERY;
|
|
|
+ return -1;
|
|
|
}
|
|
|
- snprintf(serv, servlen, "%d",
|
|
|
- ntohs(((const struct sockaddr_in *) sa)->sin_port));
|
|
|
+ if (++nest > MAX_RECURSE) {
|
|
|
+ *h_errnop = NO_RECOVERY;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (a.atype == T_AAAA) {
|
|
|
+ memcpy(in, a.rdata, sizeof(*in));
|
|
|
+ result_buf->h_name = buf;
|
|
|
+ result_buf->h_addrtype = AF_INET6;
|
|
|
+ result_buf->h_length = sizeof(*in);
|
|
|
+ result_buf->h_addr_list = (char **) addr_list;
|
|
|
+ free(packet);
|
|
|
+ break;
|
|
|
}
|
|
|
+ free(packet);
|
|
|
+ *h_errnop = HOST_NOT_FOUND;
|
|
|
+ return TRY_AGAIN;
|
|
|
}
|
|
|
-DONE:
|
|
|
- if (host && (hostlen > 0))
|
|
|
- host[hostlen-1] = 0;
|
|
|
- if (serv && (servlen > 0))
|
|
|
- serv[servlen-1] = 0;
|
|
|
- errno = serrno;
|
|
|
- return 0;
|
|
|
+
|
|
|
+ *result = result_buf;
|
|
|
+ *h_errnop = NETDB_SUCCESS;
|
|
|
+ return NETDB_SUCCESS;
|
|
|
+#endif
|
|
|
}
|
|
|
-libc_hidden_def(getnameinfo)
|
|
|
+libc_hidden_def(gethostbyname2_r)
|
|
|
#endif
|
|
|
|
|
|
|
|
|
-#ifdef L_gethostbyname_r
|
|
|
+#ifdef L_gethostbyaddr_r
|
|
|
+
|
|
|
+int gethostbyaddr_r(const void *addr, socklen_t len, int type,
|
|
|
+ struct hostent * result_buf,
|
|
|
+ char * buf, size_t buflen,
|
|
|
+ struct hostent ** result,
|
|
|
+ int * h_errnop)
|
|
|
|
|
|
-
|
|
|
- * "uClibc resolver's gethostbyname does not return the requested name
|
|
|
- * as an alias, but instead returns the canonical name. glibc's
|
|
|
- * gethostbyname has a similar bug where it returns the requested name
|
|
|
- * with the search domain name appended (to make a FQDN) as an alias,
|
|
|
- * but not the original name itself. Both contradict POSIX, which says
|
|
|
- * that the name argument passed to gethostbyname must be in the alias list"
|
|
|
- * This is fixed now, and we differ from glibc:
|
|
|
- *
|
|
|
- * $ ./gethostbyname_uclibc wer.google.com
|
|
|
- * h_name:'c13-ss-2-lb.cnet.com'
|
|
|
- * h_length:4
|
|
|
- * h_addrtype:2 AF_INET
|
|
|
- * alias:'wer.google.com' <===
|
|
|
- * addr: 0x4174efd8 '216.239.116.65'
|
|
|
- *
|
|
|
- * $ ./gethostbyname_glibc wer.google.com
|
|
|
- * h_name:'c13-ss-2-lb.cnet.com'
|
|
|
- * h_length:4
|
|
|
- * h_addrtype:2 AF_INET
|
|
|
- * alias:'wer.google.com.com' <===
|
|
|
- * addr:'216.239.116.65'
|
|
|
- *
|
|
|
- * When examples were run, /etc/resolv.conf contained "search com" line.
|
|
|
- */
|
|
|
-int gethostbyname_r(const char * name,
|
|
|
- struct hostent * result_buf,
|
|
|
- char * buf,
|
|
|
- size_t buflen,
|
|
|
- struct hostent ** result,
|
|
|
- int * h_errnop)
|
|
|
{
|
|
|
+ struct in_addr *in;
|
|
|
struct in_addr **addr_list;
|
|
|
+#ifdef __UCLIBC_HAS_IPV6__
|
|
|
+ char *qp;
|
|
|
+ size_t plen;
|
|
|
+ struct in6_addr *in6;
|
|
|
+ struct in6_addr **addr_list6;
|
|
|
+#endif
|
|
|
char **alias;
|
|
|
- char *alias0;
|
|
|
unsigned char *packet;
|
|
|
struct resolv_answer a;
|
|
|
int i;
|
|
|
- int wrong_af = 0;
|
|
|
+ int nest = 0;
|
|
|
|
|
|
*result = NULL;
|
|
|
- if (!name)
|
|
|
+ if (!addr)
|
|
|
return EINVAL;
|
|
|
|
|
|
+ memset(&a, '\0', sizeof(a));
|
|
|
+
|
|
|
+ switch (type) {
|
|
|
+ case AF_INET:
|
|
|
+ if (len != sizeof(struct in_addr))
|
|
|
+ return EINVAL;
|
|
|
+ break;
|
|
|
+#ifdef __UCLIBC_HAS_IPV6__
|
|
|
+ case AF_INET6:
|
|
|
+ if (len != sizeof(struct in6_addr))
|
|
|
+ return EINVAL;
|
|
|
+ break;
|
|
|
+#endif
|
|
|
+ default:
|
|
|
+ return EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
- {
|
|
|
- int old_errno = errno;
|
|
|
- __set_errno(0);
|
|
|
- i = __get_hosts_byname_r(name, AF_INET, result_buf,
|
|
|
+ i = __get_hosts_byaddr_r(addr, len, type, result_buf,
|
|
|
buf, buflen, result, h_errnop);
|
|
|
- if (i == NETDB_SUCCESS) {
|
|
|
- __set_errno(old_errno);
|
|
|
+ if (i == 0)
|
|
|
+ return i;
|
|
|
+ switch (*h_errnop) {
|
|
|
+ case HOST_NOT_FOUND:
|
|
|
+ case NO_ADDRESS:
|
|
|
+ break;
|
|
|
+ default:
|
|
|
return i;
|
|
|
- }
|
|
|
- switch (*h_errnop) {
|
|
|
- case HOST_NOT_FOUND:
|
|
|
- wrong_af = (i == TRY_AGAIN);
|
|
|
- case NO_ADDRESS:
|
|
|
- break;
|
|
|
- case NETDB_INTERNAL:
|
|
|
- if (errno == ENOENT) {
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- default:
|
|
|
- return i;
|
|
|
- }
|
|
|
- __set_errno(old_errno);
|
|
|
}
|
|
|
|
|
|
- DPRINTF("Nothing found in /etc/hosts\n");
|
|
|
-
|
|
|
*h_errnop = NETDB_INTERNAL;
|
|
|
|
|
|
-
|
|
|
- i = strlen(name) + 1;
|
|
|
- if ((ssize_t)buflen <= i)
|
|
|
- return ERANGE;
|
|
|
- strcpy(buf, name);
|
|
|
- alias0 = buf;
|
|
|
- buf += i;
|
|
|
- buflen -= i;
|
|
|
-
|
|
|
|
|
|
i = ALIGN_BUFFER_OFFSET(buf);
|
|
|
buf += i;
|
|
|
buflen -= i;
|
|
|
|
|
|
+#ifdef __UCLIBC_HAS_IPV6__
|
|
|
+ qp = buf;
|
|
|
+ plen = buflen;
|
|
|
+#endif
|
|
|
+ in = (struct in_addr*)buf;
|
|
|
+ buf += sizeof(*in);
|
|
|
+ buflen -= sizeof(*in);
|
|
|
+ addr_list = (struct in_addr**)buf;
|
|
|
+ buf += sizeof(*addr_list) * 2;
|
|
|
+ buflen -= sizeof(*addr_list) * 2;
|
|
|
alias = (char **)buf;
|
|
|
- buf += sizeof(alias[0]) * 2;
|
|
|
- buflen -= sizeof(alias[0]) * 2;
|
|
|
-
|
|
|
- addr_list = (struct in_addr **)buf;
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- if ((ssize_t)buflen < 256)
|
|
|
+ buf += sizeof(*alias) * ALIAS_DIM;
|
|
|
+ buflen -= sizeof(*alias) * ALIAS_DIM;
|
|
|
+ if ((ssize_t)buflen < 0)
|
|
|
return ERANGE;
|
|
|
-
|
|
|
-
|
|
|
-#ifdef __UCLIBC_MJN3_ONLY__
|
|
|
-#warning TODO -- generate the full list
|
|
|
+#ifdef __UCLIBC_HAS_IPV6__
|
|
|
+ in6 = (struct in6_addr*)qp;
|
|
|
+ qp += sizeof(*in6);
|
|
|
+ plen -= sizeof(*in6);
|
|
|
+ addr_list6 = (struct in6_addr**)qp;
|
|
|
+ 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
|
|
|
- alias[0] = alias0;
|
|
|
- alias[1] = NULL;
|
|
|
+ if (buflen < 256)
|
|
|
+ return ERANGE;
|
|
|
|
|
|
-
|
|
|
- {
|
|
|
- struct in_addr *in = (struct in_addr *)(buf + sizeof(addr_list[0]) * 2);
|
|
|
- if (inet_aton(name, in)) {
|
|
|
- addr_list[0] = in;
|
|
|
- addr_list[1] = NULL;
|
|
|
- result_buf->h_name = alias0;
|
|
|
- result_buf->h_aliases = alias;
|
|
|
- result_buf->h_addrtype = AF_INET;
|
|
|
- result_buf->h_length = sizeof(struct in_addr);
|
|
|
- result_buf->h_addr_list = (char **) addr_list;
|
|
|
- *result = result_buf;
|
|
|
- *h_errnop = NETDB_SUCCESS;
|
|
|
- return NETDB_SUCCESS;
|
|
|
+ if (type == AF_INET) {
|
|
|
+ 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 {
|
|
|
+ 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);
|
|
|
}
|
|
|
+ strcpy(qp, "ip6.arpa");
|
|
|
}
|
|
|
+#endif
|
|
|
+ addr_list[1] = NULL;
|
|
|
|
|
|
-
|
|
|
- * 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;
|
|
|
- }
|
|
|
+ alias[0] = buf;
|
|
|
+ alias[1] = NULL;
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+ i = __dns_lookup(buf, T_PTR, &packet, &a);
|
|
|
|
|
|
-
|
|
|
- {
|
|
|
- a.buf = buf;
|
|
|
-
|
|
|
- * we'll need space of one in_addr + two addr_list[] elems */
|
|
|
- a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in_addr)));
|
|
|
- a.add_count = 0;
|
|
|
- i = __dns_lookup(name, T_A, &packet, &a);
|
|
|
if (i < 0) {
|
|
|
*h_errnop = HOST_NOT_FOUND;
|
|
|
- DPRINTF("__dns_lookup returned < 0\n");
|
|
|
return TRY_AGAIN;
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- if (a.atype == T_A) {
|
|
|
-
|
|
|
-
|
|
|
- * another + 1 for NULL in last addr_list[]: */
|
|
|
- int need_bytes = sizeof(addr_list[0]) * (a.add_count + 1 + 1)
|
|
|
-
|
|
|
- + sizeof(struct in_addr);
|
|
|
-
|
|
|
- int ips_len = a.add_count * a.rdlength;
|
|
|
-
|
|
|
- buflen -= (need_bytes + ips_len);
|
|
|
- if ((ssize_t)buflen < 0) {
|
|
|
- DPRINTF("buffer too small for all addresses\n");
|
|
|
-
|
|
|
- i = ERANGE;
|
|
|
- goto free_and_ret;
|
|
|
- }
|
|
|
|
|
|
-
|
|
|
- * move them forward so that they are not destroyed */
|
|
|
- DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a.add_count, a.rdlength, a.rdata);
|
|
|
- memmove(buf + need_bytes, buf, ips_len);
|
|
|
+ strncpy(buf, a.dotted, buflen);
|
|
|
+ free(a.dotted);
|
|
|
|
|
|
-
|
|
|
- buf += need_bytes - sizeof(struct in_addr);
|
|
|
- memcpy(buf, a.rdata, sizeof(struct in_addr));
|
|
|
+ if (a.atype == T_CNAME) {
|
|
|
+ DPRINTF("Got a CNAME in gethostbyaddr()\n");
|
|
|
+ i = __decode_dotted(packet, a.rdoffset, buf, buflen);
|
|
|
+ free(packet);
|
|
|
|
|
|
-
|
|
|
- for (i = 0; i <= a.add_count; i++) {
|
|
|
- addr_list[i] = (struct in_addr*)buf;
|
|
|
- buf += sizeof(struct in_addr);
|
|
|
+ if (i < 0) {
|
|
|
+ *h_errnop = NO_RECOVERY;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if (++nest > MAX_RECURSE) {
|
|
|
+ *h_errnop = NO_RECOVERY;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ continue;
|
|
|
}
|
|
|
- addr_list[i] = NULL;
|
|
|
|
|
|
-
|
|
|
- * (it may contain search domains attached by __dns_lookup,
|
|
|
- * or CNAME of the host if it is different from the name
|
|
|
- * we used to find it) */
|
|
|
- if (a.dotted && buflen > strlen(a.dotted)) {
|
|
|
- strcpy(buf, a.dotted);
|
|
|
- alias0 = buf;
|
|
|
+ if (a.atype == T_PTR) {
|
|
|
+ i = __decode_dotted(packet, a.rdoffset, buf, buflen);
|
|
|
+ free(packet);
|
|
|
+
|
|
|
+ result_buf->h_name = buf;
|
|
|
+ result_buf->h_addrtype = type;
|
|
|
+ if (type == AF_INET)
|
|
|
+ result_buf->h_length = sizeof(*in);
|
|
|
+#ifdef __UCLIBC_HAS_IPV6__
|
|
|
+ else
|
|
|
+ result_buf->h_length = sizeof(*in6);
|
|
|
+#endif
|
|
|
+ result_buf->h_addr_list = (char **) addr_list;
|
|
|
+ result_buf->h_aliases = alias;
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
- result_buf->h_name = alias0;
|
|
|
- result_buf->h_aliases = alias;
|
|
|
- result_buf->h_addrtype = AF_INET;
|
|
|
- result_buf->h_length = sizeof(struct in_addr);
|
|
|
- result_buf->h_addr_list = (char **) addr_list;
|
|
|
- *result = result_buf;
|
|
|
- *h_errnop = NETDB_SUCCESS;
|
|
|
- i = NETDB_SUCCESS;
|
|
|
- goto free_and_ret;
|
|
|
+ free(packet);
|
|
|
+ *h_errnop = NO_ADDRESS;
|
|
|
+ return TRY_AGAIN;
|
|
|
}
|
|
|
|
|
|
- *h_errnop = HOST_NOT_FOUND;
|
|
|
- i = TRY_AGAIN;
|
|
|
+ *result = result_buf;
|
|
|
+ *h_errnop = NETDB_SUCCESS;
|
|
|
+ return NETDB_SUCCESS;
|
|
|
+}
|
|
|
+libc_hidden_def(gethostbyaddr_r)
|
|
|
+#endif
|
|
|
+
|
|
|
|
|
|
- free_and_ret:
|
|
|
- free(a.dotted);
|
|
|
- free(packet);
|
|
|
- return i;
|
|
|
+#ifdef L_res_comp
|
|
|
+
|
|
|
+
|
|
|
+ * Expand compressed domain name 'comp_dn' to full domain name.
|
|
|
+ * 'msg' is a pointer to the begining of the message,
|
|
|
+ * 'eomorig' points to the first location after the message,
|
|
|
+ * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
|
|
|
+ * Return size of compressed name or -1 if there was an error.
|
|
|
+ */
|
|
|
+int __dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
|
|
|
+ char *dst, int dstsiz)
|
|
|
+{
|
|
|
+ int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
|
|
|
+
|
|
|
+ if (n > 0 && dst[0] == '.')
|
|
|
+ dst[0] = '\0';
|
|
|
+ return n;
|
|
|
}
|
|
|
-libc_hidden_def(gethostbyname_r)
|
|
|
-#endif
|
|
|
+#endif
|
|
|
|
|
|
|
|
|
-#ifdef L_gethostbyname2_r
|
|
|
+#ifdef L_ns_name
|
|
|
|
|
|
-int gethostbyname2_r(const char *name,
|
|
|
- int family,
|
|
|
- struct hostent * result_buf,
|
|
|
- char * buf,
|
|
|
- size_t buflen,
|
|
|
- struct hostent ** result,
|
|
|
- int * h_errnop)
|
|
|
+
|
|
|
+ * is this character visible and not a space when printed ?
|
|
|
+ */
|
|
|
+static int printable(int ch)
|
|
|
{
|
|
|
-#ifndef __UCLIBC_HAS_IPV6__
|
|
|
- return family == (AF_INET)
|
|
|
- ? gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop)
|
|
|
- : HOST_NOT_FOUND;
|
|
|
-#else
|
|
|
- struct in6_addr *in;
|
|
|
- struct in6_addr **addr_list;
|
|
|
- unsigned char *packet;
|
|
|
- struct resolv_answer a;
|
|
|
- int i;
|
|
|
- int nest = 0;
|
|
|
- int wrong_af = 0;
|
|
|
+ return (ch > 0x20 && ch < 0x7f);
|
|
|
+}
|
|
|
+
|
|
|
+ * is this characted special ("in need of quoting") ?
|
|
|
+ */
|
|
|
+static int special(int ch)
|
|
|
+{
|
|
|
+ switch (ch) {
|
|
|
+ case 0x22:
|
|
|
+ case 0x2E:
|
|
|
+ case 0x3B:
|
|
|
+ case 0x5C:
|
|
|
+
|
|
|
+ case 0x40:
|
|
|
+ case 0x24:
|
|
|
+ return 1;
|
|
|
+ default:
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- if (family == AF_INET)
|
|
|
- return gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop);
|
|
|
+
|
|
|
+ * ns_name_uncompress(msg, eom, src, dst, dstsiz)
|
|
|
+ * Expand compressed domain name to presentation format.
|
|
|
+ * return:
|
|
|
+ * Number of bytes read out of `src', or -1 (with errno set).
|
|
|
+ * note:
|
|
|
+ * Root domain returns as "." not "".
|
|
|
+ */
|
|
|
+int ns_name_uncompress(const u_char *msg, const u_char *eom,
|
|
|
+ const u_char *src, char *dst, size_t dstsiz)
|
|
|
+{
|
|
|
+ u_char tmp[NS_MAXCDNAME];
|
|
|
+ int n;
|
|
|
|
|
|
- if (family != AF_INET6)
|
|
|
- return EINVAL;
|
|
|
+ n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp);
|
|
|
+ if (n == -1)
|
|
|
+ return -1;
|
|
|
+ if (ns_name_ntop(tmp, dst, dstsiz) == -1)
|
|
|
+ return -1;
|
|
|
+ return n;
|
|
|
+}
|
|
|
+libc_hidden_def(ns_name_uncompress)
|
|
|
|
|
|
- *result = NULL;
|
|
|
- if (!name)
|
|
|
- return EINVAL;
|
|
|
+
|
|
|
+ * ns_name_ntop(src, dst, dstsiz)
|
|
|
+ * Convert an encoded domain name to printable ascii as per RFC1035.
|
|
|
+ * return:
|
|
|
+ * Number of bytes written to buffer, or -1 (with errno set)
|
|
|
+ * notes:
|
|
|
+ * The root is returned as "."
|
|
|
+ * All other domains are returned in non absolute form
|
|
|
+ */
|
|
|
+int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
|
|
|
+{
|
|
|
+ static const char digits[] = "0123456789";
|
|
|
|
|
|
-
|
|
|
- {
|
|
|
- int old_errno = errno;
|
|
|
- __set_errno(0);
|
|
|
+ const u_char *cp;
|
|
|
+ char *dn, *eom;
|
|
|
+ u_char c;
|
|
|
+ u_int n;
|
|
|
|
|
|
- i = __get_hosts_byname_r(name, family, result_buf,
|
|
|
- buf, buflen, result, h_errnop);
|
|
|
- if (i == NETDB_SUCCESS) {
|
|
|
- __set_errno(old_errno);
|
|
|
- return i;
|
|
|
+ cp = src;
|
|
|
+ dn = dst;
|
|
|
+ eom = dst + dstsiz;
|
|
|
+
|
|
|
+ while ((n = *cp++) != 0) {
|
|
|
+ if ((n & NS_CMPRSFLGS) != 0) {
|
|
|
+
|
|
|
+ __set_errno(EMSGSIZE);
|
|
|
+ return -1;
|
|
|
}
|
|
|
- switch (*h_errnop) {
|
|
|
- case HOST_NOT_FOUND:
|
|
|
- wrong_af = (i == TRY_AGAIN);
|
|
|
- case NO_ADDRESS:
|
|
|
- break;
|
|
|
- case NETDB_INTERNAL:
|
|
|
- if (errno == ENOENT) {
|
|
|
- break;
|
|
|
+ if (dn != dst) {
|
|
|
+ if (dn >= eom) {
|
|
|
+ __set_errno(EMSGSIZE);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ *dn++ = '.';
|
|
|
+ }
|
|
|
+ if (dn + n >= eom) {
|
|
|
+ __set_errno(EMSGSIZE);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ for ((void)NULL; n > 0; n--) {
|
|
|
+ c = *cp++;
|
|
|
+ if (special(c)) {
|
|
|
+ if (dn + 1 >= eom) {
|
|
|
+ __set_errno(EMSGSIZE);
|
|
|
+ return -1;
|
|
|
}
|
|
|
-
|
|
|
- default:
|
|
|
- return i;
|
|
|
+ *dn++ = '\\';
|
|
|
+ *dn++ = (char)c;
|
|
|
+ } else if (!printable(c)) {
|
|
|
+ if (dn + 3 >= eom) {
|
|
|
+ __set_errno(EMSGSIZE);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ *dn++ = '\\';
|
|
|
+ *dn++ = digits[c / 100];
|
|
|
+ *dn++ = digits[(c % 100) / 10];
|
|
|
+ *dn++ = digits[c % 10];
|
|
|
+ } else {
|
|
|
+ if (dn >= eom) {
|
|
|
+ __set_errno(EMSGSIZE);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ *dn++ = (char)c;
|
|
|
+ }
|
|
|
}
|
|
|
- __set_errno(old_errno);
|
|
|
}
|
|
|
- DPRINTF("Nothing found in /etc/hosts\n");
|
|
|
-
|
|
|
- *h_errnop = NETDB_INTERNAL;
|
|
|
-
|
|
|
-
|
|
|
- i = ALIGN_BUFFER_OFFSET(buf);
|
|
|
- buf += i;
|
|
|
- buflen -= i;
|
|
|
-
|
|
|
- in = (struct in6_addr*)buf;
|
|
|
- buf += sizeof(*in);
|
|
|
- buflen -= sizeof(*in);
|
|
|
- addr_list = (struct in6_addr**)buf;
|
|
|
- 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);
|
|
|
-
|
|
|
-
|
|
|
- if (inet_pton(AF_INET6, name, in)) {
|
|
|
- result_buf->h_name = buf;
|
|
|
- result_buf->h_addrtype = AF_INET6;
|
|
|
- result_buf->h_length = sizeof(*in);
|
|
|
- result_buf->h_addr_list = (char **) addr_list;
|
|
|
- *result = result_buf;
|
|
|
- *h_errnop = NETDB_SUCCESS;
|
|
|
- return NETDB_SUCCESS;
|
|
|
+ if (dn == dst) {
|
|
|
+ if (dn >= eom) {
|
|
|
+ __set_errno(EMSGSIZE);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ *dn++ = '.';
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
- * 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;
|
|
|
+ if (dn >= eom) {
|
|
|
+ __set_errno(EMSGSIZE);
|
|
|
+ return -1;
|
|
|
}
|
|
|
+ *dn++ = '\0';
|
|
|
+ return (dn - dst);
|
|
|
+}
|
|
|
+libc_hidden_def(ns_name_ntop)
|
|
|
|
|
|
-
|
|
|
-
|
|
|
- memset(&a, '\0', sizeof(a));
|
|
|
- for (;;) {
|
|
|
- i = __dns_lookup(buf, T_AAAA, &packet, &a);
|
|
|
-
|
|
|
- if (i < 0) {
|
|
|
- *h_errnop = HOST_NOT_FOUND;
|
|
|
- return TRY_AGAIN;
|
|
|
- }
|
|
|
+
|
|
|
+ * ns_name_unpack(msg, eom, src, dst, dstsiz)
|
|
|
+ * Unpack a domain name from a message, source may be compressed.
|
|
|
+ * return:
|
|
|
+ * -1 if it fails, or consumed octets if it succeeds.
|
|
|
+ */
|
|
|
+int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
|
|
|
+ u_char *dst, size_t dstsiz)
|
|
|
+{
|
|
|
+ const u_char *srcp, *dstlim;
|
|
|
+ u_char *dstp;
|
|
|
+ int n, len, checked;
|
|
|
|
|
|
- strncpy(buf, a.dotted, buflen);
|
|
|
- free(a.dotted);
|
|
|
+ len = -1;
|
|
|
+ checked = 0;
|
|
|
+ dstp = dst;
|
|
|
+ srcp = src;
|
|
|
+ dstlim = dst + dstsiz;
|
|
|
+ if (srcp < msg || srcp >= eom) {
|
|
|
+ __set_errno(EMSGSIZE);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ while ((n = *srcp++) != 0) {
|
|
|
+
|
|
|
+ switch (n & NS_CMPRSFLGS) {
|
|
|
+ case 0:
|
|
|
+
|
|
|
+ if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
|
|
|
+ __set_errno(EMSGSIZE);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ checked += n + 1;
|
|
|
+ *dstp++ = n;
|
|
|
+ memcpy(dstp, srcp, n);
|
|
|
+ dstp += n;
|
|
|
+ srcp += n;
|
|
|
+ break;
|
|
|
|
|
|
- if (a.atype == T_CNAME) {
|
|
|
- DPRINTF("Got a CNAME in gethostbyname()\n");
|
|
|
- i = __decode_dotted(packet, a.rdoffset, buf, buflen);
|
|
|
- free(packet);
|
|
|
+ case NS_CMPRSFLGS:
|
|
|
+ if (srcp >= eom) {
|
|
|
+ __set_errno(EMSGSIZE);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if (len < 0)
|
|
|
+ len = srcp - src + 1;
|
|
|
+ srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
|
|
|
+ if (srcp < msg || srcp >= eom) {
|
|
|
+ __set_errno(EMSGSIZE);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ checked += 2;
|
|
|
+
|
|
|
+ * Check for loops in the compressed name;
|
|
|
+ * if we've looked at the whole message,
|
|
|
+ * there must be a loop.
|
|
|
+ */
|
|
|
+ if (checked >= eom - msg) {
|
|
|
+ __set_errno(EMSGSIZE);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ break;
|
|
|
|
|
|
- if (i < 0) {
|
|
|
- *h_errnop = NO_RECOVERY;
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (++nest > MAX_RECURSE) {
|
|
|
- *h_errnop = NO_RECOVERY;
|
|
|
- return -1;
|
|
|
- }
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (a.atype == T_AAAA) {
|
|
|
- memcpy(in, a.rdata, sizeof(*in));
|
|
|
- result_buf->h_name = buf;
|
|
|
- result_buf->h_addrtype = AF_INET6;
|
|
|
- result_buf->h_length = sizeof(*in);
|
|
|
- result_buf->h_addr_list = (char **) addr_list;
|
|
|
- free(packet);
|
|
|
- break;
|
|
|
+ default:
|
|
|
+ __set_errno(EMSGSIZE);
|
|
|
+ return -1;
|
|
|
}
|
|
|
- free(packet);
|
|
|
- *h_errnop = HOST_NOT_FOUND;
|
|
|
- return TRY_AGAIN;
|
|
|
}
|
|
|
-
|
|
|
- *result = result_buf;
|
|
|
- *h_errnop = NETDB_SUCCESS;
|
|
|
- return NETDB_SUCCESS;
|
|
|
-#endif
|
|
|
+ *dstp = '\0';
|
|
|
+ if (len < 0)
|
|
|
+ len = srcp - src;
|
|
|
+ return len;
|
|
|
}
|
|
|
-libc_hidden_def(gethostbyname2_r)
|
|
|
-#endif
|
|
|
+libc_hidden_def(ns_name_unpack)
|
|
|
+#endif
|
|
|
|
|
|
|
|
|
-#ifdef L_gethostbyaddr_r
|
|
|
+#ifdef L_res_init
|
|
|
|
|
|
-int gethostbyaddr_r(const void *addr, socklen_t len, int type,
|
|
|
- struct hostent * result_buf,
|
|
|
- char * buf, size_t buflen,
|
|
|
- struct hostent ** result,
|
|
|
- int * h_errnop)
|
|
|
+
|
|
|
+struct __res_state _res;
|
|
|
|
|
|
+
|
|
|
+static void res_sync_func(void)
|
|
|
{
|
|
|
- struct in_addr *in;
|
|
|
- struct in_addr **addr_list;
|
|
|
-#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- char *qp;
|
|
|
- size_t plen;
|
|
|
- struct in6_addr *in6;
|
|
|
- struct in6_addr **addr_list6;
|
|
|
-#endif
|
|
|
- char **alias;
|
|
|
- unsigned char *packet;
|
|
|
- struct resolv_answer a;
|
|
|
- int i;
|
|
|
- int nest = 0;
|
|
|
-
|
|
|
- *result = NULL;
|
|
|
- if (!addr)
|
|
|
- return EINVAL;
|
|
|
-
|
|
|
- memset(&a, '\0', sizeof(a));
|
|
|
+ struct __res_state *rp = &(_res);
|
|
|
+ int n;
|
|
|
|
|
|
- switch (type) {
|
|
|
- case AF_INET:
|
|
|
- if (len != sizeof(struct in_addr))
|
|
|
- return EINVAL;
|
|
|
- break;
|
|
|
+
|
|
|
+ if (__nameserver != (void*) &__local_nameserver) {
|
|
|
+
|
|
|
+ * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
|
|
|
+ */
|
|
|
#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- case AF_INET6:
|
|
|
- if (len != sizeof(struct in6_addr))
|
|
|
- return EINVAL;
|
|
|
- break;
|
|
|
-#endif
|
|
|
- default:
|
|
|
- return EINVAL;
|
|
|
+ if (__nameservers > rp->_u._ext.nscount)
|
|
|
+ __nameservers = rp->_u._ext.nscount;
|
|
|
+ n = __nameservers;
|
|
|
+ while (--n >= 0)
|
|
|
+ __nameserver[n].sa6 = *rp->_u._ext.nsaddrs[n];
|
|
|
+#else
|
|
|
+ if (__nameservers > rp->nscount)
|
|
|
+ __nameservers = rp->nscount;
|
|
|
+ n = __nameservers;
|
|
|
+ while (--n >= 0)
|
|
|
+ __nameserver[n].sa4 = rp->nsaddr_list[n];
|
|
|
+#endif
|
|
|
}
|
|
|
+
|
|
|
+ * to use which _res.XXX member(s).
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
|
|
|
-
|
|
|
- i = __get_hosts_byaddr_r(addr, len, type, result_buf,
|
|
|
- buf, buflen, result, h_errnop);
|
|
|
- if (i == 0)
|
|
|
- return i;
|
|
|
- switch (*h_errnop) {
|
|
|
- case HOST_NOT_FOUND:
|
|
|
- case NO_ADDRESS:
|
|
|
- break;
|
|
|
- default:
|
|
|
- return i;
|
|
|
- }
|
|
|
+
|
|
|
+int res_init(void)
|
|
|
+{
|
|
|
+ struct __res_state *rp = &(_res);
|
|
|
+ int i;
|
|
|
+ int n;
|
|
|
+#ifdef __UCLIBC_HAS_IPV6__
|
|
|
+ int m = 0;
|
|
|
+#endif
|
|
|
|
|
|
- *h_errnop = NETDB_INTERNAL;
|
|
|
+ __UCLIBC_MUTEX_LOCK(__resolv_lock);
|
|
|
+ __close_nameservers();
|
|
|
+ __open_nameservers();
|
|
|
|
|
|
-
|
|
|
- i = ALIGN_BUFFER_OFFSET(buf);
|
|
|
- buf += i;
|
|
|
- buflen -= i;
|
|
|
+ __res_sync = res_sync_func;
|
|
|
|
|
|
-#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- qp = buf;
|
|
|
- plen = buflen;
|
|
|
+ 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
|
|
|
- in = (struct in_addr*)buf;
|
|
|
- buf += sizeof(*in);
|
|
|
- buflen -= sizeof(*in);
|
|
|
- addr_list = (struct in_addr**)buf;
|
|
|
- buf += sizeof(*addr_list) * 2;
|
|
|
- buflen -= sizeof(*addr_list) * 2;
|
|
|
- alias = (char **)buf;
|
|
|
- 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);
|
|
|
- addr_list6 = (struct in6_addr**)qp;
|
|
|
- qp += sizeof(*addr_list6) * 2;
|
|
|
- plen -= sizeof(*addr_list6) * 2;
|
|
|
- if ((ssize_t)plen < 0)
|
|
|
- return ERANGE;
|
|
|
- if (plen < buflen) {
|
|
|
- buflen = plen;
|
|
|
- buf = qp;
|
|
|
- }
|
|
|
+ rp->ndots = 1;
|
|
|
+#ifdef __UCLIBC_HAS_EXTRA_COMPAT_RES_STATE__
|
|
|
+ rp->_vcsock = -1;
|
|
|
#endif
|
|
|
- if (buflen < 256)
|
|
|
- return ERANGE;
|
|
|
|
|
|
- if (type == AF_INET) {
|
|
|
- unsigned char *tmp_addr = (unsigned char *)addr;
|
|
|
+ n = __searchdomains;
|
|
|
+ if (n > ARRAY_SIZE(rp->dnsrch))
|
|
|
+ n = ARRAY_SIZE(rp->dnsrch);
|
|
|
+ for (i = 0; i < n; i++)
|
|
|
+ rp->dnsrch[i] = __searchdomain[i];
|
|
|
|
|
|
- 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]);
|
|
|
- }
|
|
|
+
|
|
|
+ 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;
|
|
|
#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- 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);
|
|
|
+ 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;
|
|
|
+ rp->_u._ext.nsaddrs[m] = sa6;
|
|
|
+ m++;
|
|
|
+ }
|
|
|
}
|
|
|
- strcpy(qp, "ip6.arpa");
|
|
|
+#endif
|
|
|
+ i++;
|
|
|
}
|
|
|
+ rp->nscount = n;
|
|
|
+#ifdef __UCLIBC_HAS_IPV6__
|
|
|
+ rp->_u._ext.nscount = m;
|
|
|
#endif
|
|
|
- addr_list[1] = NULL;
|
|
|
-
|
|
|
- alias[0] = buf;
|
|
|
- alias[1] = NULL;
|
|
|
-
|
|
|
- for (;;) {
|
|
|
- i = __dns_lookup(buf, T_PTR, &packet, &a);
|
|
|
-
|
|
|
- if (i < 0) {
|
|
|
- *h_errnop = HOST_NOT_FOUND;
|
|
|
- return TRY_AGAIN;
|
|
|
- }
|
|
|
-
|
|
|
- strncpy(buf, a.dotted, buflen);
|
|
|
- free(a.dotted);
|
|
|
-
|
|
|
- if (a.atype == T_CNAME) {
|
|
|
- DPRINTF("Got a CNAME in gethostbyaddr()\n");
|
|
|
- i = __decode_dotted(packet, a.rdoffset, buf, buflen);
|
|
|
- free(packet);
|
|
|
|
|
|
- if (i < 0) {
|
|
|
- *h_errnop = NO_RECOVERY;
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (++nest > MAX_RECURSE) {
|
|
|
- *h_errnop = NO_RECOVERY;
|
|
|
- return -1;
|
|
|
- }
|
|
|
- continue;
|
|
|
+#else
|
|
|
+ while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs) && i < __nameservers) {
|
|
|
+ struct sockaddr_in6 *sa6 = malloc(sizeof(sa6));
|
|
|
+ if (sa6) {
|
|
|
+ *sa6 = __nameserver[i].sa6;
|
|
|
+ rp->_u._ext.nsaddrs[m] = sa6;
|
|
|
+ m++;
|
|
|
}
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ rp->_u._ext.nscount = m;
|
|
|
+#endif
|
|
|
|
|
|
- if (a.atype == T_PTR) {
|
|
|
- i = __decode_dotted(packet, a.rdoffset, buf, buflen);
|
|
|
- free(packet);
|
|
|
+ __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+libc_hidden_def(res_init)
|
|
|
|
|
|
- result_buf->h_name = buf;
|
|
|
- result_buf->h_addrtype = type;
|
|
|
- if (type == AF_INET)
|
|
|
- result_buf->h_length = sizeof(*in);
|
|
|
+#ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
|
|
|
+void res_close(void)
|
|
|
+{
|
|
|
+ __UCLIBC_MUTEX_LOCK(__resolv_lock);
|
|
|
+ __close_nameservers();
|
|
|
+ __res_sync = NULL;
|
|
|
#ifdef __UCLIBC_HAS_IPV6__
|
|
|
- else
|
|
|
- result_buf->h_length = sizeof(*in6);
|
|
|
-#endif
|
|
|
- result_buf->h_addr_list = (char **) addr_list;
|
|
|
- result_buf->h_aliases = alias;
|
|
|
- break;
|
|
|
+ {
|
|
|
+ char *p1 = (char*) &(_res.nsaddr_list[0]);
|
|
|
+ int m = 0;
|
|
|
+
|
|
|
+ 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);
|
|
|
}
|
|
|
-
|
|
|
- free(packet);
|
|
|
- *h_errnop = NO_ADDRESS;
|
|
|
- return TRY_AGAIN;
|
|
|
}
|
|
|
-
|
|
|
- *result = result_buf;
|
|
|
- *h_errnop = NETDB_SUCCESS;
|
|
|
- return NETDB_SUCCESS;
|
|
|
+#endif
|
|
|
+ memset(&_res, 0, sizeof(_res));
|
|
|
+ __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
|
|
|
}
|
|
|
-libc_hidden_def(gethostbyaddr_r)
|
|
|
#endif
|
|
|
+#endif
|
|
|
|
|
|
|
|
|
-#ifdef L_res_comp
|
|
|
+#ifdef L_res_query
|
|
|
|
|
|
-
|
|
|
- * Expand compressed domain name 'comp_dn' to full domain name.
|
|
|
- * 'msg' is a pointer to the begining of the message,
|
|
|
- * 'eomorig' points to the first location after the message,
|
|
|
- * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
|
|
|
- * Return size of compressed name or -1 if there was an error.
|
|
|
- */
|
|
|
-int __dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
|
|
|
- char *dst, int dstsiz)
|
|
|
+int res_query(const char *dname, int class, int type,
|
|
|
+ unsigned char *answer, int anslen)
|
|
|
{
|
|
|
- int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
|
|
|
+ int i;
|
|
|
+ unsigned char * packet = NULL;
|
|
|
+ struct resolv_answer a;
|
|
|
|
|
|
- if (n > 0 && dst[0] == '.')
|
|
|
- dst[0] = '\0';
|
|
|
- return n;
|
|
|
-}
|
|
|
-#endif
|
|
|
+ if (!dname || class != 1 ) {
|
|
|
+ h_errno = NO_RECOVERY;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
|
|
|
+ memset(&a, '\0', sizeof(a));
|
|
|
+ i = __dns_lookup(dname, type, &packet, &a);
|
|
|
|
|
|
-#ifdef L_ns_name
|
|
|
+ if (i < 0) {
|
|
|
+ h_errno = TRY_AGAIN;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
- * printable(ch)
|
|
|
- * Thinking in noninternationalized USASCII (per the DNS spec),
|
|
|
- * is this character visible and not a space when printed ?
|
|
|
- * return:
|
|
|
- * boolean.
|
|
|
- */
|
|
|
-static int printable(int ch)
|
|
|
-{
|
|
|
- return (ch > 0x20 && ch < 0x7f);
|
|
|
-}
|
|
|
+ free(a.dotted);
|
|
|
|
|
|
-
|
|
|
- * special(ch)
|
|
|
- * Thinking in noninternationalized USASCII (per the DNS spec),
|
|
|
- * is this characted special ("in need of quoting") ?
|
|
|
- * return:
|
|
|
- * boolean.
|
|
|
- */
|
|
|
-static int special(int ch)
|
|
|
-{
|
|
|
- switch (ch) {
|
|
|
- case 0x22:
|
|
|
- case 0x2E:
|
|
|
- case 0x3B:
|
|
|
- case 0x5C:
|
|
|
-
|
|
|
- case 0x40:
|
|
|
- case 0x24:
|
|
|
- return 1;
|
|
|
- default:
|
|
|
- return 0;
|
|
|
+ if (a.atype == type) {
|
|
|
+ if (i > anslen)
|
|
|
+ i = anslen;
|
|
|
+ memcpy(answer, packet, i);
|
|
|
}
|
|
|
+ free(packet);
|
|
|
+ return i;
|
|
|
}
|
|
|
+libc_hidden_def(res_query)
|
|
|
|
|
|
|
|
|
- * ns_name_uncompress(msg, eom, src, dst, dstsiz)
|
|
|
- * Expand compressed domain name to presentation format.
|
|
|
- * return:
|
|
|
- * Number of bytes read out of `src', or -1 (with errno set).
|
|
|
- * note:
|
|
|
- * Root domain returns as "." not "".
|
|
|
+ * 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.
|
|
|
*/
|
|
|
-int ns_name_uncompress(const u_char *msg, const u_char *eom,
|
|
|
- const u_char *src, char *dst, size_t dstsiz)
|
|
|
+#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)
|
|
|
{
|
|
|
- u_char tmp[NS_MAXCDNAME];
|
|
|
- int n;
|
|
|
+ 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;
|
|
|
|
|
|
- n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp);
|
|
|
- if (n == -1)
|
|
|
- return -1;
|
|
|
- if (ns_name_ntop(tmp, dst, dstsiz) == -1)
|
|
|
+ if (!name || !answer) {
|
|
|
+ h_errno = NETDB_INTERNAL;
|
|
|
return -1;
|
|
|
- return n;
|
|
|
-}
|
|
|
-libc_hidden_def(ns_name_uncompress)
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
- * ns_name_ntop(src, dst, dstsiz)
|
|
|
- * Convert an encoded domain name to printable ascii as per RFC1035.
|
|
|
- * return:
|
|
|
- * Number of bytes written to buffer, or -1 (with errno set)
|
|
|
- * notes:
|
|
|
- * The root is returned as "."
|
|
|
- * All other domains are returned in non absolute form
|
|
|
- */
|
|
|
-int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
|
|
|
-{
|
|
|
- static const char digits[] = "0123456789";
|
|
|
+ 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();
|
|
|
+ goto again;
|
|
|
+ }
|
|
|
+
|
|
|
+ state = 0;
|
|
|
+ errno = 0;
|
|
|
+ h_errno = HOST_NOT_FOUND;
|
|
|
+ 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;
|
|
|
|
|
|
- const u_char *cp;
|
|
|
- char *dn, *eom;
|
|
|
- u_char c;
|
|
|
- u_int n;
|
|
|
+ for (domain = (const char * const *)_res_dnsrch;
|
|
|
+ *domain && !done;
|
|
|
+ domain++) {
|
|
|
|
|
|
- cp = src;
|
|
|
- dn = dst;
|
|
|
- eom = dst + dstsiz;
|
|
|
+ ret = res_querydomain(name, *domain, class, type,
|
|
|
+ answer, anslen);
|
|
|
+ if (ret > 0)
|
|
|
+ return ret;
|
|
|
|
|
|
- while ((n = *cp++) != 0) {
|
|
|
- if ((n & NS_CMPRSFLGS) != 0) {
|
|
|
-
|
|
|
- __set_errno(EMSGSIZE);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (dn != dst) {
|
|
|
- if (dn >= eom) {
|
|
|
- __set_errno(EMSGSIZE);
|
|
|
+
|
|
|
+ * 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;
|
|
|
}
|
|
|
- *dn++ = '.';
|
|
|
- }
|
|
|
- if (dn + n >= eom) {
|
|
|
- __set_errno(EMSGSIZE);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- for ((void)NULL; n > 0; n--) {
|
|
|
- c = *cp++;
|
|
|
- if (special(c)) {
|
|
|
- if (dn + 1 >= eom) {
|
|
|
- __set_errno(EMSGSIZE);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- *dn++ = '\\';
|
|
|
- *dn++ = (char)c;
|
|
|
- } else if (!printable(c)) {
|
|
|
- if (dn + 3 >= eom) {
|
|
|
- __set_errno(EMSGSIZE);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- *dn++ = '\\';
|
|
|
- *dn++ = digits[c / 100];
|
|
|
- *dn++ = digits[(c % 100) / 10];
|
|
|
- *dn++ = digits[c % 10];
|
|
|
- } else {
|
|
|
- if (dn >= eom) {
|
|
|
- __set_errno(EMSGSIZE);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- *dn++ = (char)c;
|
|
|
+
|
|
|
+ switch (h_errno) {
|
|
|
+ case NO_DATA:
|
|
|
+ state |= __GOT_NODATA;
|
|
|
+
|
|
|
+ case HOST_NOT_FOUND:
|
|
|
+
|
|
|
+ break;
|
|
|
+ case TRY_AGAIN:
|
|
|
+ if (hp->rcode == SERVFAIL) {
|
|
|
+
|
|
|
+ state |= __GOT_SERVFAIL;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ default:
|
|
|
+
|
|
|
+ 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 (dn == dst) {
|
|
|
- if (dn >= eom) {
|
|
|
- __set_errno(EMSGSIZE);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- *dn++ = '.';
|
|
|
- }
|
|
|
- if (dn >= eom) {
|
|
|
- __set_errno(EMSGSIZE);
|
|
|
- return -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;
|
|
|
}
|
|
|
- *dn++ = '\0';
|
|
|
- return (dn - dst);
|
|
|
-}
|
|
|
-libc_hidden_def(ns_name_ntop)
|
|
|
|
|
|
+
|
|
|
+ * 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
|
|
|
|
|
|
- * ns_name_unpack(msg, eom, src, dst, dstsiz)
|
|
|
- * Unpack a domain name from a message, source may be compressed.
|
|
|
- * return:
|
|
|
- * -1 if it fails, or consumed octets if it succeeds.
|
|
|
+ * Perform a call on res_query on the concatenation of name and domain,
|
|
|
+ * removing a trailing dot from name if domain is NULL.
|
|
|
*/
|
|
|
-int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
|
|
|
- u_char *dst, size_t dstsiz)
|
|
|
+int res_querydomain(const char *name, const char *domain, int class, int type,
|
|
|
+ u_char * answer, int anslen)
|
|
|
{
|
|
|
- const u_char *srcp, *dstlim;
|
|
|
- u_char *dstp;
|
|
|
- int n, len, checked;
|
|
|
+ char nbuf[MAXDNAME];
|
|
|
+ const char *longname = nbuf;
|
|
|
+ size_t n, d;
|
|
|
+#ifdef DEBUG
|
|
|
+ uint32_t _res_options;
|
|
|
+#endif
|
|
|
|
|
|
- len = -1;
|
|
|
- checked = 0;
|
|
|
- dstp = dst;
|
|
|
- srcp = src;
|
|
|
- dstlim = dst + dstsiz;
|
|
|
- if (srcp < msg || srcp >= eom) {
|
|
|
- __set_errno(EMSGSIZE);
|
|
|
+ if (!name || !answer) {
|
|
|
+ h_errno = NETDB_INTERNAL;
|
|
|
return -1;
|
|
|
}
|
|
|
-
|
|
|
- while ((n = *srcp++) != 0) {
|
|
|
-
|
|
|
- switch (n & NS_CMPRSFLGS) {
|
|
|
- case 0:
|
|
|
-
|
|
|
- if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
|
|
|
- __set_errno(EMSGSIZE);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- checked += n + 1;
|
|
|
- *dstp++ = n;
|
|
|
- memcpy(dstp, srcp, n);
|
|
|
- dstp += n;
|
|
|
- srcp += n;
|
|
|
- break;
|
|
|
-
|
|
|
- case NS_CMPRSFLGS:
|
|
|
- if (srcp >= eom) {
|
|
|
- __set_errno(EMSGSIZE);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (len < 0)
|
|
|
- len = srcp - src + 1;
|
|
|
- srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
|
|
|
- if (srcp < msg || srcp >= eom) {
|
|
|
- __set_errno(EMSGSIZE);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- checked += 2;
|
|
|
-
|
|
|
- * Check for loops in the compressed name;
|
|
|
- * if we've looked at the whole message,
|
|
|
- * there must be a loop.
|
|
|
- */
|
|
|
- if (checked >= eom - msg) {
|
|
|
- __set_errno(EMSGSIZE);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- break;
|
|
|
|
|
|
- default:
|
|
|
- __set_errno(EMSGSIZE);
|
|
|
- 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();
|
|
|
+ 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);
|
|
|
}
|
|
|
- *dstp = '\0';
|
|
|
- if (len < 0)
|
|
|
- len = srcp - src;
|
|
|
- return len;
|
|
|
+ return res_query(longname, class, type, answer, anslen);
|
|
|
}
|
|
|
-libc_hidden_def(ns_name_unpack)
|
|
|
-#endif
|
|
|
+libc_hidden_def(res_querydomain)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
|