]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
initial implementation of filter-aaaa.so as a shared object
authorEvan Hunt <each@isc.org>
Sat, 11 Aug 2018 02:32:12 +0000 (19:32 -0700)
committerEvan Hunt <each@isc.org>
Thu, 6 Dec 2018 18:29:10 +0000 (10:29 -0800)
- temporary kluge! in this version, for testing purposes,
  named always searches for a filter-aaaa module at /tmp/filter-aaaa.so.
  this enables the filter-aaaa system test to run even though the
  code to configure hooks in named.conf hasn't been written yet.
- filter-aaaa-on-v4, filter-aaaa-on-v6 and the filter-aaaa ACL are
  still configured in the view as they were before, not in the hook.

bin/named/server.c
configure
configure.ac
lib/ns/Makefile.in
lib/ns/filter-aaaa.c [new file with mode: 0644]
lib/ns/hooks.c
lib/ns/include/ns/hooks.h
lib/ns/include/ns/query.h
lib/ns/query.c
lib/ns/server.c
lib/ns/win32/libns.def

index c453396dd070357258f075b279ec58237054a9c1..37282e9e09a4527b280344c3cc1133e503d99b59 100644 (file)
@@ -3716,6 +3716,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;
@@ -5293,6 +5294,21 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
 
                CHECK(configure_dyndb(dyndb, mctx, dctx));
        }
+
+       /*
+        * XXX:
+        * temporary! this forces loading of filter-aaaa.so from the
+        * current working directory, if present. later this will
+        * happen via configuration as dyndb does above. we don't
+        * bother checking whether it succeeded; if it doesn't,
+        * filter-aaaa simply won't work.
+        */
+       if (hctx == NULL) {
+               CHECK(ns_hook_createctx(mctx, &hctx));
+       }
+       ns_hooktable_init(NULL);
+       (void) ns_hookmodule_load("/tmp/filter-aaaa.so", "", "<none>", 0,
+                                 hctx, NULL);
 #endif
 
        /*
@@ -5546,6 +5562,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);
 }
@@ -8028,7 +8047,7 @@ 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_cleanup();
@@ -9512,6 +9531,9 @@ 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_cleanup();
 
index 5031db85a3e4ffbc17bc879e7e4ad74326eb3ce0..bbca641c1b641c8d6013f0b8f5463be63acb08e2 100755 (executable)
--- a/configure
+++ b/configure
@@ -20240,8 +20240,8 @@ if test "$with_dlopen" = "yes"; then :
   case $host in #(
   *-linux*|*-gnu*) :
 
+                LDFLAGS="${LDFLAGS} -Wl,--export-dynamic"
                 SO_CFLAGS="-fPIC"
-                 LDFLAGS="${LDFLAGS} -Wl,--export-dynamic"
                 SO_LDFLAGS=""
                 if test "$use_libtool" = "yes"; then :
 
index d831bae619e82b6f00e7932f98c8f43a28ac3620..af7f90cead8671de661b7791a7c4a3b9282a20a2 100644 (file)
@@ -2638,8 +2638,8 @@ AS_CASE([$with_dlopen],
 AS_IF([test "$with_dlopen" = "yes"],
       [AS_CASE([$host],
               [*-linux*|*-gnu*],[
+                LDFLAGS="${LDFLAGS} -Wl,--export-dynamic"
                 SO_CFLAGS="-fPIC"
-                 LDFLAGS="${LDFLAGS} -Wl,--export-dynamic"
                 SO_LDFLAGS=""
                 AS_IF([test "$use_libtool" = "yes"],[
                         SO_LDFLAGS="-Xcompiler -shared"
index 2e6c0183da7f3bb97ff1ec5aa3610a76c6a1ce68..ede65f8674d6d85bdb9081f2a1d2aa2387b65d92 100644 (file)
@@ -53,8 +53,12 @@ SRCS =               client.c hooks.c interfacemgr.c lib.c listenlist.c \
                update.c version.c xfrout.c
 
 SUBDIRS =      include
-TARGETS =      timestamp
 TESTDIRS =     @UNITTESTS@
+SO_TARGETS =    filter-aaaa.@SO@
+TARGETS =      timestamp @SO_TARGETS@
+
+SO_CFLAGS =    @CFLAGS@ @SO_CFLAGS@
+SO_LDFLAGS =   @LDFLAGS@ @SO_LDFLAGS@
 
 @BIND9_MAKE_RULES@
 
@@ -80,6 +84,14 @@ libns.la: ${OBJS}
 timestamp: libns.@A@
        touch timestamp
 
+filter-aaaa.@O@: filter-aaaa.c
+       ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} ${SO_CFLAGS} \
+               -c ${srcdir}/filter-aaaa.c
+
+filter-aaaa.@SO@: filter-aaaa.o libns.@A@
+       ${LIBTOOL_MODE_LINK} @SO_LD@ ${SO_LDFLAGS} -o $@ filter-aaaa.o \
+               ${ISCLIBS} ${DNSLIBS} libns.@A@ ${ISCLIBS} @DNS_CRYPTO_LIBS@ ${DNSLIBS} ${LIBS}
+
 installdirs:
        $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir}
 
@@ -91,4 +103,4 @@ uninstall::
        ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${libdir}/libns.@A@
 
 clean distclean::
-       rm -f libns.@A@ timestamp
+       rm -f libns.@A@ timestamp filter-aaaa.@O@ filter-aaaa.@SO@
diff --git a/lib/ns/filter-aaaa.c b/lib/ns/filter-aaaa.c
new file mode 100644 (file)
index 0000000..a0e8141
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <isc/hash.h>
+#include <isc/lib.h>
+#include <isc/mem.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include <dns/result.h>
+#include <dns/view.h>
+
+#include <ns/client.h>
+#include <ns/hooks.h>
+#include <ns/log.h>
+#include <ns/query.h>
+
+ns_hook_destroy_t hook_destroy;
+ns_hook_register_t hook_register;
+ns_hook_version_t hook_version;
+
+/*
+ * 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 */
+
+
+/*% Want DNSSEC? */
+#define WANTDNSSEC(c)          (((c)->attributes & \
+                                 NS_CLIENTATTR_WANTDNSSEC) != 0)
+/*% Recursion OK? */
+#define RECURSIONOK(c)         (((c)->query.attributes & \
+                                 NS_QUERYATTR_RECURSIONOK) != 0)
+
+static bool
+filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp);
+
+static bool
+filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp);
+
+static bool
+filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp);
+
+static bool
+filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp);
+
+ns_hook_t filter_respbegin = {
+       .callback = filter_respond_begin,
+};
+ns_hook_t filter_respanyfound = {
+       .callback = filter_respond_any_found,
+};
+ns_hook_t filter_prepresp = {
+       .callback = filter_prep_response_begin,
+};
+ns_hook_t filter_donesend = {
+       .callback = filter_query_done_send,
+};
+
+isc_result_t
+hook_register(const char *parameters, const char *file, unsigned long line,
+             ns_hookctx_t *hctx, ns_hooktable_t *hooktable, void **instp)
+{
+       UNUSED(parameters);
+       UNUSED(instp);
+
+       isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL,
+                     NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
+                     "loading params for 'filter-aaaa' module from %s:%lu",
+                     file, line);
+
+       /*
+        * TODO:
+        * configure with parameters here
+        */
+
+       ns_hook_add(hooktable, NS_QUERY_RESPOND_BEGIN,
+                   &filter_respbegin);
+       ns_hook_add(hooktable, NS_QUERY_RESPOND_ANY_FOUND,
+                   &filter_respanyfound);
+       ns_hook_add(hooktable, NS_QUERY_PREP_RESPONSE_BEGIN,
+                   &filter_prepresp);
+       ns_hook_add(hooktable, NS_QUERY_DONE_SEND,
+                   &filter_donesend);
+
+       /*
+        * TODO:
+        * Set up a serial number that can be used for accessing
+        * data blobs in qctx, client, view;
+        * return an instance pointer for later destruction
+        */
+       return (ISC_R_SUCCESS);
+}
+
+void
+hook_destroy(void **instp) {
+       UNUSED(instp);
+
+       return;
+}
+
+int
+hook_version(unsigned int *flags) {
+       UNUSED(flags);
+
+       return (NS_HOOK_VERSION);
+}
+
+/*
+ * Check whether this is a V4 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 a V6 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);
+}
+
+/*
+ * The filter-aaaa-on-v4 option suppresses AAAAs for IPv4
+ * clients if there is an A; filter-aaaa-on-v6 option does
+ * the same for IPv6 clients.
+ */
+static bool
+filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp) {
+       query_ctx_t *qctx = (query_ctx_t *) hookdata;
+       isc_result_t result;
+
+       UNUSED(cbdata);
+
+       qctx->filter_aaaa = dns_aaaa_ok;
+       if (qctx->client->view->v4_aaaa != dns_aaaa_ok ||
+           qctx->client->view->v6_aaaa != dns_aaaa_ok)
+       {
+               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->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->filter_aaaa = qctx->client->view->v6_aaaa;
+               }
+       }
+
+       *resp = ISC_R_UNSET;
+       return (false);
+}
+
+/*
+ * Optionally hide AAAA rrsets if there is a matching A.
+ * (This version is for processing answers to explicit AAAA
+ * queries; ANY queries are handled in query_filter_aaaa_any().)
+ */
+static bool
+filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) {
+       query_ctx_t *qctx = (query_ctx_t *) hookdata;
+       isc_result_t result = ISC_R_UNSET;
+
+       UNUSED(cbdata);
+
+       if (qctx->filter_aaaa != dns_aaaa_break_dnssec &&
+           (qctx->filter_aaaa != dns_aaaa_filter ||
+            (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL &&
+             dns_rdataset_isassociated(qctx->sigrdataset))))
+       {
+               *resp = result;
+               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) {
+                       qctx->rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
+                       if (qctx->sigrdataset != NULL &&
+                           dns_rdataset_isassociated(qctx->sigrdataset))
+                       {
+                               qctx->sigrdataset->attributes |=
+                                       DNS_RDATASETATTR_RENDERED;
+                       }
+                       qctx->client->hookflags |= FILTER_AAAA_FILTERED;
+               } else if (!qctx->authoritative &&
+                          RECURSIONOK(qctx->client) &&
+                          (result == DNS_R_DELEGATION ||
+                           result == ISC_R_NOTFOUND))
+               {
+                       /*
+                        * This is an ugly kludge to recurse
+                        * for the A and discard the result.
+                        *
+                        * Continue to add the AAAA now.
+                        * We'll make a note to not render it
+                        * if the recursion for the A succeeds.
+                        */
+                       result = ns_query_recurse(qctx->client,
+                                                 dns_rdatatype_a,
+                                                 qctx->client->query.qname,
+                                                 NULL, NULL, qctx->resuming);
+                       if (result == ISC_R_SUCCESS) {
+                               qctx->client->hookflags |=
+                                       FILTER_AAAA_RECURSING;
+                               qctx->client->query.attributes |=
+                                       NS_QUERYATTR_RECURSING;
+                       }
+               }
+       } else if (qctx->qtype == dns_rdatatype_a &&
+                  ((qctx->client->hookflags & FILTER_AAAA_RECURSING) != 0))
+       {
+
+               dns_rdataset_t *mrdataset = NULL;
+               dns_rdataset_t *sigrdataset = NULL;
+
+               result = dns_message_findname(qctx->client->message,
+                                             DNS_SECTION_ANSWER, qctx->fname,
+                                             dns_rdatatype_aaaa, 0,
+                                             NULL, &mrdataset);
+               if (result == ISC_R_SUCCESS) {
+                       mrdataset->attributes |= DNS_RDATASETATTR_RENDERED;
+               }
+
+               result = dns_message_findname(qctx->client->message,
+                                             DNS_SECTION_ANSWER, qctx->fname,
+                                             dns_rdatatype_rrsig,
+                                             dns_rdatatype_aaaa,
+                                             NULL, &sigrdataset);
+               if (result == ISC_R_SUCCESS) {
+                       sigrdataset->attributes |= DNS_RDATASETATTR_RENDERED;
+               }
+
+               qctx->client->hookflags &= ~FILTER_AAAA_RECURSING;
+
+               result = ns_query_done(qctx);
+
+               *resp = result;
+               return (true);
+
+       }
+
+       *resp = result;
+       return (false);
+}
+
+static bool
+filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) {
+       query_ctx_t *qctx = (query_ctx_t *) hookdata;
+       dns_name_t *name = NULL;
+       dns_rdataset_t *aaaa = NULL, *aaaa_sig = NULL;
+       dns_rdataset_t *a = NULL;
+       bool have_a = true;
+
+       UNUSED(cbdata);
+
+       if (qctx->filter_aaaa == dns_aaaa_ok) {
+               *resp = ISC_R_UNSET;
+               return (false);
+       }
+
+       dns_message_findname(qctx->client->message, DNS_SECTION_ANSWER,
+                            (qctx->fname != NULL)
+                             ? qctx->fname
+                             : qctx->tname,
+                            dns_rdatatype_any, 0, &name, NULL);
+
+       /*
+        * If we're not authoritative, just assume there's an
+        * A even if it wasn't in the cache and therefore isn't
+        * in the message.  But if we're authoritative, then
+        * if there was an A, it should be here.
+        */
+       if (qctx->authoritative && name != NULL) {
+               dns_message_findtype(name, dns_rdatatype_a, 0, &a);
+               if (a == NULL) {
+                       have_a = false;
+               }
+       }
+
+       if (name != NULL) {
+               dns_message_findtype(name, dns_rdatatype_aaaa, 0, &aaaa);
+               dns_message_findtype(name, dns_rdatatype_rrsig,
+                                    dns_rdatatype_aaaa, &aaaa_sig);
+       }
+
+       if (have_a && aaaa != NULL &&
+           (aaaa_sig == NULL || !WANTDNSSEC(qctx->client) ||
+            qctx->filter_aaaa == dns_aaaa_break_dnssec))
+       {
+               aaaa->attributes |= DNS_RDATASETATTR_RENDERED;
+               if (aaaa_sig != NULL) {
+                       aaaa_sig->attributes |= DNS_RDATASETATTR_RENDERED;
+               }
+       }
+
+       *resp = ISC_R_UNSET;
+       return (false);
+}
+
+/*
+ * Hide AAAA rrsets in the additional section if there is a matching A,
+ * and hide NS in the additional section if AAAA was filtered in the answer
+ * section.
+ */
+static bool
+filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) {
+       query_ctx_t *qctx = (query_ctx_t *) hookdata;
+       isc_result_t result;
+
+       UNUSED(cbdata);
+
+       if (qctx->filter_aaaa == dns_aaaa_ok) {
+               *resp = ISC_R_UNSET;
+               return (false);
+       }
+
+       result = dns_message_firstname(qctx->client->message,
+                                      DNS_SECTION_ADDITIONAL);
+       while (result == ISC_R_SUCCESS) {
+               dns_name_t *name = NULL;
+               dns_rdataset_t *aaaa = NULL, *aaaa_sig = NULL;
+               dns_rdataset_t *a = NULL;
+
+               dns_message_currentname(qctx->client->message,
+                                       DNS_SECTION_ADDITIONAL,
+                                       &name);
+
+               result = dns_message_nextname(qctx->client->message,
+                                             DNS_SECTION_ADDITIONAL);
+
+               dns_message_findtype(name, dns_rdatatype_a, 0, &a);
+               if (a == NULL) {
+                       continue;
+               }
+
+               dns_message_findtype(name, dns_rdatatype_aaaa, 0,
+                                    &aaaa);
+               if (aaaa == NULL) {
+                       continue;
+               }
+
+               dns_message_findtype(name, dns_rdatatype_rrsig,
+                                    dns_rdatatype_aaaa, &aaaa_sig);
+
+               if (aaaa_sig == NULL || !WANTDNSSEC(qctx->client) ||
+                    qctx->filter_aaaa == dns_aaaa_break_dnssec)
+               {
+                       aaaa->attributes |= DNS_RDATASETATTR_RENDERED;
+                       if (aaaa_sig != NULL) {
+                               aaaa_sig->attributes |=
+                                       DNS_RDATASETATTR_RENDERED;
+                       }
+               }
+       }
+
+       if ((qctx->client->hookflags & FILTER_AAAA_FILTERED) != 0) {
+               result = dns_message_firstname(qctx->client->message,
+                                              DNS_SECTION_AUTHORITY);
+               while (result == ISC_R_SUCCESS) {
+                       dns_name_t *name = NULL;
+                       dns_rdataset_t *ns = NULL, *ns_sig = NULL;
+
+                       dns_message_currentname(qctx->client->message,
+                                               DNS_SECTION_AUTHORITY,
+                                               &name);
+
+                       result = dns_message_findtype(name, dns_rdatatype_ns,
+                                                     0, &ns);
+                       if (result == ISC_R_SUCCESS) {
+                               ns->attributes |= DNS_RDATASETATTR_RENDERED;
+                       }
+
+                       result = dns_message_findtype(name, dns_rdatatype_rrsig,
+                                                     dns_rdatatype_ns,
+                                                     &ns_sig);
+                       if (result == ISC_R_SUCCESS) {
+                               ns_sig->attributes |= DNS_RDATASETATTR_RENDERED;
+                       }
+
+                       result = dns_message_nextname(qctx->client->message,
+                                                     DNS_SECTION_AUTHORITY);
+               }
+       }
+
+       *resp = ISC_R_UNSET;
+       return (false);
+}
index 4b97c5b3d5ffe7ff95b8c2f99d07d08430513ae7..66438f6604f72e01176e8d2c1792057c1abfd1af 100644 (file)
@@ -42,7 +42,6 @@ struct ns_hook_module {
        char                            *filename;
        ns_hook_register_t              *register_func;
        ns_hook_destroy_t               *destroy_func;
-       char                            *name;
        void                            *inst;
        LINK(ns_hook_module_t)          link;
 };
@@ -108,11 +107,6 @@ load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) {
 
        REQUIRE(hmodp != NULL && *hmodp == NULL);
 
-       isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
-                     NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
-                     "loading module '%s'",
-                     filename);
-
        flags = RTLD_NOW|RTLD_LOCAL;
 #ifdef RTLD_DEEPBIND
        flags |= RTLD_DEEPBIND;
@@ -140,16 +134,12 @@ load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) {
                CHECK(ISC_R_FAILURE);
        }
 
-       CHECK(load_symbol(handle, filename, "hook_init",
+       CHECK(load_symbol(handle, filename, "hook_register",
                          (void **)&register_func));
        CHECK(load_symbol(handle, filename, "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;
@@ -200,7 +190,7 @@ unload_library(ns_hook_module_t **hmodp) {
                isc_mem_free(hmod->mctx, hmod->filename);
        }
 
-       isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(ns_hook_module_t));
+       isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod));
 }
 #elif _WIN32
 static isc_result_t
@@ -240,10 +230,6 @@ load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) {
 
        REQUIRE(hmodp != NULL && *hmodp == NULL);
 
-       isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
-                     NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
-                     "loading module '%s'", filename);
-
        handle = LoadLibraryA(filename);
        if (handle == NULL) {
                CHECK(ISC_R_FAILURE);
@@ -263,16 +249,12 @@ load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) {
                CHECK(ISC_R_FAILURE);
        }
 
-       CHECK(load_symbol(handle, filename, "hook_init",
+       CHECK(load_symbol(handle, filename, "hook_register",
                          (void **)&register_func));
        CHECK(load_symbol(handle, filename, "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;
@@ -347,21 +329,25 @@ unload_library(ns_hook_module_t **hmodp) {
 
 isc_result_t
 ns_hookmodule_load(const char *libname, const char *parameters,
-                  const char *file, unsigned long line, isc_mem_t *mctx)
+                  const char *file, unsigned long line,
+                  ns_hookctx_t *hctx, ns_hooktable_t *hooktable)
 {
        isc_result_t result;
        ns_hook_module_t *module = NULL;
 
-       RUNTIME_CHECK(isc_once_do(&once, init_modules) == ISC_R_SUCCESS);
+       if (hooktable == NULL) {
+               hooktable = ns__hook_table;
+       }
+
+       REQUIRE(NS_HOOKCTX_VALID(hctx));
 
        isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
                      NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
                      "loading module '%s'", libname);
 
-       CHECK(load_library(mctx, libname, &module));
-       CHECK(module->register_func(mctx, parameters, file, line,
-                                   &module->inst));
-
+       CHECK(load_library(hctx->mctx, libname, &module));
+       CHECK(module->register_func(parameters, file, line, hctx,
+                                   hooktable, &module->inst));
 
        APPEND(hook_modules, module, link);
        result = ISC_R_SUCCESS;
@@ -386,7 +372,7 @@ ns_hookmodule_cleanup(void) {
                UNLINK(hook_modules, hmod, link);
                isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL,
                              NS_LOGMODULE_HOOKS, ISC_LOG_INFO,
-                             "unloading module '%s'", hmod->name);
+                             "unloading module '%s'", hmod->filename);
                hmod->destroy_func(&hmod->inst);
                ENSURE(hmod->inst == NULL);
                unload_library(&hmod);
@@ -394,6 +380,40 @@ ns_hookmodule_cleanup(void) {
        }
 }
 
+isc_result_t
+ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp) {
+       ns_hookctx_t *hctx;
+
+       REQUIRE(hctxp != NULL && *hctxp == NULL);
+
+       hctx = isc_mem_get(mctx, sizeof(*hctx));
+       memset(hctx, 0, sizeof(*hctx));
+       hctx->lctx = ns_lctx;
+
+       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;
+
+       REQUIRE(hctxp != NULL && NS_HOOKCTX_VALID(*hctxp));
+
+       hctx = *hctxp;
+       *hctxp = NULL;
+
+       hctx->magic = 0;
+
+       hctx->lctx = NULL;
+
+       isc_mem_putanddetach(&hctx->mctx, hctx, sizeof(*hctx));
+}
+
 void
 ns_hooktable_init(ns_hooktable_t *hooktable) {
        int i;
index aa6d8d1548bb853a5d6aceec9d4639db3abd5193..3001661a43cda6358a1871837ede6d177651c2ee 100644 (file)
 #include <stdbool.h>
 
 #include <isc/list.h>
+#include <isc/magic.h>
 #include <isc/result.h>
 
+#include <dns/rdatatype.h>
+
+#include <ns/client.h>
+#include <ns/query.h>
 /*
  * Hooks 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:
@@ -185,6 +190,38 @@ typedef enum {
 typedef bool
 (*ns_hook_cb_t)(void *hook_data, void *callback_data, isc_result_t *resultp);
 
+typedef struct ns_hook {
+       ns_hook_cb_t callback;
+       void *callback_data;
+       ISC_LINK(struct ns_hook) link;
+} ns_hook_t;
+
+/*
+ * ns__hook_table is a globally visible pointer to the active hook
+ * table. It's initialized to point to 'hooktab', which is the default
+ * global hook table.
+ */
+typedef ISC_LIST(ns_hook_t) ns_hooklist_t;
+typedef ns_hooklist_t ns_hooktable_t[NS_QUERY_HOOKS_COUNT];
+LIBNS_EXTERNAL_DATA extern ns_hooktable_t *ns__hook_table;
+
+/*!
+ * Context for intializing 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;
+       isc_mem_t               *mctx;
+       isc_log_t               *lctx;
+} ns_hookctx_t;
+
+#define NS_HOOKCTX_MAGIC       ISC_MAGIC('H', 'k', 'c', 'x')
+#define NS_HOOKCTX_VALID(d)    ISC_MAGIC_VALID(d, NS_HOOKCTX_MAGIC)
 /*
  * API version
  *
@@ -198,10 +235,11 @@ typedef bool
 #define NS_HOOK_AGE 0
 #endif
 
-typedef isc_result_t ns_hook_register_t(isc_mem_t *mctx,
-                                       const char *parameters,
+typedef isc_result_t ns_hook_register_t(const char *parameters,
                                        const char *file,
                                        unsigned long line,
+                                       ns_hookctx_t *hctx,
+                                       ns_hooktable_t *hooktable,
                                        void **instp);
 /*%
  * Called when registering a new module.
@@ -236,21 +274,6 @@ typedef int ns_hook_version_t(unsigned int *flags);
  * the future to pass back driver capabilities or other information.
  */
 
-typedef struct ns_hook {
-       ns_hook_cb_t callback;
-       void *callback_data;
-       ISC_LINK(struct ns_hook) link;
-} ns_hook_t;
-
-/*
- * ns__hook_table is a globally visible pointer to the active hook
- * table. It's initialized to point to 'hooktab', which is the default
- * global hook table.
- */
-typedef ISC_LIST(ns_hook_t) ns_hooklist_t;
-typedef ns_hooklist_t ns_hooktable_t[NS_QUERY_HOOKS_COUNT];
-LIBNS_EXTERNAL_DATA extern ns_hooktable_t *ns__hook_table;
-
 /*
  * Run a hook. Calls the function or functions registered at hookpoint 'id'.
  * If one of them returns true, we interrupt processing and return the
@@ -280,9 +303,16 @@ LIBNS_EXTERNAL_DATA extern ns_hooktable_t *ns__hook_table;
 #define NS_PROCESS_HOOK_VOID(table, id, data) \
        _NS_PROCESS_HOOK(table, id, data)
 
+isc_result_t
+ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp);
+
+void
+ns_hook_destroyctx(ns_hookctx_t **hctxp);
+
 isc_result_t
 ns_hookmodule_load(const char *libname, const char *parameters,
-                  const char *file, unsigned long line, isc_mem_t *mctx);
+                  const char *file, unsigned long line,
+                  ns_hookctx_t *hctx, ns_hooktable_t *hooktable);
 void
 ns_hookmodule_cleanup(void);
 
index ad59b2b48c20753c66d4fc3e589b6fe8e57e5497..853c7e5a90f1d8fe8074955984a596949b5e58dc 100644 (file)
@@ -98,27 +98,28 @@ struct ns_query {
        bool root_key_sentinel_not_ta;
 };
 
-#define NS_QUERYATTR_RECURSIONOK       0x0001
-#define NS_QUERYATTR_CACHEOK           0x0002
-#define NS_QUERYATTR_PARTIALANSWER     0x0004
-#define NS_QUERYATTR_NAMEBUFUSED       0x0008
-#define NS_QUERYATTR_RECURSING         0x0010
-#define NS_QUERYATTR_QUERYOKVALID      0x0040
-#define NS_QUERYATTR_QUERYOK           0x0080
-#define NS_QUERYATTR_WANTRECURSION     0x0100
-#define NS_QUERYATTR_SECURE            0x0200
-#define NS_QUERYATTR_NOAUTHORITY       0x0400
-#define NS_QUERYATTR_NOADDITIONAL      0x0800
-#define NS_QUERYATTR_CACHEACLOKVALID   0x1000
-#define NS_QUERYATTR_CACHEACLOK                0x2000
-#define NS_QUERYATTR_DNS64             0x4000
-#define NS_QUERYATTR_DNS64EXCLUDE      0x8000
+#define NS_QUERYATTR_RECURSIONOK       0x00001
+#define NS_QUERYATTR_CACHEOK           0x00002
+#define NS_QUERYATTR_PARTIALANSWER     0x00004
+#define NS_QUERYATTR_NAMEBUFUSED       0x00008
+#define NS_QUERYATTR_RECURSING         0x00010
+#define NS_QUERYATTR_QUERYOKVALID      0x00040
+#define NS_QUERYATTR_QUERYOK           0x00080
+#define NS_QUERYATTR_WANTRECURSION     0x00100
+#define NS_QUERYATTR_SECURE            0x00200
+#define NS_QUERYATTR_NOAUTHORITY       0x00400
+#define NS_QUERYATTR_NOADDITIONAL      0x00800
+#define NS_QUERYATTR_CACHEACLOKVALID   0x01000
+#define NS_QUERYATTR_CACHEACLOK                0x02000
+#define NS_QUERYATTR_DNS64             0x04000
+#define NS_QUERYATTR_DNS64EXCLUDE      0x08000
 #define NS_QUERYATTR_RRL_CHECKED       0x10000
 #define NS_QUERYATTR_REDIRECT          0x20000
 
-/* query context structure */
+typedef struct query_ctx query_ctx_t;
 
-typedef struct query_ctx {
+/* query context structure */
+struct query_ctx {
        isc_buffer_t *dbuf;                     /* name buffer */
        dns_name_t *fname;                      /* found name from DB lookup */
        dns_name_t *tname;                      /* temporary name, used
@@ -169,7 +170,7 @@ typedef struct query_ctx {
 
        isc_result_t result;                    /* query result */
        int line;                               /* line to report error */
-} query_ctx_t;
+};
 
 /*
  * The following functions are expected to be used only within query.c
@@ -212,24 +213,53 @@ ns_query_start(ns_client_t *client);
 void
 ns_query_cancel(ns_client_t *client);
 
-/*%
- * (Must not be used outside this module and its associated unit tests.)
+/*
+ * The following functions are expected to be used only within query.c
+ * and query modules.
  */
+
 isc_result_t
-ns__query_sfcache(query_ctx_t *qctx);
+ns_query_done(query_ctx_t *qctx);
+/*%<
+ * Finalize this phase of the query process:
+ *
+ * - Clean up.
+ * - If we have an answer ready (positive or negative), send it.
+ * - If we need to restart for a chaining query, call ns__query_start() again.
+ * - If we've started recursion, then just clean up; things will be
+ *   restarted via fetch_callback()/query_resume().
+ */
+
+isc_result_t
+ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
+                dns_name_t *qdomain, dns_rdataset_t *nameservers,
+                bool resuming);
+/*%<
+ * Prepare client for recursion, then create a resolver fetch, with
+ * the event callback set to fetch_callback(). Afterward we terminate
+ * this phase of the query, and resume with a new query context when
+ * recursion completes.
+ */
+
 
+isc_result_t
+ns__query_sfcache(query_ctx_t *qctx);
 /*%
  * (Must not be used outside this module and its associated unit tests.)
  */
+
 isc_result_t
 ns__query_start(query_ctx_t *qctx);
+/*%
+ * (Must not be used outside this module and its associated unit tests.)
+ */
 
+void
+ns__query_inithooks(void);
 /*
  * XXX:
  * Temporary function used to initialize the filter-aaaa hooks,
  * which are currently hard-coded rather than loaded as a module.
  */
-void
-ns__query_inithooks(void);
 
 #endif /* NS_QUERY_H */
index 104ef4d7cf79ce2c28bbb3a02210180fe5fbaa83..93e1d8fdf44661da219c97ea8bb0c18e71b9d2d5 100644 (file)
@@ -420,47 +420,6 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata);
 static void
 query_addauth(query_ctx_t *qctx);
 
-/*
- * XXX:
- * This is a temporary hooks table, pre-populated with functions
- * implementing filter-aaaa. Later, this will be redesigned to be set up at
- * initialization time when the filter-aaaa module is loaded.
- *
- * To activate this hooks table at runtime, call ns__query_inithooks().
- */
-static bool
-filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp);
-
-static bool
-filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp);
-
-static bool
-filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp);
-
-static bool
-filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp);
-
-ns_hook_t filter_respbegin = {
-       .callback = filter_respond_begin,
-       .callback_data = NULL,
-       .link = { (void *) -1, (void *) -1 },
-};
-ns_hook_t filter_respanyfound = {
-       .callback = filter_respond_any_found,
-       .callback_data = NULL,
-       .link = { (void *) -1, (void *) -1 },
-};
-ns_hook_t filter_prepresp = {
-       .callback = filter_prep_response_begin,
-       .callback_data = NULL,
-       .link = { (void *) -1, (void *) -1 },
-};
-ns_hook_t filter_donesend = {
-       .callback = filter_query_done_send,
-       .callback_data = NULL,
-       .link = { (void *) -1, (void *) -1 },
-};
-
 /*%
  * Increment query statistics counters.
  */
@@ -4443,24 +4402,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;
@@ -5549,12 +5490,6 @@ 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
- * this phase of the query, and resume with a new query context when
- * recursion completes.
- */
 isc_result_t
 ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
                 dns_name_t *qdomain, dns_rdataset_t *nameservers,
@@ -6555,8 +6490,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 (ns_query_done(qctx));
+               }
        }
 
        /*
@@ -6875,6 +6811,7 @@ query_respond_any(query_ctx_t *qctx) {
                CCTRACE(ISC_LOG_ERROR,
                       "query_respond_any: rdataset iterator failed");
                QUERY_ERROR(qctx, DNS_R_SERVFAIL);
+               return (ns_query_done(qctx));
        }
 
        if (found) {
@@ -7787,7 +7724,7 @@ query_delegation(query_ctx_t *qctx) {
                if (dns_rdatatype_atparent(qctx->type)) {
                        /*
                         * Parent is recursive for this rdata
-                        * type (i.e., DS)
+                        * type (i.e., DS).
                         */
                        result = ns_query_recurse(qctx->client,
                                                  qctx->qtype, qname,
@@ -7796,7 +7733,7 @@ query_delegation(query_ctx_t *qctx) {
                } else if (qctx->dns64) {
                        /*
                         * Look up an A record so we can
-                        * synthesize DNS64
+                        * synthesize DNS64.
                         */
                        result = ns_query_recurse(qctx->client,
                                                  dns_rdatatype_a, qname,
@@ -7804,7 +7741,7 @@ query_delegation(query_ctx_t *qctx) {
                                                  qctx->resuming);
                } else {
                        /*
-                        * Any other recursion
+                        * Any other recursion.
                         */
                        result = ns_query_recurse(qctx->client,
                                                  qctx->qtype, qname,
@@ -10905,326 +10842,3 @@ ns_query_start(ns_client_t *client) {
        ns_client_attach(client, &qclient);
        (void)query_setup(qclient, qtype);
 }
-
-/*
- * 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 */
-
-/*
- * The filter-aaaa-on-v4 option suppresses AAAAs for IPv4
- * clients if there is an A; filter-aaaa-on-v6 option does
- * the same for IPv6 clients.
- */
-static bool
-filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp) {
-       query_ctx_t *qctx = (query_ctx_t *) hookdata;
-       isc_result_t result;
-
-       UNUSED(cbdata);
-
-       qctx->filter_aaaa = dns_aaaa_ok;
-       if (qctx->client->view->v4_aaaa != dns_aaaa_ok ||
-           qctx->client->view->v6_aaaa != dns_aaaa_ok)
-       {
-               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->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->filter_aaaa = qctx->client->view->v6_aaaa;
-               }
-       }
-
-       *resp = ISC_R_UNSET;
-       return (false);
-}
-
-/*
- * Optionally hide AAAA rrsets if there is a matching A.
- * (This version is for processing answers to explicit AAAA
- * queries; ANY queries are handled in query_filter_aaaa_any().)
- */
-static bool
-filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) {
-       query_ctx_t *qctx = (query_ctx_t *) hookdata;
-       isc_result_t result = ISC_R_UNSET;
-
-       UNUSED(cbdata);
-
-       if (qctx->filter_aaaa != dns_aaaa_break_dnssec &&
-           (qctx->filter_aaaa != dns_aaaa_filter ||
-            (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL &&
-             dns_rdataset_isassociated(qctx->sigrdataset))))
-       {
-               *resp = result;
-               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) {
-                       qctx->rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
-                       if (qctx->sigrdataset != NULL &&
-                           dns_rdataset_isassociated(qctx->sigrdataset))
-                       {
-                               qctx->sigrdataset->attributes |=
-                                       DNS_RDATASETATTR_RENDERED;
-                       }
-                       qctx->client->hookflags |= 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.
-                        */
-                       INSIST(!REDIRECT(qctx->client));
-                       result = ns_query_recurse(qctx->client,
-                                                 dns_rdatatype_a,
-                                                 qctx->client->query.qname,
-                                                 NULL, NULL, qctx->resuming);
-                       if (result == ISC_R_SUCCESS) {
-                               qctx->client->hookflags |=
-                                       FILTER_AAAA_RECURSING;
-                               qctx->client->query.attributes |=
-                                       NS_QUERYATTR_RECURSING;
-                       }
-               }
-       } else if (qctx->qtype == dns_rdatatype_a &&
-                  ((qctx->client->hookflags & FILTER_AAAA_RECURSING) != 0))
-       {
-
-               dns_rdataset_t *mrdataset = NULL;
-               dns_rdataset_t *sigrdataset = NULL;
-
-               result = dns_message_findname(qctx->client->message,
-                                             DNS_SECTION_ANSWER, qctx->fname,
-                                             dns_rdatatype_aaaa, 0,
-                                             NULL, &mrdataset);
-               if (result == ISC_R_SUCCESS) {
-                       mrdataset->attributes |= DNS_RDATASETATTR_RENDERED;
-               }
-
-               result = dns_message_findname(qctx->client->message,
-                                             DNS_SECTION_ANSWER, qctx->fname,
-                                             dns_rdatatype_rrsig,
-                                             dns_rdatatype_aaaa,
-                                             NULL, &sigrdataset);
-               if (result == ISC_R_SUCCESS) {
-                       sigrdataset->attributes |= DNS_RDATASETATTR_RENDERED;
-               }
-
-               qctx->client->hookflags &= ~FILTER_AAAA_RECURSING;
-
-               result = ns_query_done(qctx);
-
-               *resp = result;
-               return (true);
-
-       }
-
-       *resp = result;
-       return (false);
-}
-
-static bool
-filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) {
-       query_ctx_t *qctx = (query_ctx_t *) hookdata;
-       dns_name_t *name = NULL;
-       dns_rdataset_t *aaaa = NULL, *aaaa_sig = NULL;
-       dns_rdataset_t *a = NULL;
-       bool have_a = true;
-
-       UNUSED(cbdata);
-
-       if (qctx->filter_aaaa == dns_aaaa_ok) {
-               *resp = ISC_R_UNSET;
-               return (false);
-       }
-
-       dns_message_findname(qctx->client->message, DNS_SECTION_ANSWER,
-                            (qctx->fname != NULL)
-                             ? qctx->fname
-                             : qctx->tname,
-                            dns_rdatatype_any, 0, &name, NULL);
-
-       /*
-        * If we're not authoritative, just assume there's an
-        * A even if it wasn't in the cache and therefore isn't
-        * in the message.  But if we're authoritative, then
-        * if there was an A, it should be here.
-        */
-       if (qctx->authoritative && name != NULL) {
-               dns_message_findtype(name, dns_rdatatype_a, 0, &a);
-               if (a == NULL) {
-                       have_a = false;
-               }
-       }
-
-       if (name != NULL) {
-               dns_message_findtype(name, dns_rdatatype_aaaa, 0, &aaaa);
-               dns_message_findtype(name, dns_rdatatype_rrsig,
-                                    dns_rdatatype_aaaa, &aaaa_sig);
-       }
-
-       if (have_a && aaaa != NULL &&
-           (aaaa_sig == NULL || !WANTDNSSEC(qctx->client) ||
-            qctx->filter_aaaa == dns_aaaa_break_dnssec))
-       {
-               aaaa->attributes |= DNS_RDATASETATTR_RENDERED;
-               if (aaaa_sig != NULL) {
-                       aaaa_sig->attributes |= DNS_RDATASETATTR_RENDERED;
-               }
-       }
-
-       *resp = ISC_R_UNSET;
-       return (false);
-}
-
-/*
- * Hide AAAA rrsets in the additional section if there is a matching A,
- * and hide NS in the additional section if AAAA was filtered in the answer
- * section.
- */
-static bool
-filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) {
-       query_ctx_t *qctx = (query_ctx_t *) hookdata;
-       isc_result_t result;
-
-       UNUSED(cbdata);
-
-       if (qctx->filter_aaaa == dns_aaaa_ok) {
-               *resp = ISC_R_UNSET;
-               return (false);
-       }
-
-       result = dns_message_firstname(qctx->client->message,
-                                      DNS_SECTION_ADDITIONAL);
-       while (result == ISC_R_SUCCESS) {
-               dns_name_t *name = NULL;
-               dns_rdataset_t *aaaa = NULL, *aaaa_sig = NULL;
-               dns_rdataset_t *a = NULL;
-
-               dns_message_currentname(qctx->client->message,
-                                       DNS_SECTION_ADDITIONAL,
-                                       &name);
-
-               result = dns_message_nextname(qctx->client->message,
-                                             DNS_SECTION_ADDITIONAL);
-
-               dns_message_findtype(name, dns_rdatatype_a, 0, &a);
-               if (a == NULL) {
-                       continue;
-               }
-
-               dns_message_findtype(name, dns_rdatatype_aaaa, 0,
-                                    &aaaa);
-               if (aaaa == NULL) {
-                       continue;
-               }
-
-               dns_message_findtype(name, dns_rdatatype_rrsig,
-                                    dns_rdatatype_aaaa, &aaaa_sig);
-
-               if (aaaa_sig == NULL || !WANTDNSSEC(qctx->client) ||
-                    qctx->filter_aaaa == dns_aaaa_break_dnssec)
-               {
-                       aaaa->attributes |= DNS_RDATASETATTR_RENDERED;
-                       if (aaaa_sig != NULL) {
-                               aaaa_sig->attributes |=
-                                       DNS_RDATASETATTR_RENDERED;
-                       }
-               }
-       }
-
-       if ((qctx->client->hookflags & FILTER_AAAA_FILTERED) != 0) {
-               result = dns_message_firstname(qctx->client->message,
-                                              DNS_SECTION_AUTHORITY);
-               while (result == ISC_R_SUCCESS) {
-                       dns_name_t *name = NULL;
-                       dns_rdataset_t *ns = NULL, *ns_sig = NULL;
-
-                       dns_message_currentname(qctx->client->message,
-                                               DNS_SECTION_AUTHORITY,
-                                               &name);
-
-                       result = dns_message_findtype(name, dns_rdatatype_ns,
-                                                     0, &ns);
-                       if (result == ISC_R_SUCCESS) {
-                               ns->attributes |= DNS_RDATASETATTR_RENDERED;
-                       }
-
-                       result = dns_message_findtype(name, dns_rdatatype_rrsig,
-                                                     dns_rdatatype_ns,
-                                                     &ns_sig);
-                       if (result == ISC_R_SUCCESS) {
-                               ns_sig->attributes |= DNS_RDATASETATTR_RENDERED;
-                       }
-
-                       result = dns_message_nextname(qctx->client->message,
-                                                     DNS_SECTION_AUTHORITY);
-               }
-       }
-
-       *resp = ISC_R_UNSET;
-       return (false);
-}
-
-void
-ns__query_inithooks() {
-       /*
-        * XXX: This function is temporary.  Later, the hook table
-        * will be set up when initializing hook modules after
-        * configuring the server.
-        *
-        * For now, however, we just call this once when initializing named
-        * and it will set up all the filter-aaaa hooks.
-        */
-
-       ns_hooktable_init(NULL);
-       ns_hook_add(NULL, NS_QUERY_RESPOND_BEGIN, &filter_respbegin);
-       ns_hook_add(NULL, NS_QUERY_RESPOND_ANY_FOUND, &filter_respanyfound);
-       ns_hook_add(NULL, NS_QUERY_PREP_RESPONSE_BEGIN, &filter_prepresp);
-       ns_hook_add(NULL, NS_QUERY_DONE_SEND, &filter_donesend);
-}
index fde2c459d5a2b948f56e21170d3da6c597248e45..a328ceebeb659e35492b170724242993f442f302 100644 (file)
@@ -108,11 +108,6 @@ ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview,
 
        ISC_LIST_INIT(sctx->altsecrets);
 
-       /*
-        * XXX: temporary.
-        */
-       ns__query_inithooks();
-
        sctx->magic = SCTX_MAGIC;
        *sctxp = sctx;
 
index 9918d505122a9805ee525c0bc41d09aa7c692cae..ab5efa25ddb21945bb983f0ed34e79da49cb9d40 100644 (file)
@@ -17,14 +17,23 @@ ns_client_checkaclsilent
 ns_client_detach
 ns_client_dumprecursing
 ns_client_error
-ns_client_getsockaddr
+ns_client_findversion
 ns_client_getdestaddr
+ns_client_getnamebuf
+ns_client_getsockaddr
+ns_client_keepname
 ns_client_killoldestquery
 ns_client_log
 ns_client_logv
+ns_client_newdbversion
+ns_client_newname
+ns_client_newnamebuf
+ns_client_newrdataset
 ns_client_next
+ns_client_putrdataset
 ns_client_qnamereplace
 ns_client_recursing
+ns_client_releasename
 ns_client_replace
 ns_client_send
 ns_client_sendraw
@@ -34,6 +43,16 @@ ns_client_sourceip
 ns_clientmgr_create
 ns_clientmgr_createclients
 ns_clientmgr_destroy
+ns_hook_add
+ns_hook_createctx
+ns_hook_destroyctx
+ns_hookmodule_cleanup
+ns_hookmodule_load
+ns_hooktable_create
+ns_hooktable_free
+ns_hooktable_init
+ns_hooktable_reset
+ns_hooktable_save
 ns_interface_attach
 ns_interface_detach
 ns_interface_shutdown