mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-08 17:52:10 -04:00
BIND 9.19.21
-----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAARcAAAAHc3NoLXJzYQAAAAMBAAEAAAEBANamVSTMToLcHCXRu1f52e tTJWV3T1GSVrPYXwAGe6EVC7m9CTl06FZ9ZG/ymn1S1++dk4ByVZXf6dODe2Mu0RuqGmyf MUEMKXVdj3cEQhgRaMjBXvIZoYAsQlbHO2BEttomq8PhrpLRizDBq4Bv2aThM0XN2QqSGS ozwYMcPiGUoMVNcVrC4ZQ+Cptb5C4liqAcpRqrSo8l1vcNg5b1Hk6r7NFPdx542gsGMLae wZrnKn3LWz3ZXTGeK2cRmBxm/bydiVSCsc9XjB+tWtIGUpQsfaXqZ7Hs6t+1f1vsnu88oJ oi1dRBo3YNRl49UiCukXWayQrPJa8wwxURS9W28JMAAAADZ2l0AAAAAAAAAAZzaGE1MTIA AAEUAAAADHJzYS1zaGEyLTUxMgAAAQBSREyaosd+mY8kovqAvGYR8pOui/7gOi6pBprPGw RlOB5z6YOx5FOjbVL/YvBhKk2gbox++o8jCMEmdNNbWeO3U3uBvxCa+8QGARbuMV6vdoR4 qjnOgOfryXyaRw7PQX0ZH0gPw1B1036y5bnW7WPkqrTvGgxW34O1q6j0EumE0vh90E24/l PAWKDCTqDR/+slGDuWgtPcCZuClljw1Mh0dAliKkGhp0l80qMQSr6O/p66A44UxzKwtnnt lagtO0j4nZ+BxC/hyaFc/FlCzeoc48qFQRIt0ZjYKU+XK0CUr2RTpYFdi/n7y3BNd7bDkD nIkEDddn/lXP5rkAdkmDCa -----END SSH SIGNATURE----- gpgsig -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAg25GGAuUyFX1gxo7QocNm8V6J/8 frHSduYX7Aqk4iJLwAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQEGqBHXwCtEJxRzHbTp6CfBNjqwIAjRD9G+HC4M7q77KBEBgc6dRf15ZRRgiWJCk5P iHMZkEMyWCnELMzhiTzgE= -----END SSH SIGNATURE----- Merge tag 'v9.19.21' BIND 9.19.21
This commit is contained in:
commit
8610799317
26 changed files with 1393 additions and 740 deletions
26
CHANGES
26
CHANGES
|
|
@ -77,25 +77,37 @@
|
|||
'host -C' commands when one of the name servers returns
|
||||
SERVFAIL. [GL #4508]
|
||||
|
||||
--- 9.19.21 released ---
|
||||
|
||||
6323. [placeholder]
|
||||
|
||||
6322. [placeholder]
|
||||
6322. [security] Specific DNS answers could cause a denial-of-service
|
||||
condition due to DNS validation taking a long time.
|
||||
(CVE-2023-50387) [GL #4424]
|
||||
|
||||
6321. [placeholder]
|
||||
6321. [security] Change 6315 inadvertently introduced regressions that
|
||||
could cause named to crash. [GL #4234]
|
||||
|
||||
6320. [placeholder]
|
||||
|
||||
6319. [placeholder]
|
||||
--- 9.19.20 released ---
|
||||
|
||||
6319. [func] Limit isc_async_run() overhead for RBTDB tree pruning.
|
||||
[GL #4383]
|
||||
|
||||
6318. [placeholder]
|
||||
|
||||
6317. [placeholder]
|
||||
6317. [security] Restore DNS64 state when handling a serve-stale timeout.
|
||||
(CVE-2023-5679) [GL #4334]
|
||||
|
||||
6316. [placeholder]
|
||||
6316. [security] Specific queries could trigger an assertion check with
|
||||
nxdomain-redirect enabled. (CVE-2023-5517) [GL #4281]
|
||||
|
||||
6315. [placeholder]
|
||||
6315. [security] Speed up parsing of DNS messages with many different
|
||||
names. (CVE-2023-4408) [GL #4234]
|
||||
|
||||
6314. [placeholder]
|
||||
6314. [bug] Address race conditions in dns_tsigkey_find().
|
||||
[GL #4182]
|
||||
|
||||
6313. [bug] When dnssec-policy is in effect the DNSKEY's TTLs in
|
||||
the zone where not being updated to match the policy.
|
||||
|
|
|
|||
|
|
@ -5458,6 +5458,21 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
|||
INSIST(result == ISC_R_SUCCESS);
|
||||
dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "max-validations-per-fetch", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
dns_resolver_setmaxvalidations(view->resolver,
|
||||
cfg_obj_asuint32(obj));
|
||||
}
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "max-validation-failures-per-fetch",
|
||||
&obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
dns_resolver_setmaxvalidationfails(view->resolver,
|
||||
cfg_obj_asuint32(obj));
|
||||
}
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "fetches-per-zone", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
|
|
|
|||
|
|
@ -347,18 +347,18 @@ if changes_added_lines:
|
|||
# MR.
|
||||
|
||||
release_notes_regex = re.compile(r"doc/(arm|notes)/notes-.*\.(rst|xml)")
|
||||
release_notes_changed = list(filter(release_notes_regex.match, modified_files))
|
||||
release_notes_changed = list(filter(release_notes_regex.match, affected_files))
|
||||
release_notes_label_set = "Release Notes" in mr_labels
|
||||
if not release_notes_changed:
|
||||
if release_notes_label_set:
|
||||
fail(
|
||||
"This merge request has the *Release Notes* label set. "
|
||||
"Add a release note or unset the *Release Notes* label."
|
||||
"Update release notes or unset the *Release Notes* label."
|
||||
)
|
||||
elif "Customer" in mr_labels:
|
||||
warn(
|
||||
"This merge request has the *Customer* label set. "
|
||||
"Add a release note unless the changes introduced are trivial."
|
||||
"Update release notes unless the changes introduced are trivial."
|
||||
)
|
||||
if release_notes_changed and not release_notes_label_set:
|
||||
fail(
|
||||
|
|
@ -367,7 +367,9 @@ if release_notes_changed and not release_notes_label_set:
|
|||
)
|
||||
|
||||
if release_notes_changed:
|
||||
notes_added_lines = added_lines(target_branch, release_notes_changed)
|
||||
modified_or_new_files = danger.git.modified_files + danger.git.created_files
|
||||
release_notes_added = list(filter(release_notes_regex.match, modified_or_new_files))
|
||||
notes_added_lines = added_lines(target_branch, release_notes_added)
|
||||
identifiers_found = filter(relnotes_issue_or_mr_id_regex.search, notes_added_lines)
|
||||
if notes_added_lines and not any(identifiers_found):
|
||||
warn("No valid issue/MR identifiers found in added release notes.")
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ information about each release, and source code.
|
|||
.. include:: ../notes/notes-known-issues.rst
|
||||
|
||||
.. include:: ../notes/notes-current.rst
|
||||
.. include:: ../notes/notes-9.19.21.rst
|
||||
.. include:: ../notes/notes-9.19.20.rst
|
||||
.. include:: ../notes/notes-9.19.19.rst
|
||||
.. include:: ../notes/notes-9.19.18.rst
|
||||
.. include:: ../notes/notes-9.19.17.rst
|
||||
|
|
|
|||
|
|
@ -3736,6 +3736,21 @@ system.
|
|||
set to zero, :any:`max-clients-per-query` no longer applies and there is no
|
||||
upper bound, other than that imposed by :any:`recursive-clients`.
|
||||
|
||||
.. namedconf:statement:: max-validations-per-fetch
|
||||
:tags: server
|
||||
:short: Set the maximum number of DNSSEC validations that can happen in single fetch
|
||||
|
||||
This is an **experimental** setting to set the maximum number of DNSSEC
|
||||
validations that can happen in a single resolver fetch. The default is 16.
|
||||
|
||||
.. namedconf:statement:: max-validation-failures-per-fetch
|
||||
:tags: server
|
||||
:short: Set the maximum number of DNSSEC validation failures that can happen in single fetch
|
||||
|
||||
This is an **experimental** setting to set the maximum number of DNSSEC
|
||||
validation failures that can happen in a single resolver fetch. The default
|
||||
is 1.
|
||||
|
||||
.. namedconf:statement:: fetches-per-zone
|
||||
:tags: server, query
|
||||
:short: Sets the maximum number of simultaneous iterative queries allowed to any one domain before the server blocks new queries for data in or beneath that zone.
|
||||
|
|
|
|||
|
|
@ -193,6 +193,8 @@ options {
|
|||
max-transfer-time-in <integer>;
|
||||
max-transfer-time-out <integer>;
|
||||
max-udp-size <integer>;
|
||||
max-validation-failures-per-fetch <integer>; // experimental
|
||||
max-validations-per-fetch <integer>; // experimental
|
||||
max-zone-ttl ( unlimited | <duration> ); // deprecated
|
||||
memstatistics <boolean>;
|
||||
memstatistics-file <quoted_string>;
|
||||
|
|
@ -475,6 +477,8 @@ view <string> [ <class> ] {
|
|||
max-transfer-time-in <integer>;
|
||||
max-transfer-time-out <integer>;
|
||||
max-udp-size <integer>;
|
||||
max-validation-failures-per-fetch <integer>; // experimental
|
||||
max-validations-per-fetch <integer>; // experimental
|
||||
max-zone-ttl ( unlimited | <duration> ); // deprecated
|
||||
message-compression <boolean>;
|
||||
min-cache-ttl <duration>;
|
||||
|
|
|
|||
19
doc/notes/notes-9.19.20.rst
Normal file
19
doc/notes/notes-9.19.20.rst
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
.. 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.
|
||||
|
||||
Notes for BIND 9.19.20
|
||||
----------------------
|
||||
|
||||
.. note::
|
||||
|
||||
The BIND 9.19.20 release was withdrawn after the discovery of a
|
||||
regression in a security fix in it during pre-release testing. ISC
|
||||
would like to acknowledge the assistance of Curtis Tuplin of SaskTel.
|
||||
70
doc/notes/notes-9.19.21.rst
Normal file
70
doc/notes/notes-9.19.21.rst
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
.. 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.
|
||||
|
||||
Notes for BIND 9.19.21
|
||||
----------------------
|
||||
|
||||
Security Fixes
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
- Validating DNS messages containing a lot of DNSSEC signatures could
|
||||
cause excessive CPU load, leading to a denial-of-service condition.
|
||||
This has been fixed. :cve:`2023-50387`
|
||||
|
||||
ISC would like to thank Elias Heftrig, Haya Schulmann, Niklas Vogel,
|
||||
and Michael Waidner from the German National Research Center for
|
||||
Applied Cybersecurity ATHENE for bringing this vulnerability to our
|
||||
attention. :gl:`#4424`
|
||||
|
||||
- Parsing DNS messages with many different names could cause excessive
|
||||
CPU load. This has been fixed. :cve:`2023-4408`
|
||||
|
||||
ISC would like to thank Shoham Danino from Reichman University, Anat
|
||||
Bremler-Barr from Tel-Aviv University, Yehuda Afek from Tel-Aviv
|
||||
University, and Yuval Shavitt from Tel-Aviv University for bringing
|
||||
this vulnerability to our attention. :gl:`#4234`
|
||||
|
||||
- Specific queries could cause :iscman:`named` to crash with an
|
||||
assertion failure when :any:`nxdomain-redirect` was enabled. This has
|
||||
been fixed. :cve:`2023-5517` :gl:`#4281`
|
||||
|
||||
- A bad interaction between DNS64 and serve-stale could cause
|
||||
:iscman:`named` to crash with an assertion failure, when both of these
|
||||
features were enabled. This has been fixed. :cve:`2023-5679`
|
||||
:gl:`#4334`
|
||||
|
||||
Feature Changes
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
- :iscman:`named-compilezone` no longer performs zone integrity checks
|
||||
by default; this allows faster conversion of a zone file from one
|
||||
format to another. :gl:`#4364`
|
||||
|
||||
Zone checks can be performed by running :iscman:`named-checkzone`
|
||||
separately, or the previous default behavior can be restored by using:
|
||||
|
||||
::
|
||||
|
||||
named-compilezone -i full -k fail -n fail -r warn -m warn -M warn -S warn -T warn -W warn -C check-svcb:fail
|
||||
|
||||
Bug Fixes
|
||||
~~~~~~~~~
|
||||
|
||||
- The counters exported via the statistics channel were changed back to
|
||||
64-bit signed values; they were being inadvertently truncated to
|
||||
unsigned 32-bit values since BIND 9.15.0. :gl:`#4467`
|
||||
|
||||
Known Issues
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- There are no new known issues with this release. See :ref:`above
|
||||
<relnotes_known_issues>` for a list of all known issues affecting this
|
||||
BIND 9 branch.
|
||||
|
|
@ -145,12 +145,4 @@ typedef struct {
|
|||
bool exiting;
|
||||
} db_nodelock_t;
|
||||
|
||||
/*%
|
||||
* Prune context
|
||||
*/
|
||||
typedef struct {
|
||||
dns_db_t *db;
|
||||
dns_dbnode_t *node;
|
||||
} db_prune_t;
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
|
|
|||
|
|
@ -164,7 +164,8 @@ computeid(dst_key_t *key);
|
|||
static isc_result_t
|
||||
frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
|
||||
unsigned int protocol, dns_rdataclass_t rdclass,
|
||||
isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp);
|
||||
isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
|
||||
dst_key_t **keyp);
|
||||
|
||||
static isc_result_t
|
||||
algorithm_status(unsigned int alg);
|
||||
|
|
@ -754,6 +755,13 @@ dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
|
|||
isc_result_t
|
||||
dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass,
|
||||
isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) {
|
||||
return (dst_key_fromdns_ex(name, rdclass, source, mctx, false, keyp));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dst_key_fromdns_ex(const dns_name_t *name, dns_rdataclass_t rdclass,
|
||||
isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
|
||||
dst_key_t **keyp) {
|
||||
uint8_t alg, proto;
|
||||
uint32_t flags, extflags;
|
||||
dst_key_t *key = NULL;
|
||||
|
|
@ -784,7 +792,7 @@ dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass,
|
|||
}
|
||||
|
||||
result = frombuffer(name, alg, flags, proto, rdclass, source, mctx,
|
||||
&key);
|
||||
no_rdata, &key);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
|
|
@ -805,7 +813,7 @@ dst_key_frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
|
|||
REQUIRE(dst_initialized);
|
||||
|
||||
result = frombuffer(name, alg, flags, protocol, rdclass, source, mctx,
|
||||
&key);
|
||||
false, &key);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
|
|
@ -2313,7 +2321,8 @@ computeid(dst_key_t *key) {
|
|||
static isc_result_t
|
||||
frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
|
||||
unsigned int protocol, dns_rdataclass_t rdclass,
|
||||
isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) {
|
||||
isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
|
||||
dst_key_t **keyp) {
|
||||
dst_key_t *key;
|
||||
isc_result_t ret;
|
||||
|
||||
|
|
@ -2335,10 +2344,12 @@ frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
|
|||
return (DST_R_UNSUPPORTEDALG);
|
||||
}
|
||||
|
||||
ret = key->func->fromdns(key, source);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
dst_key_free(&key);
|
||||
return (ret);
|
||||
if (!no_rdata) {
|
||||
ret = key->func->fromdns(key, source);
|
||||
if (ret != ISC_R_SUCCESS) {
|
||||
dst_key_free(&key);
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -860,27 +860,6 @@ dns_message_findtype(const dns_name_t *name, dns_rdatatype_t type,
|
|||
*\li #ISC_R_NOTFOUND -- the desired type does not exist.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_message_find(const dns_name_t *name, dns_rdataclass_t rdclass,
|
||||
dns_rdatatype_t type, dns_rdatatype_t covers,
|
||||
dns_rdataset_t **rdataset);
|
||||
/*%<
|
||||
* Search the name for the specified rdclass and type. If it is found,
|
||||
* *rdataset is filled in with a pointer to that rdataset.
|
||||
*
|
||||
* Requires:
|
||||
*\li if '**rdataset' is non-NULL, *rdataset needs to be NULL.
|
||||
*
|
||||
*\li 'type' be a valid type, and NOT dns_rdatatype_any.
|
||||
*
|
||||
*\li If 'type' is dns_rdatatype_rrsig, 'covers' must be a valid type.
|
||||
* Otherwise it should be 0.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_R_SUCCESS -- all is well.
|
||||
*\li #ISC_R_NOTFOUND -- the desired type does not exist.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_message_addname(dns_message_t *msg, dns_name_t *name,
|
||||
dns_section_t section);
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/hashmap.h>
|
||||
#include <isc/lang.h>
|
||||
#include <isc/magic.h>
|
||||
#include <isc/region.h> /* Required for storage size of dns_label_t. */
|
||||
|
|
@ -119,6 +120,7 @@ struct dns_name {
|
|||
isc_buffer_t *buffer;
|
||||
ISC_LINK(dns_name_t) link;
|
||||
ISC_LIST(dns_rdataset_t) list;
|
||||
isc_hashmap_t *hashmap;
|
||||
};
|
||||
|
||||
#define DNS_NAME_MAGIC ISC_MAGIC('D', 'N', 'S', 'n')
|
||||
|
|
|
|||
|
|
@ -112,6 +112,12 @@ struct dns_rbtnode {
|
|||
*/
|
||||
ISC_LINK(dns_rbtnode_t) deadlink;
|
||||
|
||||
/*%
|
||||
* This linked list is used to store nodes from which tree pruning can
|
||||
* be started.
|
||||
*/
|
||||
ISC_LINK(dns_rbtnode_t) prunelink;
|
||||
|
||||
/*@{*/
|
||||
/*!
|
||||
* These values are used in the RBT DB implementation. The appropriate
|
||||
|
|
|
|||
|
|
@ -578,6 +578,14 @@ dns_resolver_printbadcache(dns_resolver_t *resolver, FILE *fp);
|
|||
* \li resolver to be valid.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_resolver_setmaxvalidations(dns_resolver_t *resolver, uint32_t max);
|
||||
void
|
||||
dns_resolver_setmaxvalidationfails(dns_resolver_t *resolver, uint32_t max);
|
||||
/*%
|
||||
* Set maximum numbers of validations and maximum validation failures per fetch.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_resolver_setmaxdepth(dns_resolver_t *resolver, unsigned int maxdepth);
|
||||
unsigned int
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@
|
|||
#include <isc/refcount.h>
|
||||
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/rdata.h>
|
||||
#include <dns/rdataset.h>
|
||||
#include <dns/rdatastruct.h> /* for dns_rdata_rrsig_t */
|
||||
#include <dns/types.h>
|
||||
|
|
@ -144,6 +145,13 @@ struct dns_validator {
|
|||
unsigned int authcount;
|
||||
unsigned int authfail;
|
||||
isc_stdtime_t start;
|
||||
|
||||
bool digest_sha1;
|
||||
bool supported_algorithm;
|
||||
dns_rdata_t rdata;
|
||||
bool resume;
|
||||
uint32_t *nvalidations;
|
||||
uint32_t *nfails;
|
||||
};
|
||||
|
||||
/*%
|
||||
|
|
@ -161,6 +169,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
|
|||
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
|
||||
dns_message_t *message, unsigned int options,
|
||||
isc_loop_t *loop, isc_job_cb cb, void *arg,
|
||||
uint32_t *nvalidations, uint32_t *nfails,
|
||||
dns_validator_t **validatorp);
|
||||
/*%<
|
||||
* Start a DNSSEC validation.
|
||||
|
|
|
|||
|
|
@ -482,6 +482,10 @@ dst_key_tofile(const dst_key_t *key, int type, const char *directory);
|
|||
*/
|
||||
|
||||
isc_result_t
|
||||
dst_key_fromdns_ex(const dns_name_t *name, dns_rdataclass_t rdclass,
|
||||
isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata,
|
||||
dst_key_t **keyp);
|
||||
isc_result_t
|
||||
dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass,
|
||||
isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp);
|
||||
/*%<
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/hash.h>
|
||||
#include <isc/hashmap.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/string.h>
|
||||
|
|
@ -779,6 +781,11 @@ ISC_REFCOUNT_TRACE_IMPL(dns_message, dns__message_destroy);
|
|||
ISC_REFCOUNT_IMPL(dns_message, dns__message_destroy);
|
||||
#endif
|
||||
|
||||
static bool
|
||||
name_match(void *node, const void *key) {
|
||||
return (dns_name_equal(node, key));
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
findname(dns_name_t **foundname, const dns_name_t *target,
|
||||
dns_namelist_t *section) {
|
||||
|
|
@ -796,26 +803,25 @@ findname(dns_name_t **foundname, const dns_name_t *target,
|
|||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_message_find(const dns_name_t *name, dns_rdataclass_t rdclass,
|
||||
dns_rdatatype_t type, dns_rdatatype_t covers,
|
||||
dns_rdataset_t **rdatasetp) {
|
||||
dns_rdataset_t *rds = NULL;
|
||||
static uint32_t
|
||||
rds_hash(dns_rdataset_t *rds) {
|
||||
isc_hash32_t state;
|
||||
|
||||
REQUIRE(name != NULL);
|
||||
REQUIRE(rdatasetp == NULL || *rdatasetp == NULL);
|
||||
isc_hash32_init(&state);
|
||||
isc_hash32_hash(&state, &rds->rdclass, sizeof(rds->rdclass), true);
|
||||
isc_hash32_hash(&state, &rds->type, sizeof(rds->type), true);
|
||||
isc_hash32_hash(&state, &rds->covers, sizeof(rds->covers), true);
|
||||
|
||||
ISC_LIST_FOREACH_REV (name->list, rds, link) {
|
||||
if (rds->rdclass == rdclass && rds->type == type &&
|
||||
rds->covers == covers)
|
||||
{
|
||||
SET_IF_NOT_NULL(rdatasetp, rds);
|
||||
return (isc_hash32_finalize(&state));
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
}
|
||||
static bool
|
||||
rds_match(void *node, const void *key0) {
|
||||
const dns_rdataset_t *rds = node;
|
||||
const dns_rdataset_t *key = key0;
|
||||
|
||||
return (ISC_R_NOTFOUND);
|
||||
return (rds->rdclass == key->rdclass && rds->type == key->type &&
|
||||
rds->covers == key->covers);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
|
|
@ -939,22 +945,38 @@ getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
static void
|
||||
cleanup_name_hashmaps(dns_namelist_t *section) {
|
||||
dns_name_t *name = NULL;
|
||||
ISC_LIST_FOREACH (*section, name, link) {
|
||||
if (name->hashmap != NULL) {
|
||||
isc_hashmap_destroy(&name->hashmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
||||
unsigned int options) {
|
||||
isc_region_t r;
|
||||
unsigned int count;
|
||||
dns_name_t *name = NULL;
|
||||
dns_name_t *name2 = NULL;
|
||||
dns_name_t *found_name = NULL;
|
||||
dns_rdataset_t *rdataset = NULL;
|
||||
dns_rdatalist_t *rdatalist = NULL;
|
||||
isc_result_t result;
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
dns_rdatatype_t rdtype;
|
||||
dns_rdataclass_t rdclass;
|
||||
dns_namelist_t *section = &msg->sections[DNS_SECTION_QUESTION];
|
||||
bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
|
||||
bool seen_problem = false;
|
||||
bool free_name = false;
|
||||
bool free_hashmaps = false;
|
||||
isc_hashmap_t *name_map = NULL;
|
||||
|
||||
if (msg->counts[DNS_SECTION_QUESTION] > 1) {
|
||||
isc_hashmap_create(msg->mctx, 1, &name_map);
|
||||
}
|
||||
|
||||
for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
|
||||
name = NULL;
|
||||
|
|
@ -972,13 +994,21 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
/* If there is only one QNAME, skip the duplicity checks */
|
||||
if (name_map == NULL) {
|
||||
result = ISC_R_SUCCESS;
|
||||
goto skip_name_check;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run through the section, looking to see if this name
|
||||
* is already there. If it is found, put back the allocated
|
||||
* name since we no longer need it, and set our name pointer
|
||||
* to point to the name we found.
|
||||
*/
|
||||
result = findname(&name2, name, section);
|
||||
result = isc_hashmap_add(name_map, dns_name_hash(name),
|
||||
name_match, name, name,
|
||||
(void **)&found_name);
|
||||
|
||||
/*
|
||||
* If it is the first name in the section, accept it.
|
||||
|
|
@ -990,19 +1020,25 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
|||
* this should be legal or not. In either case we no longer
|
||||
* need this name pointer.
|
||||
*/
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
skip_name_check:
|
||||
switch (result) {
|
||||
case ISC_R_SUCCESS:
|
||||
if (!ISC_LIST_EMPTY(*section)) {
|
||||
DO_ERROR(DNS_R_FORMERR);
|
||||
}
|
||||
ISC_LIST_APPEND(*section, name, link);
|
||||
free_name = false;
|
||||
} else {
|
||||
break;
|
||||
case ISC_R_EXISTS:
|
||||
dns_message_puttempname(msg, &name);
|
||||
name = name2;
|
||||
name2 = NULL;
|
||||
free_name = false;
|
||||
name = found_name;
|
||||
found_name = NULL;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
free_name = false;
|
||||
|
||||
/*
|
||||
* Get type and class.
|
||||
*/
|
||||
|
|
@ -1032,53 +1068,86 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
|||
msg->tkey = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Can't ask the same question twice.
|
||||
*/
|
||||
result = dns_message_find(name, rdclass, rdtype, 0, NULL);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
DO_ERROR(DNS_R_FORMERR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new rdatalist.
|
||||
*/
|
||||
rdatalist = newrdatalist(msg);
|
||||
if (rdatalist == NULL) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto cleanup;
|
||||
}
|
||||
rdataset = isc_mempool_get(msg->rdspool);
|
||||
rdatalist->type = rdtype;
|
||||
rdatalist->rdclass = rdclass;
|
||||
rdatalist->covers = 0;
|
||||
|
||||
/*
|
||||
* Convert rdatalist to rdataset, and attach the latter to
|
||||
* the name.
|
||||
*/
|
||||
rdatalist->type = rdtype;
|
||||
rdatalist->rdclass = rdclass;
|
||||
|
||||
dns_rdataset_init(rdataset);
|
||||
dns_message_gettemprdataset(msg, &rdataset);
|
||||
dns_rdatalist_tordataset(rdatalist, rdataset);
|
||||
|
||||
rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
|
||||
|
||||
/*
|
||||
* Skip the duplicity check for first rdataset
|
||||
*/
|
||||
if (ISC_LIST_EMPTY(name->list)) {
|
||||
result = ISC_R_SUCCESS;
|
||||
goto skip_rds_check;
|
||||
}
|
||||
|
||||
/*
|
||||
* Can't ask the same question twice.
|
||||
*/
|
||||
if (name->hashmap == NULL) {
|
||||
isc_hashmap_create(msg->mctx, 1, &name->hashmap);
|
||||
free_hashmaps = true;
|
||||
|
||||
INSIST(ISC_LIST_HEAD(name->list) ==
|
||||
ISC_LIST_TAIL(name->list));
|
||||
|
||||
dns_rdataset_t *old_rdataset =
|
||||
ISC_LIST_HEAD(name->list);
|
||||
|
||||
result = isc_hashmap_add(
|
||||
name->hashmap, rds_hash(old_rdataset),
|
||||
rds_match, old_rdataset, old_rdataset, NULL);
|
||||
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
}
|
||||
result = isc_hashmap_add(name->hashmap, rds_hash(rdataset),
|
||||
rds_match, rdataset, rdataset, NULL);
|
||||
if (result == ISC_R_EXISTS) {
|
||||
DO_ERROR(DNS_R_FORMERR);
|
||||
}
|
||||
|
||||
skip_rds_check:
|
||||
ISC_LIST_APPEND(name->list, rdataset, link);
|
||||
|
||||
rdataset = NULL;
|
||||
}
|
||||
|
||||
if (seen_problem) {
|
||||
return (DNS_R_RECOVERABLE);
|
||||
result = DNS_R_RECOVERABLE;
|
||||
}
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
cleanup:
|
||||
if (rdataset != NULL) {
|
||||
if (dns_rdataset_isassociated(rdataset)) {
|
||||
dns_rdataset_disassociate(rdataset);
|
||||
}
|
||||
dns_message_puttemprdataset(msg, &rdataset);
|
||||
}
|
||||
|
||||
if (free_name) {
|
||||
dns_message_puttempname(msg, &name);
|
||||
}
|
||||
|
||||
if (free_hashmaps) {
|
||||
cleanup_name_hashmaps(section);
|
||||
}
|
||||
|
||||
if (name_map != NULL) {
|
||||
isc_hashmap_destroy(&name_map);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
|
@ -1105,7 +1174,6 @@ auth_signed(dns_namelist_t *section) {
|
|||
ISC_LIST_FOREACH (*section, name, link) {
|
||||
int auth_dnssec = 0, auth_rrsig = 0;
|
||||
dns_rdataset_t *rds = NULL;
|
||||
|
||||
ISC_LIST_FOREACH (name->list, rds, link) {
|
||||
switch (rds->type) {
|
||||
case dns_rdatatype_ds:
|
||||
|
|
@ -1152,19 +1220,26 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
|||
isc_region_t r;
|
||||
unsigned int count, rdatalen;
|
||||
dns_name_t *name = NULL;
|
||||
dns_name_t *name2 = NULL;
|
||||
dns_name_t *found_name = NULL;
|
||||
dns_rdataset_t *rdataset = NULL;
|
||||
dns_rdataset_t *found_rdataset = NULL;
|
||||
dns_rdatalist_t *rdatalist = NULL;
|
||||
isc_result_t result;
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
dns_rdatatype_t rdtype, covers;
|
||||
dns_rdataclass_t rdclass;
|
||||
dns_rdata_t *rdata = NULL;
|
||||
dns_ttl_t ttl;
|
||||
dns_namelist_t *section = &msg->sections[sectionid];
|
||||
bool free_name = false, free_rdataset = false, seen_problem = false;
|
||||
bool free_name = false, seen_problem = false;
|
||||
bool free_hashmaps = false;
|
||||
bool preserve_order = ((options & DNS_MESSAGEPARSE_PRESERVEORDER) != 0);
|
||||
bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
|
||||
bool isedns, issigzero, istsig;
|
||||
isc_hashmap_t *name_map = NULL;
|
||||
|
||||
if (msg->counts[sectionid] > 1) {
|
||||
isc_hashmap_create(msg->mctx, 1, &name_map);
|
||||
}
|
||||
|
||||
for (count = 0; count < msg->counts[sectionid]; count++) {
|
||||
int recstart = source->current;
|
||||
|
|
@ -1172,10 +1247,10 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
|||
|
||||
skip_name_search = false;
|
||||
skip_type_search = false;
|
||||
free_rdataset = false;
|
||||
isedns = false;
|
||||
issigzero = false;
|
||||
istsig = false;
|
||||
found_rdataset = NULL;
|
||||
|
||||
name = NULL;
|
||||
dns_message_gettempname(msg, &name);
|
||||
|
|
@ -1212,8 +1287,8 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
|||
if (msg->rdclass_set == 0 &&
|
||||
rdtype != dns_rdatatype_opt && /* class is UDP SIZE */
|
||||
rdtype != dns_rdatatype_tsig && /* class is ANY */
|
||||
rdtype != dns_rdatatype_tkey)
|
||||
{ /* class is undefined */
|
||||
rdtype != dns_rdatatype_tkey) /* class is undefined */
|
||||
{
|
||||
msg->rdclass = rdclass;
|
||||
msg->rdclass_set = 1;
|
||||
}
|
||||
|
|
@ -1320,10 +1395,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
|||
* Then put the meta-class back into the finished rdata.
|
||||
*/
|
||||
rdata = newrdata(msg);
|
||||
if (rdata == NULL) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto cleanup;
|
||||
}
|
||||
if (msg->opcode == dns_opcode_update &&
|
||||
update(sectionid, rdclass))
|
||||
{
|
||||
|
|
@ -1412,34 +1483,63 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
|||
free_name = false;
|
||||
}
|
||||
} else {
|
||||
if (name_map == NULL) {
|
||||
result = ISC_R_SUCCESS;
|
||||
goto skip_name_check;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run through the section, looking to see if this name
|
||||
* is already there. If it is found, put back the
|
||||
* allocated name since we no longer need it, and set
|
||||
* our name pointer to point to the name we found.
|
||||
*/
|
||||
result = findname(&name2, name, section);
|
||||
result = isc_hashmap_add(name_map, dns_name_hash(name),
|
||||
name_match, name, name,
|
||||
(void **)&found_name);
|
||||
|
||||
/*
|
||||
* If it is a new name, append to the section.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
dns_message_puttempname(msg, &name);
|
||||
name = name2;
|
||||
} else {
|
||||
skip_name_check:
|
||||
switch (result) {
|
||||
case ISC_R_SUCCESS:
|
||||
ISC_LIST_APPEND(*section, name, link);
|
||||
break;
|
||||
case ISC_R_EXISTS:
|
||||
dns_message_puttempname(msg, &name);
|
||||
name = found_name;
|
||||
found_name = NULL;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
free_name = false;
|
||||
}
|
||||
|
||||
rdatalist = newrdatalist(msg);
|
||||
rdatalist->type = rdtype;
|
||||
rdatalist->covers = covers;
|
||||
rdatalist->rdclass = rdclass;
|
||||
rdatalist->ttl = ttl;
|
||||
|
||||
dns_message_gettemprdataset(msg, &rdataset);
|
||||
dns_rdatalist_tordataset(rdatalist, rdataset);
|
||||
dns_rdataset_setownercase(rdataset, name);
|
||||
rdatalist = NULL;
|
||||
|
||||
/*
|
||||
* Search name for the particular type and class.
|
||||
* Skip this stage if in update mode or this is a meta-type.
|
||||
*/
|
||||
if (preserve_order || msg->opcode == dns_opcode_update ||
|
||||
skip_type_search)
|
||||
if (isedns || istsig || issigzero) {
|
||||
/* Skip adding the rdataset to the tables */
|
||||
} else if (preserve_order || msg->opcode == dns_opcode_update ||
|
||||
skip_type_search)
|
||||
{
|
||||
result = ISC_R_NOTFOUND;
|
||||
result = ISC_R_SUCCESS;
|
||||
|
||||
ISC_LIST_APPEND(name->list, rdataset, link);
|
||||
} else {
|
||||
/*
|
||||
* If this is a type that can only occur in
|
||||
|
|
@ -1449,57 +1549,74 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
|||
DO_ERROR(DNS_R_FORMERR);
|
||||
}
|
||||
|
||||
rdataset = NULL;
|
||||
result = dns_message_find(name, rdclass, rdtype, covers,
|
||||
&rdataset);
|
||||
}
|
||||
if (ISC_LIST_EMPTY(name->list)) {
|
||||
result = ISC_R_SUCCESS;
|
||||
goto skip_rds_check;
|
||||
}
|
||||
|
||||
if (name->hashmap == NULL) {
|
||||
isc_hashmap_create(msg->mctx, 1,
|
||||
&name->hashmap);
|
||||
free_hashmaps = true;
|
||||
|
||||
INSIST(ISC_LIST_HEAD(name->list) ==
|
||||
ISC_LIST_TAIL(name->list));
|
||||
|
||||
dns_rdataset_t *old_rdataset =
|
||||
ISC_LIST_HEAD(name->list);
|
||||
|
||||
result = isc_hashmap_add(
|
||||
name->hashmap, rds_hash(old_rdataset),
|
||||
rds_match, old_rdataset, old_rdataset,
|
||||
NULL);
|
||||
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
result = isc_hashmap_add(
|
||||
name->hashmap, rds_hash(rdataset), rds_match,
|
||||
rdataset, rdataset, (void **)&found_rdataset);
|
||||
|
||||
/*
|
||||
* If we found an rdataset that matches, we need to
|
||||
* append this rdata to that set. If we did not, we
|
||||
* need to create a new rdatalist, store the important
|
||||
* bits there, convert it to an rdataset, and link the
|
||||
* latter to the name. Yuck. When appending, make
|
||||
* certain that the type isn't a singleton type, such as
|
||||
* SOA or CNAME.
|
||||
*
|
||||
* Note that this check will be bypassed when preserving
|
||||
* order, the opcode is an update, or the type search is
|
||||
* skipped.
|
||||
*/
|
||||
skip_rds_check:
|
||||
switch (result) {
|
||||
case ISC_R_EXISTS:
|
||||
/* Free the rdataset we used as the key */
|
||||
dns__message_putassociatedrdataset(msg,
|
||||
&rdataset);
|
||||
result = ISC_R_SUCCESS;
|
||||
rdataset = found_rdataset;
|
||||
|
||||
if (!dns_rdatatype_issingleton(rdtype)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we found an rdataset that matches, we need to
|
||||
* append this rdata to that set. If we did not, we need
|
||||
* to create a new rdatalist, store the important bits there,
|
||||
* convert it to an rdataset, and link the latter to the name.
|
||||
* Yuck. When appending, make certain that the type isn't
|
||||
* a singleton type, such as SOA or CNAME.
|
||||
*
|
||||
* Note that this check will be bypassed when preserving order,
|
||||
* the opcode is an update, or the type search is skipped.
|
||||
*/
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
if (dns_rdatatype_issingleton(rdtype)) {
|
||||
dns_rdata_t *first;
|
||||
dns_rdatalist_fromrdataset(rdataset,
|
||||
&rdatalist);
|
||||
first = ISC_LIST_HEAD(rdatalist->rdata);
|
||||
dns_rdata_t *first =
|
||||
ISC_LIST_HEAD(rdatalist->rdata);
|
||||
INSIST(first != NULL);
|
||||
if (dns_rdata_compare(rdata, first) != 0) {
|
||||
DO_ERROR(DNS_R_FORMERR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
rdataset = isc_mempool_get(msg->rdspool);
|
||||
free_rdataset = true;
|
||||
|
||||
rdatalist = newrdatalist(msg);
|
||||
if (rdatalist == NULL) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rdatalist->type = rdtype;
|
||||
rdatalist->covers = covers;
|
||||
rdatalist->rdclass = rdclass;
|
||||
rdatalist->ttl = ttl;
|
||||
|
||||
dns_rdataset_init(rdataset);
|
||||
dns_rdatalist_tordataset(rdatalist, rdataset);
|
||||
dns_rdataset_setownercase(rdataset, name);
|
||||
|
||||
if (!isedns && !istsig && !issigzero) {
|
||||
break;
|
||||
case ISC_R_SUCCESS:
|
||||
ISC_LIST_APPEND(name->list, rdataset, link);
|
||||
free_rdataset = false;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1534,8 +1651,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
|||
dns_rcode_t ercode;
|
||||
|
||||
msg->opt = rdataset;
|
||||
rdataset = NULL;
|
||||
free_rdataset = false;
|
||||
ercode = (dns_rcode_t)((msg->opt->ttl &
|
||||
DNS_MESSAGE_EDNSRCODE_MASK) >>
|
||||
20);
|
||||
|
|
@ -1546,8 +1661,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
|||
msg->sig0 = rdataset;
|
||||
msg->sig0name = name;
|
||||
msg->sigstart = recstart;
|
||||
rdataset = NULL;
|
||||
free_rdataset = false;
|
||||
free_name = false;
|
||||
} else if (istsig) {
|
||||
msg->tsig = rdataset;
|
||||
|
|
@ -1557,23 +1670,17 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
|||
* Windows doesn't like TSIG names to be compressed.
|
||||
*/
|
||||
msg->tsigname->attributes.nocompress = true;
|
||||
rdataset = NULL;
|
||||
free_rdataset = false;
|
||||
free_name = false;
|
||||
}
|
||||
rdataset = NULL;
|
||||
|
||||
if (seen_problem) {
|
||||
if (free_name) {
|
||||
dns_message_puttempname(msg, &name);
|
||||
}
|
||||
if (free_rdataset) {
|
||||
dns__message_putassociatedrdataset(msg,
|
||||
&rdataset);
|
||||
}
|
||||
free_name = free_rdataset = false;
|
||||
free_name = false;
|
||||
}
|
||||
INSIST(!free_name);
|
||||
INSIST(!free_rdataset);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1591,16 +1698,23 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t dctx,
|
|||
}
|
||||
|
||||
if (seen_problem) {
|
||||
return (DNS_R_RECOVERABLE);
|
||||
result = DNS_R_RECOVERABLE;
|
||||
}
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
cleanup:
|
||||
if (rdataset != NULL && rdataset != found_rdataset) {
|
||||
dns__message_putassociatedrdataset(msg, &rdataset);
|
||||
}
|
||||
if (free_name) {
|
||||
dns_message_puttempname(msg, &name);
|
||||
}
|
||||
if (free_rdataset) {
|
||||
dns__message_putassociatedrdataset(msg, &rdataset);
|
||||
|
||||
if (free_hashmaps) {
|
||||
cleanup_name_hashmaps(section);
|
||||
}
|
||||
|
||||
if (name_map != NULL) {
|
||||
isc_hashmap_destroy(&name_map);
|
||||
}
|
||||
|
||||
return (result);
|
||||
|
|
@ -1661,6 +1775,7 @@ dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
|
|||
dctx = DNS_DECOMPRESS_ALWAYS;
|
||||
|
||||
ret = getquestions(source, msg, dctx, options);
|
||||
|
||||
if (ret == ISC_R_UNEXPECTEDEND && ignore_tc) {
|
||||
goto truncated;
|
||||
}
|
||||
|
|
@ -2349,15 +2464,13 @@ dns_message_renderreset(dns_message_t *msg) {
|
|||
dns_message_puttempname(msg, &msg->tsigname);
|
||||
}
|
||||
if (msg->tsig != NULL) {
|
||||
dns_rdataset_disassociate(msg->tsig);
|
||||
dns_message_puttemprdataset(msg, &msg->tsig);
|
||||
dns__message_putassociatedrdataset(msg, &msg->tsig);
|
||||
}
|
||||
if (msg->sig0name != NULL) {
|
||||
dns_message_puttempname(msg, &msg->sig0name);
|
||||
}
|
||||
if (msg->sig0 != NULL) {
|
||||
dns_rdataset_disassociate(msg->sig0);
|
||||
dns_message_puttemprdataset(msg, &msg->sig0);
|
||||
dns__message_putassociatedrdataset(msg, &msg->sig0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2406,7 +2519,7 @@ dns_message_findname(dns_message_t *msg, dns_section_t section,
|
|||
const dns_name_t *target, dns_rdatatype_t type,
|
||||
dns_rdatatype_t covers, dns_name_t **name,
|
||||
dns_rdataset_t **rdataset) {
|
||||
dns_name_t *foundname;
|
||||
dns_name_t *foundname = NULL;
|
||||
isc_result_t result;
|
||||
|
||||
/*
|
||||
|
|
@ -2524,6 +2637,10 @@ dns_message_puttempname(dns_message_t *msg, dns_name_t **itemp) {
|
|||
REQUIRE(!ISC_LINK_LINKED(item, link));
|
||||
REQUIRE(ISC_LIST_HEAD(item->list) == NULL);
|
||||
|
||||
if (item->hashmap != NULL) {
|
||||
isc_hashmap_destroy(&item->hashmap);
|
||||
}
|
||||
|
||||
/*
|
||||
* we need to check this in case dns_name_dup() was used.
|
||||
*/
|
||||
|
|
@ -2551,8 +2668,7 @@ dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
|
|||
static void
|
||||
dns__message_putassociatedrdataset(dns_message_t *msg, dns_rdataset_t **item) {
|
||||
dns_rdataset_disassociate(*item);
|
||||
isc_mempool_put(msg->rdspool, *item);
|
||||
*item = NULL;
|
||||
dns_message_puttemprdataset(msg, item);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2735,8 +2851,7 @@ dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
|
|||
return (ISC_R_SUCCESS);
|
||||
|
||||
cleanup:
|
||||
dns_rdataset_disassociate(opt);
|
||||
dns_message_puttemprdataset(msg, &opt);
|
||||
dns__message_putassociatedrdataset(msg, &opt);
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1406,6 +1406,7 @@ rbtnode_new(isc_mem_t *mctx, const dns_name_t *name) {
|
|||
};
|
||||
|
||||
ISC_LINK_INIT(node, deadlink);
|
||||
ISC_LINK_INIT(node, prunelink);
|
||||
|
||||
isc_refcount_init(&node->references, 0);
|
||||
|
||||
|
|
|
|||
134
lib/dns/rbtdb.c
134
lib/dns/rbtdb.c
|
|
@ -464,6 +464,7 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log) {
|
|||
unsigned int i;
|
||||
isc_result_t result;
|
||||
char buf[DNS_NAME_FORMATSIZE];
|
||||
dns_rbtnode_t *node = NULL;
|
||||
dns_rbt_t **treep = NULL;
|
||||
isc_time_t start;
|
||||
|
||||
|
|
@ -486,8 +487,6 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log) {
|
|||
* the overhead of unlinking all nodes here should be negligible.
|
||||
*/
|
||||
for (i = 0; i < rbtdb->node_lock_count; i++) {
|
||||
dns_rbtnode_t *node = NULL;
|
||||
|
||||
node = ISC_LIST_HEAD(rbtdb->deadnodes[i]);
|
||||
while (node != NULL) {
|
||||
ISC_LIST_UNLINK(rbtdb->deadnodes[i], node, deadlink);
|
||||
|
|
@ -495,6 +494,12 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log) {
|
|||
}
|
||||
}
|
||||
|
||||
node = ISC_LIST_HEAD(rbtdb->prunenodes);
|
||||
while (node != NULL) {
|
||||
ISC_LIST_UNLINK(rbtdb->prunenodes, node, prunelink);
|
||||
node = ISC_LIST_HEAD(rbtdb->prunenodes);
|
||||
}
|
||||
|
||||
rbtdb->quantum = (rbtdb->loop != NULL) ? 100 : 0;
|
||||
|
||||
for (;;) {
|
||||
|
|
@ -1173,16 +1178,26 @@ is_leaf(dns_rbtnode_t *node) {
|
|||
node->left == NULL && node->right == NULL);
|
||||
}
|
||||
|
||||
/*%
|
||||
* The tree lock must be held when this function is called as it reads and
|
||||
* updates rbtdb->prunenodes.
|
||||
*/
|
||||
static void
|
||||
send_to_prune_tree(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
|
||||
isc_rwlocktype_t locktype DNS__DB_FLARG) {
|
||||
db_prune_t *prune = isc_mem_get(rbtdb->common.mctx, sizeof(*prune));
|
||||
*prune = (db_prune_t){ .node = node };
|
||||
bool pruning_queued = (ISC_LIST_HEAD(rbtdb->prunenodes) != NULL);
|
||||
|
||||
INSIST(locktype == isc_rwlocktype_write);
|
||||
|
||||
dns_db_attach((dns_db_t *)rbtdb, &prune->db);
|
||||
dns__rbtdb_newref(rbtdb, node, locktype DNS__DB_FLARG_PASS);
|
||||
INSIST(!ISC_LINK_LINKED(node, prunelink));
|
||||
ISC_LIST_APPEND(rbtdb->prunenodes, node, prunelink);
|
||||
|
||||
isc_async_run(rbtdb->loop, prune_tree, prune);
|
||||
if (!pruning_queued) {
|
||||
dns_db_t *db = NULL;
|
||||
dns_db_attach((dns_db_t *)rbtdb, &db);
|
||||
isc_async_run(rbtdb->loop, prune_tree, db);
|
||||
}
|
||||
}
|
||||
|
||||
/*%
|
||||
|
|
@ -1480,64 +1495,83 @@ restore_locks:
|
|||
}
|
||||
|
||||
/*
|
||||
* Prune the tree by recursively cleaning-up single leaves. In the worst
|
||||
* case, the number of iteration is the number of tree levels, which is at
|
||||
* most the maximum number of domain name labels, i.e, 127. In practice, this
|
||||
* should be much smaller (only a few times), and even the worst case would be
|
||||
* acceptable for a single event.
|
||||
* Prune the tree by recursively cleaning up single leaves. Go through all
|
||||
* nodes stored in the rbtdb->prunenodes list; for each of them, in the worst
|
||||
* case, it will be necessary to traverse a number of tree levels equal to the
|
||||
* maximum legal number of domain name labels (127); in practice, the number of
|
||||
* tree levels to traverse will virtually always be much smaller (a few levels
|
||||
* at most). While holding the tree lock throughout this entire operation is
|
||||
* less than ideal, so is splitting the latter up by queueing a separate
|
||||
* prune_tree() run for each node to start pruning from (as queueing requires
|
||||
* allocating memory and can therefore potentially be exploited to exhaust
|
||||
* available memory). Also note that actually freeing up the memory used by
|
||||
* RBTDB nodes (which is what this function does) is essential to keeping cache
|
||||
* memory use in check, so since the tree lock needs to be acquired anyway,
|
||||
* freeing as many nodes as possible before the tree lock gets released is
|
||||
* prudent.
|
||||
*/
|
||||
static void
|
||||
prune_tree(void *arg) {
|
||||
db_prune_t *prune = (db_prune_t *)arg;
|
||||
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)prune->db;
|
||||
dns_rbtnode_t *node = prune->node;
|
||||
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)arg;
|
||||
dns_rbtnode_t *node = NULL;
|
||||
dns_rbtnode_t *parent = NULL;
|
||||
unsigned int locknum;
|
||||
isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
|
||||
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
|
||||
|
||||
isc_mem_put(rbtdb->common.mctx, prune, sizeof(*prune));
|
||||
|
||||
TREE_WRLOCK(&rbtdb->tree_lock, &tlocktype);
|
||||
locknum = node->locknum;
|
||||
NODE_WRLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype);
|
||||
do {
|
||||
parent = node->parent;
|
||||
dns__rbtdb_decref(rbtdb, node, 0, &nlocktype, &tlocktype, true,
|
||||
true DNS__DB_FILELINE);
|
||||
|
||||
if (parent != NULL && parent->down == NULL) {
|
||||
/*
|
||||
* node was the only down child of the parent and has
|
||||
* just been removed. We'll then need to examine the
|
||||
* parent. Keep the lock if possible; otherwise,
|
||||
* release the old lock and acquire one for the parent.
|
||||
*/
|
||||
if (parent->locknum != locknum) {
|
||||
NODE_UNLOCK(&rbtdb->node_locks[locknum].lock,
|
||||
&nlocktype);
|
||||
locknum = parent->locknum;
|
||||
NODE_WRLOCK(&rbtdb->node_locks[locknum].lock,
|
||||
&nlocktype);
|
||||
while ((node = ISC_LIST_HEAD(rbtdb->prunenodes)) != NULL) {
|
||||
locknum = node->locknum;
|
||||
NODE_WRLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype);
|
||||
do {
|
||||
if (ISC_LINK_LINKED(node, prunelink)) {
|
||||
ISC_LIST_UNLINK(rbtdb->prunenodes, node,
|
||||
prunelink);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to gain a reference to the node before
|
||||
* decrementing it in the next iteration.
|
||||
*/
|
||||
if (ISC_LINK_LINKED(parent, deadlink)) {
|
||||
ISC_LIST_UNLINK(rbtdb->deadnodes[locknum],
|
||||
parent = node->parent;
|
||||
dns__rbtdb_decref(rbtdb, node, 0, &nlocktype,
|
||||
&tlocktype, true,
|
||||
true DNS__DB_FILELINE);
|
||||
|
||||
if (parent != NULL && parent->down == NULL) {
|
||||
/*
|
||||
* node was the only down child of the parent
|
||||
* and has just been removed. We'll then need
|
||||
* to examine the parent. Keep the lock if
|
||||
* possible; otherwise, release the old lock and
|
||||
* acquire one for the parent.
|
||||
*/
|
||||
if (parent->locknum != locknum) {
|
||||
NODE_UNLOCK(
|
||||
&rbtdb->node_locks[locknum].lock,
|
||||
&nlocktype);
|
||||
locknum = parent->locknum;
|
||||
NODE_WRLOCK(
|
||||
&rbtdb->node_locks[locknum].lock,
|
||||
&nlocktype);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to gain a reference to the node
|
||||
* before decrementing it in the next iteration.
|
||||
*/
|
||||
if (ISC_LINK_LINKED(parent, deadlink)) {
|
||||
ISC_LIST_UNLINK(
|
||||
rbtdb->deadnodes[locknum],
|
||||
parent, deadlink);
|
||||
}
|
||||
dns__rbtdb_newref(rbtdb, parent,
|
||||
nlocktype DNS__DB_FILELINE);
|
||||
} else {
|
||||
parent = NULL;
|
||||
}
|
||||
dns__rbtdb_newref(rbtdb, parent,
|
||||
nlocktype DNS__DB_FILELINE);
|
||||
} else {
|
||||
parent = NULL;
|
||||
}
|
||||
|
||||
node = parent;
|
||||
} while (node != NULL);
|
||||
NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype);
|
||||
node = parent;
|
||||
} while (node != NULL);
|
||||
NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype);
|
||||
}
|
||||
TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype);
|
||||
|
||||
dns_db_detach((dns_db_t **)&rbtdb);
|
||||
|
|
@ -3907,6 +3941,8 @@ dns__rbtdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
|
|||
ISC_LIST_INIT(rbtdb->deadnodes[i]);
|
||||
}
|
||||
|
||||
ISC_LIST_INIT(rbtdb->prunenodes);
|
||||
|
||||
rbtdb->active = rbtdb->node_lock_count;
|
||||
|
||||
for (i = 0; i < (int)(rbtdb->node_lock_count); i++) {
|
||||
|
|
|
|||
|
|
@ -152,6 +152,10 @@ struct dns_rbtdb {
|
|||
*/
|
||||
dns_rbtnodelist_t *deadnodes;
|
||||
|
||||
/* List of nodes from which recursive tree pruning can be started from.
|
||||
* Locked by tree_lock. */
|
||||
dns_rbtnodelist_t prunenodes;
|
||||
|
||||
/*
|
||||
* Heaps. These are used for TTL based expiry in a cache,
|
||||
* or for zone resigning in a zone DB. hmctx is the memory
|
||||
|
|
|
|||
|
|
@ -178,6 +178,16 @@
|
|||
*/
|
||||
#define MINIMUM_QUERY_TIMEOUT (MAX_SINGLE_QUERY_TIMEOUT + 1000U)
|
||||
|
||||
/*
|
||||
* The default maximum number of validations and validation failures per-fetch
|
||||
*/
|
||||
#ifndef DEFAULT_MAX_VALIDATIONS
|
||||
#define DEFAULT_MAX_VALIDATIONS 16
|
||||
#endif
|
||||
#ifndef DEFAULT_MAX_VALIDATION_FAILURES
|
||||
#define DEFAULT_MAX_VALIDATION_FAILURES 1
|
||||
#endif
|
||||
|
||||
/* The default time in seconds for the whole query to live. */
|
||||
#ifndef DEFAULT_QUERY_TIMEOUT
|
||||
#define DEFAULT_QUERY_TIMEOUT MINIMUM_QUERY_TIMEOUT
|
||||
|
|
@ -457,6 +467,9 @@ struct fetchctx {
|
|||
dns_adbaddrinfo_t *addrinfo;
|
||||
unsigned int depth;
|
||||
char clientstr[ISC_SOCKADDR_FORMATSIZE];
|
||||
|
||||
uint32_t nvalidations;
|
||||
uint32_t nfails;
|
||||
};
|
||||
|
||||
#define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!')
|
||||
|
|
@ -567,6 +580,9 @@ struct dns_resolver {
|
|||
atomic_bool exiting;
|
||||
atomic_bool priming;
|
||||
|
||||
atomic_uint_fast32_t maxvalidations;
|
||||
atomic_uint_fast32_t maxvalidationfails;
|
||||
|
||||
/* Locked by lock. */
|
||||
unsigned int spillat; /* clients-per-query */
|
||||
|
||||
|
|
@ -961,7 +977,8 @@ valcreate(fetchctx_t *fctx, dns_message_t *message, dns_adbaddrinfo_t *addrinfo,
|
|||
|
||||
result = dns_validator_create(
|
||||
fctx->res->view, name, type, rdataset, sigrdataset, message,
|
||||
valoptions, fctx->loop, validated, valarg, &validator);
|
||||
valoptions, fctx->loop, validated, valarg, &fctx->nvalidations,
|
||||
&fctx->nfails, &validator);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
inc_stats(fctx->res, dns_resstatscounter_val);
|
||||
if ((valoptions & DNS_VALIDATOR_DEFER) == 0) {
|
||||
|
|
@ -4518,6 +4535,8 @@ fctx_create(dns_resolver_t *res, isc_loop_t *loop, const dns_name_t *name,
|
|||
.fwdpolicy = dns_fwdpolicy_none,
|
||||
.result = ISC_R_FAILURE,
|
||||
.loop = loop,
|
||||
.nvalidations = atomic_load_relaxed(&res->maxvalidations),
|
||||
.nfails = atomic_load_relaxed(&res->maxvalidationfails),
|
||||
};
|
||||
|
||||
isc_mem_attach(mctx, &fctx->mctx);
|
||||
|
|
@ -9960,6 +9979,8 @@ dns_resolver_create(dns_view_t *view, isc_loopmgr_t *loopmgr, isc_nm_t *nm,
|
|||
.maxqueries = DEFAULT_MAX_QUERIES,
|
||||
.alternates = ISC_LIST_INITIALIZER,
|
||||
.nloops = isc_loopmgr_nloops(loopmgr),
|
||||
.maxvalidations = DEFAULT_MAX_VALIDATIONS,
|
||||
.maxvalidationfails = DEFAULT_MAX_VALIDATION_FAILURES,
|
||||
};
|
||||
|
||||
RTRACE("create");
|
||||
|
|
@ -10925,6 +10946,18 @@ dns_resolver_settimeout(dns_resolver_t *resolver, unsigned int timeout) {
|
|||
resolver->query_timeout = timeout;
|
||||
}
|
||||
|
||||
void
|
||||
dns_resolver_setmaxvalidations(dns_resolver_t *resolver, uint32_t max) {
|
||||
REQUIRE(VALID_RESOLVER(resolver));
|
||||
atomic_store(&resolver->maxvalidations, max);
|
||||
}
|
||||
|
||||
void
|
||||
dns_resolver_setmaxvalidationfails(dns_resolver_t *resolver, uint32_t max) {
|
||||
REQUIRE(VALID_RESOLVER(resolver));
|
||||
atomic_store(&resolver->maxvalidationfails, max);
|
||||
}
|
||||
|
||||
void
|
||||
dns_resolver_setmaxdepth(dns_resolver_t *resolver, unsigned int maxdepth) {
|
||||
REQUIRE(VALID_RESOLVER(resolver));
|
||||
|
|
|
|||
|
|
@ -1539,38 +1539,44 @@ isc_result_t
|
|||
dns_tsigkey_find(dns_tsigkey_t **tsigkey, const dns_name_t *name,
|
||||
const dns_name_t *algorithm, dns_tsigkeyring_t *ring) {
|
||||
dns_tsigkey_t *key = NULL;
|
||||
isc_stdtime_t now = isc_stdtime_now();
|
||||
isc_result_t result;
|
||||
isc_rwlocktype_t locktype = isc_rwlocktype_read;
|
||||
isc_stdtime_t now = isc_stdtime_now();
|
||||
|
||||
REQUIRE(name != NULL);
|
||||
REQUIRE(VALID_TSIGKEYRING(ring));
|
||||
REQUIRE(tsigkey != NULL && *tsigkey == NULL);
|
||||
|
||||
RWLOCK(&ring->lock, isc_rwlocktype_read);
|
||||
again:
|
||||
RWLOCK(&ring->lock, locktype);
|
||||
result = isc_hashmap_find(ring->keys, dns_name_hash(name), tkey_match,
|
||||
name, (void **)&key);
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
RWUNLOCK(&ring->lock, isc_rwlocktype_read);
|
||||
RWUNLOCK(&ring->lock, locktype);
|
||||
return (result);
|
||||
}
|
||||
if (algorithm != NULL && !dns_name_equal(key->algorithm, algorithm)) {
|
||||
RWUNLOCK(&ring->lock, isc_rwlocktype_read);
|
||||
RWUNLOCK(&ring->lock, locktype);
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
if (key->inception != key->expire && isc_serial_lt(key->expire, now)) {
|
||||
/*
|
||||
* The key has expired.
|
||||
*/
|
||||
RWUNLOCK(&ring->lock, isc_rwlocktype_read);
|
||||
RWLOCK(&ring->lock, isc_rwlocktype_write);
|
||||
if (locktype == isc_rwlocktype_read) {
|
||||
RWUNLOCK(&ring->lock, locktype);
|
||||
locktype = isc_rwlocktype_write;
|
||||
key = NULL;
|
||||
goto again;
|
||||
}
|
||||
rm_lru(key);
|
||||
rm_hashmap(key);
|
||||
RWUNLOCK(&ring->lock, isc_rwlocktype_write);
|
||||
RWUNLOCK(&ring->lock, locktype);
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
RWUNLOCK(&ring->lock, isc_rwlocktype_read);
|
||||
adjust_lru(key);
|
||||
dns_tsigkey_ref(key);
|
||||
RWUNLOCK(&ring->lock, locktype);
|
||||
adjust_lru(key);
|
||||
*tsigkey = key;
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
|
|
|||
1277
lib/dns/validator.c
1277
lib/dns/validator.c
File diff suppressed because it is too large
Load diff
|
|
@ -138,6 +138,8 @@ static void
|
|||
shutdown_trigger_close_cb(uv_handle_t *handle) {
|
||||
isc_loop_t *loop = uv_handle_get_data(handle);
|
||||
|
||||
loop->shuttingdown = true;
|
||||
|
||||
isc_loop_detach(&loop);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2152,6 +2152,10 @@ static cfg_clausedef_t view_clauses[] = {
|
|||
{ "max-recursion-queries", &cfg_type_uint32, 0 },
|
||||
{ "max-stale-ttl", &cfg_type_duration, 0 },
|
||||
{ "max-udp-size", &cfg_type_uint32, 0 },
|
||||
{ "max-validations-per-fetch", &cfg_type_uint32,
|
||||
CFG_CLAUSEFLAG_EXPERIMENTAL },
|
||||
{ "max-validation-failures-per-fetch", &cfg_type_uint32,
|
||||
CFG_CLAUSEFLAG_EXPERIMENTAL },
|
||||
{ "message-compression", &cfg_type_boolean, 0 },
|
||||
{ "min-cache-ttl", &cfg_type_duration, 0 },
|
||||
{ "min-ncache-ttl", &cfg_type_duration, 0 },
|
||||
|
|
|
|||
|
|
@ -479,10 +479,10 @@ static void
|
|||
query_addnxrrsetnsec(query_ctx_t *qctx);
|
||||
|
||||
static isc_result_t
|
||||
query_nxdomain(query_ctx_t *qctx, isc_result_t res);
|
||||
query_nxdomain(query_ctx_t *qctx, isc_result_t result);
|
||||
|
||||
static isc_result_t
|
||||
query_redirect(query_ctx_t *qctx);
|
||||
query_redirect(query_ctx_t *qctx, isc_result_t result);
|
||||
|
||||
static isc_result_t
|
||||
query_ncache(query_ctx_t *qctx, isc_result_t result);
|
||||
|
|
@ -6253,6 +6253,13 @@ query_lookup_stale(ns_client_t *client) {
|
|||
query_ctx_t qctx;
|
||||
|
||||
qctx_init(client, NULL, client->query.qtype, &qctx);
|
||||
if (DNS64(client)) {
|
||||
qctx.qtype = qctx.type = dns_rdatatype_a;
|
||||
qctx.dns64 = true;
|
||||
}
|
||||
if (DNS64EXCLUDE(client)) {
|
||||
qctx.dns64_exclude = true;
|
||||
}
|
||||
dns_db_attach(client->view->cachedb, &qctx.db);
|
||||
client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
|
||||
client->query.dboptions |= DNS_DBFIND_STALETIMEOUT;
|
||||
|
|
@ -7697,8 +7704,7 @@ query_usestale(query_ctx_t *qctx, isc_result_t result) {
|
|||
* result from the search.
|
||||
*/
|
||||
static isc_result_t
|
||||
query_gotanswer(query_ctx_t *qctx, isc_result_t res) {
|
||||
isc_result_t result = res;
|
||||
query_gotanswer(query_ctx_t *qctx, isc_result_t result) {
|
||||
char errmsg[256];
|
||||
|
||||
CCTRACE(ISC_LOG_DEBUG(3), "query_gotanswer");
|
||||
|
|
@ -7774,7 +7780,7 @@ root_key_sentinel:
|
|||
return (query_coveringnsec(qctx));
|
||||
|
||||
case DNS_R_NCACHENXDOMAIN:
|
||||
result = query_redirect(qctx);
|
||||
result = query_redirect(qctx, result);
|
||||
if (result != ISC_R_COMPLETE) {
|
||||
return (result);
|
||||
}
|
||||
|
|
@ -9515,11 +9521,10 @@ query_addnxrrsetnsec(query_ctx_t *qctx) {
|
|||
* Handle NXDOMAIN and empty wildcard responses.
|
||||
*/
|
||||
static isc_result_t
|
||||
query_nxdomain(query_ctx_t *qctx, isc_result_t res) {
|
||||
query_nxdomain(query_ctx_t *qctx, isc_result_t result) {
|
||||
dns_section_t section;
|
||||
uint32_t ttl;
|
||||
isc_result_t result = res;
|
||||
bool empty_wild = (res == DNS_R_EMPTYWILD);
|
||||
bool empty_wild = (result == DNS_R_EMPTYWILD);
|
||||
|
||||
CCTRACE(ISC_LOG_DEBUG(3), "query_nxdomain");
|
||||
|
||||
|
|
@ -9528,7 +9533,7 @@ query_nxdomain(query_ctx_t *qctx, isc_result_t res) {
|
|||
INSIST(qctx->is_zone || REDIRECT(qctx->client));
|
||||
|
||||
if (!empty_wild) {
|
||||
result = query_redirect(qctx);
|
||||
result = query_redirect(qctx, result);
|
||||
if (result != ISC_R_COMPLETE) {
|
||||
return (result);
|
||||
}
|
||||
|
|
@ -9616,7 +9621,7 @@ cleanup:
|
|||
* redirecting, so query processing should continue past it.
|
||||
*/
|
||||
static isc_result_t
|
||||
query_redirect(query_ctx_t *qctx) {
|
||||
query_redirect(query_ctx_t *qctx, isc_result_t saved_result) {
|
||||
isc_result_t result;
|
||||
|
||||
CCTRACE(ISC_LOG_DEBUG(3), "query_redirect");
|
||||
|
|
@ -9657,7 +9662,7 @@ query_redirect(query_ctx_t *qctx) {
|
|||
SAVE(qctx->client->query.redirect.rdataset, qctx->rdataset);
|
||||
SAVE(qctx->client->query.redirect.sigrdataset,
|
||||
qctx->sigrdataset);
|
||||
qctx->client->query.redirect.result = DNS_R_NCACHENXDOMAIN;
|
||||
qctx->client->query.redirect.result = saved_result;
|
||||
dns_name_copy(qctx->fname, qctx->client->query.redirect.fname);
|
||||
qctx->client->query.redirect.authoritative =
|
||||
qctx->authoritative;
|
||||
|
|
@ -10252,7 +10257,7 @@ query_coveringnsec(query_ctx_t *qctx) {
|
|||
* We now have the proof that we have an NXDOMAIN. Apply
|
||||
* NXDOMAIN redirection if configured.
|
||||
*/
|
||||
result = query_redirect(qctx);
|
||||
result = query_redirect(qctx, DNS_R_COVERINGNSEC);
|
||||
if (result != ISC_R_COMPLETE) {
|
||||
redirected = true;
|
||||
goto cleanup;
|
||||
|
|
|
|||
Loading…
Reference in a new issue