mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-25 02:47:54 -04:00
Scheduling and rescheduling a zonefetch is also similar. Refactor into zonefetch functions. This also increments and decrements the zone's internal reference counter in the same module, which may be less confusing when reading the code.
272 lines
6.8 KiB
C
272 lines
6.8 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*/
|
|
|
|
/*! \file */
|
|
|
|
#include <isc/async.h>
|
|
#include <isc/loop.h>
|
|
|
|
#include <dns/resolver.h>
|
|
#include <dns/view.h>
|
|
#include <dns/zone.h>
|
|
#include <dns/zonefetch.h>
|
|
|
|
#include "zone_p.h"
|
|
|
|
void
|
|
dns_zonefetch_run(void *arg) {
|
|
dns_zonefetch_t *fetch = (dns_zonefetch_t *)arg;
|
|
dns_zone_t *zone;
|
|
dns_view_t *view;
|
|
isc_loop_t *loop;
|
|
isc_result_t result;
|
|
dns_resolver_t *resolver = NULL;
|
|
|
|
zone = fetch->zone;
|
|
if (dns__zone_exiting(zone)) {
|
|
result = ISC_R_SHUTTINGDOWN;
|
|
goto cancel;
|
|
}
|
|
view = dns_zone_getview(zone);
|
|
loop = dns_zone_getloop(zone);
|
|
|
|
INSIST(view != NULL);
|
|
INSIST(loop != NULL);
|
|
|
|
fetch->fetchmethods.start_fetch(fetch);
|
|
|
|
result = dns_view_getresolver(view, &resolver);
|
|
if (result != ISC_R_SUCCESS) {
|
|
goto cancel;
|
|
}
|
|
|
|
if (isc_log_wouldlog(ISC_LOG_DEBUG(3))) {
|
|
char namebuf[DNS_NAME_FORMATSIZE];
|
|
char typebuf[DNS_RDATATYPE_FORMATSIZE];
|
|
dns_name_format(fetch->qname, namebuf, sizeof(namebuf));
|
|
dns_rdatatype_format(fetch->qtype, typebuf, sizeof(typebuf));
|
|
dns_zone_logc(zone, DNS_LOGCATEGORY_DNSSEC, ISC_LOG_DEBUG(3),
|
|
"Do fetch for %s/%s request", namebuf, typebuf);
|
|
}
|
|
|
|
/*
|
|
* Use of DNS_FETCHOPT_NOCACHED is essential here. If it is not
|
|
* set and the cache still holds a non-expired, validated version
|
|
* of the RRset being queried for by the time the response is
|
|
* received, the cached RRset will be passed to dns_zonefetch_done()
|
|
* instead of the one received in the response as the latter will
|
|
* have a lower trust level due to not being validated until
|
|
* dns_zonefetch_done() is called.
|
|
*/
|
|
INSIST((fetch->options & DNS_FETCHOPT_NOCACHED) != 0);
|
|
|
|
result = dns_resolver_createfetch(
|
|
resolver, fetch->qname, fetch->qtype, NULL, NULL, NULL, NULL, 0,
|
|
fetch->options, 0, NULL, NULL, loop, dns_zonefetch_done, fetch,
|
|
NULL, &fetch->rrset, &fetch->sigset, &fetch->fetch);
|
|
|
|
dns_resolver_detach(&resolver);
|
|
|
|
cancel:
|
|
if (result == ISC_R_SUCCESS) {
|
|
return;
|
|
} else if (result != ISC_R_SHUTTINGDOWN) {
|
|
char namebuf[DNS_NAME_FORMATSIZE];
|
|
char typebuf[DNS_RDATATYPE_FORMATSIZE];
|
|
dns_name_format(fetch->qname, namebuf, sizeof(namebuf));
|
|
dns_rdatatype_format(fetch->qtype, typebuf, sizeof(typebuf));
|
|
dns_zone_log(zone, ISC_LOG_WARNING,
|
|
"Failed fetch for %s/%s request", namebuf,
|
|
typebuf);
|
|
}
|
|
|
|
/*
|
|
* Fetch failed, cancel.
|
|
*/
|
|
dns__zone_lock(zone);
|
|
|
|
dns_name_t *zname = dns_fixedname_name(&fetch->name);
|
|
isc_mem_t *mctx = dns_zone_getmctx(zone);
|
|
bool free_needed;
|
|
|
|
isc_refcount_decrement(dns__zone_irefs(zone));
|
|
dns_name_free(zname, mctx);
|
|
|
|
fetch->fetchmethods.cancel_fetch(fetch);
|
|
|
|
isc_mem_putanddetach(&fetch->mctx, fetch, sizeof(*fetch));
|
|
free_needed = dns__zone_free_check(zone);
|
|
|
|
dns__zone_unlock(zone);
|
|
|
|
if (free_needed) {
|
|
dns__zone_free(zone);
|
|
}
|
|
}
|
|
|
|
void
|
|
dns_zonefetch_done(void *arg) {
|
|
dns_fetchresponse_t *resp = (dns_fetchresponse_t *)arg;
|
|
isc_result_t result = ISC_R_NOMORE;
|
|
isc_result_t eresult;
|
|
dns_zonefetch_t *fetch = NULL;
|
|
dns_zone_t *zone = NULL;
|
|
dns_view_t *view = NULL;
|
|
isc_mem_t *mctx = NULL;
|
|
dns_name_t *zname = NULL;
|
|
dns_rdataset_t *rrset = NULL;
|
|
dns_rdataset_t *sigset = NULL;
|
|
|
|
INSIST(resp != NULL);
|
|
|
|
fetch = resp->arg;
|
|
|
|
INSIST(fetch != NULL);
|
|
|
|
mctx = fetch->mctx;
|
|
zone = fetch->zone;
|
|
zname = dns_fixedname_name(&fetch->name);
|
|
rrset = &fetch->rrset;
|
|
sigset = &fetch->sigset;
|
|
view = dns_zone_getview(zone);
|
|
eresult = resp->result;
|
|
|
|
/* Free resources which are not of interest */
|
|
if (resp->node != NULL) {
|
|
dns_db_detachnode(&resp->node);
|
|
}
|
|
if (resp->db != NULL) {
|
|
dns_db_detach(&resp->db);
|
|
}
|
|
dns_resolver_destroyfetch(&fetch->fetch);
|
|
|
|
dns__zone_lock(zone);
|
|
if (dns__zone_exiting(zone) || view == NULL) {
|
|
goto cleanup;
|
|
}
|
|
|
|
result = fetch->fetchmethods.done_fetch(fetch, eresult);
|
|
|
|
cleanup:
|
|
isc_refcount_decrement(dns__zone_irefs(zone));
|
|
|
|
if (dns_rdataset_isassociated(rrset)) {
|
|
dns_rdataset_disassociate(rrset);
|
|
}
|
|
if (dns_rdataset_isassociated(sigset)) {
|
|
dns_rdataset_disassociate(sigset);
|
|
}
|
|
|
|
fetch->fetchmethods.cleanup_fetch(fetch);
|
|
|
|
dns_resolver_freefresp(&resp);
|
|
|
|
if (result == DNS_R_CONTINUE) {
|
|
dns__zone_unlock(zone);
|
|
fetch->fetchmethods.continue_fetch(fetch);
|
|
} else {
|
|
bool free_needed = false;
|
|
dns_name_free(zname, mctx);
|
|
isc_mem_putanddetach(&fetch->mctx, fetch,
|
|
sizeof(dns_zonefetch_t));
|
|
free_needed = dns__zone_free_check(zone);
|
|
|
|
dns__zone_unlock(zone);
|
|
|
|
if (free_needed) {
|
|
dns__zone_free(zone);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
zonefetch_schedule(dns_zonefetch_t *fetch, dns_name_t *name) {
|
|
dns_zone_t *zone = fetch->zone;
|
|
|
|
isc_refcount_increment0(dns__zone_irefs(zone));
|
|
|
|
if (name != NULL) {
|
|
dns_name_t *fname = dns_fixedname_initname(&fetch->name);
|
|
dns_name_dup(name, fetch->mctx, fname);
|
|
}
|
|
|
|
dns_rdataset_init(&fetch->rrset);
|
|
dns_rdataset_init(&fetch->sigset);
|
|
|
|
isc_async_run(dns_zone_getloop(zone), dns_zonefetch_run, fetch);
|
|
}
|
|
|
|
void
|
|
dns_zonefetch_schedule(dns_zonefetch_t *fetch, dns_name_t *name) {
|
|
REQUIRE(fetch != NULL);
|
|
REQUIRE(name != NULL);
|
|
|
|
zonefetch_schedule(fetch, name);
|
|
}
|
|
|
|
void
|
|
dns_zonefetch_reschedule(dns_zonefetch_t *fetch) {
|
|
REQUIRE(fetch != NULL);
|
|
|
|
zonefetch_schedule(fetch, NULL);
|
|
}
|
|
|
|
isc_result_t
|
|
dns_zonefetch_verify(dns_zonefetch_t *fetch, isc_result_t eresult,
|
|
dns_trust_t trust) {
|
|
char namebuf[DNS_NAME_FORMATSIZE];
|
|
char typebuf[DNS_RDATATYPE_FORMATSIZE];
|
|
dns_rdataset_t *rrset = NULL;
|
|
dns_rdataset_t *sigset = NULL;
|
|
|
|
REQUIRE(fetch != NULL);
|
|
|
|
rrset = &fetch->rrset;
|
|
sigset = &fetch->sigset;
|
|
dns_name_format(fetch->qname, namebuf, sizeof(namebuf));
|
|
dns_rdatatype_format(fetch->qtype, typebuf, sizeof(typebuf));
|
|
|
|
if (eresult != ISC_R_SUCCESS) {
|
|
dns_zone_logc(fetch->zone, DNS_LOGCATEGORY_DNSSEC,
|
|
ISC_LOG_WARNING, "Unable to fetch %s/%s: %s",
|
|
namebuf, typebuf, isc_result_totext(eresult));
|
|
return eresult;
|
|
}
|
|
|
|
/* No records found */
|
|
if (!dns_rdataset_isassociated(rrset)) {
|
|
dns_zone_logc(fetch->zone, DNS_LOGCATEGORY_DNSSEC,
|
|
ISC_LOG_WARNING, "No %s records found for '%s'",
|
|
typebuf, namebuf);
|
|
return ISC_R_NOTFOUND;
|
|
}
|
|
|
|
/* No RRSIGs found */
|
|
if (!dns_rdataset_isassociated(sigset)) {
|
|
dns_zone_logc(fetch->zone, DNS_LOGCATEGORY_DNSSEC,
|
|
ISC_LOG_WARNING, "No %s RRSIGs found for '%s'",
|
|
typebuf, namebuf);
|
|
return DNS_R_NOVALIDSIG;
|
|
}
|
|
|
|
/* Check trust level */
|
|
if (rrset->trust < trust) {
|
|
dns_zone_logc(fetch->zone, DNS_LOGCATEGORY_DNSSEC,
|
|
ISC_LOG_WARNING,
|
|
"Invalid %s RRset for '%s' trust level %u",
|
|
typebuf, namebuf, rrset->trust);
|
|
return DNS_R_NOVALIDSIG;
|
|
}
|
|
|
|
return ISC_R_SUCCESS;
|
|
}
|