+2129. [func] Provide a pool of UDP sockets for queries to be
+ made over. See use-queryport-pool, queryport-pool-ports
+ and queryport-pool-updateinterval. [RT #16415]
+
2128. [doc] xsltproc --nonet, update DTD versions. [RT #16635]
2127. [port] Improved OpenSSL 0.9.8 support. [RT #16563]
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: interfacemgr.c,v 1.85 2006/07/20 01:10:31 marka Exp $ */
+/* $Id: interfacemgr.c,v 1.86 2007/02/02 02:18:03 marka Exp $ */
/*! \file */
(void)dns_acl_match(&listen_netaddr,
NULL, ele->acl,
NULL, &match, NULL);
- if (match > 0 && ele->port == le->port)
+ if (match > 0 &&
+ (ele->port == le->port ||
+ ele->port == 0))
break;
else
match = 0;
- PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- $Id: named.conf.docbook,v 1.26 2007/01/29 23:57:22 marka Exp $ -->
+<!-- $Id: named.conf.docbook,v 1.27 2007/02/02 02:18:04 marka Exp $ -->
<refentry>
<refentryinfo>
<date>Aug 13, 2004</date>
additional-from-cache <replaceable>boolean</replaceable>;
query-source ( ( <replaceable>ipv4_address</replaceable> | * ) | <optional> address ( <replaceable>ipv4_address</replaceable> | * ) </optional> ) <optional> port ( <replaceable>integer</replaceable> | * ) </optional>;
query-source-v6 ( ( <replaceable>ipv6_address</replaceable> | * ) | <optional> address ( <replaceable>ipv6_address</replaceable> | * ) </optional> ) <optional> port ( <replaceable>integer</replaceable> | * ) </optional>;
+ use-queryport-pool <replaceable>boolean</replaceable>;
+ queryport-pool-ports <replaceable>integer</replaceable>;
+ queryport-pool-updateinterval <replaceable>integer</replaceable>;
cleaning-interval <replaceable>integer</replaceable>;
min-roots <replaceable>integer</replaceable>; // not implemented
lame-ttl <replaceable>integer</replaceable>;
additional-from-cache <replaceable>boolean</replaceable>;
query-source ( ( <replaceable>ipv4_address</replaceable> | * ) | <optional> address ( <replaceable>ipv4_address</replaceable> | * ) </optional> ) <optional> port ( <replaceable>integer</replaceable> | * ) </optional>;
query-source-v6 ( ( <replaceable>ipv6_address</replaceable> | * ) | <optional> address ( <replaceable>ipv6_address</replaceable> | * ) </optional> ) <optional> port ( <replaceable>integer</replaceable> | * ) </optional>;
+ use-queryport-pool <replaceable>boolean</replaceable>;
+ queryport-pool-ports <replaceable>integer</replaceable>;
+ queryport-pool-updateinterval <replaceable>integer</replaceable>;
cleaning-interval <replaceable>integer</replaceable>;
min-roots <replaceable>integer</replaceable>; // not implemented
lame-ttl <replaceable>integer</replaceable>;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: server.c,v 1.475 2007/01/12 00:14:51 marka Exp $ */
+/* $Id: server.c,v 1.476 2007/02/02 02:18:05 marka Exp $ */
/*! \file */
const char *str;
dns_order_t *order = NULL;
isc_uint32_t udpsize;
- unsigned int check = 0;
+ unsigned int resopts = 0;
dns_zone_t *zone = NULL;
isc_uint32_t max_clients_per_query;
const char *sep = ": view ";
isc_boolean_t rfc1918;
isc_boolean_t empty_zones_enable;
const cfg_obj_t *disablelist = NULL;
+ isc_uint32_t nqports, qports_updateinterval;
REQUIRE(DNS_VIEW_VALID(view));
str = cfg_obj_asstring(obj);
if (strcasecmp(str, "fail") == 0) {
- check = DNS_RESOLVER_CHECKNAMES |
+ resopts |= DNS_RESOLVER_CHECKNAMES |
DNS_RESOLVER_CHECKNAMESFAIL;
view->checknames = ISC_TRUE;
} else if (strcasecmp(str, "warn") == 0) {
- check = DNS_RESOLVER_CHECKNAMES;
+ resopts |= DNS_RESOLVER_CHECKNAMES;
view->checknames = ISC_FALSE;
} else if (strcasecmp(str, "ignore") == 0) {
- check = 0;
view->checknames = ISC_FALSE;
} else
INSIST(0);
result = ISC_R_UNEXPECTED;
goto cleanup;
}
+
+ obj = NULL;
+ (void)ns_config_get(maps, "use-queryport-pool", &obj);
+ if (obj == NULL || cfg_obj_asboolean(obj)) {
+ isc_sockaddr_t sa;
+ isc_boolean_t logit4 = ISC_FALSE, logit6 = ISC_FALSE;
+
+ resopts |= (DNS_RESOLVER_USEDISPATCHPOOL4 |
+ DNS_RESOLVER_USEDISPATCHPOOL6);
+
+ /* Check consistency with query-source(-v6) */
+ if (dispatch4 == NULL)
+ resopts &= ~DNS_RESOLVER_USEDISPATCHPOOL4;
+ else {
+ result = dns_dispatch_getlocaladdress(dispatch4, &sa);
+ INSIST(result == ISC_R_SUCCESS);
+ if (isc_sockaddr_getport(&sa) != 0) {
+ logit4 = ISC_TRUE;
+ resopts &= ~DNS_RESOLVER_USEDISPATCHPOOL4;
+ }
+ }
+
+ if (dispatch6 == NULL)
+ resopts &= ~DNS_RESOLVER_USEDISPATCHPOOL6;
+ else {
+ result = dns_dispatch_getlocaladdress(dispatch6, &sa);
+ INSIST(result == ISC_R_SUCCESS);
+ if (isc_sockaddr_getport(&sa) != 0) {
+ logit6 = ISC_TRUE;
+ resopts &= ~DNS_RESOLVER_USEDISPATCHPOOL6;
+ }
+ }
+ if (logit4 && obj != NULL)
+ cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
+ "specific query-source port "
+ "cannot coexist with queryport-pool. "
+ "(Pool disabled)");
+ if (logit6 && obj != NULL)
+ cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
+ "specific query-source-v6 port "
+ "cannot coexist with queryport-pool. "
+ "(Pool disabled)");
+ }
+
CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31,
ns_g_socketmgr, ns_g_timermgr,
- check, ns_g_dispatchmgr,
+ resopts, ns_g_dispatchmgr,
dispatch4, dispatch6));
+ /*
+ * Query-port pool parameters.
+ */
+ obj = NULL;
+ nqports = 8;
+ result = ns_config_get(maps, "queryport-pool-ports", &obj);
+ if (result == ISC_R_SUCCESS) {
+ if ((resopts & (DNS_RESOLVER_USEDISPATCHPOOL4 |
+ DNS_RESOLVER_USEDISPATCHPOOL6)) == 0) {
+ cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
+ "queryport-pool-ports is effective only "
+ "with 'use-queryport-pool yes' (ignored)");
+ } else
+ nqports = cfg_obj_asuint32(obj);
+ }
+
+ obj = NULL;
+ qports_updateinterval = 15;
+ result = ns_config_get(maps, "queryport-pool-updateinterval", &obj);
+ if (result == ISC_R_SUCCESS) {
+ if ((resopts & (DNS_RESOLVER_USEDISPATCHPOOL4 |
+ DNS_RESOLVER_USEDISPATCHPOOL6)) == 0) {
+ cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
+ "queryport-pool-updateinterval is "
+ "effective only with 'use-queryport-pool "
+ "yes' (ignored)");
+ } else
+ qports_updateinterval = cfg_obj_asuint32(obj);
+ }
+
+ if ((resopts & (DNS_RESOLVER_USEDISPATCHPOOL4 |
+ DNS_RESOLVER_USEDISPATCHPOOL6)) != 0) {
+ CHECK(dns_resolver_createdispatchpool(view->resolver,
+ nqports,
+ qports_updateinterval
+ * 60));
+ }
+
/*
* Set the ADB cache size to 1/8th of the max-cache-size.
*/
result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj);
INSIST(result == ISC_R_SUCCESS);
dns_resolver_setzeronosoattl(view->resolver, cfg_obj_asboolean(obj));
-
+
/*
* Set the resolver's EDNS UDP size.
*/
}
static isc_result_t
-add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr) {
+add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr,
+ isc_boolean_t wcardport_ok)
+{
ns_listenelt_t *lelt = NULL;
dns_acl_t *src_acl = NULL;
dns_aclelement_t aelt;
REQUIRE(isc_sockaddr_pf(addr) == AF_INET6);
isc_sockaddr_any6(&any_sa6);
- if (!isc_sockaddr_equal(&any_sa6, addr)) {
+ if (!isc_sockaddr_equal(&any_sa6, addr) &&
+ (wcardport_ok || isc_sockaddr_getport(addr) != 0)) {
aelt.type = dns_aclelementtype_ipprefix;
aelt.negative = ISC_FALSE;
aelt.u.ip_prefix.prefixlen = 128;
view != NULL;
view = ISC_LIST_NEXT(view, link)) {
dns_dispatch_t *dispatch6;
+ isc_boolean_t use_portpool = ISC_FALSE;
+ unsigned int resopts;
dispatch6 = dns_resolver_dispatchv6(view->resolver);
if (dispatch6 == NULL)
result = dns_dispatch_getlocaladdress(dispatch6, &addr);
if (result != ISC_R_SUCCESS)
goto fail;
- result = add_listenelt(mctx, list, &addr);
+ resopts = dns_resolver_getoptions(view->resolver);
+ if ((resopts & (DNS_RESOLVER_USEDISPATCHPOOL4 |
+ DNS_RESOLVER_USEDISPATCHPOOL6)) != 0) {
+ /*
+ * If the resolver uses a dynamic pool of query ports
+ * with a specific source address, some of the current
+ * and future ports may override an existing wildcard
+ * IPv6 port. So we need to allow wildcard match
+ * in this case.
+ */
+ use_portpool = ISC_TRUE;
+ }
+ result = add_listenelt(mctx, list, &addr, use_portpool);
if (result != ISC_R_SUCCESS)
goto fail;
}
continue;
addrp = dns_zone_getnotifysrc6(zone);
- result = add_listenelt(mctx, list, addrp);
+ result = add_listenelt(mctx, list, addrp, ISC_FALSE);
if (result != ISC_R_SUCCESS)
goto fail;
addrp = dns_zone_getxfrsource6(zone);
- result = add_listenelt(mctx, list, addrp);
+ result = add_listenelt(mctx, list, addrp, ISC_FALSE);
if (result != ISC_R_SUCCESS)
goto fail;
}
- PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- File: $Id: Bv9ARM-book.xml,v 1.312 2007/01/29 23:57:22 marka Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.313 2007/02/02 02:18:05 marka Exp $ -->
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<title>BIND 9 Administrator Reference Manual</title>
<optional> port ( <replaceable>ip_port</replaceable> | <replaceable>*</replaceable> ) </optional> |
<optional> address ( <replaceable>ip6_addr</replaceable> | <replaceable>*</replaceable> ) </optional>
<optional> port ( <replaceable>ip_port</replaceable> | <replaceable>*</replaceable> ) </optional> ) ; </optional>
+ <optional> use-queryport-pool <replaceable>yse_or_no</replaceable>; </optional>
+ <optional> queryport-pool-ports <replaceable>number</replaceable>; </optional>
+ <optional> queryport-pool-interval <replaceable>number</replaceable>; </optional>
<optional> max-transfer-time-in <replaceable>number</replaceable>; </optional>
<optional> max-transfer-time-out <replaceable>number</replaceable>; </optional>
<optional> max-transfer-idle-in <replaceable>number</replaceable>; </optional>
</para>
</sect3>
- <sect3>
+ <sect3 id="query_address">
<title>Query Address</title>
<para>
If the server doesn't know the answer to a question, it will
a wildcard IP address (<command>INADDR_ANY</command>)
will be used.
If <command>port</command> is <command>*</command> or is omitted,
- a random unprivileged port will be used. The <command>avoid-v4-udp-ports</command>
+ a pool of random unprivileged port will be used. See
+ <command>use-queryport-pool</command>,
+ <command>queryport-pool-ports</command> and
+ <command>queryport-pool-updateinterval</command> for how the pool
+ is configured.
+ The <command>avoid-v4-udp-ports</command>
and <command>avoid-v6-udp-ports</command> options can be used
to prevent named
- from selecting certain ports. The defaults are:
+ from selecting certain ports.
+ The defaults are:
</para>
<programlisting>query-source address * port *;
query-source-v6 address * port *;
</programlisting>
+ <variablelist>
+ <varlistentry>
+ <term><command>use-queryport-pool</command></term>
+ <listitem>
+ <para>
+ Enable they use of query port pools. By default query port
+ pools are enabled unless there is a explicit port defined
+ in <command>query-source</command> or
+ <command>query-source-v6</command>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>queryport-pool-ports</command></term>
+ <listitem>
+ <para>
+ Specify how many pool ports to use. The default is 8.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>queryport-pool-updateinterval</command></term>
+ <listitem>
+ <para>
+ Specify how often, in minutes, that the queryport pool
+ should be recreated (new ports selected). The default
+ is 15 minutes.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
<note>
<para>
The address specified in the <command>query-source</command> option
is used for both UDP and TCP queries, but the port applies only
- to
- UDP queries. TCP queries always use a random
+ to UDP queries. TCP queries always use a random
unprivileged port.
</para>
</note>
<optional> query-source <optional> address ( <replaceable>ip_addr</replaceable> | <replaceable>*</replaceable> ) </optional> <optional> port ( <replaceable>ip_port</replaceable> | <replaceable>*</replaceable> ) </optional>; </optional>
<optional> query-source-v6 <optional> address ( <replaceable>ip_addr</replaceable> | <replaceable>*</replaceable> ) </optional> <optional> port ( <replaceable>ip_port</replaceable> | <replaceable>*</replaceable> ) </optional>; </optional>
};
+ <optional> use-queryport-pool <replaceable>yse_or_no</replaceable>; </optional>
+ <optional> queryport-pool-ports <replaceable>number</replaceable>; </optional>
+ <optional> queryport-pool-interval <replaceable>number</replaceable>; </optional>
</programlisting>
</sect2>
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dispatch.c,v 1.127 2006/07/19 00:42:13 marka Exp $ */
+/* $Id: dispatch.c,v 1.128 2007/02/02 02:18:06 marka Exp $ */
/*! \file */
lfsr->state = random();
}
+/*
+ * Return an unpredictable non-reserved UDP port. We share the QID
+ * framework for this purpose.
+ */
+static in_port_t
+get_randomport(dns_qid_t *qid) {
+ isc_uint32_t p;
+
+ p = isc_lfsr_generate32(&qid->qid_lfsr1, &qid->qid_lfsr2);
+
+ /* XXX: should the range be configurable? */
+ return ((in_port_t)(1024 + (p % (65535 - 1024))));
+}
+
/*
* Return an unpredictable message ID.
*/
}
static isc_boolean_t
-blacklisted(dns_dispatchmgr_t *mgr, isc_socket_t *sock) {
+blacklisted(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
+ isc_sockaddr_t *sockaddrp)
+{
isc_sockaddr_t sockaddr;
isc_result_t result;
+ REQUIRE(sock != NULL || sockaddrp != NULL);
+
if (mgr->portlist == NULL)
return (ISC_FALSE);
- result = isc_socket_getsockname(sock, &sockaddr);
- if (result != ISC_R_SUCCESS)
- return (ISC_FALSE);
+ if (sock != NULL) {
+ sockaddrp = &sockaddr;
+ result = isc_socket_getsockname(sock, sockaddrp);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_FALSE);
+ }
- if (mgr->portlist != NULL &&
- dns_portlist_match(mgr->portlist, isc_sockaddr_pf(&sockaddr),
- isc_sockaddr_getport(&sockaddr)))
+ if (dns_portlist_match(mgr->portlist, isc_sockaddr_pf(sockaddrp),
+ isc_sockaddr_getport(sockaddrp)))
return (ISC_TRUE);
return (ISC_FALSE);
}
if (disp->mgr->portlist != NULL &&
isc_sockaddr_getport(addr) == 0 &&
isc_sockaddr_getport(&disp->local) == 0 &&
- blacklisted(disp->mgr, disp->socket))
+ blacklisted(disp->mgr, disp->socket, NULL))
return (ISC_FALSE);
/*
dns_dispatch_t **dispp)
{
isc_result_t result;
- dns_dispatch_t *disp;
+ dns_dispatch_t *disp = NULL;
REQUIRE(VALID_DISPATCHMGR(mgr));
REQUIRE(sockmgr != NULL);
LOCK(&mgr->lock);
+ if ((attributes & DNS_DISPATCHATTR_RANDOMPORT) != 0) {
+ REQUIRE(isc_sockaddr_getport(localaddr) == 0);
+ goto createudp;
+ }
+
/*
- * First, see if we have a dispatcher that matches.
+ * See if we have a dispatcher that matches.
*/
- disp = NULL;
result = dispatch_find(mgr, localaddr, attributes, mask, &disp);
if (result == ISC_R_SUCCESS) {
disp->refcount++;
return (ISC_R_SUCCESS);
}
+ createudp:
/*
* Nope, create one.
*/
dns_dispatch_t *disp;
isc_socket_t *sock = NULL;
isc_socket_t *held[DNS_DISPATCH_HELD];
- unsigned int i = 0, j = 0;
+ unsigned int i = 0, j = 0, k = 0;
+ isc_sockaddr_t localaddr_bound;
/*
* dispatch_allocate() checks mgr for us.
* from returning the same port to us too quickly.
*/
memset(held, 0, sizeof(held));
+ localaddr_bound = *localaddr;
getsocket:
- result = create_socket(sockmgr, localaddr, &sock);
+ if ((attributes & DNS_DISPATCHATTR_RANDOMPORT) != 0) {
+ isc_sockaddr_setport(&localaddr_bound,
+ get_randomport(mgr->qid));
+ if (blacklisted(mgr, NULL, &localaddr_bound)) {
+ if (++k == 1024)
+ attributes &= ~DNS_DISPATCHATTR_RANDOMPORT;
+ goto getsocket;
+ }
+ result = create_socket(sockmgr, &localaddr_bound, &sock);
+ if (result == ISC_R_ADDRINUSE) {
+ if (++k == 1024)
+ attributes &= ~DNS_DISPATCHATTR_RANDOMPORT;
+ goto getsocket;
+ }
+ } else
+ result = create_socket(sockmgr, localaddr, &sock);
if (result != ISC_R_SUCCESS)
goto deallocate_dispatch;
- if (isc_sockaddr_getport(localaddr) == 0 && blacklisted(mgr, sock)) {
+ if ((attributes & DNS_DISPATCHATTR_RANDOMPORT) == 0 &&
+ isc_sockaddr_getport(localaddr) == 0 &&
+ blacklisted(mgr, sock, NULL))
+ {
if (held[i] != NULL)
isc_socket_detach(&held[i]);
held[i++] = sock;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dispatch.h,v 1.52 2006/12/22 01:59:43 marka Exp $ */
+/* $Id: dispatch.h,v 1.53 2007/02/02 02:18:06 marka Exp $ */
#ifndef DNS_DISPATCH_H
#define DNS_DISPATCH_H 1
* _MAKEQUERY
* The dispatcher can be used to issue queries to other servers, and
* accept replies from them.
+ *
+ * _RANDOMPORT
+ * TBD
*/
#define DNS_DISPATCHATTR_PRIVATE 0x00000001U
#define DNS_DISPATCHATTR_TCP 0x00000002U
#define DNS_DISPATCHATTR_NOLISTEN 0x00000020U
#define DNS_DISPATCHATTR_MAKEQUERY 0x00000040U
#define DNS_DISPATCHATTR_CONNECTED 0x00000080U
+#define DNS_DISPATCHATTR_RANDOMPORT 0x00000100U
/*@}*/
isc_result_t
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: resolver.h,v 1.53 2006/12/22 01:45:00 marka Exp $ */
+/* $Id: resolver.h,v 1.54 2007/02/02 02:18:06 marka Exp $ */
#ifndef DNS_RESOLVER_H
#define DNS_RESOLVER_H 1
#define DNS_RESOLVER_CHECKNAMES 0x01
#define DNS_RESOLVER_CHECKNAMESFAIL 0x02
+#define DNS_RESOLVER_USEDISPATCHPOOL4 0x04
+#define DNS_RESOLVER_USEDISPATCHPOOL6 0x08
isc_result_t
dns_resolver_create(dns_view_t *view,
*\li Generally, applications should not create a resolver directly, but
* should instead call dns_view_createresolver().
*
- *\li No options are currently defined.
- *
* Requires:
*
*\li 'view' is a valid view.
void
dns_resolver_setzeronosoattl(dns_resolver_t *resolver, isc_boolean_t state);
+unsigned int
+dns_resolver_getoptions(dns_resolver_t *resolver);
+
+isc_result_t
+dns_resolver_createdispatchpool(dns_resolver_t *res, unsigned int ndisps,
+ unsigned int interval);
+/*%<
+ * Create a pool of dispatches
+ *
+ * Notes:
+ *
+ *\li Generally, applications should not create a resolver directly, but
+ * should instead call dns_view_createresolver().
+ *
+ * Requires:
+ *
+ *\li 'res' is a valid resolver that has not been frozen. Also it must have
+ * either the _USEDISPATCHPOOL4 or _USEDISPATCHPOOL6 option.
+ *
+ *\li 'taskmgr' is a valid task manager.
+ *
+ *\li 'ndisps' > 0.
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS On success.
+ *
+ *\li Anything else Failure.
+ */
+
ISC_LANG_ENDDECLS
#endif /* DNS_RESOLVER_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: resolver.c,v 1.340 2007/01/08 01:13:38 marka Exp $ */
+/* $Id: resolver.c,v 1.341 2007/02/02 02:18:06 marka Exp $ */
/*! \file */
#include <isc/print.h>
#include <isc/string.h>
+#include <isc/random.h>
#include <isc/task.h>
#include <isc/timer.h>
#include <isc/util.h>
ISC_LINK(struct alternate) link;
} alternate_t;
+#ifdef ISC_RWLOCK_USEATOMIC
+#define DNS_RESOLVER_USERWLOCK 1
+#else
+#define DNS_RESOLVER_USERWLOCK 0
+#endif
+
+#if DNS_RESOLVER_USERWLOCK
+#define RES_INITLOCK(l) isc_rwlock_init((l), 0, 0)
+#define RES_DESTROYLOCK(l) isc_rwlock_destroy(l)
+#define RES_LOCK(l, t) RWLOCK((l), (t))
+#define RES_UNLOCK(l, t) RWUNLOCK((l), (t))
+#else
+#define RES_INITLOCK(l) isc_mutex_init(l)
+#define RES_DESTROYLOCK(l) DESTROYLOCK(l)
+#define RES_LOCK(l, t) LOCK(l)
+#define RES_UNLOCK(l, t) UNLOCK(l)
+#endif
+
struct dns_resolver {
/* Unlocked. */
unsigned int magic;
isc_mem_t * mctx;
isc_mutex_t lock;
isc_mutex_t nlock;
- isc_mutex_t primelock;
+ isc_mutex_t primelock;
+#if DNS_RESOLVER_USERWLOCK
+ isc_rwlock_t poollock;
+#else
+ isc_mutex_t poollock;
+#endif
dns_rdataclass_t rdclass;
isc_socketmgr_t * socketmgr;
isc_timermgr_t * timermgr;
dns_dispatchmgr_t * dispatchmgr;
dns_dispatch_t * dispatchv4;
dns_dispatch_t * dispatchv6;
+ unsigned int ndisps;
unsigned int nbuckets;
fctxbucket_t * buckets;
isc_uint32_t lame_ttl;
unsigned int spillatmin;
isc_timer_t * spillattimer;
isc_boolean_t zero_no_soa_ttl;
+ isc_timer_t * disppooltimer;
/* Locked by lock. */
unsigned int references;
isc_boolean_t exiting;
unsigned int activebuckets;
isc_boolean_t priming;
unsigned int spillat;
+ unsigned int nextdisp;
/* Locked by primelock. */
dns_fetch_t * primefetch;
/* Locked by nlock. */
unsigned int nfctx;
+ /* Locked by poollock. */
+ dns_dispatch_t ** dispatchv4pool;
+ dns_dispatch_t ** dispatchv6pool;
};
#define RES_MAGIC ISC_MAGIC('R', 'e', 's', '!')
if (result != ISC_R_SUCCESS)
goto cleanup_query;
} else {
+ int did = 0;
+ isc_uint32_t val;
+
+ if (res->ndisps > 0) {
+ isc_random_get(&val);
+ did = val % res->ndisps;
+ }
switch (isc_sockaddr_pf(&addrinfo->sockaddr)) {
case PF_INET:
- dns_dispatch_attach(res->dispatchv4,
- &query->dispatch);
+ if (res->ndisps > 0) {
+ RES_LOCK(&res->poollock,
+ isc_rwlocktype_read);
+ dns_dispatch_attach(res->dispatchv4pool[did],
+ &query->dispatch);
+ RES_UNLOCK(&res->poollock,
+ isc_rwlocktype_read);
+ } else {
+ dns_dispatch_attach(res->dispatchv4,
+ &query->dispatch);
+ }
break;
case PF_INET6:
- dns_dispatch_attach(res->dispatchv6,
- &query->dispatch);
+ if (res->ndisps > 0) {
+ RES_LOCK(&res->poollock,
+ isc_rwlocktype_read);
+ dns_dispatch_attach(res->dispatchv6pool[did],
+ &query->dispatch);
+ RES_UNLOCK(&res->poollock,
+ isc_rwlocktype_read);
+ } else {
+ dns_dispatch_attach(res->dispatchv6,
+ &query->dispatch);
+ }
break;
default:
result = ISC_R_NOTIMPLEMENTED;
INSIST(res->nfctx == 0);
+ RES_DESTROYLOCK(&res->poollock);
DESTROYLOCK(&res->primelock);
DESTROYLOCK(&res->nlock);
DESTROYLOCK(&res->lock);
dns_dispatch_detach(&res->dispatchv4);
if (res->dispatchv6 != NULL)
dns_dispatch_detach(&res->dispatchv6);
+ if (res->dispatchv4pool != NULL) {
+ for (i = 0; i < res->ndisps; i++)
+ dns_dispatch_detach(&res->dispatchv4pool[i]);
+ isc_mem_put(res->mctx, res->dispatchv4pool,
+ res->ndisps * sizeof(dns_dispatch_t *));
+ }
+ if (res->dispatchv6pool != NULL) {
+ for (i = 0; i < res->ndisps; i++)
+ dns_dispatch_detach(&res->dispatchv6pool[i]);
+ isc_mem_put(res->mctx, res->dispatchv6pool,
+ res->ndisps * sizeof(dns_dispatch_t *));
+ }
while ((a = ISC_LIST_HEAD(res->alternates)) != NULL) {
ISC_LIST_UNLINK(res->alternates, a, link);
if (!a->isaddress)
dns_name_free(&a->_u._n.name, res->mctx);
isc_mem_put(res->mctx, a, sizeof(*a));
}
+ if (res->disppooltimer != NULL)
+ isc_timer_detach(&res->disppooltimer);
dns_resolver_reset_algorithms(res);
dns_resolver_resetmustbesecure(res);
#if USE_ALGLOCK
res->spillatmax = 100;
res->spillattimer = NULL;
res->zero_no_soa_ttl = ISC_FALSE;
+ res->ndisps = 0;
+ res->nextdisp = 0; /* meaningless at this point, but init it */
+ res->dispatchv4pool = NULL;
+ res->dispatchv6pool = NULL;
+ res->disppooltimer = NULL;
res->nbuckets = ntasks;
res->activebuckets = ntasks;
res->dispatchv4 = NULL;
if (dispatchv4 != NULL)
- dns_dispatch_attach(dispatchv4, &res->dispatchv4);
+ dns_dispatch_attach(dispatchv4, &res->dispatchv4);
+
res->dispatchv6 = NULL;
if (dispatchv6 != NULL)
dns_dispatch_attach(dispatchv6, &res->dispatchv6);
if (result != ISC_R_SUCCESS)
goto cleanup_nlock;
+ result = RES_INITLOCK(&res->poollock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_primelock;
+
task = NULL;
result = isc_task_create(taskmgr, 0, &task);
if (result != ISC_R_SUCCESS)
- goto cleanup_primelock;
+ goto cleanup_poollock;
result = isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL,
task, spillattimer_countdown, res,
&res->spillattimer);
isc_task_detach(&task);
if (result != ISC_R_SUCCESS)
- goto cleanup_primelock;
+ goto cleanup_poollock;
#if USE_ALGLOCK
result = isc_rwlock_init(&res->alglock, 0, 0);
isc_timer_detach(&res->spillattimer);
#endif
+ cleanup_poollock:
+ RES_DESTROYLOCK(&res->poollock);
+
cleanup_primelock:
DESTROYLOCK(&res->primelock);
resolver->zero_no_soa_ttl = state;
}
+
+unsigned int
+dns_resolver_getoptions(dns_resolver_t *resolver) {
+ REQUIRE(VALID_RESOLVER(resolver));
+
+ return (resolver->options);
+}
+
+static void
+disppooltimer_update(isc_task_t *task, isc_event_t *event) {
+ dns_resolver_t *res = event->ev_arg;
+ isc_sockaddr_t addr4, addr6;
+ dns_dispatch_t *disp4, *disp6;
+ isc_result_t result;
+ unsigned int nxt;
+ unsigned int attrs_base, attrs, attrmask;
+
+ REQUIRE(VALID_RESOLVER(res));
+ REQUIRE((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0 ||
+ (res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0);
+
+ UNUSED(task);
+ isc_event_free(&event);
+
+ LOCK(&res->lock);
+ nxt = res->nextdisp++;
+ if (res->nextdisp == res->ndisps)
+ res->nextdisp = 0;
+ UNLOCK(&res->lock);
+
+ attrs_base = 0;
+ attrs_base |= DNS_DISPATCHATTR_UDP;
+ attrs_base |= DNS_DISPATCHATTR_RANDOMPORT;
+
+ attrmask = 0;
+ attrmask |= DNS_DISPATCHATTR_UDP;
+ attrmask |= DNS_DISPATCHATTR_TCP;
+ attrmask |= DNS_DISPATCHATTR_IPV4;
+ attrmask |= DNS_DISPATCHATTR_IPV6;
+
+ RES_LOCK(&res->poollock, isc_rwlocktype_read);
+ if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0) {
+ result = dns_dispatch_getlocaladdress(res->dispatchv4pool[nxt],
+ &addr4);
+ INSIST(result == ISC_R_SUCCESS);
+ }
+ if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0) {
+ result = dns_dispatch_getlocaladdress(res->dispatchv6pool[nxt],
+ &addr6);
+ INSIST(result == ISC_R_SUCCESS);
+ }
+ RES_UNLOCK(&res->poollock, isc_rwlocktype_read);
+
+ if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0) {
+ attrs = attrs_base;
+ attrs |= DNS_DISPATCHATTR_IPV4;
+
+ disp4 = NULL;
+ result = dns_dispatch_getudp(res->dispatchmgr,
+ res->socketmgr,
+ res->taskmgr, &addr4,
+ 4096, 1000, 32768, 16411,
+ 16433, attrs, attrmask,
+ &disp4);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_ERROR,
+ "could not update an IPv4 random query "
+ "port: %s",
+ isc_result_totext(result));
+ /* keep the old one */
+ }
+
+ /*
+ * We don't try to ensure the new dispatch is unique (see the
+ * comments in dns_resolver_createdispatchpool()).
+ */
+ }
+ if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0) {
+ attrs = attrs_base;
+ attrs |= DNS_DISPATCHATTR_IPV6;
+
+ disp6 = NULL;
+ result = dns_dispatch_getudp(res->dispatchmgr,
+ res->socketmgr,
+ res->taskmgr, &addr6,
+ 4096, 1000, 32768, 16411,
+ 16433, attrs, attrmask,
+ &disp6);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_ERROR,
+ "could not update an IPv6 random query "
+ "port: %s",
+ isc_result_totext(result));
+ }
+ }
+
+ RES_LOCK(&res->poollock, isc_rwlocktype_write);
+ if (disp4 != NULL) {
+ dns_dispatch_detach(&res->dispatchv4pool[nxt]);
+ res->dispatchv4pool[nxt] = disp4;
+ }
+ if (disp6 != NULL) {
+ dns_dispatch_detach(&res->dispatchv6pool[nxt]);
+ res->dispatchv6pool[nxt] = disp6;
+ }
+ RES_UNLOCK(&res->poollock, isc_rwlocktype_write);
+
+ return;
+}
+
+isc_result_t
+dns_resolver_createdispatchpool(dns_resolver_t *res, unsigned int ndisps,
+ unsigned int tick)
+{
+ unsigned int i;
+ isc_result_t result = ISC_R_SUCCESS;
+ unsigned int attrs_base, attrs, attrmask;
+ isc_sockaddr_t addr4, addr6;
+ dns_dispatch_t *disp;
+ isc_task_t *task;
+ isc_interval_t interval;
+
+ REQUIRE(VALID_RESOLVER(res));
+ REQUIRE(!res->frozen); /* meaning we don't have to lock res */
+ REQUIRE(ndisps > 0);
+ REQUIRE((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0 ||
+ (res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0);
+
+ attrs_base = 0;
+ attrs_base |= DNS_DISPATCHATTR_UDP;
+ attrs_base |= DNS_DISPATCHATTR_RANDOMPORT;
+
+ attrmask = 0;
+ attrmask |= DNS_DISPATCHATTR_UDP;
+ attrmask |= DNS_DISPATCHATTR_TCP;
+ attrmask |= DNS_DISPATCHATTR_IPV4;
+ attrmask |= DNS_DISPATCHATTR_IPV6;
+
+ if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0) {
+ INSIST(res->dispatchv4 != NULL);
+ result = dns_dispatch_getlocaladdress(res->dispatchv4, &addr4);
+ INSIST(result == ISC_R_SUCCESS &&
+ isc_sockaddr_getport(&addr4) == 0);
+ res->dispatchv4pool = isc_mem_get(res->mctx,
+ sizeof(dns_dispatch_t *) *
+ ndisps);
+ if (res->dispatchv4pool == NULL)
+ return (ISC_R_NOMEMORY);
+ for (i = 0; i < ndisps; i++)
+ res->dispatchv4pool[i] = NULL;
+ }
+ if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0) {
+ INSIST(res->dispatchv6 != NULL);
+ result = dns_dispatch_getlocaladdress(res->dispatchv6, &addr6);
+ INSIST(result == ISC_R_SUCCESS &&
+ isc_sockaddr_getport(&addr6) == 0);
+ res->dispatchv6pool = isc_mem_get(res->mctx,
+ sizeof(dns_dispatch_t *) *
+ ndisps);
+ if (res->dispatchv6pool == NULL) {
+ isc_mem_put(res->mctx, res->dispatchv4pool,
+ sizeof(dns_dispatch_t *) * ndisps);
+ res->dispatchv4pool = NULL;
+ return (ISC_R_NOMEMORY);
+ }
+ for (i = 0; i < ndisps; i++)
+ res->dispatchv6pool[i] = NULL;
+ }
+
+ for (i = 0; i < ndisps; i++) {
+ if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0) {
+ attrs = attrs_base;
+ attrs |= DNS_DISPATCHATTR_IPV4;
+
+ disp = NULL;
+ result = dns_dispatch_getudp(res->dispatchmgr,
+ res->socketmgr,
+ res->taskmgr, &addr4,
+ 4096, 1000, 32768, 16411,
+ 16433, attrs, attrmask,
+ &disp);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ res->dispatchv4pool[i] = disp;
+
+ /*
+ * It might be better to ensure all ports are
+ * different, but in practice it's probably okay to
+ * assume dns_dispatch_getudp() made reasonable
+ * choices.
+ */
+ }
+ if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0) {
+ attrs = attrs_base;
+ attrs |= DNS_DISPATCHATTR_IPV6;
+
+ disp = NULL;
+ result = dns_dispatch_getudp(res->dispatchmgr,
+ res->socketmgr,
+ res->taskmgr, &addr6,
+ 4096, 1000, 32768, 16411,
+ 16433, attrs, attrmask,
+ &disp);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ res->dispatchv6pool[i] = disp;
+ }
+ }
+
+ /* start update timer */
+ if (tick != 0) {
+ task = NULL;
+ result = isc_task_create(res->taskmgr, 0, &task);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ isc_interval_set(&interval, tick, 0);
+ result = isc_timer_create(res->timermgr, isc_timertype_ticker,
+ NULL, &interval, task,
+ disppooltimer_update,
+ res, &res->disppooltimer);
+ isc_task_detach(&task);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ }
+
+ res->ndisps = ndisps;
+ res->nextdisp = 0;
+
+ return (result);
+
+ cleanup:
+ for (i = 0; i < ndisps; i++) {
+ if (res->dispatchv4pool[i] != NULL)
+ dns_dispatch_detach(&res->dispatchv4pool[i]);
+ if (res->dispatchv6pool[i] != NULL)
+ dns_dispatch_detach(&res->dispatchv6pool[i]);
+ }
+ if (res->dispatchv4pool != NULL) {
+ isc_mem_put(res->mctx, res->dispatchv4pool,
+ sizeof(dns_dispatch_t *) * ndisps);
+ }
+ if (res->dispatchv6pool != NULL) {
+ isc_mem_put(res->mctx, res->dispatchv6pool,
+ sizeof(dns_dispatch_t *) * ndisps);
+ }
+
+ return (result);
+}
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: namedconf.c,v 1.72 2006/12/21 06:02:30 marka Exp $ */
+/* $Id: namedconf.c,v 1.73 2007/02/02 02:18:06 marka Exp $ */
/*! \file */
{ "empty-zones-enable", &cfg_type_boolean, 0 },
{ "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI },
{ "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 },
+ { "use-queryport-pool", &cfg_type_boolean, 0 },
+ { "queryport-pool-ports", &cfg_type_uint32, 0 },
+ { "queryport-pool-updateinterval", &cfg_type_uint32, 0 },
{ NULL, NULL, 0 }
};