- a sequence of labels ending with a pointer
*/
-#define __FORCE_GLIBC
-#include <features.h>
#include <string.h>
#include <stdio.h>
+#include <stdio_ext.h>
#include <signal.h>
#include <errno.h>
#include <sys/poll.h>
#include <sys/utsname.h>
#include <sys/un.h>
#include <sys/stat.h>
+#include <sys/param.h>
#include <bits/uClibc_mutex.h>
#include "internal/parse_config.h"
#define MAX_RECURSE 5
#define MAXALIASES (4)
#define BUFSZ (80) /* one line */
-#define SBUFSIZE (BUFSZ + 1 + (sizeof(char *) * MAXALIASES))
+
+#define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
+#define DNS_LABELTYPE_BITSTRING 0x41
#undef DEBUG
/* #define DEBUG */
#define DPRINTF(X,args...)
#endif
-#undef ARRAY_SIZE
-#define ARRAY_SIZE(v) (sizeof(v) / sizeof((v)[0]))
-
/* Make sure the incoming char * buffer is aligned enough to handle our random
* structures. This define is the same as we use for malloc alignment (which
* has same requirements). The offset is the number of bytes we need to adjust
} sockaddr46_t;
-__UCLIBC_MUTEX_EXTERN(__resolv_lock);
+__UCLIBC_MUTEX_EXTERN(__resolv_lock) attribute_hidden;
/* Protected by __resolv_lock */
extern void (*__res_sync)(void) attribute_hidden;
#ifdef L_encodeh
-int attribute_hidden __encode_header(struct resolv_header *h, unsigned char *dest, int maxlen)
+int __encode_header(struct resolv_header *h, unsigned char *dest, int maxlen)
{
if (maxlen < HFIXEDSZ)
return -1;
return HFIXEDSZ;
}
-#endif
+#endif /* L_encodeh */
#ifdef L_decodeh
-void attribute_hidden __decode_header(unsigned char *data,
+void __decode_header(unsigned char *data,
struct resolv_header *h)
{
h->id = (data[0] << 8) | data[1];
h->nscount = (data[8] << 8) | data[9];
h->arcount = (data[10] << 8) | data[11];
}
-#endif
+#endif /* L_decodeh */
#ifdef L_encoded
/* Encode a dotted string into nameserver transport-level encoding.
This routine is fairly dumb, and doesn't attempt to compress
the data */
-int attribute_hidden __encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
+int __encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
{
unsigned used = 0;
return used;
}
-#endif
+#endif /* L_encoded */
#ifdef L_decoded
/* Decode a dotted string from nameserver transport-level encoding.
This routine understands compressed data. */
-int attribute_hidden __decode_dotted(const unsigned char *packet,
+int __decode_dotted(const unsigned char *packet,
int offset,
int packet_len,
char *dest,
return total;
}
-#endif
+#endif /* L_decoded */
#ifdef L_encodeq
-int attribute_hidden __encode_question(const struct resolv_question *q,
+int __encode_question(const struct resolv_question *q,
unsigned char *dest,
int maxlen)
{
return i + 4;
}
-#endif
+#endif /* L_encodeq */
#ifdef L_encodea
-int attribute_hidden __encode_answer(struct resolv_answer *a, unsigned char *dest, int maxlen)
+int __encode_answer(struct resolv_answer *a, unsigned char *dest, int maxlen)
{
int i;
return i + RRFIXEDSZ + a->rdlength;
}
-#endif
+#endif /* L_encodea */
#ifdef CURRENTLY_UNUSED
return total;
}
-#endif
+#endif /* L_encodep */
#ifdef L_decodep
__decode_header(data, h);
return HFIXEDSZ;
}
-#endif
+#endif /* L_decodep */
#ifdef L_formquery
const char *name,
int type,
unsigned char *packet,
- int maxlen);
+ int maxlen) attribute_hidden;
int __form_query(int id,
const char *name,
int type,
return i + j;
}
-#endif
+#endif /* L_formquery */
#endif /* CURRENTLY_UNUSED */
}
/* Must be called under __resolv_lock. */
-void attribute_hidden __open_nameservers(void)
+void __open_nameservers(void)
{
static uint32_t resolv_conf_mtime;
if (__res_sync)
__res_sync();
}
-#endif
+#endif /* L_opennameservers */
#ifdef L_closenameservers
/* Must be called under __resolv_lock. */
-void attribute_hidden __close_nameservers(void)
+void __close_nameservers(void)
{
if (__nameserver != (void*) &__local_nameserver)
free(__nameserver);
__searchdomain = NULL;
/*__searchdomains = 0; - already is */
}
-#endif
+#endif /* L_closenameservers */
#ifdef L_dnslookup
* appended. (why the filed is called "dotted" I have no idea)
* This is a malloced string. May be NULL because strdup failed.
*/
-int attribute_hidden __dns_lookup(const char *name,
+int __dns_lookup(const char *name,
int type,
unsigned char **outpacket,
struct resolv_answer *a)
goto try_next_server;
}
reply_timeout--;
-#else
+#else /* !USE_SELECT */
reply_timeout = __resolv_timeout * 1000;
wait_again:
fds.fd = fd;
}
/*TODO: better timeout accounting?*/
reply_timeout -= 1000;
-#endif
+#endif /* USE_SELECT */
/* vda: a bogus response seen in real world (caused SEGV in uclibc):
* "ping www.google.com" sending AAAA query and getting
/* bug 660 says we treat negative response as an error
* and retry, which is, eh, an error. :)
* We were incurring long delays because of this. */
- if (h.rcode == NXDOMAIN) {
+ if (h.rcode == NXDOMAIN || h.rcode == SERVFAIL) {
/* if possible, try next search domain */
if (!ends_with_dot) {
DPRINTF("variant:%d sdomains:%d\n", variant, sdomains);
}
/* no more search domains to try */
}
- /* dont loop, this is "no such host" situation */
- h_errno = HOST_NOT_FOUND;
- goto fail1;
+ if (h.rcode != SERVFAIL) {
+ /* dont loop, this is "no such host" situation */
+ h_errno = HOST_NOT_FOUND;
+ goto fail1;
+ }
}
/* Insert other non-fatal errors here, which do not warrant
* switching to next nameserver */
DPRINTF("Decoding answer at pos %d\n", pos);
first_answer = 1;
+ a->dotted = NULL;
for (j = 0; j < h.ancount; j++) {
i = __decode_answer(packet, pos, packet_len, &ma);
if (i < 0) {
ma.buf = a->buf;
ma.buflen = a->buflen;
ma.add_count = a->add_count;
+ free(a->dotted);
memcpy(a, &ma, sizeof(ma));
if (a->atype != T_SIG && (NULL == a->buf || (type != T_A && type != T_AAAA)))
break;
free(packet);
return -1;
}
-#endif
+#endif /* L_dnslookup */
#ifdef L_read_etc_hosts_r
parser_t * __open_etc_hosts(void)
{
- parser_t * parser;
- if ((parser = config_open("/etc/hosts")) == NULL) {
+ parser_t *parser;
+ parser = config_open("/etc/hosts");
#ifdef FALLBACK_TO_CONFIG_RESOLVCONF
+ if (parser == NULL)
parser = config_open("/etc/config/hosts");
#endif
- }
return parser;
}
-#define MINTOKENS 2 //dotted ip address + canonical name
+#define MINTOKENS 2 /* ip address + canonical name */
#define MAXTOKENS (MINTOKENS + MAXALIASES)
#define HALISTOFF (sizeof(char*) * MAXTOKENS)
#define INADDROFF (HALISTOFF + 2 * sizeof(char*))
-int attribute_hidden __read_etc_hosts_r(
+int __read_etc_hosts_r(
parser_t * parser,
const char *name,
int type,
struct hostent **result,
int *h_errnop)
{
- char **alias;
- char **host_aliases;
char **tok = NULL;
struct in_addr *h_addr0 = NULL;
const size_t aliaslen = INADDROFF +
*h_errnop = HOST_NOT_FOUND;
/* <ip>[[:space:]][<aliases>] */
while (config_read(parser, &tok, MAXTOKENS, MINTOKENS, "# \t", PARSE_NORMAL)) {
- result_buf->h_aliases = alias = host_aliases = tok+1;
+ result_buf->h_aliases = tok+1;
if (action == GETHOSTENT) {
/* Return whatever the next entry happens to be. */
break;
if (strcmp(name, *tok) != 0)
continue;
} else { /* GET_HOSTS_BYNAME */
- while (*alias) {
- if (strcasecmp(name, *(alias++)) == 0)
+ int aliases = 0;
+ char **alias = tok + 1;
+ while (aliases < MAXALIASES) {
+ char *tmp = *(alias+aliases++);
+ if (tmp && strcasecmp(name, tmp) == 0)
goto found;
}
continue;
return ret;
#undef in6
}
-#endif
+#endif /* L_read_etc_hosts_r */
#ifdef L_get_hosts_byname_r
-int attribute_hidden __get_hosts_byname_r(const char *name,
+int __get_hosts_byname_r(const char *name,
int type,
struct hostent *result_buf,
char *buf,
return __read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME,
result_buf, buf, buflen, result, h_errnop);
}
-#endif
+#endif /* L_get_hosts_byname_r */
#ifdef L_get_hosts_byaddr_r
-int attribute_hidden __get_hosts_byaddr_r(const char *addr,
+int __get_hosts_byaddr_r(const char *addr,
int len,
int type,
struct hostent *result_buf,
return __read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR,
result_buf, buf, buflen, result, h_errnop);
}
-#endif
+#endif /* L_get_hosts_byaddr_r */
#ifdef L_getnameinfo
unsigned flags)
{
int serrno = errno;
- unsigned ok;
+ bool ok = 0;
struct hostent *hoste = NULL;
char domain[256];
if (sa == NULL || addrlen < sizeof(sa_family_t))
return EAI_FAMILY;
- ok = sa->sa_family;
- if (ok == AF_LOCAL) /* valid */;
+ if (sa->sa_family == AF_LOCAL) /* valid */;
#ifdef __UCLIBC_HAS_IPV4__
- else if (ok == AF_INET) {
+ else if (sa->sa_family == AF_INET) {
if (addrlen < sizeof(struct sockaddr_in))
return EAI_FAMILY;
}
#endif
#ifdef __UCLIBC_HAS_IPV6__
- else if (ok == AF_INET6) {
+ else if (sa->sa_family == AF_INET6) {
if (addrlen < sizeof(struct sockaddr_in6))
return EAI_FAMILY;
}
else
return EAI_FAMILY;
- ok = 0;
if (host != NULL && hostlen > 0)
switch (sa->sa_family) {
case AF_INET:
if (hoste) {
char *c;
-#undef min
-#define min(x,y) (((x) > (y)) ? (y) : (x))
if ((flags & NI_NOFQDN)
&& (getdomainname(domain, sizeof(domain)) == 0)
&& (c = strstr(hoste->h_name, domain)) != NULL
&& (c != hoste->h_name) && (*(--c) == '.')
) {
strncpy(host, hoste->h_name,
- min(hostlen, (size_t) (c - hoste->h_name)));
- host[min(hostlen - 1, (size_t) (c - hoste->h_name))] = '\0';
+ MIN(hostlen, (size_t) (c - hoste->h_name)));
+ host[MIN(hostlen - 1, (size_t) (c - hoste->h_name))] = '\0';
} else {
strncpy(host, hoste->h_name, hostlen);
}
ok = 1;
-#undef min
}
}
return 0;
}
libc_hidden_def(getnameinfo)
-#endif
+#endif /* L_getnameinfo */
#ifdef L_gethostbyname_r
/* talk to DNS servers */
a.buf = buf;
/* take into account that at least one address will be there,
- * we'll need space of one in_addr + two addr_list[] elems */
+ * we'll need space for one in_addr + two addr_list[] elems */
a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in_addr)));
a.add_count = 0;
packet_len = __dns_lookup(name, T_A, &packet, &a);
}
*h_errnop = HOST_NOT_FOUND;
+ __set_h_errno(HOST_NOT_FOUND);
i = TRY_AGAIN;
free_and_ret:
}
libc_hidden_def(gethostbyname_r)
link_warning(gethostbyname_r, "gethostbyname_r is obsolescent, use getnameinfo() instead.");
-#endif
+#endif /* L_gethostbyname_r */
#ifdef L_gethostbyname2_r
#endif /* __UCLIBC_HAS_IPV6__ */
}
libc_hidden_def(gethostbyname2_r)
-#endif
+#endif /* L_gethostbyname2_r */
#ifdef L_gethostbyaddr_r
}
libc_hidden_def(gethostbyaddr_r)
link_warning(gethostbyaddr_r, "gethostbyaddr_r is obsolescent, use getaddrinfo() instead.");
-#endif
+#endif /* L_gethostbyaddr_r */
#ifdef L_gethostent_r
return ret;
}
libc_hidden_def(gethostent_r)
-#endif
+#endif /* L_gethostent_r */
#ifdef L_gethostent
gethostent_r(&hoste, buf, sizeof(buf), &host, &h_errno);
return host;
}
-#endif
+#endif /* L_gethostent */
#ifdef L_gethostbyname2
#endif
}
libc_hidden_def(gethostbyname2)
-#endif
+#endif /* L_gethostbyname2 */
#ifdef L_gethostbyname
}
libc_hidden_def(gethostbyname)
link_warning(gethostbyname, "gethostbyname is obsolescent, use getnameinfo() instead.");
-#endif
+#endif /* L_gethostbyname */
#ifdef L_gethostbyaddr
}
libc_hidden_def(gethostbyaddr)
link_warning(gethostbyaddr, "gethostbyaddr is obsolescent, use getaddrinfo() instead.");
-#endif
+#endif /* L_gethostbyaddr */
#ifdef L_res_comp
dst[0] = '\0';
return n;
}
+libc_hidden_def(dn_expand)
+
+/*
+ * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
+ * Return the size of the compressed name or -1.
+ * 'length' is the size of the array pointed to by 'comp_dn'.
+ */
+int
+dn_comp(const char *src, u_char *dst, int dstsiz,
+ u_char **dnptrs, u_char **lastdnptr)
+{
+ return ns_name_compress(src, dst, (size_t) dstsiz,
+ (const u_char **) dnptrs,
+ (const u_char **) lastdnptr);
+}
+libc_hidden_def(dn_comp)
#endif /* L_res_comp */
*/
int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
{
- static const char digits[] = "0123456789";
-
const u_char *cp;
char *dn, *eom;
u_char c;
return -1;
}
*dn++ = '\\';
- *dn++ = digits[c / 100];
- *dn++ = digits[(c % 100) / 10];
- *dn++ = digits[c % 10];
+ *dn++ = "0123456789"[c / 100];
+ c = c % 100;
+ *dn++ = "0123456789"[c / 10];
+ *dn++ = "0123456789"[c % 10];
} else {
if (dn >= eom) {
__set_errno(EMSGSIZE);
}
libc_hidden_def(ns_name_ntop)
+static int encode_bitstring(const char **bp, const char *end,
+ unsigned char **labelp,
+ unsigned char ** dst,
+ unsigned const char *eom)
+{
+ int afterslash = 0;
+ const char *cp = *bp;
+ unsigned char *tp;
+ const char *beg_blen;
+ int value = 0, count = 0, tbcount = 0, blen = 0;
+
+ beg_blen = NULL;
+
+ /* a bitstring must contain at least 2 characters */
+ if (end - cp < 2)
+ return EINVAL;
+
+ /* XXX: currently, only hex strings are supported */
+ if (*cp++ != 'x')
+ return EINVAL;
+ if (!isxdigit((unsigned char) *cp)) /*%< reject '\[x/BLEN]' */
+ return EINVAL;
+
+ for (tp = *dst + 1; cp < end && tp < eom; cp++) {
+ unsigned char c = *cp;
+
+ switch (c) {
+ case ']': /*%< end of the bitstring */
+ if (afterslash) {
+ char *end_blen;
+ if (beg_blen == NULL)
+ return EINVAL;
+ blen = (int)strtol(beg_blen, &end_blen, 10);
+ if (*end_blen != ']')
+ return EINVAL;
+ }
+ if (count)
+ *tp++ = ((value << 4) & 0xff);
+ cp++; /*%< skip ']' */
+ goto done;
+ case '/':
+ afterslash = 1;
+ break;
+ default:
+ if (afterslash) {
+ if (!__isdigit_char(c))
+ return EINVAL;
+ if (beg_blen == NULL) {
+ if (c == '0') {
+ /* blen never begings with 0 */
+ return EINVAL;
+ }
+ beg_blen = cp;
+ }
+ } else {
+ if (!__isdigit_char(c)) {
+ c = c | 0x20; /* lowercase */
+ c = c - 'a';
+ if (c > 5) /* not a-f? */
+ return EINVAL;
+ c += 10 + '0';
+ }
+ value <<= 4;
+ value += (c - '0');
+ count += 4;
+ tbcount += 4;
+ if (tbcount > 256)
+ return EINVAL;
+ if (count == 8) {
+ *tp++ = value;
+ count = 0;
+ }
+ }
+ break;
+ }
+ }
+ done:
+ if (cp >= end || tp >= eom)
+ return EMSGSIZE;
+
+ /*
+ * bit length validation:
+ * If a <length> is present, the number of digits in the <bit-data>
+ * MUST be just sufficient to contain the number of bits specified
+ * by the <length>. If there are insignificant bits in a final
+ * hexadecimal or octal digit, they MUST be zero.
+ * RFC2673, Section 3.2.
+ */
+ if (blen > 0) {
+ int traillen;
+
+ if (((blen + 3) & ~3) != tbcount)
+ return EINVAL;
+ traillen = tbcount - blen; /*%< between 0 and 3 */
+ if (((value << (8 - traillen)) & 0xff) != 0)
+ return EINVAL;
+ }
+ else
+ blen = tbcount;
+ if (blen == 256)
+ blen = 0;
+
+ /* encode the type and the significant bit fields */
+ **labelp = DNS_LABELTYPE_BITSTRING;
+ **dst = blen;
+
+ *bp = cp;
+ *dst = tp;
+
+ return 0;
+}
+
+int ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
+{
+ static const char digits[] = "0123456789";
+ u_char *label, *bp, *eom;
+ int c, n, escaped, e = 0;
+ char *cp;
+
+ escaped = 0;
+ bp = dst;
+ eom = dst + dstsiz;
+ label = bp++;
+
+ while ((c = *src++) != 0) {
+ if (escaped) {
+ if (c == '[') { /*%< start a bit string label */
+ cp = strchr(src, ']');
+ if (cp == NULL) {
+ errno = EINVAL; /*%< ??? */
+ return -1;
+ }
+ e = encode_bitstring(&src, cp + 2,
+ &label, &bp, eom);
+ if (e != 0) {
+ errno = e;
+ return -1;
+ }
+ escaped = 0;
+ label = bp++;
+ c = *src++;
+ if (c == '\0')
+ goto done;
+ if (c != '.') {
+ errno = EINVAL;
+ return -1;
+ }
+ continue;
+ }
+ cp = strchr(digits, c);
+ if (cp != NULL) {
+ n = (cp - digits) * 100;
+ c = *src++;
+ if (c == '\0')
+ goto ret_EMSGSIZE;
+ cp = strchr(digits, c);
+ if (cp == NULL)
+ goto ret_EMSGSIZE;
+ n += (cp - digits) * 10;
+ c = *src++;
+ if (c == '\0')
+ goto ret_EMSGSIZE;
+ cp = strchr(digits, c);
+ if (cp == NULL)
+ goto ret_EMSGSIZE;
+ n += (cp - digits);
+ if (n > 255)
+ goto ret_EMSGSIZE;
+ c = n;
+ }
+ escaped = 0;
+ } else if (c == '\\') {
+ escaped = 1;
+ continue;
+ } else if (c == '.') {
+ c = (bp - label - 1);
+ if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
+ goto ret_EMSGSIZE;
+ }
+ if (label >= eom) {
+ goto ret_EMSGSIZE;
+ }
+ *label = c;
+ /* Fully qualified ? */
+ if (*src == '\0') {
+ if (c != 0) {
+ if (bp >= eom) {
+ goto ret_EMSGSIZE;
+ }
+ *bp++ = '\0';
+ }
+ if ((bp - dst) > MAXCDNAME) {
+ goto ret_EMSGSIZE;
+ }
+
+ return 1;
+ }
+ if (c == 0 || *src == '.') {
+ goto ret_EMSGSIZE;
+ }
+ label = bp++;
+ continue;
+ }
+ if (bp >= eom) {
+ goto ret_EMSGSIZE;
+ }
+ *bp++ = (u_char)c;
+ }
+ c = (bp - label - 1);
+ if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
+ goto ret_EMSGSIZE;
+ }
+ done:
+ if (label >= eom) {
+ goto ret_EMSGSIZE;
+ }
+ *label = c;
+ if (c != 0) {
+ if (bp >= eom) {
+ goto ret_EMSGSIZE;
+ }
+ *bp++ = 0;
+ }
+ if ((bp - dst) > MAXCDNAME) { /*%< src too big */
+ goto ret_EMSGSIZE;
+ }
+
+ return 0;
+
+ ret_EMSGSIZE:
+ errno = EMSGSIZE;
+ return -1;
+}
+libc_hidden_def(ns_name_pton)
+
/*
* ns_name_unpack(msg, eom, src, dst, dstsiz)
* Unpack a domain name from a message, source may be compressed.
return len;
}
libc_hidden_def(ns_name_unpack)
+
+static int labellen(const unsigned char *lp)
+{
+ unsigned bitlen;
+ unsigned char l = *lp;
+
+ if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* should be avoided by the caller */
+ return -1;
+ }
+
+ if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
+ if (l == DNS_LABELTYPE_BITSTRING) {
+ bitlen = lp[1];
+ if (bitlen == 0)
+ bitlen = 256;
+ return ((bitlen + 7 ) / 8 + 1);
+ }
+
+ return -1; /*%< unknwon ELT */
+ }
+
+ return l;
+}
+
+static int mklower(int ch)
+{
+ if (ch >= 0x41 && ch <= 0x5A)
+ return (ch + 0x20);
+
+ return ch;
+}
+
+static int dn_find(const unsigned char *domain,
+ const unsigned char *msg,
+ const unsigned char * const *dnptrs,
+ const unsigned char * const *lastdnptr)
+{
+ const unsigned char *dn, *cp, *sp;
+ const unsigned char * const *cpp;
+ u_int n;
+
+ for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
+ sp = *cpp;
+ /*
+ * terminate search on:
+ * root label
+ * compression pointer
+ * unusable offset
+ */
+ while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
+ (sp - msg) < 0x4000) {
+ dn = domain;
+ cp = sp;
+
+ while ((n = *cp++) != 0) {
+ /*
+ * check for indirection
+ */
+ switch (n & NS_CMPRSFLGS) {
+ case 0: /*%< normal case, n == len */
+ n = labellen(cp - 1); /*%< XXX */
+ if (n != *dn++)
+ goto next;
+
+ for (; n > 0; n--)
+ if (mklower(*dn++) !=
+ mklower(*cp++))
+ goto next;
+ /* Is next root for both ? */
+ if (*dn == '\0' && *cp == '\0')
+ return (sp - msg);
+ if (*dn)
+ continue;
+ goto next;
+ case NS_CMPRSFLGS: /*%< indirection */
+ cp = msg + (((n & 0x3f) << 8) | *cp);
+ break;
+
+ default: /*%< illegal type */
+ errno = EMSGSIZE;
+ return -1;
+ }
+ }
+next:
+ sp += *sp + 1;
+ }
+ }
+
+ errno = ENOENT;
+ return -1;
+}
+
+int ns_name_pack(const unsigned char *src,
+ unsigned char *dst, int dstsiz,
+ const unsigned char **dnptrs,
+ const unsigned char **lastdnptr)
+{
+ unsigned char *dstp;
+ const unsigned char **cpp, **lpp, *eob, *msg;
+ const unsigned char *srcp;
+ int n, l, first = 1;
+
+ srcp = src;
+ dstp = dst;
+ eob = dstp + dstsiz;
+ lpp = cpp = NULL;
+
+ if (dnptrs != NULL) {
+ msg = *dnptrs++;
+ if (msg != NULL) {
+ for (cpp = dnptrs; *cpp != NULL; cpp++)
+ continue;
+
+ lpp = cpp; /*%< end of list to search */
+ }
+ } else {
+ msg = NULL;
+ }
+
+ /* make sure the domain we are about to add is legal */
+ l = 0;
+ do {
+ int l0;
+
+ n = *srcp;
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ l0 = labellen(srcp);
+ if (l0 < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ l += l0 + 1;
+ if (l > MAXCDNAME) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ srcp += l0 + 1;
+ } while (n != 0);
+
+ /* from here on we need to reset compression pointer array on error */
+ srcp = src;
+
+ do {
+ /* Look to see if we can use pointers. */
+ n = *srcp;
+
+ if (n != 0 && msg != NULL) {
+ l = dn_find(srcp, msg, (const unsigned char * const *) dnptrs,
+ (const unsigned char * const *) lpp);
+ if (l >= 0) {
+ if (dstp + 1 >= eob) {
+ goto cleanup;
+ }
+
+ *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS;
+ *dstp++ = l % 256;
+ return (dstp - dst);
+ }
+
+ /* Not found, save it. */
+ if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
+ (dstp - msg) < 0x4000 && first) {
+ *cpp++ = dstp;
+ *cpp = NULL;
+ first = 0;
+ }
+ }
+
+ /* copy label to buffer */
+ if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
+ /* Should not happen. */
+ goto cleanup;
+ }
+
+ n = labellen(srcp);
+ if (dstp + 1 + n >= eob) {
+ goto cleanup;
+ }
+
+ memcpy(dstp, srcp, (size_t)(n + 1));
+ srcp += n + 1;
+ dstp += n + 1;
+ } while (n != 0);
+
+ if (dstp > eob) {
+cleanup:
+ if (msg != NULL)
+ *lpp = NULL;
+
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ return dstp - dst;
+}
+libc_hidden_def(ns_name_pack)
+
+int ns_name_compress(const char *src,
+ unsigned char *dst, size_t dstsiz,
+ const unsigned char **dnptrs,
+ const unsigned char **lastdnptr)
+{
+ unsigned char tmp[NS_MAXCDNAME];
+
+ if (ns_name_pton(src, tmp, sizeof(tmp)) == -1)
+ return -1;
+
+ return ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr);
+}
+libc_hidden_def(ns_name_compress)
+
+int ns_name_skip(const unsigned char **ptrptr,
+ const unsigned char *eom)
+{
+ const unsigned char *cp;
+ u_int n;
+ int l;
+
+ cp = *ptrptr;
+ while (cp < eom && (n = *cp++) != 0) {
+ /* Check for indirection. */
+ switch (n & NS_CMPRSFLGS) {
+ case 0: /*%< normal case, n == len */
+ cp += n;
+ continue;
+ case NS_TYPE_ELT: /*%< EDNS0 extended label */
+ l = labellen(cp - 1);
+ if (l < 0) {
+ errno = EMSGSIZE; /*%< XXX */
+ return -1;
+ }
+ cp += l;
+ continue;
+ case NS_CMPRSFLGS: /*%< indirection */
+ cp++;
+ break;
+ default: /*%< illegal type */
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ break;
+ }
+
+ if (cp > eom) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ *ptrptr = cp;
+
+ return 0;
+}
+libc_hidden_def(ns_name_skip)
+
+int dn_skipname(const unsigned char *ptr, const unsigned char *eom)
+{
+ const unsigned char *saveptr = ptr;
+
+ if (ns_name_skip(&ptr, eom) == -1)
+ return -1;
+
+ return ptr - saveptr;
+}
+libc_hidden_def(dn_skipname)
#endif /* L_ns_name */
*/
}
-/* Our res_init never fails (always returns 0) */
-int res_init(void)
+/* has to be called under __resolv_lock */
+static int
+__res_vinit(res_state rp, int preinit)
{
- struct __res_state *rp = &(_res);
- int i;
- int n;
+ int i, n, options, retrans, retry, ndots;
#ifdef __UCLIBC_HAS_IPV6__
int m = 0;
#endif
- __UCLIBC_MUTEX_LOCK(__resolv_lock);
__close_nameservers();
__open_nameservers();
- __res_sync = res_sync_func;
+ if (preinit) {
+ options = rp->options;
+ retrans = rp->retrans;
+ retry = rp->retry;
+ ndots = rp->ndots;
+ }
memset(rp, 0, sizeof(*rp));
- rp->options = RES_INIT;
- rp->retrans = RES_TIMEOUT;
- rp->retry = RES_DFLRETRY;
- rp->ndots = 1;
+
+ if (!preinit) {
+ rp->options = RES_DEFAULT;
+ rp->retrans = RES_TIMEOUT;
+ rp->retry = RES_DFLRETRY;
+ rp->ndots = 1;
+ } else {
+ rp->options = options;
+ rp->retrans = retrans;
+ rp->retry = retry;
+ rp->ndots = ndots;
+ }
+
#ifdef __UCLIBC_HAS_COMPAT_RES_STATE__
/* Was: "rp->id = random();" but:
* - random() pulls in largish static buffers
if (__nameserver[i].sa.sa_family == AF_INET6
&& m < ARRAY_SIZE(rp->_u._ext.nsaddrs)
) {
- struct sockaddr_in6 *sa6 = malloc(sizeof(sa6));
+ struct sockaddr_in6 *sa6 = malloc(sizeof(*sa6));
if (sa6) {
*sa6 = __nameserver[i].sa6; /* struct copy */
rp->_u._ext.nsaddrs[m] = sa6;
#else /* IPv6 only */
while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs) && i < __nameservers) {
- struct sockaddr_in6 *sa6 = malloc(sizeof(sa6));
+ struct sockaddr_in6 *sa6 = malloc(sizeof(*sa6));
if (sa6) {
*sa6 = __nameserver[i].sa6; /* struct copy */
rp->_u._ext.nsaddrs[m] = sa6;
rp->_u._ext.nscount = m;
#endif
+ rp->options |= RES_INIT;
+
+ return 0;
+}
+
+static unsigned int
+res_randomid(void)
+{
+ return 0xffff & getpid();
+}
+
+/* Our res_init never fails (always returns 0) */
+int
+res_init(void)
+{
+ /*
+ * These three fields used to be statically initialized. This made
+ * it hard to use this code in a shared library. It is necessary,
+ * now that we're doing dynamic initialization here, that we preserve
+ * the old semantics: if an application modifies one of these three
+ * fields of _res before res_init() is called, res_init() will not
+ * alter them. Of course, if an application is setting them to
+ * _zero_ before calling res_init(), hoping to override what used
+ * to be the static default, we can't detect it and unexpected results
+ * will follow. Zero for any of these fields would make no sense,
+ * so one can safely assume that the applications were already getting
+ * unexpected results.
+ *
+ * _res.options is tricky since some apps were known to diddle the bits
+ * before res_init() was first called. We can't replicate that semantic
+ * with dynamic initialization (they may have turned bits off that are
+ * set in RES_DEFAULT). Our solution is to declare such applications
+ * "broken". They could fool us by setting RES_INIT but none do (yet).
+ */
+
+ __UCLIBC_MUTEX_LOCK(__resolv_lock);
+
+ if (!_res.retrans)
+ _res.retrans = RES_TIMEOUT;
+ if (!_res.retry)
+ _res.retry = 4;
+ if (!(_res.options & RES_INIT))
+ _res.options = RES_DEFAULT;
+
+ /*
+ * This one used to initialize implicitly to zero, so unless the app
+ * has set it to something in particular, we can randomize it now.
+ */
+ if (!_res.id)
+ _res.id = res_randomid();
+
+ __res_sync = NULL;
+ __res_vinit(&_res, 1);
+ __res_sync = res_sync_func;
+
__UCLIBC_MUTEX_UNLOCK(__resolv_lock);
+
return 0;
}
libc_hidden_def(res_init)
-#ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
-void res_close(void)
+static void
+__res_iclose(res_state statp)
{
+ struct __res_state * rp = statp;
__UCLIBC_MUTEX_LOCK(__resolv_lock);
+ if (rp == NULL)
+ rp = __res_state();
__close_nameservers();
__res_sync = NULL;
#ifdef __UCLIBC_HAS_IPV6__
{
- char *p1 = (char*) &(_res.nsaddr_list[0]);
- int m = 0;
+ char *p1 = (char*) &(rp->nsaddr_list[0]);
+ unsigned int m = 0;
/* free nsaddrs[m] if they do not point to nsaddr_list[x] */
- while (m < ARRAY_SIZE(_res._u._ext.nsaddrs)) {
- char *p2 = (char*)(_res._u._ext.nsaddrs[m]);
- if (p2 < p1 || (p2 - p1) > sizeof(_res.nsaddr_list))
+ while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs)) {
+ char *p2 = (char*)(rp->_u._ext.nsaddrs[m++]);
+ if (p2 < p1 || (p2 - p1) > (signed)sizeof(rp->nsaddr_list))
free(p2);
}
}
#endif
- memset(&_res, 0, sizeof(_res));
+ memset(rp, 0, sizeof(struct __res_state));
__UCLIBC_MUTEX_UNLOCK(__resolv_lock);
}
+
+/*
+ * This routine is for closing the socket if a virtual circuit is used and
+ * the program wants to close it. This provides support for endhostent()
+ * which expects to close the socket.
+ *
+ * This routine is not expected to be user visible.
+ */
+
+void
+res_nclose(res_state statp)
+{
+ __res_iclose(statp);
+}
+
+#ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
+void res_close(void)
+{
+ __res_iclose(NULL);
+}
#endif
/* This needs to be after the use of _res in res_init, above. */
# if defined __UCLIBC_HAS_TLS__
# undef __resp
__thread struct __res_state *__resp = &_res;
-/*
- * FIXME: Add usage of hidden attribute for this when used in the shared
- * library. It currently crashes the linker when doing section
- * relocations.
- */
extern __thread struct __res_state *__libc_resp
- __attribute__ ((alias ("__resp"))) attribute_hidden;
+ __attribute__ ((alias ("__resp"))) attribute_hidden attribute_tls_model_ie;
# else
# undef __resp
struct __res_state *__resp = &_res;
# endif
-#endif
+#endif /* !__UCLIBC_HAS_THREADS__ */
+
+/*
+ * Set up default settings. If the configuration file exist, the values
+ * there will have precedence. Otherwise, the server address is set to
+ * INADDR_ANY and the default domain name comes from the gethostname().
+ *
+ * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
+ * rather than INADDR_ANY ("0.0.0.0") as the default name server address
+ * since it was noted that INADDR_ANY actually meant ``the first interface
+ * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
+ * it had to be "up" in order for you to reach your own name server. It
+ * was later decided that since the recommended practice is to always
+ * install local static routes through 127.0.0.1 for all your network
+ * interfaces, that we could solve this problem without a code change.
+ *
+ * The configuration file should always be used, since it is the only way
+ * to specify a default domain. If you are running a server on your local
+ * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
+ * in the configuration file.
+ *
+ * Return 0 if completes successfully, -1 on error
+ */
+int
+res_ninit(res_state statp)
+{
+ int ret;
+ __UCLIBC_MUTEX_LOCK(__resolv_lock);
+ ret = __res_vinit(statp, 0);
+ __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
+ return ret;
+}
#endif /* L_res_init */
}
# endif
-#endif
+#endif /* L_res_state */
#ifdef L_res_query
free(a.dotted);
- if (a.atype == type) { /* CNAME */
- if (i > anslen)
- i = anslen;
- memcpy(answer, packet, i);
- }
+ if (i > anslen)
+ i = anslen;
+ memcpy(answer, packet, i);
+
free(packet);
return i;
}
return res_query(longname, class, type, answer, anslen);
}
libc_hidden_def(res_querydomain)
+#endif /* L_res_query */
+
+#ifdef L_ns_netint
+unsigned int ns_get16(const unsigned char *src)
+{
+ unsigned int dst;
+ NS_GET16(dst, src);
+ return dst;
+}
+
+unsigned long ns_get32(const unsigned char *src)
+{
+ unsigned long dst;
+ NS_GET32(dst, src);
+ return dst;
+}
+
+void ns_put16(unsigned int src, unsigned char *dst)
+{
+ NS_PUT16(src, dst);
+}
+
+void ns_put32(unsigned long src, unsigned char *dst)
+{
+ NS_PUT32(src, dst);
+}
+#endif /* L_ns_netint */
+
+#ifdef L_ns_parse
+/* These need to be in the same order as the nres.h:ns_flag enum. */
+struct _ns_flagdata { unsigned short mask, shift; };
+static const struct _ns_flagdata _ns_flagdata[16] = {
+ { 0x8000, 15 }, /*%< qr. */
+ { 0x7800, 11 }, /*%< opcode. */
+ { 0x0400, 10 }, /*%< aa. */
+ { 0x0200, 9 }, /*%< tc. */
+ { 0x0100, 8 }, /*%< rd. */
+ { 0x0080, 7 }, /*%< ra. */
+ { 0x0040, 6 }, /*%< z. */
+ { 0x0020, 5 }, /*%< ad. */
+ { 0x0010, 4 }, /*%< cd. */
+ { 0x000f, 0 }, /*%< rcode. */
+ { 0x0000, 0 }, /*%< expansion (1/6). */
+ { 0x0000, 0 }, /*%< expansion (2/6). */
+ { 0x0000, 0 }, /*%< expansion (3/6). */
+ { 0x0000, 0 }, /*%< expansion (4/6). */
+ { 0x0000, 0 }, /*%< expansion (5/6). */
+ { 0x0000, 0 }, /*%< expansion (6/6). */
+};
+
+static void setsection(ns_msg *msg, ns_sect sect)
+{
+ msg->_sect = sect;
+ if (sect == ns_s_max) {
+ msg->_rrnum = -1;
+ msg->_ptr = NULL;
+ } else {
+ msg->_rrnum = 0;
+ msg->_ptr = msg->_sections[(int)sect];
+ }
+}
+
+int ns_skiprr(const unsigned char *ptr,
+ const unsigned char *eom,
+ ns_sect section, int count)
+{
+ const u_char *optr = ptr;
+
+ for (; count > 0; count--) {
+ int b, rdlength;
+
+ b = dn_skipname(ptr, eom);
+ if (b < 0) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
+ if (section != ns_s_qd) {
+ if (ptr + NS_INT32SZ + NS_INT16SZ > eom) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ ptr += NS_INT32SZ/*TTL*/;
+ NS_GET16(rdlength, ptr);
+ ptr += rdlength/*RData*/;
+ }
+ }
+
+ if (ptr > eom) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ return ptr - optr;
+}
+libc_hidden_def(ns_skiprr)
+
+int
+ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle)
+{
+ const u_char *eom = msg + msglen;
+ int i;
+
+ handle->_msg = msg;
+ handle->_eom = eom;
+ if (msg + NS_INT16SZ > eom) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ NS_GET16(handle->_id, msg);
+ if (msg + NS_INT16SZ > eom) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ NS_GET16(handle->_flags, msg);
+ for (i = 0; i < ns_s_max; i++) {
+ if (msg + NS_INT16SZ > eom) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ NS_GET16(handle->_counts[i], msg);
+ }
+ for (i = 0; i < ns_s_max; i++)
+ if (handle->_counts[i] == 0)
+ handle->_sections[i] = NULL;
+ else {
+ int b = ns_skiprr(msg, eom, (ns_sect)i,
+ handle->_counts[i]);
+
+ if (b < 0)
+ return -1;
+ handle->_sections[i] = msg;
+ msg += b;
+ }
+
+ if (msg != eom) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ setsection(handle, ns_s_max);
+ return 0;
+}
+
+int
+ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr)
+{
+ int b;
+ int tmp;
+
+ /* Make section right. */
+ tmp = section;
+ if (tmp < 0 || section >= ns_s_max) {
+ errno = ENODEV;
+ return -1;
+ }
+
+ if (section != handle->_sect)
+ setsection(handle, section);
+
+ /* Make rrnum right. */
+ if (rrnum == -1)
+ rrnum = handle->_rrnum;
+ if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) {
+ errno = ENODEV;
+ return -1;
+ }
+ if (rrnum < handle->_rrnum)
+ setsection(handle, section);
+ if (rrnum > handle->_rrnum) {
+ b = ns_skiprr(handle->_ptr, handle->_eom, section,
+ rrnum - handle->_rrnum);
+
+ if (b < 0)
+ return -1;
+ handle->_ptr += b;
+ handle->_rrnum = rrnum;
+ }
+
+ /* Do the parse. */
+ b = dn_expand(handle->_msg, handle->_eom,
+ handle->_ptr, rr->name, NS_MAXDNAME);
+ if (b < 0)
+ return -1;
+ handle->_ptr += b;
+ if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+ NS_GET16(rr->type, handle->_ptr);
+ NS_GET16(rr->rr_class, handle->_ptr);
+ if (section == ns_s_qd) {
+ rr->ttl = 0;
+ rr->rdlength = 0;
+ rr->rdata = NULL;
+ } else {
+ if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+ NS_GET32(rr->ttl, handle->_ptr);
+ NS_GET16(rr->rdlength, handle->_ptr);
+ if (handle->_ptr + rr->rdlength > handle->_eom) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+ rr->rdata = handle->_ptr;
+ handle->_ptr += rr->rdlength;
+ }
+ if (++handle->_rrnum > handle->_counts[(int)section])
+ setsection(handle, (ns_sect)((int)section + 1));
+
+ return 0;
+}
+
+int ns_msg_getflag(ns_msg handle, int flag)
+{
+ return ((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift;
+}
+#endif /* L_ns_parse */
+
+#ifdef L_res_data
+int res_mkquery(int op, const char *dname, int class, int type,
+ const unsigned char *data, int datalen,
+ const unsigned char *newrr_in,
+ unsigned char *buf, int buflen)
+{
+ HEADER *hp;
+ unsigned char *cp, *ep;
+ unsigned char *dnptrs[20], **dpp, **lastdnptr;
+ uint32_t _res_options;
+ int n;
+
+ if (!buf || buflen < HFIXEDSZ) {
+ h_errno = NETDB_INTERNAL;
+ return -1;
+ }
+
+ again:
+ __UCLIBC_MUTEX_LOCK(__resolv_lock);
+ _res_options = _res.options;
+ __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
+ if (!(_res_options & RES_INIT)) {
+ res_init(); /* our res_init never fails */
+ goto again;
+ }
+
+#ifdef DEBUG
+ if (_res_options & RES_DEBUG)
+ printf(";; res_mkquery(%d, %s, %d, %d)\n",
+ op, dname && *dname ? dname : "<null>", class, type);
#endif
+ memset(buf, 0, HFIXEDSZ);
+ hp = (HEADER *) buf;
+ hp->id = getpid() & 0xffff;
+ hp->opcode = op;
+ hp->rd = (_res_options & RES_RECURSE) != 0U;
+ hp->rcode = NOERROR;
+
+ cp = buf + HFIXEDSZ;
+ ep = buf + buflen;
+ dpp = dnptrs;
+ *dpp++ = buf;
+ *dpp++ = NULL;
+ lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+
+ /*
+ * perform opcode specific processing
+ */
+ switch (op) {
+ case QUERY:
+ case NS_NOTIFY_OP:
+ if (ep - cp < QFIXEDSZ)
+ return -1;
+
+ n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
+ if (n < 0)
+ return -1;
+
+ cp += n;
+ NS_PUT16(type, cp);
+ NS_PUT16(class, cp);
+ hp->qdcount = htons(1);
+
+ if (op == QUERY || data == NULL)
+ break;
+
+ /*
+ * Make an additional record for completion domain.
+ */
+ if ((ep - cp) < RRFIXEDSZ)
+ return -1;
+
+ n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ,
+ dnptrs, lastdnptr);
+ if (n < 0)
+ return -1;
+
+ cp += n;
+ NS_PUT16(T_NULL, cp);
+ NS_PUT16(class, cp);
+ NS_PUT32(0, cp);
+ NS_PUT16(0, cp);
+ hp->arcount = htons(1);
+
+ break;
+
+ case IQUERY:
+ /*
+ * Initialize answer section
+ */
+ if (ep - cp < 1 + RRFIXEDSZ + datalen)
+ return -1;
+
+ *cp++ = '\0'; /*%< no domain name */
+ NS_PUT16(type, cp);
+ NS_PUT16(class, cp);
+ NS_PUT32(0, cp);
+ NS_PUT16(datalen, cp);
+
+ if (datalen) {
+ memcpy(cp, data, (size_t)datalen);
+ cp += datalen;
+ }
+
+ hp->ancount = htons(1);
+ break;
+
+ default:
+ return -1;
+ }
+
+ return cp - buf;
+}
+#endif /* L_res_data */
+
/* Unimplemented: */
-/* res_mkquery */
/* res_send */
-/* dn_comp */