Compare commits

...
Author SHA1 Message Date
Matthijs Mekking 5294313284 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-08-09 14:29:51 +02:00
Matthijs Mekking d07faffa93 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-08-09 14:27:56 +02:00
Matthijs Mekking caa7d9ba00 Add more generic remote server configuration
Add a new "remote" statement that configures a remote server and how to
communicate with it.

This takes two additional config options, "source" and "source-v6" to
configure the source address the remote server accepts. This may be
different per remote server.

The "remote" addresses can still refer to remote-server statements,
but this new statement makes "primaries", "masters", "parental-agents"
redundant and the plan is to deprecate these redundant statements.
Also it can be used for future "forwarders" work (see issue 2553).

Add new check config code and test to ensure there are no duplicate
names between "remote", "parental-agents" and "primaries" (and
"masters") lists.

Update the checkds system test to make use of "remote" configuration,
make sure the test still passes.
2022-08-04 14:29:49 +02:00
Matthijs Mekking 13aa796043 Add updateds system test 2022-07-26 12:08:42 +02:00
Matthijs Mekking dbae8fe142 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-07-26 12:08:26 +02:00
37 changed files with 1870 additions and 584 deletions
+86 -43
View File
@@ -500,6 +500,46 @@ named_config_getzonetype(const cfg_obj_t *zonetypeobj) {
return (ztype);
}
static isc_result_t
named_tuple_getport(const cfg_obj_t *obj, bool optional, in_port_t *portp) {
uint32_t val;
if (obj == NULL || !cfg_obj_isuint32(obj)) {
if (optional) {
return (ISC_R_SUCCESS);
}
}
val = cfg_obj_asuint32(obj);
if (val >= UINT16_MAX) {
cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
"port '%u' out of range", val);
return (ISC_R_RANGE);
}
*portp = (in_port_t)val;
return (ISC_R_SUCCESS);
}
static isc_result_t
named_tuple_getdscp(const cfg_obj_t *obj, bool optional, isc_dscp_t *dscpp) {
uint32_t val;
if (obj == NULL || !cfg_obj_isuint32(obj)) {
if (optional) {
return (ISC_R_SUCCESS);
}
}
val = cfg_obj_asuint32(obj);
if (val >= UINT16_MAX) {
cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
"dscp '%u' out of range", val);
return (ISC_R_RANGE);
}
*dscpp = (isc_dscp_t)val;
return (ISC_R_SUCCESS);
}
isc_result_t
named_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list,
in_port_t defport, isc_mem_t *mctx,
@@ -633,19 +673,25 @@ getremotesdef(const cfg_obj_t *cctx, const char *list, const char *name,
isc_result_t
named_config_getremotesdef(const cfg_obj_t *cctx, const char *list,
const char *name, const cfg_obj_t **ret) {
isc_result_t result;
const char *name, const cfg_obj_t **ret,
bool *isremote) {
isc_result_t result = ISC_R_NOTFOUND;
if (strcmp(list, "parental-agents") == 0) {
return (getremotesdef(cctx, list, name, ret));
/* Try "remote" first. */
result = getremotesdef(cctx, "remote", name, ret);
if (result == ISC_R_SUCCESS) {
*isremote = true;
return (result);
} else if (strcmp(list, "parental-agents") == 0) {
result = getremotesdef(cctx, list, name, ret);
} else if (strcmp(list, "primaries") == 0) {
result = getremotesdef(cctx, list, name, ret);
if (result != ISC_R_SUCCESS) {
result = getremotesdef(cctx, "masters", name, ret);
}
return (result);
}
return (ISC_R_NOTFOUND);
*isremote = false;
return (result);
}
static isc_result_t
@@ -723,6 +769,7 @@ named_config_getipandkeylist(const cfg_obj_t *config, const char *listtype,
uint32_t stackcount = 0, pushed = 0;
isc_result_t result;
const cfg_listelt_t *element;
const cfg_obj_t *remoteobj;
const cfg_obj_t *addrlist;
const cfg_obj_t *portobj;
const cfg_obj_t *dscpobj;
@@ -742,6 +789,7 @@ named_config_getipandkeylist(const cfg_obj_t *config, const char *listtype,
in_port_t port;
isc_dscp_t dscp;
} *stack = NULL;
bool isremote = false;
REQUIRE(ipkl != NULL);
REQUIRE(ipkl->count == 0);
@@ -771,30 +819,37 @@ named_config_getipandkeylist(const cfg_obj_t *config, const char *listtype,
}
newlist:
addrlist = cfg_tuple_get(list, "addresses");
portobj = cfg_tuple_get(list, "port");
dscpobj = cfg_tuple_get(list, "dscp");
if (isremote) {
addrlist = NULL;
portobj = NULL;
dscpobj = NULL;
/* TODO: source, source-v6 */
remoteobj = cfg_tuple_get(list, "options");
(void)cfg_map_get(remoteobj, "addresses", &addrlist);
if (cfg_obj_isuint32(portobj)) {
uint32_t val = cfg_obj_asuint32(portobj);
if (val > UINT16_MAX) {
cfg_obj_log(portobj, named_g_lctx, ISC_LOG_ERROR,
"port '%u' out of range", val);
result = ISC_R_RANGE;
result = named_tuple_getport(list, true, &port);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
port = (in_port_t)val;
}
if (dscpobj != NULL && cfg_obj_isuint32(dscpobj)) {
if (cfg_obj_asuint32(dscpobj) > 63) {
cfg_obj_log(dscpobj, named_g_lctx, ISC_LOG_ERROR,
"dscp value '%u' is out of range",
cfg_obj_asuint32(dscpobj));
result = ISC_R_RANGE;
result = named_tuple_getdscp(list, true, &dscp);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
} else {
addrlist = cfg_tuple_get(list, "addresses");
portobj = cfg_tuple_get(list, "port");
dscpobj = cfg_tuple_get(list, "dscp");
result = named_tuple_getport(portobj, true, &port);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
result = named_tuple_getdscp(dscpobj, true, &dscp);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
}
result = ISC_R_NOMEMORY;
@@ -812,8 +867,8 @@ resume:
tls = cfg_tuple_get(cfg_listelt_value(element), "tls");
if (!cfg_obj_issockaddr(addr)) {
const char *listname = cfg_obj_asstring(addr);
isc_result_t tresult;
const char *listname = cfg_obj_asstring(addr);
/* Grow lists? */
grow_array(mctx, lists, l, listcount);
@@ -828,8 +883,8 @@ resume:
continue;
}
list = NULL;
tresult = named_config_getremotesdef(config, listtype,
listname, &list);
tresult = named_config_getremotesdef(
config, listtype, listname, &list, &isremote);
if (tresult == ISC_R_NOTFOUND) {
cfg_obj_log(addr, named_g_lctx, ISC_LOG_ERROR,
"%s \"%s\" not found", listtype,
@@ -987,14 +1042,8 @@ named_config_getport(const cfg_obj_t *config, const char *type,
result = named_config_get(maps, type, &portobj);
INSIST(result == ISC_R_SUCCESS);
if (cfg_obj_asuint32(portobj) >= UINT16_MAX) {
cfg_obj_log(portobj, named_g_lctx, ISC_LOG_ERROR,
"port '%u' out of range",
cfg_obj_asuint32(portobj));
return (ISC_R_RANGE);
}
*portp = (in_port_t)cfg_obj_asuint32(portobj);
return (ISC_R_SUCCESS);
return (named_tuple_getport(portobj, false, portp));
}
isc_result_t
@@ -1013,14 +1062,8 @@ named_config_getdscp(const cfg_obj_t *config, isc_dscp_t *dscpp) {
*dscpp = -1;
return (ISC_R_SUCCESS);
}
if (cfg_obj_asuint32(dscpobj) >= 64) {
cfg_obj_log(dscpobj, named_g_lctx, ISC_LOG_ERROR,
"dscp '%u' out of range",
cfg_obj_asuint32(dscpobj));
return (ISC_R_RANGE);
}
*dscpp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
return (ISC_R_SUCCESS);
return (named_tuple_getdscp(dscpobj, false, dscpp));
}
struct keyalgorithms {
+2 -1
View File
@@ -64,7 +64,8 @@ named_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp,
isc_result_t
named_config_getremotesdef(const cfg_obj_t *cctx, const char *list,
const char *name, const cfg_obj_t **ret);
const char *name, const cfg_obj_t **ret,
bool *isremote);
isc_result_t
named_config_getipandkeylist(const cfg_obj_t *config, const char *listtype,
+17
View File
@@ -505,6 +505,23 @@ PRIMARIES
ipv6_address [ port integer ] ) [ key
string ] [ tls string ]; ... };
REMOTE
^^^^^^
::
remote string {
addresses { ( remote-servers | ipv4_address [ port integer ]
| ipv6_address [ port integer ] ) [ key string ] [ tls
string ]; ... };
dscp integer;
port integer;
source ( ipv4_address | * ) [ port ( integer | * ) ] [ dscp
integer ];
source-v6 ( ipv6_address | * ) [ port ( integer | * ) ] [ dscp
integer ];
};
SERVER
^^^^^^
+4 -1
View File
@@ -1880,9 +1880,12 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
if (obj == NULL && ztype == dns_zone_mirror &&
dns_name_equal(dns_zone_getorigin(zone), dns_rootname))
{
bool isremote = false;
result = named_config_getremotesdef(
named_g_config, "primaries",
DEFAULT_IANA_ROOT_ZONE_PRIMARIES, &obj);
DEFAULT_IANA_ROOT_ZONE_PRIMARIES, &obj,
&isremote);
INSIST(!isremote);
RETERR(result);
}
if (obj != NULL) {
@@ -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.
*/
parental-agents "net" {
192.168.1.1;
};
remote "net" {
addresses { 192.168.1.2; };
};
zone "example.net" {
type primary;
file "example.net.db";
parental-agents { "net"; };
};
@@ -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.
*/
primaries "net" {
addresses { 192.168.1.1; };
};
parental-agents "net" {
addresses { 192.168.1.2; };
};
zone "example.net" {
type primary;
file "example.net.db";
parental-agents { "net"; };
};
@@ -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.
*/
remote "net" {
addresses { 192.168.1.1; };
};
remote "net" {
addresses { 192.168.1.2; };
};
zone "example.net" {
type primary;
file "example.net.db";
parental-agents { "net"; };
};
@@ -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
@@ -183,6 +183,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;
};
@@ -192,6 +195,10 @@ view "fourth" {
parental-agents {
"parents";
};
update-ds {
1.2.3.4;
1.2.3.5;
};
dnssec-policy "default";
};
zone "dnssec-inherit" {
+9 -6
View File
@@ -34,8 +34,14 @@ controls {
inet 10.53.0.9 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
parental-agents "ns2" port @PORT@ {
10.53.0.2;
remote "ns2" {
addresses { 10.53.0.2; };
port @PORT@;
};
remote "ns4" {
addresses { 10.53.0.4; };
port @PORT@;
};
zone "." {
@@ -99,10 +105,7 @@ zone "multiple-dspublished.checkds" {
type primary;
file "multiple-dspublished.checkds.db";
dnssec-policy "default";
parental-agents {
10.53.0.2 port @PORT@;
10.53.0.4 port @PORT@;
};
parental-agents { "ns2"; "ns4"; };
};
/*
+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,45 @@
/*
* 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";
};
+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
@@ -382,7 +382,7 @@ The following blocks are supported:
Controls global server configuration options and sets defaults for other statements.
``parental-agents``
Defines a named list of servers for inclusion in primary and secondary zones' ``parental-agents`` lists.
Defines a named list of servers for inclusion in primary and secondary zones' ``parental-agents`` or ``update-ds`` lists.
.. _primaries:
@@ -6648,6 +6648,12 @@ Zone Options
``dnssec-secure-to-insecure``
See the description of ``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
@@ -1042,6 +1042,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> );
@@ -1115,6 +1116,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
@@ -55,6 +55,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
@@ -68,6 +68,7 @@
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
@@ -58,6 +58,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
@@ -71,6 +71,7 @@
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> );
+48 -36
View File
@@ -2029,11 +2029,11 @@ bind9_check_remoteserverlist(const cfg_obj_t *cctx, const char *list,
}
/*
* Check primaries lists for duplicates.
* Check remote server lists for duplicates.
*/
static isc_result_t
bind9_check_primarylists(const cfg_obj_t *cctx, isc_log_t *logctx,
isc_mem_t *mctx) {
bind9_check_remoteserverlists(const cfg_obj_t *cctx, isc_log_t *logctx,
isc_mem_t *mctx) {
isc_result_t result, tresult;
isc_symtab_t *symtab = NULL;
@@ -2041,6 +2041,16 @@ bind9_check_primarylists(const cfg_obj_t *cctx, isc_log_t *logctx,
if (result != ISC_R_SUCCESS) {
return (result);
}
tresult = bind9_check_remoteserverlist(cctx, "remote", logctx, symtab,
mctx);
if (tresult != ISC_R_SUCCESS) {
result = tresult;
}
tresult = bind9_check_remoteserverlist(cctx, "parental-agents", logctx,
symtab, mctx);
if (tresult != ISC_R_SUCCESS) {
result = tresult;
}
tresult = bind9_check_remoteserverlist(cctx, "primaries", logctx,
symtab, mctx);
if (tresult != ISC_R_SUCCESS) {
@@ -2055,28 +2065,6 @@ bind9_check_primarylists(const cfg_obj_t *cctx, isc_log_t *logctx,
return (result);
}
/*
* Check parental-agents lists for duplicates.
*/
static isc_result_t
bind9_check_parentalagentlists(const cfg_obj_t *cctx, isc_log_t *logctx,
isc_mem_t *mctx) {
isc_result_t result, tresult;
isc_symtab_t *symtab = NULL;
result = isc_symtab_create(mctx, 100, freekey, mctx, false, &symtab);
if (result != ISC_R_SUCCESS) {
return (result);
}
tresult = bind9_check_remoteserverlist(cctx, "parental-agents", logctx,
symtab, mctx);
if (tresult != ISC_R_SUCCESS) {
result = tresult;
}
isc_symtab_destroy(&symtab);
return (result);
}
#if HAVE_LIBNGHTTP2
static isc_result_t
bind9_check_httpserver(const cfg_obj_t *http, isc_log_t *logctx,
@@ -2362,10 +2350,15 @@ get_remotes(const cfg_obj_t *cctx, const char *list, const char *name,
static isc_result_t
get_remoteservers_def(const char *list, const char *name, const cfg_obj_t *cctx,
const cfg_obj_t **ret) {
const cfg_obj_t **ret, bool *isremote) {
isc_result_t result = ISC_R_NOTFOUND;
if (strcmp(list, "primaries") == 0) {
/* Try "remote" first. */
result = get_remotes(cctx, "remote", name, ret);
if (result == ISC_R_SUCCESS) {
*isremote = true;
return (result);
} else if (strcmp(list, "primaries") == 0) {
result = get_remotes(cctx, "primaries", name, ret);
if (result != ISC_R_SUCCESS) {
result = get_remotes(cctx, "masters", name, ret);
@@ -2373,6 +2366,8 @@ get_remoteservers_def(const char *list, const char *name, const cfg_obj_t *cctx,
} else if (strcmp(list, "parental-agents") == 0) {
result = get_remotes(cctx, "parental-agents", name, ret);
}
*isremote = false;
return (result);
}
@@ -2389,6 +2384,8 @@ validate_remotes(const char *list, const cfg_obj_t *obj,
const cfg_listelt_t **stack = NULL;
uint32_t stackcount = 0, pushed = 0;
const cfg_obj_t *listobj;
const cfg_obj_t *remoteobj;
bool isremote = false;
REQUIRE(countp != NULL);
result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab);
@@ -2398,7 +2395,13 @@ validate_remotes(const char *list, const cfg_obj_t *obj,
}
newlist:
listobj = cfg_tuple_get(obj, "addresses");
if (isremote) {
listobj = NULL;
remoteobj = cfg_tuple_get(obj, "options");
(void)cfg_map_get(remoteobj, "addresses", &listobj);
} else {
listobj = cfg_tuple_get(obj, "addresses");
}
element = cfg_list_first(listobj);
resume:
for (; element != NULL; element = cfg_list_next(element)) {
@@ -2483,7 +2486,8 @@ resume:
if (tresult == ISC_R_EXISTS) {
continue;
}
tresult = get_remoteservers_def(list, listname, config, &obj);
tresult = get_remoteservers_def(list, listname, config, &obj,
&isremote);
if (tresult != ISC_R_SUCCESS) {
if (result == ISC_R_SUCCESS) {
result = tresult;
@@ -3316,12 +3320,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,
@@ -3339,6 +3348,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;
}
}
/*
@@ -5781,11 +5797,7 @@ bind9_check_namedconf(const cfg_obj_t *config, bool check_plugins,
result = ISC_R_FAILURE;
}
if (bind9_check_primarylists(config, logctx, mctx) != ISC_R_SUCCESS) {
result = ISC_R_FAILURE;
}
if (bind9_check_parentalagentlists(config, logctx, mctx) !=
if (bind9_check_remoteserverlists(config, logctx, mctx) !=
ISC_R_SUCCESS) {
result = ISC_R_FAILURE;
}
+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 \
+226
View File
@@ -0,0 +1,226 @@
/*
* 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.
* if 'count' is not zero, 'keynames' and 'tlsnames' are
*not NULL.
*/
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);
/*%<
* Skipt 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
@@ -127,6 +127,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;
+8 -29
View File
@@ -642,7 +642,7 @@ dns_zone_maintenance(dns_zone_t *zone);
*/
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);
/*%<
@@ -650,8 +650,8 @@ 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 'count' the number of primaries.
*\li 'addresses' array of isc_sockaddr_t with port set or NULL.
*\li 'count' the number of addresses.
*\li 'keynames' array of dns_name_t's for tsig keys or NULL.
*
*\li If 'primaries' is NULL then 'count' must be zero.
@@ -663,7 +663,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);
/*%<
@@ -684,29 +684,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
@@ -717,8 +696,8 @@ 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 'count' to be the number of notifiees.
*\li 'addresses' to be non-NULL if count != 0.
*\li 'count' to be the number of addresses.
*
* Returns:
*\li #ISC_R_SUCCESS
+416
View File
@@ -0,0 +1,416 @@
/*
* 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->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;
}
+226 -467
View File
File diff suppressed because it is too large Load Diff
+30
View File
@@ -242,6 +242,33 @@ static cfg_type_t cfg_type_remoteservers = { "remote-servers", cfg_parse_tuple,
cfg_print_tuple, cfg_doc_tuple,
&cfg_rep_tuple, remotes_fields };
/*%
* Statement to configure communication with remote servers.
*/
static cfg_clausedef_t remote_clauses[] = {
{ "port", &cfg_type_uint32, 0 },
{ "dscp", &cfg_type_uint32, 0 },
{ "source", &cfg_type_sockaddr4wild, 0 },
{ "source-v6", &cfg_type_sockaddr6wild, 0 },
{ "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
{ NULL, NULL, 0 }
};
static cfg_clausedef_t *remote_clausesets[] = { remote_clauses, NULL };
cfg_type_t cfg_type_remoteopts = { "remoteopts", cfg_parse_map,
cfg_print_map, cfg_doc_map,
&cfg_rep_map, remote_clausesets };
static cfg_tuplefielddef_t remote_fields[] = { { "name", &cfg_type_astring, 0 },
{ "options",
&cfg_type_remoteopts, 0 },
{ NULL, NULL, 0 } };
static cfg_type_t cfg_type_remote = { "remote", cfg_parse_tuple,
cfg_print_tuple, cfg_doc_tuple,
&cfg_rep_tuple, remote_fields };
/*%
* "sockaddrkeylist", a list of socket addresses with optional keys
* and an optional default port, as used in the remote-servers option.
@@ -1162,6 +1189,7 @@ static cfg_clausedef_t namedconf_clauses[] = {
{ "options", &cfg_type_options, 0 },
{ "parental-agents", &cfg_type_remoteservers, CFG_CLAUSEFLAG_MULTI },
{ "primaries", &cfg_type_remoteservers, CFG_CLAUSEFLAG_MULTI },
{ "remote", &cfg_type_remote, CFG_CLAUSEFLAG_MULTI },
{ "statistics-channels", &cfg_type_statschannels,
CFG_CLAUSEFLAG_MULTI },
{ "tls", &cfg_type_tlsconf, CFG_CLAUSEFLAG_MULTI },
@@ -2405,6 +2433,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 }
};