nsec3.c revision 9c03f13e18c1b0c32f62391a17300378605bbc7b
/*
* Copyright (C) 2006, 2008-2011 Internet Systems Consortium, Inc. ("ISC")
*
* 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.24 2011/10/28 06:20:06 each Exp $ */
#include <config.h>
#include <isc/iterated_hash.h>
#include <dns/compress.h>
#include <dns/dbiterator.h>
#include <dns/fixedname.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdatasetiter.h>
#include <dns/rdatastruct.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 INITIAL(x) (((x) & DNS_NSEC3FLAG_INITIAL) != 0)
#define REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0)
static void
if (bit != 0)
else
}
static unsigned int
}
unsigned int flags, unsigned int iterations,
{
isc_region_t r;
unsigned int i, window;
int octet;
unsigned int max_type;
unsigned char *p;
switch (hashalg) {
case dns_hash_sha1:
break;
}
p = buffer;
*p++ = hashalg;
*p++ = flags;
*p++ = iterations >> 8;
*p++ = iterations;
*p++ = salt_length;
p += salt_length;
*p++ = hash_length;
p += hash_length;
/*
* Use the end of the space for a raw bitmap leaving enough
* space for the window identifiers and length octets.
*/
max_type = 0;
goto collapse_bitmap;
if (result != ISC_R_SUCCESS)
return (result);
result == ISC_R_SUCCESS;
{
/*
* Work out if we need to set the RRSIG bit for
* this node. We set the RRSIG bit if either of
* the following conditions are met:
* 1) We have a SOA or DS then we need to set
* the RRSIG bit as both always will be signed.
* 2) We set the RRSIG bit if we don't have
* a NS record but do have other data.
*/
else
}
}
if (dns_rdatatype_rrsig > max_type)
}
/*
* At zone cuts, deny the existence of glue in the parent zone.
*/
for (i = 0; i <= max_type; i++) {
}
}
if (result != ISC_R_NOMORE)
return (result);
break;
break;
if (octet < 0)
continue;
/*
* Note: potentially overlapping move.
*/
}
return (ISC_R_SUCCESS);
}
/* This should never fail */
i += 2;
break;
continue;
type % 256));
break;
}
return (present);
}
unsigned char rethash[NSEC3_MAX_HASH_LENGTH],
{
unsigned char hash[NSEC3_MAX_HASH_LENGTH];
unsigned char nametext[DNS_NAME_FORMATSIZE];
/* hash the node name */
if (len == 0U)
return (DNS_R_BADALG);
if (hash_length != NULL)
*hash_length = len;
/* convert the hash to base32hex */
/* convert the hex to a domain name */
}
unsigned int
switch (hash) {
case dns_hash_sha1: return(ISC_SHA1_DIGESTLENGTH);
}
return (0);
}
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
{
/*
* Create a singleton diff.
*/
/*
* Apply it to the database.
*/
if (result != ISC_R_SUCCESS) {
return (result);
}
/*
* Merge it into the current pending journal entry.
*/
/*
* 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
{
if (result == ISC_R_NOTFOUND) {
return (ISC_R_SUCCESS);
}
if (result != ISC_R_SUCCESS)
return (result);
(isc_stdtime_t) 0, &iter);
if (result != ISC_R_SUCCESS)
goto cleanup_node;
if (result == ISC_R_SUCCESS) {
} else if (result == ISC_R_NOMORE) {
} else
return (result);
}
static isc_boolean_t
const dns_rdata_nsec3param_t *nsec3param)
{
return (ISC_TRUE);
return (ISC_FALSE);
}
/*%
* Delete NSEC3 records at "name" which match "param", recording the
* change in "diff".
*/
static isc_result_t
{
if (result == ISC_R_NOTFOUND)
return (ISC_R_SUCCESS);
if (result != ISC_R_SUCCESS)
return (result);
if (result == ISC_R_NOTFOUND) {
goto cleanup_node;
}
if (result != ISC_R_SUCCESS)
goto cleanup_node;
result == ISC_R_SUCCESS;
{
continue;
if (result != ISC_R_SUCCESS)
goto failure;
if (result != ISC_R_SUCCESS)
goto failure;
}
if (result != ISC_R_NOMORE)
goto failure;
return (result);
}
static isc_boolean_t
return (ISC_TRUE);
result == ISC_R_SUCCESS;
unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
continue;
} else
continue;
continue;
return (ISC_TRUE);
}
}
return (ISC_FALSE);
}
static isc_result_t
const dns_rdata_nsec3param_t *nsec3param)
{
result == ISC_R_SUCCESS;
break;
}
return (result);
}
{
int pass;
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 old_length;
unsigned int salt_length;
/*
* Chain parameters.
*/
/*
* Default flags for a new chain.
*/
/*
* If this is the first NSEC3 in the chain nexthash will
* remain pointing to itself.
*/
next_length = sizeof(nexthash);
salt, salt_length));
/*
* Create the node if it doesn't exist and hold
* a reference to it until we have added the NSEC3.
*/
/*
* Seek the iterator to the 'newnode'.
*/
/*
* If we updating a existing NSEC3 then find its
* next field.
*/
if (result == ISC_R_SUCCESS) {
if (result == ISC_R_SUCCESS) {
/*
* 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;
nsec3param, diff);
goto failure;
} else
} else {
if (result != ISC_R_NOMORE)
goto failure;
}
}
/*
* Find the previous NSEC3 (if any) and update it if required.
*/
pass = 0;
do {
if (result == ISC_R_NOMORE) {
pass++;
}
(isc_stdtime_t) 0, &rdataset,
NULL);
if (result != ISC_R_SUCCESS)
continue;
if (result == ISC_R_NOMORE) {
continue;
}
if (result != ISC_R_SUCCESS)
goto failure;
if (maybe_remove_unsecure) {
/*
* If we have OPTOUT set in the previous NSEC3 record
* we actually need to delete the NSEC3 record.
* Otherwise we just need to replace the NSEC3 record.
*/
nsec3param, diff);
goto failure;
}
goto addnsec3;
} else {
/*
* Is this is a unsecure delegation we are adding?
* If so no change is required.
*/
goto failure;
}
}
/*
* Delete the old previous NSEC3.
*/
/*
* Fixup the previous NSEC3.
*/
&buffer));
break;
} while (pass < 2);
/*
* Create the NSEC3 RDATA.
*/
/*
* Delete the old NSEC3 and record the change.
*/
/*
* Add the new NSEC3 and record the change.
*/
/*
* Add missing NSEC3 records for empty nodes
*/
do {
break;
if (exists)
break;
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.
*/
(isc_stdtime_t) 0, &rdataset,
NULL);
if (result == ISC_R_SUCCESS) {
if (result == ISC_R_SUCCESS) {
break;
}
if (result != ISC_R_NOMORE)
goto failure;
}
/*
* Find the previous NSEC3 and update it.
*/
pass = 0;
do {
if (result == ISC_R_NOMORE) {
pass++;
}
(isc_stdtime_t) 0,
if (result != ISC_R_SUCCESS)
continue;
if (result == ISC_R_NOMORE) {
continue;
}
if (result != ISC_R_SUCCESS)
goto failure;
/*
* Delete the old previous NSEC3.
*/
/*
* Fixup the previous NSEC3.
*/
sizeof(nsec3buf));
&buffer));
&tuple));
break;
} while (pass < 2);
/*
* Create the NSEC3 RDATA for the empty node.
*/
&rdata));
/*
* Delete the old NSEC3 and record the change.
*/
/*
* Add the new NSEC3 and record the change.
*/
} while (1);
if (result == ISC_R_NOMORE)
return (result);
}
/*%
* Add NSEC3 records for "name", recording the change in "diff".
* The existing NSEC3 records are removed.
*/
{
/*
* Find the NSEC3 parameters for this zone.
*/
if (result != ISC_R_SUCCESS)
return (result);
dns_rdatatype_nsec3param, 0, 0,
if (result == ISC_R_NOTFOUND)
return (ISC_R_SUCCESS);
if (result != ISC_R_SUCCESS)
return (result);
/*
* Update each active NSEC3 chain.
*/
result == ISC_R_SUCCESS;
if (nsec3param.flags != 0)
continue;
/*
* We have a active chain. Update it.
*/
}
if (result == ISC_R_NOMORE)
return (result);
}
{
/*
* Algorithm 0 (reserved by RFC 4034) is used to identify
* NSEC3PARAM records from DNSKEY pointers.
*/
return (ISC_FALSE);
}
void
{
buf[0] = 0;
}
#ifdef BIND9
static isc_result_t
{
else
if (result == ISC_R_NOTFOUND) {
goto failure;
}
result == ISC_R_SUCCESS;
break;
}
if (result == ISC_R_SUCCESS) {
} else if (result == ISC_R_NOMORE) {
}
return (result);
}
#endif
#ifdef BIND9
{
if (result != ISC_R_SUCCESS)
return (result);
/*
* Cause all NSEC3 chains to be deleted.
*/
if (result == ISC_R_NOTFOUND)
goto try_private;
if (result != ISC_R_SUCCESS)
goto failure;
result == ISC_R_SUCCESS;
if (nonsec)
if (!flag) {
&tuple));
}
}
if (result != ISC_R_NOMORE)
goto failure;
if (privatetype == 0)
goto success;
if (result == ISC_R_NOTFOUND)
goto success;
if (result != ISC_R_SUCCESS)
goto failure;
result == ISC_R_SUCCESS;
continue;
if (nonsec)
if (!flag) {
}
}
if (result != ISC_R_NOMORE)
goto failure;
return (result);
}
#endif
{
/*
* Find the NSEC3 parameters for this zone.
*/
if (result != ISC_R_SUCCESS)
return (result);
goto failure;
dns_rdatatype_nsec3param, 0, 0,
if (result == ISC_R_NOTFOUND)
goto try_private;
if (result != ISC_R_SUCCESS)
goto failure;
/*
* Update each active NSEC3 chain.
*/
result == ISC_R_SUCCESS;
if (nsec3param.flags != 0)
continue;
/*
* We have a active chain. Update it.
*/
}
if (result != ISC_R_NOMORE)
goto failure;
if (!dns_rdataset_isassociated(&prdataset))
goto success;
/*
* Update each active NSEC3 chain.
*/
result == ISC_R_SUCCESS;
unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
continue;
continue;
continue;
/*
* We have a active chain. Update it.
*/
}
if (result == ISC_R_NOMORE)
return (result);
}
/*%
* Determine whether any NSEC3 records that were associated with
* 'name' should be deleted or if they should continue to exist.
* ISC_TRUE indicates they should be deleted.
* ISC_FALSE indicates they should be retained.
*/
static isc_result_t
{
(isc_stdtime_t) 0, NULL,
result == DNS_R_ZONECUT) {
return (ISC_R_SUCCESS);
}
return (ISC_R_SUCCESS);
}
/*
* Silence compiler.
*/
return (result);
}
{
int pass;
unsigned char *salt;
unsigned char nexthash[NSEC3_MAX_HASH_LENGTH];
unsigned char nsec3buf[DNS_NSEC3_BUFFERSIZE];
unsigned int iterations;
unsigned int labels;
unsigned int salt_length;
/*
* Chain parameters.
*/
/*
* If this is the first NSEC3 in the chain nexthash will
* remain pointing to itself.
*/
next_length = sizeof(nexthash);
salt, salt_length));
if (result == ISC_R_NOTFOUND)
goto success;
if (result != ISC_R_SUCCESS)
goto failure;
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.
*/
if (result == ISC_R_SUCCESS) {
}
if (result == ISC_R_NOMORE)
goto success;
if (result != ISC_R_SUCCESS)
goto failure;
/*
* Find the previous NSEC3 and update it.
*/
pass = 0;
do {
if (result == ISC_R_NOMORE) {
pass++;
}
(isc_stdtime_t) 0, &rdataset,
NULL);
if (result != ISC_R_SUCCESS)
continue;
if (result == ISC_R_NOMORE) {
continue;
}
if (result != ISC_R_SUCCESS)
goto failure;
/*
* Delete the old previous NSEC3.
*/
/*
* Fixup the previous NSEC3.
*/
&buffer));
break;
} while (pass < 2);
/*
* Delete the old NSEC3 and record the change.
*/
/*
* Delete NSEC3 records for now non active nodes.
*/
do {
break;
if (!yesno)
break;
salt, salt_length));
if (result == ISC_R_NOTFOUND)
goto success;
if (result != ISC_R_SUCCESS)
goto failure;
(isc_stdtime_t) 0, &rdataset,
NULL);
if (result == ISC_R_NOTFOUND)
goto success;
if (result != ISC_R_SUCCESS)
goto failure;
if (result == ISC_R_SUCCESS) {
}
if (result == ISC_R_NOMORE)
goto success;
if (result != ISC_R_SUCCESS)
goto failure;
pass = 0;
do {
if (result == ISC_R_NOMORE) {
pass++;
}
(isc_stdtime_t) 0,
if (result != ISC_R_SUCCESS)
continue;
if (result == ISC_R_NOMORE) {
continue;
}
if (result != ISC_R_SUCCESS)
goto failure;
/*
* Delete the old previous NSEC3.
*/
/*
* Fixup the previous NSEC3.
*/
sizeof(nsec3buf));
&buffer));
&tuple));
break;
} while (pass < 2);
/*
* Delete the old NSEC3 and record the change.
*/
} while (1);
return (result);
}
{
}
{
/*
* Find the NSEC3 parameters for this zone.
*/
if (result != ISC_R_SUCCESS)
return (result);
dns_rdatatype_nsec3param, 0, 0,
if (result == ISC_R_NOTFOUND)
goto try_private;
if (result != ISC_R_SUCCESS)
goto failure;
/*
* Update each active NSEC3 chain.
*/
result == ISC_R_SUCCESS;
if (nsec3param.flags != 0)
continue;
/*
* We have a active chain. Update it.
*/
}
if (privatetype == 0)
goto success;
if (result == ISC_R_NOTFOUND)
goto success;
if (result != ISC_R_SUCCESS)
goto failure;
/*
* Update each NSEC3 chain being built.
*/
result == ISC_R_SUCCESS;
unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
continue;
continue;
continue;
/*
* We have a active chain. Update it.
*/
}
if (result == ISC_R_NOMORE)
return (result);
}
{
}
{
if (result != ISC_R_SUCCESS)
return (result);
dns_rdatatype_nsec3param, 0, 0,
if (result == ISC_R_NOTFOUND)
goto try_private;
if (result != ISC_R_SUCCESS) {
return (result);
}
result == ISC_R_SUCCESS;
if (nsec3param.flags == 0)
break;
}
if (result == ISC_R_SUCCESS) {
return (ISC_R_SUCCESS);
}
if (result == ISC_R_NOMORE)
if (privatetype == 0 || complete) {
return (ISC_R_SUCCESS);
}
if (result == ISC_R_NOTFOUND) {
return (ISC_R_SUCCESS);
}
if (result != ISC_R_SUCCESS)
return (result);
result == ISC_R_SUCCESS;
unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
continue;
break;
}
if (result == ISC_R_SUCCESS) {
}
if (result == ISC_R_NOMORE) {
}
return (result);
}
{
if (result != ISC_R_SUCCESS)
return (result);
if (result == ISC_R_NOTFOUND) {
*iterationsp = 0;
return (ISC_R_SUCCESS);
}
if (result != ISC_R_SUCCESS)
goto failure;
result == ISC_R_SUCCESS;
dst_key_free(&key);
}
if (result != ISC_R_NOMORE)
goto failure;
if (minbits <= 1024)
*iterationsp = 150;
else if (minbits <= 2048)
*iterationsp = 500;
else
*iterationsp = 2500;
return (result);
}