diff options
Diffstat (limited to 'libc/inet/resolv.c')
-rw-r--r-- | libc/inet/resolv.c | 503 |
1 files changed, 356 insertions, 147 deletions
diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c index ed2e0d2fa..d7a659a8c 100644 --- a/libc/inet/resolv.c +++ b/libc/inet/resolv.c @@ -11,6 +11,7 @@ /* * Portions Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. + * Portions Copyright © 2021 mirabilos <m@mirbsd.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -247,6 +248,7 @@ Domain name in a message can be represented as either: #include <netdb.h> #include <ctype.h> #include <stdbool.h> +#include <stdint.h> #include <time.h> #include <arpa/nameser.h> #include <sys/utsname.h> @@ -254,6 +256,7 @@ Domain name in a message can be represented as either: #include <sys/stat.h> #include <sys/param.h> #include <bits/uClibc_mutex.h> +#include <fcntl.h> #include "internal/parse_config.h" /* poll() is not supported in kernel <= 2.0, therefore if __NR_poll is @@ -395,14 +398,6 @@ extern int __dns_lookup(const char *name, int type, unsigned char **outpacket, struct resolv_answer *a) attribute_hidden; -extern int __encode_dotted(const char *dotted, - unsigned char *dest, - int maxlen) attribute_hidden; -extern int __decode_dotted(const unsigned char *packet, - int offset, - int packet_len, - char *dest, - int dest_len) attribute_hidden; extern int __encode_header(struct resolv_header *h, unsigned char *dest, int maxlen) attribute_hidden; @@ -416,6 +411,13 @@ extern int __encode_answer(struct resolv_answer *a, int maxlen) attribute_hidden; extern void __open_nameservers(void) attribute_hidden; extern void __close_nameservers(void) attribute_hidden; +extern int __hnbad(const char *dotted) attribute_hidden; + +#define __encode_dotted(dotted,dest,maxlen) \ + dn_comp((dotted), (dest), (maxlen), NULL, NULL) +#define __decode_dotted(packet,offset,packet_len,dest,dest_len) \ + dn_expand((packet), (packet) + (packet_len), (packet) + (offset), \ + (dest), (dest_len)) /* * Theory of operation. @@ -552,116 +554,6 @@ void __decode_header(unsigned char *data, #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 __encode_dotted(const char *dotted, unsigned char *dest, int maxlen) -{ - unsigned used = 0; - - while (dotted && *dotted) { - char *c = strchr(dotted, '.'); - int l = c ? c - dotted : strlen(dotted); - - /* two consecutive dots are not valid */ - if (l == 0) - return -1; - - if (l >= (maxlen - used - 1)) - return -1; - - dest[used++] = l; - memcpy(dest + used, dotted, l); - used += l; - - if (!c) - break; - dotted = c + 1; - } - - if (maxlen < 1) - return -1; - - dest[used++] = 0; - - return used; -} -#endif /* L_encoded */ - - -#ifdef L_decoded - -/* Decode a dotted string from nameserver transport-level encoding. - This routine understands compressed data. */ -int __decode_dotted(const unsigned char *packet, - int offset, - int packet_len, - char *dest, - int dest_len) -{ - unsigned b; - bool measure = 1; - unsigned total = 0; - unsigned used = 0; - unsigned maxiter = 256; - - if (!packet) - return -1; - - dest[0] = '\0'; - while (--maxiter) { - if (offset >= packet_len) - return -1; - b = packet[offset++]; - if (b == 0) - break; - - if (measure) - total++; - - if ((b & 0xc0) == 0xc0) { - if (offset >= packet_len) - return -1; - if (measure) - total++; - /* compressed item, redirect */ - offset = ((b & 0x3f) << 8) | packet[offset]; - measure = 0; - continue; - } - - if (used + b + 1 >= dest_len) - return -1; - if (offset + b >= packet_len) - return -1; - memcpy(dest + used, packet + offset, b); - offset += b; - used += b; - - if (measure) - total += b; - - if (packet[offset] != 0) - dest[used++] = '.'; - else - dest[used++] = '\0'; - } - if (!maxiter) - return -1; - - /* The null byte must be counted too */ - if (measure) - total++; - - DPRINTF("Total decode len = %d\n", total); - - return total; -} -#endif /* L_decoded */ - - #ifdef L_encodeq int __encode_question(const struct resolv_question *q, @@ -1155,6 +1047,263 @@ static int __decode_answer(const unsigned char *message, /* packet */ return i + RRFIXEDSZ + a->rdlength; } + +#if defined __UCLIBC_DNSRAND_MODE_URANDOM__ || defined __UCLIBC_DNSRAND_MODE_PRNGPLUS__ + +/* + * Get a random int from urandom. + * Return 0 on success and -1 on failure. + * + * This will dip into the entropy pool maintaind by the system. + */ +int _dnsrand_getrandom_urandom(int *rand_value) { + static int urand_fd = -1; + static int errCnt = 0; + if (urand_fd == -1) { + urand_fd = open("/dev/urandom", O_RDONLY); + if (urand_fd == -1) { + if ((errCnt % 16) == 0) { + DPRINTF("uCLibC:WARN:DnsRandGetRand: urandom is unavailable...\n"); + } + errCnt += 1; + return -1; + } + } + if (read(urand_fd, rand_value, sizeof(int)) == sizeof(int)) { /* small reads like few bytes here should be safe in general. */ + DPRINTF("uCLibC:DBUG:DnsRandGetRand: URandom:0x%lx\n", *rand_value); + return 0; + } + return -1; +} + +#endif + +#if defined __UCLIBC_DNSRAND_MODE_CLOCK__ || defined __UCLIBC_DNSRAND_MODE_PRNGPLUS__ + +/* + * Try get a sort of random int by looking at current time in system realtime clock. + * Return 0 on success and -1 on failure. + * + * This requries the realtime related uclibc feature to be enabled and also + * the system should have a clock source with nanosec resolution to be mapped + * to CLOCK_REALTIME, for this to generate values that appear random plausibly. + */ +int _dnsrand_getrandom_clock(int *rand_value) { +#if defined __USE_POSIX199309 && defined __UCLIBC_HAS_REALTIME__ + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { + *rand_value = (ts.tv_sec + ts.tv_nsec) % INT_MAX; + DPRINTF("uCLibC:DBUG:DnsRandGetRand: Clock:0x%lx\n", *rand_value); + return 0; + } +#endif + return -1; +} + +#endif + +#ifdef __UCLIBC_DNSRAND_MODE_PRNGPLUS__ + +/* + * Try get a random int by first checking at urandom and then at realtime clock. + * Return 0 on success and -1 on failure. + * + * Chances are most embedded targets using linux/bsd/... could have urandom and + * also it can potentially give better random values, so try urandom first. + * However if there is failure wrt urandom, then try realtime clock based helper. + */ +int _dnsrand_getrandom_urcl(int *rand_value) { + if (_dnsrand_getrandom_urandom(rand_value) == 0) { + return 0; + } + if (_dnsrand_getrandom_clock(rand_value) == 0) { + return 0; + } + DPRINTF("uCLibC:DBUG:DnsRandGetRand: URCL:Nothing:0x%lx\n", *rand_value); + return -1; +} + +#define DNSRAND_PRNGSTATE_INT32LEN 32 +#undef DNSRAND_PRNGRUN_SHORT +#ifdef DNSRAND_PRNGRUN_SHORT +#define DNSRAND_RESEED_OP1 (DNSRAND_PRNGSTATE_INT32LEN/2) +#define DNSRAND_RESEED_OP2 (DNSRAND_PRNGSTATE_INT32LEN/4) +#else +#define DNSRAND_RESEED_OP1 (DNSRAND_PRNGSTATE_INT32LEN*6) +#define DNSRAND_RESEED_OP2 DNSRAND_PRNGSTATE_INT32LEN +#endif + +#define DNSRAND_TIMEFORCED_RESEED_CHECKMOD (DNSRAND_PRNGSTATE_INT32LEN/8) +#define DNSRAND_TIMEFORCED_RESEED_SECS 120 + +time_t clock_getcursec(void) { + static time_t dummyTime = 0; +#if defined __USE_POSIX199309 && defined __UCLIBC_HAS_REALTIME__ + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { + return ts.tv_sec; + } +#endif + dummyTime += DNSRAND_TIMEFORCED_RESEED_SECS; + return dummyTime; +} + +/* + * This logic uses uclibc's random PRNG to generate random int. This keeps the + * logic fast by not depending on a more involved CPRNG kind of logic nor on a + * kernel to user space handshake at the core. + * + * However to ensure that pseudo random sequences based on a given seeding of the + * PRNG logic, is not generated for too long so as to allow a advarsary to try guess + * the internal states of the prng logic and inturn the next number, srandom is + * used periodically to reseed PRNG logic, when and where possible. + * + * To help with this periodic reseeding, by default the logic will first try to + * see if it can get some relatively random number using /dev/urandom. If not it + * will try use the current time to generate plausibly random value as substitute. + * If neither of these sources are available, then the prng itself is used to seed + * a new state, so that the pseudo random sequence can continue, which is better + * than the fallback simple counter. + * + * Also to add bit more of variance wrt this periodic reseeding, the period interval + * at which this reseeding occurs keeps changing within a predefined window. The + * window is controlled based on how often this logic is called (which currently + * will depend on how often requests for dns query (and inturn dnsrand_next) occurs, + * as well as a self driven periodically changing request count boundry. + * + * The internally generated random values are not directly exposed, instead result + * of adjacent values large mult with mod is used to greatly reduce the possibility + * of trying to infer the internal values from externally exposed random values. + * This should also make longer run of prng ok to an extent. + * + * NOTE: The Random PRNG used here maintains its own internal state data, so that + * it doesnt impact any other users of random prng calls in the system/program + * compiled against uclibc. + * + * NOTE: If your target doesnt support int64_t, then the code uses XOR instead of + * mult with mod based transform on the internal random sequence, to generate the + * random number that is returned. However as XOR is not a one way transform, this + * is supported only in DNSRAND_PRNGRUN_SHORT mode by default, which needs to be + * explicitly enabled by the platform developer, by defining the same. + * + */ +int _dnsrand_getrandom_prng(int *rand_value) { + static time_t reSeededSec = 0; + time_t curSec = 0; + bool bTimeForcedReSeed = 0; + static int cnt = -1; + static int nextReSeedWindow = DNSRAND_RESEED_OP1; + static int32_t prngState[DNSRAND_PRNGSTATE_INT32LEN]; /* prng logic internally assumes int32_t wrt state array, so to help align if required */ + static struct random_data prngData; + int32_t val, val2; + int calc; + int prngSeed = 0x19481869; + + if (cnt == -1) { + _dnsrand_getrandom_urcl(&prngSeed); + memset(&prngData, 0, sizeof(prngData)); + initstate_r(prngSeed, (char*)&prngState, DNSRAND_PRNGSTATE_INT32LEN*4, &prngData); + } + cnt += 1; + if ((cnt % DNSRAND_TIMEFORCED_RESEED_CHECKMOD) == 0) { + curSec = clock_getcursec(); + if ((curSec - reSeededSec) >= DNSRAND_TIMEFORCED_RESEED_SECS) { + bTimeForcedReSeed = 1; + } + } + if (((cnt % nextReSeedWindow) == 0) || bTimeForcedReSeed) { + if (curSec == 0) curSec = clock_getcursec(); + reSeededSec = curSec; + if (_dnsrand_getrandom_urcl(&prngSeed) != 0) { + random_r(&prngData, &prngSeed); + } + srandom_r(prngSeed, &prngData); + random_r(&prngData, &val); + nextReSeedWindow = DNSRAND_RESEED_OP1 + (val % DNSRAND_RESEED_OP2); + DPRINTF("uCLibC:DBUG:DnsRandNext: PRNGWindow:%d\n", nextReSeedWindow); + cnt = 0; + } + random_r(&prngData, &val); + random_r(&prngData, &val2); +#ifdef INT64_MAX + calc = ((int64_t)val * (int64_t)val2) % INT_MAX; +#else +# ifdef DNSRAND_PRNGRUN_SHORT + calc = val ^ val2; +# warning "[No int64] using xor based random number transform logic in short prng run mode, bcas int64_t not supported on this target" +# else +# error "[No int64] using xor based random number transform logic only supported with short prng runs, you may want to define DNSRAND_PRNGRUN_SHORT" +# endif +#endif + *rand_value = calc; + DPRINTF("uCLibC:DBUG:DnsRandGetRand: PRNGPlus: %d, 0x%lx 0x%lx 0x%lx\n", cnt, val, val2, *rand_value); + return 0; +} + +#endif + +/** + * If DNS query's id etal is generated using a simple counter, then it can be + * subjected to dns poisoning relatively easily, so adding some randomness can + * increase the difficulty wrt dns poisoning and is thus desirable. + * + * However given that embedded targets may or may not have different sources available + * with them to try generate random values, this logic tries to provides flexibility + * to the platform developer to decide, how they may want to handle this. + * + * If a given target doesnt support urandom nor realtime clock OR for some reason + * if the platform developer doesnt want to use random dns query id etal, then + * they can define __UCLIBC_DNSRAND_MODE_SIMPLECOUNTER__ so that a simple incrementing + * counter is used. + * + * However if the target has support for urandom or realtime clock, then the prngplus + * based random generation tries to give a good balance between randomness and performance. + * This is the default and is enabled when no other mode is defined. It is also indirectly + * enabled by defining __UCLIBC_DNSRAND_MODE_PRNGPLUS__ instead of the other modes. + * + * If urandom is available on the target and one wants to keep things simple and use + * it directly, then one can define __UCLIBC_DNSRAND_MODE_URANDOM__. Do note that this + * will be relatively slower compared to other options. But it can normally generate + * good random values/ids by dipping into the entropy pool available in the system. + * + * If system realtime clock is available on target and enabled, then if one wants to + * keep things simple and use it directly, then define __UCLIBC_DNSRAND_MODE_CLOCK__. + * Do note that this requires nanosecond resolution / granularity wrt the realtime + * clock source to generate plausibly random values/ids. As processor &/ io performance + * improves, the effectiveness of this strategy can be impacted in some cases. + * + * If either the URandom or Clock based get random fails, then the logic is setup to + * try fallback to the simple counter mode, with the help of the def_value, which is + * setup to be the next increment wrt the previously generated / used value, by the + * caller of dnsrand_next. + * + */ +int dnsrand_next(int def_value) { + int val = def_value; +#if defined __UCLIBC_DNSRAND_MODE_SIMPLECOUNTER__ + return val; +#elif defined __UCLIBC_DNSRAND_MODE_URANDOM__ + if (_dnsrand_getrandom_urandom(&val) == 0) { + return val; + } + return def_value; +#elif defined __UCLIBC_DNSRAND_MODE_CLOCK__ + if (_dnsrand_getrandom_clock(&val) == 0) { + return val; + } + return def_value; +#else + if (_dnsrand_getrandom_prng(&val) == 0) { + return val; + } + return def_value; +#endif +} + +int dnsrand_setup(int def_value) { + return def_value; +} + /* On entry: * a.buf(len) = auxiliary buffer for IP addresses after first one * a.add_count = how many additional addresses are there already @@ -1204,6 +1353,7 @@ int __dns_lookup(const char *name, bool ends_with_dot; bool contains_dot; sockaddr46_t sa; + int num_answers; fd = -1; lookup = NULL; @@ -1258,7 +1408,7 @@ int __dns_lookup(const char *name, } /* first time? pick starting server etc */ if (local_ns_num < 0) { - local_id = last_id; + local_id = dnsrand_setup(last_id); /*TODO: implement /etc/resolv.conf's "options rotate" (a.k.a. RES_ROTATE bit in _res.options) local_ns_num = 0; @@ -1268,7 +1418,7 @@ int __dns_lookup(const char *name, } if (local_ns_num >= __nameservers) local_ns_num = 0; - local_id++; + local_id = dnsrand_next(++local_id); local_id &= 0xffff; /* write new values back while still under lock */ last_id = local_id; @@ -1446,6 +1596,7 @@ int __dns_lookup(const char *name, goto fail1; } pos = HFIXEDSZ; + /*XXX TODO: check that question matches query (and qdcount==1?) */ for (j = 0; j < h.qdcount; j++) { DPRINTF("Skipping question %d at %d\n", j, pos); i = __length_question(packet + pos, packet_len - pos); @@ -1460,6 +1611,7 @@ int __dns_lookup(const char *name, DPRINTF("Decoding answer at pos %d\n", pos); first_answer = 1; + num_answers = 0; a->dotted = NULL; for (j = 0; j < h.ancount; j++) { i = __decode_answer(packet, pos, packet_len, &ma); @@ -1467,12 +1619,15 @@ int __dns_lookup(const char *name, DPRINTF("failed decode %d\n", i); /* If the message was truncated but we have * decoded some answers, pretend it's OK */ - if (j && h.tc) + if (num_answers && h.tc) break; goto try_next_server; } pos += i; + if (__hnbad(ma.dotted)) + break; + ++num_answers; if (first_answer) { ma.buf = a->buf; ma.buflen = a->buflen; @@ -1502,6 +1657,10 @@ int __dns_lookup(const char *name, ++a->add_count; } } + if (!num_answers) { + h_errno = NO_RECOVERY; + goto fail1; + } /* Success! */ DPRINTF("Answer name = |%s|\n", a->dotted); @@ -1619,7 +1778,7 @@ int __read_etc_hosts_r( found: result_buf->h_name = *(result_buf->h_aliases++); result_buf->h_addr_list = (char**)(buf + HALISTOFF); - *(result_buf->h_addr_list + 1) = '\0'; + *(result_buf->h_addr_list + 1) = 0; h_addr0 = (struct in_addr*)(buf + INADDROFF); result_buf->h_addr = (char*)h_addr0; if (0) /* nothing */; @@ -2468,7 +2627,7 @@ int gethostbyaddr_r(const void *addr, socklen_t addrlen, /* Decode CNAME into buf, feed it to __dns_lookup() again */ i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen); free(packet); - if (i < 0) { + if (i < 0 || __hnbad(buf)) { *h_errnop = NO_RECOVERY; return -1; } @@ -2477,6 +2636,10 @@ int gethostbyaddr_r(const void *addr, socklen_t addrlen, if (a.atype == T_PTR) { /* ADDRESS */ i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen); free(packet); + if (__hnbad(buf)) { + *h_errnop = NO_RECOVERY; + return -1; + } result_buf->h_name = buf; result_buf->h_addrtype = type; result_buf->h_length = addrlen; @@ -2646,7 +2809,7 @@ libc_hidden_def(gethostbyaddr) * '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, +int weak_function 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); @@ -2655,14 +2818,14 @@ int dn_expand(const u_char *msg, const u_char *eom, const u_char *src, dst[0] = '\0'; return n; } -libc_hidden_def(dn_expand) +libc_hidden_weak(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 +int weak_function dn_comp(const char *src, u_char *dst, int dstsiz, u_char **dnptrs, u_char **lastdnptr) { @@ -2670,7 +2833,7 @@ dn_comp(const char *src, u_char *dst, int dstsiz, (const u_char **) dnptrs, (const u_char **) lastdnptr); } -libc_hidden_def(dn_comp) +libc_hidden_weak(dn_comp) #endif /* L_res_comp */ @@ -2710,7 +2873,7 @@ static int special(int ch) * note: * Root domain returns as "." not "". */ -int ns_name_uncompress(const u_char *msg, const u_char *eom, +int weak_function 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]; @@ -2723,7 +2886,7 @@ int ns_name_uncompress(const u_char *msg, const u_char *eom, return -1; return n; } -libc_hidden_def(ns_name_uncompress) +libc_hidden_weak(ns_name_uncompress) /* * ns_name_ntop(src, dst, dstsiz) @@ -2734,7 +2897,7 @@ libc_hidden_def(ns_name_uncompress) * 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) +int weak_function ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) { const u_char *cp; char *dn, *eom; @@ -2804,7 +2967,7 @@ int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) *dn++ = '\0'; return (dn - dst); } -libc_hidden_def(ns_name_ntop) +libc_hidden_weak(ns_name_ntop) static int encode_bitstring(const char **bp, const char *end, unsigned char **labelp, @@ -2918,7 +3081,7 @@ static int encode_bitstring(const char **bp, const char *end, return 0; } -int ns_name_pton(const char *src, u_char *dst, size_t dstsiz) +int weak_function ns_name_pton(const char *src, u_char *dst, size_t dstsiz) { static const char digits[] = "0123456789"; u_char *label, *bp, *eom; @@ -3039,7 +3202,52 @@ int ns_name_pton(const char *src, u_char *dst, size_t dstsiz) errno = EMSGSIZE; return -1; } -libc_hidden_def(ns_name_pton) +libc_hidden_weak(ns_name_pton) + +/* + * __hnbad(dotted) + * Check whether a name is valid enough for DNS. The rules, as + * laid down by glibc, are: + * - printable input string + * - converts to label notation + * - each label only contains [0-9a-zA-Z_-], up to 63 octets + * - first label doesn’t begin with ‘-’ + * This both is weaker than Unix hostnames (e.g. it allows + * underscores and leading/trailing hyphen-minus) and stronger + * than general (e.g. a leading “*.” is valid sometimes), take care. + * return: + * 0 if the name is ok + */ +int weak_function __hnbad(const char *dotted) +{ + unsigned char c, n, *cp; + unsigned char buf[NS_MAXCDNAME]; + + cp = (unsigned char *)dotted; + while ((c = *cp++)) + if (c < 0x21 || c > 0x7E) + return (1); + if (ns_name_pton(dotted, buf, sizeof(buf)) < 0) + return (2); + if (buf[0] > 0 && buf[1] == '-') + return (3); + cp = buf; + while ((n = *cp++)) { + if (n > 63) + return (4); + while (n--) { + c = *cp++; + if (c < '-' || + (c > '-' && c < '0') || + (c > '9' && c < 'A') || + (c > 'Z' && c < '_') || + (c > '_' && c < 'a') || + c > 'z') + return (5); + } + } + return (0); +} /* * ns_name_unpack(msg, eom, src, dst, dstsiz) @@ -3047,7 +3255,7 @@ libc_hidden_def(ns_name_pton) * 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, +int weak_function 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; @@ -3114,7 +3322,7 @@ int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, len = srcp - src; return len; } -libc_hidden_def(ns_name_unpack) +libc_hidden_weak(ns_name_unpack) static int labellen(const unsigned char *lp) { @@ -3208,7 +3416,7 @@ next: return -1; } -int ns_name_pack(const unsigned char *src, +int weak_function ns_name_pack(const unsigned char *src, unsigned char *dst, int dstsiz, const unsigned char **dnptrs, const unsigned char **lastdnptr) @@ -3311,15 +3519,15 @@ cleanup: if (msg != NULL) *lpp = NULL; - errno = EMSGSIZE; - return -1; + errno = EMSGSIZE; + return -1; } return dstp - dst; } -libc_hidden_def(ns_name_pack) +libc_hidden_weak(ns_name_pack) -int ns_name_compress(const char *src, +int weak_function ns_name_compress(const char *src, unsigned char *dst, size_t dstsiz, const unsigned char **dnptrs, const unsigned char **lastdnptr) @@ -3331,9 +3539,9 @@ int ns_name_compress(const char *src, return ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr); } -libc_hidden_def(ns_name_compress) +libc_hidden_weak(ns_name_compress) -int ns_name_skip(const unsigned char **ptrptr, +int weak_function ns_name_skip(const unsigned char **ptrptr, const unsigned char *eom) { const unsigned char *cp; @@ -3375,9 +3583,9 @@ int ns_name_skip(const unsigned char **ptrptr, return 0; } -libc_hidden_def(ns_name_skip) +libc_hidden_weak(ns_name_skip) -int dn_skipname(const unsigned char *ptr, const unsigned char *eom) +int weak_function dn_skipname(const unsigned char *ptr, const unsigned char *eom) { const unsigned char *saveptr = ptr; @@ -3386,7 +3594,7 @@ int dn_skipname(const unsigned char *ptr, const unsigned char *eom) return ptr - saveptr; } -libc_hidden_def(dn_skipname) +libc_hidden_weak(dn_skipname) #endif /* L_ns_name */ @@ -3395,7 +3603,7 @@ libc_hidden_def(dn_skipname) /* Will be called under __resolv_lock. */ static void res_sync_func(void) { - struct __res_state *rp = &(_res); + struct __res_state *rp = __res_state(); int n; /* If we didn't get malloc failure earlier... */ @@ -3947,7 +4155,8 @@ res_ninit(res_state statp) #endif /* L_res_init */ #ifdef L_res_state -# if defined __UCLIBC_HAS_TLS__ +# if !defined __UCLIBC_HAS_TLS__ +extern struct __res_state *__resp; struct __res_state * __res_state (void) { |