diff --git a/bin/named/server.c b/bin/named/server.c index 13cb46e1b9..9c3bd99e3c 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -5300,15 +5300,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, } #ifdef HAVE_DLOPEN - /* - * XXX: because dns64 is still automatically configured, - * we need to create a hooktable for every view regardless - * of whether hook_list is set or not. - */ -#if 0 - if (plugin_list != NULL) -#endif - { + if (plugin_list != NULL) { INSIST(view->hooktable == NULL); CHECK(ns_hooktable_create(view->mctx, (ns_hooktable_t **) &view->hooktable)); @@ -5320,9 +5312,6 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, CHECK(cfg_pluginlist_foreach(config, plugin_list, named_g_lctx, register_one_plugin, view)); } - - /* XXX: temporary initialization for built in dns64 hooks */ - ns__query_inithooks(view); #endif /* diff --git a/bin/plugins/Makefile.in b/bin/plugins/Makefile.in index 0c4f7695d5..9b667c3c23 100644 --- a/bin/plugins/Makefile.in +++ b/bin/plugins/Makefile.in @@ -24,24 +24,32 @@ NSLIBS = ../../lib/ns/libns.@A@ LIBS = -SO_TARGETS = lib/filter-aaaa.@SO@ -SO_INSTALL = filter-aaaa.@SO@ +SO_TARGETS = lib/dns64.@SO@ lib/filter-aaaa.@SO@ +SO_INSTALL = dns64.@SO@ filter-aaaa.@SO@ TARGETS = @SO_TARGETS@ -SO_OBJS = filter-aaaa.@O@ -SO_SRCS = filter-aaaa.c +SO_OBJS = dns64.@O@ filter-aaaa.@O@ +SO_SRCS = dns64.c filter-aaaa.c CFLAGS = @CFLAGS@ @SO_CFLAGS@ SO_LDFLAGS = @LDFLAGS@ @SO_LDFLAGS@ -MANPAGES = filter-aaaa.8 +MANPAGES = dns64.8 filter-aaaa.8 -HTMLPAGES = filter-aaaa.html +HTMLPAGES = dns64.html filter-aaaa.html MANOBJS = ${MANPAGES} ${HTMLPAGES} @BIND9_MAKE_RULES@ +lib/dns64.@SO@: dns64.@SO@ + $(SHELL) ${top_srcdir}/mkinstalldirs `pwd`/lib + ${LIBTOOL_MODE_INSTALL} ${INSTALL} dns64.@SO@ `pwd`/lib + +dns64.@SO@: dns64.@O@ + ${LIBTOOL_MODE_LINK} @SO_LD@ ${SO_LDFLAGS} -o $@ \ + dns64.@O@ ${LIBS} + lib/filter-aaaa.@SO@: filter-aaaa.@SO@ $(SHELL) ${top_srcdir}/mkinstalldirs `pwd`/lib ${LIBTOOL_MODE_INSTALL} ${INSTALL} filter-aaaa.@SO@ `pwd`/lib @@ -56,7 +64,7 @@ docclean manclean maintainer-clean:: rm -f ${MANOBJS} clean distclean:: - rm -f filter-aaaa.so + rm -f dns64.@SO@ filter-aaaa.@SO@ rm -f ${TARGETS} ${OBJS} installdirs: @@ -73,7 +81,10 @@ install:: @SO_TARGETS@ installdirs fi \ done ${INSTALL_DATA} ${srcdir}/filter-aaaa.8 ${DESTDIR}${mandir}/man8 + ${INSTALL_DATA} ${srcdir}/dns64.8 ${DESTDIR}${mandir}/man8 uninstall:: + ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${plugindir}/dns64.@SO@ ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${plugindir}/filter-aaaa.@SO@ + rm -f ${DESTDIR}${mandir}/man8/dns64.8 rm -f ${DESTDIR}${mandir}/man8/filter-aaaa.8 diff --git a/bin/plugins/dns64.8 b/bin/plugins/dns64.8 new file mode 100644 index 0000000000..3b54513f92 --- /dev/null +++ b/bin/plugins/dns64.8 @@ -0,0 +1,144 @@ +.\" 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: dns64.so +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.79.1 +.\" Date: 2018-11-30 +.\" Manual: BIND9 +.\" Source: ISC +.\" Language: English +.\" +.TH "DNS64\&.SO" "8" "2018\-11\-30" "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" +dns64.so \- perform DNS64 synthesis +.SH "SYNOPSIS" +.HP 24 +\fBplugin query "dns64\&.so"\fR [\fI{\ parameters\ }\fR]; +.SH "DESCRIPTION" +.PP +\fBdns64\&.so\fR +is a query plugin module for +\fBnamed\fR, enabling +\fBnamed\fR +to perform DNS64 address synthesis\&. +.PP +Until BIND 9\&.12, this feature was implemented natively in +\fBnamed\fR +and enabled with the +\fBdns64\fR +option\&. This option is now deprecated in +named\&.conf, but can be passed as parameters to the +\fBdns64\&.so\fR +plugin, for example: +.sp +.if n \{\ +.RS 4 +.\} +.nf + acl rfc1918 { 10/8; 192\&.168/16; 172\&.16/12; }; + plugin query "/usr/local/lib/dns64\&.so" { + dns64 64:FF9B::/96 { + clients { any; }; + mapped { !rfc1918; any; }; + exclude { 64:FF9B::/96; ::ffff:0000:0000/96; }; + suffix ::; + }; + dns64\-server "dns64\&.example\&.net\&."; + dns64\-contact "hostmaster\&.example\&.net\&."; + }; +.fi +.if n \{\ +.RE +.\} +.PP +This plugin enables +\fBnamed\fR +to return mapped IPv4 addresses to AAAA queries when there are no AAAA records\&. It is intended to be used in conjunction with NAT64\&. +.PP +Each +\fBdns64\fR +option defined in the plugin parameters defines one DNS64 prefix\&. Multiple DNS64 prefixes can be defined\&. +.PP +Compatible IPv6 prefixes have lengths of 32, 40, 48, 56, 64 and 96 as per RFC 6052\&. +.PP +Additionally a reverse IP6\&.ARPA zone will be created for the prefix to provide a mapping from the IP6\&.ARPA names to the corresponding IN\-ADDR\&.ARPA names using synthesized CNAMEs\&. +\fBdns64\-server\fR +and +\fBdns64\-contact\fR +can be used to specify the name of the server and contact for the zones\&. These are not settable on a per\-prefix basis\&. +.PP +Each +\fBdns64\fR +supports an optional +\fBclients\fR +ACL that determines which clients are affected by this directive\&. If not defined, it defaults to +\fBany;\fR\&. +.PP +Each +\fBdns64\fR +supports an optional +\fBmapped\fR +ACL that selects which IPv4 addresses are to be mapped in the corresponding A RRset\&. If not defined it defaults to +\fBany;\fR\&. +.PP +Normally, DNS64 won\*(Aqt apply to a domain name that owns one or more AAAA records; these records will simply be returned\&. The optional +\fBexclude\fR +ACL allows specification of a list of IPv6 addresses that will be ignored if they appear in a domain name\*(Aqs AAAA records, and DNS64 will be applied to any A records the domain name owns\&. If not defined, +\fBexclude\fR +defaults to ::ffff:0\&.0\&.0\&.0/96\&. +.PP +A optional +\fBsuffix\fR +can also be defined to set the bits trailing the mapped IPv4 address bits\&. By default these bits are set to +\fB::\fR\&. The bits matching the prefix and mapped IPv4 address must be zero\&. +.PP +If +\fBrecursive\-only\fR +is set to +\fByes\fR +the DNS64 synthesis will only happen for recursive queries\&. The default is +\fBno\fR\&. +.PP +If +\fBbreak\-dnssec\fR +is set to +\fByes\fR +the DNS64 synthesis will happen even if the result, if validated, would cause a DNSSEC validation failure\&. If this option is set to +\fBno\fR +(the default), the DO is set on the incoming query, and there are RRSIGs on the applicable records, then synthesis will not happen\&. +.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/plugins/dns64.c b/bin/plugins/dns64.c new file mode 100644 index 0000000000..b669c3769d --- /dev/null +++ b/bin/plugins/dns64.c @@ -0,0 +1,952 @@ +/* + * 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 + +#define CHECK(op) \ + do { \ + result = (op); \ + if (result != ISC_R_SUCCESS) { \ + goto cleanup; \ + } \ + } while (0) + +#define QUERY_ERROR(qctx, r) \ +do { \ + qctx->result = r; \ + qctx->want_restart = false; \ + qctx->line = __LINE__; \ +} while (0) + +#define SAVE(a, b) do { INSIST(a == NULL); a = b; b = NULL; } while (0) +#define RESTORE(a, b) SAVE(a, b) + +/* + * Client attribute tests. + */ +/*% Recursion OK? */ +#define RECURSIONOK(c) (((c)->query.attributes & \ + NS_QUERYATTR_RECURSIONOK) != 0) +/*% Want DNSSEC? */ +#define WANTDNSSEC(c) (((c)->attributes & \ + NS_CLIENTATTR_WANTDNSSEC) != 0) + +#define DNS64(c) (((c)->query.attributes & \ + NS_QUERYATTR_DNS64) != 0) + +#define DNS64EXCLUDE(c) (((c)->query.attributes & \ + NS_QUERYATTR_DNS64EXCLUDE) != 0) + +static uint32_t +dns64_ttl(dns_db_t *db, dns_dbversion_t *version); + +static bool +dns64_aaaaok(ns_client_t *client, dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset); + +static isc_result_t +dns64_synth(query_ctx_t *qctx); + +static void +dns64_filter(query_ctx_t *qctx); + +/* + * Hook registration structures: pointers to these structures will + * be added to a hook table when this module is registered. + */ +static ns_hookresult_t +dns64_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp); +static ns_hook_t dns64_init = { + .action = dns64_qctx_initialize, +}; + +static ns_hookresult_t +dns64_respond_begin(void *arg, void *cbdata, isc_result_t *resp); +static ns_hook_t dns64_respbegin = { + .action = dns64_respond_begin, +}; + +static ns_hookresult_t +dns64_addanswer(void *arg, void *cbdata, isc_result_t *resp); +static ns_hook_t dns64_addanswerbegin = { + .action = dns64_addanswer, +}; + +static ns_hookresult_t +dns64_resume_restored(void *arg, void *cbdata, isc_result_t *resp); +static ns_hook_t dns64_resumerest = { + .action = dns64_resume_restored, +}; + +static ns_hookresult_t +dns64_notfound_recurse(void *arg, void *cbdata, isc_result_t *resp); +static ns_hook_t dns64_nfrec = { + .action = dns64_notfound_recurse, +}; + +static ns_hookresult_t +dns64_delegation_recurse(void *arg, void *cbdata, isc_result_t *resp); +static ns_hook_t dns64_delrec = { + .action = dns64_delegation_recurse, +}; + +static ns_hookresult_t +dns64_nodata_begin(void *arg, void *cbdata, isc_result_t *resp); +static ns_hook_t dns64_nodata = { + .action = dns64_nodata_begin, +}; + +static ns_hookresult_t +dns64_zerottl_recurse(void *arg, void *cbdata, isc_result_t *resp); +static ns_hook_t dns64_zerottl = { + .action = dns64_zerottl_recurse, +}; + +static ns_hookresult_t +dns64_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp); +static ns_hook_t dns64_destroy = { + .action = dns64_qctx_destroy, +}; + +/** + ** Support for parsing of parameters and configuration of the module. + **/ + +/** + ** Mandatory plugin API functions: + ** + ** - plugin_check + ** - plugin_destroy + ** - plugin_register + ** - plugin_version + **/ + +/* + * Called by ns_plugin_register() to register hook actions into + * a hook table. + */ +isc_result_t +plugin_register(const char *parameters, + const void *cfg, const char *cfg_file, unsigned long cfg_line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx, + ns_hooktable_t *hooktable, void **instp) +{ + + UNUSED(cfg); + UNUSED(actx); + UNUSED(instp); + + isc_log_write(lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_INFO, + "loading 'dns64' " + "module from %s:%lu, %s parameters", + cfg_file, cfg_line, parameters != NULL ? "with" : "no"); + + ns_hook_add(hooktable, mctx, + NS_QUERY_QCTX_INITIALIZED, &dns64_init); + ns_hook_add(hooktable, mctx, + NS_QUERY_RESPOND_BEGIN, &dns64_respbegin); + ns_hook_add(hooktable, mctx, + NS_QUERY_ADDANSWER_BEGIN, &dns64_addanswerbegin); + ns_hook_add(hooktable, mctx, + NS_QUERY_RESUME_RESTORED, &dns64_resumerest); + ns_hook_add(hooktable, mctx, + NS_QUERY_NOTFOUND_RECURSE, &dns64_nfrec); + ns_hook_add(hooktable, mctx, + NS_QUERY_DELEGATION_RECURSE_BEGIN, &dns64_delrec); + ns_hook_add(hooktable, mctx, + NS_QUERY_NODATA_BEGIN, &dns64_nodata); + ns_hook_add(hooktable, mctx, + NS_QUERY_ZEROTTL_RECURSE, &dns64_zerottl); + ns_hook_add(hooktable, mctx, + NS_QUERY_QCTX_DESTROYED, &dns64_destroy); + + return (ISC_R_SUCCESS); +} + +isc_result_t +plugin_check(const char *parameters, + const void *cfg, const char *cfg_file, unsigned long cfg_line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx) +{ + UNUSED(parameters); + UNUSED(cfg_file); + UNUSED(cfg_line); + UNUSED(cfg); + UNUSED(mctx); + UNUSED(lctx); + UNUSED(actx); + + return (ISC_R_SUCCESS); +} + +/* + * Called by ns_plugins_free(); frees memory allocated by + * the module when it was registered. + */ +void +plugin_destroy(void **instp) { + UNUSED(instp); + + return; + +} + +/* + * Returns plugin API version for compatibility checks. + */ +int +plugin_version(void) { + return (NS_PLUGIN_VERSION); +} + +/** + ** DNS64 feature implementation begins here. + **/ +static uint32_t +dns64_ttl(dns_db_t *db, dns_dbversion_t *version) { + dns_dbnode_t *node = NULL; + dns_rdata_soa_t soa; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_t rdataset; + isc_result_t result; + uint32_t ttl = UINT32_MAX; + + dns_rdataset_init(&rdataset); + + result = dns_db_getoriginnode(db, &node); + if (result != ISC_R_SUCCESS) + goto cleanup; + + result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa, + 0, 0, &rdataset, NULL); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_rdataset_first(&rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + + dns_rdataset_current(&rdataset, &rdata); + result = dns_rdata_tostruct(&rdata, &soa, NULL); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + ttl = ISC_MIN(rdataset.ttl, soa.minimum); + +cleanup: + if (dns_rdataset_isassociated(&rdataset)) + dns_rdataset_disassociate(&rdataset); + if (node != NULL) + dns_db_detachnode(db, &node); + return (ttl); +} + +static bool +dns64_aaaaok(ns_client_t *client, dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset) +{ + isc_netaddr_t netaddr; + dns_aclenv_t *env = ns_interfacemgr_getaclenv(client->interface->mgr); + dns_dns64_t *dns64 = ISC_LIST_HEAD(client->view->dns64); + unsigned int flags = 0; + unsigned int i, count; + bool *aaaaok; + + INSIST(client->dns64_aaaaok == NULL); + INSIST(client->dns64_aaaaoklen == 0); + INSIST(client->dns64_aaaa == NULL); + INSIST(client->dns64_sigaaaa == NULL); + + if (dns64 == NULL) + return (true); + + if (RECURSIONOK(client)) + flags |= DNS_DNS64_RECURSIVE; + + if (WANTDNSSEC(client) && sigrdataset != NULL && + dns_rdataset_isassociated(sigrdataset)) + flags |= DNS_DNS64_DNSSEC; + + count = dns_rdataset_count(rdataset); + aaaaok = isc_mem_get(client->mctx, sizeof(bool) * count); + + isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); + if (dns_dns64_aaaaok(dns64, &netaddr, client->signer, + env, flags, rdataset, aaaaok, count)) + { + for (i = 0; i < count; i++) { + if (aaaaok != NULL && !aaaaok[i]) { + SAVE(client->dns64_aaaaok, aaaaok); + client->dns64_aaaaoklen = count; + break; + } + } + if (aaaaok != NULL) + isc_mem_put(client->mctx, aaaaok, + sizeof(bool) * count); + return (true); + } + if (aaaaok != NULL) + isc_mem_put(client->mctx, aaaaok, + sizeof(bool) * count); + return (NS_HOOK_CONTINUE); +} + +static isc_result_t +dns64_synth(query_ctx_t *qctx) { + ns_client_t *client = qctx->client; + dns_aclenv_t *env = ns_interfacemgr_getaclenv(client->interface->mgr); + dns_name_t *name, *mname; + dns_rdata_t *dns64_rdata; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdatalist_t *dns64_rdatalist; + dns_rdataset_t *dns64_rdataset; + dns_rdataset_t *mrdataset; + isc_buffer_t *buffer; + isc_region_t r; + isc_result_t result; + dns_view_t *view = client->view; + isc_netaddr_t netaddr; + dns_dns64_t *dns64; + unsigned int flags = 0; + const dns_section_t section = DNS_SECTION_ANSWER; + + /*% + * To the current response for 'qctx->client', add the answer RRset + * '*rdatasetp' and an optional signature set '*sigrdatasetp', with + * owner name '*namep', to the answer section, unless they are + * already there. Also add any pertinent additional data. + * + * If 'qctx->dbuf' is not NULL, then 'qctx->fname' is the name + * whose data is stored 'qctx->dbuf'. In this case, + * query_addrrset() guarantees that when it returns the name + * will either have been kept or released. + */ + qctx->qtype = qctx->type = dns_rdatatype_aaaa; + + name = qctx->fname; + mname = NULL; + mrdataset = NULL; + buffer = NULL; + dns64_rdata = NULL; + dns64_rdataset = NULL; + dns64_rdatalist = NULL; + result = dns_message_findname(client->message, section, + name, dns_rdatatype_aaaa, + qctx->rdataset->covers, + &mname, &mrdataset); + if (result == ISC_R_SUCCESS) { + /* + * We've already got an RRset of the given name and type. + * There's nothing else to do; + */ + 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) { + 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) { + ns_client_releasename(client, &qctx->fname); + } + } + + if (qctx->rdataset->trust != dns_trust_secure) { + client->query.attributes &= ~NS_QUERYATTR_SECURE; + } + + isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); + + result = isc_buffer_allocate(client->mctx, &buffer, + view->dns64cnt * 16 * + dns_rdataset_count(qctx->rdataset)); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_message_gettemprdataset(client->message, + &dns64_rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_message_gettemprdatalist(client->message, + &dns64_rdatalist); + if (result != ISC_R_SUCCESS) + goto cleanup; + + dns_rdatalist_init(dns64_rdatalist); + dns64_rdatalist->rdclass = dns_rdataclass_in; + dns64_rdatalist->type = dns_rdatatype_aaaa; + if (client->dns64_ttl != UINT32_MAX) + dns64_rdatalist->ttl = ISC_MIN(qctx->rdataset->ttl, + client->dns64_ttl); + else + dns64_rdatalist->ttl = ISC_MIN(qctx->rdataset->ttl, 600); + + if (RECURSIONOK(client)) + flags |= DNS_DNS64_RECURSIVE; + + /* + * We use the signatures from the A lookup to set DNS_DNS64_DNSSEC + * as this provides a easy way to see if the answer was signed. + */ + if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL && + dns_rdataset_isassociated(qctx->sigrdataset)) + flags |= DNS_DNS64_DNSSEC; + + for (result = dns_rdataset_first(qctx->rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(qctx->rdataset)) { + for (dns64 = ISC_LIST_HEAD(client->view->dns64); + dns64 != NULL; dns64 = dns_dns64_next(dns64)) { + + dns_rdataset_current(qctx->rdataset, &rdata); + isc_buffer_availableregion(buffer, &r); + INSIST(r.length >= 16); + result = dns_dns64_aaaafroma(dns64, &netaddr, + client->signer, env, flags, + rdata.data, r.base); + if (result != ISC_R_SUCCESS) { + dns_rdata_reset(&rdata); + continue; + } + isc_buffer_add(buffer, 16); + isc_buffer_remainingregion(buffer, &r); + isc_buffer_forward(buffer, 16); + result = dns_message_gettemprdata(client->message, + &dns64_rdata); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_rdata_init(dns64_rdata); + dns_rdata_fromregion(dns64_rdata, dns_rdataclass_in, + dns_rdatatype_aaaa, &r); + ISC_LIST_APPEND(dns64_rdatalist->rdata, dns64_rdata, + link); + dns64_rdata = NULL; + dns_rdata_reset(&rdata); + } + } + if (result != ISC_R_NOMORE) + goto cleanup; + + if (ISC_LIST_EMPTY(dns64_rdatalist->rdata)) + goto cleanup; + + result = dns_rdatalist_tordataset(dns64_rdatalist, dns64_rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_rdataset_setownercase(dns64_rdataset, mname); + client->query.attributes |= NS_QUERYATTR_NOADDITIONAL; + dns64_rdataset->trust = qctx->rdataset->trust; + + /* Add rdataset to mname */ + ISC_LIST_APPEND(mname->list, dns64_rdataset, link); + + ns_query_setorder(client, mname, dns64_rdataset); + + dns64_rdataset = NULL; + dns64_rdatalist = NULL; + dns_message_takebuffer(client->message, &buffer); + + /* + * XXX: this functionality will need to be restored + * inc_stats(client, ns_statscounter_dns64); + */ + result = ISC_R_SUCCESS; + + cleanup: + if (buffer != NULL) + isc_buffer_free(&buffer); + + if (dns64_rdata != NULL) + dns_message_puttemprdata(client->message, &dns64_rdata); + + if (dns64_rdataset != NULL) + dns_message_puttemprdataset(client->message, &dns64_rdataset); + + if (dns64_rdatalist != NULL) { + for (dns64_rdata = ISC_LIST_HEAD(dns64_rdatalist->rdata); + dns64_rdata != NULL; + dns64_rdata = ISC_LIST_HEAD(dns64_rdatalist->rdata)) + { + ISC_LIST_UNLINK(dns64_rdatalist->rdata, + dns64_rdata, link); + dns_message_puttemprdata(client->message, &dns64_rdata); + } + dns_message_puttemprdatalist(client->message, &dns64_rdatalist); + } + + return (result); +} + +static void +dns64_filter(query_ctx_t *qctx) { + ns_client_t *client = qctx->client; + dns_name_t *name, *mname; + dns_rdata_t *myrdata; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdatalist_t *myrdatalist; + dns_rdataset_t *myrdataset; + isc_buffer_t *buffer; + isc_region_t r; + isc_result_t result; + unsigned int i; + const dns_section_t section = DNS_SECTION_ANSWER; + + INSIST(client->dns64_aaaaok != NULL); + INSIST(client->dns64_aaaaoklen == + dns_rdataset_count(qctx->rdataset)); + + name = qctx->fname; + mname = NULL; + buffer = NULL; + myrdata = NULL; + myrdataset = NULL; + myrdatalist = NULL; + result = dns_message_findname(client->message, section, + name, dns_rdatatype_aaaa, + qctx->rdataset->covers, + &mname, &myrdataset); + if (result == ISC_R_SUCCESS) { + /* + * We've already got an RRset of the given name and type. + * There's nothing else to do; + */ + 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) { + ns_client_releasename(client, &qctx->fname); + } + qctx->dbuf = NULL; + } + + if (qctx->rdataset->trust != dns_trust_secure) { + client->query.attributes &= ~NS_QUERYATTR_SECURE; + } + + result = isc_buffer_allocate(client->mctx, &buffer, + 16 * dns_rdataset_count(qctx->rdataset)); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_message_gettemprdataset(client->message, &myrdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_message_gettemprdatalist(client->message, &myrdatalist); + if (result != ISC_R_SUCCESS) + goto cleanup; + + dns_rdatalist_init(myrdatalist); + myrdatalist->rdclass = dns_rdataclass_in; + myrdatalist->type = dns_rdatatype_aaaa; + myrdatalist->ttl = qctx->rdataset->ttl; + + i = 0; + for (result = dns_rdataset_first(qctx->rdataset); + result == ISC_R_SUCCESS; + result = dns_rdataset_next(qctx->rdataset)) + { + if (!client->dns64_aaaaok[i++]) + continue; + dns_rdataset_current(qctx->rdataset, &rdata); + INSIST(rdata.length == 16); + isc_buffer_putmem(buffer, rdata.data, rdata.length); + isc_buffer_remainingregion(buffer, &r); + isc_buffer_forward(buffer, rdata.length); + result = dns_message_gettemprdata(client->message, &myrdata); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_rdata_init(myrdata); + dns_rdata_fromregion(myrdata, dns_rdataclass_in, + dns_rdatatype_aaaa, &r); + ISC_LIST_APPEND(myrdatalist->rdata, myrdata, link); + myrdata = NULL; + dns_rdata_reset(&rdata); + } + if (result != ISC_R_NOMORE) + goto cleanup; + + result = dns_rdatalist_tordataset(myrdatalist, myrdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_rdataset_setownercase(myrdataset, name); + client->query.attributes |= NS_QUERYATTR_NOADDITIONAL; + if (mname == name) { + 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; + + /* Add rdataset to mname */ + ISC_LIST_APPEND(mname->list, myrdataset, link); + + ns_query_setorder(client, mname, myrdataset); + + myrdataset = NULL; + myrdatalist = NULL; + dns_message_takebuffer(client->message, &buffer); + + cleanup: + if (buffer != NULL) + isc_buffer_free(&buffer); + + if (myrdata != NULL) + dns_message_puttemprdata(client->message, &myrdata); + + if (myrdataset != NULL) + dns_message_puttemprdataset(client->message, &myrdataset); + + if (myrdatalist != NULL) { + for (myrdata = ISC_LIST_HEAD(myrdatalist->rdata); + myrdata != NULL; + myrdata = ISC_LIST_HEAD(myrdatalist->rdata)) + { + ISC_LIST_UNLINK(myrdatalist->rdata, myrdata, link); + dns_message_puttemprdata(client->message, &myrdata); + } + dns_message_puttemprdatalist(client->message, &myrdatalist); + } + if (qctx->dbuf != NULL) { + ns_client_releasename(client, &name); + } +} + +static ns_hookresult_t +dns64_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp) { + UNUSED(arg); + UNUSED(cbdata); + + *resp = ISC_R_UNSET; + return (NS_HOOK_CONTINUE); +} + +static ns_hookresult_t +dns64_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + + UNUSED(cbdata); + + /* + * Check to see if the AAAA RRset has non-excluded addresses + * in it. If not look for a A RRset. + */ + INSIST(qctx->client->dns64_aaaaok == NULL); + + if (qctx->qtype == dns_rdatatype_aaaa && !qctx->dns64_exclude && + !ISC_LIST_EMPTY(qctx->view->dns64) && + qctx->client->message->rdclass == dns_rdataclass_in && + !dns64_aaaaok(qctx->client, qctx->rdataset, qctx->sigrdataset)) + { + /* + * Look to see if there are A records for this name. + */ + qctx->client->dns64_ttl = qctx->rdataset->ttl; + SAVE(qctx->client->dns64_aaaa, qctx->rdataset); + SAVE(qctx->client->dns64_sigaaaa, qctx->sigrdataset); + 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; + + /* + * XXX: we are depending here on DNS64 + * being reached before any other modules that + * might set up recursion. In particular if + * the filter-aaaa module runs first, there'll + * be an assertion failure. We need to make this + * order-indeendent. + */ + *resp = ns_query_lookup(qctx); + return (NS_HOOK_RETURN); + } + + *resp = ISC_R_UNSET; + return (NS_HOOK_CONTINUE); +} + +static ns_hookresult_t +dns64_addanswer(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + + UNUSED(cbdata); + + if (qctx->dns64) { + isc_result_t result = dns64_synth(qctx); + qctx->noqname = NULL; + dns_rdataset_disassociate(qctx->rdataset); + dns_message_puttemprdataset(qctx->client->message, + &qctx->rdataset); + if (result == ISC_R_NOMORE) { + if (qctx->dns64_exclude) { + if (!qctx->is_zone) { + *resp = ns_query_done(qctx); + return (NS_HOOK_RETURN); + } + /* + * Add a fake SOA record. + */ + (void) ns_query_addsoa(qctx, 600, + DNS_SECTION_AUTHORITY); + *resp = ns_query_done(qctx); + return (NS_HOOK_RETURN); + } + if (qctx->is_zone) { + qctx->nxresult = DNS_R_NXDOMAIN; + *resp = ns_query_nodata(qctx); + } else { + qctx->nxresult = DNS_R_NXDOMAIN; + *resp = ns_query_ncache(qctx); + } + } else if (result != ISC_R_SUCCESS) { + qctx->result = result; + *resp = ns_query_done(qctx); + } else { + *resp = ISC_R_COMPLETE; + } + return (NS_HOOK_RETURN); + } else if (qctx->client->dns64_aaaaok != NULL) { + dns64_filter(qctx); + ns_client_putrdataset(qctx->client, &qctx->rdataset); + *resp = ISC_R_COMPLETE; + return (NS_HOOK_RETURN); + } + + *resp = ISC_R_UNSET; + return (NS_HOOK_CONTINUE); +} + +static ns_hookresult_t +dns64_resume_restored(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + + UNUSED(cbdata); + + if (DNS64(qctx->client)) { + qctx->client->query.attributes &= ~NS_QUERYATTR_DNS64; + qctx->dns64 = true; + } + + if (DNS64EXCLUDE(qctx->client)) { + qctx->client->query.attributes &= ~NS_QUERYATTR_DNS64EXCLUDE; + qctx->dns64_exclude = true; + } + + *resp = ISC_R_UNSET; + return (NS_HOOK_CONTINUE); +} + +static ns_hookresult_t +dns64_notfound_recurse(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + + UNUSED(cbdata); + + if (qctx->dns64) { + qctx->client->query.attributes |= NS_QUERYATTR_DNS64; + } + if (qctx->dns64_exclude) { + qctx->client->query.attributes |= NS_QUERYATTR_DNS64EXCLUDE; + } + + *resp = ISC_R_UNSET; + return (NS_HOOK_CONTINUE); +} + +static ns_hookresult_t +dns64_delegation_recurse(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + + UNUSED(cbdata); + + /* + * Look up an A record so we can synthesize DNS64. + */ + if (qctx->dns64) { + qctx->result = ns_query_recurse(qctx->client, + dns_rdatatype_a, + qctx->client->query.qname, + NULL, NULL, + qctx->resuming); + qctx->client->query.attributes |= NS_QUERYATTR_RECURSING; + if (qctx->result == ISC_R_SUCCESS) { + qctx->client->query.attributes |= NS_QUERYATTR_DNS64; + if (qctx->dns64_exclude) { + qctx->client->query.attributes |= + NS_QUERYATTR_DNS64EXCLUDE; + } + } + *resp = ISC_R_COMPLETE; + return (NS_HOOK_RETURN); + } + + *resp = ISC_R_UNSET; + return (NS_HOOK_CONTINUE); +} + +static ns_hookresult_t +dns64_nodata_begin(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + + UNUSED(cbdata); + + if (qctx->dns64 && !qctx->dns64_exclude) { + isc_buffer_t b; + + /* + * Restore the answers from the previous AAAA lookup. + */ + if (qctx->rdataset != NULL) { + ns_client_putrdataset(qctx->client, &qctx->rdataset); + } + if (qctx->sigrdataset != NULL) { + ns_client_putrdataset(qctx->client, &qctx->sigrdataset); + } + RESTORE(qctx->rdataset, qctx->client->dns64_aaaa); + RESTORE(qctx->sigrdataset, qctx->client->dns64_sigaaaa); + if (qctx->fname == NULL) { + qctx->dbuf = ns_client_getnamebuf(qctx->client); + if (qctx->dbuf == NULL) { + QUERY_ERROR(qctx, DNS_R_SERVFAIL); + *resp = ns_query_done(qctx); + return (NS_HOOK_RETURN); + } + qctx->fname = ns_client_newname(qctx->client, + qctx->dbuf, &b); + if (qctx->fname == NULL) { + QUERY_ERROR(qctx, DNS_R_SERVFAIL); + *resp = ns_query_done(qctx); + return (NS_HOOK_RETURN); + } + } + dns_name_copy(qctx->client->query.qname, qctx->fname, NULL); + qctx->dns64 = false; + } else if ((qctx->nxresult == DNS_R_NXRRSET || + qctx->nxresult == DNS_R_NCACHENXRRSET) && + !ISC_LIST_EMPTY(qctx->view->dns64) && + !qctx->nxrewrite && + qctx->client->message->rdclass == dns_rdataclass_in && + qctx->qtype == dns_rdatatype_aaaa) + { + /* + * Look to see if there are A records for this name. + */ + switch (qctx->nxresult) { + case DNS_R_NCACHENXRRSET: + /* + * This is from the negative cache; if the ttl is + * zero, we need to work out whether we have just + * decremented to zero or there was no negative + * cache ttl in the answer. + */ + if (qctx->rdataset->ttl != 0) { + qctx->client->dns64_ttl = qctx->rdataset->ttl; + break; + } + if (dns_rdataset_first(qctx->rdataset) == ISC_R_SUCCESS) + qctx->client->dns64_ttl = 0; + break; + case DNS_R_NXRRSET: + qctx->client->dns64_ttl = + dns64_ttl(qctx->db, qctx->version); + break; + default: + INSIST(0); + ISC_UNREACHABLE(); + } + + SAVE(qctx->client->dns64_aaaa, qctx->rdataset); + SAVE(qctx->client->dns64_sigaaaa, qctx->sigrdataset); + ns_client_releasename(qctx->client, &qctx->fname); + dns_db_detachnode(qctx->db, &qctx->node); + qctx->type = qctx->qtype = dns_rdatatype_a; + qctx->dns64 = true; + *resp = ns_query_lookup(qctx); + return (NS_HOOK_RETURN); + } + + *resp = ISC_R_UNSET; + return (NS_HOOK_CONTINUE); +} + +static ns_hookresult_t +dns64_zerottl_recurse(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + + UNUSED(cbdata); + + if (qctx->dns64) { + qctx->client->query.attributes |= NS_QUERYATTR_DNS64; + } + if (qctx->dns64_exclude) { + qctx->client->query.attributes |= NS_QUERYATTR_DNS64EXCLUDE; + } + + *resp = ISC_R_UNSET; + return (NS_HOOK_CONTINUE); +} + +static ns_hookresult_t +dns64_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp) { + UNUSED(arg); + UNUSED(cbdata); + + *resp = ISC_R_UNSET; + return (NS_HOOK_CONTINUE); +} diff --git a/bin/plugins/dns64.docbook b/bin/plugins/dns64.docbook new file mode 100644 index 0000000000..af274231a9 --- /dev/null +++ b/bin/plugins/dns64.docbook @@ -0,0 +1,154 @@ + + + + + + 2018-11-30 + + + ISC + Internet Systems Consortium, Inc. + + + dns64.so + 8 + BIND9 + + + + dns64.so + perform DNS64 synthesis + + + + + 2018 + Internet Systems Consortium, Inc. ("ISC") + + + + + + plugin query "dns64.so" + { parameters }; + + + + DESCRIPTION + + dns64.so is a query plugin module for + named, enabling named + to perform DNS64 address synthesis. + + + Until BIND 9.12, this feature was implemented natively in + named and enabled with the + dns64 option. + This option is now deprecated in named.conf, + but can be passed as parameters to the + dns64.so plugin, for example: + + + acl rfc1918 { 10/8; 192.168/16; 172.16/12; }; + + plugin query "/usr/local/lib/dns64.so" { + dns64 64:FF9B::/96 { + clients { any; }; + mapped { !rfc1918; any; }; + exclude { 64:FF9B::/96; ::ffff:0000:0000/96; }; + suffix ::; + }; + + dns64-server "dns64.example.net."; + dns64-contact "hostmaster.example.net."; + }; + + + This plugin enables named to + return mapped IPv4 addresses to AAAA queries when + there are no AAAA records. It is intended to be + used in conjunction with NAT64. + + + Each dns64 option defined in the plugin + parameters defines one DNS64 prefix. Multiple DNS64 prefixes + can be defined. + + + Compatible IPv6 prefixes have lengths of 32, 40, 48, 56, + 64 and 96 as per RFC 6052. + + + Additionally a reverse IP6.ARPA zone will be created for + the prefix to provide a mapping from the IP6.ARPA names + to the corresponding IN-ADDR.ARPA names using synthesized + CNAMEs. dns64-server and + dns64-contact can be used to specify + the name of the server and contact for the zones. + These are not settable on a per-prefix basis. + + + Each dns64 supports an optional + clients ACL that determines which + clients are affected by this directive. If not defined, + it defaults to any;. + + + Each dns64 supports an optional + mapped ACL that selects which + IPv4 addresses are to be mapped in the corresponding + A RRset. If not defined it defaults to + any;. + + + Normally, DNS64 won't apply to a domain name that + owns one or more AAAA records; these records will + simply be returned. The optional + exclude ACL allows specification + of a list of IPv6 addresses that will be ignored + if they appear in a domain name's AAAA records, and + DNS64 will be applied to any A records the domain + name owns. If not defined, exclude + defaults to ::ffff:0.0.0.0/96. + + + A optional suffix can also + be defined to set the bits trailing the mapped + IPv4 address bits. By default these bits are + set to ::. The bits + matching the prefix and mapped IPv4 address + must be zero. + + + If recursive-only is set to + yes the DNS64 synthesis will + only happen for recursive queries. The default + is no. + + + If break-dnssec is set to + yes the DNS64 synthesis will + happen even if the result, if validated, would + cause a DNSSEC validation failure. If this option + is set to no (the default), the DO + is set on the incoming query, and there are RRSIGs on + the applicable records, then synthesis will not happen. + + + + SEE ALSO + + BIND 9 Administrator Reference Manual. + + + + diff --git a/bin/plugins/dns64.html b/bin/plugins/dns64.html new file mode 100644 index 0000000000..d2ceee67fa --- /dev/null +++ b/bin/plugins/dns64.html @@ -0,0 +1,135 @@ + + + + + +dns64.so + + +
+
+
+

Name

+

dns64.so — perform DNS64 synthesis

+
+
+

Synopsis

+

plugin query "dns64.so" [{ parameters }]; +

+
+
+

DESCRIPTION

+

+ dns64.so is a query plugin module for + named, enabling named + to perform DNS64 address synthesis. +

+

+ Until BIND 9.12, this feature was implemented natively in + named and enabled with the + dns64 option. + This option is now deprecated in named.conf, + but can be passed as parameters to the + dns64.so plugin, for example: +

+
+	acl rfc1918 { 10/8; 192.168/16; 172.16/12; };
+
+	plugin query "/usr/local/lib/dns64.so" {
+		dns64 64:FF9B::/96 {
+			clients { any; };
+			mapped { !rfc1918; any; };
+			exclude { 64:FF9B::/96; ::ffff:0000:0000/96; };
+			suffix ::;
+		};
+
+		dns64-server "dns64.example.net.";
+		dns64-contact "hostmaster.example.net.";
+	};
+
+

+ This plugin enables named to + return mapped IPv4 addresses to AAAA queries when + there are no AAAA records. It is intended to be + used in conjunction with NAT64. +

+

+ Each dns64 option defined in the plugin + parameters defines one DNS64 prefix. Multiple DNS64 prefixes + can be defined. +

+

+ Compatible IPv6 prefixes have lengths of 32, 40, 48, 56, + 64 and 96 as per RFC 6052. +

+

+ Additionally a reverse IP6.ARPA zone will be created for + the prefix to provide a mapping from the IP6.ARPA names + to the corresponding IN-ADDR.ARPA names using synthesized + CNAMEs. dns64-server and + dns64-contact can be used to specify + the name of the server and contact for the zones. + These are not settable on a per-prefix basis. +

+

+ Each dns64 supports an optional + clients ACL that determines which + clients are affected by this directive. If not defined, + it defaults to any;. +

+

+ Each dns64 supports an optional + mapped ACL that selects which + IPv4 addresses are to be mapped in the corresponding + A RRset. If not defined it defaults to + any;. +

+

+ Normally, DNS64 won't apply to a domain name that + owns one or more AAAA records; these records will + simply be returned. The optional + exclude ACL allows specification + of a list of IPv6 addresses that will be ignored + if they appear in a domain name's AAAA records, and + DNS64 will be applied to any A records the domain + name owns. If not defined, exclude + defaults to ::ffff:0.0.0.0/96. +

+

+ A optional suffix can also + be defined to set the bits trailing the mapped + IPv4 address bits. By default these bits are + set to ::. The bits + matching the prefix and mapped IPv4 address + must be zero. +

+

+ If recursive-only is set to + yes the DNS64 synthesis will + only happen for recursive queries. The default + is no. +

+

+ If break-dnssec is set to + yes the DNS64 synthesis will + happen even if the result, if validated, would + cause a DNSSEC validation failure. If this option + is set to no (the default), the DO + is set on the incoming query, and there are RRSIGs on + the applicable records, then synthesis will not happen. +

+
+
+

SEE ALSO

+

+ BIND 9 Administrator Reference Manual. +

+
+
+ diff --git a/bin/tests/system/dns64/ns1/named.conf.in b/bin/tests/system/dns64/ns1/named.conf.in index 778c0bc9a5..664b50cf09 100644 --- a/bin/tests/system/dns64/ns1/named.conf.in +++ b/bin/tests/system/dns64/ns1/named.conf.in @@ -34,6 +34,8 @@ options { }; }; +plugin query "../../../../plugins/lib/dns64.so"; + zone "." { type master; file "root.db"; diff --git a/bin/tests/system/dns64/ns2/named.conf.in b/bin/tests/system/dns64/ns2/named.conf.in index 386a9d740b..4c45890106 100644 --- a/bin/tests/system/dns64/ns2/named.conf.in +++ b/bin/tests/system/dns64/ns2/named.conf.in @@ -58,6 +58,8 @@ options { response-policy { zone "rpz"; }; }; +plugin query "../../../../plugins/lib/dns64.so"; + zone "." { type hint; file "../../common/root.hint"; diff --git a/bin/tests/system/dns64/ns3/named.conf.in b/bin/tests/system/dns64/ns3/named.conf.in index 01abb12a84..6d29fc6b41 100644 --- a/bin/tests/system/dns64/ns3/named.conf.in +++ b/bin/tests/system/dns64/ns3/named.conf.in @@ -41,6 +41,8 @@ options { response-policy { zone "rpz"; }; }; +plugin query "../../../../plugins/lib/dns64.so"; + zone "." { type hint; file "../../common/root.hint"; diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 86d4ccd187..ceb84c0498 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -18106,6 +18106,7 @@ allow-query { !{ !10/8; any; }; key example; }; + diff --git a/doc/arm/man.dns64.html b/doc/arm/man.dns64.html new file mode 100644 index 0000000000..0ca519e7e4 --- /dev/null +++ b/doc/arm/man.dns64.html @@ -0,0 +1,173 @@ + + + + + +dns64.so + + + + + + + + +
+
+
+

Name

+

dns64.so — perform DNS64 synthesis

+
+
+

Synopsis

+

hook query "dns64.so" [{ parameters }]; +

+
+
+

DESCRIPTION

+

+ dns64.so is a query hook module for + named, enabling named + to perform DNS64 address synthesis. +

+

+ Until BIND 9.12, this feature was implemented natively in + named and enabled with the + dns64 option. + This option is now deprecated in named.conf, + but can be passed as parameters to the + dns64.so module, for example: +

+
+	acl rfc1918 { 10/8; 192.168/16; 172.16/12; };
+
+	plugin query "/usr/local/lib/dns64.so" {
+		dns64 64:FF9B::/96 {
+			clients { any; };
+			mapped { !rfc1918; any; };
+			exclude { 64:FF9B::/96; ::ffff:0000:0000/96; };
+			suffix ::;
+		};
+
+		dns64-server "dns64.example.net.";
+		dns64-contact "hostmaster.example.net.";
+	};
+
+

+ This plugin enables named to + return mapped IPv4 addresses to AAAA queries when + there are no AAAA records. It is intended to be + used in conjunction with NAT64. +

+

+ Each dns64 option defined in the plugin + parameters defines one DNS64 prefix. Multiple DNS64 prefixes + can be defined. +

+

+ Compatible IPv6 prefixes have lengths of 32, 40, 48, 56, + 64 and 96 as per RFC 6052. +

+

+ Additionally a reverse IP6.ARPA zone will be created for + the prefix to provide a mapping from the IP6.ARPA names + to the corresponding IN-ADDR.ARPA names using synthesized + CNAMEs. dns64-server and + dns64-contact can be used to specify + the name of the server and contact for the zones. + These are not settable on a per-prefix basis. +

+

+ Each dns64 supports an optional + clients ACL that determines which + clients are affected by this directive. If not defined, + it defaults to any;. +

+

+ Each dns64 supports an optional + mapped ACL that selects which + IPv4 addresses are to be mapped in the corresponding + A RRset. If not defined it defaults to + any;. +

+

+ Normally, DNS64 won't apply to a domain name that + owns one or more AAAA records; these records will + simply be returned. The optional + exclude ACL allows specification + of a list of IPv6 addresses that will be ignored + if they appear in a domain name's AAAA records, and + DNS64 will be applied to any A records the domain + name owns. If not defined, exclude + defaults to ::ffff:0.0.0.0/96. +

+

+ A optional suffix can also + be defined to set the bits trailing the mapped + IPv4 address bits. By default these bits are + set to ::. The bits + matching the prefix and mapped IPv4 address + must be zero. +

+

+ If recursive-only is set to + yes the DNS64 synthesis will + only happen for recursive queries. The default + is no. +

+

+ If break-dnssec is set to + yes the DNS64 synthesis will + happen even if the result, if validated, would + cause a DNSSEC validation failure. If this option + is set to no (the default), the DO + is set on the incoming query, and there are RRSIGs on + the applicable records, then synthesis will not happen. +

+
+
+

SEE ALSO

+

+ BIND 9 Administrator Reference Manual. +

+
+
+ +

BIND 9.13.4 (Development Release)

+ + diff --git a/doc/arm/plugins.xml b/doc/arm/plugins.xml index 507970b85d..2f840edf3b 100644 --- a/doc/arm/plugins.xml +++ b/doc/arm/plugins.xml @@ -26,15 +26,16 @@ in the future. - The only plugin currently included in BIND is - filter-aaaa.so, which replaces the - filter-aaaa feature that previously existed natively + The only plugins currently included in BIND are + filter-aaaa.so and dns64.so, + which replace the filter-aaaa and + dns64 features that previously existed natively as part of named. - The code for this feature has been removed from named, - and can no longer be configured using standard + The code for these features has been removed from named, + and they can no longer be configured using standard named.conf syntax, but linking in the - filter-aaaa.so plugin provides identical - functionality. + filter-aaaa.so or dns64.so + plugins provides identical functionality.
Configuring Plugins diff --git a/lib/ns/include/ns/query.h b/lib/ns/include/ns/query.h index 8a946f0fb3..6a5cd20d0a 100644 --- a/lib/ns/include/ns/query.h +++ b/lib/ns/include/ns/query.h @@ -239,6 +239,43 @@ ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, * recursion completes. */ +isc_result_t +ns_query_lookup(query_ctx_t *qctx); +/*%< + * Perform a local database lookup, in either an authoritative or + * cache database. If unable to answer, call ns_query_done(); otherwise + * hand off processing to query_gotanswer(). + */ + +isc_result_t +ns_query_addsoa(query_ctx_t *qctx, dns_ttl_t ttl, dns_section_t section); +/*%< + * Add SOA to the authority section when sending negative responses + * (or to the additional section if sending negative responses triggered + * by RPZ rewriting.) + */ + +isc_result_t +ns_query_nodata(query_ctx_t *qctx); +/*%< + * Handle authoritative NOERROR/NODATA responses. + */ + +isc_result_t +ns_query_ncache(query_ctx_t *qctx); +/*%< + * Handle negative cache responses, DNS_R_NCACHENXRRSET or + * DNS_R_NCACHENXDOMAIN. (Note: may be called with other + * result codes as a result of hook actions; for example, + * DNS64 may call with DNS_R_NXOMAIN.) + */ + +void +ns_query_setorder(ns_client_t *client, dns_name_t *name, + dns_rdataset_t *rdataset); +/*%< + * Set the ordering for 'rdataset'. + */ isc_result_t ns__query_sfcache(query_ctx_t *qctx); @@ -252,12 +289,4 @@ ns__query_start(query_ctx_t *qctx); * (Must not be used outside this module and its associated unit tests.) */ -/* - * XXX: - * Temporary function used to initialize the dns64 hooks, - * which are currently hard-coded rather than loaded as a module. - */ -void -ns__query_inithooks(dns_view_t *view); - #endif /* NS_QUERY_H */ diff --git a/lib/ns/query.c b/lib/ns/query.c index 0e9a3f5459..aef079735e 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -123,13 +123,6 @@ do { \ /*% Secure? */ #define SECURE(c) (((c)->query.attributes & \ NS_QUERYATTR_SECURE) != 0) -/*% DNS64 A lookup? */ -#define DNS64(c) (((c)->query.attributes & \ - NS_QUERYATTR_DNS64) != 0) - -#define DNS64EXCLUDE(c) (((c)->query.attributes & \ - NS_QUERYATTR_DNS64EXCLUDE) != 0) - #define REDIRECT(c) (((c)->query.attributes & \ NS_QUERYATTR_REDIRECT) != 0) @@ -311,10 +304,10 @@ get_hooktab(query_ctx_t *qctx) { * 2. Start the search (ns__query_start()) * * 3. Identify authoritative data sources which may have an answer; - * search them (query_lookup()). If an answer is found, go to 7. + * search them (ns_query_lookup()). If an answer is found, go to 7. * * 4. If recursion or cache access are allowed, search the cache - * (query_lookup() again, using the cache database) to find a better + * (ns_query_lookup() again, using the cache database) to find a better * answer. If an answer is found, go to 7. * * 5. If recursion is allowed, begin recursion (ns_query_recurse()). @@ -340,15 +333,15 @@ get_hooktab(query_ctx_t *qctx) { * otherwise go to 15 to clean up and return the delegation to the client. * * 10. No such domain (query_nxdomain()). Attempt redirection; if - * unsuccessful, add authority section records (query_addsoa(), + * unsuccessful, add authority section records (ns_query_addsoa(), * query_addauth()), then go to 15 to return NXDOMAIN to client. * - * 11. Empty answer (query_nodata()). Add authority section records - * (query_addsoa(), query_addauth()) and signatures if authoritative + * 11. Empty answer (ns_query_nodata()). Add authority section records + * (ns_query_addsoa(), query_addauth()) and signatures if authoritative * (query_sign_nodata()) then go to 15 and return * NOERROR/ANCOUNT=0 to client. * - * 12. No such domain or empty answer returned from cache (query_ncache()). + * 12. No such domain or empty answer returned from cache (ns_query_ncache()). * Set response code appropriately, go to 11. * * 13. Prepare a response (query_prepresponse()) and then fill it @@ -376,9 +369,6 @@ qctx_init(ns_client_t *client, dns_fetchevent_t *event, static isc_result_t query_setup(ns_client_t *client, dns_rdatatype_t qtype); -static isc_result_t -query_lookup(query_ctx_t *qctx); - static void fetch_callback(isc_task_t *task, isc_event_t *event); @@ -410,12 +400,6 @@ query_respond_any(query_ctx_t *qctx); static isc_result_t query_respond(query_ctx_t *qctx); -static isc_result_t -query_dns64(query_ctx_t *qctx); - -static void -query_filter64(query_ctx_t *qctx); - static isc_result_t query_notfound(query_ctx_t *qctx); @@ -431,9 +415,6 @@ query_delegation_recurse(query_ctx_t *qctx); static void query_addds(query_ctx_t *qctx); -static isc_result_t -query_nodata(query_ctx_t *qctx); - static isc_result_t query_sign_nodata(query_ctx_t *qctx); @@ -446,9 +427,6 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild); static isc_result_t query_redirect(query_ctx_t *qctx); -static isc_result_t -query_ncache(query_ctx_t *qctx); - static isc_result_t query_coveringnsec(query_ctx_t *qctx); @@ -467,10 +445,6 @@ query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl); static isc_result_t query_prepresponse(query_ctx_t *qctx); -static isc_result_t -query_addsoa(query_ctx_t *qctx, unsigned int override_ttl, - dns_section_t section); - static isc_result_t query_addns(query_ctx_t *qctx); @@ -483,113 +457,6 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata); static void query_addauth(query_ctx_t *qctx); -/* - * XXX: will be moved to a module later. - */ -static uint32_t -dns64_ttl(dns_db_t *db, dns_dbversion_t *version); - -static bool -dns64_aaaaok(ns_client_t *client, dns_rdataset_t *rdataset, - dns_rdataset_t *sigrdataset); - -static isc_result_t -query_dns64(query_ctx_t *qctx); - -static void -query_filter64(query_ctx_t *qctx); - -/* - * XXX: - * This is a temporary hooks table, pre-populated with pointers to - * the functions implementing dns64. Later, this will be - * set up at initialization time when the dns64 module is loaded. - * To activate this hooks table at runtime, call ns__query_inithooks(). - */ - -static bool -dns64_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp); -static ns_hook_t dns64_init = { - .action = dns64_qctx_initialize, -}; - -static bool -dns64_respond_begin(void *arg, void *cbdata, isc_result_t *resp); -static ns_hook_t dns64_respbegin = { - .action = dns64_respond_begin, -}; - -static bool -dns64_respond_add_answer(void *arg, void *cbdata, isc_result_t *resp); -static ns_hook_t dns64_respaddanswer = { - .action = dns64_respond_add_answer, -}; - -static bool -dns64_resume_restored(void *arg, void *cbdata, isc_result_t *resp); -static ns_hook_t dns64_resumerest = { - .action = dns64_resume_restored, -}; - -static bool -dns64_notfound_recurse(void *arg, void *cbdata, isc_result_t *resp); -static ns_hook_t dns64_nfrec = { - .action = dns64_notfound_recurse, -}; - -static bool -dns64_delegation_recurse(void *arg, void *cbdata, isc_result_t *resp); -static ns_hook_t dns64_delrec = { - .action = dns64_delegation_recurse, -}; - -static bool -dns64_nodata_begin(void *arg, void *cbdata, isc_result_t *resp); -static ns_hook_t dns64_nodata = { - .action = dns64_nodata_begin, -}; - -static bool -dns64_zerottl_recurse(void *arg, void *cbdata, isc_result_t *resp); -static ns_hook_t dns64_zerottl = { - .action = dns64_zerottl_recurse, -}; - -static bool -dns64_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp); -static ns_hook_t dns64_destroy = { - .action = dns64_qctx_destroy, -}; - -/* - * XXX: - * This function is temporary. Later, this will be done from the - * registration function in the dns64 module. - */ -void -ns__query_inithooks(dns_view_t *view) { - REQUIRE(view != NULL); - - ns_hook_add(view->hooktable, view->mctx, - NS_QUERY_QCTX_INITIALIZED, &dns64_init); - ns_hook_add(view->hooktable, view->mctx, - NS_QUERY_RESPOND_BEGIN, &dns64_respbegin); - ns_hook_add(view->hooktable, view->mctx, - NS_QUERY_ADDANSWER_BEGIN, &dns64_respaddanswer); - ns_hook_add(view->hooktable, view->mctx, - NS_QUERY_RESUME_RESTORED, &dns64_resumerest); - ns_hook_add(view->hooktable, view->mctx, - NS_QUERY_NOTFOUND_RECURSE, &dns64_nfrec); - ns_hook_add(view->hooktable, view->mctx, - NS_QUERY_DELEGATION_RECURSE_BEGIN, &dns64_delrec); - ns_hook_add(view->hooktable, view->mctx, - NS_QUERY_NODATA_BEGIN, &dns64_nodata); - ns_hook_add(view->hooktable, view->mctx, - NS_QUERY_ZEROTTL_RECURSE, &dns64_zerottl); - ns_hook_add(view->hooktable, view->mctx, - NS_QUERY_QCTX_DESTROYED, &dns64_destroy); -} - /*% * Increment query statistics counters. */ @@ -2167,16 +2034,12 @@ query_addtoname(dns_name_t *name, dns_rdataset_t *rdataset) { ISC_LIST_APPEND(name->list, rdataset, link); } -/* - * 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; +void +ns_query_setorder(ns_client_t *client, dns_name_t *name, + dns_rdataset_t *rdataset) +{ dns_order_t *order = client->view->order; - CTRACE(ISC_LOG_DEBUG(3), "query_setorder"); - UNUSED(client); if (order != NULL) { @@ -2184,6 +2047,7 @@ query_setorder(query_ctx_t *qctx, dns_name_t *name, dns_rdataset_t *rdataset) { rdataset->type, rdataset->rdclass); } + rdataset->attributes |= DNS_RDATASETATTR_LOADORDER; }; @@ -2306,7 +2170,7 @@ query_addrrset(query_ctx_t *qctx, dns_name_t **namep, * section processing if needed. */ query_addtoname(mname, rdataset); - query_setorder(qctx, mname, rdataset); + ns_query_setorder(client, mname, rdataset); query_additional(qctx, rdataset); /* @@ -4705,93 +4569,6 @@ query_findclosestnsec3(dns_name_t *qname, dns_db_t *db, return; } -static uint32_t -dns64_ttl(dns_db_t *db, dns_dbversion_t *version) { - dns_dbnode_t *node = NULL; - dns_rdata_soa_t soa; - dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdataset_t rdataset; - isc_result_t result; - uint32_t ttl = UINT32_MAX; - - dns_rdataset_init(&rdataset); - - result = dns_db_getoriginnode(db, &node); - if (result != ISC_R_SUCCESS) - goto cleanup; - - result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa, - 0, 0, &rdataset, NULL); - if (result != ISC_R_SUCCESS) - goto cleanup; - result = dns_rdataset_first(&rdataset); - if (result != ISC_R_SUCCESS) - goto cleanup; - - dns_rdataset_current(&rdataset, &rdata); - result = dns_rdata_tostruct(&rdata, &soa, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - ttl = ISC_MIN(rdataset.ttl, soa.minimum); - -cleanup: - if (dns_rdataset_isassociated(&rdataset)) - dns_rdataset_disassociate(&rdataset); - if (node != NULL) - dns_db_detachnode(db, &node); - return (ttl); -} - -static bool -dns64_aaaaok(ns_client_t *client, dns_rdataset_t *rdataset, - dns_rdataset_t *sigrdataset) -{ - isc_netaddr_t netaddr; - dns_aclenv_t *env = ns_interfacemgr_getaclenv(client->interface->mgr); - dns_dns64_t *dns64 = ISC_LIST_HEAD(client->view->dns64); - unsigned int flags = 0; - unsigned int i, count; - bool *aaaaok; - - INSIST(client->dns64_aaaaok == NULL); - INSIST(client->dns64_aaaaoklen == 0); - INSIST(client->dns64_aaaa == NULL); - INSIST(client->dns64_sigaaaa == NULL); - - if (dns64 == NULL) - return (true); - - if (RECURSIONOK(client)) - flags |= DNS_DNS64_RECURSIVE; - - if (WANTDNSSEC(client) && sigrdataset != NULL && - dns_rdataset_isassociated(sigrdataset)) - flags |= DNS_DNS64_DNSSEC; - - count = dns_rdataset_count(rdataset); - aaaaok = isc_mem_get(client->mctx, sizeof(bool) * count); - - isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); - if (dns_dns64_aaaaok(dns64, &netaddr, client->signer, - env, flags, rdataset, aaaaok, count)) - { - for (i = 0; i < count; i++) { - if (aaaaok != NULL && !aaaaok[i]) { - SAVE(client->dns64_aaaaok, aaaaok); - client->dns64_aaaaoklen = count; - break; - } - } - if (aaaaok != NULL) - isc_mem_put(client->mctx, aaaaok, - sizeof(bool) * count); - return (true); - } - if (aaaaok != NULL) - isc_mem_put(client->mctx, aaaaok, - sizeof(bool) * count); - return (false); -} - /* * Look for the name and type in the redirection zone. If found update * the arguments as appropriate. Return true if a update was @@ -5329,7 +5106,7 @@ root_key_sentinel_detect(query_ctx_t *qctx) { * * Called first by query_setup(), and then again as often as needed to * follow a CNAME chain. Determines which authoritative database to - * search, then hands off processing to query_lookup(). + * search, then hands off processing to ns_query_lookup(). */ isc_result_t ns__query_start(query_ctx_t *qctx) { @@ -5534,19 +5311,14 @@ ns__query_start(query_ctx_t *qctx) { } } - return (query_lookup(qctx)); + return (ns_query_lookup(qctx)); cleanup: return (result); } -/*% - * Perform a local database lookup, in either an authoritative or - * cache database. If unable to answer, call ns_query_done(); otherwise - * hand off processing to query_gotanswer(). - */ -static isc_result_t -query_lookup(query_ctx_t *qctx) { +isc_result_t +ns_query_lookup(query_ctx_t *qctx) { isc_buffer_t b; isc_result_t result; dns_clientinfomethods_t cm; @@ -5554,7 +5326,7 @@ query_lookup(query_ctx_t *qctx) { dns_name_t *rpzqname = NULL; unsigned int dboptions; - CCTRACE(ISC_LOG_DEBUG(3), "query_lookup"); + CCTRACE(ISC_LOG_DEBUG(3), "ns_query_lookup"); CALL_HOOK(NS_QUERY_LOOKUP_BEGIN, qctx); @@ -5567,7 +5339,7 @@ query_lookup(query_ctx_t *qctx) { qctx->dbuf = ns_client_getnamebuf(qctx->client); if (ISC_UNLIKELY(qctx->dbuf == NULL)) { CCTRACE(ISC_LOG_ERROR, - "query_lookup: ns_client_getnamebuf failed (2)"); + "ns_query_lookup: ns_client_getnamebuf failed (2)"); QUERY_ERROR(qctx, ISC_R_NOMEMORY); return (ns_query_done(qctx)); } @@ -5577,7 +5349,7 @@ query_lookup(query_ctx_t *qctx) { if (ISC_UNLIKELY(qctx->fname == NULL || qctx->rdataset == NULL)) { CCTRACE(ISC_LOG_ERROR, - "query_lookup: ns_client_newname failed (2)"); + "ns_query_lookup: ns_client_newname failed (2)"); QUERY_ERROR(qctx, ISC_R_NOMEMORY); return (ns_query_done(qctx)); } @@ -5588,7 +5360,8 @@ query_lookup(query_ctx_t *qctx) { qctx->sigrdataset = ns_client_newrdataset(qctx->client); if (qctx->sigrdataset == NULL) { CCTRACE(ISC_LOG_ERROR, - "query_lookup: ns_client_newrdataset failed (2)"); + "ns_query_lookup: " + "ns_client_newrdataset failed (2)"); QUERY_ERROR(qctx, ISC_R_NOMEMORY); return (ns_query_done(qctx)); } @@ -6496,8 +6269,8 @@ query_checkrpz(query_ctx_t *qctx, isc_result_t result) { if (qctx->rpz_st->m.rpz->addsoa) { bool override_ttl = dns_rdataset_isassociated(qctx->rdataset); - rresult = query_addsoa(qctx, override_ttl, - DNS_SECTION_ADDITIONAL); + rresult = ns_query_addsoa(qctx, override_ttl, + DNS_SECTION_ADDITIONAL); if (rresult != ISC_R_SUCCESS) { QUERY_ERROR(qctx, result); return (ISC_R_COMPLETE); @@ -6868,11 +6641,11 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t res) { case DNS_R_EMPTYNAME: qctx->nxresult = DNS_R_EMPTYNAME; - return (query_nodata(qctx)); + return (ns_query_nodata(qctx)); case DNS_R_NXRRSET: qctx->nxresult = DNS_R_NXRRSET; - return (query_nodata(qctx)); + return (ns_query_nodata(qctx)); case DNS_R_EMPTYWILD: return (query_nxdomain(qctx, true)); @@ -6889,11 +6662,11 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t res) { return (result); } qctx->nxresult = DNS_R_NCACHENXDOMAIN; - return (query_ncache(qctx)); + return (ns_query_ncache(qctx)); case DNS_R_NCACHENXRRSET: qctx->nxresult = DNS_R_NCACHENXRRSET; - return (query_ncache(qctx)); + return (ns_query_ncache(qctx)); case DNS_R_CNAME: return (query_cname(qctx)); @@ -6914,7 +6687,7 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t res) { * If serve-stale is enabled, query_usestale() already * set up 'qctx' for looking up a stale response. */ - return (query_lookup(qctx)); + return (ns_query_lookup(qctx)); } /* @@ -7388,345 +7161,6 @@ query_respond(query_ctx_t *qctx) { return (result); } -static isc_result_t -query_dns64(query_ctx_t *qctx) { - ns_client_t *client = qctx->client; - dns_aclenv_t *env = ns_interfacemgr_getaclenv(client->interface->mgr); - dns_name_t *name, *mname; - dns_rdata_t *dns64_rdata; - dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdatalist_t *dns64_rdatalist; - dns_rdataset_t *dns64_rdataset; - dns_rdataset_t *mrdataset; - isc_buffer_t *buffer; - isc_region_t r; - isc_result_t result; - dns_view_t *view = client->view; - isc_netaddr_t netaddr; - dns_dns64_t *dns64; - unsigned int flags = 0; - const dns_section_t section = DNS_SECTION_ANSWER; - - /*% - * To the current response for 'qctx->client', add the answer RRset - * '*rdatasetp' and an optional signature set '*sigrdatasetp', with - * owner name '*namep', to the answer section, unless they are - * already there. Also add any pertinent additional data. - * - * If 'qctx->dbuf' is not NULL, then 'qctx->fname' is the name - * whose data is stored 'qctx->dbuf'. In this case, - * query_addrrset() guarantees that when it returns the name - * will either have been kept or released. - */ - CTRACE(ISC_LOG_DEBUG(3), "query_dns64"); - - qctx->qtype = qctx->type = dns_rdatatype_aaaa; - - name = qctx->fname; - mname = NULL; - mrdataset = NULL; - buffer = NULL; - dns64_rdata = NULL; - dns64_rdataset = NULL; - dns64_rdatalist = NULL; - result = dns_message_findname(client->message, section, - name, dns_rdatatype_aaaa, - qctx->rdataset->covers, - &mname, &mrdataset); - if (result == ISC_R_SUCCESS) { - /* - * We've already got an RRset of the given name and type. - * There's nothing else to do; - */ - CTRACE(ISC_LOG_DEBUG(3), - "query_dns64: dns_message_findname succeeded: done"); - 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) { - 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) { - ns_client_releasename(client, &qctx->fname); - } - } - - if (qctx->rdataset->trust != dns_trust_secure) { - client->query.attributes &= ~NS_QUERYATTR_SECURE; - } - - isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); - - result = isc_buffer_allocate(client->mctx, &buffer, - view->dns64cnt * 16 * - dns_rdataset_count(qctx->rdataset)); - if (result != ISC_R_SUCCESS) - goto cleanup; - result = dns_message_gettemprdataset(client->message, - &dns64_rdataset); - if (result != ISC_R_SUCCESS) - goto cleanup; - result = dns_message_gettemprdatalist(client->message, - &dns64_rdatalist); - if (result != ISC_R_SUCCESS) - goto cleanup; - - dns_rdatalist_init(dns64_rdatalist); - dns64_rdatalist->rdclass = dns_rdataclass_in; - dns64_rdatalist->type = dns_rdatatype_aaaa; - if (client->dns64_ttl != UINT32_MAX) - dns64_rdatalist->ttl = ISC_MIN(qctx->rdataset->ttl, - client->dns64_ttl); - else - dns64_rdatalist->ttl = ISC_MIN(qctx->rdataset->ttl, 600); - - if (RECURSIONOK(client)) - flags |= DNS_DNS64_RECURSIVE; - - /* - * We use the signatures from the A lookup to set DNS_DNS64_DNSSEC - * as this provides a easy way to see if the answer was signed. - */ - if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL && - dns_rdataset_isassociated(qctx->sigrdataset)) - flags |= DNS_DNS64_DNSSEC; - - for (result = dns_rdataset_first(qctx->rdataset); - result == ISC_R_SUCCESS; - result = dns_rdataset_next(qctx->rdataset)) { - for (dns64 = ISC_LIST_HEAD(client->view->dns64); - dns64 != NULL; dns64 = dns_dns64_next(dns64)) { - - dns_rdataset_current(qctx->rdataset, &rdata); - isc_buffer_availableregion(buffer, &r); - INSIST(r.length >= 16); - result = dns_dns64_aaaafroma(dns64, &netaddr, - client->signer, env, flags, - rdata.data, r.base); - if (result != ISC_R_SUCCESS) { - dns_rdata_reset(&rdata); - continue; - } - isc_buffer_add(buffer, 16); - isc_buffer_remainingregion(buffer, &r); - isc_buffer_forward(buffer, 16); - result = dns_message_gettemprdata(client->message, - &dns64_rdata); - if (result != ISC_R_SUCCESS) - goto cleanup; - dns_rdata_init(dns64_rdata); - dns_rdata_fromregion(dns64_rdata, dns_rdataclass_in, - dns_rdatatype_aaaa, &r); - ISC_LIST_APPEND(dns64_rdatalist->rdata, dns64_rdata, - link); - dns64_rdata = NULL; - dns_rdata_reset(&rdata); - } - } - if (result != ISC_R_NOMORE) - goto cleanup; - - if (ISC_LIST_EMPTY(dns64_rdatalist->rdata)) - goto cleanup; - - result = dns_rdatalist_tordataset(dns64_rdatalist, dns64_rdataset); - if (result != ISC_R_SUCCESS) - goto cleanup; - dns_rdataset_setownercase(dns64_rdataset, mname); - client->query.attributes |= NS_QUERYATTR_NOADDITIONAL; - dns64_rdataset->trust = qctx->rdataset->trust; - - query_addtoname(mname, dns64_rdataset); - query_setorder(qctx, mname, dns64_rdataset); - - dns64_rdataset = NULL; - dns64_rdatalist = NULL; - dns_message_takebuffer(client->message, &buffer); - inc_stats(client, ns_statscounter_dns64); - result = ISC_R_SUCCESS; - - cleanup: - if (buffer != NULL) - isc_buffer_free(&buffer); - - if (dns64_rdata != NULL) - dns_message_puttemprdata(client->message, &dns64_rdata); - - if (dns64_rdataset != NULL) - dns_message_puttemprdataset(client->message, &dns64_rdataset); - - if (dns64_rdatalist != NULL) { - for (dns64_rdata = ISC_LIST_HEAD(dns64_rdatalist->rdata); - dns64_rdata != NULL; - dns64_rdata = ISC_LIST_HEAD(dns64_rdatalist->rdata)) - { - ISC_LIST_UNLINK(dns64_rdatalist->rdata, - dns64_rdata, link); - dns_message_puttemprdata(client->message, &dns64_rdata); - } - dns_message_puttemprdatalist(client->message, &dns64_rdatalist); - } - - CTRACE(ISC_LOG_DEBUG(3), "query_dns64: done"); - return (result); -} - -static void -query_filter64(query_ctx_t *qctx) { - ns_client_t *client = qctx->client; - dns_name_t *name, *mname; - dns_rdata_t *myrdata; - dns_rdata_t rdata = DNS_RDATA_INIT; - dns_rdatalist_t *myrdatalist; - dns_rdataset_t *myrdataset; - isc_buffer_t *buffer; - isc_region_t r; - isc_result_t result; - unsigned int i; - const dns_section_t section = DNS_SECTION_ANSWER; - - CTRACE(ISC_LOG_DEBUG(3), "query_filter64"); - - INSIST(client->dns64_aaaaok != NULL); - INSIST(client->dns64_aaaaoklen == - dns_rdataset_count(qctx->rdataset)); - - name = qctx->fname; - mname = NULL; - buffer = NULL; - myrdata = NULL; - myrdataset = NULL; - myrdatalist = NULL; - result = dns_message_findname(client->message, section, - name, dns_rdatatype_aaaa, - qctx->rdataset->covers, - &mname, &myrdataset); - if (result == ISC_R_SUCCESS) { - /* - * We've already got an RRset of the given name and type. - * There's nothing else to do; - */ - CTRACE(ISC_LOG_DEBUG(3), - "query_filter64: dns_message_findname succeeded: done"); - 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) { - ns_client_releasename(client, &qctx->fname); - } - qctx->dbuf = NULL; - } - - if (qctx->rdataset->trust != dns_trust_secure) { - client->query.attributes &= ~NS_QUERYATTR_SECURE; - } - - result = isc_buffer_allocate(client->mctx, &buffer, - 16 * dns_rdataset_count(qctx->rdataset)); - if (result != ISC_R_SUCCESS) - goto cleanup; - result = dns_message_gettemprdataset(client->message, &myrdataset); - if (result != ISC_R_SUCCESS) - goto cleanup; - result = dns_message_gettemprdatalist(client->message, &myrdatalist); - if (result != ISC_R_SUCCESS) - goto cleanup; - - dns_rdatalist_init(myrdatalist); - myrdatalist->rdclass = dns_rdataclass_in; - myrdatalist->type = dns_rdatatype_aaaa; - myrdatalist->ttl = qctx->rdataset->ttl; - - i = 0; - for (result = dns_rdataset_first(qctx->rdataset); - result == ISC_R_SUCCESS; - result = dns_rdataset_next(qctx->rdataset)) - { - if (!client->dns64_aaaaok[i++]) - continue; - dns_rdataset_current(qctx->rdataset, &rdata); - INSIST(rdata.length == 16); - isc_buffer_putmem(buffer, rdata.data, rdata.length); - isc_buffer_remainingregion(buffer, &r); - isc_buffer_forward(buffer, rdata.length); - result = dns_message_gettemprdata(client->message, &myrdata); - if (result != ISC_R_SUCCESS) - goto cleanup; - dns_rdata_init(myrdata); - dns_rdata_fromregion(myrdata, dns_rdataclass_in, - dns_rdatatype_aaaa, &r); - ISC_LIST_APPEND(myrdatalist->rdata, myrdata, link); - myrdata = NULL; - dns_rdata_reset(&rdata); - } - if (result != ISC_R_NOMORE) - goto cleanup; - - result = dns_rdatalist_tordataset(myrdatalist, myrdataset); - if (result != ISC_R_SUCCESS) - goto cleanup; - dns_rdataset_setownercase(myrdataset, name); - client->query.attributes |= NS_QUERYATTR_NOADDITIONAL; - if (mname == name) { - 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_addtoname(mname, myrdataset); - query_setorder(qctx, mname, myrdataset); - - myrdataset = NULL; - myrdatalist = NULL; - dns_message_takebuffer(client->message, &buffer); - - cleanup: - if (buffer != NULL) - isc_buffer_free(&buffer); - - if (myrdata != NULL) - dns_message_puttemprdata(client->message, &myrdata); - - if (myrdataset != NULL) - dns_message_puttemprdataset(client->message, &myrdataset); - - if (myrdatalist != NULL) { - for (myrdata = ISC_LIST_HEAD(myrdatalist->rdata); - myrdata != NULL; - myrdata = ISC_LIST_HEAD(myrdatalist->rdata)) - { - ISC_LIST_UNLINK(myrdatalist->rdata, myrdata, link); - dns_message_puttemprdata(client->message, &myrdata); - } - dns_message_puttemprdatalist(client->message, &myrdatalist); - } - if (qctx->dbuf != NULL) { - ns_client_releasename(client, &name); - } - - CTRACE(ISC_LOG_DEBUG(3), "query_filter64: done"); -} - /*% * Handle the case of a name not being found in a database lookup. * Called from query_gotanswer(). Passes off processing to @@ -7916,7 +7350,7 @@ query_zone_delegation(query_ctx_t *qctx) { RESTORE(qctx->zone, tzone); qctx->authoritative = true; - return (query_lookup(qctx)); + return (ns_query_lookup(qctx)); } } @@ -7930,7 +7364,7 @@ query_zone_delegation(query_ctx_t *qctx) { * cache. We'll remember the current values of fname, * rdataset, and sigrdataset. We'll then go looking for * QNAME in the cache. If we find something better, we'll - * use it instead. If not, then query_lookup() calls + * use it instead. If not, then ns_query_lookup() calls * query_notfound() which calls query_delegation(), and * we'll restore these values there. */ @@ -7944,7 +7378,7 @@ query_zone_delegation(query_ctx_t *qctx) { dns_db_attach(qctx->view->cachedb, &qctx->db); qctx->is_zone = false; - return (query_lookup(qctx)); + return (ns_query_lookup(qctx)); } return (query_prepare_delegation_response(qctx)); @@ -8216,11 +7650,8 @@ query_addds(query_ctx_t *qctx) { } } -/*% - * Handle authoritative NOERROR/NODATA responses. - */ -static isc_result_t -query_nodata(query_ctx_t *qctx) { +isc_result_t +ns_query_nodata(query_ctx_t *qctx) { isc_result_t result = qctx->nxresult; CALL_HOOK(NS_QUERY_NODATA_BEGIN, qctx); @@ -8345,14 +7776,14 @@ query_sign_nodata(query_ctx_t *qctx) { if (dns_rdataset_isassociated(qctx->rdataset)) { /* * If we've got a NSEC record, we need to save the - * name now because we're going call query_addsoa() + * name now because we're going call ns_query_addsoa() * below, and it needs to use the name buffer. */ 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() + * our hold on the name buffer so ns_query_addsoa() * may use it. */ ns_client_releasename(qctx->client, &qctx->fname); @@ -8363,8 +7794,8 @@ query_sign_nodata(query_ctx_t *qctx) { * if this was an RPZ rewrite, but if it wasn't, add it now. */ if (!qctx->nxrewrite) { - result = query_addsoa(qctx, UINT32_MAX, - DNS_SECTION_AUTHORITY); + result = ns_query_addsoa(qctx, UINT32_MAX, + DNS_SECTION_AUTHORITY); if (result != ISC_R_SUCCESS) { QUERY_ERROR(qctx, result); return (ns_query_done(qctx)); @@ -8467,14 +7898,14 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { if (dns_rdataset_isassociated(qctx->rdataset)) { /* * If we've got a NSEC record, we need to save the - * name now because we're going call query_addsoa() + * name now because we're going call ns_query_addsoa() * below, and it needs to use the name buffer. */ 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() + * our hold on the name buffer so ns_query_addsoa() * may use it. */ ns_client_releasename(qctx->client, &qctx->fname); @@ -8498,7 +7929,7 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { ttl = 0; } if (!qctx->nxrewrite || qctx->rpz_st->m.rpz->addsoa) { - result = query_addsoa(qctx, ttl, section); + result = ns_query_addsoa(qctx, ttl, section); if (result != ISC_R_SUCCESS) { QUERY_ERROR(qctx, result); return (ns_query_done(qctx)); @@ -8557,12 +7988,12 @@ query_redirect(query_ctx_t *qctx) { qctx->redirected = true; qctx->is_zone = true; qctx->nxresult = DNS_R_NXRRSET; - return (query_nodata(qctx)); + return (ns_query_nodata(qctx)); case DNS_R_NCACHENXRRSET: qctx->redirected = true; qctx->is_zone = false; qctx->nxresult = DNS_R_NCACHENXRRSET; - return (query_ncache(qctx)); + return (ns_query_ncache(qctx)); default: break; } @@ -8597,12 +8028,12 @@ query_redirect(query_ctx_t *qctx) { qctx->redirected = true; qctx->is_zone = true; qctx->nxresult = DNS_R_NXRRSET; - return (query_nodata(qctx)); + return (ns_query_nodata(qctx)); case DNS_R_NCACHENXRRSET: qctx->redirected = true; qctx->is_zone = false; qctx->nxresult = DNS_R_NCACHENXRRSET; - return (query_ncache(qctx)); + return (ns_query_ncache(qctx)); default: break; } @@ -9303,20 +8734,14 @@ query_coveringnsec(query_ctx_t *qctx) { if (qctx->sigrdataset != NULL) { ns_client_putrdataset(qctx->client, &qctx->sigrdataset); } - return (query_lookup(qctx)); + return (ns_query_lookup(qctx)); } return (ns_query_done(qctx)); } -/*% - * Handle negative cache responses, DNS_R_NCACHENXRRSET or - * DNS_R_NCACHENXDOMAIN. (Note: may be called with other - * result codes as a result of hook actions; for example, - * DNS64 may call with DNS_R_NXOMAIN.) - */ -static isc_result_t -query_ncache(query_ctx_t *qctx) { +isc_result_t +ns_query_ncache(query_ctx_t *qctx) { INSIST(!qctx->is_zone); qctx->authoritative = false; @@ -9336,7 +8761,7 @@ query_ncache(query_ctx_t *qctx) { } } - return (query_nodata(qctx)); + return (ns_query_nodata(qctx)); } /* @@ -9734,32 +9159,19 @@ query_prepresponse(query_ctx_t *qctx) { return (result); } -/*% - * Add SOA to the authority section when sending negative responses - * (or to the additional section if sending negative responses triggered - * by RPZ rewriting.) - */ -static isc_result_t -query_addsoa(query_ctx_t *qctx, unsigned int override_ttl, - dns_section_t section) -{ +isc_result_t +ns_query_addsoa(query_ctx_t *qctx, dns_ttl_t override_ttl, + dns_section_t section) { ns_client_t *client = qctx->client; - dns_name_t *name; - dns_dbnode_t *node; - isc_result_t result, eresult; + dns_name_t *name = NULL; + dns_dbnode_t *node = NULL; + isc_result_t result, eresult = ISC_R_SUCCESS; dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; dns_rdataset_t **sigrdatasetp = NULL; dns_clientinfomethods_t cm; dns_clientinfo_t ci; - CTRACE(ISC_LOG_DEBUG(3), "query_addsoa"); - /* - * Initialization. - */ - eresult = ISC_R_SUCCESS; - name = NULL; - rdataset = NULL; - node = NULL; + CTRACE(ISC_LOG_DEBUG(3), "ns_query_addsoa"); dns_clientinfomethods_init(&cm, ns_client_sourceip); dns_clientinfo_init(&ci, client, NULL); @@ -9840,8 +9252,9 @@ query_addsoa(query_ctx_t *qctx, unsigned int override_ttl, override_ttl < rdataset->ttl) { rdataset->ttl = override_ttl; - if (sigrdataset != NULL) + if (sigrdataset != NULL) { sigrdataset->ttl = override_ttl; + } } /* @@ -11106,292 +10519,3 @@ ns_query_start(ns_client_t *client) { ns_client_attach(client, &qclient); (void)query_setup(qclient, qtype); } - -static bool -dns64_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp) { - UNUSED(arg); - UNUSED(cbdata); - - *resp = ISC_R_UNSET; - return (false); -} - -static bool -dns64_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) arg; - - UNUSED(cbdata); - - /* - * Check to see if the AAAA RRset has non-excluded addresses - * in it. If not look for a A RRset. - */ - INSIST(qctx->client->dns64_aaaaok == NULL); - - if (qctx->qtype == dns_rdatatype_aaaa && !qctx->dns64_exclude && - !ISC_LIST_EMPTY(qctx->view->dns64) && - qctx->client->message->rdclass == dns_rdataclass_in && - !dns64_aaaaok(qctx->client, qctx->rdataset, qctx->sigrdataset)) - { - /* - * Look to see if there are A records for this name. - */ - qctx->client->dns64_ttl = qctx->rdataset->ttl; - SAVE(qctx->client->dns64_aaaa, qctx->rdataset); - SAVE(qctx->client->dns64_sigaaaa, qctx->sigrdataset); - 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; - - /* - * XXX: we are depending here on DNS64 - * being reached before any other modules that - * might set up recursion. In particular if - * the filter-aaaa module runs first, there'll - * be an assertion failure. We need to make this - * order-indeendent. - */ - *resp = query_lookup(qctx); - return (true); - } - - *resp = ISC_R_UNSET; - return (false); -} - -static bool -dns64_respond_add_answer(void *arg, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) arg; - - UNUSED(cbdata); - - if (qctx->dns64) { - isc_result_t result = query_dns64(qctx); - qctx->noqname = NULL; - dns_rdataset_disassociate(qctx->rdataset); - dns_message_puttemprdataset(qctx->client->message, - &qctx->rdataset); - if (result == ISC_R_NOMORE) { - if (qctx->dns64_exclude) { - if (!qctx->is_zone) { - *resp = ns_query_done(qctx); - return (true); - } - /* - * Add a fake SOA record. - */ - (void) query_addsoa(qctx, 600, - DNS_SECTION_AUTHORITY); - *resp = ns_query_done(qctx); - return (true); - } - if (qctx->is_zone) { - qctx->nxresult = DNS_R_NXDOMAIN; - *resp = query_nodata(qctx); - } else { - qctx->nxresult = DNS_R_NXDOMAIN; - *resp = query_ncache(qctx); - } - } else if (result != ISC_R_SUCCESS) { - qctx->result = result; - *resp = ns_query_done(qctx); - } else { - *resp = ISC_R_COMPLETE; - } - return (true); - } else if (qctx->client->dns64_aaaaok != NULL) { - query_filter64(qctx); - ns_client_putrdataset(qctx->client, &qctx->rdataset); - *resp = ISC_R_COMPLETE; - return (true); - } - - *resp = ISC_R_UNSET; - return (false); -} - -static bool -dns64_resume_restored(void *arg, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) arg; - - UNUSED(cbdata); - - if (DNS64(qctx->client)) { - qctx->client->query.attributes &= ~NS_QUERYATTR_DNS64; - qctx->dns64 = true; - } - - if (DNS64EXCLUDE(qctx->client)) { - qctx->client->query.attributes &= ~NS_QUERYATTR_DNS64EXCLUDE; - qctx->dns64_exclude = true; - } - - *resp = ISC_R_UNSET; - return (false); -} - -static bool -dns64_notfound_recurse(void *arg, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) arg; - - UNUSED(cbdata); - - if (qctx->dns64) { - qctx->client->query.attributes |= NS_QUERYATTR_DNS64; - } - if (qctx->dns64_exclude) { - qctx->client->query.attributes |= NS_QUERYATTR_DNS64EXCLUDE; - } - - *resp = ISC_R_UNSET; - return (false); -} - -static bool -dns64_delegation_recurse(void *arg, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) arg; - - UNUSED(cbdata); - - /* - * Look up an A record so we can synthesize DNS64. - */ - if (qctx->dns64) { - qctx->result = ns_query_recurse(qctx->client, - dns_rdatatype_a, - qctx->client->query.qname, - NULL, NULL, qctx->resuming); - qctx->client->query.attributes |= NS_QUERYATTR_RECURSING; - - if (qctx->result == ISC_R_SUCCESS) { - qctx->client->query.attributes |= NS_QUERYATTR_DNS64; - if (qctx->dns64_exclude) { - qctx->client->query.attributes |= - NS_QUERYATTR_DNS64EXCLUDE; - } - } - - *resp = ISC_R_COMPLETE; - return (true); - } - - *resp = ISC_R_UNSET; - return (false); -} - -static bool -dns64_nodata_begin(void *arg, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) arg; - - UNUSED(cbdata); - - if (qctx->dns64 && !qctx->dns64_exclude) { - isc_buffer_t b; - - /* - * Restore the answers from the previous AAAA lookup. - */ - if (qctx->rdataset != NULL) { - ns_client_putrdataset(qctx->client, &qctx->rdataset); - } - if (qctx->sigrdataset != NULL) { - ns_client_putrdataset(qctx->client, &qctx->sigrdataset); - } - RESTORE(qctx->rdataset, qctx->client->dns64_aaaa); - RESTORE(qctx->sigrdataset, qctx->client->dns64_sigaaaa); - if (qctx->fname == NULL) { - qctx->dbuf = ns_client_getnamebuf(qctx->client); - if (qctx->dbuf == NULL) { - CCTRACE(ISC_LOG_ERROR, - "query_nodata: " - "ns_client_getnamebuf failed (3)"); - QUERY_ERROR(qctx, DNS_R_SERVFAIL); - *resp = ns_query_done(qctx); - return (true); - } - qctx->fname = ns_client_newname(qctx->client, - qctx->dbuf, &b); - if (qctx->fname == NULL) { - CCTRACE(ISC_LOG_ERROR, - "query_nodata: " - "ns_client_newname failed (3)"); - QUERY_ERROR(qctx, DNS_R_SERVFAIL); - *resp = ns_query_done(qctx); - return (true); - } - } - dns_name_copy(qctx->client->query.qname, qctx->fname, NULL); - qctx->dns64 = false; - } else if ((qctx->nxresult == DNS_R_NXRRSET || - qctx->nxresult == DNS_R_NCACHENXRRSET) && - !ISC_LIST_EMPTY(qctx->view->dns64) && - !qctx->nxrewrite && - qctx->client->message->rdclass == dns_rdataclass_in && - qctx->qtype == dns_rdatatype_aaaa) - { - /* - * Look to see if there are A records for this name. - */ - switch (qctx->nxresult) { - case DNS_R_NCACHENXRRSET: - /* - * This is from the negative cache; if the ttl is - * zero, we need to work out whether we have just - * decremented to zero or there was no negative - * cache ttl in the answer. - */ - if (qctx->rdataset->ttl != 0) { - qctx->client->dns64_ttl = qctx->rdataset->ttl; - break; - } - if (dns_rdataset_first(qctx->rdataset) == ISC_R_SUCCESS) - qctx->client->dns64_ttl = 0; - break; - case DNS_R_NXRRSET: - qctx->client->dns64_ttl = - dns64_ttl(qctx->db, qctx->version); - break; - default: - INSIST(0); - } - - SAVE(qctx->client->dns64_aaaa, qctx->rdataset); - SAVE(qctx->client->dns64_sigaaaa, qctx->sigrdataset); - ns_client_releasename(qctx->client, &qctx->fname); - dns_db_detachnode(qctx->db, &qctx->node); - qctx->type = qctx->qtype = dns_rdatatype_a; - qctx->dns64 = true; - *resp = query_lookup(qctx); - return (true); - } - - *resp = ISC_R_UNSET; - return (false); -} - -static bool -dns64_zerottl_recurse(void *arg, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) arg; - - UNUSED(cbdata); - - if (qctx->dns64) { - qctx->client->query.attributes |= NS_QUERYATTR_DNS64; - } - if (qctx->dns64_exclude) { - qctx->client->query.attributes |= NS_QUERYATTR_DNS64EXCLUDE; - } - - *resp = ISC_R_UNSET; - return (false); -} - -static bool -dns64_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp) { - UNUSED(arg); - UNUSED(cbdata); - - *resp = ISC_R_UNSET; - return (false); -}