/* * 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 #include #include #include #include #include #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); result = fetch->fetchmethods.start_fetch(fetch); if (result != ISC_R_SUCCESS) { goto cancel; } 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, 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->cache != NULL) { dns_db_detach(&resp->cache); } 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)); dns_rdataset_cleanup(rrset); dns_rdataset_cleanup(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; }