update.c
来自「非常好的dns解析软件」· C语言 代码 · 共 2,383 行 · 第 1/5 页
C
2,383 行
DNS_DBFIND_GLUEOK | DNS_DBFIND_NOWILD, (isc_stdtime_t) 0, NULL, dns_fixedname_name(&foundname), NULL, NULL); if (result == ISC_R_SUCCESS) { *flag = ISC_FALSE; return (ISC_R_SUCCESS); } else if (result == DNS_R_ZONECUT) { /* * We are at the zonecut. The name will have an NSEC, but * non-delegation will be omitted from the type bit map. */ *flag = ISC_FALSE; return (ISC_R_SUCCESS); } else if (result == DNS_R_GLUE || result == DNS_R_DNAME) { *flag = ISC_TRUE; 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 * have had their NSECs removed because they are obscured by * a zone cut. */static isc_result_tnext_active(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *oldname, dns_name_t *newname, isc_boolean_t forward){ isc_result_t result; dns_dbiterator_t *dbit = NULL; isc_boolean_t has_nsec; unsigned int wraps = 0; CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit)); CHECK(dns_dbiterator_seek(dbit, oldname)); do { dns_dbnode_t *node = NULL; if (forward) result = dns_dbiterator_next(dbit); else result = dns_dbiterator_prev(dbit); if (result == ISC_R_NOMORE) { /* * Wrap around. */ if (forward) CHECK(dns_dbiterator_first(dbit)); else CHECK(dns_dbiterator_last(dbit)); wraps++; if (wraps == 2) { update_log(client, zone, ISC_LOG_ERROR, "secure zone with no NSECs"); result = DNS_R_BADZONE; goto failure; } } CHECK(dns_dbiterator_current(dbit, &node, newname)); dns_db_detachnode(db, &node); /* * The iterator may hold the tree lock, and * rrset_exists() calls dns_db_findnode() which * may try to reacquire it. To avoid deadlock * we must pause the iterator first. */ CHECK(dns_dbiterator_pause(dbit)); CHECK(rrset_exists(db, ver, newname, dns_rdatatype_nsec, 0, &has_nsec)); } while (! has_nsec); failure: if (dbit != NULL) dns_dbiterator_destroy(&dbit); return (result);}/*% * Add a NSEC record for "name", recording the change in "diff". * The existing NSEC is removed. */static isc_result_tadd_nsec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_ttl_t nsecttl, dns_diff_t *diff){ isc_result_t result; dns_dbnode_t *node = NULL; unsigned char buffer[DNS_NSEC_BUFFERSIZE]; dns_rdata_t rdata = DNS_RDATA_INIT; dns_difftuple_t *tuple = NULL; dns_fixedname_t fixedname; dns_name_t *target; dns_fixedname_init(&fixedname); target = dns_fixedname_name(&fixedname); /* * Find the successor name, aka NSEC target. */ CHECK(next_active(client, zone, db, ver, name, target, ISC_TRUE)); /* * Create the NSEC RDATA. */ CHECK(dns_db_findnode(db, name, ISC_FALSE, &node)); dns_rdata_init(&rdata); CHECK(dns_nsec_buildrdata(db, ver, node, target, buffer, &rdata)); dns_db_detachnode(db, &node); /* * Delete the old NSEC and record the change. */ CHECK(delete_if(true_p, db, ver, name, dns_rdatatype_nsec, 0, NULL, diff)); /* * Add the new NSEC and record the change. */ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, nsecttl, &rdata, &tuple)); CHECK(do_one_tuple(&tuple, db, ver, diff)); INSIST(tuple == NULL); failure: if (node != NULL) dns_db_detachnode(db, &node); return (result);}/*% * Add a placeholder NSEC record for "name", recording the change in "diff". */static isc_result_tadd_placeholder_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_diff_t *diff) { isc_result_t result; dns_difftuple_t *tuple = NULL; isc_region_t r; unsigned char data[1] = { 0 }; /* The root domain, no bits. */ dns_rdata_t rdata = DNS_RDATA_INIT; r.base = data; r.length = sizeof(data); dns_rdata_fromregion(&rdata, dns_db_class(db), dns_rdatatype_nsec, &r); CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 0, &rdata, &tuple)); CHECK(do_one_tuple(&tuple, db, ver, diff)); failure: return (result);}static isc_result_tfind_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, isc_mem_t *mctx, unsigned int maxkeys, dst_key_t **keys, unsigned int *nkeys){ isc_result_t result; dns_dbnode_t *node = NULL; const char *directory = dns_zone_getkeydirectory(zone); CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); CHECK(dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db), directory, mctx, maxkeys, keys, nkeys)); failure: if (node != NULL) dns_db_detachnode(db, &node); return (result);}static isc_boolean_tksk_sanity(dns_db_t *db, dns_dbversion_t *ver) { isc_boolean_t ret = ISC_FALSE; isc_boolean_t have_ksk = ISC_FALSE, have_nonksk = ISC_FALSE; isc_result_t result; dns_dbnode_t *node = NULL; dns_rdataset_t rdataset; dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdata_dnskey_t dnskey; dns_rdataset_init(&rdataset); CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); CHECK(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0, &rdataset, NULL)); CHECK(dns_rdataset_first(&rdataset)); while (result == ISC_R_SUCCESS && (!have_ksk || !have_nonksk)) { dns_rdataset_current(&rdataset, &rdata); CHECK(dns_rdata_tostruct(&rdata, &dnskey, NULL)); if ((dnskey.flags & (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH)) == DNS_KEYOWNER_ZONE) { if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0) have_ksk = ISC_TRUE; else have_nonksk = ISC_TRUE; } dns_rdata_reset(&rdata); result = dns_rdataset_next(&rdataset); } if (have_ksk && have_nonksk) ret = ISC_TRUE; failure: if (dns_rdataset_isassociated(&rdataset)) dns_rdataset_disassociate(&rdataset); if (node != NULL) dns_db_detachnode(db, &node); return (ret);}/*% * Add RRSIG records for an RRset, recording the change in "diff". */static isc_result_tadd_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys, isc_mem_t *mctx, isc_stdtime_t inception, isc_stdtime_t expire, isc_boolean_t check_ksk){ isc_result_t result; dns_dbnode_t *node = NULL; dns_rdataset_t rdataset; dns_rdata_t sig_rdata = DNS_RDATA_INIT; isc_buffer_t buffer; unsigned char data[1024]; /* XXX */ unsigned int i; dns_rdataset_init(&rdataset); isc_buffer_init(&buffer, data, sizeof(data)); /* Get the rdataset to sign. */ 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); for (i = 0; i < nkeys; i++) { if (check_ksk && type != dns_rdatatype_dnskey && (dst_key_flags(keys[i]) & DNS_KEYFLAG_KSK) != 0) continue; /* Calculate the signature, creating a RRSIG RDATA. */ CHECK(dns_dnssec_sign(name, &rdataset, keys[i], &inception, &expire, mctx, &buffer, &sig_rdata)); /* Update the database and journal with the RRSIG. */ /* XXX inefficient - will cause dataset merging */ CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, name, rdataset.ttl, &sig_rdata)); dns_rdata_reset(&sig_rdata); } failure: if (dns_rdataset_isassociated(&rdataset)) dns_rdataset_disassociate(&rdataset); if (node != NULL) dns_db_detachnode(db, &node); return (result);}/*% * Update RRSIG and NSEC 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" * and added (as a minimal diff) to "diff". * * The RRSIGs generated will be valid for 'sigvalidityinterval' seconds. */static isc_result_tupdate_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *oldver, dns_dbversion_t *newver, dns_diff_t *diff, isc_uint32_t sigvalidityinterval){ isc_result_t result; dns_difftuple_t *t; dns_diff_t diffnames; dns_diff_t affected; dns_diff_t sig_diff; dns_diff_t nsec_diff; dns_diff_t nsec_mindiff; isc_boolean_t flag; dst_key_t *zone_keys[MAXZONEKEYS]; unsigned int nkeys = 0; unsigned int i; isc_stdtime_t now, inception, expire; dns_ttl_t nsecttl; dns_rdata_soa_t soa; dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_t rdataset; dns_dbnode_t *node = NULL; isc_boolean_t check_ksk; dns_diff_init(client->mctx, &diffnames); dns_diff_init(client->mctx, &affected); dns_diff_init(client->mctx, &sig_diff); dns_diff_init(client->mctx, &nsec_diff); dns_diff_init(client->mctx, &nsec_mindiff); result = find_zone_keys(zone, db, newver, client->mctx, MAXZONEKEYS, zone_keys, &nkeys); if (result != ISC_R_SUCCESS) { update_log(client, zone, ISC_LOG_ERROR, "could not get zone keys for secure dynamic update"); goto failure; } isc_stdtime_get(&now); inception = now - 3600; /* Allow for some clock skew. */ expire = now + sigvalidityinterval; /* * Do we look at the KSK flag on the DNSKEY to determining which * keys sign which RRsets? First check the zone option then * check the keys flags to make sure atleast one has a ksk set * and one doesn't. */ check_ksk = ISC_TF((dns_zone_getoptions(zone) & DNS_ZONEOPT_UPDATECHECKKSK) != 0); if (check_ksk) check_ksk = ksk_sanity(db, newver); /* * Get the NSEC's TTL from the SOA MINIMUM field. */ CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); dns_rdataset_init(&rdataset); CHECK(dns_db_findrdataset(db, node, newver, dns_rdatatype_soa, 0, (isc_stdtime_t) 0, &rdataset, NULL)); CHECK(dns_rdataset_first(&rdataset)); dns_rdataset_current(&rdataset, &rdata); CHECK(dns_rdata_tostruct(&rdata, &soa, NULL)); nsecttl = soa.minimum; dns_rdataset_disassociate(&rdataset); dns_db_detachnode(db, &node); /* * Find all RRsets directly affected by the update, and * update their RRSIGs. Also build a list of names affected * by the update in "diffnames". */ CHECK(dns_diff_sort(diff, temp_order)); t = ISC_LIST_HEAD(diff->tuples); while (t != NULL) { dns_name_t *name = &t->name; /* Now "name" is a new, unique name affected by the update. */ CHECK(namelist_append_name(&diffnames, name)); while (t != NULL && dns_name_equal(&t->name, name)) { dns_rdatatype_t type; type = t->rdata.type; /* * Now "name" and "type" denote a new unique RRset * affected by the update. */ /* Don't sign RRSIGs. */ if (type == dns_rdatatype_rrsig) goto skip; /* * Delete all old RRSIGs covering this type, since they * are all invalid when the signed RRset has changed. * We may not be able to recreate all of them - tough. */ CHECK(delete_if(true_p, db, newver, name, dns_rdatatype_rrsig, type, NULL, &sig_diff)); /* * If this RRset still exists after the update, * add a new signature for it. */ CHECK(rrset_exists(db, newver, name, type, 0, &flag)); if (flag) { CHECK(add_sigs(db, newver, name, type, &sig_diff, zone_keys, nkeys, client->mctx, inception, expire, check_ksk)); } skip: /* Skip any other updates to the same RRset. */ while (t != NULL && dns_name_equal(&t->name, name) && t->rdata.type == type) { t = ISC_LIST_NEXT(t, link); } } } /* Remove orphaned NSECs and RRSIG NSECs. */ for (t = ISC_LIST_HEAD(diffnames.tuples); t != NULL; t = ISC_LIST_NEXT(t, link)) { CHECK(non_nsec_rrset_exists(db, newver, &t->name, &flag)); if (! flag) { CHECK(delete_if(true_p, db, newver, &t->name, dns_rdatatype_any, 0, NULL, &sig_diff)); } } /* * When a name is created or deleted, its predecessor needs to * have its NSEC updated. */ for (t = ISC_LIST_HEAD(diffnames.tuples); t != NULL; t = ISC_LIST_NEXT(t, link)) { isc_boolean_t existed, exists; dns_fixedname_t fixedname; dns_name_t *prevname; dns_fixedname_init(&fixedname); prevname = dns_fixedname_name(&fixedname); CHECK(name_exists(db, oldver, &t->name, &existed)); CHECK(name_exists(db, newver, &t->name, &exists)); if (exists == existed) continue; /* * Find the predecessor. * When names become obscured or unobscured in this update * transaction, we may find the wrong predecessor because * the NSECs have not yet been updated to reflect the delegation * change. This should not matter because in this case, * the correct predecessor is either the delegation node or * a newly unobscured node, and those nodes are on the * "affected" list in any case. */ CHECK(next_active(client, zone, db, newver, &t->name, prevname, ISC_FALSE)); CHECK(namelist_append_name(&affected, prevname)); } /* * Find names potentially affected by delegation changes * (obscured by adding an NS or DNAME, or unobscured by * removing one). */ for (t = ISC_LIST_HEAD(diffnames.tuples); t != NULL; t = ISC_LIST_NEXT(t, link)) { isc_boolean_t ns_existed, dname_existed; isc_boolean_t ns_exists, dname_exists; CHECK(rrset_exists(db, oldver, &t->name, dns_rdatatype_ns, 0, &ns_existed)); CHECK(rrset_exists(db, oldver, &t->name, dns_rdatatype_dname, 0, &dname_existed)); CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ns, 0, &ns_exists)); CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_dname, 0, &dname_exists)); if ((ns_exists || dname_exists) == (ns_existed || dname_existed)) continue; /* * There was a delegation change. Mark all subdomains * of t->name as potentially needing a NSEC update.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?