aboutsummaryrefslogtreecommitdiff
path: root/lib/libc/resolv
diff options
context:
space:
mode:
authorHajimu UMEMOTO <ume@FreeBSD.org>2006-03-21 15:37:16 +0000
committerHajimu UMEMOTO <ume@FreeBSD.org>2006-03-21 15:37:16 +0000
commitab96eeabe8f319206346df2f486e01caabbfd8f4 (patch)
tree6a044a277848f8d42cf8a314d701efea03241963 /lib/libc/resolv
parent03970c5728f7f53ce03efacc0cf12ef383d7cdda (diff)
downloadsrc-ab96eeabe8f319206346df2f486e01caabbfd8f4.tar.gz
src-ab96eeabe8f319206346df2f486e01caabbfd8f4.zip
Notes
Diffstat (limited to 'lib/libc/resolv')
-rw-r--r--lib/libc/resolv/Makefile.inc7
-rw-r--r--lib/libc/resolv/Symbol.map102
-rw-r--r--lib/libc/resolv/h_errno.c49
-rw-r--r--lib/libc/resolv/herror.c11
-rw-r--r--lib/libc/resolv/mtctxres.c14
-rw-r--r--lib/libc/resolv/res_comp.c11
-rw-r--r--lib/libc/resolv/res_data.c47
-rw-r--r--lib/libc/resolv/res_debug.c27
-rw-r--r--lib/libc/resolv/res_init.c87
-rw-r--r--lib/libc/resolv/res_mkquery.c14
-rw-r--r--lib/libc/resolv/res_query.c52
-rw-r--r--lib/libc/resolv/res_send.c118
-rw-r--r--lib/libc/resolv/res_state.c96
13 files changed, 578 insertions, 57 deletions
diff --git a/lib/libc/resolv/Makefile.inc b/lib/libc/resolv/Makefile.inc
new file mode 100644
index 000000000000..8e4366c751cd
--- /dev/null
+++ b/lib/libc/resolv/Makefile.inc
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+# resolv sources
+.PATH: ${.CURDIR}/resolv
+
+SRCS+= herror.c h_errno.c mtctxres.c res_comp.c res_data.c res_debug.c \
+ res_init.c res_mkquery.c res_query.c res_send.c res_state.c
diff --git a/lib/libc/resolv/Symbol.map b/lib/libc/resolv/Symbol.map
new file mode 100644
index 000000000000..3239a2031f1e
--- /dev/null
+++ b/lib/libc/resolv/Symbol.map
@@ -0,0 +1,102 @@
+# $FreeBSD$
+
+FBSD_1.0 {
+ #h_nerr; # Why is this not staticized in net/herror.c?
+ h_errlist;
+ herror;
+ hstrerror;
+ __dn_expand;
+ __dn_comp;
+ __dn_skipname;
+ __res_hnok;
+ __res_ownok;
+ __res_mailok;
+ __res_dnok;
+ __putlong;
+ __putshort;
+ _getlong;
+ _getshort;
+ dn_comp;
+ dn_expand;
+ __fp_resstat;
+ __p_query;
+ __fp_query;
+ __fp_nquery;
+ __p_cdnname;
+ __p_cdname;
+ __p_fqnname;
+ __p_fqname;
+ __p_cert_syms;
+ __p_class_syms;
+ __p_key_syms;
+ __p_type_syms;
+ __sym_ston;
+ __sym_ntos;
+ __sym_ntop;
+ __p_rcode;
+ __p_sockun;
+ __p_type;
+ __p_section;
+ __p_class;
+ __p_option;
+ __p_time;
+ __loc_aton;
+ __loc_ntoa;
+ __dn_count_labels;
+ __p_secstodate;
+ fp_resstat;
+ p_query;
+ p_fqnname;
+ sym_ston;
+ sym_ntos;
+ sym_ntop;
+ dn_count_labels;
+ p_secstodate;
+ __res_init;
+ __res_randomid;
+ ___res;
+ ___res_ext;
+ __h_errno;
+ __h_errno_set;
+ __h_error;
+ h_errno;
+ res_init;
+ __res_mkquery;
+ res_mkquery;
+ __res_opt;
+ __res_freeupdrec;
+ #__res_get_nibblesuffix; # Excluded
+ #__res_get_nibblesuffix2; # Excluded
+ __res_getservers;
+ __res_hostalias;
+ __res_nametoclass;
+ __res_nametotype;
+ __res_nclose;
+ __res_ndestroy;
+ __res_ninit;
+ __res_nmkquery;
+ __res_nopt;
+ __res_nquery;
+ __res_nquerydomain;
+ __res_nsearch;
+ __res_nsend;
+ __res_ourserver_p;
+ __res_pquery;
+ __res_query;
+ __res_search;
+ __res_querydomain;
+ __res_setservers;
+ __res_state;
+ __res_vinit;
+ __hostalias;
+ res_query;
+ res_search;
+ res_querydomain;
+ __res_isourserver;
+ __res_nameinquery;
+ __res_queriesmatch;
+ __res_send;
+ __res_close;
+ _res_close;
+ res_send;
+};
diff --git a/lib/libc/resolv/h_errno.c b/lib/libc/resolv/h_errno.c
new file mode 100644
index 000000000000..4d471b49cbc4
--- /dev/null
+++ b/lib/libc/resolv/h_errno.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2006 The FreeBSD Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#undef h_errno
+extern int h_errno;
+
+int *
+__h_errno(void)
+{
+ return (&__res_state()->res_h_errno);
+}
+
+void
+__h_errno_set(res_state res, int err)
+{
+ h_errno = res->res_h_errno = err;
+}
+
+/* binary backward compatibility for FreeBSD 5.x and 6.x */
+__weak_reference(__h_errno, __h_error);
diff --git a/lib/libc/resolv/herror.c b/lib/libc/resolv/herror.c
index 58807e9678e0..be4b43ec1d9c 100644
--- a/lib/libc/resolv/herror.c
+++ b/lib/libc/resolv/herror.c
@@ -52,9 +52,12 @@
static const char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: herror.c,v 1.2.206.1 2004/03/09 08:33:54 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
+#include "namespace.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/uio.h>
@@ -66,7 +69,7 @@ static const char rcsid[] = "$Id: herror.c,v 1.2.206.1 2004/03/09 08:33:54 marka
#include <resolv.h>
#include <string.h>
#include <unistd.h>
-#include <irs.h>
+#include "un-namespace.h"
#include "port_after.h"
@@ -77,12 +80,10 @@ const char *h_errlist[] = {
"Unknown server error", /* 3 NO_RECOVERY */
"No address associated with name", /* 4 NO_ADDRESS */
};
-int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] };
+const int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] };
-#if !(__GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
#undef h_errno
int h_errno;
-#endif
/*
* herror --
@@ -110,7 +111,7 @@ herror(const char *s) {
DE_CONST("\n", t);
v->iov_base = t;
v->iov_len = 1;
- writev(STDERR_FILENO, iov, (v - iov) + 1);
+ _writev(STDERR_FILENO, iov, (v - iov) + 1);
}
/*
diff --git a/lib/libc/resolv/mtctxres.c b/lib/libc/resolv/mtctxres.c
index f33cf11e3f42..86b5a79600f0 100644
--- a/lib/libc/resolv/mtctxres.c
+++ b/lib/libc/resolv/mtctxres.c
@@ -1,13 +1,18 @@
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <port_before.h>
#ifdef DO_PTHREADS
#include <pthread.h>
+#ifdef _LIBC
+#include <pthread_np.h>
+#endif
#endif
#include <errno.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <resolv_mt.h>
-#include <irs.h>
#include <port_after.h>
#ifdef DO_PTHREADS
@@ -40,6 +45,7 @@ _mtctxres_init(void) {
}
#endif
+#ifndef _LIBC
/*
* To support binaries that used the private MT-safe interface in
* Solaris 8, we still need to provide the __res_enable_mt()
@@ -54,6 +60,7 @@ int
__res_disable_mt(void) {
return (0);
}
+#endif
#ifdef DO_PTHREADS
static int
@@ -99,6 +106,11 @@ ___mtctxres(void) {
#ifdef DO_PTHREADS
mtctxres_t *mt;
+#ifdef _LIBC
+ if (pthread_main_np() != 0)
+ return (&sharedctx);
+#endif
+
/*
* This if clause should only be executed if we are linking
* statically. When linked dynamically _mtctxres_init() should
diff --git a/lib/libc/resolv/res_comp.c b/lib/libc/resolv/res_comp.c
index 8cc99a762884..cf45f0758450 100644
--- a/lib/libc/resolv/res_comp.c
+++ b/lib/libc/resolv/res_comp.c
@@ -72,6 +72,8 @@
static const char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: res_comp.c,v 1.1.2.1.4.2 2005/07/28 07:43:22 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
#include <sys/types.h>
@@ -261,3 +263,12 @@ u_int32_t _getlong(const u_char *src) { return (ns_get32(src)); }
u_int16_t _getshort(const u_char *src) { return (ns_get16(src)); }
#endif /*__ultrix__*/
#endif /*BIND_4_COMPAT*/
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <resolv.h>.
+ */
+#undef dn_comp
+__weak_reference(__dn_comp, dn_comp);
+#undef dn_expand
+__weak_reference(__dn_expand, dn_expand);
diff --git a/lib/libc/resolv/res_data.c b/lib/libc/resolv/res_data.c
index 204e03d685f4..a864b6079655 100644
--- a/lib/libc/resolv/res_data.c
+++ b/lib/libc/resolv/res_data.c
@@ -18,6 +18,8 @@
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: res_data.c,v 1.1.206.2 2004/03/16 12:34:18 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -33,14 +35,15 @@ static const char rcsid[] = "$Id: res_data.c,v 1.1.206.2 2004/03/16 12:34:18 mar
#include <ctype.h>
#include <netdb.h>
#include <resolv.h>
+#ifndef _LIBC
#include <res_update.h>
+#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "port_after.h"
-#undef _res
const char *_res_opcodes[] = {
"QUERY",
@@ -71,11 +74,6 @@ const char *_res_sectioncodes[] = {
#endif
#ifndef __BIND_NOSTATIC
-struct __res_state _res
-# if defined(__BIND_RES_TEXT)
- = { RES_TIMEOUT, } /* Motorola, et al. */
-# endif
- ;
/* Proto. */
@@ -107,7 +105,7 @@ res_init(void) {
if (!_res.retrans)
_res.retrans = RES_TIMEOUT;
if (!_res.retry)
- _res.retry = 4;
+ _res.retry = RES_DFLRETRY;
if (!(_res.options & RES_INIT))
_res.options = RES_DEFAULT;
@@ -158,6 +156,7 @@ res_mkquery(int op, /* opcode of query */
newrr_in, buf, buflen));
}
+#ifndef _LIBC
int
res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) {
if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
@@ -167,6 +166,7 @@ res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) {
return (res_nmkupdate(&_res, rrecp_in, buf, buflen));
}
+#endif
int
res_query(const char *name, /* domain name */
@@ -181,6 +181,7 @@ res_query(const char *name, /* domain name */
return (res_nquery(&_res, name, class, type, answer, anslen));
}
+#ifndef _LIBC
void
res_send_setqhook(res_send_qhook hook) {
_res.qhook = hook;
@@ -190,6 +191,7 @@ void
res_send_setrhook(res_send_rhook hook) {
_res.rhook = hook;
}
+#endif
int
res_isourserver(const struct sockaddr_in *inp) {
@@ -206,6 +208,7 @@ res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) {
return (res_nsend(&_res, buf, buflen, ans, anssiz));
}
+#ifndef _LIBC
int
res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key,
u_char *ans, int anssiz)
@@ -217,12 +220,14 @@ res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key,
return (res_nsendsigned(&_res, buf, buflen, key, ans, anssiz));
}
+#endif
void
res_close(void) {
res_nclose(&_res);
}
+#ifndef _LIBC
int
res_update(ns_updrec *rrecp_in) {
if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
@@ -232,6 +237,7 @@ res_update(ns_updrec *rrecp_in) {
return (res_nupdate(&_res, rrecp_in, NULL));
}
+#endif
int
res_search(const char *name, /* domain name */
@@ -264,6 +270,12 @@ res_querydomain(const char *name,
answer, anslen));
}
+int
+res_opt(int n0, u_char *buf, int buflen, int anslen)
+{
+ return (res_nopt(&_res, n0, buf, buflen, anslen));
+}
+
const char *
hostalias(const char *name) {
static char abuf[MAXDNAME];
@@ -288,4 +300,25 @@ local_hostname_length(const char *hostname) {
}
#endif /*ultrix*/
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <resolv.h>.
+ */
+#undef res_init
+__weak_reference(__res_init, res_init);
+#undef p_query
+__weak_reference(__p_query, p_query);
+#undef res_mkquery
+__weak_reference(__res_mkquery, res_mkquery);
+#undef res_query
+__weak_reference(__res_query, res_query);
+#undef res_send
+__weak_reference(__res_send, res_send);
+#undef res_close
+__weak_reference(__res_close, _res_close);
+#undef res_search
+__weak_reference(__res_search, res_search);
+#undef res_querydomain
+__weak_reference(__res_querydomain, res_querydomain);
+
#endif
diff --git a/lib/libc/resolv/res_debug.c b/lib/libc/resolv/res_debug.c
index 8dda12c5e81c..29c6ef42f8ce 100644
--- a/lib/libc/resolv/res_debug.c
+++ b/lib/libc/resolv/res_debug.c
@@ -97,6 +97,8 @@
static const char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: res_debug.c,v 1.3.2.5.4.6 2005/07/28 07:43:22 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -375,7 +377,7 @@ const struct res_sym __p_class_syms[] = {
/*
* Names of message sections.
*/
-const struct res_sym __p_default_section_syms[] = {
+static const struct res_sym __p_default_section_syms[] = {
{ns_s_qd, "QUERY", (char *)0},
{ns_s_an, "ANSWER", (char *)0},
{ns_s_ns, "AUTHORITY", (char *)0},
@@ -383,7 +385,7 @@ const struct res_sym __p_default_section_syms[] = {
{0, (char *)0, (char *)0}
};
-const struct res_sym __p_update_section_syms[] = {
+static const struct res_sym __p_update_section_syms[] = {
{S_ZONE, "ZONE", (char *)0},
{S_PREREQ, "PREREQUISITE", (char *)0},
{S_UPDATE, "UPDATE", (char *)0},
@@ -470,7 +472,7 @@ const struct res_sym __p_type_syms[] = {
/*
* Names of DNS rcodes.
*/
-const struct res_sym __p_rcode_syms[] = {
+static const struct res_sym __p_rcode_syms[] = {
{ns_r_noerror, "NOERROR", "no error"},
{ns_r_formerr, "FORMERR", "format error"},
{ns_r_servfail, "SERVFAIL", "server failed"},
@@ -1161,3 +1163,22 @@ res_nametotype(const char *buf, int *successp) {
*successp = success;
return (result);
}
+
+/*
+ * Weak aliases for applications that use certain private entry points,
+ * and fail to include <resolv.h>.
+ */
+#undef fp_resstat
+__weak_reference(__fp_resstat, fp_resstat);
+#undef p_fqnname
+__weak_reference(__p_fqnname, p_fqnname);
+#undef sym_ston
+__weak_reference(__sym_ston, sym_ston);
+#undef sym_ntos
+__weak_reference(__sym_ntos, sym_ntos);
+#undef sym_ntop
+__weak_reference(__sym_ntop, sym_ntop);
+#undef dn_count_labels
+__weak_reference(__dn_count_labels, dn_count_labels);
+#undef p_secstodate
+__weak_reference(__p_secstodate, p_secstodate);
diff --git a/lib/libc/resolv/res_init.c b/lib/libc/resolv/res_init.c
index 28a3ebd088e9..30ff9dc42fe2 100644
--- a/lib/libc/resolv/res_init.c
+++ b/lib/libc/resolv/res_init.c
@@ -72,6 +72,8 @@
static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93";
static const char rcsid[] = "$Id: res_init.c,v 1.9.2.5.4.5 2005/11/03 00:00:52 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -106,12 +108,12 @@ static const char rcsid[] = "$Id: res_init.c,v 1.9.2.5.4.5 2005/11/03 00:00:52 m
#include <sys/systeminfo.h>
#endif
-static void res_setoptions __P((res_state, const char *, const char *));
+static void res_setoptions(res_state, const char *, const char *);
#ifdef RESOLVSORT
static const char sort_mask[] = "/&";
#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
-static u_int32_t net_mask __P((struct in_addr));
+static u_int32_t net_mask(struct in_addr);
#endif
#if !defined(isascii) /* XXX - could be a function */
@@ -153,9 +155,9 @@ res_ninit(res_state statp) {
/* This function has to be reachable by res_data.c but not publically. */
int
__res_vinit(res_state statp, int preinit) {
- register FILE *fp;
- register char *cp, **pp;
- register int n;
+ FILE *fp;
+ char *cp, **pp;
+ int n;
char buf[BUFSIZ];
int nserv = 0; /* number of nameserver records read from file */
int haveenv = 0;
@@ -253,7 +255,7 @@ __res_vinit(res_state statp, int preinit) {
#endif /* SOLARIS2 */
/* Allow user to override the local domain definition */
- if ((cp = getenv("LOCALDOMAIN")) != NULL) {
+ if (issetugid() == 0 && (cp = getenv("LOCALDOMAIN")) != NULL) {
(void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
statp->defdname[sizeof(statp->defdname) - 1] = '\0';
haveenv++;
@@ -390,6 +392,10 @@ __res_vinit(res_state statp, int preinit) {
#ifdef RESOLVSORT
if (MATCH(buf, "sortlist")) {
struct in_addr a;
+ struct in6_addr a6;
+ int m, i;
+ u_char *u;
+ struct __res_state_ext *ext = statp->_u._ext.ext;
cp = buf + sizeof("sortlist") - 1;
while (nsort < MAXRESOLVSORT) {
@@ -424,6 +430,57 @@ __res_vinit(res_state statp, int preinit) {
statp->sort_list[nsort].mask =
net_mask(statp->sort_list[nsort].addr);
}
+ ext->sort_list[nsort].af = AF_INET;
+ ext->sort_list[nsort].addr.ina =
+ statp->sort_list[nsort].addr;
+ ext->sort_list[nsort].mask.ina.s_addr =
+ statp->sort_list[nsort].mask;
+ nsort++;
+ }
+ else if (inet_pton(AF_INET6, net, &a6) == 1) {
+
+ ext->sort_list[nsort].af = AF_INET6;
+ ext->sort_list[nsort].addr.in6a = a6;
+ u = (u_char *)&ext->sort_list[nsort].mask.in6a;
+ *cp++ = n;
+ net = cp;
+ while (*cp && *cp != ';' &&
+ isascii(*cp) && !isspace(*cp))
+ cp++;
+ m = n;
+ n = *cp;
+ *cp = 0;
+ switch (m) {
+ case '/':
+ m = atoi(net);
+ break;
+ case '&':
+ if (inet_pton(AF_INET6, net, u) == 1) {
+ m = -1;
+ break;
+ }
+ /*FALLTHROUGH*/
+ default:
+ m = sizeof(struct in6_addr) * CHAR_BIT;
+ break;
+ }
+ if (m >= 0) {
+ for (i = 0; i < sizeof(struct in6_addr); i++) {
+ if (m <= 0) {
+ *u = 0;
+ } else {
+ m -= CHAR_BIT;
+ *u = (u_char)~0;
+ if (m < 0)
+ *u <<= -m;
+ }
+ u++;
+ }
+ }
+ statp->sort_list[nsort].addr.s_addr =
+ (u_int32_t)0xffffffff;
+ statp->sort_list[nsort].mask =
+ (u_int32_t)0xffffffff;
nsort++;
}
*cp = n;
@@ -486,7 +543,9 @@ __res_vinit(res_state statp, int preinit) {
#endif
}
- if ((cp = getenv("RES_OPTIONS")) != NULL)
+ if (issetugid())
+ statp->options |= RES_NOALIASES;
+ else if ((cp = getenv("RES_OPTIONS")) != NULL)
res_setoptions(statp, cp, "env");
statp->options |= RES_INIT;
return (0);
@@ -506,7 +565,9 @@ res_setoptions(res_state statp, const char *options, const char *source)
{
const char *cp = options;
int i;
+#ifndef _LIBC
struct __res_state_ext *ext = statp->_u._ext.ext;
+#endif
#ifdef DEBUG
if (statp->options & RES_DEBUG)
@@ -580,6 +641,10 @@ res_setoptions(res_state statp, const char *options, const char *source)
statp->options |= RES_NOTLDQUERY;
} else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
statp->options |= RES_USE_INET6;
+ } else if (!strncmp(cp, "insecure1", sizeof("insecure1") - 1)) {
+ statp->options |= RES_INSECURE1;
+ } else if (!strncmp(cp, "insecure2", sizeof("insecure2") - 1)) {
+ statp->options |= RES_INSECURE2;
} else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
statp->options |= RES_ROTATE;
} else if (!strncmp(cp, "no-check-names",
@@ -591,6 +656,7 @@ res_setoptions(res_state statp, const char *options, const char *source)
statp->options |= RES_USE_EDNS0;
}
#endif
+#ifndef _LIBC
else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
statp->options |= RES_USE_DNAME;
}
@@ -620,10 +686,13 @@ res_setoptions(res_state statp, const char *options, const char *source)
~RES_NO_NIBBLE2;
}
}
+#endif
else {
/* XXX - print a warning here? */
}
+#ifndef _LIBC
skip:
+#endif
/* skip to next run of spaces */
while (*cp && *cp != ' ' && *cp != '\t')
cp++;
@@ -636,7 +705,7 @@ static u_int32_t
net_mask(in) /* XXX - should really use system's version of this */
struct in_addr in;
{
- register u_int32_t i = ntohl(in.s_addr);
+ u_int32_t i = ntohl(in.s_addr);
if (IN_CLASSA(i))
return (htonl(IN_CLASSA_NET));
@@ -687,6 +756,7 @@ res_ndestroy(res_state statp) {
statp->_u._ext.ext = NULL;
}
+#ifndef _LIBC
const char *
res_get_nibblesuffix(res_state statp) {
if (statp->_u._ext.ext)
@@ -700,6 +770,7 @@ res_get_nibblesuffix2(res_state statp) {
return (statp->_u._ext.ext->nsuffix2);
return ("ip6.int");
}
+#endif
void
res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
diff --git a/lib/libc/resolv/res_mkquery.c b/lib/libc/resolv/res_mkquery.c
index 89000edf6ad4..60f1efc19e3f 100644
--- a/lib/libc/resolv/res_mkquery.c
+++ b/lib/libc/resolv/res_mkquery.c
@@ -72,6 +72,8 @@
static const char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: res_mkquery.c,v 1.1.2.2.4.2 2004/03/16 12:34:18 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
#include <sys/types.h>
@@ -104,9 +106,9 @@ res_nmkquery(res_state statp,
u_char *buf, /* buffer to put query */
int buflen) /* size of buffer */
{
- register HEADER *hp;
- register u_char *cp, *ep;
- register int n;
+ HEADER *hp;
+ u_char *cp, *ep;
+ int n;
u_char *dnptrs[20], **dpp, **lastdnptr;
UNUSED(newrr_in);
@@ -214,8 +216,8 @@ res_nopt(res_state statp,
int buflen, /* size of buffer */
int anslen) /* UDP answer buffer size */
{
- register HEADER *hp;
- register u_char *cp, *ep;
+ HEADER *hp;
+ u_char *cp, *ep;
u_int16_t flags = 0;
#ifdef DEBUG
@@ -234,6 +236,8 @@ res_nopt(res_state statp,
ns_put16(T_OPT, cp); /* TYPE */
cp += INT16SZ;
+ if (anslen > 0xffff)
+ anslen = 0xffff; /* limit to 16bit value */
ns_put16(anslen & 0xffff, cp); /* CLASS = UDP payload size */
cp += INT16SZ;
*cp++ = NOERROR; /* extended RCODE */
diff --git a/lib/libc/resolv/res_query.c b/lib/libc/resolv/res_query.c
index 5156ce84c086..cb21ac6d3fc5 100644
--- a/lib/libc/resolv/res_query.c
+++ b/lib/libc/resolv/res_query.c
@@ -72,6 +72,8 @@
static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: res_query.c,v 1.2.2.3.4.2 2004/03/16 12:34:19 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
#include <sys/types.h>
@@ -86,6 +88,7 @@ static const char rcsid[] = "$Id: res_query.c,v 1.2.2.3.4.2 2004/03/16 12:34:19
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include "port_after.h"
/* Options. Leave them on. */
@@ -209,7 +212,6 @@ res_nsearch(res_state statp,
int anslen) /* size of answer */
{
const char *cp, * const *domain;
- HEADER *hp = (HEADER *) answer;
char tmp[NS_MAXDNAME];
u_int dots;
int trailing_dot, ret, saved_herrno;
@@ -242,6 +244,17 @@ res_nsearch(res_state statp,
answer, anslen);
if (ret > 0 || trailing_dot)
return (ret);
+ if (errno == ECONNREFUSED) {
+ RES_SET_H_ERRNO(statp, TRY_AGAIN);
+ return (-1);
+ }
+ switch (statp->res_h_errno) {
+ case NO_DATA:
+ case HOST_NOT_FOUND:
+ break;
+ default:
+ return (-1);
+ }
saved_herrno = statp->res_h_errno;
tried_as_is++;
}
@@ -265,6 +278,9 @@ res_nsearch(res_state statp,
(domain[0][0] == '.' && domain[0][1] == '\0'))
root_on_list++;
+ if (root_on_list && tried_as_is)
+ continue;
+
ret = res_nquerydomain(statp, name, *domain,
class, type,
answer, anslen);
@@ -297,11 +313,24 @@ res_nsearch(res_state statp,
/* keep trying */
break;
case TRY_AGAIN:
- if (hp->rcode == SERVFAIL) {
- /* try next search element, if any */
- got_servfail++;
- break;
- }
+ /*
+ * This can occur due to a server failure
+ * (that is, all listed servers have failed),
+ * or all listed servers have timed out.
+ * ((HEADER *)answer)->rcode may not be set
+ * to SERVFAIL in the case of a timeout.
+ *
+ * Either way we must terminate the search
+ * and return TRY_AGAIN in order to avoid
+ * non-deterministic return codes. For
+ * example, loaded name servers or races
+ * against network startup/validation (dhcp,
+ * ppp, etc) can cause the search to timeout
+ * on one search element, e.g. 'fu.bar.com',
+ * and return a definitive failure on the
+ * next search element, e.g. 'fu.'.
+ */
+ got_servfail++;
/* FALLTHROUGH */
default:
/* anything else implies that we're done */
@@ -316,6 +345,14 @@ res_nsearch(res_state statp,
}
}
+ switch (statp->res_h_errno) {
+ case NO_DATA:
+ case HOST_NOT_FOUND:
+ break;
+ default:
+ goto giveup;
+ }
+
/*
* If the query has not already been tried as is then try it
* unless RES_NOTLDQUERY is set and there were no dots.
@@ -335,6 +372,7 @@ res_nsearch(res_state statp,
* else send back meaningless H_ERRNO, that being the one from
* the last DNSRCH we did.
*/
+giveup:
if (saved_herrno != -1)
RES_SET_H_ERRNO(statp, saved_herrno);
else if (got_nodata)
@@ -401,6 +439,8 @@ res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
if (statp->options & RES_NOALIASES)
return (NULL);
+ if (issetugid())
+ return (NULL);
file = getenv("HOSTALIASES");
if (file == NULL || (fp = fopen(file, "r")) == NULL)
return (NULL);
diff --git a/lib/libc/resolv/res_send.c b/lib/libc/resolv/res_send.c
index 5be248932596..f31abf1327eb 100644
--- a/lib/libc/resolv/res_send.c
+++ b/lib/libc/resolv/res_send.c
@@ -72,14 +72,19 @@
static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: res_send.c,v 1.5.2.2.4.7 2005/08/15 02:04:41 marka Exp $";
#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
/*
* Send query to name server and wait for reply.
*/
#include "port_before.h"
+#ifndef USE_KQUEUE
#include "fd_setsize.h"
+#endif
+#include "namespace.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
@@ -103,12 +108,18 @@ static const char rcsid[] = "$Id: res_send.c,v 1.5.2.2.4.7 2005/08/15 02:04:41 m
#include "port_after.h"
+#ifdef USE_KQUEUE
+#include <sys/event.h>
+#else
#ifdef USE_POLL
#ifdef HAVE_STROPTS_H
#include <stropts.h>
#endif
#include <poll.h>
#endif /* USE_POLL */
+#endif
+
+#include "un-namespace.h"
/* Options. Leave them on. */
#define DEBUG
@@ -125,18 +136,22 @@ static int highestFD = 0;
/* Forward. */
-static int get_salen __P((const struct sockaddr *));
-static struct sockaddr * get_nsaddr __P((res_state, size_t));
+static int get_salen(const struct sockaddr *);
+static struct sockaddr * get_nsaddr(res_state, size_t);
static int send_vc(res_state, const u_char *, int,
u_char *, int, int *, int);
-static int send_dg(res_state, const u_char *, int,
+static int send_dg(res_state,
+#ifdef USE_KQUEUE
+ int kq,
+#endif
+ const u_char *, int,
u_char *, int, int *, int,
int *, int *);
static void Aerror(const res_state, FILE *, const char *, int,
const struct sockaddr *, int);
static void Perror(const res_state, FILE *, const char *, int);
static int sock_eq(struct sockaddr *, struct sockaddr *);
-#if defined(NEED_PSELECT) && !defined(USE_POLL)
+#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
static int pselect(int, void *, void *, void *,
struct timespec *,
const sigset_t *);
@@ -289,6 +304,9 @@ res_nsend(res_state statp,
const u_char *buf, int buflen, u_char *ans, int anssiz)
{
int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
+#ifdef USE_KQUEUE
+ int kq;
+#endif
char abuf[NI_MAXHOST];
#ifdef USE_POLL
@@ -309,6 +327,13 @@ res_nsend(res_state statp,
gotsomewhere = 0;
terrno = ETIMEDOUT;
+#ifdef USE_KQUEUE
+ if ((kq = kqueue()) < 0) {
+ Perror(statp, stderr, "kqueue", errno);
+ return (-1);
+ }
+#endif
+
/*
* If the ns_addr_list in the resolver context has changed, then
* invalidate our cached copy and the associated timing data.
@@ -332,7 +357,7 @@ res_nsend(res_state statp,
if (EXT(statp).nssocks[ns] == -1)
continue;
peerlen = sizeof(peer);
- if (getsockname(EXT(statp).nssocks[ns],
+ if (_getsockname(EXT(statp).nssocks[ns],
(struct sockaddr *)&peer, &peerlen) < 0) {
needclose++;
break;
@@ -424,6 +449,9 @@ res_nsend(res_state statp,
res_nclose(statp);
goto next_ns;
case res_done:
+#ifdef USE_KQUEUE
+ _close(kq);
+#endif
return (resplen);
case res_modified:
/* give the hook another try */
@@ -457,7 +485,11 @@ res_nsend(res_state statp,
resplen = n;
} else {
/* Use datagrams. */
- n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
+ n = send_dg(statp,
+#ifdef USE_KQUEUE
+ kq,
+#endif
+ buf, buflen, ans, anssiz, &terrno,
ns, &v_circuit, &gotsomewhere);
if (n < 0)
goto fail;
@@ -516,11 +548,17 @@ res_nsend(res_state statp,
} while (!done);
}
+#ifdef USE_KQUEUE
+ _close(kq);
+#endif
return (resplen);
next_ns: ;
} /*foreach ns*/
} /*foreach retry*/
res_nclose(statp);
+#ifdef USE_KQUEUE
+ _close(kq);
+#endif
if (!v_circuit) {
if (!gotsomewhere)
errno = ECONNREFUSED; /* no nameservers found */
@@ -531,6 +569,9 @@ res_nsend(res_state statp,
return (-1);
fail:
res_nclose(statp);
+#ifdef USE_KQUEUE
+ _close(kq);
+#endif
return (-1);
}
@@ -608,7 +649,7 @@ send_vc(res_state statp,
struct sockaddr_storage peer;
ISC_SOCKLEN_T size = sizeof peer;
- if (getpeername(statp->_vcsock,
+ if (_getpeername(statp->_vcsock,
(struct sockaddr *)&peer, &size) < 0 ||
!sock_eq((struct sockaddr *)&peer, nsap)) {
res_nclose(statp);
@@ -620,7 +661,7 @@ send_vc(res_state statp,
if (statp->_vcsock >= 0)
res_nclose(statp);
- statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
+ statp->_vcsock = _socket(nsap->sa_family, SOCK_STREAM, 0);
if (statp->_vcsock > highestFD) {
res_nclose(statp);
errno = ENOTSOCK;
@@ -641,7 +682,7 @@ send_vc(res_state statp,
}
}
errno = 0;
- if (connect(statp->_vcsock, nsap, nsaplen) < 0) {
+ if (_connect(statp->_vcsock, nsap, nsaplen) < 0) {
*terrno = errno;
Aerror(statp, stderr, "connect/vc", errno, nsap,
nsaplen);
@@ -658,7 +699,7 @@ send_vc(res_state statp,
iov[0] = evConsIovec(&len, INT16SZ);
DE_CONST(buf, tmp);
iov[1] = evConsIovec(tmp, buflen);
- if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
+ if (_writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
*terrno = errno;
Perror(statp, stderr, "write failed", errno);
res_nclose(statp);
@@ -670,7 +711,7 @@ send_vc(res_state statp,
read_len:
cp = ans;
len = INT16SZ;
- while ((n = read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
+ while ((n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
cp += n;
if ((len -= n) == 0)
break;
@@ -716,7 +757,8 @@ send_vc(res_state statp,
return (0);
}
cp = ans;
- while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
+ while (len != 0 &&
+ (n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
cp += n;
len -= n;
}
@@ -735,8 +777,8 @@ send_vc(res_state statp,
while (len != 0) {
char junk[PACKETSZ];
- n = read(statp->_vcsock, junk,
- (len > sizeof junk) ? sizeof junk : len);
+ n = _read(statp->_vcsock, junk,
+ (len > sizeof junk) ? sizeof junk : len);
if (n > 0)
len -= n;
else
@@ -767,6 +809,9 @@ send_vc(res_state statp,
static int
send_dg(res_state statp,
+#ifdef USE_KQUEUE
+ int kq,
+#endif
const u_char *buf, int buflen, u_char *ans, int anssiz,
int *terrno, int ns, int *v_circuit, int *gotsomewhere)
{
@@ -778,17 +823,22 @@ send_dg(res_state statp,
struct sockaddr_storage from;
ISC_SOCKLEN_T fromlen;
int resplen, seconds, n, s;
+#ifdef USE_KQUEUE
+ struct kevent kv;
+#else
#ifdef USE_POLL
int polltimeout;
struct pollfd pollfd;
#else
fd_set dsmask;
#endif
+#endif
nsap = get_nsaddr(statp, ns);
nsaplen = get_salen(nsap);
if (EXT(statp).nssocks[ns] == -1) {
- EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0);
+ EXT(statp).nssocks[ns] = _socket(nsap->sa_family,
+ SOCK_DGRAM, 0);
if (EXT(statp).nssocks[ns] > highestFD) {
res_nclose(statp);
errno = ENOTSOCK;
@@ -819,8 +869,16 @@ send_dg(res_state statp,
* socket operation, and select returns if the
* error message is received. We can thus detect
* the absence of a nameserver without timing out.
+ *
+ * When the option "insecure1" is specified, we'd
+ * rather expect to see responses from an "unknown"
+ * address. In order to let the kernel accept such
+ * responses, do not connect the socket here.
+ * XXX: or do we need an explicit option to disable
+ * connecting?
*/
- if (connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
+ if (!(statp->options & RES_INSECURE1) &&
+ _connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
Aerror(statp, stderr, "connect(dg)", errno, nsap,
nsaplen);
res_nclose(statp);
@@ -832,13 +890,20 @@ send_dg(res_state statp,
}
s = EXT(statp).nssocks[ns];
#ifndef CANNOT_CONNECT_DGRAM
- if (send(s, (const char*)buf, buflen, 0) != buflen) {
+ if (statp->options & RES_INSECURE1) {
+ if (_sendto(s,
+ (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) {
+ Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
+ res_nclose(statp);
+ return (0);
+ }
+ } else if (send(s, (const char*)buf, buflen, 0) != buflen) {
Perror(statp, stderr, "send", errno);
res_nclose(statp);
return (0);
}
#else /* !CANNOT_CONNECT_DGRAM */
- if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
+ if (_sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
{
Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
res_nclose(statp);
@@ -862,13 +927,18 @@ send_dg(res_state statp,
now = evNowTime();
nonow:
#ifndef USE_POLL
- FD_ZERO(&dsmask);
- FD_SET(s, &dsmask);
if (evCmpTime(finish, now) > 0)
timeout = evSubTime(finish, now);
else
timeout = evConsTime(0, 0);
+#ifdef USE_KQUEUE
+ EV_SET(&kv, s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
+ n = _kevent(kq, &kv, 1, &kv, 1, &timeout);
+#else
+ FD_ZERO(&dsmask);
+ FD_SET(s, &dsmask);
n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
+#endif
#else
timeout = evSubTime(finish, now);
if (timeout.tv_sec < 0)
@@ -888,17 +958,21 @@ send_dg(res_state statp,
if (n < 0) {
if (errno == EINTR)
goto wait;
+#ifdef USE_KQUEUE
+ Perror(statp, stderr, "kevent", errno);
+#else
#ifndef USE_POLL
Perror(statp, stderr, "select", errno);
#else
Perror(statp, stderr, "poll", errno);
#endif /* USE_POLL */
+#endif
res_nclose(statp);
return (0);
}
errno = 0;
fromlen = sizeof(from);
- resplen = recvfrom(s, (char*)ans, anssiz,0,
+ resplen = _recvfrom(s, (char*)ans, anssiz,0,
(struct sockaddr *)&from, &fromlen);
if (resplen <= 0) {
Perror(statp, stderr, "recvfrom", errno);
@@ -1061,7 +1135,7 @@ sock_eq(struct sockaddr *a, struct sockaddr *b) {
}
}
-#if defined(NEED_PSELECT) && !defined(USE_POLL)
+#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
/* XXX needs to move to the porting library. */
static int
pselect(int nfds, void *rfds, void *wfds, void *efds,
diff --git a/lib/libc/resolv/res_state.c b/lib/libc/resolv/res_state.c
new file mode 100644
index 000000000000..542dba824055
--- /dev/null
+++ b/lib/libc/resolv/res_state.c
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 2006 The FreeBSD Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <stdlib.h>
+
+#include "namespace.h"
+#include "reentrant.h"
+#include "un-namespace.h"
+
+#undef _res
+
+struct __res_state _res;
+
+static thread_key_t res_key;
+static once_t res_init_once = ONCE_INITIALIZER;
+static int res_thr_keycreated = 0;
+
+static void
+free_res(void *ptr)
+{
+ res_state statp = ptr;
+
+ if (statp->options & RES_INIT)
+ res_ndestroy(statp);
+ free(statp);
+}
+
+static void
+res_keycreate(void)
+{
+ res_thr_keycreated = thr_keycreate(&res_key, free_res) == 0;
+}
+
+res_state
+__res_state(void)
+{
+ res_state statp;
+
+ if (thr_main() != 0)
+ return (&_res);
+
+ if (thr_once(&res_init_once, res_keycreate) != 0 ||
+ !res_thr_keycreated)
+ return (&_res);
+
+ statp = thr_getspecific(res_key);
+ if (statp != NULL)
+ return (statp);
+ statp = calloc(1, sizeof(*statp));
+ if (statp == NULL)
+ return (&_res);
+#ifdef __BIND_RES_TEXT
+ statp->options = RES_TIMEOUT; /* Motorola, et al. */
+#endif
+ if (thr_setspecific(res_key, statp) == 0)
+ return (statp);
+ free(statp);
+ return (&_res);
+}
+
+/* binary backward compatibility for FreeBSD 5.x and 6.x */
+struct __res_state_ext *
+___res_ext(void)
+{
+ return (__res_state()->_u._ext.ext);
+}
+
+__weak_reference(__res_state, ___res);