Fully randomize UDP query ports to improve forgery resilience. [rt17949]

This commit is contained in:
Evan Hunt
2008-05-27 22:36:11 +00:00
parent 0598502e9e
commit 3917e0f147
12 changed files with 3044 additions and 3422 deletions
+5
View File
@@ -1,3 +1,8 @@
--- 9.5.0-P1 released ---
2375. [security] Fully randomize UDP query ports to improve
forgery resilience. [RT #17949]
--- 9.5.0 released ---
2374. [bug] "blackhole" ACLs could cause named to segfault due
+1 -9
View File
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: client.c,v 1.250.16.5 2008/04/03 06:20:33 tbox Exp $ */
/* $Id: client.c,v 1.250.16.6 2008/05/27 22:36:09 each Exp $ */
#include <config.h>
@@ -1513,14 +1513,6 @@ client_request(isc_task_t *task, isc_event_t *event) {
dns_generalstats_increment(ns_g_server->nsstats,
dns_nsstatscounter_tcp);
/*
* Hash the incoming request here as it is after
* dns_dispatch_importrecv().
*/
dns_dispatch_hash(&client->now, sizeof(client->now));
dns_dispatch_hash(isc_buffer_base(buffer),
isc_buffer_usedlength(buffer));
/*
* It's a request. Parse it.
*/
+20 -65
View File
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: server.c,v 1.495.10.10 2008/04/03 06:20:33 tbox Exp $ */
/* $Id: server.c,v 1.495.10.11 2008/05/27 22:36:09 each Exp $ */
/*! \file */
@@ -596,6 +596,14 @@ get_view_querysource_dispatch(const cfg_obj_t **maps,
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;
@@ -605,7 +613,7 @@ get_view_querysource_dispatch(const cfg_obj_t **maps,
disp = NULL;
result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr,
ns_g_taskmgr, &sa, 4096,
1000, 32768, 16411, 16433,
1024, 32768, 16411, 16433,
attrs, attrmask, &disp);
if (result != ISC_R_SUCCESS) {
isc_sockaddr_t any;
@@ -1015,7 +1023,6 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
isc_boolean_t rfc1918;
isc_boolean_t empty_zones_enable;
const cfg_obj_t *disablelist = NULL;
isc_uint32_t nqports, qports_updateinterval;
dns_stats_t *resstats = NULL;
dns_stats_t *resquerystats = NULL;
@@ -1330,53 +1337,6 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
resopts, ns_g_dispatchmgr,
dispatch4, dispatch6));
/*
* Query-port pool parameters.
*/
obj = NULL;
nqports = 8;
result = ns_config_get(maps, "queryport-pool-ports", &obj);
if (result == ISC_R_SUCCESS) {
if ((resopts & (DNS_RESOLVER_USEDISPATCHPOOL4 |
DNS_RESOLVER_USEDISPATCHPOOL6)) == 0) {
cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
"queryport-pool-ports is effective only "
"with 'use-queryport-pool yes' (ignored)");
} else
nqports = cfg_obj_asuint32(obj);
}
obj = NULL;
qports_updateinterval = 15;
result = ns_config_get(maps, "queryport-pool-updateinterval", &obj);
if (result == ISC_R_SUCCESS) {
if ((resopts & (DNS_RESOLVER_USEDISPATCHPOOL4 |
DNS_RESOLVER_USEDISPATCHPOOL6)) == 0) {
cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
"queryport-pool-updateinterval is "
"effective only with 'use-queryport-pool "
"yes' (ignored)");
} else
qports_updateinterval = cfg_obj_asuint32(obj);
}
if ((resopts & (DNS_RESOLVER_USEDISPATCHPOOL4 |
DNS_RESOLVER_USEDISPATCHPOOL6)) != 0) {
CHECK(dns_resolver_createdispatchpool(view->resolver,
nqports,
qports_updateinterval
* 60));
}
if (resstats == NULL) {
CHECK(dns_generalstats_create(mctx, &resstats,
dns_resstatscounter_max));
}
dns_view_setresstats(view, resstats);
if (resquerystats == NULL)
CHECK(dns_rdatatypestats_create(mctx, &resquerystats));
dns_view_setresquerystats(view, resquerystats);
/*
* Set the ADB cache size to 1/8th of the max-cache-size.
*/
@@ -2652,8 +2612,6 @@ adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
view != NULL;
view = ISC_LIST_NEXT(view, link)) {
dns_dispatch_t *dispatch6;
isc_boolean_t use_portpool = ISC_FALSE;
unsigned int resopts;
dispatch6 = dns_resolver_dispatchv6(view->resolver);
if (dispatch6 == NULL)
@@ -2661,19 +2619,16 @@ adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
result = dns_dispatch_getlocaladdress(dispatch6, &addr);
if (result != ISC_R_SUCCESS)
goto fail;
resopts = dns_resolver_getoptions(view->resolver);
if ((resopts & (DNS_RESOLVER_USEDISPATCHPOOL4 |
DNS_RESOLVER_USEDISPATCHPOOL6)) != 0) {
/*
* If the resolver uses a dynamic pool of query ports
* with a specific source address, some of the current
* and future ports may override an existing wildcard
* IPv6 port. So we need to allow wildcard match
* in this case.
*/
use_portpool = ISC_TRUE;
}
result = add_listenelt(mctx, list, &addr, use_portpool);
/*
* We always add non-wildcard address regardless of whether
* the port is 'any' (the fourth arg is TRUE): if the port is
* specific, we need to add it since it may conflict with a
* listening interface; if it's zero, we'll dynamically open
* query ports, and some of them may override an existing
* wildcard IPv6 port.
*/
result = add_listenelt(mctx, list, &addr, ISC_TRUE);
if (result != ISC_R_SUCCESS)
goto fail;
}
+15 -14
View File
@@ -18,7 +18,7 @@
- PERFORMANCE OF THIS SOFTWARE.
-->
<!-- File: $Id: Bv9ARM-book.xml,v 1.340.24.9 2008/05/05 22:38:15 each Exp $ -->
<!-- File: $Id: Bv9ARM-book.xml,v 1.340.24.10 2008/05/27 22:36:09 each Exp $ -->
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<title>BIND 9 Administrator Reference Manual</title>
@@ -6243,11 +6243,17 @@ listen-on-v6 port 1234 { !2001:db8::/32; any; };
a wildcard IP address (<command>INADDR_ANY</command>)
will be used.
If <command>port</command> is <command>*</command> or is omitted,
a pool of random unprivileged ports will be used. See the
<command>use-queryport-pool</command>,
<command>queryport-pool-ports</command> and
<command>queryport-pool-updateinterval</command> options below for how the pool
is configured.
a random unprivileged port number is picked up and will be
used for each query.
Previously, the <command>use-queryport-pool</command> was provided
to support a pool of such random ports, but this option is now
obsolete because reusing the same ports in the pool is not
sufficiently secure.
For the same reason, it is generally strongly discouraged to
specify a particular port for the
<command>query-source</command> or
<command>query-source-v6</command> options;
it implicitly disables the use of randomized port numbers.
The <command>avoid-v4-udp-ports</command>
and <command>avoid-v6-udp-ports</command> options can be used
to prevent named
@@ -6264,10 +6270,7 @@ query-source-v6 address * port *;
<term><command>use-queryport-pool</command></term>
<listitem>
<para>
Enable the use of query port pools. By default query port
pools are enabled unless there is a explicit port defined
in <command>query-source</command> or
<command>query-source-v6</command>.
This option is obsolete.
</para>
</listitem>
</varlistentry>
@@ -6276,7 +6279,7 @@ query-source-v6 address * port *;
<term><command>queryport-pool-ports</command></term>
<listitem>
<para>
Specify how many pool ports to use. The default is 8.
This option is obsolete.
</para>
</listitem>
</varlistentry>
@@ -6285,9 +6288,7 @@ query-source-v6 address * port *;
<term><command>queryport-pool-updateinterval</command></term>
<listitem>
<para>
Specify how often, in minutes, that the queryport pool
should be recreated (new ports selected). The default
is 15 minutes.
This option is obsolete.
</para>
</listitem>
</varlistentry>
+15 -14
View File
@@ -14,7 +14,7 @@
- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
-->
<!-- $Id: Bv9ARM.ch06.html,v 1.168.18.10 2008/05/06 01:41:46 tbox Exp $ -->
<!-- $Id: Bv9ARM.ch06.html,v 1.168.18.11 2008/05/27 22:36:09 each Exp $ -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
@@ -3218,11 +3218,17 @@ listen-on-v6 port 1234 { !2001:db8::/32; any; };
a wildcard IP address (<span><strong class="command">INADDR_ANY</strong></span>)
will be used.
If <span><strong class="command">port</strong></span> is <span><strong class="command">*</strong></span> or is omitted,
a pool of random unprivileged ports will be used. See the
<span><strong class="command">use-queryport-pool</strong></span>,
<span><strong class="command">queryport-pool-ports</strong></span> and
<span><strong class="command">queryport-pool-updateinterval</strong></span> options below for how the pool
is configured.
a random unprivileged port number is picked up and will be
used for each query.
Previously, the <command>use-queryport-pool</command> was provided
to support a pool of such random ports, but this option is now
obsolete because reusing the same ports in the pool is not
sufficiently secure.
For the same reason, it is generally strongly discouraged to
specify a particular port for the
<span><strong class="command">query-source</strong></span> or
<span><strong class="command">query-source-v6</strong></span>
options; it implicitly disables the use of randomized port numbers.
The <span><strong class="command">avoid-v4-udp-ports</strong></span>
and <span><strong class="command">avoid-v6-udp-ports</strong></span> options can be used
to prevent named
@@ -3235,20 +3241,15 @@ query-source-v6 address * port *;
<div class="variablelist"><dl>
<dt><span class="term"><span><strong class="command">use-queryport-pool</strong></span></span></dt>
<dd><p>
Enable the use of query port pools. By default query port
pools are enabled unless there is a explicit port defined
in <span><strong class="command">query-source</strong></span> or
<span><strong class="command">query-source-v6</strong></span>.
This option is obsolete.
</p></dd>
<dt><span class="term"><span><strong class="command">queryport-pool-ports</strong></span></span></dt>
<dd><p>
Specify how many pool ports to use. The default is 8.
This option is obsolete.
</p></dd>
<dt><span class="term"><span><strong class="command">queryport-pool-updateinterval</strong></span></span></dt>
<dd><p>
Specify how often, in minutes, that the queryport pool
should be recreated (new ports selected). The default
is 15 minutes.
This option is obsolete.
</p></dd>
</dl></div>
<div class="note" style="margin-left: 0.5in; margin-right: 0.5in;">
+2748 -2786
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -1,3 +1,3 @@
LIBINTERFACE = 42
LIBREVISION = 2
LIBINTERFACE = 43
LIBREVISION = 0
LIBAGE = 0
+190 -487
View File
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: dispatch.c,v 1.137.128.3 2008/04/03 06:10:19 marka Exp $ */
/* $Id: dispatch.c,v 1.137.128.4 2008/05/27 22:36:11 each Exp $ */
/*! \file */
@@ -29,6 +29,7 @@
#include <isc/mem.h>
#include <isc/mutex.h>
#include <isc/print.h>
#include <isc/random.h>
#include <isc/string.h>
#include <isc/task.h>
#include <isc/time.h>
@@ -47,25 +48,22 @@
typedef ISC_LIST(dns_dispentry_t) dns_displist_t;
/* transaction ID */
typedef struct dns_tid {
isc_uint16_t tid_state;
isc_uint16_t *tid_vtable;
isc_uint16_t *tid_pool;
isc_uint16_t tid_a1, tid_a2, tid_a3;
isc_uint16_t tid_c1, tid_c2, tid_c3;
isc_uint16_t tid_state2;
isc_boolean_t tid_usepool;
} dns_tid_t;
typedef struct dns_qid {
unsigned int magic;
unsigned int qid_nbuckets; /*%< hash table size */
unsigned int qid_increment; /*%< id increment on collision */
isc_mutex_t lock;
dns_tid_t tid;
dns_displist_t *qid_table; /*%< the table itself */
} 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;
@@ -79,6 +77,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;
@@ -105,6 +107,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;
@@ -124,6 +127,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;
@@ -166,14 +170,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_tid_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);
@@ -193,13 +197,8 @@ static isc_result_t dispatch_createudp(dns_dispatchmgr_t *mgr,
static isc_boolean_t destroy_mgr_ok(dns_dispatchmgr_t *mgr);
static void destroy_mgr(dns_dispatchmgr_t **mgrp);
static isc_result_t qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
unsigned int increment, isc_boolean_t usepool,
dns_qid_t **qidp);
unsigned int increment, dns_qid_t **qidp);
static void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp);
static isc_uint16_t tid_next(dns_tid_t *tid);
static isc_result_t tid_init(isc_mem_t *mctx, dns_tid_t *tid,
isc_boolean_t usepool);
static void tid_destroy(isc_mem_t *mctx, dns_tid_t *tid);
#define LVL(x) ISC_LOG_DEBUG(x)
@@ -280,40 +279,152 @@ request_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
}
/*
* Return an unpredictable non-reserved UDP port. We share the QID
* framework for this purpose.
* ARC4 random number generator obtained from OpenBSD
*/
static in_port_t
get_randomport(dns_tid_t *tid) {
isc_uint16_t p;
p = tid_next(tid);
/* XXX: should the range be configurable? */
return ((in_port_t)(1024 + (p % (65535 - 1024))));
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;
}
/*
* Return an unpredictable message ID.
*/
static dns_messageid_t
dns_randomid(dns_tid_t *tid) {
isc_uint32_t id;
static void
dispatch_arc4addrandom(arc4ctx_t *actx, unsigned char *dat, int datlen) {
int n;
isc_uint8_t si;
id = tid_next(tid);
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;
}
return ((dns_messageid_t)id);
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);
}
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;
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);
@@ -430,7 +541,7 @@ destroy_disp(isc_task_t *task, isc_event_t *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;
@@ -439,8 +550,10 @@ bucket_search(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id,
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);
}
@@ -642,13 +755,10 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
goto restart;
}
dns_dispatch_hash(&ev->timestamp, sizeof(&ev->timestamp));
dns_dispatch_hash(ev->region.base, ev->region.length);
/* 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"));
@@ -881,14 +991,13 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
goto restart;
}
dns_dispatch_hash(tcpmsg->buffer.base, tcpmsg->buffer.length);
/*
* 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"));
@@ -1040,6 +1149,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);
@@ -1123,10 +1234,14 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
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;
@@ -1177,6 +1292,8 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
if (entropy != NULL)
isc_entropy_attach(entropy, &mgr->entropy);
dispatch_arc4init(&mgr->arc4ctx);
*mgrp = mgr;
return (ISC_R_SUCCESS);
@@ -1188,6 +1305,8 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
DESTROYLOCK(&mgr->pool_lock);
kill_buffer_lock:
DESTROYLOCK(&mgr->buffer_lock);
kill_arc4_lock:
DESTROYLOCK(&mgr->arc4_lock);
kill_lock:
DESTROYLOCK(&mgr->lock);
deallocate:
@@ -1275,7 +1394,7 @@ dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr,
isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
isc_mempool_associatelock(mgr->bpool, &mgr->pool_lock);
result = qid_allocate(mgr, buckets, increment, ISC_TRUE, &mgr->qid);
result = qid_allocate(mgr, buckets, increment, &mgr->qid);
if (result != ISC_R_SUCCESS)
goto cleanup;
@@ -1436,7 +1555,7 @@ dispatch_find(dns_dispatchmgr_t *mgr, isc_sockaddr_t *local,
static isc_result_t
qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
unsigned int increment, isc_boolean_t usepool, dns_qid_t **qidp)
unsigned int increment, dns_qid_t **qidp)
{
dns_qid_t *qid;
unsigned int i;
@@ -1458,17 +1577,8 @@ qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
return (ISC_R_NOMEMORY);
}
result = tid_init(mgr->mctx, &qid->tid, usepool);
if (result != ISC_R_SUCCESS) {
isc_mem_put(mgr->mctx, qid->qid_table,
buckets * sizeof(dns_displist_t));
isc_mem_put(mgr->mctx, qid, sizeof(*qid));
return (ISC_R_NOMEMORY);
}
result = isc_mutex_init(&qid->lock);
if (result != ISC_R_SUCCESS) {
tid_destroy(mgr->mctx, &qid->tid);
isc_mem_put(mgr->mctx, qid->qid_table,
buckets * sizeof(dns_displist_t));
isc_mem_put(mgr->mctx, qid, sizeof(*qid));
@@ -1496,7 +1606,6 @@ qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) {
*qidp = NULL;
qid->magic = 0;
tid_destroy(mctx, &qid->tid);
isc_mem_put(mctx, qid->qid_table,
qid->qid_nbuckets * sizeof(dns_displist_t));
DESTROYLOCK(&qid->lock);
@@ -1533,6 +1642,7 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests,
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;
@@ -1638,7 +1748,7 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
return (result);
}
result = qid_allocate(mgr, buckets, increment, ISC_FALSE, &disp->qid);
result = qid_allocate(mgr, buckets, increment, &disp->qid);
if (result != ISC_R_SUCCESS)
goto deallocate_dispatch;
@@ -1795,6 +1905,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
isc_socket_t *held[DNS_DISPATCH_HELD];
unsigned int i = 0, j = 0, k = 0;
isc_sockaddr_t localaddr_bound;
in_port_t localport = 0;
/*
* dispatch_allocate() checks mgr for us.
@@ -1813,8 +1924,11 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
localaddr_bound = *localaddr;
getsocket:
if ((attributes & DNS_DISPATCHATTR_RANDOMPORT) != 0) {
isc_sockaddr_setport(&localaddr_bound,
get_randomport(&mgr->qid->tid));
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;
@@ -1826,6 +1940,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
attributes &= ~DNS_DISPATCHATTR_RANDOMPORT;
goto getsocket;
}
localport = prt;
} else
result = create_socket(sockmgr, localaddr, &sock);
if (result != ISC_R_SUCCESS)
@@ -1854,6 +1969,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
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);
@@ -1986,19 +2102,20 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
/*
* Try somewhat hard to find an unique ID.
*/
id = (dns_messageid_t)dispatch_arc4random(disp->mgr);
qid = DNS_QID(disp);
LOCK(&qid->lock);
id = dns_randomid(&qid->tid);
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) {
@@ -2020,6 +2137,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
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;
@@ -2331,418 +2449,3 @@ dns_dispatchmgr_dump(dns_dispatchmgr_t *mgr) {
}
}
#endif
/*
* Allow the user to pick one of two ID randomization algorithms.
*
* The first algorithm is an adaptation of the sequence shuffling
* algorithm discovered by Carter Bays and S. D. Durham [ACM Trans. Math.
* Software 2 (1976), 59-64], as documented as Algorithm B in Chapter
* 3.2.2 in Volume 2 of Knuth's "The Art of Computer Programming". We use
* a randomly selected linear congruential random number generator with a
* modulus of 2^16, whose increment is a randomly picked odd number, and
* whose multiplier is picked from a set which meets the following
* criteria:
* Is of the form 8*n+5, which ensures "high potency" according to
* principle iii in the summary chapter 3.6. This form also has a
* gcd(a-1,m) of 4 which is good according to principle iv.
*
* Is between 0.01 and 0.99 times the modulus as specified by
* principle iv.
*
* Passes the spectral test "with flying colors" (ut >= 1) in
* dimensions 2 through 6 as calculated by Algorithm S in Chapter
* 3.3.4 and the ratings calculated by formula 35 in section E.
*
* Of the multipliers that pass this test, pick the set that is
* best according to the theoretical bounds of the serial
* correlation test. This was calculated using a simplified
* version of Knuth's Theorem K in Chapter 3.3.3.
*
* These criteria may not be important for this use, but we might as well
* pick from the best generators since there are so many possible ones and
* we don't have that many random bits to do the picking.
*
* We use a modulus of 2^16 instead of something bigger so that we will
* tend to cycle through all the possible IDs before repeating any,
* however the shuffling will perturb this somewhat. Theoretically there
* is no minimimum interval between two uses of the same ID, but in
* practice it seems to be >64000.
*
* Our adaptatation of Algorithm B mixes the hash state which has
* captured various random events into the shuffler to perturb the
* sequence.
*
* One disadvantage of this algorithm is that if the generator parameters
* were to be guessed, it would be possible to mount a limited brute force
* attack on the ID space since the IDs are only shuffled within a limited
* range.
*
* The second algorithm uses the same random number generator to populate
* a pool of 65536 IDs. The hash state is used to pick an ID from a window
* of 4096 IDs in this pool, then the chosen ID is swapped with the ID
* at the beginning of the window and the window position is advanced.
* This means that the interval between uses of the ID will be no less
* than 65536-4096. The ID sequence in the pool will become more random
* over time.
*
* For both algorithms, two more linear congruential random number generators
* are selected. The ID from the first part of algorithm is used to seed
* the first of these generators, and its output is used to seed the second.
* The strategy is use these generators as 1 to 1 hashes to obfuscate the
* properties of the generator used in the first part of either algorithm.
*
* The first algorithm may be suitable for use in a client resolver since
* its memory requirements are fairly low and it's pretty random out of
* the box. It is somewhat succeptible to a limited brute force attack,
* so the second algorithm is probably preferable for a longer running
* program that issues a large number of queries and has time to randomize
* the pool.
*/
#define TID_SHUFFLE_TABLE_SIZE 100 /* Suggested by Knuth */
/*
* Pick one of the next 4096 IDs in the pool.
* There is a tradeoff here between randomness and how often and ID is reused.
*/
#define TID_LOOKAHEAD 4096 /* Must be a power of 2 */
#define TID_SHUFFLE_ONLY 1 /* algorithm 1 */
#define TID_USE_POOL 2 /* algorithm 2 */
#define TID_HASHSHIFT 3
#define TID_HASHROTATE(v) \
(((v) << TID_HASHSHIFT) | ((v) >> ((sizeof(v) * 8) - TID_HASHSHIFT)))
static isc_uint32_t tid_hash_state;
/*
* Keep a running hash of various bits of data that we'll use to
* stir the ID pool or perturb the ID generator
*/
static void
tid_hash(void *data, size_t len) {
unsigned char *p = data;
/*
* Hash function similar to the one we use for hashing names.
* We don't fold case or toss the upper bit here, though.
* This hash doesn't do much interesting when fed binary zeros,
* so there may be a better hash function.
* This function doesn't need to be very strong since we're
* only using it to stir the pool, but it should be reasonably
* fast.
*/
/*
* We don't care about locking access to tid_hash_state.
* In fact races make the result even more non deteministic.
*/
while (len-- > 0U) {
tid_hash_state = TID_HASHROTATE(tid_hash_state);
tid_hash_state += *p++;
}
}
/*
* Table of good linear congruential multipliers for modulus 2^16
* in order of increasing serial correlation bounds (so trim from
* the end).
*/
static const isc_uint16_t tid_multiplier_table[] = {
17565, 25013, 11733, 19877, 23989, 23997, 24997, 25421,
26781, 27413, 35901, 35917, 35973, 36229, 38317, 38437,
39941, 40493, 41853, 46317, 50581, 51429, 53453, 53805,
11317, 11789, 12045, 12413, 14277, 14821, 14917, 18989,
19821, 23005, 23533, 23573, 23693, 27549, 27709, 28461,
29365, 35605, 37693, 37757, 38309, 41285, 45261, 47061,
47269, 48133, 48597, 50277, 50717, 50757, 50805, 51341,
51413, 51581, 51597, 53445, 11493, 14229, 20365, 20653,
23485, 25541, 27429, 29421, 30173, 35445, 35653, 36789,
36797, 37109, 37157, 37669, 38661, 39773, 40397, 41837,
41877, 45293, 47277, 47845, 49853, 51085, 51349, 54085,
56933, 8877, 8973, 9885, 11365, 11813, 13581, 13589,
13613, 14109, 14317, 15765, 15789, 16925, 17069, 17205,
17621, 17941, 19077, 19381, 20245, 22845, 23733, 24869,
25453, 27213, 28381, 28965, 29245, 29997, 30733, 30901,
34877, 35485, 35613, 36133, 36661, 36917, 38597, 40285,
40693, 41413, 41541, 41637, 42053, 42349, 45245, 45469,
46493, 48205, 48613, 50861, 51861, 52877, 53933, 54397,
55669, 56453, 56965, 58021, 7757, 7781, 8333, 9661,
12229, 14373, 14453, 17549, 18141, 19085, 20773, 23701,
24205, 24333, 25261, 25317, 27181, 30117, 30477, 34757,
34885, 35565, 35885, 36541, 37957, 39733, 39813, 41157,
41893, 42317, 46621, 48117, 48181, 49525, 55261, 55389,
56845, 7045, 7749, 7965, 8469, 9133, 9549, 9789,
10173, 11181, 11285, 12253, 13453, 13533, 13757, 14477,
15053, 16901, 17213, 17269, 17525, 17629, 18605, 19013,
19829, 19933, 20069, 20093, 23261, 23333, 24949, 25309,
27613, 28453, 28709, 29301, 29541, 34165, 34413, 37301,
37773, 38045, 38405, 41077, 41781, 41925, 42717, 44437,
44525, 44613, 45933, 45941, 47077, 50077, 50893, 52117,
5293, 55069, 55989, 58125, 59205, 6869, 14685, 15453,
16821, 17045, 17613, 18437, 21029, 22773, 22909, 25445,
25757, 26541, 30709, 30909, 31093, 31149, 37069, 37725,
37925, 38949, 39637, 39701, 40765, 40861, 42965, 44813,
45077, 45733, 47045, 50093, 52861, 52957, 54181, 56325,
56365, 56381, 56877, 57013, 5741, 58101, 58669, 8613,
10045, 10261, 10653, 10733, 11461, 12261, 14069, 15877,
17757, 21165, 23885, 24701, 26429, 26645, 27925, 28765,
29197, 30189, 31293, 39781, 39909, 40365, 41229, 41453,
41653, 42165, 42365, 47421, 48029, 48085, 52773, 5573,
57037, 57637, 58341, 58357, 58901, 6357, 7789, 9093,
10125, 10709, 10765, 11957, 12469, 13437, 13509, 14773,
15437, 15773, 17813, 18829, 19565, 20237, 23461, 23685,
23725, 23941, 24877, 25461, 26405, 29509, 30285, 35181,
37229, 37893, 38565, 40293, 44189, 44581, 45701, 47381,
47589, 48557, 4941, 51069, 5165, 52797, 53149, 5341,
56301, 56765, 58581, 59493, 59677, 6085, 6349, 8293,
8501, 8517, 11597, 11709, 12589, 12693, 13517, 14909,
17397, 18085, 21101, 21269, 22717, 25237, 25661, 29189,
30101, 31397, 33933, 34213, 34661, 35533, 36493, 37309,
40037, 4189, 42909, 44309, 44357, 44389, 4541, 45461,
46445, 48237, 54149, 55301, 55853, 56621, 56717, 56901,
5813, 58437, 12493, 15365, 15989, 17829, 18229, 19341,
21013, 21357, 22925, 24885, 26053, 27581, 28221, 28485,
30605, 30613, 30789, 35437, 36285, 37189, 3941, 41797,
4269, 42901, 43293, 44645, 45221, 46893, 4893, 50301,
50325, 5189, 52109, 53517, 54053, 54485, 5525, 55949,
56973, 59069, 59421, 60733, 61253, 6421, 6701, 6709,
7101, 8669, 15797, 19221, 19837, 20133, 20957, 21293,
21461, 22461, 29085, 29861, 30869, 34973, 36469, 37565,
38125, 38829, 39469, 40061, 40117, 44093, 47429, 48341,
50597, 51757, 5541, 57629, 58405, 59621, 59693, 59701,
61837, 7061, 10421, 11949, 15405, 20861, 25397, 25509,
25893, 26037, 28629, 28869, 29605, 30213, 34205, 35637,
36365, 37285, 3773, 39117, 4021, 41061, 42653, 44509,
4461, 44829, 4725, 5125, 52269, 56469, 59085, 5917,
60973, 8349, 17725, 18637, 19773, 20293, 21453, 22533,
24285, 26333, 26997, 31501, 34541, 34805, 37509, 38477,
41333, 44125, 46285, 46997, 47637, 48173, 4925, 50253,
50381, 50917, 51205, 51325, 52165, 52229, 5253, 5269,
53509, 56253, 56341, 5821, 58373, 60301, 61653, 61973,
62373, 8397, 11981, 14341, 14509, 15077, 22261, 22429,
24261, 28165, 28685, 30661, 34021, 34445, 39149, 3917,
43013, 43317, 44053, 44101, 4533, 49541, 49981, 5277,
54477, 56357, 57261, 57765, 58573, 59061, 60197, 61197,
62189, 7725, 8477, 9565, 10229, 11437, 14613, 14709,
16813, 20029, 20677, 31445, 3165, 31957, 3229, 33541,
36645, 3805, 38973, 3965, 4029, 44293, 44557, 46245,
48917, 4909, 51749, 53709, 55733, 56445, 5925, 6093,
61053, 62637, 8661, 9109, 10821, 11389, 13813, 14325,
15501, 16149, 18845, 22669, 26437, 29869, 31837, 33709,
33973, 34173, 3677, 3877, 3981, 39885, 42117, 4421,
44221, 44245, 44693, 46157, 47309, 5005, 51461, 52037,
55333, 55693, 56277, 58949, 6205, 62141, 62469, 6293,
10101, 12509, 14029, 17997, 20469, 21149, 25221, 27109,
2773, 2877, 29405, 31493, 31645, 4077, 42005, 42077,
42469, 42501, 44013, 48653, 49349, 4997, 50101, 55405,
56957, 58037, 59429, 60749, 61797, 62381, 62837, 6605,
10541, 23981, 24533, 2701, 27333, 27341, 31197, 33805,
3621, 37381, 3749, 3829, 38533, 42613, 44381, 45901,
48517, 51269, 57725, 59461, 60045, 62029, 13805, 14013,
15461, 16069, 16157, 18573, 2309, 23501, 28645, 3077,
31541, 36357, 36877, 3789, 39429, 39805, 47685, 47949,
49413, 5485, 56757, 57549, 57805, 58317, 59549, 62213,
62613, 62853, 62933, 8909, 12941, 16677, 20333, 21541,
24429, 26077, 26421, 2885, 31269, 33381, 3661, 40925,
42925, 45173, 4525, 4709, 53133, 55941, 57413, 57797,
62125, 62237, 62733, 6773, 12317, 13197, 16533, 16933,
18245, 2213, 2477, 29757, 33293, 35517, 40133, 40749,
4661, 49941, 62757, 7853, 8149, 8573, 11029, 13421,
21549, 22709, 22725, 24629, 2469, 26125, 2669, 34253,
36709, 41013, 45597, 46637, 52285, 52333, 54685, 59013,
60997, 61189, 61981, 62605, 62821, 7077, 7525, 8781,
10861, 15277, 2205, 22077, 28517, 28949, 32109, 33493,
4661, 49941, 62757, 7853, 8149, 8573, 11029, 13421,
21549, 22709, 22725, 24629, 2469, 26125, 2669, 34253,
36709, 41013, 45597, 46637, 52285, 52333, 54685, 59013,
60997, 61189, 61981, 62605, 62821, 7077, 7525, 8781,
10861, 15277, 2205, 22077, 28517, 28949, 32109, 33493,
3685, 39197, 39869, 42621, 44997, 48565, 5221, 57381,
61749, 62317, 63245, 63381, 23149, 2549, 28661, 31653,
33885, 36341, 37053, 39517, 42805, 45853, 48997, 59349,
60053, 62509, 63069, 6525, 1893, 20181, 2365, 24893,
27397, 31357, 32277, 33357, 34437, 36677, 37661, 43469,
43917, 50997, 53869, 5653, 13221, 16741, 17893, 2157,
28653, 31789, 35301, 35821, 61613, 62245, 12405, 14517,
17453, 18421, 3149, 3205, 40341, 4109, 43941, 46869,
48837, 50621, 57405, 60509, 62877, 8157, 12933, 12957,
16501, 19533, 3461, 36829, 52357, 58189, 58293, 63053,
17109, 1933, 32157, 37701, 59005, 61621, 13029, 15085,
16493, 32317, 35093, 5061, 51557, 62221, 20765, 24613,
2629, 30861, 33197, 33749, 35365, 37933, 40317, 48045,
56229, 61157, 63797, 7917, 17965, 1917, 1973, 20301,
2253, 33157, 58629, 59861, 61085, 63909, 8141, 9221,
14757, 1581, 21637, 26557, 33869, 34285, 35733, 40933,
42517, 43501, 53653, 61885, 63805, 7141, 21653, 54973,
31189, 60061, 60341, 63357, 16045, 2053, 26069, 33997,
43901, 54565, 63837, 8949, 17909, 18693, 32349, 33125,
37293, 48821, 49053, 51309, 64037, 7117, 1445, 20405,
23085, 26269, 26293, 27349, 32381, 33141, 34525, 36461,
37581, 43525, 4357, 43877, 5069, 55197, 63965, 9845,
12093, 2197, 2229, 32165, 33469, 40981, 42397, 8749,
10853, 1453, 18069, 21693, 30573, 36261, 37421, 42533
};
#define TID_MULT_TABLE_SIZE \
((sizeof tid_multiplier_table) / \
(sizeof tid_multiplier_table[0]))
#define TID_RANGE_MASK (TID_LOOKAHEAD - 1)
#define TID_POOL_MASK 0xFFFF /* used to wrap the pool index */
#define TID_SHUFFLE_ONLY 1
#define TID_USE_POOL 2
static isc_uint16_t
tid_next(dns_tid_t *tid) {
isc_uint16_t id, compressed_hash;
isc_uint16_t j;
compressed_hash = ((tid_hash_state >> 16) ^
(tid_hash_state)) & 0xFFFF;
if (tid->tid_usepool) {
isc_uint16_t pick;
pick = compressed_hash & TID_RANGE_MASK;
pick = (tid->tid_state + pick) & TID_POOL_MASK;
id = tid->tid_pool[pick];
if (pick != 0) {
/* Swap two IDs to stir the pool */
tid->tid_pool[pick] =
tid->tid_pool[tid->tid_state];
tid->tid_pool[tid->tid_state] = id;
}
/* increment the base pointer into the pool */
if (tid->tid_state == 65535)
tid->tid_state = 0;
else
tid->tid_state++;
} else {
/*
* This is the original Algorithm B
* j = ((u_long)
* QUERID_SHUFFLE_TABLE_SIZE * tid_state2) >> 16;
*
* We'll perturb it with some random stuff ...
*/
j = ((isc_uint32_t) TID_SHUFFLE_TABLE_SIZE *
(tid->tid_state2 ^ compressed_hash)) >> 16;
tid->tid_state2 = id = tid->tid_vtable[j];
tid->tid_state = (((isc_uint32_t) tid->tid_a1 *
tid->tid_state) +
tid->tid_c1) & 0xFFFF;
tid->tid_vtable[j] = tid->tid_state;
}
/* Now lets obfuscate ... */
id = (((isc_uint32_t) tid->tid_a2 * id) +
tid->tid_c2) & 0xFFFF;
id = (((isc_uint32_t) tid->tid_a3 * id) +
tid->tid_c3) & 0xFFFF;
return (id);
}
static isc_result_t
tid_init(isc_mem_t *mctx, dns_tid_t *tid, isc_boolean_t usepool) {
isc_time_t now;
pid_t mypid;
isc_uint16_t a1ndx, a2ndx, a3ndx, c1ndx, c2ndx, c3ndx;
int i;
isc_time_now(&now);
mypid = getpid();
/* Initialize the state */
memset(tid, 0, sizeof(*tid));
tid_hash(&now, sizeof now);
tid_hash(&mypid, sizeof mypid);
/*
* Select our random number generators and initial seed.
* We could really use more random bits at this point,
* but we'll try to make a silk purse out of a sows ear ...
*/
/* generator 1 */
a1ndx = ((isc_uint32_t) TID_MULT_TABLE_SIZE *
(tid_hash_state & 0xFFFF)) >> 16;
tid->tid_a1 = tid_multiplier_table[a1ndx];
c1ndx = (tid_hash_state >> 9) & 0x7FFF;
tid->tid_c1 = 2 * c1ndx + 1;
/* generator 2, distinct from 1 */
a2ndx = ((isc_uint32_t) (TID_MULT_TABLE_SIZE - 1) *
((tid_hash_state >> 10) & 0xFFFF)) >> 16;
if (a2ndx >= a1ndx)
a2ndx++;
tid->tid_a2 = tid_multiplier_table[a2ndx];
c2ndx = tid_hash_state % 32767;
if (c2ndx >= c1ndx)
c2ndx++;
tid->tid_c2 = 2*c2ndx + 1;
/* generator 3, distinct from 1 and 2 */
a3ndx = ((isc_uint32_t) (TID_MULT_TABLE_SIZE - 2) *
((tid_hash_state >> 20) & 0xFFFF)) >> 16;
if (a3ndx >= a1ndx || a3ndx >= a2ndx)
a3ndx++;
if (a3ndx >= a1ndx && a3ndx >= a2ndx)
a3ndx++;
tid->tid_a3 = tid_multiplier_table[a3ndx];
c3ndx = tid_hash_state % 32766;
if (c3ndx >= c1ndx || c3ndx >= c2ndx)
c3ndx++;
if (c3ndx >= c1ndx && c3ndx >= c2ndx)
c3ndx++;
tid->tid_c3 = 2*c3ndx + 1;
tid->tid_state =
((tid_hash_state >> 16) ^ (tid_hash_state)) & 0xFFFF;
tid->tid_usepool = usepool;
if (tid->tid_usepool) {
tid->tid_pool = isc_mem_get(mctx,
0x10000 * sizeof(isc_uint16_t));
if (tid->tid_pool == NULL)
return (ISC_R_NOMEMORY);
for (i = 0; ; i++) {
tid->tid_pool[i] = tid->tid_state;
tid->tid_state =
(((u_long) tid->tid_a1 *
tid->tid_state) +
tid->tid_c1) & 0xFFFF;
if (i == 0xFFFF)
break;
}
} else {
tid->tid_vtable = isc_mem_get(mctx, TID_SHUFFLE_TABLE_SIZE *
(sizeof(isc_uint16_t)) );
if (tid->tid_vtable == NULL)
return (ISC_R_NOMEMORY);
for (i = 0; i < TID_SHUFFLE_TABLE_SIZE; i++) {
tid->tid_vtable[i] = tid->tid_state;
tid->tid_state =
(((isc_uint32_t) tid->tid_a1 *
tid->tid_state) +
tid->tid_c1) & 0xFFFF;
}
tid->tid_state2 = tid->tid_state;
}
return (ISC_R_SUCCESS);
}
static void
tid_destroy(isc_mem_t *mctx, dns_tid_t *tid) {
if (tid->tid_usepool)
isc_mem_put(mctx, tid->tid_pool,
0x10000 * sizeof(isc_uint16_t));
else
isc_mem_put(mctx, tid->tid_vtable,
TID_SHUFFLE_TABLE_SIZE *
(sizeof(isc_uint16_t)) );
memset(tid, 0, sizeof(*tid));
}
void
dns_dispatch_hash(void *data, size_t len) {
tid_hash(data, len);
}
+2 -9
View File
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: dispatch.h,v 1.56.128.2 2008/04/03 06:20:34 tbox Exp $ */
/* $Id: dispatch.h,v 1.56.128.3 2008/05/27 22:36:11 each Exp $ */
#ifndef DNS_DISPATCH_H
#define DNS_DISPATCH_H 1
@@ -115,7 +115,7 @@ struct dns_dispatchevent {
* accept replies from them.
*
* _RANDOMPORT
* TBD
* Allocate UDP port randomly.
*/
#define DNS_DISPATCHATTR_PRIVATE 0x00000001U
#define DNS_DISPATCHATTR_TCP 0x00000002U
@@ -458,13 +458,6 @@ dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event);
* event != NULL
*/
void
dns_dispatch_hash(void *data, size_t len);
/*%<
* Feed 'data' to the dispatch query id generator where 'len' is the size
* of 'data'.
*/
ISC_LANG_ENDDECLS
#endif /* DNS_DISPATCH_H */
+40 -31
View File
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: resolver.c,v 1.355.12.15 2008/05/06 01:11:30 each Exp $ */
/* $Id: resolver.c,v 1.355.12.16 2008/05/27 22:36:11 each Exp $ */
/*! \file */
@@ -1221,44 +1221,53 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
if (result != ISC_R_SUCCESS)
goto cleanup_query;
} else {
int did = 0;
isc_uint32_t val;
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;
if (res->ndisps > 0) {
isc_random_get(&val);
did = val % res->ndisps;
}
switch (isc_sockaddr_pf(&addrinfo->sockaddr)) {
case PF_INET:
if (res->dispatchv4pool != NULL) {
RES_LOCK(&res->poollock,
isc_rwlocktype_read);
dns_dispatch_attach(res->dispatchv4pool[did],
&query->dispatch);
RES_UNLOCK(&res->poollock,
isc_rwlocktype_read);
} else {
dns_dispatch_attach(res->dispatchv4,
&query->dispatch);
}
case AF_INET:
disp_base = res->dispatchv4;
attrs |= DNS_DISPATCHATTR_IPV4;
break;
case PF_INET6:
if (res->dispatchv6pool != NULL) {
RES_LOCK(&res->poollock,
isc_rwlocktype_read);
dns_dispatch_attach(res->dispatchv6pool[did],
&query->dispatch);
RES_UNLOCK(&res->poollock,
isc_rwlocktype_read);
} else {
dns_dispatch_attach(res->dispatchv6,
&query->dispatch);
}
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
+1 -1
View File
@@ -1,3 +1,3 @@
LIBINTERFACE = 40
LIBREVISION = 2
LIBREVISION = 3
LIBAGE = 0
+5 -4
View File
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: namedconf.c,v 1.78.46.6 2008/04/03 02:12:22 marka Exp $ */
/* $Id: namedconf.c,v 1.78.46.7 2008/05/27 22:36:11 each Exp $ */
/*! \file */
@@ -781,8 +781,9 @@ view_clauses[] = {
*/
{ "query-source", &cfg_type_querysource4, 0 },
{ "query-source-v6", &cfg_type_querysource6, 0 },
{ "queryport-pool-ports", &cfg_type_uint32, 0 },
{ "queryport-pool-updateinterval", &cfg_type_uint32, 0 },
{ "queryport-pool-ports", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
{ "queryport-pool-updateinterval", &cfg_type_uint32,
CFG_CLAUSEFLAG_OBSOLETE},
{ "recursion", &cfg_type_boolean, 0 },
{ "request-ixfr", &cfg_type_boolean, 0 },
{ "request-nsid", &cfg_type_boolean, 0 },
@@ -793,7 +794,7 @@ view_clauses[] = {
{ "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
{ "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP },
{ "transfer-format", &cfg_type_transferformat, 0 },
{ "use-queryport-pool", &cfg_type_boolean, 0 },
{ "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
{ "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 },
{ NULL, NULL, 0 }
};