Merge branch '15-filter-aaaa-module' into 'master'

first module: filter-aaaa

See merge request isc-projects/bind9!799
This commit is contained in:
Evan Hunt 2018-12-06 13:57:49 -05:00
commit 71e54bfe0f
88 changed files with 4929 additions and 2319 deletions

17
CHANGES
View file

@ -1,3 +1,20 @@
5106. [experimental] A new "plugin" mechanism has been added to allow
extension of query processing functionality through
the use of dynamically loadable libraries. A
"filter-aaaa.so" plugin has been implemented,
replacing the filter-aaaa feature that was formerly
implemented as a native part of BIND.
The "filter-aaaa", "filter-aaaa-on-v4" and
"filter-aaaa-on-v6" options can no longer be
configured using native named.conf syntax. However,
loading the filter-aaaa.so plugin and setting its
parameters provides identical functionality.
Note that the plugin API is a work in progress and
is likely to evolve as further plugins are
implemented. [GL #15]
5105. [bug] Fix a race between process_fd and socketclose in
unix socket code. [GL #744]

View file

@ -12,7 +12,7 @@ VPATH = @srcdir@
top_srcdir = @top_srcdir@
SUBDIRS = named rndc dig delv dnssec tools nsupdate check confgen \
@NZD_TOOLS@ @PYTHON_TOOLS@ @PKCS11_TOOLS@ tests
@NZD_TOOLS@ @PYTHON_TOOLS@ @PKCS11_TOOLS@ plugins tests
TARGETS =
@BIND9_MAKE_RULES@

View file

@ -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} \

View file

@ -46,6 +46,8 @@
static const char *program = "named-checkconf";
static bool loadplugins = 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':
loadplugins = 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, loadplugins, 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);

View file

@ -52,7 +52,7 @@
<refsynopsisdiv>
<cmdsynopsis sepchar=" ">
<command>named-checkconf</command>
<arg choice="opt" rep="norepeat"><option>-hjlvz</option></arg>
<arg choice="opt" rep="norepeat"><option>-chjlvz</option></arg>
<arg choice="opt" rep="norepeat"><option>-p</option>
<arg choice="opt" rep="norepeat"><option>-x</option>
</arg></arg>
@ -114,6 +114,17 @@
</listitem>
</varlistentry>
<varlistentry>
<term>-c</term>
<listitem>
<para>
Check "core" configuration only. This suppresses the loading
of plugin modules, and causes all parameters to
<command>plugin</command> statements to be ignored.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-p</term>
<listitem>

View file

@ -154,10 +154,7 @@ options {\n\
# fetch-glue <obsolete>;\n\
fetch-quota-params 100 0.1 0.3 0.7;\n\
fetches-per-server 0;\n\
fetches-per-zone 0;\n\
filter-aaaa-on-v4 no;\n\
filter-aaaa-on-v6 no;\n\
filter-aaaa { any; };\n"
fetches-per-zone 0;\n"
#ifdef HAVE_GEOIP
" geoip-use-ecs yes;\n"
#endif

View file

@ -102,6 +102,7 @@
#include <dst/result.h>
#include <ns/client.h>
#include <ns/hooks.h>
#include <ns/listenlist.h>
#include <ns/interfacemgr.h>
@ -3646,6 +3647,35 @@ create_mapped_acl(void) {
return (result);
}
#ifdef HAVE_DLOPEN
/*%
* A callback for the cfg_pluginlist_foreach() call in configure_view() below.
* If registering any plugin fails, registering subsequent ones is not
* attempted.
*/
static isc_result_t
register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj,
const char *plugin_path, const char *parameters,
void *callback_data)
{
dns_view_t *view = callback_data;
isc_result_t result;
result = ns_plugin_register(plugin_path, parameters, config,
cfg_obj_file(obj), cfg_obj_line(obj),
named_g_mctx, named_g_lctx,
named_g_aclconfctx, view);
if (result != ISC_R_SUCCESS) {
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
"%s: plugin configuration failed: %s",
plugin_path, isc_result_totext(result));
}
return (result);
}
#endif
/*
* Configure 'view' according to 'vconfig', taking defaults from 'config'
* where values are missing in 'vconfig'.
@ -3674,7 +3704,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
const cfg_obj_t *dlvobj = NULL;
unsigned int dlzargc;
char **dlzargv;
const cfg_obj_t *dyndb_list;
const cfg_obj_t *dyndb_list, *plugin_list;
const cfg_obj_t *disabled;
const cfg_obj_t *obj, *obj2;
const cfg_listelt_t *element;
@ -5088,46 +5118,6 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
dns_quotatype_zone, r);
}
obj = NULL;
result = named_config_get(maps, "filter-aaaa-on-v4", &obj);
INSIST(result == ISC_R_SUCCESS);
if (cfg_obj_isboolean(obj)) {
if (cfg_obj_asboolean(obj))
view->v4_aaaa = dns_aaaa_filter;
else
view->v4_aaaa = dns_aaaa_ok;
} else {
const char *v4_aaaastr = cfg_obj_asstring(obj);
if (strcasecmp(v4_aaaastr, "break-dnssec") == 0) {
view->v4_aaaa = dns_aaaa_break_dnssec;
} else {
INSIST(0);
ISC_UNREACHABLE();
}
}
obj = NULL;
result = named_config_get(maps, "filter-aaaa-on-v6", &obj);
INSIST(result == ISC_R_SUCCESS);
if (cfg_obj_isboolean(obj)) {
if (cfg_obj_asboolean(obj))
view->v6_aaaa = dns_aaaa_filter;
else
view->v6_aaaa = dns_aaaa_ok;
} else {
const char *v6_aaaastr = cfg_obj_asstring(obj);
if (strcasecmp(v6_aaaastr, "break-dnssec") == 0) {
view->v6_aaaa = dns_aaaa_break_dnssec;
} else {
INSIST(0);
ISC_UNREACHABLE();
}
}
CHECK(configure_view_acl(vconfig, config, named_g_config,
"filter-aaaa", NULL, actx,
named_g_mctx, &view->aaaa_acl));
obj = NULL;
result = named_config_get(maps, "prefetch", &obj);
if (result == ISC_R_SUCCESS) {
@ -5269,10 +5259,11 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
* Load DynDB modules.
*/
dyndb_list = NULL;
if (voptions != NULL)
if (voptions != NULL) {
(void)cfg_map_get(voptions, "dyndb", &dyndb_list);
else
} else {
(void)cfg_map_get(config, "dyndb", &dyndb_list);
}
#ifdef HAVE_DLOPEN
for (element = cfg_list_first(dyndb_list);
@ -5294,6 +5285,31 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
}
#endif
/*
* Load plugins.
*/
plugin_list = NULL;
if (voptions != NULL) {
(void)cfg_map_get(voptions, "plugin", &plugin_list);
} else {
(void)cfg_map_get(config, "plugin", &plugin_list);
}
#ifdef HAVE_DLOPEN
if (plugin_list != NULL) {
INSIST(view->hooktable == NULL);
CHECK(ns_hooktable_create(view->mctx,
(ns_hooktable_t **) &view->hooktable));
view->hooktable_free = ns_hooktable_free;
ns_plugins_create(view->mctx, (ns_plugins_t **)&view->plugins);
view->plugins_free = ns_plugins_free;
CHECK(cfg_pluginlist_foreach(config, plugin_list, named_g_lctx,
register_one_plugin, view));
}
#endif
/*
* Setup automatic empty zones. If recursion is off then
* they are disabled by default.
@ -8064,8 +8080,12 @@ load_configuration(const char *filename, named_server_t *server,
/*
* Check the validity of the configuration.
*
* (Ignore plugin 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.
@ -9510,6 +9530,9 @@ shutdown_server(isc_task_t *task, isc_event_t *event) {
dns_view_detach(&view);
}
/*
* Shut down all dyndb instances.
*/
dns_dyndb_cleanup(true);
while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {

72
bin/plugins/Makefile.in Normal file
View file

@ -0,0 +1,72 @@
# 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.
srcdir = @srcdir@
VPATH = @srcdir@
top_srcdir = @top_srcdir@
@BIND9_MAKE_INCLUDES@
CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include -I. \
${NS_INCLUDES} ${DNS_INCLUDES} \
${ISCCFG_INCLUDES} ${ISC_INCLUDES}
DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@
ISCLIBS = ../../lib/isc/libisc.@A@ @OPENSSL_LIBS@
NSLIBS = ../../lib/ns/libns.@A@
LIBS =
SO_TARGETS = lib/filter-aaaa.@SO@
TARGETS = @SO_TARGETS@
SO_OBJS = filter-aaaa.@O@
SO_SRCS = filter-aaaa.c
CFLAGS = @CFLAGS@ @SO_CFLAGS@
SO_LDFLAGS = @LDFLAGS@ @SO_LDFLAGS@
MANPAGES = filter-aaaa.8
HTMLPAGES = filter-aaaa.html
MANOBJS = ${MANPAGES} ${HTMLPAGES}
@BIND9_MAKE_RULES@
lib/filter-aaaa.@SO@: filter-aaaa.@SO@
$(SHELL) ${top_srcdir}/mkinstalldirs `pwd`/lib
${LIBTOOL_MODE_INSTALL} ${INSTALL} filter-aaaa.@SO@ `pwd`/lib
filter-aaaa.@SO@: filter-aaaa.@O@
${LIBTOOL_MODE_LINK} @SO_LD@ ${SO_LDFLAGS} -o $@ \
filter-aaaa.@O@ ${LIBS}
doc man:: ${MANOBJS}
docclean manclean maintainer-clean::
rm -f ${MANOBJS}
clean distclean::
rm -f filter-aaaa.so
rm -f ${TARGETS} ${OBJS}
installdirs:
$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir}
$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man8
install:: filter-aaaa.@SO@ installdirs
${LIBTOOL_MODE_INSTALL} ${INSTALL_LIBRARY} filter-aaaa.@SO@ \
${DESTDIR}${libdir}
${INSTALL_DATA} ${srcdir}/filter-aaaa.8 ${DESTDIR}${mandir}/man8
uninstall::
${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${libdir}/filter-aaaa.@SO@
rm -f ${DESTDIR}${mandir}/man8/filter-aaaa.8

116
bin/plugins/filter-aaaa.8 Normal file
View file

@ -0,0 +1,116 @@
.\" Copyright (C) 2018 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/.
.\"
.hy 0
.ad l
'\" t
.\" Title: filter-aaaa.so
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 2018-08-13
.\" Manual: BIND9
.\" Source: ISC
.\" Language: English
.\"
.TH "FILTER\-AAAA\&.SO" "8" "2018\-08\-13" "ISC" "BIND9"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\" http://bugs.debian.org/507673
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.\" -----------------------------------------------------------------
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "NAME"
filter-aaaa.so \- filter AAAA in DNS responses when A is present
.SH "SYNOPSIS"
.HP 28
\fBhook query "filter\-aaaa\&.so"\fR [\fI{\ parameters\ }\fR];
.SH "DESCRIPTION"
.PP
\fBfilter\-aaaa\&.so\fR
is a query hook module for
\fBnamed\fR, enabling
\fBnamed\fR
to omit some IPv6 addresses when responding to clients\&.
.PP
Until BIND 9\&.12, this feature was implemented natively in
\fBnamed\fR
and enabled with the
\fBfilter\-aaaa\fR
ACL and the
\fBfilter\-aaaa\-on\-v4\fR
and
\fBfilter\-aaaa\-on\-v6\fR
options\&. These options are now deprecated in
named\&.conf, but can be passed as parameters to the
\fBfilter\-aaaa\&.so\fR
hook module, for example:
.sp
.if n \{\
.RS 4
.\}
.nf
hook query "/usr/local/lib/filter\-aaaa\&.so" {
filter\-aaaa\-on\-v4 yes;
filter\-aaaa\-on\-v6 yes;
filter\-aaaa { 192\&.0\&.2\&.1; 2001:db8:2::1; };
};
.fi
.if n \{\
.RE
.\}
.PP
This module is intended to aid transition from IPv4 to IPv6 by withholding IPv6 addresses from DNS clients which are not connected to the IPv6 Internet, when the name being looked up has an IPv4 address available\&. Use of this module is not recommended unless absolutely necessary\&.
.PP
Note: This mechanism can erroneously cause other servers not to give AAAA records to their clients\&. If a recursing server with both IPv6 and IPv4 network connections queries an authoritative server using this mechanism via IPv4, it will be denied AAAA records even if its client is using IPv6\&.
.SH "OPTIONS"
.PP
\fBfilter\-aaaa\fR
.RS 4
Specifies a list of client addresses for which AAAA filtering is to be applied\&. The default is
\fBany\fR\&.
.RE
.PP
\fBfilter\-aaaa\-on\-v4\fR
.RS 4
If set to
\fByes\fR, the DNS client is at an IPv4 address, in
\fBfilter\-aaaa\fR, and if the response does not include DNSSEC signatures, then all AAAA records are deleted from the response\&. This filtering applies to all responses and not only authoritative responses\&.
.sp
If set to
\fBbreak\-dnssec\fR, then AAAA records are deleted even when DNSSEC is enabled\&. As suggested by the name, this causes the response to fail to verify, because the DNSSEC protocol is designed to detect deletions\&.
.sp
This mechanism can erroneously cause other servers not to give AAAA records to their clients\&. A recursing server with both IPv6 and IPv4 network connections that queries an authoritative server using this mechanism via IPv4 will be denied AAAA records even if its client is using IPv6\&.
.RE
.PP
\fBfilter\-aaaa\-on\-v6\fR
.RS 4
Identical to
\fBfilter\-aaaa\-on\-v4\fR, except it filters AAAA responses to queries from IPv6 clients instead of IPv4 clients\&. To filter all responses, set both options to
\fByes\fR\&.
.RE
.SH "SEE ALSO"
.PP
BIND 9 Administrator Reference Manual\&.
.SH "AUTHOR"
.PP
\fBInternet Systems Consortium, Inc\&.\fR
.SH "COPYRIGHT"
.br
Copyright \(co 2018 Internet Systems Consortium, Inc. ("ISC")
.br

925
bin/plugins/filter-aaaa.c Normal file
View file

@ -0,0 +1,925 @@
/*
* 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.
*/
/*! \file */
#include <config.h>
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include <isc/buffer.h>
#include <isc/hash.h>
#include <isc/ht.h>
#include <isc/lib.h>
#include <isc/log.h>
#include <isc/mem.h>
#include <isc/netaddr.h>
#include <isc/result.h>
#include <isc/types.h>
#include <isc/util.h>
#include <isccfg/aclconf.h>
#include <isccfg/cfg.h>
#include <isccfg/grammar.h>
#include <ns/client.h>
#include <ns/hooks.h>
#include <ns/log.h>
#include <ns/query.h>
#include <ns/types.h>
#include <dns/acl.h>
#include <dns/db.h>
#include <dns/enumtype.h>
#include <dns/log.h>
#include <dns/message.h>
#include <dns/rdataset.h>
#include <dns/result.h>
#include <dns/types.h>
#include <dns/view.h>
#define CHECK(op) \
do { \
result = (op); \
if (result != ISC_R_SUCCESS) { \
goto cleanup; \
} \
} while (0)
/*
* Possible values for the settings of filter-aaaa-on-v4 and
* filter-aaaa-on-v6: "no" is NONE, "yes" is FILTER, "break-dnssec"
* is BREAK_DNSSEC.
*/
typedef enum {
NONE = 0,
FILTER = 1,
BREAK_DNSSEC = 2
} filter_aaaa_t;
/*
* Persistent data for use by this module. This will be associated
* with client object address in the hash table, and will remain
* accessible until the client object is detached.
*/
typedef struct filter_data {
filter_aaaa_t mode;
uint32_t flags;
} filter_data_t;
typedef struct filter_instance {
ns_plugin_t *module;
isc_mem_t *mctx;
/*
* Memory pool for use with persistent data.
*/
isc_mempool_t *datapool;
/*
* Hash table associating a client object with its persistent data.
*/
isc_ht_t *ht;
/*
* Values configured when the module is loaded.
*/
filter_aaaa_t v4_aaaa;
filter_aaaa_t v6_aaaa;
dns_acl_t *aaaa_acl;
} filter_instance_t;
/*
* Per-client flags set by this module
*/
#define FILTER_AAAA_RECURSING 0x0001 /* Recursing for A */
#define FILTER_AAAA_FILTERED 0x0002 /* AAAA was removed from answer */
/*
* Client attribute tests.
*/
#define WANTDNSSEC(c) (((c)->attributes & NS_CLIENTATTR_WANTDNSSEC) != 0)
#define RECURSIONOK(c) (((c)->query.attributes & \
NS_QUERYATTR_RECURSIONOK) != 0)
/*
* Forward declarations of functions referenced in install_hooks().
*/
static ns_hookresult_t
filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp);
static ns_hookresult_t
filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp);
static ns_hookresult_t
filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp);
static ns_hookresult_t
filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp);
static ns_hookresult_t
filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp);
static ns_hookresult_t
filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp);
/*%
* Register the functions to be called at each hook point in 'hooktable', using
* memory context 'mctx' for allocating copies of stack-allocated structures
* passed to ns_hook_add(). Make sure 'inst' will be passed as the 'cbdata'
* argument to every callback.
*/
static void
install_hooks(ns_hooktable_t *hooktable, isc_mem_t *mctx,
filter_instance_t *inst)
{
const ns_hook_t filter_init = {
.action = filter_qctx_initialize,
.action_data = inst,
};
const ns_hook_t filter_respbegin = {
.action = filter_respond_begin,
.action_data = inst,
};
const ns_hook_t filter_respanyfound = {
.action = filter_respond_any_found,
.action_data = inst,
};
const ns_hook_t filter_prepresp = {
.action = filter_prep_response_begin,
.action_data = inst,
};
const ns_hook_t filter_donesend = {
.action = filter_query_done_send,
.action_data = inst,
};
const ns_hook_t filter_destroy = {
.action = filter_qctx_destroy,
.action_data = inst,
};
ns_hook_add(hooktable, mctx, -
NS_QUERY_QCTX_INITIALIZED, &filter_init);
ns_hook_add(hooktable, mctx,
NS_QUERY_RESPOND_BEGIN, &filter_respbegin);
ns_hook_add(hooktable, mctx,
NS_QUERY_RESPOND_ANY_FOUND, &filter_respanyfound);
ns_hook_add(hooktable, mctx,
NS_QUERY_PREP_RESPONSE_BEGIN, &filter_prepresp);
ns_hook_add(hooktable, mctx,
NS_QUERY_DONE_SEND, &filter_donesend);
ns_hook_add(hooktable, mctx,
NS_QUERY_QCTX_DESTROYED, &filter_destroy);
}
/**
** Support for parsing of parameters and configuration of the module.
**/
/*
* Support for parsing of parameters.
*/
static const char *filter_aaaa_enums[] = { "break-dnssec", NULL };
static isc_result_t
parse_filter_aaaa(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
}
static void
doc_filter_aaaa(cfg_printer_t *pctx, const cfg_type_t *type) {
cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean);
}
static cfg_type_t cfg_type_filter_aaaa = {
"filter_aaaa", parse_filter_aaaa, cfg_print_ustring,
doc_filter_aaaa, &cfg_rep_string, filter_aaaa_enums,
};
static cfg_clausedef_t param_clauses[] = {
{ "filter-aaaa", &cfg_type_bracketed_aml, 0 },
{ "filter-aaaa-on-v4", &cfg_type_filter_aaaa, 0 },
{ "filter-aaaa-on-v6", &cfg_type_filter_aaaa, 0 },
};
static cfg_clausedef_t *param_clausesets[] = {
param_clauses,
NULL
};
static cfg_type_t cfg_type_parameters = {
"filter-aaaa-params", cfg_parse_mapbody, cfg_print_mapbody,
cfg_doc_mapbody, &cfg_rep_map, param_clausesets
};
static isc_result_t
parse_filter_aaaa_on(const cfg_obj_t *param_obj, const char *param_name,
filter_aaaa_t *dstp)
{
const cfg_obj_t *obj = NULL;
isc_result_t result;
result = cfg_map_get(param_obj, param_name, &obj);
if (result != ISC_R_SUCCESS) {
return (ISC_R_SUCCESS);
}
if (cfg_obj_isboolean(obj)) {
if (cfg_obj_asboolean(obj)) {
*dstp = FILTER;
} else {
*dstp = NONE;
}
} else if (strcasecmp(cfg_obj_asstring(obj), "break-dnssec") == 0) {
*dstp = BREAK_DNSSEC;
} else {
result = ISC_R_UNEXPECTED;
}
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 void *cfg, const char *cfg_file, unsigned long cfg_line,
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;
const cfg_obj_t *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, &param_obj));
CHECK(check_syntax(param_obj, cfg, mctx, lctx, actx));
CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v4",
&inst->v4_aaaa));
CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v6",
&inst->v6_aaaa));
result = cfg_map_get(param_obj, "filter-aaaa", &obj);
if (result == ISC_R_SUCCESS) {
CHECK(cfg_acl_fromconfig(obj, (const cfg_obj_t *) cfg,
lctx, (cfg_aclconfctx_t *) actx,
mctx, 0, &inst->aaaa_acl));
} else {
CHECK(dns_acl_any(mctx, &inst->aaaa_acl));
}
cleanup:
if (param_obj != NULL) {
cfg_obj_destroy(parser, &param_obj);
}
if (parser != NULL) {
cfg_parser_destroy(&parser);
}
return (result);
}
/**
** Mandatory plugin API functions:
**
** - plugin_destroy
** - plugin_register
** - plugin_version
** - plugin_check
**/
/*
* Called by ns_plugin_register() to initialize the plugin and
* register hook functions into the view hook table.
*/
isc_result_t
plugin_register(const char *parameters,
const void *cfg, const char *cfg_file, unsigned long cfg_line,
isc_mem_t *mctx, isc_log_t *lctx, void *actx,
ns_hooktable_t *hooktable, void **instp)
{
filter_instance_t *inst = NULL;
isc_result_t result;
isc_log_write(lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
"registering 'filter-aaaa' "
"module from %s:%lu, %s parameters",
cfg_file, cfg_line, parameters != NULL ? "with" : "no");
inst = isc_mem_get(mctx, sizeof(*inst));
memset(inst, 0, sizeof(*inst));
isc_mem_attach(mctx, &inst->mctx);
if (parameters != NULL) {
CHECK(parse_parameters(inst, parameters, cfg, cfg_file,
cfg_line, mctx, lctx, actx));
}
CHECK(isc_mempool_create(mctx, sizeof(filter_data_t),
&inst->datapool));
CHECK(isc_ht_init(&inst->ht, mctx, 16));
/*
* Fill the mempool with 1K filter_aaaa state objects at
* a time; ideally after a single allocation, the mempool will
* have enough to handle all the simultaneous queries the system
* requires and it won't be necessary to allocate more.
*
* We don't set any limit on the number of free state objects
* so that they'll always be returned to the pool and not
* freed until the pool is destroyed on shutdown.
*/
isc_mempool_setfillcount(inst->datapool, 1024);
isc_mempool_setfreemax(inst->datapool, UINT_MAX);
/*
* Set hook points in the view's hooktable.
*/
install_hooks(hooktable, mctx, inst);
*instp = inst;
cleanup:
if (result != ISC_R_SUCCESS && inst != NULL) {
plugin_destroy((void **) &inst);
}
return (result);
}
isc_result_t
plugin_check(const char *parameters,
const void *cfg, const char *cfg_file, unsigned long cfg_line,
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, &param_obj));
CHECK(check_syntax(param_obj, cfg, mctx, lctx, actx));
cleanup:
if (param_obj != NULL) {
cfg_obj_destroy(parser, &param_obj);
}
if (parser != NULL) {
cfg_parser_destroy(&parser);
}
return (result);
}
/*
* Called by ns_plugins_free(); frees memory allocated by
* the module when it was registered.
*/
void
plugin_destroy(void **instp) {
filter_instance_t *inst = (filter_instance_t *) *instp;
if (inst->ht != NULL) {
isc_ht_destroy(&inst->ht);
}
if (inst->datapool != NULL) {
isc_mempool_destroy(&inst->datapool);
}
if (inst->aaaa_acl != NULL) {
dns_acl_detach(&inst->aaaa_acl);
}
isc_mem_putanddetach(&inst->mctx, inst, sizeof(*inst));
*instp = NULL;
return;
}
/*
* Returns hook module API version for compatibility checks.
*/
int
plugin_version(void) {
return (NS_PLUGIN_VERSION);
}
/**
** "filter-aaaa" feature implementation begins here.
**/
/*%
* Structure describing the filtering to be applied by process_section().
*/
typedef struct section_filter {
query_ctx_t * qctx;
filter_aaaa_t mode;
dns_section_t section;
const dns_name_t * name;
dns_rdatatype_t type;
bool only_if_a_exists;
} section_filter_t;
/*
* Check whether this is an IPv4 client.
*/
static bool
is_v4_client(ns_client_t *client) {
if (isc_sockaddr_pf(&client->peeraddr) == AF_INET) {
return (true);
}
if (isc_sockaddr_pf(&client->peeraddr) == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&client->peeraddr.type.sin6.sin6_addr))
{
return (true);
}
return (false);
}
/*
* Check whether this is an IPv6 client.
*/
static bool
is_v6_client(ns_client_t *client) {
if (isc_sockaddr_pf(&client->peeraddr) == AF_INET6 &&
!IN6_IS_ADDR_V4MAPPED(&client->peeraddr.type.sin6.sin6_addr))
{
return (true);
}
return (false);
}
static filter_data_t *
client_state_get(const query_ctx_t *qctx, filter_instance_t *inst) {
filter_data_t *client_state = NULL;
isc_result_t result;
result = isc_ht_find(inst->ht, (const unsigned char *)&qctx->client,
sizeof(qctx->client), (void **)&client_state);
return (result == ISC_R_SUCCESS ? client_state : NULL);
}
static void
client_state_create(const query_ctx_t *qctx, filter_instance_t *inst) {
filter_data_t *client_state;
isc_result_t result;
client_state = isc_mempool_get(inst->datapool);
if (client_state == NULL) {
return;
}
client_state->mode = NONE;
client_state->flags = 0;
result = isc_ht_add(inst->ht, (const unsigned char *)&qctx->client,
sizeof(qctx->client), client_state);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
}
static void
client_state_destroy(const query_ctx_t *qctx, filter_instance_t *inst) {
filter_data_t *client_state = client_state_get(qctx, inst);
isc_result_t result;
if (client_state == NULL) {
return;
}
result = isc_ht_delete(inst->ht, (const unsigned char *)&qctx->client,
sizeof(qctx->client));
RUNTIME_CHECK(result == ISC_R_SUCCESS);
isc_mempool_put(inst->datapool, client_state);
}
/*%
* Mark 'rdataset' and 'sigrdataset' as rendered, gracefully handling NULL
* pointers and non-associated rdatasets.
*/
static void
mark_as_rendered(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
if (rdataset != NULL && dns_rdataset_isassociated(rdataset)) {
rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
}
if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) {
sigrdataset->attributes |= DNS_RDATASETATTR_RENDERED;
}
}
/*%
* Check whether an RRset of given 'type' is present at given 'name'. If
* it is found and either it is not signed or the combination of query
* flags and configured processing 'mode' allows it, mark the RRset and its
* associated signatures as already rendered to prevent them from appearing
* in the response message stored in 'qctx'. If 'only_if_a_exists' is
* true, an RRset of type A must also exist at 'name' in order for the
* above processing to happen.
*/
static bool
process_name(query_ctx_t *qctx, filter_aaaa_t mode, const dns_name_t *name,
dns_rdatatype_t type, bool only_if_a_exists)
{
dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
isc_result_t result;
bool modified = false;
if (only_if_a_exists) {
CHECK(dns_message_findtype(name, dns_rdatatype_a, 0, NULL));
}
dns_message_findtype(name, type, 0, &rdataset);
dns_message_findtype(name, dns_rdatatype_rrsig, type, &sigrdataset);
if (rdataset != NULL &&
(sigrdataset == NULL || !WANTDNSSEC(qctx->client) ||
mode == BREAK_DNSSEC))
{
/*
* An RRset of given 'type' was found at 'name' and at least
* one of the following is true:
*
* - the RRset is not signed,
* - the client did not set the DO bit in its request,
* - configuration allows us to tamper with signed responses.
*
* This means it is okay to filter out this RRset and its
* signatures, if any, from the response.
*/
mark_as_rendered(rdataset, sigrdataset);
modified = true;
}
cleanup:
return (modified);
}
/*%
* Apply the requested section filter, i.e. prevent (when possible, as
* determined by process_name()) RRsets of given 'type' from being rendered
* in the given 'section' of the response message stored in 'qctx'. Clear
* the AD bit if the answer and/or authority section was modified. If
* 'name' is NULL, all names in the given 'section' are processed;
* otherwise, only 'name' is. 'only_if_a_exists' is passed through to
* process_name().
*/
static void
process_section(const section_filter_t *filter) {
query_ctx_t *qctx = filter->qctx;
filter_aaaa_t mode = filter->mode;
dns_section_t section = filter->section;
const dns_name_t *name = filter->name;
dns_rdatatype_t type = filter->type;
bool only_if_a_exists = filter->only_if_a_exists;
dns_message_t *message = qctx->client->message;
isc_result_t result;
for (result = dns_message_firstname(message, section);
result == ISC_R_SUCCESS;
result = dns_message_nextname(message, section))
{
dns_name_t *cur = NULL;
dns_message_currentname(message, section, &cur);
if (name != NULL && !dns_name_equal(name, cur)) {
/*
* We only want to process 'name' and this is not it.
*/
continue;
}
if (!process_name(qctx, mode, cur, type, only_if_a_exists)) {
/*
* Response was not modified, do not touch the AD bit.
*/
continue;
}
if (section == DNS_SECTION_ANSWER ||
section == DNS_SECTION_AUTHORITY)
{
message->flags &= ~DNS_MESSAGEFLAG_AD;
}
}
}
/*
* Initialize filter state, fetching it from a memory pool and storing it
* in a hash table keyed according to the client object; this enables us to
* retrieve persistent data related to a client query for as long as the
* object persists.
*/
static ns_hookresult_t
filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp) {
query_ctx_t *qctx = (query_ctx_t *) arg;
filter_instance_t *inst = (filter_instance_t *) cbdata;
filter_data_t *client_state;
*resp = ISC_R_UNSET;
client_state = client_state_get(qctx, inst);
if (client_state == NULL) {
client_state_create(qctx, inst);
}
return (NS_HOOK_CONTINUE);
}
/*
* Determine whether this client should have AAAA filtered or not, based on
* the client address family and the settings of filter-aaaa-on-v4 and
* filter-aaaa-on-v6.
*/
static ns_hookresult_t
filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) {
query_ctx_t *qctx = (query_ctx_t *) arg;
filter_instance_t *inst = (filter_instance_t *) cbdata;
filter_data_t *client_state = client_state_get(qctx, inst);
isc_result_t result;
*resp = ISC_R_UNSET;
if (client_state == NULL) {
return (NS_HOOK_CONTINUE);
}
if (inst->v4_aaaa != NONE || inst->v6_aaaa != NONE) {
result = ns_client_checkaclsilent(qctx->client, NULL,
inst->aaaa_acl, true);
if (result == ISC_R_SUCCESS &&
inst->v4_aaaa != NONE &&
is_v4_client(qctx->client))
{
client_state->mode = inst->v4_aaaa;
} else if (result == ISC_R_SUCCESS &&
inst->v6_aaaa != NONE &&
is_v6_client(qctx->client))
{
client_state->mode = inst->v6_aaaa;
}
}
return (NS_HOOK_CONTINUE);
}
/*
* Hide AAAA rrsets if there is a matching A. Trigger recursion if
* necessary to find out whether an A exists.
*
* (This version is for processing answers to explicit AAAA queries; ANY
* queries are handled in filter_respond_any_found().)
*/
static ns_hookresult_t
filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) {
query_ctx_t *qctx = (query_ctx_t *) arg;
filter_instance_t *inst = (filter_instance_t *) cbdata;
filter_data_t *client_state = client_state_get(qctx, inst);
isc_result_t result = ISC_R_UNSET;
*resp = ISC_R_UNSET;
if (client_state == NULL) {
return (NS_HOOK_CONTINUE);
}
if (client_state->mode != BREAK_DNSSEC &&
(client_state->mode != FILTER ||
(WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL &&
dns_rdataset_isassociated(qctx->sigrdataset))))
{
return (NS_HOOK_CONTINUE);
}
if (qctx->qtype == dns_rdatatype_aaaa) {
dns_rdataset_t *trdataset;
trdataset = ns_client_newrdataset(qctx->client);
result = dns_db_findrdataset(qctx->db, qctx->node,
qctx->version,
dns_rdatatype_a, 0,
qctx->client->now,
trdataset, NULL);
if (dns_rdataset_isassociated(trdataset)) {
dns_rdataset_disassociate(trdataset);
}
ns_client_putrdataset(qctx->client, &trdataset);
/*
* We found an AAAA. If we also found an A, then the AAAA
* must not be rendered.
*
* If the A is not in our cache, then any result other than
* DNS_R_DELEGATION or ISC_R_NOTFOUND means there is no A,
* and so AAAAs are okay.
*
* We assume there is no A if we can't recurse for this
* client. That might be the wrong answer, but what else
* can we do? Besides, the fact that we have the AAAA and
* are using this mechanism in the first place suggests
* that we care more about As than AAAAs, and would have
* cached an A if it existed.
*/
if (result == ISC_R_SUCCESS) {
mark_as_rendered(qctx->rdataset, qctx->sigrdataset);
qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD;
client_state->flags |= FILTER_AAAA_FILTERED;
} else if (!qctx->authoritative &&
RECURSIONOK(qctx->client) &&
(result == DNS_R_DELEGATION ||
result == ISC_R_NOTFOUND))
{
/*
* This is an ugly kludge to recurse
* for the A and discard the result.
*
* Continue to add the AAAA now.
* We'll make a note to not render it
* if the recursion for the A succeeds.
*/
result = ns_query_recurse(qctx->client,
dns_rdatatype_a,
qctx->client->query.qname,
NULL, NULL, qctx->resuming);
if (result == ISC_R_SUCCESS) {
client_state->flags |= FILTER_AAAA_RECURSING;
qctx->client->query.attributes |=
NS_QUERYATTR_RECURSING;
}
}
} else if (qctx->qtype == dns_rdatatype_a &&
(client_state->flags & FILTER_AAAA_RECURSING) != 0)
{
const section_filter_t filter_answer = {
.qctx = qctx,
.mode = client_state->mode,
.section = DNS_SECTION_ANSWER,
.name = qctx->fname,
.type = dns_rdatatype_aaaa,
};
process_section(&filter_answer);
client_state->flags &= ~FILTER_AAAA_RECURSING;
result = ns_query_done(qctx);
*resp = result;
return (NS_HOOK_RETURN);
}
*resp = result;
return (NS_HOOK_CONTINUE);
}
/*
* When answering an ANY query, remove AAAA if A is present.
*/
static ns_hookresult_t
filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp) {
query_ctx_t *qctx = (query_ctx_t *) arg;
filter_instance_t *inst = (filter_instance_t *) cbdata;
filter_data_t *client_state = client_state_get(qctx, inst);
*resp = ISC_R_UNSET;
if (client_state != NULL && client_state->mode != NONE) {
/*
* If we are authoritative, require an A record to be
* present before filtering out AAAA records; otherwise,
* just assume an A record exists even if it was not in the
* cache (and therefore is not in the response message),
* thus proceeding with filtering out AAAA records.
*/
const section_filter_t filter_answer = {
.qctx = qctx,
.mode = client_state->mode,
.section = DNS_SECTION_ANSWER,
.name = qctx->tname,
.type = dns_rdatatype_aaaa,
.only_if_a_exists = qctx->authoritative,
};
process_section(&filter_answer);
}
return (NS_HOOK_CONTINUE);
}
/*
* Hide AAAA rrsets in the additional section if there is a matching A, and
* hide NS in the authority section if AAAA was filtered in the answer
* section.
*/
static ns_hookresult_t
filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp) {
query_ctx_t *qctx = (query_ctx_t *) arg;
filter_instance_t *inst = (filter_instance_t *) cbdata;
filter_data_t *client_state = client_state_get(qctx, inst);
*resp = ISC_R_UNSET;
if (client_state != NULL && client_state->mode != NONE) {
const section_filter_t filter_additional = {
.qctx = qctx,
.mode = client_state->mode,
.section = DNS_SECTION_ADDITIONAL,
.type = dns_rdatatype_aaaa,
.only_if_a_exists = true,
};
process_section(&filter_additional);
if ((client_state->flags & FILTER_AAAA_FILTERED) != 0) {
const section_filter_t filter_authority = {
.qctx = qctx,
.mode = client_state->mode,
.section = DNS_SECTION_AUTHORITY,
.type = dns_rdatatype_ns,
};
process_section(&filter_authority);
}
}
return (NS_HOOK_CONTINUE);
}
/*
* If the client is being detached, then we can delete our persistent data
* from hash table and return it to the memory pool.
*/
static ns_hookresult_t
filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp) {
query_ctx_t *qctx = (query_ctx_t *) arg;
filter_instance_t *inst = (filter_instance_t *) cbdata;
*resp = ISC_R_UNSET;
if (!qctx->detach_client) {
return (NS_HOOK_CONTINUE);
}
client_state_destroy(qctx, inst);
return (NS_HOOK_CONTINUE);
}

View file

@ -0,0 +1,146 @@
<!--
- 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.
-->
<!-- Converted by db4-upgrade version 1.0 -->
<refentry xmlns:db="http://docbook.org/ns/docbook" version="5.0" xml:id="man.filter-aaaa">
<info>
<date>2018-08-13</date>
</info>
<refentryinfo>
<corpname>ISC</corpname>
<corpauthor>Internet Systems Consortium, Inc.</corpauthor>
</refentryinfo>
<refmeta>
<refentrytitle><application>filter-aaaa.so</application></refentrytitle>
<manvolnum>8</manvolnum>
<refmiscinfo>BIND9</refmiscinfo>
</refmeta>
<refnamediv>
<refname><application>filter-aaaa.so</application></refname>
<refpurpose>filter AAAA in DNS responses when A is present</refpurpose>
</refnamediv>
<docinfo>
<copyright>
<year>2018</year>
<holder>Internet Systems Consortium, Inc. ("ISC")</holder>
</copyright>
</docinfo>
<refsynopsisdiv>
<cmdsynopsis sepchar=" ">
<command>plugin query "filter-aaaa.so"</command>
<arg choice="opt" rep="norepeat"><replaceable class="parameter">{ parameters }</replaceable></arg>;
</cmdsynopsis>
</refsynopsisdiv>
<refsection><info><title>DESCRIPTION</title></info>
<para>
<command>filter-aaaa.so</command> is a query plugin module for
<command>named</command>, enabling <command>named</command>
to omit some IPv6 addresses when responding to clients.
</para>
<para>
Until BIND 9.12, this feature was implemented natively in
<command>named</command> and enabled with the
<command>filter-aaaa</command> ACL and the
<command>filter-aaaa-on-v4</command> and
<command>filter-aaaa-on-v6</command> options. These options are
now deprecated in <filename>named.conf</filename>, but can be
passed as parameters to the <command>filter-aaaa.so</command>
plugin, for example:
</para>
<programlisting>
plugin query "/usr/local/lib/filter-aaaa.so" {
filter-aaaa-on-v4 yes;
filter-aaaa-on-v6 yes;
filter-aaaa { 192.0.2.1; 2001:db8:2::1; };
};
</programlisting>
<para>
This module is intended to aid transition from IPv4 to IPv6 by
withholding IPv6 addresses from DNS clients which are not connected
to the IPv6 Internet, when the name being looked up has an IPv4
address available. Use of this module is not recommended unless
absolutely necessary.
</para>
<para>
Note: This mechanism can erroneously cause other servers not to
give AAAA records to their clients. If a recursing server with
both IPv6 and IPv4 network connections queries an authoritative
server using this mechanism via IPv4, it will be denied AAAA
records even if its client is using IPv6.
</para>
</refsection>
<refsection><info><title>OPTIONS</title></info>
<variablelist>
<varlistentry>
<term><command>filter-aaaa</command></term>
<listitem>
<para>
Specifies a list of client addresses for which AAAA
filtering is to be applied. The default is
<userinput>any</userinput>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>filter-aaaa-on-v4</command></term>
<listitem>
<para>
If set to <userinput>yes</userinput>, the DNS client is
at an IPv4 address, in <command>filter-aaaa</command>,
and if the response does not include DNSSEC signatures,
then all AAAA records are deleted from the response.
This filtering applies to all responses and not only
authoritative responses.
</para>
<para>
If set to <userinput>break-dnssec</userinput>,
then AAAA records are deleted even when DNSSEC is
enabled. As suggested by the name, this causes the
response to fail to verify, because the DNSSEC protocol is
designed to detect deletions.
</para>
<para>
This mechanism can erroneously cause other servers not to
give AAAA records to their clients. A recursing server with
both IPv6 and IPv4 network connections that queries an
authoritative server using this mechanism via IPv4 will be
denied AAAA records even if its client is using IPv6.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>filter-aaaa-on-v6</command></term>
<listitem>
<para>
Identical to <command>filter-aaaa-on-v4</command>,
except it filters AAAA responses to queries from IPv6
clients instead of IPv4 clients. To filter all
responses, set both options to <userinput>yes</userinput>.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsection>
<refsection><info><title>SEE ALSO</title></info>
<para>
<citetitle>BIND 9 Administrator Reference Manual</citetitle>.
</para>
</refsection>
</refentry>

View file

@ -0,0 +1,115 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!--
- Copyright (C) 2018 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/.
-->
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>filter-aaaa.so</title>
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry">
<a name="man.filter-aaaa"></a><div class="titlepage"></div>
<div class="refnamediv">
<h2>Name</h2>
<p><span class="application">filter-aaaa.so</span> &#8212; filter AAAA in DNS responses when A is present</p>
</div>
<div class="refsynopsisdiv">
<h2>Synopsis</h2>
<div class="cmdsynopsis"><p><code class="command">hook query "filter-aaaa.so"</code> [<em class="replaceable"><code>{ parameters }</code></em>];
</p></div>
</div>
<div class="refsection">
<a name="id-1.7"></a><h2>DESCRIPTION</h2>
<p>
<span class="command"><strong>filter-aaaa.so</strong></span> is a query hook module for
<span class="command"><strong>named</strong></span>, enabling <span class="command"><strong>named</strong></span>
to omit some IPv6 addresses when responding to clients.
</p>
<p>
Until BIND 9.12, this feature was implemented natively in
<span class="command"><strong>named</strong></span> and enabled with the
<span class="command"><strong>filter-aaaa</strong></span> ACL and the
<span class="command"><strong>filter-aaaa-on-v4</strong></span> and
<span class="command"><strong>filter-aaaa-on-v6</strong></span> options. These options are
now deprecated in <code class="filename">named.conf</code>, but can be
passed as parameters to the <span class="command"><strong>filter-aaaa.so</strong></span>
hook module, for example:
</p>
<pre class="programlisting">
hook query "/usr/local/lib/filter-aaaa.so" {
filter-aaaa-on-v4 yes;
filter-aaaa-on-v6 yes;
filter-aaaa { 192.0.2.1; 2001:db8:2::1; };
};
</pre>
<p>
This module is intended to aid transition from IPv4 to IPv6 by
withholding IPv6 addresses from DNS clients which are not connected
to the IPv6 Internet, when the name being looked up has an IPv4
address available. Use of this module is not recommended unless
absolutely necessary.
</p>
<p>
Note: This mechanism can erroneously cause other servers not to
give AAAA records to their clients. If a recursing server with
both IPv6 and IPv4 network connections queries an authoritative
server using this mechanism via IPv4, it will be denied AAAA
records even if its client is using IPv6.
</p>
</div>
<div class="refsection">
<a name="id-1.8"></a><h2>OPTIONS</h2>
<div class="variablelist"><dl class="variablelist">
<dt><span class="term"><span class="command"><strong>filter-aaaa</strong></span></span></dt>
<dd><p>
Specifies a list of client addresses for which AAAA
filtering is to be applied. The default is
<strong class="userinput"><code>any</code></strong>.
</p></dd>
<dt><span class="term"><span class="command"><strong>filter-aaaa-on-v4</strong></span></span></dt>
<dd>
<p>
If set to <strong class="userinput"><code>yes</code></strong>, the DNS client is
at an IPv4 address, in <span class="command"><strong>filter-aaaa</strong></span>,
and if the response does not include DNSSEC signatures,
then all AAAA records are deleted from the response.
This filtering applies to all responses and not only
authoritative responses.
</p>
<p>
If set to <strong class="userinput"><code>break-dnssec</code></strong>,
then AAAA records are deleted even when DNSSEC is
enabled. As suggested by the name, this causes the
response to fail to verify, because the DNSSEC protocol is
designed to detect deletions.
</p>
<p>
This mechanism can erroneously cause other servers not to
give AAAA records to their clients. A recursing server with
both IPv6 and IPv4 network connections that queries an
authoritative server using this mechanism via IPv4 will be
denied AAAA records even if its client is using IPv6.
</p>
</dd>
<dt><span class="term"><span class="command"><strong>filter-aaaa-on-v6</strong></span></span></dt>
<dd><p>
Identical to <span class="command"><strong>filter-aaaa-on-v4</strong></span>,
except it filters AAAA responses to queries from IPv6
clients instead of IPv4 clients. To filter all
responses, set both options to <strong class="userinput"><code>yes</code></strong>.
</p></dd>
</dl></div>
</div>
<div class="refsection">
<a name="id-1.9"></a><h2>SEE ALSO</h2>
<p>
<em class="citetitle">BIND 9 Administrator Reference Manual</em>.
</p>
</div>
</div></body>
</html>

View file

@ -26,3 +26,6 @@ rm -f ns4/dsset-*
rm -f dig.out.*
rm -f ns*/named.lock
rm -f ns*/managed-keys.bind*
rm -f ns*/trusted.conf
rm -f ns*/keygen.out

View file

@ -9,7 +9,7 @@
* information regarding copyright ownership.
*/
options {
plugin query "../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v4 yes;
filter-aaaa { none; };
};

View file

@ -9,7 +9,7 @@
* information regarding copyright ownership.
*/
options {
plugin query "../../../plugins/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

View file

@ -9,10 +9,9 @@
* information regarding copyright ownership.
*/
options {
filter-aaaa-on-v4 no;
};
view myview {
filter-aaaa { any; };
plugin query "../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v4 no;
filter-aaaa { any; };
};
};

View file

@ -9,10 +9,9 @@
* information regarding copyright ownership.
*/
options {
filter-aaaa { any; };
};
view myview {
filter-aaaa-on-v4 no;
plugin query "../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v4 yes;
filter-aaaa { none; };
};
};

View file

@ -9,10 +9,11 @@
* information regarding copyright ownership.
*/
options {
filter-aaaa { none; };
plugin query "../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v4 yes;
filter-aaaa { 1.0.0.0/8; };
};
view myview {
filter-aaaa-on-v4 yes;
match-clients { any; };
};

View file

@ -1,18 +0,0 @@
/*
* 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.
*/
options {
filter-aaaa-on-v4 yes;
};
view myview {
filter-aaaa { none; };
};

View file

@ -9,6 +9,6 @@
* information regarding copyright ownership.
*/
options {
plugin query "../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v4 yes;
};

View file

@ -9,6 +9,6 @@
* information regarding copyright ownership.
*/
options {
plugin query "../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v4 break-dnssec;
};

View file

@ -9,7 +9,7 @@
* information regarding copyright ownership.
*/
options {
plugin query "../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v4 break-dnssec;
filter-aaaa { 1.0.0.0/8; };
};

View file

@ -9,7 +9,7 @@
* information regarding copyright ownership.
*/
options {
plugin query "../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v4 yes;
filter-aaaa { 1.0.0.0/8; };
};

View file

@ -9,10 +9,9 @@
* information regarding copyright ownership.
*/
options {
filter-aaaa-on-v4 yes;
};
view myview {
filter-aaaa { 1.0.0.0/8; };
plugin query "../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v4 yes;
filter-aaaa { 1.0.0.0/8; };
};
};

View file

@ -1,18 +0,0 @@
/*
* 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.
*/
options {
filter-aaaa { 1.0.0.0/8; };
};
view myview {
filter-aaaa-on-v4 yes;
};

View file

@ -1,18 +0,0 @@
/*
* 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.
*/
options {
};
view myview {
filter-aaaa { 1.0.0.0/8; };
filter-aaaa-on-v4 yes;
};

View file

@ -1,19 +0,0 @@
/*
* 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.
*/
options {
filter-aaaa-on-v4 no;
};
view myview {
filter-aaaa { 1.0.0.0/8; };
filter-aaaa-on-v4 yes;
};

View file

@ -20,11 +20,16 @@ options {
recursion no;
dnssec-validation yes;
notify yes;
filter-aaaa-on-v4 yes;
filter-aaaa { 10.53.0.1; };
minimal-responses no;
};
acl filterees { 10.53.0.1; };
plugin query "../../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v4 yes;
filter-aaaa { filterees; };
};
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;

View file

@ -20,9 +20,12 @@ options {
recursion no;
dnssec-validation yes;
notify yes;
minimal-responses no;
};
plugin query "../../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v6 yes;
filter-aaaa { fd92:7065:b8e:ffff::1; };
minimal-responses no;
};
key rndc_key {

View file

@ -21,10 +21,15 @@ infile=signed.db.in
zonefile=signed.db.signed
outfile=signed.db.signed
keyname1=`$KEYGEN -a $DEFAULT_ALGORITHM -b $DEFAULT_BITS -n zone $zone 2> /dev/null`
keyname2=`$KEYGEN -f KSK -a $DEFAULT_ALGORITHM -b $DEFAULT_BITS -n zone $zone 2> /dev/null`
$KEYGEN -a $DEFAULT_ALGORITHM $zone 2>&1 > /dev/null | cat_i
$KEYGEN -f KSK -a $DEFAULT_ALGORITHM $zone 2>&1 > keygen.out | cat_i
keyname=`cat keygen.out`
rm -f keygen.out
cat $infile $keyname1.key $keyname2.key >$zonefile
keyfile_to_trusted_keys $keyname > trusted.conf
cp trusted.conf ../ns2/trusted.conf
cp trusted.conf ../ns3/trusted.conf
cp trusted.conf ../ns5/trusted.conf
$SIGNER -o $zone -f $outfile $zonefile > /dev/null 2> signer.err || cat signer.err
echo_i "signed $zone"
$SIGNER -S -o $zone -f $outfile $infile > /dev/null 2> signer.err || cat signer.err
echo_i "signed zone '$zone'"

View file

@ -20,9 +20,12 @@ options {
recursion yes;
dnssec-validation yes;
notify yes;
minimal-responses no;
};
plugin query "../../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v4 yes;
filter-aaaa { 10.53.0.2; };
minimal-responses no;
};
key rndc_key {
@ -35,3 +38,5 @@ controls {
};
zone "." { type hint; file "hints"; };
include "trusted.conf";

View file

@ -20,9 +20,12 @@ options {
recursion yes;
dnssec-validation yes;
notify yes;
minimal-responses no;
};
plugin query "../../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v6 yes;
filter-aaaa { fd92:7065:b8e:ffff::2; };
minimal-responses no;
};
key rndc_key {
@ -35,3 +38,5 @@ controls {
};
zone "." { type hint; file "hints"; };
include "trusted.conf";

View file

@ -20,9 +20,12 @@ options {
recursion yes;
dnssec-validation yes;
notify yes;
minimal-responses no;
};
plugin query "../../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v4 break-dnssec;
filter-aaaa { 10.53.0.3; };
minimal-responses no;
};
key rndc_key {
@ -35,3 +38,5 @@ controls {
};
zone "." { type hint; file "hints"; };
include "trusted.conf";

View file

@ -20,9 +20,12 @@ options {
recursion yes;
dnssec-validation yes;
notify yes;
minimal-responses no;
};
plugin query "../../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v6 break-dnssec;
filter-aaaa { fd92:7065:b8e:ffff::3; };
minimal-responses no;
};
key rndc_key {
@ -35,3 +38,5 @@ controls {
};
zone "." { type hint; file "hints"; };
include "trusted.conf";

View file

@ -20,9 +20,12 @@ options {
recursion no;
dnssec-validation no;
notify yes;
minimal-responses no;
};
plugin query "../../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v4 break-dnssec;
filter-aaaa { 10.53.0.4; };
minimal-responses no;
};
key rndc_key {

View file

@ -20,9 +20,12 @@ options {
recursion no;
dnssec-validation no;
notify yes;
minimal-responses no;
};
plugin query "../../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v6 break-dnssec;
filter-aaaa { fd92:7065:b8e:ffff::4; };
minimal-responses no;
};
key rndc_key {

View file

@ -21,10 +21,8 @@ infile=signed.db.in
zonefile=signed.db.signed
outfile=signed.db.signed
keyname1=`$KEYGEN -a $DEFAULT_ALGORITHM -b $DEFAULT_BITS -n zone $zone 2> /dev/null`
keyname2=`$KEYGEN -f KSK -a $DEFAULT_ALGORITHM -b $DEFAULT_BITS -n zone $zone 2> /dev/null`
$KEYGEN -a $DEFAULT_ALGORITHM $zone 2>&1 > /dev/null | cat_i
$KEYGEN -f KSK -a $DEFAULT_ALGORITHM $zone 2>&1 > /dev/null | cat_i
cat $infile $keyname1.key $keyname2.key >$zonefile
$SIGNER -o $zone -f $outfile $zonefile > /dev/null 2> signer.err || cat signer.err
echo_i "signed $zone"
$SIGNER -S -o $zone -f $outfile $infile > /dev/null 2> signer.err || cat signer.err
echo_i "signed zone '$zone'"

View file

@ -25,9 +25,12 @@ options {
exclude { any; };
mapped { any; };
};
minimal-responses no;
};
plugin query "../../../../plugins/lib/filter-aaaa.so" {
filter-aaaa-on-v4 break-dnssec;
filter-aaaa { any; };
minimal-responses no;
};
key rndc_key {
@ -40,3 +43,5 @@ controls {
};
zone "." { type hint; file "hints"; };
include "trusted.conf";

View file

@ -0,0 +1,19 @@
#!/bin/sh
#
# 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.
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
$FEATURETEST --have-dlopen || {
echo_i "dlopen() not supported - skipping filter-aaaa test"
exit 255
}
exit 0

View file

@ -117,7 +117,6 @@ echo_i "checking that A and not AAAA is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS any dual.signed -b 10.53.0.1 @10.53.0.1 > dig.out.ns1.test$n || ret=1
grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1
grep "AUTHORITY: 0," dig.out.ns1.test$n > /dev/null || ret=1
grep "1.0.0.3" dig.out.ns1.test$n > /dev/null || ret=1
grep "::3" dig.out.ns1.test$n > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
@ -128,7 +127,6 @@ echo_i "checking that A and not AAAA is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS any dual.unsigned -b 10.53.0.1 @10.53.0.1 > dig.out.ns1.test$n || ret=1
grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1
grep "AUTHORITY: 0," dig.out.ns1.test$n > /dev/null || ret=1
grep "1.0.0.6" dig.out.ns1.test$n > /dev/null || ret=1
grep "::6" dig.out.ns1.test$n > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
@ -150,7 +148,6 @@ echo_i "checking that A and not AAAA is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS any dual.unsigned +dnssec -b 10.53.0.1 @10.53.0.1 > dig.out.ns1.test$n || ret=1
grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1
grep "AUTHORITY: 0," dig.out.ns1.test$n > /dev/null || ret=1
grep "1.0.0.6" dig.out.ns1.test$n > /dev/null || ret=1
grep "::6" dig.out.ns1.test$n > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
@ -222,7 +219,6 @@ else
echo_i "skipped."
fi
#
# Authoritative tests against:
# filter-aaaa-on-v4 break-dnssec;
@ -403,6 +399,7 @@ n=`expr $n + 1`
echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive ($n)"
ret=0
$DIG $DIGOPTS aaaa aaaa-only.signed -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
grep ::2 dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -420,6 +417,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.signed -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -429,6 +427,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -437,6 +436,7 @@ n=`expr $n + 1`
echo_i "checking that AAAA is returned when both AAAA and A records exist, signed and DO set, recursive ($n)"
ret=0
$DIG $DIGOPTS aaaa dual.signed +dnssec -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
grep ::3 dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -446,6 +446,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned +dnssec -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -484,6 +485,7 @@ echo_i "checking that both A and AAAA are returned when both AAAA and A records
ret=0
$DIG $DIGOPTS any dual.signed +dnssec -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
grep ::3 dig.out.ns2.test$n > /dev/null || ret=1
grep "1.0.0.3" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
@ -532,7 +534,7 @@ if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking that AAAA is omitted from additional section, qtype=MX, unsigned ($n)"
echo_i "checking that AAAA is omitted from additional section, qtype=MX, unsigned, recursive ($n)"
ret=0
$DIG $DIGOPTS +add +dnssec mx unsigned -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "^mx.unsigned.*AAAA" dig.out.ns2.test$n > /dev/null 2>&1 && ret=1
@ -540,15 +542,21 @@ if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking that AAAA is included in additional section, qtype=MX, signed ($n)"
echo_i "checking that AAAA is included in additional section, qtype=MX, signed, recursive ($n)"
ret=0
# we need to prime the cache with addresses for the MX, since additional
# section data won't be included unless it's validated, and that doesn't
# necessarily happen otherwise.
$DIG $DIGOPTS +dnssec mx.signed @10.53.0.2 > /dev/null
$DIG $DIGOPTS +dnssec mx.signed aaaa @10.53.0.2 > /dev/null
$DIG $DIGOPTS +add +dnssec mx signed -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1
grep "^mx.signed.*AAAA" dig.out.ns2.test$n > /dev/null 2>&1 || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "checking that AAAA is included in additional section, qtype=MX, unsigned, over IPv6 ($n)"
echo_i "checking that AAAA is included in additional section, qtype=MX, unsigned, recursive, over IPv6 ($n)"
if $TESTSOCK6 fd92:7065:b8e:ffff::2
then
ret=0
@ -560,7 +568,6 @@ else
echo_i "skipped."
fi
#
# Recursive tests against:
# filter-aaaa-on-v4 break-dnssec;
@ -570,6 +577,7 @@ n=`expr $n + 1`
echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive with break-dnssec ($n)"
ret=0
$DIG $DIGOPTS aaaa aaaa-only.signed -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null || ret=1
grep ::2 dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -587,6 +595,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.signed -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -596,6 +605,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -605,6 +615,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.signed +dnssec -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -613,6 +624,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned +dnssec -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -711,6 +723,7 @@ echo_i "checking that AAAA is omitted from additional section, qtype=MX, signed,
ret=0
$DIG $DIGOPTS +add +dnssec mx signed -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1
grep "^mx.signed.*AAAA" dig.out.ns3.test$n > /dev/null 2>&1 && ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1070,6 +1083,7 @@ n=`expr $n + 1`
echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive ($n)"
ret=0
$DIG $DIGOPTS aaaa aaaa-only.signed -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
grep ::2 dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1087,6 +1101,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.signed -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1096,6 +1111,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1104,6 +1120,7 @@ n=`expr $n + 1`
echo_i "checking that AAAA is returned when both AAAA and A records exist, signed and DO set, recursive ($n)"
ret=0
$DIG $DIGOPTS aaaa dual.signed +dnssec -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
grep ::3 dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1113,6 +1130,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned +dnssec -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1151,6 +1169,7 @@ echo_i "checking that both A and AAAA are returned when both AAAA and A records
ret=0
$DIG $DIGOPTS any dual.signed +dnssec -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
grep ::3 dig.out.ns2.test$n > /dev/null || ret=1
grep "1.0.0.3" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
@ -1206,6 +1225,7 @@ echo_i "checking that AAAA is included in additional section, qtype=MX, signed (
ret=0
$DIG $DIGOPTS +add +dnssec mx signed -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
grep "^mx.signed.*AAAA" dig.out.ns2.test$n > /dev/null 2>&1 || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1227,6 +1247,7 @@ n=`expr $n + 1`
echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive with break-dnssec ($n)"
ret=0
$DIG $DIGOPTS aaaa aaaa-only.signed -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null || ret=1
grep ::2 dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1244,6 +1265,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.signed -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1253,6 +1275,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1262,6 +1285,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.signed +dnssec -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1270,6 +1294,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex
ret=0
$DIG $DIGOPTS aaaa dual.unsigned +dnssec -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1
grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1
grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
@ -1362,6 +1387,7 @@ n=`expr $n + 1`
echo_i "checking that AAAA is omitted from additional section, qtype=MX, signed, recursive with break-dnssec ($n)"
ret=0
$DIG $DIGOPTS +add +dnssec mx signed -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1
grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null || ret=1
grep "^mx.signed.*AAAA" dig.out.ns3.test$n > /dev/null 2>&1 && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`

7
configure vendored
View file

@ -11916,7 +11916,7 @@ fi
XTARGETS=
case "$enable_developer" in
yes)
STD_CDEFINES="$STD_CDEFINES -DISC_MEM_DEFAULTFILL=1 -DISC_LIST_CHECKINIT=1 -DNS_HOOKS_ENABLE=1"
STD_CDEFINES="$STD_CDEFINES -DISC_MEM_DEFAULTFILL=1 -DISC_LIST_CHECKINIT=1"
test "${enable_fixed_rrset+set}" = set || enable_fixed_rrset=yes
test "${enable_querytrace+set}" = set || enable_querytrace=yes
test "${with_cmocka+set}" = set || with_cmocka=yes
@ -20240,8 +20240,8 @@ if test "$with_dlopen" = "yes"; then :
case $host in #(
*-linux*|*-gnu*) :
LDFLAGS="${LDFLAGS} -Wl,--export-dynamic"
SO_CFLAGS="-fPIC"
LDFLAGS="${LDFLAGS} -Wl,--export-dynamic"
SO_LDFLAGS=""
if test "$use_libtool" = "yes"; then :
@ -21548,7 +21548,7 @@ ac_config_commands="$ac_config_commands chmod"
# elsewhere if there's a good reason for doing so.
#
ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/isc/Makefile bin/python/isc/utils.py bin/python/isc/tests/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/python/dnssec-keymgr.py bin/python/isc/__init__.py bin/python/isc/checkds.py bin/python/isc/coverage.py bin/python/isc/dnskey.py bin/python/isc/eventlist.py bin/python/isc/keydict.py bin/python/isc/keyevent.py bin/python/isc/keymgr.py bin/python/isc/keyseries.py bin/python/isc/keyzone.py bin/python/isc/policy.py bin/python/isc/rndc.py bin/python/isc/tests/dnskey_test.py bin/python/isc/tests/policy_test.py bin/rndc/Makefile bin/tests/Makefile bin/tests/headerdep_test.sh bin/tests/optional/Makefile bin/tests/pkcs11/Makefile bin/tests/pkcs11/benchmarks/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/dlzs.conf bin/tests/system/dyndb/Makefile bin/tests/system/dyndb/driver/Makefile bin/tests/system/pipelined/Makefile bin/tests/system/rndc/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/scripts/check-secure-delegation.pl contrib/scripts/zone-edit.sh doc/Makefile doc/arm/Makefile doc/arm/noteversion.xml doc/arm/pkgversion.xml doc/arm/releaseinfo.xml doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/tex/Makefile doc/tex/armstyle.sty doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-manpage.xsl doc/xsl/isc-notes-html.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/irs/tests/Makefile lib/isc/pthreads/Makefile lib/isc/pthreads/include/Makefile lib/isc/pthreads/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/include/pk11/Makefile lib/isc/include/pkcs11/Makefile lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isc/unix/include/pkcs11/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccc/tests/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/isccfg/tests/Makefile lib/ns/Makefile lib/ns/include/Makefile lib/ns/include/ns/Makefile lib/ns/tests/Makefile lib/samples/Makefile lib/samples/Makefile-postinstall unit/unittest.sh fuzz/Makefile"
ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/plugins/Makefile bin/python/Makefile bin/python/isc/Makefile bin/python/isc/utils.py bin/python/isc/tests/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/python/dnssec-keymgr.py bin/python/isc/__init__.py bin/python/isc/checkds.py bin/python/isc/coverage.py bin/python/isc/dnskey.py bin/python/isc/eventlist.py bin/python/isc/keydict.py bin/python/isc/keyevent.py bin/python/isc/keymgr.py bin/python/isc/keyseries.py bin/python/isc/keyzone.py bin/python/isc/policy.py bin/python/isc/rndc.py bin/python/isc/tests/dnskey_test.py bin/python/isc/tests/policy_test.py bin/rndc/Makefile bin/tests/Makefile bin/tests/headerdep_test.sh bin/tests/optional/Makefile bin/tests/pkcs11/Makefile bin/tests/pkcs11/benchmarks/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/dlzs.conf bin/tests/system/dyndb/Makefile bin/tests/system/dyndb/driver/Makefile bin/tests/system/pipelined/Makefile bin/tests/system/rndc/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/scripts/check-secure-delegation.pl contrib/scripts/zone-edit.sh doc/Makefile doc/arm/Makefile doc/arm/noteversion.xml doc/arm/pkgversion.xml doc/arm/releaseinfo.xml doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/tex/Makefile doc/tex/armstyle.sty doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-manpage.xsl doc/xsl/isc-notes-html.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/irs/tests/Makefile lib/isc/pthreads/Makefile lib/isc/pthreads/include/Makefile lib/isc/pthreads/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/include/pk11/Makefile lib/isc/include/pkcs11/Makefile lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isc/unix/include/pkcs11/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccc/tests/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/isccfg/tests/Makefile lib/ns/Makefile lib/ns/include/Makefile lib/ns/include/ns/Makefile lib/ns/tests/Makefile lib/samples/Makefile lib/samples/Makefile-postinstall unit/unittest.sh fuzz/Makefile"
#
@ -22562,6 +22562,7 @@ do
"bin/named/unix/Makefile") CONFIG_FILES="$CONFIG_FILES bin/named/unix/Makefile" ;;
"bin/nsupdate/Makefile") CONFIG_FILES="$CONFIG_FILES bin/nsupdate/Makefile" ;;
"bin/pkcs11/Makefile") CONFIG_FILES="$CONFIG_FILES bin/pkcs11/Makefile" ;;
"bin/plugins/Makefile") CONFIG_FILES="$CONFIG_FILES bin/plugins/Makefile" ;;
"bin/python/Makefile") CONFIG_FILES="$CONFIG_FILES bin/python/Makefile" ;;
"bin/python/isc/Makefile") CONFIG_FILES="$CONFIG_FILES bin/python/isc/Makefile" ;;
"bin/python/isc/utils.py") CONFIG_FILES="$CONFIG_FILES bin/python/isc/utils.py" ;;

View file

@ -76,7 +76,7 @@ AC_ARG_ENABLE(developer,
XTARGETS=
case "$enable_developer" in
yes)
STD_CDEFINES="$STD_CDEFINES -DISC_MEM_DEFAULTFILL=1 -DISC_LIST_CHECKINIT=1 -DNS_HOOKS_ENABLE=1"
STD_CDEFINES="$STD_CDEFINES -DISC_MEM_DEFAULTFILL=1 -DISC_LIST_CHECKINIT=1"
test "${enable_fixed_rrset+set}" = set || enable_fixed_rrset=yes
test "${enable_querytrace+set}" = set || enable_querytrace=yes
test "${with_cmocka+set}" = set || with_cmocka=yes
@ -2638,8 +2638,8 @@ AS_CASE([$with_dlopen],
AS_IF([test "$with_dlopen" = "yes"],
[AS_CASE([$host],
[*-linux*|*-gnu*],[
LDFLAGS="${LDFLAGS} -Wl,--export-dynamic"
SO_CFLAGS="-fPIC"
LDFLAGS="${LDFLAGS} -Wl,--export-dynamic"
SO_LDFLAGS=""
AS_IF([test "$use_libtool" = "yes"],[
SO_LDFLAGS="-Xcompiler -shared"
@ -2961,6 +2961,7 @@ AC_CONFIG_FILES([
bin/named/unix/Makefile
bin/nsupdate/Makefile
bin/pkcs11/Makefile
bin/plugins/Makefile
bin/python/Makefile
bin/python/isc/Makefile
bin/python/isc/utils.py

View file

@ -1325,6 +1325,9 @@ controls {
</informaltable>
</section>
</section>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="plugins.xml"/>
</chapter>
<chapter xml:id="Bv9ARM.ch04"><info><title>Advanced DNS Features</title></info>
@ -6432,69 +6435,6 @@ options {
</listitem>
</varlistentry>
<varlistentry>
<term><command>filter-aaaa-on-v4</command></term>
<listitem>
<para>
This option is intended to help the
transition from IPv4 to IPv6 by not giving IPv6 addresses
to DNS clients unless they have connections to the IPv6
Internet. This is not recommended unless absolutely
necessary. The default is <userinput>no</userinput>.
The <command>filter-aaaa-on-v4</command> option
may also be specified in <command>view</command> statements
to override the global <command>filter-aaaa-on-v4</command>
option.
</para>
<para>
If <userinput>yes</userinput>,
the DNS client is at an IPv4 address, in <command>filter-aaaa</command>,
and if the response does not include DNSSEC signatures,
then all AAAA records are deleted from the response.
This filtering applies to all responses and not only
authoritative responses.
</para>
<para>
If <userinput>break-dnssec</userinput>,
then AAAA records are deleted even when DNSSEC is enabled.
As suggested by the name, this makes the response not verify,
because the DNSSEC protocol is designed detect deletions.
</para>
<para>
This mechanism can erroneously cause other servers to
not give AAAA records to their clients.
A recursing server with both IPv6 and IPv4 network connections
that queries an authoritative server using this mechanism
via IPv4 will be denied AAAA records even if its client is
using IPv6.
</para>
<para>
This mechanism is applied to authoritative as well as
non-authoritative records.
A client using IPv4 that is not allowed recursion can
erroneously be given AAAA records because the server is not
allowed to check for A records.
</para>
<para>
Some AAAA records are given to IPv4 clients in glue records.
IPv4 clients that are servers can then erroneously
answer requests for AAAA records received via IPv4.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>filter-aaaa-on-v6</command></term>
<listitem>
<para>
Identical to <command>filter-aaaa-on-v4</command>,
except it filters AAAA responses to queries from IPv6
clients instead of IPv4 clients. To filter all
responses, set both options to <userinput>yes</userinput>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>ixfr-from-differences</command></term>
<listitem>
@ -7347,18 +7287,6 @@ options {
</listitem>
</varlistentry>
<varlistentry>
<term><command>filter-aaaa</command></term>
<listitem>
<para>
Specifies a list of addresses to which
<command>filter-aaaa-on-v4</command>
and <command>filter-aaaa-on-v6</command>
apply. The default is <userinput>any</userinput>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>keep-response-order</command></term>
<listitem>
@ -18351,6 +18279,7 @@ allow-query { !{ !10/8; any; }; key example; };
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../../bin/dnssec/dnssec-signzone.docbook"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../../bin/dnssec/dnssec-verify.docbook"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../../bin/tools/dnstap-read.docbook"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../../bin/plugins/filter-aaaa.docbook"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../../bin/dig/host.docbook"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../../bin/tools/mdig.docbook"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../../bin/check/named-checkconf.docbook"/>

View file

@ -0,0 +1,153 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!--
- Copyright (C) 2000-2018 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/.
-->
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>filter-aaaa.so</title>
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="Bv9ARM.html" title="BIND 9 Administrator Reference Manual">
<link rel="up" href="Bv9ARM.ch12.html" title="Manual pages">
<link rel="prev" href="man.dnstap-read.html" title="dnstap-read">
<link rel="next" href="man.host.html" title="host">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr><th colspan="3" align="center"><span class="application">filter-aaaa.so</span></th></tr>
<tr>
<td width="20%" align="left">
<a accesskey="p" href="man.dnstap-read.html">Prev</a> </td>
<th width="60%" align="center">Manual pages</th>
<td width="20%" align="right"> <a accesskey="n" href="man.host.html">Next</a>
</td>
</tr>
</table>
<hr>
</div>
<div class="refentry">
<a name="man.filter-aaaa"></a><div class="titlepage"></div>
<div class="refnamediv">
<h2>Name</h2>
<p><span class="application">filter-aaaa.so</span> &#8212; filter AAAA in DNS responses when A is present</p>
</div>
<div class="refsynopsisdiv">
<h2>Synopsis</h2>
<div class="cmdsynopsis"><p><code class="command">hook query "filter-aaaa.so"</code> [<em class="replaceable"><code>{ parameters }</code></em>];
</p></div>
</div>
<div class="refsection">
<a name="id-1.13.19.7"></a><h2>DESCRIPTION</h2>
<p>
<span class="command"><strong>filter-aaaa.so</strong></span> is a query hook module for
<span class="command"><strong>named</strong></span>, enabling <span class="command"><strong>named</strong></span>
to omit some IPv6 addresses when responding to clients.
</p>
<p>
Until BIND 9.12, this feature was impleented natively in
<span class="command"><strong>named</strong></span> and enabled with the
<span class="command"><strong>filter-aaaa</strong></span> ACL and the
<span class="command"><strong>filter-aaaa-on-v4</strong></span> and
<span class="command"><strong>filter-aaaa-on-v6</strong></span> options. These options are
now deprecated in <code class="filename">named.conf</code>, but can be
passed as parameters to the <span class="command"><strong>filter-aaaa.so</strong></span>
hook module, for example:
</p>
<pre class="programlisting">
hook query "/usr/local/lib/filter-aaaa.so" {
filter-aaaa-on-v4 yes;
filter-aaaa-on-v6 yes;
filter-aaaa { 192.0.2.1; 2001:db8:2::1; };
};
</pre>
<p>
This module is intended to aid transition from IPv4 to IPv6 by
withholding IPv6 addresses from DNS clients which are not connected
to the IPv6 Internet, when the name being looked up has an IPv4
address available. Use of this module is not recommended unless
absolutely necessary.
</p>
<p>
Note: This mechanism can erroneously cause other servers not to
give AAAA records to their clients. If a recursing server with
both IPv6 and IPv4 network connections queries an authoritative
server using this mechanism via IPv4, it will be denied AAAA
records even if its client is using IPv6.
</p>
</div>
<div class="refsection">
<a name="id-1.13.19.8"></a><h2>OPTIONS</h2>
<div class="variablelist"><dl class="variablelist">
<dt><span class="term"><span class="command"><strong>filter-aaaa</strong></span></span></dt>
<dd><p>
Specifies a list of client addresses for which AAAA
filtering is to be applied. The default is
<strong class="userinput"><code>any</code></strong>.
</p></dd>
<dt><span class="term"><span class="command"><strong>filter-aaaa-on-v4</strong></span></span></dt>
<dd>
<p>
If set to <strong class="userinput"><code>yes</code></strong>, the DNS client is
at an IPv4 address, in <span class="command"><strong>filter-aaaa</strong></span>,
and if the response does not include DNSSEC signatures,
then all AAAA records are deleted from the response.
This filtering applies to all responses and not only
authoritative responses.
</p>
<p>
If set to <strong class="userinput"><code>break-dnssec</code></strong>,
then AAAA records are deleted even when DNSSEC is
enabled. As suggested by the name, this causes the
response to fail to verify, because the DNSSEC protocol is
designed to detect deletions.
</p>
<p>
This mechanism can erroneously cause other servers not to
give AAAA records to their clients. A recursing server with
both IPv6 and IPv4 network connections that queries an
authoritative server using this mechanism via IPv4 will be
denied AAAA records even if its client is using IPv6.
</p>
</dd>
<dt><span class="term"><span class="command"><strong>filter-aaaa-on-v6</strong></span></span></dt>
<dd><p>
Identical to <span class="command"><strong>filter-aaaa-on-v4</strong></span>,
except it filters AAAA responses to queries from IPv6
clients instead of IPv4 clients. To filter all
responses, set both options to <strong class="userinput"><code>yes</code></strong>.
</p></dd>
</dl></div>
</div>
<div class="refsection">
<a name="id-1.13.19.9"></a><h2>SEE ALSO</h2>
<p>
<em class="citetitle">BIND 9 Administrator Reference Manual</em>.
</p>
</div>
</div>
<div class="navfooter">
<hr>
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left">
<a accesskey="p" href="man.dnstap-read.html">Prev</a> </td>
<td width="20%" align="center"><a accesskey="u" href="Bv9ARM.ch12.html">Up</a></td>
<td width="40%" align="right"> <a accesskey="n" href="man.host.html">Next</a>
</td>
</tr>
<tr>
<td width="40%" align="left" valign="top">
<span class="application">dnstap-read</span> </td>
<td width="20%" align="center"><a accesskey="h" href="Bv9ARM.html">Home</a></td>
<td width="40%" align="right" valign="top"> host</td>
</tr>
</table>
</div>
<p xmlns:db="http://docbook.org/ns/docbook" style="text-align: center;">BIND 9.13.2 (Development Release)</p>
</body>
</html>

View file

@ -153,6 +153,19 @@
as described in RFC 7706. [GL #33]
</para>
</listitem>
<listitem>
<para>
A new <command>plugin</command> mechanism has been added to allow
extension of query processing functionality through the use of
external libraries. The new <filename>filter-aaaa.so</filename>
plugin replaces the <command>filter-aaaa</command> feature that
was formerly implemented as a native part of BIND.
</para>
<para>
The plugin API is a work in progress and is likely to evolve
as further plugins are implemented. [GL #15]
</para>
</listitem>
<listitem>
<para>
BIND now can be compiled against the <command>libidn2</command>
@ -289,6 +302,18 @@
the operating system, and it cannot be built without threads.
</para>
</listitem>
<listitem>
<para>
The <command>filter-aaaa</command>,
<command>filter-aaaa-on-v4</command>, and
<command>filter-aaaa-on-v6</command> options have been removed
from <command>named</command>, and can no longer be
configured using native <filename>named.conf</filename> syntax.
However, loading the new <filename>filter-aaaa.so</filename>
plugin and setting its parameters provides identical
functionality.
</para>
</listitem>
<listitem>
<para>
<command>named</command> can no longer use the EDNS CLIENT-SUBNET

95
doc/arm/plugins.xml Normal file
View file

@ -0,0 +1,95 @@
<!--
- 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.
-->
<!-- Converted by db4-upgrade version 1.0 -->
<section xmlns:db="http://docbook.org/ns/docbook" version="5.0" xml:id="module-info"><info><title>Plugins</title></info>
<para>
Plugins are a mechanism to extend the functionality of
<command>named</command> using dynamically loadable libraries.
By using plugins, core server functionality can be kept simple
for the majority of users; more complex code implementing optional
features need only be installed by users that need those features.
</para>
<para>
The plugin interface is a work in progress, and is expected to evolve
as more plugins are added. Currently, only "query plugins" are supported;
these modify the name server query logic. Other plugin types may be added
in the future.
</para>
<para>
The only plugin currently included in BIND is
<filename>filter-aaaa.so</filename>, which replaces the
<command>filter-aaaa</command> feature that previously existed natively
as part of <command>named</command>.
The code for this feature has been removed from <command>named</command>,
and can no longer be configured using standard
<filename>named.conf</filename> syntax, but linking in the
<filename>filter-aaaa.so</filename> plugin provides identical
functionality.
</para>
<section><info><title>Configuring Plugins</title></info>
<para>
A plugin is configured with the <command>plugin</command>
statement in <filename>named.conf</filename>:
</para>
<screen>
plugin query "library.so" {
<replaceable>parameters</replaceable>
};
</screen>
<para>
In this example, file <filename>library.so</filename> is the plugin
library. <literal>query</literal> indicates that this is a query
plugin.
<para>
</para>
Multiple <command>plugin</command> statements can be specified, to load
different plugins or multiple instances of the same plugin.
</para>
<para>
<replaceable>parameters</replaceable> are passed as an opaque
string to the plugin's initialization routine. Configuration
syntax will differ depending on the module.
</para>
</section>
<section><info><title>Developing Plugins</title></info>
<para>
Each plugin implements four functions:
<itemizedlist>
<listitem><command>plugin_register</command> to allocate memory,
configure a plugin instance, and attach to hook points within
<command>named</command>,</listitem>
<listitem><command>plugin_destroy</command> to tear down the plugin
instance and free memory,</listitem>
<listitem><command>plugin_version</command> to check that the plugin
is compatible with the current version of the plugin API,</listitem>
<listitem><command>plugin_check</command> to test syntactic
correctness of the plugin parameters.</listitem>
</itemizedlist>
</para>
<para>
At various locations within the <command>named</command> source code,
there are "hook points" at which a plugin may register itself.
When a hook point is reached while <command>named</command> is
running, it is checked to see whether any plugins have registered
themselves there; if so, the associated "hook action" is called -
this is a function within the plugin library. Hook actions may
examine the runtime state and make changes - for example, modifying
the answers to be sent back to a client or forcing a query to be
aborted. More details can be found in the file
<filename>lib/ns/include/ns/hooks.h</filename>.
</para>
</section>
</section>

View file

@ -24,6 +24,9 @@ dlz <string> {
dyndb <string> <quoted_string> {
<unspecified-text> }; // may occur multiple times
hook ( query ) <string> [ { <unspecified-text> }
]; // may occur multiple times
key <string> {
algorithm <string>;
secret <string>;
@ -172,9 +175,9 @@ options {
fetches-per-server <integer> [ ( drop | fail ) ];
fetches-per-zone <integer> [ ( drop | fail ) ];
files ( default | unlimited | <sizeval> );
filter-aaaa { <address_match_element>; ... };
filter-aaaa-on-v4 ( break-dnssec | <boolean> );
filter-aaaa-on-v6 ( break-dnssec | <boolean> );
filter-aaaa { <address_match_element>; ... }; // obsolete
filter-aaaa-on-v4 <boolean>; // obsolete
filter-aaaa-on-v6 <boolean>; // obsolete
flush-zones-on-shutdown <boolean>;
forward ( first | only );
forwarders [ port <integer> ] [ dscp <integer> ] { ( <ipv4_address>
@ -533,13 +536,15 @@ view <string> [ <class> ] {
fetch-quota-params <integer> <fixedpoint> <fixedpoint> <fixedpoint>;
fetches-per-server <integer> [ ( drop | fail ) ];
fetches-per-zone <integer> [ ( drop | fail ) ];
filter-aaaa { <address_match_element>; ... };
filter-aaaa-on-v4 ( break-dnssec | <boolean> );
filter-aaaa-on-v6 ( break-dnssec | <boolean> );
filter-aaaa { <address_match_element>; ... }; // obsolete
filter-aaaa-on-v4 <boolean>; // obsolete
filter-aaaa-on-v6 <boolean>; // obsolete
forward ( first | only );
forwarders [ port <integer> ] [ dscp <integer> ] { ( <ipv4_address>
| <ipv6_address> ) [ port <integer> ] [ dscp <integer> ]; ... };
glue-cache <boolean>;
hook ( query ) <string> [ {
<unspecified-text> } ]; // may occur multiple times
inline-signing <boolean>;
ixfr-from-differences ( primary | master | secondary | slave |
<boolean> );

View file

@ -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

View file

@ -54,6 +54,8 @@
#include <isccfg/grammar.h>
#include <isccfg/namedconf.h>
#include <ns/hooks.h>
#include <bind9/check.h>
static unsigned char dlviscorg_ndata[] = "\003dlv\003isc\003org";
@ -471,7 +473,7 @@ check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
static const char *acls[] = { "allow-query", "allow-query-on",
"allow-query-cache", "allow-query-cache-on",
"blackhole", "keep-response-order", "match-clients",
"match-destinations", "sortlist", "filter-aaaa", NULL };
"match-destinations", "sortlist", NULL };
while (acls[i] != NULL) {
tresult = checkacl(acls[i++], actx, NULL, voptions, config,
@ -789,102 +791,6 @@ check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
return (result);
}
static isc_result_t
check_filteraaaa(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
const char *viewname, const cfg_obj_t *config,
isc_log_t *logctx, isc_mem_t *mctx)
{
const cfg_obj_t *options, *aclobj, *obj;
dns_acl_t *acl = NULL;
isc_result_t result = ISC_R_SUCCESS;
dns_aaaa_t filter4, filter6;
const char *forview = " for view ";
if (viewname == NULL) {
viewname = "";
forview = "";
}
aclobj = options = NULL;
acl = NULL;
if (voptions != NULL)
cfg_map_get(voptions, "filter-aaaa", &aclobj);
if (config != NULL && aclobj == NULL) {
options = NULL;
cfg_map_get(config, "options", &options);
if (options != NULL)
cfg_map_get(options, "filter-aaaa", &aclobj);
}
if (aclobj == NULL)
return (result);
result = cfg_acl_fromconfig(aclobj, config, logctx,
actx, mctx, 0, &acl);
if (result != ISC_R_SUCCESS)
goto failure;
obj = NULL;
if (voptions != NULL)
cfg_map_get(voptions, "filter-aaaa-on-v4", &obj);
if (obj == NULL && config != NULL) {
options = NULL;
cfg_map_get(config, "options", &options);
if (options != NULL)
cfg_map_get(options, "filter-aaaa-on-v4", &obj);
}
if (obj == NULL)
filter4 = dns_aaaa_ok; /* default */
else if (cfg_obj_isboolean(obj))
filter4 = cfg_obj_asboolean(obj) ? dns_aaaa_filter :
dns_aaaa_ok;
else
filter4 = dns_aaaa_break_dnssec; /* break-dnssec */
obj = NULL;
if (voptions != NULL)
cfg_map_get(voptions, "filter-aaaa-on-v6", &obj);
if (obj == NULL && config != NULL) {
options = NULL;
cfg_map_get(config, "options", &options);
if (options != NULL)
cfg_map_get(options, "filter-aaaa-on-v6", &obj);
}
if (obj == NULL)
filter6 = dns_aaaa_ok; /* default */
else if (cfg_obj_isboolean(obj))
filter6 = cfg_obj_asboolean(obj) ? dns_aaaa_filter :
dns_aaaa_ok;
else
filter6 = dns_aaaa_break_dnssec; /* break-dnssec */
if ((filter4 != dns_aaaa_ok || filter6 != dns_aaaa_ok) &&
dns_acl_isnone(acl))
{
cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
"\"filter-aaaa\" is 'none;' but "
"either filter-aaaa-on-v4 or filter-aaaa-on-v6 "
"is enabled%s%s", forview, viewname);
result = ISC_R_FAILURE;
} else if (filter4 == dns_aaaa_ok && filter6 == dns_aaaa_ok &&
!dns_acl_isnone(acl))
{
cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
"\"filter-aaaa\" is set but "
"neither filter-aaaa-on-v4 or filter-aaaa-on-v6 "
"is enabled%s%s", forview, viewname);
result = ISC_R_FAILURE;
}
failure:
if (acl != NULL)
dns_acl_detach(&acl);
return (result);
}
typedef struct {
const char *name;
unsigned int scale;
@ -3442,10 +3348,50 @@ check_rpz_catz(const char *rpz_catz, const cfg_obj_t *rpz_obj,
return (result);
}
#ifdef HAVE_DLOPEN
/*%
* Data structure used for the 'callback_data' argument to check_one_plugin().
*/
struct check_one_plugin_data {
isc_mem_t *mctx;
isc_log_t *lctx;
cfg_aclconfctx_t *actx;
isc_result_t *check_result;
};
/*%
* A callback for the cfg_pluginlist_foreach() call in check_viewconf() below.
* Since the point is to check configuration of all plugins even when
* processing some of them fails, always return ISC_R_SUCCESS and indicate any
* check failures through the 'check_result' variable passed in via the
* 'callback_data' structure.
*/
static isc_result_t
check_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj,
const char *plugin_path, const char *parameters,
void *callback_data)
{
struct check_one_plugin_data *data = callback_data;
isc_result_t result;
result = ns_plugin_check(plugin_path, parameters, config,
cfg_obj_file(obj), cfg_obj_line(obj),
data->mctx, data->lctx, data->actx);
if (result != ISC_R_SUCCESS) {
cfg_obj_log(obj, data->lctx, ISC_LOG_ERROR,
"%s: plugin check failed: %s",
plugin_path, isc_result_totext(result));
*data->check_result = result;
}
return (ISC_R_SUCCESS);
}
#endif
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 check_plugins, isc_symtab_t *inview,
isc_log_t *logctx, isc_mem_t *mctx)
{
const cfg_obj_t *zones = NULL;
@ -3461,6 +3407,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 *plugin_list = NULL;
bool enablednssec, enablevalidation;
const char *valstr = "no";
unsigned int tflags, mflags;
@ -3750,11 +3697,6 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
if (tresult != ISC_R_SUCCESS)
result = tresult;
tresult = check_filteraaaa(actx, voptions, viewname, config,
logctx, mctx);
if (tresult != ISC_R_SUCCESS)
result = tresult;
tresult = check_dns64(actx, voptions, config, logctx, mctx);
if (tresult != ISC_R_SUCCESS)
result = tresult;
@ -3763,6 +3705,35 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
if (tresult != ISC_R_SUCCESS)
result = tresult;
/*
* Load plugins.
*/
if (check_plugins) {
if (voptions != NULL) {
(void)cfg_map_get(voptions, "plugin", &plugin_list);
} else {
(void)cfg_map_get(config, "plugin", &plugin_list);
}
}
#ifdef HAVE_DLOPEN
{
struct check_one_plugin_data check_one_plugin_data = {
.mctx = mctx,
.lctx = logctx,
.actx = actx,
.check_result = &tresult,
};
(void)cfg_pluginlist_foreach(config, plugin_list, logctx,
check_one_plugin,
&check_one_plugin_data);
if (tresult != ISC_R_SUCCESS) {
result = tresult;
}
}
#endif /* HAVE_DLOPEN */
cleanup:
if (symtab != NULL)
isc_symtab_destroy(&symtab);
@ -4017,8 +3988,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 check_plugins,
isc_log_t *logctx, isc_mem_t *mctx)
{
const cfg_obj_t *options = NULL;
const cfg_obj_t *views = NULL;
@ -4074,13 +4045,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,
check_plugins, 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 *plugins = NULL;
(void)cfg_map_get(config, "zone", &zones);
if (zones != NULL) {
@ -4089,6 +4062,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, "plugin", &plugins);
if (plugins != NULL) {
cfg_obj_log(plugins, logctx, ISC_LOG_ERROR,
"when using 'view' statements, "
"all plugins must be defined in views");
result = ISC_R_FAILURE;
}
}
tresult = isc_symtab_create(mctx, 100, NULL, NULL, true, &symtab);
@ -4152,8 +4133,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, check_plugins,
inview, logctx, mctx);
if (tresult != ISC_R_SUCCESS)
result = ISC_R_FAILURE;
}

View file

@ -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_plugins,
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_plugins' is true, load plugins and check the validity of their
* parameters as well.
*
* Requires:
*\li config is a valid parse tree
*

View file

@ -2589,7 +2589,7 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
result = isc_taskmgr_excltask(adb->taskmgr, &adb->excl);
if (result != ISC_R_SUCCESS) {
DP(DEF_LEVEL, "adb: task-exclusive mode unavailable, "
"intializing table sizes to %u\n",
"initializing table sizes to %u\n",
nbuckets[11]);
adb->nentries = nbuckets[11];
adb->nnames = nbuckets[11];

View file

@ -190,7 +190,8 @@ cleanup:
"driver '%s': %s (%s)", instname, filename,
dlerror(), isc_result_totext(result));
if (imp != NULL)
isc_mem_putanddetach(&imp->mctx, imp, sizeof(dyndb_implementation_t));
isc_mem_putanddetach(&imp->mctx, imp,
sizeof(dyndb_implementation_t));
if (result != ISC_R_SUCCESS && handle != NULL)
dlclose(handle);
@ -305,7 +306,8 @@ cleanup:
"driver '%s': %d (%s)", instname, filename,
GetLastError(), isc_result_totext(result));
if (imp != NULL)
isc_mem_putanddetach(&imp->mctx, imp, sizeof(dyndb_implementation_t));
isc_mem_putanddetach(&imp->mctx, imp,
sizeof(dyndb_implementation_t));
if (result != ISC_R_SUCCESS && handle != NULL)
FreeLibrary(handle);

View file

@ -1142,7 +1142,7 @@ dns_db_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
*
* \li 'sigrdataset' is a valid, disassociated rdataset, or it is NULL.
*
* \li If 'covers' != 0, 'type' must be SIG.
* \li If 'covers' != 0, 'type' must be RRSIG.
*
* \li 'type' is not a meta-RR type such as 'ANY' or 'OPT'.
*

View file

@ -22,7 +22,7 @@ ISC_LANG_BEGINDECLS
/*!
* \brief
* Context for intializing a dyndb module.
* Context for initializing a dyndb module.
*
* This structure passes global server data to which a dyndb
* module will need access -- the server memory context, hash
@ -40,7 +40,7 @@ struct dns_dyndbctx {
dns_zonemgr_t *zmgr;
isc_task_t *task;
isc_timermgr_t *timermgr;
bool *refvar;
bool *refvar;
};
#define DNS_DYNDBCTX_MAGIC ISC_MAGIC('D', 'd', 'b', 'c')
@ -71,7 +71,7 @@ typedef isc_result_t dns_dyndb_register_t(isc_mem_t *mctx,
* 'parameters' contains the driver configuration text. 'dctx' is the
* initialization context set up in dns_dyndb_createctx().
*
* '*instp' must be set to the driver instance handle if the functino
* '*instp' will be set to the driver instance handle if the function
* is successful.
*
* Returns:

View file

@ -181,7 +181,7 @@ typedef int dns_messagetextflag_t;
additional section. */
#define DNS_MESSAGERENDER_PREFER_AAAA 0x0010 /*%< prefer AAAA records in
additional section. */
#define DNS_MESSAGERENDER_FILTER_AAAA 0x0020 /*%< filter AAAA records */
/* Obsolete: DNS_MESSAGERENDER_FILTER_AAAA 0x0020 */
typedef struct dns_msgblock dns_msgblock_t;

View file

@ -92,7 +92,6 @@ typedef struct dns_rdatasetmethods {
dns_name_t *name);
isc_result_t (*addglue)(dns_rdataset_t *rdataset,
dns_dbversion_t *version,
unsigned int options,
dns_message_t *msg);
} dns_rdatasetmethods_t;
@ -197,13 +196,6 @@ struct dns_rdataset {
*/
#define DNS_RDATASETTOWIRE_OMITDNSSEC 0x0001
/*%
* _FILTERAAAA
* If A records are present, omit AAAA records when adding
* glue
*/
#define DNS_RDATASETADDGLUE_FILTERAAAA 0x0001
void
dns_rdataset_init(dns_rdataset_t *rdataset);
/*%<
@ -580,14 +572,11 @@ dns_rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name);
*/
isc_result_t
dns_rdataset_addglue(dns_rdataset_t *rdataset,
dns_dbversion_t *version,
unsigned int options,
dns_rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version,
dns_message_t *msg);
/*%<
* Add glue records for rdataset to the additional section of message in
* 'msg'. 'rdataset' must be of type NS. If DNS_RDATASETADDGLUE_FILTERAAAA
* is set in 'options' there is type A glue, type AAAA glue is not added.
* 'msg'. 'rdataset' must be of type NS.
*
* In case a successful result is not returned, the caller should try to
* add glue directly to the message by iterating for additional data.
@ -595,7 +584,6 @@ dns_rdataset_addglue(dns_rdataset_t *rdataset,
* Requires:
* \li 'rdataset' is a valid NS rdataset.
* \li 'version' is the DB version.
* \li 'options' is options; currently only _FILTERAAAA is defined.
* \li 'msg' is the DNS message to which the glue should be added.
*
* Returns:

View file

@ -216,12 +216,6 @@ typedef enum {
dns_masterformat_map = 3
} dns_masterformat_t;
typedef enum {
dns_aaaa_ok = 0,
dns_aaaa_filter = 1,
dns_aaaa_break_dnssec = 2
} dns_aaaa_t;
/*
* These are generated by gen.c.
*/

View file

@ -179,9 +179,6 @@ struct dns_view {
uint16_t padding;
dns_acl_t * pad_acl;
unsigned int maxbits;
dns_aaaa_t v4_aaaa;
dns_aaaa_t v6_aaaa;
dns_acl_t * aaaa_acl;
dns_dns64list_t dns64;
unsigned int dns64cnt;
dns_rpz_zones_t *rpzs;
@ -238,6 +235,15 @@ struct dns_view {
dns_dtenv_t *dtenv; /* Dnstap environment */
dns_dtmsgtype_t dttypes; /* Dnstap message types
to log */
/* Registered module instances */
void *plugins;
void (*plugins_free)(isc_mem_t *, void **);
/* Hook table */
void *hooktable; /* ns_hooktable */
void (*hooktable_free)(isc_mem_t *, void **);
};
#define DNS_VIEW_MAGIC ISC_MAGIC('V','i','e','w')

View file

@ -1903,48 +1903,6 @@ wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
return (true);
}
/*
* Decide whether to not answer with an AAAA record and its RRSIG
*/
static inline bool
norender_rdataset(const dns_rdataset_t *rdataset, unsigned int options,
dns_section_t sectionid)
{
if (sectionid == DNS_SECTION_QUESTION)
return (false);
switch (rdataset->type) {
case dns_rdatatype_ns:
if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
sectionid != DNS_SECTION_AUTHORITY)
return (false);
break;
case dns_rdatatype_aaaa:
if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0)
return (false);
break;
case dns_rdatatype_rrsig:
if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
(rdataset->covers != dns_rdatatype_ns &&
rdataset->covers != dns_rdatatype_aaaa))
return (false);
if ((rdataset->covers == dns_rdatatype_ns) &&
(sectionid != DNS_SECTION_AUTHORITY))
return (false);
break;
default:
return (false);
}
if (rdataset->rdclass != dns_rdataclass_in)
return (false);
return (true);
}
static isc_result_t
renderset(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
dns_compress_t *cctx, isc_buffer_t *target,
@ -2104,22 +2062,6 @@ dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
preferred_glue))
goto next;
/*
* Suppress AAAAs if asked and we are
* not doing DNSSEC or are breaking DNSSEC.
* Say so in the AD bit if we break DNSSEC.
*/
if (norender_rdataset(rdataset, options,
sectionid))
{
if (sectionid == DNS_SECTION_ANSWER ||
sectionid == DNS_SECTION_AUTHORITY)
msg->flags &= ~DNS_MESSAGEFLAG_AD;
if (OPTOUT(rdataset))
msg->flags &= ~DNS_MESSAGEFLAG_AD;
goto next;
}
st = *(msg->buffer);
count = 0;

View file

@ -561,7 +561,6 @@ static void rdataset_getownercase(const dns_rdataset_t *rdataset,
dns_name_t *name);
static isc_result_t rdataset_addglue(dns_rdataset_t *rdataset,
dns_dbversion_t *version,
unsigned int options,
dns_message_t *msg);
static void free_gluetable(rbtdb_version_t *version);
@ -9807,9 +9806,7 @@ out:
}
static isc_result_t
rdataset_addglue(dns_rdataset_t *rdataset,
dns_dbversion_t *version,
unsigned int options,
rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version,
dns_message_t *msg)
{
dns_rbtdb_t *rbtdb = rdataset->private1;
@ -9926,42 +9923,39 @@ restart:
}
}
if (ISC_LIKELY((options & DNS_RDATASETADDGLUE_FILTERAAAA) == 0))
{
if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) {
result = dns_message_gettemprdataset(msg,
&rdataset_aaaa);
if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
dns_message_puttempname(msg, &name);
if (rdataset_a != NULL) {
dns_message_puttemprdataset(msg,
&rdataset_a);
}
if (sigrdataset_a != NULL) {
dns_message_puttemprdataset(msg,
&sigrdataset_a);
}
goto no_glue;
if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) {
result = dns_message_gettemprdataset(msg,
&rdataset_aaaa);
if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
dns_message_puttempname(msg, &name);
if (rdataset_a != NULL) {
dns_message_puttemprdataset(msg,
&rdataset_a);
}
if (sigrdataset_a != NULL) {
dns_message_puttemprdataset(msg,
&sigrdataset_a);
}
goto no_glue;
}
}
if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) {
result = dns_message_gettemprdataset(msg,
&sigrdataset_aaaa);
if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
dns_message_puttempname(msg, &name);
if (rdataset_a != NULL) {
dns_message_puttemprdataset(msg,
&rdataset_a);
}
if (sigrdataset_a != NULL)
dns_message_puttemprdataset(msg,
&sigrdataset_a);
if (rdataset_aaaa != NULL)
dns_message_puttemprdataset(msg,
&rdataset_aaaa);
goto no_glue;
if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) {
result = dns_message_gettemprdataset(msg,
&sigrdataset_aaaa);
if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
dns_message_puttempname(msg, &name);
if (rdataset_a != NULL) {
dns_message_puttemprdataset(msg,
&rdataset_a);
}
if (sigrdataset_a != NULL)
dns_message_puttemprdataset(msg,
&sigrdataset_a);
if (rdataset_aaaa != NULL)
dns_message_puttemprdataset(msg,
&rdataset_aaaa);
goto no_glue;
}
}
@ -9975,20 +9969,17 @@ restart:
ISC_LIST_APPEND(name->list, sigrdataset_a, link);
}
if (ISC_LIKELY((options & DNS_RDATASETADDGLUE_FILTERAAAA) == 0))
{
if (rdataset_aaaa != NULL) {
dns_rdataset_clone(&ge->rdataset_aaaa,
rdataset_aaaa);
ISC_LIST_APPEND(name->list, rdataset_aaaa,
link);
}
if (sigrdataset_aaaa != NULL) {
dns_rdataset_clone(&ge->sigrdataset_aaaa,
sigrdataset_aaaa);
ISC_LIST_APPEND(name->list, sigrdataset_aaaa,
link);
}
if (rdataset_aaaa != NULL) {
dns_rdataset_clone(&ge->rdataset_aaaa,
rdataset_aaaa);
ISC_LIST_APPEND(name->list, rdataset_aaaa,
link);
}
if (sigrdataset_aaaa != NULL) {
dns_rdataset_clone(&ge->sigrdataset_aaaa,
sigrdataset_aaaa);
ISC_LIST_APPEND(name->list, sigrdataset_aaaa,
link);
}
dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL);

View file

@ -751,9 +751,7 @@ dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
}
isc_result_t
dns_rdataset_addglue(dns_rdataset_t *rdataset,
dns_dbversion_t *version,
unsigned int options,
dns_rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version,
dns_message_t *msg)
{
REQUIRE(DNS_RDATASET_VALID(rdataset));
@ -763,6 +761,5 @@ dns_rdataset_addglue(dns_rdataset_t *rdataset,
if (rdataset->methods->addglue == NULL)
return (ISC_R_NOTIMPLEMENTED);
return ((rdataset->methods->addglue)(rdataset, version,
options, msg));
return ((rdataset->methods->addglue)(rdataset, version, msg));
}

View file

@ -225,9 +225,6 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
view->padding = 0;
view->pad_acl = NULL;
view->maxbits = 0;
view->v4_aaaa = dns_aaaa_ok;
view->v6_aaaa = dns_aaaa_ok;
view->aaaa_acl = NULL;
view->rpzs = NULL;
view->catzs = NULL;
dns_fixedname_init(&view->dlv_fixed);
@ -259,6 +256,11 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
view->dtenv = NULL;
view->dttypes = 0;
view->plugins = NULL;
view->plugins_free = NULL;
view->hooktable = NULL;
view->hooktable_free = NULL;
isc_mutex_init(&view->new_zone_lock);
result = dns_order_create(view->mctx, &view->order);
@ -454,8 +456,6 @@ destroy(dns_view_t *view) {
dns_acl_detach(&view->upfwdacl);
if (view->denyansweracl != NULL)
dns_acl_detach(&view->denyansweracl);
if (view->aaaa_acl != NULL)
dns_acl_detach(&view->aaaa_acl);
if (view->pad_acl != NULL)
dns_acl_detach(&view->pad_acl);
if (view->answeracl_exclude != NULL)
@ -550,6 +550,12 @@ destroy(dns_view_t *view) {
isc_mutex_destroy(&view->lock);
isc_mem_free(view->mctx, view->nta_file);
isc_mem_free(view->mctx, view->name);
if (view->hooktable != NULL && view->hooktable_free != NULL) {
view->hooktable_free(view->mctx, &view->hooktable);
}
if (view->plugins != NULL && view->plugins_free != NULL) {
view->plugins_free(view->mctx, &view->plugins);
}
isc_mem_putanddetach(&view->mctx, view, sizeof(*view));
}

View file

@ -555,6 +555,47 @@ const char *
cfg_map_nextclause(const cfg_type_t *map, const void **clauses,
unsigned int *idx);
typedef isc_result_t
(pluginlist_cb_t)(const cfg_obj_t *config, const cfg_obj_t *obj,
const char *plugin_path, const char *parameters,
void *callback_data);
/*%<
* Function prototype for the callback used with cfg_pluginlist_foreach().
* Called once for each element of the list passed to cfg_pluginlist_foreach().
* If this callback returns anything else than #ISC_R_SUCCESS, no further list
* elements will be processed.
*
* \li 'config' - the 'config' object passed to cfg_pluginlist_foreach()
* \li 'obj' - object representing the specific "plugin" stanza to be processed
* \li 'plugin_path' - path to the shared object with plugin code
* \li 'parameters' - configuration text for the plugin
* \li 'callback_data' - the pointer passed to cfg_pluginlist_foreach()
*/
isc_result_t
cfg_pluginlist_foreach(const cfg_obj_t *config, const cfg_obj_t *list,
isc_log_t *lctx, pluginlist_cb_t callback,
void *callback_data);
/*%<
* For every "plugin" stanza present in 'list' (which in turn is a part of
* 'config'), invoke the given 'callback', passing 'callback_data' to it along
* with a fixed set of arguments (see the definition of the #pluginlist_cb_t
* type). Use logging context 'lctx' for logging error messages. Interrupt
* processing if 'callback' returns something else than #ISC_R_SUCCESS for any
* element of 'list'.
*
* Requires:
*
* \li 'config' is not NULL
* \li 'callback' is not NULL
*
* Returns:
*
* \li #ISC_R_SUCCESS if 'callback' returned #ISC_R_SUCCESS for all elements of
* 'list'
* \li first 'callback' return value which was not #ISC_R_SUCCESS otherwise
*/
ISC_LANG_ENDDECLS
#endif /* ISCCFG_CFG_H */

View file

@ -301,7 +301,10 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_qstring;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_astring;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_ustring;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sstring;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_bracketed_aml;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_bracketed_text;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_optional_bracketed_text;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_keyref;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sockaddr;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sockaddrdscp;
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr;
@ -432,6 +435,14 @@ cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
void
cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type);
isc_result_t
cfg_parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
const cfg_type_t *othertype, cfg_obj_t **ret);
void
cfg_doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *enumtype,
const cfg_type_t *othertype);
void
cfg_print_chars(cfg_printer_t *pctx, const char *text, int len);
/*%< Print 'len' characters at 'text' */

View file

@ -49,14 +49,6 @@
* Forward declarations of static functions.
*/
static isc_result_t
parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
const cfg_type_t *othertype, cfg_obj_t **ret);
static void
doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *enumtype,
const cfg_type_t *othertype);
static isc_result_t
parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
@ -94,8 +86,6 @@ doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type);
#endif /* HAVE_GEOIP */
static cfg_type_t cfg_type_acl;
static cfg_type_t cfg_type_addrmatchelt;
static cfg_type_t cfg_type_bracketed_aml;
static cfg_type_t cfg_type_bracketed_dscpsockaddrlist;
static cfg_type_t cfg_type_bracketed_namesockaddrkeylist;
static cfg_type_t cfg_type_bracketed_netaddrlist;
@ -108,7 +98,7 @@ static cfg_type_t cfg_type_dlz;
static cfg_type_t cfg_type_dnstap;
static cfg_type_t cfg_type_dnstapoutput;
static cfg_type_t cfg_type_dyndb;
static cfg_type_t cfg_type_filter_aaaa;
static cfg_type_t cfg_type_plugin;
static cfg_type_t cfg_type_ixfrdifftype;
static cfg_type_t cfg_type_key;
static cfg_type_t cfg_type_logfile;
@ -120,7 +110,6 @@ static cfg_type_t cfg_type_masterselement;
static cfg_type_t cfg_type_maxttl;
static cfg_type_t cfg_type_minimal;
static cfg_type_t cfg_type_nameportiplist;
static cfg_type_t cfg_type_negated;
static cfg_type_t cfg_type_notifytype;
static cfg_type_t cfg_type_optional_allow;
static cfg_type_t cfg_type_optional_class;
@ -606,11 +595,11 @@ static cfg_type_t cfg_type_updatemethod = {
static const char *zonestat_enums[] = { "full", "terse", "none", NULL };
static isc_result_t
parse_zonestat(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
}
static void
doc_zonestat(cfg_printer_t *pctx, const cfg_type_t *type) {
doc_enum_or_other(pctx, type, &cfg_type_boolean);
cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean);
}
static cfg_type_t cfg_type_zonestat = {
"zonestat", parse_zonestat, cfg_print_ustring, doc_zonestat,
@ -951,7 +940,7 @@ static isc_result_t
parse_optional_enum(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret)
{
return (parse_enum_or_other(pctx, type, &cfg_type_void, ret));
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_void, ret));
}
static void
@ -1007,6 +996,7 @@ namedconf_or_view_clauses[] = {
{ "dyndb", &cfg_type_dyndb, CFG_CLAUSEFLAG_MULTI },
{ "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
{ "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI },
{ "plugin", &cfg_type_plugin, CFG_CLAUSEFLAG_MULTI },
{ "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI },
{ "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
{ "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI },
@ -1907,9 +1897,9 @@ view_clauses[] = {
{ "fetch-quota-params", &cfg_type_fetchquota, 0 },
{ "fetches-per-server", &cfg_type_fetchesper, 0 },
{ "fetches-per-zone", &cfg_type_fetchesper, 0 },
{ "filter-aaaa", &cfg_type_bracketed_aml, 0 },
{ "filter-aaaa-on-v4", &cfg_type_filter_aaaa, 0 },
{ "filter-aaaa-on-v6", &cfg_type_filter_aaaa, 0 },
{ "filter-aaaa", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_OBSOLETE },
{ "filter-aaaa-on-v4", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
{ "filter-aaaa-on-v6", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
{ "glue-cache", &cfg_type_boolean, 0 },
{ "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 },
{ "lame-ttl", &cfg_type_ttlval, 0 },
@ -2394,6 +2384,29 @@ static cfg_type_t cfg_type_dyndb = {
&cfg_rep_tuple, dyndb_fields
};
/*%
* The "plugin" statement syntax.
* Currently only one plugin type is supported: query.
*/
static const char *plugin_enums[] = {
"query", NULL
};
static cfg_type_t cfg_type_plugintype = {
"plugintype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
&cfg_rep_string, plugin_enums
};
static cfg_tuplefielddef_t plugin_fields[] = {
{ "type", &cfg_type_plugintype, 0 },
{ "library", &cfg_type_astring, 0 },
{ "parameters", &cfg_type_optional_bracketed_text, 0 },
{ NULL, NULL, 0 }
};
static cfg_type_t cfg_type_plugin = {
"plugin", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
&cfg_rep_tuple, plugin_fields
};
/*%
* Clauses that can be found within the 'key' statement.
*/
@ -2470,11 +2483,11 @@ static const char *printtime_enums[] = {
};
static isc_result_t
parse_printtime(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
}
static void
doc_printtime(cfg_printer_t *pctx, const cfg_type_t *type) {
doc_enum_or_other(pctx, type, &cfg_type_boolean);
cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean);
}
static cfg_type_t cfg_type_printtime = {
"printtime", parse_printtime, cfg_print_ustring, doc_printtime,
@ -2690,12 +2703,12 @@ static cfg_type_t cfg_type_sizeval = {
static isc_result_t
parse_size(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
return (parse_enum_or_other(pctx, type, &cfg_type_sizeval, ret));
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_sizeval, ret));
}
static void
doc_size(cfg_printer_t *pctx, const cfg_type_t *type) {
doc_enum_or_other(pctx, type, &cfg_type_sizeval);
cfg_doc_enum_or_other(pctx, type, &cfg_type_sizeval);
}
static const char *size_enums[] = { "default", "unlimited", NULL };
@ -2729,13 +2742,18 @@ static isc_result_t
parse_size_or_percent(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret)
{
return (parse_enum_or_other(pctx, type, &cfg_type_sizeval_percent,
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_sizeval_percent,
ret));
}
static void
doc_parse_size_or_percent(cfg_printer_t *pctx, const cfg_type_t *type) {
doc_enum_or_other(pctx, type, &cfg_type_sizeval_percent);
UNUSED(type);
cfg_print_cstr(pctx, "( default | unlimited | ");
cfg_doc_terminal(pctx, &cfg_type_sizeval);
cfg_print_cstr(pctx, " | ");
cfg_doc_terminal(pctx, &cfg_type_percentage);
cfg_print_cstr(pctx, " )");
}
static const char *sizeorpercent_enums[] = { "default", "unlimited", NULL };
@ -2776,59 +2794,6 @@ parse_maybe_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
return (result);
}
static isc_result_t
parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
const cfg_type_t *othertype, cfg_obj_t **ret)
{
isc_result_t result;
CHECK(cfg_peektoken(pctx, 0));
if (pctx->token.type == isc_tokentype_string &&
cfg_is_enum(TOKEN_STRING(pctx), enumtype->of)) {
CHECK(cfg_parse_enum(pctx, enumtype, ret));
} else {
CHECK(cfg_parse_obj(pctx, othertype, ret));
}
cleanup:
return (result);
}
static void
doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *enumtype,
const cfg_type_t *othertype)
{
const char * const *p;
bool first = true;
/*
* If othertype is cfg_type_void, it means that enumtype is
* optional.
*/
if (othertype == &cfg_type_void)
cfg_print_cstr(pctx, "[ ");
cfg_print_cstr(pctx, "( ");
for (p = enumtype->of; *p != NULL; p++) {
if (!first)
cfg_print_cstr(pctx, " | ");
first = false;
cfg_print_cstr(pctx, *p);
}
if (othertype == &cfg_type_sizeval_percent) {
if (!first)
cfg_print_cstr(pctx, " | ");
cfg_doc_terminal(pctx, &cfg_type_sizeval);
cfg_print_cstr(pctx, " | ");
cfg_doc_terminal(pctx, &cfg_type_percentage);
} else if (othertype != &cfg_type_void) {
if (!first)
cfg_print_cstr(pctx, " | ");
cfg_doc_terminal(pctx, othertype);
}
cfg_print_cstr(pctx, " )");
if (othertype == &cfg_type_void)
cfg_print_cstr(pctx, " ]");
}
static isc_result_t
parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
return (parse_maybe_optional_keyvalue(pctx, type, false, ret));
@ -2874,11 +2839,11 @@ static isc_result_t
parse_dialup_type(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret)
{
return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
}
static void
doc_dialup_type(cfg_printer_t *pctx, const cfg_type_t *type) {
doc_enum_or_other(pctx, type, &cfg_type_boolean);
cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean);
}
static cfg_type_t cfg_type_dialuptype = {
"dialuptype", parse_dialup_type, cfg_print_ustring, doc_dialup_type,
@ -2890,11 +2855,11 @@ static isc_result_t
parse_notify_type(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret)
{
return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
}
static void
doc_notify_type(cfg_printer_t *pctx, const cfg_type_t *type) {
doc_enum_or_other(pctx, type, &cfg_type_boolean);
cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean);
}
static cfg_type_t cfg_type_notifytype = {
"notifytype", parse_notify_type, cfg_print_ustring, doc_notify_type,
@ -2904,11 +2869,11 @@ static cfg_type_t cfg_type_notifytype = {
static const char *minimal_enums[] = { "no-auth", "no-auth-recursive", NULL };
static isc_result_t
parse_minimal(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
}
static void
doc_minimal(cfg_printer_t *pctx, const cfg_type_t *type) {
doc_enum_or_other(pctx, type, &cfg_type_boolean);
cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean);
}
static cfg_type_t cfg_type_minimal = {
"mimimal", parse_minimal, cfg_print_ustring, doc_minimal,
@ -2922,32 +2887,17 @@ static isc_result_t
parse_ixfrdiff_type(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret)
{
return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
}
static void
doc_ixfrdiff_type(cfg_printer_t *pctx, const cfg_type_t *type) {
doc_enum_or_other(pctx, type, &cfg_type_boolean);
cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean);
}
static cfg_type_t cfg_type_ixfrdifftype = {
"ixfrdiff", parse_ixfrdiff_type, cfg_print_ustring, doc_ixfrdiff_type,
&cfg_rep_string, ixfrdiff_enums,
};
static const char *filter_aaaa_enums[] = { "break-dnssec", NULL };
static isc_result_t
parse_filter_aaaa(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret) {
return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
}
static void
doc_filter_aaaa(cfg_printer_t *pctx, const cfg_type_t *type) {
doc_enum_or_other(pctx, type, &cfg_type_boolean);
}
static cfg_type_t cfg_type_filter_aaaa = {
"filter_aaaa", parse_filter_aaaa, cfg_print_ustring,
doc_filter_aaaa, &cfg_rep_string, filter_aaaa_enums,
};
static keyword_type_t key_kw = { "key", &cfg_type_astring };
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = {
@ -3394,99 +3344,6 @@ static cfg_type_t cfg_type_querysource = {
"querysource", NULL, print_querysource, NULL, &cfg_rep_sockaddr, NULL
};
/*% addrmatchelt */
static isc_result_t
parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret)
{
isc_result_t result;
UNUSED(type);
CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
if (pctx->token.type == isc_tokentype_string ||
pctx->token.type == isc_tokentype_qstring) {
if (pctx->token.type == isc_tokentype_string &&
(strcasecmp(TOKEN_STRING(pctx), "key") == 0)) {
CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret));
} else if (pctx->token.type == isc_tokentype_string &&
(strcasecmp(TOKEN_STRING(pctx), "geoip") == 0)) {
#ifdef HAVE_GEOIP
CHECK(cfg_gettoken(pctx, 0));
CHECK(cfg_parse_obj(pctx, &cfg_type_geoip, ret));
#else
cfg_parser_error(pctx, CFG_LOG_NEAR, "'geoip' "
"not supported in this build");
return (ISC_R_UNEXPECTEDTOKEN);
#endif
} else {
if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK |
CFG_ADDR_V4PREFIXOK |
CFG_ADDR_V6OK))
{
CHECK(cfg_parse_netprefix(pctx, NULL, ret));
} else {
CHECK(cfg_parse_astring(pctx, NULL, ret));
}
}
} else if (pctx->token.type == isc_tokentype_special) {
if (pctx->token.value.as_char == '{') {
/* Nested match list. */
CHECK(cfg_parse_obj(pctx,
&cfg_type_bracketed_aml, ret));
} else if (pctx->token.value.as_char == '!') {
CHECK(cfg_gettoken(pctx, 0)); /* read "!" */
CHECK(cfg_parse_obj(pctx, &cfg_type_negated, ret));
} else {
goto bad;
}
} else {
bad:
cfg_parser_error(pctx, CFG_LOG_NEAR,
"expected IP match list element");
return (ISC_R_UNEXPECTEDTOKEN);
}
cleanup:
return (result);
}
/*%
* A negated address match list element (like "! 10.0.0.1").
* Somewhat sneakily, the caller is expected to parse the
* "!", but not to print it.
*/
static cfg_tuplefielddef_t negated_fields[] = {
{ "negated", &cfg_type_addrmatchelt, 0 },
{ NULL, NULL, 0 }
};
static void
print_negated(cfg_printer_t *pctx, const cfg_obj_t *obj) {
cfg_print_cstr(pctx, "!");
cfg_print_tuple(pctx, obj);
}
static cfg_type_t cfg_type_negated = {
"negated", cfg_parse_tuple, print_negated, NULL, &cfg_rep_tuple,
&negated_fields
};
/*% An address match list element */
static cfg_type_t cfg_type_addrmatchelt = {
"address_match_element", parse_addrmatchelt, NULL, cfg_doc_terminal,
NULL, NULL
};
/*% A bracketed address match list */
static cfg_type_t cfg_type_bracketed_aml = {
"bracketed_aml", cfg_parse_bracketed_list, cfg_print_bracketed_list,
cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_addrmatchelt
};
/*%
* The socket address syntax in the "controls" statement is silly.
* It allows both socket address families, but also allows "*",
@ -3631,12 +3488,12 @@ static isc_result_t
parse_logversions(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret)
{
return (parse_enum_or_other(pctx, type, &cfg_type_uint32, ret));
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_uint32, ret));
}
static void
doc_logversions(cfg_printer_t *pctx, const cfg_type_t *type) {
doc_enum_or_other(pctx, type, &cfg_type_uint32);
cfg_doc_enum_or_other(pctx, type, &cfg_type_uint32);
}
static cfg_type_t cfg_type_logversions = {
@ -4045,12 +3902,12 @@ static cfg_type_t cfg_type_ttlval = {
static isc_result_t
parse_maxttl(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
return (parse_enum_or_other(pctx, type, &cfg_type_ttlval, ret));
return (cfg_parse_enum_or_other(pctx, type, &cfg_type_ttlval, ret));
}
static void
doc_maxttl(cfg_printer_t *pctx, const cfg_type_t *type) {
doc_enum_or_other(pctx, type, &cfg_type_ttlval);
cfg_doc_enum_or_other(pctx, type, &cfg_type_ttlval);
}
/*%

View file

@ -1134,7 +1134,6 @@ doc_btext(cfg_printer_t *pctx, const cfg_type_t *type) {
cfg_print_cstr(pctx, "{ <unspecified-text> }");
}
bool
cfg_is_enum(const char *s, const char *const *enums) {
const char * const *p;
@ -1193,6 +1192,58 @@ cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) {
cfg_print_cstr(pctx, " )");
}
isc_result_t
cfg_parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
const cfg_type_t *othertype, cfg_obj_t **ret)
{
isc_result_t result;
CHECK(cfg_peektoken(pctx, 0));
if (pctx->token.type == isc_tokentype_string &&
cfg_is_enum(TOKEN_STRING(pctx), enumtype->of))
{
CHECK(cfg_parse_enum(pctx, enumtype, ret));
} else {
CHECK(cfg_parse_obj(pctx, othertype, ret));
}
cleanup:
return (result);
}
void
cfg_doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *enumtype,
const cfg_type_t *othertype)
{
const char * const *p;
bool first = true;
/*
* If othertype is cfg_type_void, it means that enumtype is
* optional.
*/
if (othertype == &cfg_type_void) {
cfg_print_cstr(pctx, "[ ");
}
cfg_print_cstr(pctx, "( ");
for (p = enumtype->of; *p != NULL; p++) {
if (!first) {
cfg_print_cstr(pctx, " | ");
}
first = false;
cfg_print_cstr(pctx, *p);
}
if (othertype != &cfg_type_void) {
if (!first) {
cfg_print_cstr(pctx, " | ");
}
cfg_doc_terminal(pctx, othertype);
}
cfg_print_cstr(pctx, " )");
if (othertype == &cfg_type_void) {
cfg_print_cstr(pctx, " ]");
}
}
void
cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
REQUIRE(pctx != NULL);
@ -1275,6 +1326,145 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bracketed_text = {
&cfg_rep_string, NULL
};
static cfg_type_t cfg_type_addrmatchelt;
static cfg_type_t cfg_type_negated;
static isc_result_t
parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret)
{
isc_result_t result;
UNUSED(type);
CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
if (pctx->token.type == isc_tokentype_string ||
pctx->token.type == isc_tokentype_qstring) {
if (pctx->token.type == isc_tokentype_string &&
(strcasecmp(TOKEN_STRING(pctx), "key") == 0)) {
CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret));
} else if (pctx->token.type == isc_tokentype_string &&
(strcasecmp(TOKEN_STRING(pctx), "geoip") == 0)) {
#ifdef HAVE_GEOIP
CHECK(cfg_gettoken(pctx, 0));
CHECK(cfg_parse_obj(pctx, &cfg_type_geoip, ret));
#else
cfg_parser_error(pctx, CFG_LOG_NEAR, "'geoip' "
"not supported in this build");
return (ISC_R_UNEXPECTEDTOKEN);
#endif
} else {
if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK |
CFG_ADDR_V4PREFIXOK |
CFG_ADDR_V6OK))
{
CHECK(cfg_parse_netprefix(pctx, NULL, ret));
} else {
CHECK(cfg_parse_astring(pctx, NULL, ret));
}
}
} else if (pctx->token.type == isc_tokentype_special) {
if (pctx->token.value.as_char == '{') {
/* Nested match list. */
CHECK(cfg_parse_obj(pctx,
&cfg_type_bracketed_aml, ret));
} else if (pctx->token.value.as_char == '!') {
CHECK(cfg_gettoken(pctx, 0)); /* read "!" */
CHECK(cfg_parse_obj(pctx, &cfg_type_negated, ret));
} else {
goto bad;
}
} else {
bad:
cfg_parser_error(pctx, CFG_LOG_NEAR,
"expected IP match list element");
return (ISC_R_UNEXPECTEDTOKEN);
}
cleanup:
return (result);
}
/*%
* A negated address match list element (like "! 10.0.0.1").
* Somewhat sneakily, the caller is expected to parse the
* "!", but not to print it.
*/
static cfg_tuplefielddef_t negated_fields[] = {
{ "negated", &cfg_type_addrmatchelt, 0 },
{ NULL, NULL, 0 }
};
static void
print_negated(cfg_printer_t *pctx, const cfg_obj_t *obj) {
cfg_print_cstr(pctx, "!");
cfg_print_tuple(pctx, obj);
}
static cfg_type_t cfg_type_negated = {
"negated", cfg_parse_tuple, print_negated, NULL, &cfg_rep_tuple,
&negated_fields
};
/*% An address match list element */
static cfg_type_t cfg_type_addrmatchelt = {
"address_match_element", parse_addrmatchelt, NULL, cfg_doc_terminal,
NULL, NULL
};
/*%
* A bracketed address match list
*/
LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bracketed_aml = {
"bracketed_aml", cfg_parse_bracketed_list, cfg_print_bracketed_list,
cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_addrmatchelt
};
/*
* Optional bracketed text
*/
static isc_result_t
parse_optional_btext(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret)
{
isc_result_t result;
UNUSED(type);
CHECK(cfg_peektoken(pctx, ISC_LEXOPT_BTEXT));
if (pctx->token.type == isc_tokentype_btext) {
CHECK(cfg_parse_obj(pctx, &cfg_type_bracketed_text, ret));
} else {
CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
}
cleanup:
return (result);
}
static void
print_optional_btext(cfg_printer_t *pctx, const cfg_obj_t *obj) {
if (obj->type == &cfg_type_void) {
return;
}
pctx->indent++;
cfg_print_cstr(pctx, "{");
cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length);
print_close(pctx);
}
static void
doc_optional_btext(cfg_printer_t *pctx, const cfg_type_t *type) {
UNUSED(type);
cfg_print_cstr(pctx, "[ { <unspecified-text> } ]");
}
cfg_type_t cfg_type_optional_bracketed_text = {
"optional_btext", parse_optional_btext, print_optional_btext,
doc_optional_btext, NULL, NULL
};
/*
* Booleans
*/
@ -1485,7 +1675,7 @@ print_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
isc_result_t
cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type,
cfg_obj_t **ret)
cfg_obj_t **ret)
{
isc_result_t result;
@ -2001,6 +2191,7 @@ static struct flagtext {
{ CFG_CLAUSEFLAG_MULTI, "may occur multiple times" },
{ CFG_CLAUSEFLAG_EXPERIMENTAL, "experimental" },
{ CFG_CLAUSEFLAG_NOOP, "non-operational" },
{ CFG_CLAUSEFLAG_DEPRECATED, "deprecated" },
{ 0, NULL }
};
@ -3266,3 +3457,51 @@ cfg_parser_mapadd(cfg_parser_t *pctx, cfg_obj_t *mapobj,
return (result);
}
isc_result_t
cfg_pluginlist_foreach(const cfg_obj_t *config, const cfg_obj_t *list,
isc_log_t *lctx, pluginlist_cb_t *callback,
void *callback_data)
{
isc_result_t result = ISC_R_SUCCESS;
const cfg_listelt_t *element;
REQUIRE(config != NULL);
REQUIRE(callback != NULL);
for (element = cfg_list_first(list);
element != NULL;
element = cfg_list_next(element))
{
const cfg_obj_t *plugin = cfg_listelt_value(element);
const cfg_obj_t *obj;
const char *type, *library;
const char *parameters = NULL;
/* Get the path to the plugin module. */
obj = cfg_tuple_get(plugin, "type");
type = cfg_obj_asstring(obj);
/* Only query plugins are supported currently. */
if (strcasecmp(type, "query") != 0) {
cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
"unsupported plugin type");
return (ISC_R_FAILURE);
}
library = cfg_obj_asstring(cfg_tuple_get(plugin, "library"));
obj = cfg_tuple_get(plugin, "parameters");
if (obj != NULL && cfg_obj_isstring(obj)) {
parameters = cfg_obj_asstring(obj);
}
result = callback(config, obj, library, parameters,
callback_data);
if (result != ISC_R_SUCCESS) {
break;
}
}
return (result);
}

View file

@ -14,6 +14,7 @@ cfg_create_obj
cfg_create_tuple
cfg_doc_bracketed_list
cfg_doc_enum
cfg_doc_enum_or_other
cfg_doc_map
cfg_doc_mapbody
cfg_doc_obj
@ -71,6 +72,7 @@ cfg_parse_buffer3
cfg_parse_buffer4
cfg_parse_dscp
cfg_parse_enum
cfg_parse_enum_or_other
cfg_parse_file
cfg_parse_fixedpoint
cfg_parse_listelt

View file

@ -43,18 +43,21 @@ DNSDEPLIBS = ../../lib/dns/libdns.@A@
LIBS = @LIBS@
# Alphabetically
OBJS = client.@O@ interfacemgr.@O@ lib.@O@ \
OBJS = client.@O@ hooks.@O@ interfacemgr.@O@ lib.@O@ \
listenlist.@O@ log.@O@ notify.@O@ query.@O@ \
server.@O@ sortlist.@O@ stats.@O@ update.@O@ \
version.@O@ xfrout.@O@
SRCS = client.c interfacemgr.c lib.c listenlist.c \
SRCS = client.c hooks.c interfacemgr.c lib.c listenlist.c \
log.c notify.c query.c server.c sortlist.c stats.c \
update.c version.c xfrout.c
SUBDIRS = include
TARGETS = timestamp
TESTDIRS = @UNITTESTS@
TARGETS = timestamp
SO_CFLAGS = @CFLAGS@ @SO_CFLAGS@
SO_LDFLAGS = @LDFLAGS@ @SO_LDFLAGS@
@BIND9_MAKE_RULES@

View file

@ -1097,23 +1097,6 @@ client_send(ns_client_t *client) {
preferred_glue = DNS_MESSAGERENDER_PREFER_AAAA;
}
/*
* filter-aaaa-on-v4 yes or break-dnssec option to suppress
* AAAA records.
*
* We already know that request came via IPv4,
* that we have both AAAA and A records,
* and that we either have no signatures that the client wants
* or we are supposed to break DNSSEC.
*
* Override preferred glue if necessary.
*/
if ((client->attributes & NS_CLIENTATTR_FILTER_AAAA) != 0) {
render_opts |= DNS_MESSAGERENDER_FILTER_AAAA;
if (preferred_glue == DNS_MESSAGERENDER_PREFER_AAAA)
preferred_glue = DNS_MESSAGERENDER_PREFER_A;
}
/*
* Create an OPT for our reply.
*/
@ -3046,8 +3029,8 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
client->interface = NULL;
client->peeraddr_valid = false;
dns_ecs_init(&client->ecs);
client->filter_aaaa = dns_aaaa_ok;
client->needshutdown = (client->sctx->options & NS_SERVER_CLIENTTEST);
client->needshutdown = ((client->sctx->options &
NS_SERVER_CLIENTTEST) != 0);
ISC_EVENT_INIT(&client->ctlevent, sizeof(client->ctlevent), 0, NULL,
NS_EVENT_CLIENTCONTROL, client_start, client, client,
@ -3997,3 +3980,240 @@ ns_client_sourceip(dns_clientinfo_t *ci, isc_sockaddr_t **addrp) {
*addrp = &client->peeraddr;
return (ISC_R_SUCCESS);
}
dns_rdataset_t *
ns_client_newrdataset(ns_client_t *client) {
dns_rdataset_t *rdataset;
isc_result_t result;
REQUIRE(NS_CLIENT_VALID(client));
rdataset = NULL;
result = dns_message_gettemprdataset(client->message, &rdataset);
if (result != ISC_R_SUCCESS) {
return (NULL);
}
return (rdataset);
}
void
ns_client_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) {
dns_rdataset_t *rdataset;
REQUIRE(NS_CLIENT_VALID(client));
REQUIRE(rdatasetp != NULL);
rdataset = *rdatasetp;
if (rdataset != NULL) {
if (dns_rdataset_isassociated(rdataset)) {
dns_rdataset_disassociate(rdataset);
}
dns_message_puttemprdataset(client->message, rdatasetp);
}
}
isc_result_t
ns_client_newnamebuf(ns_client_t *client) {
isc_buffer_t *dbuf;
isc_result_t result;
CTRACE("ns_client_newnamebuf");
dbuf = NULL;
result = isc_buffer_allocate(client->mctx, &dbuf, 1024);
if (result != ISC_R_SUCCESS) {
CTRACE("ns_client_newnamebuf: "
"isc_buffer_allocate failed: done");
return (result);
}
ISC_LIST_APPEND(client->query.namebufs, dbuf, link);
CTRACE("ns_client_newnamebuf: done");
return (ISC_R_SUCCESS);
}
dns_name_t *
ns_client_newname(ns_client_t *client, isc_buffer_t *dbuf, isc_buffer_t *nbuf) {
dns_name_t *name;
isc_region_t r;
isc_result_t result;
REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0);
CTRACE("ns_client_newname");
name = NULL;
result = dns_message_gettempname(client->message, &name);
if (result != ISC_R_SUCCESS) {
CTRACE("ns_client_newname: "
"dns_message_gettempname failed: done");
return (NULL);
}
isc_buffer_availableregion(dbuf, &r);
isc_buffer_init(nbuf, r.base, r.length);
dns_name_init(name, NULL);
dns_name_setbuffer(name, nbuf);
client->query.attributes |= NS_QUERYATTR_NAMEBUFUSED;
CTRACE("ns_client_newname: done");
return (name);
}
isc_buffer_t *
ns_client_getnamebuf(ns_client_t *client) {
isc_buffer_t *dbuf;
isc_result_t result;
isc_region_t r;
CTRACE("ns_client_getnamebuf");
/*%
* Return a name buffer with space for a maximal name, allocating
* a new one if necessary.
*/
if (ISC_LIST_EMPTY(client->query.namebufs)) {
result = ns_client_newnamebuf(client);
if (result != ISC_R_SUCCESS) {
CTRACE("ns_client_getnamebuf: "
"ns_client_newnamebuf failed: done");
return (NULL);
}
}
dbuf = ISC_LIST_TAIL(client->query.namebufs);
INSIST(dbuf != NULL);
isc_buffer_availableregion(dbuf, &r);
if (r.length < DNS_NAME_MAXWIRE) {
result = ns_client_newnamebuf(client);
if (result != ISC_R_SUCCESS) {
CTRACE("ns_client_getnamebuf: "
"ns_client_newnamebuf failed: done");
return (NULL);
}
dbuf = ISC_LIST_TAIL(client->query.namebufs);
isc_buffer_availableregion(dbuf, &r);
INSIST(r.length >= 255);
}
CTRACE("ns_client_getnamebuf: done");
return (dbuf);
}
void
ns_client_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf) {
isc_region_t r;
CTRACE("ns_client_keepname");
/*%
* 'name' is using space in 'dbuf', but 'dbuf' has not yet been
* adjusted to take account of that. We do the adjustment.
*/
REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) != 0);
dns_name_toregion(name, &r);
isc_buffer_add(dbuf, r.length);
dns_name_setbuffer(name, NULL);
client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED;
}
void
ns_client_releasename(ns_client_t *client, dns_name_t **namep) {
dns_name_t *name = *namep;
/*%
* 'name' is no longer needed. Return it to our pool of temporary
* names. If it is using a name buffer, relinquish its exclusive
* rights on the buffer.
*/
CTRACE("ns_client_releasename");
if (dns_name_hasbuffer(name)) {
INSIST((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED)
!= 0);
client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED;
}
dns_message_puttempname(client->message, namep);
CTRACE("ns_client_releasename: done");
}
isc_result_t
ns_client_newdbversion(ns_client_t *client, unsigned int n) {
unsigned int i;
ns_dbversion_t *dbversion;
for (i = 0; i < n; i++) {
dbversion = isc_mem_get(client->mctx, sizeof(*dbversion));
if (dbversion != NULL) {
dbversion->db = NULL;
dbversion->version = NULL;
ISC_LIST_INITANDAPPEND(client->query.freeversions,
dbversion, link);
} else {
/*
* We only return ISC_R_NOMEMORY if we couldn't
* allocate anything.
*/
if (i == 0) {
return (ISC_R_NOMEMORY);
} else {
return (ISC_R_SUCCESS);
}
}
}
return (ISC_R_SUCCESS);
}
static inline ns_dbversion_t *
client_getdbversion(ns_client_t *client) {
isc_result_t result;
ns_dbversion_t *dbversion;
if (ISC_LIST_EMPTY(client->query.freeversions)) {
result = ns_client_newdbversion(client, 1);
if (result != ISC_R_SUCCESS) {
return (NULL);
}
}
dbversion = ISC_LIST_HEAD(client->query.freeversions);
INSIST(dbversion != NULL);
ISC_LIST_UNLINK(client->query.freeversions, dbversion, link);
return (dbversion);
}
ns_dbversion_t *
ns_client_findversion(ns_client_t *client, dns_db_t *db) {
ns_dbversion_t *dbversion;
for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
dbversion != NULL;
dbversion = ISC_LIST_NEXT(dbversion, link))
{
if (dbversion->db == db) {
break;
}
}
if (dbversion == NULL) {
/*
* This is a new zone for this query. Add it to
* the active list.
*/
dbversion = client_getdbversion(client);
if (dbversion == NULL) {
return (NULL);
}
dns_db_attach(db, &dbversion->db);
dns_db_currentversion(db, &dbversion->version);
dbversion->acl_checked = false;
dbversion->queryok = false;
ISC_LIST_APPEND(client->query.activeversions,
dbversion, link);
}
return (dbversion);
}

518
lib/ns/hooks.c Normal file
View file

@ -0,0 +1,518 @@
/*
* 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.
*/
/*! \file */
#include <config.h>
#include <string.h>
#if HAVE_DLFCN_H
#include <dlfcn.h>
#elif _WIN32
#include <windows.h>
#endif
#include <isc/list.h>
#include <isc/log.h>
#include <isc/mem.h>
#include <isc/mutex.h>
#include <isc/result.h>
#include <isc/platform.h>
#include <isc/util.h>
#include <isc/types.h>
#include <dns/view.h>
#include <ns/hooks.h>
#include <ns/log.h>
#include <ns/query.h>
#define CHECK(op) \
do { \
result = (op); \
if (result != ISC_R_SUCCESS) { \
goto cleanup; \
} \
} while (0)
struct ns_plugin {
isc_mem_t *mctx;
void *handle;
void *inst;
char *modpath;
ns_plugin_check_t *check_func;
ns_plugin_register_t *register_func;
ns_plugin_destroy_t *destroy_func;
LINK(ns_plugin_t) link;
};
static ns_hooklist_t default_hooktable[NS_HOOKPOINTS_COUNT];
LIBNS_EXTERNAL_DATA ns_hooktable_t *ns__hook_table = &default_hooktable;
#if HAVE_DLFCN_H && HAVE_DLOPEN
static isc_result_t
load_symbol(void *handle, const char *modpath,
const char *symbol_name, void **symbolp)
{
void *symbol = NULL;
REQUIRE(handle != NULL);
REQUIRE(symbolp != NULL && *symbolp == NULL);
/*
* Clear any pre-existing error conditions before running dlsym().
* (In this case, we expect dlsym() to return non-NULL values
* and will always return an error if it returns NULL, but
* this ensures that we'll report the correct error condition
* if there is one.)
*/
dlerror();
symbol = dlsym(handle, symbol_name);
if (symbol == NULL) {
const char *errmsg = dlerror();
if (errmsg == NULL) {
errmsg = "returned function pointer is NULL";
}
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"failed to look up symbol %s in "
"plugin '%s': %s",
symbol_name, modpath, errmsg);
return (ISC_R_FAILURE);
}
*symbolp = symbol;
return (ISC_R_SUCCESS);
}
static isc_result_t
load_plugin(isc_mem_t *mctx, const char *modpath, ns_plugin_t **pluginp) {
isc_result_t result;
void *handle = NULL;
ns_plugin_t *plugin = NULL;
ns_plugin_check_t *check_func = NULL;
ns_plugin_register_t *register_func = NULL;
ns_plugin_destroy_t *destroy_func = NULL;
ns_plugin_version_t *version_func = NULL;
int version, flags;
REQUIRE(pluginp != NULL && *pluginp == NULL);
flags = RTLD_LAZY | RTLD_LOCAL;
#ifdef RTLD_DEEPBIND
flags |= RTLD_DEEPBIND;
#endif
handle = dlopen(modpath, flags);
if (handle == NULL) {
const char *errmsg = dlerror();
if (errmsg == NULL) {
errmsg = "unknown error";
}
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"failed to dlopen() plugin '%s': %s",
modpath, errmsg);
return (ISC_R_FAILURE);
}
CHECK(load_symbol(handle, modpath, "plugin_version",
(void **)&version_func));
version = version_func();
if (version < (NS_PLUGIN_VERSION - NS_PLUGIN_AGE) ||
version > NS_PLUGIN_VERSION)
{
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"plugin API version mismatch: %d/%d",
version, NS_PLUGIN_VERSION);
CHECK(ISC_R_FAILURE);
}
CHECK(load_symbol(handle, modpath, "plugin_check",
(void **)&check_func));
CHECK(load_symbol(handle, modpath, "plugin_register",
(void **)&register_func));
CHECK(load_symbol(handle, modpath, "plugin_destroy",
(void **)&destroy_func));
plugin = isc_mem_get(mctx, sizeof(*plugin));
memset(plugin, 0, sizeof(*plugin));
isc_mem_attach(mctx, &plugin->mctx);
plugin->handle = handle;
plugin->modpath = isc_mem_strdup(plugin->mctx, modpath);
plugin->check_func = check_func;
plugin->register_func = register_func;
plugin->destroy_func = destroy_func;
ISC_LINK_INIT(plugin, link);
*pluginp = plugin;
plugin = NULL;
cleanup:
if (result != ISC_R_SUCCESS) {
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"failed to dynamically load "
"plugin '%s': %s", modpath,
isc_result_totext(result));
if (plugin != NULL) {
isc_mem_putanddetach(&plugin->mctx, plugin,
sizeof(*plugin));
}
if (handle != NULL) {
(void) dlclose(handle);
}
}
return (result);
}
static void
unload_plugin(ns_plugin_t **pluginp) {
ns_plugin_t *plugin = NULL;
REQUIRE(pluginp != NULL && *pluginp != NULL);
plugin = *pluginp;
*pluginp = NULL;
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
"unloading plugin '%s'", plugin->modpath);
if (plugin->inst != NULL) {
plugin->destroy_func(&plugin->inst);
}
if (plugin->handle != NULL) {
(void) dlclose(plugin->handle);
}
if (plugin->modpath != NULL) {
isc_mem_free(plugin->mctx, plugin->modpath);
}
isc_mem_putanddetach(&plugin->mctx, plugin, sizeof(*plugin));
}
#elif _WIN32
static isc_result_t
load_symbol(HMODULE handle, const char *modpath,
const char *symbol_name, void **symbolp)
{
void *symbol = NULL;
REQUIRE(handle != NULL);
REQUIRE(symbolp != NULL && *symbolp == NULL);
symbol = GetProcAddress(handle, symbol_name);
if (symbol == NULL) {
int errstatus = GetLastError();
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"failed to look up symbol %s in "
"plugin '%s': %d",
symbol_name, modpath, errstatus);
return (ISC_R_FAILURE);
}
*symbolp = symbol;
return (ISC_R_SUCCESS);
}
static isc_result_t
load_plugin(isc_mem_t *mctx, const char *modpath, ns_plugin_t **pluginp) {
isc_result_t result;
HMODULE handle;
ns_plugin_t *plugin = NULL;
ns_plugin_register_t *register_func = NULL;
ns_plugin_destroy_t *destroy_func = NULL;
ns_plugin_version_t *version_func = NULL;
int version;
REQUIRE(pluginp != NULL && *pluginp == NULL);
handle = LoadLibraryA(modpath);
if (handle == NULL) {
CHECK(ISC_R_FAILURE);
}
CHECK(load_symbol(handle, modpath, "plugin_version",
(void **)&version_func));
version = version_func(NULL);
if (version < (NS_PLUGIN_VERSION - NS_PLUGIN_AGE) ||
version > NS_PLUGIN_VERSION)
{
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"plugin API version mismatch: %d/%d",
version, NS_PLUGIN_VERSION);
CHECK(ISC_R_FAILURE);
}
CHECK(load_symbol(handle, modpath, "plugin_register",
(void **)&register_func));
CHECK(load_symbol(handle, modpath, "plugin_destroy",
(void **)&destroy_func));
plugin = isc_mem_get(mctx, sizeof(*plugin));
memset(plugin, 0, sizeof(*plugin));
isc_mem_attach(mctx, &plugin->mctx);
plugin->handle = handle;
plugin->modpath = isc_mem_strdup(plugin->mctx, modpath);
plugin->register_func = register_func;
plugin->destroy_func = destroy_func;
ISC_LINK_INIT(plugin, link);
*pluginp = plugin;
plugin = NULL;
cleanup:
if (result != ISC_R_SUCCESS) {
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"failed to dynamically load "
"plugin '%s': %d (%s)", modpath,
GetLastError(), isc_result_totext(result));
if (plugin != NULL) {
isc_mem_putanddetach(&plugin->mctx, plugin,
sizeof(*plugin));
}
if (handle != NULL) {
FreeLibrary(handle);
}
}
return (result);
}
static void
unload_plugin(ns_plugin_t **pluginp) {
ns_plugin_t *plugin = NULL;
REQUIRE(pluginp != NULL && *pluginp != NULL);
plugin = *pluginp;
*pluginp = NULL;
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
"unloading plugin '%s'", plugin->modpath);
if (plugin->inst != NULL) {
plugin->destroy_func(&plugin->inst);
}
if (plugin->handle != NULL) {
FreeLibrary(plugin->handle);
}
if (plugin->modpath != NULL) {
isc_mem_free(plugin->mctx, plugin->modpath);
}
isc_mem_putanddetach(&plugin->mctx, plugin, sizeof(*plugin));
}
#else /* HAVE_DLFCN_H || _WIN32 */
static isc_result_t
load_plugin(isc_mem_t *mctx, const char *modpath, ns_plugin_t **pluginp) {
UNUSED(mctx);
UNUSED(modpath);
UNUSED(pluginp);
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_ERROR,
"plugin support is not implemented");
return (ISC_R_NOTIMPLEMENTED);
}
static void
unload_plugin(ns_plugin_t **pluginp) {
UNUSED(pluginp);
}
#endif /* HAVE_DLFCN_H */
isc_result_t
ns_plugin_register(const char *modpath, const char *parameters,
const void *cfg, const char *cfg_file,
unsigned long cfg_line,
isc_mem_t *mctx, isc_log_t *lctx, void *actx,
dns_view_t *view)
{
isc_result_t result;
ns_plugin_t *plugin = NULL;
REQUIRE(mctx != NULL);
REQUIRE(lctx != NULL);
REQUIRE(view != NULL);
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
"loading plugin '%s'", modpath);
CHECK(load_plugin(mctx, modpath, &plugin));
isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
"registering plugin '%s'", modpath);
CHECK(plugin->register_func(parameters, cfg, cfg_file, cfg_line,
mctx, lctx, actx, view->hooktable,
&plugin->inst));
ISC_LIST_APPEND(*(ns_plugins_t *)view->plugins, plugin, link);
cleanup:
if (result != ISC_R_SUCCESS && plugin != NULL) {
unload_plugin(&plugin);
}
return (result);
}
isc_result_t
ns_plugin_check(const char *modpath, const char *parameters,
const void *cfg, const char *cfg_file, unsigned long cfg_line,
isc_mem_t *mctx, isc_log_t *lctx, void *actx)
{
isc_result_t result;
ns_plugin_t *plugin = NULL;
CHECK(load_plugin(mctx, modpath, &plugin));
result = plugin->check_func(parameters, cfg, cfg_file, cfg_line,
mctx, lctx, actx);
cleanup:
if (plugin != NULL) {
unload_plugin(&plugin);
}
return (result);
}
void
ns_hooktable_init(ns_hooktable_t *hooktable) {
int i;
for (i = 0; i < NS_HOOKPOINTS_COUNT; i++) {
ISC_LIST_INIT((*hooktable)[i]);
}
}
isc_result_t
ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep) {
ns_hooktable_t *hooktable = NULL;
REQUIRE(tablep != NULL && *tablep == NULL);
hooktable = isc_mem_get(mctx, sizeof(*hooktable));
ns_hooktable_init(hooktable);
*tablep = hooktable;
return (ISC_R_SUCCESS);
}
void
ns_hooktable_free(isc_mem_t *mctx, void **tablep) {
ns_hooktable_t *table = NULL;
ns_hook_t *hook = NULL, *next = NULL;
int i = 0;
REQUIRE(tablep != NULL && *tablep != NULL);
table = *tablep;
*tablep = NULL;
for (i = 0; i < NS_HOOKPOINTS_COUNT; i++) {
for (hook = ISC_LIST_HEAD((*table)[i]);
hook != NULL;
hook = next)
{
next = ISC_LIST_NEXT(hook, link);
ISC_LIST_UNLINK((*table)[i], hook, link);
if (hook->mctx != NULL) {
isc_mem_putanddetach(&hook->mctx,
hook, sizeof(*hook));
}
}
}
isc_mem_put(mctx, table, sizeof(*table));
}
void
ns_hook_add(ns_hooktable_t *hooktable, isc_mem_t *mctx,
ns_hookpoint_t hookpoint, const ns_hook_t *hook)
{
ns_hook_t *copy = NULL;
REQUIRE(hooktable != NULL);
REQUIRE(mctx != NULL);
REQUIRE(hookpoint < NS_HOOKPOINTS_COUNT);
REQUIRE(hook != NULL);
copy = isc_mem_get(mctx, sizeof(*copy));
memset(copy, 0, sizeof(*copy));
copy->action = hook->action;
copy->action_data = hook->action_data;
isc_mem_attach(mctx, &copy->mctx);
ISC_LINK_INIT(copy, link);
ISC_LIST_APPEND((*hooktable)[hookpoint], copy, link);
}
void
ns_plugins_create(isc_mem_t *mctx, ns_plugins_t **listp) {
ns_plugins_t *plugins = NULL;
REQUIRE(listp != NULL && *listp == NULL);
plugins = isc_mem_get(mctx, sizeof(*plugins));
memset(plugins, 0, sizeof(*plugins));
ISC_LIST_INIT(*plugins);
*listp = plugins;
}
void
ns_plugins_free(isc_mem_t *mctx, void **listp) {
ns_plugins_t *list = NULL;
ns_plugin_t *plugin = NULL, *next = NULL;
REQUIRE(listp != NULL && *listp != NULL);
list = *listp;
*listp = NULL;
for (plugin = ISC_LIST_HEAD(*list);
plugin != NULL;
plugin = next)
{
next = ISC_LIST_NEXT(plugin, link);
ISC_LIST_UNLINK(*list, plugin, link);
unload_plugin(&plugin);
}
isc_mem_put(mctx, list, sizeof(*list));
}

View file

@ -1,197 +0,0 @@
/*
* 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.
*/
#ifndef NS_HOOKS_H
#define NS_HOOKS_H 1
#ifdef NS_HOOKS_ENABLE
/*! \file */
#include <stdbool.h>
#include <isc/result.h>
/*
* Hooks provide a way of running a callback function once a certain place in
* code is reached. Current use is limited to libns unit tests and thus:
*
* - hook-related types and macros are not placed in libns header files,
* - hook-related code is compiled away unless --with-atf is used,
* - hook-related macro names are prefixed with "NS_".
*
* However, the implementation is pretty generic and could be repurposed for
* general use, e.g. as part of libisc, after some further customization.
*
* Hooks are created by inserting a macro into any function returning
* isc_result_t (NS_PROCESS_HOOK()) or void (NS_PROCESS_HOOK_VOID()). As both
* of these macros contain a return statement which is inlined into the
* function into which the hook is inserted, a hook callback is able to cause
* that function to return at hook insertion point. For functions returning
* isc_result_t, if a hook callback intends to cause a return at hook insertion
* point, it also has to set the value to be returned by the function.
*
* Hook callbacks are functions which:
*
* - return a boolean value; if true is returned by the callback, the
* function into which the hook is inserted will return at hook insertion
* point; if false is returned by the callback, execution of the
* function into which the hook is inserted continues normally,
*
* - accept three pointers as arguments:
*
* - a pointer specified by the hook itself,
* - a pointer specified upon inserting the callback into the hook table,
* - a pointer to isc_result_t which will be returned by the function
* into which the hook is inserted if the callback returns true.
*
* Hook tables are arrays which consist of a number of tuples (one tuple per
* hook identifier), each of which determines the callback to be invoked when a
* given hook is processed and the data to be passed to that callback. In an
* attempt to keep things as simple as possible, current implementation uses
* hook tables which are statically-sized arrays only allowing a single
* callback to be invoked for each hook identifier.
*
* In order for a hook callback to be called for a given hook, a pointer to
* that callback (along with an optional pointer to callback-specific data) has
* to be inserted into the relevant hook table entry for that hook. Replacing
* whole hook tables is also possible.
*
* Consider the following sample code:
*
* ----------------------------------------------------------------------------
* ns_hook_t *foo_hook_table = NULL;
*
* isc_result_t
* foo_bar(void) {
* int val = 42;
*
* ...
*
* NS_PROCESS_HOOK(foo_hook_table, FOO_EXTRACT_VAL, &val);
*
* ...
*
* printf("This message may not be printed due to use of hooks.");
*
* return (ISC_R_SUCCESS);
* }
*
* bool
* cause_failure(void *hook_data, void *callback_data, isc_result_t *resultp) {
* int *valp = (int *)hook_data;
* bool *calledp = (bool *)callback_data;
*
* ...
*
* *resultp = ISC_R_FAILURE;
*
* return (true);
* }
*
* bool
* examine_val(void *hook_data, void *callback_data, isc_result_t *resultp) {
* int *valp = (int *)hook_data;
* int *valcopyp = (int *)callback_data;
*
* UNUSED(resultp);
*
* ...
*
* return (false);
* }
*
* void
* test_foo_bar(void) {
* bool called = false;
* int valcopy;
*
* ns_hook_t my_hooks[FOO_HOOKS_COUNT] = {
* [FOO_EXTRACT_VAL] = {
* .callback = cause_failure,
* .callback_data = &called,
* },
* };
*
* foo_hook_table = my_hooks;
* foo_bar();
*
* {
* const ns_hook_t examine_hook = {
* .callback = examine_val,
* .callback_data = &valcopy,
* };
*
* my_hooks[FOO_EXTRACT_VAL] = examine_hook;
* }
* foo_bar();
*
* }
* ----------------------------------------------------------------------------
*
* When test_foo_bar() is called, "foo_hook_table" is set to "my_hooks". Then
* foo_bar() gets invoked. Once execution reaches the insertion point for hook
* FOO_EXTRACT_VAL, cause_failure() will be called with &val as "hook_data" and
* &called as "callback_data". It can do whatever it pleases with these two
* values. Eventually, cause_failure() sets *resultp to ISC_R_FAILURE and
* returns true, which causes foo_bar() to return ISC_R_FAILURE and never
* execute the printf() call below hook insertion point.
*
* Execution then returns to test_foo_bar(). Unlike before the first call to
* foo_bar(), this time only a single hook ("examine_hook") is defined instead
* of a complete hook table. This hook is then subsequently inserted at index
* FOO_EXTRACT_VAL into the "my_hook" hook table. This causes the hook
* previously set at that index (the one calling cause_failure()) to be
* replaced with "examine_hook". Thus, when the second call to foo_bar() is
* subsequently made, examine_val() will be called with &val as "hook_data" and
* &valcopy as "callback_data". Contrary to cause_failure(), extract_val()
* returns false, which means it does not access "resultp" and does not
* cause foo_bar() to return at hook insertion point. Thus, printf() will be
* called this time and foo_bar() will return ISC_R_SUCCESS.
*/
enum {
NS_QUERY_SETUP_QCTX_INITIALIZED,
NS_QUERY_LOOKUP_BEGIN,
NS_QUERY_DONE_BEGIN,
NS_QUERY_HOOKS_COUNT /* MUST BE LAST */
};
typedef bool
(*ns_hook_cb_t)(void *hook_data, void *callback_data, isc_result_t *resultp);
typedef struct ns_hook {
ns_hook_cb_t callback;
void *callback_data;
} ns_hook_t;
#define _NS_PROCESS_HOOK(table, id, data, ...) \
if (table != NULL) { \
ns_hook_cb_t _callback = table[id].callback; \
void *_callback_data = table[id].callback_data; \
isc_result_t _result; \
\
if (_callback != NULL && \
_callback(data, _callback_data, &_result)) { \
return __VA_ARGS__; \
} \
}
#define NS_PROCESS_HOOK(table, id, data) \
_NS_PROCESS_HOOK(table, id, data, _result)
#define NS_PROCESS_HOOK_VOID(table, id, data) \
_NS_PROCESS_HOOK(table, id, data)
LIBNS_EXTERNAL_DATA extern ns_hook_t *ns__hook_table;
#endif /* NS_HOOKS_ENABLE */
#endif /* NS_HOOKS_H */

View file

@ -13,7 +13,7 @@ top_srcdir = @top_srcdir@
VERSION=@BIND9_VERSION@
HEADERS = client.h interfacemgr.h lib.h listenlist.h log.h \
HEADERS = client.h hooks.h interfacemgr.h lib.h listenlist.h log.h \
notify.h query.h server.h sortlist.h stats.h \
types.h update.h version.h xfrout.h
SUBDIRS =

View file

@ -148,7 +148,6 @@ struct ns_client {
struct in6_pktinfo pktinfo;
isc_dscp_t dscp;
isc_event_t ctlevent;
dns_aaaa_t filter_aaaa;
/*%
* Information about recent FORMERR response(s), for
* FORMERR loop avoidance. This is separate for each
@ -185,8 +184,8 @@ typedef ISC_LIST(ns_client_t) client_list_t;
#define NS_CLIENTATTR_MULTICAST 0x00008 /*%< recv'd from multicast */
#define NS_CLIENTATTR_WANTDNSSEC 0x00010 /*%< include dnssec records */
#define NS_CLIENTATTR_WANTNSID 0x00020 /*%< include nameserver ID */
#define NS_CLIENTATTR_FILTER_AAAA 0x00040 /*%< suppress AAAAs */
#define NS_CLIENTATTR_FILTER_AAAA_RC 0x00080 /*%< recursing for A against AAAA */
/* Obsolete: NS_CLIENTATTR_FILTER_AAAA 0x00040 */
/* Obsolete: NS_CLIENTATTR_FILTER_AAAA_RC 0x00080 */
#define NS_CLIENTATTR_WANTAD 0x00100 /*%< want AD in response if possible */
#define NS_CLIENTATTR_WANTCOOKIE 0x00200 /*%< return a COOKIE */
#define NS_CLIENTATTR_HAVECOOKIE 0x00400 /*%< has a valid COOKIE */
@ -427,4 +426,71 @@ ns__client_request(isc_task_t *task, isc_event_t *event);
* Handle client requests.
* (Not intended for use outside this module and associated tests.)
*/
dns_rdataset_t *
ns_client_newrdataset(ns_client_t *client);
void
ns_client_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp);
/*%<
* Get and release temporary rdatasets in the client message;
* used in query.c and in plugins.
*/
isc_result_t
ns_client_newnamebuf(ns_client_t *client);
/*%<
* Allocate a name buffer for the client message.
*/
dns_name_t *
ns_client_newname(ns_client_t *client, isc_buffer_t *dbuf, isc_buffer_t *nbuf);
/*%<
* Get a temporary name for the client message.
*/
isc_buffer_t *
ns_client_getnamebuf(ns_client_t *client);
/*%<
* Get a name buffer from the pool, or allocate a new one if needed.
*/
void
ns_client_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf);
/*%<
* Adjust buffer 'dbuf' to reflect that 'name' is using space in it,
* and set client attributes appropriately.
*/
void
ns_client_releasename(ns_client_t *client, dns_name_t **namep);
/*%<
* Release 'name' back to the pool of temporary names for the client
* message. If it is using a name buffer, relinquish its exclusive
* rights on the buffer.
*/
isc_result_t
ns_client_newdbversion(ns_client_t *client, unsigned int n);
/*%<
* Allocate 'n' new database versions for use by client queries.
*/
ns_dbversion_t *
ns_client_getdbversion(ns_client_t *client);
/*%<
* Get a free database version for use by a client query, allocating
* a new one if necessary.
*/
ns_dbversion_t *
ns_client_findversion(ns_client_t *client, dns_db_t *db);
/*%<
* Find the correct database version to use with a client query.
* If we have already done a query related to the database 'db',
* make sure subsequent queries are from the same version;
* otherwise, take a database version from the list of dbversions
* allocated by ns_client_newdbversion().
*/
#endif /* NS_CLIENT_H */

390
lib/ns/include/ns/hooks.h Normal file
View file

@ -0,0 +1,390 @@
/*
* 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.
*/
#ifndef NS_HOOKS_H
#define NS_HOOKS_H 1
/*! \file */
#include <stdbool.h>
#include <isc/list.h>
#include <isc/magic.h>
#include <isc/result.h>
#include <dns/rdatatype.h>
#include <ns/client.h>
#include <ns/query.h>
/*
* "Hooks" are a mechanism to call a defined function or set of functions once
* a certain place in code is reached. Hook actions can inspect and alter the
* state of an ongoing process, allowing processing to continue afterward or
* triggering an early return.
*
* Currently hooks are used in two ways: in plugins, which use them to
* add functionality to query processing, and in the unit tests for libns,
* where they are used to inspect state before and after certain functions have
* run.
*
* Both of these uses are limited to libns, so hooks are currently defined in
* the ns/hooks.h header file, and hook-related macro and function names are
* prefixed with `NS_` and `ns_`. However, the design is fairly generic and
* could be repurposed for general use, e.g. as part of libisc, after some
* further customization.
*
* Hooks are created by defining a hook point identifier in the ns_hookpoint_t
* enum below, and placing a special call at a corresponding location in the
* code which invokes the action(s) for that hook; there are two such special
* calls currently implemented, namely the CALL_HOOK() and CALL_HOOK_NORETURN()
* macros in query.c. The former macro contains a "goto cleanup" statement
* which is inlined into the function into which the hook has been inserted;
* this enables the hook action to cause the calling function to return from
* the hook insertion point. For functions returning isc_result_t, if a hook
* action intends to cause a return at hook insertion point, it also has to set
* the value to be returned by the calling function.
*
* A hook table is an array (indexed by the value of the hook point identifier)
* in which each cell contains a linked list of structures, each of which
* contains a function pointer to a hook action and a pointer to data which is
* to be passed to the action function when it is called.
*
* Each view has its own separate hook table, populated by loading plugin
* modules specified in the "plugin" statements in named.conf. There is also a
* special, global hook table (ns__hook_table) that is only used by libns unit
* tests and whose existence can be safely ignored by plugin modules.
*
* Hook actions are functions which:
*
* - return an ns_hookresult_t value:
* - if NS_HOOK_RETURN is returned by the hook action, the function
* into which the hook is inserted will return and no further hook
* actions at the same hook point will be invoked,
* - if NS_HOOK_CONTINUE is returned by the hook action and there are
* further hook actions set up at the same hook point, they will be
* processed; if NS_HOOK_CONTINUE is returned and there are no
* further hook actions set up at the same hook point, execution of
* the function into which the hook has been inserted will be
* resumed.
*
* - accept three pointers as arguments:
* - a pointer specified by the special call at the hook insertion point,
* - a pointer specified upon inserting the action into the hook table,
* - a pointer to an isc_result_t value which will be returned by the
* function into which the hook is inserted if the action returns
* NS_HOOK_RETURN.
*
* In order for a hook action to be called for a given hook, a pointer to that
* action function (along with an optional pointer to action-specific data) has
* to be inserted into the relevant hook table entry for that hook using an
* ns_hook_add() call. If multiple actions are set up at a single hook point,
* they are processed in FIFO order.
*
* As an example, consider the following hypothetical function in query.c:
*
* ----------------------------------------------------------------------------
* static isc_result_t
* query_foo(query_ctx_t *qctx) {
* isc_result_t result;
*
* CALL_HOOK(NS_QUERY_FOO_BEGIN, qctx);
*
* ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY,
* ISC_LOG_DEBUG(99), "Lorem ipsum dolor sit amet...");
*
* result = ISC_R_COMPLETE;
*
* cleanup:
* return (result);
* }
* ----------------------------------------------------------------------------
*
* and the following hook action:
*
* ----------------------------------------------------------------------------
* static ns_hookresult_t
* cause_failure(void *hook_data, void *action_data, isc_result_t *resultp) {
* UNUSED(hook_data);
* UNUSED(action_data);
*
* *resultp = ISC_R_FAILURE;
*
* return (NS_HOOK_RETURN);
* }
* ----------------------------------------------------------------------------
*
* If this hook action was installed in the hook table using:
*
* ----------------------------------------------------------------------------
* const ns_hook_t foo_fail = {
* .action = cause_failure,
* };
*
* ns_hook_add(..., NS_QUERY_FOO_BEGIN, &foo_fail);
* ----------------------------------------------------------------------------
*
* then query_foo() would return ISC_R_FAILURE every time it is called due
* to the cause_failure() hook action returning NS_HOOK_RETURN and setting
* '*resultp' to ISC_R_FAILURE. query_foo() would also never log the
* "Lorem ipsum dolor sit amet..." message.
*
* Consider a different hook action:
*
* ----------------------------------------------------------------------------
* static ns_hookresult_t
* log_qtype(void *hook_data, void *action_data, isc_result_t *resultp) {
* query_ctx_t *qctx = (query_ctx_t *)hook_data;
* FILE *stream = (FILE *)action_data;
*
* UNUSED(resultp);
*
* fprintf(stream, "QTYPE=%u\n", qctx->qtype);
*
* return (NS_HOOK_CONTINUE);
* }
* ----------------------------------------------------------------------------
*
* If this hook action was installed in the hook table instead of
* cause_failure(), using:
*
* ----------------------------------------------------------------------------
* const ns_hook_t foo_log_qtype = {
* .action = log_qtype,
* .action_data = stderr,
* };
*
* ns_hook_add(..., NS_QUERY_FOO_BEGIN, &foo_log_qtype);
* ----------------------------------------------------------------------------
*
* then the QTYPE stored in the query context passed to query_foo() would be
* logged to stderr upon each call to that function; 'qctx' would be passed to
* the hook action in 'hook_data' since it is specified in the CALL_HOOK() call
* inside query_foo() while stderr would be passed to the hook action in
* 'action_data' since it is specified in the ns_hook_t structure passed to
* ns_hook_add(). As the hook action returns NS_HOOK_CONTINUE,
* query_foo() would also be logging the "Lorem ipsum dolor sit amet..."
* message before returning ISC_R_COMPLETE.
*/
/*!
* Currently-defined hook points. So long as these are unique,
* the order in which they are declared is unimportant, but
* currently matches the order in which they are referenced in
* query.c.
*/
typedef enum {
/* hookpoints from query.c */
NS_QUERY_QCTX_INITIALIZED,
NS_QUERY_QCTX_DESTROYED,
NS_QUERY_SETUP,
NS_QUERY_START_BEGIN,
NS_QUERY_LOOKUP_BEGIN,
NS_QUERY_RESUME_BEGIN,
NS_QUERY_RESUME_RESTORED,
NS_QUERY_GOT_ANSWER_BEGIN,
NS_QUERY_RESPOND_ANY_BEGIN,
NS_QUERY_RESPOND_ANY_FOUND,
NS_QUERY_ADDANSWER_BEGIN,
NS_QUERY_RESPOND_BEGIN,
NS_QUERY_NOTFOUND_BEGIN,
NS_QUERY_NOTFOUND_RECURSE,
NS_QUERY_PREP_DELEGATION_BEGIN,
NS_QUERY_ZONE_DELEGATION_BEGIN,
NS_QUERY_DELEGATION_BEGIN,
NS_QUERY_DELEGATION_RECURSE_BEGIN,
NS_QUERY_NODATA_BEGIN,
NS_QUERY_NXDOMAIN_BEGIN,
NS_QUERY_NCACHE_BEGIN,
NS_QUERY_ZEROTTL_RECURSE,
NS_QUERY_CNAME_BEGIN,
NS_QUERY_DNAME_BEGIN,
NS_QUERY_PREP_RESPONSE_BEGIN,
NS_QUERY_DONE_BEGIN,
NS_QUERY_DONE_SEND,
/* XXX other files could be added later */
NS_HOOKPOINTS_COUNT /* MUST BE LAST */
} ns_hookpoint_t;
/*
* Returned by a hook action to indicate how to proceed after it has
* been called: continue processing, or return immediately.
*/
typedef enum {
NS_HOOK_CONTINUE,
NS_HOOK_RETURN,
} ns_hookresult_t;
typedef ns_hookresult_t
(*ns_hook_action_t)(void *arg, void *data, isc_result_t *resultp);
typedef struct ns_hook {
isc_mem_t *mctx;
ns_hook_action_t action;
void *action_data;
ISC_LINK(struct ns_hook) link;
} ns_hook_t;
typedef ISC_LIST(ns_hook_t) ns_hooklist_t;
typedef ns_hooklist_t ns_hooktable_t[NS_HOOKPOINTS_COUNT];
/*%
* ns__hook_table is a global hook table, which is used if view->hooktable
* is NULL. It's intended only for use by unit tests.
*/
LIBNS_EXTERNAL_DATA extern ns_hooktable_t *ns__hook_table;
/*
* Plugin API version
*
* When the API changes, increment NS_PLUGIN_VERSION. If the
* change is backward-compatible (e.g., adding a new function call
* but not changing or removing an old one), increment NS_PLUGIN_AGE
* as well; if not, set NS_PLUGIN_AGE to 0.
*/
#ifndef NS_PLUGIN_VERSION
#define NS_PLUGIN_VERSION 1
#define NS_PLUGIN_AGE 0
#endif
typedef isc_result_t
ns_plugin_register_t(const char *parameters,
const void *cfg, const char *file, unsigned long line,
isc_mem_t *mctx, isc_log_t *lctx, void *actx,
ns_hooktable_t *hooktable, void **instp);
/*%<
* Called when registering a new plugin.
*
* 'parameters' contains the plugin configuration text.
*
* '*instp' will be set to the module instance handle if the function
* is successful.
*
* Returns:
*\li #ISC_R_SUCCESS
*\li #ISC_R_NOMEMORY
*\li Other errors are possible
*/
typedef void
ns_plugin_destroy_t(void **instp);
/*%<
* Destroy a plugin instance.
*
* '*instp' must be set to NULL by the function before it returns.
*/
typedef isc_result_t
ns_plugin_check_t(const char *parameters,
const void *cfg, const char *file, unsigned long line,
isc_mem_t *mctx, isc_log_t *lctx, void *actx);
/*%<
* Check the validity of 'parameters'.
*/
typedef int
ns_plugin_version_t(void);
/*%<
* Return the API version number a plugin was compiled with.
*
* If the returned version number is no greater than
* NS_PLUGIN_VERSION, and no less than NS_PLUGIN_VERSION - NS_PLUGIN_AGE,
* then the module is API-compatible with named.
*/
/*%
* Prototypes for API functions to be defined in each module.
*/
ns_plugin_check_t plugin_check;
ns_plugin_destroy_t plugin_destroy;
ns_plugin_register_t plugin_register;
ns_plugin_version_t plugin_version;
isc_result_t
ns_plugin_register(const char *modpath, const char *parameters,
const void *cfg, const char *cfg_file,
unsigned long cfg_line,
isc_mem_t *mctx, isc_log_t *lctx, void *actx,
dns_view_t *view);
/*%<
* Load the plugin module specified from the file 'modpath', and
* register an instance using 'parameters'.
*
* 'cfg_file' and 'cfg_line' specify the location of the plugin
* declaration in the configuration file.
*
* 'cfg' and 'actx' are the configuration context and ACL configuration
* context, respectively; they are passed as void * here in order to
* prevent this library from having a dependency on libisccfg).
*
* 'instp' will be left pointing to the instance of the plugin
* created by the module's plugin_register function.
*/
isc_result_t
ns_plugin_check(const char *modpath, const char *parameters,
const void *cfg, const char *cfg_file, unsigned long cfg_line,
isc_mem_t *mctx, isc_log_t *lctx, void *actx);
/*%<
* Open the plugin module at 'modpath' and check the validity of
* 'parameters', logging any errors or warnings found, then
* close it without configuring it.
*/
void
ns_plugins_create(isc_mem_t *mctx, ns_plugins_t **listp);
/*%<
* Create and initialize a plugin list.
*/
void
ns_plugins_free(isc_mem_t *mctx, void **listp);
/*%<
* Close each plugin module in a plugin list, then free the list object.
*/
void
ns_hooktable_free(isc_mem_t *mctx, void **tablep);
/*%<
* Free a hook table.
*/
void
ns_hook_add(ns_hooktable_t *hooktable, isc_mem_t *mctx,
ns_hookpoint_t hookpoint, const ns_hook_t *hook);
/*%<
* Allocate (using memory context 'mctx') a copy of the 'hook' structure
* describing a hook action and append it to the list of hooks at 'hookpoint'
* in 'hooktable'.
*
* Requires:
*\li 'hooktable' is not NULL
*
*\li 'mctx' is not NULL
*
*\li 'hookpoint' is less than NS_QUERY_HOOKS_COUNT
*
*\li 'hook' is not NULL
*/
void
ns_hooktable_init(ns_hooktable_t *hooktable);
/*%<
* Initialize a hook table.
*/
isc_result_t
ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep);
/*%<
* Allocate and initialize a hook table.
*/
#endif /* NS_HOOKS_H */

View file

@ -42,6 +42,7 @@ LIBNS_EXTERNAL_DATA extern isc_logmodule_t ns_modules[];
#define NS_LOGMODULE_XFER_IN (&ns_modules[4])
#define NS_LOGMODULE_XFER_OUT (&ns_modules[5])
#define NS_LOGMODULE_NOTIFY (&ns_modules[6])
#define NS_LOGMODULE_HOOKS (&ns_modules[7])
void
ns_log_init(isc_log_t *lctx);

View file

@ -31,8 +31,8 @@
typedef struct ns_dbversion {
dns_db_t *db;
dns_dbversion_t *version;
bool acl_checked;
bool queryok;
bool acl_checked;
bool queryok;
ISC_LINK(struct ns_dbversion) link;
} ns_dbversion_t;
@ -52,7 +52,7 @@ typedef struct ns_query_recparam {
struct ns_query {
unsigned int attributes;
unsigned int restarts;
bool timerset;
bool timerset;
dns_name_t * qname;
dns_name_t * origqname;
dns_rdatatype_t qtype;
@ -61,8 +61,8 @@ struct ns_query {
dns_db_t * gluedb;
dns_db_t * authdb;
dns_zone_t * authzone;
bool authdbset;
bool isreferral;
bool authdbset;
bool isreferral;
isc_mutex_t fetchlock;
dns_fetch_t * fetch;
dns_fetch_t * prefetch;
@ -72,7 +72,7 @@ struct ns_query {
ISC_LIST(ns_dbversion_t) freeversions;
dns_rdataset_t * dns64_aaaa;
dns_rdataset_t * dns64_sigaaaa;
bool * dns64_aaaaok;
bool * dns64_aaaaok;
unsigned int dns64_aaaaoklen;
unsigned int dns64_options;
unsigned int dns64_ttl;
@ -87,8 +87,8 @@ struct ns_query {
isc_result_t result;
dns_rdataset_t * rdataset;
dns_rdataset_t * sigrdataset;
bool authoritative;
bool is_zone;
bool authoritative;
bool is_zone;
} redirect;
ns_query_recparam_t recparam;
@ -98,29 +98,33 @@ struct ns_query {
bool root_key_sentinel_not_ta;
};
#define NS_QUERYATTR_RECURSIONOK 0x0001
#define NS_QUERYATTR_CACHEOK 0x0002
#define NS_QUERYATTR_PARTIALANSWER 0x0004
#define NS_QUERYATTR_NAMEBUFUSED 0x0008
#define NS_QUERYATTR_RECURSING 0x0010
#define NS_QUERYATTR_QUERYOKVALID 0x0040
#define NS_QUERYATTR_QUERYOK 0x0080
#define NS_QUERYATTR_WANTRECURSION 0x0100
#define NS_QUERYATTR_SECURE 0x0200
#define NS_QUERYATTR_NOAUTHORITY 0x0400
#define NS_QUERYATTR_NOADDITIONAL 0x0800
#define NS_QUERYATTR_CACHEACLOKVALID 0x1000
#define NS_QUERYATTR_CACHEACLOK 0x2000
#define NS_QUERYATTR_DNS64 0x4000
#define NS_QUERYATTR_DNS64EXCLUDE 0x8000
#define NS_QUERYATTR_RECURSIONOK 0x00001
#define NS_QUERYATTR_CACHEOK 0x00002
#define NS_QUERYATTR_PARTIALANSWER 0x00004
#define NS_QUERYATTR_NAMEBUFUSED 0x00008
#define NS_QUERYATTR_RECURSING 0x00010
#define NS_QUERYATTR_QUERYOKVALID 0x00040
#define NS_QUERYATTR_QUERYOK 0x00080
#define NS_QUERYATTR_WANTRECURSION 0x00100
#define NS_QUERYATTR_SECURE 0x00200
#define NS_QUERYATTR_NOAUTHORITY 0x00400
#define NS_QUERYATTR_NOADDITIONAL 0x00800
#define NS_QUERYATTR_CACHEACLOKVALID 0x01000
#define NS_QUERYATTR_CACHEACLOK 0x02000
#define NS_QUERYATTR_DNS64 0x04000
#define NS_QUERYATTR_DNS64EXCLUDE 0x08000
#define NS_QUERYATTR_RRL_CHECKED 0x10000
#define NS_QUERYATTR_REDIRECT 0x20000
/* query context structure */
typedef struct query_ctx query_ctx_t;
typedef struct query_ctx {
/* query context structure */
struct query_ctx {
isc_buffer_t *dbuf; /* name buffer */
dns_name_t *fname; /* found name from DB lookup */
dns_name_t *tname; /* temporary name, used
* when processing ANY
* queries */
dns_rdataset_t *rdataset; /* found rdataset */
dns_rdataset_t *sigrdataset; /* found sigrdataset */
dns_rdataset_t *noqname; /* rdataset needing
@ -146,6 +150,8 @@ typedef struct query_ctx {
dns_fixedname_t dsname; /* name needing DS */
ns_client_t *client; /* client object */
bool detach_client; /* client needs detaching */
dns_fetchevent_t *event; /* recursion event */
dns_db_t *db; /* zone or cache database */
@ -162,9 +168,40 @@ typedef struct query_ctx {
dns_rpz_st_t *rpz_st; /* RPZ state */
dns_zone_t *zone; /* zone to search */
dns_view_t *view; /* client view */
isc_result_t result; /* query result */
int line; /* line to report error */
} query_ctx_t;
};
/*
* The following functions are expected to be used only within query.c
* and query modules.
*/
isc_result_t
ns_query_done(query_ctx_t *qctx);
/*%<
* Finalize this phase of the query process:
*
* - Clean up.
* - If we have an answer ready (positive or negative), send it.
* - If we need to restart for a chaining query, call ns__query_start() again.
* - If we've started recursion, then just clean up; things will be
* restarted via fetch_callback()/query_resume().
*/
isc_result_t
ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
dns_name_t *qdomain, dns_rdataset_t *nameservers,
bool resuming);
/*%<
* Prepare client for recursion, then create a resolver fetch, with
* the event callback set to fetch_callback(). Afterward we terminate
* this phase of the query, and resume with a new query context when
* recursion completes.
*/
isc_result_t
ns_query_init(ns_client_t *client);
@ -178,16 +215,45 @@ ns_query_start(ns_client_t *client);
void
ns_query_cancel(ns_client_t *client);
/*%
* (Must not be used outside this module and its associated unit tests.)
/*
* The following functions are expected to be used only within query.c
* and query modules.
*/
isc_result_t
ns_query_done(query_ctx_t *qctx);
/*%<
* Finalize this phase of the query process:
*
* - Clean up.
* - If we have an answer ready (positive or negative), send it.
* - If we need to restart for a chaining query, call ns__query_start() again.
* - If we've started recursion, then just clean up; things will be
* restarted via fetch_callback()/query_resume().
*/
isc_result_t
ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
dns_name_t *qdomain, dns_rdataset_t *nameservers,
bool resuming);
/*%<
* Prepare client for recursion, then create a resolver fetch, with
* the event callback set to fetch_callback(). Afterward we terminate
* this phase of the query, and resume with a new query context when
* recursion completes.
*/
isc_result_t
ns__query_sfcache(query_ctx_t *qctx);
/*%
/*%<
* (Must not be used outside this module and its associated unit tests.)
*/
isc_result_t
ns__query_start(query_ctx_t *qctx);
/*%<
* (Must not be used outside this module and its associated unit tests.)
*/
#endif /* NS_QUERY_H */

View file

@ -18,6 +18,8 @@ typedef struct ns_altsecret ns_altsecret_t;
typedef ISC_LIST(ns_altsecret_t) ns_altsecretlist_t;
typedef struct ns_client ns_client_t;
typedef struct ns_clientmgr ns_clientmgr_t;
typedef struct ns_plugin ns_plugin_t;
typedef ISC_LIST(ns_plugin_t) ns_plugins_t;
typedef struct ns_interface ns_interface_t;
typedef struct ns_interfacemgr ns_interfacemgr_t;
typedef struct ns_query ns_query_t;

View file

@ -50,6 +50,7 @@ LIBNS_EXTERNAL_DATA isc_logmodule_t ns_modules[] = {
{ "ns/xfer-in", 0 },
{ "ns/xfer-out", 0 },
{ "ns/notify", 0 },
{ "ns/hooks", 0 },
{ NULL, 0 }
};

File diff suppressed because it is too large Load diff

View file

@ -22,6 +22,7 @@
#include <dns/tkey.h>
#include <dns/stats.h>
#include <ns/query.h>
#include <ns/server.h>
#include <ns/stats.h>

View file

@ -20,8 +20,6 @@
#include <isc/util.h>
#ifdef NS_HOOKS_ENABLE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@ -126,18 +124,6 @@ main(void) {
return (cmocka_run_group_tests(tests, NULL, NULL));
}
#else
#include <stdio.h>
int
main(void) {
printf("1..0 # Skipped: libns hooks not enabled\n");
return (0);
}
#endif /* NS_HOOKS_ENABLE */
#else /* HAVE_CMOCKA */
#include <stdio.h>

View file

@ -20,8 +20,6 @@
#include <isc/util.h>
#ifdef NS_HOOKS_ENABLE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@ -154,18 +152,6 @@ main(void) {
return (cmocka_run_group_tests(tests, NULL, NULL));
}
#else
#include <stdio.h>
int
main(void) {
printf("1..0 # Skipped: libns hooks not enabled\n");
return (0);
}
#endif /* NS_HOOKS_ENABLE */
#else /* HAVE_CMOCKA */
#include <stdio.h>

View file

@ -13,8 +13,6 @@
#include <config.h>
#ifdef NS_HOOKS_ENABLE
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
@ -47,11 +45,10 @@
#include <dns/zone.h>
#include <ns/client.h>
#include <ns/hooks.h>
#include <ns/interfacemgr.h>
#include <ns/server.h>
#include "../hooks.h"
#include "nstest.h"
isc_mem_t *mctx = NULL;
@ -287,8 +284,6 @@ ns_test_begin(FILE *logfile, bool start_managers) {
CHECK(ISC_R_FAILURE);
}
ns__hook_table = NULL;
return (ISC_R_SUCCESS);
cleanup:
@ -634,17 +629,17 @@ destroy_message:
}
/*%
* A hook callback which stores the query context pointed to by "hook_data" at
* "callback_data". Causes execution to be interrupted at hook insertion
* A hook action which stores the query context pointed to by "arg" at
* "data". Causes execution to be interrupted at hook insertion
* point.
*/
static bool
extract_qctx(void *hook_data, void *callback_data, isc_result_t *resultp) {
static ns_hookresult_t
extract_qctx(void *arg, void *data, isc_result_t *resultp) {
query_ctx_t **qctxp;
query_ctx_t *qctx;
REQUIRE(hook_data != NULL);
REQUIRE(callback_data != NULL);
REQUIRE(arg != NULL);
REQUIRE(data != NULL);
REQUIRE(resultp != NULL);
/*
@ -654,10 +649,10 @@ extract_qctx(void *hook_data, void *callback_data, isc_result_t *resultp) {
*/
qctx = isc_mem_get(mctx, sizeof(*qctx));
if (qctx != NULL) {
memmove(qctx, (query_ctx_t *)hook_data, sizeof(*qctx));
memmove(qctx, (query_ctx_t *)arg, sizeof(*qctx));
}
qctxp = (query_ctx_t **)callback_data;
qctxp = (query_ctx_t **)data;
/*
* If memory allocation failed, the supplied pointer will simply be set
* to NULL. We rely on the user of this hook to react properly.
@ -665,7 +660,7 @@ extract_qctx(void *hook_data, void *callback_data, isc_result_t *resultp) {
*qctxp = qctx;
*resultp = ISC_R_UNSET;
return (true);
return (NS_HOOK_RETURN);
}
/*%
@ -677,12 +672,10 @@ extract_qctx(void *hook_data, void *callback_data, isc_result_t *resultp) {
*/
static isc_result_t
create_qctx_for_client(ns_client_t *client, query_ctx_t **qctxp) {
ns_hook_t *saved_hook_table;
ns_hook_t query_hooks[NS_QUERY_HOOKS_COUNT + 1] = {
[NS_QUERY_SETUP_QCTX_INITIALIZED] = {
.callback = extract_qctx,
.callback_data = qctxp,
},
ns_hooktable_t *saved_hook_table = NULL, *query_hooks = NULL;
const ns_hook_t hook = {
.action = extract_qctx,
.action_data = qctxp,
};
REQUIRE(client != NULL);
@ -696,10 +689,17 @@ create_qctx_for_client(ns_client_t *client, query_ctx_t **qctxp) {
* further processing. Make sure we do not overwrite any previously
* set hooks.
*/
ns_hooktable_create(mctx, &query_hooks);
ns_hook_add(query_hooks, mctx, NS_QUERY_SETUP, &hook);
saved_hook_table = ns__hook_table;
ns__hook_table = query_hooks;
ns_query_start(client);
ns__hook_table = saved_hook_table;
ns_hooktable_free(mctx, (void **)&query_hooks);
if (*qctxp == NULL) {
return (ISC_R_NOMEMORY);
@ -801,16 +801,15 @@ ns_test_qctx_destroy(query_ctx_t **qctxp) {
*qctxp = NULL;
}
bool
ns_test_hook_catch_call(void *hook_data, void *callback_data,
isc_result_t *resultp)
ns_hookresult_t
ns_test_hook_catch_call(void *arg, void *data, isc_result_t *resultp)
{
UNUSED(hook_data);
UNUSED(callback_data);
UNUSED(arg);
UNUSED(data);
*resultp = ISC_R_UNSET;
return (true);
return (NS_HOOK_RETURN);
}
/*
@ -927,4 +926,3 @@ ns_test_getdata(const char *file, unsigned char *buf,
isc_stdio_close(f);
return (result);
}
#endif

View file

@ -30,6 +30,7 @@
#include <ns/interfacemgr.h>
#include <ns/client.h>
#include <ns/hooks.h>
typedef struct ns_test_id {
const char *description;
@ -150,6 +151,5 @@ ns_test_qctx_destroy(query_ctx_t **qctxp);
/*%
* A hook callback interrupting execution at given hook's insertion point.
*/
bool
ns_test_hook_catch_call(void *hook_data, void *callback_data,
isc_result_t *resultp);
ns_hookresult_t
ns_test_hook_catch_call(void *arg, void *data, isc_result_t *resultp);

View file

@ -19,8 +19,6 @@
#include <isc/util.h>
#ifdef NS_HOOKS_ENABLE
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
@ -31,12 +29,12 @@
#include <dns/badcache.h>
#include <dns/view.h>
#include <ns/client.h>
#include <ns/hooks.h>
#include <ns/query.h>
#include <isc/util.h>
#include "../hooks.h"
#include "nstest.h"
static int
@ -84,8 +82,12 @@ typedef struct {
*/
static void
run_sfcache_test(const ns__query_sfcache_test_params_t *test) {
ns_hooktable_t *query_hooks = NULL;
query_ctx_t *qctx = NULL;
isc_result_t result;
const ns_hook_t hook = {
.action = ns_test_hook_catch_call,
};
REQUIRE(test != NULL);
REQUIRE(test->id.description != NULL);
@ -93,14 +95,11 @@ run_sfcache_test(const ns__query_sfcache_test_params_t *test) {
test->cache_entry_flags == 0);
/*
* Interrupt execution if query_done() is called.
* Interrupt execution if ns_query_done() is called.
*/
ns_hook_t query_hooks[NS_QUERY_HOOKS_COUNT + 1] = {
[NS_QUERY_DONE_BEGIN] = {
.callback = ns_test_hook_catch_call,
.callback_data = NULL,
},
};
ns_hooktable_create(mctx, &query_hooks);
ns_hook_add(query_hooks, mctx, NS_QUERY_DONE_BEGIN, &hook);
ns__hook_table = query_hooks;
/*
@ -160,6 +159,7 @@ run_sfcache_test(const ns__query_sfcache_test_params_t *test) {
* Clean up.
*/
ns_test_qctx_destroy(&qctx);
ns_hooktable_free(mctx, (void **)&query_hooks);
}
/* test ns__query_sfcache() */
@ -282,8 +282,12 @@ typedef struct {
*/
static void
run_start_test(const ns__query_start_test_params_t *test) {
ns_hooktable_t *query_hooks = NULL;
query_ctx_t *qctx = NULL;
isc_result_t result;
const ns_hook_t hook = {
.action = ns_test_hook_catch_call,
};
REQUIRE(test != NULL);
REQUIRE(test->id.description != NULL);
@ -293,18 +297,11 @@ run_start_test(const ns__query_start_test_params_t *test) {
test->auth_zone_path != NULL));
/*
* Interrupt execution if query_lookup() or query_done() is called.
* Interrupt execution if query_lookup() or ns_query_done() is called.
*/
ns_hook_t query_hooks[NS_QUERY_HOOKS_COUNT + 1] = {
[NS_QUERY_LOOKUP_BEGIN] = {
.callback = ns_test_hook_catch_call,
.callback_data = NULL,
},
[NS_QUERY_DONE_BEGIN] = {
.callback = ns_test_hook_catch_call,
.callback_data = NULL,
},
};
ns_hooktable_create(mctx, &query_hooks);
ns_hook_add(query_hooks, mctx, NS_QUERY_LOOKUP_BEGIN, &hook);
ns_hook_add(query_hooks, mctx, NS_QUERY_DONE_BEGIN, &hook);
ns__hook_table = query_hooks;
/*
@ -421,6 +418,7 @@ run_start_test(const ns__query_start_test_params_t *test) {
ns_test_cleanup_zone();
}
ns_test_qctx_destroy(&qctx);
ns_hooktable_free(mctx, (void **)&query_hooks);
}
/* test ns__query_start() */
@ -604,18 +602,6 @@ main(void) {
return (cmocka_run_group_tests(tests, NULL, NULL));
}
#else
#include <stdio.h>
int
main(void) {
printf("1..0 # Skipped: libns hooks not enabled\n");
return (0);
}
#endif /* NS_HOOKS_ENABLE */
#else /* HAVE_CMOCKA */
#include <stdio.h>

View file

@ -17,14 +17,23 @@ ns_client_checkaclsilent
ns_client_detach
ns_client_dumprecursing
ns_client_error
ns_client_getsockaddr
ns_client_findversion
ns_client_getdestaddr
ns_client_getnamebuf
ns_client_getsockaddr
ns_client_keepname
ns_client_killoldestquery
ns_client_log
ns_client_logv
ns_client_newdbversion
ns_client_newname
ns_client_newnamebuf
ns_client_newrdataset
ns_client_next
ns_client_putrdataset
ns_client_qnamereplace
ns_client_recursing
ns_client_releasename
ns_client_replace
ns_client_send
ns_client_sendraw
@ -34,6 +43,12 @@ ns_client_sourceip
ns_clientmgr_create
ns_clientmgr_createclients
ns_clientmgr_destroy
ns_hook_add
ns_hooktable_create
ns_hooktable_free
ns_hooktable_init
ns_hooktable_reset
ns_hooktable_save
ns_interface_attach
ns_interface_detach
ns_interface_shutdown
@ -61,9 +76,15 @@ ns_listenlist_detach
ns_log_init
ns_log_setcontext
ns_notify_start
ns_plugin_check
ns_plugin_register
ns_plugins_create
ns_plugins_free
ns_query_cancel
ns_query_done
ns_query_free
ns_query_init
ns_query_recurse
ns_query_start
ns_server_attach
ns_server_create

View file

@ -153,6 +153,7 @@
./bin/dnssec/win32/verify.vcxproj.filters.in X 2013,2015,2018
./bin/dnssec/win32/verify.vcxproj.in X 2013,2014,2015,2016,2017,2018
./bin/dnssec/win32/verify.vcxproj.user X 2013,2018
./bin/named/Makefile.in MAKE 1998,1999,2000,2001,2002,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018
./bin/named/bind9.xsl SGML 2006,2007,2008,2009,2012,2013,2014,2015,2016,2017,2018
./bin/named/bind9.xsl.h X 2007,2008,2009,2011,2012,2013,2014,2015,2016,2017,2018
./bin/named/builtin.c C 2001,2002,2003,2004,2005,2007,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018
@ -239,6 +240,10 @@
./bin/pkcs11/win32/pk11tokens.vcxproj.filters.in X 2014,2015,2018
./bin/pkcs11/win32/pk11tokens.vcxproj.in X 2014,2015,2016,2017,2018
./bin/pkcs11/win32/pk11tokens.vcxproj.user X 2014,2018
./bin/plugins/filter-aaaa.8 MAN DOCBOOK
./bin/plugins/filter-aaaa.c C 2018
./bin/plugins/filter-aaaa.docbook SGML 2018
./bin/plugins/filter-aaaa.html HTML DOCBOOK
./bin/python/dnssec-checkds.8 MAN DOCBOOK
./bin/python/dnssec-checkds.docbook SGML 2012,2013,2014,2015,2016,2017,2018
./bin/python/dnssec-checkds.html HTML DOCBOOK
@ -622,6 +627,7 @@
./bin/tests/system/filter-aaaa/clean.sh SH 2010,2012,2014,2016,2018
./bin/tests/system/filter-aaaa/ns1/sign.sh SH 2010,2012,2014,2016,2018
./bin/tests/system/filter-aaaa/ns4/sign.sh SH 2010,2012,2014,2016,2018
./bin/tests/system/filter-aaaa/prereq.sh SH 2018
./bin/tests/system/filter-aaaa/setup.sh SH 2010,2012,2014,2016,2017,2018
./bin/tests/system/filter-aaaa/tests.sh SH 2010,2012,2015,2016,2018
./bin/tests/system/formerr/clean.sh SH 2013,2014,2015,2016,2018
@ -1469,6 +1475,7 @@
./doc/arm/man.dnssec-signzone.html X 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018
./doc/arm/man.dnssec-verify.html X 2012,2013,2014,2015,2016,2017,2018
./doc/arm/man.dnstap-read.html X 2015,2016,2017,2018
./doc/arm/man.filter-aaaa.html X 2018
./doc/arm/man.host.html X 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018
./doc/arm/man.mdig.html X 2016,2017,2018
./doc/arm/man.named-checkconf.html X 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018
@ -1503,6 +1510,7 @@
./doc/arm/options.grammar.xml SGML 2018
./doc/arm/pkcs11.xml SGML 2010,2012,2013,2014,2015,2016,2018
./doc/arm/pkgversion.xml.in SGML 2015,2016,2018
./doc/arm/plugins.xml SGML 2018
./doc/arm/redirect.zoneopt.xml SGML 2018
./doc/arm/releaseinfo.xml.in SGML 2015,2016,2018
./doc/arm/server.grammar.xml SGML 2018
@ -2480,8 +2488,9 @@
./lib/ns/Kyuafile X 2017,2018
./lib/ns/api X 2017,2018
./lib/ns/client.c C 2017,2018
./lib/ns/hooks.h C 2017,2018
./lib/ns/hooks.c C 2018
./lib/ns/include/ns/client.h C 2017,2018
./lib/ns/include/ns/hooks.h C 2017,2018
./lib/ns/include/ns/interfacemgr.h C 2017,2018
./lib/ns/include/ns/lib.h C 2017,2018
./lib/ns/include/ns/listenlist.h C 2017,2018

View file

@ -360,7 +360,6 @@ my @enablelist = ("developer",
"isc-spnego",
"native-pkcs11",
"openssl-hash",
"filter-aaaa",
"querytrace",
"rpz-nsdname",
"rpz-nsip");