+2448. [func] Add NSEC3 support. [RT #15452]
+
2447. [cleanup] libbind has been split out as a seperate product.
2446. [func] Add a new log message about build options on startup.
--- /dev/null
+
+ DNSSEC and UPDATE
+
+ Converting from insecure to secure
+
+As of BIND 9.6.0 it is possible to move a zone between being insecure
+to secure and back again. A secure zone can be using NSEC or NSEC3.
+
+To move a zone from insecure to secure you need to configure named
+so that it can see the K* files which contain the public and private
+parts of the keys that will be used to sign the zone. These files
+will have been generated by dnssec-keygen. You can do this by
+placing them in the key-directory as specified in named.conf.
+
+ zone example.net {
+ type master;
+ allow-update { .... };
+ file "dynamic/example.net/example.net";
+ key-directory "dynamic/example.net";
+ };
+
+Assuming one KSK and ons ZSK DNSKEY key has been generated. Then
+this will cause the zone to be signed with the ZSK and the DNSKEY
+RRset to be signed with the KSK DNSKEY. A NSEC chain will also be
+generated as part of the initial signing process.
+
+ % nsupdate
+ > ttl 3600
+ > update add example.net DNSKEY 256 3 7 AwEAAZn17pUF0KpbPA2c7Gz76Vb18v0teKT3EyAGfBfL8eQ8al35zz3Y I1m/SAQBxIqMfLtIwqWPdgthsu36azGQAX8=
+ > update add example.net DNSKEY 257 3 7 AwEAAd/7odU/64o2LGsifbLtQmtO8dFDtTAZXSX2+X3e/UNlq9IHq3Y0 XtC0Iuawl/qkaKVxXe2lo8Ct+dM6UehyCqk=
+ > send
+
+While the update request will complete almost immediately the zone
+will not be completely signed until named has hand time to walk the
+zone and generate the NSEC and RRSIG records. Initially the NSEC
+record at the zone apex will have the OPT bit set. When the NSEC
+chain is complete the OPT bit will be cleared. Additionally when
+the zone fully signed the private type (default TYPE65535) records
+will have a non zero value for the final octet.
+
+The private type record has 5 octets.
+ algorithm (octet 1)
+ key id in network order (octet 2 and 3)
+ removal flag (octet 4)
+ complete flag (octet 5)
+
+If you wish to go straight to a secure zone using NSEC3 you should
+also add a NSECPARAM record to the update request with the flags
+field set to indicate whether the NSEC3 chain will have the OPTOUT
+bit set or not.
+
+ % nsupdate
+ > ttl 3600
+ > update add example.net DNSKEY 256 3 7 AwEAAZn17pUF0KpbPA2c7Gz76Vb18v0teKT3EyAGfBfL8eQ8al35zz3Y I1m/SAQBxIqMfLtIwqWPdgthsu36azGQAX8=
+ > update add example.net DNSKEY 257 3 7 AwEAAd/7odU/64o2LGsifbLtQmtO8dFDtTAZXSX2+X3e/UNlq9IHq3Y0 XtC0Iuawl/qkaKVxXe2lo8Ct+dM6UehyCqk=
+ > update add example.net NSEC3PARAM 1 1 100 1234567890
+ > send
+
+Again the update request will complete almost immediately however the
+NSEC3PARAM record will have additional flag bits set indicating that the
+NSEC3 chain is under construction. When the NSEC3 chain is complete the
+flags field will be set to zero.
+
+While the initial signing and NSEC/NSEC3 chain generation is happening
+other updates are possible.
+
+ DNSKEY roll overs via UPDATE
+
+It is possible to perform key rollovers via update. You need to
+add the K* files for the new keys so that named can find them. You
+can then add the new DNSKEY RRs via update. Named will then cause
+the zone to be signed with the new keys. When the signing is
+complete the private type records will be updated so that the last
+octet is non zero.
+
+If this is for a KSK you need to inform the parent and any trust
+anchor repositories of the new KSK.
+
+You should then wait for the maximum TLL in the zone before removing the
+old DNSKEY. If it is a KSK that is being updated you also need to wait
+for the DS RRset in the parent to be updated and its TTL to expire.
+This ensures that all clients will be able to verify atleast a signature
+when you remove the old DNSKEY.
+
+The can be removed the old DNSKEY via UPDATE. Take care to specify
+the correct key. Named will clean out any signatures generated by
+the old key after the update completes.
+
+ NSEC3PARAM rollovers via UPDATE.
+
+Add the new NSEC3PARAM record via update. When the new NSEC3 chain
+has been generated the NSEC3PARAM flag field will be zero. At this
+point you can remove the old NSEC3PARAM record. The old chain will
+be removed after the update request completes.
+
+ Converting from NSEC to NSEC3
+
+To do this you just need to add a NSEC3PARAM record. When the
+conversion is complete the NSEC chain will have been removed and
+the NSEC3PARAM record will have a zero flag field. The NSEC3 chain
+will be generated before the NSEC chain is destroyed.
+
+ Converting from NSEC3 to NSEC
+
+To do this remove all NSEC3PARAM records with a zero flag field. The
+NSEC chain will be generated before the NSEC3 chain is removed.
+
+ Converting from secure to insecure
+
+To do this remove all the DNSKEY records. Any NSEC or NSEC3 chains
+will be removed as will as associated NSEC3PARAM records. The will
+take place after the update requests completes.
+
+ Periodic re-signing.
+
+Named will periodically re-sign RRsets which have not been re-signed
+as a result of some update action. The signature lifetimes will
+be adjusted so as to spread the re-sign load over time rather than
+all at once.
+
+ NSEC3 and OPTOUT
+
+Named only supports creating new NSEC3 chains where all the NSEC3
+records in the zone have the same OPTOUT state. Named supports
+UPDATES to zones where the NSEC3 records in the chain have mixed
+OPTOUT state. Named does not support changing the OPTOUT state of
+an individual NSEC3 record, the entire chain needs to be changed if
+the OPTOUT state of an individual NSEC3 needs to be changed.
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnssec-keyfromlabel.c,v 1.3 2008/03/31 23:47:11 tbox Exp $ */
+/* $Id: dnssec-keyfromlabel.c,v 1.4 2008/09/24 02:46:21 marka Exp $ */
/*! \file */
const char *program = "dnssec-keyfromlabel";
int verbose;
-static const char *algs = "RSA | RSAMD5 | DH | DSA | RSASHA1";
+static const char *algs = "RSA | RSAMD5 | DH | DSA | RSASHA1 |"
+ " NSEC3DSA | NSEC3RSASHA1";
static void
usage(void) {
- PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- $Id: dnssec-keyfromlabel.docbook,v 1.3 2008/03/31 23:47:11 tbox Exp $ -->
+<!-- $Id: dnssec-keyfromlabel.docbook,v 1.4 2008/09/24 02:46:21 marka Exp $ -->
<refentry id="man.dnssec-keyfromlabel">
<refentryinfo>
<date>february 8, 2008</date>
<para>
Selects the cryptographic algorithm. The value of
<option>algorithm</option> must be one of RSAMD5 (RSA)
- or RSASHA1, DSA or DH (Diffie Hellman). These values
- are case insensitive.
+ or RSASHA1, DSA, NSEC3RSASHA1, NSEC3DSA or DH (Diffie Hellman).
+ These values are case insensitive.
</para>
<para>
Note 1: that for DNSSEC, RSASHA1 is a mandatory to implement
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnssec-keygen.c,v 1.79 2007/08/28 07:20:42 tbox Exp $ */
+/* $Id: dnssec-keygen.c,v 1.80 2008/09/24 02:46:21 marka Exp $ */
/*! \file */
const char *program = "dnssec-keygen";
int verbose;
-static const char *algs = "RSA | RSAMD5 | DH | DSA | RSASHA1 | HMAC-MD5 |"
- " HMAC-SHA1 | HMAC-SHA224 | HMAC-SHA256 | "
+static const char *algs = "RSA | RSAMD5 | DH | DSA | RSASHA1 | NSEC3DSA |"
+ " NSEC3RSASHA1 | HMAC-MD5 |"
+ " HMAC-SHA1 | HMAC-SHA224 | HMAC-SHA256 |"
" HMAC-SHA384 | HMAC-SHA512";
static isc_boolean_t
fprintf(stderr, " -b key size, in bits:\n");
fprintf(stderr, " RSAMD5:\t\t[512..%d]\n", MAX_RSA);
fprintf(stderr, " RSASHA1:\t\t[512..%d]\n", MAX_RSA);
+ fprintf(stderr, " NSEC3RSASHA1:\t\t[512..%d]\n", MAX_RSA);
fprintf(stderr, " DH:\t\t[128..4096]\n");
fprintf(stderr, " DSA:\t\t[512..1024] and divisible by 64\n");
+ fprintf(stderr, " NSEC3DSA:\t\t[512..1024] and divisible by 64\n");
fprintf(stderr, " HMAC-MD5:\t[1..512]\n");
fprintf(stderr, " HMAC-SHA1:\t[1..160]\n");
fprintf(stderr, " HMAC-SHA224:\t[1..224]\n");
switch (alg) {
case DNS_KEYALG_RSAMD5:
case DNS_KEYALG_RSASHA1:
+ case DNS_KEYALG_NSEC3RSASHA1:
if (size != 0 && (size < 512 || size > MAX_RSA))
fatal("RSA key size %d out of range", size);
break;
fatal("DH key size %d out of range", size);
break;
case DNS_KEYALG_DSA:
+ case DNS_KEYALG_NSEC3DSA:
if (size != 0 && !dsa_size_ok(size))
fatal("invalid DSS key size: %d", size);
break;
break;
}
- if (!(alg == DNS_KEYALG_RSAMD5 || alg == DNS_KEYALG_RSASHA1) &&
- rsa_exp != 0)
+ if (!(alg == DNS_KEYALG_RSAMD5 || alg == DNS_KEYALG_RSASHA1 ||
+ alg == DNS_KEYALG_NSEC3RSASHA1) && rsa_exp != 0)
fatal("specified RSA exponent for a non-RSA key");
if (alg != DNS_KEYALG_DH && generator != 0)
- PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- $Id: dnssec-keygen.docbook,v 1.19 2007/06/18 23:47:17 tbox Exp $ -->
+<!-- $Id: dnssec-keygen.docbook,v 1.20 2008/09/24 02:46:21 marka Exp $ -->
<refentry id="man.dnssec-keygen">
<refentryinfo>
<date>June 30, 2000</date>
<para>
Selects the cryptographic algorithm. The value of
<option>algorithm</option> must be one of RSAMD5 (RSA) or RSASHA1,
- DSA, DH (Diffie Hellman), or HMAC-MD5. These values
- are case insensitive.
+ DSA, NSEC3RSASHA1, NSEC3DSA, DH (Diffie Hellman), or HMAC-MD5.
+ These values are case insensitive.
</para>
<para>
Note 1: that for DNSSEC, RSASHA1 is a mandatory to implement
- algorithm,
- and DSA is recommended. For TSIG, HMAC-MD5 is mandatory.
+ algorithm, and DSA is recommended. For TSIG, HMAC-MD5 is
+ mandatory.
</para>
<para>
Note 2: HMAC-MD5 and DH automatically set the -k flag.
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnssec-signzone.c,v 1.206 2008/06/02 23:47:04 tbox Exp $ */
+/* $Id: dnssec-signzone.c,v 1.207 2008/09/24 02:46:21 marka Exp $ */
/*! \file */
#include <time.h>
#include <isc/app.h>
+#include <isc/base32.h>
#include <isc/commandline.h>
#include <isc/entropy.h>
#include <isc/event.h>
#include <isc/file.h>
#include <isc/hash.h>
+#include <isc/hex.h>
#include <isc/mem.h>
#include <isc/mutex.h>
#include <isc/os.h>
#include <isc/stdio.h>
#include <isc/string.h>
#include <isc/task.h>
-#include <isc/util.h>
#include <isc/time.h>
+#include <isc/util.h>
#include <dns/db.h>
#include <dns/dbiterator.h>
#include <dns/master.h>
#include <dns/masterdump.h>
#include <dns/nsec.h>
+#include <dns/nsec3.h>
#include <dns/rdata.h>
+#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdataclass.h>
#include <dns/rdatasetiter.h>
const char *program = "dnssec-signzone";
int verbose;
+typedef struct hashlist hashlist_t;
+
+static int nsec_datatype = dns_rdatatype_nsec;
+
+#define IS_NSEC3 (nsec_datatype == dns_rdatatype_nsec3)
+#define OPTOUT(x) (((x) & DNS_NSEC3FLAG_OPTOUT) != 0)
+
#define BUFSIZE 2048
#define MAXDSKEYS 8
static dns_dbiterator_t *gdbiter; /* The database iterator */
static dns_rdataclass_t gclass; /* The class */
static dns_name_t *gorigin; /* The database origin */
+static int nsec3flags = 0;
static isc_task_t *master = NULL;
static unsigned int ntasks = 0;
static isc_boolean_t shuttingdown = ISC_FALSE, finished = ISC_FALSE;
static dns_fixedname_t dlv_fixed;
static dns_master_style_t *dsstyle = NULL;
static unsigned int serialformat = SOA_SERIAL_KEEP;
+static unsigned int hash_length = 0;
+static isc_boolean_t unknownalg = ISC_FALSE;
#define INCSTAT(counter) \
if (printstats) { \
static void
sign(isc_task_t *task, isc_event_t *event);
-
-static inline void
-set_bit(unsigned char *array, unsigned int index, unsigned int bit) {
- unsigned int shift, mask;
-
- shift = 7 - (index % 8);
- mask = 1 << shift;
-
- if (bit != 0)
- array[index / 8] |= mask;
- else
- array[index / 8] &= (~mask & 0xFF);
-}
+static isc_boolean_t
+nsec3only(dns_dbnode_t *node);
static void
dumpnode(dns_name_t *name, dns_dbnode_t *node) {
isc_mem_put(mctx, nowsignedby, arraysize * sizeof(isc_boolean_t));
}
+struct hashlist {
+ unsigned char *hashbuf;
+ size_t entries;
+ size_t size;
+ size_t length;
+};
+
+static void
+hashlist_init(hashlist_t *l, unsigned int nodes, unsigned int length) {
+
+ l->entries = 0;
+ l->length = length + 1;
+
+ if (nodes != 0) {
+ l->size = nodes;
+ l->hashbuf = malloc(l->size * l->length);
+ if (l->hashbuf == NULL)
+ l->size = 0;
+ } else {
+ l->size = 0;
+ l->hashbuf = NULL;
+ }
+}
+
+static void
+hashlist_add(hashlist_t *l, const unsigned char *hash, size_t len)
+{
+
+ REQUIRE(len <= l->length);
+
+ if (l->entries == l->size) {
+ l->size = l->size * 2 + 100;
+ l->hashbuf = realloc(l->hashbuf, l->size * l->length);
+ }
+ memset(l->hashbuf + l->entries * l->length, 0, l->length);
+ memcpy(l->hashbuf + l->entries * l->length, hash, len);
+ l->entries++;
+}
+
+static void
+hashlist_add_dns_name(hashlist_t *l, /*const*/ dns_name_t *name,
+ unsigned int hashalg, unsigned int iterations,
+ const unsigned char *salt, size_t salt_length,
+ isc_boolean_t speculative)
+{
+ char nametext[DNS_NAME_FORMATSIZE];
+ unsigned char hash[NSEC3_MAX_HASH_LENGTH + 1];
+ unsigned int len;
+ size_t i;
+
+ len = isc_iterated_hash(hash, hashalg, iterations, salt, salt_length,
+ name->ndata, name->length);
+ if (verbose) {
+ dns_name_format(name, nametext, sizeof nametext);
+ for (i = 0 ; i < len; i++)
+ fprintf(stderr, "%02x", hash[i]);
+ fprintf(stderr, " %s\n", nametext);
+ }
+ hash[len++] = speculative ? 1 : 0;
+ hashlist_add(l, hash, len);
+}
+
+static int
+hashlist_comp(const void *a, const void *b) {
+ return (memcmp(a, b, hash_length + 1));
+}
+
+static void
+hashlist_sort(hashlist_t *l) {
+ qsort(l->hashbuf, l->entries, l->length, hashlist_comp);
+}
+
+static isc_boolean_t
+hashlist_hasdup(hashlist_t *l) {
+ unsigned char *current;
+ unsigned char *next = l->hashbuf;
+ size_t entries = l->entries;
+
+ /*
+ * Skip initial speculative wild card hashs.
+ */
+ while (entries > 0 && next[l->length-1] != 0) {
+ next += l->length;
+ entries--;
+ }
+
+ current = next;
+ while (entries-- > 1U) {
+ next += l->length;
+ if (next[l->length-1] != 0)
+ continue;
+ if (memcmp(current, next, l->length - 1) == 0)
+ return (ISC_TRUE);
+ current = next;
+ }
+ return (ISC_FALSE);
+}
+
+static const unsigned char *
+hashlist_findnext(const hashlist_t *l,
+ const unsigned char hash[NSEC3_MAX_HASH_LENGTH])
+{
+ unsigned int entries = l->entries;
+ const unsigned char *next = bsearch(hash, l->hashbuf, l->entries,
+ l->length, hashlist_comp);
+ INSIST(next != NULL);
+
+ do {
+ if (next < l->hashbuf + (l->entries - 1) * l->length)
+ next += l->length;
+ else
+ next = l->hashbuf;
+ if (next[l->length - 1] == 0)
+ break;
+ } while (entries-- > 1);
+ INSIST(entries != 0);
+ return (next);
+}
+
+static isc_boolean_t
+hashlist_exists(const hashlist_t *l,
+ const unsigned char hash[NSEC3_MAX_HASH_LENGTH])
+{
+ if (bsearch(hash, l->hashbuf, l->entries, l->length, hashlist_comp))
+ return (ISC_TRUE);
+ else
+ return (ISC_FALSE);
+}
+
+static void
+addnowildcardhash(hashlist_t *l, /*const*/ dns_name_t *name,
+ unsigned int hashalg, unsigned int iterations,
+ const unsigned char *salt, size_t salt_length)
+{
+ dns_fixedname_t fixed;
+ dns_name_t *wild;
+ dns_dbnode_t *node = NULL;
+ isc_result_t result;
+ char namestr[DNS_NAME_FORMATSIZE];
+
+ dns_fixedname_init(&fixed);
+ wild = dns_fixedname_name(&fixed);
+
+ result = dns_name_concatenate(dns_wildcardname, name, wild, NULL);
+ if (result == ISC_R_NOSPACE)
+ return;
+ check_result(result,"addnowildcardhash: dns_name_concatenate()");
+
+ result = dns_db_findnode(gdb, wild, ISC_FALSE, &node);
+ if (result == ISC_R_SUCCESS) {
+ dns_db_detachnode(gdb, &node);
+ return;
+ }
+
+ if (verbose) {
+ dns_name_format(wild, namestr, sizeof(namestr));
+ fprintf(stderr, "adding no-wildcardhash for %s\n", namestr);
+ }
+
+ hashlist_add_dns_name(l, wild, hashalg, iterations, salt, salt_length,
+ ISC_TRUE);
+}
+
static void
opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass,
dns_db_t **dbp)
return (result);
}
-static isc_boolean_t
-nsec_setbit(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdatatype_t type,
- unsigned int val)
-{
- isc_result_t result;
- dns_rdata_t rdata = DNS_RDATA_INIT;
- dns_rdata_nsec_t nsec;
- unsigned int newlen;
- unsigned char bitmap[8192 + 512];
- unsigned char nsecdata[8192 + 512 + DNS_NAME_MAXWIRE];
- isc_boolean_t answer = ISC_FALSE;
- unsigned int i, len, window;
- int octet;
-
- result = dns_rdataset_first(rdataset);
- check_result(result, "dns_rdataset_first()");
- dns_rdataset_current(rdataset, &rdata);
- result = dns_rdata_tostruct(&rdata, &nsec, NULL);
- check_result(result, "dns_rdata_tostruct");
-
- INSIST(nsec.len <= sizeof(bitmap));
-
- newlen = 0;
-
- memset(bitmap, 0, sizeof(bitmap));
- for (i = 0; i < nsec.len; i += len) {
- INSIST(i + 2 <= nsec.len);
- window = nsec.typebits[i];
- len = nsec.typebits[i+1];
- i += 2;
- INSIST(len > 0 && len <= 32);
- INSIST(i + len <= nsec.len);
- memmove(&bitmap[window * 32 + 512], &nsec.typebits[i], len);
- }
- set_bit(bitmap + 512, type, val);
- for (window = 0; window < 256; window++) {
- for (octet = 31; octet >= 0; octet--)
- if (bitmap[window * 32 + 512 + octet] != 0)
- break;
- if (octet < 0)
- continue;
- bitmap[newlen] = window;
- bitmap[newlen + 1] = octet + 1;
- newlen += 2;
- /*
- * Overlapping move.
- */
- memmove(&bitmap[newlen], &bitmap[window * 32 + 512], octet + 1);
- newlen += octet + 1;
- }
- if (newlen != nsec.len ||
- memcmp(nsec.typebits, bitmap, newlen) != 0) {
- dns_rdata_t newrdata = DNS_RDATA_INIT;
- isc_buffer_t b;
- dns_diff_t diff;
- dns_difftuple_t *tuple = NULL;
-
- dns_diff_init(mctx, &diff);
- result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL, name,
- rdataset->ttl, &rdata, &tuple);
- check_result(result, "dns_difftuple_create");
- dns_diff_append(&diff, &tuple);
-
- nsec.typebits = bitmap;
- nsec.len = newlen;
- isc_buffer_init(&b, nsecdata, sizeof(nsecdata));
- result = dns_rdata_fromstruct(&newrdata, rdata.rdclass,
- dns_rdatatype_nsec, &nsec,
- &b);
- check_result(result, "dns_rdata_fromstruct");
-
- result = dns_difftuple_create(mctx, DNS_DIFFOP_ADD,
- name, rdataset->ttl,
- &newrdata, &tuple);
- check_result(result, "dns_difftuple_create");
- dns_diff_append(&diff, &tuple);
- result = dns_diff_apply(&diff, gdb, gversion);
- check_result(result, "dns_difftuple_apply");
- dns_diff_clear(&diff);
- answer = ISC_TRUE;
- }
- dns_rdata_freestruct(&nsec);
- return (answer);
-}
-
static isc_boolean_t
delegation(dns_name_t *name, dns_dbnode_t *node, isc_uint32_t *ttlp) {
dns_rdataset_t nsset;
return (ISC_TF(result == ISC_R_SUCCESS));
}
+static isc_boolean_t
+secure(dns_name_t *name, dns_dbnode_t *node) {
+ dns_rdataset_t dsset;
+ isc_result_t result;
+
+ if (dns_name_equal(name, gorigin))
+ return (ISC_FALSE);
+
+ dns_rdataset_init(&dsset);
+ result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_ds,
+ 0, 0, &dsset, NULL);
+ if (dns_rdataset_isassociated(&dsset))
+ dns_rdataset_disassociate(&dsset);
+
+ return (ISC_TF(result == ISC_R_SUCCESS));
+}
+
/*%
- * Signs all records at a name. This mostly just signs each set individually,
- * but also adds the RRSIG bit to any NSECs generated earlier, deals with
- * parent/child KEY signatures, and handles other exceptional cases.
+ * Signs all records at a name.
*/
static void
signname(dns_dbnode_t *node, dns_name_t *name) {
dns_rdataset_t rdataset;
dns_rdatasetiter_t *rdsiter;
isc_boolean_t isdelegation = ISC_FALSE;
- isc_boolean_t hasds = ISC_FALSE;
- isc_boolean_t changed = ISC_FALSE;
dns_diff_t del, add;
char namestr[DNS_NAME_FORMATSIZE];
- isc_uint32_t nsttl = 0;
+ dns_rdataset_init(&rdataset);
dns_name_format(name, namestr, sizeof(namestr));
/*
* Determine if this is a delegation point.
*/
- if (delegation(name, node, &nsttl))
+ if (delegation(name, node, NULL))
isdelegation = ISC_TRUE;
- /*
- * If this is a delegation point, look for a DS set.
- */
- if (isdelegation) {
- dns_rdataset_t dsset;
- dns_rdataset_t sigdsset;
-
- dns_rdataset_init(&dsset);
- dns_rdataset_init(&sigdsset);
- result = dns_db_findrdataset(gdb, node, gversion,
- dns_rdatatype_ds,
- 0, 0, &dsset, &sigdsset);
- if (result == ISC_R_SUCCESS) {
- dns_rdataset_disassociate(&dsset);
- if (generateds) {
- result = dns_db_deleterdataset(gdb, node,
- gversion,
- dns_rdatatype_ds,
- 0);
- check_result(result, "dns_db_deleterdataset");
- } else
- hasds = ISC_TRUE;
- }
- if (generateds) {
- result = loadds(name, nsttl, &dsset);
- if (result == ISC_R_SUCCESS) {
- result = dns_db_addrdataset(gdb, node,
- gversion, 0,
- &dsset, 0, NULL);
- check_result(result, "dns_db_addrdataset");
- hasds = ISC_TRUE;
- dns_rdataset_disassociate(&dsset);
- if (dns_rdataset_isassociated(&sigdsset))
- dns_rdataset_disassociate(&sigdsset);
- } else if (dns_rdataset_isassociated(&sigdsset)) {
- result = dns_db_deleterdataset(gdb, node,
- gversion,
- dns_rdatatype_rrsig,
- dns_rdatatype_ds);
- check_result(result, "dns_db_deleterdataset");
- dns_rdataset_disassociate(&sigdsset);
- }
- } else if (dns_rdataset_isassociated(&sigdsset))
- dns_rdataset_disassociate(&sigdsset);
- }
-
- /*
- * Make sure that NSEC bits are appropriately set.
- */
- dns_rdataset_init(&rdataset);
- RUNTIME_CHECK(dns_db_findrdataset(gdb, node, gversion,
- dns_rdatatype_nsec, 0, 0, &rdataset,
- NULL) == ISC_R_SUCCESS);
- if (!nokeys)
- changed = nsec_setbit(name, &rdataset, dns_rdatatype_rrsig, 1);
- if (changed) {
- dns_rdataset_disassociate(&rdataset);
- RUNTIME_CHECK(dns_db_findrdataset(gdb, node, gversion,
- dns_rdatatype_nsec, 0, 0,
- &rdataset,
- NULL) == ISC_R_SUCCESS);
- }
- if (hasds)
- (void)nsec_setbit(name, &rdataset, dns_rdatatype_ds, 1);
- else
- (void)nsec_setbit(name, &rdataset, dns_rdatatype_ds, 0);
- dns_rdataset_disassociate(&rdataset);
-
/*
* Now iterate through the rdatasets.
*/
* isn't a DS record.
*/
if (isdelegation) {
- if (rdataset.type != dns_rdatatype_nsec &&
+ if (rdataset.type != nsec_datatype &&
rdataset.type != dns_rdatatype_ds)
goto skip;
} else if (rdataset.type == dns_rdatatype_ds) {
while (result == ISC_R_SUCCESS) {
dns_rdatasetiter_current(rdsiter, &rdataset);
if (rdataset.type != dns_rdatatype_nsec &&
+ rdataset.type != dns_rdatatype_nsec3 &&
rdataset.type != dns_rdatatype_rrsig)
active = ISC_TRUE;
dns_rdataset_disassociate(&rdataset);
fatal("rdataset iteration failed: %s",
isc_result_totext(result));
- if (!active) {
+ if (!active && nsec_datatype == dns_rdatatype_nsec) {
/*%
* The node is empty of everything but NSEC / RRSIG records.
*/
fatal("rdataset iteration failed: %s",
isc_result_totext(result));
dns_rdatasetiter_destroy(&rdsiter2);
+
+#if 0
+ /*
+ * Delete all NSEC records and RRSIG(NSEC) if we are in
+ * NSEC3 mode and vica versa.
+ */
+ for (result = dns_rdatasetiter_first(rdsiter2);
+ result == ISC_R_SUCCESS;
+ result = dns_rdatasetiter_next(rdsiter2)) {
+ dns_rdatasetiter_current(rdsiter, &rdataset);
+ type = rdataset.type;
+ covers = rdataset.covers;
+ if (type == dns_rdatatype_rrsig)
+ type = covers;
+ dns_rdataset_disassociate(&rdataset);
+ if (type == nsec_datatype ||
+ (type != dns_rdatatype_nsec &&
+ type != dns_rdatatype_nsec3))
+ continue;
+ if (covers != 0)
+ type = dns_rdatatype_rrsig;
+ result = dns_db_deleterdataset(gdb, node, gversion,
+ type, covers);
+ check_result(result, "dns_db_deleterdataset()");
+ }
+#endif
}
dns_rdatasetiter_destroy(&rdsiter);
isc_result_t result;
gdbiter = NULL;
- result = dns_db_createiterator(gdb, ISC_FALSE, &gdbiter);
+ result = dns_db_createiterator(gdb, 0, &gdbiter);
check_result(result, "dns_db_createiterator()");
-
- result = dns_dbiterator_first(gdbiter);
- check_result(result, "dns_dbiterator_first()");
}
/*%
/*%
* Sign the apex of the zone.
+ * Note the origin may not be the first node if there are out of zone
+ * records.
*/
static void
signapex(void) {
dns_fixedname_init(&fixed);
name = dns_fixedname_name(&fixed);
+ result = dns_dbiterator_seek(gdbiter, gorigin);
+ check_result(result, "dns_dbiterator_seek()");
result = dns_dbiterator_current(gdbiter, &node, name);
check_result(result, "dns_dbiterator_current()");
signname(node, name);
dumpnode(name, node);
cleannode(gdb, gversion, node);
dns_db_detachnode(gdb, &node);
- result = dns_dbiterator_next(gdbiter);
+ result = dns_dbiterator_first(gdbiter);
if (result == ISC_R_NOMORE)
finished = ISC_TRUE;
else if (result != ISC_R_SUCCESS)
dns_rdataset_t nsec;
isc_boolean_t found;
isc_result_t result;
+ static dns_name_t *zonecut = NULL; /* Protected by namelock. */
+ static dns_fixedname_t fzonecut; /* Protected by namelock. */
static unsigned int ended = 0; /* Protected by namelock. */
if (shuttingdown)
if (result != ISC_R_SUCCESS)
fatal("failure iterating database: %s",
isc_result_totext(result));
+ /*
+ * The origin was handled by signapex().
+ */
+ if (dns_name_equal(name, gorigin)) {
+ dns_db_detachnode(gdb, &node);
+ goto next;
+ }
+ /*
+ * Sort the zone data from the glue and out-of-zone data.
+ * For NSEC zones nodes with zone data have NSEC records.
+ * For NSEC3 zones the NSEC3 nodes are zone data but
+ * outside of the zone name space. For the rest we need
+ * to track the bottom of zone cuts.
+ * Nodes which don't need to be signed are dumped here.
+ */
dns_rdataset_init(&nsec);
result = dns_db_findrdataset(gdb, node, gversion,
- dns_rdatatype_nsec, 0, 0,
+ nsec_datatype, 0, 0,
&nsec, NULL);
- if (result == ISC_R_SUCCESS)
- found = ISC_TRUE;
- else
- dumpnode(name, node);
if (dns_rdataset_isassociated(&nsec))
dns_rdataset_disassociate(&nsec);
- if (!found)
+ if (result == ISC_R_SUCCESS) {
+ found = ISC_TRUE;
+ } else if (nsec_datatype == dns_rdatatype_nsec3) {
+ if (dns_name_issubdomain(name, gorigin) &&
+ (zonecut == NULL ||
+ !dns_name_issubdomain(name, zonecut))) {
+ if (delegation(name, node, NULL)) {
+ dns_fixedname_init(&fzonecut);
+ zonecut = dns_fixedname_name(&fzonecut);
+ dns_name_copy(name, zonecut, NULL);
+ if (!OPTOUT(nsec3flags) ||
+ secure(name, node))
+ found = ISC_TRUE;
+ } else
+ found = ISC_TRUE;
+ }
+ }
+
+ if (!found) {
+ dumpnode(name, node);
dns_db_detachnode(gdb, &node);
+ }
+ next:
result = dns_dbiterator_next(gdbiter);
if (result == ISC_R_NOMORE) {
finished = ISC_TRUE;
isc_task_send(master, ISC_EVENT_PTR(&wevent));
}
+/*%
+ * Update / remove the DS RRset. Preserve RRSIG(DS) if possible.
+ */
+static void
+add_ds(dns_name_t *name, dns_dbnode_t *node, isc_uint32_t nsttl) {
+ dns_rdataset_t dsset;
+ dns_rdataset_t sigdsset;
+ isc_result_t result;
+
+ dns_rdataset_init(&dsset);
+ dns_rdataset_init(&sigdsset);
+ result = dns_db_findrdataset(gdb, node, gversion,
+ dns_rdatatype_ds,
+ 0, 0, &dsset, &sigdsset);
+ if (result == ISC_R_SUCCESS) {
+ dns_rdataset_disassociate(&dsset);
+ result = dns_db_deleterdataset(gdb, node, gversion,
+ dns_rdatatype_ds, 0);
+ check_result(result, "dns_db_deleterdataset");
+ }
+ result = loadds(name, nsttl, &dsset);
+ if (result == ISC_R_SUCCESS) {
+ result = dns_db_addrdataset(gdb, node, gversion, 0,
+ &dsset, 0, NULL);
+ check_result(result, "dns_db_addrdataset");
+ dns_rdataset_disassociate(&dsset);
+ if (dns_rdataset_isassociated(&sigdsset))
+ dns_rdataset_disassociate(&sigdsset);
+ } else if (dns_rdataset_isassociated(&sigdsset)) {
+ result = dns_db_deleterdataset(gdb, node, gversion,
+ dns_rdatatype_rrsig,
+ dns_rdatatype_ds);
+ check_result(result, "dns_db_deleterdataset");
+ dns_rdataset_disassociate(&sigdsset);
+ }
+}
+
/*%
* Generate NSEC records for the zone.
*/
dns_name_t *name, *nextname, *zonecut;
isc_boolean_t done = ISC_FALSE;
isc_result_t result;
+ isc_uint32_t nsttl = 0;
dns_fixedname_init(&fname);
name = dns_fixedname_name(&fname);
dns_fixedname_init(&fzonecut);
zonecut = NULL;
- result = dns_db_createiterator(gdb, ISC_FALSE, &dbiter);
+ result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter);
check_result(result, "dns_db_createiterator()");
result = dns_dbiterator_first(dbiter);
while (!done) {
dns_dbiterator_current(dbiter, &node, name);
- if (delegation(name, node, NULL)) {
+ if (delegation(name, node, &nsttl)) {
zonecut = dns_fixedname_name(&fzonecut);
dns_name_copy(name, zonecut, NULL);
+ if (generateds)
+ add_ds(name, node, nsttl);
}
result = dns_dbiterator_next(dbiter);
nextnode = NULL;
dns_dbiterator_destroy(&dbiter);
}
+/*%
+ * Does this node only contain NSEC3 records or RRSIG records or is empty.
+ */
+static isc_boolean_t
+nsec3only(dns_dbnode_t *node) {
+ dns_rdatasetiter_t *rdsiter = NULL;
+ isc_result_t result;
+ dns_rdataset_t rdataset;
+ isc_boolean_t answer = ISC_TRUE;
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
+ check_result(result, "dns_db_allrdatasets()");
+ result = dns_rdatasetiter_first(rdsiter);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdatasetiter_current(rdsiter, &rdataset);
+ if (rdataset.type != dns_rdatatype_nsec3 &&
+ rdataset.type != dns_rdatatype_rrsig) {
+ answer = ISC_FALSE;
+ result = ISC_R_NOMORE;
+ } else
+ result = dns_rdatasetiter_next(rdsiter);
+ dns_rdataset_disassociate(&rdataset);
+ }
+ if (result != ISC_R_NOMORE)
+ fatal("rdataset iteration failed: %s",
+ isc_result_totext(result));
+ dns_rdatasetiter_destroy(&rdsiter);
+ return (answer);
+}
+
+static void
+addnsec3param(const unsigned char *salt, size_t salt_length,
+ unsigned int iterations)
+{
+ dns_dbnode_t *node = NULL;
+ dns_rdata_nsec3param_t nsec3param;
+ unsigned char nsec3parambuf[5 + 255];
+ dns_rdatalist_t rdatalist;
+ dns_rdataset_t rdataset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_buffer_t b;
+ isc_result_t result;
+
+ dns_rdataset_init(&rdataset);
+
+ nsec3param.common.rdclass = gclass;
+ nsec3param.common.rdtype = dns_rdatatype_nsec3param;
+ ISC_LINK_INIT(&nsec3param.common, link);
+ nsec3param.mctx = NULL;
+ nsec3param.flags = 0;
+ nsec3param.hash = unknownalg ? DNS_NSEC3_UNKNOWNALG : dns_hash_sha1;
+ nsec3param.iterations = iterations;
+ nsec3param.salt_length = salt_length;
+ DE_CONST(salt, nsec3param.salt);
+
+ isc_buffer_init(&b, nsec3parambuf, sizeof(nsec3parambuf));
+ result = dns_rdata_fromstruct(&rdata, gclass,
+ dns_rdatatype_nsec3param,
+ &nsec3param, &b);
+ rdatalist.rdclass = rdata.rdclass;
+ rdatalist.type = rdata.type;
+ rdatalist.covers = 0;
+ rdatalist.ttl = 0;
+ ISC_LIST_INIT(rdatalist.rdata);
+ ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
+ result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
+ check_result(result, "dns_rdatalist_tordataset()");
+
+ result = dns_db_findnode(gdb, gorigin, ISC_TRUE, &node);
+ check_result(result, "dns_db_find(gorigin)");
+ result = dns_db_addrdataset(gdb, node, gversion, 0, &rdataset,
+ DNS_DBADD_MERGE, NULL);
+ if (result == DNS_R_UNCHANGED)
+ result = ISC_R_SUCCESS;
+ check_result(result, "addnsec3param: dns_db_addrdataset()");
+ dns_db_detachnode(gdb, &node);
+}
+
+static void
+addnsec3(dns_name_t *name, dns_dbnode_t *node,
+ const unsigned char *salt, size_t salt_length,
+ unsigned int iterations, hashlist_t *hashlist,
+ dns_ttl_t ttl)
+{
+ unsigned char hash[NSEC3_MAX_HASH_LENGTH];
+ const unsigned char *nexthash;
+ unsigned char nsec3buffer[DNS_NSEC3_BUFFERSIZE];
+ dns_fixedname_t hashname;
+ dns_rdatalist_t rdatalist;
+ dns_rdataset_t rdataset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_result_t result;
+ dns_dbnode_t *nsec3node = NULL;
+ char namebuf[DNS_NAME_FORMATSIZE];
+ size_t hash_length;
+
+ dns_name_format(name, namebuf, sizeof(namebuf));
+
+ dns_fixedname_init(&hashname);
+ dns_rdataset_init(&rdataset);
+
+ dns_name_downcase(name, name, NULL);
+ result = dns_nsec3_hashname(&hashname, hash, &hash_length,
+ name, gorigin, dns_hash_sha1, iterations,
+ salt, salt_length);
+ check_result(result, "addnsec3: dns_nsec3_hashname()");
+ nexthash = hashlist_findnext(hashlist, hash);
+ result = dns_nsec3_buildrdata(gdb, gversion, node,
+ unknownalg ?
+ DNS_NSEC3_UNKNOWNALG : dns_hash_sha1,
+ nsec3flags, iterations,
+ salt, salt_length,
+ nexthash, ISC_SHA1_DIGESTLENGTH,
+ nsec3buffer, &rdata);
+ check_result(result, "addnsec3: dns_nsec3_buildrdata()");
+ rdatalist.rdclass = rdata.rdclass;
+ rdatalist.type = rdata.type;
+ rdatalist.covers = 0;
+ rdatalist.ttl = ttl;
+ ISC_LIST_INIT(rdatalist.rdata);
+ ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
+ result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
+ check_result(result, "dns_rdatalist_tordataset()");
+ result = dns_db_findnsec3node(gdb, dns_fixedname_name(&hashname),
+ ISC_TRUE, &nsec3node);
+ check_result(result, "addnsec3: dns_db_findnode()");
+ result = dns_db_addrdataset(gdb, nsec3node, gversion, 0, &rdataset,
+ 0, NULL);
+ if (result == DNS_R_UNCHANGED)
+ result = ISC_R_SUCCESS;
+ check_result(result, "addnsec3: dns_db_addrdataset()");
+ dns_db_detachnode(gdb, &nsec3node);
+}
+
+/*%
+ * Clean out NSEC3 record and RRSIG(NSEC3) that are not in the hash list.
+ *
+ * Extract the hash from the first label of 'name' then see if it
+ * is in hashlist. If 'name' is not in the hashlist then delete the
+ * any NSEC3 records which have the same parameters as the chain we
+ * are building.
+ *
+ * XXXMPA Should we also check that it of the form <hash>.<origin>?
+ */
+static void
+nsec3clean(dns_name_t *name, dns_dbnode_t *node,
+ unsigned int hashalg, unsigned int iterations,
+ const unsigned char *salt, size_t salt_length, hashlist_t *hashlist)
+{
+ dns_label_t label;
+ dns_rdata_nsec3_t nsec3;
+ dns_rdata_t rdata, delrdata;
+ dns_rdatalist_t rdatalist;
+ dns_rdataset_t rdataset, delrdataset;
+ isc_boolean_t delete_rrsigs = ISC_FALSE;
+ isc_buffer_t target;
+ isc_result_t result;
+ unsigned char hash[NSEC3_MAX_HASH_LENGTH + 1];
+
+ /*
+ * Get the first label.
+ */
+ dns_name_getlabel(name, 0, &label);
+
+ /*
+ * We want just the label contents.
+ */
+ isc_region_consume(&label, 1);
+
+ /*
+ * Decode base32hex string.
+ */
+ isc_buffer_init(&target, hash, sizeof(hash) - 1);
+ result = isc_base32hex_decoderegion(&label, &target);
+ if (result != ISC_R_SUCCESS)
+ return;
+
+ hash[isc_buffer_usedlength(&target)] = 0;
+
+ if (hashlist_exists(hashlist, hash))
+ return;
+
+ /*
+ * Verify that the NSEC3 parameters match the current ones
+ * otherwise we are dealing with a different NSEC3 chain.
+ */
+ dns_rdataset_init(&rdataset);
+ dns_rdataset_init(&delrdataset);
+
+ result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_nsec3,
+ 0, 0, &rdataset, NULL);
+ if (result != ISC_R_SUCCESS)
+ return;
+
+ /*
+ * Delete any matching NSEC3 records which have parameters that
+ * match the NSEC3 chain we are building.
+ */
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdata_init(&rdata);
+ dns_rdataset_current(&rdataset, &rdata);
+ dns_rdata_tostruct(&rdata, &nsec3, NULL);
+ if (nsec3.hash == hashalg &&
+ nsec3.iterations == iterations &&
+ nsec3.salt_length == salt_length &&
+ !memcmp(nsec3.salt, salt, salt_length))
+ break;
+ rdatalist.rdclass = rdata.rdclass;
+ rdatalist.type = rdata.type;
+ rdatalist.covers = 0;
+ rdatalist.ttl = rdataset.ttl;
+ ISC_LIST_INIT(rdatalist.rdata);
+ dns_rdata_init(&delrdata);
+ dns_rdata_clone(&rdata, &delrdata);
+ ISC_LIST_APPEND(rdatalist.rdata, &delrdata, link);
+ result = dns_rdatalist_tordataset(&rdatalist, &delrdataset);
+ check_result(result, "dns_rdatalist_tordataset()");
+ result = dns_db_subtractrdataset(gdb, node, gversion,
+ &delrdataset, 0, NULL);
+ dns_rdataset_disassociate(&delrdataset);
+ if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED)
+ check_result(result, "dns_db_subtractrdataset(NSEC3)");
+ delete_rrsigs = ISC_TRUE;
+ }
+ dns_rdataset_disassociate(&rdataset);
+ if (result != ISC_R_NOMORE)
+ check_result(result, "dns_rdataset_first/next");
+
+ if (!delete_rrsigs)
+ return;
+ /*
+ * Delete the NSEC3 RRSIGs
+ */
+ result = dns_db_deleterdataset(gdb, node, gversion,
+ dns_rdatatype_rrsig,
+ dns_rdatatype_nsec3);
+ if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED)
+ check_result(result, "dns_db_deleterdataset(RRSIG(NSEC3))");
+}
+
+/*
+ * Generate NSEC3 records for the zone.
+ */
+static void
+nsec3ify(unsigned int hashalg, unsigned int iterations,
+ const unsigned char *salt, size_t salt_length, hashlist_t *hashlist)
+{
+ dns_dbiterator_t *dbiter = NULL;
+ dns_dbnode_t *node = NULL, *nextnode = NULL;
+ dns_fixedname_t fname, fnextname, fzonecut;
+ dns_name_t *name, *nextname, *zonecut;
+ isc_boolean_t done = ISC_FALSE;
+ isc_result_t result;
+ isc_boolean_t active;
+ isc_uint32_t nsttl = 0;
+ unsigned int count, nlabels;
+ int order;
+
+ dns_fixedname_init(&fname);
+ name = dns_fixedname_name(&fname);
+ dns_fixedname_init(&fnextname);
+ nextname = dns_fixedname_name(&fnextname);
+ dns_fixedname_init(&fzonecut);
+ zonecut = NULL;
+
+ /*
+ * Walk the zone generating the hash names.
+ */
+ result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter);
+ check_result(result, "dns_db_createiterator()");
+
+ result = dns_dbiterator_first(dbiter);
+ check_result(result, "dns_dbiterator_first()");
+
+ while (!done) {
+ dns_dbiterator_current(dbiter, &node, name);
+ result = dns_dbiterator_next(dbiter);
+ nextnode = NULL;
+ while (result == ISC_R_SUCCESS) {
+ result = dns_dbiterator_current(dbiter, &nextnode,
+ nextname);
+ if (result != ISC_R_SUCCESS)
+ break;
+ active = active_node(nextnode);
+ if (!active) {
+ dns_db_detachnode(gdb, &nextnode);
+ result = dns_dbiterator_next(dbiter);
+ continue;
+ }
+ if (!dns_name_issubdomain(nextname, gorigin) ||
+ (zonecut != NULL &&
+ dns_name_issubdomain(nextname, zonecut))) {
+ dns_db_detachnode(gdb, &nextnode);
+ result = dns_dbiterator_next(dbiter);
+ continue;
+ }
+ if (delegation(nextname, nextnode, &nsttl)) {
+ zonecut = dns_fixedname_name(&fzonecut);
+ dns_name_copy(nextname, zonecut, NULL);
+ if (generateds)
+ add_ds(nextname, nextnode, nsttl);
+ if (OPTOUT(nsec3flags) &&
+ !secure(nextname, nextnode)) {
+ dns_db_detachnode(gdb, &nextnode);
+ result = dns_dbiterator_next(dbiter);
+ continue;
+ }
+ }
+ dns_db_detachnode(gdb, &nextnode);
+ break;
+ }
+ if (result == ISC_R_NOMORE) {
+ dns_name_copy(gorigin, nextname, NULL);
+ done = ISC_TRUE;
+ } else if (result != ISC_R_SUCCESS)
+ fatal("iterating through the database failed: %s",
+ isc_result_totext(result));
+ dns_name_downcase(name, name, NULL);
+ hashlist_add_dns_name(hashlist, name, hashalg, iterations,
+ salt, salt_length, ISC_FALSE);
+ dns_db_detachnode(gdb, &node);
+ /*
+ * Add hashs for empty nodes. Use closest encloser logic.
+ * The closest encloser either has data or is a empty
+ * node for another <name,nextname> span so we don't add
+ * it here. Empty labels on nextname are within the span.
+ */
+ dns_name_downcase(nextname, nextname, NULL);
+ dns_name_fullcompare(name, nextname, &order, &nlabels);
+ addnowildcardhash(hashlist, name, hashalg, iterations,
+ salt, salt_length);
+ count = dns_name_countlabels(nextname);
+ while (count > nlabels + 1) {
+ count--;
+ dns_name_split(nextname, count, NULL, nextname);
+ hashlist_add_dns_name(hashlist, nextname, hashalg,
+ iterations, salt, salt_length,
+ ISC_FALSE);
+ addnowildcardhash(hashlist, nextname, hashalg,
+ iterations, salt, salt_length);
+ }
+ }
+ dns_dbiterator_destroy(&dbiter);
+
+ /*
+ * We have all the hashes now so we can sort them.
+ */
+ hashlist_sort(hashlist);
+
+ /*
+ * Check for duplicate hashes. If found the salt needs to
+ * be changed.
+ */
+ if (hashlist_hasdup(hashlist))
+ fatal("Duplicate hash detected. Pick a different salt.");
+
+ /*
+ * Generate the nsec3 records.
+ */
+ zonecut = NULL;
+ done = ISC_FALSE;
+
+ addnsec3param(salt, salt_length, iterations);
+
+ result = dns_db_createiterator(gdb, DNS_DB_NONSEC3, &dbiter);
+ check_result(result, "dns_db_createiterator()");
+
+ result = dns_dbiterator_first(dbiter);
+ check_result(result, "dns_dbiterator_first()");
+
+ while (!done) {
+ dns_dbiterator_current(dbiter, &node, name);
+ result = dns_dbiterator_next(dbiter);
+ nextnode = NULL;
+ while (result == ISC_R_SUCCESS) {
+ result = dns_dbiterator_current(dbiter, &nextnode,
+ nextname);
+ if (result != ISC_R_SUCCESS)
+ break;
+ /*
+ * Cleanout NSEC3 RRsets which don't exist in the
+ * hash table.
+ */
+ nsec3clean(nextname, nextnode, hashalg, iterations,
+ salt, salt_length, hashlist);
+ /*
+ * Skip NSEC3 only nodes when looking for the next
+ * node in the zone. Also skips now empty nodes.
+ */
+ if (nsec3only(nextnode)) {
+ dns_db_detachnode(gdb, &nextnode);
+ result = dns_dbiterator_next(dbiter);
+ continue;
+ }
+ if (!dns_name_issubdomain(nextname, gorigin) ||
+ (zonecut != NULL &&
+ dns_name_issubdomain(nextname, zonecut))) {
+ dns_db_detachnode(gdb, &nextnode);
+ result = dns_dbiterator_next(dbiter);
+ continue;
+ }
+ if (delegation(nextname, nextnode, NULL)) {
+ zonecut = dns_fixedname_name(&fzonecut);
+ dns_name_copy(nextname, zonecut, NULL);
+ if (OPTOUT(nsec3flags) &&
+ !secure(nextname, nextnode)) {
+ dns_db_detachnode(gdb, &nextnode);
+ result = dns_dbiterator_next(dbiter);
+ continue;
+ }
+ }
+ dns_db_detachnode(gdb, &nextnode);
+ break;
+ }
+ if (result == ISC_R_NOMORE) {
+ dns_name_copy(gorigin, nextname, NULL);
+ done = ISC_TRUE;
+ } else if (result != ISC_R_SUCCESS)
+ fatal("iterating through the database failed: %s",
+ isc_result_totext(result));
+ /*
+ * We need to pause here to release the lock on the database.
+ */
+ dns_dbiterator_pause(dbiter);
+ addnsec3(name, node, salt, salt_length, iterations,
+ hashlist, zonettl);
+ dns_db_detachnode(gdb, &node);
+ /*
+ * Add NSEC3's for empty nodes. Use closest encloser logic.
+ */
+ dns_name_fullcompare(name, nextname, &order, &nlabels);
+ count = dns_name_countlabels(nextname);
+ while (count > nlabels + 1) {
+ count--;
+ dns_name_split(nextname, count, NULL, nextname);
+ addnsec3(nextname, NULL, salt, salt_length,
+ iterations, hashlist, zonettl);
+ }
+ }
+ dns_dbiterator_destroy(&dbiter);
+}
+
/*%
* Load the zone file from disk
*/
fprintf(stderr, "\t-n ncpus (number of cpus present)\n");
fprintf(stderr, "\t-k key_signing_key\n");
fprintf(stderr, "\t-l lookasidezone\n");
+ fprintf(stderr, "\t-3 salt (NSEC3 salt)\n");
+ fprintf(stderr, "\t-H interations (NSEC3 interations)\n");
+ fprintf(stderr, "\t-A (NSEC3 optout)\n");
fprintf(stderr, "\t-z:\t");
fprintf(stderr, "ignore KSK flag in DNSKEYs");
isc_task_t **tasks = NULL;
isc_buffer_t b;
int len;
+ unsigned int iterations = 100U;
+ const unsigned char *salt = NULL;
+ size_t salt_length = 0;
+ unsigned char saltbuf[255];
+ hashlist_t hashlist;
+
+#define CMDLINE_FLAGS "3:aAc:d:e:f:ghH:i:I:j:k:l:m:n:N:o:O:pr:s:StUv:z"
+
+ /*
+ * Process memory debugging arguement first.
+ */
+ while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
+ switch (ch) {
+ case 'm':
+ if (strcasecmp(isc_commandline_argument, "record") == 0)
+ isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
+ if (strcasecmp(isc_commandline_argument, "trace") == 0)
+ isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
+ if (strcasecmp(isc_commandline_argument, "usage") == 0)
+ isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
+ if (strcasecmp(isc_commandline_argument, "size") == 0)
+ isc_mem_debugging |= ISC_MEM_DEBUGSIZE;
+ if (strcasecmp(isc_commandline_argument, "mctx") == 0)
+ isc_mem_debugging |= ISC_MEM_DEBUGCTX;
+ break;
+ default:
+ break;
+ }
+ }
+ isc_commandline_reset = ISC_TRUE;
masterstyle = &dns_master_style_explicitttl;
isc_commandline_errprint = ISC_FALSE;
- while ((ch = isc_commandline_parse(argc, argv,
- "ac:d:e:f:ghi:I:j:k:l:n:N:o:O:pr:s:Stv:z"))
- != -1) {
+ while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
switch (ch) {
+ case '3':
+ if (strcmp(isc_commandline_argument, "-")) {
+ isc_buffer_t target;
+ char *sarg;
+
+ sarg = isc_commandline_argument;
+ isc_buffer_init(&target, saltbuf,
+ sizeof(saltbuf));
+ result = isc_hex_decodestring(sarg, &target);
+ check_result(result,
+ "isc_hex_decodestring(salt)");
+ salt = saltbuf;
+ salt_length = isc_buffer_usedlength(&target);
+ } else {
+ salt = saltbuf;
+ salt_length = 0;
+ }
+ nsec_datatype = dns_rdatatype_nsec3;
+ break;
+
+ case 'A':
+ nsec3flags |= DNS_NSEC3FLAG_OPTOUT;
+ break;
+
case 'a':
tryverify = ISC_TRUE;
break;
dskeyfile[ndskeys++] = isc_commandline_argument;
break;
+ case 'm':
+ break;
+
case 'n':
endp = NULL;
ntasks = strtol(isc_commandline_argument, &endp, 0);
serialformatstr = isc_commandline_argument;
break;
+ case 'H':
+ iterations = strtoul(isc_commandline_argument,
+ &endp, 0);
+ if (*endp != '\0')
+ fatal("iterations must be numeric");
+ if (iterations > 0xffffU)
+ fatal("iterations too big");
+ break;
+
case 'o':
origin = isc_commandline_argument;
break;
printstats = ISC_TRUE;
break;
+ case 'U': /* Undocumented for testing only. */
+ unknownalg = ISC_TRUE;
+ break;
+
case 'v':
endp = NULL;
verbose = strtol(isc_commandline_argument, &endp, 0);
cycle = (endtime - starttime) / 4;
if (ntasks == 0)
- ntasks = isc_os_ncpus();
+ ntasks = isc_os_ncpus() * 2;
vbprintf(4, "using %d cpus\n", ntasks);
rdclass = strtoclass(classname);
0, 24, 0, 0, 0, 8, mctx);
check_result(result, "dns_master_stylecreate");
-
gdb = NULL;
TIME_NOW(&timer_start);
loadzone(file, origin, rdclass, &gdb);
gclass = dns_db_class(gdb);
zonettl = soattl();
+ if (IS_NSEC3) {
+ isc_boolean_t answer;
+ hash_length = dns_nsec3_hashlength(dns_hash_sha1);
+ hashlist_init(&hashlist, dns_db_nodecount(gdb) * 2,
+ hash_length);
+ result = dns_nsec_nseconly(gdb, gversion, &answer);
+ check_result(result, "dns_nsec_nseconly");
+ if (answer)
+ fatal("NSEC3 generation requested with "
+ "NSEC only DNSKEY");
+ }
+
ISC_LIST_INIT(keylist);
if (argc == 0) {
nokeys = ISC_TRUE;
}
+ if (IS_NSEC3) {
+ unsigned int max;
+ result = dns_nsec3_maxiterations(gdb, NULL, mctx, &max);
+ check_result(result, "dns_nsec3_maxiterations()");
+ if (iterations > max)
+ fatal("NSEC3 interations too big for weakest DNSKEY "
+ "strength. Maximum iterations allowed %u.", max);
+ }
+
warnifallksk(gdb);
gversion = NULL;
break;
}
- nsecify();
+ if (IS_NSEC3)
+ nsec3ify(dns_hash_sha1, iterations, salt, salt_length,
+ &hashlist);
+ else
+ nsecify();
if (!nokeys) {
writeset("keyset-", dns_rdatatype_dnskey);
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
[<!ENTITY mdash "—">]>
<!--
- - 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
- PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- $Id: dnssec-signzone.docbook,v 1.27 2007/06/18 23:47:18 tbox Exp $ -->
+<!-- $Id: dnssec-signzone.docbook,v 1.28 2008/09/24 02:46:21 marka Exp $ -->
<refentry id="man.dnssec-signzone">
<refentryinfo>
<date>June 30, 2000</date>
<year>2005</year>
<year>2006</year>
<year>2007</year>
+ <year>2008</year>
<holder>Internet Systems Consortium, Inc. ("ISC")</holder>
</copyright>
<copyright>
<arg><option>-t</option></arg>
<arg><option>-v <replaceable class="parameter">level</replaceable></option></arg>
<arg><option>-z</option></arg>
+ <arg><option>-3 <replaceable class="parameter">salt</replaceable></option></arg>
+ <arg><option>-H <replaceable class="parameter">iterations</replaceable></option></arg>
+ <arg><option>-A</option></arg>
<arg choice="req">zonefile</arg>
<arg rep="repeat">key</arg>
</cmdsynopsis>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>-3 <replaceable class="parameter">salt</replaceable></term>
+ <listitem>
+ <para>
+ Generate a NSEC3 chain with the given hex encoded salt.
+ A dash (<replaceable class="parameter">salt</replaceable>) can
+ be used to indicate that no salt is to be used when generating the NSEC3 chain.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-H <replaceable class="parameter">iterations</replaceable></term>
+ <listitem>
+ <para>
+ When generating a NSEC3 chain use this many interations. The
+ default is 100.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-A</term>
+ <listitem>
+ <para>
+ When generating a NSEC3 chain set the OPTOUT flag on all
+ NSEC3 records and do not generate NSEC3 records for insecure
+ delegations.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term>zonefile</term>
<listitem>
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnssectool.h,v 1.20 2007/06/19 23:46:59 tbox Exp $ */
+/* $Id: dnssectool.h,v 1.21 2008/09/24 02:46:21 marka Exp $ */
#ifndef DNSSECTOOL_H
#define DNSSECTOOL_H 1
void
type_format(const dns_rdatatype_t type, char *cp, unsigned int size);
-#define TYPE_FORMATSIZE 10
+#define TYPE_FORMATSIZE 20
void
alg_format(const dns_secalg_t alg, char *cp, unsigned int size);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: config.c,v 1.90 2008/09/04 05:56:42 marka Exp $ */
+/* $Id: config.c,v 1.91 2008/09/24 02:46:21 marka Exp $ */
/*! \file */
clients-per-query 10;\n\
max-clients-per-query 100;\n\
zero-no-soa-ttl-cache no;\n\
+ nsec3-test-zone no;\n\
"
" /* zone */\n\
- PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- $Id: named.conf.docbook,v 1.38 2008/09/04 05:56:42 marka Exp $ -->
+<!-- $Id: named.conf.docbook,v 1.39 2008/09/24 02:46:21 marka Exp $ -->
<refentry>
<refentryinfo>
<date>Aug 13, 2004</date>
zero-no-soa-ttl <replaceable>boolean</replaceable>;
zero-no-soa-ttl-cache <replaceable>boolean</replaceable>;
+ nsec3-test-zone <replaceable>boolean</replaceable>; // testing only
+
allow-v6-synthesis { <replaceable>address_match_element</replaceable>; ... }; // obsolete
deallocate-on-exit <replaceable>boolean</replaceable>; // obsolete
fake-iquery <replaceable>boolean</replaceable>; // obsolete
try-tcp-refresh <replaceable>boolean</replaceable>;
key-directory <replaceable>quoted_string</replaceable>;
+ nsec3-test-zone <replaceable>boolean</replaceable>; // testing only
+
ixfr-base <replaceable>quoted_string</replaceable>; // obsolete
ixfr-tmp-file <replaceable>quoted_string</replaceable>; // obsolete
maintain-ixfr-base <replaceable>boolean</replaceable>; // obsolete
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: query.c,v 1.308 2008/08/26 06:09:18 marka Exp $ */
+/* $Id: query.c,v 1.309 2008/09/24 02:46:21 marka Exp $ */
/*! \file */
#include <isc/mem.h>
#include <isc/util.h>
+#include <isc/hex.h>
#include <dns/adb.h>
#include <dns/byaddr.h>
#include <dns/events.h>
#include <dns/message.h>
#include <dns/ncache.h>
+#include <dns/nsec3.h>
#include <dns/order.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#define SECURE(c) (((c)->query.attributes & \
NS_QUERYATTR_SECURE) != 0)
+/*% No QNAME Proof? */
+#define NOQNAME(r) (((r)->attributes & \
+ DNS_RDATASETATTR_NOQNAME) != 0)
+
#if 0
#define CTRACE(m) isc_log_write(ns_g_lctx, \
NS_LOGCATEGORY_CLIENT, \
validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
+static void
+query_findclosestnsec3(dns_name_t *qname, dns_db_t *db,
+ dns_dbversion_t *version, ns_client_t *client,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
+ dns_name_t *fname, isc_boolean_t exact,
+ dns_name_t *found);
+
/*%
* Increment query statistics counters.
*/
*/
static void
mark_secure(ns_client_t *client, dns_db_t *db, dns_name_t *name,
- dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+ isc_uint32_t ttl, dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset)
{
isc_result_t result;
dns_dbnode_t *node = NULL;
result = dns_db_findnode(db, name, ISC_TRUE, &node);
if (result != ISC_R_SUCCESS)
return;
+ /*
+ * Bound the validated ttls then minimise.
+ */
+ if (sigrdataset->ttl > ttl)
+ sigrdataset->ttl = ttl;
+ if (rdataset->ttl > ttl)
+ rdataset->ttl = ttl;
+ if (rdataset->ttl > sigrdataset->ttl)
+ rdataset->ttl = sigrdataset->ttl;
+ else
+ sigrdataset->ttl = rdataset->ttl;
+
(void)dns_db_addrdataset(db, node, NULL, client->now, rdataset,
0, NULL);
(void)dns_db_addrdataset(db, node, NULL, client->now, sigrdataset,
client->view->acceptexpired)) {
dst_key_free(&key);
dns_rdataset_disassociate(&keyrdataset);
- mark_secure(client, db, name, rdataset,
- sigrdataset);
+ mark_secure(client, db, name,
+ rrsig.originalttl,
+ rdataset, sigrdataset);
return (ISC_TRUE);
}
dst_key_free(&key);
}
}
+static void
+fixrdataset(ns_client_t *client, dns_rdataset_t **rdataset) {
+ if (*rdataset == NULL)
+ *rdataset = query_newrdataset(client);
+ else if (dns_rdataset_isassociated(*rdataset))
+ dns_rdataset_disassociate(*rdataset);
+}
+
+static void
+fixfname(ns_client_t *client, dns_name_t **fname, isc_buffer_t **dbuf,
+ isc_buffer_t *nbuf)
+{
+ if (*fname == NULL) {
+ *dbuf = query_getnamebuf(client);
+ if (*dbuf == NULL)
+ return;
+ *fname = query_newname(client, *dbuf, nbuf);
+ }
+}
+
static void
query_addds(ns_client_t *client, dns_db_t *db, dns_dbnode_t *node,
- dns_dbversion_t *version)
+ dns_dbversion_t *version, dns_name_t *name)
{
+ dns_fixedname_t fixed;
+ dns_name_t *fname = NULL;
dns_name_t *rname;
dns_rdataset_t *rdataset, *sigrdataset;
+ isc_buffer_t *dbuf, b;
isc_result_t result;
+ unsigned int count;
CTRACE("query_addds");
rname = NULL;
result = dns_db_findrdataset(db, node, version, dns_rdatatype_ds, 0,
client->now, rdataset, sigrdataset);
/*
- * If we didn't find it, look for an NSEC. */
+ * If we didn't find it, look for an NSEC.
+ */
if (result == ISC_R_NOTFOUND)
result = dns_db_findrdataset(db, node, version,
dns_rdatatype_nsec, 0, client->now,
rdataset, sigrdataset);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
- goto cleanup;
+ goto addnsec3;
if (!dns_rdataset_isassociated(rdataset) ||
!dns_rdataset_isassociated(sigrdataset))
- goto cleanup;
+ goto addnsec3;
/*
* We've already added the NS record, so if the name's not there,
ISC_LIST_APPEND(rname->list, sigrdataset, link);
rdataset = NULL;
sigrdataset = NULL;
+ return;
+
+ addnsec3:
+ /*
+ * Add the NSEC3 which proves the DS does not exist.
+ */
+ dbuf = query_getnamebuf(client);
+ if (dbuf == NULL)
+ goto cleanup;
+ fname = query_newname(client, dbuf, &b);
+ dns_fixedname_init(&fixed);
+ query_findclosestnsec3(name, db, version, client, rdataset,
+ sigrdataset, fname, ISC_TRUE,
+ dns_fixedname_name(&fixed));
+ if (!dns_rdataset_isassociated(rdataset))
+ goto cleanup;
+ query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf,
+ DNS_SECTION_AUTHORITY);
+ /*
+ * Did we find the closest provable encloser instead?
+ * If so add the nearest to the closest provable encloser.
+ */
+ if (!dns_name_equal(name, dns_fixedname_name(&fixed))) {
+ count = dns_name_countlabels(dns_fixedname_name(&fixed)) + 1;
+ dns_name_getlabelsequence(name,
+ dns_name_countlabels(name) - count,
+ count, dns_fixedname_name(&fixed));
+ fixfname(client, &fname, &dbuf, &b);
+ fixrdataset(client, &rdataset);
+ fixrdataset(client, &sigrdataset);
+ if (fname == NULL || rdataset == NULL || sigrdataset == NULL)
+ goto cleanup;
+ query_findclosestnsec3(dns_fixedname_name(&fixed), db, version,
+ client, rdataset, sigrdataset, fname,
+ ISC_FALSE, NULL);
+ if (!dns_rdataset_isassociated(rdataset))
+ goto cleanup;
+ query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf,
+ DNS_SECTION_AUTHORITY);
+ }
cleanup:
if (rdataset != NULL)
query_putrdataset(client, &rdataset);
if (sigrdataset != NULL)
query_putrdataset(client, &sigrdataset);
+ if (fname != NULL)
+ query_releasename(client, &fname);
}
static void
dns_name_t *wname;
dns_dbnode_t *node;
unsigned int options;
- unsigned int olabels, nlabels;
+ unsigned int olabels, nlabels, labels;
isc_result_t result;
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_nsec_t nsec;
isc_boolean_t have_wname;
int order;
+ dns_fixedname_t cfixed;
+ dns_name_t *cname;
CTRACE("query_addwildcardproof");
fname = NULL;
0, &node, fname, rdataset, sigrdataset);
if (node != NULL)
dns_db_detachnode(db, &node);
- if (result == DNS_R_NXDOMAIN) {
+
+ if (!dns_rdataset_isassociated(rdataset)) {
+ /*
+ * fname contains the closest encloser.
+ */
+ dns_fixedname_init(&cfixed);
+ cname = dns_fixedname_name(&cfixed);
+ dns_name_copy(fname, cname, NULL);
+
+ /*
+ * Add closest (provable) encloser NSEC3.
+ */
+ query_findclosestnsec3(cname, db, NULL, client, rdataset,
+ sigrdataset, fname, ISC_TRUE, cname);
+ if (!dns_rdataset_isassociated(rdataset))
+ goto cleanup;
+ query_addrrset(client, &fname, &rdataset, &sigrdataset,
+ dbuf, DNS_SECTION_AUTHORITY);
+
+ if (fname == NULL) {
+ dbuf = query_getnamebuf(client);
+ if (dbuf == NULL)
+ goto cleanup;
+ fname = query_newname(client, dbuf, &b);
+ }
+
+ if (rdataset == NULL)
+ rdataset = query_newrdataset(client);
+ else if (dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+
+ if (sigrdataset == NULL)
+ sigrdataset = query_newrdataset(client);
+ else if (dns_rdataset_isassociated(sigrdataset))
+ dns_rdataset_disassociate(sigrdataset);
+
+ if (fname == NULL || rdataset == NULL || sigrdataset == NULL)
+ goto cleanup;
+ /*
+ * Add no qname proof.
+ */
+ labels = dns_name_countlabels(cname) + 1;
+ if (dns_name_countlabels(name) == labels)
+ dns_name_copy(name, wname, NULL);
+ else
+ dns_name_split(name, labels, NULL, wname);
+
+ query_findclosestnsec3(wname, db, NULL, client, rdataset,
+ sigrdataset, fname, ISC_FALSE, NULL);
+ if (!dns_rdataset_isassociated(rdataset))
+ goto cleanup;
+ query_addrrset(client, &fname, &rdataset, &sigrdataset,
+ dbuf, DNS_SECTION_AUTHORITY);
+
+ if (ispositive)
+ goto cleanup;
+
+ /*
+ * Add the no wildcard proof.
+ */
+ if (fname == NULL) {
+ dbuf = query_getnamebuf(client);
+ if (dbuf == NULL)
+ goto cleanup;
+ fname = query_newname(client, dbuf, &b);
+ }
+
+ if (rdataset == NULL)
+ rdataset = query_newrdataset(client);
+ else if (dns_rdataset_isassociated(rdataset))
+ dns_rdataset_disassociate(rdataset);
+
+ if (sigrdataset == NULL)
+ sigrdataset = query_newrdataset(client);
+ else if (dns_rdataset_isassociated(sigrdataset))
+ dns_rdataset_disassociate(sigrdataset);
+
+ if (fname == NULL || rdataset == NULL || sigrdataset == NULL)
+ goto cleanup;
+ result = dns_name_concatenate(dns_wildcardname,
+ cname, wname, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ query_findclosestnsec3(wname, db, NULL, client, rdataset,
+ sigrdataset, fname, ISC_FALSE, NULL);
+ if (!dns_rdataset_isassociated(rdataset))
+ goto cleanup;
+ query_addrrset(client, &fname, &rdataset, &sigrdataset,
+ dbuf, DNS_SECTION_AUTHORITY);
+
+ goto cleanup;
+ } else if (result == DNS_R_NXDOMAIN) {
if (!ispositive)
result = dns_rdataset_first(rdataset);
if (result == ISC_R_SUCCESS) {
if (sigrdatasetp == NULL)
return;
+
sigrdataset = *sigrdatasetp;
if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset))
return;
query_addnoqnameproof(ns_client_t *client, dns_rdataset_t *rdataset) {
isc_buffer_t *dbuf, b;
dns_name_t *fname;
- dns_rdataset_t *nsec, *nsecsig;
+ dns_rdataset_t *neg, *negsig;
isc_result_t result = ISC_R_NOMEMORY;
CTRACE("query_addnoqnameproof");
fname = NULL;
- nsec = NULL;
- nsecsig = NULL;
+ neg = NULL;
+ negsig = NULL;
dbuf = query_getnamebuf(client);
if (dbuf == NULL)
goto cleanup;
fname = query_newname(client, dbuf, &b);
- nsec = query_newrdataset(client);
- nsecsig = query_newrdataset(client);
- if (fname == NULL || nsec == NULL || nsecsig == NULL)
+ neg = query_newrdataset(client);
+ negsig = query_newrdataset(client);
+ if (fname == NULL || neg == NULL || negsig == NULL)
+ goto cleanup;
+
+ result = dns_rdataset_getnoqname(rdataset, fname, neg, negsig);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ query_addrrset(client, &fname, &neg, &negsig, dbuf,
+ DNS_SECTION_AUTHORITY);
+
+ if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) == 0)
goto cleanup;
- result = dns_rdataset_getnoqname(rdataset, fname, nsec, nsecsig);
+ if (fname == NULL) {
+ dbuf = query_getnamebuf(client);
+ if (dbuf == NULL)
+ goto cleanup;
+ fname = query_newname(client, dbuf, &b);
+ }
+ if (neg == NULL)
+ neg = query_newrdataset(client);
+ else if (dns_rdataset_isassociated(neg))
+ dns_rdataset_disassociate(neg);
+ if (negsig == NULL)
+ negsig = query_newrdataset(client);
+ else if (dns_rdataset_isassociated(negsig))
+ dns_rdataset_disassociate(negsig);
+ if (fname == NULL || neg == NULL || negsig == NULL)
+ goto cleanup;
+ result = dns_rdataset_getclosest(rdataset, fname, neg, negsig);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
- query_addrrset(client, &fname, &nsec, &nsecsig, dbuf,
+ query_addrrset(client, &fname, &neg, &negsig, dbuf,
DNS_SECTION_AUTHORITY);
cleanup:
- if (nsec != NULL)
- query_putrdataset(client, &nsec);
- if (nsecsig != NULL)
- query_putrdataset(client, &nsecsig);
+ if (neg != NULL)
+ query_putrdataset(client, &neg);
+ if (negsig != NULL)
+ query_putrdataset(client, &negsig);
if (fname != NULL)
query_releasename(client, &fname);
}
}
}
+static void
+query_findclosestnsec3(dns_name_t *qname, dns_db_t *db,
+ dns_dbversion_t *version, ns_client_t *client,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
+ dns_name_t *fname, isc_boolean_t exact,
+ dns_name_t *found)
+{
+ unsigned char salt[256];
+ size_t salt_length = sizeof(salt);
+ isc_uint16_t iterations;
+ isc_result_t result;
+ unsigned int dboptions;
+ dns_fixedname_t fixed;
+ dns_hash_t hash;
+ dns_name_t name;
+ int order;
+ unsigned int count;
+ dns_rdata_nsec3_t nsec3;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_boolean_t optout;
+
+ salt_length = sizeof(salt);
+ result = dns_db_getnsec3parameters(db, version, &hash, NULL,
+ &iterations, salt, &salt_length);
+ if (result != ISC_R_SUCCESS)
+ return;
+
+ dns_name_init(&name, NULL);
+ dns_name_clone(qname, &name);
+
+ /*
+ * Map unknown algorithm to known value.
+ */
+ if (hash == DNS_NSEC3_UNKNOWNALG)
+ hash = 1;
+
+ again:
+ dns_fixedname_init(&fixed);
+ result = dns_nsec3_hashname(&fixed, NULL, NULL, &name,
+ dns_db_origin(db), hash,
+ iterations, salt, salt_length);
+ if (result != ISC_R_SUCCESS)
+ return;
+
+ dboptions = client->query.dboptions | DNS_DBFIND_FORCENSEC3;
+ result = dns_db_find(db, dns_fixedname_name(&fixed), version,
+ dns_rdatatype_nsec3, dboptions, client->now,
+ NULL, fname, rdataset, sigrdataset);
+
+ if (result == DNS_R_NXDOMAIN) {
+ if (!dns_rdataset_isassociated(rdataset)) {
+ return;
+ }
+ result = dns_rdataset_first(rdataset);
+ INSIST(result == ISC_R_SUCCESS);
+ dns_rdataset_current(rdataset, &rdata);
+ dns_rdata_tostruct(&rdata, &nsec3, NULL);
+ dns_rdata_reset(&rdata);
+ optout = ISC_TF((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0);
+ if (found != NULL && optout &&
+ dns_name_fullcompare(&name, dns_db_origin(db), &order,
+ &count) == dns_namereln_subdomain) {
+ dns_rdataset_disassociate(rdataset);
+ if (dns_rdataset_isassociated(sigrdataset))
+ dns_rdataset_disassociate(sigrdataset);
+ count = dns_name_countlabels(&name) - 1;
+ dns_name_getlabelsequence(&name, 1, count, &name);
+ ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
+ NS_LOGMODULE_QUERY, ISC_LOG_DEBUG(3),
+ "looking for closest provable encloser");
+ goto again;
+ }
+ if (exact)
+ ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
+ NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
+ "expected a exact match NSEC3, got "
+ "a covering record");
+
+ } else if (result != ISC_R_SUCCESS) {
+ return;
+ } else if (!exact)
+ ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
+ NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
+ "expected covering NSEC3, got an exact match");
+ if (found != NULL)
+ dns_name_copy(&name, found, NULL);
+ return;
+}
+
/*
* Do the bulk of query processing for the current query of 'client'.
* If 'event' is non-NULL, we are returning from recursion and 'qtype'
isc_result_t result, eresult;
dns_fixedname_t fixed;
dns_fixedname_t wildcardname;
- dns_dbversion_t *version;
+ dns_dbversion_t *version, *zversion;
dns_zone_t *zone;
dns_rdata_cname_t cname;
dns_rdata_dname_t dname;
zrdataset = NULL;
sigrdataset = NULL;
zsigrdataset = NULL;
+ zversion = NULL;
node = NULL;
db = NULL;
zdb = NULL;
* We're authoritative for an ancestor of QNAME.
*/
if (!USECACHE(client) || !RECURSIONOK(client)) {
+ dns_fixedname_t fixed;
+
+ dns_fixedname_init(&fixed);
+ dns_name_copy(fname,
+ dns_fixedname_name(&fixed), NULL);
+
/*
* If we don't have a cache, this is the best
* answer.
&rdataset, sigrdatasetp,
dbuf, DNS_SECTION_AUTHORITY);
client->query.gluedb = NULL;
- if (WANTDNSSEC(client) && dns_db_issecure(db))
- query_addds(client, db, node, version);
+ if (WANTDNSSEC(client))
+ query_addds(client, db, node, version,
+ dns_fixedname_name(&fixed));
} else {
/*
* We might have a better answer or delegation
zsigrdataset = sigrdataset;
sigrdataset = NULL;
dns_db_detachnode(db, &node);
+ zversion = version;
version = NULL;
db = NULL;
dns_db_attach(client->view->cachedb, &db);
zrdataset = NULL;
sigrdataset = zsigrdataset;
zsigrdataset = NULL;
+ version = zversion;
+ zversion = NULL;
/*
* We don't clean up zdb here because we
* may still need it. It will get cleaned
else
QUERY_ERROR(DNS_R_SERVFAIL);
} else {
+ dns_fixedname_t fixed;
+
+ dns_fixedname_init(&fixed);
+ dns_name_copy(fname,
+ dns_fixedname_name(&fixed), NULL);
/*
* This is the best answer.
*/
client->query.attributes &=
~NS_QUERYATTR_CACHEGLUEOK;
if (WANTDNSSEC(client))
- query_addds(client, db, node, version);
+ query_addds(client, db, node, version,
+ dns_fixedname_name(&fixed));
}
}
goto cleanup;
/* FALLTHROUGH */
case DNS_R_NXRRSET:
INSIST(is_zone);
+ /*
+ * Look for a NSEC3 record if we don't have a NSEC record.
+ */
+ if (!dns_rdataset_isassociated(rdataset) &&
+ WANTDNSSEC(client)) {
+ if ((fname->attributes & DNS_NAMEATTR_WILDCARD) == 0) {
+ dns_name_t *found;
+ dns_name_t *qname;
+
+ dns_fixedname_init(&fixed);
+ found = dns_fixedname_name(&fixed);
+ qname = client->query.qname;
+
+ query_findclosestnsec3(qname, db, version,
+ client, rdataset,
+ sigrdataset, fname,
+ ISC_TRUE, found);
+ /*
+ * Did we find the closest provable encloser
+ * instead? If so add the nearest to the
+ * closest provable encloser.
+ */
+ if (found &&
+ dns_rdataset_isassociated(rdataset) &&
+ !dns_name_equal(qname, found))
+ {
+ unsigned int count;
+ unsigned int skip;
+
+ /*
+ * Add the closest provable encloser.
+ */
+ query_addrrset(client, &fname,
+ &rdataset, &sigrdataset,
+ dbuf,
+ DNS_SECTION_AUTHORITY);
+
+ count = dns_name_countlabels(found)
+ + 1;
+ skip = dns_name_countlabels(qname) -
+ count;
+ dns_name_getlabelsequence(qname, skip,
+ count,
+ found);
+
+ fixfname(client, &fname, &dbuf, &b);
+ fixrdataset(client, &rdataset);
+ fixrdataset(client, &sigrdataset);
+ if (fname == NULL ||
+ rdataset == NULL ||
+ sigrdataset == NULL) {
+ QUERY_ERROR(DNS_R_SERVFAIL);
+ goto cleanup;
+ }
+ /*
+ * 'nearest' doesn't exist so
+ * 'exist' is set to ISC_FALSE.
+ */
+ query_findclosestnsec3(found, db,
+ version,
+ client,
+ rdataset,
+ sigrdataset,
+ fname,
+ ISC_FALSE,
+ NULL);
+ }
+ } else {
+ query_releasename(client, &fname);
+ query_addwildcardproof(client, db, version,
+ client->query.qname,
+ ISC_FALSE);
+ }
+ }
if (dns_rdataset_isassociated(rdataset)) {
/*
* If we've got a NSEC record, we need to save the
* below, and it needs to use the name buffer.
*/
query_keepname(client, fname, dbuf);
- } else {
+ } else if (fname != NULL) {
/*
* We're not going to use fname, and need to release
* our hold on the name buffer so query_addsoa()
&sigrdataset);
}
goto cleanup;
+
case DNS_R_EMPTYWILD:
empty_wild = ISC_TRUE;
/* FALLTHROUGH */
+
case DNS_R_NXDOMAIN:
INSIST(is_zone);
if (dns_rdataset_isassociated(rdataset)) {
* below, and it needs to use the name buffer.
*/
query_keepname(client, fname, dbuf);
- } else {
+ } else if (fname != NULL) {
/*
* We're not going to use fname, and need to release
* our hold on the name buffer so query_addsoa()
QUERY_ERROR(result);
goto cleanup;
}
- /*
- * Add NSEC record if we found one.
- */
- if (dns_rdataset_isassociated(rdataset)) {
- if (WANTDNSSEC(client)) {
+
+ if (WANTDNSSEC(client)) {
+ /*
+ * Add NSEC record if we found one.
+ */
+ if (dns_rdataset_isassociated(rdataset))
query_addrrset(client, &fname, &rdataset,
&sigrdataset,
NULL, DNS_SECTION_AUTHORITY);
- query_addwildcardproof(client, db, version,
- client->query.qname,
- ISC_FALSE);
- }
+ query_addwildcardproof(client, db, version,
+ client->query.qname, ISC_FALSE);
}
+
/*
* Set message rcode.
*/
else
client->message->rcode = dns_rcode_nxdomain;
goto cleanup;
+
case DNS_R_NCACHENXDOMAIN:
case DNS_R_NCACHENXRRSET:
INSIST(!is_zone);
fname = NULL;
rdataset = NULL;
goto cleanup;
+
case DNS_R_CNAME:
/*
* Keep a copy of the rdataset. We have to do this because
NULL);
need_wildcardproof = ISC_TRUE;
}
- if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0 &&
- WANTDNSSEC(client))
+ if (NOQNAME(rdataset) && WANTDNSSEC(client))
noqname = rdataset;
else
noqname = NULL;
dns_rdataset_disassociate(rdataset);
} else if ((qtype == dns_rdatatype_any ||
rdataset->type == qtype) && rdataset->type != 0) {
+ if (NOQNAME(rdataset) && WANTDNSSEC(client))
+ noqname = rdataset;
+ else
+ noqname = NULL;
query_addrrset(client,
fname != NULL ? &fname : &tname,
&rdataset, NULL,
NULL, DNS_SECTION_ANSWER);
+ if (noqname != NULL)
+ query_addnoqnameproof(client, noqname);
n++;
INSIST(tname != NULL);
/*
- * rdataset is non-NULL only in certain pathological
- * cases involving DNAMEs.
+ * rdataset is non-NULL only in certain
+ * pathological cases involving DNAMEs.
*/
if (rdataset != NULL)
query_putrdataset(client, &rdataset);
if (fname != NULL)
dns_message_puttempname(client->message, &fname);
- if (n == 0) {
+ if (n == 0 && is_zone) {
/*
* We didn't match any rdatasets.
*/
sigrdatasetp = &sigrdataset;
else
sigrdatasetp = NULL;
- if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0 &&
- WANTDNSSEC(client))
+ if (NOQNAME(rdataset) && WANTDNSSEC(client))
noqname = rdataset;
else
noqname = NULL;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: update.c,v 1.146 2008/04/03 05:55:51 marka Exp $ */
+/* $Id: update.c,v 1.147 2008/09/24 02:46:21 marka Exp $ */
#include <config.h>
#include <dns/keyvalues.h>
#include <dns/message.h>
#include <dns/nsec.h>
+#include <dns/nsec3.h>
#include <dns/rdataclass.h>
#include <dns/rdataset.h>
#include <dns/rdatasetiter.h>
rr_action, rr_action_data));
node = NULL;
- result = dns_db_findnode(db, name, ISC_FALSE, &node);
+ if (type == dns_rdatatype_nsec3 ||
+ (type == dns_rdatatype_rrsig && covers == dns_rdatatype_nsec3))
+ result = dns_db_findnsec3node(db, name, ISC_FALSE, &node);
+ else
+ result = dns_db_findnode(db, name, ISC_FALSE, &node);
if (result == ISC_R_NOTFOUND)
return (ISC_R_SUCCESS);
if (result != ISC_R_SUCCESS)
/*%
* Return true iff 'db_rr' is neither a SOA nor an NS RR nor
- * an RRSIG nor a NSEC.
+ * an RRSIG nor an NSEC3PARAM nor a NSEC.
*/
static isc_boolean_t
type_not_soa_nor_ns_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
UNUSED(update_rr);
return ((db_rr->type != dns_rdatatype_soa &&
db_rr->type != dns_rdatatype_ns &&
+ db_rr->type != dns_rdatatype_nsec3param &&
db_rr->type != dns_rdatatype_rrsig &&
db_rr->type != dns_rdatatype_nsec) ?
ISC_TRUE : ISC_FALSE);
* Compare the address and protocol fields only. These
* form the first five bytes of the RR data. Do a
* raw binary comparison; unpacking the WKS RRs using
- * dns_rdata_tostruct() might be cleaner in some ways,
- * but it would require us to pass around an mctx.
+ * dns_rdata_tostruct() might be cleaner in some ways.
*/
INSIST(db_rr->length >= 5 && update_rr->length >= 5);
return (memcmp(db_rr->data, update_rr->data, 5) == 0 ?
ISC_TRUE : ISC_FALSE);
}
+
+ if (db_rr->type == dns_rdatatype_nsec3param) {
+ if (db_rr->length != update_rr->length)
+ return (ISC_FALSE);
+ INSIST(db_rr->length >= 4 && update_rr->length >= 4);
+ /*
+ * Replace records added in this UPDATE request.
+ */
+ if (db_rr->data[0] == update_rr->data[0] &&
+ db_rr->data[1] & DNS_NSEC3FLAG_UPDATE &&
+ update_rr->data[1] & DNS_NSEC3FLAG_UPDATE &&
+ memcmp(db_rr->data+2, update_rr->data+2,
+ update_rr->length - 2) == 0)
+ return (ISC_TRUE);
+ }
return (ISC_FALSE);
}
dns_fixedname_init(&fixedname);
child = dns_fixedname_name(&fixedname);
- CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit));
+ CHECK(dns_db_createiterator(db, DNS_DB_NONSEC3, &dbit));
for (result = dns_dbiterator_seek(dbit, name);
result == ISC_R_SUCCESS;
is_non_nsec_action(void *data, dns_rdataset_t *rrset) {
UNUSED(data);
if (!(rrset->type == dns_rdatatype_nsec ||
+ rrset->type == dns_rdatatype_nsec3 ||
(rrset->type == dns_rdatatype_rrsig &&
- rrset->covers == dns_rdatatype_nsec)))
+ (rrset->covers == dns_rdatatype_nsec ||
+ rrset->covers == dns_rdatatype_nsec3))))
return (ISC_R_EXISTS);
return (ISC_R_SUCCESS);
}
return (result);
}
-
static isc_result_t
is_glue(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
isc_boolean_t *flag)
}
}
+static isc_result_t
+is_active(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+ isc_boolean_t *flag, isc_boolean_t *unsecure)
+{
+ isc_result_t result;
+ dns_fixedname_t foundname;
+ dns_fixedname_init(&foundname);
+ result = dns_db_find(db, name, ver, dns_rdatatype_any,
+ DNS_DBFIND_GLUEOK | DNS_DBFIND_NOWILD,
+ (isc_stdtime_t) 0, NULL,
+ dns_fixedname_name(&foundname),
+ NULL, NULL);
+ if (result == ISC_R_SUCCESS || result == DNS_R_EMPTYNAME) {
+ *flag = ISC_TRUE;
+ if (unsecure != NULL)
+ *unsecure = ISC_FALSE;
+ return (ISC_R_SUCCESS);
+ } else if (result == DNS_R_ZONECUT) {
+ *flag = ISC_TRUE;
+ if (unsecure != NULL) {
+ /*
+ * We are at the zonecut. Check to see if there
+ * is a DS RRset.
+ */
+ if (dns_db_find(db, name, ver, dns_rdatatype_ds, 0,
+ (isc_stdtime_t) 0, NULL,
+ dns_fixedname_name(&foundname),
+ NULL, NULL) == DNS_R_NXRRSET)
+ *unsecure = ISC_TRUE;
+ else
+ *unsecure = ISC_FALSE;
+ }
+ return (ISC_R_SUCCESS);
+ } else if (result == DNS_R_GLUE || result == DNS_R_DNAME ||
+ result == DNS_R_DELEGATION || result == DNS_R_NXDOMAIN) {
+ *flag = ISC_FALSE;
+ if (unsecure != NULL)
+ *unsecure = ISC_FALSE;
+ return (ISC_R_SUCCESS);
+ } else {
+ return (result);
+ }
+}
+
/*%
* Find the next/previous name that has a NSEC record.
* In other words, skip empty database nodes and names that
unsigned int wraps = 0;
isc_boolean_t secure = dns_db_issecure(db);
- CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit));
+ CHECK(dns_db_createiterator(db, 0, &dbit));
CHECK(dns_dbiterator_seek(dbit, oldname));
do {
static void
set_bit(unsigned char *array, unsigned int index) {
- unsigned int shift, mask;
+ unsigned int shift, bit;
shift = 7 - (index % 8);
- mask = 1 << shift;
+ bit = 1 << shift;
- array[index / 8] |= mask;
+ array[index / 8] |= bit;
}
/*%
isc_buffer_init(&buffer, data, sizeof(data));
/* Get the rdataset to sign. */
- CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
+ if (type == dns_rdatatype_nsec3)
+ CHECK(dns_db_findnsec3node(db, name, ISC_FALSE, &node));
+ else
+ CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
CHECK(dns_db_findrdataset(db, node, ver, type, 0,
(isc_stdtime_t) 0, &rdataset, NULL));
dns_db_detachnode(db, &node);
}
/*%
- * Update RRSIG and NSEC records affected by an update. The original
+ * Update RRSIG, NSEC and NSEC3 records affected by an update. The original
* update, including the SOA serial update but exluding the RRSIG & NSEC
* changes, is in "diff" and has already been applied to "newver" of "db".
* The database version prior to the update is "oldver".
*
- * The necessary RRSIG and NSEC changes will be applied to "newver"
+ * The necessary RRSIG, NSEC and NSEC3 changes will be applied to "newver"
* and added (as a minimal diff) to "diff".
*
* The RRSIGs generated will be valid for 'sigvalidityinterval' seconds.
dns_rdataset_t rdataset;
dns_dbnode_t *node = NULL;
isc_boolean_t check_ksk;
+ isc_boolean_t unsecure;
dns_diff_init(client->mctx, &diffnames);
dns_diff_init(client->mctx, &affected);
*deleted_zsk = ISC_FALSE;
/*
- * Get the NSEC's TTL from the SOA MINIMUM field.
+ * Get the NSEC/NSEC3 TTL from the SOA MINIMUM field.
*/
CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
dns_rdataset_init(&rdataset);
}
}
}
+ update_log(client, zone, ISC_LOG_DEBUG(3), "updated data signatures");
/* Remove orphaned NSECs and RRSIG NSECs. */
for (t = ISC_LIST_HEAD(diffnames.tuples);
NULL, &sig_diff));
}
}
+ update_log(client, zone, ISC_LOG_DEBUG(3),
+ "removed any orphaned NSEC records");
+
+ /*
+ * If we don't have a NSEC record at the origin then we need to
+ * update the NSEC3 records.
+ */
+ CHECK(rrset_exists(db, newver, dns_db_origin(db), dns_rdatatype_nsec,
+ 0, &flag));
+ if (!flag)
+ goto update_nsec3;
+
+ update_log(client, zone, ISC_LOG_DEBUG(3), "rebuilding NSEC chain");
/*
* When a name is created or deleted, its predecessor needs to
dns_rdatatype_nsec, 0, &flag));
if (! flag)
CHECK(add_placeholder_nsec(db, newver, &t->name,
- diff));
+ diff));
}
}
dns_diff_appendminimal(&nsec_mindiff, &t);
}
+ update_log(client, zone, ISC_LOG_DEBUG(3),
+ "signing rebuilt NSEC chain");
+
/* Update RRSIG NSECs. */
for (t = ISC_LIST_HEAD(nsec_mindiff.tuples);
t != NULL;
}
}
+ update_nsec3:
+
+ /* Record our changes for the journal. */
+ while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) {
+ ISC_LIST_UNLINK(sig_diff.tuples, t, link);
+ dns_diff_appendminimal(diff, &t);
+ }
+ while ((t = ISC_LIST_HEAD(nsec_mindiff.tuples)) != NULL) {
+ ISC_LIST_UNLINK(nsec_mindiff.tuples, t, link);
+ dns_diff_appendminimal(diff, &t);
+ }
+
+ INSIST(ISC_LIST_EMPTY(sig_diff.tuples));
+ INSIST(ISC_LIST_EMPTY(nsec_diff.tuples));
+ INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples));
+
+ /*
+ * Check if we have any active NSEC3 chains by looking for a
+ * NSEC3PARAM RRset.
+ */
+ CHECK(rrset_exists(db, newver, dns_db_origin(db),
+ dns_rdatatype_nsec3param, 0, &flag));
+ if (!flag) {
+ update_log(client, zone, ISC_LOG_DEBUG(3),
+ "no NSEC3 chains to rebuild");
+ goto failure;
+ }
+
+ update_log(client, zone, ISC_LOG_DEBUG(3), "rebuilding NSEC3 chains");
+
+ dns_diff_clear(&diffnames);
+ dns_diff_clear(&affected);
+
+ CHECK(dns_diff_sort(diff, temp_order));
+
+ /*
+ * Find names potentially affected by delegation changes
+ * (obscured by adding an NS or DNAME, or unobscured by
+ * removing one).
+ */
+ t = ISC_LIST_HEAD(diff->tuples);
+ while (t != NULL) {
+ dns_name_t *name = &t->name;
+
+ isc_boolean_t ns_existed, dname_existed;
+ isc_boolean_t ns_exists, dname_exists;
+
+ if (t->rdata.type == dns_rdatatype_nsec ||
+ t->rdata.type == dns_rdatatype_rrsig) {
+ t = ISC_LIST_NEXT(t, link);
+ continue;
+ }
+
+ CHECK(namelist_append_name(&affected, name));
+
+ CHECK(rrset_exists(db, oldver, name, dns_rdatatype_ns, 0,
+ &ns_existed));
+ CHECK(rrset_exists(db, oldver, name, dns_rdatatype_dname, 0,
+ &dname_existed));
+ CHECK(rrset_exists(db, newver, name, dns_rdatatype_ns, 0,
+ &ns_exists));
+ CHECK(rrset_exists(db, newver, name, dns_rdatatype_dname, 0,
+ &dname_exists));
+
+ if ((ns_exists || dname_exists) == (ns_existed || dname_existed))
+ goto nextname;
+ /*
+ * There was a delegation change. Mark all subdomains
+ * of t->name as potentially needing a NSEC3 update.
+ */
+ CHECK(namelist_append_subdomain(db, name, &affected));
+
+ nextname:
+ while (t != NULL && dns_name_equal(&t->name, name))
+ t = ISC_LIST_NEXT(t, link);
+ }
+
+ for (t = ISC_LIST_HEAD(affected.tuples);
+ t != NULL;
+ t = ISC_LIST_NEXT(t, link)) {
+ dns_name_t *name = &t->name;
+
+ unsecure = ISC_FALSE; /* Silence compiler warning. */
+ CHECK(is_active(db, newver, name, &flag, &unsecure));
+
+ if (!flag) {
+ CHECK(dns_nsec3_delnsec3s(db, newver, name,
+ &nsec_diff));
+ } else {
+ CHECK(dns_nsec3_addnsec3s(db, newver, name, nsecttl,
+ unsecure, &nsec_diff));
+ }
+ }
+
+ /*
+ * Minimize the set of NSEC3 updates so that we don't
+ * have to regenerate the RRSIG NSEC3s for NSEC3s that were
+ * replaced with identical ones.
+ */
+ while ((t = ISC_LIST_HEAD(nsec_diff.tuples)) != NULL) {
+ ISC_LIST_UNLINK(nsec_diff.tuples, t, link);
+ dns_diff_appendminimal(&nsec_mindiff, &t);
+ }
+
+ update_log(client, zone, ISC_LOG_DEBUG(3),
+ "signing rebuilt NSEC3 chain");
+
+ /* Update RRSIG NSEC3s. */
+ for (t = ISC_LIST_HEAD(nsec_mindiff.tuples);
+ t != NULL;
+ t = ISC_LIST_NEXT(t, link))
+ {
+ if (t->op == DNS_DIFFOP_DEL) {
+ CHECK(delete_if(true_p, db, newver, &t->name,
+ dns_rdatatype_rrsig,
+ dns_rdatatype_nsec3,
+ NULL, &sig_diff));
+ } else if (t->op == DNS_DIFFOP_ADD) {
+ CHECK(add_sigs(client, zone, db, newver, &t->name,
+ dns_rdatatype_nsec3,
+ &sig_diff, zone_keys, nkeys,
+ client->mctx, inception, expire,
+ check_ksk));
+ } else {
+ INSIST(0);
+ }
+ }
+
/* Record our changes for the journal. */
while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) {
ISC_LIST_UNLINK(sig_diff.tuples, t, link);
/*%
* DS records are not allowed to exist without corresponding NS records,
- * draft-ietf-dnsext-delegation-signer-11.txt, 2.2 Protocol Change,
+ * RFC 3658, 2.2 Protocol Change,
* "DS RRsets MUST NOT appear at non-delegation points or at a zone's apex".
*/
return (ok ? ISC_R_SUCCESS : DNS_R_REFUSED);
}
+static isc_result_t
+rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+ const dns_rdata_t *rdata, isc_boolean_t *flag)
+{
+ dns_rdataset_t rdataset;
+ dns_dbnode_t *node = NULL;
+ isc_result_t result;
+
+ dns_rdataset_init(&rdataset);
+ if (rdata->type == dns_rdatatype_nsec3)
+ CHECK(dns_db_findnsec3node(db, name, ISC_FALSE, &node));
+ else
+ CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
+ result = dns_db_findrdataset(db, node, ver, rdata->type, 0,
+ (isc_stdtime_t) 0, &rdataset, NULL);
+ if (result == ISC_R_NOTFOUND) {
+ *flag = ISC_FALSE;
+ result = ISC_R_SUCCESS;
+ goto failure;
+ }
+
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdata_t myrdata = DNS_RDATA_INIT;
+ dns_rdataset_current(&rdataset, &myrdata);
+ if (!dns_rdata_compare(&myrdata, rdata))
+ break;
+ }
+ dns_rdataset_disassociate(&rdataset);
+ if (result == ISC_R_SUCCESS) {
+ *flag = ISC_TRUE;
+ } else if (result == ISC_R_NOMORE) {
+ *flag = ISC_FALSE;
+ result = ISC_R_SUCCESS;
+ }
+
+ failure:
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
+static isc_result_t
+get_iterations(dns_db_t *db, dns_dbversion_t *ver, unsigned int *iterationsp) {
+ dns_dbnode_t *node = NULL;
+ dns_rdata_nsec3param_t nsec3param;
+ dns_rdataset_t rdataset;
+ isc_result_t result;
+ unsigned int iterations = 0;
+
+ dns_rdataset_init(&rdataset);
+
+ result = dns_db_getoriginnode(db, &node);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
+ 0, (isc_stdtime_t) 0, &rdataset, NULL);
+ dns_db_detachnode(db, &node);
+ if (result == ISC_R_NOTFOUND)
+ goto success;
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_current(&rdataset, &rdata);
+ CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
+ if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
+ continue;
+ if (nsec3param.iterations > iterations)
+ iterations = nsec3param.iterations;
+ }
+ if (result != ISC_R_NOMORE)
+ goto failure;
+
+ success:
+ *iterationsp = iterations;
+ result = ISC_R_SUCCESS;
+
+ failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ return (result);
+}
+
+/*
+ * Prevent the zone entering a inconsistant state where
+ * NSEC only DNSKEYs are present with NSEC3 chains.
+ */
+static isc_result_t
+check_dnssec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
+ dns_dbversion_t *ver, dns_diff_t *diff)
+{
+ dns_diff_t temp_diff;
+ dns_diffop_t op;
+ dns_difftuple_t *tuple, *newtuple = NULL, *next;
+ isc_boolean_t flag;
+ isc_result_t result;
+ unsigned int iterations = 0, max;
+
+ dns_diff_init(diff->mctx, &temp_diff);
+
+ CHECK(dns_nsec_nseconly(db, ver, &flag));
+
+ if (flag)
+ CHECK(dns_nsec3_active(db, ver, ISC_FALSE, &flag));
+ if (flag) {
+ update_log(client, zone, ISC_LOG_WARNING,
+ "NSEC only DNSKEYs and NSEC3 chains not allowed");
+ } else {
+ CHECK(get_iterations(db, ver, &iterations));
+ CHECK(dns_nsec3_maxiterations(db, ver, client->mctx, &max));
+ if (iterations > max) {
+ flag = ISC_TRUE;
+ update_log(client, zone, ISC_LOG_WARNING,
+ "too many NSEC3 iterations (%u) for "
+ "weakest DNSKEY (%u)", iterations, max);
+ }
+ }
+ if (flag) {
+ for (tuple = ISC_LIST_HEAD(diff->tuples);
+ tuple != NULL;
+ tuple = next) {
+ next = ISC_LIST_NEXT(tuple, link);
+ if (tuple->rdata.type != dns_rdatatype_dnskey &&
+ tuple->rdata.type != dns_rdatatype_nsec3param)
+ continue;
+ op = (tuple->op == DNS_DIFFOP_DEL) ?
+ DNS_DIFFOP_ADD : DNS_DIFFOP_DEL;
+ CHECK(dns_difftuple_create(temp_diff.mctx, op,
+ &tuple->name, tuple->ttl,
+ &tuple->rdata, &newtuple));
+ CHECK(do_one_tuple(&newtuple, db, ver, &temp_diff));
+ INSIST(newtuple == NULL);
+ }
+ for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
+ tuple != NULL;
+ tuple = ISC_LIST_HEAD(temp_diff.tuples)) {
+ ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
+ dns_diff_appendminimal(diff, &tuple);
+ }
+ }
+
+
+ failure:
+ dns_diff_clear(&temp_diff);
+ return (result);
+}
+
+#ifdef ALLOW_NSEC3PARAM_UPDATE
+/*
+ * Delay NSEC3PARAM changes as they need to be applied to the whole zone.
+ */
+static isc_result_t
+add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
+ dns_name_t *name, dns_dbversion_t *ver, dns_diff_t *diff)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ dns_difftuple_t *tuple, *newtuple = NULL, *next;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
+ dns_diff_t temp_diff;
+ dns_diffop_t op;
+ isc_boolean_t flag;
+
+ update_log(client, zone, ISC_LOG_DEBUG(3),
+ "checking for NSEC3PARAM changes");
+
+ dns_diff_init(diff->mctx, &temp_diff);
+
+ /*
+ * Extract NSEC3PARAM tuples from list.
+ */
+ for (tuple = ISC_LIST_HEAD(diff->tuples);
+ tuple != NULL;
+ tuple = next) {
+
+ next = ISC_LIST_NEXT(tuple, link);
+
+ if (tuple->rdata.type != dns_rdatatype_nsec3param ||
+ !dns_name_equal(name, &tuple->name))
+ continue;
+ ISC_LIST_UNLINK(diff->tuples, tuple, link);
+ ISC_LIST_APPEND(temp_diff.tuples, tuple, link);
+ }
+
+ for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
+ tuple != NULL; tuple = next) {
+
+ if (tuple->op == DNS_DIFFOP_ADD) {
+ next = ISC_LIST_NEXT(tuple, link);
+ while (next != NULL) {
+ unsigned char *next_data = next->rdata.data;
+ unsigned char *tuple_data = tuple->rdata.data;
+ if (next_data[0] != tuple_data[0] ||
+ /* Ignore flags. */
+ next_data[2] != tuple_data[2] ||
+ next_data[3] != tuple_data[3] ||
+ next_data[4] != tuple_data[4] ||
+ !memcmp(&next_data[5], &tuple_data[5],
+ tuple_data[4])) {
+ next = ISC_LIST_NEXT(next, link);
+ continue;
+ }
+ op = (next->op == DNS_DIFFOP_DEL) ?
+ DNS_DIFFOP_ADD : DNS_DIFFOP_DEL;
+ CHECK(dns_difftuple_create(diff->mctx, op,
+ name, next->ttl,
+ &next->rdata,
+ &newtuple));
+ CHECK(do_one_tuple(&newtuple, db, ver, diff));
+ ISC_LIST_UNLINK(temp_diff.tuples, next, link);
+ dns_diff_appendminimal(diff, &next);
+ next = ISC_LIST_NEXT(tuple, link);
+ }
+
+ INSIST(tuple->rdata.data[1] & DNS_NSEC3FLAG_UPDATE);
+
+ /*
+ * See if we already have a CREATE request in progress.
+ */
+ dns_rdata_clone(&tuple->rdata, &rdata);
+ INSIST(rdata.length <= sizeof(buf));
+ memcpy(buf, rdata.data, rdata.length);
+ buf[1] |= DNS_NSEC3FLAG_CREATE;
+ buf[1] &= ~DNS_NSEC3FLAG_UPDATE;
+ rdata.data = buf;
+
+ CHECK(rr_exists(db, ver, name, &rdata, &flag));
+
+ if (!flag) {
+ CHECK(dns_difftuple_create(diff->mctx,
+ DNS_DIFFOP_ADD,
+ name, tuple->ttl,
+ &rdata,
+ &newtuple));
+ CHECK(do_one_tuple(&newtuple, db, ver, diff));
+ }
+ /*
+ * Remove the temporary add record.
+ */
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
+ name, tuple->ttl,
+ &tuple->rdata, &newtuple));
+ CHECK(do_one_tuple(&newtuple, db, ver, diff));
+ next = ISC_LIST_NEXT(tuple, link);
+ ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
+ dns_diff_appendminimal(diff, &tuple);
+ dns_rdata_reset(&rdata);
+ } else
+ next = ISC_LIST_NEXT(tuple, link);
+ }
+
+ /*
+ * Reverse any pending changes.
+ */
+ for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
+ tuple != NULL; tuple = next) {
+ next = ISC_LIST_NEXT(tuple, link);
+ if ((tuple->rdata.data[1] & ~DNS_NSEC3FLAG_OPTOUT) != 0) {
+ op = (tuple->op == DNS_DIFFOP_DEL) ?
+ DNS_DIFFOP_ADD : DNS_DIFFOP_DEL;
+ CHECK(dns_difftuple_create(diff->mctx, op, name,
+ tuple->ttl, &tuple->rdata,
+ &newtuple));
+ CHECK(do_one_tuple(&newtuple, db, ver, diff));
+ ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
+ dns_diff_appendminimal(diff, &tuple);
+ }
+ }
+
+ /*
+ * Convert deletions into delayed deletions.
+ */
+ for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
+ tuple != NULL; tuple = next) {
+ next = ISC_LIST_NEXT(tuple, link);
+ /*
+ * See if we already have a REMOVE request in progress.
+ */
+ dns_rdata_clone(&tuple->rdata, &rdata);
+ INSIST(rdata.length <= sizeof(buf));
+ memcpy(buf, rdata.data, rdata.length);
+ buf[1] |= DNS_NSEC3FLAG_REMOVE;
+ rdata.data = buf;
+
+ CHECK(rr_exists(db, ver, name, &rdata, &flag));
+
+ if (!flag) {
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
+ name, tuple->ttl, &rdata,
+ &newtuple));
+ CHECK(do_one_tuple(&newtuple, db, ver, diff));
+ }
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
+ tuple->ttl, &tuple->rdata,
+ &newtuple));
+ CHECK(do_one_tuple(&newtuple, db, ver, diff));
+ ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
+ dns_diff_appendminimal(diff, &tuple);
+ dns_rdata_reset(&rdata);
+ }
+
+ result = ISC_R_SUCCESS;
+ failure:
+ dns_diff_clear(&temp_diff);
+ return (result);
+}
+#endif
+
+/*
+ * Add records to cause the delayed signing of the zone by added DNSKEY
+ * to remove the RRSIG records generated by a deleted DNSKEY.
+ */
static isc_result_t
add_signing_records(dns_db_t *db, dns_name_t *name, dns_dbversion_t *ver,
dns_rdatatype_t privatetype, dns_diff_t *diff)
{
- isc_result_t result = ISC_R_SUCCESS;
dns_difftuple_t *tuple, *newtuple = NULL;
dns_rdata_dnskey_t dnskey;
dns_rdata_t rdata = DNS_RDATA_INIT;
- unsigned char buf[4];
+ isc_boolean_t flag;
isc_region_t r;
+ isc_result_t result = ISC_R_SUCCESS;
isc_uint16_t keyid;
+ unsigned char buf[5];
for (tuple = ISC_LIST_HEAD(diff->tuples);
tuple != NULL;
tuple = ISC_LIST_NEXT(tuple, link)) {
- if (tuple->rdata.type != dns_rdatatype_dnskey ||
- tuple->op != DNS_DIFFOP_ADD)
+ if (tuple->rdata.type != dns_rdatatype_dnskey)
continue;
dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
buf[0] = dnskey.algorithm;
buf[1] = (keyid & 0xff00) >> 8;
buf[2] = (keyid & 0xff);
- buf[3] = 0;
+ buf[3] = (tuple->op == DNS_DIFFOP_ADD) ? 0 : 1;
+ buf[4] = 0;
rdata.data = buf;
rdata.length = sizeof(buf);
rdata.type = privatetype;
rdata.rdclass = tuple->rdata.rdclass;
- CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
- 0, &rdata, &newtuple));
+ CHECK(rr_exists(db, ver, name, &rdata, &flag));
+ if (flag)
+ continue;
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
+ name, 0, &rdata, &newtuple));
CHECK(do_one_tuple(&newtuple, db, ver, diff));
INSIST(newtuple == NULL);
+ /*
+ * Remove any record which says this operation has already
+ * completed.
+ */
+ buf[4] = 1;
+ CHECK(rr_exists(db, ver, name, &rdata, &flag));
+ if (flag) {
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
+ name, 0, &rdata, &newtuple));
+ CHECK(do_one_tuple(&newtuple, db, ver, diff));
+ INSIST(newtuple == NULL);
+ }
+ }
+ failure:
+ return (result);
+}
+
+#ifdef ALLOW_NSEC3PARAM_UPDATE
+/*
+ * Mark all NSEC3 chains for deletion without creating a NSEC chain as
+ * a side effect of deleting the last chain.
+ */
+static isc_result_t
+delete_chains(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin,
+ dns_diff_t *diff)
+{
+ dns_dbnode_t *node = NULL;
+ dns_difftuple_t *tuple = NULL;
+ dns_name_t next;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_t rdataset;
+ isc_boolean_t flag;
+ isc_result_t result = ISC_R_SUCCESS;
+ unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
+
+ dns_name_init(&next, NULL);
+ dns_rdataset_init(&rdataset);
+
+ result = dns_db_getoriginnode(db, &node);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Cause all NSEC3 chains to be deleted.
+ */
+ result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
+ 0, (isc_stdtime_t) 0, &rdataset, NULL);
+ if (result == ISC_R_NOTFOUND)
+ goto success;
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdataset_current(&rdataset, &rdata);
+ INSIST(rdata.length <= sizeof(buf));
+ memcpy(buf, rdata.data, rdata.length);
+
+ if (buf[1] == (DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC)) {
+ dns_rdata_reset(&rdata);
+ continue;
+ }
+
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
+ origin, 0, &rdata, &tuple));
+ CHECK(do_one_tuple(&tuple, db, ver, diff));
+ INSIST(tuple == NULL);
+
+ buf[1] = DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC;
+ rdata.data = buf;
+
+ CHECK(rr_exists(db, ver, origin, &rdata, &flag));
+
+ if (!flag) {
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
+ origin, 0, &rdata, &tuple));
+ CHECK(do_one_tuple(&tuple, db, ver, diff));
+ INSIST(tuple == NULL);
+ }
+ dns_rdata_reset(&rdata);
}
+ if (result != ISC_R_NOMORE)
+ goto failure;
+ success:
+ result = ISC_R_SUCCESS;
+
failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ dns_db_detachnode(db, &node);
return (result);
}
+#endif
static void
update_action(isc_task_t *task, isc_event_t *event) {
isc_boolean_t deleted_zsk;
dns_difftuple_t *tuple;
dns_rdata_dnskey_t dnskey;
+#ifdef ALLOW_NSEC3PARAM_UPDATE
+ unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
+#endif
+#if !defined(ALLOW_SECURE_TO_INSECURE) || !defined(ALLOW_INSECURE_TO_SECURE)
+ isc_boolean_t had_dnskey;
+#endif
INSIST(event->ev_type == DNS_EVENT_UPDATE);
* is forbidden from updating NSEC records."
*/
if (dns_db_issecure(db)) {
- if (rdata.type == dns_rdatatype_nsec) {
+ if (rdata.type == dns_rdatatype_nsec3) {
+ FAILC(DNS_R_REFUSED,
+ "explicit NSEC3 updates are not allowed "
+ "in secure zones");
+ } else if (rdata.type == dns_rdatatype_nsec) {
FAILC(DNS_R_REFUSED,
"explicit NSEC updates are not allowed "
"in secure zones");
typebuf);
continue;
}
- if (rdata.type == dns_rdatatype_ns &&
+ if ((rdata.type == dns_rdatatype_ns ||
+ rdata.type == dns_rdatatype_dname) &&
dns_name_iswildcard(name)) {
+ char typebuf[DNS_RDATATYPE_FORMATSIZE];
+
+ dns_rdatatype_format(rdata.type, typebuf,
+ sizeof(typebuf));
update_log(client, zone,
LOGLEVEL_PROTOCOL,
- "attempt to add wildcard NS record"
- "ignored");
+ "attempt to add wildcard %s record "
+ "ignored", typebuf);
continue;
}
if (rdata.type == dns_rdatatype_cname) {
}
soa_serial_changed = ISC_TRUE;
}
+
+#ifdef ALLOW_NSEC3PARAM_UPDATE
+ if (rdata.type == dns_rdatatype_nsec3param) {
+ /*
+ * Ignore attempts to add NSEC3PARAM records
+ * with any flags other than OPTOUT.
+ */
+ if ((rdata.data[1] & ~DNS_NSEC3FLAG_OPTOUT) != 0) {
+ update_log(client, zone,
+ LOGLEVEL_PROTOCOL,
+ "attempt to add NSEC3PARAM "
+ "record with non OPTOUT "
+ "flag");
+ continue;
+ }
+
+ /*
+ * Set the NSEC3CHAIN creation flag.
+ */
+ INSIST(rdata.length <= sizeof(buf));
+ memcpy(buf, rdata.data, rdata.length);
+ buf[1] |= DNS_NSEC3FLAG_UPDATE;
+ rdata.data = buf;
+ /*
+ * Force the TTL to zero for NSEC3PARAM records.
+ */
+ ttl = 0;
+ }
+#else
+ if (rdata.type == dns_rdatatype_nsec3param) {
+ update_log(client, zone, LOGLEVEL_PROTOCOL,
+ "attempt to add NSEC3PARAM "
+ "record ignored");
+ continue;
+ };
+#endif
+
if ((options & DNS_ZONEOPT_CHECKWILDCARD) != 0 &&
dns_name_internalwildcard(name)) {
char namestr[DNS_NAME_FORMATSIZE];
dns_diff_clear(&ctx.del_diff);
dns_diff_clear(&ctx.add_diff);
} else {
- CHECK(do_diff(&ctx.del_diff, db, ver, &diff));
- CHECK(do_diff(&ctx.add_diff, db, ver, &diff));
+ CHECK(do_diff(&ctx.del_diff, db, ver,
+ &diff));
+ CHECK(do_diff(&ctx.add_diff, db, ver,
+ &diff));
CHECK(update_one_rr(db, ver, &diff,
DNS_DIFFOP_ADD,
name, ttl, &rdata));
dns_rdatatype_any, 0,
&rdata, &diff));
}
+#ifndef ALLOW_NSEC3PARAM_UPDATE
+ } else if (rdata.type == dns_rdatatype_nsec3param) {
+ update_log(client, zone, LOGLEVEL_PROTOCOL,
+ "attempt to delete a NSEC3PARAM "
+ "records ignored");
+ continue;
+#endif
} else if (dns_name_equal(name, zonename) &&
(rdata.type == dns_rdatatype_soa ||
rdata.type == dns_rdatatype_ns)) {
if (result != ISC_R_NOMORE)
FAIL(result);
+ /*
+ * Check that any changes to DNSKEY/NSEC3PARAM records make sense.
+ * If they don't then back out all changes to DNSKEY/NSEC3PARAM
+ * records.
+ */
+ if (! ISC_LIST_EMPTY(diff.tuples))
+ CHECK(check_dnssec(client, zone, db, ver, &diff));
+
/*
* If any changes were made, increment the SOA serial number,
* update RRSIGs and NSECs (if zone is secure), and write the update
CHECK(remove_orphaned_ds(db, ver, &diff));
+ CHECK(rrset_exists(db, ver, zonename, dns_rdatatype_dnskey,
+ 0, &has_dnskey));
+
+#if !defined(ALLOW_SECURE_TO_INSECURE) || !defined(ALLOW_INSECURE_TO_SECURE)
+ CHECK(rrset_exists(db, oldver, zonename, dns_rdatatype_dnskey,
+ 0, &had_dnskey));
+
+#ifndef ALLOW_SECURE_TO_INSECURE
+ if (had_dnskey && !has_dnskey) {
+ update_log(client, zone, LOGLEVEL_PROTOCOL,
+ "update rejected: all DNSKEY records "
+ "removed");
+ result = DNS_R_REFUSED;
+ goto failure;
+ }
+#endif
+#ifndef ALLOW_INSECURE_TO_SECURE
+ if (had_dnskey && !has_dnskey) {
+ update_log(client, zone, LOGLEVEL_PROTOCOL,
+ "update rejected: DNSKEY record added");
+ result = DNS_R_REFUSED;
+ goto failure;
+ }
+#endif
+#endif
+
CHECK(add_signing_records(db, zonename, ver,
dns_zone_getprivatetype(zone),
&diff));
- CHECK(rrset_exists(db, ver, zonename, dns_rdatatype_dnskey,
- 0, &has_dnskey));
+#ifdef ALLOW_NSEC3PARAM_UPDATE
+ CHECK(add_nsec3param_records(client, zone, db, zonename,
+ ver, &diff));
+#endif
- if (has_dnskey && dns_db_isdnssec(db)) {
+ if (!has_dnskey) {
+ /*
+ * We are transitioning from secure to insecure.
+ * Cause all NSEC3 chains to be deleted. When the
+ * the last signature for the DNSKEY records are
+ * remove any NSEC chain present will also be removed.
+ */
+#ifdef ALLOW_NSEC3PARAM_UPDATE
+ CHECK(delete_chains(db, ver, zonename, &diff));
+#endif
+ } else if (has_dnskey && dns_db_isdnssec(db)) {
isc_uint32_t interval;
interval = dns_zone_getsigvalidityinterval(zone);
result = update_signatures(client, zone, db, oldver,
if (result != ISC_R_SUCCESS) {
update_log(client, zone,
ISC_LOG_ERROR,
- "RRSIG/NSEC update failed: %s",
+ "RRSIG/NSEC/NSEC3 update failed: %s",
isc_result_totext(result));
goto failure;
}
*/
dns_zone_notify(zone);
+ /*
+ * Cause the zone to be signed with the key that we
+ * have just added or have the corresponding signatures
+ * deleted.
+ *
+ * Note: we are already committed to this course of action.
+ */
for (tuple = ISC_LIST_HEAD(diff.tuples);
tuple != NULL;
tuple = ISC_LIST_NEXT(tuple, link)) {
dns_secalg_t algorithm;
isc_uint16_t keyid;
- if (tuple->rdata.type != dns_rdatatype_dnskey ||
- tuple->op != DNS_DIFFOP_ADD)
+ if (tuple->rdata.type != dns_rdatatype_dnskey)
continue;
dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
algorithm = dnskey.algorithm;
keyid = dst_region_computeid(&r, algorithm);
- result = dns_zone_signwithkey(zone, algorithm, keyid);
+ result = dns_zone_signwithkey(zone, algorithm, keyid,
+ ISC_TF(tuple->op == DNS_DIFFOP_DEL));
if (result != ISC_R_SUCCESS) {
update_log(client, zone, ISC_LOG_ERROR,
"dns_zone_signwithkey failed: %s",
dns_result_totext(result));
}
}
+
+#ifdef ALLOW_NSEC3PARAM_UPDATE
+ /*
+ * Cause the zone to add/delete NSEC3 chains for the
+ * defered NSEC3PARAM changes.
+ *
+ * Note: we are already committed to this course of action.
+ */
+ for (tuple = ISC_LIST_HEAD(diff.tuples);
+ tuple != NULL;
+ tuple = ISC_LIST_NEXT(tuple, link)) {
+ dns_rdata_nsec3param_t nsec3param;
+
+ if (tuple->rdata.type != dns_rdatatype_nsec3param ||
+ tuple->op != DNS_DIFFOP_ADD)
+ continue;
+
+ dns_rdata_tostruct(&tuple->rdata, &nsec3param, NULL);
+ if (nsec3param.flags == 0)
+ continue;
+
+ result = dns_zone_addnsec3chain(zone, &nsec3param);
+ if (result != ISC_R_SUCCESS) {
+ update_log(client, zone, ISC_LOG_ERROR,
+ "dns_zone_addnsec3chain failed: %s",
+ dns_result_totext(result));
+ }
+ }
+#endif
} else {
update_log(client, zone, LOGLEVEL_DEBUG, "redundant request");
dns_db_closeversion(db, &ver, ISC_TRUE);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: xfrout.c,v 1.129 2008/08/15 19:36:49 jinmei Exp $ */
+/* $Id: xfrout.c,v 1.130 2008/09/24 02:46:21 marka Exp $ */
#include <config.h>
it->ver = ver;
it->now = now;
it->node = NULL;
- result = dns_db_createiterator(it->db, ISC_FALSE, &it->dbit);
+ result = dns_db_createiterator(it->db, 0, &it->dbit);
if (result != ISC_R_SUCCESS)
return (result);
it->rdatasetit = NULL;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zoneconf.c,v 1.146 2008/05/21 23:47:00 tbox Exp $ */
+/* $Id: zoneconf.c,v 1.147 2008/09/24 02:46:21 marka Exp $ */
/*% */
result = ns_config_get(maps, "zero-no-soa-ttl", &obj);
INSIST(result == ISC_R_SUCCESS);
dns_zone_setzeronosoattl(zone, cfg_obj_asboolean(obj));
+
+ obj = NULL;
+ result = ns_config_get(maps, "nsec3-test-zone", &obj);
+ INSIST(result == ISC_R_SUCCESS);
+ dns_zone_setoption(zone, DNS_ZONEOPT_NSEC3TESTZONE,
+ cfg_obj_asboolean(obj));
}
/*
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: nsupdate.c,v 1.159 2008/04/02 02:37:41 marka Exp $ */
+/* $Id: nsupdate.c,v 1.160 2008/09/24 02:46:21 marka Exp $ */
/*! \file */
static dns_rdataclass_t defaultclass = dns_rdataclass_in;
static dns_rdataclass_t zoneclass = dns_rdataclass_none;
static dns_message_t *answer = NULL;
+static isc_uint32_t default_ttl = 0;
+static isc_boolean_t default_ttl_set = ISC_FALSE;
typedef struct nsu_requestinfo {
dns_message_t *msg;
return (STATUS_MORE);
}
+static isc_uint16_t
+evaluate_ttl(char *cmdline) {
+ char *word;
+ isc_result_t result;
+ isc_uint32_t ttl;
+
+ word = nsu_strsep(&cmdline, " \t\r\n");
+ if (*word == 0) {
+ fprintf(stderr, "could not ttl\n");
+ return (STATUS_SYNTAX);
+ }
+
+ result = isc_parse_uint32(&ttl, word, 10);
+ if (result != ISC_R_SUCCESS)
+ return (STATUS_SYNTAX);
+
+ if (ttl > TTL_MAX) {
+ fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n",
+ word, TTL_MAX);
+ return (STATUS_SYNTAX);
+ }
+ default_ttl = ttl;
+ default_ttl_set = ISC_TRUE;
+
+ return (STATUS_MORE);
+}
+
static isc_uint16_t
evaluate_class(char *cmdline) {
char *word;
if (isdelete) {
ttl = 0;
goto parseclass;
+ } else if (default_ttl_set) {
+ ttl = default_ttl;
+ goto parseclass;
} else {
fprintf(stderr, "ttl '%s': %s\n", word,
isc_result_totext(result));
return (evaluate_class(cmdline));
if (strcasecmp(word, "send") == 0)
return (STATUS_SEND);
+ if (strcasecmp(word, "debug") == 0) {
+ if (debugging)
+ ddebugging = ISC_TRUE;
+ else
+ debugging = ISC_TRUE;
+ return (STATUS_MORE);
+ }
+ if (strcasecmp(word, "ttl") == 0)
+ return (evaluate_ttl(cmdline));
if (strcasecmp(word, "show") == 0) {
show_message(stdout, updatemsg, "Outgoing update query:");
return (STATUS_MORE);
- PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- $Id: nsupdate.docbook,v 1.32 2008/08/29 03:16:14 marka Exp $ -->
+<!-- $Id: nsupdate.docbook,v 1.33 2008/09/24 02:46:21 marka Exp $ -->
<refentry id="man.nsupdate">
<refentryinfo>
<date>Jun 30, 2000</date>
<cmdsynopsis>
<command>nsupdate</command>
<arg><option>-d</option></arg>
+ <arg><option>-D</option></arg>
<group>
<arg><option>-y <replaceable class="parameter"><optional>hmac:</optional>keyname:secret</replaceable></option></arg>
<arg><option>-k <replaceable class="parameter">keyfile</replaceable></option></arg>
This provides tracing information about the update requests that are
made and the replies received from the name server.
</para>
+ <para>
+ The <option>-D</option> option makes <command>nsupdate</command>
+ report additional debugging information to <option>-d</option>.
+ </para>
<para>
Transaction signatures can be used to authenticate the Dynamic DNS
updates.
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: Makefile.in,v 1.129 2007/06/19 23:46:59 tbox Exp $
+# $Id: Makefile.in,v 1.130 2008/09/24 02:46:21 marka Exp $
srcdir = @srcdir@
VPATH = @srcdir@
gxba_test@EXEEXT@ \
gxbn_test@EXEEXT@ \
hash_test@EXEEXT@ \
+ nsec3hash@EXEEXT@ \
fsaccess_test@EXEEXT@ \
inter_test@EXEEXT@ \
journalprint@EXEEXT@ \
${LIBTOOL_MODE_LINK} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ cfg_test.@O@ \
${ISCCFGLIBS} ${DNSLIBS} ${ISCLIBS} ${LIBS}
+nsec3hash@EXEEXT@: nsec3hash.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ nsec3hash.@O@ \
+ ${DNSLIBS} ${ISCLIBS} ${LIBS}
+
distclean::
rm -f headerdep_test.sh
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: db_test.c,v 1.64 2007/06/19 23:46:59 tbox Exp $ */
+/* $Id: db_test.c,v 1.65 2008/09/24 02:46:21 marka Exp $ */
/*! \file
* \author
dns_db_currentversion(dbi->db, &dbi->iversion);
}
- result = dns_db_createiterator(dbi->db, ISC_FALSE,
- &dbi->dbiterator);
+ result = dns_db_createiterator(dbi->db, 0, &dbi->dbiterator);
if (result == ISC_R_SUCCESS) {
if (seektext != NULL) {
len = strlen(seektext);
--- /dev/null
+/*
+ * Copyright (C) 2006 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: nsec3hash.c,v 1.2 2008/09/24 02:46:21 marka Exp $ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <isc/base32.h>
+#include <isc/buffer.h>
+#include <isc/hex.h>
+#include <isc/iterated_hash.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/types.h>
+
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/types.h>
+
+const char *program = "nsec3hash";
+
+static void
+fatal(const char *format, ...) {
+ va_list args;
+
+ fprintf(stderr, "%s: ", program);
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+static void
+check_result(isc_result_t result, const char *message) {
+ if (result != ISC_R_SUCCESS)
+ fatal("%s: %s", message, isc_result_totext(result));
+}
+
+static void
+usage() {
+ fatal("salt hash iterations domain");
+}
+
+int
+main(int argc, char **argv) {
+ dns_fixedname_t fixed;
+ dns_name_t *name;
+ isc_buffer_t buffer;
+ isc_region_t region;
+ isc_result_t result;
+ unsigned char hash[NSEC3_MAX_HASH_LENGTH];
+ unsigned char salt[255];
+ unsigned char text[1024];
+ unsigned int hash_alg;
+ unsigned int length;
+ unsigned int iterations;
+ unsigned int salt_length;
+
+ if (argc != 5)
+ usage();
+
+ if (strcmp(argv[1], "-") == 0) {
+ salt_length = 0;
+ salt[0] = 0;
+ } else {
+ isc_buffer_init(&buffer, salt, sizeof(salt));
+ result = isc_hex_decodestring(argv[1], &buffer);
+ check_result(result, "isc_hex_decodestring(salt)");
+ salt_length = isc_buffer_usedlength(&buffer);
+ if (salt_length > 255U)
+ fatal("salt too long");
+ }
+ hash_alg = atoi(argv[2]);
+ if (hash_alg > 255U)
+ fatal("hash algorithm too large");
+ iterations = atoi(argv[3]);
+ if (iterations > 0xffffU)
+ fatal("iterations to large");
+
+ dns_fixedname_init(&fixed);
+ name = dns_fixedname_name(&fixed);
+ isc_buffer_init(&buffer, argv[4], strlen(argv[4]));
+ isc_buffer_add(&buffer, strlen(argv[4]));
+ result = dns_name_fromtext(name, &buffer, dns_rootname, 0, NULL);
+ check_result(result, "dns_name_fromtext() failed");
+
+ dns_name_downcase(name, name, NULL);
+ length = isc_iterated_hash(hash, hash_alg, iterations, salt,
+ salt_length, name->ndata, name->length);
+ if (length == 0)
+ fatal("isc_iterated_hash failed");
+ region.base = hash;
+ region.length = length;
+ isc_buffer_init(&buffer, text, sizeof(text));
+ isc_base32hex_totext(®ion, 1, "", &buffer);
+ fprintf(stdout, "%.*s (salt=%s, hash=%u, iterations=%u)\n",
+ (int)isc_buffer_usedlength(&buffer), text, argv[1], hash_alg, iterations);
+ exit(0);
+}
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: nsecify.c,v 1.6 2007/06/19 23:46:59 tbox Exp $ */
+/* $Id: nsecify.c,v 1.7 2008/09/24 02:46:21 marka Exp $ */
#include <config.h>
result = dns_db_newversion(db, &wversion);
check_result(result, "dns_db_newversion()");
dbiter = NULL;
- result = dns_db_createiterator(db, ISC_FALSE, &dbiter);
+ result = dns_db_createiterator(db, 0, &dbiter);
check_result(result, "dns_db_createiterator()");
result = dns_dbiterator_first(dbiter);
node = NULL;
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: Makefile.in,v 1.29 2007/06/19 23:47:00 tbox Exp $
+# $Id: Makefile.in,v 1.30 2008/09/24 02:46:21 marka Exp $
srcdir = @srcdir@
VPATH = @srcdir@
test: subdirs
if test -f ./runall.sh; then sh ./runall.sh; fi
-clean distclean::
+testclean clean distclean::
if test -f ./cleanall.sh; then sh ./cleanall.sh; fi
distclean::
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: clean.sh,v 1.21 2007/10/30 23:56:09 marka Exp $
+# $Id: clean.sh,v 1.22 2008/09/24 02:46:21 marka Exp $
-rm -f */K* */keyset-* */dsset-* */dlvset-* */signedkey-* */*.signed */trusted.conf */tmp*
+rm -f */K* */keyset-* */dsset-* */dlvset-* */signedkey-* */*.signed */trusted.conf */tmp* */*.jnl */*.bk
rm -f ns1/root.db ns2/example.db ns3/secure.example.db
rm -f ns3/unsecure.example.db ns3/bogus.example.db ns3/keyless.example.db
rm -f ns3/dynamic.example.db ns3/dynamic.example.db.signed.jnl
rm -f dig.out.*
rm -f random.data
rm -f ns2/dlv.db
+rm -f ns3/multiple.example.db ns3/nsec3-unknown.example.db ns3/nsec3.example.db
+rm -f ns3/optout-unknown.example.db ns3/optout.example.db
+rm -f ns7/multiple.example.bk ns7/nsec3.example.bk ns7/optout.example.bk
rm -f */named.memstats
+rm -f ns3/nsec3.nsec3.example.db
+rm -f ns3/nsec3.optout.example.db
+rm -f ns3/optout.nsec3.example.db
+rm -f ns3/optout.optout.example.db
+rm -f ns3/secure.nsec3.example.db
+rm -f ns3/secure.optout.example.db
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: sign.sh,v 1.23 2007/06/19 23:47:02 tbox Exp $
+# $Id: sign.sh,v 1.24 2008/09/24 02:46:21 marka Exp $
SYSTEMTESTTOP=../..
. $SYSTEMTESTTOP/conf.sh
cp trusted.conf ../ns3/trusted.conf
cp trusted.conf ../ns4/trusted.conf
cp trusted.conf ../ns6/trusted.conf
+cp trusted.conf ../ns7/trusted.conf
--- /dev/null
+; Copyright (C) 2006 Internet Systems Consortium, Inc. ("ISC")
+;
+; 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.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: child.nsec3.example.db,v 1.2 2008/09/24 02:46:21 marka Exp $
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2006081400 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+@ IN NS ns2.example.
--- /dev/null
+; Copyright (C) 2006 Internet Systems Consortium, Inc. ("ISC")
+;
+; 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.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: child.optout.example.db,v 1.2 2008/09/24 02:46:21 marka Exp $
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2006081400 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+@ IN NS ns2.example.
; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
; PERFORMANCE OF THIS SOFTWARE.
-; $Id: example.db.in,v 1.17 2007/06/19 23:47:02 tbox Exp $
+; $Id: example.db.in,v 1.18 2008/09/24 02:46:21 marka Exp $
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
keyless NS ns.keyless
ns.keyless A 10.53.0.3
+nsec3 NS ns.nsec3
+ns.nsec3 A 10.53.0.3
+
+optout NS ns.optout
+ns.optout A 10.53.0.3
+
+nsec3-unknown NS ns.nsec3-unknown
+ns.nsec3-unknown A 10.53.0.3
+
+optout-unknown NS ns.optout-unknown
+ns.optout-unknown A 10.53.0.3
+
+multiple NS ns.multiple
+ns.multiple A 10.53.0.3
+
*.wild A 10.0.0.27
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: named.conf,v 1.28 2007/06/19 23:47:02 tbox Exp $ */
+/* $Id: named.conf,v 1.29 2008/09/24 02:46:21 marka Exp $ */
// NS2
file "rfc2335.example.db";
};
+zone "child.nsec3.example" {
+ type master;
+ file "child.nsec3.example.db";
+ allow-update { none; };
+};
+
+zone "child.optout.example" {
+ type master;
+ file "child.optout.example.db";
+ allow-update { none; };
+};
include "trusted.conf";
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: sign.sh,v 1.28 2007/06/19 23:47:02 tbox Exp $
+# $Id: sign.sh,v 1.29 2008/09/24 02:46:21 marka Exp $
SYSTEMTESTTOP=../..
. $SYSTEMTESTTOP/conf.sh
( cd ../ns3 && sh sign.sh )
-for subdomain in secure bogus dynamic keyless
+for subdomain in secure bogus dynamic keyless nsec3 optout nsec3-unknown optout-unknown multiple
do
cp ../ns3/keyset-$subdomain.example. .
done
--- /dev/null
+; Copyright (C) 2008 Internet Systems Consortium, Inc. ("ISC")
+;
+; 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.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: insecure.nsec3.example.db,v 1.2 2008/09/24 02:46:21 marka Exp $
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
--- /dev/null
+; Copyright (C) 2008 Internet Systems Consortium, Inc. ("ISC")
+;
+; 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.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: insecure.optout.example.db,v 1.2 2008/09/24 02:46:21 marka Exp $
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
--- /dev/null
+; Copyright (C) 2006 Internet Systems Consortium, Inc. ("ISC")
+;
+; 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.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: multiple.example.db.in,v 1.2 2008/09/24 02:46:21 marka Exp $
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.e A 10.0.0.6
+child NS ns2.example.
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: named.conf,v 1.31 2007/06/19 23:47:02 tbox Exp $ */
+/* $Id: named.conf,v 1.32 2008/09/24 02:46:21 marka Exp $ */
// NS3
allow-update { any; };
};
+zone "insecure.nsec3.example" {
+ type master;
+ file "insecure.nsec3.example.db";
+ allow-update { any; };
+};
+
+zone "insecure.optout.example" {
+ type master;
+ file "insecure.optout.example.db";
+ allow-update { any; };
+};
+
zone "keyless.example" {
type master;
file "keyless.example.db.signed";
};
+zone "nsec3.example" {
+ type master;
+ file "nsec3.example.db.signed";
+};
+
+zone "optout.nsec3.example" {
+ type master;
+ file "optout.nsec3.example.db.signed";
+};
+
+zone "nsec3.nsec3.example" {
+ type master;
+ file "nsec3.nsec3.example.db.signed";
+};
+
+zone "secure.nsec3.example" {
+ type master;
+ file "secure.nsec3.example.db.signed";
+};
+
+zone "optout.example" {
+ type master;
+ file "optout.example.db.signed";
+};
+
+zone "secure.optout.example" {
+ type master;
+ file "secure.optout.example.db.signed";
+};
+
+zone "nsec3.optout.example" {
+ type master;
+ file "nsec3.optout.example.db.signed";
+};
+
+zone "optout.optout.example" {
+ type master;
+ file "optout.optout.example.db.signed";
+};
+
+zone "nsec3-unknown.example" {
+ type master;
+ nsec3-test-zone yes;
+ file "nsec3-unknown.example.db.signed";
+};
+
+zone "optout-unknown.example" {
+ type master;
+ nsec3-test-zone yes;
+ file "optout-unknown.example.db.signed";
+};
+
+zone "multiple.example" {
+ type master;
+ file "multiple.example.db.signed";
+ allow-update { any; };
+};
+
zone "mustbesecure.example" {
type master;
file "mustbesecure.example.db";
--- /dev/null
+; Copyright (C) 2006 Internet Systems Consortium, Inc. ("ISC")
+;
+; 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.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: nsec3-unknown.example.db.in,v 1.2 2008/09/24 02:46:21 marka Exp $
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.e A 10.0.0.6
+child NS ns2.example.
--- /dev/null
+; Copyright (C) 2006 Internet Systems Consortium, Inc. ("ISC")
+;
+; 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.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: nsec3.example.db.in,v 1.2 2008/09/24 02:46:21 marka Exp $
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.wild A 10.0.0.6
+child NS ns2.example.
+insecure NS ns.insecure
+ns.insecure A 10.53.0.3
+secure NS ns.secure
+ns.secure A 10.53.0.3
+nsec3 NS ns.nsec3
+ns.nsec3 A 10.53.0.3
+optout NS ns.optout
+ns.optout A 10.53.0.3
+02HC3EM7BDD011A0GMS3HKKJT2IF5VP8 A 10.0.0.17
--- /dev/null
+; Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000, 2001 Internet Software Consortium.
+;
+; 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.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: nsec3.nsec3.example.db.in,v 1.2 2008/09/24 02:46:21 marka Exp $
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
--- /dev/null
+; Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000, 2001 Internet Software Consortium.
+;
+; 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.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: nsec3.optout.example.db.in,v 1.2 2008/09/24 02:46:21 marka Exp $
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
--- /dev/null
+; Copyright (C) 2006 Internet Systems Consortium, Inc. ("ISC")
+;
+; 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.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: optout-unknown.example.db.in,v 1.2 2008/09/24 02:46:21 marka Exp $
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.e A 10.0.0.6
+child NS ns2.example.
--- /dev/null
+; Copyright (C) 2006 Internet Systems Consortium, Inc. ("ISC")
+;
+; 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.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: optout.example.db.in,v 1.2 2008/09/24 02:46:21 marka Exp $
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a A 10.0.0.3
+*.wild A 10.0.0.6
+insecure NS ns.insecure
+ns.insecure A 10.53.0.3
+secure NS ns.secure
+ns.secure A 10.53.0.3
+nsec3 NS ns.nsec3
+ns.nsec3 A 10.53.0.3
+optout NS ns.optout
+ns.optout A 10.53.0.3
+child NS ns2.example.
+insecure.empty NS ns.insecure.empty
+ns.insecure.empty A 10.53.0.3
+foo.*.empty-wild NS ns
--- /dev/null
+; Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000, 2001 Internet Software Consortium.
+;
+; 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.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: optout.nsec3.example.db.in,v 1.2 2008/09/24 02:46:21 marka Exp $
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
--- /dev/null
+; Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000, 2001 Internet Software Consortium.
+;
+; 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.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: optout.optout.example.db.in,v 1.2 2008/09/24 02:46:21 marka Exp $
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
; PERFORMANCE OF THIS SOFTWARE.
-; $Id: secure.example.db.in,v 1.11 2007/06/19 23:47:02 tbox Exp $
+; $Id: secure.example.db.in,v 1.12 2008/09/24 02:46:21 marka Exp $
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
b A 10.0.0.2
d A 10.0.0.4
z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
x CNAME a
private NS ns.private
--- /dev/null
+; Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000, 2001 Internet Software Consortium.
+;
+; 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.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: secure.nsec3.example.db.in,v 1.2 2008/09/24 02:46:21 marka Exp $
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
--- /dev/null
+; Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000, 2001 Internet Software Consortium.
+;
+; 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.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: secure.optout.example.db.in,v 1.2 2008/09/24 02:46:21 marka Exp $
+
+$TTL 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns
+ns A 10.53.0.3
+
+a A 10.0.0.1
+b A 10.0.0.2
+d A 10.0.0.4
+z A 10.0.0.26
+a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
+x CNAME a
+
+private NS ns.private
+ns.private A 10.53.0.2
+
+insecure NS ns.insecure
+ns.insecure A 10.53.0.2
+
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: sign.sh,v 1.23 2007/06/19 23:47:02 tbox Exp $
+# $Id: sign.sh,v 1.24 2008/09/24 02:46:21 marka Exp $
+
+SYSTEMTESTTOP=../..
+. $SYSTEMTESTTOP/conf.sh
RANDFILE=../random.data
<$zonefile.tmp perl -p -e 's/ keyless.example/ b.keyless.example/
if /^a.b.keyless.example/../NXT/;' >$zonefile.signed
rm -f $zonefile.tmp
+
+#
+# NSEC3/NSEC test zone
+#
+zone=secure.nsec3.example.
+infile=secure.nsec3.example.db.in
+zonefile=secure.nsec3.example.db
+
+keyname=`$KEYGEN -r $RANDFILE -a RSAMD5 -b 768 -n zone $zone`
+
+cat $infile $keyname.key >$zonefile
+
+$SIGNER -r $RANDFILE -o $zone $zonefile > /dev/null
+
+#
+# NSEC3/NSEC3 test zone
+#
+zone=nsec3.nsec3.example.
+infile=nsec3.nsec3.example.db.in
+zonefile=nsec3.nsec3.example.db
+
+keyname=`$KEYGEN -r $RANDFILE -a NSEC3RSASHA1 -b 768 -n zone $zone`
+
+cat $infile $keyname.key >$zonefile
+
+$SIGNER -3 - -r $RANDFILE -o $zone $zonefile > /dev/null
+
+#
+# OPTOUT/NSEC3 test zone
+#
+zone=optout.nsec3.example.
+infile=optout.nsec3.example.db.in
+zonefile=optout.nsec3.example.db
+
+keyname=`$KEYGEN -r $RANDFILE -a NSEC3RSASHA1 -b 768 -n zone $zone`
+
+cat $infile $keyname.key >$zonefile
+
+$SIGNER -3 - -A -r $RANDFILE -o $zone $zonefile > /dev/null
+
+#
+# A nsec3 zone (non-optout).
+#
+zone=nsec3.example.
+infile=nsec3.example.db.in
+zonefile=nsec3.example.db
+
+keyname=`$KEYGEN -r $RANDFILE -a NSEC3RSASHA1 -b 768 -n zone $zone`
+
+cat $infile $keyname.key >$zonefile
+
+$SIGNER -g -3 - -r $RANDFILE -o $zone $zonefile > /dev/null
+
+#
+# OPTOUT/NSEC test zone
+#
+zone=secure.optout.example.
+infile=secure.optout.example.db.in
+zonefile=secure.optout.example.db
+
+keyname=`$KEYGEN -r $RANDFILE -a RSAMD5 -b 768 -n zone $zone`
+
+cat $infile $keyname.key >$zonefile
+
+$SIGNER -r $RANDFILE -o $zone $zonefile > /dev/null
+
+#
+# OPTOUT/NSEC3 test zone
+#
+zone=nsec3.optout.example.
+infile=nsec3.optout.example.db.in
+zonefile=nsec3.optout.example.db
+
+keyname=`$KEYGEN -r $RANDFILE -a NSEC3RSASHA1 -b 768 -n zone $zone`
+
+cat $infile $keyname.key >$zonefile
+
+$SIGNER -3 - -r $RANDFILE -o $zone $zonefile > /dev/null
+
+#
+# OPTOUT/OPTOUT test zone
+#
+zone=optout.optout.example.
+infile=optout.optout.example.db.in
+zonefile=optout.optout.example.db
+
+keyname=`$KEYGEN -r $RANDFILE -a NSEC3RSASHA1 -b 768 -n zone $zone`
+
+cat $infile $keyname.key >$zonefile
+
+$SIGNER -3 - -A -r $RANDFILE -o $zone $zonefile > /dev/null
+
+#
+# A optout nsec3 zone.
+#
+zone=optout.example.
+infile=optout.example.db.in
+zonefile=optout.example.db
+
+keyname=`$KEYGEN -r $RANDFILE -a NSEC3RSASHA1 -b 768 -n zone $zone`
+
+cat $infile $keyname.key >$zonefile
+
+$SIGNER -g -3 - -A -r $RANDFILE -o $zone $zonefile > /dev/null
+
+#
+# A nsec3 zone (non-optout) with unknown hash algorithm.
+#
+zone=nsec3-unknown.example.
+infile=nsec3-unknown.example.db.in
+zonefile=nsec3-unknown.example.db
+
+keyname=`$KEYGEN -r $RANDFILE -a NSEC3RSASHA1 -b 768 -n zone $zone`
+
+cat $infile $keyname.key >$zonefile
+
+$SIGNER -3 - -U -r $RANDFILE -o $zone $zonefile > /dev/null
+
+#
+# A optout nsec3 zone.
+#
+zone=optout-unknown.example.
+infile=optout-unknown.example.db.in
+zonefile=optout-unknown.example.db
+
+keyname=`$KEYGEN -r $RANDFILE -a NSEC3RSASHA1 -b 768 -n zone $zone`
+
+cat $infile $keyname.key >$zonefile
+
+$SIGNER -3 - -U -A -r $RANDFILE -o $zone $zonefile > /dev/null
+
+#
+# A multiple parameter nsec3 zone.
+#
+zone=multiple.example.
+infile=multiple.example.db.in
+zonefile=multiple.example.db
+
+keyname=`$KEYGEN -r $RANDFILE -a NSEC3RSASHA1 -b 768 -n zone $zone`
+
+cat $infile $keyname.key >$zonefile
+
+$SIGNER -r $RANDFILE -o $zone $zonefile > /dev/null
+mv $zonefile.signed $zonefile
+$SIGNER -3 - -r $RANDFILE -o $zone $zonefile > /dev/null
+mv $zonefile.signed $zonefile
+$SIGNER -3 AAAA -r $RANDFILE -o $zone $zonefile > /dev/null
+mv $zonefile.signed $zonefile
+$SIGNER -3 BBBB -r $RANDFILE -o $zone $zonefile > /dev/null
+mv $zonefile.signed $zonefile
+$SIGNER -3 CCCC -r $RANDFILE -o $zone $zonefile > /dev/null
+mv $zonefile.signed $zonefile
+$SIGNER -3 DDDD -r $RANDFILE -o $zone $zonefile > /dev/null
--- /dev/null
+/*
+ * Copyright (C) 2006 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: named.conf,v 1.2 2008/09/24 02:46:21 marka Exp $ */
+
+// NS3
+
+controls { /* empty */ };
+
+options {
+ query-source address 10.53.0.7;
+ notify-source 10.53.0.7;
+ transfer-source 10.53.0.7;
+ port 5300;
+ pid-file "named.pid";
+ listen-on { 10.53.0.7; };
+ listen-on-v6 { none; };
+ recursion no;
+ notify yes;
+ dnssec-enable yes;
+ dnssec-validation yes;
+};
+
+zone "." {
+ type hint;
+ file "../../common/root.hint";
+};
+
+zone "nsec3.example" {
+ type slave;
+ masters { 10.53.0.3; };
+ file "nsec3.example.bk";
+};
+
+zone "optout.example" {
+ type slave;
+ masters { 10.53.0.3; };
+ file "optout.example.bk";
+};
+
+zone "nsec3-unknown.example" {
+ type slave;
+ masters { 10.53.0.3; };
+ file "nsec3-unknown.example.bk";
+};
+
+zone "optout-unknown.example" {
+ type slave;
+ masters { 10.53.0.3; };
+ file "optout-unknown.example.bk";
+};
+
+zone "multiple.example" {
+ type slave;
+ masters { 10.53.0.3; };
+ file "multiple.example.bk";
+};
+
+include "trusted.conf";
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: tests.sh,v 1.51 2007/06/19 23:47:02 tbox Exp $
+# $Id: tests.sh,v 1.52 2008/09/24 02:46:21 marka Exp $
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking positive validation ($n)"
+echo "I:checking positive validation NSEC ($n)"
ret=0
$DIG $DIGOPTS +noauth a.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
$DIG $DIGOPTS +noauth a.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking positive wildcard validation ($n)"
+echo "I:checking positive validation NSEC3 ($n)"
+ret=0
+$DIG $DIGOPTS +noauth a.nsec3.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth a.nsec3.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking positive validation OPTOUT ($n)"
+ret=0
+$DIG $DIGOPTS +noauth a.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth a.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking positive wildcard validation NSEC ($n)"
ret=0
$DIG $DIGOPTS a.wild.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
$DIG $DIGOPTS a.wild.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
$PERL ../digcomp.pl dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking positive wildcard validation NSEC3 ($n)"
+ret=0
+$DIG $DIGOPTS a.wild.nsec3.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS a.wild.nsec3.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking positive wildcard validation OPTOUT ($n)"
+ret=0
+$DIG $DIGOPTS a.wild.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS a.wild.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking negative validation ($n)"
+echo "I:checking negative validation NXDOMAIN NSEC ($n)"
ret=0
$DIG $DIGOPTS +noauth q.example. @10.53.0.2 a > dig.out.ns2.test$n || ret=1
$DIG $DIGOPTS +noauth q.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
$PERL ../digcomp.pl dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking negative validation NXDOMAIN NSEC3 ($n)"
+ret=0
+$DIG $DIGOPTS +noauth q.nsec3.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth q.nsec3.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking negative validation NXDOMAIN OPTOUT ($n)"
+ret=0
+$DIG $DIGOPTS +noauth q.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth q.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking negative validation NODATA NSEC ($n)"
+ret=0
+$DIG $DIGOPTS +noauth a.example. @10.53.0.2 txt > dig.out.ns2.test$n || ret=1
+$DIG $DIGOPTS +noauth a.example. @10.53.0.4 txt > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "ANSWER: 0" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking negative validation NODATA NSEC3 ($n)"
+ret=0
+$DIG $DIGOPTS +noauth a.nsec3.example. \
+ @10.53.0.3 txt > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth a.nsec3.example. \
+ @10.53.0.4 txt > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "ANSWER: 0" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking negative validation NODATA OPTOUT ($n)"
+ret=0
+$DIG $DIGOPTS +noauth a.optout.example. \
+ @10.53.0.3 txt > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth a.optout.example. \
+ @10.53.0.4 txt > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "ANSWER: 0" dig.out.ns4.test$n > /dev/null || ret=1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking negative wildcard validation ($n)"
+echo "I:checking negative wildcard validation NSEC ($n)"
ret=0
$DIG $DIGOPTS b.wild.example. @10.53.0.2 txt > dig.out.ns2.test$n || ret=1
$DIG $DIGOPTS b.wild.example. @10.53.0.4 txt > dig.out.ns4.test$n || ret=1
$PERL ../digcomp.pl dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking negative wildcard validation NSEC3 ($n)"
+ret=0
+$DIG $DIGOPTS b.wild.nsec3.example. @10.53.0.3 txt > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS b.wild.nsec3.example. @10.53.0.4 txt > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking negative wildcard validation OPTOUT ($n)"
+ret=0
+$DIG $DIGOPTS b.wild.optout.example. \
+ @10.53.0.3 txt > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS b.wild.optout.example. \
+ @10.53.0.4 txt > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
# Check the insecure.example domain
-echo "I:checking 1-server insecurity proof ($n)"
+echo "I:checking 1-server insecurity proof NSEC ($n)"
ret=0
$DIG $DIGOPTS +noauth a.insecure.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
$DIG $DIGOPTS +noauth a.insecure.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking 1-server negative insecurity proof ($n)"
+echo "I:checking 1-server insecurity proof NSEC3 ($n)"
+ret=0
+$DIG $DIGOPTS +noauth a.insecure.nsec3.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth a.insecure.nsec3.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking 1-server insecurity proof OPTOUT ($n)"
+ret=0
+$DIG $DIGOPTS +noauth a.insecure.optout.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth a.insecure.optout.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking 1-server negative insecurity proof NSEC ($n)"
ret=0
$DIG $DIGOPTS q.insecure.example. a @10.53.0.3 \
> dig.out.ns3.test$n || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
-echo "I:checking 1-server negative insecurity proof with SOA hack ($n)"
+echo "I:checking 1-server negative insecurity proof NSEC3 ($n)"
+ret=0
+$DIG $DIGOPTS q.insecure.nsec3.example. a @10.53.0.3 \
+ > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS q.insecure.nsec3.example. a @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking 1-server negative insecurity proof OPTOUT ($n)"
+ret=0
+$DIG $DIGOPTS q.insecure.optout.example. a @10.53.0.3 \
+ > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS q.insecure.optout.example. a @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking 1-server negative insecurity proof with SOA hack NSEC ($n)"
ret=0
$DIG $DIGOPTS r.insecure.example. soa @10.53.0.3 \
> dig.out.ns3.test$n || ret=1
> dig.out.ns4.test$n || ret=1
$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+grep "0 IN SOA" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking 1-server negative insecurity proof with SOA hack NSEC3 ($n)"
+ret=0
+$DIG $DIGOPTS r.insecure.nsec3.example. soa @10.53.0.3 \
+ > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS r.insecure.nsec3.example. soa @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+grep "0 IN SOA" dig.out.ns4.test$n > /dev/null || ret=1
+# Note - this is looking for failure, hence the &&
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking 1-server negative insecurity proof with SOA hack OPTOUT ($n)"
+ret=0
+$DIG $DIGOPTS r.insecure.optout.example. soa @10.53.0.3 \
+ > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS r.insecure.optout.example. soa @10.53.0.4 \
+ > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+grep "0 IN SOA" dig.out.ns4.test$n > /dev/null || ret=1
# Note - this is looking for failure, hence the &&
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
n=`expr $n + 1`
# Check the secure.example domain
-echo "I:checking multi-stage positive validation ($n)"
+echo "I:checking multi-stage positive validation NSEC/NSEC ($n)"
+ret=0
+$DIG $DIGOPTS +noauth a.secure.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth a.secure.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking multi-stage positive validation NSEC/NSEC3 ($n)"
+ret=0
+$DIG $DIGOPTS +noauth a.nsec3.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth a.nsec3.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking multi-stage positive validation NSEC/OPTOUT ($n)"
ret=0
-$DIG $DIGOPTS +noauth a.secure.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
-$DIG $DIGOPTS +noauth a.secure.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$DIG $DIGOPTS +noauth a.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth a.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking multi-stage positive validation NSEC3/NSEC ($n)"
+ret=0
+$DIG $DIGOPTS +noauth a.secure.nsec3.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth a.secure.nsec3.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking multi-stage positive validation NSEC3/NSEC3 ($n)"
+ret=0
+$DIG $DIGOPTS +noauth a.nsec3.nsec3.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth a.nsec3.nsec3.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking multi-stage positive validation NSEC3/OPTOUT ($n)"
+ret=0
+$DIG $DIGOPTS +noauth a.optout.nsec3.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth a.optout.nsec3.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking multi-stage positive validation OPTOUT/NSEC ($n)"
+ret=0
+$DIG $DIGOPTS +noauth a.secure.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth a.secure.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking multi-stage positive validation OPTOUT/NSEC3 ($n)"
+ret=0
+$DIG $DIGOPTS +noauth a.nsec3.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth a.nsec3.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking multi-stage positive validation OPTOUT/OPTOUT ($n)"
+ret=0
+$DIG $DIGOPTS +noauth a.optout.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth a.optout.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
+echo "I:checking empty NODATA OPTOUT ($n)"
+ret=0
+$DIG $DIGOPTS +noauth empty.optout.example. \
+ @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth empty.optout.example. \
+ @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "status: NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
+#grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
# Check the bogus domain
echo "I:checking failed validation ($n)"
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: ifconfig.sh,v 1.54 2008/07/25 20:40:07 fdupont Exp $
+# $Id: ifconfig.sh,v 1.55 2008/09/24 02:46:21 marka Exp $
#
# Set up interface aliases for bind9 system tests.
case "$1" in
start|up)
- for ns in 1 2 3 4 5 6
+ for ns in 1 2 3 4 5 6 7
do
if test -n "$base"
then
;;
stop|down)
- for ns in 6 5 4 3 2 1
+ for ns in 7 6 5 4 3 2 1
do
if test -n "$base"
then
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zone2bdb.c,v 1.1 2002/05/16 04:25:22 marka Exp $ */
+/* $Id: zone2bdb.c,v 1.2 2008/09/24 02:46:21 marka Exp $ */
#include <stdio.h>
REQUIRE(dns_db_load(db, argv[2]) == ISC_R_SUCCESS);
- REQUIRE(dns_db_createiterator(db, ISC_FALSE, &dbiter) == ISC_R_SUCCESS);
+ REQUIRE(dns_db_createiterator(db, 0, &dbiter) == ISC_R_SUCCESS);
dns_rdataset_init(&rdataset);
dns_rdata_init(&rdata);
result = dns_db_load (db, zonefile);
isc_result_check (result, "Check Zone Syntax: dns_db_load");
- result = dns_db_createiterator (db, ISC_FALSE, &dbit);
+ result = dns_db_createiterator (db, 0, &dbit);
isc_result_check (result, "dns_db_createiterator");
result = dns_dbiterator_first (dbit);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zonetodb.c,v 1.18 2007/06/18 23:47:33 tbox Exp $ */
+/* $Id: zonetodb.c,v 1.19 2008/09/24 02:46:21 marka Exp $ */
#include <stdlib.h>
#include <string.h>
PQclear(res);
dbiter = NULL;
- result = dns_db_createiterator(db, ISC_FALSE, &dbiter);
+ result = dns_db_createiterator(db, 0, &dbiter);
check_result(result, "dns_db_createiterator()");
result = dns_dbiterator_first(dbiter);
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zone2sqlite.c,v 1.1 2007/03/05 05:30:22 marka Exp $ */
+/* $Id: zone2sqlite.c,v 1.2 2008/09/24 02:46:21 marka Exp $ */
#include <stdlib.h>
#include <string.h>
}
dbiter = NULL;
- result = dns_db_createiterator(db, ISC_FALSE, &dbiter);
+ result = dns_db_createiterator(db, 0, &dbiter);
check_result(result, "dns_db_createiterator()");
result = dns_dbiterator_first(dbiter);
notify-source ( <ipv4_address> | * ) [ port ( <integer> | * ) ];
notify-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ];
notify-to-soa <boolean>;
+ nsec3-test-zone <boolean>; // test only
pid-file ( <quoted_string> | none );
port <integer>;
preferred-glue <string>;
notify-source ( <ipv4_address> | * ) [ port ( <integer> | * ) ];
notify-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ];
notify-to-soa <boolean>;
+ nsec3-test-zone <boolean>; // test only
preferred-glue <string>;
provide-ixfr <boolean>;
query-source <querysource4>;
notify-source-v6 ( <ipv6_address> | * ) [ port ( <integer>
| * ) ];
notify-to-soa <boolean>;
+ nsec3-test-zone <boolean>; // test only
pubkey <integer> <integer> <integer>
<quoted_string>; // obsolete
sig-signing-nodes <integer>;
notify-source ( <ipv4_address> | * ) [ port ( <integer> | * ) ];
notify-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ];
notify-to-soa <boolean>;
+ nsec3-test-zone <boolean>; // test only
pubkey <integer> <integer> <integer> <quoted_string>; // obsolete
sig-signing-nodes <integer>;
sig-signing-signatures <integer>;
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: Makefile.in,v 1.162 2008/04/01 23:47:10 tbox Exp $
+# $Id: Makefile.in,v 1.163 2008/09/24 02:46:22 marka Exp $
srcdir = @srcdir@
VPATH = @srcdir@
dlz.@O@ dnssec.@O@ ds.@O@ forward.@O@ iptable.@O@ journal.@O@ \
keytable.@O@ lib.@O@ log.@O@ lookup.@O@ \
master.@O@ masterdump.@O@ message.@O@ \
- name.@O@ ncache.@O@ nsec.@O@ order.@O@ peer.@O@ portlist.@O@ \
+ name.@O@ ncache.@O@ nsec.@O@ nsec3.@O@ order.@O@ peer.@O@ portlist.@O@ \
rbt.@O@ rbtdb.@O@ rbtdb64.@O@ rcode.@O@ rdata.@O@ \
rdatalist.@O@ \
rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ request.@O@ \
dlz.c dnssec.c ds.c forward.c iptable.c journal.c \
keytable.c lib.c log.c lookup.c \
master.c masterdump.c message.c \
- name.c ncache.c nsec.c order.c peer.c portlist.c \
+ name.c ncache.c nsec.c nsec3.c order.c peer.c portlist.c \
rbt.c rbtdb.c rbtdb64.c rcode.c rdata.c \
rdatalist.c \
rdataset.c rdatasetiter.c rdataslab.c request.c \
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: cache.c,v 1.79 2008/05/01 18:23:07 jinmei Exp $ */
+/* $Id: cache.c,v 1.80 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
REQUIRE(VALID_CACHE(cache));
- result = dns_db_createiterator(cache->db, ISC_FALSE, &iterator);
+ result = dns_db_createiterator(cache->db, 0, &iterator);
if (result != ISC_R_SUCCESS)
return result;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: db.c,v 1.87 2008/04/03 05:55:52 marka Exp $ */
+/* $Id: db.c,v 1.88 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
return ((db->methods->findnode)(db, name, create, nodep));
}
+isc_result_t
+dns_db_findnsec3node(dns_db_t *db, dns_name_t *name,
+ isc_boolean_t create, dns_dbnode_t **nodep)
+{
+
+ /*
+ * Find the node with name 'name'.
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(nodep != NULL && *nodep == NULL);
+
+ return ((db->methods->findnsec3node)(db, name, create, nodep));
+}
+
isc_result_t
dns_db_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
***/
isc_result_t
-dns_db_createiterator(dns_db_t *db, isc_boolean_t relative_names,
+dns_db_createiterator(dns_db_t *db, unsigned int flags,
dns_dbiterator_t **iteratorp)
{
/*
REQUIRE(DNS_DB_VALID(db));
REQUIRE(iteratorp != NULL && *iteratorp == NULL);
- return (db->methods->createiterator(db, relative_names, iteratorp));
+ return (db->methods->createiterator(db, flags, iteratorp));
}
/***
return (NULL);
}
+isc_result_t
+dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version,
+ dns_hash_t *hash, isc_uint8_t *flags,
+ isc_uint16_t *iterations,
+ unsigned char *salt, size_t *salt_length)
+{
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(dns_db_iszone(db) == ISC_TRUE);
+
+ if (db->methods->getnsec3parameters != NULL)
+ return ((db->methods->getnsec3parameters)(db, version, hash,
+ flags, iterations,
+ salt, salt_length));
+
+ return (ISC_R_NOTFOUND);
+}
+
isc_result_t
dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
isc_stdtime_t resign)
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: diff.c,v 1.17 2008/04/02 02:37:42 marka Exp $ */
+/* $Id: diff.c,v 1.18 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
* but such diffs should never be created in the first
* place.
*/
- node = NULL;
- CHECK(dns_db_findnode(db, name, ISC_TRUE, &node));
while (t != NULL && dns_name_equal(&t->name, name)) {
dns_rdatatype_t type, covers;
ISC_LIST_INIT(rdl.rdata);
ISC_LINK_INIT(&rdl, link);
+ node = NULL;
+ if (type != dns_rdatatype_nsec3 &&
+ covers != dns_rdatatype_nsec3)
+ CHECK(dns_db_findnode(db, name, ISC_TRUE,
+ &node));
+ else
+ CHECK(dns_db_findnsec3node(db, name, ISC_TRUE,
+ &node));
+
offline = ISC_FALSE;
while (t != NULL &&
dns_name_equal(&t->name, name) &&
dns_rdataset_disassociate(modified);
CHECK(result);
}
+ dns_db_detachnode(db, &node);
if (modified != NULL &&
dns_rdataset_isassociated(modified))
dns_rdataset_disassociate(modified);
}
- dns_db_detachnode(db, &node);
}
return (ISC_R_SUCCESS);
/*
* Principal Author: Brian Wellington
- * $Id: dst_api.c,v 1.14 2008/04/01 23:47:10 tbox Exp $
+ * $Id: dst_api.c,v 1.15 2008/09/24 02:46:22 marka Exp $
*/
/*! \file */
RETERR(dst__openssl_init());
RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5]));
RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1]));
+ RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1]));
#ifdef HAVE_OPENSSL_DSA
RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_DSA]));
+ RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_NSEC3DSA]));
#endif
RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH]));
#endif /* OPENSSL */
switch (key->key_alg) {
case DST_ALG_RSAMD5:
case DST_ALG_RSASHA1:
+ case DST_ALG_NSEC3RSASHA1:
*n = (key->key_size + 7) / 8;
break;
case DST_ALG_DSA:
+ case DST_ALG_NSEC3DSA:
*n = DNS_SIG_DSASIGSIZE;
break;
case DST_ALG_HMACMD5:
switch (key->key_alg) {
case DST_ALG_RSAMD5:
case DST_ALG_RSASHA1:
+ case DST_ALG_NSEC3RSASHA1:
case DST_ALG_DSA:
+ case DST_ALG_NSEC3DSA:
case DST_ALG_DH:
return (ISC_FALSE);
case DST_ALG_HMACMD5:
#ifndef OPENSSL
if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 ||
alg == DST_ALG_DSA || alg == DST_ALG_DH ||
- alg == DST_ALG_HMACMD5)
+ alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA ||
+ alg == DST_ALG_NSEC3RSASHA1)
return (DST_R_NOCRYPTO);
#endif
return (DST_R_UNSUPPORTEDALG);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: gen.c,v 1.81 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: gen.c,v 1.82 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
#include "gen-unix.h"
#endif
+#define TYPECLASSLEN 21
+
#define FROMTEXTARGS "rdclass, type, lexer, origin, options, target, callbacks"
#define FROMTEXTCLASS "rdclass"
#define FROMTEXTTYPE "type"
struct cc {
struct cc *next;
int rdclass;
- char classname[11];
+ char classname[TYPECLASSLEN];
} *classes;
struct tt {
struct tt *next;
int rdclass;
int type;
- char classname[11];
- char typename[11];
+ char classname[TYPECLASSLEN];
+ char typename[TYPECLASSLEN];
char dirname[256]; /* XXX Should be max path length */
} *types;
struct ttnam {
- char typename[11];
- char macroname[11];
+ char typename[TYPECLASSLEN];
+ char macroname[TYPECLASSLEN];
char attr[256];
unsigned int sorted;
int type;
int first = 1;
int lasttype = 0;
int subswitch = 0;
- char buf1[11], buf2[11];
+ char buf1[TYPECLASSLEN], buf2[TYPECLASSLEN];
const char *result = " result =";
if (res == NULL)
void
dodecl(char *type, char *function, char *args) {
struct tt *tt;
- char buf1[11], buf2[11];
+ char buf1[TYPECLASSLEN], buf2[TYPECLASSLEN];
fputs("\n", stdout);
for (tt = types; tt; tt = tt->next)
fprintf(stderr, "Error: typenames array too small\n");
exit(1);
}
-
+
if (strlen(typename) > sizeof(ttn->typename) - 1) {
fprintf(stderr, "Error: type name %s is too long\n",
typename);
newtt->type = type;
strcpy(newtt->classname, classname);
strcpy(newtt->typename, typename);
+ if (strncmp(dirname, "./", 2) == 0)
+ dirname += 2;
strcpy(newtt->dirname, dirname);
tt = types;
void
sd(int rdclass, const char *classname, const char *dirname, char filetype) {
- char buf[sizeof("0123456789_65535.h")];
- char fmt[sizeof("%10[-0-9a-z]_%d.h")];
+ char buf[sizeof("01234567890123456789_65535.h")];
+ char fmt[sizeof("%20[-0-9a-z]_%d.h")];
int type;
- char typename[11];
+ char typename[TYPECLASSLEN];
isc_dir_t dir;
if (!start_directory(dirname, &dir))
return;
- sprintf(fmt,"%s%c", "%10[-0-9a-z]_%d.", filetype);
+ sprintf(fmt,"%s%c", "%20[-0-9a-z]_%d.", filetype);
while (next_file(&dir)) {
if (sscanf(dir.filename, fmt, typename, &type) != 2)
continue;
char buf[256]; /* XXX Should be max path length */
char srcdir[256]; /* XXX Should be max path length */
int rdclass;
- char classname[11];
+ char classname[TYPECLASSLEN];
struct tt *tt;
struct cc *cc;
struct ttnam *ttn, *ttn2;
int structs = 0;
int depend = 0;
int c, i, j;
- char buf1[11];
+ char buf1[TYPECLASSLEN];
char filetype = 'c';
FILE *fd;
char *prefix = NULL;
sd(0, "", buf, filetype);
if (time(&now) != -1) {
- if ((tm = localtime(&now)) != NULL && tm->tm_year > 104)
+ if ((tm = localtime(&now)) != NULL && tm->tm_year > 104)
sprintf(year, "-%d", tm->tm_year + 1900);
else
year[0] = 0;
"\t\t strncasecmp(_s,(_tn),"
"(sizeof(_s) - 1)) == 0) { \\\n");
fprintf(stdout, "\t\t\tif ((dns_rdatatype_attributes(_d) & "
- "DNS_RDATATYPEATTR_RESERVED) != 0) \\\n");
+ "DNS_RDATATYPEATTR_RESERVED) != 0) \\\n");
fprintf(stdout, "\t\t\t\treturn (ISC_R_NOTIMPLEMENTED); \\\n");
fprintf(stdout, "\t\t\t*(_tp) = _d; \\\n");
fprintf(stdout, "\t\t\treturn (ISC_R_SUCCESS); \\\n");
if (ttn == NULL)
continue;
fprintf(stdout, "\tcase %u: return (%s); \\\n",
- i, upper(ttn->attr));
+ i, upper(ttn->attr));
}
fprintf(stdout, "\t}\n");
continue;
fprintf(stdout, "\tcase %u: return "
"(str_totext(\"%s\", target)); \\\n",
- i, upper(ttn->typename));
+ i, upper(ttn->typename));
}
fprintf(stdout, "\t}\n");
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: db.h,v 1.92 2008/04/03 05:55:52 marka Exp $ */
+/* $Id: db.h,v 1.93 2008/09/24 02:46:22 marka Exp $ */
#ifndef DNS_DB_H
#define DNS_DB_H 1
isc_stdtime_t now);
void (*printnode)(dns_db_t *db, dns_dbnode_t *node,
FILE *out);
- isc_result_t (*createiterator)(dns_db_t *db,
- isc_boolean_t relative_names,
+ isc_result_t (*createiterator)(dns_db_t *db, unsigned int options,
dns_dbiterator_t **iteratorp);
isc_result_t (*findrdataset)(dns_db_t *db, dns_dbnode_t *node,
dns_dbversion_t *version,
isc_result_t (*getoriginnode)(dns_db_t *db, dns_dbnode_t **nodep);
void (*transfernode)(dns_db_t *db, dns_dbnode_t **sourcep,
dns_dbnode_t **targetp);
+ isc_result_t (*getnsec3parameters)(dns_db_t *db,
+ dns_dbversion_t *version,
+ dns_hash_t *hash,
+ isc_uint8_t *flags,
+ isc_uint16_t *iterations,
+ unsigned char *salt,
+ size_t *salt_len);
+ isc_result_t (*findnsec3node)(dns_db_t *db, dns_name_t *name,
+ isc_boolean_t create,
+ dns_dbnode_t **nodep);
isc_result_t (*setsigningtime)(dns_db_t *db,
dns_rdataset_t *rdataset,
isc_stdtime_t resign);
#define DNS_DBFIND_NOEXACT 0x10
#define DNS_DBFIND_FORCENSEC 0x20
#define DNS_DBFIND_COVERINGNSEC 0x40
+#define DNS_DBFIND_FORCENSEC3 0x80
/*@}*/
/*@{*/
*/
#define DNS_DBSUB_EXACT 0x01
+/*@{*/
+/*%
+ * Iterator options
+ */
+#define DNS_DB_RELATIVENAMES 0x1
+#define DNS_DB_NSEC3ONLY 0x2
+#define DNS_DB_NONSEC3 0x4
+/*@}*/
+
/*****
***** Methods
*****/
* name, and 'rdataset' contains
* the negative caching proof.
*
- * \li #DNS_R_EMPTYNAME The name exists but there is
+ * \li #DNS_R_EMPTYNAME The name exists but there is
* no data at the name.
*
* \li #DNS_R_COVERINGNSEC The returned data is a NSEC
***/
isc_result_t
-dns_db_createiterator(dns_db_t *db, isc_boolean_t relative_names,
+dns_db_createiterator(dns_db_t *db, unsigned int options,
dns_dbiterator_t **iteratorp);
/*%<
* Create an iterator for version 'version' of 'db'.
*
* Notes:
*
- * \li If 'relative_names' is ISC_TRUE, then node names returned by the
- * iterator will be relative to the iterator's current origin. If
- * #ISC_FALSE, then the node names will be absolute.
+ * \li One or more of the following options can be set.
+ * #DNS_DB_RELATIVENAMES
+ * #DNS_DB_NSEC3ONLY
+ * #DNS_DB_NONSEC3
*
* Requires:
*
* \li #ISC_R_NOTFOUND - the DB implementation does not support this feature.
*/
+isc_result_t
+dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version,
+ dns_hash_t *hash, isc_uint8_t *flags,
+ isc_uint16_t *interations,
+ unsigned char *salt, size_t *salt_length);
+/*%<
+ * Get the NSEC3 parameters that are associated with this zone.
+ *
+ * Requires:
+ * \li 'db' is a valid zone database.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND - the DB implementation does not support this feature
+ * or this zone does not have NSEC3 records.
+ */
+
+isc_result_t
+dns_db_findnsec3node(dns_db_t *db, dns_name_t *name,
+ isc_boolean_t create, dns_dbnode_t **nodep);
+/*%<
+ * Find the NSEC3 node with name 'name'.
+ *
+ * Notes:
+ * \li If 'create' is ISC_TRUE and no node with name 'name' exists, then
+ * such a node will be created.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li 'name' is a valid, non-empty, absolute name.
+ *
+ * \li nodep != NULL && *nodep == NULL
+ *
+ * Ensures:
+ *
+ * \li On success, *nodep is attached to the node with name 'name'.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND If !create and name not found.
+ * \li #ISC_R_NOMEMORY Can only happen if create is ISC_TRUE.
+ *
+ * \li Other results are possible, depending upon the database
+ * implementation used.
+ */
+
isc_result_t
dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
isc_stdtime_t resign);
* \li 'version' to be open for writing.
*/
-
dns_stats_t *
dns_db_getrrsetstats(dns_db_t *db);
/*%<
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: keyvalues.h,v 1.21 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: keyvalues.h,v 1.22 2008/09/24 02:46:23 marka Exp $ */
#ifndef DNS_KEYVALUES_H
#define DNS_KEYVALUES_H 1
#define DNS_KEYALG_RSA DNS_KEYALG_RSAMD5
#define DNS_KEYALG_DH 2 /*%< Diffie Hellman KEY */
#define DNS_KEYALG_DSA 3 /*%< DSA KEY */
-#define DNS_KEYALG_DSS NS_ALG_DSA
+#define DNS_KEYALG_NSEC3DSA 6
+#define DNS_KEYALG_DSS DNS_ALG_DSA
#define DNS_KEYALG_ECC 4
#define DNS_KEYALG_RSASHA1 5
+#define DNS_KEYALG_NSEC3RSASHA1 7
#define DNS_KEYALG_INDIRECT 252
#define DNS_KEYALG_PRIVATEDNS 253
#define DNS_KEYALG_PRIVATEOID 254 /*%< Key begins with OID giving alg */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: masterdump.h,v 1.41 2008/04/01 23:47:10 tbox Exp $ */
+/* $Id: masterdump.h,v 1.42 2008/09/24 02:46:23 marka Exp $ */
#ifndef DNS_MASTERDUMP_H
#define DNS_MASTERDUMP_H 1
void
dns_master_styledestroy(dns_master_style_t **style, isc_mem_t *mctx);
+const char *
+dns_trust_totext(dns_trust_t trust);
+
ISC_LANG_ENDDECLS
#endif /* DNS_MASTERDUMP_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: ncache.h,v 1.23 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: ncache.h,v 1.24 2008/09/24 02:46:23 marka Exp $ */
#ifndef DNS_NCACHE_H
#define DNS_NCACHE_H 1
dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
dns_rdataset_t *addedrdataset);
+isc_result_t
+dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache,
+ dns_dbnode_t *node, dns_rdatatype_t covers,
+ isc_stdtime_t now, dns_ttl_t maxttl,
+ isc_boolean_t optout, dns_rdataset_t *addedrdataset);
/*%<
* Convert the authority data from 'message' into a negative cache
* rdataset, and store it in 'cache' at 'node' with a TTL limited to
* The 'covers' argument is the RR type whose nonexistence we are caching,
* or dns_rdatatype_any when caching a NXDOMAIN response.
*
+ * 'optout' indicates a DNS_RATASETATTR_OPTOUT should be set.
+ *
* Note:
*\li If 'addedrdataset' is not NULL, then it will be attached to the added
* rdataset. See dns_db_addrdataset() for more details.
*
*/
+void
+dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found,
+ dns_rdataset_t *rdataset);
+
+/*%<
+ * Extract the current rdataset and name from a ncache entry.
+ *
+ * Requires:
+ * \li 'ncacherdataset' to be valid and to be a negative cache entry
+ * \li 'found' to be valid.
+ * \li 'rdataset' to be unassociated.
+ */
+
ISC_LANG_ENDDECLS
#endif /* DNS_NCACHE_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: nsec.h,v 1.10 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: nsec.h,v 1.11 2008/09/24 02:46:23 marka Exp $ */
#ifndef DNS_NSEC_H
#define DNS_NSEC_H 1
*\li 'nsec' points to a valid rdataset of type NSEC
*/
+isc_result_t
+dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version,
+ isc_boolean_t *answer);
+/*
+ * Report whether the DNSKEY RRset has a NSEC only algorithm. Unknown
+ * algorithms are assumed to support NSEC3.
+ *
+ * Requires:
+ * 'answer' to be non NULL.
+ */
+
ISC_LANG_ENDDECLS
#endif /* DNS_NSEC_H */
/*
- * Copyright (C) 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001, 2003 Internet Software Consortium.
*
- * Permission to use, copy, modify, and/or distribute this software for any
+ * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: nsec3.h,v 1.3 2008/04/04 23:47:01 tbox Exp $ */
+/* $Id: nsec3.h,v 1.4 2008/09/24 02:46:23 marka Exp $ */
#ifndef DNS_NSEC3_H
#define DNS_NSEC3_H 1
#include <isc/lang.h>
#include <isc/iterated_hash.h>
-#include <dns/types.h>
+#include <dns/db.h>
+#include <dns/diff.h>
#include <dns/name.h>
+#include <dns/rdatastruct.h>
+#include <dns/types.h>
/*
- * hash = 1, iterations + optin = 3, salt length = 1, salt = 255 (max)
+ * hash = 1, flags =1, iterations = 2, salt length = 1, salt = 255 (max)
* hash length = 1, hash = 255 (max), bitmap = 8192 + 512 (max)
*/
#define DNS_NSEC3_BUFFERSIZE (6 + 255 + 255 + 8192 + 512)
+/*
+ * hash = 1, flags = 1, iterations = 2, salt length = 1, salt = 255 (max)
+ */
+#define DNS_NSEC3PARAM_BUFFERSIZE (5 + 255)
/*
* Test "unknown" algorithm. Is mapped to dns_hash_sha1.
dns_nsec3_buildrdata(dns_db_t *db, dns_dbversion_t *version,
dns_dbnode_t *node, unsigned int hashalg,
unsigned int optin, unsigned int iterations,
- const unsigned char *salt, size_t salt_length,
+ const unsigned char *salt, size_t salt_length,
const unsigned char *nexthash, size_t hash_length,
unsigned char *buffer, dns_rdata_t *rdata);
-/*
- * Build the rdata of a NSEC3 record.
+/*%<
+ * Build the rdata of a NSEC3 record for the data at 'node'.
+ * Note: 'node' is not the node where the NSEC3 record will be stored.
*
* Requires:
* buffer Points to a temporary buffer of at least
* rdata Points to an initialized dns_rdata_t.
*
* Ensures:
- * *rdata Contains a valid NSEC rdata. The 'data' member refers
+ * *rdata Contains a valid NSEC3 rdata. The 'data' member refers
* to 'buffer'.
*/
-isc_result_t
-dns_nsec3_build(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
- int auth_only, const char *salt, size_t salt_length,
- int iterations, dns_ttl_t ttl);
-/*
- * Build an NSEC3 record and add it to a database.
- */
-
isc_boolean_t
dns_nsec3_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type);
-/*
+/*%<
* Determine if a type is marked as present in an NSEC3 record.
*
* Requires:
size_t *hash_length, dns_name_t *name, dns_name_t *origin,
dns_hash_t hashalg, unsigned int iterations,
const unsigned char *salt, size_t saltlength);
-/*
+/*%<
* Make a hashed domain name from an unhashed one. If rethash is not NULL
* the raw hash is stored there.
*/
unsigned int
dns_nsec3_hashlength(dns_hash_t hash);
-/*
+/*%<
* Return the length of the hash produced by the specified algorithm
* or zero when unknown.
*/
isc_boolean_t
dns_nsec3_supportedhash(dns_hash_t hash);
-/*
+/*%<
* Return whether we support this hash algorithm or not.
*/
+isc_result_t
+dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version,
+ dns_name_t *name, const dns_rdata_nsec3param_t *nsec3param,
+ dns_ttl_t nsecttl, isc_boolean_t unsecure, dns_diff_t *diff);
+
+isc_result_t
+dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version,
+ dns_name_t *name, dns_ttl_t nsecttl,
+ isc_boolean_t unsecure, dns_diff_t *diff);
+/*%<
+ * Add NSEC3 records for 'name', recording the change in 'diff'.
+ * Adjust previous NSEC3 records, if any, to reflect the addition.
+ * The existing NSEC3 records are removed.
+ *
+ * dns_nsec3_addnsec3() will only add records to the chain identified by
+ * 'nsec3param'.
+ *
+ * 'unsecure' should be set to reflect if this is a potentially
+ * unsecure delegation (no DS record).
+ *
+ * dns_nsec3_addnsec3s() will examine the NSEC3PARAM RRset to determine which
+ * chains to be updated. NSEC3PARAM records with the DNS_NSEC3FLAG_CREATE
+ * will be preferentially choosen over NSEC3PARAM records without
+ * DNS_NSEC3FLAG_CREATE set. NSEC3PARAM records with DNS_NSEC3FLAG_REMOVE
+ * set will be ignored by dns_nsec3_addnsec3s(). If DNS_NSEC3FLAG_CREATE
+ * is set then the new NSEC3 will have OPTOUT set to match the that in the
+ * NSEC3PARAM record otherwise OPTOUT will be inherited from the previous
+ * record in the chain.
+ *
+ * Requires:
+ * 'db' to be valid.
+ * 'version' to be valid or NULL.
+ * 'name' to be valid.
+ * 'nsec3param' to be valid.
+ * 'diff' to be valid.
+ */
+
+isc_result_t
+dns_nsec3_delnsec3(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
+ const dns_rdata_nsec3param_t *nsec3param, dns_diff_t *diff);
+
+isc_result_t
+dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
+ dns_diff_t *diff);
+/*%<
+ * Remove NSEC3 records for 'name', recording the change in 'diff'.
+ * Adjust previous NSEC3 records, if any, to reflect the removal.
+ *
+ * dns_nsec3_delnsec3() performs the above for the chain identified by
+ * 'nsec3param'.
+ *
+ * dns_nsec3_delnsec3s() examines the NSEC3PARAM RRset in a similar manner
+ * to dns_nsec3_addnsec3s(). Unlike dns_nsec3_addnsec3s() updated NSEC3
+ * records have the OPTOUT flag preserved.
+ *
+ * Requires:
+ * 'db' to be valid.
+ * 'version' to be valid or NULL.
+ * 'name' to be valid.
+ * 'nsec3param' to be valid.
+ * 'diff' to be valid.
+ */
+
+isc_result_t
+dns_nsec3_active(dns_db_t *db, dns_dbversion_t *version,
+ isc_boolean_t complete, isc_boolean_t *answer);
+/*%<
+ * Check if there are any complete/to be built NSEC3 chains.
+ * If 'complete' is ISC_TRUE only complete chains will be recognised.
+ *
+ * Requires:
+ * 'db' to be valid.
+ * 'version' to be valid or NULL.
+ * 'answer' to be non NULL.
+ */
+
+isc_result_t
+dns_nsec3_maxiterations(dns_db_t *db, dns_dbversion_t *version,
+ isc_mem_t *mctx, unsigned int *iterationsp);
+/*%<
+ * Find the maximum permissible number of iterations allowed based on
+ * the key strength.
+ *
+ * Requires:
+ * 'db' to be valid.
+ * 'version' to be valid or NULL.
+ * 'mctx' to be valid.
+ * 'iterationsp' to be non NULL.
+ */
+
ISC_LANG_ENDDECLS
-#endif /* DNS_NSEC2_H */
+#endif /* DNS_NSEC3_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rbt.h,v 1.69 2007/10/19 17:15:53 explorer Exp $ */
+/* $Id: rbt.h,v 1.70 2008/09/24 02:46:23 marka Exp $ */
#ifndef DNS_RBT_H
#define DNS_RBT_H 1
typedef struct dns_rbtnode dns_rbtnode_t;
struct dns_rbtnode {
#if DNS_RBT_USEMAGIC
- unsigned int magic;
+ unsigned int magic;
#endif
- dns_rbtnode_t *parent;
- dns_rbtnode_t *left;
- dns_rbtnode_t *right;
- dns_rbtnode_t *down;
+ dns_rbtnode_t *parent;
+ dns_rbtnode_t *left;
+ dns_rbtnode_t *right;
+ dns_rbtnode_t *down;
#ifdef DNS_RBT_USEHASH
- dns_rbtnode_t *hashnext;
+ dns_rbtnode_t *hashnext;
#endif
- /*%
- * Used for LRU cache. This linked list is used to mark nodes which
- * have no data any longer, but we cannot unlink at that exact moment
- * because we did not or could not obtain a write lock on the tree.
- */
- ISC_LINK(dns_rbtnode_t) deadlink;
-
- /*@{*/
- /*!
- * The following bitfields add up to a total bitwidth of 32.
- * The range of values necessary for each item is indicated,
- * but in the case of "attributes" the field is wider to accomodate
- * possible future expansion. "offsetlen" could be one bit
- * narrower by always adjusting its value by 1 to find the real
- * offsetlen, but doing so does not gain anything (except perhaps
- * another bit for "attributes", which doesn't yet need any more).
- *
- * In each case below the "range" indicated is what's _necessary_ for
- * the bitfield to hold, not what it actually _can_ hold.
- */
- unsigned int is_root : 1; /*%< range is 0..1 */
- unsigned int color : 1; /*%< range is 0..1 */
- unsigned int find_callback : 1; /*%< range is 0..1 */
- unsigned int attributes : 4; /*%< range is 0..2 */
- unsigned int namelen : 8; /*%< range is 1..255 */
- unsigned int offsetlen : 8; /*%< range is 1..128 */
- unsigned int padbytes : 9; /*%< range is 0..380 */
- /*@}*/
+ /*%
+ * Used for LRU cache. This linked list is used to mark nodes which
+ * have no data any longer, but we cannot unlink at that exact moment
+ * because we did not or could not obtain a write lock on the tree.
+ */
+ ISC_LINK(dns_rbtnode_t) deadlink;
+
+ /*@{*/
+ /*!
+ * The following bitfields add up to a total bitwidth of 32.
+ * The range of values necessary for each item is indicated,
+ * but in the case of "attributes" the field is wider to accomodate
+ * possible future expansion. "offsetlen" could be one bit
+ * narrower by always adjusting its value by 1 to find the real
+ * offsetlen, but doing so does not gain anything (except perhaps
+ * another bit for "attributes", which doesn't yet need any more).
+ *
+ * In each case below the "range" indicated is what's _necessary_ for
+ * the bitfield to hold, not what it actually _can_ hold.
+ */
+ unsigned int is_root : 1; /*%< range is 0..1 */
+ unsigned int color : 1; /*%< range is 0..1 */
+ unsigned int find_callback : 1; /*%< range is 0..1 */
+ unsigned int attributes : 3; /*%< range is 0..2 */
+ unsigned int nsec3 : 1; /*%< range is 0..1 */
+ unsigned int namelen : 8; /*%< range is 1..255 */
+ unsigned int offsetlen : 8; /*%< range is 1..128 */
+ unsigned int padbytes : 9; /*%< range is 0..380 */
+ /*@}*/
#ifdef DNS_RBT_USEHASH
- unsigned int hashval;
+ unsigned int hashval;
#endif
- /*@{*/
- /*!
- * These values are used in the RBT DB implementation. The appropriate
- * node lock must be held before accessing them.
- */
- void *data;
- unsigned int dirty:1;
- unsigned int wild:1;
- unsigned int locknum:DNS_RBT_LOCKLENGTH;
+ /*@{*/
+ /*!
+ * These values are used in the RBT DB implementation. The appropriate
+ * node lock must be held before accessing them.
+ */
+ void *data;
+ unsigned int dirty:1;
+ unsigned int wild:1;
+ unsigned int locknum:DNS_RBT_LOCKLENGTH;
#ifndef DNS_RBT_USEISCREFCOUNT
- unsigned int references:DNS_RBT_REFLENGTH;
+ unsigned int references:DNS_RBT_REFLENGTH;
#else
- isc_refcount_t references; /* note that this is not in the bitfield */
+ isc_refcount_t references; /* note that this is not in the bitfield */
#endif
- /*@}*/
+ /*@}*/
};
typedef isc_result_t (*dns_rbtfindcallback_t)(dns_rbtnode_t *node,
- dns_name_t *name,
- void *callback_arg);
+ dns_name_t *name,
+ void *callback_arg);
/*****
***** Chain Info
#define DNS_RBT_LEVELBLOCK 254
typedef struct dns_rbtnodechain {
- unsigned int magic;
- isc_mem_t * mctx;
- /*%
- * The terminal node of the chain. It is not in levels[].
- * This is ostensibly private ... but in a pinch it could be
- * used tell that the chain points nowhere without needing to
- * call dns_rbtnodechain_current().
- */
- dns_rbtnode_t * end;
- /*%
- * The maximum number of labels in a name is 128; bitstrings mean
- * a conceptually very large number (which I have not bothered to
- * compute) of logical levels because splitting can potentially occur
- * at each bit. However, DNSSEC restricts the number of "logical"
- * labels in a name to 255, meaning only 254 pointers are needed
- * in the worst case.
- */
- dns_rbtnode_t * levels[DNS_RBT_LEVELBLOCK];
- /*%
- * level_count indicates how deep the chain points into the
- * tree of trees, and is the index into the levels[] array.
- * Thus, levels[level_count - 1] is the last level node stored.
- * A chain that points to the top level of the tree of trees has
- * a level_count of 0, the first level has a level_count of 1, and
- * so on.
- */
- unsigned int level_count;
- /*%
- * level_matches tells how many levels matched above the node
- * returned by dns_rbt_findnode(). A match (partial or exact) found
- * in the first level thus results in level_matches being set to 1.
- * This is used by the rbtdb to set the start point for a recursive
- * search of superdomains until the RR it is looking for is found.
- */
- unsigned int level_matches;
+ unsigned int magic;
+ isc_mem_t * mctx;
+ /*%
+ * The terminal node of the chain. It is not in levels[].
+ * This is ostensibly private ... but in a pinch it could be
+ * used tell that the chain points nowhere without needing to
+ * call dns_rbtnodechain_current().
+ */
+ dns_rbtnode_t * end;
+ /*%
+ * The maximum number of labels in a name is 128; bitstrings mean
+ * a conceptually very large number (which I have not bothered to
+ * compute) of logical levels because splitting can potentially occur
+ * at each bit. However, DNSSEC restricts the number of "logical"
+ * labels in a name to 255, meaning only 254 pointers are needed
+ * in the worst case.
+ */
+ dns_rbtnode_t * levels[DNS_RBT_LEVELBLOCK];
+ /*%
+ * level_count indicates how deep the chain points into the
+ * tree of trees, and is the index into the levels[] array.
+ * Thus, levels[level_count - 1] is the last level node stored.
+ * A chain that points to the top level of the tree of trees has
+ * a level_count of 0, the first level has a level_count of 1, and
+ * so on.
+ */
+ unsigned int level_count;
+ /*%
+ * level_matches tells how many levels matched above the node
+ * returned by dns_rbt_findnode(). A match (partial or exact) found
+ * in the first level thus results in level_matches being set to 1.
+ * This is used by the rbtdb to set the start point for a recursive
+ * search of superdomains until the RR it is looking for is found.
+ */
+ unsigned int level_matches;
} dns_rbtnodechain_t;
/*****
*****/
isc_result_t
dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *),
- void *deleter_arg, dns_rbt_t **rbtp);
+ void *deleter_arg, dns_rbt_t **rbtp);
/*%<
* Initialize a red-black tree of trees.
*
isc_result_t
dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,
- dns_name_t *foundname, void **data);
+ dns_name_t *foundname, void **data);
/*%<
* Get the data pointer associated with 'name'.
*
isc_result_t
dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
- dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
- unsigned int options, dns_rbtfindcallback_t callback,
- void *callback_arg);
+ dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
+ unsigned int options, dns_rbtfindcallback_t callback,
+ void *callback_arg);
/*%<
* Find the node for 'name'.
*
char *
dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname,
- unsigned int size);
+ unsigned int size);
/*%<
* Format the full name of a node for printing, using dns_name_format().
*
isc_result_t
dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name,
- dns_name_t *origin, dns_rbtnode_t **node);
+ dns_name_t *origin, dns_rbtnode_t **node);
/*%<
* Provide the name, origin and node to which the chain is currently pointed.
*
isc_result_t
dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
- dns_name_t *name, dns_name_t *origin);
+ dns_name_t *name, dns_name_t *origin);
/*%<
* Set the chain to the lexically first node in the tree of trees.
*
isc_result_t
dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
- dns_name_t *name, dns_name_t *origin);
+ dns_name_t *name, dns_name_t *origin);
/*%<
* Set the chain to the lexically last node in the tree of trees.
*
isc_result_t
dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name,
- dns_name_t *origin);
+ dns_name_t *origin);
/*%<
* Adjusts chain to point the DNSSEC predecessor of the name to which it
* is currently pointed.
isc_result_t
dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
- dns_name_t *origin);
+ dns_name_t *origin);
/*%<
* Adjusts chain to point the DNSSEC successor of the name to which it
* is currently pointed.
*\li <something_else> Any error result from dns_name_concatenate.
*/
+isc_result_t
+dns_rbtnodechain_down(dns_rbtnodechain_t *chain, dns_name_t *name,
+ dns_name_t *origin);
+/*%<
+ * Decend down if possible.
+ */
+
+isc_result_t
+dns_rbtnodechain_nextflat(dns_rbtnodechain_t *chain, dns_name_t *name);
+/*%<
+ * Find the next node at the current depth in DNSSEC order.
+ */
+
/*
* Wrapper macros for manipulating the rbtnode reference counter:
* Since we selectively use isc_refcount_t for the reference counter of
*/
#ifdef DNS_RBT_USEISCREFCOUNT
#define dns_rbtnode_refinit(node, n) \
- do { \
- isc_refcount_init(&(node)->references, (n)); \
- } while (0)
+ do { \
+ isc_refcount_init(&(node)->references, (n)); \
+ } while (0)
#define dns_rbtnode_refdestroy(node) \
- do { \
- isc_refcount_destroy(&(node)->references); \
- } while (0)
+ do { \
+ isc_refcount_destroy(&(node)->references); \
+ } while (0)
#define dns_rbtnode_refcurrent(node) \
- isc_refcount_current(&(node)->references)
+ isc_refcount_current(&(node)->references)
#define dns_rbtnode_refincrement0(node, refs) \
- do { \
- isc_refcount_increment0(&(node)->references, (refs)); \
- } while (0)
+ do { \
+ isc_refcount_increment0(&(node)->references, (refs)); \
+ } while (0)
#define dns_rbtnode_refincrement(node, refs) \
- do { \
- isc_refcount_increment(&(node)->references, (refs)); \
- } while (0)
+ do { \
+ isc_refcount_increment(&(node)->references, (refs)); \
+ } while (0)
#define dns_rbtnode_refdecrement(node, refs) \
- do { \
- isc_refcount_decrement(&(node)->references, (refs)); \
- } while (0)
+ do { \
+ isc_refcount_decrement(&(node)->references, (refs)); \
+ } while (0)
#else /* DNS_RBT_USEISCREFCOUNT */
#define dns_rbtnode_refinit(node, n) ((node)->references = (n))
#define dns_rbtnode_refdestroy(node) (REQUIRE((node)->references == 0))
#define dns_rbtnode_refcurrent(node) ((node)->references)
#define dns_rbtnode_refincrement0(node, refs) \
- do { \
- unsigned int *_tmp = (unsigned int *)(refs); \
- (node)->references++; \
- if ((_tmp) != NULL) \
- (*_tmp) = (node)->references; \
- } while (0)
+ do { \
+ unsigned int *_tmp = (unsigned int *)(refs); \
+ (node)->references++; \
+ if ((_tmp) != NULL) \
+ (*_tmp) = (node)->references; \
+ } while (0)
#define dns_rbtnode_refincrement(node, refs) \
- do { \
- REQUIRE((node)->references > 0); \
- (node)->references++; \
- if ((refs) != NULL) \
- (*refs) = (node)->references; \
- } while (0)
+ do { \
+ REQUIRE((node)->references > 0); \
+ (node)->references++; \
+ if ((refs) != NULL) \
+ (*refs) = (node)->references; \
+ } while (0)
#define dns_rbtnode_refdecrement(node, refs) \
- do { \
- REQUIRE((node)->references > 0); \
- (node)->references--; \
- if ((refs) != NULL) \
- (*refs) = (node)->references; \
- } while (0)
+ do { \
+ REQUIRE((node)->references > 0); \
+ (node)->references--; \
+ if ((refs) != NULL) \
+ (*refs) = (node)->references; \
+ } while (0)
#endif /* DNS_RBT_USEISCREFCOUNT */
ISC_LANG_ENDDECLS
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rcode.h,v 1.19 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: rcode.h,v 1.20 2008/09/24 02:46:23 marka Exp $ */
#ifndef DNS_RCODE_H
#define DNS_RCODE_H 1
*\li #ISC_R_NOSPACE target buffer is too small
*/
+isc_result_t
+dns_hashalg_fromtext(unsigned char *hashalg, isc_textregion_t *source);
+/*%<
+ * Convert the text 'source' refers to into a has algorithm value.
+ *
+ * Requires:
+ *\li 'hashalg' is a valid pointer.
+ *
+ *\li 'source' is a valid text region.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS on success
+ *\li #DNS_R_UNKNOWN type is unknown
+ */
+
ISC_LANG_ENDDECLS
#endif /* DNS_RCODE_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rdataset.h,v 1.64 2008/04/01 23:47:10 tbox Exp $ */
+/* $Id: rdataset.h,v 1.65 2008/09/24 02:46:23 marka Exp $ */
#ifndef DNS_RDATASET_H
#define DNS_RDATASET_H 1
dns_name_t *name);
isc_result_t (*getnoqname)(dns_rdataset_t *rdataset,
dns_name_t *name,
- dns_rdataset_t *nsec,
- dns_rdataset_t *nsecsig);
+ dns_rdataset_t *neg,
+ dns_rdataset_t *negsig);
+ isc_result_t (*addclosest)(dns_rdataset_t *rdataset,
+ dns_name_t *name);
+ isc_result_t (*getclosest)(dns_rdataset_t *rdataset,
+ dns_name_t *name,
+ dns_rdataset_t *neg,
+ dns_rdataset_t *negsig);
isc_result_t (*getadditional)(dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type,
dns_rdatatype_t qtype,
unsigned int privateuint4;
void * private5;
void * private6;
+ void * private7;
/*@}*/
};
#define DNS_RDATASETATTR_REQUIREDGLUE 0x00010000
#define DNS_RDATASETATTR_LOADORDER 0x00020000
#define DNS_RDATASETATTR_RESIGN 0x00040000
+#define DNS_RDATASETATTR_CLOSEST 0x00080000
+#define DNS_RDATASETATTR_OPTOUT 0x00100000 /*%< OPTOUT proof */
/*%
* _OMITDNSSEC:
isc_result_t
dns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
- dns_rdataset_t *nsec, dns_rdataset_t *nsecsig);
+ dns_rdataset_t *neg, dns_rdataset_t *negsig);
/*%<
* Return the noqname proof for this record.
*
* Requires:
*\li 'rdataset' to be valid and #DNS_RDATASETATTR_NOQNAME to be set.
*\li 'name' to be valid.
- *\li 'nsec' and 'nsecsig' to be valid and not associated.
+ *\li 'neg' and 'negsig' to be valid and not associated.
*/
isc_result_t
* Associate a noqname proof with this record.
* Sets #DNS_RDATASETATTR_NOQNAME if successful.
* Adjusts the 'rdataset->ttl' to minimum of the 'rdataset->ttl' and
- * the 'nsec' and 'rrsig(nsec)' ttl.
+ * the 'nsec'/'nsec3' and 'rrsig(nsec)'/'rrsig(nsec3)' ttl.
*
* Requires:
*\li 'rdataset' to be valid and #DNS_RDATASETATTR_NOQNAME to be set.
- *\li 'name' to be valid and have NSEC and RRSIG(NSEC) rdatasets.
+ *\li 'name' to be valid and have NSEC or NSEC3 and associated RRSIG
+ * rdatasets.
+ */
+
+isc_result_t
+dns_rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
+ dns_rdataset_t *nsec, dns_rdataset_t *nsecsig);
+/*%<
+ * Return the closest encloser for this record.
+ *
+ * Requires:
+ *\li 'rdataset' to be valid and #DNS_RDATASETATTR_CLOSEST to be set.
+ *\li 'name' to be valid.
+ *\li 'nsec' and 'nsecsig' to be valid and not associated.
+ */
+
+isc_result_t
+dns_rdataset_addclosest(dns_rdataset_t *rdataset, dns_name_t *name);
+/*%<
+ * Associate a closest encloset proof with this record.
+ * Sets #DNS_RDATASETATTR_CLOSEST if successful.
+ * Adjusts the 'rdataset->ttl' to minimum of the 'rdataset->ttl' and
+ * the 'nsec' and 'rrsig(nsec)' ttl.
+ *
+ * Requires:
+ *\li 'rdataset' to be valid and #DNS_RDATASETATTR_CLOSEST to be set.
+ *\li 'name' to be valid and have NSEC3 and RRSIG(NSEC3) rdatasets.
*/
isc_result_t
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rdatatype.h,v 1.24 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: rdatatype.h,v 1.25 2008/09/24 02:46:23 marka Exp $ */
#ifndef DNS_RDATATYPE_H
#define DNS_RDATATYPE_H 1
* The resulting string is guaranteed to be null-terminated.
*/
-#define DNS_RDATATYPE_FORMATSIZE sizeof("TYPE65535")
+#define DNS_RDATATYPE_FORMATSIZE sizeof("NSEC3PARAM")
+
/*%<
* Minimum size of array to pass to dns_rdatatype_format().
* May need to be adjusted if a new RR type with a very long
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: result.h,v 1.114 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: result.h,v 1.115 2008/09/24 02:46:23 marka Exp $ */
#ifndef DNS_RESULT_H
#define DNS_RESULT_H 1
#define DNS_R_COVERINGNSEC (ISC_RESULTCLASS_DNS + 101)
#define DNS_R_MXISADDRESS (ISC_RESULTCLASS_DNS + 102)
#define DNS_R_DUPLICATE (ISC_RESULTCLASS_DNS + 103)
+#define DNS_R_INVALIDNSEC3 (ISC_RESULTCLASS_DNS + 104)
-#define DNS_R_NRESULTS 104 /*%< Number of results */
+#define DNS_R_NRESULTS 105 /*%< Number of results */
/*
* DNS wire format rcodes.
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: types.h,v 1.129 2008/04/03 05:55:52 marka Exp $ */
+/* $Id: types.h,v 1.130 2008/09/24 02:46:23 marka Exp $ */
#ifndef DNS_TYPES_H
#define DNS_TYPES_H 1
typedef struct dns_forwarders dns_forwarders_t;
typedef struct dns_fwdtable dns_fwdtable_t;
typedef struct dns_iptable dns_iptable_t;
+typedef isc_uint32_t dns_iterations_t;
typedef isc_uint16_t dns_keyflags_t;
typedef struct dns_keynode dns_keynode_t;
typedef struct dns_keytable dns_keytable_t;
#endif
typedef struct dst_gssapi_signverifyctx dst_gssapi_signverifyctx_t;
+typedef enum {
+ dns_hash_sha1 = 1
+} dns_hash_t;
+
typedef enum {
dns_fwdpolicy_none = 0,
dns_fwdpolicy_first = 1,
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: validator.h,v 1.39 2007/09/19 03:38:56 marka Exp $ */
+/* $Id: validator.h,v 1.40 2008/09/24 02:46:23 marka Exp $ */
#ifndef DNS_VALIDATOR_H
#define DNS_VALIDATOR_H 1
/*
* Proofs to be cached.
*/
- dns_name_t * proofs[3];
+ dns_name_t * proofs[4];
+ /*
+ * Optout proof seen.
+ */
+ isc_boolean_t optout;
} dns_validatorevent_t;
#define DNS_VALIDATOR_NOQNAMEPROOF 0
#define DNS_VALIDATOR_NODATAPROOF 1
#define DNS_VALIDATOR_NOWILDCARDPROOF 2
+#define DNS_VALIDATOR_CLOSESTENCLOSER 3
/*%
* A validator object represents a validation in progress.
dns_rdataset_t * dsset;
dns_rdataset_t * soaset;
dns_rdataset_t * nsecset;
+ dns_rdataset_t * nsec3set;
dns_name_t * soaname;
dns_rdataset_t frdataset;
dns_rdataset_t fsigrdataset;
dns_fixedname_t fname;
dns_fixedname_t wild;
+ dns_fixedname_t nearest;
+ dns_fixedname_t closest;
ISC_LINK(dns_validator_t) link;
dns_rdataset_t dlv;
dns_fixedname_t dlvsep;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zone.h,v 1.159 2008/04/03 05:55:52 marka Exp $ */
+/* $Id: zone.h,v 1.160 2008/09/24 02:46:23 marka Exp $ */
#ifndef DNS_ZONE_H
#define DNS_ZONE_H 1
#include <isc/rwlock.h>
#include <dns/masterdump.h>
+#include <dns/rdatastruct.h>
#include <dns/types.h>
typedef enum {
#define DNS_ZONEOPT_UPDATECHECKKSK 0x00800000U /*%< check dnskey KSK flag */
#define DNS_ZONEOPT_TRYTCPREFRESH 0x01000000U /*%< try tcp refresh on udp failure */
#define DNS_ZONEOPT_NOTIFYTOSOA 0x02000000U /*%< Notify the SOA MNAME */
+#define DNS_ZONEOPT_NSEC3TESTZONE 0x04000000U /*%< nsec3-test-zone */
#ifndef NOMINUM_PUBLIC
/*
isc_result_t
dns_zone_checknames(dns_zone_t *zone, dns_name_t *name, dns_rdata_t *rdata);
-/*
+/*%<
* Check if this record meets the check-names policy.
*
* Requires:
void
dns_zone_setacache(dns_zone_t *zone, dns_acache_t *acache);
-/*
+/*%<
* Associate the zone with an additional cache.
*
* Require:
void
dns_zone_setcheckmx(dns_zone_t *zone, dns_checkmxfunc_t checkmx);
-/*
+/*%<
* Set the post load integrity callback function 'checkmx'.
* 'checkmx' will be called if the MX is not within the zone.
*
void
dns_zone_setchecksrv(dns_zone_t *zone, dns_checkmxfunc_t checksrv);
-/*
+/*%<
* Set the post load integrity callback function 'checksrv'.
* 'checksrv' will be called if the SRV TARGET is not within the zone.
*
void
dns_zone_setcheckns(dns_zone_t *zone, dns_checknsfunc_t checkns);
-/*
+/*%<
* Set the post load integrity callback function 'checkmx'.
* 'checkmx' will be called if the MX is not within the zone.
*
void
dns_zone_setnotifydelay(dns_zone_t *zone, isc_uint32_t delay);
-/*
+/*%<
* Set the minimum delay between sets of notify messages.
*
* Requires:
isc_uint32_t
dns_zone_getnotifydelay(dns_zone_t *zone);
-/*
+/*%<
* Get the minimum delay between sets of notify messages.
*
* Requires:
void
dns_zone_setisself(dns_zone_t *zone, dns_isselffunc_t isself, void *arg);
-/*
+/*%<
* Set the isself callback function and argument.
*
* isc_boolean_t
void
dns_zone_setnodes(dns_zone_t *zone, isc_uint32_t nodes);
-/*
+/*%<
* Set the number of nodes that will be checked per quantum.
*/
void
dns_zone_setsignatures(dns_zone_t *zone, isc_uint32_t signatures);
-/*
+/*%<
* Set the number of signatures that will be generated per quantum.
*/
isc_result_t
dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm,
- isc_uint16_t keyid);
-/*
+ isc_uint16_t keyid, isc_boolean_t delete);
+/*%<
* Initiate/resume signing of the entire zone with the zone DNSKEY(s)
* that match the given algorithm and keyid.
*/
+isc_result_t
+dns_zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param);
+/*%<
+ * Incrementally add a NSEC3 chain that corresponds to 'nsec3param'.
+ */
+
void
dns_zone_setprivatetype(dns_zone_t *zone, dns_rdatatype_t type);
dns_rdatatype_t
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dst.h,v 1.11 2008/04/01 23:47:10 tbox Exp $ */
+/* $Id: dst.h,v 1.12 2008/09/24 02:46:23 marka Exp $ */
#ifndef DST_DST_H
#define DST_DST_H 1
#define DST_ALG_DSA 3
#define DST_ALG_ECC 4
#define DST_ALG_RSASHA1 5
+#define DST_ALG_NSEC3DSA 6
+#define DST_ALG_NSEC3RSASHA1 7
#define DST_ALG_HMACMD5 157
#define DST_ALG_GSSAPI 160
#define DST_ALG_HMACSHA1 161 /* XXXMPA */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: journal.c,v 1.101 2008/04/01 23:47:10 tbox Exp $ */
+/* $Id: journal.c,v 1.102 2008/09/24 02:46:22 marka Exp $ */
#include <config.h>
if (result != ISC_R_SUCCESS)
return (result);
- result = dns_db_createiterator(db[0], ISC_FALSE, &dbit[0]);
+ result = dns_db_createiterator(db[0], 0, &dbit[0]);
if (result != ISC_R_SUCCESS)
goto cleanup_journal;
- result = dns_db_createiterator(db[1], ISC_FALSE, &dbit[1]);
+ result = dns_db_createiterator(db[1], 0, &dbit[1]);
if (result != ISC_R_SUCCESS)
goto cleanup_interator0;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: masterdump.c,v 1.93 2008/08/13 02:20:09 jinmei Exp $ */
+/* $Id: masterdump.c,v 1.94 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
"local" /* aka ultimate */
};
+const char *
+dns_trust_totext(dns_trust_t trust) {
+ if (trust >= sizeof(trustnames)/sizeof(*trustnames))
+ return ("bad");
+ return (trustnames[trust]);
+}
+
static isc_result_t
dump_rdatasets_text(isc_mem_t *mctx, dns_name_t *name,
dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
{
dns_dumpctx_t *dctx;
isc_result_t result;
- isc_boolean_t relative;
+ unsigned int options;
dctx = isc_mem_get(mctx, sizeof(*dctx));
if (dctx == NULL)
if (dctx->format == dns_masterformat_text &&
(dctx->tctx.style.flags & DNS_STYLEFLAG_REL_OWNER) != 0) {
- relative = ISC_TRUE;
+ options = DNS_DB_RELATIVENAMES;
} else
- relative = ISC_FALSE;
- result = dns_db_createiterator(dctx->db, relative, &dctx->dbiter);
+ options = 0;
+ result = dns_db_createiterator(dctx->db, options, &dctx->dbiter);
if (result != ISC_R_SUCCESS)
goto cleanup;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: message.c,v 1.244 2008/07/28 08:39:52 marka Exp $ */
+/* $Id: message.c,v 1.245 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
#define VALID_PSEUDOSECTION(s) (((s) >= DNS_PSEUDOSECTION_ANY) \
&& ((s) < DNS_PSEUDOSECTION_MAX))
+#define OPTOUT(x) (((x)->attributes & DNS_RDATASETATTR_OPTOUT) != 0)
+
/*%
* This is the size of each individual scratchpad buffer, and the numbers
* of various block allocations used within the server.
(sectionid == DNS_SECTION_ANSWER ||
sectionid == DNS_SECTION_AUTHORITY))
msg->flags &= ~DNS_MESSAGEFLAG_AD;
+ if (OPTOUT(rdataset))
+ msg->flags &= ~DNS_MESSAGEFLAG_AD;
rdataset->attributes |=
DNS_RDATASETATTR_RENDERED;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: ncache.c,v 1.41 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: ncache.c,v 1.42 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
#include <dns/rdata.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+
+#define DNS_NCACHE_RDATA 20U
/*
* The format of an ncache rdata is a sequence of one or more records of
dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
dns_rdataset_t *addedrdataset)
+{
+ return (dns_ncache_addoptout(message, cache, node, covers, now, maxttl,
+ ISC_FALSE, addedrdataset));
+}
+
+isc_result_t
+dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache,
+ dns_dbnode_t *node, dns_rdatatype_t covers,
+ isc_stdtime_t now, dns_ttl_t maxttl,
+ isc_boolean_t optout, dns_rdataset_t *addedrdataset)
{
isc_result_t result;
isc_buffer_t buffer;
dns_name_t *name;
dns_ttl_t ttl;
dns_trust_t trust;
- dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_t rdata[DNS_NCACHE_RDATA];
dns_rdataset_t ncrdataset;
dns_rdatalist_t ncrdatalist;
unsigned char data[4096];
+ unsigned int next = 0;
/*
* Convert the authority data from 'message' into a negative cache
*/
/*
- * First, build an ncache rdata in buffer.
+ * Initialize the list.
+ */
+ ncrdatalist.rdclass = dns_db_class(cache);
+ ncrdatalist.type = 0;
+ ncrdatalist.covers = covers;
+ ncrdatalist.ttl = maxttl;
+ ISC_LIST_INIT(ncrdatalist.rdata);
+ ISC_LINK_INIT(&ncrdatalist, link);
+
+ /*
+ * Build an ncache rdatas into buffer.
*/
ttl = maxttl;
trust = 0xffff;
if (type == dns_rdatatype_rrsig)
type = rdataset->covers;
if (type == dns_rdatatype_soa ||
- type == dns_rdatatype_nsec) {
+ type == dns_rdatatype_nsec ||
+ type == dns_rdatatype_nsec3) {
if (ttl > rdataset->ttl)
ttl = rdataset->ttl;
if (trust > rdataset->trust)
&buffer);
if (result != ISC_R_SUCCESS)
return (result);
+
+ if (next >= DNS_NCACHE_RDATA)
+ return (ISC_R_NOSPACE);
+ dns_rdata_init(&rdata[next]);
+ isc_buffer_remainingregion(&buffer, &r);
+ rdata[next].data = r.base;
+ rdata[next].length = r.length;
+ rdata[next].rdclass =
+ ncrdatalist.rdclass;
+ rdata[next].type = 0;
+ rdata[next].flags = 0;
+ ISC_LIST_APPEND(ncrdatalist.rdata,
+ &rdata[next], link);
+ isc_buffer_forward(&buffer, r.length);
+ next++;
}
}
}
trust = dns_trust_authauthority;
} else
trust = dns_trust_additional;
+ /*
+ * Now add it to the cache.
+ */
+ if (next >= DNS_NCACHE_RDATA)
+ return (ISC_R_NOSPACE);
+ dns_rdata_init(&rdata[next]);
+ isc_buffer_remainingregion(&buffer, &r);
+ rdata[next].data = r.base;
+ rdata[next].length = r.length;
+ rdata[next].rdclass = ncrdatalist.rdclass;
+ rdata[next].type = 0;
+ rdata[next].flags = 0;
+ ISC_LIST_APPEND(ncrdatalist.rdata, &rdata[next], link);
}
- /*
- * Now add it to the cache.
- */
INSIST(trust != 0xffff);
- isc_buffer_usedregion(&buffer, &r);
- rdata.data = r.base;
- rdata.length = r.length;
- rdata.rdclass = dns_db_class(cache);
- rdata.type = 0;
- rdata.flags = 0;
-
- ncrdatalist.rdclass = rdata.rdclass;
- ncrdatalist.type = 0;
- ncrdatalist.covers = covers;
- ncrdatalist.ttl = ttl;
- ISC_LIST_INIT(ncrdatalist.rdata);
- ISC_LINK_INIT(&ncrdatalist, link);
- ISC_LIST_APPEND(ncrdatalist.rdata, &rdata, link);
+ ncrdatalist.ttl = ttl;
dns_rdataset_init(&ncrdataset);
RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset)
ncrdataset.trust = trust;
if (message->rcode == dns_rcode_nxdomain)
ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN;
+ if (optout)
+ ncrdataset.attributes |= DNS_RDATASETATTR_OPTOUT;
return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset,
0, addedrdataset));
REQUIRE(rdataset != NULL);
REQUIRE(rdataset->type == 0);
- result = dns_rdataset_first(rdataset);
- if (result != ISC_R_SUCCESS)
- return (result);
- dns_rdataset_current(rdataset, &rdata);
- INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE);
- isc_buffer_init(&source, rdata.data, rdata.length);
- isc_buffer_add(&source, rdata.length);
-
savedbuffer = *target;
-
count = 0;
- do {
+
+ result = dns_rdataset_first(rdataset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(rdataset, &rdata);
+ isc_buffer_init(&source, rdata.data, rdata.length);
+ isc_buffer_add(&source, rdata.length);
dns_name_init(&name, NULL);
isc_buffer_remainingregion(&source, &remaining);
dns_name_fromregion(&name, &remaining);
count++;
}
- isc_buffer_remainingregion(&source, &remaining);
- } while (remaining.length > 0);
+ INSIST(isc_buffer_remaininglength(&source) == 0);
+ result = dns_rdataset_next(rdataset);
+ dns_rdata_reset(&rdata);
+ }
+ if (result != ISC_R_NOMORE)
+ goto rollback;
*countp = count;
NULL,
NULL,
NULL,
+ NULL,
+ NULL,
NULL
};
isc_buffer_t source;
dns_name_t tname;
dns_rdatatype_t ttype;
- unsigned int i, rcount;
- isc_uint16_t length;
REQUIRE(ncacherdataset != NULL);
REQUIRE(ncacherdataset->type == 0);
REQUIRE(type != dns_rdatatype_rrsig);
result = dns_rdataset_first(ncacherdataset);
- if (result != ISC_R_SUCCESS)
- return (result);
- dns_rdataset_current(ncacherdataset, &rdata);
- INSIST(dns_rdataset_next(ncacherdataset) == ISC_R_NOMORE);
- isc_buffer_init(&source, rdata.data, rdata.length);
- isc_buffer_add(&source, rdata.length);
-
- do {
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(ncacherdataset, &rdata);
+ isc_buffer_init(&source, rdata.data, rdata.length);
+ isc_buffer_add(&source, rdata.length);
dns_name_init(&tname, NULL);
isc_buffer_remainingregion(&source, &remaining);
dns_name_fromregion(&tname, &remaining);
isc_buffer_remainingregion(&source, &remaining);
break;
}
-
- rcount = isc_buffer_getuint16(&source);
- for (i = 0; i < rcount; i++) {
- isc_buffer_remainingregion(&source, &remaining);
- INSIST(remaining.length >= 2);
- length = isc_buffer_getuint16(&source);
- isc_buffer_remainingregion(&source, &remaining);
- INSIST(remaining.length >= length);
- isc_buffer_forward(&source, length);
- }
- isc_buffer_remainingregion(&source, &remaining);
- } while (remaining.length > 0);
-
- if (remaining.length == 0)
+ result = dns_rdataset_next(ncacherdataset);
+ dns_rdata_reset(&rdata);
+ }
+ if (result == ISC_R_NOMORE)
return (ISC_R_NOTFOUND);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ INSIST(remaining.length != 0);
rdataset->methods = &rdataset_methods;
rdataset->rdclass = ncacherdataset->rdclass;
*/
rdataset->privateuint4 = 0;
rdataset->private5 = NULL;
+ rdataset->private6 = NULL;
return (ISC_R_SUCCESS);
}
+
+void
+dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found,
+ dns_rdataset_t *rdataset)
+{
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_region_t remaining, sigregion;
+ isc_buffer_t source;
+ dns_name_t tname;
+ dns_rdatatype_t type;
+ unsigned int count;
+ dns_rdata_rrsig_t rrsig;
+ unsigned char *raw;
+
+ REQUIRE(ncacherdataset != NULL);
+ REQUIRE(ncacherdataset->type == 0);
+ REQUIRE(found != NULL);
+ REQUIRE(!dns_rdataset_isassociated(rdataset));
+
+ dns_rdataset_current(ncacherdataset, &rdata);
+ isc_buffer_init(&source, rdata.data, rdata.length);
+ isc_buffer_add(&source, rdata.length);
+
+ dns_name_init(&tname, NULL);
+ isc_buffer_remainingregion(&source, &remaining);
+ dns_name_fromregion(found, &remaining);
+ INSIST(remaining.length >= found->length);
+ isc_buffer_forward(&source, found->length);
+ remaining.length -= found->length;
+
+ INSIST(remaining.length >= 4);
+ type = isc_buffer_getuint16(&source);
+ isc_buffer_remainingregion(&source, &remaining);
+
+ rdataset->methods = &rdataset_methods;
+ rdataset->rdclass = ncacherdataset->rdclass;
+ rdataset->type = type;
+ if (type == dns_rdatatype_rrsig) {
+ /*
+ * Extract covers from RRSIG.
+ */
+ raw = remaining.base;
+ count = raw[0] * 256 + raw[1];
+ INSIST(count > 0);
+ raw += 2;
+ sigregion.length = raw[0] * 256 + raw[1];
+ raw += 2;
+ sigregion.base = raw;
+ dns_rdata_reset(&rdata);
+ dns_rdata_fromregion(&rdata, rdataset->rdclass,
+ rdataset->type, &sigregion);
+ (void)dns_rdata_tostruct(&rdata, &rrsig, NULL);
+ rdataset->covers = rrsig.covered;
+ } else
+ rdataset->covers = 0;
+ rdataset->ttl = ncacherdataset->ttl;
+ rdataset->trust = ncacherdataset->trust;
+ rdataset->private1 = NULL;
+ rdataset->private2 = NULL;
+
+ rdataset->private3 = remaining.base;
+
+ /*
+ * Reset iterator state.
+ */
+ rdataset->privateuint4 = 0;
+ rdataset->private5 = NULL;
+ rdataset->private6 = NULL;
+}
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: nsec.c,v 1.9 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: nsec.c,v 1.10 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
#include <dns/rdatastruct.h>
#include <dns/result.h>
+#include <dst/dst.h>
+
#define RETERR(x) do { \
result = (x); \
if (result != ISC_R_SUCCESS) \
*/
bm = r.base + r.length + 512;
nsec_bits = r.base + r.length;
+ set_bit(bm, dns_rdatatype_rrsig, 1);
set_bit(bm, dns_rdatatype_nsec, 1);
max_type = dns_rdatatype_nsec;
dns_rdataset_init(&rdataset);
result = dns_rdatasetiter_next(rdsiter))
{
dns_rdatasetiter_current(rdsiter, &rdataset);
- if (rdataset.type != dns_rdatatype_nsec) {
+ if (rdataset.type != dns_rdatatype_nsec &&
+ rdataset.type != dns_rdatatype_nsec3 &&
+ rdataset.type != dns_rdatatype_rrsig) {
if (rdataset.type > max_type)
max_type = rdataset.type;
set_bit(bm, rdataset.type, 1);
/* This should never fail */
result = dns_rdata_tostruct(nsec, &nsecstruct, NULL);
INSIST(result == ISC_R_SUCCESS);
-
+
present = ISC_FALSE;
for (i = 0; i < nsecstruct.len; i += len) {
INSIST(i + 2 <= nsecstruct.len);
dns_rdata_freestruct(&nsec);
return (present);
}
+
+isc_result_t
+dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version,
+ isc_boolean_t *answer)
+{
+ dns_dbnode_t *node = NULL;
+ dns_rdataset_t rdataset;
+ dns_rdata_dnskey_t dnskey;
+ isc_result_t result;
+
+ REQUIRE(answer != NULL);
+
+ dns_rdataset_init(&rdataset);
+
+ result = dns_db_getoriginnode(db, &node);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey,
+ 0, 0, &rdataset, NULL);
+ dns_db_detachnode(db, &node);
+
+ if (result == ISC_R_NOTFOUND) {
+ *answer = ISC_FALSE;
+ return (ISC_R_SUCCESS);
+ }
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ dns_rdataset_current(&rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ if (dnskey.algorithm == DST_ALG_RSAMD5 ||
+ dnskey.algorithm == DST_ALG_RSASHA1 ||
+ dnskey.algorithm == DST_ALG_DSA ||
+ dnskey.algorithm == DST_ALG_ECC)
+ break;
+ }
+ dns_rdataset_disassociate(&rdataset);
+ if (result == ISC_R_SUCCESS)
+ *answer = ISC_TRUE;
+ if (result == ISC_R_NOMORE) {
+ *answer = ISC_FALSE;
+ result = ISC_R_SUCCESS;
+ }
+ return (result);
+}
--- /dev/null
+/*
+ * Copyright (C) 2006 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: nsec3.c,v 1.2 2008/09/24 02:46:22 marka Exp $ */
+
+#include <config.h>
+
+#include <isc/base32.h>
+#include <isc/buffer.h>
+#include <isc/hex.h>
+#include <isc/iterated_hash.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dst/dst.h>
+
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/diff.h>
+#include <dns/fixedname.h>
+#include <dns/nsec3.h>
+#include <dns/rdata.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+#include <dns/rdatastruct.h>
+#include <dns/result.h>
+
+#define CHECK(x) do { \
+ result = (x); \
+ if (result != ISC_R_SUCCESS) \
+ goto failure; \
+ } while (0)
+
+#define OPTOUT(x) (((x) & DNS_NSEC3FLAG_OPTOUT) != 0)
+#define CREATE(x) (((x) & DNS_NSEC3FLAG_CREATE) != 0)
+#define REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0)
+
+static void
+set_bit(unsigned char *array, unsigned int index, unsigned int bit) {
+ unsigned int shift, mask;
+
+ shift = 7 - (index % 8);
+ mask = 1 << shift;
+
+ if (bit != 0)
+ array[index / 8] |= mask;
+ else
+ array[index / 8] &= (~mask & 0xFF);
+}
+
+static unsigned int
+bit_isset(unsigned char *array, unsigned int index) {
+ unsigned int byte, shift, mask;
+
+ byte = array[index / 8];
+ shift = 7 - (index % 8);
+ mask = 1 << shift;
+
+ return ((byte & mask) != 0);
+}
+
+isc_result_t
+dns_nsec3_buildrdata(dns_db_t *db, dns_dbversion_t *version,
+ dns_dbnode_t *node, unsigned int hashalg,
+ unsigned int flags, unsigned int iterations,
+ const unsigned char *salt, size_t salt_length,
+ const unsigned char *nexthash, size_t hash_length,
+ unsigned char *buffer, dns_rdata_t *rdata)
+{
+ isc_result_t result;
+ dns_rdataset_t rdataset;
+ isc_region_t r;
+ unsigned int i, window;
+ int octet;
+ isc_boolean_t found;
+
+ unsigned char *nsec_bits, *bm;
+ unsigned int max_type;
+ dns_rdatasetiter_t *rdsiter;
+ unsigned char *p;
+
+ REQUIRE(salt_length < 256);
+ REQUIRE(hash_length < 256);
+ REQUIRE(flags <= 0xffU);
+ REQUIRE(hashalg <= 0xffU);
+ REQUIRE(iterations <= 0xffffU);
+
+ switch (hashalg) {
+ case dns_hash_sha1:
+ REQUIRE(hash_length == ISC_SHA1_DIGESTLENGTH);
+ break;
+ }
+
+ memset(buffer, 0, DNS_NSEC3_BUFFERSIZE);
+
+ p = buffer;
+
+ *p++ = hashalg;
+ *p++ = flags;
+
+ *p++ = iterations >> 8;
+ *p++ = iterations;
+
+ *p++ = salt_length;
+ memcpy(p, salt, salt_length);
+ p += salt_length;
+
+ *p++ = hash_length;
+ memcpy(p, nexthash, hash_length);
+ p += hash_length;
+
+ r.length = p - buffer;
+ r.base = buffer;
+
+ /*
+ * Use the end of the space for a raw bitmap leaving enough
+ * space for the window identifiers and length octets.
+ */
+ bm = r.base + r.length + 512;
+ nsec_bits = r.base + r.length;
+ max_type = 0;
+ if (node == NULL)
+ goto collapse_bitmap;
+ dns_rdataset_init(&rdataset);
+ rdsiter = NULL;
+ result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ found = ISC_FALSE;
+ for (result = dns_rdatasetiter_first(rdsiter);
+ result == ISC_R_SUCCESS;
+ result = dns_rdatasetiter_next(rdsiter))
+ {
+ dns_rdatasetiter_current(rdsiter, &rdataset);
+ if (rdataset.type != dns_rdatatype_nsec &&
+ rdataset.type != dns_rdatatype_nsec3 &&
+ rdataset.type != dns_rdatatype_rrsig) {
+ if (rdataset.type > max_type)
+ max_type = rdataset.type;
+ set_bit(bm, rdataset.type, 1);
+ found = ISC_TRUE;
+ }
+ dns_rdataset_disassociate(&rdataset);
+ }
+ if (found) {
+ if (dns_rdatatype_rrsig > max_type)
+ max_type = dns_rdatatype_rrsig;
+ set_bit(bm, dns_rdatatype_rrsig, 1);
+ }
+
+ /*
+ * At zone cuts, deny the existence of glue in the parent zone.
+ */
+ if (bit_isset(bm, dns_rdatatype_ns) &&
+ ! bit_isset(bm, dns_rdatatype_soa)) {
+ for (i = 0; i <= max_type; i++) {
+ if (bit_isset(bm, i) &&
+ ! dns_rdatatype_iszonecutauth((dns_rdatatype_t)i))
+ set_bit(bm, i, 0);
+ }
+ }
+
+ dns_rdatasetiter_destroy(&rdsiter);
+ if (result != ISC_R_NOMORE)
+ return (result);
+
+ collapse_bitmap:
+ for (window = 0; window < 256; window++) {
+ if (window * 256 > max_type)
+ break;
+ for (octet = 31; octet >= 0; octet--)
+ if (bm[window * 32 + octet] != 0)
+ break;
+ if (octet < 0)
+ continue;
+ nsec_bits[0] = window;
+ nsec_bits[1] = octet + 1;
+ /*
+ * Note: potentially overlapping move.
+ */
+ memmove(&nsec_bits[2], &bm[window * 32], octet + 1);
+ nsec_bits += 3 + octet;
+ }
+ r.length = nsec_bits - r.base;
+ INSIST(r.length <= DNS_NSEC3_BUFFERSIZE);
+ dns_rdata_fromregion(rdata, dns_db_class(db), dns_rdatatype_nsec3, &r);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_boolean_t
+dns_nsec3_typepresent(dns_rdata_t *rdata, dns_rdatatype_t type) {
+ dns_rdata_nsec3_t nsec3;
+ isc_result_t result;
+ isc_boolean_t present;
+ unsigned int i, len, window;
+
+ REQUIRE(rdata != NULL);
+ REQUIRE(rdata->type == dns_rdatatype_nsec3);
+
+ /* This should never fail */
+ result = dns_rdata_tostruct(rdata, &nsec3, NULL);
+ INSIST(result == ISC_R_SUCCESS);
+
+ present = ISC_FALSE;
+ for (i = 0; i < nsec3.len; i += len) {
+ INSIST(i + 2 <= nsec3.len);
+ window = nsec3.typebits[i];
+ len = nsec3.typebits[i + 1];
+ INSIST(len > 0 && len <= 32);
+ i += 2;
+ INSIST(i + len <= nsec3.len);
+ if (window * 256 > type)
+ break;
+ if ((window + 1) * 256 <= type)
+ continue;
+ if (type < (window * 256) + len * 8)
+ present = ISC_TF(bit_isset(&nsec3.typebits[i],
+ type % 256));
+ break;
+ }
+ dns_rdata_freestruct(&nsec3);
+ return (present);
+}
+
+isc_result_t
+dns_nsec3_hashname(dns_fixedname_t *result,
+ unsigned char rethash[NSEC3_MAX_HASH_LENGTH],
+ size_t *hash_length, dns_name_t *name, dns_name_t *origin,
+ dns_hash_t hashalg, unsigned int iterations,
+ const unsigned char *salt, size_t saltlength)
+{
+ unsigned char hash[NSEC3_MAX_HASH_LENGTH];
+ unsigned char nametext[DNS_NAME_FORMATSIZE];
+ dns_fixedname_t fixed;
+ dns_name_t *downcased;
+ isc_buffer_t namebuffer;
+ isc_region_t region;
+ size_t len;
+
+ if (rethash == NULL)
+ rethash = hash;
+
+ memset(rethash, 0, NSEC3_MAX_HASH_LENGTH);
+
+ dns_fixedname_init(&fixed);
+ downcased = dns_fixedname_name(&fixed);
+ dns_name_downcase(name, downcased, NULL);
+
+ /* hash the node name */
+ len = isc_iterated_hash(rethash, hashalg, iterations, salt, saltlength,
+ downcased->ndata, downcased->length);
+ if (len == 0)
+ return (DNS_R_BADALG);
+
+ if (hash_length != NULL)
+ *hash_length = len;
+
+ /* convert the hash to base32hex */
+ region.base = rethash;
+ region.length = len;
+ isc_buffer_init(&namebuffer, nametext, sizeof nametext);
+ isc_base32hex_totext(®ion, 1, "", &namebuffer);
+
+ /* convert the hex to a domain name */
+ dns_fixedname_init(result);
+ return (dns_name_fromtext(dns_fixedname_name(result), &namebuffer,
+ origin, 0, NULL));
+}
+
+unsigned int
+dns_nsec3_hashlength(dns_hash_t hash) {
+
+ switch (hash) {
+ case dns_hash_sha1: return(ISC_SHA1_DIGESTLENGTH);
+ }
+ return (0);
+}
+
+isc_boolean_t
+dns_nsec3_supportedhash(dns_hash_t hash) {
+ switch (hash) {
+ case dns_hash_sha1: return (ISC_TRUE);
+ }
+ return (ISC_FALSE);
+}
+
+/*%
+ * Update a single RR in version 'ver' of 'db' and log the
+ * update in 'diff'.
+ *
+ * Ensures:
+ * \li '*tuple' == NULL. Either the tuple is freed, or its
+ * ownership has been transferred to the diff.
+ */
+static isc_result_t
+do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver,
+ dns_diff_t *diff)
+{
+ dns_diff_t temp_diff;
+ isc_result_t result;
+
+ /*
+ * Create a singleton diff.
+ */
+ dns_diff_init(diff->mctx, &temp_diff);
+ temp_diff.resign = diff->resign;
+ ISC_LIST_APPEND(temp_diff.tuples, *tuple, link);
+
+ /*
+ * Apply it to the database.
+ */
+ result = dns_diff_apply(&temp_diff, db, ver);
+ ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link);
+ if (result != ISC_R_SUCCESS) {
+ dns_difftuple_free(tuple);
+ return (result);
+ }
+
+ /*
+ * Merge it into the current pending journal entry.
+ */
+ dns_diff_appendminimal(diff, tuple);
+
+ /*
+ * Do not clear temp_diff.
+ */
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Set '*exists' to true iff the given name exists, to false otherwise.
+ */
+static isc_result_t
+name_exists(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
+ isc_boolean_t *exists)
+{
+ isc_result_t result;
+ dns_dbnode_t *node = NULL;
+ dns_rdatasetiter_t *iter = NULL;
+
+ result = dns_db_findnode(db, name, ISC_FALSE, &node);
+ if (result == ISC_R_NOTFOUND) {
+ *exists = ISC_FALSE;
+ return (ISC_R_SUCCESS);
+ }
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dns_db_allrdatasets(db, node, version,
+ (isc_stdtime_t) 0, &iter);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_node;
+
+ result = dns_rdatasetiter_first(iter);
+ if (result == ISC_R_SUCCESS) {
+ *exists = ISC_TRUE;
+ } else if (result == ISC_R_NOMORE) {
+ *exists = ISC_FALSE;
+ result = ISC_R_SUCCESS;
+ } else
+ *exists = ISC_FALSE;
+ dns_rdatasetiter_destroy(&iter);
+
+ cleanup_node:
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
+static isc_boolean_t
+match_nsec3param(const dns_rdata_nsec3_t *nsec3,
+ const dns_rdata_nsec3param_t *nsec3param)
+{
+ if (nsec3->hash == nsec3param->hash &&
+ nsec3->iterations == nsec3param->iterations &&
+ nsec3->salt_length == nsec3param->salt_length &&
+ !memcmp(nsec3->salt, nsec3param->salt, nsec3->salt_length))
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
+/*%
+ * Delete NSEC3 records at "name" which match "param", recording the
+ * change in "diff".
+ */
+static isc_result_t
+delete(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
+ const dns_rdata_nsec3param_t *nsec3param, dns_diff_t *diff)
+{
+ dns_dbnode_t *node = NULL ;
+ dns_difftuple_t *tuple = NULL;
+ dns_rdata_nsec3_t nsec3;
+ dns_rdataset_t rdataset;
+ isc_result_t result;
+
+ result = dns_db_findnsec3node(db, name, ISC_FALSE, &node);
+ if (result == ISC_R_NOTFOUND)
+ return (ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findrdataset(db, node, version, dns_rdatatype_nsec3, 0,
+ (isc_stdtime_t) 0, &rdataset, NULL);
+
+ if (result == ISC_R_NOTFOUND) {
+ result = ISC_R_SUCCESS;
+ goto cleanup_node;
+ }
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_node;
+
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset))
+ {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_current(&rdataset, &rdata);
+ CHECK(dns_rdata_tostruct(&rdata, &nsec3, NULL));
+
+ if (!match_nsec3param(&nsec3, nsec3param))
+ continue;
+
+ result = dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, name,
+ rdataset.ttl, &rdata, &tuple);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+ result = do_one_tuple(&tuple, db, version, diff);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+ }
+ if (result != ISC_R_NOMORE)
+ goto failure;
+ result = ISC_R_SUCCESS;
+
+ failure:
+ dns_rdataset_disassociate(&rdataset);
+ cleanup_node:
+ dns_db_detachnode(db, &node);
+
+ return (result);
+}
+
+#ifndef RFC5155_STRICT
+static isc_boolean_t
+better_param(dns_rdataset_t *nsec3paramset, dns_rdata_t *param) {
+ dns_rdataset_t rdataset;
+ isc_result_t result;
+
+ if (REMOVE(param->data[1]))
+ return (ISC_TRUE);
+
+ dns_rdataset_init(&rdataset);
+ dns_rdataset_clone(nsec3paramset, &rdataset);
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_current(&rdataset, &rdata);
+ if (rdata.length != param->length)
+ continue;
+ if (rdata.data[0] != param->data[0] ||
+ REMOVE(rdata.data[1]) ||
+ rdata.data[2] != param->data[2] ||
+ rdata.data[3] != param->data[3] ||
+ rdata.data[4] != param->data[4] ||
+ memcmp(&rdata.data[5], ¶m->data[5], param->data[4]))
+ continue;
+ if (CREATE(rdata.data[1]) && !CREATE(param->data[1])) {
+ dns_rdataset_disassociate(&rdataset);
+ return (ISC_TRUE);
+ }
+ }
+ dns_rdataset_disassociate(&rdataset);
+ return (ISC_FALSE);
+}
+#endif
+
+static isc_result_t
+find_nsec3(dns_rdata_nsec3_t *nsec3, dns_rdataset_t *rdataset,
+ const dns_rdata_nsec3param_t *nsec3param)
+{
+ isc_result_t result;
+ for (result = dns_rdataset_first(rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(rdataset)) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ dns_rdataset_current(rdataset, &rdata);
+ CHECK(dns_rdata_tostruct(&rdata, nsec3, NULL));
+ dns_rdata_reset(&rdata);
+ if (match_nsec3param(nsec3, nsec3param))
+ break;
+ }
+ failure:
+ return (result);
+}
+
+isc_result_t
+dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version,
+ dns_name_t *name, const dns_rdata_nsec3param_t *nsec3param,
+ dns_ttl_t nsecttl, isc_boolean_t unsecure, dns_diff_t *diff)
+{
+ dns_dbiterator_t *dbit = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_dbnode_t *newnode = NULL;
+ dns_difftuple_t *tuple = NULL;
+ dns_fixedname_t fixed;
+ dns_fixedname_t fprev;
+ dns_hash_t hash;
+ dns_name_t *hashname;
+ dns_name_t *origin;
+ dns_name_t *prev;
+ dns_name_t empty;
+ dns_rdata_nsec3_t nsec3;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_t rdataset;
+ int pass;
+ isc_boolean_t exists;
+ isc_boolean_t remove_unsecure = ISC_FALSE;
+ isc_uint8_t flags;
+ isc_buffer_t buffer;
+ isc_result_t result;
+ unsigned char *old_next;
+ unsigned char *salt;
+ unsigned char nexthash[NSEC3_MAX_HASH_LENGTH];
+ unsigned char nsec3buf[DNS_NSEC3_BUFFERSIZE];
+ unsigned int iterations;
+ unsigned int labels;
+ unsigned int next_length;
+ unsigned int old_length;
+ unsigned int salt_length;
+
+ dns_fixedname_init(&fixed);
+ hashname = dns_fixedname_name(&fixed);
+ dns_fixedname_init(&fprev);
+ prev = dns_fixedname_name(&fprev);
+
+ dns_rdataset_init(&rdataset);
+
+ origin = dns_db_origin(db);
+
+ /*
+ * Chain parameters.
+ */
+ hash = nsec3param->hash;
+ iterations = nsec3param->iterations;
+ salt_length = nsec3param->salt_length;
+ salt = nsec3param->salt;
+
+ /*
+ * Default flags for a new chain.
+ */
+ flags = nsec3param->flags & DNS_NSEC3FLAG_OPTOUT;
+
+ /*
+ * If this is the first NSEC3 in the chain nexthash will
+ * remain pointing to itself.
+ */
+ next_length = sizeof(nexthash);
+ CHECK(dns_nsec3_hashname(&fixed, nexthash, &next_length,
+ name, origin, hash, iterations,
+ salt, salt_length));
+
+ /*
+ * Create the node if it doesn't exist and hold
+ * a reference to it until we have added the NSEC3.
+ */
+ CHECK(dns_db_findnsec3node(db, hashname, ISC_TRUE, &newnode));
+
+ /*
+ * Seek the iterator to the 'newnode'.
+ */
+ CHECK(dns_db_createiterator(db, DNS_DB_NSEC3ONLY, &dbit));
+ CHECK(dns_dbiterator_seek(dbit, hashname));
+ CHECK(dns_dbiterator_pause(dbit));
+ result = dns_db_findrdataset(db, newnode, version, dns_rdatatype_nsec3,
+ 0, (isc_stdtime_t) 0, &rdataset, NULL);
+ /*
+ * If we updating a existing NSEC3 then find its
+ * next field.
+ */
+ if (result == ISC_R_SUCCESS) {
+ result = find_nsec3(&nsec3, &rdataset, nsec3param);
+ if (result == ISC_R_SUCCESS) {
+ if (!CREATE(nsec3param->flags))
+ flags = nsec3.flags;
+ next_length = nsec3.next_length;
+ INSIST(next_length <= sizeof(nexthash));
+ memcpy(nexthash, nsec3.next, next_length);
+ dns_rdataset_disassociate(&rdataset);
+ /*
+ * If the NSEC3 is not for a unsecure delegation then
+ * we are just updating it. If it is for a unsecure
+ * delegation then we need find out if we need to
+ * remove the NSEC3 record or not by examining the
+ * previous NSEC3 record.
+ */
+ if (!unsecure)
+ goto addnsec3;
+ else
+ remove_unsecure = ISC_TRUE;
+ } else {
+ dns_rdataset_disassociate(&rdataset);
+ if (result != ISC_R_NOMORE)
+ goto failure;
+ }
+ }
+
+ /*
+ * Find the previous NSEC3 (if any) and update it if required.
+ */
+ pass = 0;
+ do {
+ result = dns_dbiterator_prev(dbit);
+ if (result == ISC_R_NOMORE) {
+ pass++;
+ CHECK(dns_dbiterator_last(dbit));
+ }
+ CHECK(dns_dbiterator_current(dbit, &node, prev));
+ CHECK(dns_dbiterator_pause(dbit));
+ result = dns_db_findrdataset(db, node, version,
+ dns_rdatatype_nsec3, 0,
+ (isc_stdtime_t) 0, &rdataset,
+ NULL);
+ dns_db_detachnode(db, &node);
+ if (result != ISC_R_SUCCESS)
+ continue;
+
+ result = find_nsec3(&nsec3, &rdataset, nsec3param);
+ if (result == ISC_R_NOMORE) {
+ dns_rdataset_disassociate(&rdataset);
+ continue;
+ }
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ if (remove_unsecure) {
+ dns_rdataset_disassociate(&rdataset);
+ /*
+ * We have found the previous NSEC3 record and can now
+ * see if the existing NSEC3 record needs to be
+ * updated or deleted.
+ */
+ if (!OPTOUT(nsec3.flags)) {
+ /*
+ * Just update the NSEC3 record.
+ */
+ goto addnsec3;
+ } else {
+ /*
+ * This is actually a deletion not a add.
+ */
+ result = dns_nsec3_delnsec3(db, version, name,
+ nsec3param, diff);
+ goto failure;
+ }
+ } else {
+ /*
+ * Is this is a unsecure delegation we are adding?
+ * If so no change is required.
+ */
+ if (OPTOUT(nsec3.flags) && unsecure) {
+ dns_rdataset_disassociate(&rdataset);
+ goto failure;
+ }
+ }
+
+ old_next = nsec3.next;
+ old_length = nsec3.next_length;
+
+ /*
+ * Delete the old previous NSEC3.
+ */
+ CHECK(delete(db, version, prev, nsec3param, diff));
+
+ /*
+ * Fixup the previous NSEC3.
+ */
+ nsec3.next = nexthash;
+ nsec3.next_length = next_length;
+ isc_buffer_init(&buffer, nsec3buf, sizeof(nsec3buf));
+ CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass,
+ dns_rdatatype_nsec3, &nsec3,
+ &buffer));
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, prev,
+ rdataset.ttl, &rdata, &tuple));
+ CHECK(do_one_tuple(&tuple, db, version, diff));
+ INSIST(old_length <= sizeof(nexthash));
+ memcpy(nexthash, old_next, old_length);
+ if (!CREATE(nsec3param->flags))
+ flags = nsec3.flags;
+ dns_rdata_reset(&rdata);
+ dns_rdataset_disassociate(&rdataset);
+ break;
+ } while (pass < 2);
+
+ addnsec3:
+ /*
+ * Create the NSEC3 RDATA.
+ */
+ CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
+ CHECK(dns_nsec3_buildrdata(db, version, node, hash, flags, iterations,
+ salt, salt_length, nexthash, next_length,
+ nsec3buf, &rdata));
+ dns_db_detachnode(db, &node);
+
+ /*
+ * Delete the old NSEC3 and record the change.
+ */
+ CHECK(delete(db, version, hashname, nsec3param, diff));
+ /*
+ * Add the new NSEC3 and record the change.
+ */
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
+ hashname, nsecttl, &rdata, &tuple));
+ CHECK(do_one_tuple(&tuple, db, version, diff));
+ INSIST(tuple == NULL);
+ dns_rdata_reset(&rdata);
+ dns_db_detachnode(db, &newnode);
+
+ /*
+ * Add missing NSEC3 records for empty nodes
+ */
+ dns_name_init(&empty, NULL);
+ dns_name_clone(name, &empty);
+ do {
+ labels = dns_name_countlabels(&empty) - 1;
+ if (labels <= dns_name_countlabels(origin))
+ break;
+ dns_name_getlabelsequence(&empty, 1, labels, &empty);
+ CHECK(name_exists(db, version, &empty, &exists));
+ if (exists)
+ break;
+ CHECK(dns_nsec3_hashname(&fixed, nexthash, &next_length,
+ &empty, origin, hash, iterations,
+ salt, salt_length));
+
+ /*
+ * Create the node if it doesn't exist and hold
+ * a reference to it until we have added the NSEC3
+ * or we discover we don't need to add make a change.
+ */
+ CHECK(dns_db_findnsec3node(db, hashname, ISC_TRUE, &newnode));
+ result = dns_db_findrdataset(db, newnode, version,
+ dns_rdatatype_nsec3, 0,
+ (isc_stdtime_t) 0, &rdataset,
+ NULL);
+ if (result == ISC_R_SUCCESS) {
+ result = find_nsec3(&nsec3, &rdataset, nsec3param);
+ dns_rdataset_disassociate(&rdataset);
+ if (result == ISC_R_SUCCESS) {
+ dns_db_detachnode(db, &newnode);
+ break;
+ }
+ if (result != ISC_R_NOMORE)
+ goto failure;
+ }
+
+ /*
+ * Find the previous NSEC3 and update it.
+ */
+ CHECK(dns_dbiterator_seek(dbit, hashname));
+ pass = 0;
+ do {
+ result = dns_dbiterator_prev(dbit);
+ if (result == ISC_R_NOMORE) {
+ pass++;
+ CHECK(dns_dbiterator_last(dbit));
+ }
+ CHECK(dns_dbiterator_current(dbit, &node, prev));
+ CHECK(dns_dbiterator_pause(dbit));
+ result = dns_db_findrdataset(db, node, version,
+ dns_rdatatype_nsec3, 0,
+ (isc_stdtime_t) 0,
+ &rdataset, NULL);
+ dns_db_detachnode(db, &node);
+ if (result != ISC_R_SUCCESS)
+ continue;
+ result = find_nsec3(&nsec3, &rdataset, nsec3param);
+ if (result == ISC_R_NOMORE) {
+ dns_rdataset_disassociate(&rdataset);
+ continue;
+ }
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ old_next = nsec3.next;
+ old_length = nsec3.next_length;
+
+ /*
+ * Delete the old previous NSEC3.
+ */
+ CHECK(delete(db, version, prev, nsec3param, diff));
+
+ /*
+ * Fixup the previous NSEC3.
+ */
+ nsec3.next = nexthash;
+ nsec3.next_length = next_length;
+ isc_buffer_init(&buffer, nsec3buf,
+ sizeof(nsec3buf));
+ CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass,
+ dns_rdatatype_nsec3, &nsec3,
+ &buffer));
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
+ prev, rdataset.ttl, &rdata,
+ &tuple));
+ CHECK(do_one_tuple(&tuple, db, version, diff));
+ INSIST(old_length <= sizeof(nexthash));
+ memcpy(nexthash, old_next, old_length);
+ if (!CREATE(nsec3param->flags))
+ flags = nsec3.flags;
+ dns_rdata_reset(&rdata);
+ dns_rdataset_disassociate(&rdataset);
+ break;
+ } while (pass < 2);
+
+ INSIST(pass < 2);
+
+ /*
+ * Create the NSEC3 RDATA for the empty node.
+ */
+ CHECK(dns_nsec3_buildrdata(db, version, NULL, hash, flags,
+ iterations, salt, salt_length,
+ nexthash, next_length, nsec3buf,
+ &rdata));
+ /*
+ * Delete the old NSEC3 and record the change.
+ */
+ CHECK(delete(db, version, hashname, nsec3param, diff));
+
+ /*
+ * Add the new NSEC3 and record the change.
+ */
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
+ hashname, nsecttl, &rdata, &tuple));
+ CHECK(do_one_tuple(&tuple, db, version, diff));
+ INSIST(tuple == NULL);
+ dns_rdata_reset(&rdata);
+ dns_db_detachnode(db, &newnode);
+ } while (1);
+
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ failure:
+ if (dbit != NULL)
+ dns_dbiterator_destroy(&dbit);
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ if (newnode != NULL)
+ dns_db_detachnode(db, &newnode);
+ return (result);
+}
+
+/*%
+ * Add NSEC3 records for "name", recording the change in "diff".
+ * The existing NSEC3 records are removed.
+ */
+isc_result_t
+dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version,
+ dns_name_t *name, dns_ttl_t nsecttl,
+ isc_boolean_t unsecure, dns_diff_t *diff)
+{
+ dns_dbnode_t *node = NULL;
+ dns_rdata_nsec3param_t nsec3param;
+ dns_rdataset_t rdataset;
+ isc_result_t result;
+
+ dns_rdataset_init(&rdataset);
+
+ /*
+ * Find the NSEC3 parameters for this zone.
+ */
+ result = dns_db_getoriginnode(db, &node);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dns_db_findrdataset(db, node, version,
+ dns_rdatatype_nsec3param, 0, 0,
+ &rdataset, NULL);
+ dns_db_detachnode(db, &node);
+ if (result == ISC_R_NOTFOUND)
+ return (ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Update each active NSEC3 chain.
+ */
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ dns_rdataset_current(&rdataset, &rdata);
+ dns_rdata_tostruct(&rdata, &nsec3param, NULL);
+
+#ifdef RFC5155_STRICT
+ if (nsec3param.flags != 0)
+ continue;
+#else
+ if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
+ continue;
+ if (better_param(&rdataset, &rdata))
+ continue;
+#endif
+
+ /*
+ * We have a active chain. Update it.
+ */
+ CHECK(dns_nsec3_addnsec3(db, version, name, &nsec3param,
+ nsecttl, unsecure, diff));
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+
+ return (result);
+}
+
+isc_result_t
+dns_nsec3_delnsec3(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
+ const dns_rdata_nsec3param_t *nsec3param, dns_diff_t *diff)
+{
+ dns_dbiterator_t *dbit = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_difftuple_t *tuple = NULL;
+ dns_fixedname_t fixed;
+ dns_fixedname_t fprev;
+ dns_hash_t hash;
+ dns_name_t *hashname;
+ dns_name_t *origin;
+ dns_name_t *prev;
+ dns_name_t empty;
+ dns_rdata_nsec3_t nsec3;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_t rdataset;
+ int pass;
+ isc_boolean_t exists;
+ isc_buffer_t buffer;
+ isc_result_t result;
+ unsigned char *salt;
+ unsigned char nexthash[NSEC3_MAX_HASH_LENGTH];
+ unsigned char nsec3buf[DNS_NSEC3_BUFFERSIZE];
+ unsigned int iterations;
+ unsigned int labels;
+ unsigned int next_length;
+ unsigned int salt_length;
+
+ dns_fixedname_init(&fixed);
+ hashname = dns_fixedname_name(&fixed);
+ dns_fixedname_init(&fprev);
+ prev = dns_fixedname_name(&fprev);
+
+ dns_rdataset_init(&rdataset);
+
+ origin = dns_db_origin(db);
+
+ /*
+ * Chain parameters.
+ */
+ hash = nsec3param->hash;
+ iterations = nsec3param->iterations;
+ salt_length = nsec3param->salt_length;
+ salt = nsec3param->salt;
+
+ /*
+ * If this is the first NSEC3 in the chain nexthash will
+ * remain pointing to itself.
+ */
+ next_length = sizeof(nexthash);
+ CHECK(dns_nsec3_hashname(&fixed, nexthash, &next_length,
+ name, origin, hash, iterations,
+ salt, salt_length));
+
+ CHECK(dns_db_createiterator(db, DNS_DB_NSEC3ONLY, &dbit));
+
+ result = dns_dbiterator_seek(dbit, hashname);
+ if (result == ISC_R_NOTFOUND)
+ goto success;
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ CHECK(dns_dbiterator_current(dbit, &node, NULL));
+ CHECK(dns_dbiterator_pause(dbit));
+ result = dns_db_findrdataset(db, node, version, dns_rdatatype_nsec3,
+ 0, (isc_stdtime_t) 0, &rdataset, NULL);
+ dns_db_detachnode(db, &node);
+ if (result == ISC_R_NOTFOUND)
+ goto success;
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ /*
+ * If we find a existing NSEC3 for this chain then save the
+ * next field.
+ */
+ result = find_nsec3(&nsec3, &rdataset, nsec3param);
+ if (result == ISC_R_SUCCESS) {
+ next_length = nsec3.next_length;
+ INSIST(next_length <= sizeof(nexthash));
+ memcpy(nexthash, nsec3.next, next_length);
+ }
+ dns_rdataset_disassociate(&rdataset);
+ if (result == ISC_R_NOMORE)
+ goto success;
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ /*
+ * Find the previous NSEC3 and update it.
+ */
+ pass = 0;
+ do {
+ result = dns_dbiterator_prev(dbit);
+ if (result == ISC_R_NOMORE) {
+ pass++;
+ CHECK(dns_dbiterator_last(dbit));
+ }
+ CHECK(dns_dbiterator_current(dbit, &node, prev));
+ CHECK(dns_dbiterator_pause(dbit));
+ result = dns_db_findrdataset(db, node, version,
+ dns_rdatatype_nsec3, 0,
+ (isc_stdtime_t) 0, &rdataset,
+ NULL);
+ dns_db_detachnode(db, &node);
+ if (result != ISC_R_SUCCESS)
+ continue;
+ result = find_nsec3(&nsec3, &rdataset, nsec3param);
+ if (result == ISC_R_NOMORE) {
+ dns_rdataset_disassociate(&rdataset);
+ continue;
+ }
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ /*
+ * Delete the old previous NSEC3.
+ */
+ CHECK(delete(db, version, prev, nsec3param, diff));
+
+ /*
+ * Fixup the previous NSEC3.
+ */
+ nsec3.next = nexthash;
+ nsec3.next_length = next_length;
+ isc_buffer_init(&buffer, nsec3buf, sizeof(nsec3buf));
+ CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass,
+ dns_rdatatype_nsec3, &nsec3,
+ &buffer));
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, prev,
+ rdataset.ttl, &rdata, &tuple));
+ CHECK(do_one_tuple(&tuple, db, version, diff));
+ dns_rdata_reset(&rdata);
+ dns_rdataset_disassociate(&rdataset);
+ break;
+ } while (pass < 2);
+
+ /*
+ * Delete the old NSEC3 and record the change.
+ */
+ CHECK(delete(db, version, hashname, nsec3param, diff));
+
+ /*
+ * Delete NSEC3 records for now non active nodes.
+ */
+ dns_name_init(&empty, NULL);
+ dns_name_clone(name, &empty);
+ do {
+ labels = dns_name_countlabels(&empty) - 1;
+ if (labels <= dns_name_countlabels(origin))
+ break;
+ dns_name_getlabelsequence(&empty, 1, labels, &empty);
+ CHECK(name_exists(db, version, &empty, &exists));
+ if (exists)
+ break;
+
+ CHECK(dns_nsec3_hashname(&fixed, nexthash, &next_length,
+ &empty, origin, hash, iterations,
+ salt, salt_length));
+ result = dns_dbiterator_seek(dbit, hashname);
+ if (result == ISC_R_NOTFOUND)
+ goto success;
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ CHECK(dns_dbiterator_current(dbit, &node, NULL));
+ CHECK(dns_dbiterator_pause(dbit));
+ result = dns_db_findrdataset(db, node, version,
+ dns_rdatatype_nsec3, 0,
+ (isc_stdtime_t) 0, &rdataset,
+ NULL);
+ dns_db_detachnode(db, &node);
+ if (result == ISC_R_NOTFOUND)
+ goto success;
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ result = find_nsec3(&nsec3, &rdataset, nsec3param);
+ if (result == ISC_R_SUCCESS) {
+ next_length = nsec3.next_length;
+ INSIST(next_length <= sizeof(nexthash));
+ memcpy(nexthash, nsec3.next, next_length);
+ }
+ dns_rdataset_disassociate(&rdataset);
+ if (result == ISC_R_NOMORE)
+ goto success;
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ pass = 0;
+ do {
+ result = dns_dbiterator_prev(dbit);
+ if (result == ISC_R_NOMORE) {
+ pass++;
+ CHECK(dns_dbiterator_last(dbit));
+ }
+ CHECK(dns_dbiterator_current(dbit, &node, prev));
+ CHECK(dns_dbiterator_pause(dbit));
+ result = dns_db_findrdataset(db, node, version,
+ dns_rdatatype_nsec3, 0,
+ (isc_stdtime_t) 0,
+ &rdataset, NULL);
+ dns_db_detachnode(db, &node);
+ if (result != ISC_R_SUCCESS)
+ continue;
+ result = find_nsec3(&nsec3, &rdataset, nsec3param);
+ if (result == ISC_R_NOMORE) {
+ dns_rdataset_disassociate(&rdataset);
+ continue;
+ }
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ /*
+ * Delete the old previous NSEC3.
+ */
+ CHECK(delete(db, version, prev, nsec3param, diff));
+
+ /*
+ * Fixup the previous NSEC3.
+ */
+ nsec3.next = nexthash;
+ nsec3.next_length = next_length;
+ isc_buffer_init(&buffer, nsec3buf,
+ sizeof(nsec3buf));
+ CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass,
+ dns_rdatatype_nsec3, &nsec3,
+ &buffer));
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
+ prev, rdataset.ttl, &rdata,
+ &tuple));
+ CHECK(do_one_tuple(&tuple, db, version, diff));
+ dns_rdata_reset(&rdata);
+ dns_rdataset_disassociate(&rdataset);
+ break;
+ } while (pass < 2);
+
+ INSIST(pass < 2);
+
+ /*
+ * Delete the old NSEC3 and record the change.
+ */
+ CHECK(delete(db, version, hashname, nsec3param, diff));
+ } while (1);
+
+ success:
+ result = ISC_R_SUCCESS;
+
+ failure:
+ if (dbit != NULL)
+ dns_dbiterator_destroy(&dbit);
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
+isc_result_t
+dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
+ dns_diff_t *diff)
+{
+ dns_dbnode_t *node = NULL;
+ dns_rdata_nsec3param_t nsec3param;
+ dns_rdataset_t rdataset;
+ isc_result_t result;
+
+ dns_rdataset_init(&rdataset);
+
+ /*
+ * Find the NSEC3 parameters for this zone.
+ */
+ result = dns_db_getoriginnode(db, &node);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dns_db_findrdataset(db, node, version,
+ dns_rdatatype_nsec3param, 0, 0,
+ &rdataset, NULL);
+ dns_db_detachnode(db, &node);
+ if (result == ISC_R_NOTFOUND)
+ return (ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * Update each active NSEC3 chain.
+ */
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ dns_rdataset_current(&rdataset, &rdata);
+ dns_rdata_tostruct(&rdata, &nsec3param, NULL);
+
+#ifdef RFC5155_STRICT
+ if (nsec3param.flags != 0)
+ continue;
+#else
+ if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
+ continue;
+ if (better_param(&rdataset, &rdata))
+ continue;
+#endif
+
+ /*
+ * We have a active chain. Update it.
+ */
+ CHECK(dns_nsec3_delnsec3(db, version, name, &nsec3param, diff));
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+
+ return (result);
+}
+
+isc_result_t
+dns_nsec3_active(dns_db_t *db, dns_dbversion_t *version,
+ isc_boolean_t complete, isc_boolean_t *answer)
+{
+ dns_dbnode_t *node = NULL;
+ dns_rdataset_t rdataset;
+ dns_rdata_nsec3param_t nsec3param;
+ isc_result_t result;
+
+ REQUIRE(answer != NULL);
+
+ dns_rdataset_init(&rdataset);
+
+ result = dns_db_getoriginnode(db, &node);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dns_db_findrdataset(db, node, version,
+ dns_rdatatype_nsec3param, 0, 0,
+ &rdataset, NULL);
+ dns_db_detachnode(db, &node);
+
+ if (result == ISC_R_NOTFOUND) {
+ *answer = ISC_FALSE;
+ return (ISC_R_SUCCESS);
+ }
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ dns_rdataset_current(&rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ if ((nsec3param.flags) == 0 ||
+ (!complete && CREATE(nsec3param.flags)))
+ break;
+ }
+ dns_rdataset_disassociate(&rdataset);
+ if (result == ISC_R_SUCCESS)
+ *answer = ISC_TRUE;
+ if (result == ISC_R_NOMORE) {
+ *answer = ISC_FALSE;
+ result = ISC_R_SUCCESS;
+ }
+ return (result);
+}
+
+isc_result_t
+dns_nsec3_maxiterations(dns_db_t *db, dns_dbversion_t *version,
+ isc_mem_t *mctx, unsigned int *iterationsp)
+{
+ dns_dbnode_t *node = NULL;
+ dns_rdataset_t rdataset;
+ dst_key_t *key = NULL;
+ isc_buffer_t buffer;
+ isc_result_t result;
+ isc_uint16_t bits, minbits = 4096;
+
+ result = dns_db_getoriginnode(db, &node);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey,
+ 0, 0, &rdataset, NULL);
+ dns_db_detachnode(db, &node);
+ if (result == ISC_R_NOTFOUND) {
+ *iterationsp = 0;
+ return (ISC_R_SUCCESS);
+ }
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ dns_rdataset_current(&rdataset, &rdata);
+ isc_buffer_init(&buffer, rdata.data, rdata.length);
+ isc_buffer_add(&buffer, rdata.length);
+ CHECK(dst_key_fromdns(dns_db_origin(db), rdataset.rdclass,
+ &buffer, mctx, &key));
+ bits = dst_key_getbits(key);
+ dst_key_free(&key);
+ if (minbits > bits)
+ minbits = bits;
+ }
+ if (result != ISC_R_NOMORE)
+ goto failure;
+
+ if (minbits <= 1024)
+ *iterationsp = 150;
+ else if (minbits <= 2048)
+ *iterationsp = 500;
+ else
+ *iterationsp = 2500;
+ result = ISC_R_SUCCESS;
+
+ failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ return (result);
+}
/*
* Principal Author: Brian Wellington
- * $Id: opensslrsa_link.c,v 1.19 2008/04/01 23:47:10 tbox Exp $
+ * $Id: opensslrsa_link.c,v 1.20 2008/09/24 02:46:22 marka Exp $
*/
#ifdef OPENSSL
#ifndef USE_EVP
UNUSED(key);
REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 ||
- dctx->key->key_alg == DST_ALG_RSASHA1);
+ dctx->key->key_alg == DST_ALG_RSASHA1 ||
+ dctx->key->key_alg == DST_ALG_NSEC3RSASHA1);
#if USE_EVP
evp_md_ctx = EVP_MD_CTX_create();
#endif
REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 ||
- dctx->key->key_alg == DST_ALG_RSASHA1);
+ dctx->key->key_alg == DST_ALG_RSASHA1 ||
+ dctx->key->key_alg == DST_ALG_NSEC3RSASHA1);
#if USE_EVP
if (evp_md_ctx != NULL) {
#endif
REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 ||
- dctx->key->key_alg == DST_ALG_RSASHA1);
+ dctx->key->key_alg == DST_ALG_RSASHA1 ||
+ dctx->key->key_alg == DST_ALG_NSEC3RSASHA1);
#if USE_EVP
if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length)) {
#endif
REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 ||
- dctx->key->key_alg == DST_ALG_RSASHA1);
+ dctx->key->key_alg == DST_ALG_RSASHA1 ||
+ dctx->key->key_alg == DST_ALG_NSEC3RSASHA1);
isc_buffer_availableregion(sig, &r);
#endif
REQUIRE(dctx->key->key_alg == DST_ALG_RSAMD5 ||
- dctx->key->key_alg == DST_ALG_RSASHA1);
+ dctx->key->key_alg == DST_ALG_RSASHA1 ||
+ dctx->key->key_alg == DST_ALG_NSEC3RSASHA1);
#if USE_EVP
status = EVP_VerifyFinal(evp_md_ctx, sig->base, sig->length, pkey);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rbt.c,v 1.141 2008/03/31 13:11:32 fdupont Exp $ */
+/* $Id: rbt.c,v 1.142 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
* current node.
*/
new_current->is_root = current->is_root;
+ new_current->nsec3 = current->nsec3;
PARENT(new_current) = PARENT(current);
LEFT(new_current) = LEFT(current);
RIGHT(new_current) = RIGHT(current);
DIRTY(node) = 0;
dns_rbtnode_refinit(node, 0);
node->find_callback = 0;
+ node->nsec3 = 0;
MAKE_BLACK(node);
return (result);
}
+isc_result_t
+dns_rbtnodechain_down(dns_rbtnodechain_t *chain, dns_name_t *name,
+ dns_name_t *origin)
+{
+ dns_rbtnode_t *current, *successor;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_boolean_t new_origin = ISC_FALSE;
+
+ REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
+
+ successor = NULL;
+
+ current = chain->end;
+
+ if (DOWN(current) != NULL) {
+ /*
+ * Don't declare an origin change when the new origin is "."
+ * at the second level tree, because "." is already declared
+ * as the origin for the top level tree.
+ */
+ if (chain->level_count > 0 ||
+ OFFSETLEN(current) > 1)
+ new_origin = ISC_TRUE;
+
+ ADD_LEVEL(chain, current);
+ current = DOWN(current);
+
+ while (LEFT(current) != NULL)
+ current = LEFT(current);
+
+ successor = current;
+ }
+
+ if (successor != NULL) {
+ chain->end = successor;
+
+ /*
+ * It is not necessary to use dns_rbtnodechain_current like
+ * the other functions because this function will never
+ * find a node in the topmost level. This is because the
+ * root level will never be more than one name, and everything
+ * in the megatree is a successor to that node, down at
+ * the second level or below.
+ */
+
+ if (name != NULL)
+ NODENAME(chain->end, name);
+
+ if (new_origin) {
+ if (origin != NULL)
+ result = chain_name(chain, origin, ISC_FALSE);
+
+ if (result == ISC_R_SUCCESS)
+ result = DNS_R_NEWORIGIN;
+
+ } else
+ result = ISC_R_SUCCESS;
+
+ } else
+ result = ISC_R_NOMORE;
+
+ return (result);
+}
+
+isc_result_t
+dns_rbtnodechain_nextflat(dns_rbtnodechain_t *chain, dns_name_t *name) {
+ dns_rbtnode_t *current, *previous, *successor;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
+
+ successor = NULL;
+
+ current = chain->end;
+
+ if (RIGHT(current) == NULL) {
+ while (! IS_ROOT(current)) {
+ previous = current;
+ current = PARENT(current);
+
+ if (LEFT(current) == previous) {
+ successor = current;
+ break;
+ }
+ }
+ } else {
+ current = RIGHT(current);
+
+ while (LEFT(current) != NULL)
+ current = LEFT(current);
+
+ successor = current;
+ }
+
+ if (successor != NULL) {
+ chain->end = successor;
+
+ if (name != NULL)
+ NODENAME(chain->end, name);
+
+ result = ISC_R_SUCCESS;
+ } else
+ result = ISC_R_NOMORE;
+
+ return (result);
+}
+
isc_result_t
dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
dns_name_t *origin)
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rbtdb.c,v 1.262 2008/08/13 02:28:45 jinmei Exp $ */
+/* $Id: rbtdb.c,v 1.263 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
#include <dns/log.h>
#include <dns/masterdump.h>
#include <dns/nsec.h>
+#include <dns/nsec3.h>
#include <dns/rbt.h>
#include <dns/rdata.h>
#include <dns/rdataset.h>
#include <dns/rdatasetiter.h>
#include <dns/rdataslab.h>
+#include <dns/rdatastruct.h>
#include <dns/result.h>
#include <dns/stats.h>
#include <dns/view.h>
#define RBTDB_RDATATYPE_BASE(type) ((dns_rdatatype_t)((type) & 0xFFFF))
#define RBTDB_RDATATYPE_EXT(type) ((dns_rdatatype_t)((type) >> 16))
-#define RBTDB_RDATATYPE_VALUE(b, e) (((e) << 16) | (b))
+#define RBTDB_RDATATYPE_VALUE(b, e) ((rbtdb_rdatatype_t)((e) << 16) | (b))
#define RBTDB_RDATATYPE_SIGNSEC \
RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_nsec)
+#define RBTDB_RDATATYPE_SIGNSEC3 \
+ RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_nsec3)
#define RBTDB_RDATATYPE_SIGNS \
RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ns)
#define RBTDB_RDATATYPE_SIGCNAME \
#define RBTDB_VIRTUAL 300
struct noqname {
- dns_name_t name;
- void * nsec;
- void * nsecsig;
+ dns_name_t name;
+ void * neg;
+ void * negsig;
+ dns_rdatatype_t type;
};
typedef struct acachectl acachectl_t;
isc_uint16_t attributes;
dns_trust_t trust;
struct noqname *noqname;
+ struct noqname *closest;
/*%<
* We don't use the LIST macros, because the LIST structure has
* both head and tail pointers, and is doubly linked.
#define RDATASET_ATTR_NXDOMAIN 0x0010
#define RDATASET_ATTR_RESIGN 0x0020
#define RDATASET_ATTR_STATCOUNT 0x0040
+#define RDATASET_ATTR_OPTOUT 0x0080
typedef struct acache_cbarg {
dns_rdatasetadditional_t type;
(((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
#define RESIGN(header) \
(((header)->attributes & RDATASET_ATTR_RESIGN) != 0)
+#define OPTOUT(header) \
+ (((header)->attributes & RDATASET_ATTR_OPTOUT) != 0)
#define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */
#define DEFAULT_CACHE_NODE_LOCK_COUNT 1009 /*%< Should be prime. */
rbtdb_changedlist_t changed_list;
rdatasetheaderlist_t resigned_list;
ISC_LINK(struct rbtdb_version) link;
+ isc_boolean_t secure;
+ isc_boolean_t havensec3;
+ /* NSEC3 parameters */
+ dns_hash_t hash;
+ isc_uint8_t flags;
+ isc_uint16_t iterations;
+ isc_uint8_t salt_length;
+ unsigned char salt[NSEC3_MAX_HASH_LENGTH];
} rbtdb_version_t;
typedef ISC_LIST(rbtdb_version_t) rbtdb_versionlist_t;
/* Locked by tree_lock. */
dns_rbt_t * tree;
- dns_db_secure_t secure;
+ dns_rbt_t * nsec3;
/* Unlocked */
unsigned int quantum;
static unsigned int rdataset_count(dns_rdataset_t *rdataset);
static isc_result_t rdataset_getnoqname(dns_rdataset_t *rdataset,
dns_name_t *name,
- dns_rdataset_t *nsec,
- dns_rdataset_t *nsecsig);
+ dns_rdataset_t *neg,
+ dns_rdataset_t *negsig);
+static isc_result_t rdataset_getclosest(dns_rdataset_t *rdataset,
+ dns_name_t *name,
+ dns_rdataset_t *neg,
+ dns_rdataset_t *negsig);
static isc_result_t rdataset_getadditional(dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type,
dns_rdatatype_t qtype,
rdataset_count,
NULL,
rdataset_getnoqname,
+ NULL,
+ rdataset_getclosest,
rdataset_getadditional,
rdataset_setadditional,
rdataset_putadditional
dns_fixedname_t name;
dns_fixedname_t origin;
dns_rbtnodechain_t chain;
+ dns_rbtnodechain_t nsec3chain;
+ dns_rbtnodechain_t *current;
dns_rbtnode_t *node;
dns_rbtnode_t *deletions[DELETION_BATCH_MAX];
int delete;
+ isc_boolean_t nsec3only;
+ isc_boolean_t nonsec3;
} rbtdb_dbiterator_t;
static void free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log,
isc_event_t *event);
static void overmem(dns_db_t *db, isc_boolean_t overmem);
+static void setnsec3parameters(dns_db_t *db, rbtdb_version_t *version,
+ isc_boolean_t *nsec3createflag);
/*%
* 'init_count' is used to initialize 'newheader->count' which inturn
}
INSIST(result == ISC_R_SUCCESS && rbtdb->tree == NULL);
}
+
+ if (rbtdb->nsec3 != NULL) {
+ isc_time_now(&start);
+ result = dns_rbt_destroy2(&rbtdb->nsec3, rbtdb->quantum);
+ if (result == ISC_R_QUOTA) {
+ INSIST(rbtdb->task != NULL);
+ if (rbtdb->quantum != 0)
+ rbtdb->quantum = adjust_quantum(rbtdb->quantum,
+ &start);
+ if (event == NULL)
+ event = isc_event_allocate(rbtdb->common.mctx,
+ NULL,
+ DNS_EVENT_FREESTORAGE,
+ free_rbtdb_callback,
+ rbtdb,
+ sizeof(isc_event_t));
+ if (event == NULL)
+ goto again;
+ isc_task_send(rbtdb->task, &event);
+ return;
+ }
+ INSIST(result == ISC_R_SUCCESS && rbtdb->nsec3 == NULL);
+ }
+
if (event != NULL)
isc_event_free(&event);
if (log) {
ISC_TRUE);
if (version != NULL) {
version->commit_ok = ISC_TRUE;
+ version->secure = rbtdb->current_version->secure;
+ version->havensec3 = rbtdb->current_version->havensec3;
+ if (version->havensec3) {
+ version->flags = rbtdb->current_version->flags;
+ version->iterations =
+ rbtdb->current_version->iterations;
+ version->hash = rbtdb->current_version->hash;
+ version->salt_length =
+ rbtdb->current_version->salt_length;
+ memcpy(version->salt, rbtdb->current_version->salt,
+ version->salt_length);
+ } else {
+ version->flags = 0;
+ version->iterations = 0;
+ version->hash = 0;
+ version->salt_length = 0;
+ memset(version->salt, 0, sizeof(version->salt));
+ }
rbtdb->next_serial++;
rbtdb->future_version = version;
}
if (dns_name_dynamic(&(*noqname)->name))
dns_name_free(&(*noqname)->name, mctx);
- if ((*noqname)->nsec != NULL)
- isc_mem_put(mctx, (*noqname)->nsec,
- dns_rdataslab_size((*noqname)->nsec, 0));
- if ((*noqname)->nsecsig != NULL)
- isc_mem_put(mctx, (*noqname)->nsecsig,
- dns_rdataslab_size((*noqname)->nsecsig, 0));
+ if ((*noqname)->neg != NULL)
+ isc_mem_put(mctx, (*noqname)->neg,
+ dns_rdataslab_size((*noqname)->neg, 0));
+ if ((*noqname)->negsig != NULL)
+ isc_mem_put(mctx, (*noqname)->negsig,
+ dns_rdataslab_size((*noqname)->negsig, 0));
isc_mem_put(mctx, *noqname, sizeof(**noqname));
*noqname = NULL;
}
if (rdataset->noqname != NULL)
free_noqname(mctx, &rdataset->noqname);
+ if (rdataset->closest != NULL)
+ free_noqname(mctx, &rdataset->closest);
free_acachearray(mctx, rdataset, rdataset->additional_auth);
free_acachearray(mctx, rdataset, rdataset->additional_glue);
INSIST(dns_rbtnode_refcurrent(node) == 0 &&
node->data == NULL);
- result = dns_rbt_deletenode(rbtdb->tree, node, ISC_FALSE);
+ INSIST(!ISC_LINK_LINKED(node, deadlink));
+ if (node->nsec3)
+ result = dns_rbt_deletenode(rbtdb->nsec3, node,
+ ISC_FALSE);
+ else
+ result = dns_rbt_deletenode(rbtdb->tree, node,
+ ISC_FALSE);
if (result != ISC_R_SUCCESS)
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
}
INSIST(!ISC_LINK_LINKED(node, deadlink));
- result = dns_rbt_deletenode(rbtdb->tree, node, ISC_FALSE);
+ if (node->nsec3)
+ result = dns_rbt_deletenode(rbtdb->nsec3, node,
+ ISC_FALSE);
+ else
+ result = dns_rbt_deletenode(rbtdb->tree, node,
+ ISC_FALSE);
if (result != ISC_R_SUCCESS)
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
}
}
-static dns_db_secure_t
-iszonesecure(dns_db_t *db, dns_dbnode_t *origin) {
+static void
+iszonesecure(dns_db_t *db, rbtdb_version_t *version, dns_dbnode_t *origin) {
dns_rdataset_t keyset;
dns_rdataset_t nsecset, signsecset;
dns_rdata_t rdata = DNS_RDATA_INIT;
isc_boolean_t haszonekey = ISC_FALSE;
isc_boolean_t hasnsec = ISC_FALSE;
isc_boolean_t hasoptbit = ISC_FALSE;
+ isc_boolean_t nsec3createflag = ISC_FALSE;
isc_result_t result;
dns_rdataset_init(&keyset);
- result = dns_db_findrdataset(db, origin, NULL, dns_rdatatype_dnskey, 0,
- 0, &keyset, NULL);
+ result = dns_db_findrdataset(db, origin, version, dns_rdatatype_dnskey,
+ 0, 0, &keyset, NULL);
if (result == ISC_R_SUCCESS) {
dns_rdata_t keyrdata = DNS_RDATA_INIT;
result = dns_rdataset_first(&keyset);
}
dns_rdataset_disassociate(&keyset);
}
- if (!haszonekey)
- return (dns_db_insecure);
+ if (!haszonekey) {
+ version->secure = dns_db_insecure;
+ version->havensec3 = ISC_FALSE;
+ return;
+ }
dns_rdataset_init(&nsecset);
dns_rdataset_init(&signsecset);
- result = dns_db_findrdataset(db, origin, NULL, dns_rdatatype_nsec, 0,
- 0, &nsecset, &signsecset);
+ result = dns_db_findrdataset(db, origin, version, dns_rdatatype_nsec,
+ 0, 0, &nsecset, &signsecset);
if (result == ISC_R_SUCCESS) {
if (dns_rdataset_isassociated(&signsecset)) {
hasnsec = ISC_TRUE;
dns_rdataset_disassociate(&nsecset);
}
- if (hasnsec && hasoptbit)
- return (dns_db_partial);
- return (hasnsec ? dns_db_secure : dns_db_insecure);
+ setnsec3parameters(db, version, &nsec3createflag);
+
+ /*
+ * Do we have a valid NSEC/NSEC3 chain?
+ */
+ if (version->havensec3 || (hasnsec && !hasoptbit))
+ version->secure = dns_db_secure;
+ /*
+ * Do we have a NSEC/NSEC3 chain under creation?
+ */
+ else if (hasoptbit || nsec3createflag)
+ version->secure = dns_db_partial;
+ else
+ version->secure = dns_db_insecure;
+}
+
+/*%<
+ * Walk the origin node looking for NSEC3PARAM records.
+ * Cache the nsec3 parameters.
+ */
+static void
+setnsec3parameters(dns_db_t *db, rbtdb_version_t *version,
+ isc_boolean_t *nsec3createflag)
+{
+ dns_rbtnode_t *node;
+ dns_rdata_nsec3param_t nsec3param;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_region_t region;
+ isc_result_t result;
+ rdatasetheader_t *header, *header_next;
+ unsigned char *raw; /* RDATASLAB */
+ unsigned int count, length;
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+
+ RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+ version->havensec3 = ISC_FALSE;
+ node = rbtdb->origin_node;
+ NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+ for (header = node->data;
+ header != NULL;
+ header = header_next) {
+ header_next = header->next;
+ do {
+ if (header->serial <= version->serial &&
+ !IGNORE(header)) {
+ if (NONEXISTENT(header))
+ header = NULL;
+ break;
+ } else
+ header = header->down;
+ } while (header != NULL);
+
+ if (header != NULL &&
+ header->type == dns_rdatatype_nsec3param) {
+ /*
+ * Find A NSEC3PARAM with a supported algorithm.
+ */
+ raw = (unsigned char *)header + sizeof(*header);
+ count = raw[0] * 256 + raw[1]; /* count */
+#if DNS_RDATASET_FIXED
+ raw += count * 4 + 2;
+#else
+ raw += 2;
+#endif
+ while (count-- > 0U) {
+ length = raw[0] * 256 + raw[1];
+#if DNS_RDATASET_FIXED
+ raw += 4;
+#else
+ raw += 2;
+#endif
+ region.base = raw;
+ region.length = length;
+ raw += length;
+ dns_rdata_fromregion(&rdata,
+ rbtdb->common.rdclass,
+ dns_rdatatype_nsec3param,
+ ®ion);
+ result = dns_rdata_tostruct(&rdata,
+ &nsec3param,
+ NULL);
+ INSIST(result == ISC_R_SUCCESS);
+ dns_rdata_reset(&rdata);
+
+ if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG &&
+ !dns_nsec3_supportedhash(nsec3param.hash))
+ continue;
+
+#ifdef RFC5155_STRICT
+ if (nsec3param.flags != 0)
+ continue;
+#else
+ if ((nsec3param.flags & DNS_NSEC3FLAG_CREATE)
+ != 0)
+ *nsec3createflag = ISC_TRUE;
+ if ((nsec3param.flags & ~DNS_NSEC3FLAG_OPTOUT)
+ != 0)
+ continue;
+#endif
+
+ INSIST(nsec3param.salt_length <=
+ sizeof(version->salt));
+ memcpy(version->salt, nsec3param.salt,
+ nsec3param.salt_length);
+ version->hash = nsec3param.hash;
+ version->salt_length = nsec3param.salt_length;
+ version->iterations = nsec3param.iterations;
+ version->flags = nsec3param.flags;
+ version->havensec3 = ISC_TRUE;
+ /*
+ * Look for a better algorithm than the
+ * unknown test algorithm.
+ */
+ if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG)
+ goto unlock;
+ }
+ }
+ }
+ unlock:
+ NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
+ isc_rwlocktype_read);
+ RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
}
static void
* Update the zone's secure status.
*/
if (writer && commit && !IS_CACHE(rbtdb))
- rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
+ iszonesecure(db, version, rbtdb->origin_node);
if (cleanup_version != NULL) {
INSIST(EMPTY(cleanup_version->changed_list));
RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
}
- end:
+ end:
*versionp = NULL;
}
result = dns_rbt_addnode(rbtdb->tree, &foundname, &node);
if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
return (result);
+ node->nsec3 = 0;
node->find_callback = 1;
node->wild = 1;
return (ISC_R_SUCCESS);
&node);
if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
return (result);
+ node->nsec3 = 0;
}
i++;
}
node->locknum = dns_name_hash(&nodename, ISC_TRUE) %
rbtdb->node_lock_count;
#endif
+ node->nsec3 = 0;
add_empty_wildcards(rbtdb, name);
if (dns_name_iswildcard(name)) {
return (ISC_R_SUCCESS);
}
+static isc_result_t
+findnsec3node(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
+ dns_dbnode_t **nodep)
+{
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ dns_rbtnode_t *node = NULL;
+ dns_name_t nodename;
+ isc_result_t result;
+ isc_rwlocktype_t locktype = isc_rwlocktype_read;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ dns_name_init(&nodename, NULL);
+ RWLOCK(&rbtdb->tree_lock, locktype);
+ result = dns_rbt_findnode(rbtdb->nsec3, name, NULL, &node, NULL,
+ DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+ if (result != ISC_R_SUCCESS) {
+ RWUNLOCK(&rbtdb->tree_lock, locktype);
+ if (!create) {
+ if (result == DNS_R_PARTIALMATCH)
+ result = ISC_R_NOTFOUND;
+ return (result);
+ }
+ /*
+ * It would be nice to try to upgrade the lock instead of
+ * unlocking then relocking.
+ */
+ locktype = isc_rwlocktype_write;
+ RWLOCK(&rbtdb->tree_lock, locktype);
+ node = NULL;
+ result = dns_rbt_addnode(rbtdb->nsec3, name, &node);
+ if (result == ISC_R_SUCCESS) {
+ dns_rbt_namefromnode(node, &nodename);
+#ifdef DNS_RBT_USEHASH
+ node->locknum = node->hashval % rbtdb->node_lock_count;
+#else
+ node->locknum = dns_name_hash(&nodename, ISC_TRUE) %
+ rbtdb->node_lock_count;
+#endif
+ node->nsec3 = 1U;
+ } else if (result != ISC_R_EXISTS) {
+ RWUNLOCK(&rbtdb->tree_lock, locktype);
+ return (result);
+ }
+ } else
+ INSIST(node->nsec3);
+ NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
+ new_reference(rbtdb, node);
+ NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
+ RWUNLOCK(&rbtdb->tree_lock, locktype);
+
+ *nodep = (dns_dbnode_t *)node;
+
+ return (ISC_R_SUCCESS);
+}
+
static isc_result_t
zone_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
rbtdb_search_t *search = arg;
rdataset->trust = header->trust;
if (NXDOMAIN(header))
rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
+ if (OPTOUT(header))
+ rdataset->attributes |= DNS_RDATASETATTR_OPTOUT;
rdataset->private1 = rbtdb;
rdataset->private2 = node;
raw = (unsigned char *)header + sizeof(*header);
rdataset->private6 = header->noqname;
if (rdataset->private6 != NULL)
rdataset->attributes |= DNS_RDATASETATTR_NOQNAME;
+ rdataset->private7 = header->closest;
+ if (rdataset->private7 != NULL)
+ rdataset->attributes |= DNS_RDATASETATTR_CLOSEST;
+
/*
* Copy out re-signing information.
*/
return (result);
}
+static isc_boolean_t
+matchparams(rdatasetheader_t *header, rbtdb_search_t *search)
+{
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_nsec3_t nsec3;
+ unsigned char *raw; /* RDATASLAB */
+ unsigned int rdlen, count;
+ isc_region_t region;
+ isc_result_t result;
+
+ REQUIRE(header->type == dns_rdatatype_nsec3);
+
+ raw = (unsigned char *)header + sizeof(*header);
+ count = raw[0] * 256 + raw[1]; /* count */
+#if DNS_RDATASET_FIXED
+ raw += count * 4 + 2;
+#else
+ raw += 2;
+#endif
+ rdlen = raw[0] * 256 + raw[1];
+#if DNS_RDATASET_FIXED
+ raw += 4;
+#else
+ raw += 2;
+#endif
+ region.base = raw;
+ region.length = rdlen;
+ dns_rdata_fromregion(&rdata, search->rbtdb->common.rdclass,
+ dns_rdatatype_nsec3, ®ion);
+ result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
+ INSIST(result == ISC_R_SUCCESS);
+ if (nsec3.hash == search->rbtversion->hash &&
+ nsec3.iterations == search->rbtversion->iterations &&
+ nsec3.salt_length == search->rbtversion->salt_length &&
+ memcmp(nsec3.salt, search->rbtversion->salt, nsec3.salt_length) == 0)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
static inline isc_result_t
find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
dns_name_t *foundname, dns_rdataset_t *rdataset,
- dns_rdataset_t *sigrdataset, isc_boolean_t need_sig)
+ dns_rdataset_t *sigrdataset, dns_rbt_t *tree,
+ isc_boolean_t need_sig)
{
dns_rbtnode_t *node;
rdatasetheader_t *header, *header_next, *found, *foundsig;
isc_result_t result;
dns_fixedname_t fname, forigin;
dns_name_t *name, *origin;
+ dns_rdatatype_t type;
+ rbtdb_rdatatype_t sigtype;
+ isc_boolean_t wraps;
+ if (tree == search->rbtdb->nsec3) {
+ type = dns_rdatatype_nsec3;
+ sigtype = RBTDB_RDATATYPE_SIGNSEC3;
+ wraps = ISC_TRUE;
+ } else {
+ type = dns_rdatatype_nsec;
+ sigtype = RBTDB_RDATATYPE_SIGNSEC;
+ wraps = ISC_FALSE;
+ }
+
+ again:
do {
node = NULL;
dns_fixedname_init(&fname);
* active rdataset at this node.
*/
empty_node = ISC_FALSE;
- if (header->type == dns_rdatatype_nsec) {
+ if (header->type == type) {
found = header;
if (foundsig != NULL)
break;
- } else if (header->type ==
- RBTDB_RDATATYPE_SIGNSEC) {
+ } else if (header->type == sigtype) {
foundsig = header;
if (found != NULL)
break;
}
}
if (!empty_node) {
- if (found != NULL &&
- (foundsig != NULL || !need_sig))
+ if (found != NULL && search->rbtversion->havensec3 &&
+ found->type == dns_rdatatype_nsec3 &&
+ !matchparams(found, search)) {
+ empty_node = ISC_TRUE;
+ found = NULL;
+ foundsig = NULL;
+ result = dns_rbtnodechain_prev(&search->chain,
+ NULL, NULL);
+ } else if (found != NULL &&
+ (foundsig != NULL || !need_sig))
{
/*
- * We've found the right NSEC record.
+ * We've found the right NSEC/NSEC3 record.
*
* Note: for this to really be the right
* NSEC record, it's essential that the NSEC
isc_rwlocktype_read);
} while (empty_node && result == ISC_R_SUCCESS);
+ if (result == ISC_R_NOMORE && wraps) {
+ result = dns_rbtnodechain_last(&search->chain, tree,
+ NULL, NULL);
+ if (result == ISC_R_SUCCESS) {
+ wraps = ISC_FALSE;
+ goto again;
+ }
+ }
+
/*
* If the result is ISC_R_NOMORE, then we got to the beginning of
* the database and didn't find a NSEC record. This shouldn't
isc_boolean_t active;
dns_rbtnodechain_t chain;
nodelock_t *lock;
-
+ dns_rbt_t *tree;
search.rbtdb = (dns_rbtdb_t *)db;
* encounter a callback node, zone_zonecut_callback() will search the
* rdatasets at the zone cut for active DNAME or NS rdatasets.
*/
- result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node,
+ tree = (options & DNS_DBFIND_FORCENSEC3) != 0 ? search.rbtdb->nsec3 :
+ search.rbtdb->tree;
+ result = dns_rbt_findnode(tree, name, foundname, &node,
&search.chain, DNS_RBTFIND_EMPTYDATA,
zone_zonecut_callback, &search);
* If we're here, then the name does not exist, is not
* beneath a zonecut, and there's no matching wildcard.
*/
- if (search.rbtdb->secure == dns_db_secure ||
- (search.options & DNS_DBFIND_FORCENSEC) != 0)
+ if ((search.rbtversion->secure &&
+ !search.rbtversion->havensec3) ||
+ (search.options & DNS_DBFIND_FORCENSEC) != 0 ||
+ (search.options & DNS_DBFIND_FORCENSEC3) != 0)
{
result = find_closest_nsec(&search, nodep, foundname,
- rdataset, sigrdataset,
- ISC_TRUE);
+ rdataset, sigrdataset, tree,
+ search.rbtversion->secure);
if (result == ISC_R_SUCCESS)
result = active ? DNS_R_EMPTYNAME :
DNS_R_NXDOMAIN;
break;
}
+
+ /*
+ * If the NSEC3 record doesn't match the chain
+ * we are using behave as if it isn't here.
+ */
+ if (header->type == dns_rdatatype_nsec3 &&
+ !matchparams(header, &search))
+ goto partial_match;
/*
* If we found a type we were looking for,
* remember it.
*/
if (!maybe_zonecut && found != NULL)
break;
- } else if (header->type == dns_rdatatype_nsec) {
+ } else if (header->type == dns_rdatatype_nsec &&
+ !search.rbtversion->havensec3) {
/*
* Remember a NSEC rdataset even if we're
* not specifically looking for it, because
* we might need it later.
*/
nsecheader = header;
- } else if (header->type == RBTDB_RDATATYPE_SIGNSEC) {
+ } else if (header->type == RBTDB_RDATATYPE_SIGNSEC &&
+ !search.rbtversion->havensec3) {
/*
* If we need the NSEC rdataset, we'll also
* need its signature.
* The desired type doesn't exist.
*/
result = DNS_R_NXRRSET;
- if (search.rbtdb->secure == dns_db_secure &&
+ if (search.rbtversion->secure &&
+ !search.rbtversion->havensec3 &&
(nsecheader == NULL || nsecsig == NULL)) {
/*
* The zone is secure but there's no NSEC,
NODE_UNLOCK(lock, isc_rwlocktype_read);
result = find_closest_nsec(&search, nodep, foundname,
rdataset, sigrdataset,
- search.rbtdb->secure ==
- dns_db_secure);
+ search.rbtdb->tree,
+ search.rbtversion->secure);
if (result == ISC_R_SUCCESS)
result = DNS_R_EMPTYWILD;
goto tree_exit;
new_reference(search.rbtdb, node);
*nodep = node;
}
- if (search.rbtdb->secure == dns_db_secure ||
+ if ((search.rbtversion->secure &&
+ !search.rbtversion->havensec3) ||
(search.options & DNS_DBFIND_FORCENSEC) != 0)
{
bind_rdataset(search.rbtdb, node, nsecheader,
* validated updates.
*/
if (type == dns_rdatatype_nsec ||
+ type == dns_rdatatype_nsec3 ||
type == dns_rdatatype_key)
result = ISC_R_SUCCESS;
else if (type == dns_rdatatype_any)
}
static isc_result_t
-createiterator(dns_db_t *db, isc_boolean_t relative_names,
- dns_dbiterator_t **iteratorp)
+createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp)
{
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
rbtdb_dbiterator_t *rbtdbiter;
rbtdbiter->common.methods = &dbiterator_methods;
rbtdbiter->common.db = NULL;
dns_db_attach(db, &rbtdbiter->common.db);
- rbtdbiter->common.relative_names = relative_names;
+ rbtdbiter->common.relative_names =
+ ISC_TF((options & DNS_DB_RELATIVENAMES) != 0);
rbtdbiter->common.magic = DNS_DBITERATOR_MAGIC;
rbtdbiter->common.cleaning = ISC_FALSE;
rbtdbiter->paused = ISC_TRUE;
dns_fixedname_init(&rbtdbiter->origin);
rbtdbiter->node = NULL;
rbtdbiter->delete = 0;
+ rbtdbiter->nsec3only = ISC_TF((options & DNS_DB_NSEC3ONLY) != 0);
+ rbtdbiter->nonsec3 = ISC_TF((options & DNS_DB_NONSEC3) != 0);
memset(rbtdbiter->deletions, 0, sizeof(rbtdbiter->deletions));
dns_rbtnodechain_init(&rbtdbiter->chain, db->mctx);
+ dns_rbtnodechain_init(&rbtdbiter->nsec3chain, db->mctx);
+ if (rbtdbiter->nsec3only)
+ rbtdbiter->current = &rbtdbiter->nsec3chain;
+ else
+ rbtdbiter->current = &rbtdbiter->chain;
*iteratorp = (dns_dbiterator_t *)rbtdbiter;
header->noqname = newheader->noqname;
newheader->noqname = NULL;
}
+ if (header->closest == NULL &&
+ newheader->closest != NULL) {
+ header->closest = newheader->closest;
+ newheader->closest = NULL;
+ }
free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
if (addedrdataset != NULL)
bind_rdataset(rbtdb, rbtnode, header, now,
header->noqname = newheader->noqname;
newheader->noqname = NULL;
}
+ if (header->closest == NULL &&
+ newheader->closest != NULL) {
+ header->closest = newheader->closest;
+ newheader->closest = NULL;
+ }
free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
if (addedrdataset != NULL)
bind_rdataset(rbtdb, rbtnode, header, now,
struct noqname *noqname;
isc_mem_t *mctx = rbtdb->common.mctx;
dns_name_t name;
- dns_rdataset_t nsec, nsecsig;
+ dns_rdataset_t neg, negsig;
isc_result_t result;
isc_region_t r;
dns_name_init(&name, NULL);
- dns_rdataset_init(&nsec);
- dns_rdataset_init(&nsecsig);
+ dns_rdataset_init(&neg);
+ dns_rdataset_init(&negsig);
- result = dns_rdataset_getnoqname(rdataset, &name, &nsec, &nsecsig);
+ result = dns_rdataset_getnoqname(rdataset, &name, &neg, &negsig);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
noqname = isc_mem_get(mctx, sizeof(*noqname));
goto cleanup;
}
dns_name_init(&noqname->name, NULL);
- noqname->nsec = NULL;
- noqname->nsecsig = NULL;
+ noqname->neg = NULL;
+ noqname->negsig = NULL;
+ noqname->type = neg.type;
result = dns_name_dup(&name, mctx, &noqname->name);
if (result != ISC_R_SUCCESS)
goto cleanup;
- result = dns_rdataslab_fromrdataset(&nsec, mctx, &r, 0);
+ result = dns_rdataslab_fromrdataset(&neg, mctx, &r, 0);
if (result != ISC_R_SUCCESS)
goto cleanup;
- noqname->nsec = r.base;
- result = dns_rdataslab_fromrdataset(&nsecsig, mctx, &r, 0);
+ noqname->neg = r.base;
+ result = dns_rdataslab_fromrdataset(&negsig, mctx, &r, 0);
if (result != ISC_R_SUCCESS)
goto cleanup;
- noqname->nsecsig = r.base;
- dns_rdataset_disassociate(&nsec);
- dns_rdataset_disassociate(&nsecsig);
+ noqname->negsig = r.base;
+ dns_rdataset_disassociate(&neg);
+ dns_rdataset_disassociate(&negsig);
newheader->noqname = noqname;
return (ISC_R_SUCCESS);
cleanup:
- dns_rdataset_disassociate(&nsec);
- dns_rdataset_disassociate(&nsecsig);
+ dns_rdataset_disassociate(&neg);
+ dns_rdataset_disassociate(&negsig);
free_noqname(mctx, &noqname);
return(result);
}
+static inline isc_result_t
+addclosest(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader,
+ dns_rdataset_t *rdataset)
+{
+ struct noqname *closest;
+ isc_mem_t *mctx = rbtdb->common.mctx;
+ dns_name_t name;
+ dns_rdataset_t neg, negsig;
+ isc_result_t result;
+ isc_region_t r;
+
+ dns_name_init(&name, NULL);
+ dns_rdataset_init(&neg);
+ dns_rdataset_init(&negsig);
+
+ result = dns_rdataset_getclosest(rdataset, &name, &neg, &negsig);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ closest = isc_mem_get(mctx, sizeof(*closest));
+ if (closest == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ dns_name_init(&closest->name, NULL);
+ closest->neg = NULL;
+ closest->negsig = NULL;
+ closest->type = neg.type;
+ result = dns_name_dup(&name, mctx, &closest->name);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ result = dns_rdataslab_fromrdataset(&neg, mctx, &r, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ closest->neg = r.base;
+ result = dns_rdataslab_fromrdataset(&negsig, mctx, &r, 0);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ closest->negsig = r.base;
+ dns_rdataset_disassociate(&neg);
+ dns_rdataset_disassociate(&negsig);
+ newheader->closest = closest;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ dns_rdataset_disassociate(&neg);
+ dns_rdataset_disassociate(&negsig);
+ free_noqname(mctx, &closest);
+ return(result);
+}
+
+static dns_dbmethods_t zone_methods;
+
static isc_result_t
addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
REQUIRE(VALID_RBTDB(rbtdb));
+ if (rbtdb->common.methods == &zone_methods)
+ REQUIRE(((rbtnode->nsec3 &&
+ (rdataset->type == dns_rdatatype_nsec3 ||
+ rdataset->covers == dns_rdatatype_nsec3)) ||
+ (!rbtnode->nsec3 &&
+ rdataset->type != dns_rdatatype_nsec3 &&
+ rdataset->covers != dns_rdatatype_nsec3)));
+
if (rbtversion == NULL) {
if (now == 0)
isc_stdtime_get(&now);
rdataset->covers);
newheader->attributes = 0;
newheader->noqname = NULL;
+ newheader->closest = NULL;
newheader->count = init_count++;
newheader->trust = rdataset->trust;
newheader->additional_auth = NULL;
if (rbtversion != NULL) {
newheader->serial = rbtversion->serial;
now = 0;
+
if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) {
newheader->attributes |= RDATASET_ATTR_RESIGN;
newheader->resign = rdataset->resign;
newheader->resign = 0;
if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
newheader->attributes |= RDATASET_ATTR_NXDOMAIN;
+ if ((rdataset->attributes & DNS_RDATASETATTR_OPTOUT) != 0)
+ newheader->attributes |= RDATASET_ATTR_OPTOUT;
if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) {
result = addnoqname(rbtdb, newheader, rdataset);
if (result != ISC_R_SUCCESS) {
return (result);
}
}
+ if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0) {
+ result = addclosest(rbtdb, newheader, rdataset);
+ if (result != ISC_R_SUCCESS) {
+ free_rdataset(rbtdb, rbtdb->common.mctx,
+ newheader);
+ return (result);
+ }
+ }
}
/*
* this is defered until closeversion() is called.
*/
if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
- rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
+ iszonesecure(db, version, rbtdb->origin_node);
return (result);
}
REQUIRE(VALID_RBTDB(rbtdb));
+ if (rbtdb->common.methods == &zone_methods)
+ REQUIRE(((rbtnode->nsec3 &&
+ (rdataset->type == dns_rdatatype_nsec3 ||
+ rdataset->covers == dns_rdatatype_nsec3)) ||
+ (!rbtnode->nsec3 &&
+ rdataset->type != dns_rdatatype_nsec3 &&
+ rdataset->covers != dns_rdatatype_nsec3)));
+
result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
®ion,
sizeof(rdatasetheader_t));
newheader->serial = rbtversion->serial;
newheader->trust = 0;
newheader->noqname = NULL;
+ newheader->closest = NULL;
newheader->count = init_count++;
newheader->additional_auth = NULL;
newheader->additional_glue = NULL;
newheader->trust = 0;
newheader->serial = rbtversion->serial;
newheader->noqname = NULL;
+ newheader->closest = NULL;
newheader->count = 0;
newheader->additional_auth = NULL;
newheader->additional_glue = NULL;
* this is defered until closeversion() is called.
*/
if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
- rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
+ iszonesecure(db, rbtdb->current_version, rbtdb->origin_node);
return (result);
}
newheader->attributes = RDATASET_ATTR_NONEXISTENT;
newheader->trust = 0;
newheader->noqname = NULL;
+ newheader->closest = NULL;
newheader->additional_auth = NULL;
newheader->additional_glue = NULL;
if (rbtversion != NULL)
* this is defered until closeversion() is called.
*/
if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
- rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
+ iszonesecure(db, rbtdb->current_version, rbtdb->origin_node);
return (result);
}
!IS_CACHE(rbtdb) && !dns_name_equal(name, &rbtdb->common.origin))
return (DNS_R_NOTZONETOP);
- add_empty_wildcards(rbtdb, name);
+ if (rdataset->type != dns_rdatatype_nsec3 &&
+ rdataset->covers != dns_rdatatype_nsec3)
+ add_empty_wildcards(rbtdb, name);
if (dns_name_iswildcard(name)) {
/*
*/
if (rdataset->type == dns_rdatatype_ns)
return (DNS_R_INVALIDNS);
+ /*
+ * NSEC3 record owners cannot legally be wild cards.
+ */
+ if (rdataset->type == dns_rdatatype_nsec3)
+ return (DNS_R_INVALIDNSEC3);
result = add_wildcard_magic(rbtdb, name);
if (result != ISC_R_SUCCESS)
return (result);
}
node = NULL;
- result = dns_rbt_addnode(rbtdb->tree, name, &node);
+ if (rdataset->type == dns_rdatatype_nsec3 ||
+ rdataset->covers == dns_rdatatype_nsec3) {
+ result = dns_rbt_addnode(rbtdb->nsec3, name, &node);
+ if (result == ISC_R_SUCCESS)
+ node->nsec3 = 1;
+ } else {
+ result = dns_rbt_addnode(rbtdb->tree, name, &node);
+ if (result == ISC_R_SUCCESS)
+ node->nsec3 = 0;
+ }
if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
return (result);
if (result != ISC_R_EXISTS) {
newheader->trust = rdataset->trust;
newheader->serial = 1;
newheader->noqname = NULL;
+ newheader->closest = NULL;
newheader->count = init_count++;
newheader->additional_auth = NULL;
newheader->additional_glue = NULL;
* zone key, we consider the zone secure.
*/
if (! IS_CACHE(rbtdb))
- rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
+ iszonesecure(db, rbtdb->current_version, rbtdb->origin_node);
*dbloadp = NULL;
REQUIRE(VALID_RBTDB(rbtdb));
RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
- secure = ISC_TF(rbtdb->secure == dns_db_secure);
+ secure = ISC_TF(rbtdb->current_version->secure == dns_db_secure);
RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
return (secure);
REQUIRE(VALID_RBTDB(rbtdb));
RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
- dnssec = ISC_TF(rbtdb->secure != dns_db_insecure);
+ dnssec = ISC_TF(rbtdb->current_version->secure != dns_db_insecure);
RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
return (dnssec);
*nodep = rbtdb->origin_node;
} else {
- INSIST(!IS_CACHE(rbtdb));
+ INSIST(IS_CACHE(rbtdb));
result = ISC_R_NOTFOUND;
}
return (result);
}
+static isc_result_t
+getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, dns_hash_t *hash,
+ isc_uint8_t *flags, isc_uint16_t *iterations,
+ unsigned char *salt, size_t *salt_length)
+{
+ dns_rbtdb_t *rbtdb;
+ isc_result_t result = ISC_R_NOTFOUND;
+ rbtdb_version_t *rbtversion = version;
+
+ rbtdb = (dns_rbtdb_t *)db;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+
+ if (rbtversion == NULL)
+ rbtversion = rbtdb->current_version;
+
+ if (rbtversion->havensec3) {
+ if (hash != NULL)
+ *hash = rbtversion->hash;
+ if (salt != NULL && salt_length != 0) {
+ REQUIRE(*salt_length > rbtversion->salt_length);
+ memcpy(salt, rbtversion->salt, rbtversion->salt_length);
+ }
+ if (salt_length != NULL)
+ *salt_length = rbtversion->salt_length;
+ if (iterations != NULL)
+ *iterations = rbtversion->iterations;
+ if (flags != NULL)
+ *flags = rbtversion->flags;
+ result = ISC_R_SUCCESS;
+ }
+ RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+
+ return (result);
+}
+
static isc_result_t
setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
settask,
getoriginnode,
NULL,
+ getnsec3parameters,
+ findnsec3node,
setsigningtime,
getsigningtime,
resigned,
NULL,
NULL,
NULL,
+ NULL,
+ NULL,
isdnssec,
getrrsetstats
};
}
/*
- * Make the Red-Black Tree.
+ * Make the Red-Black Trees.
*/
result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->tree);
if (result != ISC_R_SUCCESS) {
free_rbtdb(rbtdb, ISC_FALSE, NULL);
return (result);
}
+
+ result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->nsec3);
+ if (result != ISC_R_SUCCESS) {
+ free_rbtdb(rbtdb, ISC_FALSE, NULL);
+ return (result);
+ }
+
/*
* In order to set the node callback bit correctly in zone databases,
* we need to know if the node has the origin name of the zone.
free_rbtdb(rbtdb, ISC_FALSE, NULL);
return (result);
}
+ rbtdb->origin_node->nsec3 = 0;
/*
* We need to give the origin node the right locknum.
*/
return (result);
}
rbtdb->attributes = 0;
- rbtdb->secure = dns_db_insecure;
rbtdb->overmem = ISC_FALSE;
rbtdb->task = NULL;
free_rbtdb(rbtdb, ISC_FALSE, NULL);
return (ISC_R_NOMEMORY);
}
+ rbtdb->current_version->secure = ISC_FALSE;
+ rbtdb->current_version->havensec3 = ISC_FALSE;
+ rbtdb->current_version->flags = 0;
+ rbtdb->current_version->iterations = 0;
+ rbtdb->current_version->hash = 0;
+ rbtdb->current_version->salt_length = 0;
+ memset(rbtdb->current_version->salt, 0,
+ sizeof(rbtdb->current_version->salt));
rbtdb->future_version = NULL;
ISC_LIST_INIT(rbtdb->open_versions);
/*
attachnode(db, node, &cloned_node);
nsec->methods = &rdataset_methods;
nsec->rdclass = db->rdclass;
- nsec->type = dns_rdatatype_nsec;
+ nsec->type = noqname->type;
nsec->covers = 0;
nsec->ttl = rdataset->ttl;
nsec->trust = rdataset->trust;
nsec->private1 = rdataset->private1;
nsec->private2 = rdataset->private2;
- nsec->private3 = noqname->nsec;
+ nsec->private3 = noqname->neg;
nsec->privateuint4 = 0;
nsec->private5 = NULL;
nsec->private6 = NULL;
+ nsec->private7 = NULL;
cloned_node = NULL;
attachnode(db, node, &cloned_node);
nsecsig->methods = &rdataset_methods;
nsecsig->rdclass = db->rdclass;
nsecsig->type = dns_rdatatype_rrsig;
- nsecsig->covers = dns_rdatatype_nsec;
+ nsecsig->covers = noqname->type;
nsecsig->ttl = rdataset->ttl;
nsecsig->trust = rdataset->trust;
nsecsig->private1 = rdataset->private1;
nsecsig->private2 = rdataset->private2;
- nsecsig->private3 = noqname->nsecsig;
+ nsecsig->private3 = noqname->negsig;
nsecsig->privateuint4 = 0;
nsecsig->private5 = NULL;
nsec->private6 = NULL;
+ nsec->private7 = NULL;
dns_name_clone(&noqname->name, name);
return (ISC_R_SUCCESS);
}
+static isc_result_t
+rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
+ dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
+{
+ dns_db_t *db = rdataset->private1;
+ dns_dbnode_t *node = rdataset->private2;
+ dns_dbnode_t *cloned_node;
+ struct noqname *closest = rdataset->private7;
+
+ cloned_node = NULL;
+ attachnode(db, node, &cloned_node);
+ nsec->methods = &rdataset_methods;
+ nsec->rdclass = db->rdclass;
+ nsec->type = closest->type;
+ nsec->covers = 0;
+ nsec->ttl = rdataset->ttl;
+ nsec->trust = rdataset->trust;
+ nsec->private1 = rdataset->private1;
+ nsec->private2 = rdataset->private2;
+ nsec->private3 = closest->neg;
+ nsec->privateuint4 = 0;
+ nsec->private5 = NULL;
+ nsec->private6 = NULL;
+ nsec->private7 = NULL;
+
+ cloned_node = NULL;
+ attachnode(db, node, &cloned_node);
+ nsecsig->methods = &rdataset_methods;
+ nsecsig->rdclass = db->rdclass;
+ nsecsig->type = dns_rdatatype_rrsig;
+ nsecsig->covers = closest->type;
+ nsecsig->ttl = rdataset->ttl;
+ nsecsig->trust = rdataset->trust;
+ nsecsig->private1 = rdataset->private1;
+ nsecsig->private2 = rdataset->private2;
+ nsecsig->private3 = closest->negsig;
+ nsecsig->privateuint4 = 0;
+ nsecsig->private5 = NULL;
+ nsec->private6 = NULL;
+ nsec->private7 = NULL;
+
+ dns_name_clone(&closest->name, name);
+
+ return (ISC_R_SUCCESS);
+}
+
/*
* Rdataset Iterator Methods
*/
* record? Or is it too old in the cache?
*
* Note: unlike everywhere else, we
- * check for now > header->ttl instead
- * of now >= header->ttl. This allows
+ * check for now > header->rdh_ttl instead
+ * of now >= header->rdh_ttl. This allows
* ANY and RRSIG queries for 0 TTL
* rdatasets to work.
*/
dns_db_detach(&rbtdbiter->common.db);
dns_rbtnodechain_reset(&rbtdbiter->chain);
+ dns_rbtnodechain_reset(&rbtdbiter->nsec3chain);
isc_mem_put(db->mctx, rbtdbiter, sizeof(*rbtdbiter));
dns_db_detach(&db);
name = dns_fixedname_name(&rbtdbiter->name);
origin = dns_fixedname_name(&rbtdbiter->origin);
dns_rbtnodechain_reset(&rbtdbiter->chain);
+ dns_rbtnodechain_reset(&rbtdbiter->nsec3chain);
- result = dns_rbtnodechain_first(&rbtdbiter->chain, rbtdb->tree, name,
- origin);
-
+ if (rbtdbiter->nsec3only) {
+ rbtdbiter->current = &rbtdbiter->nsec3chain;
+ result = dns_rbtnodechain_first(rbtdbiter->current,
+ rbtdb->nsec3, name, origin);
+ } else {
+ rbtdbiter->current = &rbtdbiter->chain;
+ result = dns_rbtnodechain_first(rbtdbiter->current,
+ rbtdb->tree, name, origin);
+ if (!rbtdbiter->nonsec3 && result == ISC_R_NOTFOUND) {
+ rbtdbiter->current = &rbtdbiter->nsec3chain;
+ result = dns_rbtnodechain_first(rbtdbiter->current,
+ rbtdb->nsec3, name,
+ origin);
+ }
+ }
if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
- result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
+ result = dns_rbtnodechain_current(rbtdbiter->current, NULL,
NULL, &rbtdbiter->node);
if (result == ISC_R_SUCCESS) {
rbtdbiter->new_origin = ISC_TRUE;
name = dns_fixedname_name(&rbtdbiter->name);
origin = dns_fixedname_name(&rbtdbiter->origin);
dns_rbtnodechain_reset(&rbtdbiter->chain);
+ dns_rbtnodechain_reset(&rbtdbiter->nsec3chain);
- result = dns_rbtnodechain_last(&rbtdbiter->chain, rbtdb->tree, name,
- origin);
+ result = ISC_R_NOTFOUND;
+ if (rbtdbiter->nsec3only && !rbtdbiter->nonsec3) {
+ rbtdbiter->current = &rbtdbiter->nsec3chain;
+ result = dns_rbtnodechain_last(rbtdbiter->current,
+ rbtdb->nsec3, name, origin);
+ }
+ if (!rbtdbiter->nsec3only && result == ISC_R_NOTFOUND) {
+ rbtdbiter->current = &rbtdbiter->chain;
+ result = dns_rbtnodechain_last(rbtdbiter->current, rbtdb->tree,
+ name, origin);
+ }
if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
- result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
+ result = dns_rbtnodechain_current(rbtdbiter->current, NULL,
NULL, &rbtdbiter->node);
if (result == ISC_R_SUCCESS) {
rbtdbiter->new_origin = ISC_TRUE;
dns_name_t *iname, *origin;
if (rbtdbiter->result != ISC_R_SUCCESS &&
+ rbtdbiter->result != ISC_R_NOTFOUND &&
rbtdbiter->result != ISC_R_NOMORE)
return (rbtdbiter->result);
iname = dns_fixedname_name(&rbtdbiter->name);
origin = dns_fixedname_name(&rbtdbiter->origin);
dns_rbtnodechain_reset(&rbtdbiter->chain);
+ dns_rbtnodechain_reset(&rbtdbiter->nsec3chain);
+
+ if (rbtdbiter->nsec3only) {
+ rbtdbiter->current = &rbtdbiter->nsec3chain;
+ result = dns_rbt_findnode(rbtdb->nsec3, name, NULL,
+ &rbtdbiter->node,
+ rbtdbiter->current,
+ DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+ } else if (rbtdbiter->nonsec3) {
+ rbtdbiter->current = &rbtdbiter->chain;
+ result = dns_rbt_findnode(rbtdb->tree, name, NULL,
+ &rbtdbiter->node,
+ rbtdbiter->current,
+ DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+ } else {
+ /*
+ * Stay on main chain if not found on either chain.
+ */
+ rbtdbiter->current = &rbtdbiter->chain;
+ result = dns_rbt_findnode(rbtdb->tree, name, NULL,
+ &rbtdbiter->node,
+ rbtdbiter->current,
+ DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+ if (result == DNS_R_PARTIALMATCH) {
+ dns_rbtnode_t *node = NULL;
+ result = dns_rbt_findnode(rbtdb->nsec3, name, NULL,
+ &node, &rbtdbiter->nsec3chain,
+ DNS_RBTFIND_EMPTYDATA,
+ NULL, NULL);
+ if (result == ISC_R_SUCCESS) {
+ rbtdbiter->node = node;
+ rbtdbiter->current = &rbtdbiter->nsec3chain;
+ }
+ }
+ }
- result = dns_rbt_findnode(rbtdb->tree, name, NULL, &rbtdbiter->node,
- &rbtdbiter->chain, DNS_RBTFIND_EMPTYDATA,
- NULL, NULL);
+#if 1
if (result == ISC_R_SUCCESS) {
- result = dns_rbtnodechain_current(&rbtdbiter->chain, iname,
+ result = dns_rbtnodechain_current(rbtdbiter->current, iname,
origin, NULL);
if (result == ISC_R_SUCCESS) {
rbtdbiter->new_origin = ISC_TRUE;
reference_iter_node(rbtdbiter);
}
-
- } else if (result == DNS_R_PARTIALMATCH)
+ } else if (result == DNS_R_PARTIALMATCH) {
result = ISC_R_NOTFOUND;
+ rbtdbiter->node = NULL;
+ }
rbtdbiter->result = result;
+#else
+ if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
+ isc_result_t tresult;
+ tresult = dns_rbtnodechain_current(rbtdbiter->current, iname,
+ origin, NULL);
+ if (tresult == ISC_R_SUCCESS) {
+ rbtdbiter->new_origin = ISC_TRUE;
+ reference_iter_node(rbtdbiter);
+ } else {
+ result = tresult;
+ rbtdbiter->node = NULL;
+ }
+ } else
+ rbtdbiter->node = NULL;
+
+ rbtdbiter->result = (result == DNS_R_PARTIALMATCH) ?
+ ISC_R_SUCCESS : result;
+#endif
return (result);
}
isc_result_t result;
rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
dns_name_t *name, *origin;
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
REQUIRE(rbtdbiter->node != NULL);
name = dns_fixedname_name(&rbtdbiter->name);
origin = dns_fixedname_name(&rbtdbiter->origin);
- result = dns_rbtnodechain_prev(&rbtdbiter->chain, name, origin);
+ result = dns_rbtnodechain_prev(rbtdbiter->current, name, origin);
+ if (result == ISC_R_NOMORE && !rbtdbiter->nsec3only &&
+ !rbtdbiter->nonsec3 &&
+ &rbtdbiter->nsec3chain == rbtdbiter->current) {
+ rbtdbiter->current = &rbtdbiter->chain;
+ dns_rbtnodechain_reset(rbtdbiter->current);
+ result = dns_rbtnodechain_last(rbtdbiter->current, rbtdb->tree,
+ name, origin);
+ if (result == ISC_R_NOTFOUND)
+ result = ISC_R_NOMORE;
+ }
dereference_iter_node(rbtdbiter);
if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
rbtdbiter->new_origin = ISC_TF(result == DNS_R_NEWORIGIN);
- result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
+ result = dns_rbtnodechain_current(rbtdbiter->current, NULL,
NULL, &rbtdbiter->node);
}
isc_result_t result;
rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
dns_name_t *name, *origin;
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
REQUIRE(rbtdbiter->node != NULL);
name = dns_fixedname_name(&rbtdbiter->name);
origin = dns_fixedname_name(&rbtdbiter->origin);
- result = dns_rbtnodechain_next(&rbtdbiter->chain, name, origin);
+ result = dns_rbtnodechain_next(rbtdbiter->current, name, origin);
+ if (result == ISC_R_NOMORE && !rbtdbiter->nsec3only &&
+ !rbtdbiter->nonsec3 && &rbtdbiter->chain == rbtdbiter->current) {
+ rbtdbiter->current = &rbtdbiter->nsec3chain;
+ dns_rbtnodechain_reset(rbtdbiter->current);
+ result = dns_rbtnodechain_first(rbtdbiter->current,
+ rbtdb->nsec3, name, origin);
+ if (result == ISC_R_NOTFOUND)
+ result = ISC_R_NOMORE;
+ }
dereference_iter_node(rbtdbiter);
if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
rbtdbiter->new_origin = ISC_TF(result == DNS_R_NEWORIGIN);
- result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
+ result = dns_rbtnodechain_current(rbtdbiter->current, NULL,
NULL, &rbtdbiter->node);
}
if (result == ISC_R_SUCCESS)
return (ISC_R_SUCCESS);
- fail:
+ fail:
if (newcbarg != NULL) {
if (newentry != NULL) {
acache_cancelentry(rbtdb->common.mctx, newentry,
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rcode.c,v 1.6 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: rcode.c,v 1.7 2008/09/24 02:46:22 marka Exp $ */
#include <config.h>
#include <ctype.h>
#define ERCODENAMES \
/* extended rcodes */ \
{ dns_rcode_badvers, "BADVERS", 0}, \
- { 0, NULL, 0 }
+ { 0, NULL, 0 }
#define TSIGRCODENAMES \
/* extended rcodes */ \
{ DNS_KEYALG_RSAMD5, "RSA", 0 }, \
{ DNS_KEYALG_DH, "DH", 0 }, \
{ DNS_KEYALG_DSA, "DSA", 0 }, \
+ { DNS_KEYALG_NSEC3DSA, "NSEC3DSA", 0 }, \
{ DNS_KEYALG_ECC, "ECC", 0 }, \
{ DNS_KEYALG_RSASHA1, "RSASHA1", 0 }, \
+ { DNS_KEYALG_NSEC3RSASHA1, "NSEC3RSASHA1", 0 }, \
{ DNS_KEYALG_INDIRECT, "INDIRECT", 0 }, \
{ DNS_KEYALG_PRIVATEDNS, "PRIVATEDNS", 0 }, \
{ DNS_KEYALG_PRIVATEOID, "PRIVATEOID", 0 }, \
{ 255, "ALL", 0 }, \
{ 0, NULL, 0}
+#define HASHALGNAMES \
+ { 1, "SHA-1", 0 }, \
+ { 0, NULL, 0 }
+
struct tbl {
unsigned int value;
const char *name;
static struct tbl certs[] = { CERTNAMES };
static struct tbl secalgs[] = { SECALGNAMES };
static struct tbl secprotos[] = { SECPROTONAMES };
+static struct tbl hashalgs[] = { HASHALGNAMES };
static struct keyflag {
const char *name;
static isc_result_t
dns_mnemonic_totext(unsigned int value, isc_buffer_t *target,
- struct tbl *table)
+ struct tbl *table)
{
int i = 0;
char buf[sizeof("4294967296")];
RETERR(dns_mnemonic_fromtext(&value, source, tsigrcodes, 0xffff));
*rcodep = value;
return (ISC_R_SUCCESS);
-}
+}
isc_result_t
dns_tsigrcode_totext(dns_rcode_t rcode, isc_buffer_t *target) {
return (dns_mnemonic_totext(secproto, target, secprotos));
}
+isc_result_t
+dns_hashalg_fromtext(unsigned char *hashalg, isc_textregion_t *source) {
+ unsigned int value;
+ RETERR(dns_mnemonic_fromtext(&value, source, hashalgs, 0xff));
+ *hashalg = value;
+ return (ISC_R_SUCCESS);
+}
+
isc_result_t
dns_keyflags_fromtext(dns_keyflags_t *flagsp, isc_textregion_t *source)
{
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rdata.c,v 1.198 2008/04/01 23:47:10 tbox Exp $ */
+/* $Id: rdata.c,v 1.199 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
static isc_uint8_t
uint8_fromregion(isc_region_t *region);
+static isc_uint8_t
+uint8_consume_fromregion(isc_region_t *region);
+
static isc_result_t
mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
warn_badmx(isc_token_t *token, isc_lex_t *lexer,
dns_rdatacallbacks_t *callbacks);
+static isc_uint16_t
+uint16_consume_fromregion(isc_region_t *region);
+
static inline int
getquad(const void *src, struct in_addr *dst,
isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks)
return(value);
}
+static isc_uint16_t
+uint16_consume_fromregion(isc_region_t *region) {
+ isc_uint16_t r = uint16_fromregion(region);
+
+ isc_region_consume(region, 2);
+ return r;
+}
+
static isc_uint16_t
uint16_fromregion(isc_region_t *region) {
return (region->base[0]);
}
+static isc_uint8_t
+uint8_consume_fromregion(isc_region_t *region) {
+ isc_uint8_t r = uint8_fromregion(region);
+
+ isc_region_consume(region, 1);
+ return r;
+}
+
static isc_result_t
mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
isc_region_t tr;
--- /dev/null
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 2004 Nominet, Ltd.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND NOMINET DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* RFC 5155 */
+
+#ifndef RDATA_GENERIC_NSEC3_50_C
+#define RDATA_GENERIC_NSEC3_50_C
+
+#include <isc/iterated_hash.h>
+#include <isc/base32.h>
+
+#define RRTYPE_NSEC3_ATTRIBUTES DNS_RDATATYPEATTR_DNSSEC
+
+static inline isc_result_t
+fromtext_nsec3(ARGS_FROMTEXT) {
+ isc_token_t token;
+ unsigned char bm[8*1024]; /* 64k bits */
+ dns_rdatatype_t covered;
+ int octet;
+ int window;
+ unsigned int flags;
+ unsigned char hashalg;
+ isc_buffer_t b;
+
+ REQUIRE(type == 50);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+ UNUSED(origin);
+ UNUSED(options);
+
+ /* Hash. */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_hashalg_fromtext(&hashalg, &token.value.as_textregion));
+ RETERR(uint8_tobuffer(hashalg, target));
+
+ /* Flags. */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ flags = token.value.as_ulong;
+ if (flags > 255U)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint8_tobuffer(flags, target));
+
+ /* Iterations. */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /* salt */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ if (token.value.as_textregion.length > (255*2))
+ RETTOK(DNS_R_TEXTTOOLONG);
+ if (strcmp(DNS_AS_STR(token), "-") == 0) {
+ RETERR(uint8_tobuffer(0, target));
+ } else {
+ RETERR(uint8_tobuffer(strlen(DNS_AS_STR(token)) / 2, target));
+ RETERR(isc_hex_decodestring(DNS_AS_STR(token), target));
+ }
+
+ /*
+ * Next hash a single base32hex word.
+ */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ isc_buffer_init(&b, bm, sizeof(bm));
+ RETTOK(isc_base32hex_decodestring(DNS_AS_STR(token), &b));
+ if (isc_buffer_usedlength(&b) > 0xffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint8_tobuffer(isc_buffer_usedlength(&b), target));
+ RETERR(mem_tobuffer(target, &bm, isc_buffer_usedlength(&b)));
+
+ memset(bm, 0, sizeof(bm));
+ do {
+ RETERR(isc_lex_getmastertoken(lexer, &token,
+ isc_tokentype_string, ISC_TRUE));
+ if (token.type != isc_tokentype_string)
+ break;
+ RETTOK(dns_rdatatype_fromtext(&covered,
+ &token.value.as_textregion));
+ bm[covered/8] |= (0x80>>(covered%8));
+ } while (1);
+ isc_lex_ungettoken(lexer, &token);
+ for (window = 0; window < 256 ; window++) {
+ /*
+ * Find if we have a type in this window.
+ */
+ for (octet = 31; octet >= 0; octet--)
+ if (bm[window * 32 + octet] != 0)
+ break;
+ if (octet < 0)
+ continue;
+ RETERR(uint8_tobuffer(window, target));
+ RETERR(uint8_tobuffer(octet + 1, target));
+ RETERR(mem_tobuffer(target, &bm[window * 32], octet + 1));
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_nsec3(ARGS_TOTEXT) {
+ isc_region_t sr;
+ unsigned int i, j, k;
+ unsigned int window, len;
+ unsigned char hash;
+ unsigned char flags;
+ char buf[sizeof("65535 ")];
+ isc_uint32_t iterations;
+
+ REQUIRE(rdata->type == 50);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(tctx);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ hash = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+
+ flags = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+
+ iterations = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ sprintf(buf, "%u ", hash);
+ RETERR(str_totext(buf, target));
+
+ sprintf(buf, "%u ", flags);
+ RETERR(str_totext(buf, target));
+
+ sprintf(buf, "%u ", iterations);
+ RETERR(str_totext(buf, target));
+
+ j = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+ INSIST(j <= sr.length);
+
+ if (j != 0) {
+ i = sr.length;
+ sr.length = j;
+ RETERR(isc_hex_totext(&sr, 1, "", target));
+ sr.length = i - j;
+ RETERR(str_totext(" ", target));
+ } else
+ RETERR(str_totext("- ", target));
+
+ j = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+ INSIST(j <= sr.length);
+
+ i = sr.length;
+ sr.length = j;
+ RETERR(isc_base32hex_totext(&sr, 1, "", target));
+ sr.length = i - j;
+
+ for (i = 0; i < sr.length; i += len) {
+ INSIST(i + 2 <= sr.length);
+ window = sr.base[i];
+ len = sr.base[i + 1];
+ INSIST(len > 0 && len <= 32);
+ i += 2;
+ INSIST(i + len <= sr.length);
+ for (j = 0; j < len; j++) {
+ dns_rdatatype_t t;
+ if (sr.base[i + j] == 0)
+ continue;
+ for (k = 0; k < 8; k++) {
+ if ((sr.base[i + j] & (0x80 >> k)) == 0)
+ continue;
+ t = window * 256 + j * 8 + k;
+ RETERR(str_totext(" ", target));
+ if (dns_rdatatype_isknown(t)) {
+ RETERR(dns_rdatatype_totext(t, target));
+ } else {
+ char buf[sizeof("TYPE65535")];
+ sprintf(buf, "TYPE%u", t);
+ RETERR(str_totext(buf, target));
+ }
+ }
+ }
+ }
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_nsec3(ARGS_FROMWIRE) {
+ isc_region_t sr, rr;
+ unsigned int window, lastwindow = 0;
+ unsigned int len;
+ unsigned int saltlen, hashlen;
+ isc_boolean_t first = ISC_TRUE;
+ unsigned int i;
+
+ REQUIRE(type == 50);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(options);
+ UNUSED(dctx);
+
+ isc_buffer_activeregion(source, &sr);
+ rr = sr;
+
+ /* hash(1), flags(1), interation(2), saltlen(1) */
+ if (sr.length < 5U)
+ RETERR(DNS_R_FORMERR);
+ saltlen = sr.base[4];
+ isc_region_consume(&sr, 5);
+
+ if (sr.length < saltlen)
+ RETERR(DNS_R_FORMERR);
+ isc_region_consume(&sr, saltlen);
+
+ if (sr.length < 1U)
+ RETERR(DNS_R_FORMERR);
+ hashlen = sr.base[0];
+ isc_region_consume(&sr, 1);
+
+ if (sr.length < hashlen)
+ RETERR(DNS_R_FORMERR);
+ isc_region_consume(&sr, hashlen);
+
+ for (i = 0; i < sr.length; i += len) {
+ /*
+ * Check for overflow.
+ */
+ if (i + 2 > sr.length)
+ RETERR(DNS_R_FORMERR);
+ window = sr.base[i];
+ len = sr.base[i + 1];
+ i += 2;
+ /*
+ * Check that bitmap windows are in the correct order.
+ */
+ if (!first && window <= lastwindow)
+ RETERR(DNS_R_FORMERR);
+ /*
+ * Check for legal lengths.
+ */
+ if (len < 1 || len > 32)
+ RETERR(DNS_R_FORMERR);
+ /*
+ * Check for overflow.
+ */
+ if (i + len > sr.length)
+ RETERR(DNS_R_FORMERR);
+ /*
+ * The last octet of the bitmap must be non zero.
+ */
+ if (sr.base[i + len - 1] == 0)
+ RETERR(DNS_R_FORMERR);
+ lastwindow = window;
+ first = ISC_FALSE;
+ }
+ if (i != sr.length)
+ return (DNS_R_EXTRADATA);
+ RETERR(mem_tobuffer(target, rr.base, rr.length));
+ isc_buffer_forward(source, rr.length);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+towire_nsec3(ARGS_TOWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(rdata->type == 50);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(cctx);
+
+ dns_rdata_toregion(rdata, &sr);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_nsec3(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 50);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_nsec3(ARGS_FROMSTRUCT) {
+ dns_rdata_nsec3_t *nsec3 = source;
+ unsigned int i, len, window, lastwindow = 0;
+ isc_boolean_t first = ISC_TRUE;
+
+ REQUIRE(type == 50);
+ REQUIRE(source != NULL);
+ REQUIRE(nsec3->common.rdtype == type);
+ REQUIRE(nsec3->common.rdclass == rdclass);
+ REQUIRE(nsec3->typebits != NULL || nsec3->len == 0);
+ REQUIRE(nsec3->hash == dns_hash_sha1);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint8_tobuffer(nsec3->hash, target));
+ RETERR(uint8_tobuffer(nsec3->flags, target));
+ RETERR(uint16_tobuffer(nsec3->iterations, target));
+ RETERR(uint8_tobuffer(nsec3->salt_length, target));
+ RETERR(mem_tobuffer(target, nsec3->salt, nsec3->salt_length));
+ RETERR(uint8_tobuffer(nsec3->next_length, target));
+ RETERR(mem_tobuffer(target, nsec3->next, nsec3->next_length));
+
+ /*
+ * Perform sanity check.
+ */
+ for (i = 0; i < nsec3->len ; i += len) {
+ INSIST(i + 2 <= nsec3->len);
+ window = nsec3->typebits[i];
+ len = nsec3->typebits[i+1];
+ i += 2;
+ INSIST(first || window > lastwindow);
+ INSIST(len > 0 && len <= 32);
+ INSIST(i + len <= nsec3->len);
+ INSIST(nsec3->typebits[i + len - 1] != 0);
+ lastwindow = window;
+ first = ISC_FALSE;
+ }
+ return (mem_tobuffer(target, nsec3->typebits, nsec3->len));
+}
+
+static inline isc_result_t
+tostruct_nsec3(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_nsec3_t *nsec3 = target;
+
+ REQUIRE(rdata->type == 50);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ nsec3->common.rdclass = rdata->rdclass;
+ nsec3->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&nsec3->common, link);
+
+ region.base = rdata->data;
+ region.length = rdata->length;
+ nsec3->hash = uint8_consume_fromregion(®ion);
+ nsec3->flags = uint8_consume_fromregion(®ion);
+ nsec3->iterations = uint16_consume_fromregion(®ion);
+
+ nsec3->salt_length = uint8_consume_fromregion(®ion);
+ nsec3->salt = mem_maybedup(mctx, region.base, nsec3->salt_length);
+ if (nsec3->salt == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_region_consume(®ion, nsec3->salt_length);
+
+ nsec3->next_length = uint8_consume_fromregion(®ion);
+ nsec3->next = mem_maybedup(mctx, region.base, nsec3->next_length);
+ if (nsec3->next == NULL)
+ goto cleanup;
+ isc_region_consume(®ion, nsec3->next_length);
+
+ nsec3->len = region.length;
+ nsec3->typebits = mem_maybedup(mctx, region.base, region.length);
+ if (nsec3->typebits == NULL)
+ goto cleanup;
+
+ nsec3->mctx = mctx;
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (nsec3->next != NULL)
+ isc_mem_free(mctx, nsec3->next);
+ isc_mem_free(mctx, nsec3->salt);
+ return (ISC_R_NOMEMORY);
+}
+
+static inline void
+freestruct_nsec3(ARGS_FREESTRUCT) {
+ dns_rdata_nsec3_t *nsec3 = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(nsec3->common.rdtype == 50);
+
+ if (nsec3->mctx == NULL)
+ return;
+
+ if (nsec3->salt != NULL)
+ isc_mem_free(nsec3->mctx, nsec3->salt);
+ if (nsec3->next != NULL)
+ isc_mem_free(nsec3->mctx, nsec3->next);
+ if (nsec3->typebits != NULL)
+ isc_mem_free(nsec3->mctx, nsec3->typebits);
+ nsec3->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_nsec3(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 50);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_nsec3(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 50);
+
+ dns_rdata_toregion(rdata, &r);
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_nsec3(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 50);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_nsec3(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 50);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_NSEC3_50_C */
--- /dev/null
+/*
+ * Copyright (C) 2004 Nominet, Ltd.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND NOMINET DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef GENERIC_NSEC3_50_H
+#define GENERIC_NSEC3_50_H 1
+
+/* $Id: nsec3_50.h,v 1.3 2008/09/24 02:46:23 marka Exp $ */
+
+/*!
+ * \brief Per RFC 5155 */
+
+#include <isc/iterated_hash.h>
+
+typedef struct dns_rdata_nsec3 {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_hash_t hash;
+ unsigned char flags;
+ dns_iterations_t iterations;
+ unsigned char salt_length;
+ unsigned char next_length;
+ isc_uint16_t len;
+ unsigned char *salt;
+ unsigned char *next;
+ unsigned char *typebits;
+} dns_rdata_nsec3_t;
+
+/*
+ * The corresponding NSEC3 interval is OPTOUT indicating possible
+ * insecure delegations.
+ */
+#define DNS_NSEC3FLAG_OPTOUT 0x01U
+
+/*%
+ * Non-standard, NSEC3PARAM only.
+ *
+ * Create a corresponding NSEC3 chain.
+ * Once the NSEC3 chain is complete this flag will be removed to signal
+ * that there is a complete chain.
+ *
+ * This flag is automatically set when a NSEC3PARAM record is added to
+ * the zone via UPDATE.
+ *
+ * NSEC3PARAM records with this flag set are supposed to be ignored by
+ * RFC 5155 compliant nameservers.
+ */
+#define DNS_NSEC3FLAG_CREATE 0x80U
+
+/*%
+ * Non-standard, NSEC3PARAM only.
+ *
+ * The corresponding NSEC3 set is to be removed once the NSEC chain
+ * has been generated.
+ *
+ * This flag is automatically set when the last active NSEC3PARAM record
+ * is removed from the zone via UPDATE.
+ *
+ * NSEC3PARAM records with this flag set are supposed to be ignored by
+ * RFC 5155 compliant nameservers.
+ */
+#define DNS_NSEC3FLAG_REMOVE 0x40U
+
+/*%
+ * Non-standard, NSEC3PARAM only.
+ *
+ * Used to identify NSEC3PARAM records added in this UPDATE request.
+ */
+#define DNS_NSEC3FLAG_UPDATE 0x20U
+
+/*%
+ * Non-standard, NSEC3PARAM only.
+ *
+ * Prevent the creation of a NSEC chain before the last NSEC3 chain
+ * is removed. This will normally only be set when the zone is
+ * transitioning from secure with NSEC3 chains to insecure.
+ */
+#define DNS_NSEC3FLAG_NONSEC 0x10U
+
+#endif /* GENERIC_NSEC3_50_H */
--- /dev/null
+/*
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 2004 Nominet, Ltd.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND NOMINET DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* RFC 5155 */
+
+#ifndef RDATA_GENERIC_NSEC3PARAM_51_C
+#define RDATA_GENERIC_NSEC3PARAM_51_C
+
+#include <isc/iterated_hash.h>
+#include <isc/base32.h>
+
+#define RRTYPE_NSEC3PARAM_ATTRIBUTES (DNS_RDATATYPEATTR_DNSSEC)
+
+static inline isc_result_t
+fromtext_nsec3param(ARGS_FROMTEXT) {
+ isc_token_t token;
+ unsigned int flags = 0;
+ unsigned char hashalg;
+
+ REQUIRE(type == 51);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(callbacks);
+ UNUSED(origin);
+ UNUSED(options);
+
+ /* Hash. */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ RETTOK(dns_hashalg_fromtext(&hashalg, &token.value.as_textregion));
+ RETERR(uint8_tobuffer(hashalg, target));
+
+ /* Flags. */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ flags = token.value.as_ulong;
+ if (flags > 255U)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint8_tobuffer(flags, target));
+
+ /* Iterations. */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
+ ISC_FALSE));
+ if (token.value.as_ulong > 0xffffU)
+ RETTOK(ISC_R_RANGE);
+ RETERR(uint16_tobuffer(token.value.as_ulong, target));
+
+ /* Salt. */
+ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+ ISC_FALSE));
+ if (token.value.as_textregion.length > (255*2))
+ RETTOK(DNS_R_TEXTTOOLONG);
+ if (strcmp(DNS_AS_STR(token), "-") == 0) {
+ RETERR(uint8_tobuffer(0, target));
+ } else {
+ RETERR(uint8_tobuffer(strlen(DNS_AS_STR(token)) / 2, target));
+ RETERR(isc_hex_decodestring(DNS_AS_STR(token), target));
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+totext_nsec3param(ARGS_TOTEXT) {
+ isc_region_t sr;
+ unsigned int i, j;
+ unsigned char hash;
+ unsigned char flags;
+ char buf[sizeof("65535 ")];
+ isc_uint32_t iterations;
+
+ REQUIRE(rdata->type == 51);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(tctx);
+
+ dns_rdata_toregion(rdata, &sr);
+
+ hash = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+
+ flags = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+
+ iterations = uint16_fromregion(&sr);
+ isc_region_consume(&sr, 2);
+
+ sprintf(buf, "%u ", hash);
+ RETERR(str_totext(buf, target));
+
+ sprintf(buf, "%u ", flags);
+ RETERR(str_totext(buf, target));
+
+ sprintf(buf, "%u ", iterations);
+ RETERR(str_totext(buf, target));
+
+ j = uint8_fromregion(&sr);
+ isc_region_consume(&sr, 1);
+ INSIST(j <= sr.length);
+
+ if (j != 0) {
+ i = sr.length;
+ sr.length = j;
+ RETERR(isc_hex_totext(&sr, 1, "", target));
+ sr.length = i - j;
+ } else
+ RETERR(str_totext("-", target));
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+fromwire_nsec3param(ARGS_FROMWIRE) {
+ isc_region_t sr, rr;
+ unsigned int saltlen;
+
+ REQUIRE(type == 51);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(options);
+ UNUSED(dctx);
+
+ isc_buffer_activeregion(source, &sr);
+ rr = sr;
+
+ /* hash(1), flags(1), interations(2), saltlen(1) */
+ if (sr.length < 5U)
+ RETERR(DNS_R_FORMERR);
+ saltlen = sr.base[4];
+ isc_region_consume(&sr, 5);
+
+ if (sr.length < saltlen)
+ RETERR(DNS_R_FORMERR);
+ isc_region_consume(&sr, saltlen);
+ RETERR(mem_tobuffer(target, rr.base, rr.length));
+ isc_buffer_forward(source, rr.length);
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+towire_nsec3param(ARGS_TOWIRE) {
+ isc_region_t sr;
+
+ REQUIRE(rdata->type == 51);
+ REQUIRE(rdata->length != 0);
+
+ UNUSED(cctx);
+
+ dns_rdata_toregion(rdata, &sr);
+ return (mem_tobuffer(target, sr.base, sr.length));
+}
+
+static inline int
+compare_nsec3param(ARGS_COMPARE) {
+ isc_region_t r1;
+ isc_region_t r2;
+
+ REQUIRE(rdata1->type == rdata2->type);
+ REQUIRE(rdata1->rdclass == rdata2->rdclass);
+ REQUIRE(rdata1->type == 51);
+ REQUIRE(rdata1->length != 0);
+ REQUIRE(rdata2->length != 0);
+
+ dns_rdata_toregion(rdata1, &r1);
+ dns_rdata_toregion(rdata2, &r2);
+ return (isc_region_compare(&r1, &r2));
+}
+
+static inline isc_result_t
+fromstruct_nsec3param(ARGS_FROMSTRUCT) {
+ dns_rdata_nsec3param_t *nsec3param = source;
+
+ REQUIRE(type == 51);
+ REQUIRE(source != NULL);
+ REQUIRE(nsec3param->common.rdtype == type);
+ REQUIRE(nsec3param->common.rdclass == rdclass);
+
+ UNUSED(type);
+ UNUSED(rdclass);
+
+ RETERR(uint8_tobuffer(nsec3param->hash, target));
+ RETERR(uint8_tobuffer(nsec3param->flags, target));
+ RETERR(uint16_tobuffer(nsec3param->iterations, target));
+ RETERR(uint8_tobuffer(nsec3param->salt_length, target));
+ RETERR(mem_tobuffer(target, nsec3param->salt,
+ nsec3param->salt_length));
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+tostruct_nsec3param(ARGS_TOSTRUCT) {
+ isc_region_t region;
+ dns_rdata_nsec3param_t *nsec3param = target;
+
+ REQUIRE(rdata->type == 51);
+ REQUIRE(target != NULL);
+ REQUIRE(rdata->length != 0);
+
+ nsec3param->common.rdclass = rdata->rdclass;
+ nsec3param->common.rdtype = rdata->type;
+ ISC_LINK_INIT(&nsec3param->common, link);
+
+ region.base = rdata->data;
+ region.length = rdata->length;
+ nsec3param->hash = uint8_consume_fromregion(®ion);
+ nsec3param->flags = uint8_consume_fromregion(®ion);
+ nsec3param->iterations = uint16_consume_fromregion(®ion);
+
+ nsec3param->salt_length = uint8_consume_fromregion(®ion);
+ nsec3param->salt = mem_maybedup(mctx, region.base,
+ nsec3param->salt_length);
+ if (nsec3param->salt == NULL)
+ return (ISC_R_NOMEMORY);
+ isc_region_consume(®ion, nsec3param->salt_length);
+
+ nsec3param->mctx = mctx;
+ return (ISC_R_SUCCESS);
+}
+
+static inline void
+freestruct_nsec3param(ARGS_FREESTRUCT) {
+ dns_rdata_nsec3param_t *nsec3param = source;
+
+ REQUIRE(source != NULL);
+ REQUIRE(nsec3param->common.rdtype == 51);
+
+ if (nsec3param->mctx == NULL)
+ return;
+
+ if (nsec3param->salt != NULL)
+ isc_mem_free(nsec3param->mctx, nsec3param->salt);
+ nsec3param->mctx = NULL;
+}
+
+static inline isc_result_t
+additionaldata_nsec3param(ARGS_ADDLDATA) {
+ REQUIRE(rdata->type == 51);
+
+ UNUSED(rdata);
+ UNUSED(add);
+ UNUSED(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+digest_nsec3param(ARGS_DIGEST) {
+ isc_region_t r;
+
+ REQUIRE(rdata->type == 51);
+
+ dns_rdata_toregion(rdata, &r);
+ return ((digest)(arg, &r));
+}
+
+static inline isc_boolean_t
+checkowner_nsec3param(ARGS_CHECKOWNER) {
+
+ REQUIRE(type == 51);
+
+ UNUSED(name);
+ UNUSED(type);
+ UNUSED(rdclass);
+ UNUSED(wildcard);
+
+ return (ISC_TRUE);
+}
+
+static inline isc_boolean_t
+checknames_nsec3param(ARGS_CHECKNAMES) {
+
+ REQUIRE(rdata->type == 51);
+
+ UNUSED(rdata);
+ UNUSED(owner);
+ UNUSED(bad);
+
+ return (ISC_TRUE);
+}
+
+#endif /* RDATA_GENERIC_NSEC3PARAM_51_C */
--- /dev/null
+/*
+ * Copyright (C) 2004 Nominet, Ltd.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND NOMINET DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef GENERIC_NSEC3PARAM_51_H
+#define GENERIC_NSEC3PARAM_51_H 1
+
+/* $Id: nsec3param_51.h,v 1.3 2008/09/24 02:46:23 marka Exp $ */
+
+/*!
+ * \brief Per RFC 5155 */
+
+#include <isc/iterated_hash.h>
+
+typedef struct dns_rdata_nsec3param {
+ dns_rdatacommon_t common;
+ isc_mem_t *mctx;
+ dns_hash_t hash;
+ unsigned char flags; /* DNS_NSEC3FLAG_* */
+ dns_iterations_t iterations;
+ unsigned char salt_length;
+ unsigned char *salt;
+} dns_rdata_nsec3param_t;
+
+#endif /* GENERIC_NSEC3PARAM_51_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rdatalist.c,v 1.35 2008/04/03 06:09:04 tbox Exp $ */
+/* $Id: rdatalist.c,v 1.36 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
#include <isc/util.h>
#include <dns/name.h>
+#include <dns/nsec3.h>
#include <dns/rdata.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
isc__rdatalist_count,
isc__rdatalist_addnoqname,
isc__rdatalist_getnoqname,
+ isc__rdatalist_addclosest,
+ isc__rdatalist_getclosest,
NULL,
NULL,
NULL
isc_result_t
dns_rdatalist_tordataset(dns_rdatalist_t *rdatalist,
- dns_rdataset_t *rdataset) {
-
+ dns_rdataset_t *rdataset)
+{
/*
* Make 'rdataset' refer to the rdata in 'rdatalist'.
*/
isc_result_t
isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) {
- dns_rdataset_t *nsec = NULL;
- dns_rdataset_t *nsecsig = NULL;
+ dns_rdataset_t *neg = NULL;
+ dns_rdataset_t *negsig = NULL;
dns_rdataset_t *rdset;
dns_ttl_t ttl;
{
if (rdset->rdclass != rdataset->rdclass)
continue;
- if (rdset->type == dns_rdatatype_nsec)
- nsec = rdset;
+ if (rdset->type == dns_rdatatype_nsec ||
+ rdset->type == dns_rdatatype_nsec3)
+ neg = rdset;
+ }
+ if (neg == NULL)
+ return (ISC_R_NOTFOUND);
+
+ for (rdset = ISC_LIST_HEAD(name->list);
+ rdset != NULL;
+ rdset = ISC_LIST_NEXT(rdset, link))
+ {
if (rdset->type == dns_rdatatype_rrsig &&
- rdset->covers == dns_rdatatype_nsec)
- nsecsig = rdset;
+ rdset->covers == neg->type)
+ negsig = rdset;
}
- if (nsec == NULL || nsecsig == NULL)
+ if (negsig == NULL)
return (ISC_R_NOTFOUND);
/*
* Minimise ttl.
*/
ttl = rdataset->ttl;
- if (nsec->ttl < ttl)
- ttl = nsec->ttl;
- if (nsecsig->ttl < ttl)
- ttl = nsecsig->ttl;
- rdataset->ttl = nsec->ttl = nsecsig->ttl = ttl;
+ if (neg->ttl < ttl)
+ ttl = neg->ttl;
+ if (negsig->ttl < ttl)
+ ttl = negsig->ttl;
+ rdataset->ttl = neg->ttl = negsig->ttl = ttl;
rdataset->attributes |= DNS_RDATASETATTR_NOQNAME;
rdataset->private6 = name;
return (ISC_R_SUCCESS);
isc_result_t
isc__rdatalist_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
- dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
+ dns_rdataset_t *neg, dns_rdataset_t *negsig)
{
dns_rdataclass_t rdclass = rdataset->rdclass;
- dns_rdataset_t *tnsec = NULL;
- dns_rdataset_t *tnsecsig = NULL;
+ dns_rdataset_t *tneg = NULL;
+ dns_rdataset_t *tnegsig = NULL;
dns_name_t *noqname = rdataset->private6;
REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0);
{
if (rdataset->rdclass != rdclass)
continue;
- if (rdataset->type == dns_rdatatype_nsec)
- tnsec = rdataset;
+ if (rdataset->type == dns_rdatatype_nsec ||
+ rdataset->type == dns_rdatatype_nsec3)
+ tneg = rdataset;
+ }
+ if (tneg == NULL)
+ return (ISC_R_NOTFOUND);
+
+ for (rdataset = ISC_LIST_HEAD(noqname->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link))
+ {
if (rdataset->type == dns_rdatatype_rrsig &&
- rdataset->covers == dns_rdatatype_nsec)
- tnsecsig = rdataset;
+ rdataset->covers == tneg->type)
+ tnegsig = rdataset;
}
- if (tnsec == NULL || tnsecsig == NULL)
+ if (tnegsig == NULL)
return (ISC_R_NOTFOUND);
dns_name_clone(noqname, name);
- dns_rdataset_clone(tnsec, nsec);
- dns_rdataset_clone(tnsecsig, nsecsig);
+ dns_rdataset_clone(tneg, neg);
+ dns_rdataset_clone(tnegsig, negsig);
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__rdatalist_addclosest(dns_rdataset_t *rdataset, dns_name_t *name) {
+ dns_rdataset_t *neg = NULL;
+ dns_rdataset_t *negsig = NULL;
+ dns_rdataset_t *rdset;
+ dns_ttl_t ttl;
+
+ for (rdset = ISC_LIST_HEAD(name->list);
+ rdset != NULL;
+ rdset = ISC_LIST_NEXT(rdset, link))
+ {
+ if (rdset->rdclass != rdataset->rdclass)
+ continue;
+ if (rdset->type == dns_rdatatype_nsec ||
+ rdset->type == dns_rdatatype_nsec3)
+ neg = rdset;
+ }
+ if (neg == NULL)
+ return (ISC_R_NOTFOUND);
+
+ for (rdset = ISC_LIST_HEAD(name->list);
+ rdset != NULL;
+ rdset = ISC_LIST_NEXT(rdset, link))
+ {
+ if (rdset->type == dns_rdatatype_rrsig &&
+ rdset->covers == neg->type)
+ negsig = rdset;
+ }
+
+ if (negsig == NULL)
+ return (ISC_R_NOTFOUND);
+ /*
+ * Minimise ttl.
+ */
+ ttl = rdataset->ttl;
+ if (neg->ttl < ttl)
+ ttl = neg->ttl;
+ if (negsig->ttl < ttl)
+ ttl = negsig->ttl;
+ rdataset->ttl = neg->ttl = negsig->ttl = ttl;
+ rdataset->attributes |= DNS_RDATASETATTR_CLOSEST;
+ rdataset->private7 = name;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc__rdatalist_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
+ dns_rdataset_t *neg, dns_rdataset_t *negsig)
+{
+ dns_rdataclass_t rdclass = rdataset->rdclass;
+ dns_rdataset_t *tneg = NULL;
+ dns_rdataset_t *tnegsig = NULL;
+ dns_name_t *closest = rdataset->private7;
+
+ REQUIRE((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0);
+ (void)dns_name_dynamic(closest); /* Sanity Check. */
+
+ for (rdataset = ISC_LIST_HEAD(closest->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link))
+ {
+ if (rdataset->rdclass != rdclass)
+ continue;
+ if (rdataset->type == dns_rdatatype_nsec ||
+ rdataset->type == dns_rdatatype_nsec3)
+ tneg = rdataset;
+ }
+ if (tneg == NULL)
+ return (ISC_R_NOTFOUND);
+
+ for (rdataset = ISC_LIST_HEAD(closest->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link))
+ {
+ if (rdataset->type == dns_rdatatype_rrsig &&
+ rdataset->covers == tneg->type)
+ tnegsig = rdataset;
+ }
+ if (tnegsig == NULL)
+ return (ISC_R_NOTFOUND);
+
+ dns_name_clone(closest, name);
+ dns_rdataset_clone(tneg, neg);
+ dns_rdataset_clone(tnegsig, negsig);
return (ISC_R_SUCCESS);
}
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rdatalist_p.h,v 1.9 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: rdatalist_p.h,v 1.10 2008/09/24 02:46:22 marka Exp $ */
#ifndef DNS_RDATALIST_P_H
#define DNS_RDATALIST_P_H
isc_result_t
isc__rdatalist_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
- dns_rdataset_t *nsec, dns_rdataset_t *nsecsig);
+ dns_rdataset_t *neg, dns_rdataset_t *negsig);
+
+isc_result_t
+isc__rdatalist_addclosest(dns_rdataset_t *rdataset, dns_name_t *name);
+
+isc_result_t
+isc__rdatalist_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
+ dns_rdataset_t *neg, dns_rdataset_t *negsig);
ISC_LANG_ENDDECLS
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rdataset.c,v 1.81 2008/04/01 23:47:10 tbox Exp $ */
+/* $Id: rdataset.c,v 1.82 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
NULL,
NULL,
NULL,
+ NULL,
+ NULL,
NULL
};
isc_result_t
dns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
- dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
+ dns_rdataset_t *neg, dns_rdataset_t *negsig)
{
REQUIRE(DNS_RDATASET_VALID(rdataset));
REQUIRE(rdataset->methods != NULL);
if (rdataset->methods->getnoqname == NULL)
return (ISC_R_NOTIMPLEMENTED);
- return((rdataset->methods->getnoqname)(rdataset, name, nsec, nsecsig));
+ return((rdataset->methods->getnoqname)(rdataset, name, neg, negsig));
+}
+
+isc_result_t
+dns_rdataset_addclosest(dns_rdataset_t *rdataset, dns_name_t *name) {
+
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(rdataset->methods != NULL);
+ if (rdataset->methods->addclosest == NULL)
+ return (ISC_R_NOTIMPLEMENTED);
+ return((rdataset->methods->addclosest)(rdataset, name));
+}
+
+isc_result_t
+dns_rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
+ dns_rdataset_t *neg, dns_rdataset_t *negsig)
+{
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(rdataset->methods != NULL);
+
+ if (rdataset->methods->getclosest == NULL)
+ return (ISC_R_NOTIMPLEMENTED);
+ return((rdataset->methods->getclosest)(rdataset, name, neg, negsig));
}
/*
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rdataslab.c,v 1.47 2008/04/23 21:32:01 each Exp $ */
+/* $Id: rdataslab.c,v 1.48 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
NULL,
NULL,
NULL,
+ NULL,
+ NULL,
NULL
};
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: resolver.c,v 1.380 2008/09/04 04:23:43 marka Exp $ */
+/* $Id: resolver.c,v 1.381 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
dns_db_t *cache, dns_dbnode_t *node,
dns_rdatatype_t covers,
isc_stdtime_t now, dns_ttl_t maxttl,
+ isc_boolean_t optout,
dns_rdataset_t *ardataset,
isc_result_t *eresultp);
static void validated(isc_task_t *task, isc_event_t *event);
resquery_t *query;
isc_sockaddr_t addr;
isc_boolean_t have_addr = ISC_FALSE;
+ unsigned int srtt;
FCTXTRACE("query");
res = fctx->res;
task = res->buckets[fctx->bucketnum].task;
- fctx_setretryinterval(fctx, addrinfo->srtt);
+ srtt = addrinfo->srtt;
+ if (ISFORWARDER(addrinfo) && srtt < 1000000)
+ srtt = 1000000;
+
+ fctx_setretryinterval(fctx, srtt);
result = fctx_startidletimer(fctx);
if (result != ISC_R_SUCCESS)
return (result);
ttl = 0;
result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
- covers, now, ttl,
+ covers, now, ttl, vevent->optout,
ardataset, &eresult);
if (result != ISC_R_SUCCESS)
goto noanswer_response;
RUNTIME_CHECK(result == ISC_R_SUCCESS);
INSIST(vevent->sigrdataset != NULL);
vevent->sigrdataset->ttl = vevent->rdataset->ttl;
+ if (vevent->proofs[DNS_VALIDATOR_CLOSESTENCLOSER] != NULL) {
+ result = dns_rdataset_addclosest(vevent->rdataset,
+ vevent->proofs[DNS_VALIDATOR_CLOSESTENCLOSER]);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ }
}
/*
}
/*
- * Do what dns_ncache_add() does, and then compute an appropriate eresult.
+ * Do what dns_ncache_addoptout() does, and then compute an appropriate eresult.
*/
static isc_result_t
ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
- dns_rdataset_t *ardataset,
+ isc_boolean_t optout, dns_rdataset_t *ardataset,
isc_result_t *eresultp)
{
isc_result_t result;
dns_rdataset_init(&rdataset);
ardataset = &rdataset;
}
- result = dns_ncache_add(message, cache, node, covers, now,
- maxttl, ardataset);
+ result = dns_ncache_addoptout(message, cache, node, covers, now,
+ maxttl, optout, ardataset);
if (result == DNS_R_UNCHANGED || result == ISC_R_SUCCESS) {
/*
* If the cache now contains a negative entry and we
ttl = 0;
result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
- covers, now, ttl, ardataset, &eresult);
+ covers, now, ttl, ISC_FALSE,
+ ardataset, &eresult);
if (result != ISC_R_SUCCESS)
goto unlock;
type = rdataset->type;
if (type == dns_rdatatype_rrsig)
type = rdataset->covers;
- if (type == dns_rdatatype_nsec) {
+ if (type == dns_rdatatype_nsec ||
+ type == dns_rdatatype_nsec3) {
/*
* NSEC or RRSIG NSEC.
*/
DNS_NAMEATTR_NCACHE;
rdataset->attributes |=
DNS_RDATASETATTR_NCACHE;
- } else {
+ } else if (type == dns_rdatatype_nsec) {
name->attributes |=
DNS_NAMEATTR_CACHE;
rdataset->attributes |=
found = ISC_FALSE;
want_chaining = ISC_FALSE;
aflag = 0;
+ if (rdataset->type == dns_rdatatype_nsec3) {
+ /*
+ * NSEC3 records are not allowed to
+ * appear in the answer section.
+ */
+ return (DNS_R_FORMERR);
+ }
if (rdataset->type == type && !found_cname) {
/*
* We've found an ordinary answer.
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: result.c,v 1.123 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: result.c,v 1.124 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
"must-be-secure", /*%< 100 DNS_R_MUSTBESECURE */
"covering NSEC record returned", /*%< 101 DNS_R_COVERINGNSEC */
"MX is an address", /*%< 102 DNS_R_MXISADDRESS */
- "duplicate query" /*%< 103 DNS_R_DUPLICATE */
+ "duplicate query", /*%< 103 DNS_R_DUPLICATE */
+ "invalid NSEC3 owner name (wildcard)", /*%< 104 DNS_R_INVALIDNSEC3 */
};
static const char *rcode_text[DNS_R_NRCODERESULTS] = {
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rootns.c,v 1.35 2008/04/01 01:37:25 marka Exp $ */
+/* $Id: rootns.c,v 1.36 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
dns_rdataset_init(&rootns);
(void)dns_db_find(db, dns_rootname, NULL, dns_rdatatype_ns, 0,
now, NULL, name, &rootns, NULL);
- result = dns_db_createiterator(db, ISC_FALSE, &dbiter);
+ result = dns_db_createiterator(db, 0, &dbiter);
if (result != ISC_R_SUCCESS)
goto cleanup;
result = dns_dbiterator_first(dbiter);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: sdb.c,v 1.64 2008/04/03 05:55:52 marka Exp $ */
+/* $Id: sdb.c,v 1.65 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
}
static isc_result_t
-createiterator(dns_db_t *db, isc_boolean_t relative_names,
- dns_dbiterator_t **iteratorp)
+createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp)
{
dns_sdb_t *sdb = (dns_sdb_t *)db;
sdb_dbiterator_t *sdbiter;
if (imp->methods->allnodes == NULL)
return (ISC_R_NOTIMPLEMENTED);
+ if ((options & DNS_DB_NSEC3ONLY) != 0 ||
+ (options & DNS_DB_NONSEC3) != 0)
+ return (ISC_R_NOTIMPLEMENTED);
+
sdbiter = isc_mem_get(sdb->common.mctx, sizeof(sdb_dbiterator_t));
if (sdbiter == NULL)
return (ISC_R_NOMEMORY);
sdbiter->common.methods = &dbiterator_methods;
sdbiter->common.db = NULL;
dns_db_attach(db, &sdbiter->common.db);
- sdbiter->common.relative_names = relative_names;
+ sdbiter->common.relative_names = ISC_TF(options & DNS_DB_RELATIVENAMES);
sdbiter->common.magic = DNS_DBITERATOR_MAGIC;
ISC_LIST_INIT(sdbiter->nodelist);
sdbiter->current = NULL;
NULL,
NULL,
NULL,
+ NULL,
+ NULL,
NULL
};
isc__rdatalist_getnoqname,
NULL,
NULL,
+ NULL,
+ NULL,
NULL
};
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: sdlz.c,v 1.17 2008/04/03 05:55:52 marka Exp $ */
+/* $Id: sdlz.c,v 1.18 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
}
static isc_result_t
-createiterator(dns_db_t *db, isc_boolean_t relative_names,
- dns_dbiterator_t **iteratorp)
+createiterator(dns_db_t *db, unsigned int options, dns_dbiterator_t **iteratorp)
{
dns_sdlz_db_t *sdlz = (dns_sdlz_db_t *)db;
sdlz_dbiterator_t *sdlziter;
if (sdlz->dlzimp->methods->allnodes == NULL)
return (ISC_R_NOTIMPLEMENTED);
+ if ((options & DNS_DB_NSEC3ONLY) != 0 ||
+ (options & DNS_DB_NONSEC3) != 0)
+ return (ISC_R_NOTIMPLEMENTED);
+
isc_buffer_init(&b, zonestr, sizeof(zonestr));
result = dns_name_totext(&sdlz->common.origin, ISC_TRUE, &b);
if (result != ISC_R_SUCCESS)
sdlziter->common.methods = &dbiterator_methods;
sdlziter->common.db = NULL;
dns_db_attach(db, &sdlziter->common.db);
- sdlziter->common.relative_names = relative_names;
+ sdlziter->common.relative_names = ISC_TF(options & DNS_DB_RELATIVENAMES);
sdlziter->common.magic = DNS_DBITERATOR_MAGIC;
ISC_LIST_INIT(sdlziter->nodelist);
sdlziter->current = NULL;
NULL,
NULL,
NULL,
+ NULL,
+ NULL,
NULL
};
isc__rdatalist_getnoqname,
NULL,
NULL,
+ NULL,
+ NULL,
NULL
};
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: validator.c,v 1.161 2008/08/21 04:43:49 marka Exp $ */
+/* $Id: validator.c,v 1.162 2008/09/24 02:46:22 marka Exp $ */
#include <config.h>
+#include <isc/base32.h>
#include <isc/mem.h>
#include <isc/print.h>
+#include <isc/sha2.h>
#include <isc/string.h>
#include <isc/task.h>
#include <isc/util.h>
-#include <isc/sha2.h>
#include <dns/db.h>
#include <dns/ds.h>
#include <dns/message.h>
#include <dns/ncache.h>
#include <dns/nsec.h>
+#include <dns/nsec3.h>
#include <dns/rdata.h>
#include <dns/rdatastruct.h>
#include <dns/rdataset.h>
/*!
* NSEC proofs to be looked for.
*/
-#define VALATTR_NEEDNOQNAME 0x0100
-#define VALATTR_NEEDNOWILDCARD 0x0200
-#define VALATTR_NEEDNODATA 0x0400
+#define VALATTR_NEEDNOQNAME 0x00000100
+#define VALATTR_NEEDNOWILDCARD 0x00000200
+#define VALATTR_NEEDNODATA 0x00000400
/*!
* NSEC proofs that have been found.
*/
-#define VALATTR_FOUNDNOQNAME 0x1000
-#define VALATTR_FOUNDNOWILDCARD 0x2000
-#define VALATTR_FOUNDNODATA 0x4000
+#define VALATTR_FOUNDNOQNAME 0x00001000
+#define VALATTR_FOUNDNOWILDCARD 0x00002000
+#define VALATTR_FOUNDNODATA 0x00004000
+#define VALATTR_FOUNDCLOSEST 0x00008000
+
+/*
+ *
+ */
+#define VALATTR_FOUNDOPTOUT 0x00010000
+#define VALATTR_FOUNDUNKNOWN 0x00020000
#define NEEDNODATA(val) ((val->attributes & VALATTR_NEEDNODATA) != 0)
#define NEEDNOQNAME(val) ((val->attributes & VALATTR_NEEDNOQNAME) != 0)
isdelegation(dns_name_t *name, dns_rdataset_t *rdataset,
isc_result_t dbresult)
{
- dns_rdataset_t set;
+ dns_label_t hashlabel;
+ dns_name_t nsec3name;
+ dns_rdata_nsec3_t nsec3;
dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_t set;
+ int order;
+ int scope;
isc_boolean_t found;
+ isc_buffer_t buffer;
isc_result_t result;
+ unsigned char hash[NSEC3_MAX_HASH_LENGTH];
+ unsigned char owner[NSEC3_MAX_HASH_LENGTH];
+ unsigned int length;
REQUIRE(dbresult == DNS_R_NXRRSET || dbresult == DNS_R_NCACHENXRRSET);
else {
result = dns_ncache_getrdataset(rdataset, name,
dns_rdatatype_nsec, &set);
+ if (result == ISC_R_NOTFOUND)
+ goto trynsec3;
if (result != ISC_R_SUCCESS)
return (ISC_FALSE);
}
if (result == ISC_R_SUCCESS) {
dns_rdataset_current(&set, &rdata);
found = dns_nsec_typepresent(&rdata, dns_rdatatype_ns);
+ dns_rdata_reset(&rdata);
}
dns_rdataset_disassociate(&set);
return (found);
+
+ trynsec3:
+ /*
+ * Iterate over the ncache entry.
+ */
+ found = ISC_FALSE;
+ dns_name_init(&nsec3name, NULL);
+ result = dns_rdataset_first(rdataset);
+ for (result = dns_rdataset_first(rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(rdataset))
+ {
+ dns_ncache_current(rdataset, &nsec3name, &set);
+ if (set.type != dns_rdatatype_nsec3) {
+ dns_rdataset_disassociate(&set);
+ continue;
+ }
+ dns_name_getlabel(&nsec3name, 0, &hashlabel);
+ isc_region_consume(&hashlabel, 1);
+ isc_buffer_init(&buffer, owner, sizeof(owner));
+ result = isc_base32hex_decoderegion(&hashlabel, &buffer);
+ if (result != ISC_R_SUCCESS) {
+ dns_rdataset_disassociate(&set);
+ continue;
+ }
+ for (result = dns_rdataset_first(&set);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&set))
+ {
+ dns_rdata_reset(&rdata);
+ dns_rdataset_current(&set, &rdata);
+ (void)dns_rdata_tostruct(&rdata, &nsec3, NULL);
+ if (nsec3.hash != 1)
+ continue;
+ length = isc_iterated_hash(hash, nsec3.hash,
+ nsec3.iterations, nsec3.salt,
+ nsec3.salt_length,
+ name->ndata, name->length);
+ if (length != isc_buffer_usedlength(&buffer))
+ continue;
+ order = memcmp(hash, owner, length);
+ if (order == 0) {
+ found = dns_nsec3_typepresent(&rdata,
+ dns_rdatatype_ns);
+ dns_rdataset_disassociate(&set);
+ return (found);
+ }
+ if ((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) == 0)
+ continue;
+ /*
+ * Does this optout span cover the name?
+ */
+ scope = memcmp(owner, nsec3.next, nsec3.next_length);
+ if ((scope < 0 && order > 0 &&
+ memcmp(hash, nsec3.next, length) < 0) ||
+ (scope >= 0 && (order > 0 ||
+ memcmp(hash, nsec3.next, length) < 0)))
+ {
+ dns_rdataset_disassociate(&set);
+ return (ISC_TRUE);
+ }
+ }
+ dns_rdataset_disassociate(&set);
+ }
+ return (found);
}
/*%
return (ISC_R_SUCCESS);
}
+static isc_result_t
+nsec3noexistnodata(dns_validator_t *val, dns_name_t* name,
+ dns_name_t *nsec3name, dns_rdataset_t *nsec3set,
+ dns_name_t *zonename, isc_boolean_t *exists,
+ isc_boolean_t *data, isc_boolean_t *optout,
+ isc_boolean_t *unknown, isc_boolean_t *setclosest,
+ isc_boolean_t *setnearest, dns_name_t *closest,
+ dns_name_t *nearest)
+{
+ char namebuf[DNS_NAME_FORMATSIZE];
+ dns_fixedname_t fzone;
+ dns_fixedname_t qfixed;
+ dns_label_t hashlabel;
+ dns_name_t *qname;
+ dns_name_t *zone;
+ dns_rdata_nsec3_t nsec3;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ int order;
+ int scope;
+ isc_boolean_t atparent;
+ isc_boolean_t first;
+ isc_boolean_t ns;
+ isc_boolean_t soa;
+ isc_buffer_t buffer;
+ isc_result_t answer = ISC_R_IGNORE;
+ isc_result_t result;
+ unsigned char hash[NSEC3_MAX_HASH_LENGTH];
+ unsigned char owner[NSEC3_MAX_HASH_LENGTH];
+ unsigned int length;
+ unsigned int qlabels;
+ unsigned int zlabels;
+
+ REQUIRE((exists == NULL && data == NULL) ||
+ (exists != NULL && data != NULL));
+ REQUIRE(nsec3set != NULL && nsec3set->type == dns_rdatatype_nsec3);
+ REQUIRE((setclosest == NULL && closest == NULL) ||
+ (setclosest != NULL && closest != NULL));
+ REQUIRE((setnearest == NULL && nearest == NULL) ||
+ (setnearest != NULL && nearest != NULL));
+
+ result = dns_rdataset_first(nsec3set);
+ if (result != ISC_R_SUCCESS) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "failure processing NSEC3 set");
+ return (result);
+ }
+
+ dns_rdataset_current(nsec3set, &rdata);
+
+ result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ validator_log(val, ISC_LOG_DEBUG(3), "looking for relevant NSEC3");
+
+ dns_fixedname_init(&fzone);
+ zone = dns_fixedname_name(&fzone);
+ zlabels = dns_name_countlabels(nsec3name);
+
+ /*
+ * NSEC3 records must have two or more labels to be valid.
+ */
+ if (zlabels < 2)
+ return (ISC_R_IGNORE);
+
+ /*
+ * Strip off the NSEC3 hash to get the zone.
+ */
+ zlabels--;
+ dns_name_split(nsec3name, zlabels, NULL, zone);
+
+ /*
+ * If not below the zone name we can ignore this record.
+ */
+ if (!dns_name_issubdomain(name, zone))
+ return (ISC_R_IGNORE);
+
+ /*
+ * Is this zone the same or deeper than the current zone?
+ */
+ if (dns_name_countlabels(zonename) == 0 ||
+ dns_name_issubdomain(zone, zonename))
+ dns_name_copy(zone, zonename, NULL);
+
+ if (!dns_name_equal(zone, zonename))
+ return (ISC_R_IGNORE);
+
+ /*
+ * Are we only looking for the most enclosing zone?
+ */
+ if (exists == NULL || data == NULL)
+ return (ISC_R_SUCCESS);
+
+ /*
+ * Only set unknown once we are sure that this NSEC3 is from
+ * the deepest covering zone.
+ */
+ if (!dns_nsec3_supportedhash(nsec3.hash)) {
+ if (unknown != NULL)
+ *unknown = ISC_TRUE;
+ return (ISC_R_IGNORE);
+ }
+
+ /*
+ * Recover the hash from the first label.
+ */
+ dns_name_getlabel(nsec3name, 0, &hashlabel);
+ isc_region_consume(&hashlabel, 1);
+ isc_buffer_init(&buffer, owner, sizeof(owner));
+ result = isc_base32hex_decoderegion(&hashlabel, &buffer);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ /*
+ * The hash lengths should match. If not ignore the record.
+ */
+ if (isc_buffer_usedlength(&buffer) != nsec3.next_length)
+ return (ISC_R_IGNORE);
+
+ /*
+ * Work out what this NSEC3 covers.
+ * Inside (<0) or outside (>=0).
+ */
+ scope = memcmp(owner, nsec3.next, nsec3.next_length);
+
+ /*
+ * Prepare to compute all the hashes.
+ */
+ dns_fixedname_init(&qfixed);
+ qname = dns_fixedname_name(&qfixed);
+ dns_name_downcase(name, qname, NULL);
+ qlabels = dns_name_countlabels(qname);
+ first = ISC_TRUE;
+
+ while (qlabels >= zlabels) {
+ length = isc_iterated_hash(hash, nsec3.hash, nsec3.iterations,
+ nsec3.salt, nsec3.salt_length,
+ qname->ndata, qname->length);
+ /*
+ * The computed hash length should match.
+ */
+ if (length != nsec3.next_length) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "ignoring NSEC bad length %u vs %u",
+ length, nsec3.next_length);
+ return (ISC_R_IGNORE);
+ }
+
+ order = memcmp(hash, owner, length);
+ if (first && order == 0) {
+ /*
+ * The hashes are the same.
+ */
+ atparent = dns_rdatatype_atparent(val->event->type);
+ ns = dns_nsec3_typepresent(&rdata, dns_rdatatype_ns);
+ soa = dns_nsec3_typepresent(&rdata, dns_rdatatype_soa);
+ if (ns && !soa) {
+ if (!atparent) {
+ /*
+ * This NSEC record is from somewhere
+ * higher in the DNS, and at the
+ * parent of a delegation. It can not
+ * be legitimately used here.
+ */
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "ignoring parent NSEC3");
+ return (ISC_R_IGNORE);
+ }
+ } else if (atparent && ns && soa) {
+ /*
+ * This NSEC record is from the child.
+ * It can not be legitimately used here.
+ */
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "ignoring child NSEC3");
+ return (ISC_R_IGNORE);
+ }
+ if (val->event->type == dns_rdatatype_cname ||
+ val->event->type == dns_rdatatype_nxt ||
+ val->event->type == dns_rdatatype_nsec ||
+ val->event->type == dns_rdatatype_key ||
+ !dns_nsec3_typepresent(&rdata, dns_rdatatype_cname)) {
+ *exists = ISC_TRUE;
+ *data = dns_nsec3_typepresent(&rdata,
+ val->event->type);
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "NSEC3 proves name exists (owner) "
+ "data=%d", *data);
+ return (ISC_R_SUCCESS);
+ }
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "NSEC3 proves CNAME exists");
+ return (ISC_R_IGNORE);
+ }
+
+ if (order == 0 &&
+ dns_nsec3_typepresent(&rdata, dns_rdatatype_ns) &&
+ !dns_nsec3_typepresent(&rdata, dns_rdatatype_soa))
+ {
+ /*
+ * This NSEC3 record is from somewhere higher in
+ * the DNS, and at the parent of a delegation.
+ * It can not be legitimately used here.
+ */
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "ignoring parent NSEC3");
+ return (ISC_R_IGNORE);
+ }
+
+ /*
+ * Potential closest encloser.
+ */
+ if (order == 0) {
+ if (closest != NULL &&
+ (dns_name_countlabels(closest) == 0 ||
+ dns_name_issubdomain(qname, closest)) &&
+ !dns_nsec3_typepresent(&rdata, dns_rdatatype_ds) &&
+ !dns_nsec3_typepresent(&rdata, dns_rdatatype_dname) &&
+ (dns_nsec3_typepresent(&rdata, dns_rdatatype_soa) ||
+ !dns_nsec3_typepresent(&rdata, dns_rdatatype_ns)))
+ {
+
+ dns_name_format(qname, namebuf,
+ sizeof(namebuf));
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "NSEC3 indicates potential "
+ "closest encloser: '%s'",
+ namebuf);
+ dns_name_copy(qname, closest, NULL);
+ *setclosest = ISC_TRUE;
+ }
+ dns_name_format(qname, namebuf, sizeof(namebuf));
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "NSEC3 at super-domain %s", namebuf);
+ return (answer);
+ }
+
+ /*
+ * Find if the name does not exist.
+ *
+ * We continue as we need to find the name closest to the
+ * closest encloser that doesn't exist.
+ *
+ * We also need to continue to ensure that we are not
+ * proving the non-existance of a record in a sub-zone.
+ * If that would be the case we will return ISC_R_IGNORE
+ * above.
+ */
+ if ((scope < 0 && order > 0 &&
+ memcmp(hash, nsec3.next, length) < 0) ||
+ (scope >= 0 && (order > 0 ||
+ memcmp(hash, nsec3.next, length) < 0)))
+ {
+ char namebuf[DNS_NAME_FORMATSIZE];
+
+ dns_name_format(qname, namebuf, sizeof(namebuf));
+ validator_log(val, ISC_LOG_DEBUG(3), "NSEC3 proves "
+ "name does not exist: '%s'", namebuf);
+ if (nearest != NULL &&
+ (dns_name_countlabels(nearest) == 0 ||
+ dns_name_issubdomain(nearest, qname))) {
+ dns_name_copy(qname, nearest, NULL);
+ *setnearest = ISC_TRUE;
+ }
+#if 0
+ /*
+ * The closest encloser may be the zone name.
+ */
+ if (closest != NULL &&
+ dns_name_countlabels(closest) == 0 &&
+ !dns_nsec3_typepresent(&rdata, dns_rdatatype_ds) &&
+ !dns_nsec3_typepresent(&rdata, dns_rdatatype_dname) &&
+ (dns_nsec3_typepresent(&rdata, dns_rdatatype_soa) ||
+ !dns_nsec3_typepresent(&rdata, dns_rdatatype_ns)))
+ {
+ char namebuf[DNS_NAME_FORMATSIZE];
+
+ dns_name_format(zone, namebuf,
+ sizeof(namebuf));
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "NSEC3 potential closest "
+ "encloser from zone name: '%s'",
+ namebuf);
+ dns_name_copy(zone, closest, NULL);
+ *setclosest = ISC_TRUE;
+ }
+#endif
+ *exists = ISC_FALSE;
+ *data = ISC_FALSE;
+ if (optout != NULL) {
+ if ((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0)
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "NSEC3 indicates optout");
+ *optout =
+ ISC_TF(nsec3.flags & DNS_NSEC3FLAG_OPTOUT);
+ }
+ answer = ISC_R_SUCCESS;
+ }
+
+ qlabels--;
+ if (qlabels > 0)
+ dns_name_split(qname, qlabels, NULL, qname);
+ first = ISC_FALSE;
+ }
+ return (answer);
+}
+
/*%
* Callback for when NSEC records have been validated.
*
- * Looks for NOQNAME and NODATA proofs.
+ * Looks for NOQNAME, NODATA and OPTOUT proofs.
*
* Resumes nsecvalidate.
*/
dns_validatorevent_t *devent;
dns_validator_t *val;
dns_rdataset_t *rdataset;
+ dns_rdataset_t *sigrdataset;
isc_boolean_t want_destroy;
isc_result_t result;
isc_boolean_t exists, data;
devent = (dns_validatorevent_t *)event;
rdataset = devent->rdataset;
+ sigrdataset = devent->sigrdataset;
val = devent->ev_arg;
result = devent->result;
dns_validator_destroy(&val->subvalidator);
}
if (!exists) {
val->attributes |= VALATTR_FOUNDNOQNAME;
+ val->attributes |= VALATTR_FOUNDCLOSEST;
+ /*
+ * The NSEC noqname proof also contains
+ * the closest encloser.
+
+ */
if (NEEDNOQNAME(val))
proofs[DNS_VALIDATOR_NOQNAMEPROOF] =
devent->name;
}
}
+
result = nsecvalidate(val, ISC_TRUE);
if (result != DNS_R_WAIT)
validator_done(val, result);
* the validation process will stall if looping was to occur.
*/
static inline isc_boolean_t
-check_deadlock(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) {
+check_deadlock(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
+ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
dns_validator_t *parent;
for (parent = val; parent != NULL; parent = parent->parent) {
if (parent->event != NULL &&
parent->event->type == type &&
- dns_name_equal(parent->event->name, name))
+ dns_name_equal(parent->event->name, name) &&
+ /*
+ * As NSEC3 records are meta data you sometimes
+ * need to prove a NSEC3 record which says that
+ * itself doesn't exist.
+ */
+ (parent->event->type != dns_rdatatype_nsec3 ||
+ rdataset == NULL || sigrdataset == NULL ||
+ parent->event->message == NULL ||
+ parent->event->rdataset != NULL ||
+ parent->event->sigrdataset != NULL))
{
validator_log(val, ISC_LOG_DEBUG(3),
"continuing validation would lead to "
if (dns_rdataset_isassociated(&val->fsigrdataset))
dns_rdataset_disassociate(&val->fsigrdataset);
- if (check_deadlock(val, name, type))
+ if (check_deadlock(val, name, type, NULL, NULL))
return (DNS_R_NOVALIDSIG);
validator_logcreate(val, name, type, caller, "fetch");
{
isc_result_t result;
- if (check_deadlock(val, name, type))
+ if (check_deadlock(val, name, type, rdataset, sigrdataset))
return (DNS_R_NOVALIDSIG);
validator_logcreate(val, name, type, caller, "validator");
* \li ISC_R_SUCCESS
*/
static isc_result_t
-checkwildcard(dns_validator_t *val) {
+checkwildcard(dns_validator_t *val, dns_rdatatype_t type, dns_name_t *zonename)
+{
dns_name_t *name, *wild;
dns_message_t *message = val->event->message;
isc_result_t result;
char namebuf[DNS_NAME_FORMATSIZE];
wild = dns_fixedname_name(&val->wild);
+
+ if (dns_name_countlabels(wild) == 0) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "in checkwildcard: no wildcard to check");
+ return (ISC_R_SUCCESS);
+ }
+
dns_name_format(wild, namebuf, sizeof(namebuf));
validator_log(val, ISC_LOG_DEBUG(3), "in checkwildcard: %s", namebuf);
rdataset != NULL;
rdataset = ISC_LIST_NEXT(rdataset, link))
{
- if (rdataset->type != dns_rdatatype_nsec)
+ if (rdataset->type != type)
continue;
- val->nsecset = rdataset;
for (sigrdataset = ISC_LIST_HEAD(name->list);
sigrdataset != NULL;
if (rdataset->trust != dns_trust_secure)
continue;
- if (((val->attributes & VALATTR_NEEDNODATA) != 0 ||
+ if (rdataset->type == dns_rdatatype_nsec &&
+ ((val->attributes & VALATTR_NEEDNODATA) != 0 ||
(val->attributes & VALATTR_NEEDNOWILDCARD) != 0) &&
(val->attributes & VALATTR_FOUNDNODATA) == 0 &&
(val->attributes & VALATTR_FOUNDNOWILDCARD) == 0 &&
name;
return (ISC_R_SUCCESS);
}
+
+ if (rdataset->type == dns_rdatatype_nsec3 &&
+ ((val->attributes & VALATTR_NEEDNODATA) != 0 ||
+ (val->attributes & VALATTR_NEEDNOWILDCARD) != 0) &&
+ (val->attributes & VALATTR_FOUNDNODATA) == 0 &&
+ (val->attributes & VALATTR_FOUNDNOWILDCARD) == 0 &&
+ nsec3noexistnodata(val, wild, name, rdataset,
+ zonename, &exists, &data,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL) == ISC_R_SUCCESS)
+ {
+ dns_name_t **proofs = val->event->proofs;
+ if (exists && !data)
+ val->attributes |= VALATTR_FOUNDNODATA;
+ if (exists && !data && NEEDNODATA(val))
+ proofs[DNS_VALIDATOR_NODATAPROOF] =
+ name;
+ if (!exists)
+ val->attributes |=
+ VALATTR_FOUNDNOWILDCARD;
+ if (!exists && NEEDNOQNAME(val))
+ proofs[DNS_VALIDATOR_NOWILDCARDPROOF] =
+ name;
+ return (ISC_R_SUCCESS);
+ }
}
}
if (result == ISC_R_NOMORE)
return (result);
}
+
+static isc_result_t
+findnsec3proofs(dns_validator_t *val) {
+ dns_name_t *name;
+ dns_message_t *message = val->event->message;
+ isc_result_t result;
+ isc_boolean_t exists, data, optout, unknown;
+ isc_boolean_t setclosest, setnearest;
+ dns_fixedname_t fclosest, fnearest, fzonename;
+ dns_name_t *closest, *nearest, *zonename;
+ dns_name_t **proofs = val->event->proofs;
+
+ dns_fixedname_init(&fclosest);
+ dns_fixedname_init(&fnearest);
+ dns_fixedname_init(&fzonename);
+ closest = dns_fixedname_name(&fclosest);
+ nearest = dns_fixedname_name(&fnearest);
+ zonename = dns_fixedname_name(&fzonename);
+
+ for (result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
+ result == ISC_R_SUCCESS;
+ result = dns_message_nextname(message, DNS_SECTION_AUTHORITY))
+ {
+ dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
+
+ name = NULL;
+ dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
+
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link))
+ {
+ if (rdataset->type != dns_rdatatype_nsec3)
+ continue;
+
+ for (sigrdataset = ISC_LIST_HEAD(name->list);
+ sigrdataset != NULL;
+ sigrdataset = ISC_LIST_NEXT(sigrdataset, link))
+ {
+ if (sigrdataset->type == dns_rdatatype_rrsig &&
+ sigrdataset->covers == dns_rdatatype_nsec3)
+ break;
+ }
+ if (sigrdataset == NULL)
+ continue;
+
+ if (rdataset->trust != dns_trust_secure)
+ continue;
+
+ result = nsec3noexistnodata(val, val->event->name,
+ name, rdataset,
+ zonename, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL);
+ if (result != ISC_R_IGNORE && result != ISC_R_SUCCESS)
+ return (result);
+ }
+ }
+ if (result != ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ if (dns_name_countlabels(zonename) == 0)
+ return (ISC_R_SUCCESS);
+
+ for (result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
+ result == ISC_R_SUCCESS;
+ result = dns_message_nextname(message, DNS_SECTION_AUTHORITY))
+ {
+ dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
+
+ name = NULL;
+ dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
+
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link))
+ {
+ if (rdataset->type != dns_rdatatype_nsec3)
+ continue;
+
+ for (sigrdataset = ISC_LIST_HEAD(name->list);
+ sigrdataset != NULL;
+ sigrdataset = ISC_LIST_NEXT(sigrdataset, link))
+ {
+ if (sigrdataset->type == dns_rdatatype_rrsig &&
+ sigrdataset->covers == dns_rdatatype_nsec3)
+ break;
+ }
+ if (sigrdataset == NULL)
+ continue;
+
+ if (rdataset->trust != dns_trust_secure)
+ continue;
+
+ /*
+ * We process all NSEC3 records to find the closest
+ * encloser and nearest name to the closest encloser.
+ */
+ setclosest = setnearest = ISC_FALSE;
+ optout = ISC_FALSE;
+ unknown = ISC_FALSE;
+ result = nsec3noexistnodata(val, val->event->name,
+ name, rdataset,
+ zonename, &exists,
+ &data, &optout, &unknown,
+ &setclosest, &setnearest,
+ closest, nearest);
+ if (setclosest)
+ proofs[DNS_VALIDATOR_CLOSESTENCLOSER] = name;
+ if (unknown)
+ val->attributes |= VALATTR_FOUNDUNKNOWN;
+ if (result != ISC_R_SUCCESS)
+ continue;
+ if (exists && !data && NEEDNODATA(val)) {
+ val->attributes |= VALATTR_FOUNDNODATA;
+ proofs[DNS_VALIDATOR_NODATAPROOF] = name;
+ }
+ if (!exists && setnearest) {
+ val->attributes |= VALATTR_FOUNDNOQNAME;
+ proofs[DNS_VALIDATOR_NOQNAMEPROOF] = name;
+ if (optout)
+ val->attributes |= VALATTR_FOUNDOPTOUT;
+ }
+ }
+ }
+ if (result != ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ /*
+ * To know we have a valid noqname and optout proofs we need to also
+ * have a valid closest encloser. Otherwise we could still be looking
+ * at proofs from the parent zone.
+ */
+ if (dns_name_countlabels(closest) > 0 &&
+ dns_name_countlabels(nearest) ==
+ dns_name_countlabels(closest) + 1 &&
+ dns_name_issubdomain(nearest, closest))
+ {
+ val->attributes |= VALATTR_FOUNDCLOSEST;
+ result = dns_name_concatenate(dns_wildcardname, closest,
+ dns_fixedname_name(&val->wild),
+ NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ } else {
+ val->attributes &= ~VALATTR_FOUNDNOQNAME;
+ val->attributes &= ~VALATTR_FOUNDOPTOUT;
+ proofs[DNS_VALIDATOR_NOQNAMEPROOF] = NULL;
+ }
+
+ /*
+ * Do we need to check for the wildcard?
+ */
+ if ((val->attributes & VALATTR_FOUNDNOQNAME) != 0 &&
+ (val->attributes & VALATTR_FOUNDCLOSEST) != 0 &&
+ (((val->attributes & VALATTR_NEEDNODATA) != 0 &&
+ (val->attributes & VALATTR_FOUNDNODATA) == 0) ||
+ (val->attributes & VALATTR_NEEDNOWILDCARD) != 0)) {
+ result = checkwildcard(val, dns_rdatatype_nsec3, zonename);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ return (result);
+}
+
/*%
* Prove a negative answer is good or that there is a NOQNAME when the
* answer is from a wildcard.
if ((val->attributes & VALATTR_NEEDNODATA) == 0 &&
(val->attributes & VALATTR_NEEDNOWILDCARD) == 0 &&
(val->attributes & VALATTR_NEEDNOQNAME) != 0) {
- if ((val->attributes & VALATTR_FOUNDNOQNAME) != 0) {
+ if ((val->attributes & VALATTR_FOUNDNOQNAME) == 0)
+ findnsec3proofs(val);
+ if ((val->attributes & VALATTR_FOUNDNOQNAME) != 0 &&
+ (val->attributes & VALATTR_FOUNDCLOSEST) != 0) {
validator_log(val, ISC_LOG_DEBUG(3),
"noqname proof found");
validator_log(val, ISC_LOG_DEBUG(3),
val->event->rdataset->trust = dns_trust_secure;
val->event->sigrdataset->trust = dns_trust_secure;
return (ISC_R_SUCCESS);
+ } else if ((val->attributes & VALATTR_FOUNDOPTOUT) != 0 &&
+ dns_name_countlabels(dns_fixedname_name(&val->wild))
+ != 0) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "optout proof found");
+ val->event->optout = ISC_TRUE;
+ markanswer(val);
+ return (ISC_R_SUCCESS);
+ } else if ((val->attributes & VALATTR_FOUNDUNKNOWN) != 0) {
+ validator_log(val, ISC_LOG_DEBUG(3),
+ "unknown NSEC3 hash algorithm found");
+ markanswer(val);
+ return (ISC_R_SUCCESS);
}
validator_log(val, ISC_LOG_DEBUG(3),
"noqname proof not found");
return (DNS_R_NOVALIDNSEC);
}
+ if ((val->attributes & VALATTR_FOUNDNOQNAME) == 0 &&
+ (val->attributes & VALATTR_FOUNDNODATA) == 0)
+ findnsec3proofs(val);
+
/*
* Do we need to check for the wildcard?
*/
if ((val->attributes & VALATTR_FOUNDNOQNAME) != 0 &&
+ (val->attributes & VALATTR_FOUNDCLOSEST) != 0 &&
(((val->attributes & VALATTR_NEEDNODATA) != 0 &&
(val->attributes & VALATTR_FOUNDNODATA) == 0) ||
(val->attributes & VALATTR_NEEDNOWILDCARD) != 0)) {
- result = checkwildcard(val);
+ result = checkwildcard(val, dns_rdatatype_nsec, NULL);
if (result != ISC_R_SUCCESS)
return (result);
}
if (((val->attributes & VALATTR_NEEDNODATA) != 0 &&
- (val->attributes & VALATTR_FOUNDNODATA) != 0) ||
+ ((val->attributes & VALATTR_FOUNDNODATA) != 0 ||
+ (val->attributes & VALATTR_FOUNDOPTOUT) != 0)) ||
((val->attributes & VALATTR_NEEDNOQNAME) != 0 &&
(val->attributes & VALATTR_FOUNDNOQNAME) != 0 &&
(val->attributes & VALATTR_NEEDNOWILDCARD) != 0 &&
- (val->attributes & VALATTR_FOUNDNOWILDCARD) != 0)) {
+ (val->attributes & VALATTR_FOUNDNOWILDCARD) != 0 &&
+ (val->attributes & VALATTR_FOUNDCLOSEST) != 0)) {
+ if ((val->attributes & VALATTR_FOUNDOPTOUT) != 0)
+ val->event->optout = ISC_TRUE;
validator_log(val, ISC_LOG_DEBUG(3),
"nonexistence proof(s) found");
return (ISC_R_SUCCESS);
}
+ findnsec3proofs(val);
validator_log(val, ISC_LOG_DEBUG(3),
"nonexistence proof(s) not found");
return (DNS_R_WAIT);
}
}
+
+/*
+ if ((val->attributes & VALATTR_NEEDOPTOUT) == 0 &&
+ val->event->message != NULL) {
+ val->attributes |= VALATTR_NEEDOPTOUT;
+ return (nsecvalidate(val, ISC_FALSE));
+ }
+*/
+
validator_log(val, ISC_LOG_DEBUG(3), "insecurity proof failed");
return (DNS_R_NOTINSECURE); /* Couldn't complete insecurity proof */
event->sigrdataset = sigrdataset;
event->message = message;
memset(event->proofs, 0, sizeof(event->proofs));
+ event->optout = ISC_FALSE;
result = isc_mutex_init(&val->lock);
if (result != ISC_R_SUCCESS)
goto cleanup_event;
dns_rdataset_init(&val->frdataset);
dns_rdataset_init(&val->fsigrdataset);
dns_fixedname_init(&val->wild);
+ dns_fixedname_init(&val->nearest);
+ dns_fixedname_init(&val->closest);
ISC_LINK_INIT(val, link);
val->magic = VALIDATOR_MAGIC;
dns_db_expirenode
dns_db_find
dns_db_findnode
+dns_db_findnsec3node
dns_db_findrdataset
dns_db_findzonecut
+dns_db_getnsec3parameters
dns_db_getoriginnode
dns_db_getrrsetstats
dns_db_getsoaserial
dns_ncache_add
dns_ncache_getrdataset
dns_ncache_towire
+dns_nsec3_active
+dns_nsec3_addnsec3
+dns_nsec3_addnsec3s
+dns_nsec3_buildrdata
+dns_nsec3_delnsec3
+dns_nsec3_delnsec3s
+dns_nsec3_hashlength
+dns_nsec3_hashname
+dns_nsec3_maxiterations
+dns_nsec3_supportedhash
+dns_nsec3_typepresent
dns_nsec_build
dns_nsec_buildrdata
+dns_nsec_nseconly
dns_nsec_typepresent
dns_opcode_totext
dns_opcodestats_create
dns_rdataset_disassociate
dns_rdataset_first
dns_rdataset_getadditional
+dns_rdataset_getclosest
dns_rdataset_getnoqname
dns_rdataset_init
dns_rdataset_invalidate
# End Source File
# Begin Source File
+SOURCE=..\include\dns\nsec3.h
+# End Source File
+# Begin Source File
+
SOURCE=..\include\dns\order.h
# End Source File
# Begin Source File
# End Source File
# Begin Source File
+SOURCE=..\nsec3.c
+# End Source File
+# Begin Source File
+
SOURCE=..\order.c
# End Source File
# Begin Source File
-@erase "$(INTDIR)\name.obj"
-@erase "$(INTDIR)\ncache.obj"
-@erase "$(INTDIR)\nsec.obj"
+ -@erase "$(INTDIR)\nsec3.obj"
-@erase "$(INTDIR)\openssl_link.obj"
-@erase "$(INTDIR)\openssldh_link.obj"
-@erase "$(INTDIR)\openssldsa_link.obj"
"$(INTDIR)\name.obj" \
"$(INTDIR)\ncache.obj" \
"$(INTDIR)\nsec.obj" \
+ "$(INTDIR)\nsec3.obj" \
"$(INTDIR)\order.obj" \
"$(INTDIR)\peer.obj" \
"$(INTDIR)\portlist.obj" \
-@erase "$(INTDIR)\ncache.sbr"
-@erase "$(INTDIR)\nsec.obj"
-@erase "$(INTDIR)\nsec.sbr"
+ -@erase "$(INTDIR)\nsec3.obj"
+ -@erase "$(INTDIR)\nsec3.sbr"
-@erase "$(INTDIR)\openssl_link.obj"
-@erase "$(INTDIR)\openssl_link.sbr"
-@erase "$(INTDIR)\openssldh_link.obj"
"$(INTDIR)\name.sbr" \
"$(INTDIR)\ncache.sbr" \
"$(INTDIR)\nsec.sbr" \
+ "$(INTDIR)\nsec3.sbr" \
"$(INTDIR)\order.sbr" \
"$(INTDIR)\peer.sbr" \
"$(INTDIR)\portlist.sbr" \
"$(INTDIR)\name.obj" \
"$(INTDIR)\ncache.obj" \
"$(INTDIR)\nsec.obj" \
+ "$(INTDIR)\nsec3.obj" \
"$(INTDIR)\order.obj" \
"$(INTDIR)\peer.obj" \
"$(INTDIR)\portlist.obj" \
$(CPP) $(CPP_PROJ) $(SOURCE)
+!ENDIF
+
+SOURCE=..\nsec3.c
+
+!IF "$(CFG)" == "libdns - Win32 Release"
+
+
+"$(INTDIR)\nsec3.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libdns - Win32 Debug"
+
+
+"$(INTDIR)\nsec3.obj" "$(INTDIR)\nsec3.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
!ENDIF
SOURCE=..\order.c
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zone.c,v 1.480 2008/04/09 04:29:16 marka Exp $ */
+/* $Id: zone.c,v 1.481 2008/09/24 02:46:22 marka Exp $ */
/*! \file */
#include <dns/message.h>
#include <dns/name.h>
#include <dns/nsec.h>
+#include <dns/nsec3.h>
#include <dns/peer.h>
#include <dns/rcode.h>
#include <dns/rdataclass.h>
#define RANGE(a, min, max) \
(((a) < (min)) ? (min) : ((a) < (max) ? (a) : (max)))
+#define NSEC3REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0)
+
/*
* Default values.
*/
typedef ISC_LIST(dns_io_t) dns_iolist_t;
typedef struct dns_signing dns_signing_t;
typedef ISC_LIST(dns_signing_t) dns_signinglist_t;
+typedef struct dns_nsec3chain dns_nsec3chain_t;
+typedef ISC_LIST(dns_nsec3chain_t) dns_nsec3chainlist_t;
#define DNS_ZONE_CHECKLOCK
#ifdef DNS_ZONE_CHECKLOCK
isc_time_t resigntime;
isc_time_t keywarntime;
isc_time_t signingtime;
+ isc_time_t nsec3chaintime;
isc_uint32_t serial;
isc_uint32_t refresh;
isc_uint32_t retry;
/*%
* Keys that are signing the zone for the first time.
*/
- ISC_LIST(dns_signing_t) signing;
+ dns_signinglist_t signing;
+ dns_nsec3chainlist_t nsec3chain;
/*%
* Signing / re-signing quantum stopping parameters.
*/
dns_dbiterator_t *dbiterator;
dns_secalg_t algorithm;
isc_uint16_t keyid;
+ isc_boolean_t delete;
+ isc_boolean_t done;
ISC_LINK(dns_signing_t) link;
};
+struct dns_nsec3chain {
+ unsigned int magic;
+ dns_db_t *db;
+ dns_dbiterator_t *dbiterator;
+ dns_rdata_nsec3param_t nsec3param;
+ unsigned char salt[255];
+ isc_boolean_t done;
+ isc_boolean_t seen_nsec;
+ isc_boolean_t delete_nsec;
+ isc_boolean_t save_delete_nsec;
+ ISC_LINK(dns_nsec3chain_t) link;
+};
+/*%<
+ * 'dbiterator' contains a iterator for the database. If we are creating
+ * a NSEC3 chain only the non-NSEC3 nodes will be iterated. If we are
+ * removing a NSEC3 chain then both NSEC3 and non-NSEC3 nodes will be
+ * iterated.
+ *
+ * 'nsec3param' contains the parameters of the NSEC3 chain being created
+ * or removed.
+ *
+ * 'salt' is buffer space and is referenced via 'nsec3param.salt'.
+ *
+ * 'seen_nsec' will be set to true if, while iterating the zone to create a
+ * NSEC3 chain, a NSEC record is seen.
+ *
+ * 'delete_nsec' will be set to true if, at the completion of the creation
+ * of a NSEC3 chain, 'seen_nsec' is true. If 'delete_nsec' is true then we
+ * are in the process of deleting the NSEC chain.
+ *
+ * 'save_delete_nsec' is used to store the initial state of 'delete_nsec'
+ * so it can be recovered in the event of a error.
+ */
+
+
#define SEND_BUFFER_SIZE 2048
static void zone_settimer(dns_zone_t *, isc_time_t *);
isc_sockaddr_t *local,
isc_time_t *now);
static isc_result_t zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm,
- isc_uint16_t keyid);
+ isc_uint16_t keyid, isc_boolean_t delete);
#define ENTER zone_debuglog(zone, me, 1, "enter")
isc_time_settoepoch(&zone->resigntime);
isc_time_settoepoch(&zone->keywarntime);
isc_time_settoepoch(&zone->signingtime);
+ isc_time_settoepoch(&zone->nsec3chaintime);
zone->serial = 0;
zone->refresh = DNS_ZONE_DEFAULTREFRESH;
zone->retry = DNS_ZONE_DEFAULTRETRY;
zone->isself = NULL;
zone->isselfarg = NULL;
ISC_LIST_INIT(zone->signing);
+ ISC_LIST_INIT(zone->nsec3chain);
zone->signatures = 10;
zone->nodes = 100;
zone->privatetype = (dns_rdatatype_t)0xffffU;
zone_free(dns_zone_t *zone) {
isc_mem_t *mctx = NULL;
dns_signing_t *signing;
+ dns_nsec3chain_t *nsec3chain;
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(isc_refcount_current(&zone->erefs) == 0);
dns_dbiterator_destroy(&signing->dbiterator);
isc_mem_put(zone->mctx, signing, sizeof *signing);
}
+ for (nsec3chain = ISC_LIST_HEAD(zone->nsec3chain);
+ nsec3chain != NULL;
+ nsec3chain = ISC_LIST_HEAD(zone->nsec3chain)) {
+ ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, link);
+ dns_db_detach(&nsec3chain->db);
+ dns_dbiterator_destroy(&nsec3chain->dbiterator);
+ isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain);
+ }
if (zone->masterfile != NULL)
isc_mem_free(zone->mctx, zone->masterfile);
zone->masterfile = NULL;
dns_rdataset_init(&rdataset);
dns_rdata_init(&rdata);
- result = dns_db_createiterator(db, ISC_FALSE, &dbiterator);
+ result = dns_db_createiterator(db, 0, &dbiterator);
if (result != ISC_R_SUCCESS)
return (ISC_TRUE);
}
static void
-set_signingtime(dns_zone_t *zone) {
+resume_signingwithkey(dns_zone_t *zone) {
dns_dbnode_t *node = NULL;
dns_dbversion_t *version = NULL;
dns_rdata_t rdata = DNS_RDATA_INIT;
result = dns_rdataset_next(&rdataset))
{
dns_rdataset_current(&rdataset, &rdata);
- if (rdata.length != 4 || rdata.data[3] != 0) {
+ if (rdata.length != 5 || rdata.data[4] != 0) {
dns_rdata_reset(&rdata);
continue;
}
result = zone_signwithkey(zone, rdata.data[0],
- (rdata.data[1] << 8) | rdata.data[2]);
+ (rdata.data[1] << 8) | rdata.data[2], ISC_TF(rdata.data[3]));
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR,
"zone_signwithkey failed: %s",
}
+static isc_result_t
+zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) {
+ dns_nsec3chain_t *nsec3chain, *current;
+ isc_result_t result;
+ isc_time_t now;
+ unsigned int options = 0;
+
+ nsec3chain = isc_mem_get(zone->mctx, sizeof *nsec3chain);
+ if (nsec3chain == NULL)
+ return (ISC_R_NOMEMORY);
+
+ nsec3chain->magic = 0;
+ nsec3chain->done = ISC_FALSE;
+ nsec3chain->db = NULL;
+ nsec3chain->dbiterator = NULL;
+ nsec3chain->nsec3param.common.rdclass = nsec3param->common.rdclass;
+ nsec3chain->nsec3param.common.rdtype = nsec3param->common.rdtype;
+ nsec3chain->nsec3param.hash = nsec3param->hash;
+ nsec3chain->nsec3param.iterations = nsec3param->iterations;
+ nsec3chain->nsec3param.flags = nsec3param->flags;
+ nsec3chain->nsec3param.salt_length = nsec3param->salt_length;
+ memcpy(nsec3chain->salt, nsec3param->salt, nsec3param->salt_length);
+ nsec3chain->nsec3param.salt = nsec3chain->salt;
+ nsec3chain->seen_nsec = ISC_FALSE;
+ nsec3chain->delete_nsec = ISC_FALSE;
+ nsec3chain->save_delete_nsec = ISC_FALSE;
+
+ for (current = ISC_LIST_HEAD(zone->nsec3chain);
+ current != NULL;
+ current = ISC_LIST_NEXT(current, link)) {
+ if (current->db == zone->db &&
+ current->nsec3param.hash == nsec3param->hash &&
+ current->nsec3param.iterations == nsec3param->iterations &&
+ current->nsec3param.salt_length == nsec3param->salt_length
+ && !memcmp(current->nsec3param.salt, nsec3param->salt,
+ nsec3param->salt_length))
+ current->done = ISC_TRUE;
+ }
+
+ if (zone->db != NULL) {
+ dns_db_attach(zone->db, &nsec3chain->db);
+ if ((nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0)
+ options = DNS_DB_NONSEC3;
+ result = dns_db_createiterator(nsec3chain->db, options,
+ &nsec3chain->dbiterator);
+ if (result == ISC_R_SUCCESS)
+ dns_dbiterator_first(nsec3chain->dbiterator);
+ if (result == ISC_R_SUCCESS) {
+ dns_dbiterator_pause(nsec3chain->dbiterator);
+ ISC_LIST_INITANDAPPEND(zone->nsec3chain,
+ nsec3chain, link);
+ nsec3chain = NULL;
+ if (isc_time_isepoch(&zone->nsec3chaintime)) {
+ TIME_NOW(&now);
+ zone->nsec3chaintime = now;
+ if (zone->task != NULL)
+ zone_settimer(zone, &now);
+ }
+ }
+ } else
+ result = ISC_R_NOTFOUND;
+
+ if (nsec3chain != NULL) {
+ if (nsec3chain->db != NULL)
+ dns_db_detach(&nsec3chain->db);
+ if (nsec3chain->dbiterator != NULL)
+ dns_dbiterator_destroy(&nsec3chain->dbiterator);
+ isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain);
+ }
+ return (result);
+}
+
+static void
+resume_addnsec3chain(dns_zone_t *zone) {
+ dns_dbnode_t *node = NULL;
+ dns_dbversion_t *version = NULL;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_t rdataset;
+ isc_result_t result;
+ dns_rdata_nsec3param_t nsec3param;
+
+ result = dns_db_findnode(zone->db, &zone->origin, ISC_FALSE, &node);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ dns_db_currentversion(zone->db, &version);
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findrdataset(zone->db, node, version,
+ dns_rdatatype_nsec3param,
+ dns_rdatatype_none, 0,
+ &rdataset, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset))
+ {
+ dns_rdataset_current(&rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ if ((nsec3param.flags & DNS_NSEC3FLAG_CREATE) != 0 ||
+ (nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) {
+ result = zone_addnsec3chain(zone, &nsec3param);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_addnsec3chain failed: %s",
+ dns_result_totext(result));
+ }
+ }
+ dns_rdata_reset(&rdata);
+ }
+ dns_rdataset_disassociate(&rdataset);
+
+ cleanup:
+ if (node != NULL)
+ dns_db_detachnode(zone->db, &node);
+ if (version != NULL)
+ dns_db_closeversion(zone->db, &version, ISC_FALSE);
+}
+
static void
set_resigntime(dns_zone_t *zone) {
dns_rdataset_t rdataset;
isc_time_set(&zone->resigntime, resign, nanosecs);
}
+static isc_result_t
+check_nsec3param(dns_zone_t *zone, dns_db_t *db) {
+ dns_dbnode_t *node = NULL;
+ dns_rdataset_t rdataset;
+ dns_dbversion_t *version = NULL;
+ dns_rdata_nsec3param_t nsec3param;
+ isc_boolean_t ok = ISC_FALSE;
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_boolean_t dynamic = (zone->type == dns_zone_master) ?
+ zone_isdynamic(zone) : ISC_FALSE;
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findnode(db, &zone->origin, ISC_FALSE, &node);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "nsec3param lookup failure: %s",
+ dns_result_totext(result));
+ return (result);
+ }
+ dns_db_currentversion(db, &version);
+
+ result = dns_db_findrdataset(db, node, version,
+ dns_rdatatype_nsec3param,
+ dns_rdatatype_none, 0, &rdataset, NULL);
+ if (result == ISC_R_NOTFOUND) {
+ result = ISC_R_SUCCESS;
+ goto cleanup;
+ }
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "nsec3param lookup failure: %s",
+ dns_result_totext(result));
+ goto cleanup;
+ }
+
+ /*
+ * For dynamic zones we must support every algorithm so we can
+ * regenerate all the NSEC3 chains.
+ * For non-dynamic zones we only need to find a supported algorithm.
+ */
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset))
+ {
+ dns_rdataset_current(&rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
+ dns_rdata_reset(&rdata);
+ INSIST(result == ISC_R_SUCCESS);
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NSEC3TESTZONE) &&
+ nsec3param.hash == DNS_NSEC3_UNKNOWNALG && !dynamic)
+ {
+ dns_zone_log(zone, ISC_LOG_WARNING,
+ "nsec3 test \"unknown\" hash algorithm found: %u",
+ nsec3param.hash);
+ ok = ISC_TRUE;
+ } else if (!dns_nsec3_supportedhash(nsec3param.hash)) {
+ if (dynamic) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "unsupported nsec3 hash algorithm"
+ " in dynamic zone: %u",
+ nsec3param.hash);
+ result = DNS_R_BADZONE;
+ /* Stop second error message. */
+ ok = ISC_TRUE;
+ break;
+ } else
+ dns_zone_log(zone, ISC_LOG_WARNING,
+ "unsupported nsec3 hash algorithm: %u",
+ nsec3param.hash);
+ } else
+ ok = ISC_TRUE;
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ if (!ok) {
+ result = DNS_R_BADZONE;
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "no supported nsec3 hash algorithm");
+ }
+
+ cleanup:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ dns_db_closeversion(db, &version, ISC_FALSE);
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
static isc_result_t
zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
isc_result_t result)
result = DNS_R_BADZONE;
goto cleanup;
}
+ if (zone->type != dns_zone_stub) {
+ result = check_nsec3param(zone, db);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ }
if (zone->type == dns_zone_master &&
DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKINTEGRITY) &&
!integrity_checks(zone, db)) {
if (zone->task != NULL) {
if (zone->type == dns_zone_master) {
set_resigntime(zone);
- set_signingtime(zone);
+ resume_signingwithkey(zone);
+ resume_addnsec3chain(zone);
}
zone_settimer(zone, &now);
}
dns_rdataset_init(&rdataset);
- result = dns_db_findnode(db, name, ISC_FALSE, &node);
+ if (type == dns_rdatatype_nsec3)
+ result = dns_db_findnsec3node(db, name, ISC_FALSE, &node);
+ else
+ result = dns_db_findnode(db, name, ISC_FALSE, &node);
if (result == ISC_R_NOTFOUND)
return (ISC_R_SUCCESS);
if (result != ISC_R_SUCCESS)
dns_rdataset_init(&rdataset);
isc_buffer_init(&buffer, data, sizeof(data));
- result = dns_db_findnode(db, name, ISC_FALSE, &node);
+ if (type == dns_rdatatype_nsec3)
+ result = dns_db_findnsec3node(db, name, ISC_FALSE, &node);
+ else
+ result = dns_db_findnode(db, name, ISC_FALSE, &node);
if (result == ISC_R_NOTFOUND)
return (ISC_R_SUCCESS);
if (result != ISC_R_SUCCESS)
dns_rdatasetiter_t *rdsit = NULL;
dns_dbnode_t *node = NULL;
- CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit));
+ CHECK(dns_db_createiterator(db, DNS_DB_NONSEC3, &dbit));
CHECK(dns_dbiterator_seek(dbit, oldname));
do {
result = dns_dbiterator_next(dbit);
return (ISC_FALSE);
}
+static isc_result_t
+add_nsec(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
+ dns_dbnode_t *node, dns_ttl_t ttl, isc_boolean_t bottom,
+ dns_diff_t *diff)
+{
+ dns_fixedname_t fixed;
+ dns_name_t *next;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_result_t result;
+ unsigned char nsecbuffer[DNS_NSEC_BUFFERSIZE];
+
+ dns_fixedname_init(&fixed);
+ next = dns_fixedname_name(&fixed);
+
+ CHECK(next_active(db, version, name, next, bottom));
+ CHECK(dns_nsec_buildrdata(db, version, node, next, nsecbuffer,
+ &rdata));
+ if (dns_name_equal(dns_db_origin(db), name)) {
+ /*
+ * Set the OPT bit to indicate that this is a
+ * partially secure zone.
+ */
+ isc_region_t region;
+
+ dns_rdata_toregion(&rdata, ®ion);
+ dns_name_fromregion(next, ®ion);
+ isc_region_consume(®ion, next->length);
+ INSIST(region.length > (2 + dns_rdatatype_opt / 8) &&
+ region.base[0] == 0 &&
+ region.base[1] > dns_rdatatype_opt / 8);
+ set_bit(region.base + 2, dns_rdatatype_opt);
+ }
+ CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADD, name, ttl,
+ &rdata));
+ failure:
+ return (result);
+}
+
static isc_result_t
sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node,
- dns_dbversion_t *version, dst_key_t *key,
+ dns_dbversion_t *version, isc_boolean_t build_nsec3,
+ isc_boolean_t build_nsec, dst_key_t *key,
isc_stdtime_t inception, isc_stdtime_t expire,
- unsigned int minimum,
- isc_boolean_t is_ksk, isc_boolean_t *delegation,
- dns_diff_t *diff, isc_int32_t *signatures, isc_mem_t *mctx)
+ unsigned int minimum, isc_boolean_t is_ksk,
+ isc_boolean_t *delegation, dns_diff_t *diff,
+ isc_int32_t *signatures, isc_mem_t *mctx)
{
isc_result_t result;
dns_rdatasetiter_t *iterator = NULL;
dns_rdata_t rdata = DNS_RDATA_INIT;
isc_buffer_t buffer;
unsigned char data[1024];
- isc_boolean_t seen_soa, seen_ns, seen_rr, seen_dname, seen_nsec;
- unsigned char nsecbuffer[DNS_NSEC_BUFFERSIZE];
+ isc_boolean_t seen_soa, seen_ns, seen_rr, seen_dname, seen_nsec,
+ seen_nsec3, seen_ds;
isc_boolean_t bottom;
- dns_name_t *next;
- dns_fixedname_t fixed;
result = dns_db_allrdatasets(db, node, version, 0, &iterator);
if (result != ISC_R_SUCCESS) {
}
dns_rdataset_init(&rdataset);
isc_buffer_init(&buffer, data, sizeof(data));
- seen_rr = seen_soa = seen_ns = seen_dname = seen_nsec = ISC_FALSE;
+ seen_rr = seen_soa = seen_ns = seen_dname = seen_nsec =
+ seen_nsec3 = seen_ds = ISC_FALSE;
for (result = dns_rdatasetiter_first(iterator);
result == ISC_R_SUCCESS;
result = dns_rdatasetiter_next(iterator)) {
seen_soa = ISC_TRUE;
else if (rdataset.type == dns_rdatatype_ns)
seen_ns = ISC_TRUE;
+ else if (rdataset.type == dns_rdatatype_ds)
+ seen_ds = ISC_TRUE;
else if (rdataset.type == dns_rdatatype_dname)
seen_dname = ISC_TRUE;
else if (rdataset.type == dns_rdatatype_nsec)
seen_nsec = ISC_TRUE;
+ else if (rdataset.type == dns_rdatatype_nsec3)
+ seen_nsec3 = ISC_TRUE;
seen_rr = ISC_TRUE;
dns_rdataset_disassociate(&rdataset);
}
goto failure;
if (seen_ns && !seen_soa)
*delegation = ISC_TRUE;
- if (!seen_nsec && seen_rr) {
+ /*
+ * Going from insecure to NSEC3.
+ * Don't generate NSEC3 records for NSEC3 records.
+ */
+ if (build_nsec3 && !seen_nsec3 && seen_rr) {
+ isc_boolean_t unsecure = !seen_ds && seen_ns && !seen_soa;
+ CHECK(dns_nsec3_addnsec3s(db, version, name, minimum,
+ unsecure, diff));
+ (*signatures)--;
+ }
+ /*
+ * Going from insecure to NSEC.
+ * Don't generate NSEC records for NSEC3 records.
+ */
+ if (build_nsec && !seen_nsec3 && !seen_nsec && seen_rr) {
/* Build and add NSEC. */
- dns_fixedname_init(&fixed);
- next = dns_fixedname_name(&fixed);
bottom = (seen_ns && !seen_soa) || seen_dname;
- CHECK(next_active(db, version, name, next, bottom));
- CHECK(dns_nsec_buildrdata(db, version, node, next, nsecbuffer,
- &rdata));
- if (dns_name_equal(dns_db_origin(db), name)) {
- /*
- * Set the OPT bit to indicate that this is a
- * partially secure zone.
- */
- isc_region_t region;
-
- dns_rdata_toregion(&rdata, ®ion);
- dns_name_fromregion(next, ®ion);
- isc_region_consume(®ion, next->length);
- INSIST(region.length > (2 + dns_rdatatype_opt / 8) &&
- region.base[0] == 0 &&
- region.base[1] > dns_rdatatype_opt / 8);
- set_bit(region.base + 2, dns_rdatatype_opt);
- }
- CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADD, name,
- minimum, &rdata));
- dns_rdata_reset(&rdata);
+ CHECK(add_nsec(db, version, name, node, minimum, bottom, diff));
/* Count a NSEC generation as a signature generation. */
(*signatures)--;
}
dns_dbnode_t *node = NULL;
/*
- * Check to see if the OPT bit has already been cleared.
+ * Check to see if the OPT bit has already been cleared.
+ */
+ CHECK(dns_db_getoriginnode(db, &node));
+ dns_rdataset_init(&rdataset);
+ CHECK(dns_db_findrdataset(db, node, version, dns_rdatatype_nsec,
+ dns_rdatatype_none, 0, &rdataset, NULL));
+ CHECK(dns_rdataset_first(&rdataset));
+ dns_rdataset_current(&rdataset, &rdata);
+
+ /*
+ * Find the NEXT name for building the new record.
+ */
+ CHECK(dns_rdata_tostruct(&rdata, &nsec, NULL));
+
+ /*
+ * Delete the old NSEC record.
+ */
+ CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_DEL, name, minimum,
+ &rdata));
+ dns_rdata_reset(&rdata);
+
+ /*
+ * Add the new NSEC record.
+ */
+ CHECK(dns_nsec_buildrdata(db, version, node, &nsec.next, nsecbuffer,
+ &rdata));
+ CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADD, name, minimum,
+ &rdata));
+ dns_rdata_reset(&rdata);
+
+ if (secureupdated != NULL)
+ *secureupdated = ISC_TRUE;
+
+ failure:
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ return (result);
+}
+
+static isc_result_t
+updatesignwithkey(dns_signing_t *signing, dns_dbversion_t *version,
+ dns_name_t *name, dns_rdatatype_t privatetype,
+ dns_diff_t *diff)
+{
+ isc_result_t result;
+ dns_dbnode_t *node = NULL;
+ dns_rdataset_t rdataset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ unsigned char data[5];
+ isc_boolean_t seen_done = ISC_FALSE;
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_getoriginnode(signing->db, &node);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ result = dns_db_findrdataset(signing->db, node, version, privatetype,
+ dns_rdatatype_none, 0, &rdataset, NULL);
+ if (result == ISC_R_NOTFOUND) {
+ result = ISC_R_SUCCESS;
+ goto failure;
+ }
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdataset_current(&rdataset, &rdata);
+ if (rdata.length != 5 ||
+ rdata.data[0] != signing->algorithm ||
+ rdata.data[1] != ((signing->keyid >> 8) & 0xff) ||
+ rdata.data[2] != (signing->keyid & 0xff)) {
+ dns_rdata_reset(&rdata);
+ continue;
+ }
+ if (!signing->delete && rdata.data[4] != 0)
+ seen_done = ISC_TRUE;
+ else
+ CHECK(update_one_rr(signing->db, version, diff,
+ DNS_DIFFOP_DEL, name, rdataset.ttl, &rdata));
+ dns_rdata_reset(&rdata);
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ if (!signing->delete && !seen_done) {
+
+ data[0] = signing->algorithm;
+ data[1] = (signing->keyid >> 8) & 0xff;
+ data[2] = signing->keyid & 0xff;
+ data[3] = 0;
+ data[4] = 1;
+ rdata.length = sizeof(data);
+ rdata.data = data;
+ rdata.type = privatetype;
+ rdata.rdclass = dns_db_class(signing->db);
+ CHECK(update_one_rr(signing->db, version, diff, DNS_DIFFOP_ADD,
+ name, rdataset.ttl, &rdata));
+ }
+ failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ if (node != NULL)
+ dns_db_detachnode(signing->db, &node);
+ return (result);
+}
+
+static isc_result_t
+fixup_nsec3param(dns_db_t *db, dns_dbversion_t *ver, dns_nsec3chain_t *chain,
+ isc_boolean_t active, dns_diff_t *diff)
+{
+ dns_dbnode_t *node = NULL;
+ dns_name_t *name = dns_db_origin(db);
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_t rdataset;
+ dns_rdata_nsec3param_t nsec3param;
+ isc_result_t result;
+ isc_buffer_t buffer;
+ unsigned char parambuf[DNS_NSEC3PARAM_BUFFERSIZE];
+ dns_ttl_t ttl = 0;
+
+ dns_rdataset_init(&rdataset);
+
+ result = dns_db_getoriginnode(db, &node);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
+ 0, 0, &rdataset, NULL);
+ if (result == ISC_R_NOTFOUND)
+ goto add;
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ /*
+ * Preserve the existing ttl.
+ */
+ ttl = rdataset.ttl;
+
+ /*
+ * Delete all NSEC3PARAM records which match that in nsec3chain.
+ */
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+
+ dns_rdataset_current(&rdataset, &rdata);
+ CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
+
+ if (nsec3param.hash != chain->nsec3param.hash ||
+ (active && nsec3param.flags != 0) ||
+ nsec3param.iterations != chain->nsec3param.iterations ||
+ nsec3param.salt_length != chain->nsec3param.salt_length ||
+ memcmp(nsec3param.salt, chain->nsec3param.salt,
+ nsec3param.salt_length)) {
+ dns_rdata_reset(&rdata);
+ continue;
+ }
+
+ CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_DEL,
+ name, rdataset.ttl, &rdata));
+ dns_rdata_reset(&rdata);
+ }
+ if (result != ISC_R_NOMORE)
+ goto failure;
+
+ add:
+ if ((chain->nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) {
+ result = ISC_R_SUCCESS;
+ goto failure;
+ }
+
+ /*
+ * Add a NSEC3PARAM record which matches that in nsec3chain but
+ * with all flags bits cleared.
+ *
+ * Note: we do not clear chain->nsec3param.flags as this change
+ * may be reversed.
+ */
+ isc_buffer_init(&buffer, ¶mbuf, sizeof(parambuf));
+ CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db),
+ dns_rdatatype_nsec3param,
+ &chain->nsec3param, &buffer));
+ rdata.data[1] = 0; /* Clear flag bits. */
+ CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, name, ttl, &rdata));
+
+ failure:
+ dns_db_detachnode(db, &node);
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ return (result);
+}
+
+static isc_result_t
+delete_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node,
+ dns_name_t *name, dns_diff_t *diff)
+{
+ dns_rdataset_t rdataset;
+ isc_result_t result;
+
+ dns_rdataset_init(&rdataset);
+
+ result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec,
+ 0, 0, &rdataset, NULL);
+ if (result == ISC_R_NOTFOUND)
+ return (ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ dns_rdataset_current(&rdataset, &rdata);
+ CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, name,
+ rdataset.ttl, &rdata));
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ failure:
+ dns_rdataset_disassociate(&rdataset);
+ return (result);
+}
+
+static isc_result_t
+deletematchingnsec3(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node,
+ dns_name_t *name, const dns_rdata_nsec3param_t *param,
+ dns_diff_t *diff)
+{
+ dns_rdataset_t rdataset;
+ dns_rdata_nsec3_t nsec3;
+ isc_result_t result;
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3,
+ 0, 0, &rdataset, NULL);
+ if (result == ISC_R_NOTFOUND)
+ return (ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ dns_rdataset_current(&rdataset, &rdata);
+ CHECK(dns_rdata_tostruct(&rdata, &nsec3, NULL));
+ if (nsec3.hash != param->hash ||
+ nsec3.iterations != param->iterations ||
+ nsec3.salt_length != param->salt_length ||
+ memcmp(nsec3.salt, param->salt, nsec3.salt_length))
+ continue;
+ CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_DEL, name,
+ rdataset.ttl, &rdata));
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ failure:
+ dns_rdataset_disassociate(&rdataset);
+ return (result);
+}
+
+static isc_result_t
+need_nsec_chain(dns_db_t *db, dns_dbversion_t *ver,
+ const dns_rdata_nsec3param_t *param,
+ isc_boolean_t *answer, isc_boolean_t *updatensec)
+{
+ dns_dbnode_t *node = NULL;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_nsec3param_t myparam;
+ dns_rdataset_t rdataset;
+ isc_result_t result;
+
+ *answer = ISC_FALSE;
+
+ result = dns_db_getoriginnode(db, &node);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec,
+ 0, 0, &rdataset, NULL);
+ if (result == ISC_R_NOTFOUND)
+ goto check_nsec3param;
+
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ CHECK(dns_rdataset_first(&rdataset));
+ dns_rdataset_current(&rdataset, &rdata);
+
+ if (!dns_nsec_typepresent(&rdata, dns_rdatatype_opt)) {
+ /*
+ * We have a complete NSEC chain. Signal to update
+ * the apex NSEC record.
+ */
+ *updatensec = ISC_TRUE;
+ goto failure;
+ }
+ dns_rdataset_disassociate(&rdataset);
+ dns_rdata_reset(&rdata);
+
+ check_nsec3param:
+ result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
+ 0, 0, &rdataset, NULL);
+ if (result == ISC_R_NOTFOUND) {
+ *answer = ISC_TRUE;
+ dns_db_detachnode(db, &node);
+ return (ISC_R_SUCCESS);
+ }
+ if (result != ISC_R_SUCCESS) {
+ dns_db_detachnode(db, &node);
+ return (result);
+ }
+
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdataset_current(&rdataset, &rdata);
+ CHECK(dns_rdata_tostruct(&rdata, &myparam, NULL));
+ dns_rdata_reset(&rdata);
+ /*
+ * Ignore any NSEC3PARAM removals.
+ */
+ if (NSEC3REMOVE(myparam.flags))
+ continue;
+ /*
+ * Ignore the chain that we are in the process of deleting.
+ */
+ if (myparam.hash == param->hash &&
+ myparam.iterations == param->iterations &&
+ myparam.salt_length == param->salt_length &&
+ !memcmp(myparam.salt, param->salt, myparam.salt_length))
+ continue;
+ /*
+ * Found an active NSEC3 chain.
+ */
+ break;
+ }
+ if (result == ISC_R_NOMORE) {
+ *answer = ISC_TRUE;
+ result = ISC_R_SUCCESS;
+ }
+
+ failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
+/*
+ * Incrementally build and sign a new NSEC3 chain using the parameters
+ * requested.
+ */
+static void
+zone_nsec3chain(dns_zone_t *zone) {
+ const char *journalfile;
+ dns_db_t *db = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_dbversion_t *version = NULL;
+ dns_diff_t sig_diff;
+ dns_diff_t nsec_diff;
+ dns_diff_t nsec3_diff;
+ dns_diff_t param_diff;
+ dns_fixedname_t fixed;
+ dns_fixedname_t nextfixed;
+ dns_name_t *name, *nextname;
+ dns_rdataset_t rdataset;
+ dns_nsec3chain_t *nsec3chain = NULL, *nextnsec3chain;
+ dns_nsec3chainlist_t cleanup;
+ dst_key_t *zone_keys[MAXZONEKEYS];
+ isc_int32_t signatures;
+ isc_boolean_t check_ksk, is_ksk;
+ isc_boolean_t delegation;
+ isc_boolean_t first;
+ isc_result_t result;
+ isc_stdtime_t now, inception, soaexpire, expire, stop;
+ isc_uint32_t jitter;
+ unsigned int i;
+ unsigned int nkeys = 0;
+ isc_uint32_t nodes;
+ isc_boolean_t unsecure = ISC_FALSE;
+ isc_boolean_t seen_soa, seen_ns, seen_dname, seen_ds;
+ isc_boolean_t seen_nsec, seen_nsec3, seen_rr;
+ dns_rdatasetiter_t *iterator = NULL;
+ dns_difftuple_t *tuple;
+ isc_boolean_t buildnsecchain;
+ isc_boolean_t updatensec = ISC_FALSE;
+
+ dns_rdataset_init(&rdataset);
+ dns_fixedname_init(&fixed);
+ name = dns_fixedname_name(&fixed);
+ dns_fixedname_init(&nextfixed);
+ nextname = dns_fixedname_name(&nextfixed);
+ dns_diff_init(zone->mctx, ¶m_diff);
+ dns_diff_init(zone->mctx, &nsec3_diff);
+ dns_diff_init(zone->mctx, &nsec_diff);
+ dns_diff_init(zone->mctx, &sig_diff);
+ sig_diff.resign = zone->sigresigninginterval;
+ ISC_LIST_INIT(cleanup);
+
+ /*
+ * Updates are disabled. Pause for 5 minutes.
+ */
+ if (zone->update_disabled) {
+ result = ISC_R_FAILURE;
+ goto failure;
+ }
+
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ dns_db_attach(zone->db, &db);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+
+ result = dns_db_newversion(db, &version);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_nsec3chain:dns_db_newversion -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+
+ result = find_zone_keys(zone, db, version, zone->mctx,
+ MAXZONEKEYS, zone_keys, &nkeys);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_nsec3chain:find_zone_keys -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+
+ isc_stdtime_get(&now);
+ inception = now - 3600; /* Allow for clock skew. */
+ soaexpire = now + dns_zone_getsigvalidityinterval(zone);
+
+ /*
+ * Spread out signatures over time if they happen to be
+ * clumped. We don't do this for each add_sigs() call as
+ * we still want some clustering to occur.
+ */
+ isc_random_get(&jitter);
+ expire = soaexpire - jitter % 3600;
+ stop = now + 5;
+
+ check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
+ if (check_ksk)
+ check_ksk = ksk_sanity(db, version);
+
+ /*
+ * We keep pulling nodes off each interator in turn until
+ * we have no more nodes to pull off or we reach the limits
+ * for this quantum.
+ */
+ nodes = zone->nodes;
+ signatures = zone->signatures;
+ LOCK_ZONE(zone);
+ nsec3chain = ISC_LIST_HEAD(zone->nsec3chain);
+ UNLOCK_ZONE(zone);
+ first = ISC_TRUE;
+
+ if (nsec3chain != NULL)
+ nsec3chain->save_delete_nsec = nsec3chain->delete_nsec;
+ /*
+ * Generate new NSEC3 chains first.
+ */
+ while (nsec3chain != NULL && nodes-- > 0 && signatures > 0) {
+ LOCK_ZONE(zone);
+ nextnsec3chain = ISC_LIST_NEXT(nsec3chain, link);
+
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ if (nsec3chain->done || nsec3chain->db != zone->db) {
+ ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain, link);
+ ISC_LIST_APPEND(cleanup, nsec3chain, link);
+ }
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+ UNLOCK_ZONE(zone);
+ if (ISC_LIST_TAIL(cleanup) == nsec3chain)
+ goto next_addchain;
+
+ /*
+ * Possible future db.
+ */
+ if (nsec3chain->db != db) {
+ goto next_addchain;
+ }
+
+ if (NSEC3REMOVE(nsec3chain->nsec3param.flags))
+ goto next_addchain;
+
+ is_ksk = ISC_FALSE;
+ delegation = ISC_FALSE;
+ dns_dbiterator_current(nsec3chain->dbiterator, &node, name);
+
+ if (nsec3chain->delete_nsec) {
+ delegation = ISC_FALSE;
+ dns_dbiterator_pause(nsec3chain->dbiterator);
+ CHECK(delete_nsec(db, version, node, name, &nsec_diff));
+ goto next_addnode;
+ }
+ /*
+ * On the first pass we need to check if the current node
+ * has not been obscured.
+ */
+ delegation = ISC_FALSE;
+ unsecure = ISC_FALSE;
+ if (first) {
+ dns_fixedname_t ffound;
+ dns_name_t *found;
+ dns_fixedname_init(&ffound);
+ found = dns_fixedname_name(&ffound);
+ result = dns_db_find(db, name, version,
+ dns_rdatatype_soa,
+ DNS_DBFIND_NOWILD, 0, NULL, found,
+ NULL, NULL);
+ if ((result == DNS_R_DELEGATION ||
+ result == DNS_R_DNAME) &&
+ !dns_name_equal(name, found)) {
+ /*
+ * Remember the obscuring name so that
+ * we skip all obscured names.
+ */
+ dns_name_copy(found, name, NULL);
+ delegation = ISC_TRUE;
+ goto next_addnode;
+ }
+ }
+
+ /*
+ * Check to see if this is a bottom of zone node.
+ */
+ result = dns_db_allrdatasets(db, node, version, 0, &iterator);
+ if (result == ISC_R_NOTFOUND) /* Empty node? */
+ goto next_addnode;
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ seen_soa = seen_ns = seen_dname = seen_ds = seen_nsec =
+ ISC_FALSE;
+ for (result = dns_rdatasetiter_first(iterator);
+ result == ISC_R_SUCCESS;
+ result = dns_rdatasetiter_next(iterator)) {
+ dns_rdatasetiter_current(iterator, &rdataset);
+ INSIST(rdataset.type != dns_rdatatype_nsec3);
+ if (rdataset.type == dns_rdatatype_soa)
+ seen_soa = ISC_TRUE;
+ else if (rdataset.type == dns_rdatatype_ns)
+ seen_ns = ISC_TRUE;
+ else if (rdataset.type == dns_rdatatype_dname)
+ seen_dname = ISC_TRUE;
+ else if (rdataset.type == dns_rdatatype_ds)
+ seen_ds = ISC_TRUE;
+ else if (rdataset.type == dns_rdatatype_nsec)
+ seen_nsec = ISC_TRUE;
+ dns_rdataset_disassociate(&rdataset);
+ }
+ dns_rdatasetiter_destroy(&iterator);
+ /*
+ * Is there a NSEC chain than needs to be cleaned up?
+ */
+ if (seen_nsec)
+ nsec3chain->seen_nsec = ISC_TRUE;
+ if (seen_ns && !seen_soa && !seen_ds)
+ unsecure = ISC_TRUE;
+ if ((seen_ns && !seen_soa) || seen_dname)
+ delegation = ISC_TRUE;
+
+ /*
+ * Process one node.
+ */
+ dns_dbiterator_pause(nsec3chain->dbiterator);
+ CHECK(dns_nsec3_addnsec3(db, version, name,
+ &nsec3chain->nsec3param,
+ zone->minimum, unsecure, &nsec3_diff));
+ /*
+ * Treat each call to dns_nsec3_addnsec3() as if it's cost is
+ * two signatures. Additionally there will, in general, be
+ * two signature generated below.
+ *
+ * If we are only changing the optout flag the cost is half
+ * that of the cost of generating a completely new chain.
+ */
+ signatures -= 4;
+
+ /*
+ * Go onto next node.
+ */
+ next_addnode:
+ first = ISC_FALSE;
+ dns_db_detachnode(db, &node);
+ do {
+ result = dns_dbiterator_next(nsec3chain->dbiterator);
+
+ if (result == ISC_R_NOMORE && nsec3chain->delete_nsec) {
+ CHECK(fixup_nsec3param(db, version, nsec3chain,
+ ISC_FALSE, ¶m_diff));
+ LOCK_ZONE(zone);
+ ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain,
+ link);
+ UNLOCK_ZONE(zone);
+ ISC_LIST_APPEND(cleanup, nsec3chain, link);
+ goto next_addchain;
+ }
+ if (result == ISC_R_NOMORE) {
+ dns_dbiterator_pause(nsec3chain->dbiterator);
+ if (nsec3chain->seen_nsec) {
+ CHECK(fixup_nsec3param(db, version,
+ nsec3chain,
+ ISC_TRUE,
+ ¶m_diff));
+ nsec3chain->delete_nsec = ISC_TRUE;
+ goto same_addchain;
+ }
+ CHECK(fixup_nsec3param(db, version, nsec3chain,
+ ISC_FALSE, ¶m_diff));
+ LOCK_ZONE(zone);
+ ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain,
+ link);
+ UNLOCK_ZONE(zone);
+ ISC_LIST_APPEND(cleanup, nsec3chain, link);
+ goto next_addchain;
+ } else if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_nsec3chain:"
+ "dns_dbiterator_next -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ } else if (delegation) {
+ dns_dbiterator_current(nsec3chain->dbiterator,
+ &node, nextname);
+ dns_db_detachnode(db, &node);
+ if (!dns_name_issubdomain(nextname, name))
+ break;
+ } else
+ break;
+ } while (1);
+ continue;
+
+ same_addchain:
+ CHECK(dns_dbiterator_first(nsec3chain->dbiterator));
+ first = ISC_TRUE;
+ continue;
+
+ next_addchain:
+ dns_dbiterator_pause(nsec3chain->dbiterator);
+ nsec3chain = nextnsec3chain;
+ first = ISC_TRUE;
+ if (nsec3chain != NULL)
+ nsec3chain->save_delete_nsec = nsec3chain->delete_nsec;
+ }
+
+ /*
+ * Process removals.
+ */
+ LOCK_ZONE(zone);
+ nsec3chain = ISC_LIST_HEAD(zone->nsec3chain);
+ UNLOCK_ZONE(zone);
+ first = ISC_TRUE;
+ buildnsecchain = ISC_FALSE;
+ while (nsec3chain != NULL && nodes-- > 0 && signatures > 0) {
+ LOCK_ZONE(zone);
+ nextnsec3chain = ISC_LIST_NEXT(nsec3chain, link);
+ UNLOCK_ZONE(zone);
+
+ if (nsec3chain->db != db)
+ goto next_removechain;
+
+ if (!NSEC3REMOVE(nsec3chain->nsec3param.flags))
+ goto next_removechain;
+
+ /*
+ * Work out if we need to build a NSEC chain as a consequence
+ * of removing this NSEC3 chain.
+ */
+ if (first && !updatensec &&
+ (nsec3chain->nsec3param.flags & DNS_NSEC3FLAG_NONSEC) == 0)
+ CHECK(need_nsec_chain(db, version,
+ &nsec3chain->nsec3param,
+ &buildnsecchain, &updatensec));
+
+ dns_dbiterator_current(nsec3chain->dbiterator, &node, name);
+ delegation = ISC_FALSE;
+
+ if (!buildnsecchain) {
+ /*
+ * Delete the NSECPARAM record that matches this chain.
+ */
+ if (first)
+ CHECK(fixup_nsec3param(db, version, nsec3chain,
+ ISC_TRUE, ¶m_diff));
+
+ /*
+ * Delete the NSEC3 records.
+ */
+ CHECK(deletematchingnsec3(db, version, node, name,
+ &nsec3chain->nsec3param,
+ &nsec3_diff));
+ goto next_removenode;
+ }
+
+ if (first) {
+ dns_fixedname_t ffound;
+ dns_name_t *found;
+ dns_fixedname_init(&ffound);
+ found = dns_fixedname_name(&ffound);
+ result = dns_db_find(db, name, version,
+ dns_rdatatype_soa,
+ DNS_DBFIND_NOWILD, 0, NULL, found,
+ NULL, NULL);
+ if ((result == DNS_R_DELEGATION ||
+ result == DNS_R_DNAME) &&
+ !dns_name_equal(name, found)) {
+ /*
+ * Remember the obscuring name so that
+ * we skip all obscured names.
+ */
+ dns_name_copy(found, name, NULL);
+ delegation = ISC_TRUE;
+ goto next_removenode;
+ }
+ }
+
+ /*
+ * Check to see if this is a bottom of zone node.
+ */
+ result = dns_db_allrdatasets(db, node, version, 0, &iterator);
+ if (result == ISC_R_NOTFOUND) /* Empty node? */
+ goto next_removenode;
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ seen_soa = seen_ns = seen_dname = seen_nsec3 = seen_nsec =
+ seen_rr = ISC_FALSE;
+ for (result = dns_rdatasetiter_first(iterator);
+ result == ISC_R_SUCCESS;
+ result = dns_rdatasetiter_next(iterator)) {
+ dns_rdatasetiter_current(iterator, &rdataset);
+ if (rdataset.type == dns_rdatatype_soa)
+ seen_soa = ISC_TRUE;
+ else if (rdataset.type == dns_rdatatype_ns)
+ seen_ns = ISC_TRUE;
+ else if (rdataset.type == dns_rdatatype_dname)
+ seen_dname = ISC_TRUE;
+ else if (rdataset.type == dns_rdatatype_nsec)
+ seen_nsec = ISC_TRUE;
+ else if (rdataset.type == dns_rdatatype_nsec3)
+ seen_nsec3 = ISC_TRUE;
+ seen_rr = ISC_TRUE;
+ dns_rdataset_disassociate(&rdataset);
+ }
+ dns_rdatasetiter_destroy(&iterator);
+
+ if (!seen_rr || seen_nsec3 || seen_nsec)
+ goto next_removenode;
+ if ((seen_ns && !seen_soa) || seen_dname)
+ delegation = ISC_TRUE;
+
+ CHECK(add_nsec(db, version, name, node, zone->minimum,
+ delegation, &nsec_diff));
+
+ next_removenode:
+ first = ISC_FALSE;
+ dns_db_detachnode(db, &node);
+ do {
+ result = dns_dbiterator_next(nsec3chain->dbiterator);
+ if (result == ISC_R_NOMORE && buildnsecchain) {
+ /*
+ * The NSEC chain should now be built.
+ * We can now remove the NSEC3 chain.
+ */
+ updatensec = ISC_TRUE;
+ goto same_removechain;
+ }
+ if (result == ISC_R_NOMORE) {
+ LOCK_ZONE(zone);
+ ISC_LIST_UNLINK(zone->nsec3chain, nsec3chain,
+ link);
+ UNLOCK_ZONE(zone);
+ ISC_LIST_APPEND(cleanup, nsec3chain, link);
+ dns_dbiterator_pause(nsec3chain->dbiterator);
+ CHECK(fixup_nsec3param(db, version, nsec3chain,
+ ISC_FALSE, ¶m_diff));
+ goto next_removechain;
+ } else if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_nsec3chain:"
+ "dns_dbiterator_next -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ } else if (delegation) {
+ dns_dbiterator_current(nsec3chain->dbiterator,
+ &node, nextname);
+ dns_db_detachnode(db, &node);
+ if (!dns_name_issubdomain(nextname, name))
+ break;
+ } else
+ break;
+ } while (1);
+ continue;
+
+ same_removechain:
+ CHECK(dns_dbiterator_first(nsec3chain->dbiterator));
+ buildnsecchain = ISC_FALSE;
+ first = ISC_TRUE;
+ continue;
+
+ next_removechain:
+ dns_dbiterator_pause(nsec3chain->dbiterator);
+ nsec3chain = nextnsec3chain;
+ first = ISC_TRUE;
+ }
+
+ /*
+ * Add / update signatures for the NSEC3 records.
+ */
+ for (tuple = ISC_LIST_HEAD(nsec3_diff.tuples);
+ tuple != NULL;
+ tuple = ISC_LIST_HEAD(nsec3_diff.tuples)) {
+ /*
+ * We have changed the NSEC3 RRset above so we need to update
+ * the signatures.
+ */
+ result = del_sigs(zone, db, version, &tuple->name,
+ dns_rdatatype_nsec3, &sig_diff,
+ zone_keys, nkeys, now);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_nsec3chain:del_sigs -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+ result = add_sigs(db, version, &tuple->name,
+ dns_rdatatype_nsec3, &sig_diff, zone_keys,
+ nkeys, zone->mctx, inception, expire,
+ check_ksk);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_nsec3chain:add_sigs -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+
+ do {
+ dns_difftuple_t *next = ISC_LIST_NEXT(tuple, link);
+ while (next != NULL &&
+ !dns_name_equal(&tuple->name, &next->name))
+ next = ISC_LIST_NEXT(next, link);
+ ISC_LIST_UNLINK(nsec3_diff.tuples, tuple, link);
+ dns_diff_appendminimal(&sig_diff, &tuple);
+ INSIST(tuple == NULL);
+ tuple = next;
+ } while (tuple != NULL);
+ }
+
+ for (tuple = ISC_LIST_HEAD(param_diff.tuples);
+ tuple != NULL;
+ tuple = ISC_LIST_HEAD(param_diff.tuples)) {
+ /*
+ * We have changed the NSEC3PARAM RRset above so we need to
+ * update the signatures.
+ */
+ result = del_sigs(zone, db, version, &tuple->name,
+ dns_rdatatype_nsec3param, &sig_diff,
+ zone_keys, nkeys, now);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_nsec3chain:del_sigs -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+ result = add_sigs(db, version, &tuple->name,
+ dns_rdatatype_nsec3param, &sig_diff,
+ zone_keys, nkeys, zone->mctx, inception,
+ expire, check_ksk);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_nsec3chain:add_sigs -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+ ISC_LIST_UNLINK(param_diff.tuples, tuple, link);
+ dns_diff_appendminimal(&sig_diff, &tuple);
+ INSIST(tuple == NULL);
+ }
+
+ if (updatensec)
+ CHECK(updatesecure(db, version, &zone->origin, zone->minimum,
+ NULL, &nsec_diff));
+
+ for (tuple = ISC_LIST_HEAD(nsec_diff.tuples);
+ tuple != NULL;
+ tuple = ISC_LIST_HEAD(nsec_diff.tuples)) {
+ result = del_sigs(zone, db, version, &tuple->name,
+ dns_rdatatype_nsec, &sig_diff,
+ zone_keys, nkeys, now);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_nsec3chain:del_sigs -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+ result = add_sigs(db, version, &tuple->name,
+ dns_rdatatype_nsec, &sig_diff,
+ zone_keys, nkeys, zone->mctx, inception,
+ expire, check_ksk);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_nsec3chain:add_sigs -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+ ISC_LIST_UNLINK(nsec_diff.tuples, tuple, link);
+ dns_diff_appendminimal(&sig_diff, &tuple);
+ INSIST(tuple == NULL);
+ }
+
+ /*
+ * If we made no effective changes to the zone then we can just
+ * cleanup otherwise we need to increment the serial.
*/
- CHECK(dns_db_getoriginnode(db, &node));
- dns_rdataset_init(&rdataset);
- CHECK(dns_db_findrdataset(db, node, version, dns_rdatatype_nsec,
- dns_rdatatype_none, 0, &rdataset, NULL));
- CHECK(dns_rdataset_first(&rdataset));
- dns_rdataset_current(&rdataset, &rdata);
- if (!dns_nsec_typepresent(&rdata, dns_rdatatype_opt))
+ if (ISC_LIST_HEAD(sig_diff.tuples) == NULL)
+ goto done;
+
+ result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa,
+ &sig_diff, zone_keys, nkeys, now);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:"
+ "del_sigs -> %s\n", dns_result_totext(result));
+ goto failure;
+ }
+
+ result = increment_soa_serial(db, version, &sig_diff, zone->mctx);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:"
+ "increment_soa_serial -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+
+ result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa,
+ &sig_diff, zone_keys, nkeys, zone->mctx, inception,
+ soaexpire, check_ksk);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:"
+ "add_sigs -> %s\n", dns_result_totext(result));
goto failure;
+ }
+
+ journalfile = dns_zone_getjournal(zone);
+ if (journalfile != NULL) {
+ dns_journal_t *journal = NULL;
+ result = dns_journal_open(zone->mctx, journalfile,
+ ISC_TRUE, &journal);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:"
+ "dns_journal_open -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+
+ result = dns_journal_write_transaction(journal, &sig_diff);
+ dns_journal_destroy(&journal);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:"
+ "dns_journal_write_transaction -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+ }
+
+ LOCK_ZONE(zone);
+ zone_needdump(zone, DNS_DUMP_DELAY);
+ UNLOCK_ZONE(zone);
+ done:
/*
- * Find the NEXT name for building the new record.
+ * Pause all iterators so that dns_db_closeversion() can succeed.
*/
- CHECK(dns_rdata_tostruct(&rdata, &nsec, NULL));
+ LOCK_ZONE(zone);
+ for (nsec3chain = ISC_LIST_HEAD(zone->nsec3chain);
+ nsec3chain != NULL;
+ nsec3chain = ISC_LIST_NEXT(nsec3chain, link))
+ dns_dbiterator_pause(nsec3chain->dbiterator);
+ UNLOCK_ZONE(zone);
/*
- * Delete the old NSEC record.
+ * Everything has succeeded. Commit the changes.
*/
- CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_DEL, name, minimum,
- &rdata));
- dns_rdata_reset(&rdata);
+ dns_db_closeversion(db, &version, ISC_TRUE);
/*
- * Add the new NSEC record.
+ * Everything succeeded so we can clean these up now.
*/
- CHECK(dns_nsec_buildrdata(db, version, node, &nsec.next, nsecbuffer,
- &rdata));
- CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADD, name, minimum,
- &rdata));
- dns_rdata_reset(&rdata);
+ nsec3chain = ISC_LIST_HEAD(cleanup);
+ while (nsec3chain != NULL) {
+ ISC_LIST_UNLINK(cleanup, nsec3chain, link);
+ dns_db_detach(&nsec3chain->db);
+ dns_dbiterator_destroy(&nsec3chain->dbiterator);
+ isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain);
+ nsec3chain = ISC_LIST_HEAD(cleanup);
+ }
- *secureupdated = ISC_TRUE;
+ set_resigntime(zone);
failure:
- if (node != NULL)
- dns_db_detachnode(db, &node);
- if (dns_rdataset_isassociated(&rdataset))
- dns_rdataset_disassociate(&rdataset);
- return (result);
+ /*
+ * On error roll back the current nsec3chain.
+ */
+ if (result != ISC_R_SUCCESS && nsec3chain != NULL) {
+ if (nsec3chain->done) {
+ dns_db_detach(&nsec3chain->db);
+ dns_dbiterator_destroy(&nsec3chain->dbiterator);
+ isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain);
+ } else {
+ result = dns_dbiterator_first(nsec3chain->dbiterator);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ dns_dbiterator_pause(nsec3chain->dbiterator);
+ nsec3chain->delete_nsec = nsec3chain->save_delete_nsec;
+ }
+ }
+
+ /*
+ * Rollback the cleanup list.
+ */
+ nsec3chain = ISC_LIST_TAIL(cleanup);
+ while (nsec3chain != NULL) {
+ ISC_LIST_UNLINK(cleanup, nsec3chain, link);
+ if (nsec3chain->done) {
+ dns_db_detach(&nsec3chain->db);
+ dns_dbiterator_destroy(&nsec3chain->dbiterator);
+ isc_mem_put(zone->mctx, nsec3chain, sizeof *nsec3chain);
+ } else {
+ LOCK_ZONE(zone);
+ ISC_LIST_PREPEND(zone->nsec3chain, nsec3chain, link);
+ UNLOCK_ZONE(zone);
+ result = dns_dbiterator_first(nsec3chain->dbiterator);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ dns_dbiterator_pause(nsec3chain->dbiterator);
+ nsec3chain->delete_nsec = nsec3chain->save_delete_nsec;
+ }
+ nsec3chain = ISC_LIST_TAIL(cleanup);
+ }
+
+ LOCK_ZONE(zone);
+ for (nsec3chain = ISC_LIST_HEAD(zone->nsec3chain);
+ nsec3chain != NULL;
+ nsec3chain = ISC_LIST_NEXT(nsec3chain, link))
+ dns_dbiterator_pause(nsec3chain->dbiterator);
+ UNLOCK_ZONE(zone);
+
+ dns_diff_clear(¶m_diff);
+ dns_diff_clear(&nsec3_diff);
+ dns_diff_clear(&nsec_diff);
+ dns_diff_clear(&sig_diff);
+
+ if (iterator != NULL)
+ dns_rdatasetiter_destroy(&iterator);
+
+ for (i = 0; i < nkeys; i++)
+ dst_key_free(&zone_keys[i]);
+
+ if (version != NULL) {
+ dns_db_closeversion(db, &version, ISC_FALSE);
+ dns_db_detach(&db);
+ } else if (db != NULL)
+ dns_db_detach(&db);
+
+ LOCK_ZONE(zone);
+ if (ISC_LIST_HEAD(zone->nsec3chain) != NULL) {
+ isc_interval_t i;
+ if (zone->update_disabled || result != ISC_R_SUCCESS)
+ isc_interval_set(&i, 60, 0); /* 1 minute */
+ else
+ isc_interval_set(&i, 0, 10000000); /* 10 ms */
+ isc_time_nowplusinterval(&zone->nsec3chaintime, &i);
+ } else
+ isc_time_settoepoch(&zone->nsec3chaintime);
+ UNLOCK_ZONE(zone);
}
static isc_result_t
-updatesignwithkey(dns_signing_t *signing, dns_dbversion_t *version,
- dns_name_t *name, dns_rdatatype_t privatetype,
- dns_diff_t *diff)
+del_sig(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
+ dns_dbnode_t *node, unsigned int nkeys, dns_secalg_t algorithm,
+ isc_uint16_t keyid, dns_diff_t *diff)
{
- isc_result_t result;
- dns_dbnode_t *node = NULL;
+ dns_rdata_rrsig_t rrsig;
dns_rdataset_t rdataset;
- dns_rdata_t rdata = DNS_RDATA_INIT;
- unsigned char data[4];
-
- dns_rdataset_init(&rdataset);
- result = dns_db_getoriginnode(signing->db, &node);
- if (result != ISC_R_SUCCESS)
- goto failure;
+ dns_rdatasetiter_t *iterator = NULL;
+ isc_result_t result;
- result = dns_db_findrdataset(signing->db, node, version, privatetype,
- dns_rdatatype_none, 0, &rdataset, NULL);
- if (result == ISC_R_NOTFOUND) {
- result = ISC_R_SUCCESS;
- goto failure;
+ result = dns_db_allrdatasets(db, node, version, 0, &iterator);
+ if (result != ISC_R_SUCCESS) {
+ if (result == ISC_R_NOTFOUND)
+ result = ISC_R_SUCCESS;
+ return (result);
}
- if (result != ISC_R_SUCCESS)
- goto failure;
- for (result = dns_rdataset_first(&rdataset);
+
+ dns_rdataset_init(&rdataset);
+ for (result = dns_rdatasetiter_first(iterator);
result == ISC_R_SUCCESS;
- result = dns_rdataset_next(&rdataset)) {
- dns_rdataset_current(&rdataset, &rdata);
- if (rdata.length != 4 ||
- rdata.data[0] != signing->algorithm ||
- rdata.data[1] != ((signing->keyid >> 8) & 0xff) ||
- rdata.data[2] != (signing->keyid & 0xff) ||
- rdata.data[3] != 0) {
- dns_rdata_reset(&rdata);
+ result = dns_rdatasetiter_next(iterator)) {
+ dns_rdatasetiter_current(iterator, &rdataset);
+ if (nkeys == 0 && rdataset.type == dns_rdatatype_nsec) {
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_current(&rdataset, &rdata);
+ CHECK(update_one_rr(db, version, diff,
+ DNS_DIFFOP_DEL, name,
+ rdataset.ttl, &rdata));
+ }
+ if (result != ISC_R_NOMORE)
+ goto failure;
+ dns_rdataset_disassociate(&rdataset);
continue;
}
- CHECK(update_one_rr(signing->db, version, diff, DNS_DIFFOP_DEL,
- name, rdataset.ttl, &rdata));
- memcpy(data, rdata.data, 4);
- data[3] = 1; /* mark as done */
- rdata.data = data;
- CHECK(update_one_rr(signing->db, version, diff, DNS_DIFFOP_ADD,
- name, rdataset.ttl, &rdata));
- break;
+ if (rdataset.type != dns_rdatatype_rrsig) {
+ dns_rdataset_disassociate(&rdataset);
+ continue;
+ }
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_current(&rdataset, &rdata);
+ CHECK(dns_rdata_tostruct(&rdata, &rrsig, NULL));
+ if (rrsig.algorithm != algorithm ||
+ rrsig.keyid != keyid)
+ continue;
+ CHECK(update_one_rr(db, version, diff,
+ DNS_DIFFOP_DEL, name,
+ rdataset.ttl, &rdata));
+ }
+ dns_rdataset_disassociate(&rdataset);
+ if (result != ISC_R_NOMORE)
+ break;
}
if (result == ISC_R_NOMORE)
result = ISC_R_SUCCESS;
failure:
if (dns_rdataset_isassociated(&rdataset))
dns_rdataset_disassociate(&rdataset);
- if (node != NULL)
- dns_db_detachnode(signing->db, &node);
+ dns_rdatasetiter_destroy(&iterator);
return (result);
}
/*
* Incrementally sign the zone using the keys requested.
- * Builds the NSEC chain is required.
+ * Builds the NSEC chain if required.
*/
static void
zone_sign(dns_zone_t *zone) {
isc_boolean_t delegation;
isc_boolean_t finishedakey = ISC_FALSE;
isc_boolean_t secureupdated = ISC_FALSE;
+ isc_boolean_t build_nsec3 = ISC_FALSE, build_nsec = ISC_FALSE;
isc_boolean_t first;
isc_result_t result;
isc_stdtime_t now, inception, soaexpire, expire, stop;
isc_stdtime_get(&now);
inception = now - 3600; /* Allow for clock skew. */
soaexpire = now + dns_zone_getsigvalidityinterval(zone);
+
/*
* Spread out signatures over time if they happen to be
* clumped. We don't do this for each add_sigs() call as
/*
* We keep pulling nodes off each interator in turn until
- * we have no more noded to pull off or we reach the limits
+ * we have no more nodes to pull off or we reach the limits
* for this quantum.
*/
nodes = zone->nodes;
signatures = zone->signatures;
signing = ISC_LIST_HEAD(zone->signing);
first = ISC_TRUE;
+ /*
+ * See if we have a NSEC chain.
+ */
+ result = dns_db_getoriginnode(db, &node);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ result = dns_db_findrdataset(db, node, version, dns_rdatatype_nsec,
+ dns_rdatatype_none, 0, &rdataset, NULL);
+ dns_db_detachnode(db, &node);
+ if (result == ISC_R_SUCCESS) {
+ build_nsec = ISC_TRUE;
+ dns_rdataset_disassociate(&rdataset);
+ } else if (result != ISC_R_NOTFOUND) {
+ goto failure;
+ } else {
+ /*
+ * No NSEC chain present.
+ * See if we need to build a NSEC3 chain?
+ */
+ result = dns_nsec3_active(db, version, ISC_TRUE, &build_nsec3);
+ if (result == ISC_R_SUCCESS) {
+ if (build_nsec3)
+ build_nsec3 = ISC_FALSE;
+ else {
+ result = dns_nsec3_active(db, version,
+ ISC_FALSE,
+ &build_nsec3);
+ if (build_nsec3)
+ secureupdated = ISC_TRUE;
+ else
+ build_nsec = ISC_TRUE;
+ }
+ }
+ }
+
while (signing != NULL && nodes-- > 0 && signatures > 0) {
nextsigning = ISC_LIST_NEXT(signing, link);
ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
- if (signing->db != zone->db) {
+ if (signing->done || signing->db != zone->db) {
/*
* The zone has been reloaded. We will have
* created new signings as part of the reload
* process so we can destroy this one.
*/
ISC_LIST_UNLINK(zone->signing, signing, link);
- dns_db_detach(&signing->db);
- dns_dbiterator_destroy(&signing->dbiterator);
- isc_mem_put(zone->mctx, signing, sizeof *signing);
+ ISC_LIST_APPEND(cleanup, signing, link);
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
goto next_signing;
}
goto next_signing;
is_ksk = ISC_FALSE;
+ delegation = ISC_FALSE;
+
dns_dbiterator_current(signing->dbiterator, &node, name);
+
+ if (signing->delete) {
+ dns_dbiterator_pause(signing->dbiterator);
+ CHECK(del_sig(db, version, name, node, nkeys,
+ signing->algorithm, signing->keyid,
+ &sig_diff));
+ goto next_node;
+ }
/*
* On the first pass we need to check if the current node
* has not been obscured.
*/
- delegation = ISC_FALSE;
if (first) {
dns_fixedname_t ffound;
dns_name_t *found;
/*
* Process one node.
*/
+ dns_dbiterator_pause(signing->dbiterator);
for (i = 0; i < nkeys; i++) {
/*
* Find the key we want to sign with.
if (check_ksk &&
(dst_key_flags(zone_keys[i]) & DNS_KEYFLAG_KSK) != 0)
is_ksk = ISC_TRUE;
- CHECK(sign_a_node(db, name, node, version,
- zone_keys[i], inception, expire,
- zone->minimum, is_ksk, &delegation,
- &sig_diff, &signatures, zone->mctx));
+ CHECK(sign_a_node(db, name, node, version, build_nsec3,
+ build_nsec, zone_keys[i], inception,
+ expire, zone->minimum, is_ksk,
+ &delegation, &sig_diff, &signatures,
+ zone->mctx));
break;
}
/*
* Go onto next node.
*/
next_node:
+ first = ISC_FALSE;
dns_db_detachnode(db, &node);
do {
result = dns_dbiterator_next(signing->dbiterator);
if (result == ISC_R_NOMORE) {
ISC_LIST_UNLINK(zone->signing, signing, link);
ISC_LIST_APPEND(cleanup, signing, link);
+ dns_dbiterator_pause(signing->dbiterator);
finishedakey = ISC_TRUE;
- if (!is_ksk && !secureupdated) {
+ if (!is_ksk && !secureupdated && nkeys != 0 &&
+ build_nsec) {
/*
* We have finished regenerating the
* zone with a zone signing key.
dns_result_totext(result));
goto failure;
}
- break;
+ goto next_signing;
} else if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR,
"zone_sign:dns_dbiterator_next -> %s\n",
break;
} else
break;
- } while (1);
+ } while (1);
+ continue;
+
next_signing:
+ dns_dbiterator_pause(signing->dbiterator);
signing = nextsigning;
- if (signing == NULL) {
- first = ISC_FALSE;
- signing = ISC_LIST_HEAD(zone->signing);
- }
+ first = ISC_TRUE;
}
if (secureupdated) {
}
}
+
+ /*
+ * Pause all iterators so that dns_db_closeversion() can succeed.
+ */
+ for (signing = ISC_LIST_HEAD(zone->signing);
+ signing != NULL;
+ signing = ISC_LIST_NEXT(signing, link))
+ dns_dbiterator_pause(signing->dbiterator);
+
+ for (signing = ISC_LIST_HEAD(cleanup);
+ signing != NULL;
+ signing = ISC_LIST_NEXT(signing, link))
+ dns_dbiterator_pause(signing->dbiterator);
+
/*
* Everything has succeeded. Commit the changes.
*/
set_resigntime(zone);
+ LOCK_ZONE(zone);
+ zone_needdump(zone, DNS_DUMP_DELAY);
+ UNLOCK_ZONE(zone);
+
failure:
/*
* Rollback the cleanup list.
ISC_LIST_UNLINK(cleanup, signing, link);
ISC_LIST_APPEND(zone->signing, signing, link);
dns_dbiterator_first(signing->dbiterator);
+ dns_dbiterator_pause(signing->dbiterator);
signing = ISC_LIST_HEAD(cleanup);
}
+
for (signing = ISC_LIST_HEAD(zone->signing);
signing != NULL;
signing = ISC_LIST_NEXT(signing, link))
dns_dbiterator_pause(signing->dbiterator);
+
dns_diff_clear(&sig_diff);
+
for (i = 0; i < nkeys; i++)
dst_key_free(&zone_keys[i]);
+
if (version != NULL) {
dns_db_closeversion(db, &version, ISC_FALSE);
dns_db_detach(&db);
} else if (db != NULL)
dns_db_detach(&db);
+
if (ISC_LIST_HEAD(zone->signing) != NULL) {
isc_interval_t i;
- if (zone->update_disabled)
+ if (zone->update_disabled || result != ISC_R_SUCCESS)
isc_interval_set(&i, 60, 0); /* 1 minute */
else
isc_interval_set(&i, 0, 10000000); /* 10 ms */
else if (!isc_time_isepoch(&zone->resigntime) &&
isc_time_compare(&now, &zone->resigntime) >= 0)
zone_resigninc(zone);
+ else if (!isc_time_isepoch(&zone->nsec3chaintime) &&
+ isc_time_compare(&now, &zone->nsec3chaintime) >= 0)
+ zone_nsec3chain(zone);
/*
* Do we need to issue a key expiry warning.
*/
isc_time_compare(&zone->signingtime, &next) < 0)
next = zone->signingtime;
}
+ if (!isc_time_isepoch(&zone->nsec3chaintime)) {
+ if (isc_time_isepoch(&next) ||
+ isc_time_compare(&zone->nsec3chaintime, &next) < 0)
+ next = zone->nsec3chaintime;
+ }
break;
case dns_zone_slave:
return (result);
}
+ result = check_nsec3param(zone, db);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
ver = NULL;
dns_db_currentversion(db, &ver);
isc_result_t
dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm,
- isc_uint16_t keyid)
+ isc_uint16_t keyid, isc_boolean_t delete)
{
isc_result_t result;
REQUIRE(DNS_ZONE_VALID(zone));
"dns_zone_signwithkey(algorithm=%u, keyid=%u)",
algorithm, keyid);
LOCK_ZONE(zone);
- result = zone_signwithkey(zone, algorithm, keyid);
+ result = zone_signwithkey(zone, algorithm, keyid, delete);
UNLOCK_ZONE(zone);
return (result);
}
+static const char *hex = "0123456789ABCDEF";
+
+isc_result_t
+dns_zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param) {
+ isc_result_t result;
+ char salt[255*2+1];
+ unsigned int i, j;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ if (nsec3param->salt_length != 0) {
+ INSIST((nsec3param->salt_length * 2U) < sizeof(salt));
+ for (i = 0, j = 0; i < nsec3param->salt_length; i++) {
+ salt[j++] = hex[(nsec3param->salt[i] >> 4) & 0xf];
+ salt[j++] = hex[nsec3param->salt[i] & 0xf];
+ }
+ salt[j] = '\0';
+ } else
+ strcpy(salt, "-");
+ dns_zone_log(zone, ISC_LOG_NOTICE,
+ "dns_zone_addnsec3chain(hash=%u, iterations=%u, salt=%s)",
+ nsec3param->hash, nsec3param->iterations,
+ salt);
+ LOCK_ZONE(zone);
+ result = zone_addnsec3chain(zone, nsec3param);
+ UNLOCK_ZONE(zone);
+
+ return (result);
+}
+
void
dns_zone_setnodes(dns_zone_t *zone, isc_uint32_t nodes) {
REQUIRE(DNS_ZONE_VALID(zone));
}
static isc_result_t
-zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, isc_uint16_t keyid) {
+zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, isc_uint16_t keyid,
+ isc_boolean_t delete)
+{
dns_signing_t *signing;
- isc_result_t result;
+ dns_signing_t *current;
+ isc_result_t result = ISC_R_SUCCESS;
isc_time_t now;
signing = isc_mem_get(zone->mctx, sizeof *signing);
signing->dbiterator = NULL;
signing->algorithm = algorithm;
signing->keyid = keyid;
+ signing->delete = delete;
+ signing->done = ISC_FALSE;
TIME_NOW(&now);
+ for (current = ISC_LIST_HEAD(zone->signing);
+ current != NULL;
+ current = ISC_LIST_NEXT(current, link)) {
+ if (current->db == zone->db &&
+ current->algorithm == signing->algorithm &&
+ current->keyid == signing->keyid) {
+ if (current->delete != signing->delete)
+ current->done = ISC_TRUE;
+ else
+ goto cleanup;
+ }
+ }
+
if (zone->db != NULL) {
dns_db_attach(zone->db, &signing->db);
- result = dns_db_createiterator(signing->db, ISC_FALSE,
+ result = dns_db_createiterator(signing->db, 0,
&signing->dbiterator);
if (result == ISC_R_SUCCESS)
} else
result = ISC_R_NOTFOUND;
+ cleanup:
if (signing != NULL) {
dns_db_detach(&signing->db);
if (signing->dbiterator != NULL)
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: Makefile.in,v 1.95 2008/06/23 23:47:11 tbox Exp $
+# $Id: Makefile.in,v 1.96 2008/09/24 02:46:23 marka Exp $
srcdir = @srcdir@
VPATH = @srcdir@
# Alphabetically
OBJS = @ISC_EXTRA_OBJS@ \
- assertions.@O@ base64.@O@ bitstring.@O@ buffer.@O@ \
+ assertions.@O@ base32.@O@ base64.@O@ bitstring.@O@ buffer.@O@ \
bufferlist.@O@ commandline.@O@ error.@O@ event.@O@ \
hash.@O@ heap.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@ \
- httpd.@O@ \
+ httpd.@O@ iterated_hash.@O@ \
lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \
md5.@O@ mem.@O@ mutexblock.@O@ \
netaddr.@O@ netscope.@O@ ondestroy.@O@ \
# Alphabetically
SRCS = @ISC_EXTRA_SRCS@ \
- assertions.c base64.c bitstring.c buffer.c \
+ assertions.c base32.c base64.c bitstring.c buffer.c \
bufferlist.c commandline.c error.c event.c \
heap.c hex.c hmacmd5.c hmacsha.c \
- httpd.c \
+ httpd.c iterated_hash.c \
lex.c lfsr.c lib.c log.c \
md5.c mem.c mutexblock.c \
netaddr.c netscope.c ondestroy.c \
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: buffer.c,v 1.47 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: buffer.c,v 1.48 2008/09/24 02:46:23 marka Exp $ */
/*! \file */
ISC__BUFFER_PUTUINT16(b, val);
}
+void
+isc__buffer_putuint24(isc_buffer_t *b, isc_uint32_t val) {
+ REQUIRE(ISC_BUFFER_VALID(b));
+ REQUIRE(b->used + 3 <= b->length);
+
+ ISC__BUFFER_PUTUINT24(b, val);
+}
+
isc_uint32_t
isc_buffer_getuint32(isc_buffer_t *b) {
unsigned char *cp;
*/
base = isc_buffer_used(b);
available = isc_buffer_availablelength(b);
- if (r->length > available)
+ if (r->length > available)
return (ISC_R_NOSPACE);
memcpy(base, r->base, r->length);
b->used += r->length;
* SUCH DAMAGE.
*/
-/* $Id: commandline.c,v 1.20 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: commandline.c,v 1.21 2008/09/24 02:46:23 marka Exp $ */
/*! \file
* This file was adapted from the NetBSD project's source tree, RCS ID:
* the previous argv was finished.
*/
if (isc_commandline_reset || *place == '\0') {
- isc_commandline_reset = ISC_FALSE;
+ if (isc_commandline_reset) {
+ isc_commandline_index = 1;
+ isc_commandline_reset = ISC_FALSE;
+ }
if (isc_commandline_progname == NULL)
isc_commandline_progname = argv[0];
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: hex.c,v 1.18 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: hex.c,v 1.19 2008/09/24 02:46:23 marka Exp $ */
/*! \file */
}
isc_result_t
-isc_hex_decodestring(char *cstr, isc_buffer_t *target) {
+isc_hex_decodestring(const char *cstr, isc_buffer_t *target) {
hex_decode_ctx_t ctx;
hex_decode_init(&ctx, -1, target);
continue;
RETERR(hex_decode_char(&ctx, c));
}
- RETERR(hex_decode_finish(&ctx));
+ RETERR(hex_decode_finish(&ctx));
return (ISC_R_SUCCESS);
}
--- /dev/null
+/*
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1999-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: base32.h,v 1.2 2008/09/24 02:46:23 marka Exp $ */
+
+#ifndef ISC_BASE32_H
+#define ISC_BASE32_H 1
+
+/*! \file */
+
+/*
+ * Routines for manipulating base 32 and base 32 hex encoded data.
+ * Based on RFC 4648.
+ *
+ * Base 32 hex preserves the sort order of data when it is encoded /
+ * decoded.
+ */
+
+#include <isc/lang.h>
+#include <isc/types.h>
+
+ISC_LANG_BEGINDECLS
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+isc_base32_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target);
+isc_result_t
+isc_base32hex_totext(isc_region_t *source, int wordlength,
+ const char *wordbreak, isc_buffer_t *target);
+/*!<
+ * \brief Convert data into base32 encoded text.
+ *
+ * Notes:
+ *\li The base32 encoded text in 'target' will be divided into
+ * words of at most 'wordlength' characters, separated by
+ * the 'wordbreak' string. No parentheses will surround
+ * the text.
+ *
+ * Requires:
+ *\li 'source' is a region containing binary data
+ *\li 'target' is a text buffer containing available space
+ *\li 'wordbreak' points to a null-terminated string of
+ * zero or more whitespace characters
+ *
+ * Ensures:
+ *\li target will contain the base32 encoded version of the data
+ * in source. The 'used' pointer in target will be advanced as
+ * necessary.
+ */
+
+isc_result_t
+isc_base32_decodestring(const char *cstr, isc_buffer_t *target);
+isc_result_t
+isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target);
+/*!<
+ * \brief Decode a null-terminated base32 string.
+ *
+ * Requires:
+ *\li 'cstr' is non-null.
+ *\li 'target' is a valid buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring'
+ * fit in 'target'.
+ *\li #ISC_R_BADBASE32 -- 'cstr' is not a valid base32 encoding.
+ *
+ * Other error returns are any possible error code from:
+ *\li isc_lex_create(),
+ *\li isc_lex_openbuffer(),
+ *\li isc_base32_tobuffer().
+ */
+
+isc_result_t
+isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+isc_result_t
+isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length);
+/*!<
+ * \brief Convert base32 encoded text from a lexer context into data.
+ *
+ * Requires:
+ *\li 'lex' is a valid lexer context
+ *\li 'target' is a buffer containing binary data
+ *\li 'length' is an integer
+ *
+ * Ensures:
+ *\li target will contain the data represented by the base32 encoded
+ * string parsed by the lexer. No more than length bytes will be read,
+ * if length is positive. The 'used' pointer in target will be
+ * advanced as necessary.
+ */
+
+isc_result_t
+isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target);
+isc_result_t
+isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target);
+/*!<
+ * \brief Decode a packed (no white space permitted) base32 region.
+ *
+ * Requires:
+ *\li 'source' is a valid region.
+ *\li 'target' is a valid buffer.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring'
+ * fit in 'target'.
+ *\li #ISC_R_BADBASE32 -- 'source' is not a valid base32 encoding.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_BASE32_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: buffer.h,v 1.51 2007/06/19 23:47:18 tbox Exp $ */
+/* $Id: buffer.h,v 1.52 2008/09/24 02:46:23 marka Exp $ */
#ifndef ISC_BUFFER_H
#define ISC_BUFFER_H 1
struct isc_buffer {
unsigned int magic;
void *base;
- /*@{*/
+ /*@{*/
/*! The following integers are byte offsets from 'base'. */
unsigned int length;
unsigned int used;
unsigned int current;
unsigned int active;
- /*@}*/
+ /*@}*/
/*! linkable */
ISC_LINK(isc_buffer_t) link;
/*! private internal elements */
*\li The used pointer in 'b' is advanced by 6.
*/
+void
+isc__buffer_putuint24(isc_buffer_t *b, isc_uint32_t val);
+/*!<
+ * Store an unsigned 24-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ *\li 'b' is a valid buffer.
+ *
+ * The length of the unused region of 'b' is at least 3.
+ *
+ * Ensures:
+ *\li The used pointer in 'b' is advanced by 3.
+ */
+
void
isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
unsigned int length);
_cp[1] = (unsigned char)(_val2 & 0x00ffU); \
} while (0)
+#define ISC__BUFFER_PUTUINT24(_b, _val) \
+ do { \
+ unsigned char *_cp; \
+ isc_uint32_t _val2 = (_val); \
+ _cp = isc_buffer_used(_b); \
+ (_b)->used += 3; \
+ _cp[0] = (unsigned char)((_val2 & 0xff0000U) >> 16); \
+ _cp[1] = (unsigned char)((_val2 & 0xff00U) >> 8); \
+ _cp[2] = (unsigned char)(_val2 & 0x00ffU); \
+ } while (0)
+
#define ISC__BUFFER_PUTUINT32(_b, _val) \
do { \
unsigned char *_cp; \
#define isc_buffer_putstr ISC__BUFFER_PUTSTR
#define isc_buffer_putuint8 ISC__BUFFER_PUTUINT8
#define isc_buffer_putuint16 ISC__BUFFER_PUTUINT16
+#define isc_buffer_putuint24 ISC__BUFFER_PUTUINT24
#define isc_buffer_putuint32 ISC__BUFFER_PUTUINT32
#else
#define isc_buffer_init isc__buffer_init
#define isc_buffer_putstr isc__buffer_putstr
#define isc_buffer_putuint8 isc__buffer_putuint8
#define isc_buffer_putuint16 isc__buffer_putuint16
+#define isc_buffer_putuint24 isc__buffer_putuint24
#define isc_buffer_putuint32 isc__buffer_putuint32
#endif
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: hex.h,v 1.11 2007/06/19 23:47:18 tbox Exp $ */
+/* $Id: hex.h,v 1.12 2008/09/24 02:46:23 marka Exp $ */
#ifndef ISC_HEX_H
#define ISC_HEX_H 1
*/
isc_result_t
-isc_hex_decodestring(char *cstr, isc_buffer_t *target);
+isc_hex_decodestring(const char *cstr, isc_buffer_t *target);
/*!<
* \brief Decode a null-terminated hex string.
*
--- /dev/null
+/*
+ * Copyright (C) 2004 Nominet, Ltd.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND NOMINET DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL NOMINET BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: iterated_hash.h,v 1.2 2008/09/24 02:46:23 marka Exp $ */
+
+#ifndef ISC_ITERATED_HASH_H
+#define ISC_ITERATED_HASH_H 1
+
+#include <isc/lang.h>
+#include <isc/sha1.h>
+
+/*
+ * The maximal hash length that can be encoded it a name
+ * using base32hex. floor(255/8)*5
+ */
+#define NSEC3_MAX_HASH_LENGTH 155
+
+/*
+ * The maximum has that can be encoded in a single label using
+ * base32hex. floor(63/8)*5
+ */
+#define NSEC3_MAX_LABEL_HASH 35
+
+ISC_LANG_BEGINDECLS
+
+int isc_iterated_hash(unsigned char out[NSEC3_MAX_HASH_LENGTH],
+ unsigned int hashalg, int iterations,
+ const unsigned char *salt, int saltlength,
+ const unsigned char *in, int inlength);
+
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_ITERATED_HASH_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: result.h,v 1.69 2007/06/19 23:47:18 tbox Exp $ */
+/* $Id: result.h,v 1.70 2008/09/24 02:46:23 marka Exp $ */
#ifndef ISC_RESULT_H
#define ISC_RESULT_H 1
#define ISC_R_DISABLED 57 /*%< disabled */
#define ISC_R_MAXSIZE 58 /*%< max size */
#define ISC_R_BADADDRESSFORM 59 /*%< invalid address format */
+#define ISC_R_BADBASE32 60 /*%< bad base32 encoding */
/*% Not a result code: the number of results. */
-#define ISC_R_NRESULTS 60
+#define ISC_R_NRESULTS 61
ISC_LANG_BEGINDECLS
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: result.c,v 1.69 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: result.c,v 1.70 2008/09/24 02:46:23 marka Exp $ */
/*! \file */
"not a valid number", /*%< 56 */
"disabled", /*%< 57 */
"max size", /*%< 58 */
- "invalid address format" /*%< 59 */
+ "invalid address format", /*%< 59 */
+ "bad base32 encoding", /*%< 60 */
};
#define ISC_RESULT_RESULTSET 2
isc_app_unblock
isc_assertion_setcallback
isc_assertion_typetotext
+isc_base32_decoderegion
+isc_base32_decodestring
+isc_base32_tobuffer
+isc_base32_totext
+isc_base32hex_decoderegion
+isc_base32hex_decodestring
+isc_base32hex_tobuffer
+isc_base32hex_totext
isc_base64_decodestring
isc_base64_tobuffer
isc_base64_totext
isc_interfaceiter_next
isc_interval_iszero
isc_interval_set
+isc_iterated_hash
isc_keyboard_canceled
isc_keyboard_close
isc_keyboard_getchar
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\iterated_hash.c\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=.\keyboard.c\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\include\isc\base32.h\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=..\include\isc\base64.h\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\include\isc\iterated_hash.h\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=.\include\isc\keyboard.h\r
# End Source File\r
# Begin Source File\r
# End Source File\r
# Begin Source File\r
\r
+SOURCE=..\base32.c\r
+# End Source File\r
+# Begin Source File\r
+\r
SOURCE=..\base64.c\r
# End Source File\r
# Begin Source File\r
CLEAN :
-@erase "$(INTDIR)\app.obj"
-@erase "$(INTDIR)\assertions.obj"
+ -@erase "$(INTDIR)\base32.obj"
-@erase "$(INTDIR)\base64.obj"
-@erase "$(INTDIR)\bitstring.obj"
-@erase "$(INTDIR)\buffer.obj"
-@erase "$(INTDIR)\inet_pton.obj"
-@erase "$(INTDIR)\interfaceiter.obj"
-@erase "$(INTDIR)\ipv6.obj"
+ -@erase "$(INTDIR)\iterated_hash.obj"
-@erase "$(INTDIR)\keyboard.obj"
-@erase "$(INTDIR)\lex.obj"
-@erase "$(INTDIR)\lfsr.obj"
"$(INTDIR)\fsaccess.obj" \
"$(INTDIR)\interfaceiter.obj" \
"$(INTDIR)\ipv6.obj" \
+ "$(INTDIR)\iterated_hash.obj" \
"$(INTDIR)\keyboard.obj" \
"$(INTDIR)\net.obj" \
"$(INTDIR)\ntpaths.obj" \
"$(INTDIR)\version.obj" \
"$(INTDIR)\win32os.obj" \
"$(INTDIR)\assertions.obj" \
+ "$(INTDIR)\base32.obj" \
"$(INTDIR)\base64.obj" \
"$(INTDIR)\bitstring.obj" \
"$(INTDIR)\buffer.obj" \
-@erase "$(INTDIR)\app.sbr"
-@erase "$(INTDIR)\assertions.obj"
-@erase "$(INTDIR)\assertions.sbr"
+ -@erase "$(INTDIR)\base32.obj"
+ -@erase "$(INTDIR)\base32.sbr"
-@erase "$(INTDIR)\base64.obj"
-@erase "$(INTDIR)\base64.sbr"
-@erase "$(INTDIR)\bitstring.obj"
-@erase "$(INTDIR)\interfaceiter.sbr"
-@erase "$(INTDIR)\ipv6.obj"
-@erase "$(INTDIR)\ipv6.sbr"
+ -@erase "$(INTDIR)\iterated_hash.obj"
+ -@erase "$(INTDIR)\iterated_hash.sbr"
-@erase "$(INTDIR)\keyboard.obj"
-@erase "$(INTDIR)\keyboard.sbr"
-@erase "$(INTDIR)\lex.obj"
"$(INTDIR)\fsaccess.sbr" \
"$(INTDIR)\interfaceiter.sbr" \
"$(INTDIR)\ipv6.sbr" \
+ "$(INTDIR)\iterated_hash.sbr" \
"$(INTDIR)\keyboard.sbr" \
"$(INTDIR)\net.sbr" \
"$(INTDIR)\ntpaths.sbr" \
"$(INTDIR)\version.sbr" \
"$(INTDIR)\win32os.sbr" \
"$(INTDIR)\assertions.sbr" \
+ "$(INTDIR)\base32.sbr" \
"$(INTDIR)\base64.sbr" \
"$(INTDIR)\bitstring.sbr" \
"$(INTDIR)\buffer.sbr" \
"$(INTDIR)\fsaccess.obj" \
"$(INTDIR)\interfaceiter.obj" \
"$(INTDIR)\ipv6.obj" \
+ "$(INTDIR)\iterated_hash.obj" \
"$(INTDIR)\keyboard.obj" \
"$(INTDIR)\net.obj" \
"$(INTDIR)\ntpaths.obj" \
"$(INTDIR)\version.obj" \
"$(INTDIR)\win32os.obj" \
"$(INTDIR)\assertions.obj" \
+ "$(INTDIR)\base32.obj" \
"$(INTDIR)\base64.obj" \
"$(INTDIR)\bitstring.obj" \
"$(INTDIR)\buffer.obj" \
"$(INTDIR)\ipv6.obj" "$(INTDIR)\ipv6.sbr" : $(SOURCE) "$(INTDIR)"
+!ENDIF
+
+
+SOURCE=..\iterated_hash.c
+
+!IF "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\iterated_hash.obj" : $(SOURCE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\iterated_hash.obj" "$(INTDIR)\iterated_hash.sbr" : $(SOURCE) "$(INTDIR)"
+
+
!ENDIF
SOURCE=.\keyboard.c
$(CPP) $(CPP_PROJ) $(SOURCE)
+!ENDIF
+
+SOURCE=..\base32.c
+
+!IF "$(CFG)" == "libisc - Win32 Release"
+
+
+"$(INTDIR)\base32.obj" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF "$(CFG)" == "libisc - Win32 Debug"
+
+
+"$(INTDIR)\base32.obj" "$(INTDIR)\base32.sbr" : $(SOURCE) "$(INTDIR)"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
!ENDIF
SOURCE=..\base64.c
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: grammar.h,v 1.15 2007/06/19 23:47:22 tbox Exp $ */
+/* $Id: grammar.h,v 1.16 2008/09/24 02:46:23 marka Exp $ */
#ifndef ISCCFG_GRAMMAR_H
#define ISCCFG_GRAMMAR_H 1
* "directory" option.
*/
#define CFG_CLAUSEFLAG_CALLBACK 0x00000020
+/*% A option that is only used in testing. */
+#define CFG_CLAUSEFLAG_TESTONLY 0x00000040
typedef struct cfg_clausedef cfg_clausedef_t;
typedef struct cfg_tuplefielddef cfg_tuplefielddef_t;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: namedconf.c,v 1.90 2008/09/04 05:56:43 marka Exp $ */
+/* $Id: namedconf.c,v 1.91 2008/09/24 02:46:23 marka Exp $ */
/*! \file */
{ "notify-source", &cfg_type_sockaddr4wild, 0 },
{ "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
{ "notify-to-soa", &cfg_type_boolean, 0 },
+ { "nsec3-test-zone", &cfg_type_boolean, CFG_CLAUSEFLAG_TESTONLY },
{ "sig-signing-nodes", &cfg_type_uint32, 0 },
{ "sig-signing-signatures", &cfg_type_uint32, 0 },
{ "sig-signing-type", &cfg_type_uint32, 0 },
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: parser.c,v 1.127 2007/10/12 04:17:18 each Exp $ */
+/* $Id: parser.c,v 1.128 2008/09/24 02:46:23 marka Exp $ */
/*! \file */
{ CFG_CLAUSEFLAG_NYI, "not yet implemented" },
{ CFG_CLAUSEFLAG_OBSOLETE, "obsolete" },
{ CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" },
+ { CFG_CLAUSEFLAG_TESTONLY, "test only" },
{ 0, NULL }
};
./bin/tests/net/netaddr_multicast.c C 2000,2001,2004,2007
./bin/tests/net/sockaddr_multicast.c C 2000,2001,2004,2007
./bin/tests/net/testsuite.h C 2000,2001,2004,2007
+./bin/tests/nsec3hash.c C 2006
./bin/tests/nsecify.c C 1999,2000,2001,2003,2004,2007
./bin/tests/printmsg.c C 1998,1999,2000,2001,2004,2007
./bin/tests/printmsg.h C 1998,1999,2000,2001,2004,2007
./bin/tests/system/dnssec/ns1/root.db.in ZONE 2000,2001,2004,2007
./bin/tests/system/dnssec/ns1/sign.sh SH 2000,2001,2002,2003,2004,2006,2007
./bin/tests/system/dnssec/ns2/.cvsignore X 2000,2001
+./bin/tests/system/dnssec/ns2/child.nsec3.example.db ZONE 2006
+./bin/tests/system/dnssec/ns2/child.optout.example.db ZONE 2006
./bin/tests/system/dnssec/ns2/dlv.db.in ZONE 2004,2007
./bin/tests/system/dnssec/ns2/dst.example.db.in ZONE 2004,2007
./bin/tests/system/dnssec/ns2/example.db.in ZONE 2000,2001,2002,2004,2007
./bin/tests/system/dnssec/ns3/dynamic.example.db.in ZONE 2002,2004,2007
./bin/tests/system/dnssec/ns3/insecure.example.db ZONE 2000,2001,2004,2007
./bin/tests/system/dnssec/ns3/keyless.example.db.in ZONE 2001,2002,2004,2007
+./bin/tests/system/dnssec/ns3/multiple.example.db.in ZONE 2006
./bin/tests/system/dnssec/ns3/named.conf CONF-C 2000,2001,2002,2004,2006,2007
+./bin/tests/system/dnssec/ns3/nsec3-unknown.example.db.in ZONE 2006
+./bin/tests/system/dnssec/ns3/nsec3.example.db.in ZONE 2006
+./bin/tests/system/dnssec/ns3/optout-unknown.example.db.in ZONE 2006
+./bin/tests/system/dnssec/ns3/optout.example.db.in ZONE 2006
./bin/tests/system/dnssec/ns3/secure.example.db.in ZONE 2000,2001,2004,2007
./bin/tests/system/dnssec/ns3/sign.sh SH 2000,2001,2002,2004,2006,2007
./bin/tests/system/dnssec/ns4/.cvsignore X 2000,2001
./bin/tests/system/dnssec/ns5/named.conf CONF-C 2000,2001,2004,2006,2007
./bin/tests/system/dnssec/ns5/trusted.conf.bad CONF-C 2000,2001,2004,2007
./bin/tests/system/dnssec/ns6/named.conf CONF-C 2004,2006,2007
+./bin/tests/system/dnssec/ns7/named.conf CONF-C 2006
./bin/tests/system/dnssec/prereq.sh SH 2000,2001,2002,2004,2006,2007
./bin/tests/system/dnssec/setup.sh SH 2000,2001,2004,2007
./bin/tests/system/dnssec/tests.sh SH 2000,2001,2002,2004,2005,2006,2007
./lib/bind/isc/Makefile.in MAKE 2001,2004,2007,2008
./lib/bind/isc/assertions.c X 2001,2004,2005
./lib/bind/isc/assertions.mdoc X 2001,2004
+./lib/bind/isc/base32.c X 2006
./lib/bind/isc/base64.c X 2001,2004,2005
./lib/bind/isc/bitncmp.c X 2001,2004,2005,2008
./lib/bind/isc/bitncmp.mdoc X 2001,2004
./lib/dns/name.c C 1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008
./lib/dns/ncache.c C 1999,2000,2001,2002,2003,2004,2005,2007
./lib/dns/nsec.c C 1999,2000,2001,2003,2004,2005,2007
+./lib/dns/nsec3.c C 2006
./lib/dns/openssl_link.c C.NAI 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008
./lib/dns/openssldh_link.c C.NAI 1999,2000,2001,2002,2004,2005,2006,2007,2008
./lib/dns/openssldsa_link.c C.NAI 1999,2000,2001,2002,2004,2005,2006,2007,2008
./lib/isc/inet_aton.c C.PORTION 1996,1997,1998,1999,2000,2001,2004,2005,2007
./lib/isc/inet_ntop.c C 1996,1997,1998,1999,2000,2001,2004,2005,2007
./lib/isc/inet_pton.c C 1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2007
-./lib/isc/iterated_hash.c C 2008
+./lib/isc/iterated_hash.c C 2006,2008
./lib/isc/lex.c C 1998,1999,2000,2001,2002,2003,2004,2005,2007
./lib/isc/lfsr.c C 1999,2000,2001,2002,2004,2005,2007
./lib/isc/lib.c C 1999,2000,2001,2004,2005,2007