📄 update.c
字号:
*/static isc_result_tforeach_node_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, rr_func *rr_action, void *rr_action_data){ foreach_node_rr_ctx_t ctx; ctx.rr_action = rr_action; ctx.rr_action_data = rr_action_data; return (foreach_rrset(db, ver, name, foreach_node_rr_action, &ctx));}/* * For each of the RRs specified by 'db', 'ver', 'name', 'type', * (which can be dns_rdatatype_any to match any type), and 'covers', call * 'action' with the RR and 'action_data' as arguments. If the name * does not exist, or if no RRset of the given type exists at the name, * do nothing. * * If 'action' returns an error, abort iteration and return the error. */static isc_result_tforeach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers, rr_func *rr_action, void *rr_action_data){ isc_result_t result; dns_dbnode_t *node; dns_rdataset_t rdataset; if (type == dns_rdatatype_any) return (foreach_node_rr(db, ver, name, rr_action, rr_action_data)); node = NULL; result = dns_db_findnode(db, name, ISC_FALSE, &node); if (result == ISC_R_NOTFOUND) return (ISC_R_SUCCESS); if (result != ISC_R_SUCCESS) return (result); dns_rdataset_init(&rdataset); result = dns_db_findrdataset(db, node, ver, type, covers, (isc_stdtime_t) 0, &rdataset, NULL); if (result == ISC_R_NOTFOUND) { result = ISC_R_SUCCESS; goto cleanup_node; } if (result != ISC_R_SUCCESS) goto cleanup_node; for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(&rdataset)) { rr_t rr = { 0, DNS_RDATA_INIT }; dns_rdataset_current(&rdataset, &rr.rdata); rr.ttl = rdataset.ttl; result = (*rr_action)(rr_action_data, &rr); if (result != ISC_R_SUCCESS) goto cleanup_rdataset; } if (result != ISC_R_NOMORE) goto cleanup_rdataset; result = ISC_R_SUCCESS; cleanup_rdataset: dns_rdataset_disassociate(&rdataset); cleanup_node: dns_db_detachnode(db, &node); return (result);}/**************************************************************************//* * Various tests on the database contents (for prerequisites, etc). *//* * Function type for predicate functions that compare a database RR 'db_rr' * against an update RR 'update_rr'. */typedef isc_boolean_t rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr);/* * Helper function for rrset_exists(). */static isc_result_trrset_exists_action(void *data, rr_t *rr) { UNUSED(data); UNUSED(rr); return (ISC_R_EXISTS);}/* * Utility macro for RR existence checking functions. * * If the variable 'result' has the value ISC_R_EXISTS or * ISC_R_SUCCESS, set *exists to ISC_TRUE or ISC_FALSE, * respectively, and return success. * * If 'result' has any other value, there was a failure. * Return the failure result code and do not set *exists. * * This would be more readable as "do { if ... } while(0)", * but that form generates tons of warnings on Solaris 2.6. */#define RETURN_EXISTENCE_FLAG \ return ((result == ISC_R_EXISTS) ? \ (*exists = ISC_TRUE, ISC_R_SUCCESS) : \ ((result == ISC_R_SUCCESS) ? \ (*exists = ISC_FALSE, ISC_R_SUCCESS) : \ result))/* * Set '*exists' to true iff an rrset of the given type exists, * to false otherwise. */static isc_result_trrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers, isc_boolean_t *exists){ isc_result_t result; result = foreach_rr(db, ver, name, type, covers, rrset_exists_action, NULL); RETURN_EXISTENCE_FLAG;}/* * Helper function for cname_incompatible_rrset_exists. */static isc_result_tcname_compatibility_action(void *data, dns_rdataset_t *rrset) { UNUSED(data); if (rrset->type != dns_rdatatype_cname && ! dns_rdatatype_isdnssec(rrset->type)) return (ISC_R_EXISTS); return (ISC_R_SUCCESS);}/* * Check whether there is an rrset incompatible with adding a CNAME RR, * i.e., anything but another CNAME (which can be replaced) or a * DNSSEC RR (which can coexist). * * If such an incompatible rrset exists, set '*exists' to ISC_TRUE. * Otherwise, set it to ISC_FALSE. */static isc_result_tcname_incompatible_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, cname_compatibility_action, NULL); RETURN_EXISTENCE_FLAG;}/* * Helper function for rr_count(). */static isc_result_tcount_rr_action(void *data, rr_t *rr) { int *countp = data; UNUSED(rr); (*countp)++; return (ISC_R_SUCCESS);}/* * Count the number of RRs of 'type' belonging to 'name' in 'ver' of 'db'. */static isc_result_trr_count(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers, int *countp){ *countp = 0; return (foreach_rr(db, ver, name, type, covers, count_rr_action, countp));}/* * Context struct and helper function for name_exists(). */static isc_result_tname_exists_action(void *data, dns_rdataset_t *rrset) { UNUSED(data); UNUSED(rrset); return (ISC_R_EXISTS);}/* * Set '*exists' to true iff the given name exists, to false otherwise. */static isc_result_tname_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, name_exists_action, NULL); RETURN_EXISTENCE_FLAG;}typedef struct { dns_name_t *name, *signer; dns_ssutable_t *table;} ssu_check_t;static isc_result_tssu_checkrule(void *data, dns_rdataset_t *rrset) { ssu_check_t *ssuinfo = data; isc_boolean_t result; /* * If we're deleting all records, it's ok to delete RRSIG and NSEC even * if we're normally not allowed to. */ if (rrset->type == dns_rdatatype_rrsig || rrset->type == dns_rdatatype_nsec) return (ISC_TRUE); result = dns_ssutable_checkrules(ssuinfo->table, ssuinfo->signer, ssuinfo->name, rrset->type); return (result == ISC_TRUE ? ISC_R_SUCCESS : ISC_R_FAILURE);}static isc_boolean_tssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_ssutable_t *ssutable, dns_name_t *signer){ isc_result_t result; ssu_check_t ssuinfo; ssuinfo.name = name; ssuinfo.table = ssutable; ssuinfo.signer = signer; result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo); return (ISC_TF(result == ISC_R_SUCCESS));}/**************************************************************************//* * Checking of "RRset exists (value dependent)" prerequisites. * * In the RFC2136 section 3.2.5, this is the pseudocode involving * a variable called "temp", a mapping of <name, type> tuples to rrsets. * * Here, we represent the "temp" data structure as (non-minimial) "dns_diff_t" * where each typle has op==DNS_DIFFOP_EXISTS. *//* * Append a tuple asserting the existence of the RR with * 'name' and 'rdata' to 'diff'. */static isc_result_ttemp_append(dns_diff_t *diff, dns_name_t *name, dns_rdata_t *rdata) { isc_result_t result; dns_difftuple_t *tuple = NULL; REQUIRE(DNS_DIFF_VALID(diff)); CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_EXISTS, name, 0, rdata, &tuple)); ISC_LIST_APPEND(diff->tuples, tuple, link); failure: return (result);}/* * Compare two rdatasets represented as sorted lists of tuples. * All list elements must have the same owner name and type. * Return ISC_R_SUCCESS if the rdatasets are equal, rcode(dns_rcode_nxrrset) * if not. */static isc_result_ttemp_check_rrset(dns_difftuple_t *a, dns_difftuple_t *b) { for (;;) { if (a == NULL || b == NULL) break; INSIST(a->op == DNS_DIFFOP_EXISTS && b->op == DNS_DIFFOP_EXISTS); INSIST(a->rdata.type == b->rdata.type); INSIST(dns_name_equal(&a->name, &b->name)); if (dns_rdata_compare(&a->rdata, &b->rdata) != 0) return (DNS_R_NXRRSET); a = ISC_LIST_NEXT(a, link); b = ISC_LIST_NEXT(b, link); } if (a != NULL || b != NULL) return (DNS_R_NXRRSET); return (ISC_R_SUCCESS);}/* * A comparison function defining the sorting order for the entries * in the "temp" data structure. The major sort key is the owner name, * followed by the type and rdata. */static inttemp_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; int r; r = dns_name_compare(&a->name, &b->name); if (r != 0) return (r); r = (b->rdata.type - a->rdata.type); if (r != 0) return (r); r = dns_rdata_compare(&a->rdata, &b->rdata); return (r);}/* * Check the "RRset exists (value dependent)" prerequisite information * in 'temp' against the contents of the database 'db'. * * Return ISC_R_SUCCESS if the prerequisites are satisfied, * rcode(dns_rcode_nxrrset) if not. * * 'temp' must be pre-sorted. */static isc_result_ttemp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *tmpname, dns_rdatatype_t *typep){ isc_result_t result; dns_name_t *name; dns_dbnode_t *node; dns_difftuple_t *t; dns_diff_t trash; dns_diff_init(mctx, &trash); /* * For each name and type in the prerequisites, * construct a sorted rdata list of the corresponding * database contents, and compare the lists. */ t = ISC_LIST_HEAD(temp->tuples); while (t != NULL) { name = &t->name; (void)dns_name_copy(name, tmpname, NULL); *typep = t->rdata.type; /* A new unique name begins here. */ node = NULL; result = dns_db_findnode(db, name, ISC_FALSE, &node); if (result == ISC_R_NOTFOUND) return (DNS_R_NXRRSET); if (result != ISC_R_SUCCESS) return (result); /* A new unique type begins here. */ while (t != NULL && dns_name_equal(&t->name, name)) { dns_rdatatype_t type, covers; dns_rdataset_t rdataset; dns_diff_t d_rrs; /* Database RRs with this name and type */ dns_diff_t u_rrs; /* Update RRs with this name and type */ *typep = type = t->rdata.type; if (type == dns_rdatatype_rrsig || type == dns_rdatatype_sig) covers = dns_rdata_covers(&t->rdata); else covers = 0; /* * Collect all database RRs for this name and type * onto d_rrs and sort them. */ dns_rdataset_init(&rdataset); result = dns_db_findrdataset(db, node, ver, type, covers, (isc_stdtime_t) 0, &rdataset, NULL); if (result != ISC_R_SUCCESS) { dns_db_detachnode(db, &node); return (DNS_R_NXRRSET); } dns_diff_init(mctx, &d_rrs); dns_diff_init(mctx, &u_rrs); for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(&rdataset)) { dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_current(&rdataset, &rdata); result = temp_append(&d_rrs, name, &rdata); if (result != ISC_R_SUCCESS) goto failure; } if (result != ISC_R_NOMORE) goto failure; result = dns_diff_sort(&d_rrs, temp_order); if (result != ISC_R_SUCCESS) goto failure; /* * Collect all update RRs for this name and type * onto u_rrs. No need to sort them here - * they are already sorted. */ while (t != NULL && dns_name_equal(&t->name, name) && t->rdata.type == type) { dns_difftuple_t *next = ISC_LIST_NEXT(t, link); ISC_LIST_UNLINK(temp->tuples, t, link); ISC_LIST_APPEND(u_rrs.tuples, t, link); t = next; } /* Compare the two sorted lists. */ result = temp_check_rrset(ISC_LIST_HEAD(u_rrs.tuples), ISC_LIST_HEAD(d_rrs.tuples)); if (result != ISC_R_SUCCESS) goto failure; /* * We are done with the tuples, but we can't free * them yet because "name" still points into one * of them. Move them on a temporary list. */ ISC_LIST_APPENDLIST(trash.tuples, u_rrs.tuples, link); ISC_LIST_APPENDLIST(trash.tuples, d_rrs.tuples, link); dns_rdataset_disassociate(&rdataset); continue; failure: dns_diff_clear(&d_rrs); dns_diff_clear(&u_rrs); dns_diff_clear(&trash); dns_rdataset_disassociate(&rdataset); dns_db_detachnode(db, &node); return (result); } dns_db_detachnode(db, &node); } dns_diff_clear(&trash); return (ISC_R_SUCCESS);}/**************************************************************************//* * Conditional deletion of RRs. *//* * Context structure for delete_if(). */typedef struct { rr_predicate *predicate; dns_db_t *db; dns_dbversion_t *ver; dns_diff_t *diff;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -