diff options
Diffstat (limited to 'contrib/bind9/lib/dns/nsec3.c')
-rw-r--r-- | contrib/bind9/lib/dns/nsec3.c | 490 |
1 files changed, 448 insertions, 42 deletions
diff --git a/contrib/bind9/lib/dns/nsec3.c b/contrib/bind9/lib/dns/nsec3.c index 9c85781c2360..e75e7440abc0 100644 --- a/contrib/bind9/lib/dns/nsec3.c +++ b/contrib/bind9/lib/dns/nsec3.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2008, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2006, 2008-2010 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 @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: nsec3.c,v 1.6.12.4 2009-11-03 23:47:46 tbox Exp $ */ +/* $Id: nsec3.c,v 1.19.96.1 2011-06-21 20:15:48 each Exp $ */ #include <config.h> @@ -28,6 +28,8 @@ #include <dst/dst.h> #include <dns/db.h> +#include <dns/zone.h> +#include <dns/compress.h> #include <dns/dbiterator.h> #include <dns/diff.h> #include <dns/fixedname.h> @@ -472,7 +474,6 @@ delete(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, return (result); } -#ifndef RFC5155_STRICT static isc_boolean_t better_param(dns_rdataset_t *nsec3paramset, dns_rdata_t *param) { dns_rdataset_t rdataset; @@ -487,7 +488,17 @@ better_param(dns_rdataset_t *nsec3paramset, dns_rdata_t *param) { result == ISC_R_SUCCESS; result = dns_rdataset_next(&rdataset)) { dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdataset_current(&rdataset, &rdata); + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + + if (rdataset.type != dns_rdatatype_nsec3param) { + dns_rdata_t tmprdata = DNS_RDATA_INIT; + dns_rdataset_current(&rdataset, &tmprdata); + if (!dns_nsec3param_fromprivate(&tmprdata, &rdata, + buf, sizeof(buf))) + continue; + } else + dns_rdataset_current(&rdataset, &rdata); + if (rdata.length != param->length) continue; if (rdata.data[0] != param->data[0] || @@ -505,7 +516,6 @@ better_param(dns_rdataset_t *nsec3paramset, dns_rdata_t *param) { dns_rdataset_disassociate(&rdataset); return (ISC_FALSE); } -#endif static isc_result_t find_nsec3(dns_rdata_nsec3_t *nsec3, dns_rdataset_t *rdataset, @@ -548,7 +558,7 @@ dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version, dns_rdataset_t rdataset; int pass; isc_boolean_t exists; - isc_boolean_t remove_unsecure = ISC_FALSE; + isc_boolean_t maybe_remove_unsecure = ISC_FALSE; isc_uint8_t flags; isc_buffer_t buffer; isc_result_t result; @@ -629,8 +639,12 @@ dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version, */ if (!unsecure) goto addnsec3; - else - remove_unsecure = ISC_TRUE; + else if (CREATE(nsec3param->flags) && OPTOUT(flags)) { + result = dns_nsec3_delnsec3(db, version, name, + nsec3param, diff); + goto failure; + } else + maybe_remove_unsecure = ISC_TRUE; } else { dns_rdataset_disassociate(&rdataset); if (result != ISC_R_NOMORE) @@ -666,26 +680,19 @@ dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version, if (result != ISC_R_SUCCESS) goto failure; - if (remove_unsecure) { + if (maybe_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 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. */ - if (!OPTOUT(nsec3.flags)) { - /* - * Just update the NSEC3 record. - */ - goto addnsec3; - } else { - /* - * This is actually a deletion not a add. - */ + if (OPTOUT(nsec3.flags)) { result = dns_nsec3_delnsec3(db, version, name, nsec3param, diff); goto failure; } + goto addnsec3; } else { /* * Is this is a unsecure delegation we are adding? @@ -928,17 +935,323 @@ dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_current(&rdataset, &rdata); - dns_rdata_tostruct(&rdata, &nsec3param, NULL); + CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); + + if (nsec3param.flags != 0) + continue; + /* + * 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_boolean_t +dns_nsec3param_fromprivate(dns_rdata_t *src, dns_rdata_t *target, + unsigned char *buf, size_t buflen) +{ + dns_decompress_t dctx; + isc_result_t result; + isc_buffer_t buf1; + isc_buffer_t buf2; + + /* + * Algorithm 0 (reserved by RFC 4034) is used to identify + * NSEC3PARAM records from DNSKEY pointers. + */ + if (src->length < 1 || src->data[0] != 0) + return (ISC_FALSE); + + isc_buffer_init(&buf1, src->data + 1, src->length - 1); + isc_buffer_add(&buf1, src->length - 1); + isc_buffer_setactive(&buf1, src->length - 1); + isc_buffer_init(&buf2, buf, buflen); + dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE); + result = dns_rdata_fromwire(target, src->rdclass, + dns_rdatatype_nsec3param, + &buf1, &dctx, 0, &buf2); + dns_decompress_invalidate(&dctx); + + return (ISC_TF(result == ISC_R_SUCCESS)); +} + +void +dns_nsec3param_toprivate(dns_rdata_t *src, dns_rdata_t *target, + dns_rdatatype_t privatetype, + unsigned char *buf, size_t buflen) +{ + REQUIRE(buflen >= src->length + 1); + + REQUIRE(DNS_RDATA_INITIALIZED(target)); + + memcpy(buf + 1, src->data, src->length); + buf[0] = 0; + target->data = buf; + target->length = src->length + 1; + target->type = privatetype; + target->rdclass = src->rdclass; + target->flags = 0; + ISC_LINK_INIT(target, link); +} + +#ifdef BIND9 +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_casecompare(&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); +} +#endif + +#ifdef BIND9 +isc_result_t +dns_nsec3param_deletechains(dns_db_t *db, dns_dbversion_t *ver, + dns_zone_t *zone, 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 + 1]; + dns_name_t *origin = dns_zone_getorigin(zone); + dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone); + + 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 try_private; + 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 private = DNS_RDATA_INIT; + + dns_rdataset_current(&rdataset, &rdata); + + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, origin, + rdataset.ttl, &rdata, &tuple)); + CHECK(do_one_tuple(&tuple, db, ver, diff)); + INSIST(tuple == NULL); + + dns_nsec3param_toprivate(&rdata, &private, privatetype, + buf, sizeof(buf)); + buf[2] = DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC; + + CHECK(rr_exists(db, ver, origin, &private, &flag)); + + if (!flag) { + CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, + origin, 0, &private, + &tuple)); + CHECK(do_one_tuple(&tuple, db, ver, diff)); + INSIST(tuple == NULL); + } + dns_rdata_reset(&rdata); + } + if (result != ISC_R_NOMORE) + goto failure; + + dns_rdataset_disassociate(&rdataset); + + try_private: + if (privatetype == 0) + goto success; + result = dns_db_findrdataset(db, node, ver, privatetype, 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[0] != 0 || + buf[2] == (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); + + rdata.data = buf; + buf[2] = DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC; + + 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 + +isc_result_t +dns_nsec3_addnsec3sx(dns_db_t *db, dns_dbversion_t *version, + dns_name_t *name, dns_ttl_t nsecttl, + isc_boolean_t unsecure, dns_rdatatype_t type, + dns_diff_t *diff) +{ + dns_dbnode_t *node = NULL; + dns_rdata_nsec3param_t nsec3param; + dns_rdataset_t rdataset; + dns_rdataset_t prdataset; + isc_result_t result; + + dns_rdataset_init(&rdataset); + dns_rdataset_init(&prdataset); + + /* + * 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, type, 0, 0, + &prdataset, NULL); + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) + goto failure; + + result = dns_db_findrdataset(db, node, version, + dns_rdatatype_nsec3param, 0, 0, + &rdataset, NULL); + if (result == ISC_R_NOTFOUND) + goto try_private; + if (result != ISC_R_SUCCESS) + goto failure; + + /* + * 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); + CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); -#ifdef RFC5155_STRICT if (nsec3param.flags != 0) continue; -#else + + /* + * We have a active chain. Update it. + */ + CHECK(dns_nsec3_addnsec3(db, version, name, &nsec3param, + nsecttl, unsecure, diff)); + } + if (result != ISC_R_NOMORE) + goto failure; + + dns_rdataset_disassociate(&rdataset); + + try_private: + if (!dns_rdataset_isassociated(&prdataset)) + goto success; + /* + * Update each active NSEC3 chain. + */ + for (result = dns_rdataset_first(&prdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&prdataset)) { + dns_rdata_t rdata1 = DNS_RDATA_INIT; + dns_rdata_t rdata2 = DNS_RDATA_INIT; + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + + dns_rdataset_current(&prdataset, &rdata1); + if (!dns_nsec3param_fromprivate(&rdata1, &rdata2, + buf, sizeof(buf))) + continue; + CHECK(dns_rdata_tostruct(&rdata2, &nsec3param, NULL)); + if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) continue; - if (better_param(&rdataset, &rdata)) + if (better_param(&prdataset, &rdata2)) continue; -#endif /* * We have a active chain. Update it. @@ -947,11 +1260,13 @@ dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version, nsecttl, unsecure, diff)); } if (result == ISC_R_NOMORE) + success: result = ISC_R_SUCCESS; - failure: if (dns_rdataset_isassociated(&rdataset)) dns_rdataset_disassociate(&rdataset); + if (dns_rdataset_isassociated(&prdataset)) + dns_rdataset_disassociate(&prdataset); if (node != NULL) dns_db_detachnode(db, &node); @@ -1120,6 +1435,8 @@ dns_nsec3_delnsec3(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, */ nsec3.next = nexthash; nsec3.next_length = next_length; + if (CREATE(nsec3param->flags)) + nsec3.flags = nsec3param->flags & DNS_NSEC3FLAG_OPTOUT; isc_buffer_init(&buffer, nsec3buf, sizeof(nsec3buf)); CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass, dns_rdatatype_nsec3, &nsec3, @@ -1257,6 +1574,13 @@ isc_result_t dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, dns_diff_t *diff) { + return (dns_nsec3_delnsec3sx(db, version, name, 0, diff)); +} + +isc_result_t +dns_nsec3_delnsec3sx(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, + dns_rdatatype_t privatetype, dns_diff_t *diff) +{ dns_dbnode_t *node = NULL; dns_rdata_nsec3param_t nsec3param; dns_rdataset_t rdataset; @@ -1274,11 +1598,10 @@ dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, 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); + goto try_private; if (result != ISC_R_SUCCESS) - return (result); + goto failure; /* * Update each active NSEC3 chain. @@ -1289,17 +1612,47 @@ dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_current(&rdataset, &rdata); - dns_rdata_tostruct(&rdata, &nsec3param, NULL); + CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); -#ifdef RFC5155_STRICT if (nsec3param.flags != 0) continue; -#else + /* + * We have a active chain. Update it. + */ + CHECK(dns_nsec3_delnsec3(db, version, name, &nsec3param, diff)); + } + dns_rdataset_disassociate(&rdataset); + + try_private: + if (privatetype == 0) + goto success; + result = dns_db_findrdataset(db, node, version, privatetype, 0, 0, + &rdataset, NULL); + if (result == ISC_R_NOTFOUND) + goto success; + if (result != ISC_R_SUCCESS) + goto failure; + + /* + * Update each NSEC3 chain being built. + */ + for (result = dns_rdataset_first(&rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(&rdataset)) { + dns_rdata_t rdata1 = DNS_RDATA_INIT; + dns_rdata_t rdata2 = DNS_RDATA_INIT; + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; + + dns_rdataset_current(&rdataset, &rdata1); + if (!dns_nsec3param_fromprivate(&rdata1, &rdata2, + buf, sizeof(buf))) + continue; + CHECK(dns_rdata_tostruct(&rdata2, &nsec3param, NULL)); + if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) continue; - if (better_param(&rdataset, &rdata)) + if (better_param(&rdataset, &rdata2)) continue; -#endif /* * We have a active chain. Update it. @@ -1307,6 +1660,7 @@ dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, CHECK(dns_nsec3_delnsec3(db, version, name, &nsec3param, diff)); } if (result == ISC_R_NOMORE) + success: result = ISC_R_SUCCESS; failure: @@ -1322,6 +1676,14 @@ isc_result_t dns_nsec3_active(dns_db_t *db, dns_dbversion_t *version, isc_boolean_t complete, isc_boolean_t *answer) { + return (dns_nsec3_activex(db, version, complete, 0, answer)); +} + +isc_result_t +dns_nsec3_activex(dns_db_t *db, dns_dbversion_t *version, + isc_boolean_t complete, dns_rdatatype_t privatetype, + isc_boolean_t *answer) +{ dns_dbnode_t *node = NULL; dns_rdataset_t rdataset; dns_rdata_nsec3param_t nsec3param; @@ -1338,34 +1700,78 @@ dns_nsec3_active(dns_db_t *db, dns_dbversion_t *version, result = dns_db_findrdataset(db, node, version, dns_rdatatype_nsec3param, 0, 0, &rdataset, NULL); - dns_db_detachnode(db, &node); + if (result == ISC_R_NOTFOUND) + goto try_private; + + 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_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) + break; + } + dns_rdataset_disassociate(&rdataset); + if (result == ISC_R_SUCCESS) { + dns_db_detachnode(db, &node); + *answer = ISC_TRUE; + return (ISC_R_SUCCESS); + } + if (result == ISC_R_NOMORE) + *answer = ISC_FALSE; + + try_private: + if (privatetype == 0 || complete) { + *answer = ISC_FALSE; + return (ISC_R_SUCCESS); + } + result = dns_db_findrdataset(db, node, version, privatetype, 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_rdata_t rdata1 = DNS_RDATA_INIT; + dns_rdata_t rdata2 = DNS_RDATA_INIT; + unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; - dns_rdataset_current(&rdataset, &rdata); - result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); + dns_rdataset_current(&rdataset, &rdata1); + if (!dns_nsec3param_fromprivate(&rdata1, &rdata2, + buf, sizeof(buf))) + continue; + result = dns_rdata_tostruct(&rdata2, &nsec3param, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); - if ((nsec3param.flags) == 0 || - (!complete && CREATE(nsec3param.flags))) + if (!complete && CREATE(nsec3param.flags)) break; } dns_rdataset_disassociate(&rdataset); - if (result == ISC_R_SUCCESS) + if (result == ISC_R_SUCCESS) { *answer = ISC_TRUE; + result = ISC_R_SUCCESS; + } if (result == ISC_R_NOMORE) { *answer = ISC_FALSE; result = ISC_R_SUCCESS; } + return (result); } |