mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-22 18:19:42 +00:00
Merge branch '4480-sig0-can-be-used-to-exhaust-cpu-resources-v6' into 'v9.20.0-release'
[CVE-2024-1975] Mitigate SIG(0) CPU resources exhaustion attack vectors See merge request isc-private/bind9!689
This commit is contained in:
commit
b2cfdba565
10
CHANGES
10
CHANGES
@ -1,3 +1,13 @@
|
||||
6402. [security] A malicious DNS client that sends many queries with a
|
||||
SIG(0)-signed message can cause the server to respond
|
||||
slowly or not respond at all to other clients. Use the
|
||||
offload threadpool for SIG(0) signature verifications,
|
||||
add the 'sig0checks-quota' configuration option to
|
||||
introduce a quota for SIG(0)-signed queries running in
|
||||
parallel and add the 'sig0checks-quota-exempt' option to
|
||||
exempt certain clients by their IP/network addresses.
|
||||
(CVE-2024-1975) [GL #4480]
|
||||
|
||||
6401. [security] An excessively large number of rrtypes per owner can
|
||||
slow down database query processing, so a limit has been
|
||||
placed on the number of rrtypes that can be stored per
|
||||
|
@ -2117,15 +2117,22 @@ cleanup:
|
||||
|
||||
static isc_result_t
|
||||
matchview(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
|
||||
dns_message_t *message, dns_aclenv_t *env, isc_result_t *sigresultp,
|
||||
dns_message_t *message, dns_aclenv_t *env, ns_server_t *lsctx,
|
||||
isc_loop_t *loop, isc_job_cb cb, void *cbarg,
|
||||
isc_result_t *sigresultp, isc_result_t *viewpatchresultp,
|
||||
dns_view_t **viewp) {
|
||||
UNUSED(srcaddr);
|
||||
UNUSED(destaddr);
|
||||
UNUSED(message);
|
||||
UNUSED(env);
|
||||
UNUSED(lsctx);
|
||||
UNUSED(loop);
|
||||
UNUSED(cb);
|
||||
UNUSED(cbarg);
|
||||
UNUSED(sigresultp);
|
||||
|
||||
*viewp = view;
|
||||
*viewpatchresultp = ISC_R_SUCCESS;
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
|
@ -109,6 +109,7 @@ options {\n\
|
||||
# session-keyfile \"" NAMED_LOCALSTATEDIR "/run/named/session.key\";\n\
|
||||
session-keyname local-ddns;\n\
|
||||
startup-notify-rate 20;\n\
|
||||
sig0checks-quota 1;\n\
|
||||
statistics-file \"named.stats\";\n\
|
||||
tcp-advertised-timeout 300;\n\
|
||||
tcp-clients 150;\n\
|
||||
|
@ -278,6 +278,26 @@ struct zonelistentry {
|
||||
ISC_LINK(struct zonelistentry) link;
|
||||
};
|
||||
|
||||
/*%
|
||||
* Message-to-view matching context to run message signature validation
|
||||
* asynchronously.
|
||||
*/
|
||||
typedef struct matching_view_ctx {
|
||||
isc_netaddr_t *srcaddr;
|
||||
isc_netaddr_t *destaddr;
|
||||
dns_message_t *message;
|
||||
dns_aclenv_t *env;
|
||||
ns_server_t *sctx;
|
||||
isc_loop_t *loop;
|
||||
isc_job_cb cb;
|
||||
void *cbarg;
|
||||
isc_result_t *sigresult;
|
||||
isc_result_t *viewmatchresult;
|
||||
isc_result_t quota_result;
|
||||
dns_view_t **viewp;
|
||||
dns_view_t *view;
|
||||
} matching_view_ctx_t;
|
||||
|
||||
/*%
|
||||
* Configuration context to retain for each view that allows
|
||||
* new zones to be added at runtime.
|
||||
@ -8412,6 +8432,8 @@ load_configuration(const char *filename, named_server_t *server,
|
||||
configure_server_quota(maps, "recursive-clients",
|
||||
&server->sctx->recursionquota);
|
||||
configure_server_quota(maps, "update-quota", &server->sctx->updquota);
|
||||
configure_server_quota(maps, "sig0checks-quota",
|
||||
&server->sctx->sig0checksquota);
|
||||
|
||||
max = isc_quota_getmax(&server->sctx->recursionquota);
|
||||
if (max > 1000) {
|
||||
@ -8430,9 +8452,17 @@ load_configuration(const char *filename, named_server_t *server,
|
||||
} else {
|
||||
softquota = (max * 90) / 100;
|
||||
}
|
||||
|
||||
isc_quota_soft(&server->sctx->recursionquota, softquota);
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "sig0checks-quota-exempt", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = cfg_acl_fromconfig(
|
||||
obj, config, named_g_lctx, named_g_aclconfctx,
|
||||
named_g_mctx, 0, &server->sctx->sig0checksquota_exempt);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set "blackhole". Only legal at options level; there is
|
||||
* no default.
|
||||
@ -10043,18 +10073,19 @@ shutdown_server(void *arg) {
|
||||
isc_loopmgr_resume(named_g_loopmgr);
|
||||
}
|
||||
|
||||
/*%
|
||||
* Find a view that matches the source and destination addresses of a query.
|
||||
*/
|
||||
static isc_result_t
|
||||
get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
|
||||
dns_message_t *message, dns_aclenv_t *env,
|
||||
isc_result_t *sigresult, dns_view_t **viewp) {
|
||||
get_matching_view_sync(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
|
||||
dns_message_t *message, dns_aclenv_t *env,
|
||||
isc_result_t *sigresult, dns_view_t **viewp) {
|
||||
dns_view_t *view;
|
||||
|
||||
REQUIRE(message != NULL);
|
||||
REQUIRE(sigresult != NULL);
|
||||
REQUIRE(viewp != NULL && *viewp == NULL);
|
||||
/*
|
||||
* We should not be running synchronous view matching if signature
|
||||
* checking involves SIG(0). TSIG has priority of SIG(0), so if TSIG
|
||||
* is set then we proceed anyway.
|
||||
*/
|
||||
INSIST(message->tsigkey != NULL || message->tsig != NULL ||
|
||||
message->sig0 == NULL);
|
||||
|
||||
for (view = ISC_LIST_HEAD(named_g_server->viewlist); view != NULL;
|
||||
view = ISC_LIST_NEXT(view, link))
|
||||
@ -10064,12 +10095,10 @@ get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
|
||||
{
|
||||
const dns_name_t *tsig = NULL;
|
||||
|
||||
*sigresult = dns_message_rechecksig(message, view);
|
||||
dns_message_resetsig(message);
|
||||
*sigresult = dns_message_checksig(message, view);
|
||||
if (*sigresult == ISC_R_SUCCESS) {
|
||||
dns_tsigkey_t *tsigkey;
|
||||
|
||||
tsigkey = message->tsigkey;
|
||||
tsig = dns_tsigkey_identity(tsigkey);
|
||||
tsig = dns_tsigkey_identity(message->tsigkey);
|
||||
}
|
||||
|
||||
if (dns_acl_allowed(srcaddr, tsig, view->matchclients,
|
||||
@ -10088,6 +10117,191 @@ get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
static void
|
||||
get_matching_view_done(void *cbarg) {
|
||||
matching_view_ctx_t *mvctx = cbarg;
|
||||
dns_message_t *message = mvctx->message;
|
||||
|
||||
if (*mvctx->viewmatchresult == ISC_R_SUCCESS) {
|
||||
INSIST(mvctx->view != NULL);
|
||||
dns_view_attach(mvctx->view, mvctx->viewp);
|
||||
}
|
||||
|
||||
mvctx->cb(mvctx->cbarg);
|
||||
|
||||
if (mvctx->quota_result == ISC_R_SUCCESS) {
|
||||
isc_quota_release(&mvctx->sctx->sig0checksquota);
|
||||
}
|
||||
if (mvctx->view != NULL) {
|
||||
dns_view_detach(&mvctx->view);
|
||||
}
|
||||
isc_loop_detach(&mvctx->loop);
|
||||
ns_server_detach(&mvctx->sctx);
|
||||
isc_mem_put(message->mctx, mvctx, sizeof(*mvctx));
|
||||
dns_message_detach(&message);
|
||||
}
|
||||
|
||||
static dns_view_t *
|
||||
get_matching_view_next(dns_view_t *view, dns_rdataclass_t rdclass) {
|
||||
if (view == NULL) {
|
||||
view = ISC_LIST_HEAD(named_g_server->viewlist);
|
||||
} else {
|
||||
view = ISC_LIST_NEXT(view, link);
|
||||
}
|
||||
while (true) {
|
||||
if (view == NULL || rdclass == view->rdclass ||
|
||||
rdclass == dns_rdataclass_any)
|
||||
{
|
||||
return (view);
|
||||
}
|
||||
view = ISC_LIST_NEXT(view, link);
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
get_matching_view_continue(void *cbarg, isc_result_t result) {
|
||||
matching_view_ctx_t *mvctx = cbarg;
|
||||
dns_view_t *view = NULL;
|
||||
const dns_name_t *tsig = NULL;
|
||||
|
||||
*mvctx->sigresult = result;
|
||||
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
tsig = dns_tsigkey_identity(mvctx->message->tsigkey);
|
||||
}
|
||||
|
||||
if (dns_acl_allowed(mvctx->srcaddr, tsig, mvctx->view->matchclients,
|
||||
mvctx->env) &&
|
||||
dns_acl_allowed(mvctx->destaddr, tsig,
|
||||
mvctx->view->matchdestinations, mvctx->env) &&
|
||||
!(mvctx->view->matchrecursiveonly &&
|
||||
(mvctx->message->flags & DNS_MESSAGEFLAG_RD) == 0))
|
||||
{
|
||||
/*
|
||||
* A matching view is found.
|
||||
*/
|
||||
*mvctx->viewmatchresult = ISC_R_SUCCESS;
|
||||
get_matching_view_done(cbarg);
|
||||
return;
|
||||
}
|
||||
|
||||
dns_message_resetsig(mvctx->message);
|
||||
|
||||
view = get_matching_view_next(mvctx->view, mvctx->message->rdclass);
|
||||
dns_view_detach(&mvctx->view);
|
||||
if (view != NULL) {
|
||||
/*
|
||||
* Try the next view.
|
||||
*/
|
||||
dns_view_attach(view, &mvctx->view);
|
||||
result = dns_message_checksig_async(
|
||||
mvctx->message, view, mvctx->loop,
|
||||
get_matching_view_continue, mvctx);
|
||||
INSIST(result == DNS_R_WAIT);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* No matching view is found.
|
||||
*/
|
||||
*mvctx->viewmatchresult = ISC_R_NOTFOUND;
|
||||
get_matching_view_done(cbarg);
|
||||
}
|
||||
|
||||
/*%
|
||||
* Find a view that matches the source and destination addresses of a query.
|
||||
*/
|
||||
static isc_result_t
|
||||
get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
|
||||
dns_message_t *message, dns_aclenv_t *env, ns_server_t *sctx,
|
||||
isc_loop_t *loop, isc_job_cb cb, void *cbarg,
|
||||
isc_result_t *sigresult, isc_result_t *viewmatchresult,
|
||||
dns_view_t **viewp) {
|
||||
dns_view_t *view = NULL;
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(message != NULL);
|
||||
REQUIRE(sctx != NULL);
|
||||
REQUIRE(loop == NULL || cb != NULL);
|
||||
REQUIRE(sigresult != NULL);
|
||||
REQUIRE(viewmatchresult != NULL);
|
||||
REQUIRE(viewp != NULL && *viewp == NULL);
|
||||
|
||||
/* No offloading is requested if the loop is unset. */
|
||||
if (loop == NULL) {
|
||||
*viewmatchresult = get_matching_view_sync(
|
||||
srcaddr, destaddr, message, env, sigresult, viewp);
|
||||
return (*viewmatchresult);
|
||||
}
|
||||
|
||||
/* Also no offloading when there is no view at all to match against. */
|
||||
view = get_matching_view_next(NULL, message->rdclass);
|
||||
if (view == NULL) {
|
||||
*viewmatchresult = ISC_R_NOTFOUND;
|
||||
return (*viewmatchresult);
|
||||
}
|
||||
|
||||
dns_message_resetsig(message);
|
||||
|
||||
matching_view_ctx_t *mvctx = isc_mem_get(message->mctx, sizeof(*mvctx));
|
||||
*mvctx = (matching_view_ctx_t){
|
||||
.srcaddr = srcaddr,
|
||||
.destaddr = destaddr,
|
||||
.env = env,
|
||||
.cb = cb,
|
||||
.cbarg = cbarg,
|
||||
.sigresult = sigresult,
|
||||
.viewmatchresult = viewmatchresult,
|
||||
.quota_result = ISC_R_UNSET,
|
||||
.viewp = viewp,
|
||||
};
|
||||
ns_server_attach(sctx, &mvctx->sctx);
|
||||
isc_loop_attach(loop, &mvctx->loop);
|
||||
dns_message_attach(message, &mvctx->message);
|
||||
|
||||
/*
|
||||
* If the message has a SIG0 signature which we are going to
|
||||
* check, and the client is not exempt from the SIG(0) quota,
|
||||
* then acquire a quota. TSIG has priority over SIG(0), so if
|
||||
* TSIG is set then we don't care.
|
||||
*/
|
||||
if (message->tsigkey == NULL && message->tsig == NULL &&
|
||||
message->sig0 != NULL)
|
||||
{
|
||||
if (sctx->sig0checksquota_exempt != NULL) {
|
||||
int exempt_match;
|
||||
|
||||
result = dns_acl_match(srcaddr, NULL,
|
||||
sctx->sig0checksquota_exempt,
|
||||
env, &exempt_match, NULL);
|
||||
if (result == ISC_R_SUCCESS && exempt_match > 0) {
|
||||
mvctx->quota_result = ISC_R_EXISTS;
|
||||
}
|
||||
}
|
||||
if (mvctx->quota_result == ISC_R_UNSET) {
|
||||
mvctx->quota_result =
|
||||
isc_quota_acquire(&sctx->sig0checksquota);
|
||||
}
|
||||
if (mvctx->quota_result == ISC_R_SOFTQUOTA) {
|
||||
isc_quota_release(&sctx->sig0checksquota);
|
||||
}
|
||||
if (mvctx->quota_result != ISC_R_SUCCESS &&
|
||||
mvctx->quota_result != ISC_R_EXISTS)
|
||||
{
|
||||
*mvctx->viewmatchresult = ISC_R_QUOTA;
|
||||
isc_async_run(loop, get_matching_view_done, mvctx);
|
||||
return (DNS_R_WAIT);
|
||||
}
|
||||
}
|
||||
|
||||
dns_view_attach(view, &mvctx->view);
|
||||
result = dns_message_checksig_async(message, view, loop,
|
||||
get_matching_view_continue, mvctx);
|
||||
INSIST(result == DNS_R_WAIT);
|
||||
|
||||
return (DNS_R_WAIT);
|
||||
}
|
||||
|
||||
void
|
||||
named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
|
||||
isc_result_t result;
|
||||
|
16
bin/tests/system/checkconf/bad-sig0checks-quota-exempt.conf
Normal file
16
bin/tests/system/checkconf/bad-sig0checks-quota-exempt.conf
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
options {
|
||||
sig0checks-quota-exempt { unknownacl; };
|
||||
};
|
20
bin/tests/system/checkconf/good-sig0checks-quota-exempt.conf
Normal file
20
bin/tests/system/checkconf/good-sig0checks-quota-exempt.conf
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
acl goodacl {
|
||||
192.168.0.1;
|
||||
};
|
||||
|
||||
options {
|
||||
sig0checks-quota-exempt { 10.0.0.0/8; 2001:db8::100; goodacl; };
|
||||
};
|
@ -29,6 +29,7 @@ rm -f */ans.run
|
||||
rm -f Ksig0.example2.*
|
||||
rm -f keyname keyname.err
|
||||
rm -f ns1/example2.db
|
||||
rm -f ns1/example2-toomanykeys.db
|
||||
rm -f ns*/managed-keys.bind*
|
||||
rm -f nsupdate.out.*
|
||||
rm -f ns*/named.run.prev
|
||||
|
@ -44,6 +44,12 @@ zone "example2" {
|
||||
allow-update { key sig0.example2.; };
|
||||
};
|
||||
|
||||
zone "example2-toomanykeys" {
|
||||
type primary;
|
||||
file "example2-toomanykeys.db";
|
||||
allow-update { key sig0.example2-toomanykeys.; };
|
||||
};
|
||||
|
||||
zone "example3" {
|
||||
type primary;
|
||||
file "example3.db";
|
||||
|
@ -56,6 +56,13 @@ zone "example2" {
|
||||
primaries { 10.53.0.1; };
|
||||
};
|
||||
|
||||
zone "example2-toomanykeys" {
|
||||
type secondary;
|
||||
file "example2-toomanykeys.bk";
|
||||
allow-update-forwarding { 10.53.0.1; };
|
||||
primaries { 10.53.0.1; };
|
||||
};
|
||||
|
||||
zone "example3" {
|
||||
type secondary;
|
||||
file "example3.bk";
|
||||
|
@ -32,7 +32,7 @@ else
|
||||
fi
|
||||
|
||||
#
|
||||
# SIG(0) required cryptographic support which may not be configured.
|
||||
# SIG(0) requires cryptographic support which may not be configured.
|
||||
#
|
||||
keyname=$($KEYGEN -q -n HOST -a ${DEFAULT_ALGORITHM} -T KEY sig0.example2 2>keyname.err)
|
||||
if test -n "$keyname"; then
|
||||
@ -42,3 +42,12 @@ else
|
||||
cat ns1/example1.db >ns1/example2.db
|
||||
fi
|
||||
cat_i <keyname.err
|
||||
|
||||
cat ns1/example1.db >ns1/example2-toomanykeys.db
|
||||
for i in 1 2 3; do
|
||||
keyname=$($KEYGEN -q -n HOST -a ${DEFAULT_ALGORITHM} -T KEY sig0.example2-toomanykeys 2>/dev/null)
|
||||
if test -n "$keyname"; then
|
||||
cat $keyname.key >>ns1/example2-toomanykeys.db
|
||||
echo $keyname >keyname$i
|
||||
fi
|
||||
done
|
||||
|
@ -389,7 +389,7 @@ if test -f keyname; then
|
||||
nextpart_thrice
|
||||
ret=0
|
||||
keyname=$(cat keyname)
|
||||
$NSUPDATE -k $keyname.private -- - <<EOF || ret=1
|
||||
$NSUPDATE -k $keyname.private -- - <<EOF >nsupdate.out.test$n 2>&1 || ret=1
|
||||
local 10.53.0.1
|
||||
server 10.53.0.3 ${PORT}
|
||||
zone example2
|
||||
@ -424,7 +424,7 @@ EOF
|
||||
nextpart_thrice
|
||||
ret=0
|
||||
keyname=$(cat keyname)
|
||||
$NSUPDATE -k $keyname.private -S -O -- - <<EOF || ret=1
|
||||
$NSUPDATE -k $keyname.private -S -O -- - <<EOF >nsupdate.out.test$n 2>&1 || ret=1
|
||||
local 10.53.0.1
|
||||
server 10.53.0.3 ${TLSPORT}
|
||||
zone example2
|
||||
@ -454,6 +454,28 @@ EOF
|
||||
status=$((status + ret))
|
||||
n=$((n + 1))
|
||||
fi
|
||||
|
||||
echo_i "checking update forwarding with sig0 with too many keys ($n)"
|
||||
nextpart_thrice
|
||||
ret=0
|
||||
good=0
|
||||
bad=0
|
||||
for i in 1 2 3; do
|
||||
keyname=$(cat keyname$i)
|
||||
$NSUPDATE -d -D -k $keyname.private -- - <<EOF >nsupdate.out.test$n.$i 2>&1 && good=$((good + 1)) || bad=$((bad + 1))
|
||||
local 10.53.0.1
|
||||
server 10.53.0.3 ${PORT}
|
||||
zone example2-toomanykeys
|
||||
update add toomanykeys$i.example2-toomanykeys. 600 A 10.10.10.1
|
||||
send
|
||||
EOF
|
||||
done
|
||||
# There are three keys in the zone but named checks the signature using
|
||||
# maximum two keys, so one of these updates should have been failed.
|
||||
[ $good = 2 ] && [ $bad = 1 ] || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
n=$((n + 1))
|
||||
fi
|
||||
|
||||
echo_i "attempting an update that should be rejected by ACL ($n)"
|
||||
|
@ -4000,6 +4000,32 @@ system.
|
||||
the server will accept for updating local authoritiative zones or
|
||||
forwarding to a primary server. The default is ``100``.
|
||||
|
||||
.. namedconf:statement:: sig0checks-quota
|
||||
:tags: server
|
||||
:short: Specifies the maximum number of concurrent SIG(0) signature checks that can be processed by the server.
|
||||
|
||||
This is the maximum number of simultaneous SIG(0)-signed messages that
|
||||
the server accepts. If the quota is reached, then :iscman:`named` answers
|
||||
with a status code of REFUSED. The value of ``0`` disables the quota. The
|
||||
default is ``1``.
|
||||
|
||||
.. namedconf:statement:: sig0checks-quota-exempt
|
||||
:tags: server
|
||||
:short: Exempts specific clients or client groups from SIG(0) signature checking quota.
|
||||
|
||||
DNS clients can be exempted from SIG(0) signature checking quota with the
|
||||
:any:`sig0checks-quota-exempt` clause using their IP and/or Network
|
||||
addresses. The default value is an empty list.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
sig0checks-quota-exempt {
|
||||
10.0.0.0/8;
|
||||
2001:db8::100;
|
||||
};
|
||||
|
||||
.. _intervals:
|
||||
|
||||
Periodic Task Intervals
|
||||
|
@ -277,6 +277,8 @@ options {
|
||||
sig-signing-signatures <integer>;
|
||||
sig-signing-type <integer>;
|
||||
sig-validity-interval <integer> [ <integer> ]; // obsolete
|
||||
sig0checks-quota <integer>; // experimental
|
||||
sig0checks-quota-exempt { <address_match_element>; ... }; // experimental
|
||||
sortlist { <address_match_element>; ... }; // deprecated
|
||||
stale-answer-client-timeout ( disabled | off | <integer> );
|
||||
stale-answer-enable <boolean>;
|
||||
|
@ -34,6 +34,10 @@ Security Fixes
|
||||
ISC would like to thank Toshifumi Sakaguchi who independently discovered
|
||||
and responsibly reported the issue to ISC. :gl:`#4548`
|
||||
|
||||
- A malicious DNS client that sends many queries with a SIG(0)-signed message
|
||||
can cause server to respond slowly or not respond at all for other clients.
|
||||
:cve:`2024-1975` :gl:`#4480`
|
||||
|
||||
New Features
|
||||
~~~~~~~~~~~~
|
||||
|
||||
|
@ -352,6 +352,8 @@ struct dns_ednsopt {
|
||||
unsigned char *value;
|
||||
};
|
||||
|
||||
typedef void (*dns_message_cb_t)(void *arg, isc_result_t result);
|
||||
|
||||
/***
|
||||
*** Functions
|
||||
***/
|
||||
@ -1328,24 +1330,23 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view);
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_message_rechecksig(dns_message_t *msg, dns_view_t *view);
|
||||
dns_message_checksig_async(dns_message_t *msg, dns_view_t *view,
|
||||
isc_loop_t *loop, dns_message_cb_t cb, void *cbarg);
|
||||
/*%<
|
||||
* Reset the signature state and then if the message was signed,
|
||||
* verify the message.
|
||||
* Run dns_message_checksig() in an offloaded thread and return its result
|
||||
* using the 'cb' callback function, running on the 'loop'.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li msg is a valid parsed message.
|
||||
*\li view is a valid view or NULL
|
||||
*\li view is a valid view or NULL.
|
||||
*\li loop is a valid loop.
|
||||
*\li cb is a valid callback function.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*\li #ISC_R_SUCCESS - the message was unsigned, or the message
|
||||
* was signed correctly.
|
||||
*\li #DNS_R_WAIT
|
||||
*
|
||||
*\li #DNS_R_EXPECTEDTSIG - A TSIG was expected, but not seen
|
||||
*\li #DNS_R_UNEXPECTEDTSIG - A TSIG was seen but not expected
|
||||
*\li #DNS_R_TSIGVERIFYFAILURE - The TSIG failed to verify
|
||||
*/
|
||||
|
||||
void
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <isc/string.h>
|
||||
#include <isc/utf8.h>
|
||||
#include <isc/util.h>
|
||||
#include <isc/work.h>
|
||||
|
||||
#include <dns/dnssec.h>
|
||||
#include <dns/keyvalues.h>
|
||||
@ -180,6 +181,18 @@ msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
|
||||
#define msgblock_get(block, type) \
|
||||
((type *)msgblock_internalget(block, sizeof(type)))
|
||||
|
||||
/*
|
||||
* A context type to pass information when checking a message signature
|
||||
* asynchronously.
|
||||
*/
|
||||
typedef struct checksig_ctx {
|
||||
dns_message_t *msg;
|
||||
dns_view_t *view;
|
||||
dns_message_cb_t cb;
|
||||
void *cbarg;
|
||||
isc_result_t result;
|
||||
} checksig_ctx_t;
|
||||
|
||||
/*
|
||||
* This function differs from public dns_message_puttemprdataset() that it
|
||||
* requires the *rdatasetp to be associated, and it will disassociate and
|
||||
@ -3177,12 +3190,6 @@ dns_message_resetsig(dns_message_t *msg) {
|
||||
}
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
|
||||
dns_message_resetsig(msg);
|
||||
return (dns_message_checksig(msg, view));
|
||||
}
|
||||
|
||||
#ifdef SKAN_MSG_DEBUG
|
||||
void
|
||||
dns_message_dumpsig(dns_message_t *msg, char *txt1) {
|
||||
@ -3211,6 +3218,47 @@ dns_message_dumpsig(dns_message_t *msg, char *txt1) {
|
||||
}
|
||||
#endif /* ifdef SKAN_MSG_DEBUG */
|
||||
|
||||
static void
|
||||
checksig_run(void *arg) {
|
||||
checksig_ctx_t *chsigctx = arg;
|
||||
|
||||
chsigctx->result = dns_message_checksig(chsigctx->msg, chsigctx->view);
|
||||
}
|
||||
|
||||
static void
|
||||
checksig_cb(void *arg) {
|
||||
checksig_ctx_t *chsigctx = arg;
|
||||
dns_message_t *msg = chsigctx->msg;
|
||||
|
||||
chsigctx->cb(chsigctx->cbarg, chsigctx->result);
|
||||
|
||||
dns_view_detach(&chsigctx->view);
|
||||
isc_mem_put(msg->mctx, chsigctx, sizeof(*chsigctx));
|
||||
dns_message_detach(&msg);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_message_checksig_async(dns_message_t *msg, dns_view_t *view,
|
||||
isc_loop_t *loop, dns_message_cb_t cb, void *cbarg) {
|
||||
REQUIRE(DNS_MESSAGE_VALID(msg));
|
||||
REQUIRE(view != NULL);
|
||||
REQUIRE(loop != NULL);
|
||||
REQUIRE(cb != NULL);
|
||||
|
||||
checksig_ctx_t *chsigctx = isc_mem_get(msg->mctx, sizeof(*chsigctx));
|
||||
*chsigctx = (checksig_ctx_t){
|
||||
.cb = cb,
|
||||
.cbarg = cbarg,
|
||||
.result = ISC_R_UNSET,
|
||||
};
|
||||
dns_message_attach(msg, &chsigctx->msg);
|
||||
dns_view_attach(view, &chsigctx->view);
|
||||
|
||||
isc_work_enqueue(loop, checksig_run, checksig_cb, chsigctx);
|
||||
|
||||
return (DNS_R_WAIT);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
|
||||
isc_buffer_t b, msgb;
|
||||
@ -3238,6 +3286,12 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
|
||||
dns_rdata_sig_t sig;
|
||||
dns_rdataset_t keyset;
|
||||
isc_result_t result;
|
||||
/*
|
||||
* In order to protect from a possible DoS attack, we are
|
||||
* going to check at most two KEY RRs.
|
||||
*/
|
||||
const size_t max_keys = 2;
|
||||
size_t n;
|
||||
|
||||
result = dns_rdataset_first(msg->sig0);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
@ -3269,18 +3323,17 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
|
||||
0, false, &keyset, NULL);
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
/* XXXBEW Should possibly create a fetch here */
|
||||
result = DNS_R_KEYUNAUTHORIZED;
|
||||
goto freesig;
|
||||
} else if (keyset.trust < dns_trust_secure) {
|
||||
/* XXXBEW Should call a validator here */
|
||||
} else if (keyset.trust < dns_trust_ultimate) {
|
||||
result = DNS_R_KEYUNAUTHORIZED;
|
||||
goto freesig;
|
||||
}
|
||||
result = dns_rdataset_first(&keyset);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
for (; result == ISC_R_SUCCESS;
|
||||
result = dns_rdataset_next(&keyset))
|
||||
|
||||
for (n = 0; result == ISC_R_SUCCESS && n < max_keys;
|
||||
n++, result = dns_rdataset_next(&keyset))
|
||||
{
|
||||
dst_key_t *key = NULL;
|
||||
|
||||
@ -3308,7 +3361,7 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == ISC_R_NOMORE) {
|
||||
if (result == ISC_R_NOMORE || n == max_keys) {
|
||||
result = DNS_R_KEYUNAUTHORIZED;
|
||||
}
|
||||
|
||||
|
@ -645,6 +645,8 @@ resquery_send(resquery_t *query);
|
||||
static void
|
||||
resquery_response(isc_result_t eresult, isc_region_t *region, void *arg);
|
||||
static void
|
||||
resquery_response_continue(void *arg, isc_result_t result);
|
||||
static void
|
||||
resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg);
|
||||
static void
|
||||
fctx_try(fetchctx_t *fctx, bool retrying, bool badcache);
|
||||
@ -777,6 +779,7 @@ release_fctx(fetchctx_t *fctx);
|
||||
typedef struct respctx {
|
||||
resquery_t *query;
|
||||
fetchctx_t *fctx;
|
||||
isc_mem_t *mctx;
|
||||
isc_result_t result;
|
||||
isc_buffer_t buffer;
|
||||
unsigned int retryopts; /* updated options to pass to
|
||||
@ -7233,7 +7236,7 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
isc_result_t result;
|
||||
resquery_t *query = (resquery_t *)arg;
|
||||
fetchctx_t *fctx = NULL;
|
||||
respctx_t rctx;
|
||||
respctx_t *rctx = NULL;
|
||||
|
||||
if (eresult == ISC_R_CANCELED) {
|
||||
return;
|
||||
@ -7252,21 +7255,22 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
inc_stats(fctx->res, dns_resstatscounter_responsev6);
|
||||
}
|
||||
|
||||
rctx_respinit(query, fctx, eresult, region, &rctx);
|
||||
rctx = isc_mem_get(fctx->mctx, sizeof(*rctx));
|
||||
rctx_respinit(query, fctx, eresult, region, rctx);
|
||||
|
||||
if (eresult == ISC_R_SHUTTINGDOWN ||
|
||||
atomic_load_acquire(&fctx->res->exiting))
|
||||
{
|
||||
result = ISC_R_SHUTTINGDOWN;
|
||||
FCTXTRACE("resolver shutting down");
|
||||
rctx.finish = NULL;
|
||||
rctx_done(&rctx, result);
|
||||
return;
|
||||
rctx->finish = NULL;
|
||||
rctx_done(rctx, result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
result = rctx_timedout(&rctx);
|
||||
result = rctx_timedout(rctx);
|
||||
if (result == ISC_R_COMPLETE) {
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fctx->addrinfo = query->addrinfo;
|
||||
@ -7276,9 +7280,9 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
/*
|
||||
* Check whether the dispatcher has failed; if so we're done
|
||||
*/
|
||||
result = rctx_dispfail(&rctx);
|
||||
result = rctx_dispfail(rctx);
|
||||
if (result == ISC_R_COMPLETE) {
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (query->tsig != NULL) {
|
||||
@ -7290,17 +7294,18 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
query->tsigkey);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
FCTXTRACE3("unable to set tsig key", result);
|
||||
rctx_done(&rctx, result);
|
||||
return;
|
||||
rctx_done(rctx, result);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
dns_message_setclass(query->rmessage, fctx->res->rdclass);
|
||||
|
||||
if ((rctx.retryopts & DNS_FETCHOPT_TCP) == 0) {
|
||||
if ((rctx.retryopts & DNS_FETCHOPT_NOEDNS0) == 0) {
|
||||
dns_adb_setudpsize(fctx->adb, query->addrinfo,
|
||||
isc_buffer_usedlength(&rctx.buffer));
|
||||
if ((rctx->retryopts & DNS_FETCHOPT_TCP) == 0) {
|
||||
if ((rctx->retryopts & DNS_FETCHOPT_NOEDNS0) == 0) {
|
||||
dns_adb_setudpsize(
|
||||
fctx->adb, query->addrinfo,
|
||||
isc_buffer_usedlength(&rctx->buffer));
|
||||
} else {
|
||||
dns_adb_plainresponse(fctx->adb, query->addrinfo);
|
||||
}
|
||||
@ -7309,38 +7314,39 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
/*
|
||||
* Parse response message.
|
||||
*/
|
||||
result = rctx_parse(&rctx);
|
||||
result = rctx_parse(rctx);
|
||||
if (result == ISC_R_COMPLETE) {
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Log the incoming packet.
|
||||
*/
|
||||
rctx_logpacket(&rctx);
|
||||
rctx_logpacket(rctx);
|
||||
|
||||
if (query->rmessage->rdclass != fctx->res->rdclass) {
|
||||
rctx.resend = true;
|
||||
rctx->resend = true;
|
||||
FCTXTRACE("bad class");
|
||||
rctx_done(&rctx, result);
|
||||
return;
|
||||
rctx_done(rctx, result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process receive opt record.
|
||||
*/
|
||||
rctx.opt = dns_message_getopt(query->rmessage);
|
||||
if (rctx.opt != NULL) {
|
||||
rctx_opt(&rctx);
|
||||
rctx->opt = dns_message_getopt(query->rmessage);
|
||||
if (rctx->opt != NULL) {
|
||||
rctx_opt(rctx);
|
||||
}
|
||||
|
||||
if (query->rmessage->cc_bad && (rctx.retryopts & DNS_FETCHOPT_TCP) == 0)
|
||||
if (query->rmessage->cc_bad &&
|
||||
(rctx->retryopts & DNS_FETCHOPT_TCP) == 0)
|
||||
{
|
||||
/*
|
||||
* If the COOKIE is bad, assume it is an attack and
|
||||
* keep listening for a good answer.
|
||||
*/
|
||||
rctx.nextitem = true;
|
||||
rctx->nextitem = true;
|
||||
if (isc_log_wouldlog(dns_lctx, ISC_LOG_INFO)) {
|
||||
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
|
||||
isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
|
||||
@ -7349,8 +7355,8 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
|
||||
"bad cookie from %s", addrbuf);
|
||||
}
|
||||
rctx_done(&rctx, result);
|
||||
return;
|
||||
rctx_done(rctx, result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -7377,27 +7383,55 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
result = same_question(fctx, query->rmessage);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
FCTXTRACE3("question section invalid", result);
|
||||
rctx.nextitem = true;
|
||||
rctx_done(&rctx, result);
|
||||
return;
|
||||
rctx->nextitem = true;
|
||||
rctx_done(rctx, result);
|
||||
goto cleanup;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the message is signed, check the signature. If not, this
|
||||
* returns success anyway.
|
||||
*/
|
||||
result = dns_message_checksig(query->rmessage, fctx->res->view);
|
||||
if (query->rmessage->tsigkey == NULL && query->rmessage->tsig == NULL &&
|
||||
query->rmessage->sig0 != NULL)
|
||||
{
|
||||
/*
|
||||
* If the message is not TSIG-signed (which has priorty) and is
|
||||
* SIG(0)-signed (which consumes more resources), then run an
|
||||
* asynchronous check.
|
||||
*/
|
||||
result = dns_message_checksig_async(
|
||||
query->rmessage, fctx->res->view, fctx->loop,
|
||||
resquery_response_continue, rctx);
|
||||
INSIST(result == DNS_R_WAIT);
|
||||
} else {
|
||||
/*
|
||||
* If the message is signed, check the signature. If not, this
|
||||
* returns success anyway.
|
||||
*/
|
||||
result = dns_message_checksig(query->rmessage, fctx->res->view);
|
||||
resquery_response_continue(rctx, result);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
isc_mem_putanddetach(&rctx->mctx, rctx, sizeof(*rctx));
|
||||
}
|
||||
|
||||
static void
|
||||
resquery_response_continue(void *arg, isc_result_t result) {
|
||||
respctx_t *rctx = arg;
|
||||
fetchctx_t *fctx = rctx->fctx;
|
||||
resquery_t *query = rctx->query;
|
||||
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
FCTXTRACE3("signature check failed", result);
|
||||
if (result == DNS_R_UNEXPECTEDTSIG ||
|
||||
result == DNS_R_EXPECTEDTSIG)
|
||||
{
|
||||
rctx.nextitem = true;
|
||||
rctx->nextitem = true;
|
||||
}
|
||||
rctx_done(&rctx, result);
|
||||
return;
|
||||
rctx_done(rctx, result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -7415,7 +7449,7 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
*/
|
||||
if (dns_message_gettsig(query->rmessage, NULL) == NULL &&
|
||||
!query->rmessage->cc_ok && !query->rmessage->cc_bad &&
|
||||
(rctx.retryopts & DNS_FETCHOPT_TCP) == 0)
|
||||
(rctx->retryopts & DNS_FETCHOPT_TCP) == 0)
|
||||
{
|
||||
if (dns_adb_getcookie(query->addrinfo, NULL, 0) >
|
||||
CLIENT_COOKIE_SIZE)
|
||||
@ -7431,10 +7465,10 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
"from %s",
|
||||
addrbuf);
|
||||
}
|
||||
rctx.retryopts |= DNS_FETCHOPT_TCP;
|
||||
rctx.resend = true;
|
||||
rctx_done(&rctx, result);
|
||||
return;
|
||||
rctx->retryopts |= DNS_FETCHOPT_TCP;
|
||||
rctx->resend = true;
|
||||
rctx_done(rctx, result);
|
||||
goto cleanup;
|
||||
} else if (fctx->res->view->peers != NULL) {
|
||||
dns_peer_t *peer = NULL;
|
||||
isc_netaddr_t netaddr;
|
||||
@ -7467,47 +7501,47 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
"from %s",
|
||||
addrbuf);
|
||||
}
|
||||
rctx.retryopts |= DNS_FETCHOPT_TCP;
|
||||
rctx.resend = true;
|
||||
rctx_done(&rctx, result);
|
||||
return;
|
||||
rctx->retryopts |= DNS_FETCHOPT_TCP;
|
||||
rctx->resend = true;
|
||||
rctx_done(rctx, result);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rctx_edns(&rctx);
|
||||
rctx_edns(rctx);
|
||||
|
||||
/*
|
||||
* Deal with truncated responses by retrying using TCP.
|
||||
*/
|
||||
if ((query->rmessage->flags & DNS_MESSAGEFLAG_TC) != 0) {
|
||||
rctx.truncated = true;
|
||||
rctx->truncated = true;
|
||||
}
|
||||
|
||||
if (rctx.truncated) {
|
||||
if (rctx->truncated) {
|
||||
inc_stats(fctx->res, dns_resstatscounter_truncated);
|
||||
if ((rctx.retryopts & DNS_FETCHOPT_TCP) != 0) {
|
||||
rctx.broken_server = DNS_R_TRUNCATEDTCP;
|
||||
rctx.next_server = true;
|
||||
if ((rctx->retryopts & DNS_FETCHOPT_TCP) != 0) {
|
||||
rctx->broken_server = DNS_R_TRUNCATEDTCP;
|
||||
rctx->next_server = true;
|
||||
} else {
|
||||
rctx.retryopts |= DNS_FETCHOPT_TCP;
|
||||
rctx.resend = true;
|
||||
rctx->retryopts |= DNS_FETCHOPT_TCP;
|
||||
rctx->resend = true;
|
||||
}
|
||||
FCTXTRACE3("message truncated", result);
|
||||
rctx_done(&rctx, result);
|
||||
return;
|
||||
rctx_done(rctx, result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is it a query response?
|
||||
*/
|
||||
if (query->rmessage->opcode != dns_opcode_query) {
|
||||
rctx.broken_server = DNS_R_UNEXPECTEDOPCODE;
|
||||
rctx.next_server = true;
|
||||
rctx->broken_server = DNS_R_UNEXPECTEDOPCODE;
|
||||
rctx->next_server = true;
|
||||
FCTXTRACE("invalid message opcode");
|
||||
rctx_done(&rctx, result);
|
||||
return;
|
||||
rctx_done(rctx, result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -7543,17 +7577,17 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
/*
|
||||
* Bad server?
|
||||
*/
|
||||
result = rctx_badserver(&rctx, result);
|
||||
result = rctx_badserver(rctx, result);
|
||||
if (result == ISC_R_COMPLETE) {
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lame server?
|
||||
*/
|
||||
result = rctx_lameserver(&rctx);
|
||||
result = rctx_lameserver(rctx);
|
||||
if (result == ISC_R_COMPLETE) {
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -7578,9 +7612,9 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
query->rmessage->rcode == dns_rcode_yxdomain ||
|
||||
query->rmessage->rcode == dns_rcode_nxdomain))
|
||||
{
|
||||
result = rctx_answer(&rctx);
|
||||
result = rctx_answer(rctx);
|
||||
if (result == ISC_R_COMPLETE) {
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
} else if (query->rmessage->counts[DNS_SECTION_AUTHORITY] > 0 ||
|
||||
query->rmessage->rcode == dns_rcode_noerror ||
|
||||
@ -7590,7 +7624,7 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
* This might be an NXDOMAIN, NXRRSET, or referral.
|
||||
* Call rctx_answer_none() to determine which it is.
|
||||
*/
|
||||
result = rctx_answer_none(&rctx);
|
||||
result = rctx_answer_none(rctx);
|
||||
switch (result) {
|
||||
case ISC_R_SUCCESS:
|
||||
case DNS_R_CHASEDSSERVERS:
|
||||
@ -7609,28 +7643,28 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
* Something has gone wrong.
|
||||
*/
|
||||
if (result == DNS_R_FORMERR) {
|
||||
rctx.next_server = true;
|
||||
rctx->next_server = true;
|
||||
}
|
||||
FCTXTRACE3("rctx_answer_none", result);
|
||||
rctx_done(&rctx, result);
|
||||
return;
|
||||
rctx_done(rctx, result);
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* The server is insane.
|
||||
*/
|
||||
/* XXXRTH Log */
|
||||
rctx.broken_server = DNS_R_UNEXPECTEDRCODE;
|
||||
rctx.next_server = true;
|
||||
rctx->broken_server = DNS_R_UNEXPECTEDRCODE;
|
||||
rctx->next_server = true;
|
||||
FCTXTRACE("broken server: unexpected rcode");
|
||||
rctx_done(&rctx, result);
|
||||
return;
|
||||
rctx_done(rctx, result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Follow additional section data chains.
|
||||
*/
|
||||
rctx_additional(&rctx);
|
||||
rctx_additional(rctx);
|
||||
|
||||
/*
|
||||
* Cache the cacheable parts of the message. This may also
|
||||
@ -7639,21 +7673,24 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
|
||||
if (WANTCACHE(fctx)) {
|
||||
isc_result_t tresult;
|
||||
tresult = cache_message(fctx, query->rmessage, query->addrinfo,
|
||||
rctx.now);
|
||||
rctx->now);
|
||||
if (tresult != ISC_R_SUCCESS) {
|
||||
FCTXTRACE3("cache_message complete", tresult);
|
||||
rctx_done(&rctx, tresult);
|
||||
return;
|
||||
rctx_done(rctx, tresult);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Negative caching
|
||||
*/
|
||||
rctx_ncache(&rctx);
|
||||
rctx_ncache(rctx);
|
||||
|
||||
FCTXTRACE("resquery_response done");
|
||||
rctx_done(&rctx, result);
|
||||
rctx_done(rctx, result);
|
||||
|
||||
cleanup:
|
||||
isc_mem_putanddetach(&rctx->mctx, rctx, sizeof(*rctx));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -7680,6 +7717,7 @@ rctx_respinit(resquery_t *query, fetchctx_t *fctx, isc_result_t result,
|
||||
rctx->tnow = isc_time_now();
|
||||
rctx->finish = &rctx->tnow;
|
||||
rctx->now = (isc_stdtime_t)isc_time_seconds(&rctx->tnow);
|
||||
isc_mem_attach(fctx->mctx, &rctx->mctx);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2073,6 +2073,21 @@ check_options(const cfg_obj_t *options, const cfg_obj_t *config,
|
||||
|
||||
cfg_aclconfctx_create(mctx, &actx);
|
||||
|
||||
obj = NULL;
|
||||
(void)cfg_map_get(options, "sig0checks-quota-exempt", &obj);
|
||||
if (obj != NULL) {
|
||||
dns_acl_t *acl = NULL;
|
||||
|
||||
tresult = cfg_acl_fromconfig(obj, config, logctx, actx, mctx, 0,
|
||||
&acl);
|
||||
if (acl != NULL) {
|
||||
dns_acl_detach(&acl);
|
||||
}
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = tresult;
|
||||
}
|
||||
}
|
||||
|
||||
obj = NULL;
|
||||
(void)cfg_map_get(options, "listen-on", &obj);
|
||||
if (obj != NULL) {
|
||||
|
@ -1361,6 +1361,9 @@ static cfg_clausedef_t options_clauses[] = {
|
||||
{ "session-keyalg", &cfg_type_astring, 0 },
|
||||
{ "session-keyfile", &cfg_type_qstringornone, 0 },
|
||||
{ "session-keyname", &cfg_type_astring, 0 },
|
||||
{ "sig0checks-quota", &cfg_type_uint32, CFG_CLAUSEFLAG_EXPERIMENTAL },
|
||||
{ "sig0checks-quota-exempt", &cfg_type_bracketed_aml,
|
||||
CFG_CLAUSEFLAG_EXPERIMENTAL },
|
||||
{ "sit-secret", NULL, CFG_CLAUSEFLAG_ANCIENT },
|
||||
{ "stacksize", &cfg_type_size, CFG_CLAUSEFLAG_ANCIENT },
|
||||
{ "startup-notify-rate", &cfg_type_uint32, 0 },
|
||||
|
238
lib/ns/client.c
238
lib/ns/client.c
@ -118,11 +118,27 @@
|
||||
|
||||
atomic_uint_fast64_t ns_client_requests = 0;
|
||||
|
||||
static atomic_uint_fast32_t last_sigchecks_quota_log = 0;
|
||||
|
||||
static bool
|
||||
can_log_sigchecks_quota(void) {
|
||||
isc_stdtime_t last;
|
||||
isc_stdtime_t now = isc_stdtime_now();
|
||||
last = atomic_exchange_relaxed(&last_sigchecks_quota_log, now);
|
||||
if (now != last) {
|
||||
return (true);
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
static void
|
||||
clientmgr_destroy_cb(void *arg);
|
||||
static void
|
||||
ns_client_dumpmessage(ns_client_t *client, const char *reason);
|
||||
static void
|
||||
ns_client_request_continue(void *arg);
|
||||
static void
|
||||
compute_cookie(ns_client_t *client, uint32_t when, const unsigned char *secret,
|
||||
isc_buffer_t *buf);
|
||||
|
||||
@ -1667,6 +1683,16 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) {
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
ns_client_async_reset(ns_client_t *client) {
|
||||
if (client->async) {
|
||||
client->async = false;
|
||||
if (client->handle != NULL) {
|
||||
isc_nmhandle_unref(client->handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ns__client_reset_cb(void *client0) {
|
||||
ns_client_t *client = client0;
|
||||
@ -1693,6 +1719,8 @@ ns__client_reset_cb(void *client0) {
|
||||
client->keytag_len = 0;
|
||||
}
|
||||
|
||||
ns_client_async_reset(client);
|
||||
|
||||
client->state = NS_CLIENTSTATE_READY;
|
||||
|
||||
#ifdef WANT_SINGLETRACE
|
||||
@ -1726,6 +1754,8 @@ ns__client_put_cb(void *client0) {
|
||||
dns_message_puttemprdataset(client->message, &client->opt);
|
||||
}
|
||||
|
||||
ns_client_async_reset(client);
|
||||
|
||||
dns_message_detach(&client->message);
|
||||
|
||||
/*
|
||||
@ -1739,6 +1769,42 @@ ns__client_put_cb(void *client0) {
|
||||
ns_clientmgr_detach(&manager);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
ns_client_setup_view(ns_client_t *client, isc_netaddr_t *netaddr) {
|
||||
isc_result_t result;
|
||||
|
||||
client->sigresult = client->viewmatchresult = ISC_R_UNSET;
|
||||
|
||||
if (client->async) {
|
||||
isc_nmhandle_ref(client->handle);
|
||||
}
|
||||
|
||||
result = client->manager->sctx->matchingview(
|
||||
netaddr, &client->destaddr, client->message,
|
||||
client->manager->aclenv, client->manager->sctx,
|
||||
client->async ? client->manager->loop : NULL,
|
||||
ns_client_request_continue, client, &client->sigresult,
|
||||
&client->viewmatchresult, &client->view);
|
||||
|
||||
/* Async mode. */
|
||||
if (result == DNS_R_WAIT) {
|
||||
INSIST(client->async == true);
|
||||
return (DNS_R_WAIT);
|
||||
}
|
||||
|
||||
/*
|
||||
* matchingview() returning anything other than DNS_R_WAIT means it's
|
||||
* not running in async mode, in which case 'result' must be equal to
|
||||
* 'client->viewmatchresult'.
|
||||
*/
|
||||
INSIST(result == client->viewmatchresult);
|
||||
|
||||
/* Non-async mode. */
|
||||
ns_client_async_reset(client);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle an incoming request event from the socket (UDP case)
|
||||
* or tcpmsg (TCP case).
|
||||
@ -1748,12 +1814,7 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
isc_region_t *region, void *arg) {
|
||||
ns_client_t *client = NULL;
|
||||
isc_result_t result;
|
||||
isc_result_t sigresult = ISC_R_SUCCESS;
|
||||
isc_buffer_t *buffer = NULL;
|
||||
isc_buffer_t tbuffer;
|
||||
dns_rdataset_t *opt = NULL;
|
||||
const dns_name_t *signame = NULL;
|
||||
bool ra; /* Recursion available. */
|
||||
isc_netaddr_t netaddr;
|
||||
int match;
|
||||
dns_messageid_t id;
|
||||
@ -1761,28 +1822,6 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
bool notimp;
|
||||
size_t reqsize;
|
||||
dns_aclenv_t *env = NULL;
|
||||
#ifdef HAVE_DNSTAP
|
||||
dns_transport_type_t transport_type;
|
||||
dns_dtmsgtype_t dtmsgtype;
|
||||
#endif /* ifdef HAVE_DNSTAP */
|
||||
static const char *ra_reasons[] = {
|
||||
"ACLs not processed yet",
|
||||
"no resolver in view",
|
||||
"recursion not enabled for view",
|
||||
"allow-recursion did not match",
|
||||
"allow-query-cache did not match",
|
||||
"allow-recursion-on did not match",
|
||||
"allow-query-cache-on did not match",
|
||||
};
|
||||
enum refusal_reasons {
|
||||
INVALID,
|
||||
NO_RESOLVER,
|
||||
RECURSION_DISABLED,
|
||||
ALLOW_RECURSION,
|
||||
ALLOW_QUERY_CACHE,
|
||||
ALLOW_RECURSION_ON,
|
||||
ALLOW_QUERY_CACHE_ON
|
||||
} ra_refusal_reason = INVALID;
|
||||
|
||||
if (eresult != ISC_R_SUCCESS) {
|
||||
return;
|
||||
@ -1830,14 +1869,14 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
|
||||
(void)atomic_fetch_add_relaxed(&ns_client_requests, 1);
|
||||
|
||||
isc_buffer_init(&tbuffer, region->base, region->length);
|
||||
isc_buffer_add(&tbuffer, region->length);
|
||||
buffer = &tbuffer;
|
||||
isc_buffer_init(&client->tbuffer, region->base, region->length);
|
||||
isc_buffer_add(&client->tbuffer, region->length);
|
||||
client->buffer = &client->tbuffer;
|
||||
|
||||
client->peeraddr = isc_nmhandle_peeraddr(handle);
|
||||
client->peeraddr_valid = true;
|
||||
|
||||
reqsize = isc_buffer_usedlength(buffer);
|
||||
reqsize = isc_buffer_usedlength(client->buffer);
|
||||
|
||||
client->state = NS_CLIENTSTATE_WORKING;
|
||||
|
||||
@ -1876,7 +1915,7 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
ISC_LOG_DEBUG(3), "%s request",
|
||||
TCP_CLIENT(client) ? "TCP" : "UDP");
|
||||
|
||||
result = dns_message_peekheader(buffer, &id, &flags);
|
||||
result = dns_message_peekheader(client->buffer, &id, &flags);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
/*
|
||||
* There isn't enough header to determine whether
|
||||
@ -1951,7 +1990,7 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
/*
|
||||
* It's a request. Parse it.
|
||||
*/
|
||||
result = dns_message_parse(client->message, buffer, 0);
|
||||
result = dns_message_parse(client->message, client->buffer, 0);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
/*
|
||||
* Parsing the request failed. Send a response
|
||||
@ -2080,36 +2119,107 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
client->destsockaddr = isc_nmhandle_localaddr(handle);
|
||||
isc_netaddr_fromsockaddr(&client->destaddr, &client->destsockaddr);
|
||||
|
||||
result = client->manager->sctx->matchingview(
|
||||
&netaddr, &client->destaddr, client->message, env, &sigresult,
|
||||
&client->view);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
char classname[DNS_RDATACLASS_FORMATSIZE];
|
||||
/*
|
||||
* Offload view matching only if we are going to check a SIG(0)
|
||||
* signature.
|
||||
*/
|
||||
client->async = (client->message->tsigkey == NULL &&
|
||||
client->message->tsig == NULL &&
|
||||
client->message->sig0 != NULL);
|
||||
|
||||
result = ns_client_setup_view(client, &netaddr);
|
||||
if (result == DNS_R_WAIT) {
|
||||
return;
|
||||
}
|
||||
|
||||
ns_client_request_continue(client);
|
||||
}
|
||||
|
||||
static void
|
||||
ns_client_request_continue(void *arg) {
|
||||
ns_client_t *client = arg;
|
||||
const dns_name_t *signame = NULL;
|
||||
bool ra; /* Recursion available. */
|
||||
isc_result_t result = ISC_R_UNSET;
|
||||
static const char *ra_reasons[] = {
|
||||
"ACLs not processed yet",
|
||||
"no resolver in view",
|
||||
"recursion not enabled for view",
|
||||
"allow-recursion did not match",
|
||||
"allow-query-cache did not match",
|
||||
"allow-recursion-on did not match",
|
||||
"allow-query-cache-on did not match",
|
||||
};
|
||||
enum refusal_reasons {
|
||||
INVALID,
|
||||
NO_RESOLVER,
|
||||
RECURSION_DISABLED,
|
||||
ALLOW_RECURSION,
|
||||
ALLOW_QUERY_CACHE,
|
||||
ALLOW_RECURSION_ON,
|
||||
ALLOW_QUERY_CACHE_ON
|
||||
} ra_refusal_reason = INVALID;
|
||||
#ifdef HAVE_DNSTAP
|
||||
dns_transport_type_t transport_type;
|
||||
dns_dtmsgtype_t dtmsgtype;
|
||||
#endif /* ifdef HAVE_DNSTAP */
|
||||
|
||||
INSIST(client->viewmatchresult != ISC_R_UNSET);
|
||||
|
||||
/*
|
||||
* This function could be running asynchronously, in which case update
|
||||
* the current 'now' for correct timekeeping.
|
||||
*/
|
||||
if (client->async) {
|
||||
client->tnow = isc_time_now();
|
||||
client->now = isc_time_seconds(&client->tnow);
|
||||
}
|
||||
|
||||
if (client->viewmatchresult != ISC_R_SUCCESS) {
|
||||
isc_buffer_t b;
|
||||
isc_region_t *r;
|
||||
|
||||
/*
|
||||
* Do a dummy TSIG verification attempt so that the
|
||||
* response will have a TSIG if the query did, as
|
||||
* required by RFC2845.
|
||||
*/
|
||||
isc_buffer_t b;
|
||||
isc_region_t *r;
|
||||
|
||||
dns_message_resetsig(client->message);
|
||||
|
||||
r = dns_message_getrawmessage(client->message);
|
||||
isc_buffer_init(&b, r->base, r->length);
|
||||
isc_buffer_add(&b, r->length);
|
||||
(void)dns_tsig_verify(&b, client->message, NULL, NULL);
|
||||
|
||||
dns_rdataclass_format(client->message->rdclass, classname,
|
||||
sizeof(classname));
|
||||
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
||||
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
|
||||
"no matching view in class '%s'", classname);
|
||||
ns_client_dumpmessage(client, "no matching view in class");
|
||||
if (client->viewmatchresult == ISC_R_QUOTA) {
|
||||
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
||||
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(5),
|
||||
"SIG(0) checks quota reached");
|
||||
|
||||
if (can_log_sigchecks_quota()) {
|
||||
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
||||
NS_LOGMODULE_CLIENT, ISC_LOG_INFO,
|
||||
"SIG(0) checks quota reached");
|
||||
ns_client_dumpmessage(
|
||||
client, "SIG(0) checks quota reached");
|
||||
}
|
||||
} else {
|
||||
char classname[DNS_RDATACLASS_FORMATSIZE];
|
||||
|
||||
dns_rdataclass_format(client->message->rdclass,
|
||||
classname, sizeof(classname));
|
||||
|
||||
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
||||
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
|
||||
"no matching view in class '%s'",
|
||||
classname);
|
||||
ns_client_dumpmessage(client,
|
||||
"no matching view in class");
|
||||
}
|
||||
|
||||
ns_client_extendederror(client, DNS_EDE_PROHIBITED, NULL);
|
||||
ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_REFUSED);
|
||||
return;
|
||||
ns_client_error(client, DNS_R_REFUSED);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (isc_nm_is_proxy_handle(client->handle)) {
|
||||
@ -2140,8 +2250,8 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
"ACL",
|
||||
fmtbuf);
|
||||
}
|
||||
isc_nm_bad_request(handle);
|
||||
return;
|
||||
isc_nm_bad_request(client->handle);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* allow by default */
|
||||
@ -2161,8 +2271,8 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
"'allow-proxy-on' ACL",
|
||||
fmtbuf);
|
||||
}
|
||||
isc_nm_bad_request(handle);
|
||||
return;
|
||||
isc_nm_bad_request(client->handle);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2255,8 +2365,8 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
if (!(client->message->tsigstatus == dns_tsigerror_badkey &&
|
||||
client->message->opcode == dns_opcode_update))
|
||||
{
|
||||
ns_client_error(client, sigresult);
|
||||
return;
|
||||
ns_client_error(client, client->sigresult);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2311,6 +2421,9 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
if (client->udpsize > 512) {
|
||||
dns_peer_t *peer = NULL;
|
||||
uint16_t udpsize = client->view->maxudp;
|
||||
isc_netaddr_t netaddr;
|
||||
|
||||
isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
|
||||
(void)dns_peerlist_peerbyaddr(client->view->peers, &netaddr,
|
||||
&peer);
|
||||
if (peer != NULL) {
|
||||
@ -2340,25 +2453,25 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
|
||||
dns_dt_send(client->view, dtmsgtype, &client->peeraddr,
|
||||
&client->destsockaddr, transport_type, NULL,
|
||||
&client->requesttime, NULL, buffer);
|
||||
&client->requesttime, NULL, client->buffer);
|
||||
#endif /* HAVE_DNSTAP */
|
||||
|
||||
ns_query_start(client, handle);
|
||||
ns_query_start(client, client->handle);
|
||||
break;
|
||||
case dns_opcode_update:
|
||||
CTRACE("update");
|
||||
#ifdef HAVE_DNSTAP
|
||||
dns_dt_send(client->view, DNS_DTTYPE_UQ, &client->peeraddr,
|
||||
&client->destsockaddr, transport_type, NULL,
|
||||
&client->requesttime, NULL, buffer);
|
||||
&client->requesttime, NULL, client->buffer);
|
||||
#endif /* HAVE_DNSTAP */
|
||||
ns_client_settimeout(client, 60);
|
||||
ns_update_start(client, handle, sigresult);
|
||||
ns_update_start(client, client->handle, client->sigresult);
|
||||
break;
|
||||
case dns_opcode_notify:
|
||||
CTRACE("notify");
|
||||
ns_client_settimeout(client, 60);
|
||||
ns_notify_start(client, handle);
|
||||
ns_notify_start(client, client->handle);
|
||||
break;
|
||||
case dns_opcode_iquery:
|
||||
CTRACE("iquery");
|
||||
@ -2368,6 +2481,9 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
CTRACE("unknown opcode");
|
||||
ns_client_error(client, DNS_R_NOTIMP);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
ns_client_async_reset(client);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
|
@ -167,6 +167,7 @@ struct ns_client {
|
||||
ns_clientmgr_t *manager;
|
||||
ns_clientstate_t state;
|
||||
bool nodetach;
|
||||
bool async;
|
||||
unsigned int attributes;
|
||||
dns_view_t *view;
|
||||
dns_dispatch_t *dispatch;
|
||||
@ -192,6 +193,10 @@ struct ns_client {
|
||||
isc_time_t tnow;
|
||||
dns_name_t signername; /*%< [T]SIG key name */
|
||||
dns_name_t *signer; /*%< NULL if not valid sig */
|
||||
isc_result_t sigresult;
|
||||
isc_result_t viewmatchresult;
|
||||
isc_buffer_t *buffer;
|
||||
isc_buffer_t tbuffer;
|
||||
|
||||
isc_sockaddr_t peeraddr;
|
||||
bool peeraddr_valid;
|
||||
|
@ -66,7 +66,9 @@ typedef void (*ns_fuzzcb_t)(void);
|
||||
*/
|
||||
typedef isc_result_t (*ns_matchview_t)(
|
||||
isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr, dns_message_t *message,
|
||||
dns_aclenv_t *env, isc_result_t *sigresultp, dns_view_t **viewp);
|
||||
dns_aclenv_t *env, ns_server_t *sctx, isc_loop_t *loop, isc_job_cb cb,
|
||||
void *cbarg, isc_result_t *sigresultp, isc_result_t *viewmatchresult,
|
||||
dns_view_t **viewp);
|
||||
|
||||
/*%
|
||||
* Server context.
|
||||
@ -88,6 +90,8 @@ struct ns_server {
|
||||
isc_quota_t tcpquota;
|
||||
isc_quota_t xfroutquota;
|
||||
isc_quota_t updquota;
|
||||
isc_quota_t sig0checksquota;
|
||||
dns_acl_t *sig0checksquota_exempt;
|
||||
ISC_LIST(isc_quota_t) http_quotas;
|
||||
isc_mutex_t http_quotas_lock;
|
||||
|
||||
|
@ -66,6 +66,7 @@ ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview,
|
||||
isc_quota_init(&sctx->tcpquota, 10);
|
||||
isc_quota_init(&sctx->recursionquota, 100);
|
||||
isc_quota_init(&sctx->updquota, 100);
|
||||
isc_quota_init(&sctx->sig0checksquota, 1);
|
||||
ISC_LIST_INIT(sctx->http_quotas);
|
||||
isc_mutex_init(&sctx->http_quotas_lock);
|
||||
|
||||
@ -134,6 +135,11 @@ ns_server_detach(ns_server_t **sctxp) {
|
||||
isc_mem_put(sctx->mctx, altsecret, sizeof(*altsecret));
|
||||
}
|
||||
|
||||
if (sctx->sig0checksquota_exempt != NULL) {
|
||||
dns_acl_detach(&sctx->sig0checksquota_exempt);
|
||||
}
|
||||
|
||||
isc_quota_destroy(&sctx->sig0checksquota);
|
||||
isc_quota_destroy(&sctx->updquota);
|
||||
isc_quota_destroy(&sctx->recursionquota);
|
||||
isc_quota_destroy(&sctx->tcpquota);
|
||||
|
@ -57,15 +57,22 @@ ns_server_t *sctx = NULL;
|
||||
|
||||
static isc_result_t
|
||||
matchview(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
|
||||
dns_message_t *message, dns_aclenv_t *env, isc_result_t *sigresultp,
|
||||
dns_message_t *message, dns_aclenv_t *env, ns_server_t *lsctx,
|
||||
isc_loop_t *loop, isc_job_cb cb, void *cbarg,
|
||||
isc_result_t *sigresultp, isc_result_t *viewmatchresultp,
|
||||
dns_view_t **viewp) {
|
||||
UNUSED(srcaddr);
|
||||
UNUSED(destaddr);
|
||||
UNUSED(message);
|
||||
UNUSED(env);
|
||||
UNUSED(lsctx);
|
||||
UNUSED(loop);
|
||||
UNUSED(cb);
|
||||
UNUSED(cbarg);
|
||||
UNUSED(sigresultp);
|
||||
UNUSED(viewp);
|
||||
|
||||
*viewmatchresultp = ISC_R_NOTIMPLEMENTED;
|
||||
return (ISC_R_NOTIMPLEMENTED);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user