From 743f446d41e0e1cb81abaed1a600fa86db48a620 Mon Sep 17 00:00:00 2001 From: Colin Vidal Date: Wed, 19 Nov 2025 17:34:16 +0100 Subject: [PATCH 1/7] allow named remote-servers list with key or tls The remote-servers clause enables the following pattern: remote-servers a { 1.2.3.4; ... }; remote-servers b { a key foo; }; However, `check.c` was explicitly throwing an error if a `key` or `tls` was provided after a named server-list. Remove this check, as this is a valid use case. (cherry picked from commit 046c6819b24ebd7d087ed33518b71b0ff23d9918) --- lib/isccfg/check.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/lib/isccfg/check.c b/lib/isccfg/check.c index 74a48da8fd..842b9abb16 100644 --- a/lib/isccfg/check.c +++ b/lib/isccfg/check.c @@ -2654,22 +2654,6 @@ resume: } continue; } - if (!cfg_obj_isvoid(key)) { - cfg_obj_log(key, logctx, ISC_LOG_ERROR, - "unexpected token '%s'", - cfg_obj_asstring(key)); - if (result == ISC_R_SUCCESS) { - result = ISC_R_FAILURE; - } - } - if (!cfg_obj_isvoid(tls)) { - cfg_obj_log(key, logctx, ISC_LOG_ERROR, - "unexpected token '%s'", - cfg_obj_asstring(tls)); - if (result == ISC_R_SUCCESS) { - result = ISC_R_FAILURE; - } - } listname = cfg_obj_asstring(addr); symvalue.as_cpointer = addr; tresult = isc_symtab_define(symtab, listname, 1, symvalue, From 6a14e96650d620148caf14cec96751a83f0adde9 Mon Sep 17 00:00:00 2001 From: Colin Vidal Date: Fri, 21 Nov 2025 17:05:15 +0100 Subject: [PATCH 2/7] test named remote-servers `key` usage Even though `remote-servers` now allows using named server-list with `key` (or `tls`), the `key` or `tls` is not used, in the context of a named server-list, when configuring the server. For instance, remote-servers foo { 10.53.0.5; }; also-notify { foo key fookey; }; won't use `fookey`. Add a system test highlighting the problem. (cherry picked from commit 32a4aa95aed294a28da8abfabfb17f53699e0b56) --- .../xfer-servers-list/ns1/named.conf.j2 | 77 +++++++++++++++++++ .../system/xfer-servers-list/ns1/test.db.j2 | 23 ++++++ .../xfer-servers-list/ns2/named.conf.j2 | 48 ++++++++++++ .../xfer-servers-list/ns3/named.conf.j2 | 48 ++++++++++++ .../xfer-servers-list/ns4/named.conf.j2 | 48 ++++++++++++ .../tests_xfer_servers_list.py | 68 ++++++++++++++++ 6 files changed, 312 insertions(+) create mode 100644 bin/tests/system/xfer-servers-list/ns1/named.conf.j2 create mode 100644 bin/tests/system/xfer-servers-list/ns1/test.db.j2 create mode 100644 bin/tests/system/xfer-servers-list/ns2/named.conf.j2 create mode 100644 bin/tests/system/xfer-servers-list/ns3/named.conf.j2 create mode 100644 bin/tests/system/xfer-servers-list/ns4/named.conf.j2 create mode 100644 bin/tests/system/xfer-servers-list/tests_xfer_servers_list.py diff --git a/bin/tests/system/xfer-servers-list/ns1/named.conf.j2 b/bin/tests/system/xfer-servers-list/ns1/named.conf.j2 new file mode 100644 index 0000000000..8400ca2458 --- /dev/null +++ b/bin/tests/system/xfer-servers-list/ns1/named.conf.j2 @@ -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. + */ + +options { + listen-on port @PORT@ { 10.53.0.1; }; + transfer-source 10.53.0.1; + pid-file "named.pid"; + recursion no; + /* + * Notifications are sent from 10.53.1.1. This, the `notify + * explicit` and `also-notify` below, enables us to use specific TSIG + * keys for notifications for each secondary server instead of using + * the xfer TSIG key. + */ + notify-source 10.53.1.1; + /* + * The test. zone doesn't specify other NS, however this makes it clear + * this NS must only notify from also-notify list. + */ + notify explicit; +}; + +key xfrkey { + algorithm @DEFAULT_HMAC@; + secret "9999abcd8765"; +}; + +key notifykey2 { + algorithm @DEFAULT_HMAC@; + secret "2222abcd8765"; +}; + +key notifykey3 { + algorithm @DEFAULT_HMAC@; + secret "3333abcd8765"; +}; + +key notifykey4 { + algorithm @DEFAULT_HMAC@; + secret "4444abcd8765"; +}; + +remote-servers secondariesbis { + 10.53.0.4 port @PORT@; /* gets notifykey4 */ +}; + +remote-servers secondaries { + 10.53.0.3 port @PORT@ key notifykey3; + secondariesbis key notifykey4; + 10.53.0.2 port @PORT@; /* gets notifykey2 */ +}; + +zone "test" { + type primary; + allow-transfer { key xfrkey; }; + also-notify { secondaries key notifykey2; }; + file "test.db"; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm @DEFAULT_HMAC@; +}; + +controls { + inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; diff --git a/bin/tests/system/xfer-servers-list/ns1/test.db.j2 b/bin/tests/system/xfer-servers-list/ns1/test.db.j2 new file mode 100644 index 0000000000..569a54f164 --- /dev/null +++ b/bin/tests/system/xfer-servers-list/ns1/test.db.j2 @@ -0,0 +1,23 @@ +; 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 serial = serial | default(1) %} + +$TTL 60 +test. IN SOA ns.test. op.test. ( + @serial@ ; serial + 100 ; refresh + 100 ; retry + 300 ; expire + 60 ; minimum + ) +test. NS ns.test. +ns.test. A 10.53.0.1 diff --git a/bin/tests/system/xfer-servers-list/ns2/named.conf.j2 b/bin/tests/system/xfer-servers-list/ns2/named.conf.j2 new file mode 100644 index 0000000000..22b9595932 --- /dev/null +++ b/bin/tests/system/xfer-servers-list/ns2/named.conf.j2 @@ -0,0 +1,48 @@ +/* + * 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 { + listen-on port @PORT@ { 10.53.0.2; }; + transfer-source 10.53.0.2; + pid-file "named.pid"; + recursion no; +}; + +key xfrkey { + algorithm @DEFAULT_HMAC@; + secret "9999abcd8765"; +}; + +key notifykey2 { + algorithm @DEFAULT_HMAC@; + secret "2222abcd8765"; +}; + +zone "test" { + /* + * Notify comes from a different IP address than the primary listening + * address, and with a different key. + */ + allow-notify { key notifykey2; }; + type secondary; + primaries { 10.53.0.1 port @PORT@ key xfrkey; }; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm @DEFAULT_HMAC@; +}; + +controls { + inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; diff --git a/bin/tests/system/xfer-servers-list/ns3/named.conf.j2 b/bin/tests/system/xfer-servers-list/ns3/named.conf.j2 new file mode 100644 index 0000000000..b17757e135 --- /dev/null +++ b/bin/tests/system/xfer-servers-list/ns3/named.conf.j2 @@ -0,0 +1,48 @@ +/* + * 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 { + listen-on port @PORT@ { 10.53.0.3; }; + transfer-source 10.53.0.3; + pid-file "named.pid"; + recursion no; +}; + +key xfrkey { + algorithm @DEFAULT_HMAC@; + secret "9999abcd8765"; +}; + +key notifykey3 { + algorithm @DEFAULT_HMAC@; + secret "3333abcd8765"; +}; + +zone "test" { + /* + * Notify comes from a different IP address than the primary listening + * address, and with a different key. + */ + allow-notify { key notifykey3; }; + type secondary; + primaries { 10.53.0.1 port @PORT@ key xfrkey; }; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm @DEFAULT_HMAC@; +}; + +controls { + inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; diff --git a/bin/tests/system/xfer-servers-list/ns4/named.conf.j2 b/bin/tests/system/xfer-servers-list/ns4/named.conf.j2 new file mode 100644 index 0000000000..fce6e301ba --- /dev/null +++ b/bin/tests/system/xfer-servers-list/ns4/named.conf.j2 @@ -0,0 +1,48 @@ +/* + * 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 { + listen-on port @PORT@ { 10.53.0.4; }; + transfer-source 10.53.0.4; + pid-file "named.pid"; + recursion no; +}; + +key xfrkey { + algorithm @DEFAULT_HMAC@; + secret "9999abcd8765"; +}; + +key notifykey4 { + algorithm @DEFAULT_HMAC@; + secret "4444abcd8765"; +}; + +zone "test" { + /* + * Notify comes from a different IP address than the primary listening + * address, and with a different key. + */ + allow-notify { key notifykey4; }; + type secondary; + primaries { 10.53.0.1 port @PORT@ key xfrkey; }; +}; + +key rndc_key { + secret "1234abcd8765"; + algorithm @DEFAULT_HMAC@; +}; + +controls { + inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; +}; diff --git a/bin/tests/system/xfer-servers-list/tests_xfer_servers_list.py b/bin/tests/system/xfer-servers-list/tests_xfer_servers_list.py new file mode 100644 index 0000000000..612be36b1d --- /dev/null +++ b/bin/tests/system/xfer-servers-list/tests_xfer_servers_list.py @@ -0,0 +1,68 @@ +# 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 re + +import isctest + + +def check_soa(ns, serial): + msg = isctest.query.create("test.", "SOA") + res = isctest.query.udp(msg, ns.ip) + isctest.check.noerror(res) + assert len(res.answer) == 1 + assert ( + res.answer[0].to_text() + == f"test. 60 IN SOA ns.test. op.test. {serial} 100 100 300 60" + ) + + +def wait_for_initial_xfrin(ns): + with ns.watch_log_from_start() as watcher: + watcher.wait_for_line("Transfer status: success") + check_soa(ns, 1) + + +def wait_for_sending_notify(ns1, ns, key_name): + pattern = re.compile( + f"zone test/IN: sending notify to {ns.ip}#[0-9]+ : TSIG \\({key_name}\\)" + ) + with ns1.watch_log_from_start() as watcher: + watcher.wait_for_line(pattern) + + +def test_xfer_servers_list(ns1, ns2, ns3, ns4, templates): + # First, wait for ns2, ns3 and ns4 to xfrin foo.fr and answer it + wait_for_initial_xfrin(ns2) + wait_for_initial_xfrin(ns3) + wait_for_initial_xfrin(ns4) + + # ns1 initially notifies the secondaries using the respectively configured keys + # - 10.53.0.2 has the key defined where `secondaries` is used + # - 10.53.0.3 has the key directly after its IP address + # - 10.53.0.4 has the key defined where `secondariesbis` is used + # (inside `secondaries`), so it uses this one instead of the one + # defined where `secondaries` is used. + # Because the order notification are sent doesn't matter here, we can't use wait_for_sequence + seq = [(ns2, "notifykey2"), (ns3, "notifykey3"), (ns4, "notifykey4")] + for ns, key_name in seq: + wait_for_sending_notify(ns1, ns, key_name) + + # Then, ns1 update foo.fr. It notifies ns2, ns3 and ns4 about it + templates.render("ns1/test.db", {"serial": 2}) + with ns2.watch_log_from_here() as ns2_watcher, ns3.watch_log_from_here() as ns3_watcher, ns4.watch_log_from_here() as ns4_watcher: + ns1.rndc("reload") + ns2_watcher.wait_for_line("Transfer status: success") + ns3_watcher.wait_for_line("Transfer status: success") + ns4_watcher.wait_for_line("Transfer status: success") + check_soa(ns2, 2) + check_soa(ns3, 2) + check_soa(ns4, 2) From 5d64b3a440209ed30ac87e3f8b6a693d5de1e0c3 Mon Sep 17 00:00:00 2001 From: Colin Vidal Date: Tue, 25 Nov 2025 10:16:13 +0100 Subject: [PATCH 3/7] minimal fix for missing `key`/`tls` in named `remote-servers` The following case remote-servers foo { 10.53.0.5; }; remote-servers bar { foo key fookey; }; did not work: the `fookey` was silently ignored. No matter how `bar` was used, the server `10.53.0.5` wouldn't be contacted using the TSIG key `fookey`. The problem is the same the for `tls` property. The reason of the problem was that when `named_config_getipandkeylist()` reached a named server-list (here, `foo`), it modified the current context in order to immediately process what is inside `foo`, but forgot to look at the fields `key` and `tls`, to associate those with `foo` addresses. Fix the problem by wrapping the `key` and `tls` from the "caller" list inside the existing `lists` struct which is used to figure out if a list is already processed or not. That way, the `key` and `tls` values can be read when adding the addresses of the nested list. (cherry picked from commit e732a8d25a8cbb78eed50b33d2569e8e9ea6e038) --- bin/named/config.c | 67 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/bin/named/config.c b/bin/named/config.c index 06fbc78ac9..ddd3746a45 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -617,9 +617,8 @@ named_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, dns_name_t **tlss = NULL; struct { const char *name; - in_port_t port; - isc_sockaddr_t *src4s; - isc_sockaddr_t *src6s; + dns_name_t *key; + dns_name_t *tls; } *lists = NULL; struct { const cfg_listelt_t *element; @@ -726,7 +725,20 @@ resume: result = tresult; goto cleanup; } - lists[l++].name = listname; + lists[l].name = listname; + + result = named_config_getname(mctx, key, &lists[l].key); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + result = named_config_getname(mctx, tls, &lists[l].tls); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + l++; + /* Grow stack? */ grow_array(mctx, stack, pushed, stackcount); /* @@ -755,6 +767,12 @@ resume: goto cleanup; } + if (keys[i] == NULL && lists != NULL && lists[l-1].key != NULL) { + keys[i] = isc_mem_get(mctx, sizeof(*keys[i])); + dns_name_init(keys[i]); + dns_name_dup(lists[l-1].key, mctx, keys[i]); + } + result = named_config_getname(mctx, tls, &tlss[i]); if (result != ISC_R_SUCCESS) { i++; /* Increment here so that cleanup on error works. @@ -762,6 +780,12 @@ resume: goto cleanup; } + if (tlss[i] == NULL && lists != NULL && lists[l-1].tls != NULL) { + tlss[i] = isc_mem_get(mctx, sizeof(*tlss[i])); + dns_name_init(tlss[i]); + dns_name_dup(lists[l-1].tls, mctx, tlss[i]); + } + /* If the port is unset, take it from one of the upper levels */ if (isc_sockaddr_getport(&addrs[i]) == 0) { in_port_t addr_port = port; @@ -800,6 +824,7 @@ resume: port = stack[pushed].port; src4 = stack[pushed].src4; src6 = stack[pushed].src6; + l--; goto resume; } @@ -809,6 +834,23 @@ resume: shrink_array(mctx, sources, i, srccount); if (lists != NULL) { + for (size_t j = 0; j < listcount; j++) { + if (lists[j].key != NULL) { + if (dns_name_dynamic(lists[j].key)) { + dns_name_free(lists[j].key, mctx); + } + isc_mem_put(mctx, lists[j].key, + sizeof(*lists[j].key)); + } + + if (lists[j].tls != NULL) { + if (dns_name_dynamic(lists[j].tls)) { + dns_name_free(lists[j].tls, mctx); + } + isc_mem_put(mctx, lists[j].tls, + sizeof(*lists[j].tls)); + } + } isc_mem_cput(mctx, lists, listcount, sizeof(lists[0])); } if (stack != NULL) { @@ -860,6 +902,23 @@ cleanup: isc_mem_cput(mctx, sources, srccount, sizeof(sources[0])); } if (lists != NULL) { + for (size_t j = 0; j < listcount; j++) { + if (lists[j].key != NULL) { + if (dns_name_dynamic(lists[j].key)) { + dns_name_free(lists[j].key, mctx); + } + isc_mem_put(mctx, lists[j].key, + sizeof(*lists[j].key)); + } + + if (lists[j].tls != NULL) { + if (dns_name_dynamic(lists[j].tls)) { + dns_name_free(lists[j].tls, mctx); + } + isc_mem_put(mctx, lists[j].tls, + sizeof(*lists[j].tls)); + } + } isc_mem_cput(mctx, lists, listcount, sizeof(lists[0])); } if (stack != NULL) { From f2b46d8a6aa16926e94425c2f8bfddf098c42331 Mon Sep 17 00:00:00 2001 From: Colin Vidal Date: Tue, 25 Nov 2025 13:56:37 +0100 Subject: [PATCH 4/7] refactoring of `named_config_getipandkeylist` Function `named_config_getipandkeylist()` processes the nested lists by overriding the current local variable of the function, jumping back to the beginning of the list processing. Of course, in order to go back to the previous state and process the remaining items of the current list, a "stack" array is used in order to put and get back the next list element and associated values. This makes the logic quite complex and error prone. Instead, this commit changes the logic by recursing into the nested list (while sharing a state between all the invocations). The processing is fundamentally identical, but instead of "manually" handling the stack to go back to the previous state (and process remaining elements of the current list), takes advantage of recursion. (cherry picked from commit ccb82ea85d34f8f3802e5f5c93c8bc7c825757bd) --- bin/named/config.c | 560 ++++++++++++++++++++++----------------------- 1 file changed, 277 insertions(+), 283 deletions(-) diff --git a/bin/named/config.c b/bin/named/config.c index ddd3746a45..fbc0d3dd31 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -593,39 +593,232 @@ named_config_getname(isc_mem_t *mctx, const cfg_obj_t *obj, static const char *remotesnames[4] = { "remote-servers", "parental-agents", "primaries", "masters" }; +typedef struct { + isc_sockaddr_t *addrs; + size_t addrsallocated; + + isc_sockaddr_t *sources; + size_t sourcesallocated; + + dns_name_t **keys; + size_t keysallocated; + + dns_name_t **tlss; + size_t tlssallocated; + + size_t count; /* common to addrs, sources, keys and tlss */ + + const char **seen; + size_t seencount; + size_t seenallocated; +} getipandkeylist_state_t; + +static isc_result_t +getipandkeylist(in_port_t defport, in_port_t deftlsport, + const cfg_obj_t *config, const cfg_obj_t *list, + in_port_t listport, const cfg_obj_t *listkey, + const cfg_obj_t *listtls, isc_mem_t *mctx, + getipandkeylist_state_t *s) { + const cfg_obj_t *addrlist = cfg_tuple_get(list, "addresses"); + const cfg_obj_t *portobj = cfg_tuple_get(list, "port"); + const cfg_obj_t *src4obj = cfg_tuple_get(list, "source"); + const cfg_obj_t *src6obj = cfg_tuple_get(list, "source-v6"); + in_port_t port; + isc_sockaddr_t src4; + isc_sockaddr_t src6; + isc_result_t result = ISC_R_SUCCESS; + + 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); + return ISC_R_RANGE; + } + port = (in_port_t)val; + } else if (listport > 0) { + /* + * No port in the current list, but it is a list named elsewhere + * where the port is defined, i.e: + * + * remote-servers bar { 10.53.0.4; }; + * remote-servers foo port 5555 { bar; 10.54.0.3; }; + * ^^^ + * + * The current list is the list `bar`, and the server + * `10.53.0.4` has the port `5555` defined. + */ + port = listport; + } + + if (src4obj != NULL && cfg_obj_issockaddr(src4obj)) { + src4 = *cfg_obj_assockaddr(src4obj); + } else { + isc_sockaddr_any(&src4); + } + + if (src6obj != NULL && cfg_obj_issockaddr(src6obj)) { + src6 = *cfg_obj_assockaddr(src6obj); + } else { + isc_sockaddr_any6(&src6); + } + + for (const cfg_listelt_t *element = cfg_list_first(addrlist); + element != NULL; element = cfg_list_next(element)) + { + const cfg_obj_t *addr; + const cfg_obj_t *key; + const cfg_obj_t *tls; + + skiplist: + addr = cfg_tuple_get(cfg_listelt_value(element), + "remoteselement"); + key = cfg_tuple_get(cfg_listelt_value(element), "key"); + tls = cfg_tuple_get(cfg_listelt_value(element), "tls"); + + /* + * If this is not an address, this is the name of a nested list, + * i.e. + * + * remote-servers nestedlist { 10.53.0.4; }; + * remote-servers list { nestedlist key foo; 10.54.0.6; }; + * ^^^^^^^^^^^^^^^^^^ + * + * We are currently in the list `list`, and `addr` is the name + * `nestedlist`, so we'll immediately recurse to process + * `nestedlist` before processing the next element of `list`. + */ + if (!cfg_obj_issockaddr(addr)) { + const char *listname = cfg_obj_asstring(addr); + const cfg_obj_t *nestedlist = NULL; + isc_result_t tresult; + + for (size_t i = 0; i < s->seencount; i++) { + if (strcasecmp(s->seen[i], listname) == 0) { + element = cfg_list_next(element); + goto skiplist; + } + } + + grow_array(mctx, s->seen, s->seencount, + s->seenallocated); + s->seen[s->seencount] = listname; + + for (size_t i = 0; i < ARRAY_SIZE(remotesnames); i++) { + tresult = named_config_getremotesdef( + config, remotesnames[i], listname, + &nestedlist); + if (tresult == ISC_R_SUCCESS) { + break; + } + } + + if (tresult != ISC_R_SUCCESS) { + cfg_obj_log(addr, named_g_lctx, ISC_LOG_ERROR, + "remote-servers \"%s\" not found", + listname); + return tresult; + } + + result = getipandkeylist(defport, deftlsport, config, + nestedlist, port, key, tls, + mctx, s); + if (result != ISC_R_SUCCESS) { + goto out; + } + continue; + } + + grow_array(mctx, s->addrs, s->count, s->addrsallocated); + grow_array(mctx, s->keys, s->count, s->keysallocated); + grow_array(mctx, s->tlss, s->count, s->tlssallocated); + grow_array(mctx, s->sources, s->count, s->sourcesallocated); + + s->addrs[s->count] = *cfg_obj_assockaddr(addr); + + result = named_config_getname(mctx, key, &s->keys[s->count]); + if (result != ISC_R_SUCCESS) { + goto out; + } + + /* + * The `key` is not provided for this address, so, if we're + * inside a named list, get the `key` provided at the point the + * list is used. + */ + if (s->keys[s->count] == NULL && listkey != NULL) { + result = named_config_getname(mctx, listkey, + &s->keys[s->count]); + if (result != ISC_R_SUCCESS) { + goto out; + } + } + + result = named_config_getname(mctx, tls, &s->tlss[s->count]); + if (result != ISC_R_SUCCESS) { + goto out; + } + + /* + * The `tls` is not provided for this address, so, if we're + * inside a named list, get the `tls` provided at the point the + * named list is used. + */ + if (s->tlss[s->count] == NULL && listtls != NULL) { + result = named_config_getname(mctx, listtls, + &s->tlss[s->count]); + } + + /* If the port is unset, take it from one of the upper levels */ + if (isc_sockaddr_getport(&s->addrs[s->count]) == 0) { + in_port_t addr_port = port; + + /* If unset, use the default port or tls-port */ + if (addr_port == 0) { + if (s->tlss[s->count] != NULL) { + addr_port = deftlsport; + } else { + addr_port = defport; + } + } + + isc_sockaddr_setport(&s->addrs[s->count], addr_port); + } + + switch (isc_sockaddr_pf(&s->addrs[s->count])) { + case PF_INET: + s->sources[s->count] = src4; + break; + case PF_INET6: + s->sources[s->count] = src6; + break; + default: + result = ISC_R_NOTIMPLEMENTED; + goto out; + } + + s->count++; + } + +out: + if (result != ISC_R_SUCCESS) { + /* + * Reaching this point without success means we were in the + * middle of adding a new entry, so it needs to be counted for + * correctly free `s.keys` and `s.tlss` (as they potentially + * added a new element right before something fails) + */ + s->count++; + } + return result; +} + isc_result_t named_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, isc_mem_t *mctx, dns_ipkeylist_t *ipkl) { - uint32_t addrcount = 0, srccount = 0; - uint32_t keycount = 0, tlscount = 0; - uint32_t listcount = 0, l = 0, i = 0; - uint32_t stackcount = 0, pushed = 0; isc_result_t result; - const cfg_listelt_t *element; - const cfg_obj_t *addrlist; - const cfg_obj_t *portobj; - const cfg_obj_t *src4obj; - const cfg_obj_t *src6obj; - in_port_t port = (in_port_t)0; in_port_t def_port; in_port_t def_tlsport; - isc_sockaddr_t src4; - isc_sockaddr_t src6; - isc_sockaddr_t *addrs = NULL; - isc_sockaddr_t *sources = NULL; - dns_name_t **keys = NULL; - dns_name_t **tlss = NULL; - struct { - const char *name; - dns_name_t *key; - dns_name_t *tls; - } *lists = NULL; - struct { - const cfg_listelt_t *element; - in_port_t port; - isc_sockaddr_t src4; - isc_sockaddr_t src6; - } *stack = NULL; REQUIRE(ipkl != NULL); REQUIRE(ipkl->count == 0); @@ -648,282 +841,83 @@ named_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list, goto cleanup; } -newlist: - addrlist = cfg_tuple_get(list, "addresses"); - portobj = cfg_tuple_get(list, "port"); - src4obj = cfg_tuple_get(list, "source"); - src6obj = cfg_tuple_get(list, "source-v6"); - - 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; - goto cleanup; - } - port = (in_port_t)val; + /* + * Process the (nested) list(s). + */ + getipandkeylist_state_t s = {}; + result = getipandkeylist(def_port, def_tlsport, config, list, + (in_port_t)0, NULL, NULL, mctx, &s); + if (result != ISC_R_SUCCESS) { + goto cleanup; } - if (src4obj != NULL && cfg_obj_issockaddr(src4obj)) { - src4 = *cfg_obj_assockaddr(src4obj); - } else { - isc_sockaddr_any(&src4); + shrink_array(mctx, s.addrs, s.count, s.addrsallocated); + shrink_array(mctx, s.keys, s.count, s.keysallocated); + shrink_array(mctx, s.tlss, s.count, s.tlssallocated); + shrink_array(mctx, s.sources, s.count, s.sourcesallocated); + + ipkl->addrs = s.addrs; + ipkl->keys = s.keys; + ipkl->tlss = s.tlss; + ipkl->sources = s.sources; + ipkl->count = s.count; + + INSIST(s.addrsallocated == s.keysallocated); + INSIST(s.addrsallocated == s.tlssallocated); + INSIST(s.addrsallocated == s.sourcesallocated); + ipkl->allocated = s.addrsallocated; + + if (s.seen != NULL) { + /* + * `s.seen` is not shrinked (no point, as it's deleted right + * away anyway), so we need to use `s.seenallocated` to + * correctly free the array. + */ + isc_mem_cput(mctx, s.seen, s.seenallocated, sizeof(s.seen[0])); } - if (src6obj != NULL && cfg_obj_issockaddr(src6obj)) { - src6 = *cfg_obj_assockaddr(src6obj); - } else { - isc_sockaddr_any6(&src6); - } - - element = cfg_list_first(addrlist); -resume: - for (; element != NULL; element = cfg_list_next(element)) { - const cfg_obj_t *addr; - const cfg_obj_t *key; - const cfg_obj_t *tls; - - addr = cfg_tuple_get(cfg_listelt_value(element), - "remoteselement"); - key = cfg_tuple_get(cfg_listelt_value(element), "key"); - 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; - uint32_t j; - - /* Grow lists? */ - grow_array(mctx, lists, l, listcount); - - /* Seen? */ - for (j = 0; j < l; j++) { - if (strcasecmp(lists[j].name, listname) == 0) { - break; - } - } - if (j < l) { - continue; - } - list = NULL; - tresult = ISC_R_NOTFOUND; - for (size_t n = 0; n < ARRAY_SIZE(remotesnames); n++) { - tresult = named_config_getremotesdef( - config, remotesnames[n], listname, - &list); - if (tresult == ISC_R_SUCCESS) { - break; - } - } - if (tresult == ISC_R_NOTFOUND) { - cfg_obj_log(addr, named_g_lctx, ISC_LOG_ERROR, - "remote-servers \"%s\" not found", - listname); - } - if (tresult != ISC_R_SUCCESS) { - result = tresult; - goto cleanup; - } - lists[l].name = listname; - - result = named_config_getname(mctx, key, &lists[l].key); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - result = named_config_getname(mctx, tls, &lists[l].tls); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - l++; - - /* Grow stack? */ - grow_array(mctx, stack, pushed, stackcount); - /* - * We want to resume processing this list on the - * next element. - */ - stack[pushed].element = cfg_list_next(element); - stack[pushed].port = port; - stack[pushed].src4 = src4; - stack[pushed].src6 = src6; - pushed++; - goto newlist; - } - - grow_array(mctx, addrs, i, addrcount); - grow_array(mctx, keys, i, keycount); - grow_array(mctx, tlss, i, tlscount); - grow_array(mctx, sources, i, srccount); - - addrs[i] = *cfg_obj_assockaddr(addr); - - result = named_config_getname(mctx, key, &keys[i]); - if (result != ISC_R_SUCCESS) { - i++; /* Increment here so that cleanup on error works. - */ - goto cleanup; - } - - if (keys[i] == NULL && lists != NULL && lists[l-1].key != NULL) { - keys[i] = isc_mem_get(mctx, sizeof(*keys[i])); - dns_name_init(keys[i]); - dns_name_dup(lists[l-1].key, mctx, keys[i]); - } - - result = named_config_getname(mctx, tls, &tlss[i]); - if (result != ISC_R_SUCCESS) { - i++; /* Increment here so that cleanup on error works. - */ - goto cleanup; - } - - if (tlss[i] == NULL && lists != NULL && lists[l-1].tls != NULL) { - tlss[i] = isc_mem_get(mctx, sizeof(*tlss[i])); - dns_name_init(tlss[i]); - dns_name_dup(lists[l-1].tls, mctx, tlss[i]); - } - - /* If the port is unset, take it from one of the upper levels */ - if (isc_sockaddr_getport(&addrs[i]) == 0) { - in_port_t addr_port = port; - - /* If unset, use the default port or tls-port */ - if (addr_port == 0) { - if (tlss[i] != NULL) { - addr_port = def_tlsport; - } else { - addr_port = def_port; - } - } - - isc_sockaddr_setport(&addrs[i], addr_port); - } - - switch (isc_sockaddr_pf(&addrs[i])) { - case PF_INET: - sources[i] = src4; - break; - case PF_INET6: - sources[i] = src6; - break; - default: - i++; /* Increment here so that cleanup on error works. - */ - result = ISC_R_NOTIMPLEMENTED; - goto cleanup; - } - - i++; - } - if (pushed != 0) { - pushed--; - element = stack[pushed].element; - port = stack[pushed].port; - src4 = stack[pushed].src4; - src6 = stack[pushed].src6; - l--; - goto resume; - } - - shrink_array(mctx, addrs, i, addrcount); - shrink_array(mctx, keys, i, keycount); - shrink_array(mctx, tlss, i, tlscount); - shrink_array(mctx, sources, i, srccount); - - if (lists != NULL) { - for (size_t j = 0; j < listcount; j++) { - if (lists[j].key != NULL) { - if (dns_name_dynamic(lists[j].key)) { - dns_name_free(lists[j].key, mctx); - } - isc_mem_put(mctx, lists[j].key, - sizeof(*lists[j].key)); - } - - if (lists[j].tls != NULL) { - if (dns_name_dynamic(lists[j].tls)) { - dns_name_free(lists[j].tls, mctx); - } - isc_mem_put(mctx, lists[j].tls, - sizeof(*lists[j].tls)); - } - } - isc_mem_cput(mctx, lists, listcount, sizeof(lists[0])); - } - if (stack != NULL) { - isc_mem_cput(mctx, stack, stackcount, sizeof(stack[0])); - } - - INSIST(keycount == addrcount); - INSIST(tlscount == addrcount); - INSIST(srccount == addrcount); - - ipkl->addrs = addrs; - ipkl->keys = keys; - ipkl->tlss = tlss; - ipkl->sources = sources; - ipkl->count = addrcount; - ipkl->allocated = addrcount; - return ISC_R_SUCCESS; cleanup: - if (addrs != NULL) { - isc_mem_cput(mctx, addrs, addrcount, sizeof(addrs[0])); + /* + * Because we didn't shrinked the array back in this path, we need to + * use `s.*allocated` to correctly free the allocated arrays. + */ + if (s.addrs != NULL) { + isc_mem_cput(mctx, s.addrs, s.count, sizeof(s.addrs[0])); } - if (keys != NULL) { - for (size_t j = 0; j < i; j++) { - if (keys[j] == NULL) { + if (s.keys != NULL) { + for (size_t i = 0; i < s.count; i++) { + if (s.keys[i] == NULL) { continue; } - if (dns_name_dynamic(keys[j])) { - dns_name_free(keys[j], mctx); + if (dns_name_dynamic(s.keys[i])) { + dns_name_free(s.keys[i], mctx); } - isc_mem_put(mctx, keys[j], sizeof(*keys[j])); + isc_mem_put(mctx, s.keys[i], sizeof(*s.keys[i])); } - isc_mem_cput(mctx, keys, keycount, sizeof(keys[0])); + isc_mem_cput(mctx, s.keys, s.keysallocated, sizeof(s.keys[0])); } - if (tlss != NULL) { - for (size_t j = 0; j < i; j++) { - if (tlss[j] == NULL) { + if (s.tlss != NULL) { + for (size_t i = 0; i < s.count; i++) { + if (s.tlss[i] == NULL) { continue; } - if (dns_name_dynamic(tlss[j])) { - dns_name_free(tlss[j], mctx); + if (dns_name_dynamic(s.tlss[i])) { + dns_name_free(s.tlss[i], mctx); } - isc_mem_put(mctx, tlss[j], sizeof(*tlss[j])); + isc_mem_put(mctx, s.tlss[i], sizeof(*s.tlss[i])); } - isc_mem_cput(mctx, tlss, tlscount, sizeof(tlss[0])); + isc_mem_cput(mctx, s.tlss, s.tlssallocated, sizeof(s.tlss[0])); } - if (sources != NULL) { - isc_mem_cput(mctx, sources, srccount, sizeof(sources[0])); + if (s.sources != NULL) { + isc_mem_cput(mctx, s.sources, s.sourcesallocated, + sizeof(s.sources[0])); + } + if (s.seen != NULL) { + isc_mem_cput(mctx, s.seen, s.seenallocated, sizeof(s.seen[0])); } - if (lists != NULL) { - for (size_t j = 0; j < listcount; j++) { - if (lists[j].key != NULL) { - if (dns_name_dynamic(lists[j].key)) { - dns_name_free(lists[j].key, mctx); - } - isc_mem_put(mctx, lists[j].key, - sizeof(*lists[j].key)); - } - if (lists[j].tls != NULL) { - if (dns_name_dynamic(lists[j].tls)) { - dns_name_free(lists[j].tls, mctx); - } - isc_mem_put(mctx, lists[j].tls, - sizeof(*lists[j].tls)); - } - } - isc_mem_cput(mctx, lists, listcount, sizeof(lists[0])); - } - if (stack != NULL) { - isc_mem_cput(mctx, stack, stackcount, sizeof(stack[0])); - } return result; } From b260f7be90a20547bbbc456e08d9b4ba93905f01 Mon Sep 17 00:00:00 2001 From: Colin Vidal Date: Tue, 25 Nov 2025 15:34:26 +0100 Subject: [PATCH 5/7] check remote-servers list correctness `check.c` only checks if `remote-servers`, `primaries`, etc. are not duplicated inside the configuration file, but does not check the correctness of its definition. This commit fixes this by calling `validate_remotes()` for each `remote-servers` (and other aliases), which validates the correctness of the definition itself (this is the same call done to validate other cases like `also-notify`, etc.). (cherry picked from commit 1a732b6b8ecc89232724d80adba84350976ae2ca) --- lib/isccfg/check.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/isccfg/check.c b/lib/isccfg/check.c index 842b9abb16..a2c605bd77 100644 --- a/lib/isccfg/check.c +++ b/lib/isccfg/check.c @@ -86,6 +86,9 @@ keydirexist(const cfg_obj_t *zcgf, const char *optname, dns_name_t *zname, static const cfg_obj_t * find_maplist(const cfg_obj_t *config, const char *listname, const char *name); +static isc_result_t +validate_remotes(const cfg_obj_t *obj, const cfg_obj_t *config, + uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx); static void freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) { UNUSED(type); @@ -2209,6 +2212,12 @@ check_remoteserverlist(const cfg_obj_t *cctx, const char *list, break; } + uint32_t dummy = 0; + result = validate_remotes(obj, cctx, &dummy, logctx, mctx); + if (result != ISC_R_SUCCESS) { + break; + } + elt = cfg_list_next(elt); } return result; From 9e8994d8538fbd27199701b337b66a408f700647 Mon Sep 17 00:00:00 2001 From: Colin Vidal Date: Tue, 25 Nov 2025 15:45:22 +0100 Subject: [PATCH 6/7] check validity of key and tls in a server-list If a `key` or `tls` is associated to an IP address inside a server-list, only the `tls` existence in the configuration was checked. Also, if `key` or `tls` is associated to a named server-list inside a server-list, there was no check at all. Add the check for making sure a `key` is defined in the configuration, as well as the check for `key` and `tls` when used on a named server-list. (cherry picked from commit 2956e4fc45b3c2142a3351682d4200647448f193) --- bin/named/config.c | 2 +- lib/isccfg/check.c | 156 ++++++++++++++++++++++++++++++++------------- 2 files changed, 111 insertions(+), 47 deletions(-) diff --git a/bin/named/config.c b/bin/named/config.c index fbc0d3dd31..e247557b0b 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -623,7 +623,7 @@ getipandkeylist(in_port_t defport, in_port_t deftlsport, const cfg_obj_t *portobj = cfg_tuple_get(list, "port"); const cfg_obj_t *src4obj = cfg_tuple_get(list, "source"); const cfg_obj_t *src6obj = cfg_tuple_get(list, "source-v6"); - in_port_t port; + in_port_t port = (in_port_t)0; isc_sockaddr_t src4; isc_sockaddr_t src6; isc_result_t result = ISC_R_SUCCESS; diff --git a/lib/isccfg/check.c b/lib/isccfg/check.c index a2c605bd77..0999c740d5 100644 --- a/lib/isccfg/check.c +++ b/lib/isccfg/check.c @@ -2578,6 +2578,102 @@ get_remoteservers_def(const char *name, const cfg_obj_t *cctx, return get_remotes(cctx, "masters", name, ret); } +static isc_result_t +validate_remotes_key(const cfg_obj_t *config, const cfg_obj_t *key, + isc_log_t *logctx) { + isc_result_t result = ISC_R_SUCCESS; + + if (cfg_obj_isstring(key)) { + const cfg_obj_t *keys = NULL; + const char *str = cfg_obj_asstring(key); + dns_fixedname_t fname; + dns_name_t *nm = dns_fixedname_initname(&fname); + bool found = false; + + result = dns_name_fromstring(nm, str, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(key, logctx, ISC_LOG_ERROR, + "'%s' is not a valid name", str); + } + + result = cfg_map_get(config, "key", &keys); + + for (const cfg_listelt_t *elt = cfg_list_first(keys); + elt != NULL; elt = cfg_list_next(elt)) + { + /* + * `key` are normalized TSIG which must be + * identified by a domain name, so this is + * needed. Otherwise, with a raw string + * comparison we could have: + * + * remote-servers { x.y.z.s key foo }; + * key foo. { + * ... + * }; + * + * This would otherwise fail, even though the + * key exists. + */ + const cfg_obj_t *foundkey = cfg_listelt_value(elt); + const char *foundkeystr = + cfg_obj_asstring(cfg_map_getname(foundkey)); + dns_fixedname_t foundfname; + dns_name_t *foundkeyname = + dns_fixedname_initname(&foundfname); + + result = dns_name_fromstring(foundkeyname, foundkeystr, + dns_rootname, 0, NULL); + + if (dns_name_equal(nm, foundkeyname)) { + found = true; + break; + } + } + + if (!found) { + cfg_obj_log(key, logctx, ISC_LOG_ERROR, + "key '%s' is not defined", + cfg_obj_asstring(key)); + result = ISC_R_FAILURE; + } + } + + return result; +} + +static isc_result_t +validate_remotes_tls(const cfg_obj_t *config, const cfg_obj_t *tls, + isc_log_t *logctx) { + isc_result_t result = ISC_R_SUCCESS; + + if (cfg_obj_isstring(tls)) { + const char *str = cfg_obj_asstring(tls); + dns_fixedname_t fname; + dns_name_t *nm = dns_fixedname_initname(&fname); + + result = dns_name_fromstring(nm, str, dns_rootname, 0, NULL); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(tls, logctx, ISC_LOG_ERROR, + "'%s' is not a valid name", str); + } + + if (strcasecmp(str, "ephemeral") != 0) { + const cfg_obj_t *tlsmap = NULL; + + tlsmap = find_maplist(config, "tls", str); + if (tlsmap == NULL) { + cfg_obj_log(tls, logctx, ISC_LOG_ERROR, + "tls '%s' is not defined", + cfg_obj_asstring(tls)); + result = ISC_R_FAILURE; + } + } + } + + return result; +} + static isc_result_t validate_remotes(const cfg_obj_t *obj, const cfg_obj_t *config, uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx) { @@ -2613,54 +2709,19 @@ resume: key = cfg_tuple_get(cfg_listelt_value(element), "key"); tls = cfg_tuple_get(cfg_listelt_value(element), "tls"); + result = validate_remotes_key(config, key, logctx); + if (result != ISC_R_SUCCESS) { + goto out; + } + + result = validate_remotes_tls(config, tls, logctx); + if (result != ISC_R_SUCCESS) { + goto out; + } + if (cfg_obj_issockaddr(addr)) { count++; - if (cfg_obj_isstring(key)) { - const char *str = cfg_obj_asstring(key); - dns_fixedname_t fname; - dns_name_t *nm = dns_fixedname_initname(&fname); - tresult = dns_name_fromstring( - nm, str, dns_rootname, 0, NULL); - if (tresult != ISC_R_SUCCESS) { - cfg_obj_log(key, logctx, ISC_LOG_ERROR, - "'%s' is not a valid name", - str); - if (result == ISC_R_SUCCESS) { - result = tresult; - } - } - } - if (cfg_obj_isstring(tls)) { - const char *str = cfg_obj_asstring(tls); - dns_fixedname_t fname; - dns_name_t *nm = dns_fixedname_initname(&fname); - tresult = dns_name_fromstring( - nm, str, dns_rootname, 0, NULL); - if (tresult != ISC_R_SUCCESS) { - cfg_obj_log(tls, logctx, ISC_LOG_ERROR, - "'%s' is not a valid name", - str); - if (result == ISC_R_SUCCESS) { - result = tresult; - } - } - if (strcasecmp(str, "ephemeral") != 0) { - const cfg_obj_t *tlsmap = NULL; - - tlsmap = find_maplist(config, "tls", - str); - if (tlsmap == NULL) { - cfg_obj_log( - tls, logctx, - ISC_LOG_ERROR, - "tls '%s' is not " - "defined", - cfg_obj_asstring(tls)); - result = ISC_R_FAILURE; - } - } - } continue; } listname = cfg_obj_asstring(addr); @@ -2694,11 +2755,14 @@ resume: element = stack[--pushed]; goto resume; } + + *countp = count; + +out: if (stack != NULL) { isc_mem_cput(mctx, stack, stackcount, sizeof(*stack)); } isc_symtab_destroy(&symtab); - *countp = count; return result; } From e6eb49475a2caf9667f898d541c62b38bb899230 Mon Sep 17 00:00:00 2001 From: Colin Vidal Date: Wed, 19 Nov 2025 17:36:17 +0100 Subject: [PATCH 7/7] add checkconf test for named remote-servers Add checkconf system test to cover usage of `remote-servers` with a named server-list and a `key` and/or a `tls` option. (cherry picked from commit 4bc435ab103002fedc4ce79a37c6a0fdab8c14bb) --- .../checkconf/bad-remote-servers-key.conf | 15 +++++++++++ .../checkconf/bad-remote-servers-tls.conf | 15 +++++++++++ .../checkconf/good-remote-servers-named.conf | 27 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 bin/tests/system/checkconf/bad-remote-servers-key.conf create mode 100644 bin/tests/system/checkconf/bad-remote-servers-tls.conf create mode 100644 bin/tests/system/checkconf/good-remote-servers-named.conf diff --git a/bin/tests/system/checkconf/bad-remote-servers-key.conf b/bin/tests/system/checkconf/bad-remote-servers-key.conf new file mode 100644 index 0000000000..d4963a87f8 --- /dev/null +++ b/bin/tests/system/checkconf/bad-remote-servers-key.conf @@ -0,0 +1,15 @@ +/* + * 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-servers a { 1.2.3.4; }; +remote-servers d { a key foo; }; diff --git a/bin/tests/system/checkconf/bad-remote-servers-tls.conf b/bin/tests/system/checkconf/bad-remote-servers-tls.conf new file mode 100644 index 0000000000..461975da59 --- /dev/null +++ b/bin/tests/system/checkconf/bad-remote-servers-tls.conf @@ -0,0 +1,15 @@ +/* + * 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-servers a { 1.2.3.4; }; +remote-servers d { a tls foo; }; diff --git a/bin/tests/system/checkconf/good-remote-servers-named.conf b/bin/tests/system/checkconf/good-remote-servers-named.conf new file mode 100644 index 0000000000..f7eadc587f --- /dev/null +++ b/bin/tests/system/checkconf/good-remote-servers-named.conf @@ -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. + */ + +key foo { + algorithm hmac-sha256; + secret "9999abcd8765"; +}; + +tls bar { +}; + +remote-servers a { 1.2.3.4; }; +remote-servers b { 1.2.3.4; }; +remote-servers c { 1.2.3.4; 5.6.7.8; ::1; }; +remote-servers d { a key foo; b tls bar; c key foo tls bar; }; +remote-servers e { a key foo.; }; +remote-servers f { b tls bar; };