📄 update.c
字号:
dns_name_t *name; dns_rdata_t *update_rr;} conditional_delete_ctx_t;/* * Predicate functions for delete_if(). *//* * Return true iff 'update_rr' is neither a SOA nor an NS RR. */static isc_boolean_ttype_not_soa_nor_ns_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { UNUSED(update_rr); return ((db_rr->type != dns_rdatatype_soa && db_rr->type != dns_rdatatype_ns) ? ISC_TRUE : ISC_FALSE);}/* * Return true always. */static isc_boolean_ttrue_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { UNUSED(update_rr); UNUSED(db_rr); return (ISC_TRUE);}/* * Return true iff the two RRs have identical rdata. */static isc_boolean_trr_equal_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { /* * XXXRTH This is not a problem, but we should consider creating * dns_rdata_equal() (that used dns_name_equal()), since it * would be faster. Not a priority. */ return (dns_rdata_compare(update_rr, db_rr) == 0 ? ISC_TRUE : ISC_FALSE);}/* * Return true iff 'update_rr' should replace 'db_rr' according * to the special RFC2136 rules for CNAME, SOA, and WKS records. * * RFC2136 does not mention NSEC or DNAME, but multiple NSECs or DNAMEs * make little sense, so we replace those, too. */static isc_boolean_treplaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { if (db_rr->type != update_rr->type) return (ISC_FALSE); if (db_rr->type == dns_rdatatype_cname) return (ISC_TRUE); if (db_rr->type == dns_rdatatype_dname) return (ISC_TRUE); if (db_rr->type == dns_rdatatype_soa) return (ISC_TRUE); if (db_rr->type == dns_rdatatype_nsec) return (ISC_TRUE); if (db_rr->type == dns_rdatatype_wks) { /* * Compare the address and protocol fields only. These * form the first five bytes of the RR data. Do a * raw binary comparison; unpacking the WKS RRs using * dns_rdata_tostruct() might be cleaner in some ways, * but it would require us to pass around an mctx. */ INSIST(db_rr->length >= 5 && update_rr->length >= 5); return (memcmp(db_rr->data, update_rr->data, 5) == 0 ? ISC_TRUE : ISC_FALSE); } return (ISC_FALSE);}/* * Internal helper function for delete_if(). */static isc_result_tdelete_if_action(void *data, rr_t *rr) { conditional_delete_ctx_t *ctx = data; if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) { isc_result_t result; result = update_one_rr(ctx->db, ctx->ver, ctx->diff, DNS_DIFFOP_DEL, ctx->name, rr->ttl, &rr->rdata); 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; isc_boolean_t equal; /* * If the update RR is a "duplicate" of the update RR, * the update should be silently ignored. */ equal = ISC_TF(dns_rdata_compare(&rr->rdata, ctx->update_rr) == 0); if (equal && rr->ttl == ctx->update_rr_ttl) { ctx->ignore_add = ISC_TRUE; return (ISC_R_SUCCESS); } /* * 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); if (!equal) { 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 NSECs and RRSIGs. */#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; CHECK(dns_dbiterator_current(dbit, &node, child)); dns_db_detachnode(db, &node); 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_nsec_rrset_exists(). */static isc_result_tis_non_nsec_action(void *data, dns_rdataset_t *rrset) { UNUSED(data); if (!(rrset->type == dns_rdatatype_nsec || (rrset->type == dns_rdatatype_rrsig && rrset->covers == dns_rdatatype_nsec))) return (ISC_R_EXISTS); return (ISC_R_SUCCESS);}/* * Check whether there is an rrset other than a NSEC or RRSIG NSEC, * 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_nsec_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_nsec_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 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); }}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -