* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: query.c,v 1.238 2002/11/27 09:52:45 marka Exp $ */
+/* $Id: query.c,v 1.239 2003/01/14 00:28:49 marka Exp $ */
#include <config.h>
#define DNS_GETDB_NOEXACT 0x01U
#define DNS_GETDB_NOLOG 0x02U
+#define DNS_GETDB_PARTIAL 0x04U
static void
query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype);
unsigned int ztoptions;
dns_zone_t *zone = NULL;
dns_db_t *db = NULL;
+ isc_boolean_t partial = ISC_FALSE;
REQUIRE(zonep != NULL && *zonep == NULL);
REQUIRE(dbp != NULL && *dbp == NULL);
result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL,
&zone);
+ if (result == DNS_R_PARTIALMATCH)
+ partial = ISC_TRUE;
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
result = dns_zone_getdb(zone, &db);
*dbp = db;
*versionp = dbversion->version;
+ if (partial && (options & DNS_GETDB_PARTIAL) != 0)
+ return (DNS_R_PARTIALMATCH);
return (ISC_R_SUCCESS);
refuse:
version = NULL;
zone = NULL;
need_wildcardproof = ISC_FALSE;
+ options = 0;
if (event != NULL) {
/*
options |= DNS_GETDB_NOEXACT;
result = query_getdb(client, client->query.qname, options, &zone, &db,
&version, &is_zone);
+ if ((result != ISC_R_SUCCESS || !is_zone) && !RECURSIONOK(client) &&
+ (options & DNS_GETDB_NOEXACT) != 0 && qtype == dns_rdatatype_ds) {
+ /*
+ * Look to see if we are authoritative for the
+ * child zone if the query type is DS.
+ */
+ dns_db_t *tdb = NULL;
+ dns_zone_t *tzone = NULL;
+ dns_dbversion_t *tversion = NULL;
+ isc_result_t tresult;
+
+ tresult = query_getzonedb(client, client->query.qname,
+ DNS_GETDB_PARTIAL, &tzone, &tdb,
+ &tversion);
+ if (tresult == ISC_R_SUCCESS) {
+ options &= ~DNS_GETDB_NOEXACT;
+ query_putrdataset(client, &rdataset);
+ if (db != NULL)
+ dns_db_detach(&db);
+ if (zone != NULL)
+ dns_zone_detach(&zone);
+ version = tversion;
+ db = tdb;
+ zone = tzone;
+ is_zone = ISC_TRUE;
+ result = ISC_R_SUCCESS;
+ } else {
+ if (tdb != NULL)
+ dns_db_detach(&tdb);
+ if (tzone != NULL)
+ dns_zone_detach(&tzone);
+ }
+ }
if (result != ISC_R_SUCCESS) {
if (result == DNS_R_REFUSED)
QUERY_ERROR(DNS_R_REFUSED);
case DNS_R_DELEGATION:
authoritative = ISC_FALSE;
if (is_zone) {
+ /*
+ * Look to see if we are authoritative for the
+ * child zone if the query type is DS.
+ */
+ if (!RECURSIONOK(client) &&
+ (options & DNS_GETDB_NOEXACT) != 0 &&
+ qtype == dns_rdatatype_ds) {
+ dns_db_t *tdb = NULL;
+ dns_zone_t *tzone = NULL;
+ dns_dbversion_t *tversion = NULL;
+ result = query_getzonedb(client,
+ client->query.qname,
+ DNS_GETDB_PARTIAL,
+ &tzone, &tdb,
+ &tversion);
+ if (result == ISC_R_SUCCESS) {
+ options &= ~DNS_GETDB_NOEXACT;
+ query_putrdataset(client, &rdataset);
+ if (sigrdataset != NULL)
+ query_putrdataset(client,
+ &sigrdataset);
+ if (fname != NULL)
+ query_releasename(client,
+ &fname);
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ if (db != NULL)
+ dns_db_detach(&db);
+ if (zone != NULL)
+ dns_zone_detach(&zone);
+ version = tversion;
+ db = tdb;
+ zone = tzone;
+ authoritative = ISC_TRUE;
+ goto db_find;
+ }
+ if (tdb != NULL)
+ dns_db_detach(&tdb);
+ if (tzone != NULL)
+ dns_zone_detach(&tzone);
+ }
/*
* We're authoritative for an ancestor of QNAME.
*/
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: resolver.c,v 1.256 2003/01/05 23:19:29 marka Exp $ */
+/* $Id: resolver.c,v 1.257 2003/01/14 00:28:49 marka Exp $ */
#include <config.h>
* is used for EDNS0 black hole detection.
*/
unsigned int timeouts;
+ /*
+ * Look aside state for DS lookups.
+ */
+ dns_name_t nsname;
+ dns_fetch_t * nsfetch;
+ dns_rdataset_t nsrrset;
};
#define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!')
dns_validator_cancel(validator);
validator = ISC_LIST_NEXT(validator, link);
}
+
+ if (fctx->nsfetch != NULL)
+ dns_resolver_cancelfetch(fctx->nsfetch);
/*
* Shut down anything that is still running on behalf of this
fctx->timeouts = 0;
fctx->attributes = 0;
+ dns_name_init(&fctx->nsname, NULL);
+ fctx->nsfetch = NULL;
+ dns_rdataset_init(&fctx->nsrrset);
+
if (domain == NULL) {
dns_forwarders_t *forwarders = NULL;
result = dns_fwdtable_find(fctx->res->view->fwdtable,
return (result);
}
+ /*
+ * Trigger lookups for DNS nameservers.
+ */
+ if (negative_response && message->rcode == dns_rcode_noerror &&
+ fctx->type == dns_rdatatype_ds && soa_name != NULL &&
+ dns_name_equal(soa_name, qname) &&
+ !dns_name_equal(qname, dns_rootname))
+ return (DNS_R_CHASEDSSERVERS);
+
/*
* Did we find anything?
*/
return (result);
}
+static void
+resume_dslookup(isc_task_t *task, isc_event_t *event) {
+ dns_fetchevent_t *fevent;
+ dns_resolver_t *res;
+ fetchctx_t *fctx;
+ isc_result_t result;
+ isc_boolean_t bucket_empty = ISC_FALSE;
+ isc_boolean_t locked = ISC_FALSE;
+
+ REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
+ fevent = (dns_fetchevent_t *)event;
+ fctx = event->ev_arg;
+ REQUIRE(VALID_FCTX(fctx));
+ res = fctx->res;
+
+ UNUSED(task);
+ FCTXTRACE("resume_dslookup");
+
+ if (fevent->node != NULL)
+ dns_db_detachnode(fevent->db, &fevent->node);
+ if (fevent->db != NULL)
+ dns_db_detach(&fevent->db);
+
+ dns_resolver_destroyfetch(&fctx->nsfetch);
+
+ if (fevent->result == ISC_R_CANCELED)
+ fctx_done(fctx, ISC_R_CANCELED);
+ else if (fevent->result == ISC_R_SUCCESS) {
+
+ FCTXTRACE("resuming DS lookup");
+
+ if (dns_rdataset_isassociated(&fctx->nameservers))
+ dns_rdataset_disassociate(&fctx->nameservers);
+ dns_rdataset_clone(fevent->rdataset, &fctx->nameservers);
+ dns_name_free(&fctx->domain, fctx->res->mctx);
+ dns_name_init(&fctx->domain, NULL);
+ result = dns_name_dup(&fctx->nsname, fctx->res->mctx,
+ &fctx->domain);
+ if (result != ISC_R_SUCCESS) {
+ fctx_done(fctx, DNS_R_SERVFAIL);
+ goto cleanup;
+ }
+ /*
+ * Try again.
+ */
+ fctx_try(fctx);
+ } else {
+ unsigned int n;
+
+ n = dns_name_countlabels(&fctx->nsname);
+ dns_name_getlabelsequence(&fctx->nsname, 1, n - 1,
+ &fctx->nsname);
+
+ if (dns_name_equal(&fctx->nsname, &fctx->domain)) {
+ fctx_done(fctx, DNS_R_SERVFAIL);
+ goto cleanup;
+ }
+ if (dns_rdataset_isassociated(fevent->rdataset))
+ dns_rdataset_disassociate(fevent->rdataset);
+ FCTXTRACE("continuing to look for parent's NS records");
+ result = dns_resolver_createfetch(fctx->res, &fctx->nsname,
+ dns_rdatatype_ns,
+ &fctx->domain,
+ &fctx->nameservers, NULL,
+ 0, task,
+ resume_dslookup, fctx,
+ &fctx->nsrrset, NULL,
+ &fctx->nsfetch);
+ if (result != ISC_R_SUCCESS)
+ fctx_done(fctx, result);
+ else {
+ LOCK(&res->buckets[fctx->bucketnum].lock);
+ locked = ISC_TRUE;
+ fctx->references++;
+ }
+ }
+
+ cleanup:
+ if (dns_rdataset_isassociated(fevent->rdataset))
+ dns_rdataset_disassociate(fevent->rdataset);
+ INSIST(fevent->sigrdataset == NULL);
+ isc_event_free(&event);
+ if (!locked)
+ LOCK(&res->buckets[fctx->bucketnum].lock);
+ fctx->references--;
+ if (fctx->references == 0)
+ bucket_empty = fctx_destroy(fctx);
+ UNLOCK(&res->buckets[fctx->bucketnum].lock);
+ if (bucket_empty)
+ empty_bucket(res);
+}
+
static void
resquery_response(isc_task_t *task, isc_event_t *event) {
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(VALID_FCTX(fctx));
REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
- UNUSED(task);
QTRACE("response");
(void)isc_timer_touch(fctx->timer);
* NXDOMAIN, NXRDATASET, or referral.
*/
result = noanswer_response(fctx, NULL, ISC_FALSE);
- if (result == DNS_R_DELEGATION) {
+ if (result == DNS_R_CHASEDSSERVERS) {
+ } else if (result == DNS_R_DELEGATION) {
force_referral:
/*
* We don't have the answer, but we know a better
result = fctx_stopidletimer(fctx);
if (result != ISC_R_SUCCESS)
fctx_done(fctx, result);
+ } else if (result == DNS_R_CHASEDSSERVERS) {
+ unsigned int n;
+ add_bad(fctx, &addrinfo->sockaddr, result);
+ fctx_cancelqueries(fctx, ISC_TRUE);
+ fctx_cleanupfinds(fctx);
+ fctx_cleanupforwaddrs(fctx);
+
+ n = dns_name_countlabels(&fctx->name);
+ dns_name_getlabelsequence(&fctx->name, 1, n - 1, &fctx->nsname);
+
+ FCTXTRACE("suspending DS lookup to find parent's NS records");
+
+ result = dns_resolver_createfetch(fctx->res, &fctx->nsname,
+ dns_rdatatype_ns,
+ &fctx->domain,
+ &fctx->nameservers, NULL,
+ 0, task,
+ resume_dslookup, fctx,
+ &fctx->nsrrset, NULL,
+ &fctx->nsfetch);
+ if (result != ISC_R_SUCCESS)
+ fctx_done(fctx, result);
+ LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ fctx->references++;
+ UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ result = fctx_stopidletimer(fctx);
+ if (result != ISC_R_SUCCESS)
+ fctx_done(fctx, result);
} else {
/*
* We're done.