This is revision 2 of this patch (compared the previous patch, it
removes a noisy log message that was a side effect of the privsep
we added to our version of BIND.

Apply by doing:
       cd /usr/src
       patch -p0 < 013_bind.patch

Then rebuild and install bind:
       cd usr.sbin/bind
       make -f Makefile.bsd-wrapper obj
       make -f Makefile.bsd-wrapper
       make -f Makefile.bsd-wrapper install

Index: usr.sbin/bind/README.OpenBSD
===================================================================
RCS file: /cvs/src/usr.sbin/bind/README.OpenBSD,v
retrieving revision 1.8
retrieving revision 1.8.12.1
diff -u -p -r1.8 -r1.8.12.1
--- usr.sbin/bind/README.OpenBSD        28 Sep 2004 17:14:01 -0000      1.8
+++ usr.sbin/bind/README.OpenBSD        23 Jul 2008 17:59:55 -0000      1.8.12.1
@@ -1,11 +1,11 @@
-$OpenBSD: README.OpenBSD,v 1.8 2004/09/28 17:14:01 jakob Exp $
+$OpenBSD: README.OpenBSD,v 1.8.12.1 2008/07/23 17:59:55 brad Exp $

additional features

- write pid-file before chroot
- privilege separation for binding to privileged ports from within chroot
-- add LCG (Linear Congruential Generator) implementation to libisc
-- use LCG instead of LFSR for ID generation until LFSR is proven reliable
+- add 64K entry shuffle (somewhat like Fisher-Yates) implementation to libisc
+- use shuffle instead of LFSR for ID generation
- strlcpy/strlcat/snprintf fixes

default parameter changes
Index: usr.sbin/bind/bin/named/server.c
===================================================================
RCS file: /cvs/src/usr.sbin/bind/bin/named/server.c,v
retrieving revision 1.14
retrieving revision 1.14.4.1
diff -u -p -r1.14 -r1.14.4.1
--- usr.sbin/bind/bin/named/server.c    10 Jan 2007 19:07:58 -0000      1.14
+++ usr.sbin/bind/bin/named/server.c    23 Jul 2008 17:59:55 -0000      1.14.4.1
@@ -477,6 +477,14 @@ get_view_querysource_dispatch(const cfg_
               attrs |= DNS_DISPATCHATTR_IPV6;
               break;
       }
+
+       if (isc_sockaddr_getport(&sa) != 0) {
+               INSIST(obj != NULL);
+               cfg_obj_log(obj, ns_g_lctx, ISC_LOG_INFO,
+                           "using specific query-source port suppresses port "
+                           "randomization and can be insecure.");
+       }
+
       attrmask = 0;
       attrmask |= DNS_DISPATCHATTR_UDP;
       attrmask |= DNS_DISPATCHATTR_TCP;
@@ -486,7 +494,7 @@ get_view_querysource_dispatch(const cfg_
       disp = NULL;
       result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
                                    ns_g_taskmgr, &sa, 4096,
-                                    1000, 32768, 16411, 16433,
+                                    1024, 32768, 16411, 16433,
                                    attrs, attrmask, &disp);
       if (result != ISC_R_SUCCESS) {
               isc_sockaddr_t any;
@@ -1858,7 +1866,9 @@ scan_interfaces(ns_server_t *server, isc
}

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;
@@ -1868,7 +1878,8 @@ add_listenelt(isc_mem_t *mctx, ns_listen
       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;
@@ -1927,7 +1938,16 @@ adjust_interfaces(ns_server_t *server, i
               result = dns_dispatch_getlocaladdress(dispatch6, &addr);
               if (result != ISC_R_SUCCESS)
                       goto fail;
-               result = add_listenelt(mctx, list, &addr);
+
+               /*
+                * 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;
       }
@@ -1957,12 +1977,12 @@ adjust_interfaces(ns_server_t *server, i
                       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: usr.sbin/bind/lib/dns/dispatch.c
===================================================================
RCS file: /cvs/src/usr.sbin/bind/lib/dns/dispatch.c,v
retrieving revision 1.6
retrieving revision 1.6.4.1
diff -u -p -r1.6 -r1.6.4.1
--- usr.sbin/bind/lib/dns/dispatch.c    10 Jan 2007 19:07:59 -0000      1.6
+++ usr.sbin/bind/lib/dns/dispatch.c    23 Jul 2008 17:59:55 -0000      1.6.4.1
@@ -22,10 +22,11 @@
#include <stdlib.h>

#include <isc/entropy.h>
-#include <isc/lcg.h>
#include <isc/mem.h>
#include <isc/mutex.h>
#include <isc/print.h>
+#include <isc/random.h>
+#include <isc/shuffle.h>
#include <isc/string.h>
#include <isc/task.h>
#include <isc/util.h>
@@ -46,10 +47,18 @@ typedef struct dns_qid {
       unsigned int    qid_nbuckets;   /* hash table size */
       unsigned int    qid_increment;  /* id increment on collision */
       isc_mutex_t     lock;
-       isc_lcg_t       qid_lcg;        /* state generator info */
       dns_displist_t  *qid_table;     /* the table itself */
+       isc_shuffle_t   qid_shuffle;    /*%< state generator info */
} dns_qid_t;

+/* ARC4 Random generator state */
+typedef struct arc4ctx {
+       isc_uint8_t     i;
+       isc_uint8_t     j;
+       isc_uint8_t     s[256];
+       int             count;
+} arc4ctx_t;
+
struct dns_dispatchmgr {
       /* Unlocked. */
       unsigned int                    magic;
@@ -62,6 +71,10 @@ struct dns_dispatchmgr {
       unsigned int                    state;
       ISC_LIST(dns_dispatch_t)        list;

+       /* Locked by arc4_lock. */
+       isc_mutex_t                     arc4_lock;
+       arc4ctx_t                       arc4ctx;    /*%< ARC4 context for QID */
+
       /* locked by buffer lock */
       dns_qid_t                       *qid;
       isc_mutex_t                     buffer_lock;
@@ -88,6 +101,7 @@ struct dns_dispentry {
       unsigned int                    magic;
       dns_dispatch_t                 *disp;
       dns_messageid_t                 id;
+       in_port_t                       port;
       unsigned int                    bucket;
       isc_sockaddr_t                  host;
       isc_task_t                     *task;
@@ -107,6 +121,7 @@ struct dns_dispatch {
       isc_task_t             *task;           /* internal task */
       isc_socket_t           *socket;         /* isc socket attached to */
       isc_sockaddr_t          local;          /* local address */
+       in_port_t               localport;      /* local UDP port */
       unsigned int            maxrequests;    /* max requests */
       isc_event_t            *ctlevent;

@@ -149,14 +164,14 @@ struct dns_dispatch {
 * Statics.
 */
static dns_dispentry_t *bucket_search(dns_qid_t *, isc_sockaddr_t *,
-                                     dns_messageid_t, unsigned int);
+                                     dns_messageid_t, in_port_t, unsigned int);
static isc_boolean_t destroy_disp_ok(dns_dispatch_t *);
static void destroy_disp(isc_task_t *task, isc_event_t *event);
static void udp_recv(isc_task_t *, isc_event_t *);
static void tcp_recv(isc_task_t *, isc_event_t *);
static void startrecv(dns_dispatch_t *);
-static dns_messageid_t dns_randomid(dns_qid_t *);
-static isc_uint32_t dns_hash(dns_qid_t *, isc_sockaddr_t *, dns_messageid_t);
+static isc_uint32_t dns_hash(dns_qid_t *, isc_sockaddr_t *, dns_messageid_t,
+                            in_port_t);
static void free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len);
static void *allocate_udp_buffer(dns_dispatch_t *disp);
static inline void free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev);
@@ -258,26 +273,152 @@ request_log(dns_dispatch_t *disp, dns_di
}

/*
- * Return an unpredictable message ID.
+ * ARC4 random number generator obtained from OpenBSD
 */
-static dns_messageid_t
-dns_randomid(dns_qid_t *qid) {
-       isc_uint16_t id;
+static void
+dispatch_arc4init(arc4ctx_t *actx) {
+       int n;
+       for (n = 0; n < 256; n++)
+               actx->s[n] = n;
+       actx->i = 0;
+       actx->j = 0;
+       actx->count = 0;
+}
+
+static void
+dispatch_arc4addrandom(arc4ctx_t *actx, unsigned char *dat, int datlen) {
+       int n;
+       isc_uint8_t si;
+
+       actx->i--;
+       for (n = 0; n < 256; n++) {
+               actx->i = (actx->i + 1);
+               si = actx->s[actx->i];
+               actx->j = (actx->j + si + dat[n % datlen]);
+               actx->s[actx->i] = actx->s[actx->j];
+               actx->s[actx->j] = si;
+       }
+       actx->j = actx->i;
+}
+
+static inline isc_uint8_t
+dispatch_arc4get8(arc4ctx_t *actx) {
+       isc_uint8_t si, sj;
+
+       actx->i = (actx->i + 1);
+       si = actx->s[actx->i];
+       actx->j = (actx->j + si);
+       sj = actx->s[actx->j];
+       actx->s[actx->i] = sj;
+       actx->s[actx->j] = si;
+
+       return (actx->s[(si + sj) & 0xff]);
+}
+
+static inline isc_uint16_t
+dispatch_arc4get16(arc4ctx_t *actx) {
+       isc_uint16_t val;
+
+       val = dispatch_arc4get8(actx) << 8;
+       val |= dispatch_arc4get8(actx);
+
+       return (val);
+}

-       id = isc_lcg_generate16(&qid->qid_lcg);
+static void
+dispatch_arc4stir(dns_dispatchmgr_t *mgr) {
+       int i;
+       union {
+               unsigned char rnd[128];
+               isc_uint32_t rnd32[32];
+       } rnd;
+       isc_result_t result;

-       return (dns_messageid_t)(id & 0xFFFF);
+       if (mgr->entropy != NULL) {
+               /*
+                * We accept any quality of random data to avoid blocking.
+                */
+               result = isc_entropy_getdata(mgr->entropy, rnd.rnd,
+                                            sizeof(rnd), NULL, 0);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+       } else {
+               for (i = 0; i < 32; i++)
+                       isc_random_get(&rnd.rnd32[i]);
+       }
+       dispatch_arc4addrandom(&mgr->arc4ctx, rnd.rnd, sizeof(rnd.rnd));
+
+       /*
+        * Discard early keystream, as per recommendations in:
+        * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
+        */
+       for (i = 0; i < 256; i++)
+               (void)dispatch_arc4get8(&mgr->arc4ctx);
+
+       /*
+        * Derived from OpenBSD's implementation.  The rationale is not clear,
+        * but should be conservative enough in safety, and reasonably large
+        * for efficiency.
+        */
+       mgr->arc4ctx.count = 1600000;
+}
+
+static isc_uint16_t
+dispatch_arc4random(dns_dispatchmgr_t *mgr) {
+       isc_uint16_t result;
+
+       LOCK(&mgr->arc4_lock);
+       mgr->arc4ctx.count -= sizeof(isc_uint16_t);
+       if (mgr->arc4ctx.count <= 0)
+               dispatch_arc4stir(mgr);
+       result = dispatch_arc4get16(&mgr->arc4ctx);
+       UNLOCK(&mgr->arc4_lock);
+       return (result);
+}
+
+static isc_uint16_t
+dispatch_arc4uniformrandom(dns_dispatchmgr_t *mgr, isc_uint16_t upper_bound) {
+       isc_uint16_t min, r;
+       /* The caller must hold the manager lock. */
+
+       if (upper_bound < 2)
+               return (0);
+
+       /*
+        * Ensure the range of random numbers [min, 0xffff] be a multiple of
+        * upper_bound and contain at least a half of the 16 bit range.
+        */
+
+       if (upper_bound > 0x8000)
+               min = 1 + ~upper_bound; /* 0x8000 - upper_bound */
+       else
+               min = (isc_uint16_t)(0x10000 % (isc_uint32_t)upper_bound);
+
+       /*
+        * This could theoretically loop forever but each retry has
+        * p > 0.5 (worst case, usually far better) of selecting a
+        * number inside the range we need, so it should rarely need
+        * to re-roll.
+        */
+       for (;;) {
+               r = dispatch_arc4random(mgr);
+               if (r >= min)
+                       break;
+       }
+
+       return (r % upper_bound);
}

/*
 * Return a hash of the destination and message id.
 */
static isc_uint32_t
-dns_hash(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id) {
+dns_hash(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id,
+        in_port_t port)
+{
       unsigned int ret;

       ret = isc_sockaddr_hash(dest, ISC_TRUE);
-       ret ^= id;
+       ret ^= (id << 16) | port;
       ret %= qid->qid_nbuckets;

       INSIST(ret < qid->qid_nbuckets);
@@ -394,7 +535,7 @@ destroy_disp(isc_task_t *task, isc_event
 */
static dns_dispentry_t *
bucket_search(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id,
-             unsigned int bucket)
+             in_port_t port, unsigned int bucket)
{
       dns_dispentry_t *res;

@@ -403,8 +544,10 @@ bucket_search(dns_qid_t *qid, isc_sockad
       res = ISC_LIST_HEAD(qid->qid_table[bucket]);

       while (res != NULL) {
-               if ((res->id == id) && isc_sockaddr_equal(dest, &res->host))
+               if ((res->id == id) && isc_sockaddr_equal(dest, &res->host) &&
+                   res->port == port) {
                       return (res);
+               }
               res = ISC_LIST_NEXT(res, link);
       }

@@ -607,9 +750,9 @@ udp_recv(isc_task_t *task, isc_event_t *
       }

       /* response */
-       bucket = dns_hash(qid, &ev->address, id);
+       bucket = dns_hash(qid, &ev->address, id, disp->localport);
       LOCK(&qid->lock);
-       resp = bucket_search(qid, &ev->address, id, bucket);
+       resp = bucket_search(qid, &ev->address, id, disp->localport, bucket);
       dispatch_log(disp, LVL(90),
                    "search for response in bucket %d: %s",
                    bucket, (resp == NULL ? "not found" : "found"));
@@ -843,9 +986,10 @@ tcp_recv(isc_task_t *task, isc_event_t *
       /*
        * Response.
        */
-       bucket = dns_hash(qid, &tcpmsg->address, id);
+       bucket = dns_hash(qid, &tcpmsg->address, id, disp->localport);
       LOCK(&qid->lock);
-       resp = bucket_search(qid, &tcpmsg->address, id, bucket);
+       resp = bucket_search(qid, &tcpmsg->address, id, disp->localport,
+                            bucket);
       dispatch_log(disp, LVL(90),
                    "search for response in bucket %d: %s",
                    bucket, (resp == NULL ? "not found" : "found"));
@@ -994,6 +1138,8 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) {
       DESTROYLOCK(&mgr->lock);
       mgr->state = 0;

+       DESTROYLOCK(&mgr->arc4_lock);
+
       isc_mempool_destroy(&mgr->epool);
       isc_mempool_destroy(&mgr->rpool);
       isc_mempool_destroy(&mgr->dpool);
@@ -1072,10 +1218,14 @@ dns_dispatchmgr_create(isc_mem_t *mctx,
       if (result != ISC_R_SUCCESS)
               goto deallocate;

-       result = isc_mutex_init(&mgr->buffer_lock);
+       result = isc_mutex_init(&mgr->arc4_lock);
       if (result != ISC_R_SUCCESS)
               goto kill_lock;

+       result = isc_mutex_init(&mgr->buffer_lock);
+       if (result != ISC_R_SUCCESS)
+               goto kill_arc4_lock;
+
       result = isc_mutex_init(&mgr->pool_lock);
       if (result != ISC_R_SUCCESS)
               goto kill_buffer_lock;
@@ -1126,6 +1276,8 @@ dns_dispatchmgr_create(isc_mem_t *mctx,
       if (entropy != NULL)
               isc_entropy_attach(entropy, &mgr->entropy);

+       dispatch_arc4init(&mgr->arc4ctx);
+
       *mgrp = mgr;
       return (ISC_R_SUCCESS);

@@ -1137,6 +1289,8 @@ dns_dispatchmgr_create(isc_mem_t *mctx,
       DESTROYLOCK(&mgr->pool_lock);
 kill_buffer_lock:
       DESTROYLOCK(&mgr->buffer_lock);
+ kill_arc4_lock:
+       DESTROYLOCK(&mgr->arc4_lock);
 kill_lock:
       DESTROYLOCK(&mgr->lock);
 deallocate:
@@ -1262,20 +1416,27 @@ dns_dispatchmgr_destroy(dns_dispatchmgr_
}

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)))
+           dns_portlist_match(mgr->portlist, isc_sockaddr_pf(sockaddrp),
+                              isc_sockaddr_getport(sockaddrp)))
               return (ISC_TRUE);
       return (ISC_FALSE);
}
@@ -1296,7 +1457,7 @@ local_addr_match(dns_dispatch_t *disp, i
       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);

       /*
@@ -1404,8 +1565,8 @@ qid_allocate(dns_dispatchmgr_t *mgr, uns
       qid->qid_nbuckets = buckets;
       qid->qid_increment = increment;
       qid->magic = QID_MAGIC;
+       isc_shuffle_init(&qid->qid_shuffle);

-       isc_lcg_init(&qid->qid_lcg);
       *qidp = qid;
       return (ISC_R_SUCCESS);
}
@@ -1457,6 +1618,7 @@ dispatch_allocate(dns_dispatchmgr_t *mgr
       disp->refcount = 1;
       disp->recv_pending = 0;
       memset(&disp->local, 0, sizeof(disp->local));
+       disp->localport = 0;
       disp->shutting_down = 0;
       disp->shutdown_out = 0;
       disp->connected = 0;
@@ -1629,7 +1791,7 @@ dns_dispatch_getudp(dns_dispatchmgr_t *m
                   dns_dispatch_t **dispp)
{
       isc_result_t result;
-       dns_dispatch_t *disp;
+       dns_dispatch_t *disp = NULL;

       REQUIRE(VALID_DISPATCHMGR(mgr));
       REQUIRE(sockmgr != NULL);
@@ -1649,6 +1811,11 @@ dns_dispatch_getudp(dns_dispatchmgr_t *m

       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.
        */
@@ -1677,6 +1844,7 @@ dns_dispatch_getudp(dns_dispatchmgr_t *m
               return (ISC_R_SUCCESS);
       }

+ createudp:
       /*
        * Nope, create one.
        */
@@ -1712,7 +1880,9 @@ dispatch_createudp(dns_dispatchmgr_t *mg
       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;
+       in_port_t localport = 0;

       /*
        * dispatch_allocate() checks mgr for us.
@@ -1728,11 +1898,34 @@ dispatch_createudp(dns_dispatchmgr_t *mg
        * 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) {
+               in_port_t prt;
+
+               /* XXX: should the range be configurable? */
+               prt = 1024 + dispatch_arc4uniformrandom(mgr, 65535 - 1023);
+               isc_sockaddr_setport(&localaddr_bound, prt);
+               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;
+               }
+               localport = prt;
+       } 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;
@@ -1753,6 +1946,7 @@ dispatch_createudp(dns_dispatchmgr_t *mg
       disp->socktype = isc_sockettype_udp;
       disp->socket = sock;
       disp->local = *localaddr;
+       disp->localport = localport;

       disp->task = NULL;
       result = isc_task_create(taskmgr, 0, &disp->task);
@@ -1884,18 +2078,19 @@ dns_dispatch_addresponse(dns_dispatch_t
        * Try somewhat hard to find an unique ID.
        */
       qid = DNS_QID(disp);
+       id = (dns_messageid_t)isc_shuffle_generate16(&qid->qid_shuffle);
       LOCK(&qid->lock);
-       id = dns_randomid(qid);
-       bucket = dns_hash(qid, dest, id);
+       bucket = dns_hash(qid, dest, id, disp->localport);
       ok = ISC_FALSE;
       for (i = 0; i < 64; i++) {
-               if (bucket_search(qid, dest, id, bucket) == NULL) {
+               if (bucket_search(qid, dest, id, disp->localport, bucket) ==
+                   NULL) {
                       ok = ISC_TRUE;
                       break;
               }
               id += qid->qid_increment;
               id &= 0x0000ffff;
-               bucket = dns_hash(qid, dest, id);
+               bucket = dns_hash(qid, dest, id, disp->localport);
       }

       if (!ok) {
@@ -1917,6 +2112,7 @@ dns_dispatch_addresponse(dns_dispatch_t
       isc_task_attach(task, &res->task);
       res->disp = disp;
       res->id = id;
+       res->port = disp->localport;
       res->bucket = bucket;
       res->host = *dest;
       res->action = action;
Index: usr.sbin/bind/lib/dns/resolver.c
===================================================================
RCS file: /cvs/src/usr.sbin/bind/lib/dns/resolver.c,v
retrieving revision 1.13
retrieving revision 1.13.4.1
diff -u -p -r1.13 -r1.13.4.1
--- usr.sbin/bind/lib/dns/resolver.c    25 Jan 2007 07:31:25 -0000      1.13
+++ usr.sbin/bind/lib/dns/resolver.c    23 Jul 2008 17:59:55 -0000      1.13.4.1
@@ -1054,17 +1054,50 @@ fctx_query(fetchctx_t *fctx, dns_adbaddr
                * A dispatch will be created once the connect succeeds.
                */
       } else {
+               isc_sockaddr_t localaddr;
+               unsigned int attrs, attrmask;
+               dns_dispatch_t *disp_base;
+
+               attrs = 0;
+               attrs |= DNS_DISPATCHATTR_UDP;
+               attrs |= DNS_DISPATCHATTR_RANDOMPORT;
+
+               attrmask = 0;
+               attrmask |= DNS_DISPATCHATTR_UDP;
+               attrmask |= DNS_DISPATCHATTR_TCP;
+               attrmask |= DNS_DISPATCHATTR_IPV4;
+               attrmask |= DNS_DISPATCHATTR_IPV6;
+
               switch (isc_sockaddr_pf(&addrinfo->sockaddr)) {
-               case PF_INET:
-                       dns_dispatch_attach(res->dispatchv4, &query->dispatch);
+               case AF_INET:
+                       disp_base = res->dispatchv4;
+                       attrs |= DNS_DISPATCHATTR_IPV4;
                       break;
-               case PF_INET6:
-                       dns_dispatch_attach(res->dispatchv6, &query->dispatch);
+               case AF_INET6:
+                       disp_base = res->dispatchv6;
+                       attrs |= DNS_DISPATCHATTR_IPV6;
                       break;
               default:
                       result = ISC_R_NOTIMPLEMENTED;
                       goto cleanup_query;
               }
+
+               result = dns_dispatch_getlocaladdress(disp_base, &localaddr);
+               if (result != ISC_R_SUCCESS)
+                       goto cleanup_query;
+               if (isc_sockaddr_getport(&localaddr) == 0) {
+                       result = dns_dispatch_getudp(res->dispatchmgr,
+                                                    res->socketmgr,
+                                                    res->taskmgr,
+                                                    &localaddr,
+                                                    4096, 1000, 32768,
+                                                    16411, 16433,
+                                                    attrs, attrmask,
+                                                    &query->dispatch);
+                       if (result != ISC_R_SUCCESS)
+                               goto cleanup_query;
+               } else
+                       dns_dispatch_attach(disp_base, &query->dispatch);
               /*
                * We should always have a valid dispatcher here.  If we
                * don't support a protocol family, then its dispatcher
Index: usr.sbin/bind/lib/dns/rootns.c
===================================================================
RCS file: /cvs/src/usr.sbin/bind/lib/dns/rootns.c,v
retrieving revision 1.3
retrieving revision 1.3.12.1
diff -u -p -r1.3 -r1.3.12.1
--- usr.sbin/bind/lib/dns/rootns.c      28 Sep 2004 17:14:06 -0000      1.3
+++ usr.sbin/bind/lib/dns/rootns.c      19 Nov 2007 11:08:13 -0000      1.3.12.1
@@ -67,7 +67,7 @@ static char root_ns[] =
"I.ROOT-SERVERS.NET.     3600000 IN      A       192.36.148.17\n"
"J.ROOT-SERVERS.NET.     3600000 IN      A       192.58.128.30\n"
"K.ROOT-SERVERS.NET.     3600000 IN      A       193.0.14.129\n"
-"L.ROOT-SERVERS.NET.     3600000 IN      A       198.32.64.12\n"
+"L.ROOT-SERVERS.NET.     3600000 IN      A       199.7.83.42\n"
"M.ROOT-SERVERS.NET.     3600000 IN      A       202.12.27.33\n";

static isc_result_t
Index: usr.sbin/bind/lib/dns/include/dns/dispatch.h
===================================================================
RCS file: /cvs/src/usr.sbin/bind/lib/dns/include/dns/dispatch.h,v
retrieving revision 1.4
retrieving revision 1.4.12.1
diff -u -p -r1.4 -r1.4.12.1
--- usr.sbin/bind/lib/dns/include/dns/dispatch.h        28 Sep 2004 17:14:06 -0000      1.4
+++ usr.sbin/bind/lib/dns/include/dns/dispatch.h        23 Jul 2008 17:59:55 -0000      1.4.12.1
@@ -112,6 +112,9 @@ struct dns_dispatchevent {
 * _MAKEQUERY
 *     The dispatcher can be used to issue queries to other servers, and
 *     accept replies from them.
+ *
+ * _RANDOMPORT
+ *     Allocate UDP port randomly.
 */
#define DNS_DISPATCHATTR_PRIVATE       0x00000001U
#define DNS_DISPATCHATTR_TCP           0x00000002U
@@ -121,6 +124,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
dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
Index: usr.sbin/bind/lib/isc/Makefile.in
===================================================================
RCS file: /cvs/src/usr.sbin/bind/lib/isc/Makefile.in,v
retrieving revision 1.5
retrieving revision 1.5.12.1
diff -u -p -r1.5 -r1.5.12.1
--- usr.sbin/bind/lib/isc/Makefile.in   28 Sep 2004 17:14:07 -0000      1.5
+++ usr.sbin/bind/lib/isc/Makefile.in   23 Jul 2008 17:59:55 -0000      1.5.12.1
@@ -60,10 +60,12 @@ OBJS =              @ISC_EXTRA_OBJS@ \
               ratelimiter.@O@ region.@O@ result.@O@ rwlock.@O@ \
               serial.@O@ sha1.@O@ sockaddr.@O@ string.@O@ strtoul.@O@ \
               symtab.@O@ task.@O@ taskpool.@O@ timer.@O@ version.@O@ \
+               shuffle.@O@ \
               ${UNIXOBJS} ${NLSOBJS} ${THREADOBJS}

# Alphabetically
SRCS =         @ISC_EXTRA_SRCS@ \
+               shuffle.c \
               assertions.c base64.c bitstring.c buffer.c \
               bufferlist.c commandline.c error.c event.c \
               heap.c hex.c hmacmd5.c \
Index: usr.sbin/bind/lib/isc/random.c
===================================================================
RCS file: /cvs/src/usr.sbin/bind/lib/isc/random.c,v
retrieving revision 1.4
retrieving revision 1.4.12.1
diff -u -p -r1.4 -r1.4.12.1
--- usr.sbin/bind/lib/isc/random.c      28 Sep 2004 17:14:07 -0000      1.4
+++ usr.sbin/bind/lib/isc/random.c      23 Jul 2008 17:59:55 -0000      1.4.12.1
@@ -1,6 +1,7 @@
/*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
 * Copyright (C) 1999-2003  Internet Software Consortium.
+ * Copyright (C) 2008 Damien Miller
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
@@ -17,6 +18,8 @@

/* $ISC: random.c,v 1.15.74.5 2004/03/08 09:04:49 marka Exp $ */

+/*! \file */
+
#include <config.h>

#include <stdlib.h>
@@ -89,14 +92,54 @@ isc_random_get(isc_uint32_t *val)
}

isc_uint32_t
+isc_random_uniform(isc_uint32_t upper_bound)
+{
+       isc_uint32_t r, min;
+
+       /*
+        * Uniformity is achieved by generating new random numbers until
+        * the one returned is outside the range [0, 2**32 % upper_bound).
+        * This guarantees the selected random number will be inside
+        * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
+        * after reduction modulo upper_bound.
+        */
+
+       if (upper_bound < 2)
+               return 0;
+
+#if (ULONG_MAX > 0xffffffffUL)
+       min = 0x100000000UL % upper_bound;
+#else
+       /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
+       if (upper_bound > 0x80000000)
+               min = 1 + ~upper_bound;         /* 2**32 - upper_bound */
+       else {
+               /* (2**32 - x) % x == 2**32 % x when x <= 2**31 */
+               min = ((0xffffffff - upper_bound) + 1) % upper_bound;
+       }
+#endif
+
+       /*
+        * This could theoretically loop forever doing this, but each retry
+        * has p > 0.5 (worst case, usually far better) of selecting a
+        * number inside the range we need, so it should rarely need to
+        * re-roll.
+        */
+       for (;;) {
+               isc_random_get(&r);
+               if (r >= min)
+                       break;
+       }
+
+       return r % upper_bound;
+}
+
+isc_uint32_t
isc_random_jitter(isc_uint32_t max, isc_uint32_t jitter) {
       REQUIRE(jitter < max);
       if (jitter == 0)
               return (max);
       else
-#ifndef HAVE_ARC4RANDOM
-               return (max - rand() % jitter);
-#else
-               return (max - arc4random() % jitter);
-#endif
+               return max - isc_random_uniform(jitter);
}
+
Index: usr.sbin/bind/lib/isc/shuffle.c
===================================================================
RCS file: usr.sbin/bind/lib/isc/shuffle.c
diff -N usr.sbin/bind/lib/isc/shuffle.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ usr.sbin/bind/lib/isc/shuffle.c     23 Jul 2008 17:59:55 -0000      1.4.2.1
@@ -0,0 +1,67 @@
+/*
+ * Portions Copyright (C) 2008 Theo de Raadt
+ *
+ * Permission to use, copy, modify, and 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+/* $OpenBSD: shuffle.c,v 1.4.2.1 2008/07/23 17:59:55 brad Exp $ */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <isc/shuffle.h>
+#include <isc/random.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#define VALID_SHUFFLE(x)       (x != NULL)
+
+void
+isc_shuffle_init(isc_shuffle_t *shuffle)
+{
+       int i, i2;
+
+       REQUIRE(VALID_SHUFFLE(shuffle));
+
+       shuffle->isindex = 0;
+       /* Initialize using a Knuth shuffle */
+       for (i = 0; i < 65536; ++i) {
+               i2 = isc_random_uniform(i + 1);
+               shuffle->id_shuffle[i] = shuffle->id_shuffle[i2];
+               shuffle->id_shuffle[i2] = i;
+       }
+}
+
+isc_uint16_t
+isc_shuffle_generate16(isc_shuffle_t *shuffle)
+{
+       isc_uint32_t si;
+       isc_uint16_t r;
+       int i, i2;
+
+       REQUIRE(VALID_SHUFFLE(shuffle));
+
+       do {
+               isc_random_get(&si);
+               i = shuffle->isindex & 0xFFFF;
+               i2 = (shuffle->isindex - (si & 0x7FFF)) & 0xFFFF;
+               r = shuffle->id_shuffle[i];
+               shuffle->id_shuffle[i] = shuffle->id_shuffle[i2];
+               shuffle->id_shuffle[i2] = r;
+               shuffle->isindex++;
+       } while (r == 0);
+
+       return (r);
+}
Index: usr.sbin/bind/lib/isc/include/isc/random.h
===================================================================
RCS file: /cvs/src/usr.sbin/bind/lib/isc/include/isc/random.h,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.12.1
diff -u -p -r1.1.1.2 -r1.1.1.2.12.1
--- usr.sbin/bind/lib/isc/include/isc/random.h  28 Sep 2004 16:35:42 -0000      1.1.1.2
+++ usr.sbin/bind/lib/isc/include/isc/random.h  23 Jul 2008 17:59:55 -0000      1.1.1.2.12.1
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
 * Copyright (C) 1999-2001  Internet Software Consortium.
 *
 * Permission to use, copy, modify, and distribute this software for any
@@ -23,9 +23,11 @@
#include <isc/lang.h>
#include <isc/types.h>

-/*
- * Implements a random state pool which will let the caller return a
- * series of possibly non-reproducable random values.  Note that the
+/*! \file
+ * \brief Implements a random state pool which will let the caller return a
+ * series of possibly non-reproducable random values.
+ *
+ * Note that the
 * strength of these numbers is not all that high, and should not be
 * used in cryptography functions.  It is useful for jittering values
 * a bit here and there, such as timeouts, etc.
@@ -35,13 +37,13 @@ ISC_LANG_BEGINDECLS

void
isc_random_seed(isc_uint32_t seed);
-/*
+/*%<
 * Set the initial seed of the random state.
 */

void
isc_random_get(isc_uint32_t *val);
-/*
+/*%<
 * Get a random value.
 *
 * Requires:
@@ -50,9 +52,16 @@ isc_random_get(isc_uint32_t *val);

isc_uint32_t
isc_random_jitter(isc_uint32_t max, isc_uint32_t jitter);
-/*
+/*%<
 * Get a random value between (max - jitter) and (max).
 * This is useful for jittering timer values.
+ */
+
+isc_uint32_t
+isc_random_uniform(isc_uint32_t upper_bound);
+/*%<
+ * Get a uniformly distributed random value < upper_bound.
+ * Avoid bias when upper_bound is not a power of two.
 */

ISC_LANG_ENDDECLS
Index: usr.sbin/bind/lib/isc/include/isc/shuffle.h
===================================================================
RCS file: usr.sbin/bind/lib/isc/include/isc/shuffle.h
diff -N usr.sbin/bind/lib/isc/include/isc/shuffle.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ usr.sbin/bind/lib/isc/include/isc/shuffle.h 23 Jul 2008 17:59:55 -0000      1.1.4.1
@@ -0,0 +1,59 @@
+/*
+ * Portions Copyright (C) 2002  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and 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 INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM 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.
+ */
+
+/* $OpenBSD: shuffle.h,v 1.1.4.1 2008/07/23 17:59:55 brad Exp $ */
+
+#ifndef ISC_SHUFFLE_H
+#define ISC_SHUFFLE_H 1
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+typedef struct isc_shuffle isc_shuffle_t;
+
+struct isc_shuffle {
+       isc_uint16_t id_shuffle[65536];
+       int isindex;
+};
+
+ISC_LANG_BEGINDECLS
+
+void
+isc_shuffle_init(isc_shuffle_t *shuffle);
+/*
+ * Initialize a Shuffle generator
+ *
+ * Requires:
+ *
+ *     shuffle != NULL
+ */
+
+isc_uint16_t
+isc_shuffle_generate16(isc_shuffle_t *shuffle);
+/*
+ * Get a random number from a Shuffle generator
+ *
+ * Requires:
+ *
+ *     shuffle be valid.
+ *
+ *     data != NULL.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_SHUFFLE_H */
Index: usr.sbin/bind/lib/isc/unix/app.c
===================================================================
RCS file: /cvs/src/usr.sbin/bind/lib/isc/unix/app.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.12.1
diff -u -p -r1.1.1.2 -r1.1.1.2.12.1
--- usr.sbin/bind/lib/isc/unix/app.c    28 Sep 2004 16:35:46 -0000      1.1.1.2
+++ usr.sbin/bind/lib/isc/unix/app.c    23 Jul 2008 17:59:55 -0000      1.1.1.2.12.1
@@ -301,7 +301,7 @@ evloop() {
               int n;
               isc_time_t when, now;
               struct timeval tv, *tvp;
-               fd_set readfds, writefds;
+               fd_set *readfds, *writefds;
               int maxfd;
               isc_boolean_t readytasks;
               isc_boolean_t call_timer_dispatch = ISC_FALSE;
@@ -330,7 +330,7 @@ evloop() {
               }

               isc__socketmgr_getfdsets(&readfds, &writefds, &maxfd);
-               n = select(maxfd, &readfds, &writefds, NULL, tvp);
+               n = select(maxfd, readfds, writefds, NULL, tvp);

               if (n == 0 || call_timer_dispatch) {
                       /*
@@ -350,7 +350,7 @@ evloop() {
                       isc__timermgr_dispatch();
               }
               if (n > 0)
-                       (void)isc__socketmgr_dispatch(&readfds, &writefds,
+                       (void)isc__socketmgr_dispatch(readfds, writefds,
                                                     maxfd);
               (void)isc__taskmgr_dispatch();

Index: usr.sbin/bind/lib/isc/unix/privsep.c
===================================================================
RCS file: /cvs/src/usr.sbin/bind/lib/isc/unix/privsep.c,v
retrieving revision 1.6
retrieving revision 1.6.10.1
diff -u -p -r1.6 -r1.6.10.1
--- usr.sbin/bind/lib/isc/unix/privsep.c        4 May 2005 08:29:07 -0000       1.6
+++ usr.sbin/bind/lib/isc/unix/privsep.c        24 Jul 2008 05:28:41 -0000      1.6.10.1
@@ -189,7 +189,7 @@ check_bind(const struct sockaddr *sa, so

       if (port != NAMED_PORT_DEFAULT && port != RNDC_PORT_DEFAULT &&
           port != LWRES_PORT_DEFAULT) {
-               if (port || child_pid)
+               if ((port && port < 1024) || child_pid)
                       logmsg(LOG_ERR, "%s: disallowed port %u", pname, port);
               return (1);
       }
Index: usr.sbin/bind/lib/isc/unix/socket.c
===================================================================
RCS file: /cvs/src/usr.sbin/bind/lib/isc/unix/socket.c,v
retrieving revision 1.8
retrieving revision 1.8.4.1
diff -u -p -r1.8 -r1.8.4.1
--- usr.sbin/bind/lib/isc/unix/socket.c 10 Jan 2007 19:07:59 -0000      1.8
+++ usr.sbin/bind/lib/isc/unix/socket.c 23 Jul 2008 17:59:55 -0000      1.8.4.1
@@ -188,11 +188,12 @@ struct isc_socketmgr {
       isc_mutex_t             lock;
       /* Locked by manager lock. */
       ISC_LIST(isc_socket_t)  socklist;
-       fd_set                  read_fds;
-       fd_set                  write_fds;
-       isc_socket_t           *fds[FD_SETSIZE];
-       int                     fdstate[FD_SETSIZE];
+       fd_set                 *read_fds, *read_fds_copy;
+       fd_set                 *write_fds, *write_fds_copy;
+       isc_socket_t          **fds;
+       int                    *fdstate;
       int                     maxfd;
+       int                     fdsize;
#ifdef ISC_PLATFORM_USETHREADS
       isc_thread_t            watcher;
       isc_condition_t         shutdown_ok;
@@ -237,6 +238,7 @@ static void build_msghdr_send(isc_socket
                             struct msghdr *, struct iovec *, size_t *);
static void build_msghdr_recv(isc_socket_t *, isc_socketevent_t *,
                             struct msghdr *, struct iovec *, size_t *);
+static void expand_fdsets(isc_socketmgr_t *, int, isc_mem_t *);

#define SELECT_POKE_SHUTDOWN           (-1)
#define SELECT_POKE_NOTHING            (-2)
@@ -315,12 +317,12 @@ wakeup_socket(isc_socketmgr_t *manager,
        * or writes.
        */

-       INSIST(fd >= 0 && fd < (int)FD_SETSIZE);
+       INSIST(fd >= 0 && fd < manager->fdsize);

       if (manager->fdstate[fd] == CLOSE_PENDING) {
               manager->fdstate[fd] = CLOSED;
-               FD_CLR(fd, &manager->read_fds);
-               FD_CLR(fd, &manager->write_fds);
+               FD_CLR(fd, manager->read_fds);
+               FD_CLR(fd, manager->write_fds);
               (void)close(fd);
               return;
       }
@@ -333,9 +335,9 @@ wakeup_socket(isc_socketmgr_t *manager,
        * Set requested bit.
        */
       if (msg == SELECT_POKE_READ)
-               FD_SET(sock->fd, &manager->read_fds);
+               FD_SET(sock->fd, manager->read_fds);
       if (msg == SELECT_POKE_WRITE)
-               FD_SET(sock->fd, &manager->write_fds);
+               FD_SET(sock->fd, manager->write_fds);
}

#ifdef ISC_PLATFORM_USETHREADS
@@ -1196,7 +1198,7 @@ destroy(isc_socket_t **sockp) {
       INSIST(ISC_LIST_EMPTY(sock->recv_list));
       INSIST(ISC_LIST_EMPTY(sock->send_list));
       INSIST(sock->connect_ev == NULL);
-       REQUIRE(sock->fd >= 0 && sock->fd < (int)FD_SETSIZE);
+       REQUIRE(sock->fd >= 0 && sock->fd < manager->fdsize);

       LOCK(&manager->lock);

@@ -1371,6 +1373,78 @@ free_socket(isc_socket_t **socketp) {
       *socketp = NULL;
}

+static void
+expand_fdsets(isc_socketmgr_t *manager, int maxfd, isc_mem_t *mctx) {
+       void *tmp;
+       int newsize = manager->fdsize;
+
+       if (mctx == NULL)
+               mctx = manager->mctx;
+
+       do {
+               newsize += FD_SETSIZE;
+       } while (newsize <= maxfd);
+
+       tmp = isc_mem_get(mctx, sizeof(manager->fds[0]) * newsize);
+       memset(tmp, 0, sizeof(manager->fds[0]) * newsize);
+       if (manager->fdsize) {
+               memcpy(tmp, manager->fds,
+                   sizeof(manager->fds[0]) * manager->fdsize);
+               isc_mem_put(mctx, manager->fds,
+                   sizeof(manager->fds[0]) * manager->fdsize);
+       }
+       manager->fds = tmp;
+
+       tmp = isc_mem_get(mctx, sizeof(manager->fdstate[0]) * newsize);
+       memset(tmp, 0, sizeof(manager->fdstate[0]) * newsize);
+       if (manager->fdsize) {
+               memcpy(tmp, manager->fdstate,
+                   sizeof(manager->fdstate[0]) * manager->fdsize);
+               isc_mem_put(mctx, manager->fdstate,
+                   sizeof(manager->fdstate[0]) * manager->fdsize);
+       }
+       manager->fdstate = tmp;
+
+       tmp = isc_mem_get(mctx, howmany(newsize, NFDBITS) * sizeof(fd_mask));
+       memset(tmp, 0, howmany(newsize, NFDBITS) * sizeof(fd_mask));
+       if (manager->fdsize) {
+               memcpy(tmp, manager->read_fds,
+                   howmany(manager->fdsize, NFDBITS) * sizeof(fd_mask));
+               isc_mem_put(mctx, manager->read_fds,
+                   howmany(manager->fdsize, NFDBITS) * sizeof(fd_mask));
+       }
+       manager->read_fds = tmp;
+
+       tmp = isc_mem_get(mctx, howmany(newsize, NFDBITS) * sizeof(fd_mask));
+       memset(tmp, 0, howmany(newsize, NFDBITS) * sizeof(fd_mask));
+       if (manager->fdsize) {
+               memcpy(tmp, manager->write_fds,
+                   howmany(manager->fdsize, NFDBITS) * sizeof(fd_mask));
+               isc_mem_put(mctx, manager->write_fds,
+                   howmany(manager->fdsize, NFDBITS) * sizeof(fd_mask));
+       }
+       manager->write_fds = tmp;
+
+       /* Don't bother copying these, they are copied before use */
+       tmp = isc_mem_get(mctx, howmany(newsize, NFDBITS) * sizeof(fd_mask));
+       memset(tmp, 0, howmany(newsize, NFDBITS) * sizeof(fd_mask));
+       if (manager->fdsize) {
+               isc_mem_put(mctx, manager->read_fds_copy,
+                   howmany(manager->fdsize, NFDBITS) * sizeof(fd_mask));
+       }
+       manager->read_fds_copy = tmp;
+
+       tmp = isc_mem_get(mctx, howmany(newsize, NFDBITS) * sizeof(fd_mask));
+       memset(tmp, 0, howmany(newsize, NFDBITS) * sizeof(fd_mask));
+       if (manager->fdsize) {
+               isc_mem_put(mctx, manager->write_fds_copy,
+                   howmany(manager->fdsize, NFDBITS) * sizeof(fd_mask));
+       }
+       manager->write_fds_copy = tmp;
+
+       manager->fdsize = newsize;
+}
+
/*
 * Create a new 'type' socket managed by 'manager'.  Events
 * will be posted to 'task' and when dispatched 'action' will be
@@ -1421,16 +1495,8 @@ isc_socket_create(isc_socketmgr_t *manag
       }
#endif

-       if (sock->fd >= (int)FD_SETSIZE) {
-               (void)close(sock->fd);
-               isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
-                              ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
-                              isc_msgcat, ISC_MSGSET_SOCKET,
-                              ISC_MSG_TOOMANYFDS,
-                              "%s: too many open file descriptors", "socket");
-               free_socket(&sock);
-               return (ISC_R_NORESOURCES);
-       }
+       if (sock->fd >= sock->manager->fdsize)
+               expand_fdsets(sock->manager, sock->fd, NULL);

       if (sock->fd < 0) {
               free_socket(&sock);
@@ -1928,15 +1994,8 @@ internal_accept(isc_task_t *me, isc_even
                                        sock->pf);
                       (void)close(fd);
                       goto soft_error;
-               } else if (fd >= (int)FD_SETSIZE) {
-                       isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
-                                      ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
-                                      isc_msgcat, ISC_MSGSET_SOCKET,
-                                      ISC_MSG_TOOMANYFDS,
-                                      "%s: too many open file descriptors",
-                                      "accept");
-                       (void)close(fd);
-                       goto soft_error;
+               } else if (fd >= sock->manager->fdsize) {
+                       expand_fdsets(sock->manager, fd, NULL);
               }
       }

@@ -1980,10 +2039,13 @@ internal_accept(isc_task_t *me, isc_even
                */
               dev->address = dev->newsocket->address;

-               manager->fds[fd] = dev->newsocket;
-               manager->fdstate[fd] = MANAGED;
               if (manager->maxfd < fd)
                       manager->maxfd = fd;
+               if (manager->maxfd >= manager->fdsize)
+                       expand_fdsets(manager, manager->maxfd, NULL);
+
+               manager->fds[fd] = dev->newsocket;
+               manager->fdstate[fd] = MANAGED;

               socket_log(sock, &dev->newsocket->address, CREATION,
                          isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,
@@ -2140,7 +2202,7 @@ process_fds(isc_socketmgr_t *manager, in
       isc_socket_t *sock;
       isc_boolean_t unlock_sock;

-       REQUIRE(maxfd <= (int)FD_SETSIZE);
+       REQUIRE(maxfd <= manager->fdsize);

       /*
        * Process read/writes on other fds here.  Avoid locking
@@ -2154,8 +2216,8 @@ process_fds(isc_socketmgr_t *manager, in

               if (manager->fdstate[i] == CLOSE_PENDING) {
                       manager->fdstate[i] = CLOSED;
-                       FD_CLR(i, &manager->read_fds);
-                       FD_CLR(i, &manager->write_fds);
+                       FD_CLR(i, manager->read_fds);
+                       FD_CLR(i, manager->write_fds);

                       (void)close(i);

@@ -2166,7 +2228,7 @@ process_fds(isc_socketmgr_t *manager, in
               unlock_sock = ISC_FALSE;
               if (FD_ISSET(i, readfds)) {
                       if (sock == NULL) {
-                               FD_CLR(i, &manager->read_fds);
+                               FD_CLR(i, manager->read_fds);
                               goto check_write;
                       }
                       unlock_sock = ISC_TRUE;
@@ -2177,12 +2239,12 @@ process_fds(isc_socketmgr_t *manager, in
                               else
                                       dispatch_recv(sock);
                       }
-                       FD_CLR(i, &manager->read_fds);
+                       FD_CLR(i, manager->read_fds);
               }
       check_write:
               if (FD_ISSET(i, writefds)) {
                       if (sock == NULL) {
-                               FD_CLR(i, &manager->write_fds);
+                               FD_CLR(i, manager->write_fds);
                               continue;
                       }
                       if (!unlock_sock) {
@@ -2195,7 +2257,7 @@ process_fds(isc_socketmgr_t *manager, in
                               else
                                       dispatch_send(sock);
                       }
-                       FD_CLR(i, &manager->write_fds);
+                       FD_CLR(i, manager->write_fds);
               }
               if (unlock_sock)
                       UNLOCK(&sock->lock);
@@ -2336,7 +2398,11 @@ isc_socketmgr_create(isc_mem_t *mctx, is

       manager->magic = SOCKET_MANAGER_MAGIC;
       manager->mctx = NULL;
-       memset(manager->fds, 0, sizeof(manager->fds));
+       manager->read_fds = NULL;
+       manager->write_fds = NULL;
+       manager->fds = NULL;
+       manager->fdstate = NULL;
+       manager->fdsize = NULL;
       ISC_LIST_INIT(manager->socklist);
       if (isc_mutex_init(&manager->lock) != ISC_R_SUCCESS) {
               isc_mem_put(mctx, manager, sizeof(*manager));
@@ -2385,15 +2451,13 @@ isc_socketmgr_create(isc_mem_t *mctx, is
       /*
        * Set up initial state for the select loop
        */
-       FD_ZERO(&manager->read_fds);
-       FD_ZERO(&manager->write_fds);
#ifdef ISC_PLATFORM_USETHREADS
-       FD_SET(manager->pipe_fds[0], &manager->read_fds);
+       FD_SET(manager->pipe_fds[0], manager->read_fds);
       manager->maxfd = manager->pipe_fds[0];
#else /* ISC_PLATFORM_USETHREADS */
       manager->maxfd = 0;
#endif /* ISC_PLATFORM_USETHREADS */
-       memset(manager->fdstate, 0, sizeof(manager->fdstate));
+       expand_fdsets(manager, manager->maxfd, mctx);

#ifdef ISC_PLATFORM_USETHREADS
       /*
@@ -2499,9 +2563,23 @@ isc_socketmgr_destroy(isc_socketmgr_t **
       (void)isc_condition_destroy(&manager->shutdown_ok);
#endif /* ISC_PLATFORM_USETHREADS */

-       for (i = 0; i < (int)FD_SETSIZE; i++)
-               if (manager->fdstate[i] == CLOSE_PENDING)
-                       (void)close(i);
+       if (manager->fdsize) {
+               for (i = 0; i < manager->fdsize; i++)
+                       if (manager->fdstate[i] == CLOSE_PENDING)
+                               (void)close(i);
+                isc_mem_put(manager->mctx, manager->fds,
+                    sizeof(manager->fds[0]) * manager->fdsize);
+                isc_mem_put(manager->mctx, manager->fdstate,
+                    sizeof(manager->fdstate[0]) * manager->fdsize);
+                isc_mem_put(manager->mctx, manager->read_fds,
+                    howmany(manager->fdsize, NFDBITS) * sizeof(fd_mask));
+                isc_mem_put(manager->mctx, manager->write_fds,
+                    howmany(manager->fdsize, NFDBITS) * sizeof(fd_mask));
+                isc_mem_put(manager->mctx, manager->read_fds_copy,
+                    howmany(manager->fdsize, NFDBITS) * sizeof(fd_mask));
+                isc_mem_put(manager->mctx, manager->write_fds_copy,
+                    howmany(manager->fdsize, NFDBITS) * sizeof(fd_mask));
+       }

       DESTROYLOCK(&manager->lock);
       manager->magic = 0;
@@ -3536,12 +3614,22 @@ isc_socket_ipv6only(isc_socket_t *sock,

#ifndef ISC_PLATFORM_USETHREADS
void
-isc__socketmgr_getfdsets(fd_set *readset, fd_set *writeset, int *maxfd) {
+isc__socketmgr_getfdsets(fd_set **readset, fd_set **writeset, int *maxfd) {
       if (socketmgr == NULL)
               *maxfd = 0;
       else {
-               *readset = socketmgr->read_fds;
-               *writeset = socketmgr->write_fds;
+
+               /* Prepare duplicates of fd_sets, as select() will modify */
+               if (socketmgr->fdsize) {
+                       memcpy(socketmgr->read_fds_copy, socketmgr->read_fds,
+                           howmany(socketmgr->fdsize, NFDBITS) *
+                           sizeof(fd_mask));
+                       memcpy(socketmgr->write_fds_copy, socketmgr->write_fds,
+                           howmany(socketmgr->fdsize, NFDBITS) *
+                           sizeof(fd_mask));
+               }
+               *readset = socketmgr->read_fds_copy;
+               *writeset = socketmgr->write_fds_copy;
               *maxfd = socketmgr->maxfd + 1;
       }
}
Index: usr.sbin/bind/lib/isc/unix/socket_p.h
===================================================================
RCS file: /cvs/src/usr.sbin/bind/lib/isc/unix/socket_p.h,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.12.1
diff -u -p -r1.1.1.2 -r1.1.1.2.12.1
--- usr.sbin/bind/lib/isc/unix/socket_p.h       28 Sep 2004 16:35:49 -0000      1.1.1.2
+++ usr.sbin/bind/lib/isc/unix/socket_p.h       23 Jul 2008 17:59:56 -0000      1.1.1.2.12.1
@@ -25,7 +25,7 @@
#endif

void
-isc__socketmgr_getfdsets(fd_set *readset, fd_set *writeset, int *maxfd);
+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);