diff --git a/bin/check/Makefile.in b/bin/check/Makefile.in index b15cd90a70..8f009a4b81 100644 --- a/bin/check/Makefile.in +++ b/bin/check/Makefile.in @@ -66,7 +66,7 @@ named-checkzone.@O@: named-checkzone.c named-checkconf@EXEEXT@: named-checkconf.@O@ check-tool.@O@ ${ISCDEPLIBS} \ ${NSDEPENDLIBS} ${DNSDEPLIBS} ${ISCCFGDEPLIBS} ${BIND9DEPLIBS} export BASEOBJS="named-checkconf.@O@ check-tool.@O@"; \ - export LIBS0="${NSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} ${DNSLIBS}"; \ + export LIBS0="${BIND9LIBS} ${NSLIBS} ${ISCCFGLIBS} ${DNSLIBS}"; \ ${FINALBUILDCMD} named-checkzone@EXEEXT@: named-checkzone.@O@ check-tool.@O@ ${ISCDEPLIBS} \ diff --git a/bin/check/named-checkconf.c b/bin/check/named-checkconf.c index 753f5ba69c..d5599ea133 100644 --- a/bin/check/named-checkconf.c +++ b/bin/check/named-checkconf.c @@ -46,6 +46,8 @@ static const char *program = "named-checkconf"; +static bool loadhooks = true; + isc_log_t *logc = NULL; #define CHECK(r)\ @@ -562,7 +564,7 @@ main(int argc, char **argv) { /* * Process memory debugging argument first. */ -#define CMDLINE_FLAGS "dhjlm:t:pvxz" +#define CMDLINE_FLAGS "cdhjlm:t:pvxz" while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { switch (c) { case 'm': @@ -587,6 +589,10 @@ main(int argc, char **argv) { while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != EOF) { switch (c) { + case 'c': + loadhooks = false; + break; + case 'd': debug++; break; @@ -677,9 +683,10 @@ main(int argc, char **argv) { ISC_R_SUCCESS) exit(1); - result = bind9_check_namedconf(config, logc, mctx); - if (result != ISC_R_SUCCESS) + result = bind9_check_namedconf(config, loadhooks, logc, mctx); + if (result != ISC_R_SUCCESS) { exit_status = 1; + } if (result == ISC_R_SUCCESS && (load_zones || list_zones)) { result = load_zones_fromconfig(config, mctx, list_zones); diff --git a/bin/check/named-checkconf.docbook b/bin/check/named-checkconf.docbook index dea38896ce..69f322c4d8 100644 --- a/bin/check/named-checkconf.docbook +++ b/bin/check/named-checkconf.docbook @@ -52,7 +52,7 @@ named-checkconf - + @@ -114,6 +114,17 @@ + + -c + + + Check "core" configuration only. This suppresses the loading + of hook modules, and causes all parameters to + hook statements to be ignored. + + + + -p diff --git a/bin/hooks/filter-aaaa.c b/bin/hooks/filter-aaaa.c index 0084645262..50e5d473ac 100644 --- a/bin/hooks/filter-aaaa.c +++ b/bin/hooks/filter-aaaa.c @@ -249,8 +249,52 @@ parse_filter_aaaa_on(const cfg_obj_t *param_obj, const char *param_name, return (result); } +static isc_result_t +check_syntax(cfg_obj_t *fmap, const void *cfg, + isc_mem_t *mctx, isc_log_t *lctx, void *actx) +{ + isc_result_t result = ISC_R_SUCCESS; + const cfg_obj_t *aclobj = NULL; + dns_acl_t *acl = NULL; + filter_aaaa_t f4 = NONE, f6 = NONE; + + cfg_map_get(fmap, "filter-aaaa", &aclobj); + if (aclobj == NULL) { + return (result); + } + + CHECK(cfg_acl_fromconfig(aclobj, (const cfg_obj_t *) cfg, + lctx, (cfg_aclconfctx_t *) actx, + mctx, 0, &acl)); + + CHECK(parse_filter_aaaa_on(fmap, "filter-aaaa-on-v4", &f4)); + CHECK(parse_filter_aaaa_on(fmap, "filter-aaaa-on-v6", &f6)); + + if ((f4 != NONE || f6 != NONE) && dns_acl_isnone(acl)) { + cfg_obj_log(aclobj, lctx, ISC_LOG_WARNING, + "\"filter-aaaa\" is 'none;' but " + "either filter-aaaa-on-v4 or filter-aaaa-on-v6 " + "is enabled"); + result = ISC_R_FAILURE; + } else if (f4 == NONE && f6 == NONE && !dns_acl_isnone(acl)) { + cfg_obj_log(aclobj, lctx, ISC_LOG_WARNING, + "\"filter-aaaa\" is set but " + "neither filter-aaaa-on-v4 or filter-aaaa-on-v6 " + "is enabled"); + result = ISC_R_FAILURE; + } + + cleanup: + if (acl != NULL) { + dns_acl_detach(&acl); + } + + return (result); +} + static isc_result_t parse_parameters(filter_instance_t *inst, const char *parameters, + const char *cfg_file, unsigned long cfg_line, const void *cfg, void *actx, ns_hookctx_t *hctx) { isc_result_t result = ISC_R_SUCCESS; @@ -263,8 +307,10 @@ parse_parameters(filter_instance_t *inst, const char *parameters, isc_buffer_constinit(&b, parameters, strlen(parameters)); isc_buffer_add(&b, strlen(parameters)); - CHECK(cfg_parse_buffer(parser, &b, &cfg_type_parameters, - ¶m_obj)); + CHECK(cfg_parse_buffer4(parser, &b, cfg_file, cfg_line, + &cfg_type_parameters, 0, ¶m_obj)); + + CHECK(check_syntax(param_obj, cfg, hctx->mctx, hctx->lctx, actx)); CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v4", &inst->v4_aaaa)); @@ -323,7 +369,9 @@ hook_register(const char *parameters, isc_mem_attach(hctx->mctx, &inst->mctx); if (parameters != NULL) { - CHECK(parse_parameters(inst, parameters, cfg, actx, hctx)); + CHECK(parse_parameters(inst, parameters, + cfg_file, cfg_line, + cfg, actx, hctx)); } CHECK(isc_mempool_create(hctx->mctx, sizeof(filter_data_t), @@ -358,6 +406,34 @@ hook_register(const char *parameters, return (result); } +isc_result_t +hook_check(const char *parameters, const char *cfg_file, unsigned long cfg_line, + const void *cfg, isc_mem_t *mctx, isc_log_t *lctx, void *actx) +{ + isc_result_t result = ISC_R_SUCCESS; + cfg_parser_t *parser = NULL; + cfg_obj_t *param_obj = NULL; + isc_buffer_t b; + + CHECK(cfg_parser_create(mctx, lctx, &parser)); + + isc_buffer_constinit(&b, parameters, strlen(parameters)); + isc_buffer_add(&b, strlen(parameters)); + CHECK(cfg_parse_buffer4(parser, &b, cfg_file, cfg_line, + &cfg_type_parameters, 0, ¶m_obj)); + + CHECK(check_syntax(param_obj, cfg, mctx, lctx, actx)); + + cleanup: + if (param_obj != NULL) { + cfg_obj_destroy(parser, ¶m_obj); + } + if (parser != NULL) { + cfg_parser_destroy(&parser); + } + return (result); +} + /* * Called by ns_module_unload(); frees memory allocated by * the module when it was registered. diff --git a/bin/named/server.c b/bin/named/server.c index b6a43df85d..8204db5451 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -5308,7 +5308,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, #ifdef HAVE_DLOPEN if (hook_list != NULL) { - CHECK(ns_hook_createctx(mctx, &hctx)); + CHECK(ns_hook_createctx(mctx, view, &hctx)); INSIST(view->hooktable == NULL); CHECK(ns_hooktable_create(view->mctx, @@ -8102,8 +8102,12 @@ load_configuration(const char *filename, named_server_t *server, /* * Check the validity of the configuration. + * + * (Ignore hook module parameters for now; they will be + * checked later when the modules are actually loaded and + * registered.) */ - CHECK(bind9_check_namedconf(config, named_g_lctx, named_g_mctx)); + CHECK(bind9_check_namedconf(config, false, named_g_lctx, named_g_mctx)); /* * Fill in the maps array, used for resolving defaults. diff --git a/bin/tests/system/filter-aaaa/conf/bad1.conf b/bin/tests/system/filter-aaaa/conf/bad1.conf new file mode 100644 index 0000000000..0107435c2f --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/bad1.conf @@ -0,0 +1,15 @@ +/* + * 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. + */ + +hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa { none; }; +}; diff --git a/bin/tests/system/filter-aaaa/conf/bad2.conf b/bin/tests/system/filter-aaaa/conf/bad2.conf new file mode 100644 index 0000000000..0db0bb81c1 --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/bad2.conf @@ -0,0 +1,24 @@ +/* + * 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. + */ + +hook query "../../../hooks/lib/filter-aaaa.so" { + /* + * While this matches the defaults, it is not a good configuration + * to have in named.conf as the two options contradict each other + * indicating a error on behalf of the operator. + * + * The default is to have filter-aaaa-on-v4 off, but if it is turned + * on then it applies to all IPv4 queries. This results in + * contradictory defaults. + */ + filter-aaaa-on-v4 no; + filter-aaaa { any; }; +}; diff --git a/bin/tests/system/filter-aaaa/conf/bad3.conf b/bin/tests/system/filter-aaaa/conf/bad3.conf new file mode 100644 index 0000000000..418c548186 --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/bad3.conf @@ -0,0 +1,17 @@ +/* + * 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. + */ + +view myview { + hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 no; + filter-aaaa { any; }; + }; +}; diff --git a/bin/tests/system/filter-aaaa/conf/bad4.conf b/bin/tests/system/filter-aaaa/conf/bad4.conf new file mode 100644 index 0000000000..0357956123 --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/bad4.conf @@ -0,0 +1,17 @@ +/* + * 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. + */ + +view myview { + hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa { none; }; + }; +}; diff --git a/bin/tests/system/filter-aaaa/conf/bad5.conf b/bin/tests/system/filter-aaaa/conf/bad5.conf new file mode 100644 index 0000000000..ea807d3fbd --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/bad5.conf @@ -0,0 +1,19 @@ +/* + * 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. + */ + +plugin query "../../../plugins/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa { 1.0.0.0/8; }; +}; + +view myview { + match-clients { any; }; +}; diff --git a/bin/tests/system/filter-aaaa/conf/good1.conf b/bin/tests/system/filter-aaaa/conf/good1.conf new file mode 100644 index 0000000000..e5136a9c77 --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/good1.conf @@ -0,0 +1,14 @@ +/* + * 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. + */ + +hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; +}; diff --git a/bin/tests/system/filter-aaaa/conf/good2.conf b/bin/tests/system/filter-aaaa/conf/good2.conf new file mode 100644 index 0000000000..935e1f1211 --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/good2.conf @@ -0,0 +1,14 @@ +/* + * 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. + */ + +hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 break-dnssec; +}; diff --git a/bin/tests/system/filter-aaaa/conf/good3.conf b/bin/tests/system/filter-aaaa/conf/good3.conf new file mode 100644 index 0000000000..f92ad6b38b --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/good3.conf @@ -0,0 +1,15 @@ +/* + * 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. + */ + +hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 break-dnssec; + filter-aaaa { 1.0.0.0/8; }; +}; diff --git a/bin/tests/system/filter-aaaa/conf/good4.conf b/bin/tests/system/filter-aaaa/conf/good4.conf new file mode 100644 index 0000000000..ea4756093c --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/good4.conf @@ -0,0 +1,15 @@ +/* + * 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. + */ + +hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa { 1.0.0.0/8; }; +}; diff --git a/bin/tests/system/filter-aaaa/conf/good5.conf b/bin/tests/system/filter-aaaa/conf/good5.conf new file mode 100644 index 0000000000..131c5524dd --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/good5.conf @@ -0,0 +1,17 @@ +/* + * 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. + */ + +view myview { + hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa { 1.0.0.0/8; }; + }; +}; diff --git a/bin/tests/system/filter-aaaa/tests.sh b/bin/tests/system/filter-aaaa/tests.sh index 4ff2ebe3a2..f9b4d882b9 100644 --- a/bin/tests/system/filter-aaaa/tests.sh +++ b/bin/tests/system/filter-aaaa/tests.sh @@ -20,6 +20,26 @@ rm -f dig.out.* DIGOPTS="+tcp +noadd +nosea +nostat +nocmd -p ${PORT}" RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s" +for conf in conf/good*.conf +do + n=`expr $n + 1` + echo_i "checking that $conf is accepted ($n)" + ret=0 + $CHECKCONF "$conf" || ret=1 + if [ $ret != 0 ]; then echo_i "failed"; fi + status=`expr $status + $ret` +done + +for conf in conf/bad*.conf +do + n=`expr $n + 1` + echo_i "checking that $conf is rejected ($n)" + ret=0 + $CHECKCONF "$conf" >/dev/null && ret=1 + if [ $ret != 0 ]; then echo_i "failed"; fi + status=`expr $status + $ret` +done + # # Authoritative tests against: # filter-aaaa-on-v4 yes; diff --git a/lib/bind9/Makefile.in b/lib/bind9/Makefile.in index 5a9760c0e0..b2441fb925 100644 --- a/lib/bind9/Makefile.in +++ b/lib/bind9/Makefile.in @@ -18,7 +18,7 @@ VERSION=@BIND9_VERSION@ @BIND9_MAKE_INCLUDES@ CINCLUDES = -I. ${BIND9_INCLUDES} ${DNS_INCLUDES} ${ISC_INCLUDES} \ - ${ISCCFG_INCLUDES} @OPENSSL_INCLUDES@ + ${ISCCFG_INCLUDES} ${NS_INCLUDES} @OPENSSL_INCLUDES@ CDEFINES = CWARNINGS = @@ -26,6 +26,7 @@ CWARNINGS = ISCLIBS = ../../lib/isc/libisc.@A@ @OPENSSL_LIBS@ ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@ +NSLIBS = ../../lib/ns/libns.@A@ ISCDEPLIBS = ../../lib/isc/libisc.@A@ ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ @@ -61,8 +62,8 @@ libbind9.la: ${OBJS} ${ISCCFGDEPLIBS} ${ISCDEPLIBS} ${DNSDEPLIBS} ${LIBTOOL_MODE_LINK} \ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libbind9.la -rpath ${libdir} \ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ - ${OBJS} ${DNSLIBS} ${ISCCFGLIBS} ${ISCLIBS} @DNS_CRYPTO_LIBS@ \ - ${LIBS} + ${OBJS} ${NSLIBS} ${DNSLIBS} ${ISCCFGLIBS} ${ISCLIBS} \ + @DNS_CRYPTO_LIBS@ ${LIBS} timestamp: libbind9.@A@ touch timestamp diff --git a/lib/bind9/check.c b/lib/bind9/check.c index 4fac8e9b85..efef37f00d 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -54,6 +54,8 @@ #include #include +#include + #include static unsigned char dlviscorg_ndata[] = "\003dlv\003isc\003org"; @@ -3349,7 +3351,7 @@ check_rpz_catz(const char *rpz_catz, const cfg_obj_t *rpz_obj, static isc_result_t check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, const char *viewname, dns_rdataclass_t vclass, - isc_symtab_t *files, isc_symtab_t *inview, + isc_symtab_t *files, bool checkhooks, isc_symtab_t *inview, isc_log_t *logctx, isc_mem_t *mctx) { const cfg_obj_t *zones = NULL; @@ -3365,6 +3367,7 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, const cfg_obj_t *obj; const cfg_obj_t *options = NULL; const cfg_obj_t *opts = NULL; + const cfg_obj_t *hook_list = NULL; bool enablednssec, enablevalidation; const char *valstr = "no"; unsigned int tflags, mflags; @@ -3662,6 +3665,56 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, if (tresult != ISC_R_SUCCESS) result = tresult; + /* + * Load hook modules. + */ + if (checkhooks) { + if (voptions != NULL) { + (void)cfg_map_get(voptions, "hook", &hook_list); + } else { + (void)cfg_map_get(config, "hook", &hook_list); + } + } + +#ifdef HAVE_DLOPEN + for (element = cfg_list_first(hook_list); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *hook = cfg_listelt_value(element); + + const char *type, *library; + const char *parameters = NULL; + + /* Get the path to the hook module. */ + obj = cfg_tuple_get(hook, "type"); + type = cfg_obj_asstring(obj); + + /* Only query hooks are supported currently. */ + if (strcasecmp(type, "query") != 0) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "unsupported hook type"); + return (ISC_R_FAILURE); + } + + library = cfg_obj_asstring(cfg_tuple_get(hook, "library")); + + obj = cfg_tuple_get(hook, "parameters"); + if (obj != NULL && cfg_obj_isstring(obj)) { + parameters = cfg_obj_asstring(obj); + } + tresult = ns_module_check(library, parameters, + cfg_obj_file(obj), cfg_obj_line(obj), + config, mctx, logctx, actx); + if (tresult != ISC_R_SUCCESS) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "%s: module check failed: %s", + library, isc_result_totext(tresult)); + result = tresult; + } + } +#endif /* HAVE_DLOPEN */ + cleanup: if (symtab != NULL) isc_symtab_destroy(&symtab); @@ -3916,8 +3969,8 @@ bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx, } isc_result_t -bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx, - isc_mem_t *mctx) +bind9_check_namedconf(const cfg_obj_t *config, bool hooks, + isc_log_t *logctx, isc_mem_t *mctx) { const cfg_obj_t *options = NULL; const cfg_obj_t *views = NULL; @@ -3973,13 +4026,15 @@ bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx, } if (views == NULL) { - tresult = check_viewconf(config, NULL, NULL, dns_rdataclass_in, - files, inview, logctx, mctx); + tresult = check_viewconf(config, NULL, NULL, + dns_rdataclass_in, files, + hooks, inview, logctx, mctx); if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS) { result = ISC_R_FAILURE; } } else { const cfg_obj_t *zones = NULL; + const cfg_obj_t *hooks = NULL; (void)cfg_map_get(config, "zone", &zones); if (zones != NULL) { @@ -3988,6 +4043,14 @@ bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx, "all zones must be in views"); result = ISC_R_FAILURE; } + + (void)cfg_map_get(config, "hook", &hooks); + if (hooks != NULL) { + cfg_obj_log(hooks, logctx, ISC_LOG_ERROR, + "when using 'view' statements, " + "all hooks must be defined in views"); + result = ISC_R_FAILURE; + } } tresult = isc_symtab_create(mctx, 100, NULL, NULL, true, &symtab); @@ -4051,8 +4114,9 @@ bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx, } } if (tresult == ISC_R_SUCCESS) - tresult = check_viewconf(config, voptions, key, vclass, - files, inview, logctx, mctx); + tresult = check_viewconf(config, voptions, key, + vclass, files, hooks, + inview, logctx, mctx); if (tresult != ISC_R_SUCCESS) result = ISC_R_FAILURE; } diff --git a/lib/bind9/include/bind9/check.h b/lib/bind9/include/bind9/check.h index 92d4bdda71..4d483fcfd4 100644 --- a/lib/bind9/include/bind9/check.h +++ b/lib/bind9/include/bind9/check.h @@ -35,12 +35,15 @@ ISC_LANG_BEGINDECLS isc_result_t -bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx, - isc_mem_t *mctx); +bind9_check_namedconf(const cfg_obj_t *config, bool check_hooks, + isc_log_t *logctx, isc_mem_t *mctx); /*%< * Check the syntactic validity of a configuration parse tree generated from * a named.conf file. * + * If 'check_hooks' is true, load hook modules and check the validity of their + * parameters as well. + * * Requires: *\li config is a valid parse tree * diff --git a/lib/ns/hooks.c b/lib/ns/hooks.c index 4573f6fc1e..885b7fa25f 100644 --- a/lib/ns/hooks.c +++ b/lib/ns/hooks.c @@ -30,6 +30,8 @@ #include #include +#include + #include #include #include @@ -47,6 +49,7 @@ struct ns_module { void *handle; void *inst; char *modpath; + ns_hook_check_t *check_func; ns_hook_register_t *register_func; ns_hook_destroy_t *destroy_func; LINK(ns_module_t) link; @@ -97,6 +100,7 @@ load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) { isc_result_t result; void *handle = NULL; ns_module_t *hmod = NULL; + ns_hook_check_t *check_func = NULL; ns_hook_register_t *register_func = NULL; ns_hook_destroy_t *destroy_func = NULL; ns_hook_version_t *version_func = NULL; @@ -104,7 +108,7 @@ load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) { REQUIRE(hmodp != NULL && *hmodp == NULL); - flags = RTLD_NOW | RTLD_LOCAL; + flags = RTLD_LAZY | RTLD_LOCAL; #ifdef RTLD_DEEPBIND flags |= RTLD_DEEPBIND; #endif @@ -136,16 +140,19 @@ load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) { CHECK(ISC_R_FAILURE); } + CHECK(load_symbol(handle, modpath, "hook_check", + (void **)&check_func)); CHECK(load_symbol(handle, modpath, "hook_register", (void **)®ister_func)); CHECK(load_symbol(handle, modpath, "hook_destroy", (void **)&destroy_func)); hmod = isc_mem_get(mctx, sizeof(*hmod)); - hmod->mctx = NULL; + memset(hmod, 0, sizeof(*hmod)); isc_mem_attach(mctx, &hmod->mctx); hmod->handle = handle; hmod->modpath = isc_mem_strdup(hmod->mctx, modpath); + hmod->check_func = check_func; hmod->register_func = register_func; hmod->destroy_func = destroy_func; @@ -262,7 +269,7 @@ load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) { (void **)&destroy_func)); hmod = isc_mem_get(mctx, sizeof(*hmod)); - hmod->mctx = NULL; + memset(hmod, 0, sizeof(*hmod)); isc_mem_attach(mctx, &hmod->mctx); hmod->handle = handle; hmod->modpath = isc_mem_strdup(hmod->mctx, modpath); @@ -377,7 +384,28 @@ cleanup: } isc_result_t -ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp) { +ns_module_check(const char *modpath, const char *parameters, + const char *cfg_file, unsigned long cfg_line, + const void *cfg, isc_mem_t *mctx, isc_log_t *lctx, void *actx) +{ + isc_result_t result; + ns_module_t *hmod = NULL; + + CHECK(load_library(mctx, modpath, &hmod)); + + result = hmod->check_func(parameters, cfg_file, cfg_line, + cfg, mctx, lctx, actx); + +cleanup: + if (hmod != NULL) { + unload_library(&hmod); + } + + return (result); +} + +isc_result_t +ns_hook_createctx(isc_mem_t *mctx, dns_view_t *view, ns_hookctx_t **hctxp) { ns_hookctx_t *hctx = NULL; REQUIRE(hctxp != NULL && *hctxp == NULL); @@ -386,6 +414,8 @@ ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp) { memset(hctx, 0, sizeof(*hctx)); hctx->lctx = ns_lctx; + dns_view_attach(view, &hctx->view); + isc_mem_attach(mctx, &hctx->mctx); hctx->magic = NS_HOOKCTX_MAGIC; @@ -405,6 +435,7 @@ ns_hook_destroyctx(ns_hookctx_t **hctxp) { hctx->magic = 0; + dns_view_detach(&hctx->view); isc_mem_putanddetach(&hctx->mctx, hctx, sizeof(*hctx)); } diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index 14af15d695..64f944a4f1 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -233,6 +233,7 @@ LIBNS_EXTERNAL_DATA extern ns_hooktable_t *ns__hook_table; */ typedef struct ns_hookctx { unsigned int magic; + dns_view_t *view; isc_mem_t *mctx; isc_log_t *lctx; } ns_hookctx_t; @@ -272,14 +273,23 @@ ns_hook_register_t(const char *parameters, *\li Other errors are possible */ -typedef void ns_hook_destroy_t(void **instp); +typedef void +ns_hook_destroy_t(void **instp); /*%< * Destroy a module instance. * * '*instp' must be set to NULL by the function before it returns. */ -typedef int ns_hook_version_t(void); +typedef isc_result_t +ns_hook_check_t(const char *parameters, const char *file, unsigned long line, + const void *cfg, isc_mem_t *mctx, isc_log_t *lctx, void *actx); +/*%< + * Check the validity of 'parameters'. + */ + +typedef int +ns_hook_version_t(void); /*%< * Return the API version number a hook module was compiled with. * @@ -291,13 +301,13 @@ typedef int ns_hook_version_t(void); /*% * Prototypes for API functions to be defined in each module. */ +ns_hook_check_t hook_check; ns_hook_destroy_t hook_destroy; ns_hook_register_t hook_register; ns_hook_version_t hook_version; isc_result_t -ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp); - +ns_hook_createctx(isc_mem_t *mctx, dns_view_t *view, ns_hookctx_t **hctxp); void ns_hook_destroyctx(ns_hookctx_t **hctxp); /*%< @@ -327,6 +337,16 @@ ns_module_load(const char *modpath, const char *parameters, * created by the module's hook_register function. */ +isc_result_t +ns_module_check(const char *modpath, const char *parameters, + const char *cfg_file, unsigned long cfg_line, + const void *cfg, isc_mem_t *mctx, isc_log_t *lctx, void *actx); +/*%< + * Open the module at 'modpath' and check the validity of + * 'parameters', logging any errors or warnings found, then + * close it without configuring it. + */ + void ns_modlist_create(isc_mem_t *mctx, ns_modlist_t **listp); /*%< diff --git a/lib/ns/win32/libns.def b/lib/ns/win32/libns.def index f5be0ac290..c7192933a6 100644 --- a/lib/ns/win32/libns.def +++ b/lib/ns/win32/libns.def @@ -79,6 +79,7 @@ ns_log_init ns_log_setcontext ns_modlist_create ns_modlist_free +ns_module_check ns_module_load ns_notify_start ns_query_cancel