mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-12 16:50:00 -04:00
new: usr: Add support for EDNS ZONEVERSION option
`dig` and `named` can now make requests with an EDNS `ZONEVERSION` option present. Two new `named.conf` options have been added: `request-zoneversion` and `provide-zoneversion`. `request-zoneversion` is `off` by default. `provide-zoneversion` is `on` by default. Closes #4767 Merge branch '4767-implement-zoneversion' into 'main' See merge request isc-projects/bind9!9103
This commit is contained in:
commit
908840157e
41 changed files with 865 additions and 148 deletions
|
|
@ -328,6 +328,7 @@ help(void) {
|
|||
" +[no]yaml (Present the results as "
|
||||
"YAML)\n"
|
||||
" +[no]zflag (Set Z flag in query)\n"
|
||||
" +[no]zoneversion (Request zone version)\n"
|
||||
" global d-opts and servers (before host name) affect "
|
||||
"all "
|
||||
"queries.\n"
|
||||
|
|
@ -2574,9 +2575,22 @@ plus_option(char *option, bool is_batchfile, bool *need_clone,
|
|||
lookup->rrcomments = -1;
|
||||
}
|
||||
break;
|
||||
case 'z': /* zflag */
|
||||
FULLCHECK("zflag");
|
||||
lookup->zflag = state;
|
||||
case 'z':
|
||||
switch (cmd[1]) {
|
||||
case 'f': /* zflag */
|
||||
FULLCHECK("zflag");
|
||||
lookup->zflag = state;
|
||||
break;
|
||||
case 'o': /* zoneversion */
|
||||
FULLCHECK("zoneversion");
|
||||
if (state && lookup->edns == -1) {
|
||||
lookup->edns = DEFAULT_EDNS_VERSION;
|
||||
}
|
||||
lookup->zoneversion = state;
|
||||
break;
|
||||
default:
|
||||
goto invalid_option;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
invalid_option:
|
||||
|
|
|
|||
|
|
@ -757,6 +757,10 @@ abbreviation is unambiguous; for example, :option:`+cd` is equivalent to
|
|||
This option sets [or does not set] the last unassigned DNS header flag in a DNS query.
|
||||
This flag is off by default.
|
||||
|
||||
.. option:: +zoneversion, +nozoneversion
|
||||
|
||||
When enabled, this option includes an EDNS Zone Version request when sending a query.
|
||||
|
||||
Multiple Queries
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -705,6 +705,7 @@ clone_lookup(dig_lookup_t *lookold, bool servers) {
|
|||
looknew->opcode = lookold->opcode;
|
||||
looknew->expire = lookold->expire;
|
||||
looknew->nsid = lookold->nsid;
|
||||
looknew->zoneversion = lookold->zoneversion;
|
||||
looknew->tcp_keepalive = lookold->tcp_keepalive;
|
||||
looknew->header_only = lookold->header_only;
|
||||
looknew->https_mode = lookold->https_mode;
|
||||
|
|
@ -2591,6 +2592,14 @@ setup_lookup(dig_lookup_t *lookup) {
|
|||
i++;
|
||||
}
|
||||
|
||||
if (lookup->zoneversion) {
|
||||
INSIST(i < MAXOPTS);
|
||||
opts[i].code = DNS_OPT_ZONEVERSION;
|
||||
opts[i].length = 0;
|
||||
opts[i].value = NULL;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (lookup->ednsoptscnt != 0) {
|
||||
INSIST(i + lookup->ednsoptscnt <= MAXOPTS);
|
||||
memmove(&opts[i], lookup->ednsopts,
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ struct dig_lookup {
|
|||
tcp_mode, tcp_mode_set, tls_mode, /*% connect using TLS */
|
||||
trace, /*% dig +trace */
|
||||
trace_root, /*% initial query for either +trace or +nssearch */
|
||||
ttlunits, use_usec, waiting_connect, zflag;
|
||||
ttlunits, use_usec, waiting_connect, zflag, zoneversion;
|
||||
char textname[MXNAME]; /*% Name we're going to be looking up */
|
||||
char cmdline[MXNAME];
|
||||
dns_rdatatype_t rdtype;
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ options {\n\
|
|||
recursing-file \"named.recursing\";\n\
|
||||
recursive-clients 1000;\n\
|
||||
request-nsid false;\n\
|
||||
request-zoneversion false;\n\
|
||||
resolver-query-timeout 10;\n\
|
||||
# responselog <boolean>;\n\
|
||||
rrset-order { order random; };\n\
|
||||
|
|
@ -239,6 +240,7 @@ options {\n\
|
|||
notify yes;\n\
|
||||
notify-delay 5;\n\
|
||||
notify-to-soa no;\n\
|
||||
provide-zoneversion yes;\n\
|
||||
send-report-channel .;\n\
|
||||
serial-update-method increment;\n\
|
||||
sig-signing-nodes 100;\n\
|
||||
|
|
@ -260,6 +262,7 @@ view \"_bind\" chaos {\n\
|
|||
notify no;\n\
|
||||
allow-new-zones no;\n\
|
||||
max-cache-size 2M;\n\
|
||||
provide-zoneversion no;\n\
|
||||
\n\
|
||||
# Prevent use of this zone in DNS amplified reflection DoS attacks\n\
|
||||
rate-limit {\n\
|
||||
|
|
|
|||
|
|
@ -1391,6 +1391,13 @@ configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
|
|||
CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
|
||||
}
|
||||
|
||||
obj = NULL;
|
||||
(void)cfg_map_get(cpeer, "request-zoneversion", &obj);
|
||||
if (obj != NULL) {
|
||||
CHECK(dns_peer_setrequestzoneversion(peer,
|
||||
cfg_obj_asboolean(obj)));
|
||||
}
|
||||
|
||||
obj = NULL;
|
||||
(void)cfg_map_get(cpeer, "send-cookie", &obj);
|
||||
if (obj != NULL) {
|
||||
|
|
@ -3246,6 +3253,7 @@ create_empty_zone(dns_zone_t *pzone, dns_name_t *name, dns_view_t *view,
|
|||
|
||||
dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, false);
|
||||
dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
|
||||
dns_zone_setoption(zone, DNS_ZONEOPT_ZONEVERSION, false);
|
||||
dns_zone_setcheckdstype(zone, dns_checkdstype_no);
|
||||
dns_zone_setnotifytype(zone, dns_notifytype_no);
|
||||
dns_zone_setautomatic(zone, true);
|
||||
|
|
@ -5132,6 +5140,11 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
|||
INSIST(result == ISC_R_SUCCESS);
|
||||
view->requestnsid = cfg_obj_asboolean(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "request-zoneversion", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
view->requestzoneversion = cfg_obj_asboolean(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "send-cookie", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
|
|
|
|||
|
|
@ -358,6 +358,8 @@ init_desc(void) {
|
|||
SET_NSSTATDESC(expireopt, "Expire option received", "ExpireOpt");
|
||||
SET_NSSTATDESC(keepaliveopt, "EDNS TCP keepalive option received",
|
||||
"KeepAliveOpt");
|
||||
SET_NSSTATDESC(zoneversionopt, "ZONEVERSION option received",
|
||||
"ZoneVersionOpt");
|
||||
SET_NSSTATDESC(padopt, "EDNS padding option received", "PadOpt");
|
||||
SET_NSSTATDESC(otheropt, "Other EDNS option received", "OtherOpt");
|
||||
SET_NSSTATDESC(cookiein, "COOKIE option received", "CookieIn");
|
||||
|
|
|
|||
|
|
@ -1227,6 +1227,12 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
|
|||
dns_zone_setkasp(zone, NULL);
|
||||
}
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "provide-zoneversion", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS && obj != NULL);
|
||||
dns_zone_setoption(zone, DNS_ZONEOPT_ZONEVERSION,
|
||||
cfg_obj_asboolean(obj));
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "notify", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS && obj != NULL);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ server 0.0.0.0 {
|
|||
request-ixfr no;
|
||||
request-ixfr-max-diffs 0;
|
||||
request-nsid no;
|
||||
request-zoneversion no;
|
||||
require-cookie no;
|
||||
send-cookie no;
|
||||
tcp-keepalive no;
|
||||
|
|
@ -55,6 +56,7 @@ server :: {
|
|||
request-ixfr no;
|
||||
request-ixfr-max-diffs 0;
|
||||
request-nsid no;
|
||||
request-zoneversion no;
|
||||
require-cookie no;
|
||||
send-cookie no;
|
||||
tcp-keepalive no;
|
||||
|
|
|
|||
|
|
@ -36,4 +36,5 @@ zone "example" {
|
|||
zone "example.tld" {
|
||||
type primary;
|
||||
file "example.tld.db";
|
||||
provide-zoneversion no;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -801,6 +801,73 @@ if [ -x "$DIG" ]; then
|
|||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking dig +zoneversion to a authoritative server ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.2 +zoneversion a.example >dig.out.test$n 2>&1 || ret=1
|
||||
pat="; ZONEVERSION: ZONE: example, SOA-SERIAL: 2000042407"
|
||||
grep "$pat" dig.out.test$n >/dev/null || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking dig +zoneversion to a authoritative server with zoneversion disabled ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.2 +zoneversion a.example.tld >dig.out.test$n 2>&1 || ret=1
|
||||
grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
|
||||
grep "; ZONEVERSION:" dig.out.test$n >/dev/null && ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
if [ $HAS_PYYAML -ne 0 ]; then
|
||||
n=$((n + 1))
|
||||
echo_i "checking dig +yaml +zoneversion to a authoritative server ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.2 +yaml +zoneversion a.example >dig.out.test$n 2>&1 || ret=1
|
||||
$PYTHON yamlget.py dig.out.test$n 0 message response_message_data OPT_PSEUDOSECTION EDNS ZONEVERSION >yamlget.out.test$n 2>&1 || ret=1
|
||||
read -r value <yamlget.out.test$n
|
||||
expected="{'ZONE': 'example', 'SOA-SERIAL': 2000042407}"
|
||||
[ "$value" = "$expected" ] || ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
fi
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking dig +ednsopt=ZONEVERSION:<answer> to a authoritative server ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.2 +ednsopt=ZONEVERSION:0100000007DA a.example >dig.out.test$n 2>&1 || ret=1
|
||||
grep "status: FORMERR" dig.out.test$n >/dev/null || ret=1
|
||||
grep "; ZONEVERSION:" dig.out.test$n >/dev/null && ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking dig +zoneversion to a recursive server ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.3 +zoneversion a.example >dig.out.test$n 2>&1 || ret=1
|
||||
grep '; ZONEVERSION:' dig.out.test$n >/dev/null && ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "checking display of non serial type zoneversion ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.2 +qr +ednsopt=ZONEVERSION:0100000007DA a.example >dig.out.test$n 2>&1 || ret=1
|
||||
grep '; ZONEVERSION: LABELS: 1, TYPE: 0, VALUE: 000007da ("....")' dig.out.test$n >/dev/null && ret=1
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
if [ $HAS_PYYAML -ne 0 ]; then
|
||||
n=$((n + 1))
|
||||
echo_i "checking display of non serial type zoneversion +yaml ($n)"
|
||||
ret=0
|
||||
dig_with_opts @10.53.0.2 +qr +ednsopt=ZONEVERSION:0100000007DA a.example +yaml >dig.out.test$n 2>&1 || ret=1
|
||||
$PYTHON yamlget.py dig.out.test$n 0 message query_message_data OPT_PSEUDOSECTION EDNS ZONEVERSION >yamlget.out.test$n 2>&1 || ret=1
|
||||
expected="{'ZONE': 'example', 'TYPE': 1, 'VALUE': 000007da, PVALUE: '....'}"
|
||||
if [ $ret -ne 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
fi
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that dig gracefully handles bad escape in domain name ($n)"
|
||||
ret=0
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ use IO::Socket;
|
|||
use Net::DNS;
|
||||
use Net::DNS::Packet;
|
||||
|
||||
print "Using Net::DNS $Net::DNS::VERSION\n";
|
||||
|
||||
my $localport = int($ENV{'PORT'});
|
||||
if (!$localport) { $localport = 5300; }
|
||||
|
||||
|
|
@ -170,6 +172,15 @@ for (;;) {
|
|||
$packet->push("authority",
|
||||
new Net::DNS::RR($qname . " 300 SOA . . 0 0 0 0 0"));
|
||||
}
|
||||
} elsif ($qname eq "zoneversion") {
|
||||
$packet->push("authority", new Net::DNS::RR(". 300 SOA . . 0 0 0 0 0"));
|
||||
if ($Net::DNS::VERSION >= 1.49) {
|
||||
$packet->edns->option('ZONEVERSION' => [0, 1, '01022304'] )
|
||||
} elsif ($Net::DNS::VERSION >= 1.35) {
|
||||
$packet->edns->option('19' => {'BASE16' => '000101022304'} )
|
||||
} else {
|
||||
$packet->edns->option('19' => pack 'H*', '000101022304')
|
||||
}
|
||||
} else {
|
||||
# Data for the "bogus referrals" test
|
||||
$packet->push("authority", new Net::DNS::RR("below.www.example.com 300 NS ns.below.www.example.com"));
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ options {
|
|||
resolver-query-timeout 5000; # 5 seconds
|
||||
attach-cache "globalcache";
|
||||
max-recursion-queries 100;
|
||||
request-zoneversion yes;
|
||||
};
|
||||
|
||||
trust-anchors { };
|
||||
|
|
|
|||
|
|
@ -26,6 +26,15 @@ options {
|
|||
querylog yes;
|
||||
prefetch 4 10;
|
||||
responselog yes;
|
||||
request-nsid yes;
|
||||
request-zoneversion yes;
|
||||
};
|
||||
|
||||
// Don't break tests which depend on ans10 by requesting
|
||||
// zoneversion or nsid
|
||||
server 10.53.0.10 {
|
||||
request-nsid no;
|
||||
request-zoneversion no;
|
||||
};
|
||||
|
||||
include "trusted.conf";
|
||||
|
|
|
|||
|
|
@ -901,6 +901,23 @@ test ${lines:-1} -ne 0 && ret=1
|
|||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that received ZONEVERSION is logged ($n)"
|
||||
ret=0
|
||||
pat="received ZONEVERSION serial 2010 from 10.53.0.4#[0-9]* for mixedttl.tld/TXT zone tld"
|
||||
grep "$pat" ns5/named.run >/dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check that received ZONEVERSION is logged non serial ($n)"
|
||||
ret=0
|
||||
dig_with_opts +tcp @10.53.0.1 zoneversion >dig.out.${n} || ret=1
|
||||
pat='received ZONEVERSION type 1 value 01022304 (\.\.#\.) from 10.53.0.2#[0-9]* for zoneversion/A zone \.'
|
||||
grep "$pat" ns1/named.run >/dev/null || ret=1
|
||||
if [ $ret != 0 ]; then echo_i "failed"; fi
|
||||
status=$((status + ret))
|
||||
|
||||
n=$((n + 1))
|
||||
echo_i "check resolver behavior when FORMERR for EDNS options happens (${n})"
|
||||
ret=0
|
||||
|
|
|
|||
|
|
@ -127,3 +127,7 @@
|
|||
|
||||
``zoneload``
|
||||
Loading of zones and creation of automatic empty zones.
|
||||
|
||||
``zoneversion``
|
||||
ZONEVERSION options received from upstream servers.
|
||||
|
||||
|
|
|
|||
|
|
@ -2165,6 +2165,14 @@ Boolean Options
|
|||
ultimate primary should be set to still send NOTIFY messages to all the name servers
|
||||
listed in the NS RRset.
|
||||
|
||||
.. namedconf:statement:: provide-zoneversion
|
||||
:tags: transfer
|
||||
:short: Controls the return EDNS ZONEVERSION answers.
|
||||
|
||||
If ``yes`` EDNS ZONEVERSION answers will be returned otherwise
|
||||
not for primary, secondary and mirror zones. The default is
|
||||
``yes``.
|
||||
|
||||
.. namedconf:statement:: recursion
|
||||
:tags: query
|
||||
:short: Defines whether recursion and caching are allowed.
|
||||
|
|
@ -2188,6 +2196,18 @@ Boolean Options
|
|||
option in its response, then its contents are logged in the ``nsid``
|
||||
category at level ``info``. The default is ``no``.
|
||||
|
||||
.. namedconf:statement:: request-zoneversion
|
||||
:tags: query
|
||||
:short: Controls whether an empty EDNS(0) ZONEVERSION option is sent with all queries to authoritative name servers during iterative resolution.
|
||||
|
||||
If ``yes``, then an empty EDNS(0) ZONEVERSION option is sent
|
||||
with all queries to authoritative name servers during iterative
|
||||
resolution. If the authoritative server returns an ZONEVERSION
|
||||
option in its response, then its contents are logged in the
|
||||
``zoneversion`` category at level ``info``. If the NSID has
|
||||
also been requested and it is returned then that is appended to
|
||||
the log message. The default is ``no``.
|
||||
|
||||
.. namedconf:statement:: require-cookie
|
||||
:tags: query
|
||||
:short: Controls whether responses without a server cookie are accepted.
|
||||
|
|
@ -5601,11 +5621,13 @@ and :namedconf:ref:`options` blocks:
|
|||
- :namedconf:ref:`notify-source-v6`
|
||||
- :namedconf:ref:`notify-source`
|
||||
- :namedconf:ref:`provide-ixfr`
|
||||
- :namedconf:ref:`provide-zoneversion`
|
||||
- :namedconf:ref:`query-source-v6`
|
||||
- :namedconf:ref:`query-source`
|
||||
- :namedconf:ref:`request-expire`
|
||||
- :namedconf:ref:`request-ixfr`
|
||||
- :namedconf:ref:`request-nsid`
|
||||
- :namedconf:ref:`request-zoneversion`
|
||||
- :namedconf:ref:`require-cookie`
|
||||
- :namedconf:ref:`send-cookie`
|
||||
- :namedconf:ref:`transfer-format`
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ zone <string> [ <class> ] {
|
|||
notify-source ( <ipv4_address> | * );
|
||||
notify-source-v6 ( <ipv6_address> | * );
|
||||
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
|
||||
provide-zoneversion <boolean>;
|
||||
request-expire <boolean>;
|
||||
request-ixfr <boolean>;
|
||||
request-ixfr-max-diffs <integer>;
|
||||
|
|
|
|||
|
|
@ -226,6 +226,7 @@ options {
|
|||
preferred-glue <string>;
|
||||
prefetch <integer> [ <integer> ];
|
||||
provide-ixfr <boolean>;
|
||||
provide-zoneversion <boolean>;
|
||||
qname-minimization ( strict | relaxed | disabled | off );
|
||||
query-source [ address ] ( <ipv4_address> | * | none );
|
||||
query-source-v6 [ address ] ( <ipv6_address> | * | none );
|
||||
|
|
@ -254,6 +255,7 @@ options {
|
|||
request-ixfr <boolean>;
|
||||
request-ixfr-max-diffs <integer>;
|
||||
request-nsid <boolean>;
|
||||
request-zoneversion <boolean>;
|
||||
require-server-cookie <boolean>;
|
||||
resolver-query-timeout <integer>;
|
||||
resolver-use-dns64 <boolean>;
|
||||
|
|
@ -343,6 +345,7 @@ server <netprefix> {
|
|||
request-ixfr <boolean>;
|
||||
request-ixfr-max-diffs <integer>;
|
||||
request-nsid <boolean>;
|
||||
request-zoneversion <boolean>;
|
||||
require-cookie <boolean>;
|
||||
send-cookie <boolean>;
|
||||
tcp-keepalive <boolean>;
|
||||
|
|
@ -509,6 +512,7 @@ view <string> [ <class> ] {
|
|||
preferred-glue <string>;
|
||||
prefetch <integer> [ <integer> ];
|
||||
provide-ixfr <boolean>;
|
||||
provide-zoneversion <boolean>;
|
||||
qname-minimization ( strict | relaxed | disabled | off );
|
||||
query-source [ address ] ( <ipv4_address> | * | none );
|
||||
query-source-v6 [ address ] ( <ipv6_address> | * | none );
|
||||
|
|
@ -534,6 +538,7 @@ view <string> [ <class> ] {
|
|||
request-ixfr <boolean>;
|
||||
request-ixfr-max-diffs <integer>;
|
||||
request-nsid <boolean>;
|
||||
request-zoneversion <boolean>;
|
||||
require-server-cookie <boolean>;
|
||||
resolver-query-timeout <integer>;
|
||||
resolver-use-dns64 <boolean>;
|
||||
|
|
@ -561,6 +566,7 @@ view <string> [ <class> ] {
|
|||
request-ixfr <boolean>;
|
||||
request-ixfr-max-diffs <integer>;
|
||||
request-nsid <boolean>;
|
||||
request-zoneversion <boolean>;
|
||||
require-cookie <boolean>;
|
||||
send-cookie <boolean>;
|
||||
tcp-keepalive <boolean>;
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ zone <string> [ <class> ] {
|
|||
parental-agents [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
|
||||
parental-source ( <ipv4_address> | * );
|
||||
parental-source-v6 ( <ipv6_address> | * );
|
||||
provide-zoneversion <boolean>;
|
||||
send-report-channel <string>;
|
||||
serial-update-method ( date | increment | unixtime );
|
||||
sig-signing-nodes <integer>;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ zone <string> [ <class> ] {
|
|||
parental-source ( <ipv4_address> | * );
|
||||
parental-source-v6 ( <ipv6_address> | * );
|
||||
primaries [ port <integer> ] [ source ( <ipv4_address> | * ) ] [ source-v6 ( <ipv6_address> | * ) ] { ( <server-list> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
|
||||
provide-zoneversion <boolean>;
|
||||
request-expire <boolean>;
|
||||
request-ixfr <boolean>;
|
||||
request-ixfr-max-diffs <integer>;
|
||||
|
|
|
|||
11
lib/dns/db.c
11
lib/dns/db.c
|
|
@ -1200,3 +1200,14 @@ dns__db_logtoomanyrecords(dns_db_t *db, const dns_name_t *name,
|
|||
(db->attributes & DNS_DBATTR_CACHE) != 0 ? "cache" : "zone",
|
||||
isc_result_totext(DNS_R_TOOMANYRECORDS), limit);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_db_getzoneversion(dns_db_t *db, isc_buffer_t *b) {
|
||||
REQUIRE(db != NULL);
|
||||
REQUIRE(b != NULL);
|
||||
|
||||
if (db->methods->getzoneversion != NULL) {
|
||||
return (db->methods->getzoneversion)(db, b);
|
||||
}
|
||||
return ISC_R_NOTIMPLEMENTED;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ typedef struct dns_dbmethods {
|
|||
dns_name_t *name);
|
||||
void (*setmaxrrperset)(dns_db_t *db, uint32_t value);
|
||||
void (*setmaxtypepername)(dns_db_t *db, uint32_t value);
|
||||
isc_result_t (*getzoneversion)(dns_db_t *db, isc_buffer_t *b);
|
||||
} dns_dbmethods_t;
|
||||
|
||||
typedef isc_result_t (*dns_dbcreatefunc_t)(isc_mem_t *mctx,
|
||||
|
|
@ -1805,3 +1806,21 @@ dns_db_setmaxtypepername(dns_db_t *db, uint32_t value);
|
|||
* stored at a given node, then any subsequent attempt to add an rdataset
|
||||
* with a new RR type will return ISC_R_TOOMANYRECORDS.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_db_getzoneversion(dns_db_t *db, isc_buffer_t *b);
|
||||
/*%<
|
||||
* Provides a database specific EDNS ZONEVERSION option.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'db' is a valid database
|
||||
* \li 'b' is a valid buffer
|
||||
*
|
||||
* Returns:
|
||||
* \li ISC_R_SUCCESS when it has populated the buffer with the ZONEVERSION
|
||||
* response (maybe empty implying no ZONEVERSION to be returned).
|
||||
* \li ISC_R_NOSPACE if the buffer is too small.
|
||||
* \li ISC_R_NOTIMPLEMENTED if there is not a database specific
|
||||
* ZONEVERSION
|
||||
* \li ISC_R_FAILURE other failures
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -102,7 +102,6 @@
|
|||
#define DNS_MESSAGEEXTFLAG_DO 0x8000U
|
||||
|
||||
/*%< EDNS0 extended OPT codes */
|
||||
|
||||
#define DNS_OPT_LLQ 1 /*%< LLQ opt code */
|
||||
#define DNS_OPT_UL 2 /*%< UL opt code */
|
||||
#define DNS_OPT_NSID 3 /*%< NSID opt code */
|
||||
|
|
@ -129,7 +128,7 @@
|
|||
* options we know about. Extended DNS Errors may occur multiple times, see
|
||||
* DNS_EDE_MAX_ERRORS.
|
||||
*/
|
||||
#define DNS_EDNSOPTIONS 8 + DNS_EDE_MAX_ERRORS
|
||||
#define DNS_EDNSOPTIONS 9 + DNS_EDE_MAX_ERRORS
|
||||
|
||||
#define DNS_MESSAGE_REPLYPRESERVE (DNS_MESSAGEFLAG_RD | DNS_MESSAGEFLAG_CD)
|
||||
#define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO)
|
||||
|
|
|
|||
|
|
@ -115,6 +115,12 @@ dns_peer_setrequestnsid(dns_peer_t *peer, bool newval);
|
|||
isc_result_t
|
||||
dns_peer_getrequestnsid(dns_peer_t *peer, bool *retval);
|
||||
|
||||
isc_result_t
|
||||
dns_peer_setrequestzoneversion(dns_peer_t *peer, bool newval);
|
||||
|
||||
isc_result_t
|
||||
dns_peer_getrequestzoneversion(dns_peer_t *peer, bool *retval);
|
||||
|
||||
isc_result_t
|
||||
dns_peer_setsendcookie(dns_peer_t *peer, bool newval);
|
||||
|
||||
|
|
|
|||
|
|
@ -105,31 +105,32 @@ typedef enum { dns_quotatype_zone = 0, dns_quotatype_server } dns_quotatype_t;
|
|||
* Options that modify how a 'fetch' is done.
|
||||
*/
|
||||
enum {
|
||||
DNS_FETCHOPT_TCP = 1 << 0, /*%< Use TCP. */
|
||||
DNS_FETCHOPT_UNSHARED = 1 << 1, /*%< See below. */
|
||||
DNS_FETCHOPT_RECURSIVE = 1 << 2, /*%< Set RD? */
|
||||
DNS_FETCHOPT_NOEDNS0 = 1 << 3, /*%< Do not use EDNS. */
|
||||
DNS_FETCHOPT_FORWARDONLY = 1 << 4, /*%< Only use forwarders. */
|
||||
DNS_FETCHOPT_NOVALIDATE = 1 << 5, /*%< Disable validation. */
|
||||
DNS_FETCHOPT_WANTNSID = 1 << 6, /*%< Request NSID */
|
||||
DNS_FETCHOPT_PREFETCH = 1 << 7, /*%< Do prefetch */
|
||||
DNS_FETCHOPT_NOCDFLAG = 1 << 8, /*%< Don't set CD flag. */
|
||||
DNS_FETCHOPT_NONTA = 1 << 9, /*%< Ignore NTA table. */
|
||||
DNS_FETCHOPT_NOCACHED = 1 << 10, /*%< Force cache update. */
|
||||
DNS_FETCHOPT_QMINIMIZE = 1 << 11, /*%< Use qname minimization. */
|
||||
DNS_FETCHOPT_NOFOLLOW = 1 << 12, /*%< Don't retrieve the NS RRset
|
||||
* from the child zone when a
|
||||
* delegation is returned in
|
||||
* response to a NS query. */
|
||||
DNS_FETCHOPT_QMIN_STRICT = 1 << 13, /*%< Do not work around servers
|
||||
* that return errors on
|
||||
* non-empty terminals. */
|
||||
DNS_FETCHOPT_QMIN_SKIP_IP6A = 1 << 14, /*%< Skip some labels when
|
||||
* doing qname minimization
|
||||
* on ip6.arpa. */
|
||||
DNS_FETCHOPT_NOFORWARD = 1 << 15, /*%< Do not use forwarders if
|
||||
* possible. */
|
||||
DNS_FETCHOPT_QMINFETCH = 1 << 16, /*%< Qmin fetch */
|
||||
DNS_FETCHOPT_TCP = 1 << 0, /*%< Use TCP. */
|
||||
DNS_FETCHOPT_UNSHARED = 1 << 1, /*%< See below. */
|
||||
DNS_FETCHOPT_RECURSIVE = 1 << 2, /*%< Set RD? */
|
||||
DNS_FETCHOPT_NOEDNS0 = 1 << 3, /*%< Do not use EDNS. */
|
||||
DNS_FETCHOPT_FORWARDONLY = 1 << 4, /*%< Only use forwarders. */
|
||||
DNS_FETCHOPT_NOVALIDATE = 1 << 5, /*%< Disable validation. */
|
||||
DNS_FETCHOPT_WANTNSID = 1 << 6, /*%< Request NSID */
|
||||
DNS_FETCHOPT_PREFETCH = 1 << 7, /*%< Do prefetch */
|
||||
DNS_FETCHOPT_NOCDFLAG = 1 << 8, /*%< Don't set CD flag. */
|
||||
DNS_FETCHOPT_NONTA = 1 << 9, /*%< Ignore NTA table. */
|
||||
DNS_FETCHOPT_NOCACHED = 1 << 10, /*%< Force cache update. */
|
||||
DNS_FETCHOPT_QMINIMIZE = 1 << 11, /*%< Use qname minimization. */
|
||||
DNS_FETCHOPT_NOFOLLOW = 1 << 12, /*%< Don't retrieve the NS RRset
|
||||
* from the child zone when a
|
||||
* delegation is returned in
|
||||
* response to a NS query. */
|
||||
DNS_FETCHOPT_QMIN_STRICT = 1 << 13, /*%< Do not work around servers
|
||||
* that return errors on
|
||||
* non-empty terminals. */
|
||||
DNS_FETCHOPT_QMIN_SKIP_IP6A = 1 << 14, /*%< Skip some labels when
|
||||
* doing qname minimization
|
||||
* on ip6.arpa. */
|
||||
DNS_FETCHOPT_NOFORWARD = 1 << 15, /*%< Do not use forwarders if
|
||||
* possible. */
|
||||
DNS_FETCHOPT_QMINFETCH = 1 << 16, /*%< Qmin fetch */
|
||||
DNS_FETCHOPT_WANTZONEVERSION = 1 << 17, /*%< Request ZONEVERSION */
|
||||
|
||||
/*% EDNS version bits: */
|
||||
DNS_FETCHOPT_EDNSVERSIONSET = 1 << 23,
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ struct dns_view {
|
|||
dns_rrl_t *rrl;
|
||||
bool provideixfr;
|
||||
bool requestnsid;
|
||||
bool requestzoneversion;
|
||||
bool sendcookie;
|
||||
dns_ttl_t maxcachettl;
|
||||
dns_ttl_t maxncachettl;
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ typedef enum {
|
|||
DNS_ZONEOPT_CHECKTTL = 1 << 28, /*%< check max-zone-ttl */
|
||||
DNS_ZONEOPT_AUTOEMPTY = 1 << 29, /*%< automatic empty zone */
|
||||
DNS_ZONEOPT_CHECKSVCB = 1 << 30, /*%< check SVBC records */
|
||||
DNS_ZONEOPT_ZONEVERSION = 1U << 31, /*%< enable zoneversion */
|
||||
DNS_ZONEOPT___MAX = UINT64_MAX, /* trick to make the ENUM 64-bit wide */
|
||||
} dns_zoneopt_t;
|
||||
|
||||
|
|
@ -2785,6 +2786,24 @@ dns_zone_getrad(dns_zone_t *zone, dns_name_t *name);
|
|||
* \li 'name' is a valid name with a buffer.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_zone_getzoneversion(dns_zone_t *zone, isc_buffer_t *b);
|
||||
/**<
|
||||
* Return the EDNS ZONEVERSION for this zone.
|
||||
*
|
||||
* Note: For type SERIAL a buffer of at least 6 octets is required.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'zone' to be a valid zone.
|
||||
* \li 'b' to be a valid buffer.
|
||||
*
|
||||
* Returns
|
||||
* \li ISC_R_SUCCESS if the zone is loaded and supports ZONEVERSION.
|
||||
* \li ISC_R_NOSPACE if the buffer is too small.
|
||||
* \li DNS_R_NOTLOADED if the database is not loaded.
|
||||
* \li ISC_R_FAILURE other failure.
|
||||
*/
|
||||
|
||||
#if DNS_ZONE_TRACE
|
||||
#define dns_zone_ref(ptr) dns_zone__ref(ptr, __func__, __FILE__, __LINE__)
|
||||
#define dns_zone_unref(ptr) dns_zone__unref(ptr, __func__, __FILE__, __LINE__)
|
||||
|
|
|
|||
|
|
@ -3512,6 +3512,116 @@ static const char *option_names[] = {
|
|||
[DNS_OPT_ZONEVERSION] = "ZONEVERSION",
|
||||
};
|
||||
|
||||
static isc_result_t
|
||||
render_zoneversion(dns_message_t *msg, isc_buffer_t *optbuf,
|
||||
const dns_master_style_t *style, isc_buffer_t *target) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
unsigned int labels = isc_buffer_getuint8(optbuf);
|
||||
unsigned int type = isc_buffer_getuint8(optbuf);
|
||||
char buf[sizeof("4000000000")];
|
||||
char namebuf[DNS_NAME_FORMATSIZE];
|
||||
dns_name_t *name = ISC_LIST_HEAD(msg->sections[DNS_SECTION_QUESTION]);
|
||||
dns_name_t suffix = DNS_NAME_INITEMPTY;
|
||||
bool yaml = false, rawmode = false;
|
||||
const char *sep1 = " ", *sep2 = ", ";
|
||||
|
||||
if ((dns_master_styleflags(style) & DNS_STYLEFLAG_YAML) != 0) {
|
||||
msg->indent.count++;
|
||||
sep1 = sep2 = "\n";
|
||||
yaml = true;
|
||||
}
|
||||
|
||||
ADD_STRING(target, sep1);
|
||||
|
||||
if (msg->counts[DNS_SECTION_QUESTION] != 1 || name == NULL ||
|
||||
dns_name_countlabels(name) < labels + 1)
|
||||
{
|
||||
rawmode = true;
|
||||
INDENT(style);
|
||||
ADD_STRING(target, "LABELS: ");
|
||||
snprintf(buf, sizeof(buf), "%u", labels);
|
||||
ADD_STRING(target, buf);
|
||||
} else {
|
||||
dns_name_split(name, labels + 1, NULL, &suffix);
|
||||
dns_name_format(&suffix, namebuf, sizeof(namebuf));
|
||||
|
||||
INDENT(style);
|
||||
ADD_STRING(target, "ZONE: ");
|
||||
if (yaml) {
|
||||
char *s = namebuf;
|
||||
ADD_STRING(target, "\"");
|
||||
while (*s != 0) {
|
||||
if (*s == '\\' || *s == '"') {
|
||||
ADD_STRING(target, "\\");
|
||||
}
|
||||
if (isc_buffer_availablelength(target) < 1) {
|
||||
result = ISC_R_NOSPACE;
|
||||
goto cleanup;
|
||||
}
|
||||
isc_buffer_putmem(target, (unsigned char *)s,
|
||||
1);
|
||||
s++;
|
||||
}
|
||||
ADD_STRING(target, "\"");
|
||||
} else {
|
||||
ADD_STRING(target, namebuf);
|
||||
}
|
||||
}
|
||||
ADD_STRING(target, sep2);
|
||||
|
||||
if (!rawmode && type == 0 && isc_buffer_remaininglength(optbuf) == 4) {
|
||||
uint32_t serial = isc_buffer_getuint32(optbuf);
|
||||
INDENT(style);
|
||||
ADD_STRING(target, "SOA-SERIAL: ");
|
||||
snprintf(buf, sizeof(buf), "%u", serial);
|
||||
ADD_STRING(target, buf);
|
||||
} else {
|
||||
size_t len = isc_buffer_remaininglength(optbuf);
|
||||
unsigned char *data = isc_buffer_current(optbuf);
|
||||
INDENT(style);
|
||||
ADD_STRING(target, "TYPE: ");
|
||||
snprintf(buf, sizeof(buf), "%u", type);
|
||||
ADD_STRING(target, buf);
|
||||
ADD_STRING(target, sep2);
|
||||
INDENT(style);
|
||||
ADD_STRING(target, "VALUE: ");
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
snprintf(buf, sizeof(buf), "%02x", data[i]);
|
||||
ADD_STRING(target, buf);
|
||||
}
|
||||
if (yaml) {
|
||||
ADD_STRING(target, sep2);
|
||||
INDENT(style);
|
||||
ADD_STRING(target, "PVALUE: \"");
|
||||
} else {
|
||||
ADD_STRING(target, " (\"");
|
||||
}
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (isprint(data[i])) {
|
||||
if (yaml && (data[i] == '\\' || data[i] == '"'))
|
||||
{
|
||||
ADD_STRING(target, "\\");
|
||||
}
|
||||
if (isc_buffer_availablelength(target) < 1) {
|
||||
result = ISC_R_NOSPACE;
|
||||
goto cleanup;
|
||||
}
|
||||
isc_buffer_putmem(target, &data[i], 1);
|
||||
} else {
|
||||
ADD_STRING(target, ".");
|
||||
}
|
||||
}
|
||||
if (yaml) {
|
||||
ADD_STRING(target, "\"");
|
||||
} else {
|
||||
ADD_STRING(target, "\")");
|
||||
}
|
||||
isc_buffer_forward(optbuf, len);
|
||||
}
|
||||
cleanup:
|
||||
return result;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section,
|
||||
const dns_master_style_t *style,
|
||||
|
|
@ -3789,6 +3899,20 @@ dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section,
|
|||
optbuf = sb;
|
||||
}
|
||||
break;
|
||||
case DNS_OPT_ZONEVERSION:
|
||||
if (optlen >= 2U) {
|
||||
isc_buffer_t zonebuf = optbuf;
|
||||
isc_buffer_setactive(&zonebuf, optlen);
|
||||
result = render_zoneversion(
|
||||
msg, &zonebuf, style, target);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
isc_buffer_forward(&optbuf, optlen);
|
||||
ADD_STRING(target, "\n");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -4208,6 +4332,20 @@ dns_message_pseudosectiontotext(dns_message_t *msg, dns_pseudosection_t section,
|
|||
optbuf = sb;
|
||||
}
|
||||
break;
|
||||
case DNS_OPT_ZONEVERSION:
|
||||
if (optlen >= 2U) {
|
||||
isc_buffer_t zonebuf = optbuf;
|
||||
isc_buffer_setactive(&zonebuf, optlen);
|
||||
result = render_zoneversion(
|
||||
msg, &zonebuf, style, target);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
ADD_STRING(target, "\n");
|
||||
isc_buffer_forward(&optbuf, optlen);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ struct dns_peer {
|
|||
bool request_ixfr;
|
||||
bool support_edns;
|
||||
bool request_nsid;
|
||||
bool request_zoneversion;
|
||||
bool send_cookie;
|
||||
bool require_cookie;
|
||||
bool request_expire;
|
||||
|
|
@ -98,7 +99,8 @@ enum {
|
|||
SERVER_PADDING_BIT,
|
||||
REQUEST_TCP_KEEPALIVE_BIT,
|
||||
REQUIRE_COOKIE_BIT,
|
||||
DNS_PEER_FLAGS_COUNT
|
||||
DNS_PEER_FLAGS_COUNT,
|
||||
REQUEST_ZONEVERSION
|
||||
};
|
||||
|
||||
STATIC_ASSERT(DNS_PEER_FLAGS_COUNT <= CHAR_BIT * sizeof(uint32_t),
|
||||
|
|
@ -382,6 +384,8 @@ ACCESS_OPTION(requestixfr, REQUEST_IXFR_BIT, bool, request_ixfr)
|
|||
ACCESS_OPTION(requestixfrmaxdiffs, REQUEST_IXFRMAXDIFFS_BIT, uint32_t,
|
||||
request_ixfr_maxdiffs)
|
||||
ACCESS_OPTION(requestnsid, REQUEST_NSID_BIT, bool, request_nsid)
|
||||
ACCESS_OPTION(requestzoneversion, REQUEST_ZONEVERSION, bool,
|
||||
request_zoneversion)
|
||||
ACCESS_OPTION(requirecookie, REQUIRE_COOKIE_BIT, bool, require_cookie)
|
||||
ACCESS_OPTION(sendcookie, SEND_COOKIE_BIT, bool, send_cookie)
|
||||
ACCESS_OPTION(supportedns, SUPPORT_EDNS_BIT, bool, support_edns)
|
||||
|
|
|
|||
|
|
@ -266,6 +266,21 @@ fromwire_opt(ARGS_FROMWIRE) {
|
|||
}
|
||||
isc_region_consume(&sregion, length);
|
||||
break;
|
||||
case DNS_OPT_ZONEVERSION:
|
||||
if (length == 0) {
|
||||
/* Request */
|
||||
break;
|
||||
}
|
||||
/* Labels and Type */
|
||||
if (length < 2) {
|
||||
return DNS_R_OPTERR;
|
||||
}
|
||||
/* Type 0 (serial), length is 6. */
|
||||
if (sregion.base[1] == 0 && length != 6) {
|
||||
return DNS_R_OPTERR;
|
||||
}
|
||||
isc_region_consume(&sregion, length);
|
||||
break;
|
||||
default:
|
||||
isc_region_consume(&sregion, length);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <isc/counter.h>
|
||||
#include <isc/hash.h>
|
||||
#include <isc/hashmap.h>
|
||||
#include <isc/hex.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/loop.h>
|
||||
#include <isc/mutex.h>
|
||||
|
|
@ -2504,6 +2505,7 @@ resquery_send(resquery_t *query) {
|
|||
unsigned int flags = query->addrinfo->flags;
|
||||
bool reqnsid = res->view->requestnsid;
|
||||
bool sendcookie = res->view->sendcookie;
|
||||
bool reqzoneversion = res->view->requestzoneversion;
|
||||
bool tcpkeepalive = false;
|
||||
unsigned char cookie[COOKIE_BUFFER_SIZE];
|
||||
uint16_t padding = 0;
|
||||
|
|
@ -2546,8 +2548,6 @@ resquery_send(resquery_t *query) {
|
|||
*/
|
||||
if (peer != NULL) {
|
||||
uint8_t ednsversion;
|
||||
(void)dns_peer_getrequestnsid(peer, &reqnsid);
|
||||
(void)dns_peer_getsendcookie(peer, &sendcookie);
|
||||
result = dns_peer_getednsversion(peer,
|
||||
&ednsversion);
|
||||
if (result == ISC_R_SUCCESS &&
|
||||
|
|
@ -2555,6 +2555,10 @@ resquery_send(resquery_t *query) {
|
|||
{
|
||||
version = ednsversion;
|
||||
}
|
||||
(void)dns_peer_getrequestnsid(peer, &reqnsid);
|
||||
(void)dns_peer_getrequestzoneversion(
|
||||
peer, &reqzoneversion);
|
||||
(void)dns_peer_getsendcookie(peer, &sendcookie);
|
||||
}
|
||||
if (NOCOOKIE(query->addrinfo)) {
|
||||
sendcookie = false;
|
||||
|
|
@ -2566,6 +2570,13 @@ resquery_send(resquery_t *query) {
|
|||
ednsopts[ednsopt].value = NULL;
|
||||
ednsopt++;
|
||||
}
|
||||
if (reqzoneversion) {
|
||||
INSIST(ednsopt < DNS_EDNSOPTIONS);
|
||||
ednsopts[ednsopt].code = DNS_OPT_ZONEVERSION;
|
||||
ednsopts[ednsopt].length = 0;
|
||||
ednsopts[ednsopt].value = NULL;
|
||||
ednsopt++;
|
||||
}
|
||||
if (sendcookie) {
|
||||
INSIST(ednsopt < DNS_EDNSOPTIONS);
|
||||
ednsopts[ednsopt].code = DNS_OPT_COOKIE;
|
||||
|
|
@ -2620,8 +2631,14 @@ resquery_send(resquery_t *query) {
|
|||
query->ednsversion = version;
|
||||
result = fctx_addopt(fctx->qmessage, version, udpsize,
|
||||
ednsopts, ednsopt);
|
||||
if (reqnsid && result == ISC_R_SUCCESS) {
|
||||
query->options |= DNS_FETCHOPT_WANTNSID;
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
if (reqnsid) {
|
||||
query->options |= DNS_FETCHOPT_WANTNSID;
|
||||
}
|
||||
if (reqzoneversion) {
|
||||
query->options |=
|
||||
DNS_FETCHOPT_WANTZONEVERSION;
|
||||
}
|
||||
} else if (result != ISC_R_SUCCESS) {
|
||||
/*
|
||||
* We couldn't add the OPT, but we'll
|
||||
|
|
@ -7387,17 +7404,38 @@ checknames(dns_message_t *message) {
|
|||
checknamessection(message, DNS_SECTION_ADDITIONAL);
|
||||
}
|
||||
|
||||
static void
|
||||
make_hex(unsigned char *src, size_t srclen, char *buf, size_t buflen) {
|
||||
isc_buffer_t b;
|
||||
isc_region_t r;
|
||||
isc_result_t result;
|
||||
|
||||
r.base = src;
|
||||
r.length = srclen;
|
||||
isc_buffer_init(&b, buf, buflen);
|
||||
result = isc_hex_totext(&r, 0, "", &b);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
isc_buffer_putuint8(&b, '\0');
|
||||
}
|
||||
|
||||
static void
|
||||
make_printable(unsigned char *src, size_t srclen, char *buf, size_t buflen) {
|
||||
INSIST(buflen > srclen);
|
||||
while (srclen-- > 0) {
|
||||
unsigned char c = *src++;
|
||||
*buf++ = isprint(c) ? c : '.';
|
||||
}
|
||||
*buf = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Log server NSID at log level 'level'
|
||||
*/
|
||||
static void
|
||||
log_nsid(isc_buffer_t *opt, size_t nsid_len, resquery_t *query, int level,
|
||||
isc_mem_t *mctx) {
|
||||
static const char hex[17] = "0123456789abcdef";
|
||||
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
|
||||
char addrbuf[ISC_SOCKADDR_FORMATSIZE], *buf = NULL, *pbuf = NULL;
|
||||
size_t buflen;
|
||||
unsigned char *p, *nsid;
|
||||
unsigned char *buf = NULL, *pbuf = NULL;
|
||||
|
||||
REQUIRE(nsid_len <= UINT16_MAX);
|
||||
|
||||
|
|
@ -7407,20 +7445,10 @@ log_nsid(isc_buffer_t *opt, size_t nsid_len, resquery_t *query, int level,
|
|||
pbuf = isc_mem_get(mctx, nsid_len + 1);
|
||||
|
||||
/* Convert to hex */
|
||||
p = buf;
|
||||
nsid = isc_buffer_current(opt);
|
||||
for (size_t i = 0; i < nsid_len; i++) {
|
||||
*p++ = hex[(nsid[i] >> 4) & 0xf];
|
||||
*p++ = hex[nsid[i] & 0xf];
|
||||
}
|
||||
*p = '\0';
|
||||
make_hex(isc_buffer_current(opt), nsid_len, buf, buflen);
|
||||
|
||||
/* Make printable version */
|
||||
p = pbuf;
|
||||
for (size_t i = 0; i < nsid_len; i++) {
|
||||
*p++ = isprint(nsid[i]) ? nsid[i] : '.';
|
||||
}
|
||||
*p = '\0';
|
||||
make_printable(isc_buffer_current(opt), nsid_len, pbuf, nsid_len + 1);
|
||||
|
||||
isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
|
||||
sizeof(addrbuf));
|
||||
|
|
@ -7431,6 +7459,108 @@ log_nsid(isc_buffer_t *opt, size_t nsid_len, resquery_t *query, int level,
|
|||
isc_mem_put(mctx, buf, buflen);
|
||||
}
|
||||
|
||||
static void
|
||||
log_zoneversion(unsigned char *version, size_t version_len, unsigned char *nsid,
|
||||
size_t nsid_len, resquery_t *query, int level,
|
||||
isc_mem_t *mctx) {
|
||||
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
|
||||
char namebuf[DNS_NAME_FORMATSIZE];
|
||||
size_t nsid_buflen = 0;
|
||||
char *nsid_buf = NULL;
|
||||
char *nsid_pbuf = NULL;
|
||||
const char *nsid_hex = "";
|
||||
const char *nsid_print = "";
|
||||
const char *sep_1 = "";
|
||||
const char *sep_2 = "";
|
||||
const char *sep_3 = "";
|
||||
dns_name_t suffix = DNS_NAME_INITEMPTY;
|
||||
unsigned int labels;
|
||||
|
||||
REQUIRE(version_len <= UINT16_MAX);
|
||||
|
||||
/*
|
||||
* Don't log reflected ZONEVERSION option.
|
||||
*/
|
||||
if (version_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enforced by dns_rdata_fromwire. */
|
||||
INSIST(version_len >= 2);
|
||||
|
||||
/*
|
||||
* Sanity check on label count.
|
||||
*/
|
||||
labels = version[0] + 1;
|
||||
if (dns_name_countlabels(query->fctx->name) < labels) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get zone name.
|
||||
*/
|
||||
dns_name_split(query->fctx->name, labels, NULL, &suffix);
|
||||
dns_name_format(&suffix, namebuf, sizeof(namebuf));
|
||||
|
||||
if (nsid != NULL) {
|
||||
nsid_buflen = nsid_len * 2 + 1;
|
||||
nsid_hex = nsid_buf = isc_mem_get(mctx, nsid_buflen);
|
||||
nsid_print = nsid_pbuf = isc_mem_get(mctx, nsid_len + 1);
|
||||
|
||||
/* Convert to hex */
|
||||
make_hex(nsid, nsid_len, nsid_buf, nsid_buflen);
|
||||
|
||||
/* Convert to printable */
|
||||
make_printable(nsid, nsid_len, nsid_pbuf, nsid_len + 1);
|
||||
|
||||
sep_1 = " (NSID ";
|
||||
sep_2 = " (";
|
||||
sep_3 = "))";
|
||||
}
|
||||
|
||||
isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
|
||||
sizeof(addrbuf));
|
||||
if (version[1] == 0 && version_len == 6) {
|
||||
uint32_t serial = version[2] << 24 | version[3] << 2 |
|
||||
version[4] << 8 | version[5];
|
||||
isc_log_write(DNS_LOGCATEGORY_ZONEVERSION,
|
||||
DNS_LOGMODULE_RESOLVER, level,
|
||||
"received ZONEVERSION serial %u from %s for %s "
|
||||
"zone %s%s%s%s%s%s",
|
||||
serial, addrbuf, query->fctx->info, namebuf,
|
||||
sep_1, nsid_hex, sep_2, nsid_print, sep_3);
|
||||
} else {
|
||||
size_t version_buflen = version_len * 2 + 1;
|
||||
char *version_hex = isc_mem_get(mctx, version_buflen);
|
||||
char *version_pbuf = isc_mem_get(mctx, version_len - 1);
|
||||
|
||||
/* Convert to hex */
|
||||
make_hex(version + 2, version_len - 2, version_hex,
|
||||
version_buflen);
|
||||
|
||||
/* Convert to printable */
|
||||
make_printable(version + 2, version_len - 2, version_pbuf,
|
||||
version_len - 1);
|
||||
|
||||
isc_log_write(DNS_LOGCATEGORY_ZONEVERSION,
|
||||
DNS_LOGMODULE_RESOLVER, level,
|
||||
"received ZONEVERSION type %u value %s (%s) from "
|
||||
"%s for %s zone %s%s%s%s%s%s",
|
||||
version[1], version_hex, version_pbuf, addrbuf,
|
||||
query->fctx->info, namebuf, sep_1, nsid_hex,
|
||||
sep_2, nsid_print, sep_3);
|
||||
isc_mem_put(mctx, version_hex, version_buflen);
|
||||
isc_mem_put(mctx, version_pbuf, version_len - 1);
|
||||
}
|
||||
|
||||
if (nsid_pbuf != NULL) {
|
||||
isc_mem_put(mctx, nsid_pbuf, nsid_len + 1);
|
||||
}
|
||||
if (nsid_buf != NULL) {
|
||||
isc_mem_put(mctx, nsid_buf, nsid_buflen);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
betterreferral(respctx_t *rctx) {
|
||||
isc_result_t result;
|
||||
|
|
@ -8191,6 +8321,11 @@ rctx_opt(respctx_t *rctx) {
|
|||
isc_result_t result;
|
||||
bool seen_cookie = false;
|
||||
bool seen_nsid = false;
|
||||
bool seen_zoneversion = false;
|
||||
unsigned char *nsid = NULL;
|
||||
uint16_t nsidlen = 0;
|
||||
unsigned char *zoneversion = NULL;
|
||||
uint16_t zoneversionlen = 0;
|
||||
|
||||
result = dns_rdataset_first(rctx->opt);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
|
|
@ -8216,7 +8351,8 @@ rctx_opt(respctx_t *rctx) {
|
|||
break;
|
||||
}
|
||||
seen_nsid = true;
|
||||
|
||||
nsid = isc_buffer_current(&optbuf);
|
||||
nsidlen = optlen;
|
||||
if ((query->options & DNS_FETCHOPT_WANTNSID) != 0) {
|
||||
log_nsid(&optbuf, optlen, query, ISC_LOG_INFO,
|
||||
fctx->mctx);
|
||||
|
|
@ -8254,12 +8390,27 @@ rctx_opt(respctx_t *rctx) {
|
|||
optvalue, optlen);
|
||||
}
|
||||
break;
|
||||
case DNS_OPT_ZONEVERSION:
|
||||
if (seen_zoneversion) {
|
||||
break;
|
||||
}
|
||||
seen_zoneversion = true;
|
||||
zoneversion = isc_buffer_current(&optbuf);
|
||||
zoneversionlen = optlen;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
isc_buffer_forward(&optbuf, optlen);
|
||||
}
|
||||
INSIST(isc_buffer_remaininglength(&optbuf) == 0U);
|
||||
|
||||
if ((query->options & DNS_FETCHOPT_WANTZONEVERSION) != 0 &&
|
||||
zoneversion != NULL)
|
||||
{
|
||||
log_zoneversion(zoneversion, zoneversionlen, nsid, nsidlen,
|
||||
query, ISC_LOG_INFO, fctx->mctx);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1497,6 +1497,56 @@ dns_zone_getserial(dns_zone_t *zone, uint32_t *serialp) {
|
|||
return result;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_zone_getzoneversion(dns_zone_t *zone, isc_buffer_t *b) {
|
||||
isc_result_t result = DNS_R_NOTLOADED;
|
||||
unsigned int soacount;
|
||||
uint32_t serial;
|
||||
dns_zone_t *mayberaw = zone;
|
||||
|
||||
REQUIRE(DNS_ZONE_VALID(zone));
|
||||
REQUIRE(b != NULL);
|
||||
|
||||
LOCK_ZONE(zone);
|
||||
if (zone->raw != NULL) {
|
||||
LOCK_ZONE(zone->raw);
|
||||
mayberaw = zone->raw;
|
||||
}
|
||||
ZONEDB_LOCK(&mayberaw->dblock, isc_rwlocktype_read);
|
||||
if (DNS_ZONE_OPTION(mayberaw, DNS_ZONEOPT_ZONEVERSION) &&
|
||||
mayberaw->db != NULL)
|
||||
{
|
||||
result = dns_db_getzoneversion(mayberaw->db, b);
|
||||
if (result == ISC_R_NOTIMPLEMENTED) {
|
||||
result = zone_get_from_db(mayberaw, mayberaw->db, NULL,
|
||||
&soacount, NULL, &serial,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
if (result == ISC_R_SUCCESS && soacount == 0) {
|
||||
result = ISC_R_FAILURE;
|
||||
}
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
if (isc_buffer_availablelength(b) >= 6) {
|
||||
isc_buffer_putuint8(
|
||||
b, dns_name_countlabels(
|
||||
&mayberaw->origin) -
|
||||
1);
|
||||
isc_buffer_putuint8(b, 0);
|
||||
isc_buffer_putuint32(b, serial);
|
||||
} else {
|
||||
result = ISC_R_NOSPACE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ZONEDB_UNLOCK(&mayberaw->dblock, isc_rwlocktype_read);
|
||||
if (zone->raw != NULL) {
|
||||
UNLOCK_ZONE(zone->raw);
|
||||
}
|
||||
UNLOCK_ZONE(zone);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Single shot.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -119,36 +119,37 @@ enum isc_logcategory {
|
|||
NAMED_LOGCATEGORY_GENERAL = ISC_LOGCATEGORY_GENERAL,
|
||||
ISC_LOGCATEGORY_SSLKEYLOG,
|
||||
/* dns categories */
|
||||
DNS_LOGCATEGORY_NOTIFY,
|
||||
DNS_LOGCATEGORY_CNAME,
|
||||
DNS_LOGCATEGORY_DATABASE,
|
||||
DNS_LOGCATEGORY_SECURITY,
|
||||
DNS_LOGCATEGORY_DISPATCH,
|
||||
DNS_LOGCATEGORY_DNSSEC,
|
||||
DNS_LOGCATEGORY_DNSTAP,
|
||||
DNS_LOGCATEGORY_EDNS_DISABLED,
|
||||
DNS_LOGCATEGORY_LAME_SERVERS,
|
||||
DNS_LOGCATEGORY_NOTIFY,
|
||||
DNS_LOGCATEGORY_NSID,
|
||||
DNS_LOGCATEGORY_RESOLVER,
|
||||
DNS_LOGCATEGORY_RPZ,
|
||||
DNS_LOGCATEGORY_RPZ_PASSTHRU,
|
||||
DNS_LOGCATEGORY_RRL,
|
||||
DNS_LOGCATEGORY_SECURITY,
|
||||
DNS_LOGCATEGORY_SPILL,
|
||||
DNS_LOGCATEGORY_UPDATE_POLICY,
|
||||
DNS_LOGCATEGORY_XFER_IN,
|
||||
DNS_LOGCATEGORY_XFER_OUT,
|
||||
DNS_LOGCATEGORY_DISPATCH,
|
||||
DNS_LOGCATEGORY_LAME_SERVERS,
|
||||
DNS_LOGCATEGORY_EDNS_DISABLED,
|
||||
DNS_LOGCATEGORY_RPZ,
|
||||
DNS_LOGCATEGORY_RRL,
|
||||
DNS_LOGCATEGORY_CNAME,
|
||||
DNS_LOGCATEGORY_SPILL,
|
||||
DNS_LOGCATEGORY_DNSTAP,
|
||||
DNS_LOGCATEGORY_ZONELOAD,
|
||||
DNS_LOGCATEGORY_NSID,
|
||||
DNS_LOGCATEGORY_RPZ_PASSTHRU,
|
||||
DNS_LOGCATEGORY_UPDATE_POLICY,
|
||||
DNS_LOGCATEGORY_ZONEVERSION,
|
||||
/* ns categories */
|
||||
NS_LOGCATEGORY_CLIENT,
|
||||
NS_LOGCATEGORY_NETWORK,
|
||||
NS_LOGCATEGORY_UPDATE,
|
||||
NS_LOGCATEGORY_QUERIES,
|
||||
NS_LOGCATEGORY_UPDATE_SECURITY,
|
||||
NS_LOGCATEGORY_QUERY_ERRORS,
|
||||
NS_LOGCATEGORY_TAT,
|
||||
NS_LOGCATEGORY_SERVE_STALE,
|
||||
NS_LOGCATEGORY_RESPONSES,
|
||||
NS_LOGCATEGORY_DRA,
|
||||
NS_LOGCATEGORY_NETWORK,
|
||||
NS_LOGCATEGORY_QUERIES,
|
||||
NS_LOGCATEGORY_QUERY_ERRORS,
|
||||
NS_LOGCATEGORY_RESPONSES,
|
||||
NS_LOGCATEGORY_SERVE_STALE,
|
||||
NS_LOGCATEGORY_TAT,
|
||||
NS_LOGCATEGORY_UPDATE,
|
||||
NS_LOGCATEGORY_UPDATE_SECURITY,
|
||||
/* cfg categories */
|
||||
CFG_LOGCATEGORY_CONFIG,
|
||||
/* named categories */
|
||||
|
|
|
|||
|
|
@ -170,36 +170,37 @@ static const char *categories_description[] = {
|
|||
[ISC_LOGCATEGORY_GENERAL] = "general",
|
||||
[ISC_LOGCATEGORY_SSLKEYLOG] = "sslkeylog",
|
||||
/* dns categories */
|
||||
[DNS_LOGCATEGORY_NOTIFY] = "notify",
|
||||
[DNS_LOGCATEGORY_CNAME] = "cname",
|
||||
[DNS_LOGCATEGORY_DATABASE] = "database",
|
||||
[DNS_LOGCATEGORY_SECURITY] = "security",
|
||||
[DNS_LOGCATEGORY_DISPATCH] = "dispatch",
|
||||
[DNS_LOGCATEGORY_DNSSEC] = "dnssec",
|
||||
[DNS_LOGCATEGORY_DNSTAP] = "dnstap",
|
||||
[DNS_LOGCATEGORY_EDNS_DISABLED] = "edns-disabled",
|
||||
[DNS_LOGCATEGORY_LAME_SERVERS] = "lame-servers",
|
||||
[DNS_LOGCATEGORY_NOTIFY] = "notify",
|
||||
[DNS_LOGCATEGORY_NSID] = "nsid",
|
||||
[DNS_LOGCATEGORY_RESOLVER] = "resolver",
|
||||
[DNS_LOGCATEGORY_RPZ] = "rpz",
|
||||
[DNS_LOGCATEGORY_RPZ_PASSTHRU] = "rpz-passthru",
|
||||
[DNS_LOGCATEGORY_RRL] = "rate-limit",
|
||||
[DNS_LOGCATEGORY_SECURITY] = "security",
|
||||
[DNS_LOGCATEGORY_SPILL] = "spill",
|
||||
[DNS_LOGCATEGORY_UPDATE_POLICY] = "update-policy",
|
||||
[DNS_LOGCATEGORY_XFER_IN] = "xfer-in",
|
||||
[DNS_LOGCATEGORY_XFER_OUT] = "xfer-out",
|
||||
[DNS_LOGCATEGORY_DISPATCH] = "dispatch",
|
||||
[DNS_LOGCATEGORY_LAME_SERVERS] = "lame-servers",
|
||||
[DNS_LOGCATEGORY_EDNS_DISABLED] = "edns-disabled",
|
||||
[DNS_LOGCATEGORY_RPZ] = "rpz",
|
||||
[DNS_LOGCATEGORY_RRL] = "rate-limit",
|
||||
[DNS_LOGCATEGORY_CNAME] = "cname",
|
||||
[DNS_LOGCATEGORY_SPILL] = "spill",
|
||||
[DNS_LOGCATEGORY_DNSTAP] = "dnstap",
|
||||
[DNS_LOGCATEGORY_ZONELOAD] = "zoneload",
|
||||
[DNS_LOGCATEGORY_NSID] = "nsid",
|
||||
[DNS_LOGCATEGORY_RPZ_PASSTHRU] = "rpz-passthru",
|
||||
[DNS_LOGCATEGORY_UPDATE_POLICY] = "update-policy",
|
||||
[DNS_LOGCATEGORY_ZONEVERSION] = "zoneversion",
|
||||
/* ns categories */
|
||||
[NS_LOGCATEGORY_CLIENT] = "client",
|
||||
[NS_LOGCATEGORY_NETWORK] = "network",
|
||||
[NS_LOGCATEGORY_UPDATE] = "update",
|
||||
[NS_LOGCATEGORY_QUERIES] = "queries",
|
||||
[NS_LOGCATEGORY_UPDATE_SECURITY] = "update-security",
|
||||
[NS_LOGCATEGORY_QUERY_ERRORS] = "query-errors",
|
||||
[NS_LOGCATEGORY_TAT] = "trust-anchor-telemetry",
|
||||
[NS_LOGCATEGORY_DRA] = "dns-reporting-agent",
|
||||
[NS_LOGCATEGORY_SERVE_STALE] = "serve-stale",
|
||||
[NS_LOGCATEGORY_NETWORK] = "network",
|
||||
[NS_LOGCATEGORY_QUERIES] = "queries",
|
||||
[NS_LOGCATEGORY_QUERY_ERRORS] = "query-errors",
|
||||
[NS_LOGCATEGORY_RESPONSES] = "responses",
|
||||
[NS_LOGCATEGORY_SERVE_STALE] = "serve-stale",
|
||||
[NS_LOGCATEGORY_TAT] = "trust-anchor-telemetry",
|
||||
[NS_LOGCATEGORY_UPDATE] = "update",
|
||||
[NS_LOGCATEGORY_UPDATE_SECURITY] = "update-security",
|
||||
/* cfg categories */
|
||||
[CFG_LOGCATEGORY_CONFIG] = "config",
|
||||
/* named categories */
|
||||
|
|
|
|||
|
|
@ -4242,6 +4242,7 @@ static struct {
|
|||
{ "request-expire", dns_peer_setrequestexpire },
|
||||
{ "request-ixfr", dns_peer_setrequestixfr },
|
||||
{ "request-nsid", dns_peer_setrequestnsid },
|
||||
{ "request-zoneversion", dns_peer_setrequestzoneversion },
|
||||
{ "send-cookie", dns_peer_setsendcookie },
|
||||
{ "tcp-keepalive", dns_peer_settcpkeepalive },
|
||||
{ "tcp-only", dns_peer_setforcetcp },
|
||||
|
|
|
|||
|
|
@ -2110,6 +2110,7 @@ static cfg_clausedef_t view_clauses[] = {
|
|||
{ "recursion", &cfg_type_boolean, 0 },
|
||||
{ "request-nsid", &cfg_type_boolean, 0 },
|
||||
{ "request-sit", NULL, CFG_CLAUSEFLAG_ANCIENT },
|
||||
{ "request-zoneversion", &cfg_type_boolean, 0 },
|
||||
{ "require-server-cookie", &cfg_type_boolean, 0 },
|
||||
{ "resolver-nonbackoff-tries", NULL, CFG_CLAUSEFLAG_ANCIENT },
|
||||
{ "resolver-query-timeout", &cfg_type_uint32, 0 },
|
||||
|
|
@ -2354,6 +2355,8 @@ static cfg_clausedef_t zone_clauses[] = {
|
|||
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY },
|
||||
{ "parental-source-v6", &cfg_type_sockaddr6wild,
|
||||
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY },
|
||||
{ "provide-zoneversion", &cfg_type_boolean,
|
||||
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY | CFG_ZONE_MIRROR },
|
||||
{ "send-report-channel", &cfg_type_astring,
|
||||
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY },
|
||||
{ "request-expire", &cfg_type_boolean,
|
||||
|
|
@ -2603,6 +2606,7 @@ static cfg_clausedef_t server_clauses[] = {
|
|||
{ "request-ixfr", &cfg_type_boolean, 0 },
|
||||
{ "request-ixfr-max-diffs", &cfg_type_uint32, 0 },
|
||||
{ "request-nsid", &cfg_type_boolean, 0 },
|
||||
{ "request-zoneversion", &cfg_type_boolean, 0 },
|
||||
{ "request-sit", NULL, CFG_CLAUSEFLAG_ANCIENT },
|
||||
{ "require-cookie", &cfg_type_boolean, 0 },
|
||||
{ "send-cookie", &cfg_type_boolean, 0 },
|
||||
|
|
|
|||
|
|
@ -102,6 +102,8 @@
|
|||
#define WANTNSID(x) (((x)->attributes & NS_CLIENTATTR_WANTNSID) != 0)
|
||||
#define WANTPAD(x) (((x)->attributes & NS_CLIENTATTR_WANTPAD) != 0)
|
||||
#define WANTRC(x) (((x)->attributes & NS_CLIENTATTR_WANTRC) != 0)
|
||||
#define WANTZONEVERSION(x) \
|
||||
(((x)->attributes & NS_CLIENTATTR_WANTZONEVERSION) != 0)
|
||||
|
||||
#define MANAGER_MAGIC ISC_MAGIC('N', 'S', 'C', 'm')
|
||||
#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, MANAGER_MAGIC)
|
||||
|
|
@ -218,6 +220,17 @@ ns_client_settimeout(ns_client_t *client, unsigned int seconds) {
|
|||
/* XXXWPK TODO use netmgr to set timeout */
|
||||
}
|
||||
|
||||
static void
|
||||
client_zoneversion_reset(ns_client_t *client) {
|
||||
if (client->zoneversion == NULL) {
|
||||
return;
|
||||
}
|
||||
isc_mem_put(client->manager->mctx, client->zoneversion,
|
||||
client->zoneversionlength);
|
||||
client->zoneversion = NULL;
|
||||
client->zoneversionlength = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ns_client_endrequest(ns_client_t *client) {
|
||||
INSIST(client->state == NS_CLIENTSTATE_WORKING ||
|
||||
|
|
@ -258,6 +271,7 @@ ns_client_endrequest(ns_client_t *client) {
|
|||
dns_message_puttemprdataset(client->message, &client->opt);
|
||||
}
|
||||
|
||||
client_zoneversion_reset(client);
|
||||
client->signer = NULL;
|
||||
client->udpsize = 512;
|
||||
client->extflags = 0;
|
||||
|
|
@ -1192,6 +1206,13 @@ no_nsid:
|
|||
ednsopts[count].value = ede->value;
|
||||
count++;
|
||||
}
|
||||
if ((client->attributes & NS_CLIENTATTR_HAVEZONEVERSION) != 0) {
|
||||
INSIST(count < DNS_EDNSOPTIONS);
|
||||
ednsopts[count].code = DNS_OPT_ZONEVERSION;
|
||||
ednsopts[count].length = client->zoneversionlength;
|
||||
ednsopts[count].value = client->zoneversion;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (WANTRC(client)) {
|
||||
dns_name_t *rad = NULL;
|
||||
|
|
@ -1609,8 +1630,7 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) {
|
|||
case DNS_OPT_CLIENT_SUBNET:
|
||||
result = process_ecs(client, &optbuf, optlen);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
ns_client_error(client, result);
|
||||
return result;
|
||||
goto formerr;
|
||||
}
|
||||
ns_stats_increment(
|
||||
client->manager->sctx->nsstats,
|
||||
|
|
@ -1638,13 +1658,24 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) {
|
|||
result = process_keytag(client, &optbuf,
|
||||
optlen);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
ns_client_error(client, result);
|
||||
return result;
|
||||
goto formerr;
|
||||
}
|
||||
ns_stats_increment(
|
||||
client->manager->sctx->nsstats,
|
||||
ns_statscounter_keytagopt);
|
||||
break;
|
||||
case DNS_OPT_ZONEVERSION:
|
||||
if (optlen != 0 || WANTZONEVERSION(client)) {
|
||||
result = DNS_R_FORMERR;
|
||||
goto formerr;
|
||||
}
|
||||
ns_stats_increment(
|
||||
client->manager->sctx->nsstats,
|
||||
ns_statscounter_zoneversionopt);
|
||||
client->attributes |=
|
||||
NS_CLIENTATTR_WANTZONEVERSION;
|
||||
isc_buffer_forward(&optbuf, optlen);
|
||||
break;
|
||||
default:
|
||||
ns_stats_increment(
|
||||
client->manager->sctx->nsstats,
|
||||
|
|
@ -1660,6 +1691,17 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) {
|
|||
client->attributes |= NS_CLIENTATTR_WANTOPT;
|
||||
|
||||
return result;
|
||||
|
||||
formerr:
|
||||
if (result == DNS_R_FORMERR || result == DNS_R_OPTERR) {
|
||||
result = ns_client_addopt(client, client->message,
|
||||
&client->opt);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = DNS_R_FORMERR;
|
||||
}
|
||||
}
|
||||
ns_client_error(client, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1724,6 +1766,7 @@ ns__client_put_cb(void *client0) {
|
|||
*/
|
||||
ns_query_free(client);
|
||||
dns_ede_invalidate(&client->edectx);
|
||||
client_zoneversion_reset(client);
|
||||
|
||||
client->magic = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -224,6 +224,8 @@ struct ns_client {
|
|||
ISC_LINK(ns_client_t) rlink;
|
||||
unsigned char cookie[8];
|
||||
uint32_t expire;
|
||||
unsigned char *zoneversion;
|
||||
uint32_t zoneversionlength;
|
||||
unsigned char *keytag;
|
||||
uint16_t keytag_len;
|
||||
|
||||
|
|
@ -241,26 +243,28 @@ struct ns_client {
|
|||
#define NS_CLIENT_MAGIC ISC_MAGIC('N', 'S', 'C', 'c')
|
||||
#define NS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, NS_CLIENT_MAGIC)
|
||||
|
||||
#define NS_CLIENTATTR_TCP 0x00001
|
||||
#define NS_CLIENTATTR_RA 0x00002 /*%< Client gets recursive service */
|
||||
#define NS_CLIENTATTR_PKTINFO 0x00004 /*%< pktinfo is valid */
|
||||
#define NS_CLIENTATTR_MULTICAST 0x00008 /*%< recv'd from multicast */
|
||||
#define NS_CLIENTATTR_WANTDNSSEC 0x00010 /*%< include dnssec records */
|
||||
#define NS_CLIENTATTR_WANTNSID 0x00020 /*%< include nameserver ID */
|
||||
#define NS_CLIENTATTR_TCP 0x000001
|
||||
#define NS_CLIENTATTR_RA 0x000002 /*%< Client gets recursive service */
|
||||
#define NS_CLIENTATTR_PKTINFO 0x000004 /*%< pktinfo is valid */
|
||||
#define NS_CLIENTATTR_MULTICAST 0x000008 /*%< recv'd from multicast */
|
||||
#define NS_CLIENTATTR_WANTDNSSEC 0x000010 /*%< include dnssec records */
|
||||
#define NS_CLIENTATTR_WANTNSID 0x000020 /*%< include nameserver ID */
|
||||
#define NS_CLIENTATTR_BADCOOKIE \
|
||||
0x00040 /*%< Presented cookie is bad/out-of-date */
|
||||
#define NS_CLIENTATTR_WANTRC 0x00080 /*%< include Report-Channel */
|
||||
#define NS_CLIENTATTR_WANTAD 0x00100 /*%< want AD in response if possible */
|
||||
#define NS_CLIENTATTR_WANTCOOKIE 0x00200 /*%< return a COOKIE */
|
||||
#define NS_CLIENTATTR_HAVECOOKIE 0x00400 /*%< has a valid COOKIE */
|
||||
#define NS_CLIENTATTR_WANTEXPIRE 0x00800 /*%< return seconds to expire */
|
||||
#define NS_CLIENTATTR_HAVEEXPIRE 0x01000 /*%< return seconds to expire */
|
||||
#define NS_CLIENTATTR_WANTOPT 0x02000 /*%< add opt to reply */
|
||||
#define NS_CLIENTATTR_HAVEECS 0x04000 /*%< received an ECS option */
|
||||
#define NS_CLIENTATTR_WANTPAD 0x08000 /*%< pad reply */
|
||||
#define NS_CLIENTATTR_USEKEEPALIVE 0x10000 /*%< use TCP keepalive */
|
||||
#define NS_CLIENTATTR_NOSETFC 0x20000 /*%< don't set servfail cache */
|
||||
#define NS_CLIENTATTR_NEEDTCP 0x40000 /*%< send TC=1 */
|
||||
0x000040 /*%< Presented cookie is bad/out-of-date */
|
||||
#define NS_CLIENTATTR_WANTRC 0x000080 /*%< include Report-Channel */
|
||||
#define NS_CLIENTATTR_WANTAD 0x000100 /*%< want AD in response if possible */
|
||||
#define NS_CLIENTATTR_WANTCOOKIE 0x000200 /*%< return a COOKIE */
|
||||
#define NS_CLIENTATTR_HAVECOOKIE 0x000400 /*%< has a valid COOKIE */
|
||||
#define NS_CLIENTATTR_WANTEXPIRE 0x000800 /*%< return seconds to expire */
|
||||
#define NS_CLIENTATTR_HAVEEXPIRE 0x001000 /*%< return seconds to expire */
|
||||
#define NS_CLIENTATTR_WANTOPT 0x002000 /*%< add opt to reply */
|
||||
#define NS_CLIENTATTR_HAVEECS 0x004000 /*%< received an ECS option */
|
||||
#define NS_CLIENTATTR_WANTPAD 0x008000 /*%< pad reply */
|
||||
#define NS_CLIENTATTR_USEKEEPALIVE 0x010000 /*%< use TCP keepalive */
|
||||
#define NS_CLIENTATTR_NOSETFC 0x020000 /*%< don't set servfail cache */
|
||||
#define NS_CLIENTATTR_NEEDTCP 0x040000 /*%< send TC=1 */
|
||||
#define NS_CLIENTATTR_WANTZONEVERSION 0x100000 /*%< return zoneversion */
|
||||
#define NS_CLIENTATTR_HAVEZONEVERSION 0x200000 /*%< return zoneversion */
|
||||
|
||||
/*
|
||||
* Flag to use with the SERVFAIL cache to indicate
|
||||
|
|
|
|||
|
|
@ -84,49 +84,50 @@ enum {
|
|||
ns_statscounter_ecsopt = 46,
|
||||
ns_statscounter_padopt = 47,
|
||||
ns_statscounter_keepaliveopt = 48,
|
||||
ns_statscounter_zoneversionopt = 49,
|
||||
|
||||
ns_statscounter_nxdomainredirect = 49,
|
||||
ns_statscounter_nxdomainredirect_rlookup = 50,
|
||||
ns_statscounter_nxdomainredirect = 50,
|
||||
ns_statscounter_nxdomainredirect_rlookup = 51,
|
||||
|
||||
ns_statscounter_cookiein = 51,
|
||||
ns_statscounter_cookiebadsize = 52,
|
||||
ns_statscounter_cookiebadtime = 53,
|
||||
ns_statscounter_cookienomatch = 54,
|
||||
ns_statscounter_cookiematch = 55,
|
||||
ns_statscounter_cookienew = 56,
|
||||
ns_statscounter_badcookie = 57,
|
||||
ns_statscounter_cookiein = 52,
|
||||
ns_statscounter_cookiebadsize = 53,
|
||||
ns_statscounter_cookiebadtime = 54,
|
||||
ns_statscounter_cookienomatch = 55,
|
||||
ns_statscounter_cookiematch = 56,
|
||||
ns_statscounter_cookienew = 57,
|
||||
ns_statscounter_badcookie = 58,
|
||||
|
||||
ns_statscounter_nxdomainsynth = 58,
|
||||
ns_statscounter_nodatasynth = 59,
|
||||
ns_statscounter_wildcardsynth = 60,
|
||||
ns_statscounter_nxdomainsynth = 59,
|
||||
ns_statscounter_nodatasynth = 60,
|
||||
ns_statscounter_wildcardsynth = 61,
|
||||
|
||||
ns_statscounter_trystale = 61,
|
||||
ns_statscounter_usedstale = 62,
|
||||
ns_statscounter_trystale = 62,
|
||||
ns_statscounter_usedstale = 63,
|
||||
|
||||
ns_statscounter_prefetch = 63,
|
||||
ns_statscounter_keytagopt = 64,
|
||||
ns_statscounter_prefetch = 64,
|
||||
ns_statscounter_keytagopt = 65,
|
||||
|
||||
ns_statscounter_tcphighwater = 65,
|
||||
ns_statscounter_tcphighwater = 66,
|
||||
|
||||
ns_statscounter_reclimitdropped = 66,
|
||||
ns_statscounter_reclimitdropped = 67,
|
||||
|
||||
ns_statscounter_updatequota = 67,
|
||||
ns_statscounter_updatequota = 68,
|
||||
|
||||
ns_statscounter_recurshighwater = 68,
|
||||
ns_statscounter_recurshighwater = 69,
|
||||
|
||||
ns_statscounter_dot = 69,
|
||||
ns_statscounter_doh = 70,
|
||||
ns_statscounter_dohplain = 71,
|
||||
ns_statscounter_dot = 70,
|
||||
ns_statscounter_doh = 71,
|
||||
ns_statscounter_dohplain = 72,
|
||||
|
||||
ns_statscounter_proxyudp = 72,
|
||||
ns_statscounter_proxytcp = 73,
|
||||
ns_statscounter_proxydot = 74,
|
||||
ns_statscounter_proxydoh = 75,
|
||||
ns_statscounter_proxydohplain = 76,
|
||||
ns_statscounter_encryptedproxydot = 77,
|
||||
ns_statscounter_encryptedproxydoh = 78,
|
||||
ns_statscounter_proxyudp = 73,
|
||||
ns_statscounter_proxytcp = 74,
|
||||
ns_statscounter_proxydot = 75,
|
||||
ns_statscounter_proxydoh = 76,
|
||||
ns_statscounter_proxydohplain = 77,
|
||||
ns_statscounter_encryptedproxydot = 78,
|
||||
ns_statscounter_encryptedproxydoh = 79,
|
||||
|
||||
ns_statscounter_max = 79,
|
||||
ns_statscounter_max = 80,
|
||||
};
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -7938,6 +7938,55 @@ query_getexpire(query_ctx_t *qctx) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the zone version, if requested, when answering from a secondary,
|
||||
* mirror, or primary zone.
|
||||
*/
|
||||
static void
|
||||
query_getzoneversion(query_ctx_t *qctx) {
|
||||
CCTRACE(ISC_LOG_DEBUG(3), __func__);
|
||||
|
||||
if (qctx->zone == NULL || !qctx->is_zone ||
|
||||
qctx->client->query.restarts != 0 ||
|
||||
(qctx->client->attributes & NS_CLIENTATTR_WANTZONEVERSION) == 0 ||
|
||||
(qctx->client->attributes & NS_CLIENTATTR_HAVEZONEVERSION) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dns_zone_gettype(qctx->zone)) {
|
||||
case dns_zone_mirror:
|
||||
case dns_zone_primary:
|
||||
case dns_zone_secondary: {
|
||||
isc_buffer_t b;
|
||||
unsigned char buf[128];
|
||||
isc_buffer_init(&b, buf, sizeof(buf));
|
||||
isc_result_t result = dns_zone_getzoneversion(qctx->zone, &b);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
size_t len = isc_buffer_usedlength(&b);
|
||||
/*
|
||||
* Sanity check zone version from database
|
||||
* implementations. Minimum length and type 0
|
||||
* contraints.
|
||||
*/
|
||||
if (len < 2 || (buf[1] == 0 && len != 6)) {
|
||||
return;
|
||||
}
|
||||
qctx->client->attributes |=
|
||||
NS_CLIENTATTR_HAVEZONEVERSION;
|
||||
INSIST(qctx->client->zoneversion == NULL);
|
||||
qctx->client->zoneversion =
|
||||
isc_mem_get(qctx->client->manager->mctx, len);
|
||||
qctx->client->zoneversionlength = len;
|
||||
memmove(qctx->client->zoneversion, buf, len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*%
|
||||
* Fill the ANSWER section of a positive response.
|
||||
*/
|
||||
|
|
@ -8101,6 +8150,11 @@ query_respond(query_ctx_t *qctx) {
|
|||
*/
|
||||
query_getexpire(qctx);
|
||||
|
||||
/*
|
||||
* Set the zone version
|
||||
*/
|
||||
query_getzoneversion(qctx);
|
||||
|
||||
result = query_addanswer(qctx);
|
||||
if (result != ISC_R_COMPLETE) {
|
||||
return result;
|
||||
|
|
|
|||
Loading…
Reference in a new issue