#include "config.h"
#include <isc/result.h>
#include <isc/string.h>
#include <isc/types.h>
#include <isc/base64.h>
#include <dns/nsec3.h>
#include <dns/private.h>
#define REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0)
#define CREATE(x) (((x) & DNS_NSEC3FLAG_CREATE) != 0)
#define NONSEC(x) (((x) & DNS_NSEC3FLAG_NONSEC) != 0)
#define CHECK(x) do { \
result = (x); \
if (result != ISC_R_SUCCESS) \
goto failure; \
} while (0)
static isc_boolean_t
ignore(dns_rdata_t *param, dns_rdataset_t *privateset) {
isc_result_t result;
for (result = dns_rdataset_first(privateset);
result == ISC_R_SUCCESS;
result = dns_rdataset_next(privateset)) {
unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
dns_rdata_t private = DNS_RDATA_INIT;
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdataset_current(privateset, &private);
if (!dns_nsec3param_fromprivate(&private, &rdata,
buf, sizeof(buf)))
continue;
if (CREATE(rdata.data[1]))
return (ISC_FALSE);
if (rdata.data[0] != param->data[0] ||
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 (NONSEC(rdata.data[1]))
return (ISC_FALSE);
return (ISC_TRUE);
}
return (ISC_FALSE);
}
isc_result_t
dns_private_chains(dns_db_t *db, dns_dbversion_t *ver,
dns_rdatatype_t privatetype,
isc_boolean_t *build_nsec, isc_boolean_t *build_nsec3)
{
dns_dbnode_t *node;
dns_rdataset_t nsecset, nsec3paramset, privateset;
isc_boolean_t nsec3chain;
isc_boolean_t signing;
isc_result_t result;
unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
unsigned int count;
node = NULL;
dns_rdataset_init(&nsecset);
dns_rdataset_init(&nsec3paramset);
dns_rdataset_init(&privateset);
CHECK(dns_db_getoriginnode(db, &node));
result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec,
0, (isc_stdtime_t) 0, &nsecset, NULL);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
goto failure;
result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
0, (isc_stdtime_t) 0, &nsec3paramset,
NULL);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
goto failure;
if (dns_rdataset_isassociated(&nsecset) &&
dns_rdataset_isassociated(&nsec3paramset)) {
if (build_nsec != NULL)
*build_nsec = ISC_TRUE;
if (build_nsec3 != NULL)
*build_nsec3 = ISC_TRUE;
goto success;
}
if (privatetype != (dns_rdatatype_t)0) {
result = dns_db_findrdataset(db, node, ver, privatetype,
0, (isc_stdtime_t) 0,
&privateset, NULL);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
goto failure;
}
if (dns_rdataset_isassociated(&nsecset)) {
if (build_nsec != NULL)
*build_nsec = ISC_TRUE;
if (build_nsec3 != NULL)
*build_nsec3 = ISC_FALSE;
if (!dns_rdataset_isassociated(&privateset))
goto success;
for (result = dns_rdataset_first(&privateset);
result == ISC_R_SUCCESS;
result = dns_rdataset_next(&privateset)) {
unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
dns_rdata_t private = DNS_RDATA_INIT;
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdataset_current(&privateset, &private);
if (!dns_nsec3param_fromprivate(&private, &rdata,
buf, sizeof(buf)))
continue;
if (REMOVE(rdata.data[1]))
continue;
if (build_nsec3 != NULL)
*build_nsec3 = ISC_TRUE;
break;
}
goto success;
}
if (dns_rdataset_isassociated(&nsec3paramset)) {
if (build_nsec3 != NULL)
*build_nsec3 = ISC_TRUE;
if (build_nsec != NULL)
*build_nsec = ISC_FALSE;
if (!dns_rdataset_isassociated(&privateset))
goto success;
for (result = dns_rdataset_first(&privateset);
result == ISC_R_SUCCESS;
result = dns_rdataset_next(&privateset)) {
dns_rdata_t private = DNS_RDATA_INIT;
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdataset_current(&privateset, &private);
if (!dns_nsec3param_fromprivate(&private, &rdata,
buf, sizeof(buf)))
continue;
if (CREATE(rdata.data[1]))
goto success;
}
count = 0;
for (result = dns_rdataset_first(&nsec3paramset);
result == ISC_R_SUCCESS;
result = dns_rdataset_next(&nsec3paramset)) {
dns_rdata_t rdata = DNS_RDATA_INIT;
if (++count > 1)
goto success;
dns_rdataset_current(&nsec3paramset, &rdata);
if (ignore(&rdata, &privateset))
continue;
goto success;
}
if (build_nsec != NULL)
*build_nsec = ISC_TRUE;
goto success;
}
if (build_nsec != NULL)
*build_nsec = ISC_FALSE;
if (build_nsec3 != NULL)
*build_nsec3 = ISC_FALSE;
if (!dns_rdataset_isassociated(&privateset))
goto success;
signing = ISC_FALSE;
nsec3chain = ISC_FALSE;
for (result = dns_rdataset_first(&privateset);
result == ISC_R_SUCCESS;
result = dns_rdataset_next(&privateset)) {
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_t private = DNS_RDATA_INIT;
dns_rdataset_current(&privateset, &private);
if (!dns_nsec3param_fromprivate(&private, &rdata,
buf, sizeof(buf))) {
if (private.length == 5 && private.data[0] != 0 &&
private.data[3] == 0 && private.data[4] == 0)
signing = ISC_TRUE;
} else {
if (CREATE(rdata.data[1]))
nsec3chain = ISC_TRUE;
}
}
if (signing) {
if (nsec3chain) {
if (build_nsec3 != NULL)
*build_nsec3 = ISC_TRUE;
} else {
if (build_nsec != NULL)
*build_nsec = ISC_TRUE;
}
}
success:
result = ISC_R_SUCCESS;
failure:
if (dns_rdataset_isassociated(&nsecset))
dns_rdataset_disassociate(&nsecset);
if (dns_rdataset_isassociated(&nsec3paramset))
dns_rdataset_disassociate(&nsec3paramset);
if (dns_rdataset_isassociated(&privateset))
dns_rdataset_disassociate(&privateset);
if (node != NULL)
dns_db_detachnode(db, &node);
return (result);
}