mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-28 21:17:54 +00:00
1935. [bug] 'acache' was DO sensitive. [RT #15430]
1934. [func] Validate pending NS RRsets, in the authority section, prior to returning them if it can be done without requiring DNSKEYs to be fetched. [RT #15430]
This commit is contained in:
parent
f90bd3a009
commit
faa4af28cf
6
CHANGES
6
CHANGES
@ -1,3 +1,9 @@
|
||||
1935. [bug] 'acache' was DO sensitive. [RT #15430]
|
||||
|
||||
1934. [func] Validate pending NS RRsets, in the authority section,
|
||||
prior to returning them if it can be done without
|
||||
requiring DNSKEYs to be fetched. [RT #15430]
|
||||
|
||||
1933. [bug] dump_rdataset_raw() had a incorrect INSIST. [RT #15534]
|
||||
|
||||
1932. [bug] hpux: LDFLAGS was getting corrupted. [RT #15530]
|
||||
|
@ -15,7 +15,7 @@
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: query.c,v 1.274 2005/10/13 01:58:31 marka Exp $ */
|
||||
/* $Id: query.c,v 1.275 2005/11/02 01:28:45 marka Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
#ifdef DLZ
|
||||
#include <dns/dlz.h>
|
||||
#endif
|
||||
#include <dns/dnssec.h>
|
||||
#include <dns/events.h>
|
||||
#include <dns/message.h>
|
||||
#include <dns/ncache.h>
|
||||
@ -116,6 +117,10 @@ typedef struct client_additionalctx {
|
||||
static void
|
||||
query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype);
|
||||
|
||||
static isc_boolean_t
|
||||
validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
|
||||
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
|
||||
|
||||
/*%
|
||||
* Increment query statistics counters.
|
||||
*/
|
||||
@ -1110,10 +1115,23 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
|
||||
* Most likely the client isn't allowed to query the cache.
|
||||
*/
|
||||
goto try_glue;
|
||||
|
||||
result = dns_db_find(db, name, version, type, client->query.dboptions,
|
||||
/*
|
||||
* Attempt to validate glue.
|
||||
*/
|
||||
if (sigrdataset == NULL) {
|
||||
sigrdataset = query_newrdataset(client);
|
||||
if (sigrdataset == NULL)
|
||||
goto cleanup;
|
||||
}
|
||||
result = dns_db_find(db, name, version, type,
|
||||
client->query.dboptions | DNS_DBFIND_GLUEOK,
|
||||
client->now, &node, fname, rdataset,
|
||||
sigrdataset);
|
||||
if (result == DNS_R_GLUE &&
|
||||
validate(client, db, fname, rdataset, sigrdataset))
|
||||
result = ISC_R_SUCCESS;
|
||||
if (!WANTDNSSEC(client))
|
||||
query_putrdataset(client, &sigrdataset);
|
||||
if (result == ISC_R_SUCCESS)
|
||||
goto found;
|
||||
|
||||
@ -1590,7 +1608,8 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
|
||||
*/
|
||||
goto try_glue;
|
||||
|
||||
result = dns_db_find(db, name, version, type, client->query.dboptions,
|
||||
result = dns_db_find(db, name, version, type,
|
||||
client->query.dboptions | DNS_DBFIND_GLUEOK,
|
||||
client->now, &node, fname, NULL, NULL);
|
||||
if (result == ISC_R_SUCCESS)
|
||||
goto found;
|
||||
@ -1688,11 +1707,10 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
|
||||
rdataset = query_newrdataset(client);
|
||||
if (rdataset == NULL)
|
||||
goto cleanup;
|
||||
if (WANTDNSSEC(client)) {
|
||||
sigrdataset = query_newrdataset(client);
|
||||
if (sigrdataset == NULL)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
sigrdataset = query_newrdataset(client);
|
||||
if (sigrdataset == NULL)
|
||||
goto cleanup;
|
||||
|
||||
/*
|
||||
* Find A RRset with sig RRset. Even if we don't find a sig RRset
|
||||
@ -1703,6 +1721,20 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
|
||||
*/
|
||||
result = dns_db_findrdataset(db, node, version, dns_rdatatype_a, 0,
|
||||
client->now, rdataset, sigrdataset);
|
||||
/*
|
||||
* If we can't promote glue/pending from the cache to secure
|
||||
* then drop it.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS &&
|
||||
additionaltype == dns_rdatasetadditional_fromcache &&
|
||||
(rdataset->trust == dns_trust_pending ||
|
||||
rdataset->trust == dns_trust_glue) &&
|
||||
!validate(client, db, fname, rdataset, sigrdataset)) {
|
||||
dns_rdataset_disassociate(rdataset);
|
||||
if (dns_rdataset_isassociated(sigrdataset))
|
||||
dns_rdataset_disassociate(sigrdataset);
|
||||
result = ISC_R_NOTFOUND;
|
||||
}
|
||||
if (result == DNS_R_NCACHENXDOMAIN)
|
||||
goto setcache;
|
||||
if (result == DNS_R_NCACHENXRRSET) {
|
||||
@ -1710,50 +1742,53 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
|
||||
/*
|
||||
* Negative cache entries don't have sigrdatasets.
|
||||
*/
|
||||
INSIST(sigrdataset == NULL ||
|
||||
! dns_rdataset_isassociated(sigrdataset));
|
||||
INSIST(! dns_rdataset_isassociated(sigrdataset));
|
||||
}
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
/* Remember the result as a cache */
|
||||
ISC_LIST_APPEND(cfname.list, rdataset, link);
|
||||
if (sigrdataset != NULL &&
|
||||
dns_rdataset_isassociated(sigrdataset)) {
|
||||
ISC_LIST_APPEND(cfname.list, sigrdataset,
|
||||
link);
|
||||
sigrdataset =
|
||||
query_newrdataset(client);
|
||||
if (sigrdataset == NULL)
|
||||
needadditionalcache = ISC_FALSE;
|
||||
if (dns_rdataset_isassociated(sigrdataset)) {
|
||||
ISC_LIST_APPEND(cfname.list, sigrdataset, link);
|
||||
sigrdataset = query_newrdataset(client);
|
||||
}
|
||||
rdataset = query_newrdataset(client);
|
||||
if (rdataset == NULL) {
|
||||
if (sigrdataset == NULL || rdataset == NULL) {
|
||||
/* do not cache incomplete information */
|
||||
goto foundcache;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find AAAA RRset with sig RRset */
|
||||
result = dns_db_findrdataset(db, node, version,
|
||||
dns_rdatatype_aaaa, 0,
|
||||
client->now, rdataset,
|
||||
sigrdataset);
|
||||
result = dns_db_findrdataset(db, node, version, dns_rdatatype_aaaa,
|
||||
0, client->now, rdataset, sigrdataset);
|
||||
/* The NXDOMAIN case should be covered above */
|
||||
INSIST(result != DNS_R_NCACHENXDOMAIN);
|
||||
/*
|
||||
* If we can't promote glue/pending from the cache to secure
|
||||
* then drop it.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS &&
|
||||
additionaltype == dns_rdatasetadditional_fromcache &&
|
||||
(rdataset->trust == dns_trust_pending ||
|
||||
rdataset->trust == dns_trust_glue) &&
|
||||
!validate(client, db, fname, rdataset, sigrdataset)) {
|
||||
dns_rdataset_disassociate(rdataset);
|
||||
if (dns_rdataset_isassociated(sigrdataset))
|
||||
dns_rdataset_disassociate(sigrdataset);
|
||||
result = ISC_R_NOTFOUND;
|
||||
}
|
||||
if (result == DNS_R_NCACHENXRRSET) {
|
||||
dns_rdataset_disassociate(rdataset);
|
||||
/*
|
||||
* Negative cache entries don't have sigrdatasets.
|
||||
*/
|
||||
INSIST(sigrdataset == NULL ||
|
||||
! dns_rdataset_isassociated(sigrdataset));
|
||||
INSIST(! dns_rdataset_isassociated(sigrdataset));
|
||||
}
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
ISC_LIST_APPEND(cfname.list, rdataset, link);
|
||||
rdataset = NULL;
|
||||
if (sigrdataset != NULL &&
|
||||
dns_rdataset_isassociated(sigrdataset)) {
|
||||
ISC_LIST_APPEND(cfname.list, sigrdataset,
|
||||
link);
|
||||
if (dns_rdataset_isassociated(sigrdataset)) {
|
||||
ISC_LIST_APPEND(cfname.list, sigrdataset, link);
|
||||
sigrdataset = NULL;
|
||||
}
|
||||
}
|
||||
@ -1809,7 +1844,7 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
|
||||
need_sigrrset = ISC_TRUE;
|
||||
} else
|
||||
need_sigrrset = ISC_FALSE;
|
||||
} else if (crdataset->type == dns_rdatatype_sig &&
|
||||
} else if (crdataset->type == dns_rdatatype_rrsig &&
|
||||
need_sigrrset && WANTDNSSEC(client)) {
|
||||
ISC_LIST_UNLINK(cfname.list, crdataset, link);
|
||||
ISC_LIST_APPEND(fname->list, crdataset, link);
|
||||
@ -2240,6 +2275,152 @@ query_addcnamelike(ns_client_t *client, dns_name_t *qname, dns_name_t *tname,
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the RRsets as secure. Update the cache (db) to reflect the
|
||||
* change in trust level.
|
||||
*/
|
||||
static void
|
||||
mark_secure(ns_client_t *client, dns_db_t *db, dns_name_t *name,
|
||||
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
|
||||
{
|
||||
isc_result_t result;
|
||||
dns_dbnode_t *node = NULL;
|
||||
|
||||
rdataset->trust = dns_trust_secure;
|
||||
sigrdataset->trust = dns_trust_secure;
|
||||
|
||||
/*
|
||||
* Save the updated secure state. Ignore failures.
|
||||
*/
|
||||
result = dns_db_findnode(db, name, ISC_TRUE, &node);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return;
|
||||
(void)dns_db_addrdataset(db, node, NULL, client->now, rdataset,
|
||||
0, NULL);
|
||||
(void)dns_db_addrdataset(db, node, NULL, client->now, sigrdataset,
|
||||
0, NULL);
|
||||
dns_db_detachnode(db, &node);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the secure key that corresponds to rrsig.
|
||||
* Note: 'keyrdataset' maintains state between sucessive calls,
|
||||
* there may be multiple keys with the same keyid.
|
||||
* Return ISC_FALSE if we have exhausted all the possible keys.
|
||||
*/
|
||||
static isc_boolean_t
|
||||
get_key(ns_client_t *client, dns_db_t *db, dns_rdata_rrsig_t *rrsig,
|
||||
dns_rdataset_t *keyrdataset, dst_key_t **keyp)
|
||||
{
|
||||
isc_result_t result;
|
||||
dns_dbnode_t *node = NULL;
|
||||
isc_boolean_t secure = ISC_FALSE;
|
||||
|
||||
if (!dns_rdataset_isassociated(keyrdataset)) {
|
||||
result = dns_db_findnode(db, &rrsig->signer, ISC_FALSE, &node);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (ISC_FALSE);
|
||||
|
||||
result = dns_db_findrdataset(db, node, NULL,
|
||||
dns_rdatatype_dnskey, 0,
|
||||
client->now, keyrdataset, NULL);
|
||||
dns_db_detachnode(db, &node);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (ISC_FALSE);
|
||||
|
||||
if (keyrdataset->trust != dns_trust_secure)
|
||||
return (ISC_FALSE);
|
||||
|
||||
result = dns_rdataset_first(keyrdataset);
|
||||
} else
|
||||
result = dns_rdataset_next(keyrdataset);
|
||||
|
||||
for ( ; result == ISC_R_SUCCESS;
|
||||
result = dns_rdataset_next(keyrdataset)) {
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
isc_buffer_t b;
|
||||
|
||||
dns_rdataset_current(keyrdataset, &rdata);
|
||||
isc_buffer_init(&b, rdata.data, rdata.length);
|
||||
isc_buffer_add(&b, rdata.length);
|
||||
result = dst_key_fromdns(&rrsig->signer, rdata.rdclass, &b,
|
||||
client->mctx, keyp);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
continue;
|
||||
if (rrsig->algorithm == (dns_secalg_t)dst_key_alg(*keyp) &&
|
||||
rrsig->keyid == (dns_keytag_t)dst_key_id(*keyp) &&
|
||||
dst_key_iszonekey(*keyp)) {
|
||||
secure = ISC_TRUE;
|
||||
break;
|
||||
}
|
||||
dst_key_free(keyp);
|
||||
}
|
||||
return (secure);
|
||||
}
|
||||
|
||||
static isc_boolean_t
|
||||
verify(dst_key_t *key, dns_name_t *name, dns_rdataset_t *rdataset,
|
||||
dns_rdata_t *rdata, isc_mem_t *mctx)
|
||||
{
|
||||
isc_result_t result;
|
||||
dns_fixedname_t fixed;
|
||||
dns_fixedname_init(&fixed);
|
||||
result = dns_dnssec_verify2(name, rdataset, key, ISC_FALSE,
|
||||
mctx, rdata, NULL);
|
||||
if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD)
|
||||
return (ISC_TRUE);
|
||||
return (ISC_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the rdataset if possible with available records.
|
||||
*/
|
||||
static isc_boolean_t
|
||||
validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
|
||||
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
|
||||
{
|
||||
isc_result_t result;
|
||||
dns_rdata_t rdata = DNS_RDATA_INIT;
|
||||
dns_rdata_rrsig_t rrsig;
|
||||
dst_key_t *key = NULL;
|
||||
dns_rdataset_t keyrdataset;
|
||||
|
||||
if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset))
|
||||
return (ISC_FALSE);
|
||||
|
||||
for (result = dns_rdataset_first(sigrdataset);
|
||||
result == ISC_R_SUCCESS;
|
||||
result = dns_rdataset_next(sigrdataset)) {
|
||||
|
||||
dns_rdata_reset(&rdata);
|
||||
dns_rdataset_current(sigrdataset, &rdata);
|
||||
result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (ISC_FALSE);
|
||||
if (!dns_resolver_algorithm_supported(client->view->resolver,
|
||||
name, rrsig.algorithm))
|
||||
continue;
|
||||
if (!dns_name_issubdomain(name, &rrsig.signer))
|
||||
continue;
|
||||
dns_rdataset_init(&keyrdataset);
|
||||
do {
|
||||
if (!get_key(client, db, &rrsig, &keyrdataset, &key))
|
||||
break;
|
||||
if (verify(key, name, rdataset, &rdata, client->mctx)) {
|
||||
dst_key_free(&key);
|
||||
dns_rdataset_disassociate(&keyrdataset);
|
||||
mark_secure(client, db, name, rdataset,
|
||||
sigrdataset);
|
||||
return (ISC_TRUE);
|
||||
}
|
||||
dst_key_free(&key);
|
||||
} while (1);
|
||||
if (dns_rdataset_isassociated(&keyrdataset))
|
||||
dns_rdataset_disassociate(&keyrdataset);
|
||||
}
|
||||
return (ISC_FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
query_addbestns(ns_client_t *client) {
|
||||
dns_db_t *db, *zdb;
|
||||
@ -2287,7 +2468,11 @@ query_addbestns(ns_client_t *client) {
|
||||
rdataset = query_newrdataset(client);
|
||||
if (fname == NULL || rdataset == NULL)
|
||||
goto cleanup;
|
||||
if (WANTDNSSEC(client)) {
|
||||
/*
|
||||
* Get the RRSIGs if the client requested them or if we may
|
||||
* need to validate answers from the cache.
|
||||
*/
|
||||
if (WANTDNSSEC(client) || !is_zone) {
|
||||
sigrdataset = query_newrdataset(client);
|
||||
if (sigrdataset == NULL)
|
||||
goto cleanup;
|
||||
@ -2363,16 +2548,27 @@ query_addbestns(ns_client_t *client) {
|
||||
zsigrdataset = NULL;
|
||||
}
|
||||
|
||||
if ((client->query.dboptions & DNS_DBFIND_PENDINGOK) == 0 &&
|
||||
(rdataset->trust == dns_trust_pending ||
|
||||
(sigrdataset != NULL && sigrdataset->trust == dns_trust_pending)))
|
||||
/*
|
||||
* Attempt to validate RRsets that are pending or that are glue.
|
||||
*/
|
||||
if ((rdataset->trust == dns_trust_pending ||
|
||||
(sigrdataset != NULL && sigrdataset->trust == dns_trust_pending))
|
||||
&& !validate(client, db, fname, rdataset, sigrdataset) &&
|
||||
(client->query.dboptions & DNS_DBFIND_PENDINGOK) == 0)
|
||||
goto cleanup;
|
||||
|
||||
if (WANTDNSSEC(client) && SECURE(client) &&
|
||||
(rdataset->trust == dns_trust_glue ||
|
||||
(sigrdataset != NULL && sigrdataset->trust == dns_trust_glue)))
|
||||
if ((rdataset->trust == dns_trust_glue ||
|
||||
(sigrdataset != NULL && sigrdataset->trust == dns_trust_glue)) &&
|
||||
!validate(client, db, fname, rdataset, sigrdataset) &&
|
||||
SECURE(client) && WANTDNSSEC(client))
|
||||
goto cleanup;
|
||||
|
||||
/*
|
||||
* If the client doesn't want DNSSEC we can discard the sigrdataset
|
||||
* now.
|
||||
*/
|
||||
if (!WANTDNSSEC(client))
|
||||
query_putrdataset(client, &sigrdataset);
|
||||
query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf,
|
||||
DNS_SECTION_AUTHORITY);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user