2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-01 06:55:30 +00:00

This is "the glue fix". It changes the additional data lookup

algorithm to more closely follow RFC1035, so that root servers will
provide a more complete set of name server glue addresses in ccTLD
referral responses.

For non-referral responses, the server no longer uses glue as
additional data.

For referral responses, the servers now looks for glue A/AAAA/A6 RRs
in the zone where the NS RRs reside, even in the case where this is
different from the zone where the A/AAAA/A6 RRs would have resided had
they been authoritative data.

A6 chains included as additional info may not yet fully follow these
rules.
This commit is contained in:
Andreas Gustafsson
2000-07-05 23:10:06 +00:00
parent 66465da5d1
commit 4defd73fca

View File

@@ -15,7 +15,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
/* $Id: query.c,v 1.111 2000/07/04 01:33:47 gson Exp $ */ /* $Id: query.c,v 1.112 2000/07/05 23:10:06 gson Exp $ */
#include <config.h> #include <config.h>
@@ -339,6 +339,7 @@ query_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) {
CTRACE("query_putrdataset: done"); CTRACE("query_putrdataset: done");
} }
static inline isc_result_t static inline isc_result_t
query_newdbversion(ns_client_t *client, unsigned int n) { query_newdbversion(ns_client_t *client, unsigned int n) {
unsigned int i; unsigned int i;
@@ -440,9 +441,8 @@ query_findversion(ns_client_t *client, dns_db_t *db,
} }
static inline isc_result_t static inline isc_result_t
query_getdb(ns_client_t *client, dns_name_t *name, unsigned int options, query_getzonedb(ns_client_t *client, dns_name_t *name, unsigned int options,
dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp, dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp)
isc_boolean_t *is_zonep)
{ {
isc_result_t result; isc_result_t result;
isc_boolean_t check_acl, new_zone; isc_boolean_t check_acl, new_zone;
@@ -451,54 +451,45 @@ query_getdb(ns_client_t *client, dns_name_t *name, unsigned int options,
unsigned int ztoptions; unsigned int ztoptions;
/* /*
* Find a database to answer the query. * Find a zone database to answer the query.
*/ */
ztoptions = ((options & DNS_GETDB_NOEXACT) != 0) ? ztoptions = ((options & DNS_GETDB_NOEXACT) != 0) ?
DNS_ZTFIND_NOEXACT : 0; DNS_ZTFIND_NOEXACT : 0;
result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL, result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL,
zonep); zonep);
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
result = dns_zone_getdb(*zonep, dbp); result = dns_zone_getdb(*zonep, dbp);
*is_zonep = ISC_TRUE;
}
if (result == ISC_R_NOTFOUND) { if (result != ISC_R_SUCCESS)
if (!USECACHE(client))
return (DNS_R_REFUSED);
dns_db_attach(client->view->cachedb, dbp);
*is_zonep = ISC_FALSE;
} else if (result != ISC_R_SUCCESS)
return (result); return (result);
/* /*
* If we have a zone, and it has an ACL, we'll check it, otherwise * If the zone has an ACL, we'll check it, otherwise
* we use the view's "allow-query" ACL. Each ACL is only checked * we use the view's "allow-query" ACL. Each ACL is only checked
* once per query. * once per query.
* *
* Also, if we have a zone, we will get the version to use. * Also, get the database version to use.
*/ */
check_acl = ISC_TRUE; /* Keep compiler happy. */ check_acl = ISC_TRUE; /* Keep compiler happy. */
queryacl = NULL; queryacl = NULL;
dbversion = NULL;
if (*is_zonep) { /*
/* * Get the current version of this database.
* Get the current version of this database. */
*/ dbversion = query_findversion(client, *dbp, &new_zone);
dbversion = query_findversion(client, *dbp, &new_zone); if (dbversion == NULL)
if (dbversion == NULL) return (DNS_R_SERVFAIL);
return (DNS_R_SERVFAIL); *versionp = dbversion->version;
*versionp = dbversion->version; if (new_zone) {
if (new_zone) { queryacl = dns_zone_getqueryacl(*zonep);
queryacl = dns_zone_getqueryacl(*zonep); check_acl = ISC_TRUE;
check_acl = ISC_TRUE; } else if (!dbversion->queryok) {
} else if (!dbversion->queryok) return (DNS_R_REFUSED);
return (DNS_R_REFUSED); } else {
else check_acl = ISC_FALSE;
check_acl = ISC_FALSE; }
} else
*versionp = NULL;
if (queryacl == NULL) { if (queryacl == NULL) {
queryacl = client->view->queryacl; queryacl = client->view->queryacl;
@@ -549,12 +540,93 @@ query_getdb(ns_client_t *client, dns_name_t *name, unsigned int options,
* Remember the result of the ACL check so we * Remember the result of the ACL check so we
* don't have to check again. * don't have to check again.
*/ */
if (dbversion != NULL && result == ISC_R_SUCCESS) if (result == ISC_R_SUCCESS)
dbversion->queryok = ISC_TRUE; dbversion->queryok = ISC_TRUE;
return (result); return (result);
} }
static inline isc_result_t
query_getcachedb(ns_client_t *client, dns_db_t **dbp, unsigned int options)
{
isc_result_t result;
isc_boolean_t check_acl;
/*
* Find a cache database to answer the query.
* This may fail with ISC_R_REFUSED if the client
* is not allowed to use the cache.
*/
if (!USECACHE(client))
return (DNS_R_REFUSED);
dns_db_attach(client->view->cachedb, dbp);
if ((client->query.attributes &
NS_QUERYATTR_QUERYOKVALID) != 0) {
/*
* We've evaluated the view's queryacl already. If
* NS_QUERYATTR_QUERYOK is set, then the client is
* allowed to make queries, otherwise the query should
* be refused.
*/
check_acl = ISC_FALSE;
if ((client->query.attributes &
NS_QUERYATTR_QUERYOK) == 0)
return (DNS_R_REFUSED);
} else {
/*
* We haven't evaluated the view's queryacl yet.
*/
check_acl = ISC_TRUE;
}
if (check_acl) {
isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0);
result = ns_client_checkacl(client, "query", client->view->queryacl,
ISC_TRUE, log);
if (result == ISC_R_SUCCESS) {
/*
* We were allowed by the default
* "allow-query" ACL. Remember this so we
* don't have to check again.
*/
client->query.attributes |=
NS_QUERYATTR_QUERYOK;
}
/*
* We've now evaluated the view's query ACL, and
* the NS_QUERYATTR_QUERYOK attribute is now valid.
*/
client->query.attributes |= NS_QUERYATTR_QUERYOKVALID;
} else
result = ISC_R_SUCCESS;
return (result);
}
static inline isc_result_t
query_getdb(ns_client_t *client, dns_name_t *name, unsigned int options,
dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp,
isc_boolean_t *is_zonep)
{
isc_result_t result;
result = query_getzonedb(client, name, options, zonep, dbp, versionp);
if (result == ISC_R_SUCCESS) {
*is_zonep = ISC_TRUE;
} else if (result == ISC_R_NOTFOUND) {
result = query_getcachedb(client, dbp, options);
*is_zonep = ISC_FALSE;
}
return (result);
}
static isc_result_t static isc_result_t
query_simplefind(void *arg, dns_name_t *name, dns_rdatatype_t type, query_simplefind(void *arg, dns_name_t *name, dns_rdatatype_t type,
isc_stdtime_t now, isc_stdtime_t now,
@@ -727,16 +799,14 @@ static isc_result_t
query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
ns_client_t *client = arg; ns_client_t *client = arg;
isc_result_t result, eresult; isc_result_t result, eresult;
dns_dbnode_t *node, *znode; dns_dbnode_t *node;
dns_db_t *db, *zdb; dns_db_t *db;
dns_name_t *fname, *zfname, *mname; dns_name_t *fname, *mname;
dns_rdataset_t *rdataset, *sigrdataset, *a6rdataset, *trdataset; dns_rdataset_t *rdataset, *sigrdataset, *a6rdataset, *trdataset;
dns_rdataset_t *zrdataset, *zsigrdataset;
isc_buffer_t *dbuf; isc_buffer_t *dbuf;
isc_buffer_t b; isc_buffer_t b;
dns_dbversion_t *version, *zversion; dns_dbversion_t *version;
unsigned int dboptions; isc_boolean_t added_something, need_addname;
isc_boolean_t is_zone, added_something, need_addname;
dns_zone_t *zone; dns_zone_t *zone;
dns_rdatatype_t type; dns_rdatatype_t type;
@@ -750,46 +820,30 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
*/ */
eresult = ISC_R_SUCCESS; eresult = ISC_R_SUCCESS;
fname = NULL; fname = NULL;
zfname = NULL;
rdataset = NULL; rdataset = NULL;
zrdataset = NULL;
sigrdataset = NULL; sigrdataset = NULL;
zsigrdataset = NULL;
a6rdataset = NULL; a6rdataset = NULL;
trdataset = NULL; trdataset = NULL;
db = NULL; db = NULL;
zdb = NULL;
version = NULL; version = NULL;
zversion = NULL;
node = NULL; node = NULL;
znode = NULL;
added_something = ISC_FALSE; added_something = ISC_FALSE;
need_addname = ISC_FALSE; need_addname = ISC_FALSE;
zone = NULL; zone = NULL;
is_zone = ISC_FALSE;
/*
* We treat type A additional section processing as if it
* were "any address type" additional section processing.
* To avoid multiple lookups, we do an 'any' database
* lookup and iterate over the node.
*/
if (qtype == dns_rdatatype_a) if (qtype == dns_rdatatype_a)
type = dns_rdatatype_any; type = dns_rdatatype_any;
else else
type = qtype; type = qtype;
/* /*
* Find a database to answer the query. * Get some resources.
*/
result = query_getdb(client, name, DNS_GETDB_NOLOG,
&zone, &db, &version, &is_zone);
if (result != ISC_R_SUCCESS) {
/*
* We don't want an ACL failure to fail the query.
*/
if (result == DNS_R_REFUSED)
result = ISC_R_SUCCESS;
goto cleanup;
}
db_find:
CTRACE("query_addadditional: db_find");
/*
* Get some resources...
*/ */
dbuf = query_getnamebuf(client); dbuf = query_getnamebuf(client);
if (dbuf == NULL) if (dbuf == NULL)
@@ -801,91 +855,103 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
goto cleanup; goto cleanup;
/* /*
* Now look for an answer in the database. * Look for a zone database that might contain authoritative
* additional data.
*/
result = query_getzonedb(client, name, DNS_GETDB_NOLOG,
&zone, &db, &version);
if (result != ISC_R_SUCCESS)
goto try_cache;
CTRACE("query_addadditional: db_find");
/*
* Since we are looking for authoritative data, we do not set
* the GLUEOK flag. Glue will be looked for later, but not
* necessarily in the same database.
*/ */
node = NULL; node = NULL;
dboptions = client->query.dboptions; result = dns_db_find(db, name, version, type, client->query.dboptions,
if (db == client->query.gluedb || (!is_zone && CACHEGLUEOK(client)))
dboptions |= DNS_DBFIND_GLUEOK;
result = dns_db_find(db, name, version, type, dboptions,
client->now, &node, fname, rdataset, client->now, &node, fname, rdataset,
sigrdataset); sigrdataset);
if (result == ISC_R_SUCCESS)
goto found;
if (result == DNS_R_DELEGATION || result == ISC_R_NOTFOUND) { if (dns_rdataset_isassociated(rdataset))
if (is_zone) { dns_rdataset_disassociate(rdataset);
if (USECACHE(client)) { if (dns_rdataset_isassociated(sigrdataset))
/* dns_rdataset_disassociate(sigrdataset);
* Either the answer is in the cache, or we if (node != NULL)
* don't know it. Go look in the cache. dns_db_detachnode(db, &node);
*/ version = NULL;
query_releasename(client, &fname); dns_db_detach(&db);
is_zone = ISC_FALSE;
version = NULL; /*
query_putrdataset(client, &rdataset); * No authoritative data was found. The cache is our next best bet.
query_putrdataset(client, &sigrdataset); */
dns_db_detachnode(db, &node);
dns_db_detach(&db); try_cache:
dns_db_attach(client->view->cachedb, &db); result = query_getcachedb(client, &db, DNS_GETDB_NOLOG);
goto db_find; if (result != ISC_R_SUCCESS)
} else { /*
/* * Most likely the client isn't allowed to query the cache.
* We don't know the answer. */
*/ goto try_glue;
goto cleanup;
} result = dns_db_find(db, name, version, type, client->query.dboptions,
} else { client->now, &node, fname, rdataset,
/* sigrdataset);
* We don't have the data in the cache. If we've if (result == ISC_R_SUCCESS)
* got glue from the zone, use it. goto found;
*/
if (zdb != NULL) { if (dns_rdataset_isassociated(rdataset))
query_releasename(client, &fname); dns_rdataset_disassociate(rdataset);
query_putrdataset(client, &rdataset); if (dns_rdataset_isassociated(sigrdataset))
query_putrdataset(client, &sigrdataset); dns_rdataset_disassociate(sigrdataset);
if (node != NULL) if (node != NULL)
dns_db_detachnode(db, &node); dns_db_detachnode(db, &node);
dns_db_detach(&db); dns_db_detach(&db);
db = zdb;
zdb = NULL; try_glue:
fname = zfname; /*
dbuf = NULL; * No cached data was found. Glue is our last chance.
node = znode; * RFC1035 sayeth:
version = zversion; *
rdataset = zrdataset; * NS records cause both the usual additional section
sigrdataset = zsigrdataset; * processing to locate a type A record, and, when used
} else { * in a referral, a special search of the zone in which
/* * they reside for glue information.
* We don't know the answer. *
*/ * This is the "special search". Note that we must search
goto cleanup; * the zone where the NS record resides, not the zone it
} * points to, and that we only do the search in the delegation
} * case (identified by client->query.gluedb being set).
} else if (result == DNS_R_GLUE) { */
if (USECACHE(client) && RECURSIONOK(client)) {
/* if (client->query.gluedb == NULL)
* We found an answer, but the cache may be
* better. Remember what we've got and go look in
* the cache.
*/
query_keepname(client, fname, dbuf);
zfname = fname;
zdb = db;
zversion = version;
znode = node;
zrdataset = rdataset;
zsigrdataset = sigrdataset;
version = NULL;
db = NULL;
dns_db_attach(client->view->cachedb, &db);
is_zone = ISC_FALSE;
goto db_find;
}
} else if (result != ISC_R_SUCCESS && result != DNS_R_ZONECUT)
goto cleanup; goto cleanup;
if (dbuf != NULL) dns_db_attach(client->query.gluedb, &db);
query_keepname(client, fname, dbuf); result = dns_db_find(db, name, version, type,
client->query.dboptions | DNS_DBFIND_GLUEOK,
client->now, &node, fname, rdataset,
sigrdataset);
if (!(result == ISC_R_SUCCESS ||
result == DNS_R_ZONECUT ||
result == DNS_R_GLUE))
goto cleanup;
found:
/*
* We have found a potential additional data rdataset, or
* at least a node to iterate over.
*/
query_keepname(client, fname, dbuf);
/*
* If we have an rdataset, add it to the additional data
* section.
*/
mname = NULL; mname = NULL;
if (dns_rdataset_isassociated(rdataset) && if (dns_rdataset_isassociated(rdataset) &&
!query_isduplicate(client, fname, type, &mname)) { !query_isduplicate(client, fname, type, &mname)) {
@@ -911,9 +977,6 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
if (qtype == dns_rdatatype_a) { if (qtype == dns_rdatatype_a) {
/* /*
* We treat type A additional section processing as if it
* were "any address type" additional section processing.
*
* We now go looking for A, A6, and AAAA records, along with * We now go looking for A, A6, and AAAA records, along with
* their signatures. * their signatures.
* *
@@ -948,17 +1011,6 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
*/ */
INSIST(! dns_rdataset_isassociated(sigrdataset)); INSIST(! dns_rdataset_isassociated(sigrdataset));
} }
if (zdb != NULL && result == ISC_R_NOTFOUND) {
/*
* The cache doesn't have an A, but we may have
* one in the zone's glue.
*/
result = dns_db_findrdataset(zdb, znode, zversion,
dns_rdatatype_a, 0,
client->now,
rdataset,
sigrdataset);
}
if (result == ISC_R_SUCCESS) { if (result == ISC_R_SUCCESS) {
mname = NULL; mname = NULL;
if (!query_isduplicate(client, fname, if (!query_isduplicate(client, fname,
@@ -995,17 +1047,6 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
dns_rdataset_disassociate(rdataset); dns_rdataset_disassociate(rdataset);
INSIST(! dns_rdataset_isassociated(sigrdataset)); INSIST(! dns_rdataset_isassociated(sigrdataset));
} }
if (zdb != NULL && result == ISC_R_NOTFOUND) {
/*
* The cache doesn't have an A6, but we may have
* one in the zone's glue.
*/
result = dns_db_findrdataset(zdb, znode, zversion,
dns_rdatatype_a6, 0,
client->now,
rdataset,
sigrdataset);
}
if (result == ISC_R_SUCCESS) { if (result == ISC_R_SUCCESS) {
mname = NULL; mname = NULL;
if (!query_isduplicate(client, fname, if (!query_isduplicate(client, fname,
@@ -1040,17 +1081,6 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
dns_rdataset_disassociate(rdataset); dns_rdataset_disassociate(rdataset);
INSIST(! dns_rdataset_isassociated(sigrdataset)); INSIST(! dns_rdataset_isassociated(sigrdataset));
} }
if (zdb != NULL && result == ISC_R_NOTFOUND) {
/*
* The cache doesn't have an AAAA, but we may have
* one in the zone's glue.
*/
result = dns_db_findrdataset(zdb, znode, zversion,
dns_rdatatype_aaaa, 0,
client->now,
rdataset,
sigrdataset);
}
if (result == ISC_R_SUCCESS) { if (result == ISC_R_SUCCESS) {
mname = NULL; mname = NULL;
if (!query_isduplicate(client, fname, if (!query_isduplicate(client, fname,
@@ -1147,15 +1177,6 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
dns_db_detach(&db); dns_db_detach(&db);
if (zone != NULL) if (zone != NULL)
dns_zone_detach(&zone); dns_zone_detach(&zone);
if (zdb != NULL) {
if (zfname != NULL)
query_releasename(client, &zfname);
query_putrdataset(client, &zrdataset);
query_putrdataset(client, &zsigrdataset);
if (znode != NULL)
dns_db_detachnode(zdb, &znode);
dns_db_detach(&zdb);
}
CTRACE("query_addadditional: done"); CTRACE("query_addadditional: done");
return (eresult); return (eresult);