📄 update.c
字号:
client->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(nsec_mindiff.tuples)) != NULL) { ISC_LIST_UNLINK(nsec_mindiff.tuples, t, link); dns_diff_appendminimal(diff, &t); } INSIST(ISC_LIST_EMPTY(sig_diff.tuples)); INSIST(ISC_LIST_EMPTY(nsec_diff.tuples)); INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples)); failure: dns_diff_clear(&sig_diff); dns_diff_clear(&nsec_diff); dns_diff_clear(&nsec_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); INSIST(client->nupdates == 0); client->nupdates++; event->ev_arg = evclient; dns_zone_gettask(zone, &zonetask); isc_task_send(zonetask, ISC_EVENT_PTR(&event)); failure: if (event != NULL) isc_event_free(ISC_EVENT_PTR(&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, "update zone section empty"); /* * The zone section must contain exactly one "question", and * it must be of type SOA. */ zonename = NULL; dns_message_currentname(request, DNS_SECTION_ZONE, &zonename); zone_rdataset = ISC_LIST_HEAD(zonename->list); if (zone_rdataset->type != dns_rdatatype_soa) FAILC(DNS_R_FORMERR, "update zone section contains non-SOA"); if (ISC_LIST_NEXT(zone_rdataset, link) != NULL) FAILC(DNS_R_FORMERR, "update zone section contains multiple RRs"); /* The zone section must have exactly one name. */ result = dns_message_nextname(request, DNS_SECTION_ZONE); if (result != ISC_R_NOMORE) FAILC(DNS_R_FORMERR, "update zone section contains multiple RRs"); result = dns_zt_find(client->view->zonetable, zonename, 0, NULL, &zone); if (result != ISC_R_SUCCESS) FAILC(DNS_R_NOTAUTH, "not authoritative for update zone"); switch(dns_zone_gettype(zone)) { case dns_zone_master: /* * We can now fail due to a bad signature as we now know * that we are the master. */ if (sigresult != ISC_R_SUCCESS) FAIL(sigresult); CHECK(send_update_event(client, zone)); break; case dns_zone_slave: CHECK(checkupdateacl(client, dns_zone_getforwardacl(zone), "update forwarding", zonename, ISC_TRUE)); CHECK(send_forward_event(client, zone)); break; default: FAILC(DNS_R_NOTAUTH, "not authoritative for update zone"); } return; failure: /* * We failed without having sent an update event to the zone. * We are still in the client task context, so we can * simply give an error response without switching tasks. */ respond(client, result); if (zone != NULL) dns_zone_detach(&zone);}/* * DS records are not allowed to exist without corresponding NS records, * draft-ietf-dnsext-delegation-signer-11.txt, 2.2 Protocol Change, * "DS RRsets MUST NOT appear at non-delegation points or at a zone's apex". */static isc_result_tremove_orphaned_ds(dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) { isc_result_t result; isc_boolean_t ns_exists, ds_exists; dns_difftuple_t *t; for (t = ISC_LIST_HEAD(diff->tuples); t != NULL; t = ISC_LIST_NEXT(t, link)) { if (t->op != DNS_DIFFOP_DEL || t->rdata.type != dns_rdatatype_ns) continue; CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ns, 0, &ns_exists)); if (ns_exists) continue; CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ds, 0, &ds_exists)); if (!ds_exists) continue; CHECK(delete_if(true_p, db, newver, &t->name, dns_rdatatype_ds, 0, NULL, diff)); } return (ISC_R_SUCCESS); failure: return (result);}static voidupdate_action(isc_task_t *task, isc_event_t *event) { update_event_t *uev = (update_event_t *) event; dns_zone_t *zone = uev->zone; ns_client_t *client = (ns_client_t *)event->ev_arg; isc_result_t result; dns_db_t *db = NULL; dns_dbversion_t *oldver = NULL; dns_dbversion_t *ver = NULL; dns_diff_t diff; /* Pending updates. */ dns_diff_t temp; /* Pending RR existence assertions. */ isc_boolean_t soa_serial_changed = ISC_FALSE; isc_mem_t *mctx = client->mctx; dns_rdatatype_t covers; dns_message_t *request = client->message; dns_rdataclass_t zoneclass; dns_name_t *zonename; dns_ssutable_t *ssutable = NULL; dns_fixedname_t tmpnamefixed; dns_name_t *tmpname = NULL; INSIST(event->ev_type == DNS_EVENT_UPDATE); dns_diff_init(mctx, &diff); dns_diff_init(mctx, &temp); CHECK(dns_zone_getdb(zone, &db)); zonename = dns_db_origin(db); zoneclass = dns_db_class(db); dns_zone_getssutable(zone, &ssutable); dns_db_currentversion(db, &oldver); CHECK(dns_db_newversion(db, &ver)); /* * Check prerequisites. */ for (result = dns_message_firstname(request, DNS_SECTION_PREREQUISITE); result == ISC_R_SUCCESS; result = dns_message_nextname(request, DNS_SECTION_PREREQUISITE)) { dns_name_t *name = NULL; dns_rdata_t rdata = DNS_RDATA_INIT; dns_ttl_t ttl; dns_rdataclass_t update_class; isc_boolean_t flag; get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass, &name, &rdata, &covers, &ttl, &update_class); if (ttl != 0) FAILC(DNS_R_FORMERR, "prerequisite TTL is not zero"); if (! dns_name_issubdomain(name, zonename)) FAILN(DNS_R_NOTZONE, name, "prerequisite name is out of zone"); if (update_class == dns_rdataclass_any) { if (rdata.length != 0) FAILC(DNS_R_FORMERR, "class ANY prerequisite " "RDATA is not empty"); if (rdata.type == dns_rdatatype_any) { CHECK(name_exists(db, ver, name, &flag)); if (! flag) { FAILN(DNS_R_NXDOMAIN, name, "'name in use' prerequisite " "not satisfied"); } } else { CHECK(rrset_exists(db, ver, name, rdata.type, covers, &flag)); if (! flag) { /* RRset does not exist. */ FAILNT(DNS_R_NXRRSET, name, rdata.type, "'rrset exists (value independent)' " "prerequisite not satisfied"); } } } else if (update_class == dns_rdataclass_none) { if (rdata.length != 0) FAILC(DNS_R_FORMERR, "class NONE prerequisite " "RDATA is not empty"); if (rdata.type == dns_rdatatype_any) { CHECK(name_exists(db, ver, name, &flag)); if (flag) { FAILN(DNS_R_YXDOMAIN, name, "'name not in use' prerequisite " "not satisfied"); } } else { CHECK(rrset_exists(db, ver, name, rdata.type, covers, &flag)); if (flag) { /* RRset exists. */ FAILNT(DNS_R_YXRRSET, name, rdata.type, "'rrset does not exist' " "prerequisite not satisfied"); } } } else if (update_class == zoneclass) { /* "temp<rr.name, rr.type> += rr;" */ result = temp_append(&temp, name, &rdata); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "temp entry creation failed: %s", dns_result_totext(result)); FAIL(ISC_R_UNEXPECTED); } } else { FAILC(DNS_R_FORMERR, "malformed prerequisite"); } } if (result != ISC_R_NOMORE) FAIL(result); /* * Perform the final check of the "rrset exists (value dependent)" * prerequisites. */ if (ISC_LIST_HEAD(temp.tuples) != NULL) { dns_rdatatype_t type; /* * Sort the prerequisite records by owner name, * type, and rdata. */ result = dns_diff_sort(&temp, temp_order); if (result != ISC_R_SUCCESS) FAILC(result, "'RRset exists (value dependent)' " "prerequisite not satisfied"); dns_fixedname_init(&tmpnamefixed); tmpname = dns_fixedname_name(&tmpnamefixed); result = temp_check(mctx, &temp, db, ver, tmpname, &type); if (result != ISC_R_SUCCESS) FAILNT(result, tmpname, type, "'RRset exists (value dependent)' " "prerequisite not satisfied"); } update_log(client, zone, LOGLEVEL_DEBUG, "prerequisites are OK"); /* * Check Requestor's Permissions. It seems a bit silly to do this * only after prerequisite testing, but that is what RFC2136 says. */ result = ISC_R_SUCCESS; if (ssutable == NULL) CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone), "update", zonename, ISC_FALSE)); else if (client->signer == NULL) CHECK(checkupdateacl(client, NULL, "update", zonename, ISC_FALSE)); if (dns_zone_getupdatedisabled(zone)) FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled"); /* * Perform the Update Section Prescan. */ for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); result == ISC_R_SUCCESS; result = dns_message_nextname(request, DNS_SECTION_UPDATE)) { dns_name_t *name = NULL; dns_rdata_t rdata = DNS_RDATA_INIT; dns_ttl_t ttl; dns_rdataclass_t update_class; get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, &name, &rdata, &covers, &ttl, &update_class); if (! dns_name_issubdomain(name, zonename)) FAILC(DNS_R_NOTZONE, "update RR is outside zone"); if (update_class == zoneclass) { /* * Check for meta-RRs. The RFC2136 pseudocode says * check for ANY|AXFR|MAILA|MAILB, but the text adds * "or any other QUERY metatype" */ if (dns_rdatatype_ismeta(rdata.type)) { FAILC(DNS_R_FORMERR, "meta-RR in update"); } result = dns_zone_checknames(zone, name, &rdata); if (result != ISC_R_SUCCESS) FAIL(DNS_R_REFUSED); } else if (update_class == dns_rdataclass_any) { if (ttl != 0 || rdata.length != 0 || (dns_rdatatype_ismeta(rdata.type) && rdata.type != dns_rdatatype_any)) FAILC(DNS_R_FORMERR, "meta-RR in update"); } else if (update_class == dns_rdataclass_none) { if (ttl != 0 || dns_rdatatype_ismeta(rdata.type)) FAILC(DNS_R_FORMERR, "meta-RR in update"); } else { update_log(client, zone, ISC_LOG_WARNING, "update RR has incorrect class %d", update_class); FAIL(DNS_R_FORMERR); } /* * draft-ietf-dnsind-simple-secure-update-01 says * "Unlike traditional dynamic update, the client * is forbidden from updating NSEC records." */ if (dns_db_issecure(db)) { if (rdata.type == dns_rdatatype_nsec) { FAILC(DNS_R_REFUSED, "explicit NSEC updates are not allowed " "in secure zones"); } else if (rdata.type == dns_rdatatype_rrsig) { FAILC(DNS_R_REFUSED, "explicit RRSIG updates are currently not " "supported in secure zones"); } } if (ssutable != NULL && client->signer != NULL) { if (rdata.type != dns_rdatatype_any) { if (!dns_ssutable_checkrules(ssutable, client->signer, name, rdata.type)) FAILC(DNS_R_REFUSED, "rejected by secure update"); } else { if (!ssu_checkall(db, ver, name, ssutable, client->signer)) FAILC(DNS_R_REFUSED, "rejected by secure update"); } } } if (result != ISC_R_NOMORE) FAIL(result); update_log(client, zone, LOGLEVEL_DEBUG, "update section prescan OK"); /* * Process the Update Section. */ for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); result == ISC_R_SUCCESS; result = dns_message_nextname(request, DNS_SECTION_UPDATE)) { dns_name_t *name = NULL; dns_rdata_t rdata = DNS_RDATA_INIT; dns_ttl_t ttl; dns_rdataclass_t update_class; isc_boolean_t flag; get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, &name, &rdata, &covers, &ttl, &update_class); if (update_class == zoneclass) { /* * RFC 1123 doesn't allow MF and MD in master zones. */ if (rdata.type == dns_rdatatype_md || rdata.type == dns_rdatatype_mf) { char typebuf[DNS_RDATATYPE_FORMATSIZE]; dns_rdatatype_format(rdata.type, t
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -