2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-02 07:35:26 +00:00

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]
This commit is contained in:
Mark Andrews
2007-02-02 02:18:06 +00:00
parent 1f369c2581
commit 281bab0f36
10 changed files with 622 additions and 50 deletions

View File

@@ -1,3 +1,7 @@
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]

View File

@@ -15,7 +15,7 @@
* 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 */
@@ -802,7 +802,9 @@ do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
(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;

View File

@@ -17,7 +17,7 @@
- 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>
@@ -235,6 +235,9 @@ options {
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>;
@@ -384,6 +387,9 @@ view <replaceable>string</replaceable> <replaceable>optional_class</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>;

View File

@@ -15,7 +15,7 @@
* 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 */
@@ -953,7 +953,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
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 ";
@@ -962,6 +962,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
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));
@@ -1184,14 +1185,13 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
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);
@@ -1210,11 +1210,93 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
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.
*/
@@ -2376,7 +2458,9 @@ scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
}
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;
@@ -2386,7 +2470,8 @@ add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr) {
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;
@@ -2438,6 +2523,8 @@ adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
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)
@@ -2445,7 +2532,19 @@ adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
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;
}
@@ -2475,12 +2574,12 @@ adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
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;
}

View File

@@ -18,7 +18,7 @@
- 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>
@@ -4443,6 +4443,9 @@ category notify { null; };
<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>
@@ -6074,7 +6077,7 @@ listen-on-v6 port 1234 { !2001:db8::/32; any; };
</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
@@ -6085,22 +6088,61 @@ listen-on-v6 port 1234 { !2001:db8::/32; any; };
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>
@@ -7669,6 +7711,9 @@ query-source-v6 address * port *;
<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>

View File

@@ -15,7 +15,7 @@
* 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 */
@@ -282,6 +282,20 @@ reseed_lfsr(isc_lfsr_t *lfsr, void *arg)
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.
*/
@@ -1290,20 +1304,26 @@ dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) {
}
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 (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);
}
@@ -1324,7 +1344,7 @@ local_addr_match(dns_dispatch_t *disp, isc_sockaddr_t *addr) {
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);
/*
@@ -1669,7 +1689,7 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
dns_dispatch_t **dispp)
{
isc_result_t result;
dns_dispatch_t *disp;
dns_dispatch_t *disp = NULL;
REQUIRE(VALID_DISPATCHMGR(mgr));
REQUIRE(sockmgr != NULL);
@@ -1689,10 +1709,14 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
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++;
@@ -1717,6 +1741,7 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
return (ISC_R_SUCCESS);
}
createudp:
/*
* Nope, create one.
*/
@@ -1752,7 +1777,8 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
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.
@@ -1768,11 +1794,30 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
* from returning the same port to us too quickly.
*/
memset(held, 0, sizeof(held));
localaddr_bound = *localaddr;
getsocket:
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;

View File

@@ -15,7 +15,7 @@
* 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
@@ -113,6 +113,9 @@ struct dns_dispatchevent {
* _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
@@ -122,6 +125,7 @@ struct dns_dispatchevent {
#define DNS_DISPATCHATTR_NOLISTEN 0x00000020U
#define DNS_DISPATCHATTR_MAKEQUERY 0x00000040U
#define DNS_DISPATCHATTR_CONNECTED 0x00000080U
#define DNS_DISPATCHATTR_RANDOMPORT 0x00000100U
/*@}*/
isc_result_t

View File

@@ -15,7 +15,7 @@
* 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
@@ -106,6 +106,8 @@ typedef struct dns_fetchevent {
#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,
@@ -126,8 +128,6 @@ 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.
@@ -474,6 +474,36 @@ dns_resolver_getzeronosoattl(dns_resolver_t *resolver);
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 */

View File

@@ -15,7 +15,7 @@
* 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 */
@@ -23,6 +23,7 @@
#include <isc/print.h>
#include <isc/string.h>
#include <isc/random.h>
#include <isc/task.h>
#include <isc/timer.h>
#include <isc/util.h>
@@ -290,6 +291,24 @@ typedef struct alternate {
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;
@@ -297,6 +316,11 @@ struct dns_resolver {
isc_mutex_t lock;
isc_mutex_t nlock;
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;
@@ -307,6 +331,7 @@ struct dns_resolver {
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;
@@ -324,6 +349,7 @@ struct dns_resolver {
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;
@@ -331,10 +357,14 @@ struct dns_resolver {
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', '!')
@@ -1143,14 +1173,39 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
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:
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:
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;
@@ -5962,6 +6017,7 @@ destroy(dns_resolver_t *res) {
INSIST(res->nfctx == 0);
RES_DESTROYLOCK(&res->poollock);
DESTROYLOCK(&res->primelock);
DESTROYLOCK(&res->nlock);
DESTROYLOCK(&res->lock);
@@ -5978,12 +6034,26 @@ destroy(dns_resolver_t *res) {
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
@@ -6112,6 +6182,11 @@ dns_resolver_create(dns_view_t *view,
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;
@@ -6148,6 +6223,7 @@ dns_resolver_create(dns_view_t *view,
res->dispatchv4 = NULL;
if (dispatchv4 != NULL)
dns_dispatch_attach(dispatchv4, &res->dispatchv4);
res->dispatchv6 = NULL;
if (dispatchv6 != NULL)
dns_dispatch_attach(dispatchv6, &res->dispatchv6);
@@ -6172,17 +6248,21 @@ dns_resolver_create(dns_view_t *view,
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);
@@ -6212,6 +6292,9 @@ dns_resolver_create(dns_view_t *view,
isc_timer_detach(&res->spillattimer);
#endif
cleanup_poollock:
RES_DESTROYLOCK(&res->poollock);
cleanup_primelock:
DESTROYLOCK(&res->primelock);
@@ -7112,3 +7195,254 @@ dns_resolver_setzeronosoattl(dns_resolver_t *resolver, isc_boolean_t state) {
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);
}

View File

@@ -15,7 +15,7 @@
* 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 */
@@ -790,6 +790,9 @@ view_clauses[] = {
{ "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 }
};