update.c
来自「非常好的dns解析软件」· C语言 代码 · 共 2,383 行 · 第 1/5 页
C
2,383 行
*/ 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 NSECs, and delete/create * NSECs to make it so. We don't know the final NSEC targets yet, * so we just create placeholder NSECs with arbitrary contents * to indicate that their respective owner names should be part of * the NSEC 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 NSEC record. */ CHECK(delete_if(true_p, db, newver, &t->name, dns_rdatatype_nsec, 0, NULL, &nsec_diff)); } else { /* * This name is not obscured. It should have a NSEC. */ CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_nsec, 0, &flag)); if (! flag) CHECK(add_placeholder_nsec(db, newver, &t->name, diff)); } } /* * Now we know which names are part of the NSEC 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_nsec, 0, &flag)); if (flag) { /* * There is a NSEC, 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 RRSIG bit should always be set in the NSECs * we generate, because they will all get RRSIG NSECs. * (XXX what if the zone keys are missing?). * Because the RRSIG NSECs have not necessarily been * created yet, the correctness of the bit mask relies * on the assumption that NSECs are only created if * there is other data, and if there is other data, * there are other RRSIGs. */ CHECK(add_nsec(client, zone, db, newver, &t->name, nsecttl, &nsec_diff)); } } /* * Minimize the set of NSEC updates so that we don't * have to regenerate the RRSIG NSECs for NSECs that were * replaced with identical ones. */ while ((t = ISC_LIST_HEAD(nsec_diff.tuples)) != NULL) { ISC_LIST_UNLINK(nsec_diff.tuples, t, link); dns_diff_appendminimal(&nsec_mindiff, &t); } /* Update RRSIG NSECs. */ for (t = ISC_LIST_HEAD(nsec_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_rrsig, dns_rdatatype_nsec, NULL, &sig_diff)); } else if (t->op == DNS_DIFFOP_ADD) { CHECK(add_sigs(db, newver, &t->name, dns_rdatatype_nsec, &sig_diff, zone_keys, nkeys, client->mctx, inception, expire, check_ksk)); } 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);}/* * This implements the post load integrity checks for mx records. */static isc_result_tcheck_mx(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff){ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")]; char ownerbuf[DNS_NAME_FORMATSIZE]; char namebuf[DNS_NAME_FORMATSIZE]; char altbuf[DNS_NAME_FORMATSIZE]; dns_difftuple_t *t; dns_fixedname_t fixed; dns_name_t *foundname; dns_rdata_mx_t mx; dns_rdata_t rdata; isc_boolean_t ok = ISC_TRUE; isc_boolean_t isaddress; isc_result_t result; struct in6_addr addr6; struct in_addr addr; unsigned int options; dns_fixedname_init(&fixed); foundname = dns_fixedname_name(&fixed); dns_rdata_init(&rdata); options = dns_zone_getoptions(zone); 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_mx) continue; result = dns_rdata_tostruct(&t->rdata, &mx, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); /* * Check if we will error out if we attempt to reload the * zone. */ dns_name_format(&mx.mx, namebuf, sizeof(namebuf)); dns_name_format(&t->name, ownerbuf, sizeof(ownerbuf)); isaddress = ISC_FALSE; if ((options & DNS_RDATA_CHECKMX) != 0 && strlcpy(tmp, namebuf, sizeof(tmp)) < sizeof(tmp)) { if (tmp[strlen(tmp) - 1] == '.') tmp[strlen(tmp) - 1] = '\0'; if (inet_aton(tmp, &addr) == 1 || inet_pton(AF_INET6, tmp, &addr6) == 1) isaddress = ISC_TRUE; } if (isaddress && (options & DNS_RDATA_CHECKMXFAIL) != 0) { update_log(client, zone, ISC_LOG_ERROR, "%s/MX: '%s': %s", ownerbuf, namebuf, dns_result_totext(DNS_R_MXISADDRESS)); ok = ISC_FALSE; } else if (isaddress) { update_log(client, zone, ISC_LOG_WARNING, "%s/MX: warning: '%s': %s", ownerbuf, namebuf, dns_result_totext(DNS_R_MXISADDRESS)); } /* * Check zone integrity checks. */ if ((options & DNS_ZONEOPT_CHECKINTEGRITY) == 0) continue; result = dns_db_find(db, &mx.mx, newver, dns_rdatatype_a, 0, 0, NULL, foundname, NULL, NULL); if (result == ISC_R_SUCCESS) continue; if (result == DNS_R_NXRRSET) { result = dns_db_find(db, &mx.mx, newver, dns_rdatatype_aaaa, 0, 0, NULL, foundname, NULL, NULL); if (result == ISC_R_SUCCESS) continue; } if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN) { update_log(client, zone, ISC_LOG_ERROR, "%s/MX '%s' has no address records " "(A or AAAA)", ownerbuf, namebuf); ok = ISC_FALSE; } else if (result == DNS_R_CNAME) { update_log(client, zone, ISC_LOG_ERROR, "%s/MX '%s' is a CNAME (illegal)", ownerbuf, namebuf); ok = ISC_FALSE; } else if (result == DNS_R_DNAME) { dns_name_format(foundname, altbuf, sizeof altbuf); update_log(client, zone, ISC_LOG_ERROR, "%s/MX '%s' is below a DNAME '%s' (illegal)", ownerbuf, namebuf, altbuf); ok = ISC_FALSE; } } return (ok ? ISC_R_SUCCESS : DNS_R_REFUSED);}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; unsigned int options; 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
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?