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);
