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 + -
显示快捷键?