summaryrefslogtreecommitdiff
path: root/libc/inet/resolv.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/inet/resolv.c')
-rw-r--r--libc/inet/resolv.c503
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)
{