diff -rupN uClibc-0.9.32-ori/extra/Configs/Config.in uClibc-0.9.32/extra/Configs/Config.in --- uClibc-0.9.32-ori/extra/Configs/Config.in 2011-06-08 12:35:20.000000000 -0700 +++ uClibc-0.9.32/extra/Configs/Config.in 2012-11-14 00:13:00.485546754 -0800 @@ -1268,6 +1268,16 @@ config UCLIBC_HAS_EXTRA_COMPAT_RES_STATE Answer Y if selecting UCLIBC_HAS_COMPAT_RES_STATE is not enough. As far as I can say, this should never be needed. +config UCLIBC_HAS_RESOLVER_SUPPORT + bool "DNS resolver functions" + select UCLIBC_HAS_COMPAT_RES_STATE + help + Provide implementations for DNS resolver functions. + In particular, the following functions will be added to the + library: + + ns_get16, ns_get32, ns_put16, ns_put32 + config UCLIBC_HAS_LIBRESOLV_STUB bool "Provide libresolv stub" default n diff -rupN uClibc-0.9.32-ori/include/arpa/nameser.h uClibc-0.9.32/include/arpa/nameser.h --- uClibc-0.9.32-ori/include/arpa/nameser.h 2011-06-08 12:35:20.000000000 -0700 +++ uClibc-0.9.32/include/arpa/nameser.h 2012-11-14 00:13:23.481545598 -0800 @@ -120,13 +120,9 @@ typedef struct __ns_msg { /* Private data structure - do not use from outside library. */ struct _ns_flagdata { int mask, shift; }; -extern struct _ns_flagdata _ns_flagdata[]; +extern const struct _ns_flagdata _ns_flagdata[]; /* Accessor macros - this is part of the public interface. */ -#define ns_msg_getflag(handle, flag) ( \ - ((handle)._flags & _ns_flagdata[flag].mask) \ - >> _ns_flagdata[flag].shift \ - ) #define ns_msg_id(handle) ((handle)._id + 0) #define ns_msg_base(handle) ((handle)._msg + 0) #define ns_msg_end(handle) ((handle)._eom + 0) @@ -499,6 +495,7 @@ typedef enum __ns_cert_types { #define ns_samename __ns_samename __BEGIN_DECLS +int ns_msg_getflag (ns_msg, int) __THROW; u_int ns_get16 (const u_char *) __THROW; u_long ns_get32 (const u_char *) __THROW; void ns_put16 (u_int, u_char *) __THROW; @@ -521,6 +518,7 @@ int ns_name_ntol (const u_char *, u_cha int ns_name_ntop (const u_char *, char *, size_t) __THROW; libc_hidden_proto(ns_name_ntop) int ns_name_pton (const char *, u_char *, size_t) __THROW; +libc_hidden_proto(ns_name_pton) int ns_name_unpack (const u_char *, const u_char *, const u_char *, u_char *, size_t) __THROW; libc_hidden_proto(ns_name_unpack) diff -rupN uClibc-0.9.32-ori/include/resolv.h uClibc-0.9.32/include/resolv.h --- uClibc-0.9.32-ori/include/resolv.h 2011-06-08 12:35:20.000000000 -0700 +++ uClibc-0.9.32/include/resolv.h 2012-11-14 00:13:36.605544938 -0800 @@ -138,7 +138,6 @@ struct __res_state { } sort_list[MAXRESOLVSORT]; #endif -#ifdef __UCLIBC_HAS_IPV6__ /* I assume that the intention is to store all * DNS servers' addresses here, and duplicate in nsaddr_list[] * those which have IPv4 address. In the case of IPv4 address @@ -152,7 +151,9 @@ struct __res_state { */ union { struct { +#ifdef __UCLIBC_HAS_IPV6__ struct sockaddr_in6 *nsaddrs[MAXNS]; +#endif u_int8_t nscount; /* (was: u_int16_t) */ #ifdef __UCLIBC_HAS_COMPAT_RES_STATE__ /* rather obscure, and differs in BSD and glibc */ @@ -166,7 +167,6 @@ struct __res_state { #endif } _ext; } _u; -#endif #ifdef __UCLIBC_HAS_EXTRA_COMPAT_RES_STATE__ /* Truly obscure stuff. @@ -292,8 +292,8 @@ __END_DECLS #define res_init __res_init #if 0 #define res_isourserver __res_isourserver -#define res_mkquery __res_mkquery #endif +#define res_mkquery __res_mkquery #define res_query __res_query #define res_querydomain __res_querydomain #define res_search __res_search @@ -315,9 +315,9 @@ int res_init (void) __THROW; libc_hidden_proto(res_init) #if 0 int res_isourserver (const struct sockaddr_in *) __THROW; +#endif int res_mkquery (int, const char *, int, int, const u_char *, int, const u_char *, u_char *, int) __THROW; -#endif int res_query (const char *, int, int, u_char *, int) __THROW; libc_hidden_proto(res_query) int res_querydomain (const char *, const char *, int, int, @@ -332,12 +332,14 @@ __END_DECLS #if 0 #define b64_ntop __b64_ntop #define b64_pton __b64_pton -#define dn_comp __dn_comp #define dn_count_labels __dn_count_labels #endif +#define dn_comp __dn_comp #define dn_expand __dn_expand -#if 0 #define dn_skipname __dn_skipname +#define res_ninit __res_ninit +#define res_nclose __res_nclose +#if 0 #define fp_resstat __fp_resstat #define loc_aton __loc_aton #define loc_ntoa __loc_ntoa @@ -359,8 +361,6 @@ __END_DECLS #define res_hostalias __res_hostalias #define res_mailok __res_mailok #define res_nameinquery __res_nameinquery -#define res_nclose __res_nclose -#define res_ninit __res_ninit #define res_nmkquery __res_nmkquery #define res_npquery __res_npquery #define res_nquery __res_nquery @@ -388,7 +388,6 @@ int b64_ntop (u_char const *, size_t, c int b64_pton (char const *, u_char *, size_t) __THROW; int loc_aton (const char *ascii, u_char *binary) __THROW; const char * loc_ntoa (const u_char *binary, char *ascii) __THROW; -int dn_skipname (const u_char *, const u_char *) __THROW; void putlong (u_int32_t, u_char *) __THROW; void putshort (u_int16_t, u_char *) __THROW; const char * p_class (int) __THROW; @@ -404,11 +403,14 @@ const u_char * p_fqname (const u_char *, const char * p_option (u_long option) __THROW; char * p_secstodate (u_long) __THROW; int dn_count_labels (const char *) __THROW; +#endif +int dn_skipname (const u_char *, const u_char *) __THROW; int dn_comp (const char *, u_char *, int, u_char **, u_char **) __THROW; -#endif int dn_expand (const u_char *, const u_char *, const u_char *, char *, int) __THROW; +int res_ninit (res_state) __THROW; +void res_nclose (res_state) __THROW; #if 0 u_int res_randomid (void) __THROW; int res_nameinquery (const char *, int, int, @@ -417,7 +419,6 @@ int res_queriesmatch (const u_char *, c const u_char *, const u_char *) __THROW; const char * p_section (int section, int opcode) __THROW; /* Things involving a resolver context. */ -int res_ninit (res_state) __THROW; int res_nisourserver (const res_state, const struct sockaddr_in *) __THROW; void fp_resstat (const res_state, FILE *) __THROW; @@ -436,7 +437,6 @@ int res_nmkquery (res_state, int, const int) __THROW; int res_nsend (res_state, const u_char *, int, u_char *, int) __THROW; -void res_nclose (res_state) __THROW; #endif __END_DECLS diff -rupN uClibc-0.9.32-ori/libc/inet/Makefile.in uClibc-0.9.32/libc/inet/Makefile.in --- uClibc-0.9.32-ori/libc/inet/Makefile.in 2011-06-08 12:35:20.000000000 -0700 +++ uClibc-0.9.32/libc/inet/Makefile.in 2012-11-14 00:13:40.317544752 -0800 @@ -37,7 +37,8 @@ CSRC-$(findstring y,$(UCLIBC_HAS_IPV4)$( get_hosts_byaddr_r.c get_hosts_byname_r.c \ gethostbyaddr_r.c gethostbyname_r.c gethostbyname2_r.c \ gethostbyaddr.c gethostbyname.c gethostbyname2.c -CSRC-$(findstring y,$(UCLIBC_HAS_IPV4)$(UCLIBC_HAS_IPV6)) += \ +CSRC-$(findstring y,$(UCLIBC_HAS_RESOLVER_SUPPORT)) += \ + ns_netint.c ns_parse.c res_data.c \ res_init.c res_query.c res_comp.c ns_name.c \ _res_state.c ## # unused ATM diff -rupN uClibc-0.9.32-ori/libc/inet/ns_netint.c uClibc-0.9.32/libc/inet/ns_netint.c --- uClibc-0.9.32-ori/libc/inet/ns_netint.c 1969-12-31 16:00:00.000000000 -0800 +++ uClibc-0.9.32/libc/inet/ns_netint.c 2012-11-14 00:13:00.485546754 -0800 @@ -0,0 +1,8 @@ +/* + * Copyright (C) 2000-2006 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#define L_ns_netint +#include RESOLVER diff -rupN uClibc-0.9.32-ori/libc/inet/ns_parse.c uClibc-0.9.32/libc/inet/ns_parse.c --- uClibc-0.9.32-ori/libc/inet/ns_parse.c 1969-12-31 16:00:00.000000000 -0800 +++ uClibc-0.9.32/libc/inet/ns_parse.c 2012-11-14 00:13:23.485545598 -0800 @@ -0,0 +1,8 @@ +/* + * Copyright (C) 2000-2006 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#define L_ns_parse +#include RESOLVER diff -rupN uClibc-0.9.32-ori/libc/inet/res_data.c uClibc-0.9.32/libc/inet/res_data.c --- uClibc-0.9.32-ori/libc/inet/res_data.c 1969-12-31 16:00:00.000000000 -0800 +++ uClibc-0.9.32/libc/inet/res_data.c 2012-11-14 00:13:27.849545379 -0800 @@ -0,0 +1,8 @@ +/* + * Copyright (C) 2000-2006 Erik Andersen + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#define L_res_data +#include RESOLVER diff -rupN uClibc-0.9.32-ori/libc/inet/resolv.c uClibc-0.9.32/libc/inet/resolv.c --- uClibc-0.9.32-ori/libc/inet/resolv.c 2011-06-08 12:35:20.000000000 -0700 +++ uClibc-0.9.32/libc/inet/resolv.c 2012-11-14 00:13:32.697545135 -0800 @@ -297,6 +297,7 @@ Domain name in a message can be represen #include #include #include +#include #include #include #include @@ -339,6 +340,9 @@ Domain name in a message can be represen #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 */ @@ -590,7 +594,7 @@ int attribute_hidden __encode_header(str return HFIXEDSZ; } -#endif +#endif /* L_encodeh */ #ifdef L_decodeh @@ -611,7 +615,7 @@ void attribute_hidden __decode_header(un h->nscount = (data[8] << 8) | data[9]; h->arcount = (data[10] << 8) | data[11]; } -#endif +#endif /* L_decodeh */ #ifdef L_encoded @@ -650,7 +654,7 @@ int attribute_hidden __encode_dotted(con return used; } -#endif +#endif /* L_encoded */ #ifdef L_decoded @@ -717,7 +721,7 @@ int attribute_hidden __decode_dotted(con return total; } -#endif +#endif /* L_decoded */ #ifdef L_encodeq @@ -745,7 +749,7 @@ int attribute_hidden __encode_question(c return i + 4; } -#endif +#endif /* L_encodeq */ #ifdef L_encodea @@ -778,7 +782,7 @@ int attribute_hidden __encode_answer(str return i + RRFIXEDSZ + a->rdlength; } -#endif +#endif /* L_encodea */ #ifdef CURRENTLY_UNUSED @@ -844,7 +848,7 @@ int __encode_packet(struct resolv_header return total; } -#endif +#endif /* L_encodep */ #ifdef L_decodep @@ -855,7 +859,7 @@ int __decode_packet(unsigned char *data, __decode_header(data, h); return HFIXEDSZ; } -#endif +#endif /* L_decodep */ #ifdef L_formquery @@ -893,7 +897,7 @@ int __form_query(int id, return i + j; } -#endif +#endif /* L_formquery */ #endif /* CURRENTLY_UNUSED */ @@ -1116,7 +1120,7 @@ void attribute_hidden __open_nameservers if (__res_sync) __res_sync(); } -#endif +#endif /* L_opennameservers */ #ifdef L_closenameservers @@ -1134,7 +1138,7 @@ void attribute_hidden __close_nameserver __searchdomain = NULL; /*__searchdomains = 0; - already is */ } -#endif +#endif /* L_closenameservers */ #ifdef L_dnslookup @@ -1400,7 +1404,7 @@ int attribute_hidden __dns_lookup(const goto try_next_server; } reply_timeout--; -#else +#else /* !USE_SELECT */ reply_timeout = __resolv_timeout * 1000; wait_again: fds.fd = fd; @@ -1413,7 +1417,7 @@ int attribute_hidden __dns_lookup(const } /*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 @@ -1571,7 +1575,7 @@ int attribute_hidden __dns_lookup(const free(packet); return -1; } -#endif +#endif /* L_dnslookup */ #ifdef L_read_etc_hosts_r @@ -1700,7 +1704,7 @@ found: return ret; #undef in6 } -#endif +#endif /* L_read_etc_hosts_r */ #ifdef L_get_hosts_byname_r @@ -1716,7 +1720,7 @@ int attribute_hidden __get_hosts_byname_ 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 @@ -1758,7 +1762,7 @@ int attribute_hidden __get_hosts_byaddr_ 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 @@ -1961,7 +1965,7 @@ DONE: return 0; } libc_hidden_def(getnameinfo) -#endif +#endif /* L_getnameinfo */ #ifdef L_gethostbyname_r @@ -2175,7 +2179,7 @@ int gethostbyname_r(const char *name, } 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 @@ -2332,7 +2336,7 @@ int gethostbyname2_r(const char *name, #endif /* __UCLIBC_HAS_IPV6__ */ } libc_hidden_def(gethostbyname2_r) -#endif +#endif /* L_gethostbyname2_r */ #ifdef L_gethostbyaddr_r @@ -2493,7 +2497,7 @@ int gethostbyaddr_r(const void *addr, so } 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 @@ -2550,7 +2554,7 @@ DONE: return ret; } libc_hidden_def(gethostent_r) -#endif +#endif /* L_gethostent_r */ #ifdef L_gethostent @@ -2570,7 +2574,7 @@ struct hostent *gethostent(void) gethostent_r(&hoste, buf, sizeof(buf), &host, &h_errno); return host; } -#endif +#endif /* L_gethostent */ #ifdef L_gethostbyname2 @@ -2591,7 +2595,7 @@ struct hostent *gethostbyname2(const cha #endif } libc_hidden_def(gethostbyname2) -#endif +#endif /* L_gethostbyname2 */ #ifdef L_gethostbyname @@ -2613,7 +2617,7 @@ struct hostent *gethostbyname(const char } libc_hidden_def(gethostbyname) link_warning(gethostbyname, "gethostbyname is obsolescent, use getnameinfo() instead."); -#endif +#endif /* L_gethostbyname */ #ifdef L_gethostbyaddr @@ -2635,7 +2639,7 @@ struct hostent *gethostbyaddr(const void } libc_hidden_def(gethostbyaddr) link_warning(gethostbyaddr, "gethostbyaddr is obsolescent, use getaddrinfo() instead."); -#endif +#endif /* L_gethostbyaddr */ #ifdef L_res_comp @@ -2656,6 +2660,20 @@ int dn_expand(const u_char *msg, const u dst[0] = '\0'; return n; } + +/* + * 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); +} #endif /* L_res_comp */ @@ -2792,6 +2810,259 @@ int ns_name_ntop(const u_char *src, char } libc_hidden_def(ns_name_ntop) +static const char digits[] = "0123456789"; + +static const char digitvalue[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/ +}; + +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; + char c; + const char *beg_blen; + char *end_blen = NULL; + int value = 0, count = 0, tbcount = 0, blen = 0; + + beg_blen = end_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((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */ + return (EINVAL); + + for (tp = *dst + 1; cp < end && tp < eom; cp++) { + switch((c = *cp)) { + case ']': /*%< end of the bitstring */ + if (afterslash) { + 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(c&0xff)) + return (EINVAL); + if (beg_blen == NULL) { + + if (c == '0') { + /* blen never begings with 0 */ + return (EINVAL); + } + beg_blen = cp; + } + } else { + if (!isxdigit(c&0xff)) + return (EINVAL); + value <<= 4; + value += digitvalue[(int)c]; + 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 is present, the number of digits in the + * MUST be just sufficient to contain the number of bits specified + * by the . 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) +{ + 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 */ + if ((cp = strchr(src, ']')) == NULL) { + errno = EINVAL; /*%< ??? */ + return (-1); + } + if ((e = encode_bitstring(&src, cp + 2, + &label, &bp, eom)) + != 0) { + errno = e; + return (-1); + } + escaped = 0; + label = bp++; + if ((c = *src++) == 0) + goto done; + else if (c != '.') { + errno = EINVAL; + return (-1); + } + continue; + } + else if ((cp = strchr(digits, c)) != NULL) { + n = (cp - digits) * 100; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (cp - digits) * 10; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (cp - digits); + if (n > 255) { + errno = EMSGSIZE; + return (-1); + } + 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. */ + errno = EMSGSIZE; + return (-1); + } + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + /* Fully qualified ? */ + if (*src == '\0') { + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = '\0'; + } + if ((bp - dst) > MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + + return (1); + } + if (c == 0 || *src == '.') { + errno = EMSGSIZE; + return (-1); + } + label = bp++; + continue; + } + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = (u_char)c; + } + c = (bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */ + errno = EMSGSIZE; + return (-1); + } + done: + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = 0; + } + if ((bp - dst) > MAXCDNAME) { /*%< src too big */ + errno = EMSGSIZE; + return (-1); + } + + return (0); +} +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. @@ -2866,6 +3137,270 @@ int ns_name_unpack(const u_char *msg, co return len; } libc_hidden_def(ns_name_unpack) + +static int labellen(const unsigned char *lp) +{ + int 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) { + if ((bitlen = *(lp + 1)) == 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) { + if ((msg = *dnptrs++) != 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; + } + + if ((l0 = labellen(srcp)) < 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; +} + +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); +} + +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 */ + if ((l = labellen(cp - 1)) < 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; +} + +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; +} #endif /* L_ns_name */ @@ -2906,12 +3441,10 @@ static void res_sync_func(void) */ } -/* Our res_init never fails (always returns 0) */ -int res_init(void) +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 @@ -2920,13 +3453,27 @@ int res_init(void) __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 @@ -2992,13 +3539,14 @@ int res_init(void) rp->_u._ext.nscount = m; #endif + rp->options |= RES_INIT; + __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, int free_addr) { __UCLIBC_MUTEX_LOCK(__resolv_lock); __close_nameservers(); @@ -3018,7 +3566,27 @@ void res_close(void) memset(&_res, 0, sizeof(_res)); __UCLIBC_MUTEX_UNLOCK(__resolv_lock); } -#endif + +/* + * 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, 1); +} + +#ifdef __UCLIBC_HAS_BSD_RES_CLOSE__ +void res_close(void) +{ + __res_iclose(&_res, 0); +} +#endif /* __UCLIBC_HAS_BSD_RES_CLOSE__ */ /* This needs to be after the use of _res in res_init, above. */ #undef _res @@ -3047,7 +3615,88 @@ extern __thread struct __res_state *__li # undef __resp struct __res_state *__resp = &_res; # endif -#endif +#endif /* !__UCLIBC_HAS_THREADS__ */ + +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 = res_sync_func; + + __UCLIBC_MUTEX_UNLOCK(__resolv_lock); + + __res_vinit(&_res, 1); + + return 0; +} +libc_hidden_def(res_init) + +/* + * 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) +{ + return __res_vinit(statp, 0); +} #endif /* L_res_init */ @@ -3071,7 +3720,7 @@ __res_state (void) } # endif -#endif +#endif /* L_res_state */ #ifdef L_res_query @@ -3324,9 +3973,343 @@ int res_querydomain(const char *name, co 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. */ +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; +} + +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, %s, %d, %d)\n", + name, (op, dname ? dname : ""), 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; + + if ((n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr)) < 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 */