📄 update.c
字号:
*/ CHECK(delete_if(true_p, db, ver, name, dns_rdatatype_nxt, 0, NULL, diff)); /* * Add the new NXT and record the change. */ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 3600, /* XXXRTH */ &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 NXT record for "name", recording the change in "diff". */static isc_result_tadd_placeholder_nxt(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_nxt, &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_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; CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); CHECK(dns_dnssec_findzonekeys(db, ver, node, dns_db_origin(db), mctx, maxkeys, keys, nkeys)); failure: if (node != NULL) dns_db_detachnode(db, &node); return (result);}/* * Add SIG 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_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++) { /* Calculate the signature, creating a SIG RDATA. */ CHECK(dns_dnssec_sign(name, &rdataset, keys[i], &inception, &expire, mctx, &buffer, &sig_rdata)); /* Update the database and journal with the SIG. */ /* 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 SIG and NXT records affected by an update. The original * update, including the SOA serial update but exluding the SIG & NXT * changes, is in "diff" and has already been applied to "newver" of "db". * The database version prior to the update is "oldver". * * The necessary SIG and NXT changes will be applied to "newver" * and added (as a minimal diff) to "diff". * * The SIGs generated will be valid for 'sigvalidityinterval' seconds. */static isc_result_tupdate_signatures(isc_mem_t *mctx, 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 nxt_diff; dns_diff_t nxt_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_diff_init(mctx, &diffnames); dns_diff_init(mctx, &affected); dns_diff_init(mctx, &sig_diff); dns_diff_init(mctx, &nxt_diff); dns_diff_init(mctx, &nxt_mindiff); result = find_zone_keys(db, newver, mctx, MAXZONEKEYS, zone_keys, &nkeys); if (result != ISC_R_SUCCESS) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, 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; /* * Find all RRsets directly affected by the update, and * update their SIGs. 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 SIGs. */ if (type == dns_rdatatype_sig) goto skip; /* * Delete all old SIGs 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_sig, 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, mctx, inception, expire)); } 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 NXTs and SIG NXTs. */ for (t = ISC_LIST_HEAD(diffnames.tuples); t != NULL; t = ISC_LIST_NEXT(t, link)) { CHECK(non_nxt_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 NXT 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 NXTs 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(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 NXT update. */ CHECK(namelist_append_subdomain(db, &t->name, &affected)); } ISC_LIST_APPENDLIST(affected.tuples, diffnames.tuples, link); INSIST(ISC_LIST_EMPTY(diffnames.tuples)); CHECK(uniqify_name_list(&affected)); /* * Determine which names should have NXTs, and delete/create * NXTs to make it so. We don't know the final NXT targets yet, * so we just create placeholder NXTs with arbitrary contents * to indicate that their respective owner names should be part of * the NXT chain. */ for (t = ISC_LIST_HEAD(affected.tuples); t != NULL; t = ISC_LIST_NEXT(t, link)) { isc_boolean_t exists; CHECK(name_exists(db, newver, &t->name, &exists)); if (! exists) continue; CHECK(is_glue(db, newver, &t->name, &flag)); if (flag) { /* * This name is obscured. Delete any * existing NXT record. */ CHECK(delete_if(true_p, db, newver, &t->name, dns_rdatatype_nxt, 0, NULL, &nxt_diff)); } else { /* * This name is not obscured. It should have a NXT. */ CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_nxt, 0, &flag)); if (! flag) { add_placeholder_nxt(db, newver, &t->name, diff); } } } /* * Now we know which names are part of the NXT chain. * Make them all point at their correct targets. */ for (t = ISC_LIST_HEAD(affected.tuples); t != NULL; t = ISC_LIST_NEXT(t, link)) { CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_nxt, 0, &flag)); if (flag) { /* * There is a NXT, but we don't know if it is correct. * Delete it and create a correct one to be sure. * If the update was unnecessary, the diff minimization * will take care of eliminating it from the journal, * IXFRs, etc. * * The SIG bit should always be set in the NXTs * we generate, because they will all get SIG NXTs. * (XXX what if the zone keys are missing?). * Because the SIG NXTs have not necessarily been * created yet, the correctness of the bit mask relies * on the assumption that NXTs are only created if * there is other data, and if there is other data, * there are other SIGs. */ CHECK(add_nxt(db, newver, &t->name, &nxt_diff)); } } /* * Minimize the set of NXT updates so that we don't * have to regenerate the SIG NXTs for NXTs that were * replaced with identical ones. */ while ((t = ISC_LIST_HEAD(nxt_diff.tuples)) != NULL) { ISC_LIST_UNLINK(nxt_diff.tuples, t, link); dns_diff_appendminimal(&nxt_mindiff, &t); } /* Update SIG NXTs. */ for (t = ISC_LIST_HEAD(nxt_mindiff.tuples); t != NULL; t = ISC_LIST_NEXT(t, link)) { if (t->op == DNS_DIFFOP_DEL) { CHECK(delete_if(true_p, db, newver, &t->name, dns_rdatatype_sig, dns_rdatatype_nxt, NULL, &sig_diff)); } else if (t->op == DNS_DIFFOP_ADD) { CHECK(add_sigs(db, newver, &t->name, dns_rdatatype_nxt, &sig_diff, zone_keys, nkeys, mctx, inception, expire)); } else { INSIST(0); } } /* Record our changes for the journal. */ while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) { ISC_LIST_UNLINK(sig_diff.tuples, t, link); dns_diff_appendminimal(diff, &t); } while ((t = ISC_LIST_HEAD(nxt_mindiff.tuples)) != NULL) { ISC_LIST_UNLINK(nxt_mindiff.tuples, t, link); dns_diff_appendminimal(diff, &t); } INSIST(ISC_LIST_EMPTY(sig_diff.tuples)); INSIST(ISC_LIST_EMPTY(nxt_diff.tuples)); INSIST(ISC_LIST_EMPTY(nxt_mindiff.tuples)); failure: dns_diff_clear(&sig_diff); dns_diff_clear(&nxt_diff); dns_diff_clear(&nxt_mindiff); dns_diff_clear(&affected); dns_diff_clear(&diffnames); for (i = 0; i < nkeys; i++) dst_key_free(&zone_keys[i]); return (result);}/**************************************************************************//* * The actual update code in all its glory. We try to follow * the RFC2136 pseudocode as closely as possible. */static isc_result_tsend_update_event(ns_client_t *client, dns_zone_t *zone) { isc_result_t result = ISC_R_SUCCESS; update_event_t *event = NULL; isc_task_t *zonetask = NULL; ns_client_t *evclient; event = (update_event_t *) isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE, update_action, NULL, sizeof(*event)); if (event == NULL) FAIL(ISC_R_NOMEMORY); event->zone = zone; event->result = ISC_R_SUCCESS; evclient = NULL; ns_client_attach(client, &evclient); event->ev_arg = evclient; dns_zone_gettask(zone, &zonetask); isc_task_send(zonetask, (isc_event_t **)&event); failure: if (event != NULL) isc_event_free((isc_event_t **)&event); return (result);}static voidrespond(ns_client_t *client, isc_result_t result) { isc_result_t msg_result; msg_result = dns_message_reply(client->message, ISC_TRUE); if (msg_result != ISC_R_SUCCESS) goto msg_failure; client->message->rcode = dns_result_torcode(result); ns_client_send(client); return; msg_failure: isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, ISC_LOG_ERROR, "could not create update response message: %s", isc_result_totext(msg_result)); ns_client_next(client, msg_result);}voidns_update_start(ns_client_t *client, isc_result_t sigresult) { dns_message_t *request = client->message; isc_result_t result; dns_name_t *zonename; dns_rdataset_t *zone_rdataset; dns_zone_t *zone = NULL; /* * Interpret the zone section. */ result = dns_message_firstname(request, DNS_SECTION_ZONE); if (result != ISC_R_SUCCESS) FAILC(DNS_R_FORMERR,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -