2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 14:35:26 +00:00

2375. [security] Fully randomize UDP query ports to improve

forgery resilience. [RT #17949, #18098]
This commit is contained in:
Tatuya JINMEI 神明達哉
2008-06-23 19:41:20 +00:00
parent 40976ef802
commit 386d3a99c1
26 changed files with 3403 additions and 1553 deletions

View File

@@ -24,7 +24,8 @@
2376. [bug] Change #2144 was not complete.
2375. [placeholder]
2375. [security] Fully randomize UDP query ports to improve
forgery resilience. [RT #17949, #18098]
2374. [bug] "blackhole" ACLs could cause named to segfault due
to some uninitialized memory. [RT #18095]

View File

@@ -15,7 +15,7 @@
- PERFORMANCE OF THIS SOFTWARE.
-->
<!-- $Id: bind9.xsl,v 1.17 2008/04/09 22:48:17 jinmei Exp $ -->
<!-- $Id: bind9.xsl,v 1.18 2008/06/23 19:41:18 jinmei Exp $ -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
@@ -86,7 +86,6 @@ td, th {
</head>
<body>
<div class="header">Bind 9 Configuration and Statistics</div>
<br/>
<table>

View File

@@ -91,7 +91,6 @@ static char xslmsg[] =
" </head>\n"
" <body>\n"
" <div class=\"header\">Bind 9 Configuration and Statistics</div>\n"
"\n"
" <br/>\n"
"\n"
" <table>\n"

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: client.c,v 1.257 2008/04/03 06:09:04 tbox Exp $ */
/* $Id: client.c,v 1.258 2008/06/23 19:41:18 jinmei Exp $ */
#include <config.h>
@@ -1524,14 +1524,6 @@ client_request(isc_task_t *task, isc_event_t *event) {
dns_generalstats_increment(ns_g_server->nsstats,
dns_nsstatscounter_tcp);
/*
* Hash the incoming request here as it is after
* dns_dispatch_importrecv().
*/
dns_dispatch_hash(&client->now, sizeof(client->now));
dns_dispatch_hash(isc_buffer_base(buffer),
isc_buffer_usedlength(buffer));
/*
* It's a request. Parse it.
*/

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: server.c,v 1.508 2008/05/21 23:47:00 tbox Exp $ */
/* $Id: server.c,v 1.509 2008/06/23 19:41:18 jinmei Exp $ */
/*! \file */
@@ -33,6 +33,7 @@
#include <isc/httpd.h>
#include <isc/lex.h>
#include <isc/parseint.h>
#include <isc/portset.h>
#include <isc/print.h>
#include <isc/resource.h>
#include <isc/stdio.h>
@@ -538,13 +539,15 @@ mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver)
*/
static isc_result_t
get_view_querysource_dispatch(const cfg_obj_t **maps,
int af, dns_dispatch_t **dispatchp)
int af, dns_dispatch_t **dispatchp,
isc_boolean_t is_firstview)
{
isc_result_t result;
dns_dispatch_t *disp;
isc_sockaddr_t sa;
unsigned int attrs, attrmask;
const cfg_obj_t *obj = NULL;
unsigned int maxdispatchbuffers;
/*
* Make compiler happy.
@@ -596,6 +599,20 @@ get_view_querysource_dispatch(const cfg_obj_t **maps,
attrs |= DNS_DISPATCHATTR_IPV6;
break;
}
if (isc_sockaddr_getport(&sa) == 0) {
attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
maxdispatchbuffers = 4096;
} else {
INSIST(obj != NULL);
if (is_firstview) {
cfg_obj_log(obj, ns_g_lctx, ISC_LOG_INFO,
"using specific query-source port "
"suppresses port randomization and can be "
"insecure.");
}
maxdispatchbuffers = 1000;
}
attrmask = 0;
attrmask |= DNS_DISPATCHATTR_UDP;
attrmask |= DNS_DISPATCHATTR_TCP;
@@ -605,7 +622,7 @@ get_view_querysource_dispatch(const cfg_obj_t **maps,
disp = NULL;
result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
ns_g_taskmgr, &sa, 4096,
1000, 32768, 16411, 16433,
maxdispatchbuffers, 32768, 16411, 16433,
attrs, attrmask, &disp);
if (result != ISC_R_SUCCESS) {
isc_sockaddr_t any;
@@ -1015,7 +1032,6 @@ 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;
dns_stats_t *resstats = NULL;
dns_stats_t *resquerystats = NULL;
@@ -1272,8 +1288,12 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
*
* XXXRTH Hardwired number of tasks.
*/
CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4));
CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6));
CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4,
ISC_TF(ISC_LIST_PREV(view, link)
== NULL)));
CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6,
ISC_TF(ISC_LIST_PREV(view, link)
== NULL)));
if (dispatch4 == NULL && dispatch6 == NULL) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"unable to obtain neither an IPv4 nor"
@@ -1281,93 +1301,11 @@ 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,
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));
}
if (resstats == NULL) {
CHECK(dns_generalstats_create(mctx, &resstats,
dns_resstatscounter_max));
@@ -2674,8 +2612,6 @@ 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)
@@ -2683,19 +2619,16 @@ adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
result = dns_dispatch_getlocaladdress(dispatch6, &addr);
if (result != ISC_R_SUCCESS)
goto fail;
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);
/*
* We always add non-wildcard address regardless of whether
* the port is 'any' (the fourth arg is TRUE): if the port is
* specific, we need to add it since it may conflict with a
* listening interface; if it's zero, we'll dynamically open
* query ports, and some of them may override an existing
* wildcard IPv6 port.
*/
result = add_listenelt(mctx, list, &addr, ISC_TRUE);
if (result != ISC_R_SUCCESS)
goto fail;
}
@@ -2884,24 +2817,41 @@ set_limits(const cfg_obj_t **maps) {
SETLIMIT("files", openfiles, "open files");
}
static isc_result_t
portlist_fromconf(dns_portlist_t *portlist, unsigned int family,
const cfg_obj_t *ports)
static void
portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
isc_boolean_t positive)
{
const cfg_listelt_t *element;
isc_result_t result = ISC_R_SUCCESS;
for (element = cfg_list_first(ports);
element != NULL;
element = cfg_list_next(element)) {
const cfg_obj_t *obj = cfg_listelt_value(element);
in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
result = dns_portlist_add(portlist, family, port);
if (result != ISC_R_SUCCESS)
break;
if (cfg_obj_isuint32(obj)) {
in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
if (positive)
isc_portset_add(portset, port);
else
isc_portset_remove(portset, port);
} else {
const cfg_obj_t *obj_loport, *obj_hiport;
in_port_t loport, hiport;
obj_loport = cfg_tuple_get(obj, "loport");
loport = (in_port_t)cfg_obj_asuint32(obj_loport);
obj_hiport = cfg_tuple_get(obj, "hiport");
hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
if (positive)
isc_portset_addrange(portset, loport, hiport);
else {
isc_portset_removerange(portset, loport,
hiport);
}
}
}
return (result);
}
static isc_result_t
@@ -2940,7 +2890,7 @@ load_configuration(const char *filename, ns_server_t *server,
const cfg_obj_t *options;
const cfg_obj_t *views;
const cfg_obj_t *obj;
const cfg_obj_t *v4ports, *v6ports;
const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
const cfg_obj_t *maps[3];
const cfg_obj_t *builtin_views;
const cfg_listelt_t *element;
@@ -2952,7 +2902,9 @@ load_configuration(const char *filename, ns_server_t *server,
isc_uint32_t interface_interval;
isc_uint32_t heartbeat_interval;
isc_uint32_t udpsize;
in_port_t listen_port;
in_port_t listen_port, udpport_low, udpport_high;
isc_portset_t *v4portset = NULL;
isc_portset_t *v6portset = NULL;
int i;
cfg_aclconfctx_init(&aclconfctx);
@@ -3069,24 +3021,64 @@ load_configuration(const char *filename, ns_server_t *server,
CHECKM(ns_statschannels_configure(ns_g_server, config, &aclconfctx),
"configuring statistics server(s)");
v4ports = NULL;
v6ports = NULL;
(void)ns_config_get(maps, "avoid-v4-udp-ports", &v4ports);
(void)ns_config_get(maps, "avoid-v6-udp-ports", &v6ports);
if (v4ports != NULL || v6ports != NULL) {
dns_portlist_t *portlist = NULL;
result = dns_portlist_create(ns_g_mctx, &portlist);
if (result == ISC_R_SUCCESS && v4ports != NULL)
result = portlist_fromconf(portlist, AF_INET, v4ports);
if (result == ISC_R_SUCCESS && v6ports != NULL)
portlist_fromconf(portlist, AF_INET6, v6ports);
if (result == ISC_R_SUCCESS)
dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, portlist);
if (portlist != NULL)
dns_portlist_detach(&portlist);
CHECK(result);
} else
dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, NULL);
/*
* Configure sets of UDP query source ports.
*/
CHECKM(isc_portset_create(ns_g_mctx, &v4portset),
"creating UDP port set");
CHECKM(isc_portset_create(ns_g_mctx, &v6portset),
"creating UDP port set");
usev4ports = NULL;
usev6ports = NULL;
avoidv4ports = NULL;
avoidv6ports = NULL;
(void)ns_config_get(maps, "use-v4-udp-ports", &usev4ports);
if (usev4ports != NULL)
portset_fromconf(v4portset, usev4ports, ISC_TRUE);
else {
CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low,
&udpport_high),
"get the default UDP/IPv4 port range");
if (udpport_low == udpport_high)
isc_portset_add(v4portset, udpport_low);
else {
isc_portset_addrange(v4portset, udpport_low,
udpport_high);
}
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_INFO,
"using default UDP/IPv4 port range: [%d, %d]",
udpport_low, udpport_high);
}
(void)ns_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
if (avoidv4ports != NULL)
portset_fromconf(v4portset, avoidv4ports, ISC_FALSE);
(void)ns_config_get(maps, "use-v6-udp-ports", &usev6ports);
if (usev6ports != NULL)
portset_fromconf(v6portset, usev6ports, ISC_TRUE);
else {
CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low,
&udpport_high),
"get the default UDP/IPv6 port range");
if (udpport_low == udpport_high)
isc_portset_add(v6portset, udpport_low);
else {
isc_portset_addrange(v6portset, udpport_low,
udpport_high);
}
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_INFO,
"using default UDP/IPv6 port range: [%d, %d]",
udpport_low, udpport_high);
}
(void)ns_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
if (avoidv6ports != NULL)
portset_fromconf(v6portset, avoidv6ports, ISC_FALSE);
dns_dispatchmgr_setavailports(ns_g_dispatchmgr, v4portset, v6portset);
/*
* Set the EDNS UDP size when we don't match a view.
@@ -3569,6 +3561,12 @@ load_configuration(const char *filename, ns_server_t *server,
result = ISC_R_SUCCESS;
cleanup:
if (v4portset != NULL)
isc_portset_destroy(ns_g_mctx, &v4portset);
if (v6portset != NULL)
isc_portset_destroy(ns_g_mctx, &v6portset);
cfg_aclconfctx_destroy(&aclconfctx);
if (parser != NULL) {

View File

@@ -18,7 +18,7 @@ AC_DIVERT_PUSH(1)dnl
esyscmd([sed "s/^/# /" COPYRIGHT])dnl
AC_DIVERT_POP()dnl
AC_REVISION($Revision: 1.443 $)
AC_REVISION($Revision: 1.444 $)
AC_INIT(lib/dns/name.c)
AC_PREREQ(2.59)
@@ -317,6 +317,43 @@ lifconf.lifc_len = 0;
ISC_PLATFORM_HAVELIFCONF="#undef ISC_PLATFORM_HAVELIFCONF"])
AC_SUBST(ISC_PLATFORM_HAVELIFCONF)
#
# check if we have kqueue
#
AC_CHECK_FUNC(kqueue, ac_cv_have_kqueue=yes, ac_cv_have_kqueue=no)
case $ac_cv_have_kqueue in
yes)
ISC_PLATFORM_HAVEKQUEUE="#define ISC_PLATFORM_HAVEKQUEUE 1"
;;
*)
ISC_PLATFORM_HAVEKQUEUE="#undef ISC_PLATFORM_HAVEKQUEUE"
;;
esac
AC_SUBST(ISC_PLATFORM_HAVEKQUEUE)
#
# check if we have epoll
#
AC_CHECK_FUNC(epoll_create, ac_cv_have_epoll=yes, ac_cv_have_epoll=no)
case $ac_cv_have_epoll in
yes)
ISC_PLATFORM_HAVEEPOLL="#define ISC_PLATFORM_HAVEEPOLL 1"
;;
*)
ISC_PLATFORM_HAVEEPOLL="#undef ISC_PLATFORM_HAVEEPOLL"
;;
esac
AC_SUBST(ISC_PLATFORM_HAVEEPOLL)
#
# check if we support /dev/poll
#
AC_CHECK_HEADERS(sys/devpoll.h,
ISC_PLATFORM_HAVEDEVPOLL="#define ISC_PLATFORM_HAVEDEVPOLL 1"
,
ISC_PLATFORM_HAVEDEVPOLL="#undef ISC_PLATFORM_HAVEDEVPOLL"
)
AC_SUBST(ISC_PLATFORM_HAVEDEVPOLL)
#
# check if we need to #include sys/select.h explicitly

View File

@@ -18,7 +18,7 @@
- PERFORMANCE OF THIS SOFTWARE.
-->
<!-- File: $Id: Bv9ARM-book.xml,v 1.359 2008/06/17 20:59:25 jreed Exp $ -->
<!-- File: $Id: Bv9ARM-book.xml,v 1.360 2008/06/23 19:41:18 jinmei Exp $ -->
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<title>BIND 9 Administrator Reference Manual</title>
@@ -2955,6 +2955,33 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
</para>
</entry>
</row>
<row rowsep="0">
<entry colname="1">
<para>
<varname>port_list</varname>
</para>
</entry>
<entry colname="2">
<para>
A list of an <varname>ip_port</varname> or a port
range.
A port range is specified in the form of
<userinput>range</userinput> followed by
two <varname>ip_port</varname>s,
<varname>port_low</varname> and
<varname>port_high</varname>, which represents
port numbers from <varname>port_low</varname> through
<varname>port_high</varname>, inclusive.
<varname>port_low</varname> must not be larger than
<varname>port_high</varname>.
For example,
<userinput>range 1024 65535</userinput> represents
ports from 1024 through 65535.
In either case an asterisk (`*') character is not
allowed as a valid <varname>ip_port</varname>.
</para>
</entry>
</row>
<row rowsep="0">
<entry colname="1">
<para>
@@ -4513,7 +4540,9 @@ category notify { null; };
<optional> try-tcp-refresh <replaceable>yes_or_no</replaceable>; </optional>
<optional> allow-v6-synthesis { <replaceable>address_match_list</replaceable> }; </optional>
<optional> blackhole { <replaceable>address_match_list</replaceable> }; </optional>
<optional> use-v4-udp-ports { <replaceable>port_list</replaceable> }; </optional>
<optional> avoid-v4-udp-ports { <replaceable>port_list</replaceable> }; </optional>
<optional> use-v6-udp-ports { <replaceable>port_list</replaceable> }; </optional>
<optional> avoid-v6-udp-ports { <replaceable>port_list</replaceable> }; </optional>
<optional> listen-on <optional> port <replaceable>ip_port</replaceable> </optional> { <replaceable>address_match_list</replaceable> }; </optional>
<optional> listen-on-v6 <optional> port <replaceable>ip_port</replaceable> </optional> { <replaceable>address_match_list</replaceable> }; </optional>
@@ -6269,32 +6298,104 @@ listen-on-v6 port 1234 { !2001:db8::/32; any; };
If <command>address</command> is <command>*</command> (asterisk) or is omitted,
a wildcard IP address (<command>INADDR_ANY</command>)
will be used.
</para>
<para>
If <command>port</command> is <command>*</command> or is omitted,
a pool of random unprivileged ports will be used. See the
<command>use-queryport-pool</command>,
<command>queryport-pool-ports</command> and
<command>queryport-pool-updateinterval</command> options below 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:
a random port number from a pre-configured
range is picked up and will be used for each query.
The port range(s) is that specified in
the <command>use-v4-udp-ports</command> (for IPv4)
and <command>use-v6-udp-ports</command> (for IPv6)
options, excluding the ranges specified in
the <command>avoid-v4-udp-ports</command>
and <command>avoid-v6-udp-ports</command> options, respectively.
</para>
<para>
The defaults of the <command>query-source</command> and
<command>query-source-v6</command> options
are:
</para>
<programlisting>query-source address * port *;
query-source-v6 address * port *;
</programlisting>
<para>
If <command>use-v4-udp-ports</command> or
<command>use-v6-udp-ports</command> is unspecified,
<command>named</command> will check if the operating
system provides a programming interface to retrieve the
system's default range for ephemeral ports.
If such an interface is available,
<command>named</command> will use the corresponding system
default range; otherwise, it will use its own defaults:
</para>
<programlisting>use-v4-udp-ports { range 1024 65535; };
use-v6-udp-ports { range 1024 65535; };
</programlisting>
<para>
Note: make sure the ranges be sufficiently large for
security. A desirable size depends on various parameters,
but we generally recommend it contain at least 16384 ports
(14 bits of entropy).
Note also that the system's default range when used may be
too small for this purpose, and that the range may even be
changed while <command>named</command> is running; the new
range will automatically be applied when <command>named</command>
is reloaded.
It is encouraged to
configure <command>use-v4-udp-ports</command> and
<command>use-v6-udp-ports</command> explicitly so that the
ranges are sufficiently large and are reasonably
independent from the ranges used by other applications.
</para>
<para>
Note: the operational configuration
where <command>named</command> runs may prohibit the use
of some ports. For example, UNIX systems will not allow
<command>named</command> running without a root privilege
to use ports less than 1024.
If such ports are included in the specified (or detected)
set of query ports, the corresponding query attempts will
fail, resulting in resolution failures or delay.
It is therefore important to configure the set of ports
that can be safely used in the expected operational environment.
</para>
<para>
The defaults of the <command>avoid-v4-udp-ports</command> and
<command>avoid-v6-udp-ports</command> options
are:
</para>
<programlisting>avoid-v4-udp-ports {};
avoid-v6-udp-ports {};
</programlisting>
<para>
Note: BIND 9.5.0 introduced
the <command>use-queryport-pool</command>
option to support a pool of such random ports, but this
option is now obsolete because reusing the same ports in
the pool may not be sufficiently secure.
For the same reason, it is generally strongly discouraged to
specify a particular port for the
<command>query-source</command> or
<command>query-source-v6</command> options;
it implicitly disables the use of randomized port numbers.
</para>
<variablelist>
<varlistentry>
<term><command>use-queryport-pool</command></term>
<listitem>
<para>
Enable the 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>.
This option is obsolete.
</para>
</listitem>
</varlistentry>
@@ -6303,7 +6404,7 @@ query-source-v6 address * port *;
<term><command>queryport-pool-ports</command></term>
<listitem>
<para>
Specify how many pool ports to use. The default is 8.
This option is obsolete.
</para>
</listitem>
</varlistentry>
@@ -6312,9 +6413,7 @@ query-source-v6 address * port *;
<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.
This option is obsolete.
</para>
</listitem>
</varlistentry>
@@ -6664,17 +6763,48 @@ query-source-v6 address * port *;
</sect3>
<sect3>
<title>Bad UDP Port Lists</title>
<para><command>avoid-v4-udp-ports</command>
and <command>avoid-v6-udp-ports</command> specify a list
of IPv4 and IPv6 UDP ports that will not be used as system
assigned source ports for UDP sockets. These lists
prevent named from choosing as its random source port a
port that is blocked by your firewall. If a query went
out with such a source port, the answer would not get by
the firewall and the name server would have to query
again.
<title>UDP Port Lists</title>
<para>
<command>use-v4-udp-ports</command>,
<command>avoid-v4-udp-ports</command>,
<command>use-v6-udp-ports</command>, and
<command>avoid-v6-udp-ports</command>
specify a list of IPv4 and IPv6 UDP ports that will be
used or not used as source ports for UDP messages.
See <xref linkend="query_address"/> about how the
available ports are determined.
For example, with the following configuration
</para>
<programlisting>
use-v6-udp-ports { range 32768 65535; };
avoid-v6-udp-ports { 40000; range 50000 60000; };
</programlisting>
<para>
UDP ports of IPv6 messages sent
from <command>named</command> will be in one
of the following ranges: 32768 to 39999, 40001 to 49999,
and 60001 to 65535.
</para>
<para>
<command>avoid-v4-udp-ports</command> and
<command>avoid-v6-udp-ports</command> can be used
to prevent <command>named</command> from choosing as its random source port a
port that is blocked by your firewall or a port that is
used by other applications;
if a query went out with a source port blocked by a
firewall, the
answer would not get by the firewall and the name server would
have to query again.
Note: the desired range can also be represented only with
<command>use-v4-udp-ports</command> and
<command>use-v6-udp-ports</command>, and the
<command>avoid-</command> options are redundant in that
sense; they are provided for backward compatibility and
to possibly simplify the port specification.
</para>
</sect3>
<sect3>

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: dispatch.h,v 1.58 2008/04/03 06:09:04 tbox Exp $ */
/* $Id: dispatch.h,v 1.59 2008/06/23 19:41:19 jinmei Exp $ */
#ifndef DNS_DISPATCH_H
#define DNS_DISPATCH_H 1
@@ -105,7 +105,7 @@ struct dns_dispatchevent {
* The dispatcher is a TCP or UDP socket.
*
* _IPV4, _IPV6
* The dispatcher uses an ipv4 or ipv6 socket.
* The dispatcher uses an IPv4 or IPv6 socket.
*
* _NOLISTEN
* The dispatcher should not listen on the socket.
@@ -115,7 +115,12 @@ struct dns_dispatchevent {
* accept replies from them.
*
* _RANDOMPORT
* TBD
* Previously used to indicate that the port of a dispatch UDP must be
* chosen randomly. This behavior now always applies and the attribute
* is obsoleted.
*
* _EXCLUSIVE
* A separate socket will be used on-demand for each transaction.
*/
#define DNS_DISPATCHATTR_PRIVATE 0x00000001U
#define DNS_DISPATCHATTR_TCP 0x00000002U
@@ -125,7 +130,8 @@ struct dns_dispatchevent {
#define DNS_DISPATCHATTR_NOLISTEN 0x00000020U
#define DNS_DISPATCHATTR_MAKEQUERY 0x00000040U
#define DNS_DISPATCHATTR_CONNECTED 0x00000080U
#define DNS_DISPATCHATTR_RANDOMPORT 0x00000100U
/*#define DNS_DISPATCHATTR_RANDOMPORT 0x00000100U*/
#define DNS_DISPATCHATTR_EXCLUSIVE 0x00000200U
/*@}*/
isc_result_t
@@ -189,23 +195,33 @@ void
dns_dispatchmgr_setblackportlist(dns_dispatchmgr_t *mgr,
dns_portlist_t *portlist);
/*%<
* Sets a list of UDP ports that won't be used when creating a udp
* dispatch with a wildcard port.
* This function is deprecated. Use dns_dispatchmgr_setavailports() instead.
*
* Requires:
*\li mgr is a valid dispatchmgr
*\li portlist to be NULL or a valid port list.
*/
dns_portlist_t *
dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr);
/*%<
* Return the current port list.
* This function is deprecated and always returns NULL.
*
* Requires:
*\li mgr is a valid dispatchmgr
*/
isc_result_t
dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset,
isc_portset_t *v6portset);
/*%<
* Sets a list of UDP ports that can be used for outgoing UDP messages.
*
* Requires:
*\li mgr is a valid dispatchmgr
*\li v4portset is NULL or a valid port set
*\li v6portset is NULL or a valid port set
*/
void
dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, dns_stats_t *stats);
/*%<
@@ -331,6 +347,12 @@ dns_dispatch_starttcp(dns_dispatch_t *disp);
*\li 'disp' is valid.
*/
isc_result_t
dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest,
isc_task_t *task, isc_taskaction_t action, void *arg,
isc_uint16_t *idp, dns_dispentry_t **resp,
isc_socketmgr_t *sockmgr);
isc_result_t
dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
isc_task_t *task, isc_taskaction_t action, void *arg,
@@ -354,6 +376,10 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
*
*\li "resp" be non-NULL and *resp be NULL
*
*\li "sockmgr" be NULL or a valid socket manager. If 'disp' has
* the DNS_DISPATCHATTR_EXCLUSIVE attribute, this must not be NULL,
* which also means dns_dispatch_addresponse() cannot be used.
*
* Ensures:
*
*\li &lt;id, dest> is a unique tuple. That means incoming messages
@@ -384,6 +410,8 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp,
* argument to dns_dispatch_addresponse() when allocating '*resp'.
*/
isc_socket_t *
dns_dispatch_getentrysocket(dns_dispentry_t *resp);
isc_socket_t *
dns_dispatch_getsocket(dns_dispatch_t *disp);
@@ -421,6 +449,16 @@ dns_dispatch_cancel(dns_dispatch_t *disp);
*\li disp is valid.
*/
unsigned int
dns_dispatch_getattributes(dns_dispatch_t *disp);
/*%<
* Return the attributes (DNS_DISPATCHATTR_xxx) of this dispatch. Only the
* non-changeable attributes are expected to be referenced by the caller.
*
* Requires:
*\li disp is valid.
*/
void
dns_dispatch_changeattributes(dns_dispatch_t *disp,
unsigned int attributes, unsigned int mask);
@@ -458,13 +496,6 @@ dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event);
* event != NULL
*/
void
dns_dispatch_hash(void *data, size_t len);
/*%<
* Feed 'data' to the dispatch query id generator where 'len' is the size
* of 'data'.
*/
ISC_LANG_ENDDECLS
#endif /* DNS_DISPATCH_H */

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: resolver.h,v 1.58 2008/04/03 06:09:05 tbox Exp $ */
/* $Id: resolver.h,v 1.59 2008/06/23 19:41:19 jinmei Exp $ */
#ifndef DNS_RESOLVER_H
#define DNS_RESOLVER_H 1
@@ -107,8 +107,6 @@ 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,

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: request.c,v 1.79 2007/06/19 23:47:16 tbox Exp $ */
/* $Id: request.c,v 1.80 2008/06/23 19:41:19 jinmei Exp $ */
/*! \file */
@@ -121,6 +121,7 @@ static isc_result_t req_render(dns_message_t *message, isc_buffer_t **buffer,
static void req_senddone(isc_task_t *task, isc_event_t *event);
static void req_response(isc_task_t *task, isc_event_t *event);
static void req_timeout(isc_task_t *task, isc_event_t *event);
static isc_socket_t * req_getsocket(dns_request_t *request);
static void req_connected(isc_task_t *task, isc_event_t *event);
static void req_sendevent(dns_request_t *request, isc_result_t result);
static void req_cancel(dns_request_t *request);
@@ -146,6 +147,7 @@ dns_requestmgr_create(isc_mem_t *mctx,
isc_socket_t *socket;
isc_result_t result;
int i;
unsigned int dispattr;
req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create");
@@ -154,13 +156,14 @@ dns_requestmgr_create(isc_mem_t *mctx,
REQUIRE(socketmgr != NULL);
REQUIRE(taskmgr != NULL);
REQUIRE(dispatchmgr != NULL);
UNUSED(socket);
if (dispatchv4 != NULL) {
socket = dns_dispatch_getsocket(dispatchv4);
REQUIRE(isc_socket_gettype(socket) == isc_sockettype_udp);
dispattr = dns_dispatch_getattributes(dispatchv4);
REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
}
if (dispatchv6 != NULL) {
socket = dns_dispatch_getsocket(dispatchv6);
REQUIRE(isc_socket_gettype(socket) == isc_sockettype_udp);
dispattr = dns_dispatch_getattributes(dispatchv6);
REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
}
requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
@@ -425,12 +428,19 @@ req_send(dns_request_t *request, isc_task_t *task, isc_sockaddr_t *address) {
isc_region_t r;
isc_socket_t *socket;
isc_result_t result;
unsigned int dispattr;
req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request);
REQUIRE(VALID_REQUEST(request));
socket = dns_dispatch_getsocket(request->dispatch);
dispattr = dns_dispatch_getattributes(request->dispatch);
socket = req_getsocket(request);
isc_buffer_usedregion(request->query, &r);
/*
* We could connect the socket when we are using an exclusive dispatch
* as we do in resolver.c, but we prefer implementation simplicity
* at this moment.
*/
result = isc_socket_sendto(socket, &r, task, req_senddone,
request, address, NULL);
if (result == ISC_R_SUCCESS)
@@ -742,14 +752,16 @@ dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
if (result != ISC_R_SUCCESS)
goto cleanup;
socket = dns_dispatch_getsocket(request->dispatch);
INSIST(socket != NULL);
result = dns_dispatch_addresponse(request->dispatch, destaddr, task,
req_response, request, &id,
&request->dispentry);
result = dns_dispatch_addresponse2(request->dispatch, destaddr, task,
req_response, request, &id,
&request->dispentry,
requestmgr->socketmgr);
if (result != ISC_R_SUCCESS)
goto cleanup;
socket = req_getsocket(request);
INSIST(socket != NULL);
result = isc_buffer_allocate(mctx, &request->query,
r.length + (tcp ? 2 : 0));
if (result != ISC_R_SUCCESS)
@@ -935,13 +947,14 @@ dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message,
if (result != ISC_R_SUCCESS)
goto cleanup;
socket = dns_dispatch_getsocket(request->dispatch);
INSIST(socket != NULL);
result = dns_dispatch_addresponse(request->dispatch, destaddr, task,
req_response, request, &id,
&request->dispentry);
result = dns_dispatch_addresponse2(request->dispatch, destaddr, task,
req_response, request, &id,
&request->dispentry,
requestmgr->socketmgr);
if (result != ISC_R_SUCCESS)
goto cleanup;
socket = req_getsocket(request);
INSIST(socket != NULL);
message->id = id;
if (setkey) {
@@ -1226,6 +1239,21 @@ dns_request_destroy(dns_request_t **requestp) {
*** Private: request.
***/
static isc_socket_t *
req_getsocket(dns_request_t *request) {
unsigned int dispattr;
isc_socket_t *socket;
dispattr = dns_dispatch_getattributes(request->dispatch);
if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
INSIST(request->dispentry != NULL);
socket = dns_dispatch_getentrysocket(request->dispentry);
} else
socket = dns_dispatch_getsocket(request->dispatch);
return (socket);
}
static void
req_connected(isc_task_t *task, isc_event_t *event) {
isc_socketevent_t *sevent = (isc_socketevent_t *)event;
@@ -1425,6 +1453,7 @@ req_destroy(dns_request_t *request) {
static void
req_cancel(dns_request_t *request) {
isc_socket_t *socket;
unsigned int dispattr;
REQUIRE(VALID_REQUEST(request));
@@ -1437,16 +1466,23 @@ req_cancel(dns_request_t *request) {
if (request->timer != NULL)
isc_timer_detach(&request->timer);
dispattr = dns_dispatch_getattributes(request->dispatch);
socket = NULL;
if (DNS_REQUEST_CONNECTING(request) || DNS_REQUEST_SENDING(request)) {
if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
if (request->dispentry != NULL) {
socket = dns_dispatch_getentrysocket(
request->dispentry);
}
} else
socket = dns_dispatch_getsocket(request->dispatch);
if (DNS_REQUEST_CONNECTING(request) && socket != NULL)
isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_CONNECT);
if (DNS_REQUEST_SENDING(request) && socket != NULL)
isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_SEND);
}
if (request->dispentry != NULL)
dns_dispatch_removeresponse(&request->dispentry, NULL);
if (DNS_REQUEST_CONNECTING(request)) {
socket = dns_dispatch_getsocket(request->dispatch);
isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_CONNECT);
}
if (DNS_REQUEST_SENDING(request)) {
socket = dns_dispatch_getsocket(request->dispatch);
isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_SEND);
}
dns_dispatch_detach(&request->dispatch);
}

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: resolver.c,v 1.372 2008/06/17 22:35:08 jinmei Exp $ */
/* $Id: resolver.c,v 1.373 2008/06/23 19:41:19 jinmei Exp $ */
/*! \file */
@@ -124,6 +124,7 @@ typedef struct query {
isc_mem_t * mctx;
dns_dispatchmgr_t * dispatchmgr;
dns_dispatch_t * dispatch;
isc_boolean_t exclusivesocket;
dns_adbaddrinfo_t * addrinfo;
isc_socket_t * tcpsocket;
isc_time_t start;
@@ -294,24 +295,6 @@ 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;
@@ -319,11 +302,6 @@ 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;
@@ -333,7 +311,9 @@ struct dns_resolver {
unsigned int options;
dns_dispatchmgr_t * dispatchmgr;
dns_dispatch_t * dispatchv4;
isc_boolean_t exclusivev4;
dns_dispatch_t * dispatchv6;
isc_boolean_t exclusivev6;
unsigned int ndisps;
unsigned int nbuckets;
fctxbucket_t * buckets;
@@ -352,7 +332,6 @@ 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;
@@ -366,9 +345,6 @@ struct dns_resolver {
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', '!')
@@ -603,6 +579,7 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
unsigned int factor;
dns_adbfind_t *find;
dns_adbaddrinfo_t *addrinfo;
isc_socket_t *socket;
query = *queryp;
fctx = query->fctx;
@@ -684,6 +661,38 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
0, factor);
}
/*
* Check for any outstanding socket events. If they exist, cancel
* them and let the event handlers finish the cleanup. The resolver
* only needs to worry about managing the connect and send events;
* the dispatcher manages the recv events.
*/
if (RESQUERY_CONNECTING(query)) {
/*
* Cancel the connect.
*/
if (query->tcpsocket != NULL) {
isc_socket_cancel(query->tcpsocket, NULL,
ISC_SOCKCANCEL_CONNECT);
} else if (query->dispentry != NULL) {
INSIST(query->exclusivesocket);
socket = dns_dispatch_getentrysocket(query->dispentry);
if (socket != NULL)
isc_socket_cancel(socket, NULL,
ISC_SOCKCANCEL_CONNECT);
}
} else if (RESQUERY_SENDING(query)) {
/*
* Cancel the pending send.
*/
if (query->exclusivesocket && query->dispentry != NULL)
socket = dns_dispatch_getentrysocket(query->dispentry);
else
socket = dns_dispatch_getsocket(query->dispatch);
if (socket != NULL)
isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_SEND);
}
if (query->dispentry != NULL)
dns_dispatch_removeresponse(&query->dispentry, deventp);
@@ -695,25 +704,6 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
if (query->tsigkey != NULL)
dns_tsigkey_detach(&query->tsigkey);
/*
* Check for any outstanding socket events. If they exist, cancel
* them and let the event handlers finish the cleanup. The resolver
* only needs to worry about managing the connect and send events;
* the dispatcher manages the recv events.
*/
if (RESQUERY_CONNECTING(query))
/*
* Cancel the connect.
*/
isc_socket_cancel(query->tcpsocket, NULL,
ISC_SOCKCANCEL_CONNECT);
else if (RESQUERY_SENDING(query))
/*
* Cancel the pending send.
*/
isc_socket_cancel(dns_dispatch_getsocket(query->dispatch),
NULL, ISC_SOCKCANCEL_SEND);
if (query->dispatch != NULL)
dns_dispatch_detach(&query->dispatch);
@@ -912,43 +902,25 @@ fctx_done(fetchctx_t *fctx, isc_result_t result) {
}
static void
resquery_senddone(isc_task_t *task, isc_event_t *event) {
process_sendevent(resquery_t *query, isc_event_t *event) {
isc_socketevent_t *sevent = (isc_socketevent_t *)event;
resquery_t *query = event->ev_arg;
isc_boolean_t retry = ISC_FALSE;
isc_result_t result;
fetchctx_t *fctx;
REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
QTRACE("senddone");
/*
* XXXRTH
*
* Currently we don't wait for the senddone event before retrying
* a query. This means that if we get really behind, we may end
* up doing extra work!
*/
UNUSED(task);
INSIST(RESQUERY_SENDING(query));
query->sends--;
fctx = query->fctx;
if (RESQUERY_CANCELED(query)) {
if (query->sends == 0) {
if (query->sends == 0 && query->connects == 0) {
/*
* This query was canceled while the
* isc_socket_sendto() was in progress.
* isc_socket_sendto/connect() was in progress.
*/
if (query->tcpsocket != NULL)
isc_socket_detach(&query->tcpsocket);
resquery_destroy(&query);
}
} else
} else {
switch (sevent->result) {
case ISC_R_SUCCESS:
break;
@@ -970,6 +942,7 @@ resquery_senddone(isc_task_t *task, isc_event_t *event) {
fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
break;
}
}
isc_event_free(&event);
@@ -987,6 +960,48 @@ resquery_senddone(isc_task_t *task, isc_event_t *event) {
}
}
static void
resquery_udpconnected(isc_task_t *task, isc_event_t *event) {
resquery_t *query = event->ev_arg;
REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
QTRACE("udpconnected");
UNUSED(task);
INSIST(RESQUERY_CONNECTING(query));
query->connects--;
process_sendevent(query, event);
}
static void
resquery_senddone(isc_task_t *task, isc_event_t *event) {
resquery_t *query = event->ev_arg;
REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
QTRACE("senddone");
/*
* XXXRTH
*
* Currently we don't wait for the senddone event before retrying
* a query. This means that if we get really behind, we may end
* up doing extra work!
*/
UNUSED(task);
INSIST(RESQUERY_SENDING(query));
query->sends--;
process_sendevent(query, event);
}
static inline isc_result_t
fctx_addopt(dns_message_t *message, unsigned int version,
isc_uint16_t udpsize, isc_boolean_t request_nsid)
@@ -1139,6 +1154,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
*/
query->dispatchmgr = res->dispatchmgr;
query->dispatch = NULL;
query->exclusivesocket = ISC_FALSE;
query->tcpsocket = NULL;
if (res->view->peers != NULL) {
dns_peer_t *peer = NULL;
@@ -1221,39 +1237,16 @@ 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->dispatchv4pool != NULL) {
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);
}
dns_dispatch_attach(res->dispatchv4,
&query->dispatch);
query->exclusivesocket = res->exclusivev4;
break;
case PF_INET6:
if (res->dispatchv6pool != NULL) {
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);
}
dns_dispatch_attach(res->dispatchv6,
&query->dispatch);
query->exclusivesocket = res->exclusivev6;
break;
default:
result = ISC_R_NOTIMPLEMENTED;
@@ -1449,13 +1442,14 @@ resquery_send(resquery_t *query) {
/*
* Get a query id from the dispatch.
*/
result = dns_dispatch_addresponse(query->dispatch,
&query->addrinfo->sockaddr,
task,
resquery_response,
query,
&query->id,
&query->dispentry);
result = dns_dispatch_addresponse2(query->dispatch,
&query->addrinfo->sockaddr,
task,
resquery_response,
query,
&query->id,
&query->dispentry,
res->socketmgr);
if (result != ISC_R_SUCCESS)
goto cleanup_temps;
@@ -1672,12 +1666,24 @@ resquery_send(resquery_t *query) {
*/
dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
socket = dns_dispatch_getsocket(query->dispatch);
if (query->exclusivesocket)
socket = dns_dispatch_getentrysocket(query->dispentry);
else
socket = dns_dispatch_getsocket(query->dispatch);
/*
* Send the query!
*/
if ((query->options & DNS_FETCHOPT_TCP) == 0)
if ((query->options & DNS_FETCHOPT_TCP) == 0) {
address = &query->addrinfo->sockaddr;
if (query->exclusivesocket) {
result = isc_socket_connect(socket, address, task,
resquery_udpconnected,
query);
if (result != ISC_R_SUCCESS)
goto cleanup_message;
query->connects++;
}
}
isc_buffer_usedregion(buffer, &r);
/*
@@ -2779,6 +2785,8 @@ fctx_destroy(fetchctx_t *fctx) {
static void
fctx_timeout(isc_task_t *task, isc_event_t *event) {
fetchctx_t *fctx = event->ev_arg;
isc_timerevent_t *tevent = (isc_timerevent_t *)event;
resquery_t *query;
REQUIRE(VALID_FCTX(fctx));
@@ -2794,8 +2802,18 @@ fctx_timeout(isc_task_t *task, isc_event_t *event) {
fctx->timeouts++;
/*
* We could cancel the running queries here, or we could let
* them keep going. Right now we choose the latter...
* them keep going. Since we normally use separate sockets for
* different queries, we adopt the former approach to reduce
* the number of open sockets: cancel the oldest query if it
* expired before the query had started (this is usually the
* case but is not always so, depending on the task schedule
* timing).
*/
query = ISC_LIST_HEAD(fctx->queries);
if (query != NULL &&
isc_time_compare(&tevent->due, &query->start) >= 0) {
fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
}
fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
/*
* Our timer has triggered. Reestablish the fctx lifetime
@@ -5659,6 +5677,19 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
* There's no hope for this query.
*/
keep_trying = ISC_TRUE;
/*
* If this is a network error on an exclusive query
* socket, mark the server as bad so that we won't try
* it for this fetch again.
*/
if (query->exclusivesocket &&
(devent->result == ISC_R_HOSTUNREACH ||
devent->result == ISC_R_NETUNREACH ||
devent->result == ISC_R_CONNREFUSED ||
devent->result == ISC_R_CANCELED)) {
broken_server = devent->result;
}
}
goto done;
}
@@ -6262,7 +6293,6 @@ destroy(dns_resolver_t *res) {
INSIST(res->nfctx == 0);
RES_DESTROYLOCK(&res->poollock);
DESTROYLOCK(&res->primelock);
DESTROYLOCK(&res->nlock);
DESTROYLOCK(&res->lock);
@@ -6279,26 +6309,12 @@ 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
@@ -6395,6 +6411,7 @@ dns_resolver_create(dns_view_t *view,
unsigned int i, buckets_created = 0;
isc_task_t *task = NULL;
char name[16];
unsigned dispattr;
/*
* Create a resolver.
@@ -6429,9 +6446,6 @@ dns_resolver_create(dns_view_t *view,
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->buckets = isc_mem_get(view->mctx,
@@ -6475,12 +6489,20 @@ dns_resolver_create(dns_view_t *view,
}
res->dispatchv4 = NULL;
if (dispatchv4 != NULL)
dns_dispatch_attach(dispatchv4, &res->dispatchv4);
if (dispatchv4 != NULL) {
dns_dispatch_attach(dispatchv4, &res->dispatchv4);
dispattr = dns_dispatch_getattributes(dispatchv4);
res->exclusivev4 =
ISC_TF((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0);
}
res->dispatchv6 = NULL;
if (dispatchv6 != NULL)
if (dispatchv6 != NULL) {
dns_dispatch_attach(dispatchv6, &res->dispatchv6);
dispattr = dns_dispatch_getattributes(dispatchv6);
res->exclusivev6 =
ISC_TF((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0);
}
res->references = 1;
res->exiting = ISC_FALSE;
@@ -6502,21 +6524,17 @@ 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_poollock;
goto cleanup_primelock;
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_poollock;
goto cleanup_primelock;
#if USE_ALGLOCK
result = isc_rwlock_init(&res->alglock, 0, 0);
@@ -6546,9 +6564,6 @@ dns_resolver_create(dns_view_t *view,
isc_timer_detach(&res->spillattimer);
#endif
cleanup_poollock:
RES_DESTROYLOCK(&res->poollock);
cleanup_primelock:
DESTROYLOCK(&res->primelock);
@@ -6770,12 +6785,12 @@ dns_resolver_shutdown(dns_resolver_t *res) {
fctx != NULL;
fctx = ISC_LIST_NEXT(fctx, link))
fctx_shutdown(fctx);
if (res->dispatchv4 != NULL) {
if (res->dispatchv4 != NULL && !res->exclusivev4) {
sock = dns_dispatch_getsocket(res->dispatchv4);
isc_socket_cancel(sock, res->buckets[i].task,
ISC_SOCKCANCEL_ALL);
}
if (res->dispatchv6 != NULL) {
if (res->dispatchv6 != NULL && !res->exclusivev6) {
sock = dns_dispatch_getsocket(res->dispatchv6);
isc_socket_cancel(sock, res->buckets[i].task,
ISC_SOCKCANCEL_ALL);
@@ -7459,245 +7474,3 @@ dns_resolver_getoptions(dns_resolver_t *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 = NULL, *disp6 = NULL;
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;
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;
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:
if (res->dispatchv4pool != NULL) {
for (i = 0; i < ndisps; i++)
if (res->dispatchv4pool[i] != NULL)
dns_dispatch_detach(&res->dispatchv4pool[i]);
isc_mem_put(res->mctx, res->dispatchv4pool,
sizeof(dns_dispatch_t *) * ndisps);
}
if (res->dispatchv6pool != NULL) {
for (i = 0; i < ndisps; i++)
if (res->dispatchv6pool[i] != NULL)
dns_dispatch_detach(&res->dispatchv6pool[i]);
isc_mem_put(res->mctx, res->dispatchv6pool,
sizeof(dns_dispatch_t *) * ndisps);
}
return (result);
}

View File

@@ -13,7 +13,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: Makefile.in,v 1.93 2007/09/14 03:39:29 marka Exp $
# $Id: Makefile.in,v 1.94 2008/06/23 19:41:19 jinmei Exp $
srcdir = @srcdir@
VPATH = @srcdir@
@@ -58,7 +58,7 @@ OBJS = @ISC_EXTRA_OBJS@ \
lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \
md5.@O@ mem.@O@ mutexblock.@O@ \
netaddr.@O@ netscope.@O@ ondestroy.@O@ \
parseint.@O@ quota.@O@ radix.@O@ random.@O@ \
parseint.@O@ portset.@O@ quota.@O@ radix.@O@ random.@O@ \
ratelimiter.@O@ refcount.@O@ region.@O@ result.@O@ rwlock.@O@ \
serial.@O@ sha1.@O@ sha2.@O@ sockaddr.@O@ \
string.@O@ strtoul.@O@ symtab.@O@ task.@O@ taskpool.@O@ \
@@ -73,7 +73,7 @@ SRCS = @ISC_EXTRA_SRCS@ \
lex.c lfsr.c lib.c log.c \
md5.c mem.c mutexblock.c \
netaddr.c netscope.c ondestroy.c \
parseint.c quota.c radix.c random.c \
parseint.c portset.c quota.c radix.c random.c \
ratelimiter.c refcount.c region.c result.c rwlock.c \
serial.c sha1.c sha2.c sockaddr.c string.c strtoul.c \
symtab.c task.c taskpool.c timer.c version.c

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: platform.h.in,v 1.47 2008/01/24 23:47:00 tbox Exp $ */
/* $Id: platform.h.in,v 1.48 2008/06/23 19:41:19 jinmei Exp $ */
#ifndef ISC_PLATFORM_H
#define ISC_PLATFORM_H 1
@@ -136,6 +136,21 @@
*/
@ISC_PLATFORM_FIXIN6ISADDR@
/*! \brief
* Define if the system supports kqueue multiplexing
*/
@ISC_PLATFORM_HAVEKQUEUE@
/*! \brief
* Define if the system supports epoll multiplexing
*/
@ISC_PLATFORM_HAVEEPOLL@
/*! \brief
* Define if the system supports /dev/poll multiplexing
*/
@ISC_PLATFORM_HAVEDEVPOLL@
/*
*** Printing.
***/

View File

@@ -0,0 +1,141 @@
/*
* Copyright (C) 2008 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: portset.h,v 1.2 2008/06/23 19:41:19 jinmei Exp $ */
/*! \file isc/portset.h
* \brief Transport Protocol Port Manipuration Module
*
* This module provides simple utilities to handle a set of transport protocol
* (UDP or TCP) port numbers, e.g., for creating an ACL list. An isc_portset_t
* object is an opaque instance of a port set, for which the user can add or
* remove a specific port or a range of consecutive ports. This object is
* expected to be used as a temporary work space only, and does not protect
* simultaneous access from multiple threads. Therefore it must not be stored
* in a place that can be accessed from multiple threads.
*/
#ifndef ISC_PORTSET_H
#define ISC_PORTSET_H 1
/***
*** Imports
***/
#include <isc/net.h>
/***
*** Functions
***/
ISC_LANG_BEGINDECLS
isc_result_t
isc_portset_create(isc_mem_t *mctx, isc_portset_t **portsetp);
/*%<
* Create a port set and initialize it as an empty set.
*
* Requires:
*\li 'mctx' to be valid.
*\li 'portsetp' to be non NULL and '*portsetp' to be NULL;
*
* Returns:
*\li #ISC_R_SUCCESS
*\li #ISC_R_NOMEMORY
*/
void
isc_portset_destroy(isc_mem_t *mctx, isc_portset_t **portsetp);
/*%<
* Destroy a port set.
*
* Requires:
*\li 'mctx' to be valid and must be the same context given when the port set
* was created.
*\li '*portsetp' to be a valid set.
*/
isc_boolean_t
isc_portset_isset(isc_portset_t *portset, in_port_t port);
/*%<
* Test whether the given port is stored in the portset.
*
* Requires:
*\li 'portset' to be a valid set.
*
* Returns
* \li #ISC_TRUE if the port is found, ISC_FALSE otherwise.
*/
unsigned int
isc_portset_nports(isc_portset_t *portset);
/*%<
* Provides the number of ports stored in the given portset.
*
* Requires:
*\li 'portset' to be a valid set.
*
* Returns
* \li the number of ports stored in portset.
*/
void
isc_portset_add(isc_portset_t *portset, in_port_t port);
/*%<
* Add the given port to the portset. The port may or may not be stored in
* the portset.
*
* Requires:
*\li 'portlist' to be valid.
*/
void
isc_portset_remove(isc_portset_t *portset, in_port_t port);
/*%<
* Remove the given port to the portset. The port may or may not be stored in
* the portset.
*
* Requires:
*\li 'portlist' to be valid.
*/
void
isc_portset_addrange(isc_portset_t *portset, in_port_t port_lo,
in_port_t port_hi);
/*%<
* Add a subset of [port_lo, port_hi] (inclusive) to the portset. Ports in the
* subset may or may not be stored in portset.
*
* Requires:
*\li 'portlist' to be valid.
*\li port_lo <= port_hi
*/
void
isc_portset_removerange(isc_portset_t *portset, in_port_t port_lo,
in_port_t port_hi);
/*%<
* Subtract a subset of [port_lo, port_hi] (inclusive) from the portset. Ports
* in the subset may or may not be stored in portset.
*
* Requires:
*\li 'portlist' to be valid.
*\li port_lo <= port_hi
*/
ISC_LANG_ENDDECLS
#endif /* ISC_NETADDR_H */

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: socket.h,v 1.74 2008/06/04 23:47:11 tbox Exp $ */
/* $Id: socket.h,v 1.75 2008/06/23 19:41:19 jinmei Exp $ */
#ifndef ISC_SOCKET_H
#define ISC_SOCKET_H 1
@@ -360,6 +360,45 @@ isc_socket_detach(isc_socket_t **socketp);
* All resources used by the socket have been freed
*/
isc_result_t
isc_socket_open(isc_socket_t *sock);
/*%<
* Open a new socket file descriptor of the given socket structure. It simply
* opens a new descriptor; all of the other parameters including the socket
* type are inherited from the existing socket. This function is provided to
* avoid overhead of destroying and creating sockets when many short-lived
* sockets are frequently opened and closed. When the efficiency is not an
* issue, it should be safer to detach the unused socket and re-create a new
* one.
*
* Requires:
*
* \li there must be no other reference to this socket.
*
* \li 'socket' is a valid and previously closed by isc_socket_close()
*
* Returns:
* Same as isc_socket_create().
*/
void
isc_socket_close(isc_socket_t *sock);
/*%<
* Close a socket file descriptor of the given socket structure. This function
* is provided as an alternative to destroying an unused socket when overhead
* destroying/re-creating sockets can be significant, and is expected to be
* used with isc_socket_open().
*
* Requires:
*
* \li The socket must have a valid descriptor.
*
* \li There must be no other reference to this socket.
*
* \li There must be no pending I/O requests.
*
*/
isc_result_t
isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *addressp);
/*%<

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: timer.h,v 1.38 2007/06/19 23:47:18 tbox Exp $ */
/* $Id: timer.h,v 1.39 2008/06/23 19:41:19 jinmei Exp $ */
#ifndef ISC_TIMER_H
#define ISC_TIMER_H 1
@@ -76,6 +76,7 @@
#include <isc/event.h>
#include <isc/eventclass.h>
#include <isc/lang.h>
#include <isc/time.h>
ISC_LANG_BEGINDECLS
@@ -93,6 +94,7 @@ typedef enum {
typedef struct isc_timerevent {
struct isc_event common;
isc_time_t due;
} isc_timerevent_t;
#define ISC_TIMEREVENT_FIRSTEVENT (ISC_EVENTCLASS_TIMER + 0)

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: types.h,v 1.45 2008/01/17 23:47:00 tbox Exp $ */
/* $Id: types.h,v 1.46 2008/06/23 19:41:19 jinmei Exp $ */
#ifndef ISC_TYPES_H
#define ISC_TYPES_H 1
@@ -70,6 +70,7 @@ typedef struct isc_mempool isc_mempool_t; /*%< Memory Pool */
typedef struct isc_msgcat isc_msgcat_t; /*%< Message Catalog */
typedef struct isc_ondestroy isc_ondestroy_t; /*%< On Destroy */
typedef struct isc_netaddr isc_netaddr_t; /*%< Net Address */
typedef struct isc_portset isc_portset_t; /*%< Port Set */
typedef struct isc_quota isc_quota_t; /*%< Quota */
typedef struct isc_random isc_random_t; /*%< Random */
typedef struct isc_ratelimiter isc_ratelimiter_t; /*%< Rate Limiter */

140
lib/isc/portset.c Normal file
View File

@@ -0,0 +1,140 @@
/*
* Copyright (C) 2008 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: portset.c,v 1.2 2008/06/23 19:41:19 jinmei Exp $ */
/*! \file */
#include <isc/mem.h>
#include <isc/portset.h>
#include <isc/string.h>
#include <isc/types.h>
#include <isc/util.h>
#define ISC_PORTSET_BUFSIZE (65536 / (sizeof(isc_uint32_t) * 8))
/*%
* Internal representation of portset. It's an array of 32-bit integers, each
* bit corresponding to a single port in the ascending order. For example,
* the second most significant bit of buf[0] corresponds to port 1.
*/
struct isc_portset {
unsigned int nports; /*%< number of ports in the set */
isc_uint32_t buf[ISC_PORTSET_BUFSIZE];
};
static inline isc_boolean_t
portset_isset(isc_portset_t *portset, in_port_t port) {
return (ISC_TF((portset->buf[port >> 5] & (1 << (port & 31))) != 0));
}
static inline void
portset_add(isc_portset_t *portset, in_port_t port) {
if (!portset_isset(portset, port)) {
portset->nports++;
portset->buf[port >> 5] |= (1 << (port & 31));
}
}
static inline void
portset_remove(isc_portset_t *portset, in_port_t port) {
if (portset_isset(portset, port)) {
portset->nports--;
portset->buf[port >> 5] &= ~(1 << (port & 31));
}
}
isc_result_t
isc_portset_create(isc_mem_t *mctx, isc_portset_t **portsetp) {
isc_portset_t *portset;
REQUIRE(portsetp != NULL && *portsetp == NULL);
portset = isc_mem_get(mctx, sizeof(*portset));
if (portset == NULL)
return (ISC_R_NOMEMORY);
/* Make the set 'empty' by default */
memset(portset, 0, sizeof(*portset));
*portsetp = portset;
return (ISC_R_SUCCESS);
}
void
isc_portset_destroy(isc_mem_t *mctx, isc_portset_t **portsetp) {
isc_portset_t *portset;
REQUIRE(portsetp != NULL);
portset = *portsetp;
isc_mem_put(mctx, portset, sizeof(*portset));
}
isc_boolean_t
isc_portset_isset(isc_portset_t *portset, in_port_t port) {
REQUIRE(portset != NULL);
return (portset_isset(portset, port));
}
unsigned int
isc_portset_nports(isc_portset_t *portset) {
REQUIRE(portset != NULL);
return (portset->nports);
}
void
isc_portset_add(isc_portset_t *portset, in_port_t port) {
REQUIRE(portset != NULL);
portset_add(portset, port);
}
void
isc_portset_remove(isc_portset_t *portset, in_port_t port) {
portset_remove(portset, port);
}
void
isc_portset_addrange(isc_portset_t *portset, in_port_t port_lo,
in_port_t port_hi)
{
in_port_t p;
REQUIRE(portset != NULL);
REQUIRE(port_lo <= port_hi);
p = port_lo;
do {
portset_add(portset, p);
} while (p++ < port_hi);
}
void
isc_portset_removerange(isc_portset_t *portset, in_port_t port_lo,
in_port_t port_hi)
{
in_port_t p;
REQUIRE(portset != NULL);
REQUIRE(port_lo <= port_hi);
p = port_lo;
do {
portset_remove(portset, p);
} while (p++ < port_hi);
}

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: timer.c,v 1.81 2007/10/24 00:57:23 marka Exp $ */
/* $Id: timer.c,v 1.82 2008/06/23 19:41:19 jinmei Exp $ */
/*! \file */
@@ -577,7 +577,7 @@ isc_timer_detach(isc_timer_t **timerp) {
static void
dispatch(isc_timermgr_t *manager, isc_time_t *now) {
isc_boolean_t done = ISC_FALSE, post_event, need_schedule;
isc_event_t *event;
isc_timerevent_t *event;
isc_eventtype_t type = 0;
isc_timer_t *timer;
isc_result_t result;
@@ -650,16 +650,18 @@ dispatch(isc_timermgr_t *manager, isc_time_t *now) {
/*
* XXX We could preallocate this event.
*/
event = isc_event_allocate(manager->mctx,
event = (isc_timerevent_t *)isc_event_allocate(manager->mctx,
timer,
type,
timer->action,
timer->arg,
sizeof(*event));
if (event != NULL)
isc_task_send(timer->task, &event);
else
if (event != NULL) {
event->due = timer->due;
isc_task_send(timer->task,
(isc_event_t **)&event);
} else
UNEXPECTED_ERROR(__FILE__, __LINE__,
isc_msgcat_get(isc_msgcat,
ISC_MSGSET_TIMER,

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: app.c,v 1.57 2008/01/18 23:46:58 tbox Exp $ */
/* $Id: app.c,v 1.58 2008/06/23 19:41:19 jinmei Exp $ */
/*! \file */
@@ -30,6 +30,9 @@
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#ifdef HAVE_EPOLL
#include <sys/epoll.h>
#endif
#include <isc/app.h>
#include <isc/boolean.h>
@@ -303,8 +306,7 @@ evloop() {
int n;
isc_time_t when, now;
struct timeval tv, *tvp;
fd_set readfds, writefds;
int maxfd;
isc_socketwait_t *swait;
isc_boolean_t readytasks;
isc_boolean_t call_timer_dispatch = ISC_FALSE;
@@ -331,8 +333,8 @@ evloop() {
}
}
isc__socketmgr_getfdsets(&readfds, &writefds, &maxfd);
n = select(maxfd, &readfds, &writefds, NULL, tvp);
swait = NULL;
n = isc__socketmgr_waitevents(tvp, &swait);
if (n == 0 || call_timer_dispatch) {
/*
@@ -352,8 +354,7 @@ evloop() {
isc__timermgr_dispatch();
}
if (n > 0)
(void)isc__socketmgr_dispatch(&readfds, &writefds,
maxfd);
(void)isc__socketmgr_dispatch(swait);
(void)isc__taskmgr_dispatch();
if (want_reload) {

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: net.h,v 1.46 2007/06/19 23:47:19 tbox Exp $ */
/* $Id: net.h,v 1.47 2008/06/23 19:41:20 jinmei Exp $ */
#ifndef ISC_NET_H
#define ISC_NET_H 1
@@ -324,6 +324,23 @@ isc_net_probeunix(void);
* Returns whether UNIX domain sockets are supported.
*/
isc_result_t
isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high);
/*%<
* Returns system's default range of ephemeral UDP ports, if defined.
* If the range is not available or unknown, ISC_NET_PORTRANGELOW and
* ISC_NET_PORTRANGEHIGH will be returned.
*
* Requires:
*
*\li 'low' and 'high' must be non NULL.
*
* Returns:
*
*\li *low and *high will be the ports specifying the low and high ends of
* the range.
*/
#ifdef ISC_PLATFORM_NEEDNTOP
const char *
isc_net_ntop(int af, const void *src, char *dst, size_t size);

View File

@@ -15,10 +15,13 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: net.c,v 1.36 2007/09/13 04:45:18 each Exp $ */
/* $Id: net.c,v 1.37 2008/06/23 19:41:19 jinmei Exp $ */
#include <config.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <errno.h>
#include <unistd.h>
@@ -30,6 +33,50 @@
#include <isc/string.h>
#include <isc/util.h>
/*%
* Definitions about UDP port range specification. This is a total mess of
* portability variants: some use sysctl (but the sysctl names vary), some use
* system-specific interfaces, some have the same interface for IPv4 and IPv6,
* some separate them, etc...
*/
/*%
* The last resort defaults: use all non well known port space
*/
#ifndef ISC_NET_PORTRANGELOW
#define ISC_NET_PORTRANGELOW 1024
#endif /* ISC_NET_PORTRANGELOW */
#ifndef ISC_NET_PORTRANGEHIGH
#define ISC_NET_PORTRANGEHIGH 65535
#endif /* ISC_NET_PORTRANGEHIGH */
/*%
* sysctl variants
*/
#if defined(__FreeBSD__) || defined(__APPLE__)
#define USE_SYSCTL_PORTRANGE
#define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.portrange.first"
#define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.portrange.last"
#define SYSCTL_V6PORTRANGE_LOW "net.inet.ip.portrange.first"
#define SYSCTL_V6PORTRANGE_HIGH "net.inet.ip.portrange.last"
#endif
#ifdef __NetBSD__
#define USE_SYSCTL_PORTRANGE
#define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.anonportmin"
#define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.anonportmax"
#define SYSCTL_V6PORTRANGE_LOW "net.inet6.ip6.portrange.first"
#define SYSCTL_V6PORTRANGE_HIGH "net.inet6.ip6.portrange.last"
#endif
#ifdef __OpenBSD__
#define USE_SYSCTL_PORTRANGE
#define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.portfirst"
#define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.portlast"
#define SYSCTL_V6PORTRANGE_LOW "net.inet6.ip6.portrange.first"
#define SYSCTL_V6PORTRANGE_HIGH "net.inet6.ip6.portrange.last"
#endif
#if defined(ISC_PLATFORM_HAVEIPV6)
# if defined(ISC_PLATFORM_NEEDIN6ADDRANY)
const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
@@ -338,6 +385,60 @@ isc_net_probe_ipv6pktinfo(void) {
return (ipv6pktinfo_result);
}
#ifdef USE_SYSCTL_PORTRANGE
static isc_result_t
getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) {
int port_low, port_high;
size_t portlen;
const char *sysctlname_lowport, *sysctlname_hiport;
if (af == AF_INET) {
sysctlname_lowport = SYSCTL_V4PORTRANGE_LOW;
sysctlname_hiport = SYSCTL_V4PORTRANGE_HIGH;
} else {
sysctlname_lowport = SYSCTL_V6PORTRANGE_LOW;
sysctlname_hiport = SYSCTL_V6PORTRANGE_HIGH;
}
portlen = sizeof(portlen);
if (sysctlbyname(sysctlname_lowport, &port_low, &portlen,
NULL, 0) < 0) {
return (ISC_R_FAILURE);
}
portlen = sizeof(portlen);
if (sysctlbyname(sysctlname_hiport, &port_high, &portlen,
NULL, 0) < 0) {
return (ISC_R_FAILURE);
}
if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0)
return (ISC_R_RANGE);
*low = (in_port_t)port_low;
*high = (in_port_t)port_high;
return (ISC_R_SUCCESS);
}
#endif
isc_result_t
isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
int result = ISC_R_FAILURE;
REQUIRE(low != NULL && high != NULL);
#ifdef USE_SYSCTL_PORTRANGE
result = getudpportrange_sysctl(af, low, high);
#else
UNUSED(af);
#endif
if (result != ISC_R_SUCCESS) {
*low = ISC_NET_PORTRANGELOW;
*high = ISC_NET_PORTRANGEHIGH;
}
return (ISC_R_SUCCESS); /* we currently never fail in this function */
}
void
isc_net_disableipv4(void) {
initialize();

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: socket_p.h,v 1.11 2007/06/19 23:47:18 tbox Exp $ */
/* $Id: socket_p.h,v 1.12 2008/06/23 19:41:20 jinmei Exp $ */
#ifndef ISC_SOCKET_P_H
#define ISC_SOCKET_P_H
@@ -26,10 +26,7 @@
#include <sys/select.h>
#endif
void
isc__socketmgr_getfdsets(fd_set *readset, fd_set *writeset, int *maxfd);
isc_result_t
isc__socketmgr_dispatch(fd_set *readset, fd_set *writeset, int maxfd);
typedef struct isc_socketwait isc_socketwait_t;
int isc__socketmgr_waitevents(struct timeval *, isc_socketwait_t **);
isc_result_t isc__socketmgr_dispatch(isc_socketwait_t *);
#endif /* ISC_SOCKET_P_H */

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: namedconf.c,v 1.87 2008/04/03 02:01:08 marka Exp $ */
/* $Id: namedconf.c,v 1.88 2008/06/23 19:41:20 jinmei Exp $ */
/*! \file */
@@ -547,11 +547,19 @@ static cfg_type_t cfg_type_serverid = {
/*%
* Port list.
*/
static isc_result_t
parse_port(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
isc_result_t result;
static cfg_tuplefielddef_t porttuple_fields[] = {
{ "loport", &cfg_type_uint32, 0 },
{ "hiport", &cfg_type_uint32, 0 },
{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_porttuple = {
"porttuple", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
&cfg_rep_tuple, porttuple_fields
};
UNUSED(type);
static isc_result_t
parse_port(cfg_parser_t *pctx, cfg_obj_t **ret) {
isc_result_t result;
CHECK(cfg_parse_uint32(pctx, NULL, ret));
if ((*ret)->value.uint32 > 0xffff) {
@@ -559,18 +567,60 @@ parse_port(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
cfg_obj_destroy(pctx, ret);
result = ISC_R_RANGE;
}
cleanup:
return (result);
}
static cfg_type_t cfg_type_port = {
"port", parse_port, NULL, cfg_doc_terminal,
static isc_result_t
parse_portrange(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
isc_result_t result;
cfg_obj_t *obj = NULL;
UNUSED(type);
CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
if (pctx->token.type == isc_tokentype_number)
CHECK(parse_port(pctx, ret));
else {
CHECK(cfg_gettoken(pctx, 0));
if (pctx->token.type != isc_tokentype_string ||
strcasecmp(TOKEN_STRING(pctx), "range") != 0) {
cfg_parser_error(pctx, CFG_LOG_NEAR,
"expected integer or 'range'");
return (ISC_R_UNEXPECTEDTOKEN);
}
CHECK(cfg_create_tuple(pctx, &cfg_type_porttuple, &obj));
CHECK(parse_port(pctx, &obj->value.tuple[0]));
CHECK(parse_port(pctx, &obj->value.tuple[1]));
if (obj->value.tuple[0]->value.uint32 >
obj->value.tuple[1]->value.uint32) {
cfg_parser_error(pctx, CFG_LOG_NOPREP,
"low port '%u' must not be larger "
"than high port",
obj->value.tuple[0]->value.uint32);
result = ISC_R_RANGE;
goto cleanup;
}
*ret = obj;
obj = NULL;
}
cleanup:
if (obj != NULL)
cfg_obj_destroy(pctx, &obj);
return (result);
}
static cfg_type_t cfg_type_portrange = {
"portrange", parse_portrange, NULL, cfg_doc_terminal,
NULL, NULL
};
static cfg_type_t cfg_type_bracketed_portlist = {
"bracketed_sockaddrlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
&cfg_rep_list, &cfg_type_port
"bracketed_sockaddrlist", cfg_parse_bracketed_list,
cfg_print_bracketed_list, cfg_doc_bracketed_list,
&cfg_rep_list, &cfg_type_portrange
};
/*%
@@ -611,6 +661,8 @@ namedconf_or_view_clauses[] = {
*/
static cfg_clausedef_t
options_clauses[] = {
{ "use-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
{ "use-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
{ "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
{ "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
{ "blackhole", &cfg_type_bracketed_aml, 0 },
@@ -782,8 +834,9 @@ view_clauses[] = {
*/
{ "query-source", &cfg_type_querysource4, 0 },
{ "query-source-v6", &cfg_type_querysource6, 0 },
{ "queryport-pool-ports", &cfg_type_uint32, 0 },
{ "queryport-pool-updateinterval", &cfg_type_uint32, 0 },
{ "queryport-pool-ports", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
{ "queryport-pool-updateinterval", &cfg_type_uint32,
CFG_CLAUSEFLAG_OBSOLETE },
{ "recursion", &cfg_type_boolean, 0 },
{ "request-ixfr", &cfg_type_boolean, 0 },
{ "request-nsid", &cfg_type_boolean, 0 },
@@ -794,7 +847,7 @@ view_clauses[] = {
{ "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
{ "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP },
{ "transfer-format", &cfg_type_transferformat, 0 },
{ "use-queryport-pool", &cfg_type_boolean, 0 },
{ "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
{ "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 },
{ NULL, NULL, 0 }
};