]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Implement asynchronous view matching for SIG(0)-signed queries
authorAram Sargsyan <aram@isc.org>
Wed, 8 May 2024 18:42:48 +0000 (18:42 +0000)
committerNicki Křížek <nicki@isc.org>
Mon, 10 Jun 2024 15:33:10 +0000 (17:33 +0200)
View matching on an incoming query checks the query's signature,
which can be a CPU-heavy task for a SIG(0)-signed message. Implement
an asynchronous mode of the view matching function which uses the
offloaded signature checking facilities, and use it for the incoming
queries.

bin/delv/delv.c
bin/named/server.c
lib/ns/client.c
lib/ns/include/ns/client.h
lib/ns/include/ns/server.h
tests/libtest/ns.c

index 5af7c15653b8320d0d538f748bc613be9e0ee0fb..ef078bed0953af218663983e62b63b5e3c9845f1 100644 (file)
@@ -2118,15 +2118,21 @@ cleanup:
 static isc_result_t
 matchview(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
          dns_message_t *message, dns_aclenv_t *env, ns_server_t *lsctx,
-         isc_result_t *sigresultp, dns_view_t **viewp) {
+         isc_loop_t *loop, isc_job_cb cb, void *cbarg,
+         isc_result_t *sigresultp, isc_result_t *viewpatchresultp,
+         dns_view_t **viewp) {
        UNUSED(srcaddr);
        UNUSED(destaddr);
        UNUSED(message);
        UNUSED(env);
        UNUSED(lsctx);
+       UNUSED(loop);
+       UNUSED(cb);
+       UNUSED(cbarg);
        UNUSED(sigresultp);
 
        *viewp = view;
+       *viewpatchresultp = ISC_R_SUCCESS;
        return (ISC_R_SUCCESS);
 }
 
index 6c4ed095ab483a7511a003222dafa95675319425..a4c326943202d3aff221b169cec753d5ccd2053c 100644 (file)
@@ -278,6 +278,26 @@ struct zonelistentry {
        ISC_LINK(struct zonelistentry) link;
 };
 
+/*%
+ * Message-to-view matching context to run message signature validation
+ * asynchronously.
+ */
+typedef struct matching_view_ctx {
+       isc_netaddr_t *srcaddr;
+       isc_netaddr_t *destaddr;
+       dns_message_t *message;
+       dns_aclenv_t *env;
+       ns_server_t *sctx;
+       isc_loop_t *loop;
+       isc_job_cb cb;
+       void *cbarg;
+       isc_result_t *sigresult;
+       isc_result_t *viewmatchresult;
+       isc_result_t quota_result;
+       dns_view_t **viewp;
+       dns_view_t *view;
+} matching_view_ctx_t;
+
 /*%
  * Configuration context to retain for each view that allows
  * new zones to be added at runtime.
@@ -10059,19 +10079,19 @@ shutdown_server(void *arg) {
        isc_loopmgr_resume(named_g_loopmgr);
 }
 
-/*%
- * Find a view that matches the source and destination addresses of a query.
- */
 static isc_result_t
-get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
-                 dns_message_t *message, dns_aclenv_t *env, ns_server_t *sctx,
-                 isc_result_t *sigresult, dns_view_t **viewp) {
+get_matching_view_sync(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
+                      dns_message_t *message, dns_aclenv_t *env,
+                      isc_result_t *sigresult, dns_view_t **viewp) {
        dns_view_t *view;
 
-       REQUIRE(message != NULL);
-       REQUIRE(sctx != NULL);
-       REQUIRE(sigresult != NULL);
-       REQUIRE(viewp != NULL && *viewp == NULL);
+       /*
+        * We should not be running synchronous view matching if signature
+        * checking involves SIG(0). TSIG has priority of SIG(0), so if TSIG
+        * is set then we proceed anyway.
+        */
+       INSIST(message->tsigkey != NULL || message->tsig != NULL ||
+              message->sig0 == NULL);
 
        for (view = ISC_LIST_HEAD(named_g_server->viewlist); view != NULL;
             view = ISC_LIST_NEXT(view, link))
@@ -10080,48 +10100,9 @@ get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
                    message->rdclass == dns_rdataclass_any)
                {
                        const dns_name_t *tsig = NULL;
-                       int exempt_match;
-                       isc_result_t sig0_qresult = ISC_R_UNSET;
-
-                       if (message->sig0 != NULL) {
-                               /*
-                                * If the message has a SIG0 signature and the
-                                * client is not exempt from the quota, then
-                                * acquire a quota. If quota is reached, then
-                                * return early.
-                                */
-                               if (sctx->sig0checksquota_exempt != NULL) {
-                                       isc_result_t result = dns_acl_match(
-                                               srcaddr, NULL,
-                                               sctx->sig0checksquota_exempt,
-                                               env, &exempt_match, NULL);
-                                       if (result == ISC_R_SUCCESS &&
-                                           exempt_match > 0)
-                                       {
-                                               sig0_qresult = ISC_R_EXISTS;
-                                       }
-                               }
-                               if (sig0_qresult == ISC_R_UNSET) {
-                                       sig0_qresult = isc_quota_acquire(
-                                               &sctx->sig0checksquota);
-                               }
-                               if (sig0_qresult == ISC_R_SOFTQUOTA) {
-                                       isc_quota_release(
-                                               &sctx->sig0checksquota);
-                               }
-                               if (sig0_qresult != ISC_R_SUCCESS &&
-                                   sig0_qresult != ISC_R_EXISTS)
-                               {
-                                       return (ISC_R_QUOTA);
-                               }
-                       }
 
-                       /* Check the signature, then release the quota  */
                        dns_message_resetsig(message);
                        *sigresult = dns_message_checksig(message, view);
-                       if (sig0_qresult == ISC_R_SUCCESS) {
-                               isc_quota_release(&sctx->sig0checksquota);
-                       }
                        if (*sigresult == ISC_R_SUCCESS) {
                                tsig = dns_tsigkey_identity(message->tsigkey);
                        }
@@ -10142,6 +10123,191 @@ get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
        return (ISC_R_NOTFOUND);
 }
 
+static void
+get_matching_view_done(void *cbarg) {
+       matching_view_ctx_t *mvctx = cbarg;
+       dns_message_t *message = mvctx->message;
+
+       if (*mvctx->viewmatchresult == ISC_R_SUCCESS) {
+               INSIST(mvctx->view != NULL);
+               dns_view_attach(mvctx->view, mvctx->viewp);
+       }
+
+       mvctx->cb(mvctx->cbarg);
+
+       if (mvctx->quota_result == ISC_R_SUCCESS) {
+               isc_quota_release(&mvctx->sctx->sig0checksquota);
+       }
+       if (mvctx->view != NULL) {
+               dns_view_detach(&mvctx->view);
+       }
+       isc_loop_detach(&mvctx->loop);
+       ns_server_detach(&mvctx->sctx);
+       isc_mem_put(message->mctx, mvctx, sizeof(*mvctx));
+       dns_message_detach(&message);
+}
+
+static dns_view_t *
+get_matching_view_next(dns_view_t *view, dns_rdataclass_t rdclass) {
+       if (view == NULL) {
+               view = ISC_LIST_HEAD(named_g_server->viewlist);
+       } else {
+               view = ISC_LIST_NEXT(view, link);
+       }
+       while (true) {
+               if (view == NULL || rdclass == view->rdclass ||
+                   rdclass == dns_rdataclass_any)
+               {
+                       return (view);
+               }
+               view = ISC_LIST_NEXT(view, link);
+       };
+}
+
+static void
+get_matching_view_continue(void *cbarg, isc_result_t result) {
+       matching_view_ctx_t *mvctx = cbarg;
+       dns_view_t *view = NULL;
+       const dns_name_t *tsig = NULL;
+
+       *mvctx->sigresult = result;
+
+       if (result == ISC_R_SUCCESS) {
+               tsig = dns_tsigkey_identity(mvctx->message->tsigkey);
+       }
+
+       if (dns_acl_allowed(mvctx->srcaddr, tsig, mvctx->view->matchclients,
+                           mvctx->env) &&
+           dns_acl_allowed(mvctx->destaddr, tsig,
+                           mvctx->view->matchdestinations, mvctx->env) &&
+           !(mvctx->view->matchrecursiveonly &&
+             (mvctx->message->flags & DNS_MESSAGEFLAG_RD) == 0))
+       {
+               /*
+                * A matching view is found.
+                */
+               *mvctx->viewmatchresult = ISC_R_SUCCESS;
+               get_matching_view_done(cbarg);
+               return;
+       }
+
+       dns_message_resetsig(mvctx->message);
+
+       view = get_matching_view_next(mvctx->view, mvctx->message->rdclass);
+       dns_view_detach(&mvctx->view);
+       if (view != NULL) {
+               /*
+                * Try the next view.
+                */
+               dns_view_attach(view, &mvctx->view);
+               result = dns_message_checksig_async(
+                       mvctx->message, view, mvctx->loop,
+                       get_matching_view_continue, mvctx);
+               INSIST(result == DNS_R_WAIT);
+               return;
+       }
+
+       /*
+        * No matching view is found.
+        */
+       *mvctx->viewmatchresult = ISC_R_NOTFOUND;
+       get_matching_view_done(cbarg);
+}
+
+/*%
+ * Find a view that matches the source and destination addresses of a query.
+ */
+static isc_result_t
+get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
+                 dns_message_t *message, dns_aclenv_t *env, ns_server_t *sctx,
+                 isc_loop_t *loop, isc_job_cb cb, void *cbarg,
+                 isc_result_t *sigresult, isc_result_t *viewmatchresult,
+                 dns_view_t **viewp) {
+       dns_view_t *view = NULL;
+       isc_result_t result;
+
+       REQUIRE(message != NULL);
+       REQUIRE(sctx != NULL);
+       REQUIRE(loop == NULL || cb != NULL);
+       REQUIRE(sigresult != NULL);
+       REQUIRE(viewmatchresult != NULL);
+       REQUIRE(viewp != NULL && *viewp == NULL);
+
+       /* No offloading is requested if the loop is unset. */
+       if (loop == NULL) {
+               *viewmatchresult = get_matching_view_sync(
+                       srcaddr, destaddr, message, env, sigresult, viewp);
+               return (*viewmatchresult);
+       }
+
+       matching_view_ctx_t *mvctx = isc_mem_get(message->mctx, sizeof(*mvctx));
+       *mvctx = (matching_view_ctx_t){
+               .srcaddr = srcaddr,
+               .destaddr = destaddr,
+               .env = env,
+               .cb = cb,
+               .cbarg = cbarg,
+               .sigresult = sigresult,
+               .viewmatchresult = viewmatchresult,
+               .quota_result = ISC_R_UNSET,
+               .viewp = viewp,
+       };
+       ns_server_attach(sctx, &mvctx->sctx);
+       isc_loop_attach(loop, &mvctx->loop);
+       dns_message_attach(message, &mvctx->message);
+
+       dns_message_resetsig(message);
+
+       view = get_matching_view_next(NULL, message->rdclass);
+       if (view == NULL) {
+               *mvctx->viewmatchresult = ISC_R_NOTFOUND;
+               isc_async_run(loop, get_matching_view_done, mvctx);
+               return (DNS_R_WAIT);
+       }
+
+       /*
+        * If the message has a SIG0 signature which we are going to
+        * check, and the client is not exempt from the SIG(0) quota,
+        * then acquire a quota. TSIG has priority over SIG(0), so if
+        * TSIG is set then we don't care.
+        */
+       if (message->tsigkey == NULL && message->tsig == NULL &&
+           message->sig0 != NULL)
+       {
+               if (sctx->sig0checksquota_exempt != NULL) {
+                       int exempt_match;
+
+                       result = dns_acl_match(srcaddr, NULL,
+                                              sctx->sig0checksquota_exempt,
+                                              env, &exempt_match, NULL);
+                       if (result == ISC_R_SUCCESS && exempt_match > 0) {
+                               mvctx->quota_result = ISC_R_EXISTS;
+                       }
+               }
+               if (mvctx->quota_result == ISC_R_UNSET) {
+                       mvctx->quota_result =
+                               isc_quota_acquire(&sctx->sig0checksquota);
+               }
+               if (mvctx->quota_result == ISC_R_SOFTQUOTA) {
+                       isc_quota_release(&sctx->sig0checksquota);
+               }
+               if (mvctx->quota_result != ISC_R_SUCCESS &&
+                   mvctx->quota_result != ISC_R_EXISTS)
+               {
+                       *mvctx->viewmatchresult = ISC_R_QUOTA;
+                       isc_async_run(loop, get_matching_view_done, mvctx);
+                       return (DNS_R_WAIT);
+               }
+       }
+
+       dns_view_attach(view, &mvctx->view);
+       result = dns_message_checksig_async(message, view, loop,
+                                           get_matching_view_continue, mvctx);
+       INSIST(result == DNS_R_WAIT);
+
+       return (DNS_R_WAIT);
+}
+
 void
 named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
        isc_result_t result;
index 03afc4d25c043f5f9cdcb2a07e95e68a767181f8..1e2229b95ec9c710df006fb2799dc9d20e95ec0c 100644 (file)
@@ -1709,6 +1709,15 @@ ns__client_reset_cb(void *client0) {
                client->keytag_len = 0;
        }
 
+       isc_timer_stop(client->quotatimer);
+
+       if (client->async) {
+               client->async = false;
+               if (client->handle != NULL) {
+                       isc_nmhandle_unref(client->handle);
+               }
+       }
+
        client->state = NS_CLIENTSTATE_READY;
 
 #ifdef WANT_SINGLETRACE
@@ -1742,6 +1751,15 @@ ns__client_put_cb(void *client0) {
                dns_message_puttemprdataset(client->message, &client->opt);
        }
 
+       isc_timer_async_destroy(&client->quotatimer);
+
+       if (client->async) {
+               client->async = false;
+               if (client->handle != NULL) {
+                       isc_nmhandle_unref(client->handle);
+               }
+       }
+
        dns_message_detach(&client->message);
 
        /*
@@ -1759,46 +1777,32 @@ static isc_result_t
 ns_client_setup_view(ns_client_t *client, isc_netaddr_t *netaddr) {
        isc_result_t result;
 
+       client->sigresult = client->viewmatchresult = ISC_R_UNSET;
+
+       if (client->async) {
+               isc_nmhandle_ref(client->handle);
+       }
+
        result = client->manager->sctx->matchingview(
                netaddr, &client->destaddr, client->message,
                client->manager->aclenv, client->manager->sctx,
-               &client->sigresult, &client->view);
-       if (result != ISC_R_SUCCESS) {
-               if (result == ISC_R_QUOTA) {
-                       if (can_log_sigchecks_quota()) {
-                               ns_client_log(client, NS_LOGCATEGORY_CLIENT,
-                                             NS_LOGMODULE_CLIENT, ISC_LOG_INFO,
-                                             "SIG(0) checks quota reached");
-                               ns_client_dumpmessage(
-                                       client, "SIG(0) checks quota reached");
-                       }
-               } else {
-                       char classname[DNS_RDATACLASS_FORMATSIZE];
-                       isc_buffer_t b;
-                       isc_region_t *r;
-
-                       /*
-                        * Do a dummy TSIG verification attempt so that the
-                        * response will have a TSIG if the query did, as
-                        * required by RFC2845.
-                        */
-                       dns_message_resetsig(client->message);
-                       r = dns_message_getrawmessage(client->message);
-                       isc_buffer_init(&b, r->base, r->length);
-                       isc_buffer_add(&b, r->length);
-                       (void)dns_tsig_verify(&b, client->message, NULL, NULL);
+               client->async ? client->manager->loop : NULL,
+               ns_client_request_continue, client, &client->sigresult,
+               &client->viewmatchresult, &client->view);
 
-                       dns_rdataclass_format(client->message->rdclass,
-                                             classname, sizeof(classname));
-                       ns_client_log(client, NS_LOGCATEGORY_CLIENT,
-                                     NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
-                                     "no matching view in class '%s'",
-                                     classname);
-                       ns_client_dumpmessage(client,
-                                             "no matching view in class");
-               }
+       if (result == DNS_R_WAIT) {
+               INSIST(client->async == true);
+               return (DNS_R_WAIT);
        }
 
+       /*
+        * matchingview() is allowed to return anything other than DNS_R_WAIT
+        * only in non-async mode, in which case 'result' must be equal to
+        * 'client->viewmatchresult'.
+        */
+       INSIST(client->async == false);
+       INSIST(result == client->viewmatchresult);
+
        return (result);
 }
 
@@ -2116,19 +2120,16 @@ ns_client_request(isc_nmhandle_t *handle, isc_result_t eresult,
        client->destsockaddr = isc_nmhandle_localaddr(handle);
        isc_netaddr_fromsockaddr(&client->destaddr, &client->destsockaddr);
 
+       /*
+        * Offload view matching only if we are going to check a SIG(0)
+        * signature.
+        */
+       client->async = (client->message->tsigkey == NULL &&
+                        client->message->tsig == NULL &&
+                        client->message->sig0 != NULL);
+
        result = ns_client_setup_view(client, &netaddr);
-       if (result == ISC_R_QUOTA) {
-               ns_client_log(client, NS_LOGCATEGORY_CLIENT,
-                             NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(5),
-                             "client is starting to wait for quota");
-               client->async = true;
-               isc_nmhandle_ref(client->handle);
-               isc_async_run(client->manager->loop, ns_client_request_continue,
-                             client);
-               return;
-       } else if (result != ISC_R_SUCCESS) {
-               ns_client_extendederror(client, DNS_EDE_PROHIBITED, NULL);
-               ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_REFUSED);
+       if (result == DNS_R_WAIT) {
                return;
        }
 
@@ -2141,7 +2142,7 @@ ns_client_request_continue(void *arg) {
        isc_netaddr_t netaddr;
        const dns_name_t *signame = NULL;
        bool ra; /* Recursion available. */
-       isc_result_t result;
+       isc_result_t result = ISC_R_UNSET;
        static const char *ra_reasons[] = {
                "ACLs not processed yet",
                "no resolver in view",
@@ -2165,19 +2166,24 @@ ns_client_request_continue(void *arg) {
        dns_dtmsgtype_t dtmsgtype;
 #endif /* ifdef HAVE_DNSTAP */
 
+       INSIST(client->viewmatchresult != ISC_R_UNSET);
+
+       isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
+
        /*
-        * This function could be running asynchronously if a quota was reached
-        * before, and named was waiting for available quota. In that case we
+        * This function could be running asynchronously when validating a
+        * SIG(0) signature or waiting for a quota for it. In that case we
         * need to update the current 'now', and check that named doesn't wait
         * for too long.
         */
        if (client->async) {
-               uint64_t wait_us;
-               uint64_t maxwait_us;
-
                client->tnow = isc_time_now();
                client->now = isc_time_seconds(&client->tnow);
+       }
+       if (client->async && client->viewmatchresult == ISC_R_QUOTA) {
+               uint64_t wait_us, maxwait_us;
 
+               /* Waiting for a quota. */
                wait_us = isc_time_microdiff(&client->tnow,
                                             &client->requesttime);
                maxwait_us = US_PER_MS *
@@ -2206,27 +2212,53 @@ ns_client_request_continue(void *arg) {
                        ns_client_error(client, DNS_R_REFUSED);
                        goto cleanup;
                }
-       }
-
-       isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
 
-       if (client->view == NULL) {
-               result = ns_client_setup_view(client, &netaddr);
-               if (result == ISC_R_QUOTA) {
+               if (can_log_sigchecks_quota()) {
                        ns_client_log(client, NS_LOGCATEGORY_CLIENT,
-                                     NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(5),
-                                     "client continues waiting for quota");
-                       client->async = true;
-                       isc_nmhandle_ref(client->handle);
-                       isc_async_run(client->manager->loop,
-                                     ns_client_request_continue, client);
-                       goto cleanup;
-               } else if (result != ISC_R_SUCCESS) {
-                       ns_client_extendederror(client, DNS_EDE_PROHIBITED,
-                                               NULL);
-                       ns_client_error(client, DNS_R_REFUSED);
-                       goto cleanup;
+                                     NS_LOGMODULE_CLIENT, ISC_LOG_INFO,
+                                     "SIG(0) checks quota reached");
+                       ns_client_dumpmessage(client,
+                                             "SIG(0) checks quota reached");
                }
+
+               /* Retry after 10 milliseconds. */
+               isc_interval_t interval;
+               isc_interval_set(&interval, 0, 10 * NS_PER_MS);
+               isc_nmhandle_ref(client->handle);
+               isc_timer_start(client->quotatimer, isc_timertype_once,
+                               &interval);
+
+               result = DNS_R_WAIT;
+               goto cleanup;
+       }
+
+       if (client->viewmatchresult != ISC_R_SUCCESS) {
+               char classname[DNS_RDATACLASS_FORMATSIZE];
+               isc_buffer_t b;
+               isc_region_t *r;
+
+               /*
+                * Do a dummy TSIG verification attempt so that the
+                * response will have a TSIG if the query did, as
+                * required by RFC2845.
+                */
+               dns_message_resetsig(client->message);
+               r = dns_message_getrawmessage(client->message);
+               isc_buffer_init(&b, r->base, r->length);
+               isc_buffer_add(&b, r->length);
+               (void)dns_tsig_verify(&b, client->message, NULL, NULL);
+
+               dns_rdataclass_format(client->message->rdclass, classname,
+                                     sizeof(classname));
+               ns_client_log(client, NS_LOGCATEGORY_CLIENT,
+                             NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
+                             "no matching view in class '%s'", classname);
+               ns_client_dumpmessage(client, "no matching view in class");
+
+               ns_client_extendederror(client, DNS_EDE_PROHIBITED, NULL);
+               ns_client_error(client, DNS_R_REFUSED);
+
+               goto cleanup;
        }
 
        if (isc_nm_is_proxy_handle(client->handle)) {
@@ -2487,12 +2519,19 @@ ns_client_request_continue(void *arg) {
        }
 
 cleanup:
+
+       /*
+        * If we are running async then 'unref' the handle, and also if there
+        * are no more async calls scheduled the reset the async flag, so that
+        * the destructor doesn't try to 'unref' the handle too.
+        */
        if (client->async) {
-               /*
-                * Do not detach, only 'unref' the corresponding 'ref' when
-                * async was used, because the client can still be reused.
-                */
-               isc_nmhandle_unref(client->handle);
+               if (client->handle != NULL) {
+                       isc_nmhandle_unref(client->handle);
+               }
+               if (result != DNS_R_WAIT) {
+                       client->async = false;
+               }
        }
 }
 
@@ -2530,6 +2569,18 @@ ns__client_tcpconn(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
        return (ISC_R_SUCCESS);
 }
 
+static void
+client_quotatimer_event(void *arg) {
+       ns_client_t *client = arg;
+       isc_netaddr_t netaddr;
+       isc_result_t result;
+
+       isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
+       result = ns_client_setup_view(client, &netaddr);
+       INSIST(result == DNS_R_WAIT); /* We are in async mode. */
+       isc_nmhandle_unref(client->handle);
+}
+
 isc_result_t
 ns__client_setup(ns_client_t *client, ns_clientmgr_t *mgr, bool new) {
        isc_result_t result;
@@ -2553,6 +2604,9 @@ ns__client_setup(ns_client_t *client, ns_clientmgr_t *mgr, bool new) {
                                   client->manager->rdspool,
                                   DNS_MESSAGE_INTENTPARSE, &client->message);
 
+               isc_timer_create(client->manager->loop, client_quotatimer_event,
+                                client, &client->quotatimer);
+
                /*
                 * Set magic earlier than usual because ns_query_init()
                 * and the functions it calls will require it.
@@ -2574,6 +2628,7 @@ ns__client_setup(ns_client_t *client, ns_clientmgr_t *mgr, bool new) {
                        .magic = 0,
                        .manager = client->manager,
                        .message = client->message,
+                       .quotatimer = client->quotatimer,
                        .query = client->query,
                };
        }
@@ -2597,6 +2652,7 @@ ns__client_setup(ns_client_t *client, ns_clientmgr_t *mgr, bool new) {
        return (ISC_R_SUCCESS);
 
 cleanup:
+       isc_timer_destroy(&client->quotatimer);
        dns_message_detach(&client->message);
        ns_clientmgr_detach(&client->manager);
 
index 39c1fa0a86431abf9469eecabf6d26173c0bf12c..14acb4297c399ee572607379e406a35a6bc937ae 100644 (file)
@@ -194,6 +194,7 @@ struct ns_client {
        dns_name_t    signername; /*%< [T]SIG key name */
        dns_name_t   *signer;     /*%< NULL if not valid sig */
        isc_result_t  sigresult;
+       isc_result_t  viewmatchresult;
        isc_buffer_t *buffer;
        isc_buffer_t  tbuffer;
 
@@ -202,6 +203,8 @@ struct ns_client {
        isc_netaddr_t  destaddr;
        isc_sockaddr_t destsockaddr;
 
+       isc_timer_t *quotatimer;
+
        dns_ecs_t ecs; /*%< EDNS client subnet sent by client */
 
        /*%
index fae2040b74e6f954aa400628eaa730d0d7d4d880..9acf83a9660edbad4697253473408ab827c53099 100644 (file)
@@ -64,12 +64,11 @@ typedef void (*ns_fuzzcb_t)(void);
 /*%
  * Type for callback function to get the view that can answer a query.
  */
-typedef isc_result_t (*ns_matchview_t)(isc_netaddr_t *srcaddr,
-                                      isc_netaddr_t *destaddr,
-                                      dns_message_t *message,
-                                      dns_aclenv_t *env, ns_server_t *sctx,
-                                      isc_result_t *sigresultp,
-                                      dns_view_t  **viewp);
+typedef isc_result_t (*ns_matchview_t)(
+       isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr, dns_message_t *message,
+       dns_aclenv_t *env, ns_server_t *sctx, isc_loop_t *loop, isc_job_cb cb,
+       void *cbarg, isc_result_t *sigresultp, isc_result_t *viewmatchresult,
+       dns_view_t **viewp);
 
 /*%
  * Server context.
index f09b20045c83d9d836453c3d2bbbdb10b11aa8a8..980ab6b904d67aa911c842dc1231e3ae569a6c06 100644 (file)
@@ -58,15 +58,21 @@ ns_server_t *sctx = NULL;
 static isc_result_t
 matchview(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
          dns_message_t *message, dns_aclenv_t *env, ns_server_t *lsctx,
-         isc_result_t *sigresultp, dns_view_t **viewp) {
+         isc_loop_t *loop, isc_job_cb cb, void *cbarg,
+         isc_result_t *sigresultp, isc_result_t *viewmatchresultp,
+         dns_view_t **viewp) {
        UNUSED(srcaddr);
        UNUSED(destaddr);
        UNUSED(message);
        UNUSED(env);
        UNUSED(lsctx);
+       UNUSED(loop);
+       UNUSED(cb);
+       UNUSED(cbarg);
        UNUSED(sigresultp);
        UNUSED(viewp);
 
+       *viewmatchresultp = ISC_R_NOTIMPLEMENTED;
        return (ISC_R_NOTIMPLEMENTED);
 }