summaryrefslogtreecommitdiffstats
path: root/lib/dns
diff options
context:
space:
mode:
authordougb <dougb@FreeBSD.org>2008-12-23 18:35:21 +0000
committerdougb <dougb@FreeBSD.org>2008-12-23 18:35:21 +0000
commit6c8226d7d6bb16d3d0bc2ab68a30b0700011c64f (patch)
treed25d756be8550df073eb3ed4e5b39831380291b5 /lib/dns
parente2c9b86ef6b41282513a874faaf6d208422cfc7b (diff)
downloadFreeBSD-src-6c8226d7d6bb16d3d0bc2ab68a30b0700011c64f.zip
FreeBSD-src-6c8226d7d6bb16d3d0bc2ab68a30b0700011c64f.tar.gz
Vendor import of BIND 9.4.3
Diffstat (limited to 'lib/dns')
-rw-r--r--lib/dns/acache.c50
-rw-r--r--lib/dns/adb.c64
-rw-r--r--lib/dns/api2
-rw-r--r--lib/dns/cache.c37
-rw-r--r--lib/dns/dispatch.c1330
-rw-r--r--lib/dns/dst_parse.c8
-rw-r--r--lib/dns/dst_parse.h8
-rw-r--r--lib/dns/include/dns/dispatch.h64
-rw-r--r--lib/dns/journal.c30
-rw-r--r--lib/dns/master.c34
-rw-r--r--lib/dns/masterdump.c23
-rw-r--r--lib/dns/message.c13
-rw-r--r--lib/dns/rbt.c40
-rw-r--r--lib/dns/rbtdb.c78
-rw-r--r--lib/dns/rdata/generic/nsec_47.c10
-rw-r--r--lib/dns/rdata/generic/nsec_47.h8
-rw-r--r--lib/dns/rdata/generic/txt_16.c8
-rw-r--r--lib/dns/rdata/in_1/apl_42.c67
-rw-r--r--lib/dns/rdata/in_1/naptr_35.c14
-rw-r--r--lib/dns/request.c94
-rw-r--r--lib/dns/resolver.c335
-rw-r--r--lib/dns/rootns.c48
-rw-r--r--lib/dns/sdb.c16
-rw-r--r--lib/dns/tkey.c14
-rw-r--r--lib/dns/tsig.c76
-rw-r--r--lib/dns/validator.c110
-rw-r--r--lib/dns/view.c21
-rw-r--r--lib/dns/xfrin.c26
-rw-r--r--lib/dns/zone.c62
29 files changed, 1894 insertions, 796 deletions
diff --git a/lib/dns/acache.c b/lib/dns/acache.c
index 5787a5a..cd56c3c 100644
--- a/lib/dns/acache.c
+++ b/lib/dns/acache.c
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC")
*
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: acache.c,v 1.3.2.16 2006/07/19 00:34:56 marka Exp $ */
+/* $Id: acache.c,v 1.3.2.18 2008/02/07 23:45:56 tbox Exp $ */
#include <config.h>
@@ -137,7 +137,7 @@ struct acache_cleaner {
in seconds. */
isc_stdtime_t last_cleanup_time; /* The time when the last
- cleanup task completed */
+ cleanup task completed */
isc_timer_t *cleaning_timer;
isc_event_t *resched_event; /* Sent by cleaner task to
@@ -347,11 +347,11 @@ shutdown_buckets(dns_acache_t *acache) {
INSIST(ISC_LIST_EMPTY(dbent->originlist) &&
ISC_LIST_EMPTY(dbent->referlist));
ISC_LIST_UNLINK(acache->dbbucket[i], dbent, link);
-
+
dns_db_detach(&dbent->db);
isc_mem_put(acache->mctx, dbent, sizeof(*dbent));
-
+
acache->dbentries--;
}
}
@@ -513,7 +513,7 @@ clear_entry(dns_acache_t *acache, dns_acacheentry_t *entry) {
if (dns_name_dynamic(entry->foundname))
dns_name_free(entry->foundname, acache->mctx);
isc_mem_put(acache->mctx, entry->foundname,
- sizeof(*entry->foundname));
+ sizeof(*entry->foundname));
entry->foundname = NULL;
}
@@ -558,7 +558,7 @@ acache_cleaner_init(dns_acache_t *acache, isc_timermgr_t *timermgr,
if (timermgr != NULL) {
cleaner->acache->live_cleaners++;
-
+
result = isc_task_onshutdown(acache->task,
acache_cleaner_shutdown_action,
acache);
@@ -677,7 +677,7 @@ end_cleaning(acache_cleaner_t *cleaner, isc_event_t *event) {
*/
if (isc_refcount_current(&cleaner->current_entry->references) == 1) {
INSIST(cleaner->current_entry->callback == NULL);
-
+
if (ISC_LINK_LINKED(cleaner->current_entry, link)) {
ISC_LIST_UNLINK(acache->entries,
cleaner->current_entry, link);
@@ -701,7 +701,7 @@ end_cleaning(acache_cleaner_t *cleaner, isc_event_t *event) {
acache->stats.queries,
acache->stats.adds, acache->stats.deleted,
acache->stats.cleaned, acache->stats.cleaner_runs,
- acache->stats.overmem, acache->stats.overmem_nocreates,
+ acache->stats.overmem, acache->stats.overmem_nocreates,
acache->stats.nomem);
reset_stats(acache);
@@ -913,7 +913,7 @@ static void
acache_overmem_cleaning_action(isc_task_t *task, isc_event_t *event) {
acache_cleaner_t *cleaner = event->ev_arg;
isc_boolean_t want_cleaning = ISC_FALSE;
-
+
UNUSED(task);
INSIST(event->ev_type == DNS_EVENT_ACACHEOVERMEM);
@@ -965,10 +965,14 @@ water(void *arg, int mark) {
LOCK(&acache->cleaner.lock);
- acache->cleaner.overmem = overmem;
+ if (acache->cleaner.overmem != overmem) {
+ acache->cleaner.overmem = overmem;
- if (acache->cleaner.overmem_event != NULL)
- isc_task_send(acache->task, &acache->cleaner.overmem_event);
+ if (acache->cleaner.overmem_event != NULL)
+ isc_task_send(acache->task,
+ &acache->cleaner.overmem_event);
+ isc_mem_waterack(acache->mctx, mark);
+ }
UNLOCK(&acache->cleaner.lock);
}
@@ -1102,7 +1106,7 @@ dns_acache_create(dns_acache_t **acachep, isc_mem_t *mctx,
}
acache->live_cleaners = 0;
- result = acache_cleaner_init(acache, timermgr, &acache->cleaner);
+ result = acache_cleaner_init(acache, timermgr, &acache->cleaner);
if (result != ISC_R_SUCCESS)
goto cleanup;
@@ -1177,7 +1181,7 @@ dns_acache_detach(dns_acache_t **acachep) {
isc_task_shutdown(acache->task);
should_free = ISC_FALSE;
}
-
+
if (should_free)
destroy(acache);
}
@@ -1366,14 +1370,14 @@ dns_acache_createentry(dns_acache_t *acache, dns_db_t *origdb,
REQUIRE(entryp != NULL && *entryp == NULL);
REQUIRE(origdb != NULL);
- /*
- * Should we exceed our memory limit for some reason (for
- * example, if the cleaner does not run aggressively enough),
+ /*
+ * Should we exceed our memory limit for some reason (for
+ * example, if the cleaner does not run aggressively enough),
* then we will not create additional entries.
*
* XXXSK: It might be better to lock the acache->cleaner->lock,
- * but locking may be an expensive bottleneck. If we misread
- * the value, we will occasionally refuse to create a few
+ * but locking may be an expensive bottleneck. If we misread
+ * the value, we will occasionally refuse to create a few
* cache entries, or create a few that we should not. I do not
* expect this to happen often, and it will not have very bad
* effects when it does. So no lock for now.
@@ -1391,7 +1395,7 @@ dns_acache_createentry(dns_acache_t *acache, dns_db_t *origdb,
isc_random_get(&r);
newentry->locknum = r % DEFAULT_ACACHE_ENTRY_LOCK_COUNT;
-
+
result = isc_refcount_init(&newentry->references, 1);
if (result != ISC_R_SUCCESS) {
isc_mem_put(acache->mctx, newentry, sizeof(*newentry));
@@ -1738,7 +1742,7 @@ dns_acache_setcleaninginterval(dns_acache_t *acache, unsigned int t) {
isc_timertype_ticker,
NULL, &interval, ISC_FALSE);
}
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS)
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_ACACHE, ISC_LOG_WARNING,
"could not set acache cleaning interval: %s",
diff --git a/lib/dns/adb.c b/lib/dns/adb.c
index c65c474..ae5dec8 100644
--- a/lib/dns/adb.c
+++ b/lib/dns/adb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,9 +15,9 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: adb.c,v 1.215.18.17 2007/09/11 02:23:26 marka Exp $ */
+/* $Id: adb.c,v 1.215.18.24 2008/10/17 03:35:14 marka Exp $ */
-/*! \file
+/*! \file
*
* \note
* In finds, if task == NULL, no events will be generated, and no events
@@ -71,7 +71,7 @@
#define DNS_ADBFETCH6_MAGIC ISC_MAGIC('a', 'd', 'F', '6')
#define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)
-/*!
+/*!
* The number of buckets needs to be a prime (for good hashing).
*
* XXXRTH How many buckets do we need?
@@ -119,6 +119,7 @@ struct dns_adb {
isc_mutex_t lock;
isc_mutex_t reflock; /*%< Covers irefcnt, erefcnt */
+ isc_mutex_t overmemlock; /*%< Covers overmem */
isc_mem_t *mctx;
dns_view_t *view;
isc_timermgr_t *timermgr;
@@ -494,6 +495,7 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
isc_boolean_t new_addresses_added;
dns_rdatatype_t rdtype;
unsigned int findoptions;
+ dns_adbnamehooklist_t *hookhead;
INSIST(DNS_ADBNAME_VALID(adbname));
adb = adbname->adb;
@@ -518,10 +520,12 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
INSIST(rdata.length == 4);
memcpy(&ina.s_addr, rdata.data, 4);
isc_sockaddr_fromin(&sockaddr, &ina, 0);
+ hookhead = &adbname->v4;
} else {
INSIST(rdata.length == 16);
memcpy(in6a.s6_addr, rdata.data, 16);
isc_sockaddr_fromin6(&sockaddr, &in6a, 0);
+ hookhead = &adbname->v6;
}
INSIST(nh == NULL);
@@ -550,7 +554,7 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
link_entry(adb, addr_bucket, entry);
} else {
- for (anh = ISC_LIST_HEAD(adbname->v4);
+ for (anh = ISC_LIST_HEAD(*hookhead);
anh != NULL;
anh = ISC_LIST_NEXT(anh, plink))
if (anh->entry == foundentry)
@@ -563,12 +567,8 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
}
new_addresses_added = ISC_TRUE;
- if (nh != NULL) {
- if (rdtype == dns_rdatatype_a)
- ISC_LIST_APPEND(adbname->v4, nh, plink);
- else
- ISC_LIST_APPEND(adbname->v6, nh, plink);
- }
+ if (nh != NULL)
+ ISC_LIST_APPEND(*hookhead, nh, plink);
nh = NULL;
result = dns_rdataset_next(rdataset);
}
@@ -1738,8 +1738,11 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *qname,
bucket = entry->lock_bucket;
LOCK(&adb->entrylocks[bucket]);
- if (entry_is_lame(adb, entry, qname, qtype, now))
+ if (!FIND_RETURNLAME(find)
+ && entry_is_lame(adb, entry, qname, qtype, now)) {
+ find->options |= DNS_ADBFIND_LAMEPRUNED;
goto nextv6;
+ }
addrinfo = new_adbaddrinfo(adb, entry, find->port);
if (addrinfo == NULL) {
find->partial_result |= DNS_ADBFIND_INET6;
@@ -1773,12 +1776,15 @@ shutdown_task(isc_task_t *task, isc_event_t *ev) {
INSIST(DNS_ADB_VALID(adb));
/*
+ * Wait for lock around check_exit() call to be released.
+ */
+ LOCK(&adb->lock);
+ /*
* Kill the timer, and then the ADB itself. Note that this implies
* that this task was the one scheduled to get timer events. If
* this is not true (and it is unfortunate there is no way to INSIST()
* this) badness will occur.
*/
- LOCK(&adb->lock);
isc_timer_detach(&adb->timer);
UNLOCK(&adb->lock);
isc_event_free(&ev);
@@ -1990,6 +1996,7 @@ destroy(dns_adb_t *adb) {
DESTROYLOCK(&adb->reflock);
DESTROYLOCK(&adb->lock);
DESTROYLOCK(&adb->mplock);
+ DESTROYLOCK(&adb->overmemlock);
isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
}
@@ -2060,6 +2067,10 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
if (result != ISC_R_SUCCESS)
goto fail0d;
+ result = isc_mutex_init(&adb->overmemlock);
+ if (result != ISC_R_SUCCESS)
+ goto fail0e;
+
/*
* Initialize the bucket locks for names and elements.
* May as well initialize the list heads, too.
@@ -2162,6 +2173,8 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
if (adb->afmp != NULL)
isc_mempool_destroy(&adb->afmp);
+ DESTROYLOCK(&adb->overmemlock);
+ fail0e:
DESTROYLOCK(&adb->reflock);
fail0d:
DESTROYLOCK(&adb->mplock);
@@ -3133,8 +3146,10 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) {
address_type = DNS_ADBFIND_INET6;
fetch = name->fetch_aaaa;
name->fetch_aaaa = NULL;
- }
- INSIST(address_type != 0);
+ } else
+ fetch = NULL;
+
+ INSIST(address_type != 0 && fetch != NULL);
dns_resolver_destroyfetch(&fetch->fetch);
dev->fetch = NULL;
@@ -3582,12 +3597,21 @@ water(void *arg, int mark) {
DP(ISC_LOG_DEBUG(1),
"adb reached %s water mark", overmem ? "high" : "low");
- adb->overmem = overmem;
- if (overmem) {
- isc_interval_set(&interval, 0, 1);
- (void)isc_timer_reset(adb->timer, isc_timertype_once, NULL,
- &interval, ISC_TRUE);
+ /*
+ * We can't use adb->lock as there is potential for water
+ * to be called when adb->lock is held.
+ */
+ LOCK(&adb->overmemlock);
+ if (adb->overmem != overmem) {
+ adb->overmem = overmem;
+ if (overmem) {
+ isc_interval_set(&interval, 0, 1);
+ (void)isc_timer_reset(adb->timer, isc_timertype_once,
+ NULL, &interval, ISC_TRUE);
+ }
+ isc_mem_waterack(adb->mctx, mark);
}
+ UNLOCK(&adb->overmemlock);
}
void
diff --git a/lib/dns/api b/lib/dns/api
index 7ad5506..7949ab0 100644
--- a/lib/dns/api
+++ b/lib/dns/api
@@ -1,3 +1,3 @@
-LIBINTERFACE = 35
+LIBINTERFACE = 36
LIBREVISION = 1
LIBAGE = 0
diff --git a/lib/dns/cache.c b/lib/dns/cache.c
index 011dbf7..c9b4a95 100644
--- a/lib/dns/cache.c
+++ b/lib/dns/cache.c
@@ -1,8 +1,8 @@
/*
- * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: cache.c,v 1.57.18.16 2006/08/01 01:06:48 marka Exp $ */
+/* $Id: cache.c,v 1.57.18.18 2008/02/07 23:45:56 tbox Exp $ */
/*! \file */
@@ -42,16 +42,16 @@
#define CACHE_MAGIC ISC_MAGIC('$', '$', '$', '$')
#define VALID_CACHE(cache) ISC_MAGIC_VALID(cache, CACHE_MAGIC)
-/*!
+/*!
* Control incremental cleaning.
* DNS_CACHE_MINSIZE is how many bytes is the floor for dns_cache_setcachesize().
* See also DNS_CACHE_CLEANERINCREMENT
*/
#define DNS_CACHE_MINSIZE 2097152 /*%< Bytes. 2097152 = 2 MB */
-/*!
+/*!
* Control incremental cleaning.
* CLEANERINCREMENT is how many nodes are examined in one pass.
- * See also DNS_CACHE_MINSIZE
+ * See also DNS_CACHE_MINSIZE
*/
#define DNS_CACHE_CLEANERINCREMENT 1000U /*%< Number of nodes. */
@@ -173,7 +173,7 @@ adjust_increment(cache_cleaner_t *cleaner, unsigned int remaining,
unsigned int pps = dns_pps;
unsigned int interval;
unsigned int names;
-
+
/*
* Tune for minumum of 100 packets per second (pps).
*/
@@ -194,7 +194,7 @@ adjust_increment(cache_cleaner_t *cleaner, unsigned int remaining,
ISC_LOG_DEBUG(1), "adjust_increment interval=%u "
"names=%u usec=%" ISC_PLATFORM_QUADFORMAT "u",
interval, names, usecs);
-
+
if (usecs == 0) {
/*
* If we cleaned all the nodes in unmeasurable time
@@ -537,7 +537,7 @@ dns_cache_setcleaninginterval(dns_cache_t *cache, unsigned int t) {
isc_timertype_ticker,
NULL, &interval, ISC_FALSE);
}
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS)
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
"could not set cache cleaning interval: %s",
@@ -624,7 +624,7 @@ cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
result = ISC_R_NOMEMORY;
goto cleanup;
}
-
+
cleaner->overmem_event =
isc_event_allocate(cache->mctx, cleaner,
DNS_EVENT_CACHEOVERMEM,
@@ -662,7 +662,7 @@ begin_cleaning(cache_cleaner_t *cleaner) {
/*
* Create an iterator, if it does not already exist, and
- * position it at the beginning of the cache.
+ * position it at the beginning of the cache.
*/
if (cleaner->iterator == NULL)
result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE,
@@ -701,7 +701,7 @@ begin_cleaning(cache_cleaner_t *cleaner) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
"begin cache cleaning, mem inuse %lu",
- (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
+ (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
cleaner->state = cleaner_s_busy;
isc_task_send(cleaner->task, &cleaner->resched_event);
}
@@ -761,7 +761,7 @@ static void
overmem_cleaning_action(isc_task_t *task, isc_event_t *event) {
cache_cleaner_t *cleaner = event->ev_arg;
isc_boolean_t want_cleaning = ISC_FALSE;
-
+
UNUSED(task);
INSIST(task == cleaner->task);
@@ -980,9 +980,12 @@ water(void *arg, int mark) {
REQUIRE(VALID_CACHE(cache));
LOCK(&cache->cleaner.lock);
-
- dns_db_overmem(cache->db, overmem);
- cache->cleaner.overmem = overmem;
+
+ if (overmem != cache->cleaner.overmem) {
+ dns_db_overmem(cache->db, overmem);
+ cache->cleaner.overmem = overmem;
+ isc_mem_waterack(cache->mctx, mark);
+ }
if (cache->cleaner.overmem_event != NULL)
isc_task_send(cache->cleaner.task,
@@ -1106,7 +1109,7 @@ dns_cache_flushname(dns_cache_t *cache, dns_name_t *name) {
dns_rdatasetiter_t *iter = NULL;
dns_dbnode_t *node = NULL;
dns_db_t *db = NULL;
-
+
LOCK(&cache->lock);
if (cache->db != NULL)
dns_db_attach(cache->db, &db);
diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c
index 617fde8..794cdb5 100644
--- a/lib/dns/dispatch.c
+++ b/lib/dns/dispatch.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dispatch.c,v 1.116.18.19.12.5 2008/07/23 23:16:43 marka Exp $ */
+/* $Id: dispatch.c,v 1.116.18.37 2008/09/04 00:24:41 jinmei Exp $ */
/*! \file */
@@ -24,10 +24,12 @@
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
+#include <stdlib.h>
#include <isc/entropy.h>
#include <isc/mem.h>
#include <isc/mutex.h>
+#include <isc/portset.h>
#include <isc/print.h>
#include <isc/random.h>
#include <isc/string.h>
@@ -46,13 +48,8 @@
typedef ISC_LIST(dns_dispentry_t) dns_displist_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_displist_t *qid_table; /*%< the table itself */
-} dns_qid_t;
+typedef struct dispsocket dispsocket_t;
+typedef ISC_LIST(dispsocket_t) dispsocketlist_t;
/* ARC4 Random generator state */
typedef struct arc4ctx {
@@ -60,14 +57,26 @@ typedef struct arc4ctx {
isc_uint8_t j;
isc_uint8_t s[256];
int count;
+ isc_entropy_t *entropy; /*%< entropy source for ARC4 */
+ isc_mutex_t *lock;
} arc4ctx_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_displist_t *qid_table; /*%< the table itself */
+ dispsocketlist_t *sock_table; /*%< socket table */
+} dns_qid_t;
+
struct dns_dispatchmgr {
/* Unlocked. */
unsigned int magic;
isc_mem_t *mctx;
dns_acl_t *blackhole;
dns_portlist_t *portlist;
+ isc_entropy_t *entropy; /*%< entropy source */
/* Locked by "lock". */
isc_mutex_t lock;
@@ -91,8 +100,27 @@ struct dns_dispatchmgr {
isc_mempool_t *rpool; /*%< memory pool for replies */
isc_mempool_t *dpool; /*%< dispatch allocations */
isc_mempool_t *bpool; /*%< memory pool for buffers */
-
- isc_entropy_t *entropy; /*%< entropy source */
+ isc_mempool_t *spool; /*%< memory pool for dispsocs */
+
+ /*%
+ * Locked by qid->lock if qid exists; otherwise, can be used without
+ * being locked.
+ * Memory footprint considerations: this is a simple implementation of
+ * available ports, i.e., an ordered array of the actual port numbers.
+ * This will require about 256KB of memory in the worst case (128KB for
+ * each of IPv4 and IPv6). We could reduce it by representing it as a
+ * more sophisticated way such as a list (or array) of ranges that are
+ * searched to identify a specific port. Our decision here is the saved
+ * memory isn't worth the implementation complexity, considering the
+ * fact that the whole BIND9 process (which is mainly named) already
+ * requires a pretty large memory footprint. We may, however, have to
+ * revisit the decision when we want to use it as a separate module for
+ * an environment where memory requirement is severer.
+ */
+ in_port_t *v4ports; /*%< available ports for IPv4 */
+ unsigned int nv4ports; /*%< # of available ports for IPv4 */
+ in_port_t *v6ports; /*%< available ports for IPv4 */
+ unsigned int nv6ports; /*%< # of available ports for IPv4 */
};
#define MGR_SHUTTINGDOWN 0x00000001U
@@ -111,17 +139,65 @@ struct dns_dispentry {
isc_taskaction_t action;
void *arg;
isc_boolean_t item_out;
+ dispsocket_t *dispsocket;
ISC_LIST(dns_dispatchevent_t) items;
ISC_LINK(dns_dispentry_t) link;
};
+/*%
+ * Maximum number of dispatch sockets that can be pooled for reuse. The
+ * appropriate value may vary, but experiments have shown a busy caching server
+ * may need more than 1000 sockets concurrently opened. The maximum allowable
+ * number of dispatch sockets (per manager) will be set to the double of this
+ * value.
+ */
+#ifndef DNS_DISPATCH_POOLSOCKS
+#define DNS_DISPATCH_POOLSOCKS 2048
+#endif
+
+/*%
+ * Quota to control the number of dispatch sockets. If a dispatch has more
+ * than the quota of sockets, new queries will purge oldest ones, so that
+ * a massive number of outstanding queries won't prevent subsequent queries
+ * (especially if the older ones take longer time and result in timeout).
+ */
+#ifndef DNS_DISPATCH_SOCKSQUOTA
+#define DNS_DISPATCH_SOCKSQUOTA 3072
+#endif
+
+struct dispsocket {
+ unsigned int magic;
+ isc_socket_t *socket;
+ dns_dispatch_t *disp;
+ isc_sockaddr_t host;
+ in_port_t localport;
+ dns_dispentry_t *resp;
+ isc_task_t *task;
+ ISC_LINK(dispsocket_t) link;
+ unsigned int bucket;
+ ISC_LINK(dispsocket_t) blink;
+};
+
#define INVALID_BUCKET (0xffffdead)
+/*%
+ * Number of tasks for each dispatch that use separate sockets for different
+ * transactions. This must be a power of 2 as it will divide 32 bit numbers
+ * to get an uniformly random tasks selection. See get_dispsocket().
+ */
+#define MAX_INTERNAL_TASKS 64
+
struct dns_dispatch {
/* Unlocked. */
unsigned int magic; /*%< magic */
dns_dispatchmgr_t *mgr; /*%< dispatch manager */
- isc_task_t *task; /*%< internal task */
+ int ntasks;
+ /*%
+ * internal task buckets. We use multiple tasks to distribute various
+ * socket events well when using separate dispatch sockets. We use the
+ * 1st task (task[0]) for internal control events.
+ */
+ isc_task_t *task[MAX_INTERNAL_TASKS];
isc_socket_t *socket; /*%< isc socket attached to */
isc_sockaddr_t local; /*%< local address */
in_port_t localport; /*%< local UDP port */
@@ -143,10 +219,14 @@ struct dns_dispatch {
tcpmsg_valid : 1,
recv_pending : 1; /*%< is a recv() pending? */
isc_result_t shutdown_why;
+ ISC_LIST(dispsocket_t) activesockets;
+ ISC_LIST(dispsocket_t) inactivesockets;
+ unsigned int nsockets;
unsigned int requests; /*%< how many requests we have */
unsigned int tcpbuffers; /*%< allocated buffers */
dns_tcpmsg_t tcpmsg; /*%< for tcp streams */
dns_qid_t *qid;
+ arc4ctx_t arc4ctx; /*%< for QID/UDP port num */
};
#define QID_MAGIC ISC_MAGIC('Q', 'i', 'd', ' ')
@@ -155,6 +235,9 @@ struct dns_dispatch {
#define RESPONSE_MAGIC ISC_MAGIC('D', 'r', 's', 'p')
#define VALID_RESPONSE(e) ISC_MAGIC_VALID((e), RESPONSE_MAGIC)
+#define DISPSOCK_MAGIC ISC_MAGIC('D', 's', 'o', 'c')
+#define VALID_DISPSOCK(e) ISC_MAGIC_VALID((e), DISPSOCK_MAGIC)
+
#define DISPATCH_MAGIC ISC_MAGIC('D', 'i', 's', 'p')
#define VALID_DISPATCH(e) ISC_MAGIC_VALID((e), DISPATCH_MAGIC)
@@ -163,16 +246,33 @@ struct dns_dispatch {
#define DNS_QID(disp) ((disp)->socktype == isc_sockettype_tcp) ? \
(disp)->qid : (disp)->mgr->qid
+#define DISP_ARC4CTX(disp) ((disp)->socktype == isc_sockettype_udp) ? \
+ (&(disp)->arc4ctx) : (&(disp)->mgr->arc4ctx)
+
+/*%
+ * Locking a query port buffer is a bit tricky. We access the buffer without
+ * locking until qid is created. Technically, there is a possibility of race
+ * between the creation of qid and access to the port buffer; in practice,
+ * however, this should be safe because qid isn't created until the first
+ * dispatch is created and there should be no contending situation until then.
+ */
+#define PORTBUFLOCK(mgr) if ((mgr)->qid != NULL) LOCK(&((mgr)->qid->lock))
+#define PORTBUFUNLOCK(mgr) if ((mgr)->qid != NULL) UNLOCK((&(mgr)->qid->lock))
+
/*
* Statics.
*/
-static dns_dispentry_t *bucket_search(dns_qid_t *, isc_sockaddr_t *,
- dns_messageid_t, in_port_t, unsigned int);
+static dns_dispentry_t *entry_search(dns_qid_t *, isc_sockaddr_t *,
+ 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 destroy_dispsocket(dns_dispatch_t *, dispsocket_t **);
+static void deactivate_dispsocket(dns_dispatch_t *, dispsocket_t *);
+static void udp_exrecv(isc_task_t *, isc_event_t *);
+static void udp_shrecv(isc_task_t *, isc_event_t *);
+static void udp_recv(isc_event_t *, dns_dispatch_t *, dispsocket_t *);
static void tcp_recv(isc_task_t *, isc_event_t *);
-static void startrecv(dns_dispatch_t *);
+static isc_result_t startrecv(dns_dispatch_t *, dispsocket_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);
@@ -184,6 +284,11 @@ static dns_dispentry_t *linear_first(dns_qid_t *disp);
static dns_dispentry_t *linear_next(dns_qid_t *disp,
dns_dispentry_t *resp);
static void dispatch_free(dns_dispatch_t **dispp);
+static isc_result_t get_udpsocket(dns_dispatchmgr_t *mgr,
+ dns_dispatch_t *disp,
+ isc_socketmgr_t *sockmgr,
+ isc_sockaddr_t *localaddr,
+ isc_socket_t **sockp);
static isc_result_t dispatch_createudp(dns_dispatchmgr_t *mgr,
isc_socketmgr_t *sockmgr,
isc_taskmgr_t *taskmgr,
@@ -194,8 +299,13 @@ 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, dns_qid_t **qidp);
+ unsigned int increment, dns_qid_t **qidp,
+ isc_boolean_t needaddrtable);
static void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp);
+static isc_result_t open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local,
+ unsigned int options, isc_socket_t **sockp);
+static isc_boolean_t portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
+ isc_sockaddr_t *sockaddrp);
#define LVL(x) ISC_LOG_DEBUG(x)
@@ -275,7 +385,7 @@ request_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
}
}
-/*
+/*%
* ARC4 random number generator derived from OpenBSD.
* Only dispatch_arc4random() and dispatch_arc4uniformrandom() are expected
* to be called from general dispatch routines; the rest of them are subroutines
@@ -298,13 +408,15 @@ request_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
static void
-dispatch_arc4init(arc4ctx_t *actx) {
+dispatch_arc4init(arc4ctx_t *actx, isc_entropy_t *entropy, isc_mutex_t *lock) {
int n;
for (n = 0; n < 256; n++)
actx->s[n] = n;
actx->i = 0;
actx->j = 0;
actx->count = 0;
+ actx->entropy = entropy; /* don't have to attach */
+ actx->lock = lock;
}
static void
@@ -348,7 +460,7 @@ dispatch_arc4get16(arc4ctx_t *actx) {
}
static void
-dispatch_arc4stir(dns_dispatchmgr_t *mgr) {
+dispatch_arc4stir(arc4ctx_t *actx) {
int i;
union {
unsigned char rnd[128];
@@ -356,51 +468,55 @@ dispatch_arc4stir(dns_dispatchmgr_t *mgr) {
} rnd;
isc_result_t result;
- if (mgr->entropy != NULL) {
+ if (actx->entropy != NULL) {
/*
* We accept any quality of random data to avoid blocking.
*/
- result = isc_entropy_getdata(mgr->entropy, rnd.rnd,
+ result = isc_entropy_getdata(actx->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));
+ dispatch_arc4addrandom(actx, 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);
+ (void)dispatch_arc4get8(actx);
/*
* 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;
+ actx->count = 1600000;
}
static isc_uint16_t
-dispatch_arc4random(dns_dispatchmgr_t *mgr) {
+dispatch_arc4random(arc4ctx_t *actx) {
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);
+ if (actx->lock != NULL)
+ LOCK(actx->lock);
+
+ actx->count -= sizeof(isc_uint16_t);
+ if (actx->count <= 0)
+ dispatch_arc4stir(actx);
+ result = dispatch_arc4get16(actx);
+
+ if (actx->lock != NULL)
+ UNLOCK(actx->lock);
+
return (result);
}
static isc_uint16_t
-dispatch_arc4uniformrandom(dns_dispatchmgr_t *mgr, isc_uint16_t upper_bound) {
+dispatch_arc4uniformrandom(arc4ctx_t *actx, isc_uint16_t upper_bound) {
isc_uint16_t min, r;
- /* The caller must hold the manager lock. */
if (upper_bound < 2)
return (0);
@@ -422,7 +538,7 @@ dispatch_arc4uniformrandom(dns_dispatchmgr_t *mgr, isc_uint16_t upper_bound) {
* to re-roll.
*/
for (;;) {
- r = dispatch_arc4random(mgr);
+ r = dispatch_arc4random(actx);
if (r >= min)
break;
}
@@ -505,13 +621,15 @@ destroy_disp_ok(dns_dispatch_t *disp)
if (disp->recv_pending != 0)
return (ISC_FALSE);
+ if (!ISC_LIST_EMPTY(disp->activesockets))
+ return (ISC_FALSE);
+
if (disp->shutting_down == 0)
return (ISC_FALSE);
return (ISC_TRUE);
}
-
/*
* Called when refcount reaches 0 (and safe to destroy).
*
@@ -523,6 +641,8 @@ destroy_disp(isc_task_t *task, isc_event_t *event) {
dns_dispatch_t *disp;
dns_dispatchmgr_t *mgr;
isc_boolean_t killmgr;
+ dispsocket_t *dispsocket;
+ int i;
INSIST(event->ev_type == DNS_EVENT_DISPATCHCONTROL);
@@ -536,10 +656,16 @@ destroy_disp(isc_task_t *task, isc_event_t *event) {
dispatch_log(disp, LVL(90),
"shutting down; detaching from sock %p, task %p",
- disp->socket, disp->task);
+ disp->socket, disp->task[0]); /* XXXX */
- isc_socket_detach(&disp->socket);
- isc_task_detach(&disp->task);
+ if (disp->socket != NULL)
+ isc_socket_detach(&disp->socket);
+ while ((dispsocket = ISC_LIST_HEAD(disp->inactivesockets)) != NULL) {
+ ISC_LIST_UNLINK(disp->inactivesockets, dispsocket, link);
+ destroy_dispsocket(disp, &dispsocket);
+ }
+ for (i = 0; i < disp->ntasks; i++)
+ isc_task_detach(&disp->task[i]);
isc_event_free(&event);
dispatch_free(&disp);
@@ -550,14 +676,210 @@ destroy_disp(isc_task_t *task, isc_event_t *event) {
destroy_mgr(&mgr);
}
+/*%
+ * Find a dispsocket for socket address 'dest', and port number 'port'.
+ * Return NULL if no such entry exists.
+ */
+static dispsocket_t *
+socket_search(dns_qid_t *qid, isc_sockaddr_t *dest, in_port_t port,
+ unsigned int bucket)
+{
+ dispsocket_t *dispsock;
+
+ REQUIRE(bucket < qid->qid_nbuckets);
+
+ dispsock = ISC_LIST_HEAD(qid->sock_table[bucket]);
+
+ while (dispsock != NULL) {
+ if (isc_sockaddr_equal(dest, &dispsock->host) &&
+ dispsock->localport == port)
+ return (dispsock);
+ dispsock = ISC_LIST_NEXT(dispsock, blink);
+ }
+
+ return (NULL);
+}
+
+/*%
+ * Make a new socket for a single dispatch with a random port number.
+ * The caller must hold the disp->lock and qid->lock.
+ */
+static isc_result_t
+get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest,
+ isc_socketmgr_t *sockmgr, dns_qid_t *qid,
+ dispsocket_t **dispsockp, in_port_t *portp)
+{
+ int i;
+ isc_uint32_t r;
+ dns_dispatchmgr_t *mgr = disp->mgr;
+ isc_socket_t *sock = NULL;
+ isc_result_t result = ISC_R_FAILURE;
+ in_port_t port;
+ isc_sockaddr_t localaddr;
+ unsigned int bucket = 0;
+ dispsocket_t *dispsock;
+ unsigned int nports;
+ in_port_t *ports;
+
+ if (isc_sockaddr_pf(&disp->local) == AF_INET) {
+ nports = disp->mgr->nv4ports;
+ ports = disp->mgr->v4ports;
+ } else {
+ nports = disp->mgr->nv6ports;
+ ports = disp->mgr->v6ports;
+ }
+ if (nports == 0)
+ return (ISC_R_ADDRNOTAVAIL);
+
+ dispsock = ISC_LIST_HEAD(disp->inactivesockets);
+ if (dispsock != NULL) {
+ ISC_LIST_UNLINK(disp->inactivesockets, dispsock, link);
+ sock = dispsock->socket;
+ dispsock->socket = NULL;
+ } else {
+ dispsock = isc_mempool_get(mgr->spool);
+ if (dispsock == NULL)
+ return (ISC_R_NOMEMORY);
+
+ disp->nsockets++;
+ dispsock->socket = NULL;
+ dispsock->disp = disp;
+ dispsock->resp = NULL;
+ isc_random_get(&r);
+ dispsock->task = NULL;
+ isc_task_attach(disp->task[r % disp->ntasks], &dispsock->task);
+ ISC_LINK_INIT(dispsock, link);
+ ISC_LINK_INIT(dispsock, blink);
+ dispsock->magic = DISPSOCK_MAGIC;
+ }
+
+ /*
+ * Pick up a random UDP port and open a new socket with it. Avoid
+ * choosing ports that share the same destination because it will be
+ * very likely to fail in bind(2) or connect(2).
+ */
+ localaddr = disp->local;
+ for (i = 0; i < 64; i++) {
+ port = ports[dispatch_arc4uniformrandom(DISP_ARC4CTX(disp),
+ nports)];
+ isc_sockaddr_setport(&localaddr, port);
+
+ bucket = dns_hash(qid, dest, 0, port);
+ if (socket_search(qid, dest, port, bucket) != NULL)
+ continue;
+
+ result = open_socket(sockmgr, &localaddr, 0, &sock);
+ if (result == ISC_R_SUCCESS || result != ISC_R_ADDRINUSE)
+ break;
+ }
+
+ if (result == ISC_R_SUCCESS) {
+ dispsock->socket = sock;
+ dispsock->host = *dest;
+ dispsock->localport = port;
+ dispsock->bucket = bucket;
+ ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink);
+ *dispsockp = dispsock;
+ *portp = port;
+ } else {
+ /*
+ * We could keep it in the inactive list, but since this should
+ * be an exceptional case and might be resource shortage, we'd
+ * rather destroy it.
+ */
+ if (sock != NULL)
+ isc_socket_detach(&sock);
+ destroy_dispsocket(disp, &dispsock);
+ }
+
+ return (result);
+}
+
+/*%
+ * Destroy a dedicated dispatch socket.
+ */
+static void
+destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) {
+ dispsocket_t *dispsock;
+ dns_qid_t *qid;
+
+ /*
+ * The dispatch must be locked.
+ */
+
+ REQUIRE(dispsockp != NULL && *dispsockp != NULL);
+ dispsock = *dispsockp;
+ REQUIRE(!ISC_LINK_LINKED(dispsock, link));
+
+ disp->nsockets--;
+ dispsock->magic = 0;
+ if (dispsock->socket != NULL)
+ isc_socket_detach(&dispsock->socket);
+ if (ISC_LINK_LINKED(dispsock, blink)) {
+ qid = DNS_QID(disp);
+ LOCK(&qid->lock);
+ ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock,
+ blink);
+ UNLOCK(&qid->lock);
+ }
+ if (dispsock->task != NULL)
+ isc_task_detach(&dispsock->task);
+ isc_mempool_put(disp->mgr->spool, dispsock);
+
+ *dispsockp = NULL;
+}
+
+/*%
+ * Deactivate a dedicated dispatch socket. Move it to the inactive list for
+ * future reuse unless the total number of sockets are exceeding the maximum.
+ */
+static void
+deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) {
+ isc_result_t result;
+ dns_qid_t *qid;
+
+ /*
+ * The dispatch must be locked.
+ */
+ ISC_LIST_UNLINK(disp->activesockets, dispsock, link);
+ if (dispsock->resp != NULL) {
+ INSIST(dispsock->resp->dispsocket == dispsock);
+ dispsock->resp->dispsocket = NULL;
+ }
+
+ if (disp->nsockets > DNS_DISPATCH_POOLSOCKS)
+ destroy_dispsocket(disp, &dispsock);
+ else {
+ result = isc_socket_close(dispsock->socket);
+
+ qid = DNS_QID(disp);
+ LOCK(&qid->lock);
+ ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock,
+ blink);
+ UNLOCK(&qid->lock);
+
+ if (result == ISC_R_SUCCESS)
+ ISC_LIST_APPEND(disp->inactivesockets, dispsock, link);
+ else {
+ /*
+ * If the underlying system does not allow this
+ * optimization, destroy this temporary structure (and
+ * create a new one for a new transaction).
+ */
+ INSIST(result == ISC_R_NOTIMPLEMENTED);
+ destroy_dispsocket(disp, &dispsock);
+ }
+ }
+}
/*
- * Find an entry for query ID 'id' and socket address 'dest' in 'qid'.
+ * Find an entry for query ID 'id', socket address 'dest', and port number
+ * 'port'.
* Return NULL if no such entry exists.
*/
static dns_dispentry_t *
-bucket_search(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id,
- in_port_t port, unsigned int bucket)
+entry_search(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id,
+ in_port_t port, unsigned int bucket)
{
dns_dispentry_t *res;
@@ -566,7 +888,7 @@ 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);
}
@@ -640,6 +962,26 @@ allocate_event(dns_dispatch_t *disp) {
return (ev);
}
+static void
+udp_exrecv(isc_task_t *task, isc_event_t *ev) {
+ dispsocket_t *dispsock = ev->ev_arg;
+
+ UNUSED(task);
+
+ REQUIRE(VALID_DISPSOCK(dispsock));
+ udp_recv(ev, dispsock->disp, dispsock);
+}
+
+static void
+udp_shrecv(isc_task_t *task, isc_event_t *ev) {
+ dns_dispatch_t *disp = ev->ev_arg;
+
+ UNUSED(task);
+
+ REQUIRE(VALID_DISPATCH(disp));
+ udp_recv(ev, disp, NULL);
+}
+
/*
* General flow:
*
@@ -655,14 +997,13 @@ allocate_event(dns_dispatch_t *disp) {
* restart.
*/
static void
-udp_recv(isc_task_t *task, isc_event_t *ev_in) {
+udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) {
isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
- dns_dispatch_t *disp = ev_in->ev_arg;
dns_messageid_t id;
isc_result_t dres;
isc_buffer_t source;
unsigned int flags;
- dns_dispentry_t *resp;
+ dns_dispentry_t *resp = NULL;
dns_dispatchevent_t *rev;
unsigned int bucket;
isc_boolean_t killit;
@@ -671,8 +1012,8 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
dns_qid_t *qid;
isc_netaddr_t netaddr;
int match;
-
- UNUSED(task);
+ int result;
+ isc_boolean_t qidlocked = ISC_FALSE;
LOCK(&disp->lock);
@@ -683,7 +1024,7 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
"got packet: requests %d, buffers %d, recvs %d",
disp->requests, disp->mgr->buffers, disp->recv_pending);
- if (ev->ev_type == ISC_SOCKEVENT_RECVDONE) {
+ if (dispsock == NULL && ev->ev_type == ISC_SOCKEVENT_RECVDONE) {
/*
* Unless the receive event was imported from a listening
* interface, in which case the event type is
@@ -693,6 +1034,19 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
disp->recv_pending = 0;
}
+ if (dispsock != NULL &&
+ (ev->result == ISC_R_CANCELED || dispsock->resp == NULL)) {
+ /*
+ * dispsock->resp can be NULL if this transaction was canceled
+ * just after receiving a response. Since this socket is
+ * exclusively used and there should be at most one receive
+ * event the canceled event should have been no effect. So
+ * we can (and should) deactivate the socket right now.
+ */
+ deactivate_dispsocket(disp, dispsock);
+ dispsock = NULL;
+ }
+
if (disp->shutting_down) {
/*
* This dispatcher is shutting down.
@@ -705,12 +1059,32 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
killit = destroy_disp_ok(disp);
UNLOCK(&disp->lock);
if (killit)
- isc_task_send(disp->task, &disp->ctlevent);
+ isc_task_send(disp->task[0], &disp->ctlevent);
return;
}
- if (ev->result != ISC_R_SUCCESS) {
+ if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
+ if (dispsock != NULL) {
+ resp = dispsock->resp;
+ id = resp->id;
+ if (ev->result != ISC_R_SUCCESS) {
+ /*
+ * This is most likely a network error on a
+ * connected socket. It makes no sense to
+ * check the address or parse the packet, but it
+ * will help to return the error to the caller.
+ */
+ goto sendresponse;
+ }
+ } else {
+ free_buffer(disp, ev->region.base, ev->region.length);
+
+ UNLOCK(&disp->lock);
+ isc_event_free(&ev_in);
+ return;
+ }
+ } else if (ev->result != ISC_R_SUCCESS) {
free_buffer(disp, ev->region.base, ev->region.length);
if (ev->result != ISC_R_CANCELED)
@@ -729,7 +1103,7 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
isc_netaddr_fromsockaddr(&netaddr, &ev->address);
if (disp->mgr->blackhole != NULL &&
dns_acl_match(&netaddr, NULL, disp->mgr->blackhole,
- NULL, &match, NULL) == ISC_R_SUCCESS &&
+ NULL, &match, NULL) == ISC_R_SUCCESS &&
match > 0)
{
if (isc_log_wouldlog(dns_lctx, LVL(10))) {
@@ -771,18 +1145,32 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
goto restart;
}
- /* response */
- bucket = dns_hash(qid, &ev->address, id, disp->localport);
- LOCK(&qid->lock);
- 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"));
-
+ /*
+ * Search for the corresponding response. If we are using an exclusive
+ * socket, we've already identified it and we can skip the search; but
+ * the ID and the address must match the expected ones.
+ */
if (resp == NULL) {
+ bucket = dns_hash(qid, &ev->address, id, disp->localport);
+ LOCK(&qid->lock);
+ qidlocked = ISC_TRUE;
+ resp = entry_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"));
+
+ if (resp == NULL) {
+ free_buffer(disp, ev->region.base, ev->region.length);
+ goto unlock;
+ }
+ } else if (resp->id != id || !isc_sockaddr_equal(&ev->address,
+ &resp->host)) {
+ dispatch_log(disp, LVL(90),
+ "response to an exclusive socket doesn't match");
free_buffer(disp, ev->region.base, ev->region.length);
goto unlock;
- }
+ }
/*
* Now that we have the original dispatch the query was sent
@@ -792,7 +1180,7 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
if (disp != resp->disp) {
isc_sockaddr_t a1;
isc_sockaddr_t a2;
-
+
/*
* Check that the socket types and ports match.
*/
@@ -805,11 +1193,11 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
/*
* If both dispatches are bound to an address then fail as
- * the addresses can't be equal (enforced by the IP stack).
+ * the addresses can't be equal (enforced by the IP stack).
*
* Note under Linux a packet can be sent out via IPv4 socket
* and the response be received via a IPv6 socket.
- *
+ *
* Requests sent out via IPv6 should always come back in
* via IPv6.
*/
@@ -827,6 +1215,7 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
}
}
+ sendresponse:
queue_response = resp->item_out;
rev = allocate_event(resp->disp);
if (rev == NULL) {
@@ -841,7 +1230,7 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
*/
isc_buffer_init(&rev->buffer, ev->region.base, ev->region.length);
isc_buffer_add(&rev->buffer, ev->n);
- rev->result = ISC_R_SUCCESS;
+ rev->result = ev->result;
rev->id = id;
rev->addr = ev->address;
rev->pktinfo = ev->pktinfo;
@@ -860,14 +1249,23 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) {
isc_task_send(resp->task, ISC_EVENT_PTR(&rev));
}
unlock:
- UNLOCK(&qid->lock);
+ if (qidlocked)
+ UNLOCK(&qid->lock);
/*
* Restart recv() to get the next packet.
*/
restart:
- startrecv(disp);
-
+ result = startrecv(disp, dispsock);
+ if (result != ISC_R_SUCCESS && dispsock != NULL) {
+ /*
+ * XXX: wired. There seems to be no recovery process other than
+ * deactivate this socket anyway (since we cannot start
+ * receiving, we won't be able to receive a cancel event
+ * from the user).
+ */
+ deactivate_dispsocket(disp, dispsock);
+ }
UNLOCK(&disp->lock);
isc_event_free(&ev_in);
@@ -930,7 +1328,7 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
switch (tcpmsg->result) {
case ISC_R_CANCELED:
break;
-
+
case ISC_R_EOF:
dispatch_log(disp, LVL(90), "shutting down on EOF");
do_cancel(disp);
@@ -967,7 +1365,7 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
killit = destroy_disp_ok(disp);
UNLOCK(&disp->lock);
if (killit)
- isc_task_send(disp->task, &disp->ctlevent);
+ isc_task_send(disp->task[0], &disp->ctlevent);
return;
}
@@ -1010,8 +1408,7 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
*/
bucket = dns_hash(qid, &tcpmsg->address, id, disp->localport);
LOCK(&qid->lock);
- resp = bucket_search(qid, &tcpmsg->address, id, disp->localport,
- bucket);
+ resp = entry_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"));
@@ -1052,7 +1449,7 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
* Restart recv() to get the next packet.
*/
restart:
- startrecv(disp);
+ (void)startrecv(disp, NULL);
UNLOCK(&disp->lock);
@@ -1062,22 +1459,33 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
/*
* disp must be locked.
*/
-static void
-startrecv(dns_dispatch_t *disp) {
+static isc_result_t
+startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) {
isc_result_t res;
isc_region_t region;
+ isc_socket_t *socket;
if (disp->shutting_down == 1)
- return;
+ return (ISC_R_SUCCESS);
if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
- return;
+ return (ISC_R_SUCCESS);
- if (disp->recv_pending != 0)
- return;
+ if (disp->recv_pending != 0 && dispsock == NULL)
+ return (ISC_R_SUCCESS);
if (disp->mgr->buffers >= disp->mgr->maxbuffers)
- return;
+ return (ISC_R_NOMEMORY);
+
+ if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 &&
+ dispsock == NULL)
+ return (ISC_R_SUCCESS);
+
+ if (dispsock != NULL)
+ socket = dispsock->socket;
+ else
+ socket = disp->socket;
+ INSIST(socket != NULL);
switch (disp->socktype) {
/*
@@ -1087,28 +1495,38 @@ startrecv(dns_dispatch_t *disp) {
region.length = disp->mgr->buffersize;
region.base = allocate_udp_buffer(disp);
if (region.base == NULL)
- return;
- res = isc_socket_recv(disp->socket, &region, 1,
- disp->task, udp_recv, disp);
- if (res != ISC_R_SUCCESS) {
- free_buffer(disp, region.base, region.length);
- disp->shutdown_why = res;
- disp->shutting_down = 1;
- do_cancel(disp);
- return;
+ return (ISC_R_NOMEMORY);
+ if (dispsock != NULL) {
+ res = isc_socket_recv(socket, &region, 1,
+ dispsock->task, udp_exrecv,
+ dispsock);
+ if (res != ISC_R_SUCCESS) {
+ free_buffer(disp, region.base, region.length);
+ return (res);
+ }
+ } else {
+ res = isc_socket_recv(socket, &region, 1,
+ disp->task[0], udp_shrecv, disp);
+ if (res != ISC_R_SUCCESS) {
+ free_buffer(disp, region.base, region.length);
+ disp->shutdown_why = res;
+ disp->shutting_down = 1;
+ do_cancel(disp);
+ return (ISC_R_SUCCESS); /* recover by cancel */
+ }
+ INSIST(disp->recv_pending == 0);
+ disp->recv_pending = 1;
}
- INSIST(disp->recv_pending == 0);
- disp->recv_pending = 1;
break;
case isc_sockettype_tcp:
- res = dns_tcpmsg_readmessage(&disp->tcpmsg, disp->task,
+ res = dns_tcpmsg_readmessage(&disp->tcpmsg, disp->task[0],
tcp_recv, disp);
if (res != ISC_R_SUCCESS) {
disp->shutdown_why = res;
disp->shutting_down = 1;
do_cancel(disp);
- return;
+ return (ISC_R_SUCCESS); /* recover by cancel */
}
INSIST(disp->recv_pending == 0);
disp->recv_pending = 1;
@@ -1117,6 +1535,8 @@ startrecv(dns_dispatch_t *disp) {
INSIST(0);
break;
}
+
+ return (ISC_R_SUCCESS);
}
/*
@@ -1169,6 +1589,7 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) {
isc_mempool_destroy(&mgr->rpool);
isc_mempool_destroy(&mgr->dpool);
isc_mempool_destroy(&mgr->bpool);
+ isc_mempool_destroy(&mgr->spool);
DESTROYLOCK(&mgr->pool_lock);
@@ -1182,32 +1603,46 @@ destroy_mgr(dns_dispatchmgr_t **mgrp) {
if (mgr->blackhole != NULL)
dns_acl_detach(&mgr->blackhole);
- if (mgr->portlist != NULL)
- dns_portlist_detach(&mgr->portlist);
-
+ if (mgr->v4ports != NULL) {
+ isc_mem_put(mctx, mgr->v4ports,
+ mgr->nv4ports * sizeof(in_port_t));
+ }
+ if (mgr->v6ports != NULL) {
+ isc_mem_put(mctx, mgr->v6ports,
+ mgr->nv6ports * sizeof(in_port_t));
+ }
isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t));
isc_mem_detach(&mctx);
}
static isc_result_t
-create_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local,
- unsigned int options, isc_socket_t **sockp)
+open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local,
+ unsigned int options, isc_socket_t **sockp)
{
isc_socket_t *sock;
isc_result_t result;
- sock = NULL;
- result = isc_socket_create(mgr, isc_sockaddr_pf(local),
- isc_sockettype_udp, &sock);
- if (result != ISC_R_SUCCESS)
- return (result);
+ sock = *sockp;
+ if (sock == NULL) {
+ result = isc_socket_create(mgr, isc_sockaddr_pf(local),
+ isc_sockettype_udp, &sock);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ } else {
+ result = isc_socket_open(sock);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
#ifndef ISC_ALLOW_MAPPED
isc_socket_ipv6only(sock, ISC_TRUE);
#endif
result = isc_socket_bind(sock, local, options);
if (result != ISC_R_SUCCESS) {
- isc_socket_detach(&sock);
+ if (*sockp == NULL)
+ isc_socket_detach(&sock);
+ else
+ isc_socket_close(sock);
return (result);
}
@@ -1215,6 +1650,24 @@ create_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local,
return (ISC_R_SUCCESS);
}
+/*%
+ * Create a temporary port list to set the initial default set of dispatch
+ * ports: [1024, 65535]. This is almost meaningless as the application will
+ * normally set the ports explicitly, but is provided to fill some minor corner
+ * cases.
+ */
+static isc_result_t
+create_default_portset(isc_mem_t *mctx, isc_portset_t **portsetp) {
+ isc_result_t result;
+
+ result = isc_portset_create(mctx, portsetp);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ isc_portset_addrange(*portsetp, 1024, 65535);
+
+ return (ISC_R_SUCCESS);
+}
+
/*
* Publics.
*/
@@ -1225,6 +1678,8 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
{
dns_dispatchmgr_t *mgr;
isc_result_t result;
+ isc_portset_t *v4portset = NULL;
+ isc_portset_t *v6portset = NULL;
REQUIRE(mctx != NULL);
REQUIRE(mgrp != NULL && *mgrp == NULL);
@@ -1237,7 +1692,6 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
isc_mem_attach(mctx, &mgr->mctx);
mgr->blackhole = NULL;
- mgr->portlist = NULL;
result = isc_mutex_init(&mgr->lock);
if (result != ISC_R_SUCCESS)
@@ -1292,20 +1746,43 @@ dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
mgr->buffersize = 0;
mgr->maxbuffers = 0;
mgr->bpool = NULL;
+ mgr->spool = NULL;
mgr->entropy = NULL;
mgr->qid = NULL;
mgr->state = 0;
ISC_LIST_INIT(mgr->list);
+ mgr->v4ports = NULL;
+ mgr->v6ports = NULL;
+ mgr->nv4ports = 0;
+ mgr->nv6ports = 0;
mgr->magic = DNS_DISPATCHMGR_MAGIC;
+ result = create_default_portset(mctx, &v4portset);
+ if (result == ISC_R_SUCCESS) {
+ result = create_default_portset(mctx, &v6portset);
+ if (result == ISC_R_SUCCESS) {
+ result = dns_dispatchmgr_setavailports(mgr,
+ v4portset,
+ v6portset);
+ }
+ }
+ if (v4portset != NULL)
+ isc_portset_destroy(mctx, &v4portset);
+ if (v6portset != NULL)
+ isc_portset_destroy(mctx, &v6portset);
+ if (result != ISC_R_SUCCESS)
+ goto kill_dpool;
+
if (entropy != NULL)
isc_entropy_attach(entropy, &mgr->entropy);
- dispatch_arc4init(&mgr->arc4ctx);
+ dispatch_arc4init(&mgr->arc4ctx, mgr->entropy, &mgr->arc4_lock);
*mgrp = mgr;
return (ISC_R_SUCCESS);
+ kill_dpool:
+ isc_mempool_destroy(&mgr->dpool);
kill_rpool:
isc_mempool_destroy(&mgr->rpool);
kill_epool:
@@ -1344,22 +1821,88 @@ dns_dispatchmgr_setblackportlist(dns_dispatchmgr_t *mgr,
dns_portlist_t *portlist)
{
REQUIRE(VALID_DISPATCHMGR(mgr));
- if (mgr->portlist != NULL)
- dns_portlist_detach(&mgr->portlist);
- if (portlist != NULL)
- dns_portlist_attach(portlist, &mgr->portlist);
+ UNUSED(portlist);
+
+ /* This function is deprecated: use dns_dispatchmgr_setavailports(). */
+ return;
}
dns_portlist_t *
dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr) {
REQUIRE(VALID_DISPATCHMGR(mgr));
- return (mgr->portlist);
+ return (NULL); /* this function is deprecated */
+}
+
+isc_result_t
+dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset,
+ isc_portset_t *v6portset)
+{
+ in_port_t *v4ports, *v6ports, p;
+ unsigned int nv4ports, nv6ports, i4, i6;
+
+ REQUIRE(VALID_DISPATCHMGR(mgr));
+
+ nv4ports = isc_portset_nports(v4portset);
+ nv6ports = isc_portset_nports(v6portset);
+
+ v4ports = NULL;
+ if (nv4ports != 0) {
+ v4ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv4ports);
+ if (v4ports == NULL)
+ return (ISC_R_NOMEMORY);
+ }
+ v6ports = NULL;
+ if (nv6ports != 0) {
+ v6ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv6ports);
+ if (v6ports == NULL) {
+ if (v4ports != NULL) {
+ isc_mem_put(mgr->mctx, v4ports,
+ sizeof(in_port_t) *
+ isc_portset_nports(v4portset));
+ }
+ return (ISC_R_NOMEMORY);
+ }
+ }
+
+ p = 0;
+ i4 = 0;
+ i6 = 0;
+ do {
+ if (isc_portset_isset(v4portset, p)) {
+ INSIST(i4 < nv4ports);
+ v4ports[i4++] = p;
+ }
+ if (isc_portset_isset(v6portset, p)) {
+ INSIST(i6 < nv6ports);
+ v6ports[i6++] = p;
+ }
+ } while (p++ < 65535);
+ INSIST(i4 == nv4ports && i6 == nv6ports);
+
+ PORTBUFLOCK(mgr);
+ if (mgr->v4ports != NULL) {
+ isc_mem_put(mgr->mctx, mgr->v4ports,
+ mgr->nv4ports * sizeof(in_port_t));
+ }
+ mgr->v4ports = v4ports;
+ mgr->nv4ports = nv4ports;
+
+ if (mgr->v6ports != NULL) {
+ isc_mem_put(mgr->mctx, mgr->v6ports,
+ mgr->nv6ports * sizeof(in_port_t));
+ }
+ mgr->v6ports = v6ports;
+ mgr->nv6ports = nv6ports;
+ PORTBUFUNLOCK(mgr);
+
+ return (ISC_R_SUCCESS);
}
static isc_result_t
dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr,
- unsigned int buffersize, unsigned int maxbuffers,
- unsigned int buckets, unsigned int increment)
+ unsigned int buffersize, unsigned int maxbuffers,
+ unsigned int maxrequests, unsigned int buckets,
+ unsigned int increment)
{
isc_result_t result;
@@ -1386,24 +1929,39 @@ dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr,
maxbuffers = 8;
LOCK(&mgr->buffer_lock);
+
+ /* Create or adjust buffer pool */
if (mgr->bpool != NULL) {
isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
mgr->maxbuffers = maxbuffers;
+ } else {
+ result = isc_mempool_create(mgr->mctx, buffersize, &mgr->bpool);
+ if (result != ISC_R_SUCCESS) {
+ UNLOCK(&mgr->buffer_lock);
+ return (result);
+ }
+ isc_mempool_setname(mgr->bpool, "dispmgr_bpool");
+ isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
+ isc_mempool_associatelock(mgr->bpool, &mgr->pool_lock);
+ }
+
+ /* Create or adjust socket pool */
+ if (mgr->spool != NULL) {
+ isc_mempool_setmaxalloc(mgr->spool, DNS_DISPATCH_POOLSOCKS * 2);
UNLOCK(&mgr->buffer_lock);
return (ISC_R_SUCCESS);
}
-
- if (isc_mempool_create(mgr->mctx, buffersize,
- &mgr->bpool) != ISC_R_SUCCESS) {
+ result = isc_mempool_create(mgr->mctx, sizeof(dispsocket_t),
+ &mgr->spool);
+ if (result != ISC_R_SUCCESS) {
UNLOCK(&mgr->buffer_lock);
- return (ISC_R_NOMEMORY);
+ goto cleanup;
}
+ isc_mempool_setname(mgr->spool, "dispmgr_spool");
+ isc_mempool_setmaxalloc(mgr->spool, maxrequests);
+ isc_mempool_associatelock(mgr->spool, &mgr->pool_lock);
- isc_mempool_setname(mgr->bpool, "dispmgr_bpool");
- isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
- isc_mempool_associatelock(mgr->bpool, &mgr->pool_lock);
-
- result = qid_allocate(mgr, buckets, increment, &mgr->qid);
+ result = qid_allocate(mgr, buckets, increment, &mgr->qid, ISC_TRUE);
if (result != ISC_R_SUCCESS)
goto cleanup;
@@ -1414,8 +1972,10 @@ dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr,
cleanup:
isc_mempool_destroy(&mgr->bpool);
+ if (mgr->spool != NULL)
+ isc_mempool_destroy(&mgr->spool);
UNLOCK(&mgr->buffer_lock);
- return (ISC_R_NOMEMORY);
+ return (result);
}
void
@@ -1441,30 +2001,56 @@ dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) {
destroy_mgr(&mgr);
}
+static int
+port_cmp(const void *key, const void *ent) {
+ in_port_t p1 = *(const in_port_t *)key;
+ in_port_t p2 = *(const in_port_t *)ent;
+
+ if (p1 < p2)
+ return (-1);
+ else if (p1 == p2)
+ return (0);
+ else
+ return (1);
+}
+
static isc_boolean_t
-blacklisted(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
- isc_sockaddr_t *sockaddrp)
+portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
+ isc_sockaddr_t *sockaddrp)
{
isc_sockaddr_t sockaddr;
isc_result_t result;
+ in_port_t *ports, port;
+ unsigned int nports;
+ isc_boolean_t available = ISC_FALSE;
REQUIRE(sock != NULL || sockaddrp != NULL);
- if (mgr->portlist == NULL)
- return (ISC_FALSE);
-
+ PORTBUFLOCK(mgr);
if (sock != NULL) {
sockaddrp = &sockaddr;
result = isc_socket_getsockname(sock, sockaddrp);
if (result != ISC_R_SUCCESS)
- return (ISC_FALSE);
+ goto unlock;
}
- if (mgr->portlist != NULL &&
- dns_portlist_match(mgr->portlist, isc_sockaddr_pf(sockaddrp),
- isc_sockaddr_getport(sockaddrp)))
- return (ISC_TRUE);
- return (ISC_FALSE);
+ if (isc_sockaddr_pf(sockaddrp) == AF_INET) {
+ ports = mgr->v4ports;
+ nports = mgr->nv4ports;
+ } else {
+ ports = mgr->v6ports;
+ nports = mgr->nv6ports;
+ }
+ if (ports == NULL)
+ goto unlock;
+
+ port = isc_sockaddr_getport(sockaddrp);
+ if (bsearch(&port, ports, nports, sizeof(in_port_t), port_cmp) != NULL)
+ available = ISC_TRUE;
+
+unlock:
+ PORTBUFUNLOCK(mgr);
+ return (available);
}
#define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask)))
@@ -1474,17 +2060,20 @@ local_addr_match(dns_dispatch_t *disp, isc_sockaddr_t *addr) {
isc_sockaddr_t sockaddr;
isc_result_t result;
+ REQUIRE(disp->socket != NULL);
+
if (addr == NULL)
return (ISC_TRUE);
/*
- * Don't match wildcard ports against newly blacklisted ports.
+ * Don't match wildcard ports unless the port is available in the
+ * current configuration.
*/
- if (disp->mgr->portlist != NULL &&
- isc_sockaddr_getport(addr) == 0 &&
+ if (isc_sockaddr_getport(addr) == 0 &&
isc_sockaddr_getport(&disp->local) == 0 &&
- blacklisted(disp->mgr, disp->socket, NULL))
+ !portavailable(disp->mgr, disp->socket, NULL)) {
return (ISC_FALSE);
+ }
/*
* Check if we match the binding <address,port>.
@@ -1526,10 +2115,10 @@ dispatch_find(dns_dispatchmgr_t *mgr, isc_sockaddr_t *local,
isc_result_t result;
/*
- * Make certain that we will not match a private dispatch.
+ * Make certain that we will not match a private or exclusive dispatch.
*/
- attributes &= ~DNS_DISPATCHATTR_PRIVATE;
- mask |= DNS_DISPATCHATTR_PRIVATE;
+ attributes &= ~(DNS_DISPATCHATTR_PRIVATE|DNS_DISPATCHATTR_EXCLUSIVE);
+ mask |= (DNS_DISPATCHATTR_PRIVATE|DNS_DISPATCHATTR_EXCLUSIVE);
disp = ISC_LIST_HEAD(mgr->list);
while (disp != NULL) {
@@ -1556,7 +2145,8 @@ 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, dns_qid_t **qidp)
+ unsigned int increment, dns_qid_t **qidp,
+ isc_boolean_t needsocktable)
{
dns_qid_t *qid;
unsigned int i;
@@ -1578,16 +2168,35 @@ qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
return (ISC_R_NOMEMORY);
}
+ qid->sock_table = NULL;
+ if (needsocktable) {
+ qid->sock_table = isc_mem_get(mgr->mctx, buckets *
+ sizeof(dispsocketlist_t));
+ if (qid->sock_table == NULL) {
+ isc_mem_put(mgr->mctx, qid, sizeof(*qid));
+ isc_mem_put(mgr->mctx, qid->qid_table,
+ buckets * sizeof(dns_displist_t));
+ return (ISC_R_NOMEMORY);
+ }
+ }
+
result = isc_mutex_init(&qid->lock);
if (result != ISC_R_SUCCESS) {
+ if (qid->sock_table != NULL) {
+ isc_mem_put(mgr->mctx, qid->sock_table,
+ buckets * sizeof(dispsocketlist_t));
+ }
isc_mem_put(mgr->mctx, qid->qid_table,
buckets * sizeof(dns_displist_t));
isc_mem_put(mgr->mctx, qid, sizeof(*qid));
return (result);
}
- for (i = 0; i < buckets; i++)
+ for (i = 0; i < buckets; i++) {
ISC_LIST_INIT(qid->qid_table[i]);
+ if (qid->sock_table != NULL)
+ ISC_LIST_INIT(qid->sock_table[i]);
+ }
qid->qid_nbuckets = buckets;
qid->qid_increment = increment;
@@ -1609,6 +2218,10 @@ qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) {
qid->magic = 0;
isc_mem_put(mctx, qid->qid_table,
qid->qid_nbuckets * sizeof(dns_displist_t));
+ if (qid->sock_table != NULL) {
+ isc_mem_put(mctx, qid->sock_table,
+ qid->qid_nbuckets * sizeof(dispsocketlist_t));
+ }
DESTROYLOCK(&qid->lock);
isc_mem_put(mctx, qid, sizeof(*qid));
}
@@ -1652,6 +2265,10 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests,
disp->requests = 0;
disp->tcpbuffers = 0;
disp->qid = NULL;
+ ISC_LIST_INIT(disp->activesockets);
+ ISC_LIST_INIT(disp->inactivesockets);
+ disp->nsockets = 0;
+ dispatch_arc4init(&disp->arc4ctx, mgr->entropy, NULL);
result = isc_mutex_init(&disp->lock);
if (result != ISC_R_SUCCESS)
@@ -1704,6 +2321,8 @@ dispatch_free(dns_dispatch_t **dispp)
INSIST(disp->tcpbuffers == 0);
INSIST(disp->requests == 0);
INSIST(disp->recv_pending == 0);
+ INSIST(ISC_LIST_EMPTY(disp->activesockets));
+ INSIST(ISC_LIST_EMPTY(disp->inactivesockets));
isc_mempool_put(mgr->epool, disp->failsafe_ev);
disp->failsafe_ev = NULL;
@@ -1749,7 +2368,7 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
return (result);
}
- result = qid_allocate(mgr, buckets, increment, &disp->qid);
+ result = qid_allocate(mgr, buckets, increment, &disp->qid, ISC_FALSE);
if (result != ISC_R_SUCCESS)
goto deallocate_dispatch;
@@ -1757,8 +2376,9 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
disp->socket = NULL;
isc_socket_attach(sock, &disp->socket);
- disp->task = NULL;
- result = isc_task_create(taskmgr, 0, &disp->task);
+ disp->ntasks = 1;
+ disp->task[0] = NULL;
+ result = isc_task_create(taskmgr, 0, &disp->task[0]);
if (result != ISC_R_SUCCESS)
goto kill_socket;
@@ -1771,7 +2391,7 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
goto kill_task;
}
- isc_task_setname(disp->task, "tcpdispatch", disp);
+ isc_task_setname(disp->task[0], "tcpdispatch", disp);
dns_tcpmsg_init(mgr->mctx, disp->socket, &disp->tcpmsg);
disp->tcpmsg_valid = 1;
@@ -1785,7 +2405,7 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
UNLOCK(&mgr->lock);
mgr_log(mgr, LVL(90), "created TCP dispatcher %p", disp);
- dispatch_log(disp, LVL(90), "created task %p", disp->task);
+ dispatch_log(disp, LVL(90), "created task %p", disp->task[0]);
*dispp = disp;
@@ -1795,7 +2415,7 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
* Error returns.
*/
kill_task:
- isc_task_detach(&disp->task);
+ isc_task_detach(&disp->task[0]);
kill_socket:
isc_socket_detach(&disp->socket);
deallocate_dispatch:
@@ -1830,13 +2450,13 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
REQUIRE((attributes & DNS_DISPATCHATTR_TCP) == 0);
result = dns_dispatchmgr_setudp(mgr, buffersize, maxbuffers,
- buckets, increment);
+ maxrequests, buckets, increment);
if (result != ISC_R_SUCCESS)
return (result);
LOCK(&mgr->lock);
- if ((attributes & DNS_DISPATCHATTR_RANDOMPORT) != 0) {
+ if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
REQUIRE(isc_sockaddr_getport(localaddr) == 0);
goto createudp;
}
@@ -1857,7 +2477,7 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
{
disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
if (disp->recv_pending != 0)
- isc_socket_cancel(disp->socket, disp->task,
+ isc_socket_cancel(disp->socket, disp->task[0],
ISC_SOCKCANCEL_RECV);
}
@@ -1894,6 +2514,101 @@ dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
#endif
static isc_result_t
+get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp,
+ isc_socketmgr_t *sockmgr, isc_sockaddr_t *localaddr,
+ isc_socket_t **sockp)
+{
+ unsigned int i, j;
+ isc_socket_t *held[DNS_DISPATCH_HELD];
+ isc_sockaddr_t localaddr_bound;
+ isc_socket_t *sock = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_boolean_t anyport;
+
+ INSIST(sockp != NULL && *sockp == NULL);
+
+ localaddr_bound = *localaddr;
+ anyport = ISC_TF(isc_sockaddr_getport(localaddr) == 0);
+
+ if (anyport) {
+ unsigned int nports;
+ in_port_t *ports;
+
+ /*
+ * If no port is specified, we first try to pick up a random
+ * port by ourselves.
+ */
+ if (isc_sockaddr_pf(&disp->local) == AF_INET) {
+ nports = disp->mgr->nv4ports;
+ ports = disp->mgr->v4ports;
+ } else {
+ nports = disp->mgr->nv6ports;
+ ports = disp->mgr->v6ports;
+ }
+ if (nports == 0)
+ return (ISC_R_ADDRNOTAVAIL);
+
+ for (i = 0; i < 1024; i++) {
+ in_port_t prt;
+
+ prt = ports[dispatch_arc4uniformrandom(
+ DISP_ARC4CTX(disp),
+ nports)];
+ isc_sockaddr_setport(&localaddr_bound, prt);
+ result = open_socket(sockmgr, &localaddr_bound,
+ 0, &sock);
+ if (result == ISC_R_SUCCESS ||
+ result != ISC_R_ADDRINUSE) {
+ disp->localport = prt;
+ *sockp = sock;
+ return (result);
+ }
+ }
+
+ /*
+ * If this fails 1024 times, we then ask the kernel for
+ * choosing one.
+ */
+ }
+
+ memset(held, 0, sizeof(held));
+ i = 0;
+
+ for (j = 0; j < 0xffffU; j++) {
+ result = open_socket(sockmgr, localaddr, 0, &sock);
+ if (result != ISC_R_SUCCESS)
+ goto end;
+ else if (!anyport)
+ break;
+ else if (portavailable(mgr, sock, NULL))
+ break;
+ if (held[i] != NULL)
+ isc_socket_detach(&held[i]);
+ held[i++] = sock;
+ sock = NULL;
+ if (i == DNS_DISPATCH_HELD)
+ i = 0;
+ }
+ if (j == 0xffffU) {
+ mgr_log(mgr, ISC_LOG_ERROR,
+ "avoid-v%s-udp-ports: unable to allocate "
+ "an available port",
+ isc_sockaddr_pf(localaddr) == AF_INET ? "4" : "6");
+ result = ISC_R_FAILURE;
+ goto end;
+ }
+ *sockp = sock;
+
+end:
+ for (i = 0; i < DNS_DISPATCH_HELD; i++) {
+ if (held[i] != NULL)
+ isc_socket_detach(&held[i]);
+ }
+
+ return (result);
+}
+
+static isc_result_t
dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
isc_taskmgr_t *taskmgr,
isc_sockaddr_t *localaddr,
@@ -1904,10 +2619,7 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
isc_result_t result;
dns_dispatch_t *disp;
isc_socket_t *sock = NULL;
- 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;
+ int i = 0;
/*
* dispatch_allocate() checks mgr for us.
@@ -1917,67 +2629,46 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
if (result != ISC_R_SUCCESS)
return (result);
- /*
- * Try to allocate a socket that is not on the blacklist.
- * Hold up to DNS_DISPATCH_HELD sockets to prevent the OS
- * from returning the same port to us too quickly.
- */
- memset(held, 0, sizeof(held));
- localaddr_bound = *localaddr;
- getsocket:
- 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, 0, &sock);
- if (result == ISC_R_ADDRINUSE) {
- if (++k == 1024)
- attributes &= ~DNS_DISPATCHATTR_RANDOMPORT;
- goto getsocket;
- }
- localport = prt;
- } else
- result = create_socket(sockmgr, localaddr,
- ISC_SOCKET_REUSEADDRESS, &sock);
- if (result != ISC_R_SUCCESS)
- goto deallocate_dispatch;
- 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;
- sock = NULL;
- if (i == DNS_DISPATCH_HELD)
- i = 0;
- if (j++ == 0xffffU) {
- mgr_log(mgr, ISC_LOG_ERROR, "avoid-v%s-udp-ports: "
- "unable to allocate a non-blacklisted port",
- isc_sockaddr_pf(localaddr) == AF_INET ?
- "4" : "6");
- result = ISC_R_FAILURE;
+ if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0) {
+ result = get_udpsocket(mgr, disp, sockmgr, localaddr, &sock);
+ if (result != ISC_R_SUCCESS)
goto deallocate_dispatch;
+ } else {
+ isc_sockaddr_t sa_any;
+
+ /*
+ * For dispatches using exclusive sockets with a specific
+ * source address, we only check if the specified address is
+ * available on the system. Query sockets will be created later
+ * on demand.
+ */
+ isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr));
+ if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) {
+ result = open_socket(sockmgr, localaddr, 0, &sock);
+ if (sock != NULL)
+ isc_socket_detach(&sock);
+ if (result != ISC_R_SUCCESS)
+ goto deallocate_dispatch;
}
- goto getsocket;
}
-
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);
- if (result != ISC_R_SUCCESS)
- goto kill_socket;
+ if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0)
+ disp->ntasks = MAX_INTERNAL_TASKS;
+ else
+ disp->ntasks = 1;
+ for (i = 0; i < disp->ntasks; i++) {
+ disp->task[i] = NULL;
+ result = isc_task_create(taskmgr, 0, &disp->task[i]);
+ if (result != ISC_R_SUCCESS) {
+ while (--i >= 0)
+ isc_task_destroy(&disp->task[i]);
+ goto kill_socket;
+ }
+ isc_task_setname(disp->task[i], "udpdispatch", disp);
+ }
disp->ctlevent = isc_event_allocate(mgr->mctx, disp,
DNS_EVENT_DISPATCHCONTROL,
@@ -1988,8 +2679,6 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
goto kill_task;
}
- isc_task_setname(disp->task, "udpdispatch", disp);
-
attributes &= ~DNS_DISPATCHATTR_TCP;
attributes |= DNS_DISPATCHATTR_UDP;
disp->attributes = attributes;
@@ -2000,26 +2689,25 @@ dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
ISC_LIST_APPEND(mgr->list, disp, link);
mgr_log(mgr, LVL(90), "created UDP dispatcher %p", disp);
- dispatch_log(disp, LVL(90), "created task %p", disp->task);
- dispatch_log(disp, LVL(90), "created socket %p", disp->socket);
+ dispatch_log(disp, LVL(90), "created task %p", disp->task[0]); /* XXX */
+ if (disp->socket != NULL)
+ dispatch_log(disp, LVL(90), "created socket %p", disp->socket);
*dispp = disp;
-
- goto cleanheld;
+ return (result);
/*
* Error returns.
*/
kill_task:
- isc_task_detach(&disp->task);
+ for (i = 0; i < disp->ntasks; i++)
+ isc_task_detach(&disp->task[i]);
kill_socket:
- isc_socket_detach(&disp->socket);
+ if (disp->socket != NULL)
+ isc_socket_detach(&disp->socket);
deallocate_dispatch:
dispatch_free(&disp);
- cleanheld:
- for (i = 0; i < DNS_DISPATCH_HELD; i++)
- if (held[i] != NULL)
- isc_socket_detach(&held[i]);
+
return (result);
}
@@ -2045,6 +2733,7 @@ dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp) {
void
dns_dispatch_detach(dns_dispatch_t **dispp) {
dns_dispatch_t *disp;
+ dispsocket_t *dispsock;
isc_boolean_t killit;
REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp));
@@ -2059,8 +2748,14 @@ dns_dispatch_detach(dns_dispatch_t **dispp) {
killit = ISC_FALSE;
if (disp->refcount == 0) {
if (disp->recv_pending > 0)
- isc_socket_cancel(disp->socket, disp->task,
+ isc_socket_cancel(disp->socket, disp->task[0],
+ ISC_SOCKCANCEL_RECV);
+ for (dispsock = ISC_LIST_HEAD(disp->activesockets);
+ dispsock != NULL;
+ dispsock = ISC_LIST_NEXT(dispsock, link)) {
+ isc_socket_cancel(dispsock->socket, dispsock->task,
ISC_SOCKCANCEL_RECV);
+ }
disp->shutting_down = 1;
}
@@ -2069,26 +2764,32 @@ dns_dispatch_detach(dns_dispatch_t **dispp) {
killit = destroy_disp_ok(disp);
UNLOCK(&disp->lock);
if (killit)
- isc_task_send(disp->task, &disp->ctlevent);
+ isc_task_send(disp->task[0], &disp->ctlevent);
}
isc_result_t
-dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
- isc_task_t *task, isc_taskaction_t action, void *arg,
- dns_messageid_t *idp, dns_dispentry_t **resp)
+dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ dns_messageid_t *idp, dns_dispentry_t **resp,
+ isc_socketmgr_t *sockmgr)
{
dns_dispentry_t *res;
unsigned int bucket;
+ in_port_t localport = 0;
dns_messageid_t id;
int i;
isc_boolean_t ok;
dns_qid_t *qid;
+ dispsocket_t *dispsocket = NULL;
+ isc_result_t result;
REQUIRE(VALID_DISPATCH(disp));
REQUIRE(task != NULL);
REQUIRE(dest != NULL);
REQUIRE(resp != NULL && *resp == NULL);
REQUIRE(idp != NULL);
+ if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0)
+ REQUIRE(sockmgr != NULL);
LOCK(&disp->lock);
@@ -2102,23 +2803,75 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
return (ISC_R_QUOTA);
}
+ if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 &&
+ disp->nsockets > DNS_DISPATCH_SOCKSQUOTA) {
+ dispsocket_t *oldestsocket;
+ dns_dispentry_t *oldestresp;
+ dns_dispatchevent_t *rev;
+
+ /*
+ * Kill oldest outstanding query if the number of sockets
+ * exceeds the quota to keep the room for new queries.
+ */
+ oldestsocket = ISC_LIST_HEAD(disp->activesockets);
+ oldestresp = oldestsocket->resp;
+ if (oldestresp != NULL && !oldestresp->item_out) {
+ rev = allocate_event(oldestresp->disp);
+ if (rev != NULL) {
+ rev->buffer.base = NULL;
+ rev->result = ISC_R_CANCELED;
+ rev->id = oldestresp->id;
+ ISC_EVENT_INIT(rev, sizeof(*rev), 0,
+ NULL, DNS_EVENT_DISPATCH,
+ oldestresp->action,
+ oldestresp->arg, oldestresp,
+ NULL, NULL);
+ oldestresp->item_out = ISC_TRUE;
+ isc_task_send(oldestresp->task,
+ ISC_EVENT_PTR(&rev));
+ }
+ }
+
+ /*
+ * Move this entry to the tail so that it won't (easily) be
+ * examined before actually being canceled.
+ */
+ ISC_LIST_UNLINK(disp->activesockets, oldestsocket, link);
+ ISC_LIST_APPEND(disp->activesockets, oldestsocket, link);
+ }
+
+ qid = DNS_QID(disp);
+ LOCK(&qid->lock);
+
+ if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
+ /*
+ * Get a separate UDP socket with a random port number.
+ */
+ result = get_dispsocket(disp, dest, sockmgr, qid, &dispsocket,
+ &localport);
+ if (result != ISC_R_SUCCESS) {
+ UNLOCK(&qid->lock);
+ UNLOCK(&disp->lock);
+ return (result);
+ }
+ } else {
+ localport = disp->localport;
+ }
+
/*
* Try somewhat hard to find an unique ID.
*/
- id = (dns_messageid_t)dispatch_arc4random(disp->mgr);
- qid = DNS_QID(disp);
- LOCK(&qid->lock);
- bucket = dns_hash(qid, dest, id, disp->localport);
+ id = (dns_messageid_t)dispatch_arc4random(DISP_ARC4CTX(disp));
+ bucket = dns_hash(qid, dest, id, localport);
ok = ISC_FALSE;
for (i = 0; i < 64; i++) {
- if (bucket_search(qid, dest, id, disp->localport, bucket) ==
- NULL) {
+ if (entry_search(qid, dest, id, localport, bucket) == NULL) {
ok = ISC_TRUE;
break;
}
id += qid->qid_increment;
id &= 0x0000ffff;
- bucket = dns_hash(qid, dest, id, disp->localport);
+ bucket = dns_hash(qid, dest, id, localport);
}
if (!ok) {
@@ -2131,6 +2884,8 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
if (res == NULL) {
UNLOCK(&qid->lock);
UNLOCK(&disp->lock);
+ if (dispsocket != NULL)
+ destroy_dispsocket(disp, &dispsocket);
return (ISC_R_NOMEMORY);
}
@@ -2140,11 +2895,14 @@ 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->port = localport;
res->bucket = bucket;
res->host = *dest;
res->action = action;
res->arg = arg;
+ res->dispsocket = dispsocket;
+ if (dispsocket != NULL)
+ dispsocket->resp = res;
res->item_out = ISC_FALSE;
ISC_LIST_INIT(res->items);
ISC_LINK_INIT(res, link);
@@ -2156,27 +2914,62 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
"attached to task %p", res->task);
if (((disp->attributes & DNS_DISPATCHATTR_UDP) != 0) ||
- ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) != 0))
- startrecv(disp);
+ ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) != 0)) {
+ result = startrecv(disp, dispsocket);
+ if (result != ISC_R_SUCCESS) {
+ LOCK(&qid->lock);
+ ISC_LIST_UNLINK(qid->qid_table[bucket], res, link);
+ UNLOCK(&qid->lock);
+
+ if (dispsocket != NULL)
+ destroy_dispsocket(disp, &dispsocket);
+
+ disp->refcount--;
+ disp->requests--;
+
+ UNLOCK(&disp->lock);
+ isc_task_detach(&res->task);
+ isc_mempool_put(disp->mgr->rpool, res);
+ return (result);
+ }
+ }
+
+ if (dispsocket != NULL)
+ ISC_LIST_APPEND(disp->activesockets, dispsocket, link);
UNLOCK(&disp->lock);
*idp = id;
*resp = res;
+ if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0)
+ INSIST(res->dispsocket != NULL);
+
return (ISC_R_SUCCESS);
}
+isc_result_t
+dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ dns_messageid_t *idp, dns_dispentry_t **resp)
+{
+ REQUIRE(VALID_DISPATCH(disp));
+ REQUIRE((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0);
+
+ return (dns_dispatch_addresponse2(disp, dest, task, action, arg,
+ idp, resp, NULL));
+}
+
void
dns_dispatch_starttcp(dns_dispatch_t *disp) {
REQUIRE(VALID_DISPATCH(disp));
- dispatch_log(disp, LVL(90), "starttcp %p", disp->task);
+ dispatch_log(disp, LVL(90), "starttcp %p", disp->task[0]);
LOCK(&disp->lock);
disp->attributes |= DNS_DISPATCHATTR_CONNECTED;
- startrecv(disp);
+ (void)startrecv(disp, NULL);
UNLOCK(&disp->lock);
}
@@ -2187,6 +2980,7 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp,
dns_dispatchmgr_t *mgr;
dns_dispatch_t *disp;
dns_dispentry_t *res;
+ dispsocket_t *dispsock;
dns_dispatchevent_t *ev;
unsigned int bucket;
isc_boolean_t killit;
@@ -2224,8 +3018,14 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp,
killit = ISC_FALSE;
if (disp->refcount == 0) {
if (disp->recv_pending > 0)
- isc_socket_cancel(disp->socket, disp->task,
+ isc_socket_cancel(disp->socket, disp->task[0],
ISC_SOCKCANCEL_RECV);
+ for (dispsock = ISC_LIST_HEAD(disp->activesockets);
+ dispsock != NULL;
+ dispsock = ISC_LIST_NEXT(dispsock, link)) {
+ isc_socket_cancel(dispsock->socket, dispsock->task,
+ ISC_SOCKCANCEL_RECV);
+ }
disp->shutting_down = 1;
}
@@ -2261,6 +3061,12 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp,
request_log(disp, res, LVL(90), "detaching from task %p", res->task);
isc_task_detach(&res->task);
+ if (res->dispsocket != NULL) {
+ isc_socket_cancel(res->dispsocket->socket,
+ res->dispsocket->task, ISC_SOCKCANCEL_RECV);
+ res->dispsocket->resp = NULL;
+ }
+
/*
* Free any buffered requests as well
*/
@@ -2277,12 +3083,12 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp,
if (disp->shutting_down == 1)
do_cancel(disp);
else
- startrecv(disp);
+ (void)startrecv(disp, NULL);
killit = destroy_disp_ok(disp);
UNLOCK(&disp->lock);
if (killit)
- isc_task_send(disp->task, &disp->ctlevent);
+ isc_task_send(disp->task[0], &disp->ctlevent);
}
static void
@@ -2297,13 +3103,15 @@ do_cancel(dns_dispatch_t *disp) {
qid = DNS_QID(disp);
/*
- * Search for the first response handler without packets outstanding.
+ * Search for the first response handler without packets outstanding
+ * unless a specific hander is given.
*/
LOCK(&qid->lock);
for (resp = linear_first(qid);
- resp != NULL && resp->item_out != ISC_FALSE;
+ resp != NULL && resp->item_out;
/* Empty. */)
resp = linear_next(qid, resp);
+
/*
* No one to send the cancel event to, so nothing to do.
*/
@@ -2336,6 +3144,16 @@ dns_dispatch_getsocket(dns_dispatch_t *disp) {
return (disp->socket);
}
+isc_socket_t *
+dns_dispatch_getentrysocket(dns_dispentry_t *resp) {
+ REQUIRE(VALID_RESPONSE(resp));
+
+ if (resp->dispsocket != NULL)
+ return (resp->dispsocket->socket);
+ else
+ return (NULL);
+}
+
isc_result_t
dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp) {
@@ -2369,11 +3187,27 @@ dns_dispatch_cancel(dns_dispatch_t *disp) {
return;
}
+unsigned int
+dns_dispatch_getattributes(dns_dispatch_t *disp) {
+ REQUIRE(VALID_DISPATCH(disp));
+
+ /*
+ * We don't bother locking disp here; it's the caller's responsibility
+ * to use only non volatile flags.
+ */
+ return (disp->attributes);
+}
+
void
dns_dispatch_changeattributes(dns_dispatch_t *disp,
unsigned int attributes, unsigned int mask)
{
REQUIRE(VALID_DISPATCH(disp));
+ /* Exclusive attribute can only be set on creation */
+ REQUIRE((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0);
+ /* Also, a dispatch with randomport specified cannot start listening */
+ REQUIRE((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0 ||
+ (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0);
/* XXXMLG
* Should check for valid attributes here!
@@ -2385,13 +3219,13 @@ dns_dispatch_changeattributes(dns_dispatch_t *disp,
if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0 &&
(attributes & DNS_DISPATCHATTR_NOLISTEN) == 0) {
disp->attributes &= ~DNS_DISPATCHATTR_NOLISTEN;
- startrecv(disp);
+ (void)startrecv(disp, NULL);
} else if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN)
== 0 &&
(attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) {
disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
if (disp->recv_pending != 0)
- isc_socket_cancel(disp->socket, disp->task,
+ isc_socket_cancel(disp->socket, disp->task[0],
ISC_SOCKCANCEL_RECV);
}
}
@@ -2415,7 +3249,7 @@ dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event) {
INSIST(sevent->n <= disp->mgr->buffersize);
newsevent = (isc_socketevent_t *)
isc_event_allocate(disp->mgr->mctx, NULL,
- DNS_EVENT_IMPORTRECVDONE, udp_recv,
+ DNS_EVENT_IMPORTRECVDONE, udp_shrecv,
disp, sizeof(isc_socketevent_t));
if (newsevent == NULL)
return;
@@ -2434,8 +3268,8 @@ dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event) {
newsevent->timestamp = sevent->timestamp;
newsevent->pktinfo = sevent->pktinfo;
newsevent->attributes = sevent->attributes;
-
- isc_task_send(disp->task, ISC_EVENT_PTR(&newsevent));
+
+ isc_task_send(disp->task[0], ISC_EVENT_PTR(&newsevent));
}
#if 0
diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c
index aad7998..ce361ef 100644
--- a/lib/dns/dst_parse.c
+++ b/lib/dns/dst_parse.c
@@ -1,9 +1,9 @@
/*
- * Portions Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC")
* Portions Copyright (C) 1999-2002 Internet Software Consortium.
* Portions Copyright (C) 1995-2000 by Network Associates, Inc.
*
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
@@ -18,7 +18,7 @@
/*%
* Principal Author: Brian Wellington
- * $Id: dst_parse.c,v 1.1.6.7 2006/05/16 03:59:26 marka Exp $
+ * $Id: dst_parse.c,v 1.1.6.9 2008/01/22 23:27:05 tbox Exp $
*/
#include <config.h>
@@ -260,6 +260,7 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
REQUIRE(priv != NULL);
priv->nelements = 0;
+ memset(priv->elements, 0, sizeof(priv->elements));
#define NEXTTOKEN(lex, opt, token) \
do { \
@@ -351,7 +352,6 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
goto fail;
}
- memset(&priv->elements[n], 0, sizeof(dst_private_element_t));
tag = find_value(DST_AS_STR(token), alg);
if (tag < 0 || TAG_ALG(tag) != alg) {
ret = DST_R_INVALIDPRIVATEKEY;
diff --git a/lib/dns/dst_parse.h b/lib/dns/dst_parse.h
index 8656f59..665fcfc 100644
--- a/lib/dns/dst_parse.h
+++ b/lib/dns/dst_parse.h
@@ -1,9 +1,9 @@
/*
- * Portions Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC")
* Portions Copyright (C) 2000-2002 Internet Software Consortium.
* Portions Copyright (C) 1995-2000 by Network Associates, Inc.
*
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
@@ -16,7 +16,7 @@
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dst_parse.h,v 1.1.6.5 2006/01/27 23:57:44 marka Exp $ */
+/* $Id: dst_parse.h,v 1.1.6.7 2008/05/15 23:46:06 tbox Exp $ */
/*! \file */
#ifndef DST_DST_PARSE_H
@@ -75,7 +75,7 @@
#define HMACSHA256_NTAGS 2
#define TAG_HMACSHA256_KEY ((DST_ALG_HMACSHA256 << TAG_SHIFT) + 0)
-#define TAG_HMACSHA256_BITS ((DST_ALG_HMACSHA224 << TAG_SHIFT) + 1)
+#define TAG_HMACSHA256_BITS ((DST_ALG_HMACSHA256 << TAG_SHIFT) + 1)
#define HMACSHA384_NTAGS 2
#define TAG_HMACSHA384_KEY ((DST_ALG_HMACSHA384 << TAG_SHIFT) + 0)
diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h
index 914993b..8c14320 100644
--- a/lib/dns/include/dns/dispatch.h
+++ b/lib/dns/include/dns/dispatch.h
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dispatch.h,v 1.48.18.5.12.2 2008/07/23 07:28:56 tbox Exp $ */
+/* $Id: dispatch.h,v 1.48.18.9 2008/06/24 23:45:55 tbox Exp $ */
#ifndef DNS_DISPATCH_H
#define DNS_DISPATCH_H 1
@@ -105,7 +105,7 @@ struct dns_dispatchevent {
* The dispatcher is a TCP or UDP socket.
*
* _IPV4, _IPV6
- * The dispatcher uses an ipv4 or ipv6 socket.
+ * The dispatcher uses an IPv4 or IPv6 socket.
*
* _NOLISTEN
* The dispatcher should not listen on the socket.
@@ -115,7 +115,12 @@ struct dns_dispatchevent {
* accept replies from them.
*
* _RANDOMPORT
- * Allocate UDP port randomly.
+ * Previously used to indicate that the port of a dispatch UDP must be
+ * chosen randomly. This behavior now always applies and the attribute
+ * is obsoleted.
+ *
+ * _EXCLUSIVE
+ * A separate socket will be used on-demand for each transaction.
*/
#define DNS_DISPATCHATTR_PRIVATE 0x00000001U
#define DNS_DISPATCHATTR_TCP 0x00000002U
@@ -125,7 +130,8 @@ struct dns_dispatchevent {
#define DNS_DISPATCHATTR_NOLISTEN 0x00000020U
#define DNS_DISPATCHATTR_MAKEQUERY 0x00000040U
#define DNS_DISPATCHATTR_CONNECTED 0x00000080U
-#define DNS_DISPATCHATTR_RANDOMPORT 0x00000100U
+/*#define DNS_DISPATCHATTR_RANDOMPORT 0x00000100U*/
+#define DNS_DISPATCHATTR_EXCLUSIVE 0x00000200U
/*@}*/
isc_result_t
@@ -187,26 +193,34 @@ dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr);
void
dns_dispatchmgr_setblackportlist(dns_dispatchmgr_t *mgr,
- dns_portlist_t *portlist);
+ dns_portlist_t *portlist);
/*%<
- * Sets a list of UDP ports that won't be used when creating a udp
- * dispatch with a wildcard port.
+ * This function is deprecated. Use dns_dispatchmgr_setavailports() instead.
*
* Requires:
*\li mgr is a valid dispatchmgr
- *\li portlist to be NULL or a valid port list.
*/
dns_portlist_t *
dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr);
/*%<
- * Return the current port list.
+ * This function is deprecated and always returns NULL.
*
* Requires:
*\li mgr is a valid dispatchmgr
*/
-
+isc_result_t
+dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset,
+ isc_portset_t *v6portset);
+/*%<
+ * Sets a list of UDP ports that can be used for outgoing UDP messages.
+ *
+ * Requires:
+ *\li mgr is a valid dispatchmgr
+ *\li v4portset is NULL or a valid port set
+ *\li v6portset is NULL or a valid port set
+ */
isc_result_t
dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
@@ -319,6 +333,12 @@ dns_dispatch_starttcp(dns_dispatch_t *disp);
*/
isc_result_t
+dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest,
+ isc_task_t *task, isc_taskaction_t action, void *arg,
+ isc_uint16_t *idp, dns_dispentry_t **resp,
+ isc_socketmgr_t *sockmgr);
+
+isc_result_t
dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
isc_task_t *task, isc_taskaction_t action, void *arg,
isc_uint16_t *idp, dns_dispentry_t **resp);
@@ -341,6 +361,10 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
*
*\li "resp" be non-NULL and *resp be NULL
*
+ *\li "sockmgr" be NULL or a valid socket manager. If 'disp' has
+ * the DNS_DISPATCHATTR_EXCLUSIVE attribute, this must not be NULL,
+ * which also means dns_dispatch_addresponse() cannot be used.
+ *
* Ensures:
*
*\li &lt;id, dest> is a unique tuple. That means incoming messages
@@ -367,10 +391,12 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp,
*\li "resp" != NULL and "*resp" contain a value previously allocated
* by dns_dispatch_addresponse();
*
- *\li May only be called from within the task given as the 'task'
+ *\li May only be called from within the task given as the 'task'
* argument to dns_dispatch_addresponse() when allocating '*resp'.
*/
+isc_socket_t *
+dns_dispatch_getentrysocket(dns_dispentry_t *resp);
isc_socket_t *
dns_dispatch_getsocket(dns_dispatch_t *disp);
@@ -384,7 +410,7 @@ dns_dispatch_getsocket(dns_dispatch_t *disp);
*\li The socket the dispatcher is using.
*/
-isc_result_t
+isc_result_t
dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp);
/*%<
* Return the local address for this dispatch.
@@ -395,7 +421,7 @@ dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp);
*\li addrp to be non null.
*
* Returns:
- *\li ISC_R_SUCCESS
+ *\li ISC_R_SUCCESS
*\li ISC_R_NOTIMPLEMENTED
*/
@@ -408,6 +434,16 @@ dns_dispatch_cancel(dns_dispatch_t *disp);
*\li disp is valid.
*/
+unsigned int
+dns_dispatch_getattributes(dns_dispatch_t *disp);
+/*%<
+ * Return the attributes (DNS_DISPATCHATTR_xxx) of this dispatch. Only the
+ * non-changeable attributes are expected to be referenced by the caller.
+ *
+ * Requires:
+ *\li disp is valid.
+ */
+
void
dns_dispatch_changeattributes(dns_dispatch_t *disp,
unsigned int attributes, unsigned int mask);
@@ -421,7 +457,7 @@ dns_dispatch_changeattributes(dns_dispatch_t *disp,
* new = (old & ~mask) | (attributes & mask)
* \endcode
*
- * This function has a side effect when #DNS_DISPATCHATTR_NOLISTEN changes.
+ * This function has a side effect when #DNS_DISPATCHATTR_NOLISTEN changes.
* When the flag becomes off, the dispatch will start receiving on the
* corresponding socket. When the flag becomes on, receive events on the
* corresponding socket will be canceled.
diff --git a/lib/dns/journal.c b/lib/dns/journal.c
index 6cfb5af..4e4010f 100644
--- a/lib/dns/journal.c
+++ b/lib/dns/journal.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2002 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: journal.c,v 1.86.18.12 2007/09/07 05:21:41 marka Exp $ */
+/* $Id: journal.c,v 1.86.18.14 2008/09/25 04:01:36 tbox Exp $ */
#include <config.h>
@@ -41,7 +41,7 @@
#include <dns/result.h>
#include <dns/soa.h>
-/*! \file
+/*! \file
* \brief Journalling.
*
* A journal file consists of
@@ -107,7 +107,7 @@ static isc_boolean_t bind8_compat = ISC_TRUE; /* XXX config */
} while (0)
#define CHECK(op) \
- do { result = (op); \
+ do { result = (op); \
if (result != ISC_R_SUCCESS) goto failure; \
} while (0)
@@ -149,11 +149,11 @@ dns_db_createsoatuple(dns_db_t *db, dns_dbversion_t *ver, isc_mem_t *mctx,
dns_rdataset_init(&rdataset);
result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 0,
(isc_stdtime_t)0, &rdataset, NULL);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS)
goto freenode;
result = dns_rdataset_first(&rdataset);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS)
goto freenode;
dns_rdataset_current(&rdataset, &rdata);
@@ -674,7 +674,7 @@ dns_journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
isc_result_t result;
int namelen;
char backup[1024];
-
+
result = journal_open(mctx, filename, write, write, journalp);
if (result == ISC_R_NOTFOUND) {
namelen = strlen(filename);
@@ -1367,7 +1367,7 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) {
if (result != ISC_R_SUCCESS) {
isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
"journal open failure: %s: %s",
- isc_result_totext(result), j->filename);
+ isc_result_totext(result), filename);
return (result);
}
@@ -1405,9 +1405,9 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) {
if (n_soa == 3)
n_soa = 1;
if (n_soa == 0) {
- isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
- "%s: journal file corrupt: missing "
- "initial SOA", j->filename);
+ isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR,
+ "%s: journal file corrupt: missing "
+ "initial SOA", j->filename);
FAIL(ISC_R_UNEXPECTED);
}
CHECK(dns_difftuple_create(diff.mctx, n_soa == 1 ?
@@ -1984,7 +1984,7 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
dns_journal_destroy(&j);
return (ISC_R_SUCCESS);
}
-
+
if (DNS_SERIAL_GT(j->header.begin.serial, serial) ||
DNS_SERIAL_GT(serial, j->header.end.serial)) {
dns_journal_destroy(&j);
@@ -2008,7 +2008,7 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
}
CHECK(journal_open(mctx, newname, ISC_TRUE, ISC_TRUE, &new));
-
+
/*
* Remove overhead so space test below can succeed.
*/
@@ -2066,7 +2066,7 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
result = ISC_R_NOMEMORY;
goto failure;
}
-
+
CHECK(journal_seek(j, best_guess.offset));
CHECK(journal_seek(new, indexend));
for (i = 0; i < copy_length; i += size) {
@@ -2139,7 +2139,7 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
goto failure;
}
}
-
+
dns_journal_destroy(&j);
result = ISC_R_SUCCESS;
diff --git a/lib/dns/master.c b/lib/dns/master.c
index aa04be0..b04f2eb 100644
--- a/lib/dns/master.c
+++ b/lib/dns/master.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: master.c,v 1.148.18.18 2007/08/28 07:20:04 tbox Exp $ */
+/* $Id: master.c,v 1.148.18.21 2008/01/17 23:45:58 tbox Exp $ */
/*! \file */
@@ -536,7 +536,7 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx,
lctx->inc = NULL;
result = incctx_create(mctx, origin, &lctx->inc);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS)
goto cleanup_ctx;
lctx->format = format;
@@ -708,7 +708,7 @@ openfile_raw(dns_loadctx_t *lctx, const char *master_file) {
if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_stdio_open() failed: %s",
- isc_result_totext(result));
+ isc_result_totext(result));
}
return (result);
@@ -912,7 +912,7 @@ check_ns(dns_loadctx_t *lctx, isc_token_t *token, const char *source,
callback = lctx->callbacks->error;
else
callback = lctx->callbacks->warn;
-
+
if (token->type == isc_tokentype_string) {
struct in_addr addr;
struct in6_addr addr6;
@@ -1237,7 +1237,7 @@ load_text(dns_loadctx_t *lctx) {
/* CLASS? */
GETTOKEN(lctx->lex, 0, &token, ISC_FALSE);
if (dns_rdataclass_fromtext(&rdclass,
- &token.value.as_textregion)
+ &token.value.as_textregion)
== ISC_R_SUCCESS) {
GETTOKEN(lctx->lex, 0, &token,
ISC_FALSE);
@@ -1421,7 +1421,7 @@ load_text(dns_loadctx_t *lctx) {
target_save = target;
ictx->glue = new_name;
ictx->glue_in_use = new_in_use;
- ictx->in_use[ictx->glue_in_use] =
+ ictx->in_use[ictx->glue_in_use] =
ISC_TRUE;
} else {
result = commit(callbacks, lctx,
@@ -1689,7 +1689,7 @@ load_text(dns_loadctx_t *lctx) {
dns_name_format(name, namebuf, sizeof(namebuf));
result = DNS_R_BADOWNERNAME;
desc = dns_result_totext(result);
- if ((lctx->options & DNS_MASTER_CHECKNAMESFAIL) != 0) {
+ if ((lctx->options & DNS_MASTER_CHECKNAMESFAIL) != 0) {
(*callbacks->error)(callbacks,
"%s:%lu: %s: %s",
source, line,
@@ -1739,9 +1739,9 @@ load_text(dns_loadctx_t *lctx) {
dns_name_format(ictx->current, namebuf,
sizeof(namebuf));
(*callbacks->error)(callbacks,
- "%s:%lu: SOA "
- "record not at top of zone (%s)",
- source, line, namebuf);
+ "%s:%lu: SOA "
+ "record not at top of zone (%s)",
+ source, line, namebuf);
result = DNS_R_NOTZONETOP;
if (MANYERRS(lctx, result)) {
SETRESULT(lctx, result);
@@ -1801,7 +1801,9 @@ load_text(dns_loadctx_t *lctx) {
if (type == dns_rdatatype_rrsig && lctx->warn_sigexpired) {
dns_rdata_rrsig_t sig;
- (void)dns_rdata_tostruct(&rdata[rdcount], &sig, NULL);
+ result = dns_rdata_tostruct(&rdata[rdcount], &sig,
+ NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (isc_serial_lt(sig.timeexpire, now)) {
(*callbacks->warn)(callbacks,
"%s:%lu: "
@@ -1813,7 +1815,7 @@ load_text(dns_loadctx_t *lctx) {
if ((type == dns_rdatatype_sig || type == dns_rdatatype_nxt) &&
lctx->warn_tcr && (lctx->options & DNS_MASTER_ZONE) != 0 &&
- (lctx->options & DNS_MASTER_SLAVE) == 0) {
+ (lctx->options & DNS_MASTER_SLAVE) == 0) {
(*callbacks->warn)(callbacks, "%s:%lu: old style DNSSEC "
" zone detected", source, line);
lctx->warn_tcr = ISC_FALSE;
@@ -1871,7 +1873,7 @@ load_text(dns_loadctx_t *lctx) {
ISC_LIST_INITANDPREPEND(glue_list, this, link);
else
ISC_LIST_INITANDPREPEND(current_list, this,
- link);
+ link);
} else if (this->ttl != lctx->ttl) {
(*callbacks->warn)(callbacks,
"%s:%lu: "
@@ -1881,7 +1883,7 @@ load_text(dns_loadctx_t *lctx) {
}
ISC_LIST_APPEND(this->rdata, &rdata[rdcount], link);
- if (ictx->glue != NULL)
+ if (ictx->glue != NULL)
ictx->glue_line = line;
else
ictx->current_line = line;
@@ -2222,7 +2224,7 @@ load_raw(dns_loadctx_t *lctx) {
isc_uint16_t rdlen;
dns_rdata_init(&rdata[i]);
-
+
if (sequential_read &&
isc_buffer_availablelength(&target) < MINTSIZ) {
unsigned int j;
diff --git a/lib/dns/masterdump.c b/lib/dns/masterdump.c
index 03716e2..1ffdfcb 100644
--- a/lib/dns/masterdump.c
+++ b/lib/dns/masterdump.c
@@ -1,8 +1,8 @@
/*
- * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: masterdump.c,v 1.73.18.14 2006/08/08 06:39:36 marka Exp $ */
+/* $Id: masterdump.c,v 1.73.18.16 2008/08/13 23:46:04 tbox Exp $ */
/*! \file */
@@ -183,7 +183,7 @@ struct dns_dumpctx {
isc_buffer_t *buffer, FILE *f);
};
-#define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
+#define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
/*%
* Output tabs and spaces to go from column '*current' to
@@ -1071,13 +1071,13 @@ dns_dumpctx_detach(dns_dumpctx_t **dctxp) {
dns_dbversion_t *
dns_dumpctx_version(dns_dumpctx_t *dctx) {
- REQUIRE(DNS_DCTX_VALID(dctx));
+ REQUIRE(DNS_DCTX_VALID(dctx));
return (dctx->version);
}
dns_db_t *
dns_dumpctx_db(dns_dumpctx_t *dctx) {
- REQUIRE(DNS_DCTX_VALID(dctx));
+ REQUIRE(DNS_DCTX_VALID(dctx));
return (dctx->db);
}
@@ -1412,12 +1412,11 @@ dumptostreaminc(dns_dumpctx_t *dctx) {
"dumptostreaminc(%p) new nodes -> %d\n",
dctx, dctx->nodes);
}
- result = dns_dbiterator_pause(dctx->dbiter);
- RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = DNS_R_CONTINUE;
} else if (result == ISC_R_NOMORE)
result = ISC_R_SUCCESS;
fail:
+ RUNTIME_CHECK(dns_dbiterator_pause(dctx->dbiter) == ISC_R_SUCCESS);
isc_mem_put(dctx->mctx, buffer.base, buffer.length);
return (result);
}
@@ -1703,10 +1702,10 @@ dns_master_dumpnode(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
isc_result_t
dns_master_stylecreate(dns_master_style_t **stylep, unsigned int flags,
- unsigned int ttl_column, unsigned int class_column,
- unsigned int type_column, unsigned int rdata_column,
- unsigned int line_length, unsigned int tab_width,
- isc_mem_t *mctx)
+ unsigned int ttl_column, unsigned int class_column,
+ unsigned int type_column, unsigned int rdata_column,
+ unsigned int line_length, unsigned int tab_width,
+ isc_mem_t *mctx)
{
dns_master_style_t *style;
diff --git a/lib/dns/message.c b/lib/dns/message.c
index e8e4948..8c56377 100644
--- a/lib/dns/message.c
+++ b/lib/dns/message.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: message.c,v 1.222.18.14 2007/08/28 07:20:04 tbox Exp $ */
+/* $Id: message.c,v 1.222.18.16 2008/07/28 23:46:20 tbox Exp $ */
/*! \file */
@@ -592,6 +592,9 @@ msgreset(dns_message_t *msg, isc_boolean_t everything) {
msg->tsigkey = NULL;
}
+ if (msg->tsigctx != NULL)
+ dst_context_destroy(&msg->tsigctx);
+
if (msg->query.base != NULL) {
if (msg->free_query != 0)
isc_mem_put(msg->mctx, msg->query.base,
@@ -987,7 +990,7 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
if (name == NULL)
return (ISC_R_NOMEMORY);
free_name = ISC_TRUE;
-
+
offsets = newoffsets(msg);
if (offsets == NULL) {
result = ISC_R_NOMEMORY;
@@ -1297,7 +1300,7 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
}
/*
* When the rdata is empty, the data pointer is
- * never dereferenced, but it must still be non-NULL.
+ * never dereferenced, but it must still be non-NULL.
* Casting 1 rather than "" avoids warnings about
* discarding the const attribute of a string,
* for compilers that would warn about such things.
@@ -1436,7 +1439,7 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
rdataset)
== ISC_R_SUCCESS);
- if (rdtype != dns_rdatatype_opt &&
+ if (rdtype != dns_rdatatype_opt &&
rdtype != dns_rdatatype_tsig &&
!issigzero)
{
diff --git a/lib/dns/rbt.c b/lib/dns/rbt.c
index b8db99a..4d3ca3a 100644
--- a/lib/dns/rbt.c
+++ b/lib/dns/rbt.c
@@ -1,8 +1,8 @@
/*
- * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rbt.c,v 1.128.18.7 2005/10/13 01:26:06 marka Exp $ */
+/* $Id: rbt.c,v 1.128.18.10 2008/03/31 13:32:59 fdupont Exp $ */
/*! \file */
@@ -203,7 +203,7 @@ static inline void
rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
static void
-dns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
+dns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
dns_rbtnode_t **rootp);
static void
@@ -227,7 +227,7 @@ dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *),
isc_result_t result;
#endif
dns_rbt_t *rbt;
-
+
REQUIRE(mctx != NULL);
REQUIRE(rbtp != NULL && *rbtp == NULL);
@@ -576,7 +576,7 @@ dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) {
rbt->nodecount++;
dns_name_getlabelsequence(name,
nlabels - hlabels,
- hlabels, new_name);
+ hlabels, new_name);
hash_node(rbt, new_current, new_name);
if (common_labels ==
@@ -772,7 +772,7 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
dns_name_init(&hash_name, NULL);
hashagain:
- /*
+ /*
* Hash includes tail.
*/
dns_name_getlabelsequence(name,
@@ -832,7 +832,7 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
*/
current = NULL;
continue;
-
+
nohash:
#endif /* DNS_RBT_USEHASH */
/*
@@ -1375,7 +1375,7 @@ dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name) {
result = dns_name_concatenate(name, &current, name, NULL);
if (result != ISC_R_SUCCESS)
break;
-
+
node = find_up(node);
} while (! dns_name_isabsolute(name));
@@ -1642,7 +1642,7 @@ rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
* true red/black tree on a single level.
*/
static void
-dns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
+dns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
dns_rbtnode_t **rootp)
{
dns_rbtnode_t *child, *root, *parent, *grandparent;
@@ -2051,10 +2051,6 @@ dns_rbt_deletetreeflat(dns_rbt_t *rbt, unsigned int quantum,
node = LEFT(node);
goto traverse;
}
- if (RIGHT(node) != NULL) {
- node = RIGHT(node);
- goto traverse;
- }
if (DOWN(node) != NULL) {
node = DOWN(node);
goto traverse;
@@ -2065,20 +2061,21 @@ dns_rbt_deletetreeflat(dns_rbt_t *rbt, unsigned int quantum,
/*
* Note: we don't call unhash_node() here as we are destroying
- * the complete rbt tree.
- */
+ * the complete rbt tree.
+ */
#if DNS_RBT_USEMAGIC
node->magic = 0;
#endif
parent = PARENT(node);
+ if (RIGHT(node) != NULL)
+ PARENT(RIGHT(node)) = parent;
if (parent != NULL) {
if (LEFT(parent) == node)
- LEFT(parent) = NULL;
+ LEFT(parent) = RIGHT(node);
else if (DOWN(parent) == node)
- DOWN(parent) = NULL;
- else if (RIGHT(parent) == node)
- RIGHT(parent) = NULL;
- }
+ DOWN(parent) = RIGHT(node);
+ } else
+ parent = RIGHT(node);
isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
rbt->nodecount--;
node = parent;
@@ -2191,6 +2188,7 @@ dns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx) {
chain->end = NULL;
chain->level_count = 0;
chain->level_matches = 0;
+ memset(chain->levels, 0, sizeof(chain->levels));
chain->magic = CHAIN_MAGIC;
}
diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c
index 1d729d0..462a718 100644
--- a/lib/dns/rbtdb.c
+++ b/lib/dns/rbtdb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rbtdb.c,v 1.196.18.48 2007/08/28 07:20:04 tbox Exp $ */
+/* $Id: rbtdb.c,v 1.196.18.53 2008/01/31 23:46:05 tbox Exp $ */
/*! \file */
@@ -195,7 +195,7 @@ struct noqname {
void * nsecsig;
};
-typedef struct acachectl acachectl_t;
+typedef struct acachectl acachectl_t;
typedef struct rdatasetheader {
/*%
@@ -219,7 +219,7 @@ typedef struct rdatasetheader {
* Otherwise, it points up to the header whose down pointer points
* at this header.
*/
-
+
struct rdatasetheader *down;
/*%<
* Points to the header for the next older version of
@@ -387,7 +387,7 @@ static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target);
static unsigned int rdataset_count(dns_rdataset_t *rdataset);
static isc_result_t rdataset_getnoqname(dns_rdataset_t *rdataset,
- dns_name_t *name,
+ dns_name_t *name,
dns_rdataset_t *nsec,
dns_rdataset_t *nsecsig);
static isc_result_t rdataset_getadditional(dns_rdataset_t *rdataset,
@@ -604,13 +604,13 @@ adjust_quantum(unsigned int old, isc_time_t *start) {
/* Smooth */
new = (new + old * 3) / 4;
-
+
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
ISC_LOG_DEBUG(1), "adjust_quantum -> %d", new);
return (new);
}
-
+
static void
free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) {
unsigned int i;
@@ -647,7 +647,7 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) {
if (event == NULL)
event = isc_event_allocate(rbtdb->common.mctx,
NULL,
- DNS_EVENT_FREESTORAGE,
+ DNS_EVENT_FREESTORAGE,
free_rbtdb_callback,
rbtdb,
sizeof(isc_event_t));
@@ -890,7 +890,7 @@ free_acachearray(isc_mem_t *mctx, rdatasetheader_t *header,
/*
* Sanity check: since an additional cache entry has a reference to
* the original DB node (in the callback arg), there should be no
- * acache entries when the node can be freed.
+ * acache entries when the node can be freed.
*/
for (i = 0; i < count; i++)
INSIST(array[i].entry == NULL && array[i].cbarg == NULL);
@@ -1241,7 +1241,7 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
isc_rwlocktype_write);
RUNTIME_CHECK(result == ISC_R_SUCCESS ||
result == ISC_R_LOCKBUSY);
-
+
write_locked = ISC_TF(result == ISC_R_SUCCESS);
} else
write_locked = ISC_TRUE;
@@ -1388,6 +1388,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
rbtdb_serial_t serial, least_serial;
dns_rbtnode_t *rbtnode;
unsigned int refs;
+ isc_boolean_t writer;
REQUIRE(VALID_RBTDB(rbtdb));
version = (rbtdb_version_t *)*versionp;
@@ -1407,6 +1408,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
serial = version->serial;
+ writer = version->writer;
if (version->writer) {
if (commit) {
unsigned cur_ref;
@@ -1539,7 +1541,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
/*
* Update the zone's secure status.
*/
- if (version->writer && commit && !IS_CACHE(rbtdb))
+ if (writer && commit && !IS_CACHE(rbtdb))
rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
if (cleanup_version != NULL) {
@@ -1751,7 +1753,7 @@ zone_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
if (header != NULL) {
if (header->type == dns_rdatatype_dname)
dname_header = header;
- else if (header->type ==
+ else if (header->type ==
RBTDB_RDATATYPE_SIGDNAME)
sigdname_header = header;
else if (node != onode ||
@@ -1983,7 +1985,7 @@ valid_glue(rbtdb_search_t *search, dns_name_t *name, rbtdb_rdatatype_t type,
count = raw[0] * 256 + raw[1];
#if DNS_RDATASET_FIXED
raw += 2 + (4 * count);
-#else
+#else
raw += 2;
#endif
@@ -2997,7 +2999,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
UNUSED(name);
lock = &(search->rbtdb->node_locks[node->locknum].lock);
- locktype = isc_rwlocktype_read;
+ locktype = isc_rwlocktype_read;
NODE_LOCK(lock, locktype);
/*
@@ -3026,7 +3028,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
* will eventually take the job as the last
* resort.
* We won't downgrade the lock, since other
- * rdatasets are probably stale, too.
+ * rdatasets are probably stale, too.
*/
locktype = isc_rwlocktype_write;
@@ -3262,7 +3264,7 @@ find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
matchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_nsec, 0);
sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig,
dns_rdatatype_nsec);
-
+
do {
node = NULL;
dns_fixedname_init(&fname);
@@ -3289,7 +3291,7 @@ find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
* This rdataset is stale. If no one else is
* using the node, we can clean it up right
* now, otherwise we mark it as stale, and the
- * node as dirty, so it will get cleaned up
+ * node as dirty, so it will get cleaned up
* later.
*/
if ((header->ttl <= now - RBTDB_VIRTUAL) &&
@@ -4211,7 +4213,7 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
* can get write access.
*/
locktype = isc_rwlocktype_write;
-
+
/*
* We don't check if refcurrent(rbtnode) == 0
* and try to free like we do in cache_find(),
@@ -4482,7 +4484,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
for (topheader = rbtnode->data;
topheader != NULL;
topheader = topheader->next) {
- if (topheader->type ==
+ if (topheader->type ==
RBTDB_RDATATYPE_NCACHEANY)
break;
}
@@ -4496,7 +4498,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
* The NXDOMAIN/NODATA(QTYPE=ANY)
* is more trusted.
*/
-
+
free_rdataset(rbtdb->common.mctx,
newheader);
if (addedrdataset != NULL)
@@ -4576,7 +4578,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
INSIST(rbtversion->serial >= header->serial);
merged = NULL;
result = ISC_R_SUCCESS;
-
+
if ((options & DNS_DBADD_EXACT) != 0)
flags |= DNS_RDATASLAB_EXACT;
if ((options & DNS_DBADD_EXACTTTL) != 0 &&
@@ -4622,9 +4624,9 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
header->trust >= newheader->trust &&
dns_rdataslab_equalx((unsigned char *)header,
(unsigned char *)newheader,
- (unsigned int)(sizeof(*newheader)),
+ (unsigned int)(sizeof(*newheader)),
rbtdb->common.rdclass,
- (dns_rdatatype_t)header->type)) {
+ (dns_rdatatype_t)header->type)) {
/*
* Honour the new ttl if it is less than the
* older one.
@@ -4649,7 +4651,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
header->trust >= newheader->trust &&
dns_rdataslab_equal((unsigned char *)header,
(unsigned char *)newheader,
- (unsigned int)(sizeof(*newheader)))) {
+ (unsigned int)(sizeof(*newheader)))) {
/*
* Honour the new ttl if it is less than the
* older one.
@@ -5050,7 +5052,7 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
if ((options & DNS_DBSUB_EXACT) != 0)
result = DNS_R_NOTEXACT;
else
- result = DNS_R_UNCHANGED;
+ result = DNS_R_UNCHANGED;
}
if (result == ISC_R_SUCCESS && newrdataset != NULL)
@@ -5514,7 +5516,7 @@ dns_rbtdb_create
}
rbtdb->node_locks[i].exiting = ISC_FALSE;
}
-
+
/*
* Attach to the mctx. The database will persist so long as there
* are references to it, and attaching to the mctx ensures that our
@@ -5661,7 +5663,7 @@ rdataset_first(dns_rdataset_t *rdataset) {
rdataset->private5 = NULL;
return (ISC_R_NOMORE);
}
-
+
#if DNS_RDATASET_FIXED
if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0)
raw += 2 + (4 * count);
@@ -5928,7 +5930,7 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator) {
if (rdtype == 0) {
covers = RBTDB_RDATATYPE_EXT(header->type);
negtype = RBTDB_RDATATYPE_VALUE(covers, 0);
- } else
+ } else
negtype = RBTDB_RDATATYPE_VALUE(0, rdtype);
for (header = header->next; header != NULL; header = top_next) {
top_next = header->next;
@@ -6517,12 +6519,13 @@ acache_callback(dns_acacheentry_t *entry, void **arg) {
}
count = cbarg->count;
- if (acarray[count].entry == entry)
+ if (acarray != NULL && acarray[count].entry == entry) {
acarray[count].entry = NULL;
- INSIST(acarray[count].cbarg != NULL);
- isc_mem_put(rbtdb->common.mctx, acarray[count].cbarg,
- sizeof(acache_cbarg_t));
- acarray[count].cbarg = NULL;
+ INSIST(acarray[count].cbarg == cbarg);
+ isc_mem_put(rbtdb->common.mctx, cbarg, sizeof(acache_cbarg_t));
+ acarray[count].cbarg = NULL;
+ } else
+ isc_mem_put(rbtdb->common.mctx, cbarg, sizeof(acache_cbarg_t));
dns_acache_detachentry(&entry);
@@ -6664,9 +6667,7 @@ rdataset_setadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type,
NODE_UNLOCK(nodelock, isc_rwlocktype_write);
if (oldentry != NULL) {
- if (oldcbarg != NULL)
- acache_cancelentry(rbtdb->common.mctx, oldentry,
- &oldcbarg);
+ acache_cancelentry(rbtdb->common.mctx, oldentry, &oldcbarg);
dns_acache_detachentry(&oldentry);
}
@@ -6692,7 +6693,7 @@ rdataset_setadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type,
static isc_result_t
rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type, dns_rdatatype_t qtype)
-{
+{
dns_rbtdb_t *rbtdb = rdataset->private1;
dns_rbtnode_t *rbtnode = rdataset->private2;
unsigned char *raw = rdataset->private3; /* RDATASLAB */
@@ -6751,8 +6752,7 @@ rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset,
NODE_UNLOCK(nodelock, isc_rwlocktype_write);
if (entry != NULL) {
- if (cbarg != NULL)
- acache_cancelentry(rbtdb->common.mctx, entry, &cbarg);
+ acache_cancelentry(rbtdb->common.mctx, entry, &cbarg);
dns_acache_detachentry(&entry);
}
diff --git a/lib/dns/rdata/generic/nsec_47.c b/lib/dns/rdata/generic/nsec_47.c
index f3e56ca..dd39105 100644
--- a/lib/dns/rdata/generic/nsec_47.c
+++ b/lib/dns/rdata/generic/nsec_47.c
@@ -1,8 +1,8 @@
/*
- * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 2003 Internet Software Consortium.
*
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
@@ -15,11 +15,11 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: nsec_47.c,v 1.7 2004/03/05 05:10:15 marka Exp $ */
+/* $Id: nsec_47.c,v 1.7.20.2 2008/07/15 23:46:14 tbox Exp $ */
/* reviewed: Wed Mar 15 18:21:15 PST 2000 by brister */
-/* draft-ietf-dnsext-nsec-rdata-01.txt */
+/* RFC 3845 */
#ifndef RDATA_GENERIC_NSEC_47_C
#define RDATA_GENERIC_NSEC_47_C
@@ -255,7 +255,7 @@ fromstruct_nsec(ARGS_FROMSTRUCT) {
window = nsec->typebits[i];
len = nsec->typebits[i+1];
i += 2;
- INSIST(first || window > lastwindow);
+ INSIST(first || window > lastwindow);
INSIST(len > 0 && len <= 32);
INSIST(i + len <= nsec->len);
INSIST(nsec->typebits[i + len - 1] != 0);
diff --git a/lib/dns/rdata/generic/nsec_47.h b/lib/dns/rdata/generic/nsec_47.h
index ff03483..5c52447 100644
--- a/lib/dns/rdata/generic/nsec_47.h
+++ b/lib/dns/rdata/generic/nsec_47.h
@@ -1,8 +1,8 @@
/*
- * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 2003 Internet Software Consortium.
*
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
@@ -18,10 +18,10 @@
#ifndef GENERIC_NSEC_47_H
#define GENERIC_NSEC_47_H 1
-/* $Id: nsec_47.h,v 1.4.20.2 2005/04/29 00:16:37 marka Exp $ */
+/* $Id: nsec_47.h,v 1.4.20.4 2008/07/15 23:46:14 tbox Exp $ */
/*!
- * \brief Per draft-ietf-dnsext-nsec-rdata-01.txt */
+ * \brief Per RFC 3845 */
typedef struct dns_rdata_nsec {
dns_rdatacommon_t common;
diff --git a/lib/dns/rdata/generic/txt_16.c b/lib/dns/rdata/generic/txt_16.c
index fa3ffef..01ca87a 100644
--- a/lib/dns/rdata/generic/txt_16.c
+++ b/lib/dns/rdata/generic/txt_16.c
@@ -1,8 +1,8 @@
/*
- * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1998-2002 Internet Software Consortium.
*
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: txt_16.c,v 1.41 2004/03/05 05:10:18 marka Exp $ */
+/* $Id: txt_16.c,v 1.41.18.2 2008/02/15 23:45:53 tbox Exp $ */
/* Reviewed: Thu Mar 16 15:40:00 PST 2000 by bwelling */
@@ -142,7 +142,7 @@ fromstruct_txt(ARGS_FROMSTRUCT) {
while (region.length > 0) {
length = uint8_fromregion(&region);
isc_region_consume(&region, 1);
- if (region.length <= length)
+ if (region.length < length)
return (ISC_R_UNEXPECTEDEND);
isc_region_consume(&region, length);
}
diff --git a/lib/dns/rdata/in_1/apl_42.c b/lib/dns/rdata/in_1/apl_42.c
index 42b2e7f..2fce328 100644
--- a/lib/dns/rdata/in_1/apl_42.c
+++ b/lib/dns/rdata/in_1/apl_42.c
@@ -1,8 +1,8 @@
/*
- * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 2002 Internet Software Consortium.
*
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: apl_42.c,v 1.8.18.2 2005/04/29 00:16:42 marka Exp $ */
+/* $Id: apl_42.c,v 1.8.18.4 2008/01/22 23:27:06 tbox Exp $ */
/* RFC3123 */
@@ -49,7 +49,7 @@ fromtext_in_apl(ARGS_FROMTEXT) {
isc_tokentype_string, ISC_TRUE));
if (token.type != isc_tokentype_string)
break;
-
+
cp = DNS_AS_STR(token);
neg = ISC_TF(*cp == '!');
if (neg)
@@ -259,7 +259,7 @@ fromstruct_in_apl(ARGS_FROMSTRUCT) {
REQUIRE(apl->common.rdtype == type);
REQUIRE(apl->common.rdclass == rdclass);
REQUIRE(apl->apl != NULL || apl->apl_len == 0);
-
+
isc_buffer_init(&b, apl->apl, apl->apl_len);
isc_buffer_add(&b, apl->apl_len);
isc_buffer_setactive(&b, apl->apl_len);
@@ -306,37 +306,88 @@ freestruct_in_apl(ARGS_FREESTRUCT) {
isc_result_t
dns_rdata_apl_first(dns_rdata_in_apl_t *apl) {
+ isc_uint32_t length;
+
+ REQUIRE(apl != NULL);
REQUIRE(apl->common.rdtype == 42);
REQUIRE(apl->common.rdclass == 1);
REQUIRE(apl->apl != NULL || apl->apl_len == 0);
+ /*
+ * If no APL return ISC_R_NOMORE.
+ */
+ if (apl->apl == NULL)
+ return (ISC_R_NOMORE);
+
+ /*
+ * Sanity check data.
+ */
+ INSIST(apl->apl_len > 3U);
+ length = apl->apl[apl->offset + 3] & 0x7f;
+ INSIST(length <= apl->apl_len);
+
apl->offset = 0;
- return ((apl->apl_len != 0) ? ISC_R_SUCCESS : ISC_R_NOMORE);
+ return (ISC_R_SUCCESS);
}
isc_result_t
dns_rdata_apl_next(dns_rdata_in_apl_t *apl) {
+ isc_uint32_t length;
+
+ REQUIRE(apl != NULL);
REQUIRE(apl->common.rdtype == 42);
REQUIRE(apl->common.rdclass == 1);
REQUIRE(apl->apl != NULL || apl->apl_len == 0);
- if (apl->offset + 3 < apl->apl_len)
+ /*
+ * No APL or have already reached the end return ISC_R_NOMORE.
+ */
+ if (apl->apl == NULL || apl->offset == apl->apl_len)
return (ISC_R_NOMORE);
+
+ /*
+ * Sanity check data.
+ */
+ INSIST(apl->offset < apl->apl_len);
+ INSIST(apl->apl_len > 3U);
+ INSIST(apl->offset <= apl->apl_len - 4U);
+ length = apl->apl[apl->offset + 3] & 0x7f;
+ /*
+ * 16 to 32 bits promotion as 'length' is 32 bits so there is
+ * no overflow problems.
+ */
+ INSIST(length + apl->offset <= apl->apl_len);
+
apl->offset += apl->apl[apl->offset + 3] & 0x7f;
return ((apl->offset >= apl->apl_len) ? ISC_R_SUCCESS : ISC_R_NOMORE);
}
isc_result_t
dns_rdata_apl_current(dns_rdata_in_apl_t *apl, dns_rdata_apl_ent_t *ent) {
+ isc_uint32_t length;
+ REQUIRE(apl != NULL);
REQUIRE(apl->common.rdtype == 42);
REQUIRE(apl->common.rdclass == 1);
REQUIRE(ent != NULL);
REQUIRE(apl->apl != NULL || apl->apl_len == 0);
+ REQUIRE(apl->offset <= apl->apl_len);
- if (apl->offset >= apl->apl_len)
+ if (apl->offset == apl->apl_len)
return (ISC_R_NOMORE);
+ /*
+ * Sanity check data.
+ */
+ INSIST(apl->apl_len > 3U);
+ INSIST(apl->offset <= apl->apl_len - 4U);
+ length = apl->apl[apl->offset + 3] & 0x7f;
+ /*
+ * 16 to 32 bits promotion as 'length' is 32 bits so there is
+ * no overflow problems.
+ */
+ INSIST(length + apl->offset <= apl->apl_len);
+
ent->family = (apl->apl[apl->offset] << 8) + apl->apl[apl->offset + 1];
ent->prefix = apl->apl[apl->offset + 2];
ent->length = apl->apl[apl->offset + 3] & 0x7f;
diff --git a/lib/dns/rdata/in_1/naptr_35.c b/lib/dns/rdata/in_1/naptr_35.c
index 0e5961a..9a880ea 100644
--- a/lib/dns/rdata/in_1/naptr_35.c
+++ b/lib/dns/rdata/in_1/naptr_35.c
@@ -1,8 +1,8 @@
/*
- * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2001, 2003 Internet Software Consortium.
*
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: naptr_35.c,v 1.47.18.2 2005/04/29 00:16:42 marka Exp $ */
+/* $Id: naptr_35.c,v 1.47.18.4 2008/02/15 23:45:53 tbox Exp $ */
/* Reviewed: Thu Mar 16 16:52:50 PST 2000 by bwelling */
@@ -154,7 +154,7 @@ totext_in_naptr(ARGS_TOTEXT) {
static inline isc_result_t
fromwire_in_naptr(ARGS_FROMWIRE) {
- dns_name_t name;
+ dns_name_t name;
isc_region_t sr;
REQUIRE(type == 35);
@@ -165,7 +165,7 @@ fromwire_in_naptr(ARGS_FROMWIRE) {
dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
- dns_name_init(&name, NULL);
+ dns_name_init(&name, NULL);
/*
* Order, preference.
@@ -321,8 +321,8 @@ fromstruct_in_naptr(ARGS_FROMSTRUCT) {
REQUIRE(naptr->common.rdtype == type);
REQUIRE(naptr->common.rdclass == rdclass);
REQUIRE(naptr->flags != NULL || naptr->flags_len == 0);
- REQUIRE(naptr->service != NULL && naptr->service_len == 0);
- REQUIRE(naptr->regexp != NULL && naptr->regexp_len == 0);
+ REQUIRE(naptr->service != NULL || naptr->service_len == 0);
+ REQUIRE(naptr->regexp != NULL || naptr->regexp_len == 0);
UNUSED(type);
UNUSED(rdclass);
diff --git a/lib/dns/request.c b/lib/dns/request.c
index c0348fe..64a3a4e 100644
--- a/lib/dns/request.c
+++ b/lib/dns/request.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: request.c,v 1.72.18.5.42.2 2008/07/23 07:28:56 tbox Exp $ */
+/* $Id: request.c,v 1.72.18.8 2008/07/22 03:51:44 marka Exp $ */
/*! \file */
@@ -121,6 +121,7 @@ static isc_result_t req_render(dns_message_t *message, isc_buffer_t **buffer,
static void req_senddone(isc_task_t *task, isc_event_t *event);
static void req_response(isc_task_t *task, isc_event_t *event);
static void req_timeout(isc_task_t *task, isc_event_t *event);
+static isc_socket_t * req_getsocket(dns_request_t *request);
static void req_connected(isc_task_t *task, isc_event_t *event);
static void req_sendevent(dns_request_t *request, isc_result_t result);
static void req_cancel(dns_request_t *request);
@@ -146,6 +147,7 @@ dns_requestmgr_create(isc_mem_t *mctx,
isc_socket_t *socket;
isc_result_t result;
int i;
+ unsigned int dispattr;
req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create");
@@ -154,13 +156,14 @@ dns_requestmgr_create(isc_mem_t *mctx,
REQUIRE(socketmgr != NULL);
REQUIRE(taskmgr != NULL);
REQUIRE(dispatchmgr != NULL);
+ UNUSED(socket);
if (dispatchv4 != NULL) {
- socket = dns_dispatch_getsocket(dispatchv4);
- REQUIRE(isc_socket_gettype(socket) == isc_sockettype_udp);
+ dispattr = dns_dispatch_getattributes(dispatchv4);
+ REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
}
if (dispatchv6 != NULL) {
- socket = dns_dispatch_getsocket(dispatchv6);
- REQUIRE(isc_socket_gettype(socket) == isc_sockettype_udp);
+ dispattr = dns_dispatch_getattributes(dispatchv6);
+ REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
}
requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
@@ -425,12 +428,19 @@ req_send(dns_request_t *request, isc_task_t *task, isc_sockaddr_t *address) {
isc_region_t r;
isc_socket_t *socket;
isc_result_t result;
+ unsigned int dispattr;
req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request);
REQUIRE(VALID_REQUEST(request));
- socket = dns_dispatch_getsocket(request->dispatch);
+ dispattr = dns_dispatch_getattributes(request->dispatch);
+ socket = req_getsocket(request);
isc_buffer_usedregion(request->query, &r);
+ /*
+ * We could connect the socket when we are using an exclusive dispatch
+ * as we do in resolver.c, but we prefer implementation simplicity
+ * at this moment.
+ */
result = isc_socket_sendto(socket, &r, task, req_senddone,
request, address, NULL);
if (result == ISC_R_SUCCESS)
@@ -685,7 +695,7 @@ dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
REQUIRE(action != NULL);
REQUIRE(requestp != NULL && *requestp == NULL);
REQUIRE(timeout > 0);
- if (srcaddr != NULL)
+ if (srcaddr != NULL)
REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
mctx = requestmgr->mctx;
@@ -733,7 +743,7 @@ dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
result = DNS_R_FORMERR;
goto cleanup;
}
-
+
if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512)
tcp = ISC_TRUE;
@@ -742,14 +752,16 @@ dns_request_createraw3(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
if (result != ISC_R_SUCCESS)
goto cleanup;
- socket = dns_dispatch_getsocket(request->dispatch);
- INSIST(socket != NULL);
- result = dns_dispatch_addresponse(request->dispatch, destaddr, task,
- req_response, request, &id,
- &request->dispentry);
+ result = dns_dispatch_addresponse2(request->dispatch, destaddr, task,
+ req_response, request, &id,
+ &request->dispentry,
+ requestmgr->socketmgr);
if (result != ISC_R_SUCCESS)
goto cleanup;
+ socket = req_getsocket(request);
+ INSIST(socket != NULL);
+
result = isc_buffer_allocate(mctx, &request->query,
r.length + (tcp ? 2 : 0));
if (result != ISC_R_SUCCESS)
@@ -857,7 +869,7 @@ dns_request_createvia2(dns_requestmgr_t *requestmgr, dns_message_t *message,
udpretries, task, action, arg,
requestp));
}
-
+
isc_result_t
dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message,
isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
@@ -883,7 +895,7 @@ dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message,
REQUIRE(action != NULL);
REQUIRE(requestp != NULL && *requestp == NULL);
REQUIRE(timeout > 0);
- if (srcaddr != NULL)
+ if (srcaddr != NULL)
REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
mctx = requestmgr->mctx;
@@ -935,13 +947,14 @@ dns_request_createvia3(dns_requestmgr_t *requestmgr, dns_message_t *message,
if (result != ISC_R_SUCCESS)
goto cleanup;
- socket = dns_dispatch_getsocket(request->dispatch);
- INSIST(socket != NULL);
- result = dns_dispatch_addresponse(request->dispatch, destaddr, task,
- req_response, request, &id,
- &request->dispentry);
+ result = dns_dispatch_addresponse2(request->dispatch, destaddr, task,
+ req_response, request, &id,
+ &request->dispentry,
+ requestmgr->socketmgr);
if (result != ISC_R_SUCCESS)
goto cleanup;
+ socket = req_getsocket(request);
+ INSIST(socket != NULL);
message->id = id;
if (setkey) {
@@ -1137,7 +1150,7 @@ do_cancel(isc_task_t *task, isc_event_t *event) {
if (!DNS_REQUEST_CANCELED(request))
req_cancel(request);
send_if_done(request, ISC_R_CANCELED);
- UNLOCK(&request->requestmgr->locks[request->hash]);
+ UNLOCK(&request->requestmgr->locks[request->hash]);
}
void
@@ -1226,6 +1239,21 @@ dns_request_destroy(dns_request_t **requestp) {
*** Private: request.
***/
+static isc_socket_t *
+req_getsocket(dns_request_t *request) {
+ unsigned int dispattr;
+ isc_socket_t *socket;
+
+ dispattr = dns_dispatch_getattributes(request->dispatch);
+ if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
+ INSIST(request->dispentry != NULL);
+ socket = dns_dispatch_getentrysocket(request->dispentry);
+ } else
+ socket = dns_dispatch_getsocket(request->dispatch);
+
+ return (socket);
+}
+
static void
req_connected(isc_task_t *task, isc_event_t *event) {
isc_socketevent_t *sevent = (isc_socketevent_t *)event;
@@ -1425,6 +1453,7 @@ req_destroy(dns_request_t *request) {
static void
req_cancel(dns_request_t *request) {
isc_socket_t *socket;
+ unsigned int dispattr;
REQUIRE(VALID_REQUEST(request));
@@ -1437,16 +1466,23 @@ req_cancel(dns_request_t *request) {
if (request->timer != NULL)
isc_timer_detach(&request->timer);
+ dispattr = dns_dispatch_getattributes(request->dispatch);
+ socket = NULL;
+ if (DNS_REQUEST_CONNECTING(request) || DNS_REQUEST_SENDING(request)) {
+ if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
+ if (request->dispentry != NULL) {
+ socket = dns_dispatch_getentrysocket(
+ request->dispentry);
+ }
+ } else
+ socket = dns_dispatch_getsocket(request->dispatch);
+ if (DNS_REQUEST_CONNECTING(request) && socket != NULL)
+ isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_CONNECT);
+ if (DNS_REQUEST_SENDING(request) && socket != NULL)
+ isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_SEND);
+ }
if (request->dispentry != NULL)
dns_dispatch_removeresponse(&request->dispentry, NULL);
- if (DNS_REQUEST_CONNECTING(request)) {
- socket = dns_dispatch_getsocket(request->dispatch);
- isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_CONNECT);
- }
- if (DNS_REQUEST_SENDING(request)) {
- socket = dns_dispatch_getsocket(request->dispatch);
- isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_SEND);
- }
dns_dispatch_detach(&request->dispatch);
}
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
index cdf5788..dc648c9 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: resolver.c,v 1.284.18.66.8.4 2008/07/24 05:00:48 jinmei Exp $ */
+/* $Id: resolver.c,v 1.284.18.79 2008/10/17 22:02:13 jinmei Exp $ */
/*! \file */
@@ -121,6 +121,7 @@ typedef struct query {
isc_mem_t * mctx;
dns_dispatchmgr_t * dispatchmgr;
dns_dispatch_t * dispatch;
+ isc_boolean_t exclusivesocket;
dns_adbaddrinfo_t * addrinfo;
isc_socket_t * tcpsocket;
isc_time_t start;
@@ -213,7 +214,7 @@ struct fetchctx {
unsigned int restarts;
/*%
- * The number of timeouts that have occurred since we
+ * The number of timeouts that have occurred since we
* last successfully received a response packet. This
* is used for EDNS0 black hole detection.
*/
@@ -221,7 +222,7 @@ struct fetchctx {
/*%
* Look aside state for DS lookups.
*/
- dns_name_t nsname;
+ dns_name_t nsname;
dns_fetch_t * nsfetch;
dns_rdataset_t nsrrset;
@@ -296,8 +297,8 @@ struct dns_resolver {
unsigned int magic;
isc_mem_t * mctx;
isc_mutex_t lock;
- isc_mutex_t nlock;
- isc_mutex_t primelock;
+ isc_mutex_t nlock;
+ isc_mutex_t primelock;
dns_rdataclass_t rdclass;
isc_socketmgr_t * socketmgr;
isc_timermgr_t * timermgr;
@@ -307,7 +308,9 @@ struct dns_resolver {
unsigned int options;
dns_dispatchmgr_t * dispatchmgr;
dns_dispatch_t * dispatchv4;
+ isc_boolean_t exclusivev4;
dns_dispatch_t * dispatchv6;
+ isc_boolean_t exclusivev6;
unsigned int nbuckets;
fctxbucket_t * buckets;
isc_uint32_t lame_ttl;
@@ -331,7 +334,7 @@ struct dns_resolver {
isc_eventlist_t whenshutdown;
unsigned int activebuckets;
isc_boolean_t priming;
- unsigned int spillat;
+ unsigned int spillat; /* clients-per-query */
/* Locked by primelock. */
dns_fetch_t * primefetch;
/* Locked by nlock. */
@@ -369,8 +372,10 @@ static isc_result_t ncache_adderesult(dns_message_t *message,
isc_stdtime_t now, dns_ttl_t maxttl,
dns_rdataset_t *ardataset,
isc_result_t *eresultp);
-static void validated(isc_task_t *task, isc_event_t *event);
+static void validated(isc_task_t *task, isc_event_t *event);
static void maybe_destroy(fetchctx_t *fctx);
+static void add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
+ isc_result_t reason);
static isc_result_t
valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name,
@@ -562,6 +567,7 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
unsigned int factor;
dns_adbfind_t *find;
dns_adbaddrinfo_t *addrinfo;
+ isc_socket_t *socket;
query = *queryp;
fctx = query->fctx;
@@ -643,35 +649,48 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
0, factor);
}
- if (query->dispentry != NULL)
- dns_dispatch_removeresponse(&query->dispentry, deventp);
-
- ISC_LIST_UNLINK(fctx->queries, query, link);
-
- if (query->tsig != NULL)
- isc_buffer_free(&query->tsig);
-
- if (query->tsigkey != NULL)
- dns_tsigkey_detach(&query->tsigkey);
-
/*
* Check for any outstanding socket events. If they exist, cancel
* them and let the event handlers finish the cleanup. The resolver
* only needs to worry about managing the connect and send events;
* the dispatcher manages the recv events.
*/
- if (RESQUERY_CONNECTING(query))
+ if (RESQUERY_CONNECTING(query)) {
/*
* Cancel the connect.
*/
- isc_socket_cancel(query->tcpsocket, NULL,
- ISC_SOCKCANCEL_CONNECT);
- else if (RESQUERY_SENDING(query))
+ if (query->tcpsocket != NULL) {
+ isc_socket_cancel(query->tcpsocket, NULL,
+ ISC_SOCKCANCEL_CONNECT);
+ } else if (query->dispentry != NULL) {
+ INSIST(query->exclusivesocket);
+ socket = dns_dispatch_getentrysocket(query->dispentry);
+ if (socket != NULL)
+ isc_socket_cancel(socket, NULL,
+ ISC_SOCKCANCEL_CONNECT);
+ }
+ } else if (RESQUERY_SENDING(query)) {
/*
* Cancel the pending send.
*/
- isc_socket_cancel(dns_dispatch_getsocket(query->dispatch),
- NULL, ISC_SOCKCANCEL_SEND);
+ if (query->exclusivesocket && query->dispentry != NULL)
+ socket = dns_dispatch_getentrysocket(query->dispentry);
+ else
+ socket = dns_dispatch_getsocket(query->dispatch);
+ if (socket != NULL)
+ isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_SEND);
+ }
+
+ if (query->dispentry != NULL)
+ dns_dispatch_removeresponse(&query->dispentry, deventp);
+
+ ISC_LIST_UNLINK(fctx->queries, query, link);
+
+ if (query->tsig != NULL)
+ isc_buffer_free(&query->tsig);
+
+ if (query->tsigkey != NULL)
+ dns_tsigkey_detach(&query->tsigkey);
if (query->dispatch != NULL)
dns_dispatch_detach(&query->dispatch);
@@ -777,6 +796,8 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result) {
unsigned int count = 0;
isc_interval_t i;
isc_boolean_t logit = ISC_FALSE;
+ unsigned int old_spillat;
+ unsigned int new_spillat = 0; /* initialized to silence compiler warnings */
/*
* Caller must be holding the appropriate bucket lock.
@@ -800,7 +821,7 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result) {
fctx->type == dns_rdatatype_any ||
fctx->type == dns_rdatatype_rrsig ||
fctx->type == dns_rdatatype_sig);
-
+
/*
* Negative results must be indicated in event->result.
*/
@@ -819,11 +840,15 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result) {
(count < fctx->res->spillatmax || fctx->res->spillatmax == 0)) {
LOCK(&fctx->res->lock);
if (count == fctx->res->spillat && !fctx->res->exiting) {
+ old_spillat = fctx->res->spillat;
fctx->res->spillat += 5;
if (fctx->res->spillat > fctx->res->spillatmax &&
fctx->res->spillatmax != 0)
fctx->res->spillat = fctx->res->spillatmax;
- logit = ISC_TRUE;
+ new_spillat = fctx->res->spillat;
+ if (new_spillat != old_spillat) {
+ logit = ISC_TRUE;
+ }
isc_interval_set(&i, 20 * 60, 0);
result = isc_timer_reset(fctx->res->spillattimer,
isc_timertype_ticker, NULL,
@@ -835,7 +860,7 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
"clients-per-query increased to %u",
- count + 1);
+ new_spillat);
}
}
@@ -864,43 +889,25 @@ fctx_done(fetchctx_t *fctx, isc_result_t result) {
}
static void
-resquery_senddone(isc_task_t *task, isc_event_t *event) {
+process_sendevent(resquery_t *query, isc_event_t *event) {
isc_socketevent_t *sevent = (isc_socketevent_t *)event;
- resquery_t *query = event->ev_arg;
isc_boolean_t retry = ISC_FALSE;
isc_result_t result;
fetchctx_t *fctx;
- REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
-
- QTRACE("senddone");
-
- /*
- * XXXRTH
- *
- * Currently we don't wait for the senddone event before retrying
- * a query. This means that if we get really behind, we may end
- * up doing extra work!
- */
-
- UNUSED(task);
-
- INSIST(RESQUERY_SENDING(query));
-
- query->sends--;
fctx = query->fctx;
if (RESQUERY_CANCELED(query)) {
- if (query->sends == 0) {
+ if (query->sends == 0 && query->connects == 0) {
/*
* This query was canceled while the
- * isc_socket_sendto() was in progress.
+ * isc_socket_sendto/connect() was in progress.
*/
if (query->tcpsocket != NULL)
isc_socket_detach(&query->tcpsocket);
resquery_destroy(&query);
}
- } else
+ } else {
switch (sevent->result) {
case ISC_R_SUCCESS:
break;
@@ -914,6 +921,7 @@ resquery_senddone(isc_task_t *task, isc_event_t *event) {
/*
* No route to remote.
*/
+ add_bad(fctx, query->addrinfo, sevent->result);
fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
retry = ISC_TRUE;
break;
@@ -922,6 +930,7 @@ resquery_senddone(isc_task_t *task, isc_event_t *event) {
fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
break;
}
+ }
isc_event_free(&event);
@@ -939,9 +948,51 @@ resquery_senddone(isc_task_t *task, isc_event_t *event) {
}
}
+static void
+resquery_udpconnected(isc_task_t *task, isc_event_t *event) {
+ resquery_t *query = event->ev_arg;
+
+ REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
+
+ QTRACE("udpconnected");
+
+ UNUSED(task);
+
+ INSIST(RESQUERY_CONNECTING(query));
+
+ query->connects--;
+
+ process_sendevent(query, event);
+}
+
+static void
+resquery_senddone(isc_task_t *task, isc_event_t *event) {
+ resquery_t *query = event->ev_arg;
+
+ REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
+
+ QTRACE("senddone");
+
+ /*
+ * XXXRTH
+ *
+ * Currently we don't wait for the senddone event before retrying
+ * a query. This means that if we get really behind, we may end
+ * up doing extra work!
+ */
+
+ UNUSED(task);
+
+ INSIST(RESQUERY_SENDING(query));
+
+ query->sends--;
+
+ process_sendevent(query, event);
+}
+
static inline isc_result_t
fctx_addopt(dns_message_t *message, unsigned int version, isc_uint16_t udpsize)
-{
+{
dns_rdataset_t *rdataset;
dns_rdatalist_t *rdatalist;
dns_rdata_t *rdata;
@@ -1001,9 +1052,9 @@ fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) {
* list, and then we do exponential back-off.
*/
if (fctx->restarts < 3)
- us = 500000;
+ us = 800000;
else
- us = (500000 << (fctx->restarts - 2));
+ us = (800000 << (fctx->restarts - 2));
/*
* Double the round-trip time.
@@ -1077,6 +1128,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
*/
query->dispatchmgr = res->dispatchmgr;
query->dispatch = NULL;
+ query->exclusivesocket = ISC_FALSE;
query->tcpsocket = NULL;
if (res->view->peers != NULL) {
dns_peer_t *peer = NULL;
@@ -1159,53 +1211,21 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
if (result != ISC_R_SUCCESS)
goto cleanup_query;
} 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 AF_INET:
- disp_base = res->dispatchv4;
- attrs |= DNS_DISPATCHATTR_IPV4;
+ case PF_INET:
+ dns_dispatch_attach(res->dispatchv4,
+ &query->dispatch);
+ query->exclusivesocket = res->exclusivev4;
break;
- case AF_INET6:
- disp_base = res->dispatchv6;
- attrs |= DNS_DISPATCHATTR_IPV6;
+ case PF_INET6:
+ dns_dispatch_attach(res->dispatchv6,
+ &query->dispatch);
+ query->exclusivesocket = res->exclusivev6;
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
@@ -1378,13 +1398,14 @@ resquery_send(resquery_t *query) {
/*
* Get a query id from the dispatch.
*/
- result = dns_dispatch_addresponse(query->dispatch,
- &query->addrinfo->sockaddr,
- task,
- resquery_response,
- query,
- &query->id,
- &query->dispentry);
+ result = dns_dispatch_addresponse2(query->dispatch,
+ &query->addrinfo->sockaddr,
+ task,
+ resquery_response,
+ query,
+ &query->id,
+ &query->dispentry,
+ res->socketmgr);
if (result != ISC_R_SUCCESS)
goto cleanup_temps;
@@ -1593,12 +1614,24 @@ resquery_send(resquery_t *query) {
*/
dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
- socket = dns_dispatch_getsocket(query->dispatch);
+ if (query->exclusivesocket)
+ socket = dns_dispatch_getentrysocket(query->dispentry);
+ else
+ socket = dns_dispatch_getsocket(query->dispatch);
/*
* Send the query!
*/
- if ((query->options & DNS_FETCHOPT_TCP) == 0)
+ if ((query->options & DNS_FETCHOPT_TCP) == 0) {
address = &query->addrinfo->sockaddr;
+ if (query->exclusivesocket) {
+ result = isc_socket_connect(socket, address, task,
+ resquery_udpconnected,
+ query);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_message;
+ query->connects++;
+ }
+ }
isc_buffer_usedregion(buffer, &r);
/*
@@ -1731,7 +1764,7 @@ resquery_connected(isc_task_t *task, isc_event_t *event) {
}
isc_event_free(&event);
-
+
if (retry) {
/*
* Behave as if the idle timer has expired. For TCP
@@ -1921,8 +1954,8 @@ add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason) {
if (reason == DNS_R_LAME) /* already logged */
return;
- if (reason == DNS_R_UNEXPECTEDRCODE &&
- fctx->rmessage->opcode == dns_rcode_servfail &&
+ if (reason == DNS_R_UNEXPECTEDRCODE &&
+ fctx->rmessage->rcode == dns_rcode_servfail &&
ISFORWARDER(addrinfo))
return;
@@ -2196,6 +2229,13 @@ fctx_getaddresses(fetchctx_t *fctx) {
}
while (sa != NULL) {
+ if ((isc_sockaddr_pf(sa) == AF_INET &&
+ fctx->res->dispatchv4 == NULL) ||
+ (isc_sockaddr_pf(sa) == AF_INET6 &&
+ fctx->res->dispatchv6 == NULL)) {
+ sa = ISC_LIST_NEXT(sa, link);
+ continue;
+ }
ai = NULL;
result = dns_adb_findaddrinfo(fctx->adb,
sa, &ai, 0); /* XXXMLG */
@@ -2366,7 +2406,7 @@ possibly_mark(fetchctx_t *fctx, dns_adbaddrinfo_t *addr)
isc_netaddr_fromsockaddr(&ipaddr, sa);
blackhole = dns_dispatchmgr_getblackhole(res->dispatchmgr);
(void) dns_peerlist_peerbyaddr(res->view->peers, &ipaddr, &peer);
-
+
if (blackhole != NULL) {
int match;
@@ -2799,7 +2839,7 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) {
dns_validator_cancel(validator);
validator = ISC_LIST_NEXT(validator, link);
}
-
+
if (fctx->nsfetch != NULL)
dns_resolver_cancelfetch(fctx->nsfetch);
@@ -3252,9 +3292,9 @@ is_lame(fetchctx_t *fctx) {
static inline void
log_lame(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo) {
char namebuf[DNS_NAME_FORMATSIZE];
- char domainbuf[DNS_NAME_FORMATSIZE];
+ char domainbuf[DNS_NAME_FORMATSIZE];
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
-
+
dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
isc_sockaddr_format(&addrinfo->sockaddr, addrbuf, sizeof(addrbuf));
@@ -3822,9 +3862,9 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
sizeof(typebuf));
dns_rdataclass_format(rdataset->rdclass, classbuf,
sizeof(classbuf));
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
- "check-names %s %s/%s/%s",
+ "check-names %s %s/%s/%s",
fail ? "failure" : "warning",
namebuf, typebuf, classbuf);
if (fail) {
@@ -4411,7 +4451,7 @@ chase_additional(fetchctx_t *fctx) {
again:
rescan = ISC_FALSE;
-
+
for (result = dns_message_firstname(fctx->rmessage, section);
result == ISC_R_SUCCESS;
result = dns_message_nextname(fctx->rmessage, section)) {
@@ -4491,7 +4531,7 @@ dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, dns_name_t *oname,
return (DNS_R_FORMERR);
}
dns_fixedname_init(&prefix);
- dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL);
+ dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL);
dns_fixedname_init(fixeddname);
result = dns_name_concatenate(dns_fixedname_name(&prefix),
&dname.dname,
@@ -4650,7 +4690,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
}
/*
- * A negative response has a SOA record (Type 2)
+ * A negative response has a SOA record (Type 2)
* and a optional NS RRset (Type 1) or it has neither
* a SOA or a NS RRset (Type 3, handled above) or
* rcode is NXDOMAIN (handled above) in which case
@@ -5363,7 +5403,7 @@ checknamessection(dns_message_t *message, dns_section_t section) {
dns_name_t *name;
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdataset_t *rdataset;
-
+
for (result = dns_message_firstname(message, section);
result == ISC_R_SUCCESS;
result = dns_message_nextname(message, section))
@@ -5382,7 +5422,7 @@ checknamessection(dns_message_t *message, dns_section_t section) {
ISC_FALSE) ||
!dns_rdata_checknames(&rdata, name, NULL))
{
- rdataset->attributes |=
+ rdataset->attributes |=
DNS_RDATASETATTR_CHECKNAMES;
}
dns_rdata_reset(&rdata);
@@ -5512,6 +5552,19 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
* There's no hope for this query.
*/
keep_trying = ISC_TRUE;
+
+ /*
+ * If this is a network error on an exclusive query
+ * socket, mark the server as bad so that we won't try
+ * it for this fetch again.
+ */
+ if (query->exclusivesocket &&
+ (devent->result == ISC_R_HOSTUNREACH ||
+ devent->result == ISC_R_NETUNREACH ||
+ devent->result == ISC_R_CONNREFUSED ||
+ devent->result == ISC_R_CANCELED)) {
+ broken_server = devent->result;
+ }
}
goto done;
}
@@ -5662,12 +5715,17 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
*/
if (message->rcode != dns_rcode_noerror &&
message->rcode != dns_rcode_nxdomain) {
- if ((message->rcode == dns_rcode_formerr ||
- message->rcode == dns_rcode_notimp ||
- message->rcode == dns_rcode_servfail) &&
+ if (((message->rcode == dns_rcode_formerr ||
+ message->rcode == dns_rcode_notimp) ||
+ (message->rcode == dns_rcode_servfail &&
+ dns_message_getopt(message) == NULL)) &&
(query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
/*
* It's very likely they don't like EDNS0.
+ * If the response code is SERVFAIL, also check if the
+ * response contains an OPT RR and don't cache the
+ * failure since it can be returned for various other
+ * reasons.
*
* XXXRTH We should check if the question
* we're asking requires EDNS0, and
@@ -6154,7 +6212,7 @@ spillattimer_countdown(isc_task_t *task, isc_event_t *event) {
REQUIRE(VALID_RESOLVER(res));
UNUSED(task);
-
+
LOCK(&res->lock);
INSIST(!res->exiting);
if (res->spillat > res->spillatmin) {
@@ -6181,7 +6239,7 @@ isc_result_t
dns_resolver_create(dns_view_t *view,
isc_taskmgr_t *taskmgr, unsigned int ntasks,
isc_socketmgr_t *socketmgr,
- isc_timermgr_t *timermgr,
+ isc_timermgr_t *timermgr,
unsigned int options,
dns_dispatchmgr_t *dispatchmgr,
dns_dispatch_t *dispatchv4,
@@ -6193,6 +6251,7 @@ dns_resolver_create(dns_view_t *view,
unsigned int i, buckets_created = 0;
isc_task_t *task = NULL;
char name[16];
+ unsigned dispattr;
/*
* Create a resolver.
@@ -6259,11 +6318,20 @@ dns_resolver_create(dns_view_t *view,
}
res->dispatchv4 = NULL;
- if (dispatchv4 != NULL)
+ if (dispatchv4 != NULL) {
dns_dispatch_attach(dispatchv4, &res->dispatchv4);
+ dispattr = dns_dispatch_getattributes(dispatchv4);
+ res->exclusivev4 =
+ ISC_TF((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0);
+ }
+
res->dispatchv6 = NULL;
- if (dispatchv6 != NULL)
+ if (dispatchv6 != NULL) {
dns_dispatch_attach(dispatchv6, &res->dispatchv6);
+ dispattr = dns_dispatch_getattributes(dispatchv6);
+ res->exclusivev6 =
+ ISC_TF((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0);
+ }
res->references = 1;
res->exiting = ISC_FALSE;
@@ -6380,7 +6448,7 @@ prime_done(isc_task_t *task, isc_event_t *event) {
UNLOCK(&res->primelock);
UNLOCK(&res->lock);
-
+
if (fevent->result == ISC_R_SUCCESS &&
res->view->cache != NULL && res->view->hints != NULL) {
dns_cache_attachdb(res->view->cache, &db);
@@ -6546,12 +6614,12 @@ dns_resolver_shutdown(dns_resolver_t *res) {
fctx != NULL;
fctx = ISC_LIST_NEXT(fctx, link))
fctx_shutdown(fctx);
- if (res->dispatchv4 != NULL) {
+ if (res->dispatchv4 != NULL && !res->exclusivev4) {
sock = dns_dispatch_getsocket(res->dispatchv4);
isc_socket_cancel(sock, res->buckets[i].task,
ISC_SOCKCANCEL_ALL);
}
- if (res->dispatchv6 != NULL) {
+ if (res->dispatchv6 != NULL && !res->exclusivev6) {
sock = dns_dispatch_getsocket(res->dispatchv6);
isc_socket_cancel(sock, res->buckets[i].task,
ISC_SOCKCANCEL_ALL);
@@ -6665,6 +6733,7 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
isc_event_t *event;
unsigned int count = 0;
unsigned int spillat;
+ unsigned int spillatmin;
UNUSED(forwarders);
@@ -6695,6 +6764,7 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
LOCK(&res->lock);
spillat = res->spillat;
+ spillatmin = res->spillatmin;
UNLOCK(&res->lock);
LOCK(&res->buckets[bucketnum].lock);
@@ -6711,7 +6781,7 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
break;
}
}
-
+
/*
* Is this a duplicate?
*/
@@ -6728,7 +6798,8 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
count++;
}
}
- if (count >= res->spillatmin && res->spillatmin != 0) {
+ if (count >= spillatmin && spillatmin != 0) {
+ INSIST(fctx != NULL);
if (count >= spillat)
fctx->spilled = ISC_TRUE;
if (fctx->spilled) {
@@ -7004,7 +7075,7 @@ free_algorithm(void *node, void *arg) {
isc_mem_put(mctx, algorithms, *algorithms);
}
-
+
void
dns_resolver_reset_algorithms(dns_resolver_t *resolver) {
@@ -7048,7 +7119,7 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name,
mask = 1 << (alg%8);
result = dns_rbt_addnode(resolver->algorithms, name, &node);
-
+
if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) {
algorithms = node->data;
if (algorithms == NULL || len > *algorithms) {
@@ -7064,7 +7135,7 @@ dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name,
*new = len;
node->data = new;
if (algorithms != NULL)
- isc_mem_put(resolver->mctx, algorithms,
+ isc_mem_put(resolver->mctx, algorithms,
*algorithms);
} else
algorithms[len-1] |= mask;
@@ -7132,7 +7203,7 @@ dns_resolver_resetmustbesecure(dns_resolver_t *resolver) {
RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write);
#endif
}
-
+
static isc_boolean_t yes = ISC_TRUE, no = ISC_FALSE;
isc_result_t
@@ -7152,7 +7223,7 @@ dns_resolver_setmustbesecure(dns_resolver_t *resolver, dns_name_t *name,
if (result != ISC_R_SUCCESS)
goto cleanup;
}
- result = dns_rbt_addname(resolver->mustbesecure, name,
+ result = dns_rbt_addname(resolver->mustbesecure, name,
value ? &yes : &no);
cleanup:
#if USE_MBSLOCK
diff --git a/lib/dns/rootns.c b/lib/dns/rootns.c
index f20a49d..a988bea 100644
--- a/lib/dns/rootns.c
+++ b/lib/dns/rootns.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2002 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rootns.c,v 1.26.18.5 2007/10/31 03:02:45 tbox Exp $ */
+/* $Id: rootns.c,v 1.26.18.7 2008/02/05 23:46:09 tbox Exp $ */
/*! \file */
@@ -45,8 +45,6 @@ static char root_ns[] =
";\n"
"; Internet Root Nameservers\n"
";\n"
-"; Thu Sep 23 17:57:37 PDT 1999\n"
-";\n"
"$TTL 518400\n"
". 518400 IN NS A.ROOT-SERVERS.NET.\n"
". 518400 IN NS B.ROOT-SERVERS.NET.\n"
@@ -62,25 +60,31 @@ static char root_ns[] =
". 518400 IN NS L.ROOT-SERVERS.NET.\n"
". 518400 IN NS M.ROOT-SERVERS.NET.\n"
"A.ROOT-SERVERS.NET. 3600000 IN A 198.41.0.4\n"
+"A.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:503:BA3E::2:30\n"
"B.ROOT-SERVERS.NET. 3600000 IN A 192.228.79.201\n"
"C.ROOT-SERVERS.NET. 3600000 IN A 192.33.4.12\n"
"D.ROOT-SERVERS.NET. 3600000 IN A 128.8.10.90\n"
"E.ROOT-SERVERS.NET. 3600000 IN A 192.203.230.10\n"
"F.ROOT-SERVERS.NET. 3600000 IN A 192.5.5.241\n"
+"F.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:500:2F::F\n"
"G.ROOT-SERVERS.NET. 3600000 IN A 192.112.36.4\n"
"H.ROOT-SERVERS.NET. 3600000 IN A 128.63.2.53\n"
+"H.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:500:1::803F:235\n"
"I.ROOT-SERVERS.NET. 3600000 IN A 192.36.148.17\n"
"J.ROOT-SERVERS.NET. 3600000 IN A 192.58.128.30\n"
+"J.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:503:C27::2:30\n"
"K.ROOT-SERVERS.NET. 3600000 IN A 193.0.14.129\n"
+"K.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:7FD::1\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";
+"M.ROOT-SERVERS.NET. 3600000 IN A 202.12.27.33\n"
+"M.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:DC3::35\n";
static isc_result_t
in_rootns(dns_rdataset_t *rootns, dns_name_t *name) {
isc_result_t result;
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_ns_t ns;
-
+
if (!dns_rdataset_isassociated(rootns))
return (ISC_R_NOTFOUND);
@@ -99,7 +103,7 @@ in_rootns(dns_rdataset_t *rootns, dns_name_t *name) {
return (result);
}
-static isc_result_t
+static isc_result_t
check_node(dns_rdataset_t *rootns, dns_name_t *name,
dns_rdatasetiter_t *rdsiter) {
isc_result_t result;
@@ -227,7 +231,7 @@ dns_rootns_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
* Default to using the Internet root servers.
*/
result = dns_master_loadbuffer(&source, &db->origin,
- &db->origin, db->rdclass,
+ &db->origin, db->rdclass,
DNS_MASTER_HINT,
&callbacks, db->mctx);
} else
@@ -262,11 +266,11 @@ report(dns_view_t *view, dns_name_t *name, isc_boolean_t missing,
isc_buffer_t buffer;
isc_result_t result;
- if (strcmp(view->name, "_bind") != 0 &&
- strcmp(view->name, "_default") != 0) {
- viewname = view->name;
- sep = ": view ";
- }
+ if (strcmp(view->name, "_bind") != 0 &&
+ strcmp(view->name, "_default") != 0) {
+ viewname = view->name;
+ sep = ": view ";
+ }
dns_name_format(name, namebuf, sizeof(namebuf));
dns_rdatatype_format(rdata->type, typebuf, sizeof(typebuf));
@@ -346,7 +350,7 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db,
report(view, name, ISC_FALSE, &rdata);
result = dns_rdataset_next(&hintrrset);
}
- }
+ }
if (hresult == ISC_R_NOTFOUND &&
(rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
result = dns_rdataset_first(&rootrrset);
@@ -387,7 +391,7 @@ check_address_records(dns_view_t *view, dns_db_t *hints, dns_db_t *db,
dns_rdata_reset(&rdata);
result = dns_rdataset_next(&hintrrset);
}
- }
+ }
if (hresult == ISC_R_NOTFOUND &&
(rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
result = dns_rdataset_first(&rootrrset);
@@ -421,11 +425,11 @@ dns_root_checkhints(dns_view_t *view, dns_db_t *hints, dns_db_t *db) {
isc_stdtime_get(&now);
- if (strcmp(view->name, "_bind") != 0 &&
- strcmp(view->name, "_default") != 0) {
- viewname = view->name;
- sep = ": view ";
- }
+ if (strcmp(view->name, "_bind") != 0 &&
+ strcmp(view->name, "_default") != 0) {
+ viewname = view->name;
+ sep = ": view ";
+ }
dns_rdataset_init(&hintns);
dns_rdataset_init(&rootns);
@@ -453,7 +457,7 @@ dns_root_checkhints(dns_view_t *view, dns_db_t *hints, dns_db_t *db) {
dns_result_totext(result));
goto cleanup;
}
-
+
/*
* Look for missing root NS names.
*/
@@ -472,7 +476,7 @@ dns_root_checkhints(dns_view_t *view, dns_db_t *hints, dns_db_t *db) {
"checkhints%s%s: unable to find root "
"NS '%s' in hints", sep, viewname,
namebuf);
- } else
+ } else
check_address_records(view, hints, db, &ns.name, now);
dns_rdata_reset(&rdata);
result = dns_rdataset_next(&rootns);
diff --git a/lib/dns/sdb.c b/lib/dns/sdb.c
index fe53778..effb2bf 100644
--- a/lib/dns/sdb.c
+++ b/lib/dns/sdb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: sdb.c,v 1.45.18.13 2007/08/28 07:20:05 tbox Exp $ */
+/* $Id: sdb.c,v 1.45.18.16 2008/01/17 23:45:58 tbox Exp $ */
/*! \file */
@@ -310,7 +310,7 @@ dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval, dns_ttl_t ttl
ISC_LIST_INIT(rdatalist->rdata);
ISC_LINK_INIT(rdatalist, link);
ISC_LIST_APPEND(lookup->lists, rdatalist, link);
- } else
+ } else
if (rdatalist->ttl != ttl)
return (DNS_R_BADTTL);
@@ -337,7 +337,7 @@ dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval, dns_ttl_t ttl
isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
return (result);
}
-
+
isc_result_t
dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl,
@@ -380,7 +380,7 @@ dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl,
datalen = strlen(data);
size = initial_size(datalen);
- for (;;) {
+ do {
isc_buffer_init(&b, data, datalen);
isc_buffer_add(&b, datalen);
result = isc_lex_openbuffer(lex, &b);
@@ -638,7 +638,7 @@ newversion(dns_db_t *db, dns_dbversion_t **versionp) {
}
static void
-attachversion(dns_db_t *db, dns_dbversion_t *source,
+attachversion(dns_db_t *db, dns_dbversion_t *source,
dns_dbversion_t **targetp)
{
REQUIRE(source != NULL && source == (void *) &dummy);
@@ -792,7 +792,7 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
return (result);
}
}
-
+
*nodep = node;
return (ISC_R_SUCCESS);
}
@@ -1120,7 +1120,7 @@ allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
sdb_rdatasetiter_t *iterator;
REQUIRE(version == NULL || version == &dummy);
-
+
UNUSED(version);
UNUSED(now);
diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c
index e4dbdc7..998ea36 100644
--- a/lib/dns/tkey.c
+++ b/lib/dns/tkey.c
@@ -1,8 +1,8 @@
/*
- * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2001, 2003 Internet Software Consortium.
*
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
@@ -16,7 +16,7 @@
*/
/*
- * $Id: tkey.c,v 1.76.18.5 2005/11/30 03:44:39 marka Exp $
+ * $Id: tkey.c,v 1.76.18.7 2008/01/02 23:46:02 tbox Exp $
*/
/*! \file */
#include <config.h>
@@ -379,7 +379,7 @@ process_dhtkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name,
isc_buffer_base(&secret),
isc_buffer_usedlength(&secret),
ISC_TRUE, signer, tkeyin->inception,
- tkeyin->expire, msg->mctx, ring, NULL));
+ tkeyin->expire, ring->mctx, ring, NULL));
/* This key is good for a long time */
tkeyout->inception = tkeyin->inception;
@@ -440,7 +440,7 @@ process_gsstkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name,
result = dns_tsigkey_createfromkey(name, &tkeyin->algorithm,
dstkey, ISC_TRUE, signer,
tkeyin->inception, tkeyin->expire,
- msg->mctx, ring, NULL);
+ ring->mctx, ring, NULL);
#if 1
if (result != ISC_R_SUCCESS)
goto failure;
@@ -1106,7 +1106,7 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
result = dns_tsigkey_create(tkeyname, &rtkey.algorithm,
r.base, r.length, ISC_TRUE,
NULL, rtkey.inception, rtkey.expire,
- rmsg->mctx, ring, outkey);
+ ring->mctx, ring, outkey);
isc_buffer_free(&shared);
dns_rdata_freestruct(&rtkey);
dst_key_free(&theirkey);
@@ -1176,7 +1176,7 @@ dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg,
RETERR(dns_tsigkey_createfromkey(tkeyname, DNS_TSIG_GSSAPI_NAME,
dstkey, ISC_TRUE, NULL,
rtkey.inception, rtkey.expire,
- rmsg->mctx, ring, outkey));
+ ring->mctx, ring, outkey));
dns_rdata_freestruct(&rtkey);
return (result);
diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c
index cca1f99..f21832f 100644
--- a/lib/dns/tsig.c
+++ b/lib/dns/tsig.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2002 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -16,7 +16,7 @@
*/
/*
- * $Id: tsig.c,v 1.117.18.11 2007/09/26 23:46:34 tbox Exp $
+ * $Id: tsig.c,v 1.117.18.14 2008/01/17 23:46:03 tbox Exp $
*/
/*! \file */
#include <config.h>
@@ -105,12 +105,12 @@ static unsigned char hmacsha1_ndata[] = "\011hmac-sha1";
static unsigned char hmacsha1_offsets[] = { 0, 10 };
static dns_name_t hmacsha1 = {
- DNS_NAME_MAGIC,
- hmacsha1_ndata, 11, 2,
- DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
- hmacsha1_offsets, NULL,
- {(void *)-1, (void *)-1},
- {NULL, NULL}
+ DNS_NAME_MAGIC,
+ hmacsha1_ndata, 11, 2,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ hmacsha1_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
};
LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha1_name = &hmacsha1;
@@ -119,12 +119,12 @@ static unsigned char hmacsha224_ndata[] = "\013hmac-sha224";
static unsigned char hmacsha224_offsets[] = { 0, 12 };
static dns_name_t hmacsha224 = {
- DNS_NAME_MAGIC,
- hmacsha224_ndata, 13, 2,
- DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
- hmacsha224_offsets, NULL,
- {(void *)-1, (void *)-1},
- {NULL, NULL}
+ DNS_NAME_MAGIC,
+ hmacsha224_ndata, 13, 2,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ hmacsha224_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
};
LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha224_name = &hmacsha224;
@@ -133,12 +133,12 @@ static unsigned char hmacsha256_ndata[] = "\013hmac-sha256";
static unsigned char hmacsha256_offsets[] = { 0, 12 };
static dns_name_t hmacsha256 = {
- DNS_NAME_MAGIC,
- hmacsha256_ndata, 13, 2,
- DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
- hmacsha256_offsets, NULL,
- {(void *)-1, (void *)-1},
- {NULL, NULL}
+ DNS_NAME_MAGIC,
+ hmacsha256_ndata, 13, 2,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ hmacsha256_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
};
LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha256_name = &hmacsha256;
@@ -147,12 +147,12 @@ static unsigned char hmacsha384_ndata[] = "\013hmac-sha384";
static unsigned char hmacsha384_offsets[] = { 0, 12 };
static dns_name_t hmacsha384 = {
- DNS_NAME_MAGIC,
- hmacsha384_ndata, 13, 2,
- DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
- hmacsha384_offsets, NULL,
- {(void *)-1, (void *)-1},
- {NULL, NULL}
+ DNS_NAME_MAGIC,
+ hmacsha384_ndata, 13, 2,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ hmacsha384_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
};
LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha384_name = &hmacsha384;
@@ -161,12 +161,12 @@ static unsigned char hmacsha512_ndata[] = "\013hmac-sha512";
static unsigned char hmacsha512_offsets[] = { 0, 12 };
static dns_name_t hmacsha512 = {
- DNS_NAME_MAGIC,
- hmacsha512_ndata, 13, 2,
- DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
- hmacsha512_offsets, NULL,
- {(void *)-1, (void *)-1},
- {NULL, NULL}
+ DNS_NAME_MAGIC,
+ hmacsha512_ndata, 13, 2,
+ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
+ hmacsha512_offsets, NULL,
+ {(void *)-1, (void *)-1},
+ {NULL, NULL}
};
LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha512_name = &hmacsha512;
@@ -323,7 +323,8 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
tkey->generated = generated;
tkey->inception = inception;
tkey->expire = expire;
- tkey->mctx = mctx;
+ tkey->mctx = NULL;
+ isc_mem_attach(mctx, &tkey->mctx);
tkey->magic = TSIG_MAGIC;
@@ -509,7 +510,7 @@ tsigkey_free(dns_tsigkey_t *key) {
isc_mem_put(key->mctx, key->creator, sizeof(dns_name_t));
}
isc_refcount_destroy(&key->refs);
- isc_mem_put(key->mctx, key, sizeof(dns_tsigkey_t));
+ isc_mem_putanddetach(&key->mctx, key, sizeof(dns_tsigkey_t));
}
void
@@ -981,7 +982,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
return (DNS_R_FORMERR);
}
if (tsig.siglen > 0 && digestbits != 0 &&
- tsig.siglen < ((digestbits + 1) / 8)) {
+ tsig.siglen < ((digestbits + 1) / 8)) {
msg->tsigstatus = dns_tsigerror_badtrunc;
tsig_log(msg->tsigkey, 2,
"truncated signature length too small");
@@ -1442,7 +1443,8 @@ dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp) {
return (result);
}
- ring->mctx = mctx;
+ ring->mctx = NULL;
+ isc_mem_attach(mctx, &ring->mctx);
*ringp = ring;
return (ISC_R_SUCCESS);
@@ -1460,5 +1462,5 @@ dns_tsigkeyring_destroy(dns_tsig_keyring_t **ringp) {
dns_rbt_destroy(&ring->keys);
isc_rwlock_destroy(&ring->lock);
- isc_mem_put(ring->mctx, ring, sizeof(dns_tsig_keyring_t));
+ isc_mem_putanddetach(&ring->mctx, ring, sizeof(dns_tsig_keyring_t));
}
diff --git a/lib/dns/validator.c b/lib/dns/validator.c
index 9538b302..e686336 100644
--- a/lib/dns/validator.c
+++ b/lib/dns/validator.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 2000-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: validator.c,v 1.119.18.35 2007/09/26 04:39:45 each Exp $ */
+/* $Id: validator.c,v 1.119.18.41 2008/08/21 04:59:42 marka Exp $ */
/*! \file */
@@ -55,7 +55,7 @@
* dlv_validator_start -> validator_start -> validate -> proveunsecure
*
* validator_start -> validate -> nsecvalidate (secure wildcard answer)
- *
+ *
* \li When called with rdataset, sigrdataset and with DNS_VALIDATOR_DLV:
* validator_start -> startfinddlvsep -> dlv_validator_start ->
* validator_start -> validate -> proveunsecure
@@ -134,7 +134,8 @@ static isc_result_t
nsecvalidate(dns_validator_t *val, isc_boolean_t resume);
static isc_result_t
-proveunsecure(dns_validator_t *val, isc_boolean_t resume);
+proveunsecure(dns_validator_t *val, isc_boolean_t have_ds,
+ isc_boolean_t resume);
static void
validator_logv(dns_validator_t *val, isc_logcategory_t *category,
@@ -365,7 +366,7 @@ dsfetched(isc_task_t *task, isc_event_t *event) {
"falling back to insecurity proof (%s)",
dns_result_totext(eresult));
val->attributes |= VALATTR_INSECURITY;
- result = proveunsecure(val, ISC_FALSE);
+ result = proveunsecure(val, ISC_FALSE, ISC_FALSE);
if (result != DNS_R_WAIT)
validator_done(val, result);
} else {
@@ -444,7 +445,7 @@ dsfetched2(isc_task_t *task, isc_event_t *event) {
validator_done(val, result);
}
} else {
- result = proveunsecure(val, ISC_TRUE);
+ result = proveunsecure(val, ISC_FALSE, ISC_TRUE);
if (result != DNS_R_WAIT)
validator_done(val, result);
}
@@ -453,11 +454,12 @@ dsfetched2(isc_task_t *task, isc_event_t *event) {
eresult == DNS_R_NCACHENXDOMAIN)
{
/*
- * There is a DS which may or may not be a zone cut.
+ * There is a DS which may or may not be a zone cut.
* In either case we are still in a secure zone resume
* validation.
*/
- result = proveunsecure(val, ISC_TRUE);
+ result = proveunsecure(val, ISC_TF(eresult == ISC_R_SUCCESS),
+ ISC_TRUE);
if (result != DNS_R_WAIT)
validator_done(val, result);
} else {
@@ -558,7 +560,7 @@ dsvalidated(isc_task_t *task, isc_event_t *event) {
validator_log(val, ISC_LOG_DEBUG(3),
"dsset with trust %d", val->frdataset.trust);
if ((val->attributes & VALATTR_INSECURITY) != 0)
- result = proveunsecure(val, ISC_TRUE);
+ result = proveunsecure(val, ISC_TRUE, ISC_TRUE);
else
result = validatezonekey(val);
if (result != DNS_R_WAIT)
@@ -779,7 +781,7 @@ authvalidated(isc_task_t *task, isc_event_t *event) {
} else {
dns_name_t **proofs = val->event->proofs;
dns_name_t *wild = dns_fixedname_name(&val->wild);
-
+
if (rdataset->trust == dns_trust_secure)
val->seensig = ISC_TRUE;
@@ -787,7 +789,7 @@ authvalidated(isc_task_t *task, isc_event_t *event) {
rdataset->trust == dns_trust_secure &&
((val->attributes & VALATTR_NEEDNODATA) != 0 ||
(val->attributes & VALATTR_NEEDNOQNAME) != 0) &&
- (val->attributes & VALATTR_FOUNDNODATA) == 0 &&
+ (val->attributes & VALATTR_FOUNDNODATA) == 0 &&
(val->attributes & VALATTR_FOUNDNOQNAME) == 0 &&
nsecnoexistnodata(val, val->event->name, devent->name,
rdataset, &exists, &data, wild)
@@ -900,7 +902,7 @@ view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) {
/* End of zone chain. */
if (!dns_name_issubdomain(name, &nsec.next)) {
/*
- * XXXMPA We could look for a parent NSEC
+ * XXXMPA We could look for a parent NSEC
* at nsec.next and if found retest with
* this NSEC.
*/
@@ -937,10 +939,11 @@ view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) {
dns_rdata_freestruct(&nsec);
result = DNS_R_NCACHENXDOMAIN;
} else if (result != ISC_R_SUCCESS &&
- result != DNS_R_NCACHENXDOMAIN &&
- result != DNS_R_NCACHENXRRSET &&
- result != DNS_R_NXRRSET &&
- result != ISC_R_NOTFOUND) {
+ result != DNS_R_NCACHENXDOMAIN &&
+ result != DNS_R_NCACHENXRRSET &&
+ result != DNS_R_EMPTYNAME &&
+ result != DNS_R_NXRRSET &&
+ result != ISC_R_NOTFOUND) {
goto notfound;
}
return (result);
@@ -1196,6 +1199,7 @@ get_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo) {
return (DNS_R_WAIT);
} else if (result == DNS_R_NCACHENXDOMAIN ||
result == DNS_R_NCACHENXRRSET ||
+ result == DNS_R_EMPTYNAME ||
result == DNS_R_NXDOMAIN ||
result == DNS_R_NXRRSET)
{
@@ -1246,7 +1250,8 @@ isselfsigned(dns_validator_t *val) {
{
dns_rdata_reset(&rdata);
dns_rdataset_current(rdataset, &rdata);
- (void)dns_rdata_tostruct(&rdata, &key, NULL);
+ result = dns_rdata_tostruct(&rdata, &key, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
keytag = compute_keytag(&rdata, &key);
for (result = dns_rdataset_first(sigrdataset);
result == ISC_R_SUCCESS;
@@ -1254,7 +1259,8 @@ isselfsigned(dns_validator_t *val) {
{
dns_rdata_reset(&sigrdata);
dns_rdataset_current(sigrdataset, &sigrdata);
- (void)dns_rdata_tostruct(&sigrdata, &sig, NULL);
+ result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (sig.algorithm == key.algorithm &&
sig.keyid == keytag)
@@ -1514,7 +1520,8 @@ dlv_validatezonekey(dns_validator_t *val) {
result = dns_rdataset_next(&val->dlv)) {
dns_rdata_reset(&dlvrdata);
dns_rdataset_current(&val->dlv, &dlvrdata);
- dns_rdata_tostruct(&dlvrdata, &dlv, NULL);
+ result = dns_rdata_tostruct(&dlvrdata, &dlv, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (!dns_resolver_algorithm_supported(val->view->resolver,
val->event->name,
@@ -1534,12 +1541,13 @@ dlv_validatezonekey(dns_validator_t *val) {
{
dns_rdata_reset(&dlvrdata);
dns_rdataset_current(&val->dlv, &dlvrdata);
- (void)dns_rdata_tostruct(&dlvrdata, &dlv, NULL);
+ result = dns_rdata_tostruct(&dlvrdata, &dlv, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (!dns_resolver_digest_supported(val->view->resolver,
dlv.digest_type))
continue;
-
+
if (dlv.digest_type != digest_type)
continue;
@@ -1559,7 +1567,8 @@ dlv_validatezonekey(dns_validator_t *val) {
{
dns_rdata_reset(&keyrdata);
dns_rdataset_current(&trdataset, &keyrdata);
- (void)dns_rdata_tostruct(&keyrdata, &key, NULL);
+ result = dns_rdata_tostruct(&keyrdata, &key, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
keytag = compute_keytag(&keyrdata, &key);
if (dlv.key_tag != keytag ||
dlv.algorithm != key.algorithm)
@@ -1594,7 +1603,8 @@ dlv_validatezonekey(dns_validator_t *val) {
dns_rdata_reset(&sigrdata);
dns_rdataset_current(val->event->sigrdataset,
&sigrdata);
- (void)dns_rdata_tostruct(&sigrdata, &sig, NULL);
+ result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (dlv.key_tag != sig.keyid &&
dlv.algorithm != sig.algorithm)
continue;
@@ -1691,7 +1701,8 @@ validatezonekey(dns_validator_t *val) {
dns_rdata_reset(&sigrdata);
dns_rdataset_current(val->event->sigrdataset,
&sigrdata);
- (void)dns_rdata_tostruct(&sigrdata, &sig, NULL);
+ result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = dns_keytable_findkeynode(val->keytable,
val->event->name,
sig.algorithm,
@@ -1745,7 +1756,7 @@ validatezonekey(dns_validator_t *val) {
* the RRset is invalid.
*/
dns_name_format(val->event->name, namebuf,
- sizeof(namebuf));
+ sizeof(namebuf));
validator_log(val, ISC_LOG_DEBUG(2),
"unable to find a DNSKEY which verifies "
"the DNSKEY RRset and also matches one "
@@ -1796,8 +1807,9 @@ validatezonekey(dns_validator_t *val) {
if (result != ISC_R_SUCCESS)
return (result);
return (DNS_R_WAIT);
- } else if (result == DNS_R_NCACHENXDOMAIN ||
+ } else if (result == DNS_R_NCACHENXDOMAIN ||
result == DNS_R_NCACHENXRRSET ||
+ result == DNS_R_EMPTYNAME ||
result == DNS_R_NXDOMAIN ||
result == DNS_R_NXRRSET)
{
@@ -1848,7 +1860,8 @@ validatezonekey(dns_validator_t *val) {
result = dns_rdataset_next(val->dsset)) {
dns_rdata_reset(&dsrdata);
dns_rdataset_current(val->dsset, &dsrdata);
- dns_rdata_tostruct(&dsrdata, &ds, NULL);
+ result = dns_rdata_tostruct(&dsrdata, &ds, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (!dns_resolver_algorithm_supported(val->view->resolver,
val->event->name,
@@ -1868,7 +1881,8 @@ validatezonekey(dns_validator_t *val) {
{
dns_rdata_reset(&dsrdata);
dns_rdataset_current(val->dsset, &dsrdata);
- (void)dns_rdata_tostruct(&dsrdata, &ds, NULL);
+ result = dns_rdata_tostruct(&dsrdata, &ds, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (!dns_resolver_digest_supported(val->view->resolver,
ds.digest_type))
@@ -1896,7 +1910,8 @@ validatezonekey(dns_validator_t *val) {
{
dns_rdata_reset(&keyrdata);
dns_rdataset_current(&trdataset, &keyrdata);
- (void)dns_rdata_tostruct(&keyrdata, &key, NULL);
+ result = dns_rdata_tostruct(&keyrdata, &key, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
keytag = compute_keytag(&keyrdata, &key);
if (ds.key_tag != keytag ||
ds.algorithm != key.algorithm)
@@ -1915,7 +1930,7 @@ validatezonekey(dns_validator_t *val) {
"no DNSKEY matching DS");
continue;
}
-
+
for (result = dns_rdataset_first(val->event->sigrdataset);
result == ISC_R_SUCCESS;
result = dns_rdataset_next(val->event->sigrdataset))
@@ -1923,7 +1938,8 @@ validatezonekey(dns_validator_t *val) {
dns_rdata_reset(&sigrdata);
dns_rdataset_current(val->event->sigrdataset,
&sigrdata);
- (void)dns_rdata_tostruct(&sigrdata, &sig, NULL);
+ result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (ds.key_tag != sig.keyid ||
ds.algorithm != sig.algorithm)
continue;
@@ -1994,7 +2010,7 @@ start_positive_validation(dns_validator_t *val) {
* exclusive we stop when one is found.
*
* Returns
- * \li ISC_R_SUCCESS
+ * \li ISC_R_SUCCESS
*/
static isc_result_t
checkwildcard(dns_validator_t *val) {
@@ -2213,7 +2229,7 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) {
validator_log(val, ISC_LOG_DEBUG(3),
"nonexistence proof(s) not found");
val->attributes |= VALATTR_INSECURITY;
- return (proveunsecure(val, ISC_FALSE));
+ return (proveunsecure(val, ISC_FALSE, ISC_FALSE));
}
static isc_boolean_t
@@ -2226,7 +2242,8 @@ check_ds(dns_validator_t *val, dns_name_t *name, dns_rdataset_t *rdataset) {
result == ISC_R_SUCCESS;
result = dns_rdataset_next(rdataset)) {
dns_rdataset_current(rdataset, &dsrdata);
- (void)dns_rdata_tostruct(&dsrdata, &ds, NULL);
+ result = dns_rdata_tostruct(&dsrdata, &ds, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (dns_resolver_digest_supported(val->view->resolver,
ds.digest_type) &&
@@ -2242,7 +2259,7 @@ check_ds(dns_validator_t *val, dns_name_t *name, dns_rdataset_t *rdataset) {
/*%
* Callback from fetching a DLV record.
- *
+ *
* Resumes the DLV lookup process.
*/
static void
@@ -2316,7 +2333,7 @@ dlvfetched(isc_task_t *task, isc_event_t *event) {
/*%
* Start the DLV lookup proccess.
- *
+ *
* Returns
* \li ISC_R_SUCCESS
* \li DNS_R_WAIT
@@ -2450,6 +2467,7 @@ finddlvsep(dns_validator_t *val, isc_boolean_t resume) {
}
if (result != DNS_R_NXRRSET &&
result != DNS_R_NXDOMAIN &&
+ result != DNS_R_EMPTYNAME &&
result != DNS_R_NCACHENXRRSET &&
result != DNS_R_NCACHENXDOMAIN)
return (result);
@@ -2486,7 +2504,8 @@ finddlvsep(dns_validator_t *val, isc_boolean_t resume) {
* \li DNS_R_NOTINSECURE
*/
static isc_result_t
-proveunsecure(dns_validator_t *val, isc_boolean_t resume) {
+proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume)
+{
isc_result_t result;
dns_fixedname_t fixedsecroot;
dns_name_t *secroot;
@@ -2508,7 +2527,7 @@ proveunsecure(dns_validator_t *val, isc_boolean_t resume) {
dns_name_split(secroot, 1, NULL, secroot);
result = dns_keytable_finddeepestmatch(val->keytable,
secroot, secroot);
-
+
if (result == ISC_R_NOTFOUND) {
validator_log(val, ISC_LOG_DEBUG(3),
"not beneath secure root");
@@ -2534,12 +2553,19 @@ proveunsecure(dns_validator_t *val, isc_boolean_t resume) {
val->labels = dns_name_countlabels(secroot) + 1;
} else {
validator_log(val, ISC_LOG_DEBUG(3), "resuming proveunsecure");
- if (val->frdataset.trust >= dns_trust_secure &&
+ /*
+ * If we have a DS rdataset and it is secure then check if
+ * the DS rdataset has a supported algorithm combination.
+ * If not this is a insecure delegation as far as this
+ * resolver is concerned. Fall back to DLV if available.
+ */
+ if (have_ds && val->frdataset.trust >= dns_trust_secure &&
!check_ds(val, dns_fixedname_name(&val->fname),
&val->frdataset)) {
dns_name_format(dns_fixedname_name(&val->fname),
namebuf, sizeof(namebuf));
- if (val->mustbesecure) {
+ if ((val->view->dlv == NULL || DLVTRIED(val)) &&
+ val->mustbesecure) {
validator_log(val, ISC_LOG_WARNING,
"must be secure failure at '%s'",
namebuf);
@@ -2784,7 +2810,7 @@ validator_start(isc_task_t *task, isc_event_t *event) {
validator_log(val, ISC_LOG_DEBUG(3),
"falling back to insecurity proof");
val->attributes |= VALATTR_INSECURITY;
- result = proveunsecure(val, ISC_FALSE);
+ result = proveunsecure(val, ISC_FALSE, ISC_FALSE);
if (result == DNS_R_NOTINSECURE)
result = saved_result;
}
@@ -2798,7 +2824,7 @@ validator_start(isc_task_t *task, isc_event_t *event) {
"attempting insecurity proof");
val->attributes |= VALATTR_INSECURITY;
- result = proveunsecure(val, ISC_FALSE);
+ result = proveunsecure(val, ISC_FALSE, ISC_FALSE);
} else if (val->event->rdataset == NULL &&
val->event->sigrdataset == NULL)
{
diff --git a/lib/dns/view.c b/lib/dns/view.c
index d5a78d5..4851cf0 100644
--- a/lib/dns/view.c
+++ b/lib/dns/view.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: view.c,v 1.126.18.14 2007/08/28 07:20:05 tbox Exp $ */
+/* $Id: view.c,v 1.126.18.16 2008/06/17 23:46:03 tbox Exp $ */
/*! \file */
@@ -315,7 +315,7 @@ destroy(dns_view_t *view) {
name = ISC_LIST_HEAD(view->rootexclude[i]);
while (name != NULL) {
ISC_LIST_UNLINK(view->rootexclude[i],
- name, link);
+ name, link);
dns_name_free(name, view->mctx);
isc_mem_put(view->mctx, name, sizeof(*name));
name = ISC_LIST_HEAD(view->rootexclude[i]);
@@ -846,17 +846,6 @@ dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
}
cleanup:
- if (result == DNS_R_NXDOMAIN || result == DNS_R_NXRRSET) {
- /*
- * We don't care about any DNSSEC proof data in these cases.
- */
- if (dns_rdataset_isassociated(rdataset))
- dns_rdataset_disassociate(rdataset);
- if (sigrdataset != NULL &&
- dns_rdataset_isassociated(sigrdataset))
- dns_rdataset_disassociate(sigrdataset);
- }
-
if (dns_rdataset_isassociated(&zrdataset)) {
dns_rdataset_disassociate(&zrdataset);
if (dns_rdataset_isassociated(&zsigrdataset))
@@ -936,7 +925,7 @@ dns_view_simplefind(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
isc_result_t
dns_view_findzonecut(dns_view_t *view, dns_name_t *name, dns_name_t *fname,
isc_stdtime_t now, unsigned int options,
- isc_boolean_t use_hints,
+ isc_boolean_t use_hints,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
{
return(dns_view_findzonecut2(view, name, fname, now, options,
@@ -1348,7 +1337,7 @@ dns_view_isdelegationonly(dns_view_t *view, dns_name_t *name) {
return (ISC_TRUE);
}
-void
+void
dns_view_setrootdelonly(dns_view_t *view, isc_boolean_t value) {
REQUIRE(DNS_VIEW_VALID(view));
view->rootdelonly = value;
diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c
index f95773f..7171a37 100644
--- a/lib/dns/xfrin.c
+++ b/lib/dns/xfrin.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: xfrin.c,v 1.135.18.16.10.3 2008/07/23 23:16:43 marka Exp $ */
+/* $Id: xfrin.c,v 1.135.18.23 2008/09/25 04:15:52 marka Exp $ */
/*! \file */
@@ -248,7 +248,7 @@ static isc_result_t
axfr_init(dns_xfrin_ctx_t *xfr) {
isc_result_t result;
- xfr->is_ixfr = ISC_FALSE;
+ xfr->is_ixfr = ISC_FALSE;
if (xfr->db != NULL)
dns_db_detach(&xfr->db);
@@ -426,6 +426,10 @@ xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name, isc_uint32_t ttl,
{
isc_result_t result;
+ if (rdata->type == dns_rdatatype_none ||
+ dns_rdatatype_ismeta(rdata->type))
+ FAIL(DNS_R_FORMERR);
+
redo:
switch (xfr->state) {
case XFRST_SOAQUERY:
@@ -892,8 +896,8 @@ render(dns_message_t *msg, isc_mem_t *mctx, isc_buffer_t *buf) {
CHECK(dns_message_renderend(msg));
result = ISC_R_SUCCESS;
failure:
- if (cleanup_cctx)
- dns_compress_invalidate(&cctx);
+ if (cleanup_cctx)
+ dns_compress_invalidate(&cctx);
return (result);
}
@@ -1051,6 +1055,8 @@ xfrin_send_request(dns_xfrin_ctx_t *xfr) {
xfr->id++;
xfr->nmsg = 0;
msg->id = xfr->id;
+ if (xfr->tsigctx != NULL)
+ dst_context_destroy(&xfr->tsigctx);
CHECK(render(msg, xfr->mctx, &xfr->qbuffer));
@@ -1186,7 +1192,10 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
CHECK(dns_message_settsigkey(msg, xfr->tsigkey));
CHECK(dns_message_setquerytsig(msg, xfr->lasttsig));
+
msg->tsigctx = xfr->tsigctx;
+ xfr->tsigctx = NULL;
+
if (xfr->nmsg > 0)
msg->tcp_continuation = 1;
@@ -1299,9 +1308,11 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
xfr->nmsg++;
/*
- * Copy the context back.
+ * Take the context back.
*/
+ INSIST(xfr->tsigctx == NULL);
xfr->tsigctx = msg->tsigctx;
+ msg->tsigctx = NULL;
dns_message_destroy(&msg);
@@ -1397,6 +1408,9 @@ maybe_free(dns_xfrin_ctx_t *xfr) {
if (xfr->tcpmsg_valid)
dns_tcpmsg_invalidate(&xfr->tcpmsg);
+ if (xfr->tsigctx != NULL)
+ dst_context_destroy(&xfr->tsigctx);
+
if ((xfr->name.attributes & DNS_NAMEATTR_DYNAMIC) != 0)
dns_name_free(&xfr->name, xfr->mctx);
@@ -1438,7 +1452,7 @@ xfrin_logv(int level, const char *zonetext, isc_sockaddr_t *masteraddr,
static void
xfrin_log1(int level, const char *zonetext, isc_sockaddr_t *masteraddr,
- const char *fmt, ...)
+ const char *fmt, ...)
{
va_list ap;
diff --git a/lib/dns/zone.c b/lib/dns/zone.c
index fa6ac46..36f303c 100644
--- a/lib/dns/zone.c
+++ b/lib/dns/zone.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zone.c,v 1.410.18.52 2007/08/30 05:15:03 marka Exp $ */
+/* $Id: zone.c,v 1.410.18.55 2008/10/24 01:43:17 tbox Exp $ */
/*! \file */
@@ -813,10 +813,10 @@ dns_zone_getdbtype(dns_zone_t *zone, char ***argv, isc_mem_t *mctx) {
isc_result_t result = ISC_R_SUCCESS;
void *mem;
char **tmp, *tmp2;
-
+
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(argv != NULL && *argv == NULL);
-
+
LOCK_ZONE(zone);
size = (zone->db_argc + 1) * sizeof(char *);
for (i = 0; i < zone->db_argc; i++)
@@ -927,7 +927,7 @@ void
dns_zone_setacache(dns_zone_t *zone, dns_acache_t *acache) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(acache != NULL);
-
+
LOCK_ZONE(zone);
if (zone->acache != NULL)
dns_acache_detach(&zone->acache);
@@ -1425,7 +1425,7 @@ zone_check_mx(dns_zone_t *zone, dns_db_t *db, dns_name_t *name,
dns_fixedname_t fixed;
dns_name_t *foundname;
int level;
-
+
/*
* Outside of zone.
*/
@@ -1507,7 +1507,7 @@ zone_check_srv(dns_zone_t *zone, dns_db_t *db, dns_name_t *name,
dns_fixedname_t fixed;
dns_name_t *foundname;
int level;
-
+
/*
* "." means the services does not exist.
*/
@@ -1598,7 +1598,7 @@ zone_check_glue(dns_zone_t *zone, dns_db_t *db, dns_name_t *name,
dns_rdataset_t a;
dns_rdataset_t aaaa;
int level;
-
+
/*
* Outside of zone.
*/
@@ -1636,7 +1636,7 @@ zone_check_glue(dns_zone_t *zone, dns_db_t *db, dns_name_t *name,
if (tresult == ISC_R_SUCCESS) {
dns_rdataset_disassociate(&aaaa);
return (ISC_TRUE);
- }
+ }
if (tresult == DNS_R_DELEGATION)
dns_rdataset_disassociate(&aaaa);
if (result == DNS_R_GLUE || tresult == DNS_R_GLUE) {
@@ -1660,14 +1660,16 @@ zone_check_glue(dns_zone_t *zone, dns_db_t *db, dns_name_t *name,
if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN ||
result == DNS_R_EMPTYNAME || result == DNS_R_DELEGATION) {
const char *what;
- if (dns_name_issubdomain(name, owner))
+ isc_boolean_t required = ISC_FALSE;
+ if (dns_name_issubdomain(name, owner)) {
what = "REQUIRED GLUE ";
- else if (result == DNS_R_DELEGATION)
+ required = ISC_TRUE;
+ } else if (result == DNS_R_DELEGATION)
what = "SIBLING GLUE ";
else
what = "";
- if (result != DNS_R_DELEGATION ||
+ if (result != DNS_R_DELEGATION || required ||
DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKSIBLING)) {
dns_zone_log(zone, level, "%s/NS '%s' has no %s"
"address records (A or AAAA)",
@@ -1749,7 +1751,7 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
if (dns_name_equal(name, &zone->origin))
goto checkmx;
- result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ns,
+ result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_ns,
0, 0, &rdataset, NULL);
if (result != ISC_R_SUCCESS)
goto checkmx;
@@ -1771,7 +1773,7 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
dns_rdataset_disassociate(&rdataset);
checkmx:
- result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_mx,
+ result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_mx,
0, 0, &rdataset, NULL);
if (result != ISC_R_SUCCESS)
goto checksrv;
@@ -1790,7 +1792,7 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
checksrv:
if (zone->rdclass != dns_rdataclass_in)
goto next;
- result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_srv,
+ result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_srv,
0, 0, &rdataset, NULL);
if (result != ISC_R_SUCCESS)
goto next;
@@ -1848,12 +1850,12 @@ zone_check_dnskeys(dns_zone_t *zone, dns_db_t *db) {
for (result = dns_rdataset_first(&rdataset);
result == ISC_R_SUCCESS;
- result = dns_rdataset_next(&rdataset))
+ result = dns_rdataset_next(&rdataset))
{
dns_rdataset_current(&rdataset, &rdata);
result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
INSIST(result == ISC_R_SUCCESS);
-
+
if ((dnskey.algorithm == DST_ALG_RSASHA1 ||
dnskey.algorithm == DST_ALG_RSAMD5) &&
dnskey.datalen > 1 && dnskey.data[0] == 1 &&
@@ -1885,7 +1887,7 @@ zone_check_dnskeys(dns_zone_t *zone, dns_db_t *db) {
dns_db_detachnode(db, &node);
if (version != NULL)
dns_db_closeversion(db, &version, ISC_FALSE);
-
+
}
static isc_result_t
@@ -2039,7 +2041,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
} else if (!isc_serial_ge(serial, zone->serial))
dns_zone_log(zone, ISC_LOG_ERROR,
"zone serial has gone backwards");
- else if (serial == zone->serial && !hasinclude)
+ else if (serial == zone->serial && !hasinclude)
dns_zone_log(zone, ISC_LOG_ERROR,
"zone serial unchanged. "
"zone may fail to transfer "
@@ -2171,7 +2173,7 @@ zone_check_ns(dns_zone_t *zone, dns_db_t *db, dns_name_t *name) {
dns_fixedname_t fixed;
dns_name_t *foundname;
int level;
-
+
if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOCHECKNS))
return (ISC_TRUE);
@@ -2760,7 +2762,7 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone,
}
LOCK_ZONE(zone);
- /*
+ /*
* The refresh code assumes that 'masters' wouldn't change under it.
* If it will change then kill off any current refresh in progress
* and update the masters info. If it won't change then we can just
@@ -2815,7 +2817,7 @@ dns_zone_setmasterswithkeys(dns_zone_t *zone,
goto unlock;
}
memcpy(new, masters, count * sizeof(*new));
-
+
/*
* Similarly for mastersok.
*/
@@ -4834,7 +4836,7 @@ add_opt(dns_message_t *message, isc_uint16_t udpsize) {
if (result != ISC_R_SUCCESS)
goto cleanup;
dns_rdataset_init(rdataset);
-
+
rdatalist->type = dns_rdatatype_opt;
rdatalist->covers = 0;
@@ -4871,7 +4873,7 @@ add_opt(dns_message_t *message, isc_uint16_t udpsize) {
dns_message_puttemprdataset(message, &rdataset);
if (rdata != NULL)
dns_message_puttemprdata(message, &rdata);
-
+
return (result);
}
@@ -5161,7 +5163,7 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) {
}
}
if (key == NULL)
- (void)dns_view_getpeertsig(zone->view, &masterip, &key);
+ (void)dns_view_getpeertsig(zone->view, &masterip, &key);
if (zone->view->peers != NULL) {
dns_peer_t *peer = NULL;
@@ -5181,7 +5183,7 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) {
dns_resolver_getudpsize(zone->view->resolver);
(void)dns_peer_getudpsize(peer, &udpsize);
}
-
+
}
if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) {
result = add_opt(message, udpsize);
@@ -5315,7 +5317,7 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) {
if (zone->writeio != NULL)
zonemgr_cancelio(zone->writeio);
- if (zone->dctx != NULL)
+ if (zone->dctx != NULL)
dns_dumpctx_cancel(zone->dctx);
}
@@ -6664,7 +6666,7 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) {
}
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDCOMPACT);
}
-
+
/*
* This transfer finishing freed up a transfer quota slot.
* Let any other zones waiting for quota have it.
@@ -6702,7 +6704,7 @@ zone_loaddone(void *arg, isc_result_t result) {
ENTER;
tresult = dns_db_endload(load->db, &load->callbacks.add_private);
- if (tresult != ISC_R_SUCCESS &&
+ if (tresult != ISC_R_SUCCESS &&
(result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE))
result = tresult;
@@ -7725,7 +7727,7 @@ zone_saveunique(dns_zone_t *zone, const char *path, const char *templat) {
if (result != ISC_R_SUCCESS)
goto cleanup;
- dns_zone_log(zone, ISC_LOG_INFO, "saved '%s' as '%s'",
+ dns_zone_log(zone, ISC_LOG_WARNING, "saved '%s' as '%s'",
path, buf);
cleanup:
OpenPOWER on IntegriCloud