diff --git a/bin/Makefile.in b/bin/Makefile.in index f0c504a17ee8739228cebf3892d269fdbe10753d..8e55b450dcbd18f67f29699019c5e24c904b634d 100644 --- a/bin/Makefile.in +++ b/bin/Makefile.in @@ -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@ hooks tests TARGETS = @BIND9_MAKE_RULES@ diff --git a/bin/hooks/Makefile.in b/bin/hooks/Makefile.in new file mode 100644 index 0000000000000000000000000000000000000000..9adccfafc7cfb4ffca49bdff6a70432c39002ded --- /dev/null +++ b/bin/hooks/Makefile.in @@ -0,0 +1,69 @@ +# 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 = ${NSLIBS} ${DNSLIBS} ${ISCCFGLIBS} ${ISCLIBS} @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} + +clean distclean maintainer-clean:: + 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 diff --git a/bin/hooks/filter-aaaa.8 b/bin/hooks/filter-aaaa.8 new file mode 100644 index 0000000000000000000000000000000000000000..eca65096b240fbf94296626ade793b384ba70029 --- /dev/null +++ b/bin/hooks/filter-aaaa.8 @@ -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 +.\" 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 impleented 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 diff --git a/bin/hooks/filter-aaaa.c b/bin/hooks/filter-aaaa.c new file mode 100644 index 0000000000000000000000000000000000000000..66ac9abf598d795e30063d1ba152aafd8f732db2 --- /dev/null +++ b/bin/hooks/filter-aaaa.c @@ -0,0 +1,826 @@ +/* + * 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 + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + +/* + * Memory pool for use with persistent data. + */ +static isc_mempool_t *datapool = NULL; + +/* + * Hash table associating a client object with its persistent data. + */ +static isc_ht_t *client_ht = NULL; + +/* + * 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) + +/* + * Hook registration structures: pointers to these structures will + * be added to a hook table when this module is registered. + */ +static bool +filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp); +static ns_hook_t filter_init = { + .action = filter_qctx_initialize, + .action_data = &client_ht, +}; + +static bool +filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp); +static ns_hook_t filter_respbegin = { + .action = filter_respond_begin, + .action_data = &client_ht, +}; + +static bool +filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp); +static ns_hook_t filter_respanyfound = { + .action = filter_respond_any_found, + .action_data = &client_ht, +}; + +static bool +filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp); +static ns_hook_t filter_prepresp = { + .action = filter_prep_response_begin, + .action_data = &client_ht, +}; + +static bool +filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp); +static ns_hook_t filter_donesend = { + .action = filter_query_done_send, + .action_data = &client_ht, +}; + +static bool +filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp); +ns_hook_t filter_destroy = { + .action = filter_qctx_destroy, + .action_data = &client_ht, +}; + +/** + ** Support for parsing of parameters and configuration of the module. + **/ + +/* + * Values configured when the module is loaded. + */ +static filter_aaaa_t v4_aaaa = NONE; +static filter_aaaa_t v6_aaaa = NONE; +static dns_acl_t *aaaa_acl = NULL; + +/* + * 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 +parse_parameters(const char *parameters, const void *cfg, + void *actx, ns_hookctx_t *hctx) +{ + 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(hctx->mctx, hctx->lctx, &parser)); + + isc_buffer_constinit(&b, parameters, strlen(parameters)); + isc_buffer_add(&b, strlen(parameters)); + CHECK(cfg_parse_buffer(parser, &b, &cfg_type_parameters, + ¶m_obj)); + + CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v4", &v4_aaaa)); + CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v6", &v6_aaaa)); + + obj = NULL; + result = cfg_map_get(param_obj, "filter-aaaa", &obj); + if (result == ISC_R_SUCCESS) { + CHECK(cfg_acl_fromconfig(obj, (const cfg_obj_t *) cfg, + hctx->lctx, + (cfg_aclconfctx_t *) actx, + hctx->mctx, 0, &aaaa_acl)); + } else { + CHECK(dns_acl_any(hctx->mctx, &aaaa_acl)); + } + + cleanup: + if (param_obj != NULL) { + cfg_obj_destroy(parser, ¶m_obj); + } + if (parser != NULL) { + cfg_parser_destroy(&parser); + } + return (result); +} + +/** + ** Mandatory hook API functions: + ** + ** - hook_destroy + ** - hook_register + ** - hook_version + **/ + +/* + * Called by ns_hookmodule_load() to register hook functions into + * a hook table. + */ +isc_result_t +hook_register(const char *parameters, + const char *cfg_file, unsigned long cfg_line, + const void *cfg, void *actx, + ns_hookctx_t *hctx, ns_hooktable_t *hooktable) +{ + isc_result_t result; + + /* + * Depending on how dlopen() works on the current platform, we + * may not have access to named's global namespace, in which + * case we need to initialize libisc/libdns/libns. We compare + * the address of a global reference variable to its address + * in the calling program to determine whether this is necessary. + */ + if (hctx->refvar != &isc_bind9) { + isc_lib_register(); + isc_log_setcontext(hctx->lctx); + dns_log_setcontext(hctx->lctx); + ns_log_setcontext(hctx->lctx); + } + + isc_hash_set_initializer(hctx->hashinit); + + isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_INFO, + "loading 'filter-aaaa' " + "module from %s:%lu, %s parameters", + cfg_file, cfg_line, parameters != NULL ? "with" : "no"); + + if (parameters != NULL) { + CHECK(parse_parameters(parameters, cfg, actx, hctx)); + } + + ns_hook_add(hooktable, hctx->mctx, NS_QUERY_QCTX_INITIALIZED, + &filter_init); + ns_hook_add(hooktable, hctx->mctx, NS_QUERY_RESPOND_BEGIN, + &filter_respbegin); + ns_hook_add(hooktable, hctx->mctx, NS_QUERY_RESPOND_ANY_FOUND, + &filter_respanyfound); + ns_hook_add(hooktable, hctx->mctx, NS_QUERY_PREP_RESPONSE_BEGIN, + &filter_prepresp); + ns_hook_add(hooktable, hctx->mctx, NS_QUERY_DONE_SEND, + &filter_donesend); + ns_hook_add(hooktable, hctx->mctx, NS_QUERY_QCTX_DESTROYED, + &filter_destroy); + + CHECK(isc_mempool_create(hctx->mctx, sizeof(filter_data_t), + &datapool)); + + CHECK(isc_ht_init(&client_ht, hctx->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(datapool, 1024); + isc_mempool_setfreemax(datapool, UINT_MAX); + + cleanup: + if (result != ISC_R_SUCCESS) { + if (datapool != NULL) { + isc_mempool_destroy(&datapool); + } + } + return (result); +} + +/* + * Called by ns_hookmodule_unload_all(); frees memory allocated by + * the module when it was registered. + */ +void +hook_destroy(void) { + if (client_ht != NULL) { + isc_ht_destroy(&client_ht); + } + if (datapool != NULL) { + isc_mempool_destroy(&datapool); + } + if (aaaa_acl != NULL) { + dns_acl_detach(&aaaa_acl); + } + + return; +} + +/* + * Returns hook module API version for compatibility checks. + */ +int +hook_version(void) { + return (NS_HOOK_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, isc_ht_t **htp) { + filter_data_t *client_state; + isc_result_t result; + + result = isc_ht_find(*htp, (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, isc_ht_t **htp) { + filter_data_t *client_state; + isc_result_t result; + + client_state = isc_mempool_get(datapool); + if (client_state == NULL) { + return; + } + + client_state->mode = NONE; + client_state->flags = 0; + + result = isc_ht_add(*htp, (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, isc_ht_t **htp) { + filter_data_t *client_state = client_state_get(qctx, htp); + isc_result_t result; + + if (client_state == NULL) { + return; + } + + result = isc_ht_delete(*htp, (const unsigned char *)&qctx->client, + sizeof(qctx->client)); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + isc_mempool_put(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 bool +filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + isc_ht_t **htp = (isc_ht_t **) cbdata; + filter_data_t *client_state; + + *resp = ISC_R_UNSET; + + client_state = client_state_get(qctx, htp); + if (client_state == NULL) { + client_state_create(qctx, htp); + } + + return (false); +} + +/* + * 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 bool +filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + isc_ht_t **htp = (isc_ht_t **) cbdata; + filter_data_t *client_state = client_state_get(qctx, htp); + isc_result_t result; + + *resp = ISC_R_UNSET; + + if (client_state == NULL) { + return (false); + } + + if (v4_aaaa != NONE || v6_aaaa != NONE) { + result = ns_client_checkaclsilent(qctx->client, NULL, + aaaa_acl, true); + if (result == ISC_R_SUCCESS && + v4_aaaa != NONE && + is_v4_client(qctx->client)) + { + client_state->mode = v4_aaaa; + } else if (result == ISC_R_SUCCESS && + v6_aaaa != NONE && + is_v6_client(qctx->client)) + { + client_state->mode = v6_aaaa; + } + } + + return (false); +} + +/* + * 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 bool +filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + isc_ht_t **htp = (isc_ht_t **) cbdata; + filter_data_t *client_state = client_state_get(qctx, htp); + isc_result_t result = ISC_R_UNSET; + + *resp = ISC_R_UNSET; + + if (client_state == NULL) { + return (false); + } + + if (client_state->mode != BREAK_DNSSEC && + (client_state->mode != FILTER || + (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL && + dns_rdataset_isassociated(qctx->sigrdataset)))) + { + return (false); + } + + 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 = (*qctx->methods.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 = (*qctx->methods.query_done)(qctx); + + *resp = result; + + return (true); + } + + *resp = result; + return (false); +} + +/* + * When answering an ANY query, remove AAAA if A is present. + */ +static bool +filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + isc_ht_t **htp = (isc_ht_t **) cbdata; + filter_data_t *client_state = client_state_get(qctx, htp); + + *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 (false); +} + +/* + * 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 bool +filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + isc_ht_t **htp = (isc_ht_t **) cbdata; + filter_data_t *client_state = client_state_get(qctx, htp); + + *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 (false); +} + +/* + * If the client is being detached, then we can delete our persistent data + * from hash table and return it to the memory pool. + */ +static bool +filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + isc_ht_t **htp = (isc_ht_t **) cbdata; + + *resp = ISC_R_UNSET; + + if (!qctx->detach_client) { + return (false); + } + + client_state_destroy(qctx, htp); + + return (false); +} diff --git a/bin/hooks/filter-aaaa.docbook b/bin/hooks/filter-aaaa.docbook new file mode 100644 index 0000000000000000000000000000000000000000..3a12e144c6335c99707b040047122324c191287e --- /dev/null +++ b/bin/hooks/filter-aaaa.docbook @@ -0,0 +1,146 @@ + + + + + + 2018-08-13 + + + ISC + Internet Systems Consortium, Inc. + + + filter-aaaa.so + 8 + BIND9 + + + + filter-aaaa.so + filter AAAA in DNS responses when A is present + + + + + 2018 + Internet Systems Consortium, Inc. ("ISC") + + + + + + hook query "filter-aaaa.so" + { parameters }; + + + + DESCRIPTION + + filter-aaaa.so is a query hook module for + named, enabling named + to omit some IPv6 addresses when responding to clients. + + + Until BIND 9.12, this feature was implemented natively in + named and enabled with the + filter-aaaa ACL and the + filter-aaaa-on-v4 and + filter-aaaa-on-v6 options. These options are + now deprecated in named.conf, but can be + passed as parameters to the filter-aaaa.so + hook module, for example: + + +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; }; +}; + + + 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. + + + 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. + + + + OPTIONS + + + filter-aaaa + + + Specifies a list of client addresses for which AAAA + filtering is to be applied. The default is + any. + + + + + + filter-aaaa-on-v4 + + + If set to yes, the DNS client is + at an IPv4 address, in filter-aaaa, + 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. + + + If set to break-dnssec, + 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. + + + 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. + + + + + + filter-aaaa-on-v6 + + + Identical to filter-aaaa-on-v4, + except it filters AAAA responses to queries from IPv6 + clients instead of IPv4 clients. To filter all + responses, set both options to yes. + + + + + + + SEE ALSO + + BIND 9 Administrator Reference Manual. + + + + diff --git a/bin/hooks/filter-aaaa.html b/bin/hooks/filter-aaaa.html new file mode 100644 index 0000000000000000000000000000000000000000..0229922c94251f26ea23b235e4b39ba3637dd7be --- /dev/null +++ b/bin/hooks/filter-aaaa.html @@ -0,0 +1,115 @@ + + + + + +filter-aaaa.so + + +
+
+
+

Name

+

filter-aaaa.so — filter AAAA in DNS responses when A is present

+
+
+

Synopsis

+

hook query "filter-aaaa.so" [{ parameters }]; +

+
+
+

DESCRIPTION

+

+ filter-aaaa.so is a query hook module for + named, enabling named + to omit some IPv6 addresses when responding to clients. +

+

+ Until BIND 9.12, this feature was impleented natively in + named and enabled with the + filter-aaaa ACL and the + filter-aaaa-on-v4 and + filter-aaaa-on-v6 options. These options are + now deprecated in named.conf, but can be + passed as parameters to the filter-aaaa.so + hook module, for example: +

+
+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; };
+};
+
+

+ 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. +

+

+ 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. +

+
+
+

OPTIONS

+
+
filter-aaaa
+

+ Specifies a list of client addresses for which AAAA + filtering is to be applied. The default is + any. +

+
filter-aaaa-on-v4
+
+

+ If set to yes, the DNS client is + at an IPv4 address, in filter-aaaa, + 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. +

+

+ If set to break-dnssec, + 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. +

+

+ 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. +

+
+
filter-aaaa-on-v6
+

+ Identical to filter-aaaa-on-v4, + except it filters AAAA responses to queries from IPv6 + clients instead of IPv4 clients. To filter all + responses, set both options to yes. +

+
+
+
+

SEE ALSO

+

+ BIND 9 Administrator Reference Manual. +

+
+
+ diff --git a/bin/named/config.c b/bin/named/config.c index 405197363e59c1db6846c488c3c12e3964660ac9..c598a382b95f3d12033be58ce15a10c83287ce9d 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -154,10 +154,7 @@ options {\n\ # fetch-glue ;\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 diff --git a/bin/named/server.c b/bin/named/server.c index 374a365ecb80556e6d3deb0b1511dd2f484b1b45..93418047c48096df3c6eddfefc740e03e7777c14 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -103,6 +103,7 @@ #include #include +#include #include #include @@ -1522,6 +1523,45 @@ configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx, name, isc_result_totext(result)); return (result); } + +static isc_result_t +configure_hook(ns_hooktable_t *hooktable, const cfg_obj_t *hook, + const cfg_obj_t *config, ns_hookctx_t *hctx) +{ + isc_result_t result = ISC_R_SUCCESS; + const cfg_obj_t *obj; + const char *type, *library; + const char *parameters = NULL; + + /* Get the path to the hook module. */ + obj = cfg_tuple_get(hook, "type"); + type = cfg_obj_asstring(obj); + + /* Only query hooks are supported currently. */ + if (strcasecmp(type, "query") != 0) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, + "unsupported hook type"); + return (ISC_R_FAILURE); + } + + library = cfg_obj_asstring(cfg_tuple_get(hook, "library")); + + obj = cfg_tuple_get(hook, "parameters"); + if (obj != NULL && cfg_obj_isstring(obj)) { + parameters = cfg_obj_asstring(obj); + } + result = ns_hookmodule_load(library, parameters, + cfg_obj_file(obj), cfg_obj_line(obj), + config, named_g_aclconfctx, + hctx, hooktable); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "%s: hook module configuration failed: %s", + library, isc_result_totext(result)); + } + return (result); +} #endif @@ -3651,7 +3691,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, *hook_list; const cfg_obj_t *disabled; const cfg_obj_t *obj, *obj2; const cfg_listelt_t *element; @@ -3692,6 +3732,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, bool old_rpz_ok = false; isc_dscp_t dscp4 = -1, dscp6 = -1; dns_dyndbctx_t *dctx = NULL; + ns_hookctx_t *hctx = NULL; unsigned int resolver_param; dns_ntatable_t *ntatable = NULL; const char *qminmode = NULL; @@ -4980,42 +5021,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); - } - - 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); - } - - 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) { @@ -5162,10 +5167,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); @@ -5187,6 +5193,37 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, } #endif + /* + * Load hook modules. + */ + hook_list = NULL; + if (voptions != NULL) { + (void)cfg_map_get(voptions, "hook", &hook_list); + } else { + (void)cfg_map_get(config, "hook", &hook_list); + } + +#ifdef HAVE_DLOPEN + if (hook_list != NULL) { + const void *hashinit = isc_hash_get_initializer(); + CHECK(ns_hook_createctx(mctx, hashinit, &hctx)); + + INSIST(view->hooktable == NULL); + CHECK(ns_hooktable_create(view->mctx, + (ns_hooktable_t **) &view->hooktable)); + view->hooktable_free = ns_hooktable_free; + } + + for (element = cfg_list_first(hook_list); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *hook = cfg_listelt_value(element); + + CHECK(configure_hook(view->hooktable, hook, config, hctx)); + } +#endif + /* * Setup automatic empty zones. If recursion is off then * they are disabled by default. @@ -5436,6 +5473,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, if (dctx != NULL) { dns_dyndb_destroyctx(&dctx); } + if (hctx != NULL) { + ns_hook_destroyctx(&hctx); + } return (result); } @@ -7913,9 +7953,10 @@ load_configuration(const char *filename, named_server_t *server, CHECK(cfg_aclconfctx_create(named_g_mctx, &named_g_aclconfctx)); /* - * Shut down all dyndb instances. + * Shut down all dyndb and hook module instances. */ dns_dyndb_cleanup(false); + ns_hookmodule_unload_all(); /* * Parse the global default pseudo-config file. @@ -9377,7 +9418,11 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { dns_view_detach(&view); } + /* + * Shut down all dyndb and hook module instances. + */ dns_dyndb_cleanup(true); + ns_hookmodule_unload_all(); while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) { ISC_LIST_UNLINK(server->cachelist, nsc, link); diff --git a/bin/tests/system/filter-aaaa/clean.sh b/bin/tests/system/filter-aaaa/clean.sh index a282093ff27ba16839c89ce1db6ca3e0922229a4..a7de02fcc768a163241152ec0c3961990ce0915d 100644 --- a/bin/tests/system/filter-aaaa/clean.sh +++ b/bin/tests/system/filter-aaaa/clean.sh @@ -26,3 +26,5 @@ rm -f ns4/dsset-* rm -f dig.out.* rm -f ns*/named.lock rm -f ns*/managed-keys.bind* + +rm -f ns*/trusted.conf diff --git a/bin/tests/system/filter-aaaa/conf/bad1.conf b/bin/tests/system/filter-aaaa/conf/bad1.conf deleted file mode 100644 index 9a23fd8b96f11b86f16f4924218fea5c39b33e55..0000000000000000000000000000000000000000 --- a/bin/tests/system/filter-aaaa/conf/bad1.conf +++ /dev/null @@ -1,15 +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; - filter-aaaa { none; }; -}; diff --git a/bin/tests/system/filter-aaaa/conf/bad2.conf b/bin/tests/system/filter-aaaa/conf/bad2.conf deleted file mode 100644 index 798f4fd6e2566f2b6060c8d9c9b3c153dba38cdb..0000000000000000000000000000000000000000 --- a/bin/tests/system/filter-aaaa/conf/bad2.conf +++ /dev/null @@ -1,24 +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 { - /* - * While this matches the defaults, it is not a good configuration - * to have in named.conf as the two options contradict each other - * indicating a error on behalf of the operator. - * - * The default is to have filter-aaaa-on-v4 off, but if it is turned - * on then it applies to all IPv4 queries. This results in - * contradictory defaults. - */ - filter-aaaa-on-v4 no; - filter-aaaa { any; }; -}; diff --git a/bin/tests/system/filter-aaaa/conf/bad3.conf b/bin/tests/system/filter-aaaa/conf/bad3.conf deleted file mode 100644 index 3c068bbb71f8b9fb355f993cc8924d4a221a3b3b..0000000000000000000000000000000000000000 --- a/bin/tests/system/filter-aaaa/conf/bad3.conf +++ /dev/null @@ -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 no; -}; - -view myview { - filter-aaaa { any; }; -}; diff --git a/bin/tests/system/filter-aaaa/conf/bad4.conf b/bin/tests/system/filter-aaaa/conf/bad4.conf deleted file mode 100644 index 5744c8b2c59170d42b65322595a92ed499111d18..0000000000000000000000000000000000000000 --- a/bin/tests/system/filter-aaaa/conf/bad4.conf +++ /dev/null @@ -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 { any; }; -}; - -view myview { - filter-aaaa-on-v4 no; -}; diff --git a/bin/tests/system/filter-aaaa/conf/bad5.conf b/bin/tests/system/filter-aaaa/conf/bad5.conf deleted file mode 100644 index 39f9acca51ca3f3ccab9abd14758e5bdf940f87e..0000000000000000000000000000000000000000 --- a/bin/tests/system/filter-aaaa/conf/bad5.conf +++ /dev/null @@ -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 { none; }; -}; - -view myview { - filter-aaaa-on-v4 yes; -}; diff --git a/bin/tests/system/filter-aaaa/conf/bad6.conf b/bin/tests/system/filter-aaaa/conf/bad6.conf deleted file mode 100644 index e92bb1e5f2ab48166939707ba7c582ca7ebb4e3a..0000000000000000000000000000000000000000 --- a/bin/tests/system/filter-aaaa/conf/bad6.conf +++ /dev/null @@ -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; }; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good1.conf b/bin/tests/system/filter-aaaa/conf/good1.conf deleted file mode 100644 index 2a93ef6fb06faff918cf1962325490d31815a596..0000000000000000000000000000000000000000 --- a/bin/tests/system/filter-aaaa/conf/good1.conf +++ /dev/null @@ -1,14 +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; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good2.conf b/bin/tests/system/filter-aaaa/conf/good2.conf deleted file mode 100644 index 916af8e971dd323d7b433a919734816885c43ed2..0000000000000000000000000000000000000000 --- a/bin/tests/system/filter-aaaa/conf/good2.conf +++ /dev/null @@ -1,14 +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 break-dnssec; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good3.conf b/bin/tests/system/filter-aaaa/conf/good3.conf deleted file mode 100644 index b3f8de4d95fd0b2c08ca3795c6fdf00b72b0859d..0000000000000000000000000000000000000000 --- a/bin/tests/system/filter-aaaa/conf/good3.conf +++ /dev/null @@ -1,15 +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 break-dnssec; - filter-aaaa { 1.0.0.0/8; }; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good4.conf b/bin/tests/system/filter-aaaa/conf/good4.conf deleted file mode 100644 index d789f30b575204755322a8d7fbf334fb0d4b4cec..0000000000000000000000000000000000000000 --- a/bin/tests/system/filter-aaaa/conf/good4.conf +++ /dev/null @@ -1,15 +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; - filter-aaaa { 1.0.0.0/8; }; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good5.conf b/bin/tests/system/filter-aaaa/conf/good5.conf deleted file mode 100644 index 95baae5b28a15003c5b330729061b22eda900acc..0000000000000000000000000000000000000000 --- a/bin/tests/system/filter-aaaa/conf/good5.conf +++ /dev/null @@ -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 { 1.0.0.0/8; }; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good6.conf b/bin/tests/system/filter-aaaa/conf/good6.conf deleted file mode 100644 index 9e783670a06bf91ac3afef663dae33906c361f85..0000000000000000000000000000000000000000 --- a/bin/tests/system/filter-aaaa/conf/good6.conf +++ /dev/null @@ -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; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good7.conf b/bin/tests/system/filter-aaaa/conf/good7.conf deleted file mode 100644 index 2531de95b63a22504b7d03c48709992de776175b..0000000000000000000000000000000000000000 --- a/bin/tests/system/filter-aaaa/conf/good7.conf +++ /dev/null @@ -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; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good8.conf b/bin/tests/system/filter-aaaa/conf/good8.conf deleted file mode 100644 index f28fdd96ab4bed92ca875c87272e31f67f0ec455..0000000000000000000000000000000000000000 --- a/bin/tests/system/filter-aaaa/conf/good8.conf +++ /dev/null @@ -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; -}; diff --git a/bin/tests/system/filter-aaaa/ns1/named1.conf.in b/bin/tests/system/filter-aaaa/ns1/named1.conf.in index 55c1afe093962610af703987202ae53eb6cad90c..cd05abc9e917bef989dce90683799dbc486df0a5 100644 --- a/bin/tests/system/filter-aaaa/ns1/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns1/named1.conf.in @@ -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; }; + +hook query "../../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa { filterees; }; +}; + key rndc_key { secret "1234abcd8765"; algorithm hmac-sha256; diff --git a/bin/tests/system/filter-aaaa/ns1/named2.conf.in b/bin/tests/system/filter-aaaa/ns1/named2.conf.in index 6cf9d0d333518293705cb917bf55c40804a835c8..3201f7c9b3badb410c5cdd86772e4e604e2a7c61 100644 --- a/bin/tests/system/filter-aaaa/ns1/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns1/named2.conf.in @@ -20,9 +20,12 @@ options { recursion no; dnssec-validation yes; notify yes; + minimal-responses no; +}; + +hook query "../../../../hooks/lib/filter-aaaa.so" { filter-aaaa-on-v6 yes; filter-aaaa { fd92:7065:b8e:ffff::1; }; - minimal-responses no; }; key rndc_key { diff --git a/bin/tests/system/filter-aaaa/ns1/sign.sh b/bin/tests/system/filter-aaaa/ns1/sign.sh index 4075b3415e6cb99c4c1fc3bc66428d5d8c272769..e97d512be7b05a7a190b49cbec23166143202e2c 100755 --- a/bin/tests/system/filter-aaaa/ns1/sign.sh +++ b/bin/tests/system/filter-aaaa/ns1/sign.sh @@ -21,10 +21,13 @@ infile=signed.db.in zonefile=signed.db.signed outfile=signed.db.signed -keyname1=`$KEYGEN -a DSA -b 768 -n zone $zone 2> /dev/null` -keyname2=`$KEYGEN -f KSK -a DSA -b 768 -n zone $zone 2> /dev/null` +$KEYGEN -a rsasha256 $zone > /dev/null 2>&1 +keyname=`$KEYGEN -f KSK -a rsasha256 $zone 2> /dev/null` -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'" diff --git a/bin/tests/system/filter-aaaa/ns2/named1.conf.in b/bin/tests/system/filter-aaaa/ns2/named1.conf.in index 7b43a97a46182aa67a6d64b8b7fb2f5b8bd71b1c..0f48645932e59479261eca61928370c1177be50f 100644 --- a/bin/tests/system/filter-aaaa/ns2/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns2/named1.conf.in @@ -20,9 +20,12 @@ options { recursion yes; dnssec-validation yes; notify yes; + minimal-responses no; +}; + +hook query "../../../../hooks/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"; diff --git a/bin/tests/system/filter-aaaa/ns2/named2.conf.in b/bin/tests/system/filter-aaaa/ns2/named2.conf.in index 6a6b9baef7c6deeee4e6fb067df4b790fbd2a50b..18399cf08a28a629d43fad4d12ddf7cb295ac2a8 100644 --- a/bin/tests/system/filter-aaaa/ns2/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns2/named2.conf.in @@ -20,9 +20,12 @@ options { recursion yes; dnssec-validation yes; notify yes; + minimal-responses no; +}; + +hook query "../../../../hooks/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"; diff --git a/bin/tests/system/filter-aaaa/ns3/named1.conf.in b/bin/tests/system/filter-aaaa/ns3/named1.conf.in index 60c97d2aa67e28de57c51857295fd381f16d1e6a..2433c80d85284d208b1e1ef3aa178ec36de3480e 100644 --- a/bin/tests/system/filter-aaaa/ns3/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns3/named1.conf.in @@ -20,9 +20,12 @@ options { recursion yes; dnssec-validation yes; notify yes; + minimal-responses no; +}; + +hook query "../../../../hooks/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"; diff --git a/bin/tests/system/filter-aaaa/ns3/named2.conf.in b/bin/tests/system/filter-aaaa/ns3/named2.conf.in index fd7b8c04d1c55a763fd815a937636179ea682133..479d437980ad5d37c8d57c53c2c7f01e5b7b0ac6 100644 --- a/bin/tests/system/filter-aaaa/ns3/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns3/named2.conf.in @@ -20,9 +20,12 @@ options { recursion yes; dnssec-validation yes; notify yes; + minimal-responses no; +}; + +hook query "../../../../hooks/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"; diff --git a/bin/tests/system/filter-aaaa/ns4/named1.conf.in b/bin/tests/system/filter-aaaa/ns4/named1.conf.in index 3f7cbcb16e17f82a21d636bd241bb854ced601ab..87e2eadcf53aaa19e688c7d989b1974d642c5354 100644 --- a/bin/tests/system/filter-aaaa/ns4/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns4/named1.conf.in @@ -20,9 +20,12 @@ options { recursion no; dnssec-validation no; notify yes; + minimal-responses no; +}; + +hook query "../../../../hooks/lib/filter-aaaa.so" { filter-aaaa-on-v4 break-dnssec; filter-aaaa { 10.53.0.4; }; - minimal-responses no; }; key rndc_key { diff --git a/bin/tests/system/filter-aaaa/ns4/named2.conf.in b/bin/tests/system/filter-aaaa/ns4/named2.conf.in index 56a546e359953a801aca5e6f648eff01869628e6..79b5ce8eff6068895344833058a632c239c6cfa1 100644 --- a/bin/tests/system/filter-aaaa/ns4/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns4/named2.conf.in @@ -20,9 +20,12 @@ options { recursion no; dnssec-validation no; notify yes; + minimal-responses no; +}; + +hook query "../../../../hooks/lib/filter-aaaa.so" { filter-aaaa-on-v6 break-dnssec; filter-aaaa { fd92:7065:b8e:ffff::4; }; - minimal-responses no; }; key rndc_key { diff --git a/bin/tests/system/filter-aaaa/ns4/sign.sh b/bin/tests/system/filter-aaaa/ns4/sign.sh index 4075b3415e6cb99c4c1fc3bc66428d5d8c272769..c12980f6bde26cc0c76977bffdcc7f95e9bb6ff9 100755 --- a/bin/tests/system/filter-aaaa/ns4/sign.sh +++ b/bin/tests/system/filter-aaaa/ns4/sign.sh @@ -21,10 +21,8 @@ infile=signed.db.in zonefile=signed.db.signed outfile=signed.db.signed -keyname1=`$KEYGEN -a DSA -b 768 -n zone $zone 2> /dev/null` -keyname2=`$KEYGEN -f KSK -a DSA -b 768 -n zone $zone 2> /dev/null` +$KEYGEN -a rsasha256 $zone > /dev/null 2>&1 +keyname=`$KEYGEN -f KSK -a rsasha256 $zone 2> /dev/null` -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'" diff --git a/bin/tests/system/filter-aaaa/ns5/named.conf.in b/bin/tests/system/filter-aaaa/ns5/named.conf.in index 47b3aff31aeb698c4f1bacb62032de273eee4a69..b97ab1cafd4c984088e87c8a575e904e19969c75 100644 --- a/bin/tests/system/filter-aaaa/ns5/named.conf.in +++ b/bin/tests/system/filter-aaaa/ns5/named.conf.in @@ -25,9 +25,12 @@ options { exclude { any; }; mapped { any; }; }; + minimal-responses no; +}; + +hook query "../../../../hooks/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"; diff --git a/bin/tests/system/filter-aaaa/prereq.sh b/bin/tests/system/filter-aaaa/prereq.sh new file mode 100644 index 0000000000000000000000000000000000000000..7b8a7f4a91ac896654b5568f5f597167bb1e118c --- /dev/null +++ b/bin/tests/system/filter-aaaa/prereq.sh @@ -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 diff --git a/bin/tests/system/filter-aaaa/tests.sh b/bin/tests/system/filter-aaaa/tests.sh index 16a9332518c9aac6497e34f3c1de1024d70e89a8..4ff2ebe3a2054ac94c3370d473421e9eb8a73b1c 100644 --- a/bin/tests/system/filter-aaaa/tests.sh +++ b/bin/tests/system/filter-aaaa/tests.sh @@ -20,26 +20,6 @@ rm -f dig.out.* DIGOPTS="+tcp +noadd +nosea +nostat +nocmd -p ${PORT}" RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s" -for conf in conf/good*.conf -do - n=`expr $n + 1` - echo_i "checking that $conf is accepted ($n)" - ret=0 - $CHECKCONF "$conf" || ret=1 - if [ $ret != 0 ]; then echo_i "failed"; fi - status=`expr $status + $ret` -done - -for conf in conf/bad*.conf -do - n=`expr $n + 1` - echo_i "checking that $conf is rejected ($n)" - ret=0 - $CHECKCONF "$conf" >/dev/null && ret=1 - if [ $ret != 0 ]; then echo_i "failed"; fi - status=`expr $status + $ret` -done - # # Authoritative tests against: # filter-aaaa-on-v4 yes; @@ -117,7 +97,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 +107,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 +128,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 +199,6 @@ else echo_i "skipped." fi - # # Authoritative tests against: # filter-aaaa-on-v4 break-dnssec; @@ -403,6 +379,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 +397,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 +407,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 +416,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 +426,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 +465,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 +514,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 +522,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 +548,6 @@ else echo_i "skipped." fi - # # Recursive tests against: # filter-aaaa-on-v4 break-dnssec; @@ -570,6 +557,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 +575,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 +585,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 +595,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 +604,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 +703,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 +1063,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 +1081,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 +1091,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 +1100,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 +1110,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 +1149,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 +1205,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 +1227,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 +1245,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 +1255,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 +1265,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 +1274,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 +1367,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` diff --git a/configure b/configure index aa53344c969921339e68ee96724dfcf9e9b296aa..d82448449d461149a55fe454ac22d8bf756c010d 100755 --- a/configure +++ b/configure @@ -844,6 +844,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -1002,6 +1003,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1254,6 +1256,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1391,7 +1402,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1544,6 +1555,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -11866,7 +11878,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_atf+set}" = set || with_atf=yes @@ -19717,7 +19729,7 @@ if test "no" != "$atf"; then $as_echo "#define ATF_TEST 1" >>confdefs.h STD_CINCLUDES="$STD_CINCLUDES -I$atf/include" - STD_CDEFINES="$STD_CDEFINES -DNS_HOOKS_ENABLE=1" + STD_CDEFINES="$STD_CDEFINES" ATFBIN="$atf/bin" ATFLIBS="-L$atf/lib -latf-c" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for exp in -lm" >&5 @@ -21426,7 +21438,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/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/Makefile 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/hooks/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/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/Makefile unit/unittest.sh fuzz/Makefile" # @@ -22438,6 +22450,7 @@ do "bin/delv/Makefile") CONFIG_FILES="$CONFIG_FILES bin/delv/Makefile" ;; "bin/dig/Makefile") CONFIG_FILES="$CONFIG_FILES bin/dig/Makefile" ;; "bin/dnssec/Makefile") CONFIG_FILES="$CONFIG_FILES bin/dnssec/Makefile" ;; + "bin/hooks/Makefile") CONFIG_FILES="$CONFIG_FILES bin/hooks/Makefile" ;; "bin/named/Makefile") CONFIG_FILES="$CONFIG_FILES bin/named/Makefile" ;; "bin/named/unix/Makefile") CONFIG_FILES="$CONFIG_FILES bin/named/unix/Makefile" ;; "bin/nsupdate/Makefile") CONFIG_FILES="$CONFIG_FILES bin/nsupdate/Makefile" ;; diff --git a/configure.in b/configure.in index 284c8ab0d38be5367f6debedcc37af007e324b2c..2c09fad8d023b1db80ac3786961868d24d633bd8 100644 --- a/configure.in +++ b/configure.in @@ -75,7 +75,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_atf+set}" = set || with_atf=yes @@ -2435,7 +2435,7 @@ ATFLIBS= if test "no" != "$atf"; then AC_DEFINE(ATF_TEST, 1, [define if ATF unit tests are to be built.]) STD_CINCLUDES="$STD_CINCLUDES -I$atf/include" - STD_CDEFINES="$STD_CDEFINES -DNS_HOOKS_ENABLE=1" + STD_CDEFINES="$STD_CDEFINES" ATFBIN="$atf/bin" ATFLIBS="-L$atf/lib -latf-c" AC_CHECK_LIB(m, exp, libm=yes, libm=no) @@ -2987,6 +2987,7 @@ AC_CONFIG_FILES([ bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile + bin/hooks/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index af15b64982a7ceb08987b76d0c13939cdb9d3334..f8d031db1ac9dbc689b3cf0c401b8d691d294979 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -6418,69 +6418,6 @@ options { - - filter-aaaa-on-v4 - - - 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 no. - The filter-aaaa-on-v4 option - may also be specified in view statements - to override the global filter-aaaa-on-v4 - option. - - - If yes, - the DNS client is at an IPv4 address, in filter-aaaa, - 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. - - - If break-dnssec, - 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. - - - 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. - - - 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. - - - 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. - - - - - - filter-aaaa-on-v6 - - - Identical to filter-aaaa-on-v4, - except it filters AAAA responses to queries from IPv6 - clients instead of IPv4 clients. To filter all - responses, set both options to yes. - - - - ixfr-from-differences @@ -7299,18 +7236,6 @@ options { - - filter-aaaa - - - Specifies a list of addresses to which - filter-aaaa-on-v4 - and filter-aaaa-on-v6 - apply. The default is any. - - - - keep-response-order @@ -18250,6 +18175,7 @@ allow-query { !{ !10/8; any; }; key example; }; + diff --git a/doc/arm/man.filter-aaaa.html b/doc/arm/man.filter-aaaa.html new file mode 100644 index 0000000000000000000000000000000000000000..ad4c62b5a76800be786a7f8625469d9ff6f4755d --- /dev/null +++ b/doc/arm/man.filter-aaaa.html @@ -0,0 +1,153 @@ + + + + + +filter-aaaa.so + + + + + + + + +
+
+
+

Name

+

filter-aaaa.so — filter AAAA in DNS responses when A is present

+
+
+

Synopsis

+

hook query "filter-aaaa.so" [{ parameters }]; +

+
+
+

DESCRIPTION

+

+ filter-aaaa.so is a query hook module for + named, enabling named + to omit some IPv6 addresses when responding to clients. +

+

+ Until BIND 9.12, this feature was impleented natively in + named and enabled with the + filter-aaaa ACL and the + filter-aaaa-on-v4 and + filter-aaaa-on-v6 options. These options are + now deprecated in named.conf, but can be + passed as parameters to the filter-aaaa.so + hook module, for example: +

+
+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; };
+};
+
+

+ 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. +

+

+ 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. +

+
+
+

OPTIONS

+
+
filter-aaaa
+

+ Specifies a list of client addresses for which AAAA + filtering is to be applied. The default is + any. +

+
filter-aaaa-on-v4
+
+

+ If set to yes, the DNS client is + at an IPv4 address, in filter-aaaa, + 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. +

+

+ If set to break-dnssec, + 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. +

+

+ 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. +

+
+
filter-aaaa-on-v6
+

+ Identical to filter-aaaa-on-v4, + except it filters AAAA responses to queries from IPv6 + clients instead of IPv4 clients. To filter all + responses, set both options to yes. +

+
+
+
+

SEE ALSO

+

+ BIND 9 Administrator Reference Manual. +

+
+
+ +

BIND 9.13.2 (Development Release)

+ + diff --git a/doc/misc/options b/doc/misc/options index d0c83103700a72f105a2fb2f3df24f0b7c446ecd..5a9dcbcca3b151fe6dcad8c9a04d1192d36ffcc1 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -24,6 +24,9 @@ dlz { dyndb { }; // may occur multiple times +hook ( query ) [ { } + ]; // may occur multiple times + key { algorithm ; secret ; @@ -171,9 +174,9 @@ options { fetches-per-server [ ( drop | fail ) ]; fetches-per-zone [ ( drop | fail ) ]; files ( default | unlimited | ); - filter-aaaa { ; ... }; - filter-aaaa-on-v4 ( break-dnssec | ); - filter-aaaa-on-v6 ( break-dnssec | ); + filter-aaaa { ; ... }; // obsolete + filter-aaaa-on-v4 ; // obsolete + filter-aaaa-on-v6 ; // obsolete flush-zones-on-shutdown ; forward ( first | only ); forwarders [ port ] [ dscp ] { ( @@ -206,7 +209,7 @@ options { listen-on-v6 [ port ] [ dscp ] { ; ... }; // may occur multiple times - lmdb-mapsize ; // non-operational + lmdb-mapsize ; lock-file ( | none ); maintain-ixfr-base ; // obsolete managed-keys-directory ; @@ -531,13 +534,15 @@ view [ ] { fetch-quota-params ; fetches-per-server [ ( drop | fail ) ]; fetches-per-zone [ ( drop | fail ) ]; - filter-aaaa { ; ... }; - filter-aaaa-on-v4 ( break-dnssec | ); - filter-aaaa-on-v6 ( break-dnssec | ); + filter-aaaa { ; ... }; // obsolete + filter-aaaa-on-v4 ; // obsolete + filter-aaaa-on-v6 ; // obsolete forward ( first | only ); forwarders [ port ] [ dscp ] { ( | ) [ port ] [ dscp ]; ... }; glue-cache ; + hook ( query ) [ { + } ]; // may occur multiple times inline-signing ; ixfr-from-differences ( primary | master | secondary | slave | ); @@ -547,7 +552,7 @@ view [ ] { }; // may occur multiple times key-directory ; lame-ttl ; - lmdb-mapsize ; // non-operational + lmdb-mapsize ; maintain-ixfr-base ; // obsolete managed-keys { diff --git a/lib/bind9/check.c b/lib/bind9/check.c index 451bfbeeacdf9440fb2dd1a5621dc045ac80b6f0..05e34e8cbab826995fe663490c27238126f7487d 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -472,7 +472,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, @@ -790,102 +790,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; @@ -3602,11 +3506,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; diff --git a/lib/dns/adb.c b/lib/dns/adb.c index ae8c887340f3100d1f25ba4a5dabfedfee50db14..91e5c6777bdeed0f2657947539e82a5740d33833 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -2599,7 +2599,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]; diff --git a/lib/dns/dyndb.c b/lib/dns/dyndb.c index 93ad7954012a520878d3b0070aa073bca2749ced..6aa98dc70aca6fec01951cb68f2fddae820b4f16 100644 --- a/lib/dns/dyndb.c +++ b/lib/dns/dyndb.c @@ -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); diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index cb6c034342c30e7bb5c15a5a7eeae919735541b3..6dfcb824656e24b008d5ac8ff717865067b57acc 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -1135,7 +1135,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'. * diff --git a/lib/dns/include/dns/dyndb.h b/lib/dns/include/dns/dyndb.h index d5fedb5fda4d51ba599523633c456f669450575a..015f8efab894207c870c8242de6d46b4b998154d 100644 --- a/lib/dns/include/dns/dyndb.h +++ b/lib/dns/include/dns/dyndb.h @@ -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: diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index 28290e0be596752d4755340a28c6e5016a481616..6f389aa2df2f77bc12a33267b1ea56eaa841a290 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -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; diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index f48e32d55c775d6eec85f1cfcf7ad50455c6766c..6a07d214c9358ecbf1757ae54844856b6c229ec7 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -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: diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index c2e64287c12f131a237a5a5441fda0b6e9a26e59..17c605e69a513ecb61d6398b922b0b4d1c2e2508 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -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. */ diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index e7a70f27ba619b2270974c9081d93faf6c2a8911..3388b449852599c89e25187ba6f0537b503e1129 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -177,9 +177,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; @@ -236,6 +233,9 @@ struct dns_view { dns_dtenv_t *dtenv; /* Dnstap environment */ dns_dtmsgtype_t dttypes; /* Dnstap message types to log */ + + void *hooktable; /* ns_hooktable */ + void (*hooktable_free)(isc_mem_t *, void **); }; #define DNS_VIEW_MAGIC ISC_MAGIC('V','i','e','w') diff --git a/lib/dns/message.c b/lib/dns/message.c index 03daefd175627d3f390e0b19cb6e52a84e00bb4d..f1736979335348c1d4538c05df5aeb13d730c9f5 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -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; diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 92d8d0ec727b69c220bf58126de6406436367fa6..8f12ed7061b13e1c78f18ce006788220c66046f0 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -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); @@ -9798,9 +9797,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; @@ -9917,42 +9914,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; } } @@ -9966,20 +9960,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); diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c index d6dcc91b4897aec5aa79ee0888fcbe9afafdf2d6..576e9475b5a279a01d14f4b14d356354a194723b 100644 --- a/lib/dns/rdataset.c +++ b/lib/dns/rdataset.c @@ -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)); } diff --git a/lib/dns/view.c b/lib/dns/view.c index 7d70b373b157c76f99e07ea37683fc4acc65bdf2..76b8ab2b8b1052aba9f9c48452954870e0dd2c48 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -229,9 +229,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); @@ -260,6 +257,9 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->dtenv = NULL; view->dttypes = 0; + view->hooktable = NULL; + view->hooktable_free = NULL; + result = isc_mutex_init(&view->new_zone_lock); if (result != ISC_R_SUCCESS) goto cleanup_dynkeys; @@ -448,8 +448,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) @@ -544,6 +542,9 @@ destroy(dns_view_t *view) { DESTROYLOCK(&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); + } isc_mem_putanddetach(&view->mctx, view, sizeof(*view)); } diff --git a/lib/isccfg/include/isccfg/grammar.h b/lib/isccfg/include/isccfg/grammar.h index a066cd13e966539ce5f86e23e820dd302629d765..f20f4928ee272407233b21741ea89455d3552dc5 100644 --- a/lib/isccfg/include/isccfg/grammar.h +++ b/lib/isccfg/include/isccfg/grammar.h @@ -154,11 +154,45 @@ struct cfg_netprefix { /*% * A configuration data representation. */ +typedef enum { + CFG_REP_UINT32, + CFG_REP_UINT64, + CFG_REP_STRING, + CFG_REP_BOOLEAN, + CFG_REP_MAP, + CFG_REP_LIST, + CFG_REP_TUPLE, + CFG_REP_SOCKADDR, + CFG_REP_NETPREFIX, + CFG_REP_VOID, + CFG_REP_FIXEDPOINT, + CFG_REP_PERCENTAGE, +} cfg_repcode_t; + struct cfg_rep { const char * name; /*%< For debugging only */ + cfg_repcode_t code; cfg_freefunc_t free; /*%< How to free this kind of data. */ }; +/*@{*/ +/*% + * Predefined data representation types. + */ +LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_uint32; +LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_uint64; +LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_string; +LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_boolean; +LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_map; +LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_list; +LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_tuple; +LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_sockaddr; +LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_netprefix; +LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_void; +LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_fixedpoint; +LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_percentage; +/*@}*/ + /*% * A configuration object. This is the main building block * of the configuration parse tree. @@ -271,23 +305,6 @@ struct cfg_parser { #define CFG_ADDR_MASK (CFG_ADDR_V6OK|CFG_ADDR_V4OK) /*@}*/ -/*@{*/ -/*% - * Predefined data representation types. - */ -LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_uint32; -LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_uint64; -LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_string; -LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_boolean; -LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_map; -LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_list; -LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_tuple; -LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_sockaddr; -LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_netprefix; -LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_void; -LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_fixedpoint; -LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_percentage; -/*@}*/ /*@{*/ /*% @@ -300,7 +317,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; @@ -431,6 +451,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' */ diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index c6b1072d885f9293c820a795e4f0b9423e06425c..7b7a96e2dcf3ecbe217ea84d78cef595f04fa623 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -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_sockaddrlist; @@ -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_hook; 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, @@ -767,7 +756,7 @@ parse_boolorauto(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { static void print_boolorauto(cfg_printer_t *pctx, const cfg_obj_t *obj) { - if (obj->type->rep == &cfg_rep_void) + if (obj->type->rep->code == CFG_REP_VOID) cfg_print_cstr(pctx, "auto"); else if (obj->value.boolean) cfg_print_cstr(pctx, "yes"); @@ -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 }, + { "hook", &cfg_type_hook, 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 }, @@ -1906,9 +1896,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 }, @@ -2392,6 +2382,29 @@ static cfg_type_t cfg_type_dyndb = { &cfg_rep_tuple, dyndb_fields }; +/*% + * The "hook" statement syntax. + * Currently only one hook type is supported: query. + */ + +static const char *hook_enums[] = { + "query", NULL +}; +static cfg_type_t cfg_type_hooktype = { + "hooktype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, + &cfg_rep_string, hook_enums +}; +static cfg_tuplefielddef_t hook_fields[] = { + { "type", &cfg_type_hooktype, 0 }, + { "library", &cfg_type_astring, 0 }, + { "parameters", &cfg_type_optional_bracketed_text, 0 }, + { NULL, NULL, 0 } +}; +static cfg_type_t cfg_type_hook = { + "hook", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, hook_fields +}; + /*% * Clauses that can be found within the 'key' statement. */ @@ -2468,11 +2481,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, @@ -2688,12 +2701,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 }; @@ -2727,13 +2740,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 }; @@ -2774,59 +2792,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)); @@ -2872,11 +2837,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, @@ -2888,11 +2853,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, @@ -2902,11 +2867,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, @@ -2920,32 +2885,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 = { @@ -3386,99 +3336,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 "*", @@ -3623,12 +3480,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 = { @@ -4037,12 +3894,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); } /*% diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c index c370b1980eedcfcf1b4a5c565a0c1f4c06a3d6ed..fc60e36e371e227a488cf1ed01c60b86235de89e 100644 --- a/lib/isccfg/parser.c +++ b/lib/isccfg/parser.c @@ -108,21 +108,42 @@ parser_complain(cfg_parser_t *pctx, bool is_warning, * not need a union member). */ -LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_uint32 = { "uint32", free_noop }; -LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_uint64 = { "uint64", free_noop }; -LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_string = { "string", free_string }; -LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_boolean = { "boolean", free_noop }; -LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_map = { "map", free_map }; -LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_list = { "list", free_list }; -LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_tuple = { "tuple", free_tuple }; -LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop }; -LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_netprefix = - { "netprefix", free_noop }; -LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_void = { "void", free_noop }; -LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_fixedpoint = - { "fixedpoint", free_noop }; -LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_percentage = - { "percentage", free_noop }; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_uint32 = { + "uint32", CFG_REP_UINT32, free_noop +}; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_uint64 = { + "uint64", CFG_REP_UINT64, free_noop +}; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_string = { + "string", CFG_REP_STRING, free_string +}; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_boolean = { + "boolean", CFG_REP_BOOLEAN, free_noop +}; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_map = { + "map", CFG_REP_MAP, free_map +}; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_list = { + "list", CFG_REP_LIST, free_list +}; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_tuple = { + "tuple", CFG_REP_TUPLE, free_tuple +}; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_sockaddr = { + "sockaddr", CFG_REP_SOCKADDR, free_noop +}; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_netprefix = { + "netprefix", CFG_REP_NETPREFIX, free_noop +}; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_void = { + "void", CFG_REP_VOID, free_noop +}; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_fixedpoint = { + "fixedpoint", CFG_REP_FIXEDPOINT, free_noop +}; +LIBISCCFG_EXTERNAL_DATA cfg_rep_t cfg_rep_percentage = { + "percentage", CFG_REP_PERCENTAGE, free_noop +}; /* * Configuration type definitions. @@ -302,8 +323,11 @@ cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) { for (f = fields, i = 0; f->name != NULL; f++, i++) { const cfg_obj_t *fieldobj = obj->value.tuple[i]; - if (need_space && fieldobj->type->rep != &cfg_rep_void) + if (need_space && + fieldobj->type->rep->code != CFG_REP_VOID) + { cfg_print_cstr(pctx, " "); + } cfg_print_obj(pctx, fieldobj); need_space = (need_space || fieldobj->type->print != cfg_print_void); @@ -350,7 +374,7 @@ free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) { bool cfg_obj_istuple(const cfg_obj_t *obj) { REQUIRE(obj != NULL); - return (obj->type->rep == &cfg_rep_tuple); + return (obj->type->rep->code == CFG_REP_TUPLE); } const cfg_obj_t * @@ -359,7 +383,7 @@ cfg_tuple_get(const cfg_obj_t *tupleobj, const char* name) { const cfg_tuplefielddef_t *fields; const cfg_tuplefielddef_t *f; - REQUIRE(tupleobj != NULL && tupleobj->type->rep == &cfg_rep_tuple); + REQUIRE(tupleobj != NULL && tupleobj->type->rep->code == CFG_REP_TUPLE); REQUIRE(name != NULL); fields = tupleobj->type->of; @@ -727,7 +751,7 @@ cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) { bool cfg_obj_isvoid(const cfg_obj_t *obj) { REQUIRE(obj != NULL); - return (obj->type->rep == &cfg_rep_void); + return (obj->type->rep->code == CFG_REP_VOID); } LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_void = { @@ -788,7 +812,7 @@ cfg_print_percentage(cfg_printer_t *pctx, const cfg_obj_t *obj) { uint32_t cfg_obj_aspercentage(const cfg_obj_t *obj) { - REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_percentage); + REQUIRE(obj != NULL && obj->type->rep->code == CFG_REP_PERCENTAGE); return (obj->value.uint32); } @@ -800,7 +824,7 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_percentage = { bool cfg_obj_ispercentage(const cfg_obj_t *obj) { REQUIRE(obj != NULL); - return (obj->type->rep == &cfg_rep_percentage); + return (obj->type->rep->code == CFG_REP_PERCENTAGE); } /* @@ -874,7 +898,7 @@ cfg_print_fixedpoint(cfg_printer_t *pctx, const cfg_obj_t *obj) { uint32_t cfg_obj_asfixedpoint(const cfg_obj_t *obj) { - REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_fixedpoint); + REQUIRE(obj != NULL && obj->type->rep->code == CFG_REP_FIXEDPOINT); return (obj->value.uint32); } @@ -886,7 +910,7 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_fixedpoint = { bool cfg_obj_isfixedpoint(const cfg_obj_t *obj) { REQUIRE(obj != NULL); - return (obj->type->rep == &cfg_rep_fixedpoint); + return (obj->type->rep->code == CFG_REP_FIXEDPOINT); } /* @@ -937,12 +961,12 @@ cfg_print_uint32(cfg_printer_t *pctx, const cfg_obj_t *obj) { bool cfg_obj_isuint32(const cfg_obj_t *obj) { REQUIRE(obj != NULL); - return (obj->type->rep == &cfg_rep_uint32); + return (obj->type->rep->code == CFG_REP_UINT32); } uint32_t cfg_obj_asuint32(const cfg_obj_t *obj) { - REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint32); + REQUIRE(obj != NULL && obj->type->rep->code == CFG_REP_UINT32); return (obj->value.uint32); } @@ -958,12 +982,12 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_uint32 = { bool cfg_obj_isuint64(const cfg_obj_t *obj) { REQUIRE(obj != NULL); - return (obj->type->rep == &cfg_rep_uint64); + return (obj->type->rep->code == CFG_REP_UINT64); } uint64_t cfg_obj_asuint64(const cfg_obj_t *obj) { - REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint64); + REQUIRE(obj != NULL && obj->type->rep->code == CFG_REP_UINT64); return (obj->value.uint64); } @@ -1134,7 +1158,6 @@ doc_btext(cfg_printer_t *pctx, const cfg_type_t *type) { cfg_print_cstr(pctx, "{ }"); } - bool cfg_is_enum(const char *s, const char *const *enums) { const char * const *p; @@ -1193,6 +1216,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); @@ -1229,12 +1304,12 @@ free_string(cfg_parser_t *pctx, cfg_obj_t *obj) { bool cfg_obj_isstring(const cfg_obj_t *obj) { REQUIRE(obj != NULL); - return (obj->type->rep == &cfg_rep_string); + return (obj->type->rep->code == CFG_REP_STRING); } const char * cfg_obj_asstring(const cfg_obj_t *obj) { - REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_string); + REQUIRE(obj != NULL && obj->type->rep->code == CFG_REP_STRING); return (obj->value.string.base); } @@ -1275,6 +1350,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, "[ { } ]"); +} + +cfg_type_t cfg_type_optional_bracketed_text = { + "optional_btext", parse_optional_btext, print_optional_btext, + doc_optional_btext, NULL, NULL +}; + /* * Booleans */ @@ -1282,12 +1496,12 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bracketed_text = { bool cfg_obj_isboolean(const cfg_obj_t *obj) { REQUIRE(obj != NULL); - return (obj->type->rep == &cfg_rep_boolean); + return (obj->type->rep->code == CFG_REP_BOOLEAN); } bool cfg_obj_asboolean(const cfg_obj_t *obj) { - REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_boolean); + REQUIRE(obj != NULL && obj->type->rep->code == CFG_REP_BOOLEAN); return (obj->value.boolean); } @@ -1485,7 +1699,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; @@ -1577,12 +1791,12 @@ cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj) { bool cfg_obj_islist(const cfg_obj_t *obj) { REQUIRE(obj != NULL); - return (obj->type->rep == &cfg_rep_list); + return (obj->type->rep->code == CFG_REP_LIST); } const cfg_listelt_t * cfg_list_first(const cfg_obj_t *obj) { - REQUIRE(obj == NULL || obj->type->rep == &cfg_rep_list); + REQUIRE(obj == NULL || obj->type->rep->code == CFG_REP_LIST); if (obj == NULL) return (NULL); return (ISC_LIST_HEAD(obj->value.list)); @@ -1999,6 +2213,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 } }; @@ -2091,7 +2306,7 @@ cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) { bool cfg_obj_ismap(const cfg_obj_t *obj) { REQUIRE(obj != NULL); - return (obj->type->rep == &cfg_rep_map); + return (obj->type->rep->code == CFG_REP_MAP); } isc_result_t @@ -2100,7 +2315,7 @@ cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj) { isc_symvalue_t val; const cfg_map_t *map; - REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); + REQUIRE(mapobj != NULL && mapobj->type->rep->code == CFG_REP_MAP); REQUIRE(name != NULL); REQUIRE(obj != NULL && *obj == NULL); @@ -2115,7 +2330,7 @@ cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj) { const cfg_obj_t * cfg_map_getname(const cfg_obj_t *mapobj) { - REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); + REQUIRE(mapobj != NULL && mapobj->type->rep->code == CFG_REP_MAP); return (mapobj->value.map.id); } @@ -2123,7 +2338,7 @@ unsigned int cfg_map_count(const cfg_obj_t *mapobj) { const cfg_map_t *map; - REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); + REQUIRE(mapobj != NULL && mapobj->type->rep->code == CFG_REP_MAP); map = &mapobj->value.map; return (isc_symtab_count(map->symtab)); @@ -2611,14 +2826,14 @@ print_netprefix(cfg_printer_t *pctx, const cfg_obj_t *obj) { bool cfg_obj_isnetprefix(const cfg_obj_t *obj) { REQUIRE(obj != NULL); - return (obj->type->rep == &cfg_rep_netprefix); + return (obj->type->rep->code == CFG_REP_NETPREFIX); } void cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr, unsigned int *prefixlen) { - REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix); + REQUIRE(obj != NULL && obj->type->rep->code == CFG_REP_NETPREFIX); REQUIRE(netaddr != NULL); REQUIRE(prefixlen != NULL); @@ -2772,18 +2987,18 @@ cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) { bool cfg_obj_issockaddr(const cfg_obj_t *obj) { REQUIRE(obj != NULL); - return (obj->type->rep == &cfg_rep_sockaddr); + return (obj->type->rep->code == CFG_REP_SOCKADDR); } const isc_sockaddr_t * cfg_obj_assockaddr(const cfg_obj_t *obj) { - REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr); + REQUIRE(obj != NULL && obj->type->rep->code == CFG_REP_SOCKADDR); return (&obj->value.sockaddr); } isc_dscp_t cfg_obj_getdscp(const cfg_obj_t *obj) { - REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr); + REQUIRE(obj != NULL && obj->type->rep->code == CFG_REP_SOCKADDR); return (obj->value.sockaddrdscp.dscp); } @@ -3204,7 +3419,7 @@ cfg_parser_mapadd(cfg_parser_t *pctx, cfg_obj_t *mapobj, const cfg_clausedef_t *clause; REQUIRE(pctx != NULL); - REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map); + REQUIRE(mapobj != NULL && mapobj->type->rep->code == CFG_REP_MAP); REQUIRE(obj != NULL); REQUIRE(clausename != NULL); diff --git a/lib/isccfg/win32/libisccfg.def b/lib/isccfg/win32/libisccfg.def index c5e9be790cdf37c720e59792f4bcd94e0dca08dc..3538e01e2f5a56f9fd2ea88bc99401871d113aa8 100644 --- a/lib/isccfg/win32/libisccfg.def +++ b/lib/isccfg/win32/libisccfg.def @@ -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 diff --git a/lib/ns/Makefile.in b/lib/ns/Makefile.in index 51d21377c67bcba8e70ba80428389071e37f5650..e785969b512481ab50c03fdb1d7f50233fedf46e 100644 --- a/lib/ns/Makefile.in +++ b/lib/ns/Makefile.in @@ -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@ diff --git a/lib/ns/client.c b/lib/ns/client.c index bcf022e1ee7476f7a24f0df44f76eea4ccc72e0d..a9faf1227220a522c7b14334a685cb23fbddd6a6 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -1096,23 +1096,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. */ @@ -3051,8 +3034,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, @@ -4015,3 +3998,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); +} diff --git a/lib/ns/hooks.c b/lib/ns/hooks.c new file mode 100644 index 0000000000000000000000000000000000000000..1f1fb89ccd7617640c696c59e624ffab2b5b11fb --- /dev/null +++ b/lib/ns/hooks.c @@ -0,0 +1,525 @@ +/* + * 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 + +#include + +#if HAVE_DLFCN_H +#include +#elif _WIN32 +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define CHECK(op) \ + do { \ + result = (op); \ + if (result != ISC_R_SUCCESS) { \ + goto cleanup; \ + } \ + } while (0) + +typedef struct ns_hook_module ns_hook_module_t; +struct ns_hook_module { + isc_mem_t *mctx; + void *handle; + char *modpath; + ns_hook_register_t *register_func; + ns_hook_destroy_t *destroy_func; + void *inst; + LINK(ns_hook_module_t) link; +}; + +static ns_hooklist_t default_hooktable[NS_HOOKPOINTS_COUNT]; +LIBNS_EXTERNAL_DATA ns_hooktable_t *ns__hook_table = &default_hooktable; + +/* + * List of hook modules. + * + * These are stored here so they can be cleaned up on shutdown. + * (The order in which they are stored is not important.) + */ +static ISC_LIST(ns_hook_module_t) hook_modules; +static bool hook_modules_initialized = false; + +#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 " + "hook module '%s': %s", + symbol_name, modpath, errmsg); + return (ISC_R_FAILURE); + } + + *symbolp = symbol; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) { + isc_result_t result; + void *handle = NULL; + ns_hook_module_t *hmod = NULL; + ns_hook_register_t *register_func = NULL; + ns_hook_destroy_t *destroy_func = NULL; + ns_hook_version_t *version_func = NULL; + int version, flags; + + REQUIRE(hmodp != NULL && *hmodp == NULL); + + flags = RTLD_NOW | 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() hook module '%s': %s", + modpath, errmsg); + return (ISC_R_FAILURE); + } + + CHECK(load_symbol(handle, modpath, "hook_version", + (void **)&version_func)); + + version = version_func(); + if (version < (NS_HOOK_VERSION - NS_HOOK_AGE) || + version > NS_HOOK_VERSION) + { + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, + "hook API version mismatch: %d/%d", + version, NS_HOOK_VERSION); + CHECK(ISC_R_FAILURE); + } + + CHECK(load_symbol(handle, modpath, "hook_register", + (void **)®ister_func)); + CHECK(load_symbol(handle, modpath, "hook_destroy", + (void **)&destroy_func)); + + hmod = isc_mem_get(mctx, sizeof(*hmod)); + if (hmod == NULL) { + CHECK(ISC_R_NOMEMORY); + } + + hmod->mctx = NULL; + isc_mem_attach(mctx, &hmod->mctx); + hmod->handle = handle; + hmod->modpath = isc_mem_strdup(hmod->mctx, modpath); + hmod->register_func = register_func; + hmod->destroy_func = destroy_func; + + ISC_LINK_INIT(hmod, link); + + *hmodp = hmod; + hmod = 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 " + "hook module '%s': %s", modpath, + isc_result_totext(result)); + + if (hmod != NULL) { + isc_mem_putanddetach(&hmod->mctx, hmod, + sizeof(*hmod)); + } + + if (handle != NULL) { + (void) dlclose(handle); + } + } + + return (result); +} + +static void +unload_library(ns_hook_module_t **hmodp) { + ns_hook_module_t *hmod = NULL; + + REQUIRE(hmodp != NULL && *hmodp != NULL); + + hmod = *hmodp; + *hmodp = NULL; + + if (hmod->handle != NULL) { + (void) dlclose(hmod->handle); + } + if (hmod->modpath != NULL) { + isc_mem_free(hmod->mctx, hmod->modpath); + } + + isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod)); +} +#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 " + "hook module '%s': %d", + symbol_name, modpath, errstatus); + return (ISC_R_FAILURE); + } + + *symbolp = symbol; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) { + isc_result_t result; + HMODULE handle; + ns_hook_module_t *hmod = NULL; + ns_hook_register_t *register_func = NULL; + ns_hook_destroy_t *destroy_func = NULL; + ns_hook_version_t *version_func = NULL; + int version; + + REQUIRE(hmodp != NULL && *hmodp == NULL); + + handle = LoadLibraryA(modpath); + if (handle == NULL) { + CHECK(ISC_R_FAILURE); + } + + CHECK(load_symbol(handle, modpath, "hook_version", + (void **)&version_func)); + + version = version_func(NULL); + if (version < (NS_HOOK_VERSION - NS_HOOK_AGE) || + version > NS_HOOK_VERSION) + { + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, + "hook API version mismatch: %d/%d", + version, NS_HOOK_VERSION); + CHECK(ISC_R_FAILURE); + } + + CHECK(load_symbol(handle, modpath, "hook_register", + (void **)®ister_func)); + CHECK(load_symbol(handle, modpath, "hook_destroy", + (void **)&destroy_func)); + + hmod = isc_mem_get(mctx, sizeof(*hmod)); + if (hmod == NULL) { + CHECK(ISC_R_NOMEMORY); + } + + hmod->mctx = NULL; + isc_mem_attach(mctx, &hmod->mctx); + hmod->handle = handle; + hmod->modpath = isc_mem_strdup(hmod->mctx, modpath); + hmod->register_func = register_func; + hmod->destroy_func = destroy_func; + + ISC_LINK_INIT(hmod, link); + + *hmodp = hmod; + hmod = 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 " + "hook module '%s': %d (%s)", modpath, + GetLastError(), isc_result_totext(result)); + if (hmod != NULL) { + isc_mem_putanddetach(&hmod->mctx, hmod, + sizeof(*hmod)); + } + + if (handle != NULL) { + FreeLibrary(handle); + } + } + + return (result); +} + +static void +unload_library(ns_hook_module_t **hmodp) { + ns_hook_module_t *hmod = NULL; + + REQUIRE(hmodp != NULL && *hmodp != NULL); + + hmod = *hmodp; + *hmodp = NULL; + + if (hmod->handle != NULL) { + FreeLibrary(hmod->handle); + } + + if (hmod->modpath != NULL) { + isc_mem_free(hmod->mctx, hmod->modpath); + } + + isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod)); +} +#else /* HAVE_DLFCN_H || _WIN32 */ +static isc_result_t +load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) { + UNUSED(mctx); + UNUSED(modpath); + UNUSED(hmodp); + + isc_log_write(ns_lctx, NS_LOGCATEGORY_DATABASE, + NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, + "hook module support is not implemented"); + + return (ISC_R_NOTIMPLEMENTED); +} + +static void +unload_library(ns_hook_module_t **hmodp) { + UNUSED(hmodp); +} +#endif /* HAVE_DLFCN_H */ + +isc_result_t +ns_hookmodule_load(const char *modpath, const char *parameters, + const char *cfg_file, unsigned long cfg_line, + const void *cfg, void *actx, + ns_hookctx_t *hctx, ns_hooktable_t *hooktable) +{ + isc_result_t result = ISC_R_SUCCESS; + ns_hook_module_t *hmod = NULL; + + REQUIRE(hook_modules_initialized); + REQUIRE(NS_HOOKCTX_VALID(hctx)); + REQUIRE(hooktable != NULL); + + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_INFO, + "loading module '%s'", modpath); + + CHECK(load_library(hctx->mctx, modpath, &hmod)); + CHECK(hmod->register_func(parameters, cfg_file, cfg_line, + cfg, actx, hctx, hooktable)); + + ISC_LIST_APPEND(hook_modules, hmod, link); + +cleanup: + if (result != ISC_R_SUCCESS && hmod != NULL) { + unload_library(&hmod); + } + + return (result); +} + +void +ns_hookmodule_unload_all(void) { + ns_hook_module_t *hmod = NULL, *prev = NULL; + + if (!hook_modules_initialized) { + return; + } + + hmod = ISC_LIST_TAIL(hook_modules); + while (hmod != NULL) { + prev = ISC_LIST_PREV(hmod, link); + ISC_LIST_UNLINK(hook_modules, hmod, link); + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_INFO, + "unloading module '%s'", hmod->modpath); + hmod->destroy_func(); + unload_library(&hmod); + hmod = prev; + } +} + +isc_result_t +ns_hook_createctx(isc_mem_t *mctx, const void *hashinit, ns_hookctx_t **hctxp) { + ns_hookctx_t *hctx = NULL; + + REQUIRE(hctxp != NULL && *hctxp == NULL); + + hctx = isc_mem_get(mctx, sizeof(*hctx)); + if (hctx == NULL) { + return (ISC_R_NOMEMORY); + } + + memset(hctx, 0, sizeof(*hctx)); + hctx->hashinit = hashinit; + hctx->lctx = ns_lctx; + hctx->refvar = &isc_bind9; + + isc_mem_attach(mctx, &hctx->mctx); + hctx->magic = NS_HOOKCTX_MAGIC; + + *hctxp = hctx; + + return (ISC_R_SUCCESS); +} + +void +ns_hook_destroyctx(ns_hookctx_t **hctxp) { + ns_hookctx_t *hctx = NULL; + + REQUIRE(hctxp != NULL && NS_HOOKCTX_VALID(*hctxp)); + + hctx = *hctxp; + *hctxp = NULL; + + hctx->magic = 0; + + isc_mem_putanddetach(&hctx->mctx, hctx, sizeof(*hctx)); +} + +void +ns_hooktable_init(ns_hooktable_t *hooktable) { + int i; + + if (!hook_modules_initialized) { + ISC_LIST_INIT(hook_modules); + hook_modules_initialized = true; + } + + 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)); + if (hooktable == NULL) { + return (ISC_R_NOMEMORY); + } + + 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, ns_hook_t *hook) +{ + ns_hook_t *copy = NULL; + + REQUIRE(hookpoint < NS_HOOKPOINTS_COUNT); + REQUIRE(hook != NULL); + REQUIRE(hook->mctx == NULL); + + if (hooktable == NULL) { + hooktable = ns__hook_table; + } + + if (mctx == NULL) { + copy = hook; + } else { + 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, ©->mctx); + } + + ISC_LINK_INIT(copy, link); + ISC_LIST_APPEND((*hooktable)[hookpoint], copy, link); +} diff --git a/lib/ns/include/ns/Makefile.in b/lib/ns/include/ns/Makefile.in index 9bfa9f15982c28ebd9dac220a6e32f5d483ffd7a..2009d9a73a87e27be55785a7d41ed6344b99a03a 100644 --- a/lib/ns/include/ns/Makefile.in +++ b/lib/ns/include/ns/Makefile.in @@ -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 = diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index 8852d7c7ae81e35d92e206b16666495675f3895b..7d25eb93606c33fcd11232fd244984b0e0a00694 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -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 hook modules. + */ + +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 */ diff --git a/lib/ns/hooks.h b/lib/ns/include/ns/hooks.h similarity index 53% rename from lib/ns/hooks.h rename to lib/ns/include/ns/hooks.h index 5c3aa14409fda910fcf2709e20703aff7f684386..5612d2ab085a5cf08be15a4138d4d1fad123a254 100644 --- a/lib/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -12,14 +12,18 @@ #ifndef NS_HOOKS_H #define NS_HOOKS_H 1 -#ifdef NS_HOOKS_ENABLE - /*! \file */ #include +#include +#include #include +#include + +#include +#include /* * 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: @@ -158,40 +162,202 @@ * called this time and foo_bar() will return ISC_R_SUCCESS. */ -enum { - NS_QUERY_SETUP_QCTX_INITIALIZED, +/*! + * 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_ADDITIONAL_BEGIN, + 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_GOT_ANSWER_BEGIN, + NS_QUERY_RESPOND_ANY_BEGIN, + NS_QUERY_RESPOND_ANY_FOUND, + NS_QUERY_RESPOND_BEGIN, + NS_QUERY_NOTFOUND_BEGIN, + NS_QUERY_PREP_DELEGATION_BEGIN, + NS_QUERY_ZONE_DELEGATION_BEGIN, + NS_QUERY_DELEGATION_BEGIN, + NS_QUERY_NODATA_BEGIN, + NS_QUERY_NXDOMAIN_BEGIN, + NS_QUERY_CNAME_BEGIN, + NS_QUERY_DNAME_BEGIN, + NS_QUERY_PREP_RESPONSE_BEGIN, NS_QUERY_DONE_BEGIN, - NS_QUERY_HOOKS_COUNT /* MUST BE LAST */ -}; + NS_QUERY_DONE_SEND, + + /* XXX other files could be added later */ + + NS_HOOKPOINTS_COUNT /* MUST BE LAST */ +} ns_hookpoint_t; typedef bool -(*ns_hook_cb_t)(void *hook_data, void *callback_data, isc_result_t *resultp); +(*ns_hook_action_t)(void *arg, void *data, isc_result_t *resultp); typedef struct ns_hook { - ns_hook_cb_t callback; - void *callback_data; + isc_mem_t *mctx; + ns_hook_action_t action; + void *action_data; + ISC_LINK(struct ns_hook) link; } 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__; \ - } \ - } +typedef ISC_LIST(ns_hook_t) ns_hooklist_t; +typedef ns_hooklist_t ns_hooktable_t[NS_HOOKPOINTS_COUNT]; -#define NS_PROCESS_HOOK(table, id, data) \ - _NS_PROCESS_HOOK(table, id, data, _result) +/*% + * 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; + +/*! + * Context for initializing a hook module. + * + * This structure passes data to which a hook module will need + * access -- server memory context, hash initializer, log context, etc. + * The structure doesn't persist beyond configuring the hook module. + * The module's register function should attach to all reference-counted + * variables and its destroy function should detach from them. + */ +typedef struct ns_hookctx { + unsigned int magic; + const void *hashinit; + isc_mem_t *mctx; + isc_log_t *lctx; + bool *refvar; +} ns_hookctx_t; -#define NS_PROCESS_HOOK_VOID(table, id, data) \ - _NS_PROCESS_HOOK(table, id, data) +#define NS_HOOKCTX_MAGIC ISC_MAGIC('H', 'k', 'c', 'x') +#define NS_HOOKCTX_VALID(h) ISC_MAGIC_VALID(h, NS_HOOKCTX_MAGIC) + +/* + * API version + * + * When the API changes, increment NS_HOOK_VERSION. If the + * change is backward-compatible (e.g., adding a new function call + * but not changing or removing an old one), increment NS_HOOK_AGE + * as well; if not, set NS_HOOK_AGE to 0. + */ +#ifndef NS_HOOK_VERSION +#define NS_HOOK_VERSION 1 +#define NS_HOOK_AGE 0 +#endif + +typedef isc_result_t ns_hook_register_t(const char *parameters, + const char *file, + unsigned long line, + const void *cfg, + void *actx, + ns_hookctx_t *hctx, + ns_hooktable_t *hooktable); +/*%< + * Called when registering a new module. + * + * 'parameters' contains the driver configuration text. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li Other errors are possible + */ + +typedef void ns_hook_destroy_t(void); +/*%< + * Destroy a module instance. + */ + +typedef int ns_hook_version_t(void); +/*%< + * Return the API version number a hook module was compiled with. + * + * If the returned version number is no greater than + * NS_HOOK_VERSION, and no less than NS_HOOK_VERSION - NS_HOOK_AGE, + * then the module is API-compatible with named. + */ -LIBNS_EXTERNAL_DATA extern ns_hook_t *ns__hook_table; +/*% + * Prototypes for API functions to be defined in each module. + */ +ns_hook_destroy_t hook_destroy; +ns_hook_register_t hook_register; +ns_hook_version_t hook_version; + +isc_result_t +ns_hook_createctx(isc_mem_t *mctx, const void *hashinit, ns_hookctx_t **hctxp); +void +ns_hook_destroyctx(ns_hookctx_t **hctxp); +/*%< + * Create/destroy a hook module context. + */ + +isc_result_t +ns_hookmodule_load(const char *modpath, const char *parameters, + const char *cfg_file, unsigned long cfg_line, + const void *cfg, void *actx, + ns_hookctx_t *hctx, ns_hooktable_t *hooktable); +/*%< + * Load the hook module specified from the file 'modpath', using + * parameters 'parameters'. + * + * 'cfg_file' and 'cfg_line' specify the location of the hook module + * 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). + * + * 'hctx' is the hook context and 'hooktable' is the hook table + * into which hook points should be registered. + */ + +void +ns_hookmodule_unload_all(void); +/*%< + * Unload all currently loaded hook modules. + */ + +void +ns_hook_add(ns_hooktable_t *hooktable, isc_mem_t *mctx, + ns_hookpoint_t hookpoint, ns_hook_t *hook); +/*%< + * Append hook function 'hook' to the list of hooks at 'hookpoint' in + * 'hooktable'. + * + * If 'mctx' is not NULL, then it is a memory context in which the + * hook is to be copied before adding to the hook list. + * + * Requires: + *\li 'hook' is not NULL + + *\li 'hook->mctx' is NULL + * + *\li 'hookpoint' is less than NS_QUERY_HOOKS_COUNT + * + */ + +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. + */ + +void +ns_hooktable_free(isc_mem_t *mctx, void **tablep); +/*%< + * Free a hook table. + */ -#endif /* NS_HOOKS_ENABLE */ #endif /* NS_HOOKS_H */ diff --git a/lib/ns/include/ns/log.h b/lib/ns/include/ns/log.h index aab57aca091cf97858e8c6bee4549d06503457b7..24689a652ce7dafec5e719f9b23f645df40d0cfa 100644 --- a/lib/ns/include/ns/log.h +++ b/lib/ns/include/ns/log.h @@ -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); diff --git a/lib/ns/include/ns/query.h b/lib/ns/include/ns/query.h index f3f3b949c0a3ac4d8df3de55ae322aa7a95edaf8..f860b9d1a1768cc8f195c8f05cf3764645eeb922 100644 --- a/lib/ns/include/ns/query.h +++ b/lib/ns/include/ns/query.h @@ -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,52 @@ 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 { +/* + * These define functions in the calling program that may need + * to be run from a hook module. Currently the set includes + * query_done() and query_recurse(). + */ +typedef isc_result_t (*ns_hook_querydone_t)(query_ctx_t *qctx); + +typedef isc_result_t (*ns_hook_queryrecurse_t)(ns_client_t *client, + dns_rdatatype_t qtype, + dns_name_t *qname, + dns_name_t *qdomain, + dns_rdataset_t *nameservers, + bool resuming); +/* methods used in query hooks */ +typedef struct query_methods { + ns_hook_querydone_t query_done; + ns_hook_queryrecurse_t query_recurse; +} query_methods_t; + +/* 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 @@ -130,23 +153,25 @@ typedef struct query_ctx { unsigned int options; /* DB lookup options */ - bool redirected; /* nxdomain redirected? */ - bool is_zone; /* is DB a zone DB? */ + bool redirected; /* nxdomain redirected? */ + bool is_zone; /* is DB a zone DB? */ bool is_staticstub_zone; - bool resuming; /* resumed from recursion? */ + bool resuming; /* resumed from recursion? */ bool dns64, dns64_exclude, rpz; - bool authoritative; /* authoritative query? */ - bool want_restart; /* CNAME chain or other + bool authoritative; /* authoritative query? */ + bool want_restart; /* CNAME chain or other * restart needed */ - bool need_wildcardproof; /* wilcard proof needed */ - bool nxrewrite; /* negative answer from RPZ */ - bool findcoveringnsec; /* lookup covering NSEC */ - bool want_stale; /* want stale records? */ - bool answer_has_ns; /* NS is in answer */ + bool need_wildcardproof; /* wilcard proof needed */ + bool nxrewrite; /* negative answer from RPZ */ + bool findcoveringnsec; /* lookup covering NSEC */ + bool want_stale; /* want stale records? */ + bool answer_has_ns; /* NS is in answer */ dns_fixedname_t wildcardname; /* name needing wcard proof */ 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 */ @@ -163,9 +188,13 @@ 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 */ + + query_methods_t methods; /* query hook methods */ + isc_result_t result; /* query result */ int line; /* line to report error */ -} query_ctx_t; +}; isc_result_t ns_query_init(ns_client_t *client); @@ -179,16 +208,16 @@ 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.) - */ 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 */ diff --git a/lib/ns/log.c b/lib/ns/log.c index f167674b32e65ddbdea283e8c70874277013b73d..3e83d98401fbeb8c90563f1997ad026e936468a1 100644 --- a/lib/ns/log.c +++ b/lib/ns/log.c @@ -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 } }; diff --git a/lib/ns/query.c b/lib/ns/query.c index c3bf4e8c454f03890056b559eeded4496da92be9..f94e98bd57f7e9db858dd5d4cd8694bd36cdfa07 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -62,14 +62,13 @@ #include #include +#include #include #include #include #include #include -#include "hooks.h" - #if 0 /* * It has been recommended that DNS64 be changed to return excluded @@ -200,7 +199,6 @@ client_trace(ns_client_t *client, int level, const char *message) { #define CCTRACE(l,m) ((void)m) #endif /* WANT_QUERYTRACE */ - #define DNS_GETDB_NOEXACT 0x01U #define DNS_GETDB_NOLOG 0x02U #define DNS_GETDB_PARTIAL 0x04U @@ -234,6 +232,14 @@ query_findclosestnsec3(dns_name_t *qname, dns_db_t *db, dns_name_t *fname, bool exact, dns_name_t *found); +static isc_result_t +query_done(query_ctx_t *qctx); + +static isc_result_t +query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, + dns_name_t *qdomain, dns_rdataset_t *nameservers, + bool resuming); + static inline void log_queryerror(ns_client_t *client, isc_result_t result, int line, int level); @@ -248,21 +254,74 @@ static void log_noexistnodata(void *val, int level, const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4); -#ifdef NS_HOOKS_ENABLE - -LIBNS_EXTERNAL_DATA ns_hook_t *ns__hook_table = NULL; -#define PROCESS_HOOK(...) \ - NS_PROCESS_HOOK(ns__hook_table, __VA_ARGS__) -#define PROCESS_HOOK_VOID(...) \ - NS_PROCESS_HOOK_VOID(ns__hook_table, __VA_ARGS__) +/* + * Return the hooktable in use with 'qctx', or if there isn't one + * set, return the default hooktable. + */ +static inline ns_hooktable_t * +get_hooktab(query_ctx_t *qctx) { + if (qctx == NULL || qctx->view == NULL || + qctx->view->hooktable == NULL) + { + return (ns__hook_table); + } -#else + return (qctx->view->hooktable); +} -#define PROCESS_HOOK(...) do {} while (0) -#define PROCESS_HOOK_VOID(...) do {} while (0) +/* + * Call the specified hook function in every configured module that + * implements that function. If any hook function returns 'true', we set + * 'result' and terminate processing by jumping to the 'cleanup' tag. + * + * (Note that a hook function may set the 'result' to ISC_R_SUCCESS but + * still terminate processing within the calling function. That's why this + * is a macro instead of an inline function; it needs to be able to use + * 'goto cleanup' regardless of the return value.) + */ +#define CALL_HOOK(_id, _qctx) \ + do { \ + isc_result_t _res; \ + ns_hooktable_t *_tab = get_hooktab(_qctx); \ + ns_hook_t *_hook; \ + _hook = ISC_LIST_HEAD((*_tab)[_id]); \ + while (_hook != NULL) { \ + ns_hook_action_t _func = _hook->action; \ + void *_data = _hook->action_data; \ + INSIST(_func != NULL); \ + if (_func(_qctx, _data, &_res)) { \ + result = _res; \ + goto cleanup; \ + } else { \ + _hook = ISC_LIST_NEXT(_hook, link); \ + } \ + } \ + } while (false) -#endif +/* + * Call the specified hook function in every configured module that + * implements that function. All modules are called; hook function return + * codes are ignored. This is intended for use with initialization and + * destruction calls which *must* run in every configured module. + * + * (This could be implemented as an inline void function, but is left as a + * macro for symmetry with CALL_HOOK above.) + */ +#define CALL_HOOK_NORETURN(_id, _qctx) \ + do { \ + isc_result_t _res; \ + ns_hooktable_t *_tab = get_hooktab(_qctx); \ + ns_hook_t *_hook; \ + _hook = ISC_LIST_HEAD((*_tab)[_id]); \ + while (_hook != NULL) { \ + ns_hook_action_t _func = _hook->action; \ + void *_data = _hook->action_data; \ + INSIST(_func != NULL); \ + _func(_qctx, _data, &_res); \ + _hook = ISC_LIST_NEXT(_hook, link); \ + } \ + } while (false) /* * The functions defined below implement the query logic that previously lived @@ -327,7 +386,8 @@ LIBNS_EXTERNAL_DATA ns_hook_t *ns__hook_table = NULL; * return it to the client. * * (XXX: This description omits several special cases including - * DNS64, filter-aaaa, RPZ, RRL, and the SERVFAIL cache.) + * DNS64, RPZ, RRL, and the SERVFAIL cache. It also doesn't discuss + * query hook modules.) */ static void @@ -350,11 +410,6 @@ static void recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype, const dns_name_t *qname, const dns_name_t *qdomain); -static isc_result_t -query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, - dns_name_t *qdomain, dns_rdataset_t *nameservers, - bool resuming); - static isc_result_t query_resume(query_ctx_t *qctx); @@ -441,16 +496,12 @@ static void query_addbestns(query_ctx_t *qctx); static void -query_addwildcardproof(query_ctx_t *qctx, bool ispositive, - bool nodata); +query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata); static void query_addauth(query_ctx_t *qctx); -static isc_result_t -query_done(query_ctx_t *qctx); - -/*% +/* * Increment query statistics counters. */ static inline void @@ -590,19 +641,6 @@ ns_query_cancel(ns_client_t *client) { UNLOCK(&client->query.fetchlock); } -static inline void -query_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) { - dns_rdataset_t *rdataset = *rdatasetp; - - CTRACE(ISC_LOG_DEBUG(3), "query_putrdataset"); - if (rdataset != NULL) { - if (dns_rdataset_isassociated(rdataset)) - dns_rdataset_disassociate(rdataset); - dns_message_puttemprdataset(client->message, rdatasetp); - } - CTRACE(ISC_LOG_DEBUG(3), "query_putrdataset: done"); -} - static inline void query_reset(ns_client_t *client, bool everything) { isc_buffer_t *dbuf, *dbuf_next; @@ -640,9 +678,9 @@ query_reset(ns_client_t *client, bool everything) { dns_zone_detach(&client->query.authzone); if (client->query.dns64_aaaa != NULL) - query_putrdataset(client, &client->query.dns64_aaaa); + ns_client_putrdataset(client, &client->query.dns64_aaaa); if (client->query.dns64_sigaaaa != NULL) - query_putrdataset(client, &client->query.dns64_sigaaaa); + ns_client_putrdataset(client, &client->query.dns64_sigaaaa); if (client->query.dns64_aaaaok != NULL) { isc_mem_put(client->mctx, client->query.dns64_aaaaok, client->query.dns64_aaaaoklen * @@ -651,8 +689,8 @@ query_reset(ns_client_t *client, bool everything) { client->query.dns64_aaaaoklen = 0; } - query_putrdataset(client, &client->query.redirect.rdataset); - query_putrdataset(client, &client->query.redirect.sigrdataset); + ns_client_putrdataset(client, &client->query.redirect.rdataset); + ns_client_putrdataset(client, &client->query.redirect.sigrdataset); if (client->query.redirect.db != NULL) { if (client->query.redirect.node != NULL) dns_db_detachnode(client->query.redirect.db, @@ -722,198 +760,6 @@ ns_query_free(ns_client_t *client) { query_reset(client, true); } -/*% - * Allocate a name buffer. - */ -static inline isc_result_t -query_newnamebuf(ns_client_t *client) { - isc_buffer_t *dbuf; - isc_result_t result; - - CTRACE(ISC_LOG_DEBUG(3), "query_newnamebuf"); - - dbuf = NULL; - result = isc_buffer_allocate(client->mctx, &dbuf, 1024); - if (result != ISC_R_SUCCESS) { - CTRACE(ISC_LOG_DEBUG(3), - "query_newnamebuf: isc_buffer_allocate failed: done"); - return (result); - } - ISC_LIST_APPEND(client->query.namebufs, dbuf, link); - - CTRACE(ISC_LOG_DEBUG(3), "query_newnamebuf: done"); - return (ISC_R_SUCCESS); -} - -/*% - * Get a name buffer from the pool, or allocate a new one if needed. - */ -static inline isc_buffer_t * -query_getnamebuf(ns_client_t *client) { - isc_buffer_t *dbuf; - isc_result_t result; - isc_region_t r; - - CTRACE(ISC_LOG_DEBUG(3), "query_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 = query_newnamebuf(client); - if (result != ISC_R_SUCCESS) { - CTRACE(ISC_LOG_DEBUG(3), - "query_getnamebuf: query_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 = query_newnamebuf(client); - if (result != ISC_R_SUCCESS) { - CTRACE(ISC_LOG_DEBUG(3), - "query_getnamebuf: query_newnamebuf failed: done"); - return (NULL); - - } - dbuf = ISC_LIST_TAIL(client->query.namebufs); - isc_buffer_availableregion(dbuf, &r); - INSIST(r.length >= 255); - } - CTRACE(ISC_LOG_DEBUG(3), "query_getnamebuf: done"); - return (dbuf); -} - -static inline void -query_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf) { - isc_region_t r; - - CTRACE(ISC_LOG_DEBUG(3), "query_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; -} - -static inline void -query_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(ISC_LOG_DEBUG(3), "query_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(ISC_LOG_DEBUG(3), "query_releasename: done"); -} - -static inline dns_name_t * -query_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(ISC_LOG_DEBUG(3), "query_newname"); - name = NULL; - result = dns_message_gettempname(client->message, &name); - if (result != ISC_R_SUCCESS) { - CTRACE(ISC_LOG_DEBUG(3), - "query_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(ISC_LOG_DEBUG(3), "query_newname: done"); - return (name); -} - -static inline dns_rdataset_t * -query_newrdataset(ns_client_t *client) { - dns_rdataset_t *rdataset; - isc_result_t result; - - CTRACE(ISC_LOG_DEBUG(3), "query_newrdataset"); - rdataset = NULL; - result = dns_message_gettemprdataset(client->message, &rdataset); - if (result != ISC_R_SUCCESS) { - CTRACE(ISC_LOG_DEBUG(3), "query_newrdataset: " - "dns_message_gettemprdataset failed: done"); - return (NULL); - } - - CTRACE(ISC_LOG_DEBUG(3), "query_newrdataset: done"); - return (rdataset); -} - -static inline isc_result_t -query_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 * -query_getdbversion(ns_client_t *client) { - isc_result_t result; - ns_dbversion_t *dbversion; - - if (ISC_LIST_EMPTY(client->query.freeversions)) { - result = query_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); -} - isc_result_t ns_query_init(ns_client_t *client) { isc_result_t result; @@ -956,12 +802,12 @@ ns_query_init(ns_client_t *client) { client->query.redirect.fname = dns_fixedname_initname(&client->query.redirect.fixed); query_reset(client, false); - result = query_newdbversion(client, 3); + result = ns_client_newdbversion(client, 3); if (result != ISC_R_SUCCESS) { DESTROYLOCK(&client->query.fetchlock); return (result); } - result = query_newnamebuf(client); + result = ns_client_newnamebuf(client); if (result != ISC_R_SUCCESS) { query_freefreeversions(client, true); DESTROYLOCK(&client->query.fetchlock); @@ -970,41 +816,6 @@ ns_query_init(ns_client_t *client) { return (result); } -static ns_dbversion_t * -query_findversion(ns_client_t *client, dns_db_t *db) { - ns_dbversion_t *dbversion; - - /*% - * We may already have done a query related to this - * database. If so, we must be sure to make subsequent - * queries from the same version. - */ - 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 = query_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); -} - /*% * Check if 'client' is allowed to query the cache of its associated view. * Unless 'options' has DNS_GETDB_NOLOG set, log the result of cache ACL @@ -1134,7 +945,7 @@ query_validatezonedb(ns_client_t *client, const dns_name_t *name, /* * Get the current version of this database. */ - dbversion = query_findversion(client, db); + dbversion = ns_client_findversion(client, db); if (dbversion == NULL) { CTRACE(ISC_LOG_ERROR, "unable to get db version"); return (DNS_R_SERVFAIL); @@ -1545,7 +1356,7 @@ query_getdb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype, */ *versionp = NULL; - dbversion = query_findversion(client, tdbp); + dbversion = ns_client_findversion(client, tdbp); if (dbversion == NULL) { tresult = ISC_R_NOMEMORY; } else { @@ -1619,45 +1430,34 @@ query_isduplicate(ns_client_t *client, dns_name_t *name, } static isc_result_t -query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { - ns_client_t *client = arg; - isc_result_t result, eresult; - dns_dbnode_t *node; - dns_db_t *db; - dns_name_t *fname, *mname; - dns_rdataset_t *rdataset, *sigrdataset, *trdataset; - isc_buffer_t *dbuf; +query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { + query_ctx_t *qctx = arg; + ns_client_t *client = qctx->client; + isc_result_t result, eresult = ISC_R_SUCCESS; + dns_dbnode_t *node = NULL; + dns_db_t *db = NULL; + dns_name_t *fname = NULL, *mname = NULL; + dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; + dns_rdataset_t *trdataset = NULL; + isc_buffer_t *dbuf = NULL; isc_buffer_t b; - ns_dbversion_t *dbversion; - dns_dbversion_t *version; - bool added_something, need_addname; + ns_dbversion_t *dbversion = NULL; + dns_dbversion_t *version = NULL; + bool added_something = false, need_addname = false; dns_rdatatype_t type; dns_clientinfomethods_t cm; dns_clientinfo_t ci; - dns_rdatasetadditional_t additionaltype; + dns_rdatasetadditional_t additionaltype = + dns_rdatasetadditional_fromauth; REQUIRE(NS_CLIENT_VALID(client)); REQUIRE(qtype != dns_rdatatype_any); - if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype)) + if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype)) { return (ISC_R_SUCCESS); + } - CTRACE(ISC_LOG_DEBUG(3), "query_addadditional"); - - /* - * Initialization. - */ - eresult = ISC_R_SUCCESS; - fname = NULL; - rdataset = NULL; - sigrdataset = NULL; - trdataset = NULL; - db = NULL; - version = NULL; - node = NULL; - added_something = false; - need_addname = false; - additionaltype = dns_rdatasetadditional_fromauth; + CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb"); dns_clientinfomethods_init(&cm, ns_client_sourceip); dns_clientinfo_init(&ci, client, NULL); @@ -1668,49 +1468,56 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { * To avoid multiple lookups, we do an 'any' database * lookup and iterate over the node. */ - if (qtype == dns_rdatatype_a) + if (qtype == dns_rdatatype_a) { type = dns_rdatatype_any; - else + } else { type = qtype; + } /* * Get some resources. */ - dbuf = query_getnamebuf(client); - if (dbuf == NULL) + dbuf = ns_client_getnamebuf(client); + if (dbuf == NULL) { goto cleanup; - fname = query_newname(client, dbuf, &b); - rdataset = query_newrdataset(client); - if (fname == NULL || rdataset == NULL) + } + fname = ns_client_newname(client, dbuf, &b); + rdataset = ns_client_newrdataset(client); + if (fname == NULL || rdataset == NULL) { goto cleanup; + } if (WANTDNSSEC(client)) { - sigrdataset = query_newrdataset(client); - if (sigrdataset == NULL) + sigrdataset = ns_client_newrdataset(client); + if (sigrdataset == NULL) { goto cleanup; + } } /* * If we want only minimal responses and are here, then it must * be for glue. */ - if (client->view->minimalresponses == dns_minimal_yes) + if (qctx->view->minimalresponses == dns_minimal_yes) { goto try_glue; + } /* * Look within the same zone database for authoritative * additional data. */ - if (!client->query.authdbset || client->query.authdb == NULL) + if (!client->query.authdbset || client->query.authdb == NULL) { goto try_cache; + } - dbversion = query_findversion(client, client->query.authdb); - if (dbversion == NULL) + dbversion = ns_client_findversion(client, client->query.authdb); + if (dbversion == NULL) { goto try_cache; + } dns_db_attach(client->query.authdb, &db); version = dbversion->version; - CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: db_find"); + CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: db_find"); /* * Since we are looking for authoritative data, we do not set @@ -1724,16 +1531,21 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { if (result == ISC_R_SUCCESS) { if (sigrdataset != NULL && !dns_db_issecure(db) && dns_rdataset_isassociated(sigrdataset)) + { dns_rdataset_disassociate(sigrdataset); + } goto found; } - if (dns_rdataset_isassociated(rdataset)) + if (dns_rdataset_isassociated(rdataset)) { dns_rdataset_disassociate(rdataset); - if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + } + if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { dns_rdataset_disassociate(sigrdataset); - if (node != NULL) + } + if (node != NULL) { dns_db_detachnode(db, &node); + } version = NULL; dns_db_detach(&db); @@ -1742,8 +1554,9 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { */ try_cache: - if (!client->view->recursion) + if (!qctx->view->recursion) { goto try_glue; + } additionaltype = dns_rdatasetadditional_fromcache; result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG); @@ -1757,9 +1570,10 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { * Attempt to validate glue. */ if (sigrdataset == NULL) { - sigrdataset = query_newrdataset(client); - if (sigrdataset == NULL) + sigrdataset = ns_client_newrdataset(client); + if (sigrdataset == NULL) { goto cleanup; + } } version = NULL; @@ -1769,18 +1583,22 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { client->now, &node, fname, &cm, &ci, rdataset, sigrdataset); - dns_cache_updatestats(client->view->cache, result); - if (!WANTDNSSEC(client)) - query_putrdataset(client, &sigrdataset); + dns_cache_updatestats(qctx->view->cache, result); + if (!WANTDNSSEC(client)) { + ns_client_putrdataset(client, &sigrdataset); + } if (result == ISC_R_SUCCESS) goto found; - if (dns_rdataset_isassociated(rdataset)) + if (dns_rdataset_isassociated(rdataset)) { dns_rdataset_disassociate(rdataset); - if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + } + if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { dns_rdataset_disassociate(sigrdataset); - if (node != NULL) + } + if (node != NULL) { dns_db_detachnode(db, &node); + } dns_db_detach(&db); try_glue: @@ -1799,18 +1617,21 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { * case (identified by client->query.gluedb being set). */ - if (client->query.gluedb == NULL) + if (client->query.gluedb == NULL) { goto cleanup; + } /* * Don't poison caches using the bailiwick protection model. */ - if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb))) + if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb))) { goto cleanup; + } - dbversion = query_findversion(client, client->query.gluedb); - if (dbversion == NULL) + dbversion = ns_client_findversion(client, client->query.gluedb); + if (dbversion == NULL) { goto cleanup; + } dns_db_attach(client->query.gluedb, &db); version = dbversion->version; @@ -1819,17 +1640,19 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { client->query.dboptions | DNS_DBFIND_GLUEOK, client->now, &node, fname, &cm, &ci, rdataset, sigrdataset); - if (!(result == ISC_R_SUCCESS || - result == DNS_R_ZONECUT || - result == DNS_R_GLUE)) + if (result != ISC_R_SUCCESS && + result != DNS_R_ZONECUT && + result != DNS_R_GLUE) + { goto cleanup; + } found: /* * We have found a potential additional data rdataset, or * at least a node to iterate over. */ - query_keepname(client, fname, dbuf); + ns_client_keepname(client, fname, dbuf); /* * If we have an rdataset, add it to the additional data @@ -1837,13 +1660,15 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { */ mname = NULL; if (dns_rdataset_isassociated(rdataset) && - !query_isduplicate(client, fname, type, &mname)) { + !query_isduplicate(client, fname, type, &mname)) + { if (mname != NULL) { INSIST(mname != fname); - query_releasename(client, &fname); + ns_client_releasename(client, &fname); fname = mname; - } else + } else { need_addname = true; + } ISC_LIST_APPEND(fname->list, rdataset, link); trdataset = rdataset; rdataset = NULL; @@ -1862,8 +1687,6 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { } if (qtype == dns_rdatatype_a) { - bool have_a = false; - /* * We now go looking for A and AAAA records, along with * their signatures. @@ -1871,23 +1694,28 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { * XXXRTH This code could be more efficient. */ if (rdataset != NULL) { - if (dns_rdataset_isassociated(rdataset)) + if (dns_rdataset_isassociated(rdataset)) { dns_rdataset_disassociate(rdataset); + } } else { - rdataset = query_newrdataset(client); - if (rdataset == NULL) + rdataset = ns_client_newrdataset(client); + if (rdataset == NULL) { goto addname; + } } if (sigrdataset != NULL) { - if (dns_rdataset_isassociated(sigrdataset)) + if (dns_rdataset_isassociated(sigrdataset)) { dns_rdataset_disassociate(sigrdataset); + } } else if (WANTDNSSEC(client)) { - sigrdataset = query_newrdataset(client); - if (sigrdataset == NULL) + sigrdataset = ns_client_newrdataset(client); + if (sigrdataset == NULL) { goto addname; + } } - if (query_isduplicate(client, fname, dns_rdatatype_a, NULL)) + if (query_isduplicate(client, fname, dns_rdatatype_a, NULL)) { goto aaaa_lookup; + } result = dns_db_findrdataset(db, node, version, dns_rdatatype_a, 0, client->now, @@ -1898,12 +1726,12 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + { dns_rdataset_disassociate(sigrdataset); + } } else if (result == ISC_R_SUCCESS) { bool invalid = false; mname = NULL; - - have_a = true; if (additionaltype == dns_rdatasetadditional_fromcache && (DNS_TRUST_PENDING(rdataset->trust) || @@ -1917,16 +1745,19 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + { dns_rdataset_disassociate(sigrdataset); + } } else if (!query_isduplicate(client, fname, dns_rdatatype_a, &mname)) { if (mname != fname) { if (mname != NULL) { - query_releasename(client, - &fname); + ns_client_releasename(client, + &fname); fname = mname; - } else + } else { need_addname = true; + } } ISC_LIST_APPEND(fname->list, rdataset, link); added_something = true; @@ -1936,23 +1767,29 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { ISC_LIST_APPEND(fname->list, sigrdataset, link); sigrdataset = - query_newrdataset(client); + ns_client_newrdataset(client); } - rdataset = query_newrdataset(client); - if (rdataset == NULL) + rdataset = ns_client_newrdataset(client); + if (rdataset == NULL) { goto addname; - if (WANTDNSSEC(client) && sigrdataset == NULL) + } + if (WANTDNSSEC(client) && sigrdataset == NULL) { goto addname; + } } else { dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + { dns_rdataset_disassociate(sigrdataset); + } } } aaaa_lookup: if (query_isduplicate(client, fname, dns_rdatatype_aaaa, NULL)) + { goto addname; + } result = dns_db_findrdataset(db, node, version, dns_rdatatype_aaaa, 0, client->now, @@ -1963,19 +1800,13 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + { dns_rdataset_disassociate(sigrdataset); + } } else if (result == ISC_R_SUCCESS) { bool invalid = false; mname = NULL; - /* - * There's an A; check whether we're filtering AAAA - */ - if (have_a && - (client->filter_aaaa == dns_aaaa_break_dnssec || - (client->filter_aaaa == dns_aaaa_filter && - (!WANTDNSSEC(client) || sigrdataset == NULL || - !dns_rdataset_isassociated(sigrdataset))))) - goto addname; + if (additionaltype == dns_rdatasetadditional_fromcache && (DNS_TRUST_PENDING(rdataset->trust) || @@ -1990,16 +1821,20 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + { dns_rdataset_disassociate(sigrdataset); + } } else if (!query_isduplicate(client, fname, - dns_rdatatype_aaaa, &mname)) { + dns_rdatatype_aaaa, &mname)) + { if (mname != fname) { if (mname != NULL) { - query_releasename(client, - &fname); + ns_client_releasename(client, + &fname); fname = mname; - } else + } else { need_addname = true; + } } ISC_LIST_APPEND(fname->list, rdataset, link); added_something = true; @@ -2016,21 +1851,23 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { } addname: - CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: addname"); + CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: addname"); /* * If we haven't added anything, then we're done. */ - if (!added_something) + if (!added_something) { goto cleanup; + } /* * We may have added our rdatasets to an existing name, if so, then * need_addname will be false. Whether we used an existing name * or a new one, we must set fname to NULL to prevent cleanup. */ - if (need_addname) + if (need_addname) { dns_message_addname(client->message, fname, DNS_SECTION_ADDITIONAL); + } fname = NULL; /* @@ -2051,105 +1888,126 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { * as well. */ eresult = dns_rdataset_additionaldata(trdataset, - query_addadditional, - client); + query_additional_cb, + qctx); } cleanup: - CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: cleanup"); - query_putrdataset(client, &rdataset); - if (sigrdataset != NULL) - query_putrdataset(client, &sigrdataset); - if (fname != NULL) - query_releasename(client, &fname); - if (node != NULL) + CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: cleanup"); + ns_client_putrdataset(client, &rdataset); + if (sigrdataset != NULL) { + ns_client_putrdataset(client, &sigrdataset); + } + if (fname != NULL) { + ns_client_releasename(client, &fname); + } + if (node != NULL) { dns_db_detachnode(db, &node); - if (db != NULL) + } + if (db != NULL) { dns_db_detach(&db); + } - CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: done"); return (eresult); } -static void -query_addrdataset(ns_client_t *client, dns_section_t section, - dns_name_t *fname, dns_rdataset_t *rdataset) -{ - UNUSED(section); +/* + * Add 'rdataset' to 'name'. + */ +static inline void +query_addtoname(dns_name_t *name, dns_rdataset_t *rdataset) { + ISC_LIST_APPEND(name->list, rdataset, link); +} - /* - * Add 'rdataset' and any pertinent additional data to - * 'fname', a name in the response message for 'client'. - */ +/* + * Set the ordering for 'rdataset'. + */ +static void +query_setorder(query_ctx_t *qctx, dns_name_t *name, dns_rdataset_t *rdataset) { + ns_client_t *client = qctx->client; + dns_order_t *order = client->view->order; - CTRACE(ISC_LOG_DEBUG(3), "query_addrdataset"); + CTRACE(ISC_LOG_DEBUG(3), "query_setorder"); - ISC_LIST_APPEND(fname->list, rdataset, link); + UNUSED(client); - if (client->view->order != NULL) - rdataset->attributes |= dns_order_find(client->view->order, - fname, rdataset->type, + if (order != NULL) { + rdataset->attributes |= dns_order_find(order, name, + rdataset->type, rdataset->rdclass); + } rdataset->attributes |= DNS_RDATASETATTR_LOADORDER; +}; + +/* + * Handle glue and fetch any other needed additional data for 'rdataset'. + */ +static void +query_additional(query_ctx_t *qctx, dns_rdataset_t *rdataset) { + ns_client_t *client = qctx->client; + isc_result_t result; + + CALL_HOOK(NS_QUERY_ADDITIONAL_BEGIN, qctx); - if (NOADDITIONAL(client)) + CTRACE(ISC_LOG_DEBUG(3), "query_additional"); + + if (NOADDITIONAL(client)) { return; + } /* * Try to process glue directly. */ - if (client->view->use_glue_cache && + if (qctx->view->use_glue_cache && (rdataset->type == dns_rdatatype_ns) && (client->query.gluedb != NULL) && dns_db_iszone(client->query.gluedb)) { - isc_result_t result; ns_dbversion_t *dbversion; - unsigned int options = 0; - dbversion = query_findversion(client, client->query.gluedb); - if (dbversion == NULL) + dbversion = ns_client_findversion(client, client->query.gluedb); + if (dbversion == NULL) { goto regular; - - if (client->filter_aaaa == dns_aaaa_filter || - client->filter_aaaa == dns_aaaa_break_dnssec) - { - options |= DNS_RDATASETADDGLUE_FILTERAAAA; } result = dns_rdataset_addglue(rdataset, dbversion->version, - options, client->message); - if (result == ISC_R_SUCCESS) + client->message); + if (result == ISC_R_SUCCESS) { return; + } } -regular: + regular: /* - * Add additional data. - * + * Add other additional data if needed. * We don't care if dns_rdataset_additionaldata() fails. */ - (void)dns_rdataset_additionaldata(rdataset, query_addadditional, - client); - CTRACE(ISC_LOG_DEBUG(3), "query_addrdataset: done"); + (void)dns_rdataset_additionaldata(rdataset, query_additional_cb, qctx); + CTRACE(ISC_LOG_DEBUG(3), "query_additional: done"); + + cleanup: + return; } static void -query_addrrset(ns_client_t *client, dns_name_t **namep, +query_addrrset(query_ctx_t *qctx, dns_name_t **namep, dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp, isc_buffer_t *dbuf, dns_section_t section) { + isc_result_t result; + ns_client_t *client = qctx->client; dns_name_t *name = *namep, *mname = NULL; dns_rdataset_t *rdataset = *rdatasetp, *mrdataset = NULL; dns_rdataset_t *sigrdataset = NULL; - isc_result_t result; CTRACE(ISC_LOG_DEBUG(3), "query_addrrset"); REQUIRE(name != NULL); - if (sigrdatasetp != NULL) + if (sigrdatasetp != NULL) { sigrdataset = *sigrdatasetp; + } /*% * To the current response for 'client', add the answer RRset @@ -2170,37 +2028,50 @@ query_addrrset(ns_client_t *client, dns_name_t **namep, */ CTRACE(ISC_LOG_DEBUG(3), "query_addrrset: dns_message_findname succeeded: done"); - if (dbuf != NULL) - query_releasename(client, namep); - if ((rdataset->attributes & DNS_RDATASETATTR_REQUIRED) != 0) + if (dbuf != NULL) { + ns_client_releasename(client, namep); + } + if ((rdataset->attributes & DNS_RDATASETATTR_REQUIRED) != 0) { mrdataset->attributes |= DNS_RDATASETATTR_REQUIRED; + } return; } else if (result == DNS_R_NXDOMAIN) { /* * The name doesn't exist. */ - if (dbuf != NULL) - query_keepname(client, name, dbuf); + if (dbuf != NULL) { + ns_client_keepname(client, name, dbuf); + } dns_message_addname(client->message, name, section); *namep = NULL; mname = name; } else { RUNTIME_CHECK(result == DNS_R_NXRRSET); - if (dbuf != NULL) - query_releasename(client, namep); + if (dbuf != NULL) { + ns_client_releasename(client, namep); + } } if (rdataset->trust != dns_trust_secure && (section == DNS_SECTION_ANSWER || section == DNS_SECTION_AUTHORITY)) + { client->query.attributes &= ~NS_QUERYATTR_SECURE; + } + + /* + * Update message name, set rdataset order, and do additional + * section processing if needed. + */ + query_addtoname(mname, rdataset); + query_setorder(qctx, mname, rdataset); + query_additional(qctx, rdataset); /* * Note: we only add SIGs if we've added the type they cover, so * we do not need to check if the SIG rdataset is already in the * response. */ - query_addrdataset(client, section, mname, rdataset); *rdatasetp = NULL; if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { /* @@ -2388,7 +2259,7 @@ validate(ns_client_t *client, dns_db_t *db, dns_name_t *name, static void fixrdataset(ns_client_t *client, dns_rdataset_t **rdataset) { if (*rdataset == NULL) - *rdataset = query_newrdataset(client); + *rdataset = ns_client_newrdataset(client); else if (dns_rdataset_isassociated(*rdataset)) dns_rdataset_disassociate(*rdataset); } @@ -2398,10 +2269,10 @@ fixfname(ns_client_t *client, dns_name_t **fname, isc_buffer_t **dbuf, isc_buffer_t *nbuf) { if (*fname == NULL) { - *dbuf = query_getnamebuf(client); + *dbuf = ns_client_getnamebuf(client); if (*dbuf == NULL) return; - *fname = query_newname(client, *dbuf, nbuf); + *fname = ns_client_newname(client, *dbuf, nbuf); } } @@ -2413,16 +2284,21 @@ free_devent(ns_client_t *client, isc_event_t **eventp, REQUIRE((void*)(*eventp) == (void *)(*deventp)); - if (devent->fetch != NULL) + if (devent->fetch != NULL) { dns_resolver_destroyfetch(&devent->fetch); - if (devent->node != NULL) + } + if (devent->node != NULL) { dns_db_detachnode(devent->db, &devent->node); - if (devent->db != NULL) + } + if (devent->db != NULL) { dns_db_detach(&devent->db); - if (devent->rdataset != NULL) - query_putrdataset(client, &devent->rdataset); - if (devent->sigrdataset != NULL) - query_putrdataset(client, &devent->sigrdataset); + } + if (devent->rdataset != NULL) { + ns_client_putrdataset(client, &devent->rdataset); + } + if (devent->sigrdataset != NULL) { + ns_client_putrdataset(client, &devent->sigrdataset); + } /* * If the two pointers are the same then leave the setting of * (*deventp) to NULL to isc_event_free. @@ -2481,7 +2357,7 @@ query_prefetch(ns_client_t *client, dns_name_t *qname, ns_statscounter_recursclients); } - tmprdataset = query_newrdataset(client); + tmprdataset = ns_client_newrdataset(client); if (tmprdataset == NULL) return; if (!TCP(client)) @@ -2498,7 +2374,7 @@ query_prefetch(ns_client_t *client, dns_name_t *qname, tmprdataset, NULL, &client->query.prefetch); if (result != ISC_R_SUCCESS) { - query_putrdataset(client, &tmprdataset); + ns_client_putrdataset(client, &tmprdataset); ns_client_detach(&dummy); } dns_rdataset_clearprefetch(rdataset); @@ -2536,10 +2412,10 @@ rpz_ready(ns_client_t *client, dns_rdataset_t **rdatasetp) { CTRACE(ISC_LOG_DEBUG(3), "rpz_ready"); if (*rdatasetp == NULL) { - *rdatasetp = query_newrdataset(client); + *rdatasetp = ns_client_newrdataset(client); if (*rdatasetp == NULL) { CTRACE(ISC_LOG_ERROR, - "rpz_ready: query_newrdataset failed"); + "rpz_ready: ns_client_newrdataset failed"); return (DNS_R_SERVFAIL); } } else if (dns_rdataset_isassociated(*rdatasetp)) { @@ -2555,24 +2431,24 @@ rpz_st_clear(ns_client_t *client) { CTRACE(ISC_LOG_DEBUG(3), "rpz_st_clear"); if (st->m.rdataset != NULL) { - query_putrdataset(client, &st->m.rdataset); + ns_client_putrdataset(client, &st->m.rdataset); } rpz_match_clear(st); rpz_clean(NULL, &st->r.db, NULL, NULL); if (st->r.ns_rdataset != NULL) { - query_putrdataset(client, &st->r.ns_rdataset); + ns_client_putrdataset(client, &st->r.ns_rdataset); } if (st->r.r_rdataset != NULL) { - query_putrdataset(client, &st->r.r_rdataset); + ns_client_putrdataset(client, &st->r.r_rdataset); } rpz_clean(&st->q.zone, &st->q.db, &st->q.node, NULL); if (st->q.rdataset != NULL) { - query_putrdataset(client, &st->q.rdataset); + ns_client_putrdataset(client, &st->q.rdataset); } if (st->q.sigrdataset != NULL) { - query_putrdataset(client, &st->q.sigrdataset); + ns_client_putrdataset(client, &st->q.sigrdataset); } st->state = 0; st->m.type = DNS_RPZ_TYPE_BAD; @@ -2688,7 +2564,7 @@ query_rpzfetch(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t type) { ns_statscounter_recursclients); } - tmprdataset = query_newrdataset(client); + tmprdataset = ns_client_newrdataset(client); if (tmprdataset == NULL) return; if (!TCP(client)) @@ -2704,7 +2580,7 @@ query_rpzfetch(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t type) { client, tmprdataset, NULL, &client->query.prefetch); if (result != ISC_R_SUCCESS) { - query_putrdataset(client, &tmprdataset); + ns_client_putrdataset(client, &tmprdataset); ns_client_detach(&dummy); } } @@ -2738,8 +2614,9 @@ rpz_rrset_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type, !dns_rdataset_isassociated(*rdatasetp)); st->state &= ~DNS_RPZ_RECURSING; RESTORE(*dbp, st->r.db); - if (*rdatasetp != NULL) - query_putrdataset(client, rdatasetp); + if (*rdatasetp != NULL) { + ns_client_putrdataset(client, rdatasetp); + } RESTORE(*rdatasetp, st->r.r_rdataset); result = st->r.r_result; if (result == DNS_R_DELEGATION) { @@ -3644,7 +3521,7 @@ rpz_rewrite_ip_rrsets(ns_client_t *client, dns_name_t *name, } if (ip_db != NULL) dns_db_detach(&ip_db); - query_putrdataset(client, &p_rdataset); + ns_client_putrdataset(client, &p_rdataset); return (result); } @@ -4298,7 +4175,7 @@ cleanup: st->m.type = DNS_RPZ_TYPE_BAD; result = DNS_R_SERVFAIL; } - query_putrdataset(client, &rdataset); + ns_client_putrdataset(client, &rdataset); if ((st->state & DNS_RPZ_RECURSING) == 0) rpz_clean(NULL, &st->r.db, NULL, &st->r.ns_rdataset); @@ -4445,7 +4322,6 @@ static dns_name_t rfc1918names[] = { DNS_NAME_INITABSOLUTE(inaddr168192, inaddr192_offsets) }; - static unsigned char prisoner_data[] = "\010prisoner\004iana\003org"; static unsigned char hostmaster_data[] = "\012hostmaster\014root-servers\003org"; @@ -4594,24 +4470,6 @@ query_findclosestnsec3(dns_name_t *qname, dns_db_t *db, return; } -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); -} - -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 uint32_t dns64_ttl(dns_db_t *db, dns_dbversion_t *version) { dns_dbnode_t *node = NULL; @@ -4769,7 +4627,7 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset, if (result != ISC_R_SUCCESS) return (ISC_R_NOTFOUND); - dbversion = query_findversion(client, db); + dbversion = ns_client_findversion(client, db); if (dbversion == NULL) { dns_db_detach(&db); return (ISC_R_NOTFOUND); @@ -4987,6 +4845,9 @@ redirect2(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset, * Initialize query context 'qctx'. Run by query_setup() when * first handling a client query, and by query_resume() when * returning from recursion. + * + * Whenever this function is called, qctx_destroy() must be called + * when leaving the scope or freeing the qctx. */ static void qctx_init(ns_client_t *client, dns_fetchevent_t *event, @@ -4995,39 +4856,26 @@ qctx_init(ns_client_t *client, dns_fetchevent_t *event, REQUIRE(qctx != NULL); REQUIRE(client != NULL); + memset(qctx, 0, sizeof(*qctx)); + /* Set this first so CCTRACE will work */ qctx->client = client; + dns_view_attach(client->view, &qctx->view); - CCTRACE(ISC_LOG_DEBUG(3), "qctx_create"); + CCTRACE(ISC_LOG_DEBUG(3), "qctx_init"); qctx->event = event; qctx->qtype = qctx->type = qtype; qctx->result = ISC_R_SUCCESS; - qctx->fname = NULL; - qctx->zfname = NULL; - qctx->rdataset = NULL; - qctx->zrdataset = NULL; - qctx->sigrdataset = NULL; - qctx->zsigrdataset = NULL; - qctx->zversion = NULL; - qctx->node = NULL; - qctx->znode = NULL; - qctx->db = NULL; - qctx->zdb = NULL; - qctx->version = NULL; - qctx->zone = NULL; - qctx->need_wildcardproof = false; - qctx->redirected = false; - qctx->dns64_exclude = qctx->dns64 = qctx->rpz = false; - qctx->options = 0; - qctx->resuming = false; - qctx->is_zone = false; - qctx->findcoveringnsec = client->view->synthfromdnssec; - qctx->is_staticstub_zone = false; - qctx->nxrewrite = false; - qctx->want_stale = false; - qctx->answer_has_ns = false; - qctx->authoritative = false; + qctx->findcoveringnsec = qctx->view->synthfromdnssec; + + /* + * Pointers to methods that may be needed by query hooks. + */ + qctx->methods.query_done = query_done; + qctx->methods.query_recurse = query_recurse; + + CALL_HOOK_NORETURN(NS_QUERY_QCTX_INITIALIZED, qctx); } /*% @@ -5056,15 +4904,15 @@ qctx_clean(query_ctx_t *qctx) { static void qctx_freedata(query_ctx_t *qctx) { if (qctx->rdataset != NULL) { - query_putrdataset(qctx->client, &qctx->rdataset); + ns_client_putrdataset(qctx->client, &qctx->rdataset); } if (qctx->sigrdataset != NULL) { - query_putrdataset(qctx->client, &qctx->sigrdataset); + ns_client_putrdataset(qctx->client, &qctx->sigrdataset); } if (qctx->fname != NULL) { - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); } if (qctx->db != NULL) { @@ -5077,9 +4925,9 @@ qctx_freedata(query_ctx_t *qctx) { } if (qctx->zdb != NULL) { - query_putrdataset(qctx->client, &qctx->zsigrdataset); - query_putrdataset(qctx->client, &qctx->zrdataset); - query_releasename(qctx->client, &qctx->zfname); + ns_client_putrdataset(qctx->client, &qctx->zsigrdataset); + ns_client_putrdataset(qctx->client, &qctx->zrdataset); + ns_client_releasename(qctx->client, &qctx->zfname); dns_db_detachnode(qctx->zdb, &qctx->znode); dns_db_detach(&qctx->zdb); } @@ -5090,6 +4938,16 @@ qctx_freedata(query_ctx_t *qctx) { } } +static void +qctx_destroy(query_ctx_t *qctx) { + CALL_HOOK_NORETURN(NS_QUERY_QCTX_DESTROYED, qctx); + + dns_view_detach(&qctx->view); + if (qctx->detach_client) { + ns_client_detach(&qctx->client); + } +} + /*% * Log detailed information about the query immediately after * the client request or a return from recursion. @@ -5140,6 +4998,8 @@ query_setup(ns_client_t *client, dns_rdatatype_t qtype) { qctx_init(client, NULL, qtype, &qctx); query_trace(&qctx); + CALL_HOOK(NS_QUERY_SETUP, &qctx); + /* * If it's a SIG query, we'll iterate the node. */ @@ -5149,17 +5009,20 @@ query_setup(ns_client_t *client, dns_rdatatype_t qtype) { qctx.type = dns_rdatatype_any; } - PROCESS_HOOK(NS_QUERY_SETUP_QCTX_INITIALIZED, &qctx); - /* * Check SERVFAIL cache */ result = ns__query_sfcache(&qctx); if (result != ISC_R_COMPLETE) { + qctx_destroy(&qctx); return (result); } - return (ns__query_start(&qctx)); + result = ns__query_start(&qctx); + + cleanup: + qctx_destroy(&qctx); + return (result); } static bool @@ -5242,7 +5105,9 @@ ns__query_start(query_ctx_t *qctx) { qctx->need_wildcardproof = false; qctx->rpz = false; - if (qctx->client->view->checknames && + CALL_HOOK(NS_QUERY_START_BEGIN, qctx); + + if (qctx->view->checknames && !dns_rdata_checkowner(qctx->client->query.qname, qctx->client->message->rdclass, qctx->qtype, false)) @@ -5267,7 +5132,7 @@ ns__query_start(query_ctx_t *qctx) { /* * Setup for root key sentinel processing. */ - if (qctx->client->view->root_key_sentinel && + if (qctx->view->root_key_sentinel && qctx->client->query.restarts == 0 && (qctx->qtype == dns_rdatatype_a || qctx->qtype == dns_rdatatype_aaaa) && @@ -5322,7 +5187,7 @@ ns__query_start(query_ctx_t *qctx) { * zone to query context, set result to ISC_R_SUCCESS. */ qctx->options &= ~DNS_GETDB_NOEXACT; - query_putrdataset(qctx->client, &qctx->rdataset); + ns_client_putrdataset(qctx->client, &qctx->rdataset); if (qctx->db != NULL) { dns_db_detach(&qctx->db); } @@ -5420,6 +5285,9 @@ ns__query_start(query_ctx_t *qctx) { } return (query_lookup(qctx)); + + cleanup: + return (result); } /*% @@ -5438,7 +5306,7 @@ query_lookup(query_ctx_t *qctx) { CCTRACE(ISC_LOG_DEBUG(3), "query_lookup"); - PROCESS_HOOK(NS_QUERY_LOOKUP_BEGIN, qctx); + CALL_HOOK(NS_QUERY_LOOKUP_BEGIN, qctx); dns_clientinfomethods_init(&cm, ns_client_sourceip); dns_clientinfo_init(&ci, qctx->client, NULL); @@ -5446,20 +5314,20 @@ query_lookup(query_ctx_t *qctx) { /* * We'll need some resources... */ - qctx->dbuf = query_getnamebuf(qctx->client); + qctx->dbuf = ns_client_getnamebuf(qctx->client); if (ISC_UNLIKELY(qctx->dbuf == NULL)) { CCTRACE(ISC_LOG_ERROR, - "query_lookup: query_getnamebuf failed (2)"); + "query_lookup: ns_client_getnamebuf failed (2)"); QUERY_ERROR(qctx, DNS_R_SERVFAIL); return (query_done(qctx)); } - qctx->fname = query_newname(qctx->client, qctx->dbuf, &b); - qctx->rdataset = query_newrdataset(qctx->client); + qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b); + qctx->rdataset = ns_client_newrdataset(qctx->client); if (ISC_UNLIKELY(qctx->fname == NULL || qctx->rdataset == NULL)) { CCTRACE(ISC_LOG_ERROR, - "query_lookup: query_newname failed (2)"); + "query_lookup: ns_client_newname failed (2)"); QUERY_ERROR(qctx, DNS_R_SERVFAIL); return (query_done(qctx)); } @@ -5467,10 +5335,11 @@ query_lookup(query_ctx_t *qctx) { if ((WANTDNSSEC(qctx->client) || qctx->findcoveringnsec) && (!qctx->is_zone || dns_db_issecure(qctx->db))) { - qctx->sigrdataset = query_newrdataset(qctx->client); + qctx->sigrdataset = ns_client_newrdataset(qctx->client); if (qctx->sigrdataset == NULL) { CCTRACE(ISC_LOG_ERROR, - "query_lookup: query_newrdataset failed (2)"); + "query_lookup: " + "ns_client_newrdataset failed (2)"); QUERY_ERROR(qctx, DNS_R_SERVFAIL); return (query_done(qctx)); } @@ -5512,7 +5381,7 @@ query_lookup(query_ctx_t *qctx) { } if (!qctx->is_zone) { - dns_cache_updatestats(qctx->client->view->cache, result); + dns_cache_updatestats(qctx->view->cache, result); } if (qctx->want_stale) { @@ -5524,8 +5393,7 @@ query_lookup(query_ctx_t *qctx) { if (dns_rdataset_isassociated(qctx->rdataset) && dns_rdataset_count(qctx->rdataset) > 0 && STALE(qctx->rdataset)) { - qctx->rdataset->ttl = - qctx->client->view->staleanswerttl; + qctx->rdataset->ttl = qctx->view->staleanswerttl; success = true; } else { success = false; @@ -5545,6 +5413,9 @@ query_lookup(query_ctx_t *qctx) { } return (query_gotanswer(qctx, result)); + + cleanup: + return (result); } /* @@ -5616,6 +5487,10 @@ fetch_callback(isc_task_t *task, isc_event_t *event) { } else { query_ctx_t qctx; + /* + * Initialize a new qctx and use it to resume + * from recursion. + */ qctx_init(client, devent, 0, &qctx); query_trace(&qctx); @@ -5633,6 +5508,8 @@ fetch_callback(isc_task_t *task, isc_event_t *event) { errorloglevel, false); } } + + qctx_destroy(&qctx); } dns_resolver_destroyfetch(&fetch); @@ -5686,9 +5563,9 @@ recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype, } } -/*% +/* * Prepare client for recursion, then create a resolver fetch, with - * the event callback set to fetch_callback(). Afterward we terminate + * the event action set to fetch_callback(). Afterward we terminate * this phase of the query, and resume with a new query context when * recursion completes. */ @@ -5797,15 +5674,15 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, REQUIRE(nameservers == NULL || nameservers->type == dns_rdatatype_ns); REQUIRE(client->query.fetch == NULL); - rdataset = query_newrdataset(client); + rdataset = ns_client_newrdataset(client); if (rdataset == NULL) { return (ISC_R_NOMEMORY); } if (WANTDNSSEC(client)) { - sigrdataset = query_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); if (sigrdataset == NULL) { - query_putrdataset(client, &rdataset); + ns_client_putrdataset(client, &rdataset); return (ISC_R_NOMEMORY); } } else { @@ -5828,9 +5705,9 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, client, rdataset, sigrdataset, &client->query.fetch); if (result != ISC_R_SUCCESS) { - query_putrdataset(client, &rdataset); + ns_client_putrdataset(client, &rdataset); if (sigrdataset != NULL) { - query_putrdataset(client, &sigrdataset); + ns_client_putrdataset(client, &sigrdataset); } } @@ -5858,6 +5735,8 @@ query_resume(query_ctx_t *qctx) { char tbuf[DNS_RDATATYPE_FORMATSIZE]; #endif + CALL_HOOK(NS_QUERY_RESUME_BEGIN, qctx); + qctx->want_restart = false; qctx->rpz_st = qctx->client->query.rpz_st; @@ -5903,7 +5782,7 @@ query_resume(query_ctx_t *qctx) { SAVE(qctx->rpz_st->r.db, qctx->event->db); qctx->rpz_st->r.r_type = qctx->event->qtype; SAVE(qctx->rpz_st->r.r_rdataset, qctx->event->rdataset); - query_putrdataset(qctx->client, &qctx->event->sigrdataset); + ns_client_putrdataset(qctx->client, &qctx->event->sigrdataset); } else if (REDIRECT(qctx->client)) { /* * Restore saved state. @@ -5936,8 +5815,8 @@ query_resume(query_ctx_t *qctx) { /* * Free resources used while recursing. */ - query_putrdataset(qctx->client, &qctx->event->rdataset); - query_putrdataset(qctx->client, &qctx->event->sigrdataset); + ns_client_putrdataset(qctx->client, &qctx->event->rdataset); + ns_client_putrdataset(qctx->client, &qctx->event->sigrdataset); if (qctx->event->node != NULL) dns_db_detachnode(qctx->event->db, &qctx->event->node); if (qctx->event->db != NULL) @@ -5979,7 +5858,7 @@ query_resume(query_ctx_t *qctx) { /* * Has response policy changed out from under us? */ - if (qctx->rpz_st->rpz_ver != qctx->client->view->rpzs->rpz_ver) + if (qctx->rpz_st->rpz_ver != qctx->view->rpzs->rpz_ver) { ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, @@ -5987,7 +5866,7 @@ query_resume(query_ctx_t *qctx) { "query_resume: RPZ settings " "out of date " "(rpz_ver %d, expected %d)", - qctx->client->view->rpzs->rpz_ver, + qctx->view->rpzs->rpz_ver, qctx->rpz_st->rpz_ver); QUERY_ERROR(qctx, DNS_R_SERVFAIL); return (query_done(qctx)); @@ -5997,18 +5876,18 @@ query_resume(query_ctx_t *qctx) { /* * We'll need some resources... */ - qctx->dbuf = query_getnamebuf(qctx->client); + qctx->dbuf = ns_client_getnamebuf(qctx->client); if (qctx->dbuf == NULL) { CCTRACE(ISC_LOG_ERROR, - "query_resume: query_getnamebuf failed (1)"); + "query_resume: ns_client_getnamebuf failed (1)"); QUERY_ERROR(qctx, DNS_R_SERVFAIL); return (query_done(qctx)); } - qctx->fname = query_newname(qctx->client, qctx->dbuf, &b); + qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b); if (qctx->fname == NULL) { CCTRACE(ISC_LOG_ERROR, - "query_resume: query_newname failed (1)"); + "query_resume: ns_client_newname failed (1)"); QUERY_ERROR(qctx, DNS_R_SERVFAIL); return (query_done(qctx)); } @@ -6046,6 +5925,9 @@ query_resume(query_ctx_t *qctx) { qctx->resuming = true; return (query_gotanswer(qctx, result)); + + cleanup: + return (result); } /*% @@ -6073,13 +5955,13 @@ ns__query_sfcache(query_ctx_t *qctx) { failcache = false; } else { failcache = - dns_badcache_find(qctx->client->view->failcache, + dns_badcache_find(qctx->view->failcache, qctx->client->query.qname, qctx->qtype, &flags, &qctx->client->tnow); } #else - failcache = dns_badcache_find(qctx->client->view->failcache, + failcache = dns_badcache_find(qctx->view->failcache, qctx->client->query.qname, qctx->qtype, &flags, &qctx->client->tnow); @@ -6130,7 +6012,7 @@ query_checkrrl(query_ctx_t *qctx, isc_result_t result) { * Don't mess with responses rewritten by RPZ * Count each response at most once. */ - if (qctx->client->view->rrl != NULL && + if (qctx->view->rrl != NULL && !HAVECOOKIE(qctx->client) && ((qctx->fname != NULL && dns_name_isabsolute(qctx->fname)) || (result == ISC_R_NOTFOUND && !RECURSIONOK(qctx->client))) && @@ -6201,7 +6083,7 @@ query_checkrrl(query_ctx_t *qctx, isc_result_t result) { resp_result = ISC_R_SUCCESS; } - rrl_result = dns_rrl(qctx->client->view, + rrl_result = dns_rrl(qctx->view, &qctx->client->peeraddr, TCP(qctx->client), qctx->client->message->rdclass, @@ -6226,7 +6108,7 @@ query_checkrrl(query_ctx_t *qctx, isc_result_t result) { "%s", log_buf); } - if (!qctx->client->view->rrl->log_only) { + if (!qctx->view->rrl->log_only) { if (rrl_result == DNS_RRL_RESULT_DROP) { /* * These will also be counted in @@ -6263,8 +6145,7 @@ query_checkrrl(query_ctx_t *qctx, isc_result_t result) { return (DNS_R_DROP); } } - } else if (!TCP(qctx->client) && - qctx->client->view->requireservercookie && + } else if (!TCP(qctx->client) && qctx->view->requireservercookie && WANTCOOKIE(qctx->client) && !HAVECOOKIE(qctx->client)) { qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AA; @@ -6335,7 +6216,7 @@ query_checkrpz(query_ctx_t *qctx, isc_result_t result) { RUNTIME_CHECK(rresult == ISC_R_SUCCESS); rpz_clean(&qctx->zone, &qctx->db, &qctx->node, NULL); if (qctx->rpz_st->m.rdataset != NULL) { - query_putrdataset(qctx->client, &qctx->rdataset); + ns_client_putrdataset(qctx->client, &qctx->rdataset); RESTORE(qctx->rdataset, qctx->rpz_st->m.rdataset); } else { qctx_clean(qctx); @@ -6450,7 +6331,7 @@ query_checkrpz(query_ctx_t *qctx, isc_result_t result) { qctx->client->attributes &= ~(NS_CLIENTATTR_WANTDNSSEC | NS_CLIENTATTR_WANTAD); qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD; - query_putrdataset(qctx->client, &qctx->sigrdataset); + ns_client_putrdataset(qctx->client, &qctx->sigrdataset); qctx->rpz_st->q.is_zone = qctx->is_zone; qctx->is_zone = true; rpz_log_rewrite(qctx->client, false, @@ -6499,7 +6380,7 @@ query_rpzcname(query_ctx_t *qctx, dns_name_t *cname) { RUNTIME_CHECK(result == ISC_R_SUCCESS); } - query_keepname(client, qctx->fname, qctx->dbuf); + ns_client_keepname(client, qctx->fname, qctx->dbuf); result = query_addcname(qctx, dns_trust_authanswer, qctx->rpz_st->m.ttl); if (result != ISC_R_SUCCESS) { @@ -6535,7 +6416,7 @@ has_ta(query_ctx_t *qctx) { dns_keynode_t *keynode = NULL; isc_result_t result; - result = dns_view_getsecroots(qctx->client->view, &keytable); + result = dns_view_getsecroots(qctx->view, &keytable); if (result != ISC_R_SUCCESS) { return (false); } @@ -6614,11 +6495,14 @@ root_key_sentinel_return_servfail(query_ctx_t *qctx, isc_result_t result) { * result from the search. */ static isc_result_t -query_gotanswer(query_ctx_t *qctx, isc_result_t result) { +query_gotanswer(query_ctx_t *qctx, isc_result_t res) { + isc_result_t result = res; char errmsg[256]; CCTRACE(ISC_LOG_DEBUG(3), "query_gotanswer"); + CALL_HOOK(NS_QUERY_GOT_ANSWER_BEGIN, qctx); + if (query_checkrrl(qctx, result) != ISC_R_SUCCESS) { return (query_done(qctx)); } @@ -6627,8 +6511,9 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t result) { !dns_name_equal(qctx->client->query.qname, dns_rootname)) { result = query_checkrpz(qctx, result); - if (result == ISC_R_COMPLETE) + if (result == ISC_R_COMPLETE) { return (query_done(qctx)); + } } /* @@ -6704,6 +6589,9 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t result) { } return (query_done(qctx)); } + + cleanup: + return (result); } static void @@ -6720,14 +6608,14 @@ query_addnoqnameproof(query_ctx_t *qctx) { return; } - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) { goto cleanup; } - fname = query_newname(client, dbuf, &b); - neg = query_newrdataset(client); - negsig = query_newrdataset(client); + fname = ns_client_newname(client, dbuf, &b); + neg = ns_client_newrdataset(client); + negsig = ns_client_newrdataset(client); if (fname == NULL || neg == NULL || negsig == NULL) { goto cleanup; } @@ -6735,7 +6623,7 @@ query_addnoqnameproof(query_ctx_t *qctx) { result = dns_rdataset_getnoqname(qctx->noqname, fname, neg, negsig); RUNTIME_CHECK(result == ISC_R_SUCCESS); - query_addrrset(client, &fname, &neg, &negsig, dbuf, + query_addrrset(qctx, &fname, &neg, &negsig, dbuf, DNS_SECTION_AUTHORITY); if ((qctx->noqname->attributes & DNS_RDATASETATTR_CLOSEST) == 0) { @@ -6743,20 +6631,20 @@ query_addnoqnameproof(query_ctx_t *qctx) { } if (fname == NULL) { - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) goto cleanup; - fname = query_newname(client, dbuf, &b); + fname = ns_client_newname(client, dbuf, &b); } if (neg == NULL) { - neg = query_newrdataset(client); + neg = ns_client_newrdataset(client); } else if (dns_rdataset_isassociated(neg)) { dns_rdataset_disassociate(neg); } if (negsig == NULL) { - negsig = query_newrdataset(client); + negsig = ns_client_newrdataset(client); } else if (dns_rdataset_isassociated(negsig)) { dns_rdataset_disassociate(negsig); } @@ -6766,18 +6654,18 @@ query_addnoqnameproof(query_ctx_t *qctx) { result = dns_rdataset_getclosest(qctx->noqname, fname, neg, negsig); RUNTIME_CHECK(result == ISC_R_SUCCESS); - query_addrrset(client, &fname, &neg, &negsig, dbuf, + query_addrrset(qctx, &fname, &neg, &negsig, dbuf, DNS_SECTION_AUTHORITY); cleanup: if (neg != NULL) { - query_putrdataset(client, &neg); + ns_client_putrdataset(client, &neg); } if (negsig != NULL) { - query_putrdataset(client, &negsig); + ns_client_putrdataset(client, &negsig); } if (fname != NULL) { - query_releasename(client, &fname); + ns_client_releasename(client, &fname); } } @@ -6786,21 +6674,13 @@ query_addnoqnameproof(query_ctx_t *qctx) { */ static isc_result_t query_respond_any(query_ctx_t *qctx) { - dns_name_t *tname; - int rdatasets_found = 0; + bool found = false; dns_rdatasetiter_t *rdsiter = NULL; isc_result_t result; dns_rdatatype_t onetype = 0; /* type to use for minimal-any */ - bool have_aaaa, have_a, have_sig; + isc_buffer_t b; - /* - * If we are not authoritative, assume there is an A record - * even in if it is not in our cache. This assumption could - * be wrong but it is a good bet. - */ - have_aaaa = false; - have_a = !qctx->authoritative; - have_sig = false; + CALL_HOOK(NS_QUERY_RESPOND_ANY_BEGIN, qctx); result = dns_db_allrdatasets(qctx->db, qctx->node, qctx->version, 0, &rdsiter); @@ -6815,29 +6695,19 @@ query_respond_any(query_ctx_t *qctx) { * Calling query_addrrset() with a non-NULL dbuf is going * to either keep or release the name. We don't want it to * release fname, since we may have to call query_addrrset() - * more than once. That means we have to call query_keepname() + * more than once. That means we have to call ns_client_keepname() * now, and pass a NULL dbuf to query_addrrset(). * * If we do a query_addrrset() below, we must set qctx->fname to * NULL before leaving this block, otherwise we might try to * cleanup qctx->fname even though we're using it! */ - query_keepname(qctx->client, qctx->fname, qctx->dbuf); - tname = qctx->fname; + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); + qctx->tname = qctx->fname; result = dns_rdatasetiter_first(rdsiter); while (result == ISC_R_SUCCESS) { dns_rdatasetiter_current(rdsiter, qctx->rdataset); - /* - * Notice the presence of A and AAAAs so - * that AAAAs can be hidden from IPv4 clients. - */ - if (qctx->client->filter_aaaa != dns_aaaa_ok) { - if (qctx->rdataset->type == dns_rdatatype_aaaa) - have_aaaa = true; - else if (qctx->rdataset->type == dns_rdatatype_a) - have_a = true; - } /* * We found an NS RRset; no need to add one later. @@ -6864,7 +6734,7 @@ query_respond_any(query_ctx_t *qctx) { * ANY queries. */ dns_rdataset_disassociate(qctx->rdataset); - } else if (qctx->client->view->minimal_any && + } else if (qctx->view->minimal_any && !TCP(qctx->client) && !WANTDNSSEC(qctx->client) && qctx->qtype == dns_rdatatype_any && (qctx->rdataset->type == dns_rdatatype_sig || @@ -6873,7 +6743,7 @@ query_respond_any(query_ctx_t *qctx) { CCTRACE(ISC_LOG_DEBUG(5), "query_respond_any: " "minimal-any skip signature"); dns_rdataset_disassociate(qctx->rdataset); - } else if (qctx->client->view->minimal_any && + } else if (qctx->view->minimal_any && !TCP(qctx->client) && onetype != 0 && qctx->rdataset->type != onetype && qctx->rdataset->covers != onetype) @@ -6885,9 +6755,6 @@ query_respond_any(query_ctx_t *qctx) { qctx->rdataset->type == qctx->qtype) && qctx->rdataset->type != 0) { - if (dns_rdatatype_isdnssec(qctx->rdataset->type)) - have_sig = true; - if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client)) { qctx->noqname = qctx->rdataset; @@ -6905,7 +6772,7 @@ query_respond_any(query_ctx_t *qctx) { dns_name_t *name; name = (qctx->fname != NULL) ? qctx->fname - : tname; + : qctx->tname; query_prefetch(qctx->client, name, qctx->rdataset); } @@ -6916,31 +6783,34 @@ query_respond_any(query_ctx_t *qctx) { */ if (qctx->rdataset->type == dns_rdatatype_sig || qctx->rdataset->type == dns_rdatatype_rrsig) + { onetype = qctx->rdataset->covers; - else + } else { onetype = qctx->rdataset->type; + } - query_addrrset(qctx->client, + query_addrrset(qctx, (qctx->fname != NULL) ? &qctx->fname - : &tname, + : &qctx->tname, &qctx->rdataset, NULL, NULL, DNS_SECTION_ANSWER); query_addnoqnameproof(qctx); - rdatasets_found++; - INSIST(tname != NULL); + found = true; + INSIST(qctx->tname != NULL); /* * rdataset is non-NULL only in certain * pathological cases involving DNAMEs. */ - if (qctx->rdataset != NULL) - query_putrdataset(qctx->client, - &qctx->rdataset); + if (qctx->rdataset != NULL) { + ns_client_putrdataset(qctx->client, + &qctx->rdataset); + } - qctx->rdataset = query_newrdataset(qctx->client); + qctx->rdataset = ns_client_newrdataset(qctx->client); if (qctx->rdataset == NULL) break; } else { @@ -6953,75 +6823,61 @@ query_respond_any(query_ctx_t *qctx) { result = dns_rdatasetiter_next(rdsiter); } - /* - * Filter AAAAs if there is an A and there is no signature - * or we are supposed to break DNSSEC. - */ - if (qctx->client->filter_aaaa == dns_aaaa_break_dnssec) - qctx->client->attributes |= NS_CLIENTATTR_FILTER_AAAA; - else if (qctx->client->filter_aaaa != dns_aaaa_ok && - have_aaaa && have_a && - (!have_sig || !WANTDNSSEC(qctx->client))) - qctx->client->attributes |= NS_CLIENTATTR_FILTER_AAAA; - - if (qctx->fname != NULL) - dns_message_puttempname(qctx->client->message, &qctx->fname); + dns_rdatasetiter_destroy(&rdsiter); - if (rdatasets_found == 0) { - /* - * No matching rdatasets found in cache. If we were - * searching for RRSIG/SIG, that's probably okay; - * otherwise this is an error condition. - */ - if ((qctx->qtype == dns_rdatatype_rrsig || - qctx->qtype == dns_rdatatype_sig) && - result == ISC_R_NOMORE) - { - isc_buffer_t b; - if (!qctx->is_zone) { - qctx->authoritative = false; - dns_rdatasetiter_destroy(&rdsiter); - qctx->client->attributes &= ~NS_CLIENTATTR_RA; - query_addauth(qctx); - return (query_done(qctx)); - } + if (result != ISC_R_NOMORE) { + CCTRACE(ISC_LOG_ERROR, + "query_respond_any: rdataset iterator failed"); + QUERY_ERROR(qctx, DNS_R_SERVFAIL); + return (query_done(qctx)); + } - if (qctx->qtype == dns_rdatatype_rrsig && - dns_db_issecure(qctx->db)) { - char namebuf[DNS_NAME_FORMATSIZE]; - dns_name_format(qctx->client->query.qname, - namebuf, - sizeof(namebuf)); - ns_client_log(qctx->client, - DNS_LOGCATEGORY_DNSSEC, - NS_LOGMODULE_QUERY, - ISC_LOG_WARNING, - "missing signature for %s", - namebuf); - } + if (found) { + CALL_HOOK(NS_QUERY_RESPOND_ANY_FOUND, qctx); - dns_rdatasetiter_destroy(&rdsiter); - qctx->fname = query_newname(qctx->client, - qctx->dbuf, &b); - return (query_sign_nodata(qctx)); - } else { - CCTRACE(ISC_LOG_ERROR, - "query_respond_any: " - "no matching rdatasets in cache"); - result = DNS_R_SERVFAIL; + if (qctx->fname != NULL) { + dns_message_puttempname(qctx->client->message, + &qctx->fname); } + + query_addauth(qctx); + return (query_done(qctx)); } - dns_rdatasetiter_destroy(&rdsiter); - if (result != ISC_R_NOMORE) { - CCTRACE(ISC_LOG_ERROR, - "query_respond_any: dns_rdatasetiter_destroy failed"); - QUERY_ERROR(qctx, DNS_R_SERVFAIL); - } else { + /* + * If we're here, no matching rdatasets were found. If we were + * searching for RRSIG/SIG, that may be okay, but otherwise + * something's gone wrong. + */ + INSIST(qctx->qtype == dns_rdatatype_rrsig || + qctx->qtype == dns_rdatatype_sig); + + if (qctx->fname != NULL) { + dns_message_puttempname(qctx->client->message, + &qctx->fname); + } + + if (!qctx->is_zone) { + qctx->authoritative = false; + qctx->client->attributes &= ~NS_CLIENTATTR_RA; query_addauth(qctx); + return (query_done(qctx)); } - return (query_done(qctx)); + if (qctx->qtype == dns_rdatatype_rrsig && dns_db_issecure(qctx->db)) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(qctx->client->query.qname, + namebuf, sizeof(namebuf)); + ns_client_log(qctx->client, DNS_LOGCATEGORY_DNSSEC, + NS_LOGMODULE_QUERY, ISC_LOG_WARNING, + "missing signature for %s", namebuf); + } + + qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b); + return (query_sign_nodata(qctx)); + + cleanup: + return (result); } /* @@ -7076,101 +6932,6 @@ query_getexpire(query_ctx_t *qctx) { } } -/* - * Optionally hide AAAAs from IPv4 clients if there is an A. - * - * We add the AAAAs now, but might refuse to render them later - * after DNSSEC is figured out. - * - * This could be more efficient, but the whole idea is - * so fundamentally wrong, unavoidably inaccurate, and - * unneeded that it is best to keep it as short as possible. - */ -static isc_result_t -query_filter_aaaa(query_ctx_t *qctx) { - isc_result_t result; - - if (qctx->client->filter_aaaa != dns_aaaa_break_dnssec && - (qctx->client->filter_aaaa != dns_aaaa_filter || - (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL && - dns_rdataset_isassociated(qctx->sigrdataset)))) - { - return (ISC_R_COMPLETE); - } - - if (qctx->qtype == dns_rdatatype_aaaa) { - dns_rdataset_t *trdataset; - trdataset = query_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); - } - query_putrdataset(qctx->client, &trdataset); - - /* - * We have an AAAA but the A is not in our cache. - * Assume any result other than DNS_R_DELEGATION - * or ISC_R_NOTFOUND means there is no A and - * so AAAAs are ok. - * - * Assume there is no A if we can't recurse - * for this client, although that could be - * the wrong answer. What else can we do? - * Besides, that we have the AAAA and are using - * this mechanism suggests that we care more - * about As than AAAAs and would have cached - * the A if it existed. - */ - if (result == ISC_R_SUCCESS) { - qctx->client->attributes |= - NS_CLIENTATTR_FILTER_AAAA; - - } else if (qctx->authoritative || - !RECURSIONOK(qctx->client) || - (result != DNS_R_DELEGATION && - result != ISC_R_NOTFOUND)) - { - qctx->client->attributes &= - ~NS_CLIENTATTR_FILTER_AAAA; - } else { - /* - * 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. - */ - INSIST(!REDIRECT(qctx->client)); - result = query_recurse(qctx->client, - dns_rdatatype_a, - qctx->client->query.qname, - NULL, NULL, qctx->resuming); - if (result == ISC_R_SUCCESS) { - qctx->client->attributes |= - NS_CLIENTATTR_FILTER_AAAA_RC; - qctx->client->query.attributes |= - NS_QUERYATTR_RECURSING; - } - } - } else if (qctx->qtype == dns_rdatatype_a && - (qctx->client->attributes & - NS_CLIENTATTR_FILTER_AAAA_RC) != 0) - { - qctx->client->attributes &= ~NS_CLIENTATTR_FILTER_AAAA_RC; - qctx->client->attributes |= NS_CLIENTATTR_FILTER_AAAA; - qctx_clean(qctx); - - return (query_done(qctx)); - } - - return (ISC_R_COMPLETE); -} - /*% * Build a repsonse for a "normal" query, for a type other than ANY, * for which we have an answer (either positive or negative). @@ -7211,17 +6972,11 @@ query_respond(query_ctx_t *qctx) { /* * Check to see if the AAAA RRset has non-excluded addresses * in it. If not look for a A RRset. - * - * Note: the order of dns64_aaaaok() and query_filter_aaaa() is - * important. query_filter_aaaa() calls query_recurse() but - * continues so that the AAAA records are added. If the - * order is reversed client->query.fetch will be non-NULL - * when query_lookup() is called leading to a assertion. */ INSIST(qctx->client->query.dns64_aaaaok == NULL); if (qctx->qtype == dns_rdatatype_aaaa && !qctx->dns64_exclude && - !ISC_LIST_EMPTY(qctx->client->view->dns64) && + !ISC_LIST_EMPTY(qctx->view->dns64) && qctx->client->message->rdclass == dns_rdataclass_in && !dns64_aaaaok(qctx->client, qctx->rdataset, qctx->sigrdataset)) { @@ -7231,7 +6986,7 @@ query_respond(query_ctx_t *qctx) { qctx->client->query.dns64_ttl = qctx->rdataset->ttl; SAVE(qctx->client->query.dns64_aaaa, qctx->rdataset); SAVE(qctx->client->query.dns64_sigaaaa, qctx->sigrdataset); - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); dns_db_detachnode(qctx->db, &qctx->node); qctx->type = qctx->qtype = dns_rdatatype_a; qctx->dns64_exclude = qctx->dns64 = true; @@ -7239,9 +6994,15 @@ query_respond(query_ctx_t *qctx) { return (query_lookup(qctx)); } - result = query_filter_aaaa(qctx); - if (result != ISC_R_COMPLETE) - return (result); + /* + * XXX: This hook is meant to be at the top of this function, + * but is postponed until after DNS64 in order to avoid an + * assertion if the hook causes recursion. (When DNS64 also + * becomes a hook module, it will be necessary to find some + * other way to prevent that assertion, since the order in + * which hook modules are configured can't be enforced.) + */ + CALL_HOOK(NS_QUERY_RESPOND_BEGIN, qctx); if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) { sigrdatasetp = &qctx->sigrdataset; @@ -7311,12 +7072,12 @@ query_respond(query_ctx_t *qctx) { } } else if (qctx->client->query.dns64_aaaaok != NULL) { query_filter64(qctx); - query_putrdataset(qctx->client, &qctx->rdataset); + ns_client_putrdataset(qctx->client, &qctx->rdataset); } else { if (!qctx->is_zone && RECURSIONOK(qctx->client)) query_prefetch(qctx->client, qctx->fname, qctx->rdataset); - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp, qctx->dbuf, DNS_SECTION_ANSWER); } @@ -7332,6 +7093,9 @@ query_respond(query_ctx_t *qctx) { query_addauth(qctx); return (query_done(qctx)); + + cleanup: + return (result); } static isc_result_t @@ -7386,22 +7150,25 @@ query_dns64(query_ctx_t *qctx) { */ CTRACE(ISC_LOG_DEBUG(3), "query_dns64: dns_message_findname succeeded: done"); - if (qctx->dbuf != NULL) - query_releasename(client, &qctx->fname); + if (qctx->dbuf != NULL) { + ns_client_releasename(client, &qctx->fname); + } return (ISC_R_SUCCESS); } else if (result == DNS_R_NXDOMAIN) { /* * The name doesn't exist. */ - if (qctx->dbuf != NULL) - query_keepname(client, name, qctx->dbuf); + if (qctx->dbuf != NULL) { + ns_client_keepname(client, name, qctx->dbuf); + } dns_message_addname(client->message, name, section); qctx->fname = NULL; mname = name; } else { RUNTIME_CHECK(result == DNS_R_NXRRSET); - if (qctx->dbuf != NULL) - query_releasename(client, &qctx->fname); + if (qctx->dbuf != NULL) { + ns_client_releasename(client, &qctx->fname); + } } if (qctx->rdataset->trust != dns_trust_secure) { @@ -7488,7 +7255,10 @@ query_dns64(query_ctx_t *qctx) { dns_rdataset_setownercase(dns64_rdataset, mname); client->query.attributes |= NS_QUERYATTR_NOADDITIONAL; dns64_rdataset->trust = qctx->rdataset->trust; - query_addrdataset(client, section, mname, dns64_rdataset); + + query_addtoname(mname, dns64_rdataset); + query_setorder(qctx, mname, dns64_rdataset); + dns64_rdataset = NULL; dns64_rdatalist = NULL; dns_message_takebuffer(client->message, &buffer); @@ -7558,16 +7328,18 @@ query_filter64(query_ctx_t *qctx) { */ CTRACE(ISC_LOG_DEBUG(3), "query_filter64: dns_message_findname succeeded: done"); - if (qctx->dbuf != NULL) - query_releasename(client, &qctx->fname); + if (qctx->dbuf != NULL) { + ns_client_releasename(client, &qctx->fname); + } return; } else if (result == DNS_R_NXDOMAIN) { mname = name; qctx->fname = NULL; } else { RUNTIME_CHECK(result == DNS_R_NXRRSET); - if (qctx->dbuf != NULL) - query_releasename(client, &qctx->fname); + if (qctx->dbuf != NULL) { + ns_client_releasename(client, &qctx->fname); + } qctx->dbuf = NULL; } @@ -7621,14 +7393,18 @@ query_filter64(query_ctx_t *qctx) { dns_rdataset_setownercase(myrdataset, name); client->query.attributes |= NS_QUERYATTR_NOADDITIONAL; if (mname == name) { - if (qctx->dbuf != NULL) - query_keepname(client, name, qctx->dbuf); + if (qctx->dbuf != NULL) { + ns_client_keepname(client, name, qctx->dbuf); + } dns_message_addname(client->message, name, section); qctx->dbuf = NULL; } myrdataset->trust = qctx->rdataset->trust; - query_addrdataset(client, section, mname, myrdataset); + + query_addtoname(mname, myrdataset); + query_setorder(qctx, mname, myrdataset); + myrdataset = NULL; myrdatalist = NULL; dns_message_takebuffer(client->message, &buffer); @@ -7653,8 +7429,9 @@ query_filter64(query_ctx_t *qctx) { } dns_message_puttemprdatalist(client->message, &myrdatalist); } - if (qctx->dbuf != NULL) - query_releasename(client, &name); + if (qctx->dbuf != NULL) { + ns_client_releasename(client, &name); + } CTRACE(ISC_LOG_DEBUG(3), "query_filter64: done"); } @@ -7668,6 +7445,8 @@ static isc_result_t query_notfound(query_ctx_t *qctx) { isc_result_t result; + CALL_HOOK(NS_QUERY_NOTFOUND_BEGIN, qctx); + INSIST(!qctx->is_zone); if (qctx->db != NULL) @@ -7677,14 +7456,14 @@ query_notfound(query_ctx_t *qctx) { * If the cache doesn't even have the root NS, * try to get that from the hints DB. */ - if (qctx->client->view->hints != NULL) { + if (qctx->view->hints != NULL) { dns_clientinfomethods_t cm; dns_clientinfo_t ci; dns_clientinfomethods_init(&cm, ns_client_sourceip); dns_clientinfo_init(&ci, qctx->client, NULL); - dns_db_attach(qctx->client->view->hints, &qctx->db); + dns_db_attach(qctx->view->hints, &qctx->db); result = dns_db_findext(qctx->db, dns_rootname, NULL, dns_rdatatype_ns, 0, qctx->client->now, &qctx->node, @@ -7732,6 +7511,9 @@ query_notfound(query_ctx_t *qctx) { } return (query_delegation(qctx)); + + cleanup: + return (result); } /*% @@ -7740,9 +7522,12 @@ query_notfound(query_ctx_t *qctx) { */ static isc_result_t query_prepare_delegation_response(query_ctx_t *qctx) { + isc_result_t result; dns_rdataset_t **sigrdatasetp = NULL; bool detach = false; + CALL_HOOK(NS_QUERY_PREP_DELEGATION_BEGIN, qctx); + /* * qctx->fname could be released in query_addrrset(), so save a copy of * it here in case we need it. @@ -7768,7 +7553,7 @@ query_prepare_delegation_response(query_ctx_t *qctx) { if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) { sigrdatasetp = &qctx->sigrdataset; } - query_addrrset(qctx->client, &qctx->fname, &qctx->rdataset, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp, qctx->dbuf, DNS_SECTION_AUTHORITY); if (detach) { dns_db_detach(&qctx->client->query.gluedb); @@ -7780,6 +7565,9 @@ query_prepare_delegation_response(query_ctx_t *qctx) { query_addds(qctx); return (query_done(qctx)); + + cleanup: + return (result); } /*% @@ -7792,6 +7580,8 @@ static isc_result_t query_zone_delegation(query_ctx_t *qctx) { isc_result_t result; + CALL_HOOK(NS_QUERY_ZONE_DELEGATION_BEGIN, qctx); + /* * If the query type is DS, look to see if we are * authoritative for the child zone @@ -7816,14 +7606,16 @@ query_zone_delegation(query_ctx_t *qctx) { dns_zone_detach(&tzone); } else { qctx->options &= ~DNS_GETDB_NOEXACT; - query_putrdataset(qctx->client, - &qctx->rdataset); - if (qctx->sigrdataset != NULL) - query_putrdataset(qctx->client, - &qctx->sigrdataset); - if (qctx->fname != NULL) - query_releasename(qctx->client, - &qctx->fname); + ns_client_putrdataset(qctx->client, + &qctx->rdataset); + if (qctx->sigrdataset != NULL) { + ns_client_putrdataset(qctx->client, + &qctx->sigrdataset); + } + if (qctx->fname != NULL) { + ns_client_releasename(qctx->client, + &qctx->fname); + } if (qctx->node != NULL) dns_db_detachnode(qctx->db, &qctx->node); @@ -7854,20 +7646,23 @@ query_zone_delegation(query_ctx_t *qctx) { * query_notfound() which calls query_delegation(), and * we'll restore these values there. */ - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); SAVE(qctx->zdb, qctx->db); SAVE(qctx->znode, qctx->node); SAVE(qctx->zfname, qctx->fname); SAVE(qctx->zversion, qctx->version); SAVE(qctx->zrdataset, qctx->rdataset); SAVE(qctx->zsigrdataset, qctx->sigrdataset); - dns_db_attach(qctx->client->view->cachedb, &qctx->db); + dns_db_attach(qctx->view->cachedb, &qctx->db); qctx->is_zone = false; return (query_lookup(qctx)); } return (query_prepare_delegation_response(qctx)); + + cleanup: + return (result); } /*% @@ -7882,6 +7677,8 @@ static isc_result_t query_delegation(query_ctx_t *qctx) { isc_result_t result; + CALL_HOOK(NS_QUERY_DELEGATION_BEGIN, qctx); + qctx->authoritative = false; if (qctx->is_zone) { @@ -7908,19 +7705,20 @@ query_delegation(query_ctx_t *qctx) { * the nameservers configured in the * static-stub zone. */ - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); /* - * We've already done query_keepname() on + * We've already done ns_client_keepname() on * qctx->zfname, so we must set dbuf to NULL to * prevent query_addrrset() from trying to - * call query_keepname() again. + * call ns_client_keepname() again. */ qctx->dbuf = NULL; - query_putrdataset(qctx->client, &qctx->rdataset); - if (qctx->sigrdataset != NULL) - query_putrdataset(qctx->client, - &qctx->sigrdataset); + ns_client_putrdataset(qctx->client, &qctx->rdataset); + if (qctx->sigrdataset != NULL) { + ns_client_putrdataset(qctx->client, + &qctx->sigrdataset); + } qctx->version = NULL; dns_db_detachnode(qctx->db, &qctx->node); @@ -7952,8 +7750,7 @@ query_delegation(query_ctx_t *qctx) { */ result = query_recurse(qctx->client, qctx->qtype, qname, - NULL, NULL, - qctx->resuming); + NULL, NULL, qctx->resuming); } else if (qctx->dns64) { /* * Look up an A record so we can @@ -7961,8 +7758,7 @@ query_delegation(query_ctx_t *qctx) { */ result = query_recurse(qctx->client, dns_rdatatype_a, qname, - NULL, NULL, - qctx->resuming); + NULL, NULL, qctx->resuming); } else { /* * Any other recursion @@ -7970,8 +7766,8 @@ query_delegation(query_ctx_t *qctx) { result = query_recurse(qctx->client, qctx->qtype, qname, qctx->fname, - qctx->rdataset, - qctx->resuming); + qctx->rdataset, + qctx->resuming); } if (result == ISC_R_SUCCESS) { qctx->client->query.attributes |= @@ -7992,6 +7788,9 @@ query_delegation(query_ctx_t *qctx) { } return (query_prepare_delegation_response(qctx)); + + cleanup: + return (result); } /*% @@ -8021,8 +7820,8 @@ query_addds(query_ctx_t *qctx) { /* * We'll need some resources... */ - rdataset = query_newrdataset(client); - sigrdataset = query_newrdataset(client); + rdataset = ns_client_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); if (rdataset == NULL || sigrdataset == NULL) goto cleanup; @@ -8075,10 +7874,10 @@ query_addds(query_ctx_t *qctx) { /* * Add the NSEC3 which proves the DS does not exist. */ - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) goto cleanup; - fname = query_newname(client, dbuf, &b); + fname = ns_client_newname(client, dbuf, &b); dns_fixedname_init(&fixed); if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); @@ -8090,7 +7889,7 @@ query_addds(query_ctx_t *qctx) { dns_fixedname_name(&fixed)); if (!dns_rdataset_isassociated(rdataset)) goto cleanup; - query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf, + query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, DNS_SECTION_AUTHORITY); /* * Did we find the closest provable encloser instead? @@ -8112,24 +7911,31 @@ query_addds(query_ctx_t *qctx) { false, NULL); if (!dns_rdataset_isassociated(rdataset)) goto cleanup; - query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf, + query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, DNS_SECTION_AUTHORITY); } cleanup: - if (rdataset != NULL) - query_putrdataset(client, &rdataset); - if (sigrdataset != NULL) - query_putrdataset(client, &sigrdataset); - if (fname != NULL) - query_releasename(client, &fname); + if (rdataset != NULL) { + ns_client_putrdataset(client, &rdataset); + } + if (sigrdataset != NULL) { + ns_client_putrdataset(client, &sigrdataset); + } + if (fname != NULL) { + ns_client_releasename(client, &fname); + } } /*% * Handle authoritative NOERROR/NODATA responses. */ static isc_result_t -query_nodata(query_ctx_t *qctx, isc_result_t result) { +query_nodata(query_ctx_t *qctx, isc_result_t res) { + isc_result_t result = res; + + CALL_HOOK(NS_QUERY_NODATA_BEGIN, qctx); + #ifdef dns64_bis_return_excluded_addresses if (qctx->dns64) #else @@ -8141,26 +7947,26 @@ query_nodata(query_ctx_t *qctx, isc_result_t result) { * Restore the answers from the previous AAAA lookup. */ if (qctx->rdataset != NULL) - query_putrdataset(qctx->client, &qctx->rdataset); + ns_client_putrdataset(qctx->client, &qctx->rdataset); if (qctx->sigrdataset != NULL) - query_putrdataset(qctx->client, &qctx->sigrdataset); + ns_client_putrdataset(qctx->client, &qctx->sigrdataset); RESTORE(qctx->rdataset, qctx->client->query.dns64_aaaa); RESTORE(qctx->sigrdataset, qctx->client->query.dns64_sigaaaa); if (qctx->fname == NULL) { - qctx->dbuf = query_getnamebuf(qctx->client); + qctx->dbuf = ns_client_getnamebuf(qctx->client); if (qctx->dbuf == NULL) { CCTRACE(ISC_LOG_ERROR, "query_nodata: " - "query_getnamebuf failed (3)"); + "ns_client_getnamebuf failed (3)"); QUERY_ERROR(qctx, DNS_R_SERVFAIL); return (query_done(qctx));; } - qctx->fname = query_newname(qctx->client, + qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b); if (qctx->fname == NULL) { CCTRACE(ISC_LOG_ERROR, "query_nodata: " - "query_newname failed (3)"); + "ns_client_newname failed (3)"); QUERY_ERROR(qctx, DNS_R_SERVFAIL); return (query_done(qctx));; } @@ -8176,7 +7982,7 @@ query_nodata(query_ctx_t *qctx, isc_result_t result) { #endif } else if ((result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) && - !ISC_LIST_EMPTY(qctx->client->view->dns64) && + !ISC_LIST_EMPTY(qctx->view->dns64) && qctx->client->message->rdclass == dns_rdataclass_in && qctx->qtype == dns_rdatatype_aaaa) { @@ -8209,7 +8015,7 @@ query_nodata(query_ctx_t *qctx, isc_result_t result) { SAVE(qctx->client->query.dns64_aaaa, qctx->rdataset); SAVE(qctx->client->query.dns64_sigaaaa, qctx->sigrdataset); - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); dns_db_detachnode(qctx->db, &qctx->node); qctx->type = qctx->qtype = dns_rdatatype_a; qctx->dns64 = true; @@ -8224,7 +8030,8 @@ query_nodata(query_ctx_t *qctx, isc_result_t result) { * of its extra features (and things would probably break!). */ if (dns_rdataset_isassociated(qctx->rdataset)) { - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, + qctx->dbuf); dns_message_addname(qctx->client->message, qctx->fname, DNS_SECTION_AUTHORITY); @@ -8236,6 +8043,9 @@ query_nodata(query_ctx_t *qctx, isc_result_t result) { } return (query_done(qctx)); + + cleanup: + return (result); } /*% @@ -8282,7 +8092,7 @@ query_sign_nodata(query_ctx_t *qctx) { /* * Add the closest provable encloser. */ - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, &qctx->sigrdataset, qctx->dbuf, @@ -8324,7 +8134,7 @@ query_sign_nodata(query_ctx_t *qctx) { NULL); } } else { - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); query_addwildcardproof(qctx, false, true); } } @@ -8334,14 +8144,14 @@ query_sign_nodata(query_ctx_t *qctx) { * name now because we're going call query_addsoa() * below, and it needs to use the name buffer. */ - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); } else if (qctx->fname != NULL) { /* * We're not going to use fname, and need to release * our hold on the name buffer so query_addsoa() * may use it. */ - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); } /* @@ -8381,7 +8191,7 @@ query_addnxrrsetnsec(query_ctx_t *qctx) { INSIST(qctx->fname != NULL); if ((qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) == 0) { - query_addrrset(client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY); return; @@ -8413,12 +8223,12 @@ query_addnxrrsetnsec(query_ctx_t *qctx) { /* * We'll need some resources... */ - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) { return; } - fname = query_newname(client, dbuf, &b); + fname = ns_client_newname(client, dbuf, &b); if (fname == NULL) { return; } @@ -8427,7 +8237,7 @@ query_addnxrrsetnsec(query_ctx_t *qctx) { /* This will succeed, since we've stripped labels. */ RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, fname, fname, NULL) == ISC_R_SUCCESS); - query_addrrset(client, &fname, &qctx->rdataset, &qctx->sigrdataset, + query_addrrset(qctx, &fname, &qctx->rdataset, &qctx->sigrdataset, dbuf, DNS_SECTION_AUTHORITY); } @@ -8440,6 +8250,8 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { uint32_t ttl; isc_result_t result; + CALL_HOOK(NS_QUERY_NXDOMAIN_BEGIN, qctx); + INSIST(qctx->is_zone || REDIRECT(qctx->client)); if (!empty_wild) { @@ -8454,14 +8266,14 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { * name now because we're going call query_addsoa() * below, and it needs to use the name buffer. */ - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); } else if (qctx->fname != NULL) { /* * We're not going to use fname, and need to release * our hold on the name buffer so query_addsoa() * may use it. */ - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); } /* @@ -8492,7 +8304,7 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { * Add NSEC record if we found one. */ if (dns_rdataset_isassociated(qctx->rdataset)) - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY); query_addwildcardproof(qctx, false, false); @@ -8507,6 +8319,9 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { qctx->client->message->rcode = dns_rcode_nxdomain; return (query_done(qctx)); + + cleanup: + return (result); } /* @@ -8657,18 +8472,18 @@ query_synthnodata(query_ctx_t *qctx, const dns_name_t *signer, * NODATA proof's name now or else discard it. */ if (WANTDNSSEC(qctx->client)) { - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); } else { - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); } - dbuf = query_getnamebuf(qctx->client); + dbuf = ns_client_getnamebuf(qctx->client); if (dbuf == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - name = query_newname(qctx->client, dbuf, &b); + name = ns_client_newname(qctx->client, dbuf, &b); if (name == NULL) { result = ISC_R_NOMEMORY; goto cleanup; @@ -8682,14 +8497,14 @@ query_synthnodata(query_ctx_t *qctx, const dns_name_t *signer, if (!WANTDNSSEC(qctx->client)) { sigsoardatasetp = NULL; } - query_addrrset(qctx->client, &name, soardatasetp, sigsoardatasetp, + query_addrrset(qctx, &name, soardatasetp, sigsoardatasetp, dbuf, DNS_SECTION_AUTHORITY); if (WANTDNSSEC(qctx->client)) { /* * Add NODATA proof. */ - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY); } @@ -8699,7 +8514,7 @@ query_synthnodata(query_ctx_t *qctx, const dns_name_t *signer, cleanup: if (name != NULL) { - query_releasename(qctx->client, &name); + ns_client_releasename(qctx->client, &name); } return (result); } @@ -8715,7 +8530,7 @@ query_synthwildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset, dns_name_t *name = NULL; isc_buffer_t *dbuf, b; isc_result_t result; - dns_rdataset_t *clone = NULL, *sigclone = NULL; + dns_rdataset_t *cloneset = NULL, *clonesigset = NULL; dns_rdataset_t **sigrdatasetp; /* @@ -8723,54 +8538,54 @@ query_synthwildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset, * NOQNAME proof's name now or else discard it. */ if (WANTDNSSEC(qctx->client)) { - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); } else { - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); } - dbuf = query_getnamebuf(qctx->client); + dbuf = ns_client_getnamebuf(qctx->client); if (dbuf == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - name = query_newname(qctx->client, dbuf, &b); + name = ns_client_newname(qctx->client, dbuf, &b); if (name == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } dns_name_copy(qctx->client->query.qname, name, NULL); - clone = query_newrdataset(qctx->client); - if (clone == NULL) { + cloneset = ns_client_newrdataset(qctx->client); + if (cloneset == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - dns_rdataset_clone(rdataset, clone); + dns_rdataset_clone(rdataset, cloneset); /* * Add answer RRset. Omit the RRSIG if DNSSEC was not requested. */ if (WANTDNSSEC(qctx->client)) { - sigclone = query_newrdataset(qctx->client); - if (sigclone == NULL) { + clonesigset = ns_client_newrdataset(qctx->client); + if (clonesigset == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - dns_rdataset_clone(sigrdataset, sigclone); - sigrdatasetp = &sigclone; + dns_rdataset_clone(sigrdataset, clonesigset); + sigrdatasetp = &clonesigset; } else { sigrdatasetp = NULL; } - query_addrrset(qctx->client, &name, &clone, sigrdatasetp, + query_addrrset(qctx, &name, &cloneset, sigrdatasetp, dbuf, DNS_SECTION_ANSWER); if (WANTDNSSEC(qctx->client)) { /* * Add NOQNAME proof. */ - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY); } @@ -8780,13 +8595,13 @@ query_synthwildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset, cleanup: if (name != NULL) { - query_releasename(qctx->client, &name); + ns_client_releasename(qctx->client, &name); } - if (clone != NULL) { - query_putrdataset(qctx->client, &clone); + if (cloneset != NULL) { + ns_client_putrdataset(qctx->client, &cloneset); } - if (sigclone != NULL) { - query_putrdataset(qctx->client, &sigclone); + if (clonesigset != NULL) { + ns_client_putrdataset(qctx->client, &clonesigset); } return (result); } @@ -8872,7 +8687,7 @@ query_synthnxdomain(query_ctx_t *qctx, dns_ttl_t ttl; isc_buffer_t *dbuf, b; isc_result_t result; - dns_rdataset_t *clone = NULL, *sigclone = NULL; + dns_rdataset_t *cloneset = NULL, *clonesigset = NULL; /* * Detemine the correct TTL to use for the SOA and RRSIG @@ -8887,18 +8702,18 @@ query_synthnxdomain(query_ctx_t *qctx, * NOQNAME proof's name now or else discard it. */ if (WANTDNSSEC(qctx->client)) { - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); } else { - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); } - dbuf = query_getnamebuf(qctx->client); + dbuf = ns_client_getnamebuf(qctx->client); if (dbuf == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - name = query_newname(qctx->client, dbuf, &b); + name = ns_client_newname(qctx->client, dbuf, &b); if (name == NULL) { result = ISC_R_NOMEMORY; goto cleanup; @@ -8912,24 +8727,24 @@ query_synthnxdomain(query_ctx_t *qctx, if (!WANTDNSSEC(qctx->client)) { sigsoardatasetp = NULL; } - query_addrrset(qctx->client, &name, soardatasetp, sigsoardatasetp, + query_addrrset(qctx, &name, soardatasetp, sigsoardatasetp, dbuf, DNS_SECTION_AUTHORITY); if (WANTDNSSEC(qctx->client)) { /* * Add NOQNAME proof. */ - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY); - dbuf = query_getnamebuf(qctx->client); + dbuf = ns_client_getnamebuf(qctx->client); if (dbuf == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - name = query_newname(qctx->client, dbuf, &b); + name = ns_client_newname(qctx->client, dbuf, &b); if (name == NULL) { result = ISC_R_NOMEMORY; goto cleanup; @@ -8937,20 +8752,20 @@ query_synthnxdomain(query_ctx_t *qctx, dns_name_copy(nowild, name, NULL); - clone = query_newrdataset(qctx->client); - sigclone = query_newrdataset(qctx->client); - if (clone == NULL || sigclone == NULL) { + cloneset = ns_client_newrdataset(qctx->client); + clonesigset = ns_client_newrdataset(qctx->client); + if (cloneset == NULL || clonesigset == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - dns_rdataset_clone(nowildrdataset, clone); - dns_rdataset_clone(signowildrdataset, sigclone); + dns_rdataset_clone(nowildrdataset, cloneset); + dns_rdataset_clone(signowildrdataset, clonesigset); /* * Add NOWILDCARD proof. */ - query_addrrset(qctx->client, &name, &clone, &sigclone, + query_addrrset(qctx, &name, &cloneset, &clonesigset, dbuf, DNS_SECTION_AUTHORITY); } @@ -8960,13 +8775,13 @@ query_synthnxdomain(query_ctx_t *qctx, cleanup: if (name != NULL) { - query_releasename(qctx->client, &name); + ns_client_releasename(qctx->client, &name); } - if (clone != NULL) { - query_putrdataset(qctx->client, &clone); + if (cloneset != NULL) { + ns_client_putrdataset(qctx->client, &cloneset); } - if (sigclone != NULL) { - query_putrdataset(qctx->client, &sigclone); + if (clonesigset != NULL) { + ns_client_putrdataset(qctx->client, &clonesigset); } return (result); } @@ -9083,13 +8898,7 @@ query_coveringnsec(query_ctx_t *qctx) { if (qctx->type == dns_rdatatype_any) { /* XXX not yet */ goto cleanup; } - if (qctx->client->filter_aaaa != dns_aaaa_ok && - (qctx->type == dns_rdatatype_a || - qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */ - { - goto cleanup; - } - if (!ISC_LIST_EMPTY(qctx->client->view->dns64) && + if (!ISC_LIST_EMPTY(qctx->view->dns64) && (qctx->type == dns_rdatatype_a || qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */ { @@ -9101,8 +8910,8 @@ query_coveringnsec(query_ctx_t *qctx) { goto cleanup; } - soardataset = query_newrdataset(qctx->client); - sigsoardataset = query_newrdataset(qctx->client); + soardataset = ns_client_newrdataset(qctx->client); + sigsoardataset = ns_client_newrdataset(qctx->client); if (soardataset == NULL || sigsoardataset == NULL) { goto cleanup; } @@ -9153,13 +8962,7 @@ query_coveringnsec(query_ctx_t *qctx) { if (qctx->type == dns_rdatatype_any) { /* XXX not yet */ goto cleanup; } - if (qctx->client->filter_aaaa != dns_aaaa_ok && - (qctx->type == dns_rdatatype_a || - qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */ - { - goto cleanup; - } - if (!ISC_LIST_EMPTY(qctx->client->view->dns64) && + if (!ISC_LIST_EMPTY(qctx->view->dns64) && (qctx->type == dns_rdatatype_a || qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */ { @@ -9230,8 +9033,8 @@ query_coveringnsec(query_ctx_t *qctx) { dns_db_detachnode(db, &node); } - soardataset = query_newrdataset(qctx->client); - sigsoardataset = query_newrdataset(qctx->client); + soardataset = ns_client_newrdataset(qctx->client); + sigsoardataset = ns_client_newrdataset(qctx->client); if (soardataset == NULL || sigsoardataset == NULL) { goto cleanup; } @@ -9261,10 +9064,10 @@ query_coveringnsec(query_ctx_t *qctx) { dns_rdataset_disassociate(&sigrdataset); } if (soardataset != NULL) { - query_putrdataset(qctx->client, &soardataset); + ns_client_putrdataset(qctx->client, &soardataset); } if (sigsoardataset != NULL) { - query_putrdataset(qctx->client, &sigsoardataset); + ns_client_putrdataset(qctx->client, &sigsoardataset); } if (db != NULL) { if (node != NULL) { @@ -9283,14 +9086,14 @@ query_coveringnsec(query_ctx_t *qctx) { */ qctx->findcoveringnsec = false; if (qctx->fname != NULL) { - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); } if (qctx->node != NULL) { dns_db_detachnode(qctx->db, &qctx->node); } - query_putrdataset(qctx->client, &qctx->rdataset); + ns_client_putrdataset(qctx->client, &qctx->rdataset); if (qctx->sigrdataset != NULL) { - query_putrdataset(qctx->client, &qctx->sigrdataset); + ns_client_putrdataset(qctx->client, &qctx->sigrdataset); } return (query_lookup(qctx)); } @@ -9345,6 +9148,8 @@ query_cname(query_ctx_t *qctx) { dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdata_cname_t cname; + CALL_HOOK(NS_QUERY_CNAME_BEGIN, qctx); + /* * If we have a zero ttl from the cache refetch it. */ @@ -9405,7 +9210,7 @@ query_cname(query_ctx_t *qctx) { if (!qctx->is_zone && RECURSIONOK(qctx->client)) query_prefetch(qctx->client, qctx->fname, qctx->rdataset); - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp, qctx->dbuf, DNS_SECTION_ANSWER); @@ -9457,6 +9262,9 @@ query_cname(query_ctx_t *qctx) { query_addauth(qctx); return (query_done(qctx)); + + cleanup: + return (result); } /* @@ -9476,6 +9284,8 @@ query_dname(query_ctx_t *qctx) { isc_result_t result; unsigned int nlabels; + CALL_HOOK(NS_QUERY_DNAME_BEGIN, qctx); + /* * Compare the current qname to the found name. We need * to know how many labels and bits are in common because @@ -9509,7 +9319,7 @@ query_dname(query_ctx_t *qctx) { if (!qctx->is_zone && RECURSIONOK(qctx->client)) query_prefetch(qctx->client, qctx->fname, qctx->rdataset); - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp, qctx->dbuf, DNS_SECTION_ANSWER); @@ -9551,12 +9361,12 @@ query_dname(query_ctx_t *qctx) { prefix = dns_fixedname_initname(&fixed); dns_name_split(qctx->client->query.qname, nlabels, prefix, NULL); INSIST(qctx->fname == NULL); - qctx->dbuf = query_getnamebuf(qctx->client); + qctx->dbuf = ns_client_getnamebuf(qctx->client); if (qctx->dbuf == NULL) { dns_message_puttempname(qctx->client->message, &tname); return (query_done(qctx)); } - qctx->fname = query_newname(qctx->client, qctx->dbuf, &b); + qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b); if (qctx->fname == NULL) { dns_message_puttempname(qctx->client->message, &tname); return (query_done(qctx)); @@ -9574,7 +9384,7 @@ query_dname(query_ctx_t *qctx) { if (result != ISC_R_SUCCESS) return (query_done(qctx)); - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); /* * Synthesize a CNAME consisting of @@ -9606,6 +9416,9 @@ query_dname(query_ctx_t *qctx) { query_addauth(qctx); return (query_done(qctx)); + + cleanup: + return (result); } /*% @@ -9667,7 +9480,7 @@ query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl) { rdataset->trust = trust; dns_rdataset_setownercase(rdataset, aname); - query_addrrset(client, &aname, &rdataset, NULL, NULL, + query_addrrset(qctx, &aname, &rdataset, NULL, NULL, DNS_SECTION_ANSWER); if (rdataset != NULL) { if (dns_rdataset_isassociated(rdataset)) @@ -9682,11 +9495,15 @@ query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl) { /*% * Prepare to respond: determine whether a wildcard proof is needed, - * check whether to filter AAAA answers, then hand off to query_respond() - * or (for type ANY queries) query_respond_any(). + * then hand off to query_respond() or (for type ANY queries) + * query_respond_any(). */ static isc_result_t query_prepresponse(query_ctx_t *qctx) { + isc_result_t result; + + CALL_HOOK(NS_QUERY_PREP_RESPONSE_BEGIN, qctx); + if (WANTDNSSEC(qctx->client) && (qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) != 0) { @@ -9696,35 +9513,14 @@ query_prepresponse(query_ctx_t *qctx) { qctx->need_wildcardproof = true; } - /* - * The filter-aaaa-on-v4 option should suppress AAAAs for IPv4 - * clients if there is an A; filter-aaaa-on-v6 option does the same - * for IPv6 clients. - */ - qctx->client->filter_aaaa = dns_aaaa_ok; - if (qctx->client->view->v4_aaaa != dns_aaaa_ok || - qctx->client->view->v6_aaaa != dns_aaaa_ok) - { - isc_result_t result; - result = ns_client_checkaclsilent(qctx->client, NULL, - qctx->client->view->aaaa_acl, - true); - if (result == ISC_R_SUCCESS && - qctx->client->view->v4_aaaa != dns_aaaa_ok && - is_v4_client(qctx->client)) - qctx->client->filter_aaaa = qctx->client->view->v4_aaaa; - else if (result == ISC_R_SUCCESS && - qctx->client->view->v6_aaaa != dns_aaaa_ok && - is_v6_client(qctx->client)) - qctx->client->filter_aaaa = qctx->client->view->v6_aaaa; - } - - if (qctx->type == dns_rdatatype_any) { return (query_respond_any(qctx)); - } else { - return (query_respond(qctx)); } + + return (query_respond(qctx)); + + cleanup: + return (result); } /*% @@ -9774,14 +9570,14 @@ query_addsoa(query_ctx_t *qctx, unsigned int override_ttl, return (result); dns_name_init(name, NULL); dns_name_clone(dns_db_origin(qctx->db), name); - rdataset = query_newrdataset(client); + rdataset = ns_client_newrdataset(client); if (rdataset == NULL) { CTRACE(ISC_LOG_ERROR, "unable to allocate rdataset"); eresult = DNS_R_SERVFAIL; goto cleanup; } if (WANTDNSSEC(client) && dns_db_issecure(qctx->db)) { - sigrdataset = query_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); if (sigrdataset == NULL) { CTRACE(ISC_LOG_ERROR, "unable to allocate sigrdataset"); eresult = DNS_R_SERVFAIL; @@ -9854,16 +9650,16 @@ query_addsoa(query_ctx_t *qctx, unsigned int override_ttl, if (section == DNS_SECTION_ADDITIONAL) rdataset->attributes |= DNS_RDATASETATTR_REQUIRED; - query_addrrset(client, &name, &rdataset, + query_addrrset(qctx, &name, &rdataset, sigrdatasetp, NULL, section); } cleanup: - query_putrdataset(client, &rdataset); + ns_client_putrdataset(client, &rdataset); if (sigrdataset != NULL) - query_putrdataset(client, &sigrdataset); + ns_client_putrdataset(client, &sigrdataset); if (name != NULL) - query_releasename(client, &name); + ns_client_releasename(client, &name); if (node != NULL) dns_db_detachnode(qctx->db, &node); @@ -9907,19 +9703,19 @@ query_addns(query_ctx_t *qctx) { } dns_name_init(name, NULL); dns_name_clone(dns_db_origin(qctx->db), name); - rdataset = query_newrdataset(client); + rdataset = ns_client_newrdataset(client); if (rdataset == NULL) { CTRACE(ISC_LOG_ERROR, - "query_addns: query_newrdataset failed"); + "query_addns: ns_client_newrdataset failed"); eresult = DNS_R_SERVFAIL; goto cleanup; } if (WANTDNSSEC(client) && dns_db_issecure(qctx->db)) { - sigrdataset = query_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); if (sigrdataset == NULL) { CTRACE(ISC_LOG_ERROR, - "query_addns: query_newrdataset failed"); + "query_addns: ns_client_newrdataset failed"); eresult = DNS_R_SERVFAIL; goto cleanup; } @@ -9953,18 +9749,18 @@ query_addns(query_ctx_t *qctx) { if (sigrdataset != NULL) { sigrdatasetp = &sigrdataset; } - query_addrrset(client, &name, &rdataset, sigrdatasetp, NULL, + query_addrrset(qctx, &name, &rdataset, sigrdatasetp, NULL, DNS_SECTION_AUTHORITY); } cleanup: CTRACE(ISC_LOG_DEBUG(3), "query_addns: cleanup"); - query_putrdataset(client, &rdataset); + ns_client_putrdataset(client, &rdataset); if (sigrdataset != NULL) { - query_putrdataset(client, &sigrdataset); + ns_client_putrdataset(client, &sigrdataset); } if (name != NULL) { - query_releasename(client, &name); + ns_client_releasename(client, &name); } if (node != NULL) { dns_db_detachnode(qctx->db, &node); @@ -10011,12 +9807,12 @@ query_addbestns(query_ctx_t *qctx) { /* * We'll need some resources... */ - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) { goto cleanup; } - fname = query_newname(client, dbuf, &b); - rdataset = query_newrdataset(client); + fname = ns_client_newname(client, dbuf, &b); + rdataset = ns_client_newrdataset(client); if (fname == NULL || rdataset == NULL) { goto cleanup; } @@ -10026,7 +9822,7 @@ query_addbestns(query_ctx_t *qctx) { * need to validate answers from the cache. */ if (WANTDNSSEC(client) || !is_zone) { - sigrdataset = query_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); if (sigrdataset == NULL) { goto cleanup; } @@ -10045,7 +9841,7 @@ query_addbestns(query_ctx_t *qctx) { goto cleanup; } if (USECACHE(client)) { - query_keepname(client, fname, dbuf); + ns_client_keepname(client, fname, dbuf); dns_db_detachnode(db, &node); SAVE(zdb, db); SAVE(zfname, fname); @@ -10082,17 +9878,17 @@ query_addbestns(query_ctx_t *qctx) { } if (use_zone) { - query_releasename(client, &fname); + ns_client_releasename(client, &fname); /* - * We've already done query_keepname() on + * We've already done ns_client_keepname() on * zfname, so we must set dbuf to NULL to * prevent query_addrrset() from trying to - * call query_keepname() again. + * call ns_client_keepname() again. */ dbuf = NULL; - query_putrdataset(client, &rdataset); + ns_client_putrdataset(client, &rdataset); if (sigrdataset != NULL) { - query_putrdataset(client, &sigrdataset); + ns_client_putrdataset(client, &sigrdataset); } if (node != NULL) { @@ -10141,21 +9937,21 @@ query_addbestns(query_ctx_t *qctx) { * now. */ if (!WANTDNSSEC(client)) { - query_putrdataset(client, &sigrdataset); + ns_client_putrdataset(client, &sigrdataset); } - query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf, + query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, DNS_SECTION_AUTHORITY); cleanup: if (rdataset != NULL) { - query_putrdataset(client, &rdataset); + ns_client_putrdataset(client, &rdataset); } if (sigrdataset != NULL) { - query_putrdataset(client, &sigrdataset); + ns_client_putrdataset(client, &sigrdataset); } if (fname != NULL) { - query_releasename(client, &fname); + ns_client_releasename(client, &fname); } if (node != NULL) { dns_db_detachnode(db, &node); @@ -10167,11 +9963,13 @@ query_addbestns(query_ctx_t *qctx) { dns_zone_detach(&zone); } if (zdb != NULL) { - query_putrdataset(client, &zrdataset); - if (zsigrdataset != NULL) - query_putrdataset(client, &zsigrdataset); - if (zfname != NULL) - query_releasename(client, &zfname); + ns_client_putrdataset(client, &zrdataset); + if (zsigrdataset != NULL) { + ns_client_putrdataset(client, &zsigrdataset); + } + if (zfname != NULL) { + ns_client_releasename(client, &zfname); + } dns_db_detach(&zdb); } } @@ -10266,12 +10064,12 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, /* * We'll need some resources... */ - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) goto cleanup; - fname = query_newname(client, dbuf, &b); - rdataset = query_newrdataset(client); - sigrdataset = query_newrdataset(client); + fname = ns_client_newname(client, dbuf, &b); + rdataset = ns_client_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); if (fname == NULL || rdataset == NULL || sigrdataset == NULL) goto cleanup; @@ -10312,26 +10110,26 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, if (!dns_rdataset_isassociated(rdataset)) goto cleanup; if (!ispositive) - query_addrrset(client, &fname, &rdataset, &sigrdataset, + query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, DNS_SECTION_AUTHORITY); /* * Replace resources which were consumed by query_addrrset. */ if (fname == NULL) { - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) goto cleanup; - fname = query_newname(client, dbuf, &b); + fname = ns_client_newname(client, dbuf, &b); } if (rdataset == NULL) - rdataset = query_newrdataset(client); + rdataset = ns_client_newrdataset(client); else if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); if (sigrdataset == NULL) - sigrdataset = query_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); else if (dns_rdataset_isassociated(sigrdataset)) dns_rdataset_disassociate(sigrdataset); @@ -10351,7 +10149,7 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, fname, false, NULL); if (!dns_rdataset_isassociated(rdataset)) goto cleanup; - query_addrrset(client, &fname, &rdataset, &sigrdataset, + query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, DNS_SECTION_AUTHORITY); if (ispositive) @@ -10361,19 +10159,19 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, * Replace resources which were consumed by query_addrrset. */ if (fname == NULL) { - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) goto cleanup; - fname = query_newname(client, dbuf, &b); + fname = ns_client_newname(client, dbuf, &b); } if (rdataset == NULL) - rdataset = query_newrdataset(client); + rdataset = ns_client_newrdataset(client); else if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); if (sigrdataset == NULL) - sigrdataset = query_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); else if (dns_rdataset_isassociated(sigrdataset)) dns_rdataset_disassociate(sigrdataset); @@ -10392,7 +10190,7 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, fname, nodata, NULL); if (!dns_rdataset_isassociated(rdataset)) goto cleanup; - query_addrrset(client, &fname, &rdataset, &sigrdataset, + query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, DNS_SECTION_AUTHORITY); goto cleanup; @@ -10425,15 +10223,18 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, have_wname = true; dns_rdata_freestruct(&nsec); } - query_addrrset(client, &fname, &rdataset, &sigrdataset, + query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, DNS_SECTION_AUTHORITY); } - if (rdataset != NULL) - query_putrdataset(client, &rdataset); - if (sigrdataset != NULL) - query_putrdataset(client, &sigrdataset); - if (fname != NULL) - query_releasename(client, &fname); + if (rdataset != NULL) { + ns_client_putrdataset(client, &rdataset); + } + if (sigrdataset != NULL) { + ns_client_putrdataset(client, &sigrdataset); + } + if (fname != NULL) { + ns_client_releasename(client, &fname); + } if (have_wname) { ispositive = true; /* prevent loop */ if (!dns_name_equal(name, wname)) { @@ -10442,12 +10243,15 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, } } cleanup: - if (rdataset != NULL) - query_putrdataset(client, &rdataset); - if (sigrdataset != NULL) - query_putrdataset(client, &sigrdataset); - if (fname != NULL) - query_releasename(client, &fname); + if (rdataset != NULL) { + ns_client_putrdataset(client, &rdataset); + } + if (sigrdataset != NULL) { + ns_client_putrdataset(client, &sigrdataset); + } + if (fname != NULL) { + ns_client_releasename(client, &fname); + } } /*% @@ -10470,7 +10274,8 @@ query_addauth(query_ctx_t *qctx) { qctx->qtype != dns_rdatatype_ns) { if (qctx->fname != NULL) { - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, + &qctx->fname); } query_addbestns(qctx); } @@ -10585,21 +10390,14 @@ query_glueanswer(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(). - */ -static isc_result_t +isc_result_t query_done(query_ctx_t *qctx) { + isc_result_t result; const dns_namelist_t *secs = qctx->client->message->sections; + CCTRACE(ISC_LOG_DEBUG(3), "query_done"); - PROCESS_HOOK(NS_QUERY_DONE_BEGIN, qctx); + CALL_HOOK(NS_QUERY_DONE_BEGIN, qctx); /* * General cleanup. @@ -10632,7 +10430,6 @@ query_done(query_ctx_t *qctx) { if (qctx->want_stale) { dns_ttl_t stale_ttl = 0; - isc_result_t result; bool staleanswersok = false; /* @@ -10640,16 +10437,15 @@ query_done(query_ctx_t *qctx) { * we want rndc to be able to control returning stale * answers if they are configured. */ - dns_db_attach(qctx->client->view->cachedb, &qctx->db); + dns_db_attach(qctx->view->cachedb, &qctx->db); result = dns_db_getservestalettl(qctx->db, &stale_ttl); if (result == ISC_R_SUCCESS && stale_ttl > 0) { - switch (qctx->client->view->staleanswersok) { + switch (qctx->view->staleanswersok) { case dns_stale_answer_yes: staleanswersok = true; break; case dns_stale_answer_conf: - staleanswersok = - qctx->client->view->staleanswersenable; + staleanswersok = qctx->view->staleanswersenable; break; case dns_stale_answer_no: staleanswersok = false; @@ -10697,7 +10493,7 @@ query_done(query_ctx_t *qctx) { query_error(qctx->client, qctx->result, qctx->line); } - ns_client_detach(&qctx->client); + qctx->detach_client = true; return (qctx->result); } @@ -10720,7 +10516,7 @@ query_done(query_ctx_t *qctx) { query_glueanswer(qctx); if (qctx->client->message->rcode == dns_rcode_nxdomain && - qctx->client->view->auth_nxdomain == true) + qctx->view->auth_nxdomain == true) { qctx->client->message->flags |= DNS_MESSAGEFLAG_AA; } @@ -10737,10 +10533,15 @@ query_done(query_ctx_t *qctx) { qctx->result = ISC_R_FAILURE; } + CALL_HOOK(NS_QUERY_DONE_SEND, qctx); + query_send(qctx->client); - ns_client_detach(&qctx->client); + qctx->detach_client = true; return (qctx->result); + + cleanup: + return (result); } static inline void diff --git a/lib/ns/server.c b/lib/ns/server.c index 91ae32d69236103ef9721ca1b2424074408681bd..54eec6daf5c3e0722a7b773358de0b31d0650916 100644 --- a/lib/ns/server.c +++ b/lib/ns/server.c @@ -22,6 +22,8 @@ #include #include +#include +#include #include #include diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index d71dbd68760e725c5ec331c779b432673c72dfaf..e2ab694d125da785e0f87298700439789d300d2b 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -45,11 +45,10 @@ #include #include +#include #include #include -#include "../hooks.h" - #include "nstest.h" isc_mem_t *mctx = NULL; @@ -266,8 +265,6 @@ ns_test_begin(FILE *logfile, bool start_managers) { if (chdir(TESTS) == -1) CHECK(ISC_R_FAILURE); - ns__hook_table = NULL; - return (ISC_R_SUCCESS); cleanup: @@ -611,17 +608,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) { +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); /* @@ -631,10 +628,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. @@ -654,12 +651,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, query_hooks; + ns_hook_t hook = { + .action = extract_qctx, + .action_data = qctxp, }; REQUIRE(client != NULL); @@ -673,9 +668,15 @@ 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_init(&query_hooks); + ns_hook_add(&query_hooks, NULL, NS_QUERY_SETUP, &hook); + saved_hook_table = ns__hook_table; - ns__hook_table = query_hooks; + ns__hook_table = &query_hooks; + ns_query_start(client); + ns__hook_table = saved_hook_table; if (*qctxp == NULL) { @@ -779,11 +780,10 @@ ns_test_qctx_destroy(query_ctx_t **qctxp) { } bool -ns_test_hook_catch_call(void *hook_data, void *callback_data, - isc_result_t *resultp) +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; diff --git a/lib/ns/tests/nstest.h b/lib/ns/tests/nstest.h index bc04487046334ebda7a5f20bd34056dd14a759a8..fc69befdc695f00180b9dd60f9926a4c787b3b42 100644 --- a/lib/ns/tests/nstest.h +++ b/lib/ns/tests/nstest.h @@ -151,5 +151,4 @@ 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_test_hook_catch_call(void *arg, void *data, isc_result_t *resultp); diff --git a/lib/ns/tests/query_test.c b/lib/ns/tests/query_test.c index 81818c2d9bae21782c7b852e4947e78e039fb185..5e8d516f65018924765406c7baadb0f11a9c2d0f 100644 --- a/lib/ns/tests/query_test.c +++ b/lib/ns/tests/query_test.c @@ -21,11 +21,11 @@ #include #include #include + #include +#include #include -#include "../hooks.h" - #include "nstest.h" /***** @@ -54,6 +54,9 @@ static void ns__query_sfcache_test(const ns__query_sfcache_test_params_t *test) { query_ctx_t *qctx = NULL; isc_result_t result; + ns_hook_t hook = { + .action = ns_test_hook_catch_call, + }; REQUIRE(test != NULL); REQUIRE(test->id.description != NULL); @@ -63,13 +66,9 @@ ns__query_sfcache_test(const ns__query_sfcache_test_params_t *test) { /* * Interrupt execution if 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__hook_table = query_hooks; + + ns_hooktable_init(ns__hook_table); + ns_hook_add(ns__hook_table, NULL, NS_QUERY_DONE_BEGIN, &hook); /* * Construct a query context for a ./NS query with given flags. @@ -259,6 +258,9 @@ static void ns__query_start_test(const ns__query_start_test_params_t *test) { query_ctx_t *qctx = NULL; isc_result_t result; + ns_hook_t hook = { + .action = ns_test_hook_catch_call, + }; REQUIRE(test != NULL); REQUIRE(test->id.description != NULL); @@ -270,17 +272,10 @@ ns__query_start_test(const ns__query_start_test_params_t *test) { /* * Interrupt execution if query_lookup() or 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__hook_table = query_hooks; + + ns_hooktable_init(ns__hook_table); + ns_hook_add(ns__hook_table, NULL, NS_QUERY_LOOKUP_BEGIN, &hook); + ns_hook_add(ns__hook_table, NULL, NS_QUERY_DONE_BEGIN, &hook); /* * Construct a query context using the supplied parameters. diff --git a/lib/ns/win32/libns.def b/lib/ns/win32/libns.def index 196acd47ac78508986b35f71ef66726f4be69358..f44a5bb1dd85d40264f2ec6c86d69190fdba4732 100644 --- a/lib/ns/win32/libns.def +++ b/lib/ns/win32/libns.def @@ -17,26 +17,42 @@ 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_clientmgr_create +ns_clientmgr_createclients +ns_clientmgr_destroy +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 ns_client_settimeout ns_client_shuttingdown ns_client_sourceip -ns_clientmgr_create -ns_clientmgr_createclients -ns_clientmgr_destroy +ns_hook_add +ns_hook_createctx +ns_hook_destroyctx +ns_hookmodule_load +ns_hookmodule_unload_all +ns_hooktable_create +ns_hooktable_free +ns_hooktable_init ns_interface_attach ns_interface_detach -ns_interface_shutdown ns_interfacemgr_adjust ns_interfacemgr_attach ns_interfacemgr_create @@ -50,6 +66,7 @@ ns_interfacemgr_setbacklog ns_interfacemgr_setlistenon4 ns_interfacemgr_setlistenon6 ns_interfacemgr_shutdown +ns_interface_shutdown ns_lib_init ns_lib_shutdown ns_listenelt_create diff --git a/make/rules.in b/make/rules.in index 26bd0103ef36a7449cd869b29016a23105228a74..5cc4a4e67d39b09b1aa3c95a336cafcbc59d1084 100644 --- a/make/rules.in +++ b/make/rules.in @@ -174,7 +174,7 @@ MKDEP = ${SHELL} ${top_builddir}/make/mkdep ### necessary libraries explicitly in addition to (or instead of) ${LIBS}, ### like this: ### binary@EXEEXT@: ${OBJS} -### cc -o $@ ${OBJS} ${OTHERLIB1} ${OTHERLIB2} ${lIBS} +### cc -o $@ ${OBJS} ${OTHERLIB1} ${OTHERLIB2} ${LIBS} ### in order to modify such a rule to use this compound command, a separate ### variable "LIBS0" should be deinfed for the explicitly listed libraries, ### while making sure ${LIBS} still includes libisc. So the above rule would diff --git a/util/copyrights b/util/copyrights index 489c688e9e70f736b82ccb9eed2533cecfcf0a58..a75b2d4737b1fe7fb64ec77e4bfb776d6bc04ec1 100644 --- a/util/copyrights +++ b/util/copyrights @@ -153,6 +153,12 @@ ./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/hooks/Makefile.in MAKE 2018 +./bin/hooks/filter-aaaa.8 MAN DOCBOOK +./bin/hooks/filter-aaaa.c C 2018 +./bin/hooks/filter-aaaa.docbook SGML 2018 +./bin/hooks/filter-aaaa.html HTML DOCBOOK +./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 @@ -1207,20 +1213,6 @@ ./bin/tests/system/fetchlimit/setup.sh SH 2015,2016,2018 ./bin/tests/system/fetchlimit/tests.sh SH 2015,2016,2018 ./bin/tests/system/filter-aaaa/clean.sh SH 2010,2012,2014,2016,2018 -./bin/tests/system/filter-aaaa/conf/bad1.conf CONF-C 2010,2016,2018 -./bin/tests/system/filter-aaaa/conf/bad2.conf CONF-C 2010,2016,2018 -./bin/tests/system/filter-aaaa/conf/bad3.conf CONF-C 2010,2016,2018 -./bin/tests/system/filter-aaaa/conf/bad4.conf CONF-C 2010,2016,2018 -./bin/tests/system/filter-aaaa/conf/bad5.conf CONF-C 2010,2016,2018 -./bin/tests/system/filter-aaaa/conf/bad6.conf CONF-C 2010,2016,2018 -./bin/tests/system/filter-aaaa/conf/good1.conf CONF-C 2010,2016,2018 -./bin/tests/system/filter-aaaa/conf/good2.conf CONF-C 2010,2016,2018 -./bin/tests/system/filter-aaaa/conf/good3.conf CONF-C 2010,2016,2018 -./bin/tests/system/filter-aaaa/conf/good4.conf CONF-C 2010,2016,2018 -./bin/tests/system/filter-aaaa/conf/good5.conf CONF-C 2010,2016,2018 -./bin/tests/system/filter-aaaa/conf/good6.conf CONF-C 2010,2016,2018 -./bin/tests/system/filter-aaaa/conf/good7.conf CONF-C 2010,2016,2018 -./bin/tests/system/filter-aaaa/conf/good8.conf CONF-C 2010,2016,2018 ./bin/tests/system/filter-aaaa/ns1/named1.conf.in CONF-C 2012,2013,2016,2017,2018 ./bin/tests/system/filter-aaaa/ns1/named2.conf.in CONF-C 2012,2013,2016,2017,2018 ./bin/tests/system/filter-aaaa/ns1/root.db ZONE 2010,2012,2016,2017,2018 @@ -1241,6 +1233,7 @@ ./bin/tests/system/filter-aaaa/ns4/unsigned.db ZONE 2010,2012,2016,2017,2018 ./bin/tests/system/filter-aaaa/ns5/hints ZONE 2018 ./bin/tests/system/filter-aaaa/ns5/named.conf.in CONF-C 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 @@ -2644,6 +2637,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 @@ -3668,8 +3662,11 @@ ./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/Makefile.in MAKE 2017,2018 +./lib/ns/include/ns/Makefile.in MAKE 2017,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 diff --git a/win32utils/Configure b/win32utils/Configure index d2eed20e833eeab3affbc845dc6af7d70caced73..63c9924de3b38ea43fa99d90d3905e7f35d2fe46 100644 --- a/win32utils/Configure +++ b/win32utils/Configure @@ -351,7 +351,6 @@ my @enablelist = ("developer", "isc-spnego", "native-pkcs11", "openssl-hash", - "filter-aaaa", "querytrace", "rpz-nsdname", "rpz-nsip");