diff --git a/CHANGES b/CHANGES index 51eb7c80e8..85274a2a78 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +5619. [protocol] Implement draft-vandijk-dnsop-nsec-ttl, updating the + protocol such that NSEC(3) TTL values are set to the + minimum of the SOA MINIMUM value and the SOA TTL. + [GL #2347]. + 5618. [bug] When introducing change 5149, "rndc dumpdb" started to print a line above a stale RRset, indicating how long the data will be retained. Also, TTLs were diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c index e8ae4d0dea..d97daa78f7 100644 --- a/bin/dnssec/dnssec-signzone.c +++ b/bin/dnssec/dnssec-signzone.c @@ -1334,8 +1334,8 @@ get_soa_ttls(void) { result = dns_rdataset_first(&soaset); check_result(result, "dns_rdataset_first"); dns_rdataset_current(&soaset, &rdata); - zone_soa_min_ttl = dns_soa_getminimum(&rdata); soa_ttl = soaset.ttl; + zone_soa_min_ttl = ISC_MIN(dns_soa_getminimum(&rdata), soa_ttl); if (set_maxttl) { zone_soa_min_ttl = ISC_MIN(zone_soa_min_ttl, maxttl); soa_ttl = ISC_MIN(soa_ttl, maxttl); diff --git a/bin/tests/system/autosign/tests.sh b/bin/tests/system/autosign/tests.sh index fd0dad1111..c7bab90f1e 100755 --- a/bin/tests/system/autosign/tests.sh +++ b/bin/tests/system/autosign/tests.sh @@ -1590,7 +1590,7 @@ status=`expr $status + $ret` echo_i "check that DNAME at apex with NSEC3 is correctly signed (auto-dnssec maintain) ($n)" ret=0 $DIG $DIGOPTS txt dname-at-apex-nsec3.example @10.53.0.3 > dig.out.ns3.test$n || ret=1 -grep "RRSIG NSEC3 7 3 3600" dig.out.ns3.test$n > /dev/null || ret=1 +grep "RRSIG NSEC3 7 3 600" dig.out.ns3.test$n > /dev/null || ret=1 n=`expr $n + 1` if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh index 70251f740a..25494e9184 100644 --- a/bin/tests/system/dnssec/tests.sh +++ b/bin/tests/system/dnssec/tests.sh @@ -3830,7 +3830,7 @@ status=$((status+ret)) echo_i "check that DNAME at apex with NSEC3 is correctly signed (dnssec-signzone) ($n)" ret=0 dig_with_opts txt dname-at-apex-nsec3.example @10.53.0.3 > dig.out.ns3.test$n || ret=1 -grep "RRSIG.NSEC3 ${DEFAULT_ALGORITHM_NUMBER} 3 3600" dig.out.ns3.test$n > /dev/null || ret=1 +grep "RRSIG.NSEC3 ${DEFAULT_ALGORITHM_NUMBER} 3 600" dig.out.ns3.test$n > /dev/null || ret=1 n=$((n+1)) test "$ret" -eq 0 || echo_i "failed" status=$((status+ret)) diff --git a/doc/notes/notes-current.rst b/doc/notes/notes-current.rst index 4098e8ea0a..028dc6f829 100644 --- a/doc/notes/notes-current.rst +++ b/doc/notes/notes-current.rst @@ -45,6 +45,9 @@ Feature Changes changed from ``1800`` (ms) to ``off``. The default value may be changed again in future releases as this feature matures. [GL #2608] +- Implement ``draft-vandijk-dnsop-nsec-ttl``, NSEC(3) TTL values are now set to + the minimum of the SOA MINIMUM value and the SOA TTL. [GL #2347]. + Bug Fixes ~~~~~~~~~ diff --git a/lib/dns/update.c b/lib/dns/update.c index 808a636a81..1b923f692e 100644 --- a/lib/dns/update.c +++ b/lib/dns/update.c @@ -1578,7 +1578,8 @@ dns_update_signaturesinc(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db, DNS_ZONEOPT_DNSKEYKSKONLY) != 0); /* - * Get the NSEC/NSEC3 TTL from the SOA MINIMUM field. + * Calculate the NSEC/NSEC3 TTL as a minimum of the SOA TTL and + * MINIMUM field. */ CHECK(dns_db_findnode(db, dns_db_origin(db), false, &node)); dns_rdataset_init(&rdataset); @@ -1588,7 +1589,7 @@ dns_update_signaturesinc(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db, CHECK(dns_rdataset_first(&rdataset)); dns_rdataset_current(&rdataset, &rdata); CHECK(dns_rdata_tostruct(&rdata, &soa, NULL)); - state->nsecttl = soa.minimum; + state->nsecttl = ISC_MIN(rdataset.ttl, soa.minimum); dns_rdataset_disassociate(&rdataset); dns_db_detachnode(db, &node); diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 5f042f4f63..8c55c1774c 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -430,8 +430,9 @@ struct dns_zone { uint32_t sourceserial; /*% - * maximum zone ttl + * soa and maximum zone ttl */ + dns_ttl_t soattl; dns_ttl_t maxttl; /* @@ -868,9 +869,9 @@ rss_post(dns_zone_t *, isc_event_t *); static isc_result_t zone_get_from_db(dns_zone_t *zone, dns_db_t *db, unsigned int *nscount, - unsigned int *soacount, uint32_t *serial, uint32_t *refresh, - uint32_t *retry, uint32_t *expire, uint32_t *minimum, - unsigned int *errors); + unsigned int *soacount, uint32_t *soattl, uint32_t *serial, + uint32_t *refresh, uint32_t *retry, uint32_t *expire, + uint32_t *minimum, unsigned int *errors); static void zone_freedbargs(dns_zone_t *zone); @@ -894,6 +895,8 @@ static void zone_rekey(dns_zone_t *zone); static isc_result_t zone_send_securedb(dns_zone_t *zone, dns_db_t *db); +static dns_ttl_t +zone_nsecttl(dns_zone_t *zone); static void setrl(isc_ratelimiter_t *rl, unsigned int *rate, unsigned int value); static void @@ -986,14 +989,51 @@ inc_stats(dns_zone_t *zone, isc_statscounter_t counter) { isc_result_t dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { isc_result_t result; - dns_zone_t *zone; isc_time_t now; + dns_zone_t *zone = NULL; + dns_zone_t z = { .masterformat = dns_masterformat_none, + .journalsize = -1, + .rdclass = dns_rdataclass_none, + .type = dns_zone_none, + .refresh = DNS_ZONE_DEFAULTREFRESH, + .retry = DNS_ZONE_DEFAULTRETRY, + .maxrefresh = DNS_ZONE_MAXREFRESH, + .minrefresh = DNS_ZONE_MINREFRESH, + .maxretry = DNS_ZONE_MAXRETRY, + .minretry = DNS_ZONE_MINRETRY, + .notifytype = dns_notifytype_yes, + .zero_no_soa_ttl = true, + .check_names = dns_severity_ignore, + .idlein = DNS_DEFAULT_IDLEIN, + .idleout = DNS_DEFAULT_IDLEOUT, + .notifysrc4dscp = -1, + .notifysrc6dscp = -1, + .xfrsource4dscp = -1, + .xfrsource6dscp = -1, + .altxfrsource4dscp = -1, + .altxfrsource6dscp = -1, + .maxxfrin = MAX_XFER_TIME, + .maxxfrout = MAX_XFER_TIME, + .sigvalidityinterval = 30 * 24 * 3600, + .sigresigninginterval = 7 * 24 * 3600, + .statlevel = dns_zonestat_none, + .notifydelay = 5, + .signatures = 10, + .nodes = 100, + .privatetype = (dns_rdatatype_t)0xffffU, + .rpz_num = DNS_RPZ_INVALID_NUM, + .requestixfr = true, + .ixfr_ratio = 100, + .requestexpire = true, + .updatemethod = dns_updatemethod_increment, + .magic = ZONE_MAGIC }; REQUIRE(zonep != NULL && *zonep == NULL); REQUIRE(mctx != NULL); TIME_NOW(&now); zone = isc_mem_get(mctx, sizeof(*zone)); + *zone = z; zone->mctx = NULL; isc_mem_attach(mctx, &zone->mctx); @@ -1003,87 +1043,27 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { #ifdef DNS_ZONE_CHECKLOCK zone->locked = false; #endif /* ifdef DNS_ZONE_CHECKLOCK */ - zone->db = NULL; - zone->zmgr = NULL; + + zone->notifytime = now; + ISC_LINK_INIT(zone, link); isc_refcount_init(&zone->erefs, 1); isc_refcount_init(&zone->irefs, 0); dns_name_init(&zone->origin, NULL); - zone->strnamerd = NULL; - zone->strname = NULL; - zone->strrdclass = NULL; - zone->strviewname = NULL; - zone->masterfile = NULL; - zone->stream = NULL; ISC_LIST_INIT(zone->includes); ISC_LIST_INIT(zone->newincludes); - zone->nincludes = 0; - zone->masterformat = dns_masterformat_none; - zone->masterstyle = NULL; - zone->keydirectory = NULL; - zone->journalsize = -1; - zone->journal = NULL; - zone->rdclass = dns_rdataclass_none; - zone->type = dns_zone_none; atomic_init(&zone->flags, 0); atomic_init(&zone->options, 0); atomic_init(&zone->keyopts, 0); - zone->db_argc = 0; - zone->db_argv = NULL; isc_time_settoepoch(&zone->expiretime); isc_time_settoepoch(&zone->refreshtime); isc_time_settoepoch(&zone->dumptime); isc_time_settoepoch(&zone->loadtime); - zone->notifytime = now; isc_time_settoepoch(&zone->resigntime); isc_time_settoepoch(&zone->keywarntime); isc_time_settoepoch(&zone->signingtime); isc_time_settoepoch(&zone->nsec3chaintime); isc_time_settoepoch(&zone->refreshkeytime); - zone->refreshkeyinterval = 0; - zone->refreshkeycount = 0; - zone->refresh = DNS_ZONE_DEFAULTREFRESH; - zone->retry = DNS_ZONE_DEFAULTRETRY; - zone->expire = 0; - zone->minimum = 0; - zone->maxrefresh = DNS_ZONE_MAXREFRESH; - zone->minrefresh = DNS_ZONE_MINREFRESH; - zone->maxretry = DNS_ZONE_MAXRETRY; - zone->minretry = DNS_ZONE_MINRETRY; - zone->masters = NULL; - zone->masterdscps = NULL; - zone->masterkeynames = NULL; - zone->mastertlsnames = NULL; - zone->mastersok = NULL; - zone->masterscnt = 0; - zone->curmaster = 0; - zone->maxttl = 0; - zone->notify = NULL; - zone->notifykeynames = NULL; - zone->notifytlsnames = NULL; - zone->notifydscp = NULL; - zone->notifytype = dns_notifytype_yes; - zone->notifycnt = 0; - zone->task = NULL; - zone->loadtask = NULL; - zone->update_acl = NULL; - zone->forward_acl = NULL; - zone->notify_acl = NULL; - zone->query_acl = NULL; - zone->queryon_acl = NULL; - zone->xfr_acl = NULL; - zone->update_disabled = false; - zone->zero_no_soa_ttl = true; - zone->check_names = dns_severity_ignore; - zone->request = NULL; - zone->lctx = NULL; - zone->readio = NULL; - zone->dctx = NULL; - zone->writeio = NULL; - zone->timer = NULL; - zone->idlein = DNS_DEFAULT_IDLEIN; - zone->idleout = DNS_DEFAULT_IDLEOUT; - zone->log_key_expired_timer = 0; ISC_LIST_INIT(zone->notifies); isc_sockaddr_any(&zone->notifysrc4); isc_sockaddr_any6(&zone->notifysrc6); @@ -1091,74 +1071,14 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { isc_sockaddr_any6(&zone->xfrsource6); isc_sockaddr_any(&zone->altxfrsource4); isc_sockaddr_any6(&zone->altxfrsource6); - zone->notifysrc4dscp = -1; - zone->notifysrc6dscp = -1; - zone->xfrsource4dscp = -1; - zone->xfrsource6dscp = -1; - zone->altxfrsource4dscp = -1; - zone->altxfrsource6dscp = -1; - zone->xfr = NULL; - zone->tsigkey = NULL; - zone->transport = NULL; - zone->maxxfrin = MAX_XFER_TIME; - zone->maxxfrout = MAX_XFER_TIME; - zone->ssutable = NULL; - zone->sigvalidityinterval = 30 * 24 * 3600; - zone->keyvalidityinterval = 0; - zone->sigresigninginterval = 7 * 24 * 3600; - zone->kasp = NULL; - zone->view = NULL; - zone->prev_view = NULL; - zone->checkmx = NULL; - zone->checksrv = NULL; - zone->checkns = NULL; ISC_LINK_INIT(zone, statelink); - zone->statelist = NULL; - zone->stats = NULL; - zone->requeststats_on = false; - zone->statlevel = dns_zonestat_none; - zone->requeststats = NULL; - zone->rcvquerystats = NULL; - zone->dnssecsignstats = NULL; - zone->notifydelay = 5; - zone->isself = NULL; - zone->isselfarg = NULL; ISC_LIST_INIT(zone->signing); ISC_LIST_INIT(zone->nsec3chain); ISC_LIST_INIT(zone->setnsec3param_queue); - zone->signatures = 10; - zone->nodes = 100; - zone->privatetype = (dns_rdatatype_t)0xffffU; - zone->added = false; - zone->automatic = false; - zone->rpzs = NULL; - zone->rpz_num = DNS_RPZ_INVALID_NUM; - - zone->catzs = NULL; - zone->parentcatz = NULL; - ISC_LIST_INIT(zone->forwards); - zone->raw = NULL; - zone->secure = NULL; - zone->sourceserial = 0; - zone->sourceserialset = false; - zone->requestixfr = true; - zone->ixfr_ratio = 100; - zone->requestexpire = true; ISC_LIST_INIT(zone->rss_events); ISC_LIST_INIT(zone->rss_post); - zone->rss_db = NULL; - zone->rss_raw = NULL; - zone->rss_newver = NULL; - zone->rss_oldver = NULL; - zone->rss_event = NULL; - zone->rss_state = NULL; - zone->updatemethod = dns_updatemethod_increment; - zone->maxrecords = 0U; - zone->magic = ZONE_MAGIC; - - zone->gluecachestats = NULL; result = isc_stats_create(mctx, &zone->gluecachestats, dns_gluecachestatscounter_max); if (result != ISC_R_SUCCESS) { @@ -1448,7 +1368,7 @@ dns_zone_getserial(dns_zone_t *zone, uint32_t *serialp) { LOCK_ZONE(zone); ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); if (zone->db != NULL) { - result = zone_get_from_db(zone, zone->db, NULL, &soacount, + result = zone_get_from_db(zone, zone->db, NULL, &soacount, NULL, serialp, NULL, NULL, NULL, NULL, NULL); if (result == ISC_R_SUCCESS && soacount == 0) { @@ -2554,7 +2474,7 @@ get_raw_serial(dns_zone_t *raw, dns_masterrawheader_t *rawdata) { LOCK(&raw->lock); if (raw->db != NULL) { - result = zone_get_from_db(raw, raw->db, NULL, &soacount, + result = zone_get_from_db(raw, raw->db, NULL, &soacount, NULL, &rawdata->sourceserial, NULL, NULL, NULL, NULL, NULL); if (result == ISC_R_SUCCESS && soacount > 0U) { @@ -4714,9 +4634,9 @@ maybe_send_secure(dns_zone_t *zone) { uint32_t serial; unsigned int soacount; - result = zone_get_from_db(zone->raw, zone->raw->db, - NULL, &soacount, &serial, - NULL, NULL, NULL, NULL, NULL); + result = zone_get_from_db( + zone->raw, zone->raw->db, NULL, &soacount, NULL, + &serial, NULL, NULL, NULL, NULL, NULL); if (result == ISC_R_SUCCESS && soacount > 0U) { zone_send_secureserial(zone->raw, serial); } @@ -4753,7 +4673,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, unsigned int soacount = 0; unsigned int nscount = 0; unsigned int errors = 0; - uint32_t serial, oldserial, refresh, retry, expire, minimum; + uint32_t serial, oldserial, refresh, retry, expire, minimum, soattl; isc_time_t now; bool needdump = false; bool fixjournal = false; @@ -4894,8 +4814,9 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, * Obtain ns, soa and cname counts for top of zone. */ INSIST(db != NULL); - result = zone_get_from_db(zone, db, &nscount, &soacount, &serial, - &refresh, &retry, &expire, &minimum, &errors); + result = zone_get_from_db(zone, db, &nscount, &soacount, &soattl, + &serial, &refresh, &retry, &expire, &minimum, + &errors); if (result != ISC_R_SUCCESS && zone->type != dns_zone_key) { dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_ERROR, "could not find NS and/or SOA records"); @@ -5042,9 +4963,9 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, * This is checked in zone_replacedb() for slave zones * as they don't reload from disk. */ - result = zone_get_from_db(zone, zone->db, NULL, - &oldsoacount, &oldserial, - NULL, NULL, NULL, NULL, NULL); + result = zone_get_from_db( + zone, zone->db, NULL, &oldsoacount, NULL, + &oldserial, NULL, NULL, NULL, NULL, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); RUNTIME_CHECK(soacount > 0U); if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) && @@ -5110,6 +5031,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, zone->retry = RANGE(retry, zone->minretry, zone->maxretry); zone->expire = RANGE(expire, zone->refresh + zone->retry, DNS_MAX_EXPIRE); + zone->soattl = soattl; zone->minimum = minimum; DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS); @@ -5533,39 +5455,42 @@ invalidate_rdataset: return (result); } +#define SET_IF_NOT_NULL(obj, val) \ + if (obj != NULL) { \ + *obj = val; \ + } + +#define SET_SOA_VALUES(soattl_v, serial_v, refresh_v, retry_v, expire_v, \ + minimum_v) \ + { \ + SET_IF_NOT_NULL(soattl, soattl_v); \ + SET_IF_NOT_NULL(serial, serial_v); \ + SET_IF_NOT_NULL(refresh, refresh_v); \ + SET_IF_NOT_NULL(retry, retry_v); \ + SET_IF_NOT_NULL(expire, expire_v); \ + SET_IF_NOT_NULL(minimum, minimum_v); \ + } + +#define CLR_SOA_VALUES() \ + { \ + SET_SOA_VALUES(0, 0, 0, 0, 0, 0); \ + } + static isc_result_t zone_load_soa_rr(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, - unsigned int *soacount, uint32_t *serial, uint32_t *refresh, - uint32_t *retry, uint32_t *expire, uint32_t *minimum) { + unsigned int *soacount, uint32_t *soattl, uint32_t *serial, + uint32_t *refresh, uint32_t *retry, uint32_t *expire, + uint32_t *minimum) { isc_result_t result; - unsigned int count; + unsigned int count = 0; dns_rdataset_t rdataset; dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdata_soa_t soa; dns_rdataset_init(&rdataset); result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa, dns_rdatatype_none, 0, &rdataset, NULL); if (result == ISC_R_NOTFOUND) { INSIST(!dns_rdataset_isassociated(&rdataset)); - if (soacount != NULL) { - *soacount = 0; - } - if (serial != NULL) { - *serial = 0; - } - if (refresh != NULL) { - *refresh = 0; - } - if (retry != NULL) { - *retry = 0; - } - if (expire != NULL) { - *expire = 0; - } - if (minimum != NULL) { - *minimum = 0; - } result = ISC_R_SUCCESS; goto invalidate_rdataset; } @@ -5574,14 +5499,16 @@ zone_load_soa_rr(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, goto invalidate_rdataset; } - count = 0; result = dns_rdataset_first(&rdataset); while (result == ISC_R_SUCCESS) { dns_rdata_init(&rdata); dns_rdataset_current(&rdataset, &rdata); count++; if (count == 1) { + dns_rdata_soa_t soa; result = dns_rdata_tostruct(&rdata, &soa, NULL); + SET_SOA_VALUES(rdataset.ttl, soa.serial, soa.refresh, + soa.retry, soa.expire, soa.minimum); RUNTIME_CHECK(result == ISC_R_SUCCESS); } @@ -5590,50 +5517,14 @@ zone_load_soa_rr(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, } dns_rdataset_disassociate(&rdataset); - if (soacount != NULL) { - *soacount = count; - } - - if (count > 0) { - if (serial != NULL) { - *serial = soa.serial; - } - if (refresh != NULL) { - *refresh = soa.refresh; - } - if (retry != NULL) { - *retry = soa.retry; - } - if (expire != NULL) { - *expire = soa.expire; - } - if (minimum != NULL) { - *minimum = soa.minimum; - } - } else { - if (soacount != NULL) { - *soacount = 0; - } - if (serial != NULL) { - *serial = 0; - } - if (refresh != NULL) { - *refresh = 0; - } - if (retry != NULL) { - *retry = 0; - } - if (expire != NULL) { - *expire = 0; - } - if (minimum != NULL) { - *minimum = 0; - } - } - result = ISC_R_SUCCESS; invalidate_rdataset: + SET_IF_NOT_NULL(soacount, count); + if (count == 0) { + CLR_SOA_VALUES(); + } + dns_rdataset_invalidate(&rdataset); return (result); @@ -5644,9 +5535,9 @@ invalidate_rdataset: */ static isc_result_t zone_get_from_db(dns_zone_t *zone, dns_db_t *db, unsigned int *nscount, - unsigned int *soacount, uint32_t *serial, uint32_t *refresh, - uint32_t *retry, uint32_t *expire, uint32_t *minimum, - unsigned int *errors) { + unsigned int *soacount, uint32_t *soattl, uint32_t *serial, + uint32_t *refresh, uint32_t *retry, uint32_t *expire, + uint32_t *minimum, unsigned int *errors) { isc_result_t result; isc_result_t answer = ISC_R_SUCCESS; dns_dbversion_t *version = NULL; @@ -5657,27 +5548,10 @@ zone_get_from_db(dns_zone_t *zone, dns_db_t *db, unsigned int *nscount, dns_db_currentversion(db, &version); - if (nscount != NULL) { - *nscount = 0; - } - if (soacount != NULL) { - *soacount = 0; - } - if (serial != NULL) { - *serial = 0; - } - if (refresh != NULL) { - *refresh = 0; - } - if (retry != NULL) { - *retry = 0; - } - if (expire != NULL) { - *expire = 0; - } - if (errors != NULL) { - *errors = 0; - } + SET_IF_NOT_NULL(nscount, 0); + SET_IF_NOT_NULL(soacount, 0); + SET_IF_NOT_NULL(errors, 0); + CLR_SOA_VALUES(); node = NULL; result = dns_db_findnode(db, &zone->origin, false, &node); @@ -5694,11 +5568,13 @@ zone_get_from_db(dns_zone_t *zone, dns_db_t *db, unsigned int *nscount, } } - if (soacount != NULL || serial != NULL || refresh != NULL || - retry != NULL || expire != NULL || minimum != NULL) + if (soacount != NULL || soattl != NULL || serial != NULL || + refresh != NULL || retry != NULL || expire != NULL || + minimum != NULL) { - result = zone_load_soa_rr(db, node, version, soacount, serial, - refresh, retry, expire, minimum); + result = zone_load_soa_rr(db, node, version, soacount, soattl, + serial, refresh, retry, expire, + minimum); if (result != ISC_R_SUCCESS) { answer = result; } @@ -7567,9 +7443,9 @@ static isc_result_t sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name, dns_dbnode_t *node, dns_dbversion_t *version, bool build_nsec3, bool build_nsec, dst_key_t *key, isc_stdtime_t inception, - isc_stdtime_t expire, unsigned int minimum, bool is_ksk, - bool is_zsk, bool keyset_kskonly, bool is_bottom_of_zone, - dns_diff_t *diff, int32_t *signatures, isc_mem_t *mctx) { + isc_stdtime_t expire, dns_ttl_t nsecttl, bool is_ksk, bool is_zsk, + bool keyset_kskonly, bool is_bottom_of_zone, dns_diff_t *diff, + int32_t *signatures, isc_mem_t *mctx) { isc_result_t result; dns_rdatasetiter_t *iterator = NULL; dns_rdataset_t rdataset; @@ -7620,7 +7496,7 @@ sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name, */ if (build_nsec3 && !seen_nsec3 && seen_rr) { bool unsecure = !seen_ds && seen_ns && !seen_soa; - CHECK(dns_nsec3_addnsec3s(db, version, name, minimum, unsecure, + CHECK(dns_nsec3_addnsec3s(db, version, name, nsecttl, unsecure, diff)); (*signatures)--; } @@ -7633,7 +7509,7 @@ sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name, * Build a NSEC record except at the origin. */ if (!dns_name_equal(name, dns_db_origin(db))) { - CHECK(add_nsec(db, version, name, node, minimum, + CHECK(add_nsec(db, version, name, node, nsecttl, is_bottom_of_zone, diff)); /* Count a NSEC generation as a signature generation. */ (*signatures)--; @@ -7727,7 +7603,7 @@ failure: */ static isc_result_t updatesecure(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, - dns_ttl_t minimum, bool update_only, dns_diff_t *diff) { + dns_ttl_t nsecttl, bool update_only, dns_diff_t *diff) { isc_result_t result; dns_rdataset_t rdataset; dns_dbnode_t *node = NULL; @@ -7749,7 +7625,7 @@ updatesecure(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, } } CHECK(delete_nsec(db, version, node, name, diff)); - CHECK(add_nsec(db, version, name, node, minimum, false, diff)); + CHECK(add_nsec(db, version, name, node, nsecttl, false, diff)); success: result = ISC_R_SUCCESS; failure: @@ -7761,7 +7637,7 @@ failure: static isc_result_t updatesignwithkey(dns_zone_t *zone, dns_signing_t *signing, - dns_dbversion_t *version, bool build_nsec3, dns_ttl_t minimum, + dns_dbversion_t *version, bool build_nsec3, dns_ttl_t nsecttl, dns_diff_t *diff) { isc_result_t result; dns_dbnode_t *node = NULL; @@ -7853,9 +7729,9 @@ updatesignwithkey(dns_zone_t *zone, dns_signing_t *signing, */ if (build_nsec3) { CHECK(dns_nsec3_addnsec3s(signing->db, version, origin, - minimum, false, diff)); + nsecttl, false, diff)); } - CHECK(updatesecure(signing->db, version, origin, minimum, true, + CHECK(updatesecure(signing->db, version, origin, nsecttl, true, diff)); } @@ -8563,7 +8439,7 @@ zone_nsec3chain(dns_zone_t *zone) { dns_dbiterator_pause(nsec3chain->dbiterator); result = dns_nsec3_addnsec3( db, version, name, &nsec3chain->nsec3param, - zone->minimum, unsecure, &nsec3_diff); + zone_nsecttl(zone), unsecure, &nsec3_diff); if (result != ISC_R_SUCCESS) { dnssec_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" @@ -8822,8 +8698,9 @@ zone_nsec3chain(dns_zone_t *zone) { */ if (!dns_name_equal(name, dns_db_origin(db))) { dns_dbiterator_pause(nsec3chain->dbiterator); - CHECK(add_nsec(db, version, name, node, zone->minimum, - delegation, &nsec_diff)); + CHECK(add_nsec(db, version, name, node, + zone_nsecttl(zone), delegation, + &nsec_diff)); signatures--; } @@ -8925,7 +8802,8 @@ skip_removals: } result = updatesecure(db, version, &zone->origin, - zone->minimum, true, &nsec_diff); + zone_nsecttl(zone), true, + &nsec_diff); if (result != ISC_R_SUCCESS) { dnssec_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:updatesecure -> %s", @@ -8940,8 +8818,8 @@ skip_removals: } result = dns_nsec3_addnsec3s( - db, version, dns_db_origin(db), zone->minimum, - false, &nsec3_diff); + db, version, dns_db_origin(db), + zone_nsecttl(zone), false, &nsec3_diff); if (result != ISC_R_SUCCESS) { dnssec_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:" @@ -8983,8 +8861,8 @@ skip_removals: } if (updatensec) { - result = updatesecure(db, version, &zone->origin, zone->minimum, - false, &nsec_diff); + result = updatesecure(db, version, &zone->origin, + zone_nsecttl(zone), false, &nsec_diff); if (result != ISC_R_SUCCESS) { dnssec_log(zone, ISC_LOG_ERROR, "zone_nsec3chain:updatesecure -> %s", @@ -9650,7 +9528,7 @@ zone_sign(dns_zone_t *zone) { CHECK(sign_a_node( db, zone, name, node, version, build_nsec3, build_nsec, zone_keys[i], inception, expire, - zone->minimum, is_ksk, is_zsk, + zone_nsecttl(zone), is_ksk, is_zsk, (both && keyset_kskonly), is_bottom_of_zone, zonediff.diff, &signatures, zone->mctx)); /* @@ -9691,7 +9569,7 @@ zone_sign(dns_zone_t *zone) { */ result = updatesecure( db, version, &zone->origin, - zone->minimum, false, + zone_nsecttl(zone), false, &post_diff); if (result != ISC_R_SUCCESS) { dnssec_log(zone, ISC_LOG_ERROR, @@ -9703,7 +9581,7 @@ zone_sign(dns_zone_t *zone) { } result = updatesignwithkey( zone, signing, version, build_nsec3, - zone->minimum, &post_diff); + zone_nsecttl(zone), &post_diff); if (result != ISC_R_SUCCESS) { dnssec_log(zone, ISC_LOG_ERROR, "updatesignwithkey -> %s", @@ -11303,7 +11181,7 @@ again: ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); if (zone->db != NULL) { result = zone_get_from_db( - zone, zone->db, NULL, &soacount, + zone, zone->db, NULL, &soacount, NULL, &serial, NULL, NULL, NULL, NULL, NULL); } else { result = DNS_R_NOTLOADED; @@ -12819,7 +12697,7 @@ stub_finish_zone_update(dns_stub_t *stub, isc_time_t now) { if (zone->db == NULL) { zone_attachdb(zone, stub->db); } - result = zone_get_from_db(zone, zone->db, NULL, &soacount, NULL, + result = zone_get_from_db(zone, zone->db, NULL, &soacount, NULL, NULL, &refresh, &retry, &expire, NULL, NULL); if (result == ISC_R_SUCCESS && soacount > 0U) { zone->refresh = RANGE(refresh, zone->minrefresh, @@ -13877,8 +13755,8 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED)) { unsigned int dbsoacount; result = zone_get_from_db(zone, zone->db, NULL, &dbsoacount, - &oldserial, NULL, NULL, NULL, NULL, - NULL); + NULL, &oldserial, NULL, NULL, NULL, + NULL, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); RUNTIME_CHECK(dbsoacount > 0U); zone_debuglog(zone, me, 1, "serial: new %u, old %u", serial, @@ -15233,8 +15111,8 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, * lock and succeed in this context. */ result = zone_get_from_db(zone, zone->db, NULL, - &soacount, &oldserial, NULL, - NULL, NULL, NULL, NULL); + &soacount, NULL, &oldserial, + NULL, NULL, NULL, NULL, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); RUNTIME_CHECK(soacount > 0U); if (isc_serial_le(serial, oldserial)) { @@ -16966,7 +16844,7 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, bool dump) { } result = zone_get_from_db(zone, db, &nscount, &soacount, NULL, NULL, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); if (result == ISC_R_SUCCESS) { if (soacount != 1) { dns_zone_log(zone, ISC_LOG_ERROR, "has %d SOA records", @@ -17019,7 +16897,7 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, bool dump) { /* * This is checked in zone_postload() for master zones. */ - result = zone_get_from_db(zone, zone->db, NULL, &soacount, + result = zone_get_from_db(zone, zone->db, NULL, &soacount, NULL, &oldserial, NULL, NULL, NULL, NULL, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); @@ -17155,7 +17033,7 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { bool again = false; unsigned int soacount; unsigned int nscount; - uint32_t serial, refresh, retry, expire, minimum; + uint32_t serial, refresh, retry, expire, minimum, soattl; isc_result_t xfrresult = result; bool free_needed; dns_zone_t *secure = NULL; @@ -17212,8 +17090,8 @@ again: soacount = 0; INSIST(zone->db != NULL); result = zone_get_from_db(zone, zone->db, &nscount, &soacount, - &serial, &refresh, &retry, &expire, - &minimum, NULL); + &soattl, &serial, &refresh, &retry, + &expire, &minimum, NULL); ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); if (result == ISC_R_SUCCESS) { if (soacount != 1) { @@ -17243,6 +17121,7 @@ again: zone->expire = RANGE(expire, zone->refresh + zone->retry, DNS_MAX_EXPIRE); + zone->soattl = soattl; zone->minimum = minimum; DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS); } @@ -19991,10 +19870,10 @@ add_chains(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, CHECK(dns_private_chains(db, ver, zone->privatetype, NULL, &build_nsec3)); if (build_nsec3) { - CHECK(dns_nsec3_addnsec3sx(db, ver, origin, zone->minimum, + CHECK(dns_nsec3_addnsec3sx(db, ver, origin, zone_nsecttl(zone), false, zone->privatetype, diff)); } - CHECK(updatesecure(db, ver, origin, zone->minimum, true, diff)); + CHECK(updatesecure(db, ver, origin, zone_nsecttl(zone), true, diff)); failure: return (result); @@ -21989,3 +21868,10 @@ done: return (result); } + +static inline dns_ttl_t +zone_nsecttl(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + + return (ISC_MIN(zone->minimum, zone->soattl)); +}