add system tests covering the individual support of zone plugins.
+++ /dev/null
-view foo {
- plugin query "driver/.libs/test-syncplugin.so";
-};
-plugin query "driver/.libs/test-syncplugin.so";
--- /dev/null
+/*
+ * 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.
+ */
+
+view foo {
+ plugin query "@TOP_BUILDDIR@/testlib-driver-syncplugin.so" { rcode servfail; };
+};
+plugin query "@TOP_BUILDDIR@/testlib-driver-syncplugin.so" { rcode servfail; };
+++ /dev/null
-plugin query "driver/.libs/test-syncplugin.so";
--- /dev/null
+/*
+ * 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.
+ */
+
+plugin query "@TOP_BUILDDIR@/testlib-driver-syncplugin.so" { rcode servfail; };
+++ /dev/null
-view foo {
- plugin query "driver/.libs/test-syncplugin.so";
-};
--- /dev/null
+/*
+ * 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.
+ */
+
+view foo {
+ plugin query "@TOP_BUILDDIR@/testlib-driver-syncplugin.so" { rcode servfail; };
+};
+++ /dev/null
-view someview {
- zone "foo.bar" {
- plugin query "driver/.libs/test-syncplugin.so";
- type primary;
- file "foo.bar.db";
- };
- plugin query "driver/.libs/test-syncplugin.so";
-};
--- /dev/null
+/*
+ * 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.
+ */
+
+view someview {
+ zone "foo.bar" {
+ plugin query "@TOP_BUILDDIR@/testlib-driver-syncplugin.so" { rcode servfail; };
+ type primary;
+ file "foo.bar.db";
+ };
+ plugin query "@TOP_BUILDDIR@/testlib-driver-syncplugin.so" { rcode servfail; };
+};
+++ /dev/null
-zone "foo.bar" {
- plugin query "driver/.libs/test-syncplugin.so";
- type primary;
- file "foo.bar.db";
-};
--- /dev/null
+/*
+ * 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 "foo.bar" {
+ plugin query "@TOP_BUILDDIR@/testlib-driver-syncplugin.so" { rcode servfail; };
+ type primary;
+ file "foo.bar.db";
+};
#include <ns/hooks.h>
+typedef struct {
+ isc_mem_t *mctx;
+ uint8_t rcode;
+
+ /*
+ * Plugin will bails out without altering the response if qname first
+ * label matches `firstlbl`.
+ */
+ char *firstlbl;
+} syncplugin_t;
+
+#define CHECK(op) \
+ do { \
+ result = (op); \
+ if (result != ISC_R_SUCCESS) { \
+ goto cleanup; \
+ } \
+ } while (0)
+
static ns_hookresult_t
-syncplugin_hook(void *arg, void *cbdata, isc_result_t *resp) {
- UNUSED(arg);
- UNUSED(cbdata);
+syncplugin__hook(void *arg, void *cbdata, isc_result_t *resp) {
+ query_ctx_t *qctx = (query_ctx_t *)arg;
+ syncplugin_t *inst = cbdata;
+
UNUSED(resp);
- return NS_HOOK_CONTINUE;
+ if (inst->firstlbl != NULL) {
+ const dns_name_t *qname = qctx->client->query.qname;
+ dns_label_t label;
+
+ dns_name_getlabel(qname, 0, &label);
+
+ /*
+ * +1 because the first label byte is the length of the label
+ * itself
+ */
+ if (strncmp(inst->firstlbl, (char *)label.base + 1,
+ strlen(inst->firstlbl)) == 0)
+ {
+ return NS_HOOK_CONTINUE;
+ }
+ }
+
+ qctx->client->message->rcode = inst->rcode;
+ *resp = ns_query_done(qctx);
+ return NS_HOOK_RETURN;
+}
+
+static cfg_clausedef_t syncplugin__cfgclauses[] = {
+ { "rcode", &cfg_type_astring, 0 },
+ { "firstlbl", &cfg_type_qstring, CFG_CLAUSEFLAG_OPTIONAL }
+};
+
+static cfg_clausedef_t *syncplugin__cfgparamsclausesets[] = {
+ syncplugin__cfgclauses, NULL
+};
+
+static cfg_type_t syncplugin__cfgparams = {
+ "syncplugin-params", cfg_parse_mapbody, cfg_print_mapbody,
+ cfg_doc_mapbody, &cfg_rep_map, syncplugin__cfgparamsclausesets
+};
+
+static isc_result_t
+syncplugin__parse_rcode(const cfg_obj_t *syncplugincfg, uint8_t *rcode) {
+ isc_result_t result;
+ const cfg_obj_t *obj = NULL;
+ const char *rcodestr = NULL;
+
+ result = cfg_map_get(syncplugincfg, "rcode", &obj);
+ if (result != ISC_R_SUCCESS) {
+ return result;
+ }
+
+ rcodestr = obj->value.string.base;
+
+ if (strcmp("servfail", rcodestr) == 0) {
+ *rcode = dns_rcode_servfail;
+ } else if (strcmp("notimp", rcodestr) == 0) {
+ *rcode = dns_rcode_notimp;
+ } else if (strcmp("noerror", rcodestr) == 0) {
+ *rcode = dns_rcode_noerror;
+ } else if (strcmp("notauth", rcodestr) == 0) {
+ *rcode = dns_rcode_notauth;
+ } else if (strcmp("notzone", rcodestr) == 0) {
+ *rcode = dns_rcode_notzone;
+ } else {
+ result = ISC_R_FAILURE;
+ }
+
+ return result;
}
isc_result_t
plugin_register(const char *parameters, const void *cfg, const char *cfgfile,
unsigned long cfgline, isc_mem_t *mctx, void *actx,
ns_hooktable_t *hooktable, void **instp) {
+ isc_result_t result;
+ cfg_parser_t *parser = NULL;
+ cfg_obj_t *syncplugincfg = NULL;
+ const cfg_obj_t *obj = NULL;
+ isc_buffer_t b;
ns_hook_t hook;
+ syncplugin_t *inst = NULL;
- UNUSED(parameters);
UNUSED(cfg);
- UNUSED(cfgfile);
- UNUSED(cfgline);
- UNUSED(mctx);
UNUSED(actx);
- UNUSED(hooktable);
- UNUSED(instp);
- hook = (ns_hook_t){ .action = syncplugin_hook,
- .action_data = NULL };
- ns_hook_add(hooktable, mctx, NS_QUERY_NODATA_BEGIN, &hook);
+ inst = isc_mem_get(mctx, sizeof(*inst));
+ *inst = (syncplugin_t){ .mctx = mctx };
+ *instp = inst;
- return ISC_R_SUCCESS;
+ CHECK(cfg_parser_create(mctx, &parser));
+
+ isc_buffer_constinit(&b, parameters, strlen(parameters));
+ isc_buffer_add(&b, strlen(parameters));
+
+ CHECK(cfg_parse_buffer(parser, &b, cfgfile, cfgline,
+ &syncplugin__cfgparams, 0, &syncplugincfg));
+
+ CHECK(syncplugin__parse_rcode(syncplugincfg, &inst->rcode));
+
+ if (cfg_map_get(syncplugincfg, "firstlbl", &obj) == ISC_R_SUCCESS) {
+ const char *firstlbl = cfg_obj_asstring(obj);
+ size_t len = strlen(firstlbl) + 1;
+
+ inst->firstlbl = isc_mem_allocate(mctx, len);
+ strncpy(inst->firstlbl, firstlbl, len);
+ }
+
+ hook = (ns_hook_t){ .action = syncplugin__hook, .action_data = inst };
+ ns_hook_add(hooktable, mctx, NS_QUERY_NXDOMAIN_BEGIN, &hook);
+
+cleanup:
+ if (syncplugincfg != NULL) {
+ cfg_obj_destroy(parser, &syncplugincfg);
+ }
+
+ if (parser != NULL) {
+ cfg_parser_destroy(&parser);
+ }
+
+ return result;
}
isc_result_t
void
plugin_destroy(void **instp) {
- UNUSED(instp);
+ syncplugin_t *inst = *instp;
+ isc_mem_t *mctx = inst->mctx;
+
+ if (inst->firstlbl != NULL) {
+ isc_mem_free(mctx, inst->firstlbl);
+ }
+
+ isc_mem_put(mctx, inst, sizeof(*inst));
+ *instp = NULL;
}
int
--- /dev/null
+; 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 120
+@ SOA ns.unsigned. hostmaster.ns.unsigned. ( 1 3600 1200 604800 60 )
+@ NS ns
+@ MX 10 mx
+
+ns A 10.53.0.1
+ AAAA fd92:7065:b8e:ffff::1
+
+a A 1.1.1.1
+mx A 2.2.2.2
--- /dev/null
+; 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 120
+@ SOA ns.unsigned. hostmaster.ns.unsigned. ( 1 3600 1200 604800 60 )
+@ NS ns
+@ MX 10 mx
+
+ns A 10.53.0.1
+ AAAA fd92:7065:b8e:ffff::1
+
+a A 1.1.1.1
+mx A 2.2.2.2
--- /dev/null
+/*
+ * 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 {
+ 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; };
+ recursion no;
+ dnssec-validation yes;
+ notify yes;
+ minimal-responses no;
+};
+
+trust-anchors { };
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+ inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+plugin query "@TOP_BUILDDIR@/testlib-driver-syncplugin.so" {
+ rcode noerror;
+};
+
+zone "example.com" {
+ type primary;
+ file "example.db";
+};
+
+zone "example2.com" {
+ type primary;
+ file "example.db";
+ plugin query "@TOP_BUILDDIR@/testlib-driver-syncplugin.so" {
+ rcode servfail;
+ };
+};
+
+zone "example3.com" {
+ type primary;
+ file "example.db";
+ plugin query "@TOP_BUILDDIR@/testlib-driver-syncplugin.so" {
+ rcode notimp;
+ };
+};
+
+template exampletmpl {
+ type primary;
+ file "$name.db";
+ plugin query "@TOP_BUILDDIR@/testlib-driver-syncplugin.so" {
+ rcode notauth;
+ firstlbl "skipfoo";
+ };
+};
+
+zone "example4.com" {
+ template exampletmpl;
+ plugin query "@TOP_BUILDDIR@/testlib-driver-syncplugin.so" {
+ rcode notzone;
+ };
+};
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
+import dns
+import pytest
import isctest
+pytest.importorskip("dns")
+
+pytestmark = pytest.mark.extra_artifacts(["conf/*.conf"])
+
def test_hooks():
msg = isctest.query.create("example.com.", "A")
test_hooks()
-def test_plugins_config(run_tests_sh):
+def test_hooks_global_hook():
+ msg = isctest.query.create("idontexists.example.com", "A")
+ res = isctest.query.udp(msg, "10.53.0.2")
+ isctest.check.rcode(res, dns.rcode.NOERROR)
+
+
+def test_hooks_zone_hook1():
+ msg = isctest.query.create("idonotexists.example2.com", "A")
+ res = isctest.query.udp(msg, "10.53.0.2")
+ isctest.check.rcode(res, dns.rcode.SERVFAIL)
+
+
+def test_hooks_zone_hook2():
+ msg = isctest.query.create("idonotexists.example3.com", "A")
+ res = isctest.query.udp(msg, "10.53.0.2")
+ isctest.check.rcode(res, dns.rcode.NOTIMP)
+
+
+# ensure a plugin defined in a template is correcty registered to zone using
+# this template
+def test_hooks_zonetemplate1():
+ msg = isctest.query.create("idonotexists.example4.com", "A")
+ res = isctest.query.udp(msg, "10.53.0.2")
+ isctest.check.rcode(res, dns.rcode.NOTAUTH)
+
+
+# ensure plugin defined in zone are correctly registered when the zone also
+# using a template with plugins (the plugin defined in the template is called
+# first, but it bails out without doing anything because the first label is
+# "skipfoo". So the plugin defined in the zone is then called, and return
+# notzone)
+def test_hooks_zonetemplate2():
+ msg = isctest.query.create("skipfoo.example4.com", "A")
+ res = isctest.query.udp(msg, "10.53.0.2")
+ isctest.check.rcode(res, dns.rcode.NOTZONE)
+
+
+def test_hooks_zone_rndc_reload(servers):
+ ns2 = servers["ns2"]
+ ns2.rndc("reload")
+
+
+def test_hooks_config(run_tests_sh):
run_tests_sh()