📄 update.c
字号:
return (result); } else { return (ISC_R_SUCCESS); }}/* * Conditionally delete RRs. Apply 'predicate' to the RRs * specified by 'db', 'ver', 'name', and 'type' (which can * be dns_rdatatype_any to match any type). Delete those * RRs for which the predicate returns true, and log the * deletions in 'diff'. */static isc_result_tdelete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers, dns_rdata_t *update_rr, dns_diff_t *diff){ conditional_delete_ctx_t ctx; ctx.predicate = predicate; ctx.db = db; ctx.ver = ver; ctx.diff = diff; ctx.name = name; ctx.update_rr = update_rr; return (foreach_rr(db, ver, name, type, covers, delete_if_action, &ctx));}/**************************************************************************//* * Prepare an RR for the addition of the new RR 'ctx->update_rr', * with TTL 'ctx->update_rr_ttl', to its rdataset, by deleting * the RRs if it is replaced by the new RR or has a conflicting TTL. * The necessary changes are appended to ctx->del_diff and ctx->add_diff; * we need to do all deletions before any additions so that we don't run * into transient states with conflicting TTLs. */typedef struct { dns_db_t *db; dns_dbversion_t *ver; dns_diff_t *diff; dns_name_t *name; dns_rdata_t *update_rr; dns_ttl_t update_rr_ttl; isc_boolean_t ignore_add; dns_diff_t del_diff; dns_diff_t add_diff;} add_rr_prepare_ctx_t;static isc_result_tadd_rr_prepare_action(void *data, rr_t *rr) { isc_result_t result = ISC_R_SUCCESS; add_rr_prepare_ctx_t *ctx = data; dns_difftuple_t *tuple = NULL; /* * If the update RR is a "duplicate" of the update RR, * the update should be silently ignored. */ if (dns_rdata_compare(&rr->rdata, ctx->update_rr) == 0 && rr->ttl == ctx->update_rr_ttl) { ctx->ignore_add = ISC_TRUE; } /* * If this RR is "equal" to the update RR, it should * be deleted before the update RR is added. */ if (replaces_p(ctx->update_rr, &rr->rdata)) { CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL, ctx->name, rr->ttl, &rr->rdata, &tuple)); dns_diff_append(&ctx->del_diff, &tuple); return (ISC_R_SUCCESS); } /* * If this RR differs in TTL from the update RR, * its TTL must be adjusted. */ if (rr->ttl != ctx->update_rr_ttl) { CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL, ctx->name, rr->ttl, &rr->rdata, &tuple)); dns_diff_append(&ctx->del_diff, &tuple); CHECK(dns_difftuple_create(ctx->add_diff.mctx, DNS_DIFFOP_ADD, ctx->name, ctx->update_rr_ttl, &rr->rdata, &tuple)); dns_diff_append(&ctx->add_diff, &tuple); } failure: return (result);}/**************************************************************************//* * Miscellaneous subroutines. *//* * Extract a single update RR from 'section' of dynamic update message * 'msg', with consistency checking. * * Stores the owner name, rdata, and TTL of the update RR at 'name', * 'rdata', and 'ttl', respectively. */static voidget_current_rr(dns_message_t *msg, dns_section_t section, dns_rdataclass_t zoneclass, dns_name_t **name, dns_rdata_t *rdata, dns_rdatatype_t *covers, dns_ttl_t *ttl, dns_rdataclass_t *update_class){ dns_rdataset_t *rdataset; isc_result_t result; dns_message_currentname(msg, section, name); rdataset = ISC_LIST_HEAD((*name)->list); INSIST(rdataset != NULL); INSIST(ISC_LIST_NEXT(rdataset, link) == NULL); *covers = rdataset->covers; *ttl = rdataset->ttl; result = dns_rdataset_first(rdataset); INSIST(result == ISC_R_SUCCESS); dns_rdataset_current(rdataset, rdata); INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE); *update_class = rdata->rdclass; rdata->rdclass = zoneclass;}/* * Increment the SOA serial number of database 'db', version 'ver'. * Replace the SOA record in the database, and log the * change in 'diff'. */ /* * XXXRTH Failures in this routine will be worth logging, when * we have a logging system. Failure to find the zonename * or the SOA rdataset warrant at least an UNEXPECTED_ERROR(). */static isc_result_tincrement_soa_serial(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, isc_mem_t *mctx){ dns_difftuple_t *deltuple = NULL; dns_difftuple_t *addtuple = NULL; isc_uint32_t serial; isc_result_t result; CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple)); CHECK(dns_difftuple_copy(deltuple, &addtuple)); addtuple->op = DNS_DIFFOP_ADD; serial = dns_soa_getserial(&addtuple->rdata); /* RFC1982 */ serial = (serial + 1) & 0xFFFFFFFF; if (serial == 0) serial = 1; dns_soa_setserial(serial, &addtuple->rdata); CHECK(do_one_tuple(&deltuple, db, ver, diff)); CHECK(do_one_tuple(&addtuple, db, ver, diff)); result = ISC_R_SUCCESS; failure: if (addtuple != NULL) dns_difftuple_free(&addtuple); if (deltuple != NULL) dns_difftuple_free(&deltuple); return (result);}/* * Check that the new SOA record at 'update_rdata' does not * illegally cause the SOA serial number to decrease or stay * unchanged relative to the existing SOA in 'db'. * * Sets '*ok' to ISC_TRUE if the update is legal, ISC_FALSE if not. * * William King points out that RFC2136 is inconsistent about * the case where the serial number stays unchanged: * * section 3.4.2.2 requires a server to ignore a SOA update request * if the serial number on the update SOA is less_than_or_equal to * the zone SOA serial. * * section 3.6 requires a server to ignore a SOA update request if * the serial is less_than the zone SOA serial. * * Paul says 3.4.2.2 is correct. * */static isc_result_tcheck_soa_increment(dns_db_t *db, dns_dbversion_t *ver, dns_rdata_t *update_rdata, isc_boolean_t *ok){ isc_uint32_t db_serial; isc_uint32_t update_serial; isc_result_t result; update_serial = dns_soa_getserial(update_rdata); result = dns_db_getsoaserial(db, ver, &db_serial); if (result != ISC_R_SUCCESS) return (result); if (DNS_SERIAL_GE(db_serial, update_serial)) { *ok = ISC_FALSE; } else { *ok = ISC_TRUE; } return (ISC_R_SUCCESS);}/**************************************************************************//* * Incremental updating of NXTs and SIGs. */#define MAXZONEKEYS 32 /* Maximum number of zone keys supported. *//* * We abuse the dns_diff_t type to represent a set of domain names * affected by the update. */static isc_result_tnamelist_append_name(dns_diff_t *list, dns_name_t *name) { isc_result_t result; dns_difftuple_t *tuple = NULL; static dns_rdata_t dummy_rdata = { NULL, 0, 0, 0, 0, { (void*)(-1), (void*)(-1) } }; CHECK(dns_difftuple_create(list->mctx, DNS_DIFFOP_EXISTS, name, 0, &dummy_rdata, &tuple)); dns_diff_append(list, &tuple); failure: return (result);}static isc_result_tnamelist_append_subdomain(dns_db_t *db, dns_name_t *name, dns_diff_t *affected){ isc_result_t result; dns_fixedname_t fixedname; dns_name_t *child; dns_dbiterator_t *dbit = NULL; dns_fixedname_init(&fixedname); child = dns_fixedname_name(&fixedname); CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit)); for (result = dns_dbiterator_seek(dbit, name); result == ISC_R_SUCCESS; result = dns_dbiterator_next(dbit)) { dns_dbnode_t *node = NULL; result = dns_dbiterator_current(dbit, &node, child); dns_db_detachnode(db, &node); CHECK(result); if (! dns_name_issubdomain(child, name)) break; CHECK(namelist_append_name(affected, child)); } if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; failure: if (dbit != NULL) dns_dbiterator_destroy(&dbit); return (result);}/* * Helper function for non_nxt_rrset_exists(). */static isc_result_tis_non_nxt_action(void *data, dns_rdataset_t *rrset) { UNUSED(data); if (!(rrset->type == dns_rdatatype_nxt || (rrset->type == dns_rdatatype_sig && rrset->covers == dns_rdatatype_nxt))) return (ISC_R_EXISTS); return (ISC_R_SUCCESS);}/* * Check whether there is an rrset other than a NXT or SIG NXT, * i.e., anything that justifies the continued existence of a name * after a secure update. * * If such an rrset exists, set '*exists' to ISC_TRUE. * Otherwise, set it to ISC_FALSE. */static isc_result_tnon_nxt_rrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, isc_boolean_t *exists){ isc_result_t result; result = foreach_rrset(db, ver, name, is_non_nxt_action, NULL); RETURN_EXISTENCE_FLAG;}/* * A comparison function for sorting dns_diff_t:s by name. */static intname_order(const void *av, const void *bv) { dns_difftuple_t const * const *ap = av; dns_difftuple_t const * const *bp = bv; dns_difftuple_t const *a = *ap; dns_difftuple_t const *b = *bp; return (dns_name_compare(&a->name, &b->name));}static isc_result_tuniqify_name_list(dns_diff_t *list) { isc_result_t result; dns_difftuple_t *p, *q; CHECK(dns_diff_sort(list, name_order)); p = ISC_LIST_HEAD(list->tuples); while (p != NULL) { do { q = ISC_LIST_NEXT(p, link); if (q == NULL || ! dns_name_equal(&p->name, &q->name)) break; ISC_LIST_UNLINK(list->tuples, q, link); dns_difftuple_free(&q); } while (1); p = ISC_LIST_NEXT(p, link); } failure: return (result);}static isc_result_tis_glue(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, isc_boolean_t *flag){ isc_result_t result; dns_fixedname_t foundname; dns_fixedname_init(&foundname); result = dns_db_find(db, name, ver, dns_rdatatype_any, 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 NXT, 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 NXT record. * In other words, skip empty database nodes and names that * have had their NXTs removed because they are obscured by * a zone cut. */static isc_result_tnext_active(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_nxt; 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) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, ISC_LOG_ERROR, "secure zone with no NXTs"); result = DNS_R_BADZONE; goto failure; } } 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_nxt, 0, &has_nxt)); } while (! has_nxt); failure: if (dbit != NULL) dns_dbiterator_destroy(&dbit); return (result);}/* * Add a NXT record for "name", recording the change in "diff". * The existing NXT is removed. */static isc_result_tadd_nxt(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_diff_t *diff){ isc_result_t result; dns_dbnode_t *node = NULL; unsigned char buffer[DNS_NXT_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 NXT target. */ CHECK(next_active(db, ver, name, target, ISC_TRUE)); /* * Create the NXT RDATA. */ CHECK(dns_db_findnode(db, name, ISC_FALSE, &node)); dns_rdata_init(&rdata); CHECK(dns_nxt_buildrdata(db, ver, node, target, buffer, &rdata)); dns_db_detachnode(db, &node); /* * Delete the old NXT and record the change.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -