Compare commits

...

15 Commits

Author SHA1 Message Date
Evan Hunt
14271bf4e2 fixup! fixup! refactor validated() 2025-03-14 18:29:48 -07:00
Evan Hunt
db6e91497c fixup! split out some functionality in cache_name() 2025-03-14 18:29:48 -07:00
Evan Hunt
b735f2e821 fixup! refactor validated() 2025-03-14 18:29:48 -07:00
Evan Hunt
e39d265a99 refactor validated()
- there was special-case code in validated() to handle the results
  of a validator started by a CD=1 query. since that never happens,
  the code has been removed.
- the section of code that handles opportunistic caching of
  validated SOA, NS and NSEC data has been split out to a separate
  function.
- the number of goto statements has been reduced considerably.
2025-03-14 18:29:48 -07:00
Evan Hunt
8f03f31106 split out helper functions
- fctx_setresult() sets the event result in a fetch response
  according to the rdataset being returned - DNS_R_NCACHENXDOMAIN or
  DNS_R_NXRRSET for negative responses, ISC_R_SUCCESS, DNS_R_CNAME,
  or DNS_R_DNAME for positive ones.
- cache_rrset() looks up a node and adds an rdataset.
- delete_rrset() looks up a node and removes rdatasets of a specified
  type and, optionally, the associated signatures.
- gettrust() returns the trust level of an rdataset, or dns_trust_none
  if the rdataset is NULL or not associated.
- getrrsig() scans the rdatasets associated with a name for the
  RRSIG covering a given type.
2025-03-14 18:29:48 -07:00
Evan Hunt
d3d981f38e further subdivide caching functions
rctx_cacherdataset() has been split into two functions:
- rctx_cache_secure() starts validation for rdatasets
  that need it; they are then cached by the validator
  completion callback validated()
- rctx_cache_insecure() caches rdatasets immediately; it
  is called when validation is disabled or the data
  to be cached is glue.
2025-03-14 18:29:48 -07:00
Evan Hunt
6c291971db rename and refactor cache_name() and related functions
- renamed cache_message() to rctx_cachemessage()
- renamed cache_name() to rctx_cachename()
- merged ncache_message() into rctx_ncache()
- split out a new function, rctx_cacherdataset(), which is
  called by rctx_cachename() in a loop to process each of
  the rdatasets associated with the name.
2025-03-14 18:29:48 -07:00
Evan Hunt
d61dc02a7c reduce code duplication around findnoqname()
every call to findnoqname() was followed by a call to
dns_rdataset_addnoqname(). we can move that call into
findnoqname() itself, and simplify the calling functions
a bit.
2025-03-14 18:29:48 -07:00
Evan Hunt
503c7a86fe set ANSWERSIG flag when processing ANY responses
previously, rctx_answer_any() set the ANSWER flag for all
rdatasets in the answer section; it now sets ANSWERSIG for
RRSIG/SIG rdatasets and ANSWER for everything else.  this
error didn't cause any harm in the current code, but it
could have led to unexpected behavior in the future.
2025-03-14 18:29:48 -07:00
Evan Hunt
6876c06918 split out some functionality in cache_name()
there are now separate functions to check the cacheability of
an rdataset or to normalize TTLs, and the code to determine
whether validation is necessary has been simplified.
2025-03-14 18:29:48 -07:00
Evan Hunt
fdb9a24d18 add functions to match rdataset types
- dns_rdataset_issigtype() returns true if the rdataset is
  of type RRSIG and covers a specified type
- dns_rdataset_matchestype() returns true if the rdataset
  is of the specified type *or* the RRSIG covering it.
2025-03-14 18:29:48 -07:00
Evan Hunt
ea33257ad0 reduce steps for negative caching
whenever ncache_adderesult() was called, some preparatory code
was run first; this has now been moved into a single function
negcache() to reduce code duplication.
2025-03-14 18:29:48 -07:00
Evan Hunt
dd971ad4e4 change issecuredomain() functions to bool
dns_keytable_issecuredomain() and dns_view_issecuredomain()
previously returned a result code to inform the caller of
unexpected database failures when looking up names in the
keytable and/or NTA table. such failures are not actually
possible. both functions now return a simple bool.

also, dns_view_issecuredomain() now returns false if
view->enablevalidation is false, so the caller no longer
has to check for that.
2025-03-14 18:29:48 -07:00
Evan Hunt
8368ef5ae7 split out cookie checks from resquery_response_continue()
split the code section that handles cookie issues into a
separate function for better readablity.
2025-03-14 18:29:48 -07:00
Evan Hunt
d8778caec7 simplify dns_ncache_add()
there's no longer any reason to have both dns_ncache_add() and
dns_ncache_addoptout().
2025-03-14 18:29:48 -07:00
9 changed files with 979 additions and 1346 deletions

View File

@@ -205,9 +205,9 @@ dns_keytable_finddeepestmatch(dns_keytable_t *keytable, const dns_name_t *name,
*\li Any other result indicates an error.
*/
isc_result_t
bool
dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
dns_name_t *foundname, bool *wantdnssecp);
dns_name_t *foundname);
/*%<
* Is 'name' at or beneath a trusted key?
*
@@ -219,20 +219,11 @@ dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
*
*\li 'foundanme' is NULL or is a pointer to an initialized dns_name_t
*
*\li '*wantsdnssecp' is a valid bool.
*
* Ensures:
*
*\li On success, *wantsdnssecp will be true if and only if 'name'
* is at or beneath a trusted key. If 'foundname' is not NULL, then
* it will be updated to contain the name of the closest enclosing
* trust anchor.
*
* Returns:
*
*\li ISC_R_SUCCESS
*
*\li Any other result is an error.
*\li Returns true if and only if 'name' is at or beneath a trusted key.
* If 'foundname' is not NULL, then it will be updated to contain
* the name of the closest enclosing trust anchor.
*/
isc_result_t

View File

@@ -54,26 +54,24 @@
isc_result_t
dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
dns_ttl_t maxttl, dns_rdataset_t *addedrdataset);
isc_result_t
dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache,
dns_dbnode_t *node, dns_rdatatype_t covers,
isc_stdtime_t now, dns_ttl_t minttl, dns_ttl_t maxttl,
bool optout, dns_rdataset_t *addedrdataset);
dns_ttl_t maxttl, bool optout, bool secure,
dns_rdataset_t *addedrdataset);
/*%<
* Convert the authority data from 'message' into a negative cache
* rdataset, and store it in 'cache' at 'node' with a TTL limited to
* 'maxttl'.
*
* \li dns_ncache_add produces a negative cache entry with a trust of no
* more than answer
* \li dns_ncache_addoptout produces a negative cache entry which will have
* a trust of secure if all the records that make up the entry are secure.
* \li If 'secure' is true and all the records that make up the entry
* are secure, then dns_ncache_add produces a negative cache entry
* with trust level secure.
* \li If 'secure' is false, the negative cache entry's trust level
* will be capped at answer.
*
* The 'covers' argument is the RR type whose nonexistence we are caching,
* or dns_rdatatype_any when caching a NXDOMAIN response.
*
* 'optout' indicates a DNS_RDATASETATTR_OPTOUT should be set.
* 'optout' indicates DNS_RDATASETATTR_OPTOUT should be set. This only
* applies in secure zones; if 'secure' is false, 'optout' is ignored.
*
* Note:
*\li If 'addedrdataset' is not NULL, then it will be attached to the added

View File

@@ -689,3 +689,30 @@ dns_rdataset_equals(const dns_rdataset_t *rdataset1,
* \li 'rdataset1' is a valid rdataset.
* \li 'rdataset2' is a valid rdataset.
*/
/*%
* Returns true if the rdataset is of type 'type', or type RRSIG
* and covers 'type'.
*/
static inline bool
dns_rdataset_matchestype(const dns_rdataset_t *rdataset,
const dns_rdatatype_t type) {
REQUIRE(DNS_RDATASET_VALID(rdataset));
return rdataset->type == type ||
(rdataset->type == dns_rdatatype_rrsig &&
rdataset->covers == type);
}
/*%
* Returns true if the rdataset is of type 'type', or type RRSIG
* and covers 'type'.
*/
static inline bool
dns_rdataset_issigtype(const dns_rdataset_t *rdataset,
const dns_rdatatype_t type) {
REQUIRE(DNS_RDATASET_VALID(rdataset));
return rdataset->type == dns_rdatatype_rrsig &&
rdataset->covers == type;
}

View File

@@ -986,13 +986,12 @@ dns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp);
*\li ISC_R_NOTFOUND
*/
isc_result_t
bool
dns_view_issecuredomain(dns_view_t *view, const dns_name_t *name,
isc_stdtime_t now, bool checknta, bool *ntap,
bool *secure_domain);
isc_stdtime_t now, bool checknta, bool *ntap);
/*%<
* Is 'name' at or beneath a trusted key, and not covered by a valid
* negative trust anchor? Put answer in '*secure_domain'.
* negative trust anchor, and DNSSEC validation is enabled?
*
* If 'checknta' is false, ignore the NTA table in determining
* whether this is a secure domain. If 'checknta' is not false, and if
@@ -1001,10 +1000,6 @@ dns_view_issecuredomain(dns_view_t *view, const dns_name_t *name,
*
* Requires:
* \li 'view' is valid.
*
* Returns:
*\li ISC_R_SUCCESS
*\li Any other value indicates failure
*/
bool

View File

@@ -530,13 +530,14 @@ dns_keytable_finddeepestmatch(dns_keytable_t *keytable, const dns_name_t *name,
return result;
}
isc_result_t
bool
dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
dns_name_t *foundname, bool *wantdnssecp) {
dns_name_t *foundname) {
isc_result_t result;
dns_qpread_t qpr;
dns_keynode_t *keynode = NULL;
void *pval = NULL;
bool secure = false;
/*
* Is 'name' at or beneath a trusted key?
@@ -544,7 +545,6 @@ dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
REQUIRE(VALID_KEYTABLE(keytable));
REQUIRE(dns_name_isabsolute(name));
REQUIRE(wantdnssecp != NULL);
dns_qpmulti_query(keytable->table, &qpr);
result = dns_qp_lookup(&qpr, name, NULL, NULL, NULL, &pval, NULL);
@@ -553,16 +553,12 @@ dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name,
if (foundname != NULL) {
dns_name_copy(&keynode->name, foundname);
}
*wantdnssecp = true;
result = ISC_R_SUCCESS;
} else if (result == ISC_R_NOTFOUND) {
*wantdnssecp = false;
result = ISC_R_SUCCESS;
secure = true;
}
dns_qpread_destroy(keytable->table, &qpr);
return result;
return secure;
}
static isc_result_t

View File

@@ -50,12 +50,6 @@ atomic_getuint8(isc_buffer_t *b) {
return ret;
}
static isc_result_t
addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
dns_ttl_t maxttl, bool optout, bool secure,
dns_rdataset_t *addedrdataset);
static isc_result_t
copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
isc_result_t result;
@@ -107,25 +101,8 @@ copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
isc_result_t
dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
dns_ttl_t maxttl, dns_rdataset_t *addedrdataset) {
return addoptout(message, cache, node, covers, now, minttl, maxttl,
false, false, addedrdataset);
}
isc_result_t
dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache,
dns_dbnode_t *node, dns_rdatatype_t covers,
isc_stdtime_t now, dns_ttl_t minttl, dns_ttl_t maxttl,
bool optout, dns_rdataset_t *addedrdataset) {
return addoptout(message, cache, node, covers, now, minttl, maxttl,
optout, true, addedrdataset);
}
static isc_result_t
addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
dns_ttl_t maxttl, bool optout, bool secure,
dns_rdataset_t *addedrdataset) {
dns_ttl_t maxttl, bool optout, bool secure,
dns_rdataset_t *addedrdataset) {
isc_result_t result;
isc_buffer_t buffer;
isc_region_t r;
@@ -143,14 +120,17 @@ addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
/*
* Convert the authority data from 'message' into a negative cache
* rdataset, and store it in 'cache' at 'node'.
*
* We assume that all data in the authority section has been
* validated by the caller.
*/
REQUIRE(message != NULL);
/*
* We assume that all data in the authority section has been
* validated by the caller.
* If 'secure' is false, ignore 'optout'.
*/
optout = optout && secure;
/*
* Initialize the list.

File diff suppressed because it is too large Load Diff

View File

@@ -1533,41 +1533,31 @@ dns_view_ntacovers(dns_view_t *view, isc_stdtime_t now, const dns_name_t *name,
return dns_ntatable_covered(view->ntatable_priv, now, name, anchor);
}
isc_result_t
bool
dns_view_issecuredomain(dns_view_t *view, const dns_name_t *name,
isc_stdtime_t now, bool checknta, bool *ntap,
bool *secure_domain) {
isc_result_t result;
isc_stdtime_t now, bool checknta, bool *ntap) {
bool secure = false;
dns_fixedname_t fn;
dns_name_t *anchor;
REQUIRE(DNS_VIEW_VALID(view));
if (view->secroots_priv == NULL) {
return ISC_R_NOTFOUND;
if (!view->enablevalidation || view->secroots_priv == NULL) {
return false;
}
anchor = dns_fixedname_initname(&fn);
result = dns_keytable_issecuredomain(view->secroots_priv, name, anchor,
&secure);
if (result != ISC_R_SUCCESS) {
return result;
}
secure = dns_keytable_issecuredomain(view->secroots_priv, name, anchor);
SET_IF_NOT_NULL(ntap, false);
if (checknta && secure && view->ntatable_priv != NULL &&
dns_ntatable_covered(view->ntatable_priv, now, name, anchor))
{
if (ntap != NULL) {
*ntap = true;
}
SET_IF_NOT_NULL(ntap, true);
secure = false;
}
*secure_domain = secure;
return ISC_R_SUCCESS;
return secure;
}
void

View File

@@ -535,7 +535,6 @@ ISC_LOOP_TEST_IMPL(find) {
/* check issecuredomain() */
ISC_LOOP_TEST_IMPL(issecuredomain) {
bool issecure;
const char **n;
const char *names[] = { "example.com", "sub.example.com",
"null.example", "sub.null.example", NULL };
@@ -550,22 +549,16 @@ ISC_LOOP_TEST_IMPL(issecuredomain) {
* of installing a null key).
*/
for (n = names; *n != NULL; n++) {
assert_int_equal(dns_keytable_issecuredomain(keytable,
str2name(*n), NULL,
&issecure),
ISC_R_SUCCESS);
assert_true(issecure);
assert_true(dns_keytable_issecuredomain(keytable, str2name(*n),
NULL));
}
/*
* If the key table has no entry (not even a null one) for a domain or
* any of its ancestors, that domain is considered insecure.
*/
assert_int_equal(dns_keytable_issecuredomain(keytable,
str2name("example.org"),
NULL, &issecure),
ISC_R_SUCCESS);
assert_false(issecure);
assert_false(dns_keytable_issecuredomain(
keytable, str2name("example.org"), NULL));
destroy_tables();
@@ -595,7 +588,7 @@ ISC_LOOP_TEST_IMPL(dump) {
/* check negative trust anchors */
ISC_LOOP_TEST_IMPL(nta) {
isc_result_t result;
bool issecure, covered;
bool covered;
dns_fixedname_t fn;
dns_name_t *keyname = dns_fixedname_name(&fn);
unsigned char digest[ISC_MAX_MD_SIZE];
@@ -626,20 +619,15 @@ ISC_LOOP_TEST_IMPL(nta) {
assert_int_equal(result, ISC_R_SUCCESS);
/* Should be secure */
result = dns_view_issecuredomain(myview,
str2name("test.secure.example"), now,
true, &covered, &issecure);
assert_int_equal(result, ISC_R_SUCCESS);
assert_true(dns_view_issecuredomain(
myview, str2name("test.secure.example"), now, true, &covered));
assert_false(covered);
assert_true(issecure);
/* Should not be secure */
result = dns_view_issecuredomain(myview,
str2name("test.insecure.example"), now,
true, &covered, &issecure);
assert_int_equal(result, ISC_R_SUCCESS);
assert_false(dns_view_issecuredomain(myview,
str2name("test.insecure.example"),
now, true, &covered));
assert_true(covered);
assert_false(issecure);
/* NTA covered */
covered = dns_view_ntacovers(myview, now, str2name("insecure.example"),
@@ -652,38 +640,30 @@ ISC_LOOP_TEST_IMPL(nta) {
assert_false(covered);
/* As of now + 2, the NTA should be clear */
result = dns_view_issecuredomain(myview,
str2name("test.insecure.example"),
now + 2, true, &covered, &issecure);
assert_int_equal(result, ISC_R_SUCCESS);
assert_true(dns_view_issecuredomain(myview,
str2name("test.insecure.example"),
now + 2, true, &covered));
assert_false(covered);
assert_true(issecure);
/* Now check deletion */
result = dns_view_issecuredomain(myview, str2name("test.new.example"),
now, true, &covered, &issecure);
assert_int_equal(result, ISC_R_SUCCESS);
assert_true(dns_view_issecuredomain(
myview, str2name("test.new.example"), now, true, &covered));
assert_false(covered);
assert_true(issecure);
result = dns_ntatable_add(ntatable, str2name("new.example"), false, now,
3600);
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_view_issecuredomain(myview, str2name("test.new.example"),
now, true, &covered, &issecure);
assert_int_equal(result, ISC_R_SUCCESS);
assert_false(dns_view_issecuredomain(
myview, str2name("test.new.example"), now, true, &covered));
assert_true(covered);
assert_false(issecure);
result = dns_ntatable_delete(ntatable, str2name("new.example"));
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_view_issecuredomain(myview, str2name("test.new.example"),
now, true, &covered, &issecure);
assert_int_equal(result, ISC_R_SUCCESS);
assert_true(dns_view_issecuredomain(
myview, str2name("test.new.example"), now, true, &covered));
assert_false(covered);
assert_true(issecure);
isc_loopmgr_shutdown(loopmgr);