diff --git a/bin/named/config.c b/bin/named/config.c index a49503df00..f073bcd328 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -566,35 +566,44 @@ named_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp, } } +static isc_result_t +getprimariesdef(const cfg_obj_t *cctx, const char *list, const char *name, + const cfg_obj_t **ret) { + isc_result_t result; + const cfg_obj_t *obj = NULL; + const cfg_listelt_t *elt; + + REQUIRE(cctx != NULL); + REQUIRE(name != NULL); + REQUIRE(ret != NULL && *ret == NULL); + + result = cfg_map_get(cctx, list, &obj); + if (result != ISC_R_SUCCESS) { + return (result); + } + elt = cfg_list_first(obj); + while (elt != NULL) { + obj = cfg_listelt_value(elt); + if (strcasecmp(cfg_obj_asstring(cfg_tuple_get(obj, "name")), + name) == 0) { + *ret = obj; + return (ISC_R_SUCCESS); + } + elt = cfg_list_next(elt); + } + return (ISC_R_NOTFOUND); +} + isc_result_t named_config_getprimariesdef(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) { isc_result_t result; - const cfg_obj_t *primaries = NULL; - const cfg_listelt_t *elt; - result = cfg_map_get(cctx, "primaries", &primaries); + result = getprimariesdef(cctx, "primaries", name, ret); if (result != ISC_R_SUCCESS) { - result = cfg_map_get(cctx, "masters", &primaries); + result = getprimariesdef(cctx, "masters", name, ret); } - if (result != ISC_R_SUCCESS) { - return (result); - } - - for (elt = cfg_list_first(primaries); elt != NULL; - elt = cfg_list_next(elt)) { - const cfg_obj_t *list; - const char *listname; - - list = cfg_listelt_value(elt); - listname = cfg_obj_asstring(cfg_tuple_get(list, "name")); - - if (strcasecmp(listname, name) == 0) { - *ret = list; - return (ISC_R_SUCCESS); - } - } - return (ISC_R_NOTFOUND); + return (result); } isc_result_t @@ -714,6 +723,7 @@ resume: if (j < l) { continue; } + list = NULL; tresult = named_config_getprimariesdef(config, listname, &list); if (tresult == ISC_R_NOTFOUND) { diff --git a/bin/tests/system/checkconf/bad-duplicate-primaries-1.conf b/bin/tests/system/checkconf/bad-duplicate-primaries-1.conf new file mode 100644 index 0000000000..cf10157770 --- /dev/null +++ b/bin/tests/system/checkconf/bad-duplicate-primaries-1.conf @@ -0,0 +1,13 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * 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 http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +primaries duplicate { 1.2.3.4; }; +primaries duplicate { 4.3.2.1; }; diff --git a/bin/tests/system/checkconf/bad-duplicate-primaries-2.conf b/bin/tests/system/checkconf/bad-duplicate-primaries-2.conf new file mode 100644 index 0000000000..b7c6f2146f --- /dev/null +++ b/bin/tests/system/checkconf/bad-duplicate-primaries-2.conf @@ -0,0 +1,13 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * 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 http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +masters duplicate { 1.2.3.4; }; +primaries duplicate { 4.3.2.1; }; diff --git a/bin/tests/system/checkconf/good-masters-and-primaries.conf b/bin/tests/system/checkconf/good-masters-and-primaries.conf new file mode 100644 index 0000000000..156c63c3f5 --- /dev/null +++ b/bin/tests/system/checkconf/good-masters-and-primaries.conf @@ -0,0 +1,13 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * 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 http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +masters a { 1.2.3.4; }; +primaries b { 1.2.3.4; }; diff --git a/doc/man/named.conf.5in b/doc/man/named.conf.5in index 98266cd82c..bc3319edd5 100644 --- a/doc/man/named.conf.5in +++ b/doc/man/named.conf.5in @@ -193,8 +193,8 @@ managed\-keys { string ( static\-key .nf .ft C masters string [ port integer ] [ dscp - integer ] { ( masters | ipv4_address [ - port integer ] | ipv6_address [ port + integer ] { ( primaries | ipv4_address + [ port integer ] | ipv6_address [ port integer ] ) [ key string ]; ... }; .ft P .fi @@ -218,7 +218,7 @@ options { allow\-transfer { address_match_element; ... }; allow\-update { address_match_element; ... }; allow\-update\-forwarding { address_match_element; ... }; - also\-notify [ port integer ] [ dscp integer ] { ( masters | + also\-notify [ port integer ] [ dscp integer ] { ( primaries | ipv4_address [ port integer ] | ipv6_address [ port integer ] ) [ key string ]; ... }; alt\-transfer\-source ( ipv4_address | * ) [ port ( integer | * ) @@ -236,7 +236,7 @@ options { blackhole { address_match_element; ... }; cache\-file quoted_string; catalog\-zones { zone string [ default\-masters [ port integer ] - [ dscp integer ] { ( masters | ipv4_address [ port + [ dscp integer ] { ( primaries | ipv4_address [ port integer ] | ipv6_address [ port integer ] ) [ key string ]; ... } ] [ zone\-directory quoted_string ] [ in\-memory boolean ] [ min\-update\-interval duration ]; ... }; @@ -375,7 +375,7 @@ options { new\-zones\-directory quoted_string; no\-case\-compress { address_match_element; ... }; nocookie\-udp\-size integer; - notify ( explicit | master\-only | boolean ); + notify ( explicit | master\-only | primary\-only | boolean ); notify\-delay integer; notify\-rate integer; notify\-source ( ipv4_address | * ) [ port ( integer | * ) ] [ @@ -515,6 +515,20 @@ plugin ( query ) string [ { unspecified\-text .fi .UNINDENT .UNINDENT +.SS PRIMARIES +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +primaries string [ port integer ] [ dscp + integer ] { ( primaries | ipv4_address + [ port integer ] | ipv6_address [ port + integer ] ) [ key string ]; ... }; +.ft P +.fi +.UNINDENT +.UNINDENT .SS SERVER .INDENT 0.0 .INDENT 3.5 @@ -620,7 +634,7 @@ view string [ class ] { allow\-transfer { address_match_element; ... }; allow\-update { address_match_element; ... }; allow\-update\-forwarding { address_match_element; ... }; - also\-notify [ port integer ] [ dscp integer ] { ( masters | + also\-notify [ port integer ] [ dscp integer ] { ( primaries | ipv4_address [ port integer ] | ipv6_address [ port integer ] ) [ key string ]; ... }; alt\-transfer\-source ( ipv4_address | * ) [ port ( integer | * ) @@ -632,7 +646,7 @@ view string [ class ] { auto\-dnssec ( allow | maintain | off ); cache\-file quoted_string; catalog\-zones { zone string [ default\-masters [ port integer ] - [ dscp integer ] { ( masters | ipv4_address [ port + [ dscp integer ] { ( primaries | ipv4_address [ port integer ] | ipv6_address [ port integer ] ) [ key string ]; ... } ] [ zone\-directory quoted_string ] [ in\-memory boolean ] [ min\-update\-interval duration ]; ... }; @@ -752,7 +766,7 @@ view string [ class ] { new\-zones\-directory quoted_string; no\-case\-compress { address_match_element; ... }; nocookie\-udp\-size integer; - notify ( explicit | master\-only | boolean ); + notify ( explicit | master\-only | primary\-only | boolean ); notify\-delay integer; notify\-source ( ipv4_address | * ) [ port ( integer | * ) ] [ dscp integer ]; @@ -892,7 +906,7 @@ view string [ class ] { allow\-update { address_match_element; ... }; allow\-update\-forwarding { address_match_element; ... }; also\-notify [ port integer ] [ dscp integer ] { ( - masters | ipv4_address [ port integer ] | + primaries | ipv4_address [ port integer ] | ipv6_address [ port integer ] ) [ key string ]; ... }; alt\-transfer\-source ( ipv4_address | * ) [ port ( @@ -932,9 +946,10 @@ view string [ class ] { key\-directory quoted_string; masterfile\-format ( map | raw | text ); masterfile\-style ( full | relative ); - masters [ port integer ] [ dscp integer ] { ( masters - | ipv4_address [ port integer ] | ipv6_address [ - port integer ] ) [ key string ]; ... }; + masters [ port integer ] [ dscp integer ] { ( + primaries | ipv4_address [ port integer ] | + ipv6_address [ port integer ] ) [ key string ]; + ... }; max\-ixfr\-ratio ( unlimited | percentage ); max\-journal\-size ( default | unlimited | sizeval ); max\-records integer; @@ -948,13 +963,17 @@ view string [ class ] { min\-refresh\-time integer; min\-retry\-time integer; multi\-master boolean; - notify ( explicit | master\-only | boolean ); + notify ( explicit | master\-only | primary\-only | boolean ); notify\-delay integer; notify\-source ( ipv4_address | * ) [ port ( integer | * ) ] [ dscp integer ]; notify\-source\-v6 ( ipv6_address | * ) [ port ( integer | * ) ] [ dscp integer ]; notify\-to\-soa boolean; + primaries [ port integer ] [ dscp integer ] { ( + primaries | ipv4_address [ port integer ] | + ipv6_address [ port integer ] ) [ key string ]; + ... }; request\-expire boolean; request\-ixfr boolean; serial\-update\-method ( date | increment | unixtime ); @@ -1001,7 +1020,7 @@ zone string [ class ] { allow\-transfer { address_match_element; ... }; allow\-update { address_match_element; ... }; allow\-update\-forwarding { address_match_element; ... }; - also\-notify [ port integer ] [ dscp integer ] { ( masters | + also\-notify [ port integer ] [ dscp integer ] { ( primaries | ipv4_address [ port integer ] | ipv6_address [ port integer ] ) [ key string ]; ... }; alt\-transfer\-source ( ipv4_address | * ) [ port ( integer | * ) @@ -1039,7 +1058,7 @@ zone string [ class ] { key\-directory quoted_string; masterfile\-format ( map | raw | text ); masterfile\-style ( full | relative ); - masters [ port integer ] [ dscp integer ] { ( masters | + masters [ port integer ] [ dscp integer ] { ( primaries | ipv4_address [ port integer ] | ipv6_address [ port integer ] ) [ key string ]; ... }; max\-ixfr\-ratio ( unlimited | percentage ); @@ -1055,13 +1074,16 @@ zone string [ class ] { min\-refresh\-time integer; min\-retry\-time integer; multi\-master boolean; - notify ( explicit | master\-only | boolean ); + notify ( explicit | master\-only | primary\-only | boolean ); notify\-delay integer; notify\-source ( ipv4_address | * ) [ port ( integer | * ) ] [ dscp integer ]; notify\-source\-v6 ( ipv6_address | * ) [ port ( integer | * ) ] [ dscp integer ]; notify\-to\-soa boolean; + primaries [ port integer ] [ dscp integer ] { ( primaries | + ipv4_address [ port integer ] | ipv6_address [ port + integer ] ) [ key string ]; ... }; request\-expire boolean; request\-ixfr boolean; serial\-update\-method ( date | increment | unixtime ); diff --git a/doc/misc/options b/doc/misc/options index b6e5cc466f..0a648e8a46 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -166,16 +166,13 @@ options { dnssec-secure-to-insecure ; dnssec-update-mode ( maintain | no-resign ); dnssec-validation ( yes | no | auto ); - dnstap { ( all | auth | client | forwarder | - resolver | update ) [ ( query | response ) ]; - ... }; // not configured - dnstap-identity ( | none | - hostname ); // not configured - dnstap-output ( file | unix ) [ - size ( unlimited | ) ] [ versions ( - unlimited | ) ] [ suffix ( increment - | timestamp ) ]; // not configured - dnstap-version ( | none ); // not configured + dnstap { ( all | auth | client | forwarder | resolver | update ) [ + ( query | response ) ]; ... }; + dnstap-identity ( | none | hostname ); + dnstap-output ( file | unix ) [ size ( unlimited | + ) ] [ versions ( unlimited | ) ] [ suffix ( + increment | timestamp ) ]; + dnstap-version ( | none ); dscp ; dual-stack-servers [ port ] { ( [ port ] [ dscp ] | [ port @@ -199,13 +196,13 @@ options { forward ( first | only ); forwarders [ port ] [ dscp ] { ( | ) [ port ] [ dscp ]; ... }; - fstrm-set-buffer-hint ; // not configured - fstrm-set-flush-timeout ; // not configured - fstrm-set-input-queue-size ; // not configured - fstrm-set-output-notify-threshold ; // not configured - fstrm-set-output-queue-model ( mpsc | spsc ); // not configured - fstrm-set-output-queue-size ; // not configured - fstrm-set-reopen-interval ; // not configured + fstrm-set-buffer-hint ; + fstrm-set-flush-timeout ; + fstrm-set-input-queue-size ; + fstrm-set-output-notify-threshold ; + fstrm-set-output-queue-model ( mpsc | spsc ); + fstrm-set-output-queue-size ; + fstrm-set-reopen-interval ; geoip-directory ( | none ); geoip-use-ecs ; // obsolete glue-cache ; @@ -555,9 +552,8 @@ view [ ] { dnssec-secure-to-insecure ; dnssec-update-mode ( maintain | no-resign ); dnssec-validation ( yes | no | auto ); - dnstap { ( all | auth | client | forwarder | - resolver | update ) [ ( query | response ) ]; - ... }; // not configured + dnstap { ( all | auth | client | forwarder | resolver | update ) [ + ( query | response ) ]; ... }; dual-stack-servers [ port ] { ( [ port ] [ dscp ] | [ port ] [ dscp ] | [ port diff --git a/lib/bind9/check.c b/lib/bind9/check.c index f2078fc6c2..1b1ae19ecb 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -1664,37 +1664,135 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx, return (result); } +/* + * Check "primaries" style list. + */ static isc_result_t -get_primaries_def(const cfg_obj_t *cctx, const char *name, - const cfg_obj_t **ret) { - isc_result_t result; - const cfg_obj_t *primaries = NULL; +bind9_check_primarylist(const cfg_obj_t *cctx, const char *list, + isc_log_t *logctx, isc_symtab_t *symtab, + isc_mem_t *mctx) { + isc_symvalue_t symvalue; + isc_result_t result, tresult; + const cfg_obj_t *obj = NULL; const cfg_listelt_t *elt; - result = cfg_map_get(cctx, "primaries", &primaries); + result = cfg_map_get(cctx, list, &obj); if (result != ISC_R_SUCCESS) { - result = cfg_map_get(cctx, "masters", &primaries); + return (ISC_R_SUCCESS); } + + elt = cfg_list_first(obj); + while (elt != NULL) { + char *tmp; + const char *name; + + obj = cfg_listelt_value(elt); + name = cfg_obj_asstring(cfg_tuple_get(obj, "name")); + + tmp = isc_mem_strdup(mctx, name); + symvalue.as_cpointer = obj; + tresult = isc_symtab_define(symtab, tmp, 1, symvalue, + isc_symexists_reject); + if (tresult == ISC_R_EXISTS) { + const char *file = NULL; + unsigned int line; + + RUNTIME_CHECK( + isc_symtab_lookup(symtab, tmp, 1, &symvalue) == + ISC_R_SUCCESS); + file = cfg_obj_file(symvalue.as_cpointer); + line = cfg_obj_line(symvalue.as_cpointer); + + if (file == NULL) { + file = ""; + } + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "primaries list '%s' is duplicated: " + "also defined at %s:%u", + name, file, line); + isc_mem_free(mctx, tmp); + result = tresult; + break; + } else if (tresult != ISC_R_SUCCESS) { + isc_mem_free(mctx, tmp); + result = tresult; + break; + } + + elt = cfg_list_next(elt); + } + return (result); +} + +/* + * Check primaries lists for duplicates. + */ +static isc_result_t +bind9_check_primarylists(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_primarylist(cctx, "primaries", logctx, symtab, + mctx); + if (tresult != ISC_R_SUCCESS) { + result = tresult; + } + tresult = bind9_check_primarylist(cctx, "masters", logctx, symtab, + mctx); + if (tresult != ISC_R_SUCCESS) { + result = tresult; + } + isc_symtab_destroy(&symtab); + return (result); +} + +static isc_result_t +get_primaries(const cfg_obj_t *cctx, const char *list, const char *name, + const cfg_obj_t **ret) { + isc_result_t result; + const cfg_obj_t *obj = NULL; + const cfg_listelt_t *elt = NULL; + + result = cfg_map_get(cctx, list, &obj); if (result != ISC_R_SUCCESS) { return (result); } - for (elt = cfg_list_first(primaries); elt != NULL; - elt = cfg_list_next(elt)) { - const cfg_obj_t *list; + elt = cfg_list_first(obj); + while (elt != NULL) { const char *listname; - list = cfg_listelt_value(elt); - listname = cfg_obj_asstring(cfg_tuple_get(list, "name")); + obj = cfg_listelt_value(elt); + listname = cfg_obj_asstring(cfg_tuple_get(obj, "name")); if (strcasecmp(listname, name) == 0) { - *ret = list; + *ret = obj; return (ISC_R_SUCCESS); } + + elt = cfg_list_next(elt); } + return (ISC_R_NOTFOUND); } +static isc_result_t +get_primaries_def(const cfg_obj_t *cctx, const char *name, + const cfg_obj_t **ret) { + isc_result_t result; + + result = get_primaries(cctx, "primaries", name, ret); + if (result != ISC_R_SUCCESS) { + result = get_primaries(cctx, "masters", name, ret); + } + return (result); +} + static isc_result_t validate_primaries(const cfg_obj_t *obj, const cfg_obj_t *config, uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx) { @@ -4781,6 +4879,10 @@ 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; + } + (void)cfg_map_get(config, "view", &views); if (views != NULL && options != NULL) {