]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2129. [func] Provide a pool of UDP sockets for queries to be
authorMark Andrews <marka@isc.org>
Fri, 2 Feb 2007 02:18:06 +0000 (02:18 +0000)
committerMark Andrews <marka@isc.org>
Fri, 2 Feb 2007 02:18:06 +0000 (02:18 +0000)
                        made over. See use-queryport-pool, queryport-pool-ports
                        and queryport-pool-updateinterval.  [RT #16415]

CHANGES
bin/named/interfacemgr.c
bin/named/named.conf.docbook
bin/named/server.c
doc/arm/Bv9ARM-book.xml
lib/dns/dispatch.c
lib/dns/include/dns/dispatch.h
lib/dns/include/dns/resolver.h
lib/dns/resolver.c
lib/isccfg/namedconf.c

diff --git a/CHANGES b/CHANGES
index 3243047d2a24177c45aad96c6c2d0d2385a16bbb..bc36ef13a02ea354b05c1887f405e01e7c157abb 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -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]
index ddece0bca2d231d9389b1c9ccd767c1da66b827f..fd5a6ead9731bd66db184f2235828f9383c95e57 100644 (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;
index d2e0810c89473ea3d511ddb803f8724076ac7655..02299b582863ee54a84f3ed5f6b784bdab3e7061 100644 (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>;
index 889300e79d4b214efc808f6d18cf9c0d8e219f81..e45d51205c351df006de57de2c0c497457c4f057 100644 (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.
         */
@@ -1241,7 +1323,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
        result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj);
        INSIST(result == ISC_R_SUCCESS);
        dns_resolver_setzeronosoattl(view->resolver, cfg_obj_asboolean(obj));
-       
+
        /*
         * Set the resolver's EDNS UDP size.
         */
@@ -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;
        }
index 29b3b1ba28f0e9094baf2cacceea1cd6b5728f55..7a806cda4114b40c99666dd663343b3043f2589f 100644 (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>
index 2a12d3cb71695a2926a3e16468a6a9542bf14bc2..db8b603b589d9a3d4bcff65b5abeef85ffb73df1 100644 (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 (result != ISC_R_SUCCESS)
-               return (ISC_FALSE);
+       if (sock != NULL) {
+               sockaddrp = &sockaddr;
+               result = isc_socket_getsockname(sock, sockaddrp);
+               if (result != ISC_R_SUCCESS)
+                       return (ISC_FALSE);
+       }
 
-       if (mgr->portlist != NULL &&
-           dns_portlist_match(mgr->portlist, isc_sockaddr_pf(&sockaddr),
-                              isc_sockaddr_getport(&sockaddr)))
+       if (dns_portlist_match(mgr->portlist, isc_sockaddr_pf(sockaddrp),
+                              isc_sockaddr_getport(sockaddrp)))
                return (ISC_TRUE);
        return (ISC_FALSE);
 }
@@ -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:
-       result = create_socket(sockmgr, localaddr, &sock);
+       if ((attributes & DNS_DISPATCHATTR_RANDOMPORT) != 0) {
+               isc_sockaddr_setport(&localaddr_bound,
+                                    get_randomport(mgr->qid));
+               if (blacklisted(mgr, NULL, &localaddr_bound)) {
+                       if (++k == 1024)
+                               attributes &= ~DNS_DISPATCHATTR_RANDOMPORT;
+                       goto getsocket;
+               }
+               result = create_socket(sockmgr, &localaddr_bound, &sock);
+               if (result == ISC_R_ADDRINUSE) {
+                       if (++k == 1024)
+                               attributes &= ~DNS_DISPATCHATTR_RANDOMPORT;
+                       goto getsocket;
+               }
+       } else 
+               result = create_socket(sockmgr, localaddr, &sock);
        if (result != ISC_R_SUCCESS)
                goto deallocate_dispatch;
-       if (isc_sockaddr_getport(localaddr) == 0 && blacklisted(mgr, sock)) {
+       if ((attributes & DNS_DISPATCHATTR_RANDOMPORT) == 0 &&
+           isc_sockaddr_getport(localaddr) == 0 &&
+           blacklisted(mgr, sock, NULL))
+       {
                if (held[i] != NULL)
                        isc_socket_detach(&held[i]);
                held[i++] = sock;
index ed6cec5373fb5a6f9412f44308ff53eecd1d4377..dc65a50d731322223252f7197699abe28aff4f99 100644 (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
index 163018dce5cc659732b4a52dac18d5000c1850eb..d23e9869c1a0fad19bcaa572d130167654e1e744 100644 (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 */
index e11f6f618f736b3865fe85e775db8dd72900dfb1..52b142c99e1cbd7e3e4a13cb53acfd961bff9cb3 100644 (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,13 +291,36 @@ 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;
        isc_mem_t *                     mctx;
        isc_mutex_t                     lock;
        isc_mutex_t                     nlock;  
-       isc_mutex_t                     primelock;      
+       isc_mutex_t                     primelock;
+#if DNS_RESOLVER_USERWLOCK
+       isc_rwlock_t                    poollock;
+#else
+       isc_mutex_t                     poollock;
+#endif
        dns_rdataclass_t                rdclass;
        isc_socketmgr_t *               socketmgr;
        isc_timermgr_t *                timermgr;
@@ -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:
-                               dns_dispatch_attach(res->dispatchv4,
-                                                   &query->dispatch);
+                               if (res->ndisps > 0) {
+                                       RES_LOCK(&res->poollock,
+                                                isc_rwlocktype_read);
+                                       dns_dispatch_attach(res->dispatchv4pool[did],
+                                                           &query->dispatch);
+                                       RES_UNLOCK(&res->poollock,
+                                                  isc_rwlocktype_read);
+                               } else {
+                                       dns_dispatch_attach(res->dispatchv4,
+                                                           &query->dispatch);
+                               }
                                break;
                        case PF_INET6:
-                               dns_dispatch_attach(res->dispatchv6,
-                                                   &query->dispatch);
+                               if (res->ndisps > 0) {
+                                       RES_LOCK(&res->poollock,
+                                                isc_rwlocktype_read);
+                                       dns_dispatch_attach(res->dispatchv6pool[did],
+                                                           &query->dispatch);
+                                       RES_UNLOCK(&res->poollock,
+                                                  isc_rwlocktype_read);
+                               } else {
+                                       dns_dispatch_attach(res->dispatchv6,
+                                                           &query->dispatch);
+                               }
                                break;
                        default:
                                result = ISC_R_NOTIMPLEMENTED;
@@ -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;
@@ -6147,7 +6222,8 @@ dns_resolver_create(dns_view_t *view,
 
        res->dispatchv4 = NULL;
        if (dispatchv4 != NULL)
-               dns_dispatch_attach(dispatchv4, &res->dispatchv4);
+                       dns_dispatch_attach(dispatchv4, &res->dispatchv4);
+
        res->dispatchv6 = NULL;
        if (dispatchv6 != NULL)
                dns_dispatch_attach(dispatchv6, &res->dispatchv6);
@@ -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);
+}
index dad4e54ad172a7ab017e97a4267e358afa4e43c3..a7eac1ca17e5e0dc930856f6e597897c9deecb59 100644 (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 }
 };