|
@@ -2200,12 +2200,13 @@ int gethostbyname2_r(const char *name,
|
|
|
? gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop)
|
|
|
: HOST_NOT_FOUND;
|
|
|
#else
|
|
|
- struct in6_addr *in;
|
|
|
struct in6_addr **addr_list;
|
|
|
+ char **alias;
|
|
|
+ char *alias0;
|
|
|
unsigned char *packet;
|
|
|
struct resolv_answer a;
|
|
|
int i;
|
|
|
- int nest = 0;
|
|
|
+ int packet_len;
|
|
|
int wrong_af = 0;
|
|
|
|
|
|
if (family == AF_INET)
|
|
@@ -2220,9 +2221,8 @@ int gethostbyname2_r(const char *name,
|
|
|
|
|
|
/* do /etc/hosts first */
|
|
|
{
|
|
|
- int old_errno = errno; /* Save the old errno and reset errno */
|
|
|
- __set_errno(0); /* to check for missing /etc/hosts. */
|
|
|
-
|
|
|
+ int old_errno = errno; /* save the old errno and reset errno */
|
|
|
+ __set_errno(0); /* to check for missing /etc/hosts. */
|
|
|
i = __get_hosts_byname_r(name, AF_INET6 /*family*/, result_buf,
|
|
|
buf, buflen, result, h_errnop);
|
|
|
if (i == NETDB_SUCCESS) {
|
|
@@ -2244,42 +2244,58 @@ int gethostbyname2_r(const char *name,
|
|
|
}
|
|
|
__set_errno(old_errno);
|
|
|
}
|
|
|
+
|
|
|
DPRINTF("Nothing found in /etc/hosts\n");
|
|
|
|
|
|
*h_errnop = NETDB_INTERNAL;
|
|
|
|
|
|
+ /* prepare future h_aliases[0] */
|
|
|
+ i = strlen(name) + 1;
|
|
|
+ if ((ssize_t)buflen <= i)
|
|
|
+ return ERANGE;
|
|
|
+ memcpy(buf, name, i); /* paranoia: name might change */
|
|
|
+ alias0 = buf;
|
|
|
+ buf += i;
|
|
|
+ buflen -= i;
|
|
|
/* make sure pointer is aligned */
|
|
|
i = ALIGN_BUFFER_OFFSET(buf);
|
|
|
buf += i;
|
|
|
buflen -= i;
|
|
|
/* Layout in buf:
|
|
|
- * struct in6_addr* in;
|
|
|
- * struct in6_addr* addr_list[2];
|
|
|
- * char scratch_buf[256];
|
|
|
+ * char *alias[2];
|
|
|
+ * struct in6_addr* addr_list[NN+1];
|
|
|
+ * struct in6_addr* in[NN];
|
|
|
*/
|
|
|
- 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;
|
|
|
+ alias = (char **)buf;
|
|
|
+ buf += sizeof(alias[0]) * 2;
|
|
|
+ buflen -= sizeof(alias[0]) * 2;
|
|
|
+ addr_list = (struct in6_addr **)buf;
|
|
|
+ /* buflen may be < 0, must do signed compare */
|
|
|
if ((ssize_t)buflen < 256)
|
|
|
return ERANGE;
|
|
|
- addr_list[0] = in;
|
|
|
- addr_list[1] = NULL;
|
|
|
- strncpy(buf, name, buflen);
|
|
|
- buf[buflen] = '\0';
|
|
|
+
|
|
|
+ /* we store only one "alias" - the name itself */
|
|
|
+#ifdef __UCLIBC_MJN3_ONLY__
|
|
|
+#warning TODO -- generate the full list
|
|
|
+#endif
|
|
|
+ alias[0] = alias0;
|
|
|
+ alias[1] = NULL;
|
|
|
|
|
|
/* maybe it is already an address? */
|
|
|
- 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_buf->h_aliases = ??? */
|
|
|
- *result = result_buf;
|
|
|
- *h_errnop = NETDB_SUCCESS;
|
|
|
- return NETDB_SUCCESS;
|
|
|
+ {
|
|
|
+ struct in6_addr *in = (struct in6_addr *)(buf + sizeof(addr_list[0]) * 2);
|
|
|
+ if (inet_pton(AF_INET6, 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_INET6;
|
|
|
+ result_buf->h_length = sizeof(struct in6_addr);
|
|
|
+ result_buf->h_addr_list = (char **) addr_list;
|
|
|
+ *result = result_buf;
|
|
|
+ *h_errnop = NETDB_SUCCESS;
|
|
|
+ return NETDB_SUCCESS;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* what if /etc/hosts has it but it's not IPv6?
|
|
@@ -2291,51 +2307,80 @@ int gethostbyname2_r(const char *name,
|
|
|
}
|
|
|
|
|
|
/* talk to DNS servers */
|
|
|
-/* TODO: why it's so different from gethostbyname_r (IPv4 case)? */
|
|
|
- memset(&a, '\0', sizeof(a));
|
|
|
- for (;;) {
|
|
|
- int packet_len;
|
|
|
+ a.buf = buf;
|
|
|
+ /* take into account that at least one address will be there,
|
|
|
+ * we'll need space of one in6_addr + two addr_list[] elems */
|
|
|
+ a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in6_addr)));
|
|
|
+ a.add_count = 0;
|
|
|
+ packet_len = __dns_lookup(name, T_AAAA, &packet, &a);
|
|
|
+ if (packet_len < 0) {
|
|
|
+ *h_errnop = HOST_NOT_FOUND;
|
|
|
+ DPRINTF("__dns_lookup returned < 0\n");
|
|
|
+ return TRY_AGAIN;
|
|
|
+ }
|
|
|
|
|
|
-/* Hmm why we memset(a) to zeros only once? */
|
|
|
- packet_len = __dns_lookup(buf, T_AAAA, &packet, &a);
|
|
|
- if (packet_len < 0) {
|
|
|
- *h_errnop = HOST_NOT_FOUND;
|
|
|
- return TRY_AGAIN;
|
|
|
+ if (a.atype == T_AAAA) { /* ADDRESS */
|
|
|
+ /* we need space for addr_list[] and one IPv6 address */
|
|
|
+ /* + 1 accounting for 1st addr (it's in a.rdata),
|
|
|
+ * another + 1 for NULL in last addr_list[]: */
|
|
|
+ int need_bytes = sizeof(addr_list[0]) * (a.add_count + 1 + 1)
|
|
|
+ /* for 1st addr (it's in a.rdata): */
|
|
|
+ + sizeof(struct in6_addr);
|
|
|
+ /* how many bytes will 2nd and following addresses take? */
|
|
|
+ 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");
|
|
|
+ /* *h_errnop = NETDB_INTERNAL; - already is */
|
|
|
+ i = ERANGE;
|
|
|
+ goto free_and_ret;
|
|
|
}
|
|
|
- strncpy(buf, a.dotted, buflen);
|
|
|
- free(a.dotted);
|
|
|
|
|
|
- if (a.atype != T_CNAME)
|
|
|
- break;
|
|
|
+ /* if there are additional addresses in buf,
|
|
|
+ * 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);
|
|
|
|
|
|
- DPRINTF("Got a CNAME in gethostbyname()\n");
|
|
|
- if (++nest > MAX_RECURSE) {
|
|
|
- *h_errnop = NO_RECOVERY;
|
|
|
- return -1;
|
|
|
+ /* 1st address is in a.rdata, insert it */
|
|
|
+ buf += need_bytes - sizeof(struct in6_addr);
|
|
|
+ memcpy(buf, a.rdata, sizeof(struct in6_addr));
|
|
|
+
|
|
|
+ /* fill addr_list[] */
|
|
|
+ for (i = 0; i <= a.add_count; i++) {
|
|
|
+ addr_list[i] = (struct in6_addr*)buf;
|
|
|
+ buf += sizeof(struct in6_addr);
|
|
|
}
|
|
|
- i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
|
|
|
- free(packet);
|
|
|
- if (i < 0) {
|
|
|
- *h_errnop = NO_RECOVERY;
|
|
|
- return -1;
|
|
|
+ addr_list[i] = NULL;
|
|
|
+
|
|
|
+ /* if we have enough space, we can report "better" name
|
|
|
+ * (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_AAAA) { /* ADDRESS */
|
|
|
- memcpy(in, a.rdata, sizeof(*in));
|
|
|
- result_buf->h_name = buf;
|
|
|
+
|
|
|
+ result_buf->h_name = alias0;
|
|
|
+ result_buf->h_aliases = alias;
|
|
|
result_buf->h_addrtype = AF_INET6;
|
|
|
- result_buf->h_length = sizeof(*in);
|
|
|
+ result_buf->h_length = sizeof(struct in6_addr);
|
|
|
result_buf->h_addr_list = (char **) addr_list;
|
|
|
- /* result_buf->h_aliases = ??? */
|
|
|
- free(packet);
|
|
|
*result = result_buf;
|
|
|
*h_errnop = NETDB_SUCCESS;
|
|
|
- return NETDB_SUCCESS;
|
|
|
+ i = NETDB_SUCCESS;
|
|
|
+ goto free_and_ret;
|
|
|
}
|
|
|
- free(packet);
|
|
|
+
|
|
|
*h_errnop = HOST_NOT_FOUND;
|
|
|
- return TRY_AGAIN;
|
|
|
+ __set_h_errno(HOST_NOT_FOUND);
|
|
|
+ i = TRY_AGAIN;
|
|
|
|
|
|
+ free_and_ret:
|
|
|
+ free(a.dotted);
|
|
|
+ free(packet);
|
|
|
+ return i;
|
|
|
#endif /* __UCLIBC_HAS_IPV6__ */
|
|
|
}
|
|
|
libc_hidden_def(gethostbyname2_r)
|