Compare commits

...
Author SHA1 Message Date
Matthijs Mekking d0b1a8b69a fixup! Refactor zone.c, use dns_remote_t structure 2022-10-28 10:26:05 +02:00
Matthijs Mekking 2d2a5dc860 fixup! Add new files for remote server communication 2022-10-28 10:24:36 +02:00
Matthijs Mekking 6bf3a30585 Refactor zone.c, use dns_remote_t structure
Use the new dns_remote_t structure for remote server communication to
primaries, parental agents, etc.
2022-10-26 14:40:30 +02:00
Matthijs Mekking 8cfeb973a4 Add new files for remote server communication
The dns_remote_t structure is intended to replace the variables in
the structure that deals with remote server communication to primaries,
parental agents, forwarders, etc.
2022-10-26 14:38:19 +02:00
Matthijs Mekking 0dc43a0a1f Add updateds system test 2022-10-21 16:33:51 +02:00
Matthijs Mekking 24d9677c0f Add update-ds configuration
Introduce a way to configure servers that can be used to dynamically
update DS records during KSK rollovers. The update-ds configuration
option is a zone only option and may reference a parental-agents
statement.

Add some checkconf checks similar to parental-agents, like the option
being at the wrong level, a duplicate list, an empty list, at the
wrong zone type, and a reference to parental-agents not found.
2022-10-21 16:26:54 +02:00
27 changed files with 1606 additions and 504 deletions
@@ -0,0 +1,21 @@
/*
* 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 {
update-ds { 192.168.1.2; };
};
zone "example.net" {
type primary;
file "example.net.db";
};
@@ -0,0 +1,19 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
zone "example.net" {
type primary;
file "example.net.db";
update-ds { 192.168.1.1; };
update-ds { 192.168.1.1; };
};
@@ -0,0 +1,18 @@
/*
* 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.
*/
zone "example.net" {
type primary;
file "example.net.db";
update-ds { };
};
@@ -0,0 +1,18 @@
/*
* 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.
*/
zone "." {
type mirror;
file "root.mirror";
update-ds { 192.168.1.1; };
};
@@ -0,0 +1,22 @@
/*
* 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.
*/
parental-agents "com" {
192.168.1.2;
};
zone "example.net" {
type primary;
file "example.net.db";
update-ds { "net"; };
};
+7
View File
@@ -188,6 +188,9 @@ view "fourth" {
1.2.3.4;
1.2.3.5;
};
update-ds {
"parents";
};
dnssec-policy "test";
parental-source 10.10.10.10 port 53 dscp 55;
};
@@ -198,6 +201,10 @@ view "fourth" {
parental-agents {
"parents";
};
update-ds {
1.2.3.4;
1.2.3.5;
};
dnssec-policy "default";
};
zone "dnssec-inherit" {
+23
View File
@@ -0,0 +1,23 @@
#!/bin/sh
# 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.
set -e
rm -f dig.out*
rm -f ns*/named.conf ns*/named.memstats ns*/named.run*
rm -f ns*/*.jnl ns*/*.jbk
rm -f ns*/K*.private ns*/K*.key ns*/K*.state
rm -f ns*/dsset-*
rm -f ns*/*.db ns*/*.jnl ns*/*.jbk ns*/*.db.signed ns*/*.db.infile
rm -f ns*/keygen.out.* ns*/settime.out.* ns*/signer.out.*
rm -f ns*/managed-keys.bind*
@@ -0,0 +1,47 @@
/*
* 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.
*/
// NS2
options {
query-source address 10.53.0.2;
notify-source 10.53.0.2;
transfer-source 10.53.0.2;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
allow-transfer { any; };
recursion no;
};
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "." {
type hint;
file "../../common/root.hint";
};
zone "updateds" {
type primary;
file "updateds.db";
dnssec-policy yes;
allow-update { any; };
};
+31
View File
@@ -0,0 +1,31 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../../conf.sh
echo_i "ns2/setup.sh"
for subdomain in dspublish dswithdraw rollover
do
cp "../ns9/dsset-$subdomain.updateds." .
done
zone="updateds"
infile="updateds.db.infile"
zonefile="updateds.db"
CSK=$($KEYGEN -k default $zone 2> keygen.out.$zone)
cat template.db.in "${CSK}.key" > "$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile"
$SIGNER -S -g -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone 2>&1
@@ -0,0 +1,26 @@
; 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.
$TTL 300
@ IN SOA secondary.example. hostmaster.example. (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns2
ns2 A 10.53.0.2
dspublish NS ns9.dspublish
dswithdraw NS ns9.dswithdraw
rollover NS ns9.rollover
@@ -0,0 +1,77 @@
/*
* 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.
*/
// NS9
options {
query-source address 10.53.0.9;
notify-source 10.53.0.9;
transfer-source 10.53.0.9;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.9; };
listen-on-v6 { none; };
allow-transfer { any; };
recursion no;
};
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
parental-agents "ns2" port @PORT@ {
10.53.0.2;
};
zone "." {
type hint;
file "../../common/root.hint";
};
/*
* Zone with parental agent configured, time to submit the DS.
*/
zone "dspublish.updateds" {
type primary;
file "dspublish.updateds.db";
dnssec-policy "default";
parental-agents { "ns2"; };
update-ds { "ns2"; };
};
/*
* Zone with parental agent configured, time to withdraw the DS.
*/
zone "dswithdraw.updateds" {
type primary;
file "dswithdraw.updateds.db";
dnssec-policy "insecure";
parental-agents { "ns2"; };
update-ds { "ns2" };
};
/*
* Zone with parental agent configured, time to update the DS (rollover).
*/
zone "rollover.updateds" {
type primary;
file "rollover.updateds.db";
dnssec-policy "default";
parental-agents { "ns2"; };
update-ds { "ns2" };
};
+61
View File
@@ -0,0 +1,61 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../../conf.sh
echo_i "ns9/setup.sh"
setup() {
zone="$1"
echo_i "setting up zone: $zone"
zonefile="${zone}.db"
infile="${zone}.db.infile"
echo "$zone" >> zones
}
# Short environment variable names for key states and times.
H="HIDDEN"
R="RUMOURED"
O="OMNIPRESENT"
U="UNRETENTIVE"
T="now-30d"
Y="now-1y"
setup "dspublish.updateds"
cp template.db.in "$zonefile"
keytimes="-P $T -P sync $T -A $T"
CSK=$($KEYGEN -k default $keytimes $zone 2> keygen.out.$zone)
$SETTIME -s -g $O -k $O $T -r $O $T -z $O $T -d $H $T "$CSK" > settime.out.$zone 2>&1
cat template.db.in "${CSK}.key" > "$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
setup "dswithdraw.updateds"
cp template.db.in "$zonefile"
keytimes="-P $Y -P sync $Y -A $Y"
CSK=$($KEYGEN -k default $keytimes $zone 2> keygen.out.$zone)
$SETTIME -s -g $H -k $O $T -r $O $T -z $O $T -d $O $T "$CSK" > settime.out.$zone 2>&1
cat template.db.in "${CSK}.key" > "$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# TODO
setup "rollover.updateds"
cp template.db.in "$zonefile"
keytimes="-P $Y -P sync $Y -A $Y"
CSK=$($KEYGEN -k default $keytimes $zone 2> keygen.out.$zone)
$SETTIME -s -g $H -k $O $T -r $O $T -z $O $T -d $U $T "$CSK" > settime.out.$zone 2>&1
cat template.db.in "${CSK}.key" > "$infile"
private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >> "$infile"
$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
@@ -0,0 +1,27 @@
; 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.
$TTL 300
@ IN SOA mname1. . (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns9
ns9 A 10.53.0.9
a A 10.0.0.1
b A 10.0.0.2
c A 10.0.0.3
+32
View File
@@ -0,0 +1,32 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../conf.sh
set -e
$SHELL clean.sh
copy_setports ns2/named.conf.in ns2/named.conf
copy_setports ns9/named.conf.in ns9/named.conf
# Setup zones
(
cd ns9
$SHELL setup.sh
)
(
cd ns2
$SHELL setup.sh
)
+277
View File
@@ -0,0 +1,277 @@
#!/usr/bin/python3
# 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.
import mmap
import os
import subprocess
import sys
import time
import pytest
pytest.importorskip("dns", minversion="2.0.0")
import dns.exception
import dns.message
import dns.name
import dns.query
import dns.rcode
import dns.rdataclass
import dns.rdatatype
import dns.resolver
def has_signed_apex_nsec(zone, response):
has_nsec = False
has_rrsig = False
ttl = 300
nextname = "a."
types = "NS SOA RRSIG NSEC DNSKEY CDS CDNSKEY"
match = "{0} {1} IN NSEC {2}{0} {3}".format(zone, ttl, nextname, types)
sig = "{0} {1} IN RRSIG NSEC 13 2 300".format(zone, ttl)
for rr in response.answer:
if match in rr.to_text():
has_nsec = True
if sig in rr.to_text():
has_rrsig = True
if not has_nsec:
print("error: missing apex NSEC record in response")
if not has_rrsig:
print("error: missing NSEC signature in response")
return has_nsec and has_rrsig
def do_query(server, qname, qtype, tcp=False):
query = dns.message.make_query(qname, qtype, use_edns=True, want_dnssec=True)
try:
if tcp:
response = dns.query.tcp(
query, server.nameservers[0], timeout=3, port=server.port
)
else:
response = dns.query.udp(
query, server.nameservers[0], timeout=3, port=server.port
)
except dns.exception.Timeout:
print(
"error: query timeout for query {} {} to {}".format(
qname, qtype, server.nameservers[0]
)
)
return None
return response
def verify_zone(zone, transfer):
verify = os.getenv("VERIFY")
assert verify is not None
filename = "{}out".format(zone)
with open(filename, "w", encoding="utf-8") as file:
for rr in transfer.answer:
file.write(rr.to_text())
file.write("\n")
# dnssec-verify command with default arguments.
verify_cmd = [verify, "-z", "-o", zone, filename]
verifier = subprocess.run(verify_cmd, capture_output=True, check=True)
if verifier.returncode != 0:
print("error: dnssec-verify {} failed".format(zone))
sys.stderr.buffer.write(verifier.stderr)
return verifier.returncode == 0
def read_statefile(server, zone):
addr = server.nameservers[0]
count = 0
keyid = 0
state = {}
response = do_query(server, zone, "DS", tcp=True)
if not isinstance(response, dns.message.Message):
print("error: no response for {} DS from {}".format(zone, addr))
return {}
if response.rcode() == dns.rcode.NOERROR:
# fetch key id from response.
for rr in response.answer:
if rr.match(
dns.name.from_text(zone),
dns.rdataclass.IN,
dns.rdatatype.DS,
dns.rdatatype.NONE,
):
if count == 0:
keyid = list(dict(rr.items).items())[0][0].key_tag
count += 1
if count != 1:
print(
"error: expected a single DS in response for {} from {},"
"got {}".format(zone, addr, count)
)
return {}
else:
print(
"error: {} response for {} DNSKEY from {}".format(
dns.rcode.to_text(response.rcode()), zone, addr
)
)
return {}
filename = "ns9/K{}+013+{:05d}.state".format(zone, keyid)
print("read state file {}".format(filename))
try:
with open(filename, "r", encoding="utf-8") as file:
for line in file:
if line.startswith(";"):
continue
key, val = line.strip().split(":", 1)
state[key.strip()] = val.strip()
except FileNotFoundError:
# file may not be written just yet.
return {}
return state
def zone_check(server, zone):
addr = server.nameservers[0]
# wait until zone is fully signed.
signed = False
for _ in range(10):
response = do_query(server, zone, "NSEC")
if not isinstance(response, dns.message.Message):
print("error: no response for {} NSEC from {}".format(zone, addr))
elif response.rcode() == dns.rcode.NOERROR:
signed = has_signed_apex_nsec(zone, response)
else:
print(
"error: {} response for {} NSEC from {}".format(
dns.rcode.to_text(response.rcode()), zone, addr
)
)
if signed:
break
time.sleep(1)
assert signed
# check if zone if DNSSEC valid.
verified = False
transfer = do_query(server, zone, "AXFR", tcp=True)
if not isinstance(transfer, dns.message.Message):
print("error: no response for {} AXFR from {}".format(zone, addr))
elif transfer.rcode() == dns.rcode.NOERROR:
verified = verify_zone(zone, transfer)
else:
print(
"error: {} response for {} AXFR from {}".format(
dns.rcode.to_text(transfer.rcode()), zone, addr
)
)
assert verified
def keystate_check(server, zone, key):
val = 0
deny = False
search = key
if key.startswith("!"):
deny = True
search = key[1:]
for _ in range(10):
state = read_statefile(server, zone)
try:
val = state[search]
except KeyError:
pass
if not deny and val != 0:
break
if deny and val == 0:
break
time.sleep(1)
if deny:
assert val == 0
else:
assert val != 0
def wait_for_log(filename, log):
found = False
for _ in range(10):
print("read log file {}".format(filename))
try:
with open(filename, "r", encoding="utf-8") as file:
s = mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ)
if s.find(bytes(log, "ascii")) != -1:
found = True
except FileNotFoundError:
print("file not found {}".format(filename))
if found:
break
print("sleep")
time.sleep(1)
assert found
def test_updateds_publishds(named_port):
# Create resolver instances that will be used to send queries.
server = dns.resolver.Resolver()
server.nameservers = ["10.53.0.9"]
server.port = named_port
parent = dns.resolver.Resolver()
parent.nameservers = ["10.53.0.2"]
parent.port = named_port
# DS published in parent.
parent_check(parent, "publishds.updateds.")
def test_updateds_withdrawds(named_port):
# We create resolver instances that will be used to send queries.
server = dns.resolver.Resolver()
server.nameservers = ["10.53.0.9"]
server.port = named_port
parent = dns.resolver.Resolver()
parent.nameservers = ["10.53.0.2"]
parent.port = named_port
# DS removed from parent.
parent_check(parent, "withdrawds.updateds.")
# TBD: Key event does not change DS at the parent.
+7 -1
View File
@@ -400,7 +400,7 @@ The following blocks are supported:
Controls global server configuration options and sets defaults for other statements.
:any:`parental-agents`
Defines a named list of servers for inclusion in primary and secondary zones' :any:`parental-agents` lists.
Defines a named list of servers for inclusion in primary and secondary zones' ``parental-agents`` or ``update-ds`` lists.
:any:`primaries`
Defines a named list of servers for inclusion in stub and secondary zones' :any:`primaries` or :any:`also-notify` lists. (Note: this is a synonym for the original keyword ``masters``, which can still be used, but is no longer the preferred terminology.)
@@ -7298,6 +7298,12 @@ Zone Options
:any:`dnssec-secure-to-insecure`
See the description of :any:`dnssec-secure-to-insecure` in :ref:`boolean_options`.
``update-ds``
Defines a named list of servers that will be used to send dynamic
updates to. When the zone is configured with a ``dnssec-policy``,
BIND will try to update the DS RRset at these servers during a key
rollover.
.. _dynamic_update_policies:
Dynamic Update Policies
+2
View File
@@ -720,6 +720,7 @@ zone <string> [ <class> ] {
sig\-signing\-type <integer>;
sig\-validity\-interval <integer> [ <integer> ];
update\-check\-ksk <boolean>;
update\-ds [ port <integer> ] [ dscp <integer> ] { ( <remote\-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
update\-policy ( local | { ( deny | grant ) <string> ( 6to4\-self | external | krb5\-self | krb5\-selfsub | krb5\-subdomain | krb5\-subdomain\-self\-rhs | ms\-self | ms\-selfsub | ms\-subdomain | ms\-subdomain\-self\-rhs | name | self | selfsub | selfwild | subdomain | tcp\-self | wildcard | zonesub ) [ <string> ] <rrtypelist>; ... };
zero\-no\-soa\-ttl <boolean>;
zone\-statistics ( full | terse | none | <boolean> );
@@ -795,6 +796,7 @@ zone <string> [ <class> ] {
transfer\-source\-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
try\-tcp\-refresh <boolean>;
update\-check\-ksk <boolean>;
update\-ds [ port <integer> ] [ dscp <integer> ] { ( <remote\-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
use\-alt\-transfer\-source <boolean>;
zero\-no\-soa\-ttl <boolean>;
zone\-statistics ( full | terse | none | <boolean> );
+1
View File
@@ -56,6 +56,7 @@ zone <string> [ <class> ] {
sig-signing-type <integer>;
sig-validity-interval <integer> [ <integer> ];
update-check-ksk <boolean>;
update-ds [ port <integer> ] [ dscp <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
update-policy ( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesub ) [ <string> ] <rrtypelist>; ... };
zero-no-soa-ttl <boolean>;
zone-statistics ( full | terse | none | <boolean> );
+1
View File
@@ -59,6 +59,7 @@ zone <string> [ <class> ] {
transfer-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
try-tcp-refresh <boolean>;
update-check-ksk <boolean>;
update-ds [ port <integer> ] [ dscp <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
use-alt-transfer-source <boolean>;
zero-no-soa-ttl <boolean>;
zone-statistics ( full | terse | none | <boolean> );
+14 -2
View File
@@ -3345,12 +3345,17 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
}
/*
* Primary and secondary zones that have a "parental-agents" field,
* must have a corresponding "parental-agents" clause.
* Primary and secondary zones that have a "parental-agents" or
* "update-ds" field, must have a corresponding "parental-agents"
* clause.
*/
if (ztype == CFG_ZONE_PRIMARY || ztype == CFG_ZONE_SECONDARY) {
bool updateds = false;
obj = NULL;
(void)cfg_map_get(zoptions, "parental-agents", &obj);
check_parentalagents:
if (obj != NULL) {
uint32_t count;
tresult = validate_remotes("parental-agents", obj,
@@ -3368,6 +3373,13 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
result = ISC_R_FAILURE;
}
}
if (!updateds) {
obj = NULL;
(void)cfg_map_get(zoptions, "update-ds", &obj);
updateds = true;
goto check_parentalagents;
}
}
/*
+2
View File
@@ -109,6 +109,7 @@ libdns_la_HEADERS = \
include/dns/rdatasetiter.h \
include/dns/rdataslab.h \
include/dns/rdatatype.h \
include/dns/remote.h \
include/dns/request.h \
include/dns/resolver.h \
include/dns/result.h \
@@ -212,6 +213,7 @@ libdns_la_SOURCES = \
rdataset.c \
rdatasetiter.c \
rdataslab.c \
remote.c \
request.c \
resolver.c \
result.c \
+225
View File
@@ -0,0 +1,225 @@
/*
* 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.
*/
#pragma once
/*! \file dns/remote.h */
#include <stdbool.h>
#include <isc/lang.h>
#include <isc/mem.h>
#include <dns/types.h>
ISC_LANG_BEGINDECLS
struct dns_remote {
isc_mem_t *mctx;
isc_sockaddr_t *addresses;
isc_dscp_t *dscps;
dns_name_t **keynames;
dns_name_t **tlsnames;
bool *ok;
unsigned int addrcnt;
unsigned int curraddr;
};
isc_sockaddr_t *
dns_remote_addresses(dns_remote_t *remote);
/*%<
* Return the addresses of the remote server.
*
* Requires:
* 'remote' is not NULL.
*/
unsigned int
dns_remote_count(dns_remote_t *remote);
/*%<
* Return the number of addresses of the remote server.
*
* Requires:
* 'remote' is not NULL.
*/
dns_name_t **
dns_remote_keynames(dns_remote_t *remote);
/*%<
* Return the keynames of the remote server.
*
* Requires:
* 'remote' is not NULL.
*/
dns_name_t **
dns_remote_tlsnames(dns_remote_t *remote);
/*%<
* Return the tlsnames of the remote server.
*
* Requires:
* 'remote' is not NULL.
*/
void
dns_remote_init(dns_remote_t *remote, unsigned int count,
const isc_sockaddr_t *addrs, const isc_dscp_t *dscp,
dns_name_t **keynames, dns_name_t **tlsnames, bool mark,
isc_mem_t *mctx);
/*%<
* Initialize a remote server. Set the provided addresses (addrs),
* dscp's (dscp), key names (keynames) and tls names (tlsnames). Use the
* provided memory context (mctx) for allocations. If 'mark' is 'true',
* set up a list of boolean values to mark the server bad or good.
*
* Requires:
* 'remote' is not NULL.
* 'mctx' is not NULL.
* 'addrs' is not NULL, or 'count' equals zero.
* 'keynames' and 'tlsnames' are not NULL, then 'count > 0'.
*/
void
dns_remote_clear(dns_remote_t *remote);
/*%<
* Clear remote server 'remote', free memory.
*
* Requires:
* 'remote' is not NULL.
*/
bool
dns_remote_equal(dns_remote_t *a, dns_remote_t *b);
/*%<
* Compare two remote servers 'a' and 'b'. Check if the address
* count, the addresses, the dscps, the key names and the tls names are
* the same. Return 'true' if so, 'false' otherwise.
*
* Requires:
* 'a' is not NULL and 'b' is not NULL.
*/
void
dns_remote_reset(dns_remote_t *remote, bool clear_ok);
/*%<
* Reset the remote server, set the current address back to the
* first. If 'clear_ok' is 'true', clear any servers marked ok.
*
* Requires:
* 'remote' is not NULL.
*/
void
dns_remote_next(dns_remote_t *remote, bool skip_good);
/*%<
* Skip to the next address. If 'skip_good' is 'true', skip over
* already addresses already considered good, whatever good means in the
* context of this remote server.
*
* Requires:
* 'remote' is not NULL.
*/
isc_sockaddr_t
dns_remote_curraddr(dns_remote_t *remote);
/*%<
* Return the currently used address for this remote server.
*
* Requires:
* 'remote' is not NULL.
'remote->addresses' is not NULL.
*/
isc_sockaddr_t
dns_remote_addr(dns_remote_t *remote, unsigned int i);
/*%<
* Return the address at index 'i'. Returns NULL if we i is equal
* or larger than the address count.
*
* Requires:
* 'remote' is not NULL.
'remote->addresses' is not NULL.
*/
isc_dscp_t
dns_remote_dscp(dns_remote_t *remote);
/*%<
* Return the current dscp. Returns -1 if we have iterated over all
* addresses already, or if dscps are not used.
*
* Requires:
* 'remote' is not NULL.
*/
dns_name_t *
dns_remote_keyname(dns_remote_t *remote);
/*%<
* Return the current key name. Returns NULL if we have iterated
* over all addresses already, or if keynames are not used.
*
* Requires:
* 'remote' is not NULL.
*/
dns_name_t *
dns_remote_tlsname(dns_remote_t *remote);
/*%<
* Return the current tls name. Returns NULL if we have iterated
* over all addresses already, or if tlsnames are not used.
*
* Requires:
* 'remote' is not NULL.
*/
bool
dns_remote_allgood(dns_remote_t *remote);
/*%<
* Return 'true' if all the addresses are considered good.
*
* Requires:
* 'remote' is not NULL.
*/
void
dns_remote_mark(dns_remote_t *remote, bool good);
/*%<
* Mark the current address 'good' (or not good if 'good' is
* 'false').
*
* Requires:
* 'remote' is not NULL.
* The current address index is lower than the address count.
*/
bool
dns_remote_addrok(dns_remote_t *remote);
/*%<
* Return 'true' if the current address is marked good, 'false'
* otherwise. Also return 'true' if marking servers is not used.
*
* Requires:
* 'remote' is not NULL.
* The current address index is lower than the address count.
*/
bool
dns_remote_done(dns_remote_t *remote);
/*%<
* Return 'true' if we iterated over all addresses, 'false' otherwise.
*
* Requires:
* 'remote' is not NULL.
*/
ISC_LANG_ENDDECLS
+1
View File
@@ -128,6 +128,7 @@ typedef struct dns_rdataset dns_rdataset_t;
typedef ISC_LIST(dns_rdataset_t) dns_rdatasetlist_t;
typedef struct dns_rdatasetiter dns_rdatasetiter_t;
typedef uint16_t dns_rdatatype_t;
typedef struct dns_remote dns_remote_t;
typedef struct dns_request dns_request_t;
typedef struct dns_requestmgr dns_requestmgr_t;
typedef struct dns_resolver dns_resolver_t;
+9 -30
View File
@@ -633,7 +633,7 @@ dns_zone_dumptostream(dns_zone_t *zone, FILE *fd, dns_masterformat_t format,
*/
void
dns_zone_setprimaries(dns_zone_t *zone, const isc_sockaddr_t *primaries,
dns_zone_setprimaries(dns_zone_t *zone, isc_sockaddr_t *addresses,
dns_name_t **keynames, dns_name_t **tlsnames,
uint32_t count);
/*%<
@@ -641,11 +641,11 @@ dns_zone_setprimaries(dns_zone_t *zone, const isc_sockaddr_t *primaries,
*
* Require:
*\li 'zone' to be a valid zone.
*\li 'primaries' array of isc_sockaddr_t with port set or NULL.
*\li 'addresses' array of isc_sockaddr_t with port set or NULL.
*\li 'count' the number of primaries.
*\li 'keynames' array of dns_name_t's for tsig keys or NULL.
*
*\li If 'primaries' is NULL then 'count' must be zero.
*\li If 'addresses' is NULL then 'count' must be zero.
*
* Returns:
*\li #ISC_R_SUCCESS
@@ -654,7 +654,7 @@ dns_zone_setprimaries(dns_zone_t *zone, const isc_sockaddr_t *primaries,
*/
void
dns_zone_setparentals(dns_zone_t *zone, const isc_sockaddr_t *parentals,
dns_zone_setparentals(dns_zone_t *zone, isc_sockaddr_t *addresses,
dns_name_t **keynames, dns_name_t **tlsnames,
uint32_t count);
/*%<
@@ -662,11 +662,11 @@ dns_zone_setparentals(dns_zone_t *zone, const isc_sockaddr_t *parentals,
*
* Require:
*\li 'zone' to be a valid zone.
*\li 'parentals' array of isc_sockaddr_t with port set or NULL.
*\li 'addresses' array of isc_sockaddr_t with port set or NULL.
*\li 'count' the number of primaries.
*\li 'keynames' array of dns_name_t's for tsig keys or NULL.
*
*\li If 'parentals' is NULL then 'count' must be zero.
*\li If 'addresses' is NULL then 'count' must be zero.
*
* Returns:
*\li #ISC_R_SUCCESS
@@ -675,29 +675,8 @@ dns_zone_setparentals(dns_zone_t *zone, const isc_sockaddr_t *parentals,
*/
void
dns_zone_setparentals(dns_zone_t *zone, const isc_sockaddr_t *parentals,
dns_name_t **keynames, dns_name_t **tlsnames,
uint32_t count);
/*%<
* Set the list of parental agents for the zone.
*
* Require:
*\li 'zone' to be a valid zone.
*\li 'parentals' array of isc_sockaddr_t with port set or NULL.
*\li 'count' the number of parentals.
*\li 'keynames' array of dns_name_t's for tsig keys or NULL.
*
*\li If 'parentals' is NULL then 'count' must be zero.
*
* Returns:
*\li #ISC_R_SUCCESS
*\li #ISC_R_NOMEMORY
*\li Any result dns_name_dup() can return, if keynames!=NULL
*/
void
dns_zone_setalsonotify(dns_zone_t *zone, const isc_sockaddr_t *notify,
const isc_dscp_t *dscps, dns_name_t **keynames,
dns_zone_setalsonotify(dns_zone_t *zone, isc_sockaddr_t *addresses,
isc_dscp_t *dscps, dns_name_t **keynames,
dns_name_t **tlsnames, uint32_t count);
/*%<
* Set the list of additional servers to be notified when
@@ -708,7 +687,7 @@ dns_zone_setalsonotify(dns_zone_t *zone, const isc_sockaddr_t *notify,
*
* Require:
*\li 'zone' to be a valid zone.
*\li 'notify' to be non-NULL if count != 0.
*\li 'addresses' to be non-NULL if count != 0.
*\li 'count' to be the number of notifiees.
*
* Returns:
+418
View File
@@ -0,0 +1,418 @@
/*
* 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.
*/
/*! \file */
#include <stdbool.h>
#include <string.h>
#include <isc/result.h>
#include <isc/sockaddr.h>
#include <isc/types.h>
#include <isc/util.h>
#include <dns/name.h>
#include <dns/remote.h>
#include <dns/types.h>
isc_sockaddr_t *
dns_remote_addresses(dns_remote_t *remote) {
REQUIRE(remote != NULL);
return (remote->addresses);
}
unsigned int
dns_remote_count(dns_remote_t *remote) {
REQUIRE(remote != NULL);
return (remote->addrcnt);
}
dns_name_t **
dns_remote_keynames(dns_remote_t *remote) {
REQUIRE(remote != NULL);
return (remote->keynames);
}
dns_name_t **
dns_remote_tlsnames(dns_remote_t *remote) {
REQUIRE(remote != NULL);
return (remote->tlsnames);
}
void
dns_remote_init(dns_remote_t *remote, unsigned int count,
const isc_sockaddr_t *addrs, const isc_dscp_t *dscp,
dns_name_t **keynames, dns_name_t **tlsnames, bool mark,
isc_mem_t *mctx) {
unsigned int i;
REQUIRE(remote != NULL);
REQUIRE(count == 0 || addrs != NULL);
if (keynames != NULL || tlsnames != NULL) {
REQUIRE(count != 0);
}
remote->mctx = mctx;
if (addrs != NULL) {
remote->addresses = isc_mem_get(mctx,
count * sizeof(isc_sockaddr_t));
memmove(remote->addresses, addrs,
count * sizeof(isc_sockaddr_t));
} else {
remote->addresses = NULL;
}
if (dscp != NULL) {
remote->dscps = isc_mem_get(mctx, count * sizeof(isc_dscp_t));
memmove(remote->dscps, dscp, count * sizeof(isc_dscp_t));
} else {
remote->dscps = NULL;
}
if (keynames != NULL) {
remote->keynames = isc_mem_get(mctx, count * sizeof(keynames));
for (i = 0; i < count; i++) {
remote->keynames[i] = NULL;
}
for (i = 0; i < count; i++) {
if (keynames[i] != NULL) {
remote->keynames[i] =
isc_mem_get(mctx, sizeof(dns_name_t));
dns_name_init(remote->keynames[i], NULL);
dns_name_dup(keynames[i], mctx,
remote->keynames[i]);
}
}
} else {
remote->keynames = NULL;
}
if (tlsnames != NULL) {
remote->tlsnames = isc_mem_get(mctx, count * sizeof(tlsnames));
for (i = 0; i < count; i++) {
remote->tlsnames[i] = NULL;
}
for (i = 0; i < count; i++) {
if (tlsnames[i] != NULL) {
remote->tlsnames[i] =
isc_mem_get(mctx, sizeof(dns_name_t));
dns_name_init(remote->tlsnames[i], NULL);
dns_name_dup(tlsnames[i], mctx,
remote->tlsnames[i]);
}
}
} else {
remote->tlsnames = NULL;
}
if (mark) {
remote->ok = isc_mem_get(mctx, count * sizeof(bool));
for (i = 0; i < count; i++) {
remote->ok[i] = false;
}
} else {
remote->ok = NULL;
}
remote->addrcnt = count;
remote->curraddr = 0;
}
static bool
same_addrs(isc_sockaddr_t const *oldlist, isc_sockaddr_t const *newlist,
uint32_t count) {
unsigned int i;
if (oldlist == NULL && newlist == NULL) {
return (true);
}
if (oldlist == NULL || newlist == NULL) {
return (false);
}
for (i = 0; i < count; i++) {
if (!isc_sockaddr_equal(&oldlist[i], &newlist[i])) {
return (false);
}
}
return (true);
}
static bool
same_names(dns_name_t *const *oldlist, dns_name_t *const *newlist,
uint32_t count) {
unsigned int i;
if (oldlist == NULL && newlist == NULL) {
return (true);
}
if (oldlist == NULL || newlist == NULL) {
return (false);
}
for (i = 0; i < count; i++) {
if (oldlist[i] == NULL && newlist[i] == NULL) {
continue;
}
if (oldlist[i] == NULL || newlist[i] == NULL ||
!dns_name_equal(oldlist[i], newlist[i]))
{
return (false);
}
}
return (true);
}
static bool
same_dscp(isc_dscp_t *oldlist, isc_dscp_t *newlist, uint32_t count) {
unsigned int i;
if (oldlist == NULL && newlist == NULL) {
return (true);
}
if (oldlist == NULL || newlist == NULL) {
return (false);
}
for (i = 0; i < count; i++) {
if (oldlist[i] != newlist[i]) {
return (false);
}
}
return (true);
}
void
dns_remote_clear(dns_remote_t *remote) {
unsigned int count;
isc_mem_t *mctx;
REQUIRE(remote != NULL);
count = remote->addrcnt;
mctx = remote->mctx;
if (mctx == NULL) {
return;
}
if (remote->ok != NULL) {
isc_mem_put(mctx, remote->ok, count * sizeof(bool));
remote->ok = NULL;
}
if (remote->addresses != NULL) {
isc_mem_put(mctx, remote->addresses,
count * sizeof(isc_sockaddr_t));
remote->addresses = NULL;
}
if (remote->dscps != NULL) {
isc_mem_put(mctx, remote->dscps, count * sizeof(isc_dscp_t));
remote->dscps = NULL;
}
if (remote->keynames != NULL) {
unsigned int i;
for (i = 0; i < count; i++) {
if (remote->keynames[i] != NULL) {
dns_name_free(remote->keynames[i], mctx);
isc_mem_put(mctx, remote->keynames[i],
sizeof(dns_name_t));
remote->keynames[i] = NULL;
}
}
isc_mem_put(mctx, remote->keynames,
count * sizeof(dns_name_t *));
remote->keynames = NULL;
}
if (remote->tlsnames != NULL) {
unsigned int i;
for (i = 0; i < count; i++) {
if (remote->tlsnames[i] != NULL) {
dns_name_free(remote->tlsnames[i], mctx);
isc_mem_put(mctx, remote->tlsnames[i],
sizeof(dns_name_t));
remote->tlsnames[i] = NULL;
}
}
isc_mem_put(mctx, remote->tlsnames,
count * sizeof(dns_name_t *));
remote->tlsnames = NULL;
}
remote->curraddr = 0;
remote->addrcnt = 0;
remote->mctx = NULL;
}
bool
dns_remote_equal(dns_remote_t *a, dns_remote_t *b) {
REQUIRE(a != NULL);
REQUIRE(b != NULL);
if (a->addrcnt != b->addrcnt) {
return (false);
}
if (!same_addrs(a->addresses, b->addresses, a->addrcnt)) {
return (false);
}
if (!same_dscp(a->dscps, b->dscps, a->addrcnt)) {
return (false);
}
if (!same_names(a->keynames, b->keynames, a->addrcnt)) {
return (false);
}
if (!same_names(a->tlsnames, b->tlsnames, a->addrcnt)) {
return (false);
}
return (true);
}
void
dns_remote_reset(dns_remote_t *remote, bool clear_ok) {
REQUIRE(remote != NULL);
remote->curraddr = 0;
if (clear_ok && remote->ok != NULL) {
for (unsigned int i = 0; i < remote->addrcnt; i++) {
remote->ok[i] = false;
}
}
}
isc_sockaddr_t
dns_remote_curraddr(dns_remote_t *remote) {
REQUIRE(remote != NULL);
REQUIRE(remote->addresses != NULL);
REQUIRE(remote->curraddr < remote->addrcnt);
return (remote->addresses[remote->curraddr]);
}
isc_sockaddr_t
dns_remote_addr(dns_remote_t *remote, unsigned int i) {
REQUIRE(remote != NULL);
REQUIRE(remote->addresses != NULL);
REQUIRE(i < remote->addrcnt);
return (remote->addresses[i]);
}
isc_dscp_t
dns_remote_dscp(dns_remote_t *remote) {
REQUIRE(remote != NULL);
if (remote->dscps == NULL) {
return -1;
}
if (remote->curraddr >= remote->addrcnt) {
return -1;
}
return (remote->dscps[remote->curraddr]);
}
dns_name_t *
dns_remote_keyname(dns_remote_t *remote) {
REQUIRE(remote != NULL);
if (remote->keynames == NULL) {
return (NULL);
}
if (remote->curraddr >= remote->addrcnt) {
return (NULL);
}
return (remote->keynames[remote->curraddr]);
}
dns_name_t *
dns_remote_tlsname(dns_remote_t *remote) {
REQUIRE(remote != NULL);
if (remote->tlsnames == NULL) {
return (NULL);
}
if (remote->curraddr >= remote->addrcnt) {
return (NULL);
}
return (remote->tlsnames[remote->curraddr]);
}
void
dns_remote_next(dns_remote_t *remote, bool skip_good) {
REQUIRE(remote != NULL);
skip_to_next:
remote->curraddr++;
if (remote->curraddr >= remote->addrcnt) {
return;
}
if (skip_good && remote->ok != NULL && remote->ok[remote->curraddr]) {
goto skip_to_next;
}
}
bool
dns_remote_done(dns_remote_t *remote) {
REQUIRE(remote != NULL);
return (remote->curraddr >= remote->addrcnt);
}
bool
dns_remote_allgood(dns_remote_t *remote) {
REQUIRE(remote != NULL);
if (remote->ok == NULL) {
return (true);
}
for (unsigned int i = 0; i < remote->addrcnt; i++) {
if (!remote->ok[i]) {
return (false);
}
}
return (true);
}
bool
dns_remote_addrok(dns_remote_t *remote) {
REQUIRE(remote != NULL);
REQUIRE(remote->curraddr < remote->addrcnt);
if (remote->ok == NULL) {
return (true);
}
return (remote->ok[remote->curraddr]);
}
void
dns_remote_mark(dns_remote_t *remote, bool good) {
REQUIRE(remote != NULL);
REQUIRE(remote->curraddr < remote->addrcnt);
remote->ok[remote->curraddr] = good;
}
+218 -471
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -2406,6 +2406,8 @@ static cfg_clausedef_t zone_only_clauses[] = {
{ "server-addresses", &cfg_type_bracketed_netaddrlist,
CFG_ZONE_STATICSTUB },
{ "server-names", &cfg_type_namelist, CFG_ZONE_STATICSTUB },
{ "update-ds", &cfg_type_namesockaddrkeylist,
CFG_ZONE_PRIMARY | CFG_ZONE_SECONDARY },
{ "update-policy", &cfg_type_updatepolicy, CFG_ZONE_PRIMARY },
{ NULL, NULL, 0 }
};