summaryrefslogtreecommitdiffstats
path: root/lib/ns/include/ns
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ns/include/ns')
-rw-r--r--lib/ns/include/ns/client.h578
-rw-r--r--lib/ns/include/ns/events.h25
-rw-r--r--lib/ns/include/ns/hooks.h612
-rw-r--r--lib/ns/include/ns/interfacemgr.h192
-rw-r--r--lib/ns/include/ns/listenlist.h137
-rw-r--r--lib/ns/include/ns/log.h72
-rw-r--r--lib/ns/include/ns/notify.h44
-rw-r--r--lib/ns/include/ns/query.h271
-rw-r--r--lib/ns/include/ns/server.h201
-rw-r--r--lib/ns/include/ns/sortlist.h80
-rw-r--r--lib/ns/include/ns/stats.h138
-rw-r--r--lib/ns/include/ns/types.h33
-rw-r--r--lib/ns/include/ns/update.h43
-rw-r--r--lib/ns/include/ns/xfrout.h30
14 files changed, 2456 insertions, 0 deletions
diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h
new file mode 100644
index 0000000..7a7196f
--- /dev/null
+++ b/lib/ns/include/ns/client.h
@@ -0,0 +1,578 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file
+ * \brief
+ * This module defines two objects, ns_client_t and ns_clientmgr_t.
+ *
+ * An ns_client_t object handles incoming DNS requests from clients
+ * on a given network interface.
+ *
+ * Each ns_client_t object can handle only one TCP connection or UDP
+ * request at a time. Therefore, several ns_client_t objects are
+ * typically created to serve each network interface, e.g., one
+ * for handling TCP requests and a few (one per CPU) for handling
+ * UDP requests.
+ *
+ * Incoming requests are classified as queries, zone transfer
+ * requests, update requests, notify requests, etc, and handed off
+ * to the appropriate request handler. When the request has been
+ * fully handled (which can be much later), the ns_client_t must be
+ * notified of this by calling one of the following functions
+ * exactly once in the context of its task:
+ * \code
+ * ns_client_send() (sending a non-error response)
+ * ns_client_sendraw() (sending a raw response)
+ * ns_client_error() (sending an error response)
+ * ns_client_drop() (sending no response, logging the reason)
+ *\endcode
+ * This will release any resources used by the request and
+ * and allow the ns_client_t to listen for the next request.
+ *
+ * A ns_clientmgr_t manages a number of ns_client_t objects.
+ * New ns_client_t objects are created by calling
+ * ns_clientmgr_createclients(). They are destroyed by
+ * destroying their manager.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/atomic.h>
+#include <isc/buffer.h>
+#include <isc/magic.h>
+#include <isc/netmgr.h>
+#include <isc/quota.h>
+#include <isc/stdtime.h>
+
+#include <dns/db.h>
+#include <dns/ecs.h>
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatatype.h>
+#include <dns/types.h>
+
+#include <ns/query.h>
+#include <ns/types.h>
+
+/***
+ *** Types
+ ***/
+
+#define NS_CLIENT_TCP_BUFFER_SIZE 65535
+#define NS_CLIENT_SEND_BUFFER_SIZE 4096
+
+/*!
+ * Client object states. Ordering is significant: higher-numbered
+ * states are generally "more active", meaning that the client can
+ * have more dynamically allocated data, outstanding events, etc.
+ * In the list below, any such properties listed for state N
+ * also apply to any state > N.
+ */
+
+typedef enum {
+ NS_CLIENTSTATE_FREED = 0,
+ /*%<
+ * The client object no longer exists.
+ */
+
+ NS_CLIENTSTATE_INACTIVE = 1,
+ /*%<
+ * The client object exists and has a task and timer.
+ * Its "query" struct and sendbuf are initialized.
+ * It has a message and OPT, both in the reset state.
+ */
+
+ NS_CLIENTSTATE_READY = 2,
+ /*%<
+ * The client object is either a TCP or a UDP one, and
+ * it is associated with a network interface. It is on the
+ * client manager's list of active clients.
+ *
+ * If it is a TCP client object, it has a TCP listener socket
+ * and an outstanding TCP listen request.
+ *
+ * If it is a UDP client object, it has a UDP listener socket
+ * and an outstanding UDP receive request.
+ */
+
+ NS_CLIENTSTATE_WORKING = 3,
+ /*%<
+ * The client object has received a request and is working
+ * on it. It has a view, and it may have any of a non-reset OPT,
+ * recursion quota, and an outstanding write request.
+ */
+
+ NS_CLIENTSTATE_RECURSING = 4,
+ /*%<
+ * The client object is recursing. It will be on the
+ * 'recursing' list.
+ */
+
+ NS_CLIENTSTATE_MAX = 5
+ /*%<
+ * Sentinel value used to indicate "no state".
+ */
+} ns_clientstate_t;
+
+typedef ISC_LIST(ns_client_t) client_list_t;
+
+/*% nameserver client manager structure */
+struct ns_clientmgr {
+ /* Unlocked. */
+ unsigned int magic;
+
+ isc_mem_t *mctx;
+ isc_mem_t *send_mctx;
+ ns_server_t *sctx;
+ isc_taskmgr_t *taskmgr;
+ isc_timermgr_t *timermgr;
+ isc_refcount_t references;
+ int tid;
+
+ /* Attached by clients, needed for e.g. recursion */
+ isc_task_t *task;
+
+ dns_aclenv_t *aclenv;
+
+ /* Lock covers the recursing list */
+ isc_mutex_t reclock;
+ client_list_t recursing; /*%< Recursing clients */
+};
+
+/*% nameserver client structure */
+struct ns_client {
+ unsigned int magic;
+ isc_mem_t *mctx;
+ int tid;
+ bool allocated; /* Do we need to free it? */
+ ns_server_t *sctx;
+ ns_clientmgr_t *manager;
+ ns_clientstate_t state;
+ int nupdates;
+ bool nodetach;
+ bool shuttingdown;
+ unsigned int attributes;
+ isc_task_t *task;
+ dns_view_t *view;
+ dns_dispatch_t *dispatch;
+ isc_nmhandle_t *handle; /* Permanent pointer to handle */
+ isc_nmhandle_t *sendhandle; /* Waiting for send callback */
+ isc_nmhandle_t *reqhandle; /* Waiting for request callback
+ (query, update, notify) */
+ isc_nmhandle_t *fetchhandle; /* Waiting for recursive fetch */
+ isc_nmhandle_t *prefetchhandle; /* Waiting for prefetch / rpzfetch */
+ isc_nmhandle_t *updatehandle; /* Waiting for update callback */
+ unsigned char *tcpbuf;
+ size_t tcpbuf_size;
+ dns_message_t *message;
+ unsigned char *sendbuf;
+ dns_rdataset_t *opt;
+ dns_ednsopt_t *ede;
+ uint16_t udpsize;
+ uint16_t extflags;
+ int16_t ednsversion; /* -1 noedns */
+ uint16_t additionaldepth;
+ void (*cleanup)(ns_client_t *);
+ ns_query_t query;
+ isc_time_t requesttime;
+ isc_stdtime_t now;
+ isc_time_t tnow;
+ dns_name_t signername; /*%< [T]SIG key name */
+ dns_name_t *signer; /*%< NULL if not valid sig */
+ bool mortal; /*%< Die after handling request */
+ isc_quota_t *recursionquota;
+
+ isc_sockaddr_t peeraddr;
+ bool peeraddr_valid;
+ isc_netaddr_t destaddr;
+ isc_sockaddr_t destsockaddr;
+
+ dns_ecs_t ecs; /*%< EDNS client subnet sent by client */
+
+ struct in6_pktinfo pktinfo;
+ /*%
+ * Information about recent FORMERR response(s), for
+ * FORMERR loop avoidance. This is separate for each
+ * client object rather than global only to avoid
+ * the need for locking.
+ */
+ struct {
+ isc_sockaddr_t addr;
+ isc_stdtime_t time;
+ dns_messageid_t id;
+ } formerrcache;
+
+ /*% Callback function to send a response when unit testing */
+ void (*sendcb)(isc_buffer_t *buf);
+
+ ISC_LINK(ns_client_t) rlink;
+ unsigned char cookie[8];
+ uint32_t expire;
+ unsigned char *keytag;
+ uint16_t keytag_len;
+
+ /*%
+ * Used to override the DNS response code in ns_client_error().
+ * If set to -1, the rcode is determined from the result code,
+ * but if set to any other value, the least significant 12
+ * bits will be used as the rcode in the response message.
+ */
+ int32_t rcode_override;
+};
+
+#define NS_CLIENT_MAGIC ISC_MAGIC('N', 'S', 'C', 'c')
+#define NS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, NS_CLIENT_MAGIC)
+
+#define NS_CLIENTATTR_TCP 0x00001
+#define NS_CLIENTATTR_RA 0x00002 /*%< Client gets recursive service */
+#define NS_CLIENTATTR_PKTINFO 0x00004 /*%< pktinfo is valid */
+#define NS_CLIENTATTR_MULTICAST 0x00008 /*%< recv'd from multicast */
+#define NS_CLIENTATTR_WANTDNSSEC 0x00010 /*%< include dnssec records */
+#define NS_CLIENTATTR_WANTNSID 0x00020 /*%< include nameserver ID */
+/* Obsolete: NS_CLIENTATTR_FILTER_AAAA 0x00040 */
+/* Obsolete: NS_CLIENTATTR_FILTER_AAAA_RC 0x00080 */
+#define NS_CLIENTATTR_WANTAD 0x00100 /*%< want AD in response if possible */
+#define NS_CLIENTATTR_WANTCOOKIE 0x00200 /*%< return a COOKIE */
+#define NS_CLIENTATTR_HAVECOOKIE 0x00400 /*%< has a valid COOKIE */
+#define NS_CLIENTATTR_WANTEXPIRE 0x00800 /*%< return seconds to expire */
+#define NS_CLIENTATTR_HAVEEXPIRE 0x01000 /*%< return seconds to expire */
+#define NS_CLIENTATTR_WANTOPT 0x02000 /*%< add opt to reply */
+#define NS_CLIENTATTR_HAVEECS 0x04000 /*%< received an ECS option */
+#define NS_CLIENTATTR_WANTPAD 0x08000 /*%< pad reply */
+#define NS_CLIENTATTR_USEKEEPALIVE 0x10000 /*%< use TCP keepalive */
+
+#define NS_CLIENTATTR_NOSETFC 0x20000 /*%< don't set servfail cache */
+
+/*
+ * Flag to use with the SERVFAIL cache to indicate
+ * that a query had the CD bit set.
+ */
+#define NS_FAILCACHE_CD 0x01
+
+extern atomic_uint_fast64_t ns_client_requests;
+
+/***
+ *** Functions
+ ***/
+
+/*
+ * Note! These ns_client_ routines MUST be called ONLY from the client's
+ * task in order to ensure synchronization.
+ */
+
+void
+ns_client_send(ns_client_t *client);
+/*%<
+ * Finish processing the current client request and
+ * send client->message as a response.
+ * \brief
+ * Note! These ns_client_ routines MUST be called ONLY from the client's
+ * task in order to ensure synchronization.
+ */
+
+void
+ns_client_sendraw(ns_client_t *client, dns_message_t *msg);
+/*%<
+ * Finish processing the current client request and
+ * send msg as a response using client->message->id for the id.
+ */
+
+void
+ns_client_error(ns_client_t *client, isc_result_t result);
+/*%<
+ * Finish processing the current client request and return
+ * an error response to the client. The error response
+ * will have an RCODE determined by 'result'.
+ */
+
+void
+ns_client_extendederror(ns_client_t *client, uint16_t code, const char *text);
+/*%<
+ * Set extended error with INFO-CODE <code> and EXTRA-TEXT <text>.
+ */
+
+void
+ns_client_drop(ns_client_t *client, isc_result_t result);
+/*%<
+ * Log the reason the current client request has failed; no response
+ * will be sent.
+ */
+
+bool
+ns_client_shuttingdown(ns_client_t *client);
+/*%<
+ * Return true iff the client is currently shutting down.
+ */
+
+isc_result_t
+ns_client_replace(ns_client_t *client);
+/*%<
+ * Try to replace the current client with a new one, so that the
+ * current one can go off and do some lengthy work without
+ * leaving the dispatch/socket without service.
+ */
+
+void
+ns_client_settimeout(ns_client_t *client, unsigned int seconds);
+/*%<
+ * Set a timer in the client to go off in the specified amount of time.
+ */
+
+isc_result_t
+ns_clientmgr_create(ns_server_t *sctx, isc_taskmgr_t *taskmgr,
+ isc_timermgr_t *timermgr, dns_aclenv_t *aclenv, int tid,
+ ns_clientmgr_t **managerp);
+/*%<
+ * Create a client manager.
+ */
+
+void
+ns_clientmgr_shutdown(ns_clientmgr_t *manager);
+/*%<
+ * Shutdown a client manager and all ns_client_t objects
+ * managed by it
+ */
+
+void
+ns_clientmgr_detach(ns_clientmgr_t **managerp);
+/*%<
+ * Detach from a client manager.
+ */
+
+isc_sockaddr_t *
+ns_client_getsockaddr(ns_client_t *client);
+/*%<
+ * Get the socket address of the client whose request is
+ * currently being processed.
+ */
+
+isc_sockaddr_t *
+ns_client_getdestaddr(ns_client_t *client);
+/*%<
+ * Get the destination address (server) for the request that is
+ * currently being processed.
+ */
+
+isc_result_t
+ns_client_checkaclsilent(ns_client_t *client, isc_netaddr_t *netaddr,
+ dns_acl_t *acl, bool default_allow);
+
+/*%<
+ * Convenience function for client request ACL checking.
+ *
+ * Check the current client request against 'acl'. If 'acl'
+ * is NULL, allow the request iff 'default_allow' is true.
+ * If netaddr is NULL, check the ACL against client->peeraddr;
+ * otherwise check it against netaddr.
+ *
+ * Notes:
+ *\li This is appropriate for checking allow-update,
+ * allow-query, allow-transfer, etc. It is not appropriate
+ * for checking the blackhole list because we treat positive
+ * matches as "allow" and negative matches as "deny"; in
+ * the case of the blackhole list this would be backwards.
+ *
+ * Requires:
+ *\li 'client' points to a valid client.
+ *\li 'netaddr' points to a valid address, or is NULL.
+ *\li 'acl' points to a valid ACL, or is NULL.
+ *
+ * Returns:
+ *\li ISC_R_SUCCESS if the request should be allowed
+ * \li DNS_R_REFUSED if the request should be denied
+ *\li No other return values are possible.
+ */
+
+isc_result_t
+ns_client_checkacl(ns_client_t *client, isc_sockaddr_t *sockaddr,
+ const char *opname, dns_acl_t *acl, bool default_allow,
+ int log_level);
+/*%<
+ * Like ns_client_checkaclsilent, except the outcome of the check is
+ * logged at log level 'log_level' if denied, and at debug 3 if approved.
+ * Log messages will refer to the request as an 'opname' request.
+ *
+ * Requires:
+ *\li 'client' points to a valid client.
+ *\li 'sockaddr' points to a valid address, or is NULL.
+ *\li 'acl' points to a valid ACL, or is NULL.
+ *\li 'opname' points to a null-terminated string.
+ */
+
+void
+ns_client_log(ns_client_t *client, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *fmt, ...)
+ ISC_FORMAT_PRINTF(5, 6);
+
+void
+ns_client_logv(ns_client_t *client, isc_logcategory_t *category,
+ isc_logmodule_t *module, int level, const char *fmt, va_list ap)
+ ISC_FORMAT_PRINTF(5, 0);
+
+void
+ns_client_aclmsg(const char *msg, const dns_name_t *name, dns_rdatatype_t type,
+ dns_rdataclass_t rdclass, char *buf, size_t len);
+
+#define NS_CLIENT_ACLMSGSIZE(x) \
+ (DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + \
+ DNS_RDATACLASS_FORMATSIZE + sizeof(x) + sizeof("'/'"))
+
+void
+ns_client_recursing(ns_client_t *client);
+/*%<
+ * Add client to end of th recursing list.
+ */
+
+void
+ns_client_killoldestquery(ns_client_t *client);
+/*%<
+ * Kill the oldest recursive query (recursing list head).
+ */
+
+void
+ns_client_dumprecursing(FILE *f, ns_clientmgr_t *manager);
+/*%<
+ * Dump the outstanding recursive queries to 'f'.
+ */
+
+void
+ns_client_qnamereplace(ns_client_t *client, dns_name_t *name);
+/*%<
+ * Replace the qname.
+ */
+
+isc_result_t
+ns_client_sourceip(dns_clientinfo_t *ci, isc_sockaddr_t **addrp);
+
+isc_result_t
+ns_client_addopt(ns_client_t *client, dns_message_t *message,
+ dns_rdataset_t **opt);
+
+/*%<
+ * Get a client object from the inactive queue, or create one, as needed.
+ * (Not intended for use outside this module and associated tests.)
+ */
+
+void
+ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult,
+ isc_region_t *region, void *arg);
+
+/*%<
+ * Handle client requests.
+ * (Not intended for use outside this module and associated tests.)
+ */
+
+isc_result_t
+ns__client_tcpconn(isc_nmhandle_t *handle, isc_result_t result, void *arg);
+
+/*%<
+ * Called every time a TCP connection is establish. This is used for
+ * updating TCP statistics.
+ */
+
+dns_rdataset_t *
+ns_client_newrdataset(ns_client_t *client);
+
+void
+ns_client_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp);
+/*%<
+ * Get and release temporary rdatasets in the client message;
+ * used in query.c and in plugins.
+ */
+
+isc_result_t
+ns_client_newnamebuf(ns_client_t *client);
+/*%<
+ * Allocate a name buffer for the client message.
+ */
+
+dns_name_t *
+ns_client_newname(ns_client_t *client, isc_buffer_t *dbuf, isc_buffer_t *nbuf);
+/*%<
+ * Get a temporary name for the client message.
+ */
+
+isc_buffer_t *
+ns_client_getnamebuf(ns_client_t *client);
+/*%<
+ * Get a name buffer from the pool, or allocate a new one if needed.
+ */
+
+void
+ns_client_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf);
+/*%<
+ * Adjust buffer 'dbuf' to reflect that 'name' is using space in it,
+ * and set client attributes appropriately.
+ */
+
+void
+ns_client_releasename(ns_client_t *client, dns_name_t **namep);
+/*%<
+ * Release 'name' back to the pool of temporary names for the client
+ * message. If it is using a name buffer, relinquish its exclusive
+ * rights on the buffer.
+ */
+
+isc_result_t
+ns_client_newdbversion(ns_client_t *client, unsigned int n);
+/*%<
+ * Allocate 'n' new database versions for use by client queries.
+ */
+
+ns_dbversion_t *
+ns_client_getdbversion(ns_client_t *client);
+/*%<
+ * Get a free database version for use by a client query, allocating
+ * a new one if necessary.
+ */
+
+ns_dbversion_t *
+ns_client_findversion(ns_client_t *client, dns_db_t *db);
+/*%<
+ * Find the correct database version to use with a client query.
+ * If we have already done a query related to the database 'db',
+ * make sure subsequent queries are from the same version;
+ * otherwise, take a database version from the list of dbversions
+ * allocated by ns_client_newdbversion().
+ */
+
+isc_result_t
+ns__client_setup(ns_client_t *client, ns_clientmgr_t *manager, bool new);
+/*%<
+ * Perform initial setup of an allocated client.
+ */
+
+void
+ns__client_reset_cb(void *client0);
+/*%<
+ * Reset the client object so that it can be reused.
+ */
+
+void
+ns__client_put_cb(void *client0);
+/*%<
+ * Free all resources allocated to this client object, so that
+ * it can be freed.
+ */
diff --git a/lib/ns/include/ns/events.h b/lib/ns/include/ns/events.h
new file mode 100644
index 0000000..b651827
--- /dev/null
+++ b/lib/ns/include/ns/events.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+#include <isc/eventclass.h>
+
+/*! \file ns/events.h
+ * \brief
+ * Registry of NS event numbers.
+ */
+
+#define NS_EVENT_CLIENTCONTROL (ISC_EVENTCLASS_NS + 0)
+#define NS_EVENT_HOOKASYNCDONE (ISC_EVENTCLASS_NS + 1)
+#define NS_EVENT_IFSCAN (ISC_EVENTCLASS_NS + 2)
diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h
new file mode 100644
index 0000000..cb146ff
--- /dev/null
+++ b/lib/ns/include/ns/hooks.h
@@ -0,0 +1,612 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <stdbool.h>
+
+#include <isc/event.h>
+#include <isc/list.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/result.h>
+#include <isc/task.h>
+
+#include <dns/rdatatype.h>
+
+#include <ns/client.h>
+#include <ns/query.h>
+/*
+ * "Hooks" are a mechanism to call a defined function or set of functions once
+ * a certain place in code is reached. Hook actions can inspect and alter the
+ * state of an ongoing process, allowing processing to continue afterward or
+ * triggering an early return.
+ *
+ * Currently hooks are used in two ways: in plugins, which use them to
+ * add functionality to query processing, and in the unit tests for libns,
+ * where they are used to inspect state before and after certain functions have
+ * run.
+ *
+ * Both of these uses are limited to libns, so hooks are currently defined in
+ * the ns/hooks.h header file, and hook-related macro and function names are
+ * prefixed with `NS_` and `ns_`. However, the design is fairly generic and
+ * could be repurposed for general use, e.g. as part of libisc, after some
+ * further customization.
+ *
+ * Hooks are created by defining a hook point identifier in the ns_hookpoint_t
+ * enum below, and placing a special call at a corresponding location in the
+ * code which invokes the action(s) for that hook; there are two such special
+ * calls currently implemented, namely the CALL_HOOK() and CALL_HOOK_NORETURN()
+ * macros in query.c. The former macro contains a "goto cleanup" statement
+ * which is inlined into the function into which the hook has been inserted;
+ * this enables the hook action to cause the calling function to return from
+ * the hook insertion point. For functions returning isc_result_t, if a hook
+ * action intends to cause a return at hook insertion point, it also has to set
+ * the value to be returned by the calling function.
+ *
+ * A hook table is an array (indexed by the value of the hook point identifier)
+ * in which each cell contains a linked list of structures, each of which
+ * contains a function pointer to a hook action and a pointer to data which is
+ * to be passed to the action function when it is called.
+ *
+ * Each view has its own separate hook table, populated by loading plugin
+ * modules specified in the "plugin" statements in named.conf. There is also a
+ * special, global hook table (ns__hook_table) that is only used by libns unit
+ * tests and whose existence can be safely ignored by plugin modules.
+ *
+ * Hook actions are functions which:
+ *
+ * - return an ns_hookresult_t value:
+ * - if NS_HOOK_RETURN is returned by the hook action, the function
+ * into which the hook is inserted will return and no further hook
+ * actions at the same hook point will be invoked,
+ * - if NS_HOOK_CONTINUE is returned by the hook action and there are
+ * further hook actions set up at the same hook point, they will be
+ * processed; if NS_HOOK_CONTINUE is returned and there are no
+ * further hook actions set up at the same hook point, execution of
+ * the function into which the hook has been inserted will be
+ * resumed.
+ *
+ * - accept three pointers as arguments:
+ * - a pointer specified by the special call at the hook insertion point,
+ * - a pointer specified upon inserting the action into the hook table,
+ * - a pointer to an isc_result_t value which will be returned by the
+ * function into which the hook is inserted if the action returns
+ * NS_HOOK_RETURN.
+ *
+ * In order for a hook action to be called for a given hook, a pointer to that
+ * action function (along with an optional pointer to action-specific data) has
+ * to be inserted into the relevant hook table entry for that hook using an
+ * ns_hook_add() call. If multiple actions are set up at a single hook point
+ * (e.g. by multiple plugin modules), they are processed in FIFO order, that is
+ * they are performed in the same order in which their relevant ns_hook_add()
+ * calls were issued. Since the configuration is loaded from a single thread,
+ * this means that multiple actions at a single hook point are determined by
+ * the order in which the relevant plugin modules were declared in the
+ * configuration file(s). The hook API currently does not support changing
+ * this order.
+ *
+ * As an example, consider the following hypothetical function in query.c:
+ *
+ * ----------------------------------------------------------------------------
+ * static isc_result_t
+ * query_foo(query_ctx_t *qctx) {
+ * isc_result_t result;
+ *
+ * CALL_HOOK(NS_QUERY_FOO_BEGIN, qctx);
+ *
+ * ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY,
+ * ISC_LOG_DEBUG(99), "Lorem ipsum dolor sit amet...");
+ *
+ * result = ISC_R_COMPLETE;
+ *
+ * cleanup:
+ * return (result);
+ * }
+ * ----------------------------------------------------------------------------
+ *
+ * and the following hook action:
+ *
+ * ----------------------------------------------------------------------------
+ * static ns_hookresult_t
+ * cause_failure(void *hook_data, void *action_data, isc_result_t *resultp) {
+ * UNUSED(hook_data);
+ * UNUSED(action_data);
+ *
+ * *resultp = ISC_R_FAILURE;
+ *
+ * return (NS_HOOK_RETURN);
+ * }
+ * ----------------------------------------------------------------------------
+ *
+ * If this hook action was installed in the hook table using:
+ *
+ * ----------------------------------------------------------------------------
+ * const ns_hook_t foo_fail = {
+ * .action = cause_failure,
+ * };
+ *
+ * ns_hook_add(..., NS_QUERY_FOO_BEGIN, &foo_fail);
+ * ----------------------------------------------------------------------------
+ *
+ * then query_foo() would return ISC_R_FAILURE every time it is called due
+ * to the cause_failure() hook action returning NS_HOOK_RETURN and setting
+ * '*resultp' to ISC_R_FAILURE. query_foo() would also never log the
+ * "Lorem ipsum dolor sit amet..." message.
+ *
+ * Consider a different hook action:
+ *
+ * ----------------------------------------------------------------------------
+ * static ns_hookresult_t
+ * log_qtype(void *hook_data, void *action_data, isc_result_t *resultp) {
+ * query_ctx_t *qctx = (query_ctx_t *)hook_data;
+ * FILE *stream = (FILE *)action_data;
+ *
+ * UNUSED(resultp);
+ *
+ * fprintf(stream, "QTYPE=%u\n", qctx->qtype);
+ *
+ * return (NS_HOOK_CONTINUE);
+ * }
+ * ----------------------------------------------------------------------------
+ *
+ * If this hook action was installed in the hook table instead of
+ * cause_failure(), using:
+ *
+ * ----------------------------------------------------------------------------
+ * const ns_hook_t foo_log_qtype = {
+ * .action = log_qtype,
+ * .action_data = stderr,
+ * };
+ *
+ * ns_hook_add(..., NS_QUERY_FOO_BEGIN, &foo_log_qtype);
+ * ----------------------------------------------------------------------------
+ *
+ * then the QTYPE stored in the query context passed to query_foo() would be
+ * logged to stderr upon each call to that function; 'qctx' would be passed to
+ * the hook action in 'hook_data' since it is specified in the CALL_HOOK() call
+ * inside query_foo() while stderr would be passed to the hook action in
+ * 'action_data' since it is specified in the ns_hook_t structure passed to
+ * ns_hook_add(). As the hook action returns NS_HOOK_CONTINUE,
+ * query_foo() would also be logging the "Lorem ipsum dolor sit amet..."
+ * message before returning ISC_R_COMPLETE.
+ *
+ * ASYNCHRONOUS EVENT HANDLING IN QUERY HOOKS
+ *
+ * Usually a hook action works synchronously; it completes some particular
+ * job in the middle of query processing, thus blocking the caller (and the
+ * worker thread handling the query). But sometimes an action can be time
+ * consuming and the blocking behavior may not be acceptable. For example,
+ * a hook may need to send some kind of query (like a DB lookup) to an
+ * external backend server and wait for the response to complete the hook's
+ * action. Depending on the network condition, the external server's load,
+ * etc, it may take several seconds or more.
+ *
+ * In order to handle such a situation, a hook action can start an
+ * asynchronous event by calling ns_query_hookasync(). This is similar
+ * to ns_query_recurse(), but more generic. ns_query_hookasync() will
+ * call the 'runasync' function with a specified 'arg' (both passed to
+ * ns_query_hookasync()) and a set of task and associated event arguments
+ * to be called to resume query handling upon completion of the
+ * asynchronous event.
+ *
+ * The implementation of 'runasync' is assumed to allocate and build an
+ * instance of ns_hook_resevent_t whose action, arg, and task are set to
+ * the passed values from ns_query_hookasync(). Other fields of
+ * ns_hook_resevent_t must be correctly set in the hook implementation
+ * by the time it's sent to the specified task:
+ *
+ * - hookpoint: the point from which the query handling should be resumed
+ * (which should usually be the hook point that triggered the asynchronous
+ * event).
+ * - origresult: the result code passed to the hook action that triggers the
+ * asynchronous event through the 'resultp' pointer. Some hook points need
+ * this value to correctly resume the query handling.
+ * - saved_qctx: the 'qctx' passed to 'runasync'. This holds some
+ * intermediate data for resolving the query, and will be used to resume the
+ * query handling. The 'runasync' implementation must not modify it.
+ *
+ * The hook implementation should somehow maintain the created event
+ * instance so that it can eventually send the event.
+ *
+ * 'runasync' then creates an instance of ns_hookasync_t with specifying its
+ * own cancel and destroy function, and returns it to ns_query_hookasync()
+ * in the passed pointer.
+ *
+ * On return from ns_query_hookasync(), the hook action MUST return
+ * NS_HOOK_RETURN to suspend the query handling.
+ *
+ * On the completion of the asynchronous event, the hook implementation is
+ * supposed to send the resumeevent to the corresponding task. The query
+ * module resumes the query handling so that the hook action of the
+ * specified hook point will be called, skipping some intermediate query
+ * handling steps. So, typically, the same hook action will be called
+ * twice. The hook implementation must somehow remember the context, and
+ * handle the second call to complete its action using the result of the
+ * asynchronous event.
+ *
+ * Example: assume the following hook-specific structure to manage
+ * asynchronous events:
+ *
+ * typedef struct hookstate {
+ * bool async;
+ * ns_hook_resevent_t *rev
+ * ns_hookpoint_t hookpoint;
+ * isc_result_t origresult;
+ * } hookstate_t;
+ *
+ * 'async' is supposed to be true if and only if hook-triggered
+ * asynchronous processing is taking place.
+ *
+ * A hook action that uses an asynchronous event would look something
+ * like this:
+ *
+ * hook_recurse(void *hook_data, void *action_data, isc_result_t *resultp) {
+ * hookstate_t *state = somehow_retrieve_from(action_data);
+ * if (state->async) {
+ * // just resumed from an asynchronous hook action.
+ * // complete the hook's action using the result of the
+ * // internal asynchronous event.
+ * state->async = false;
+ * return (NS_HOOK_CONTINUE);
+ * }
+ *
+ * // Initial call to the hook action. Start the internal
+ * // asynchronous event, and have the query module suspend
+ * // its own handling by returning NS_HOOK_RETURN.
+ * state->hookpoint = ...; // would be hook point for this hook
+ * state->origresult = *resultp;
+ * ns_query_hookasync(hook_data, runasync, state);
+ * state->async = true;
+ * return (NS_HOOK_RETURN);
+ * }
+ *
+ * And the 'runasync' function would be something like this:
+ *
+ * static isc_result_t
+ * runasync(query_ctx_t *qctx, void *arg, isc_taskaction_t action,
+ * void *evarg, isc_task_t *task, ns_hookasync_t **ctxp) {
+ * hookstate_t *state = arg;
+ * ns_hook_resevent_t *rev = isc_event_allocate(
+ * mctx, task, NS_EVENT_HOOKASYNCDONE, action, evarg,
+ * sizeof(*rev));
+ * ns_hookasync_t *ctx = isc_mem_get(mctx, sizeof(*ctx));
+ *
+ * *ctx = (ns_hookasync_t){ .private = NULL };
+ * isc_mem_attach(mctx, &ctx->mctx);
+ * ctx->cancel = ...; // set the cancel function, which cancels the
+ * // internal asynchronous event (if necessary).
+ * // it should eventually result in sending
+ * // the 'rev' event to the calling task.
+ * ctx->destroy = ...; // set the destroy function, which frees 'ctx'
+ *
+ * rev->hookpoint = state->hookpoint;
+ * rev->origresult = state->origresult;
+ * rev->saved_qctx = qctx;
+ * rev->ctx = ctx;
+ *
+ * state->rev = rev; // store the resume event so we can send it later
+ *
+ * // initiate some asynchronous process here - for example, a
+ * // recursive fetch.
+ *
+ * *ctxp = ctx;
+ * return (ISC_R_SUCCESS);
+ * }
+ *
+ * Finally, in the completion handler for the asynchronous process, we
+ * need to send a resumption event so that query processing can resume.
+ * For example, the completion handler might call this function:
+ *
+ * static void
+ * asyncproc_done(hookstate_t *state) {
+ * isc_event_t *ev = (isc_event_t *)state->rev;
+ * isc_task_send(ev->ev_sender, &ev);
+ * }
+ *
+ * Caveats:
+ * - On resuming from a hook-initiated asynchronous process, code in
+ * the query module before the hook point needs to be exercised.
+ * So if this part has side effects, it's possible that the resuming
+ * doesn't work well. Currently, NS_QUERY_RESPOND_ANY_FOUND is
+ * explicitly prohibited to be used as the resume point.
+ * - In general, hooks other than those called at the beginning of the
+ * caller function may not work safely with asynchronous processing for
+ * the reason stated in the previous bullet. For example, a hook action
+ * for NS_QUERY_DONE_SEND may not be able to start an asychronous
+ * function safely.
+ * - Hook-triggered asynchronous processing is not allowed to be running
+ * while the standard DNS recursive fetch is taking place (starting
+ * from a call to dns_resolver_createfetch()), as the two would be
+ * using some of the same context resources. For this reason the
+ * NS_QUERY_NOTFOUND_RECURSE and NS_QUERY_ZEROTTL_RECURSE hook points
+ * are explicitly prohibited from being used for asynchronous hook
+ * actions.
+ * - Specifying multiple hook actions for the same hook point at the
+ * same time may cause problems, as resumption from one hook action
+ * could cause another hook to be called twice unintentionally.
+ * It's generally not safe to assume such a use case works,
+ * especially if the hooks are developed independently. (Note that
+ * that's not necessarily specific to the use of asynchronous hook
+ * actions. As long as hook actions have side effects, including
+ * modifying the internal query state, it's not guaranteed safe
+ * to use multiple independent hooks at the same time.)
+ */
+
+/*!
+ * Currently-defined hook points. So long as these are unique, the order in
+ * which they are declared is unimportant, but it currently matches the
+ * order in which they are referenced in query.c.
+ */
+typedef enum {
+ /* hookpoints from query.c */
+ NS_QUERY_QCTX_INITIALIZED,
+ NS_QUERY_QCTX_DESTROYED,
+ NS_QUERY_SETUP,
+ NS_QUERY_START_BEGIN,
+ NS_QUERY_LOOKUP_BEGIN,
+ NS_QUERY_RESUME_BEGIN,
+ NS_QUERY_RESUME_RESTORED,
+ NS_QUERY_GOT_ANSWER_BEGIN,
+ NS_QUERY_RESPOND_ANY_BEGIN,
+ NS_QUERY_RESPOND_ANY_FOUND,
+ NS_QUERY_ADDANSWER_BEGIN,
+ NS_QUERY_RESPOND_BEGIN,
+ NS_QUERY_NOTFOUND_BEGIN,
+ NS_QUERY_NOTFOUND_RECURSE,
+ NS_QUERY_PREP_DELEGATION_BEGIN,
+ NS_QUERY_ZONE_DELEGATION_BEGIN,
+ NS_QUERY_DELEGATION_BEGIN,
+ NS_QUERY_DELEGATION_RECURSE_BEGIN,
+ NS_QUERY_NODATA_BEGIN,
+ NS_QUERY_NXDOMAIN_BEGIN,
+ NS_QUERY_NCACHE_BEGIN,
+ NS_QUERY_ZEROTTL_RECURSE,
+ NS_QUERY_CNAME_BEGIN,
+ NS_QUERY_DNAME_BEGIN,
+ NS_QUERY_PREP_RESPONSE_BEGIN,
+ NS_QUERY_DONE_BEGIN,
+ NS_QUERY_DONE_SEND,
+
+ /* XXX other files could be added later */
+
+ NS_HOOKPOINTS_COUNT /* MUST BE LAST */
+} ns_hookpoint_t;
+
+/*
+ * Returned by a hook action to indicate how to proceed after it has
+ * been called: continue processing, or return immediately.
+ */
+typedef enum {
+ NS_HOOK_CONTINUE,
+ NS_HOOK_RETURN,
+} ns_hookresult_t;
+
+typedef ns_hookresult_t (*ns_hook_action_t)(void *arg, void *data,
+ isc_result_t *resultp);
+
+typedef struct ns_hook {
+ isc_mem_t *mctx;
+ ns_hook_action_t action;
+ void *action_data;
+ ISC_LINK(struct ns_hook) link;
+} ns_hook_t;
+
+typedef ISC_LIST(ns_hook_t) ns_hooklist_t;
+typedef ns_hooklist_t ns_hooktable_t[NS_HOOKPOINTS_COUNT];
+
+/*%
+ * ns__hook_table is a global hook table, which is used if view->hooktable
+ * is NULL. It's intended only for use by unit tests.
+ */
+extern ns_hooktable_t *ns__hook_table;
+
+typedef void (*ns_hook_cancelasync_t)(ns_hookasync_t *);
+typedef void (*ns_hook_destroyasync_t)(ns_hookasync_t **);
+
+/*%
+ * Context for a hook-initiated asynchronous process. This works
+ * similarly to dns_fetch_t.
+ */
+struct ns_hookasync {
+ isc_mem_t *mctx;
+
+ /*
+ * The following two are equivalent to dns_resolver_cancelfetch and
+ * dns_resolver_destroyfetch, respectively, but specified as function
+ * pointers since they can be hook-specific.
+ */
+ ns_hook_cancelasync_t cancel;
+ ns_hook_destroyasync_t destroy;
+
+ void *private; /* hook-specific data */
+};
+
+/*
+ * isc_event to be sent on the completion of a hook-initiated asyncronous
+ * process, similar to dns_fetchevent_t.
+ */
+typedef struct ns_hook_resevent {
+ ISC_EVENT_COMMON(struct ns_hook_resevent);
+ ns_hookasync_t *ctx; /* asynchronous processing context */
+ ns_hookpoint_t hookpoint; /* hook point from which to resume */
+ isc_result_t origresult; /* result code at the point of call to hook */
+ query_ctx_t *saved_qctx; /* qctx at the point of call to hook */
+} ns_hook_resevent_t;
+
+/*
+ * Plugin API version
+ *
+ * When the API changes, increment NS_PLUGIN_VERSION. If the
+ * change is backward-compatible (e.g., adding a new function call
+ * but not changing or removing an old one), increment NS_PLUGIN_AGE
+ * as well; if not, set NS_PLUGIN_AGE to 0.
+ */
+#ifndef NS_PLUGIN_VERSION
+#define NS_PLUGIN_VERSION 1
+#define NS_PLUGIN_AGE 0
+#endif /* ifndef NS_PLUGIN_VERSION */
+
+typedef isc_result_t
+ns_plugin_register_t(const char *parameters, const void *cfg, const char *file,
+ unsigned long line, isc_mem_t *mctx, isc_log_t *lctx,
+ void *actx, ns_hooktable_t *hooktable, void **instp);
+/*%<
+ * Called when registering a new plugin.
+ *
+ * 'parameters' contains the plugin configuration text.
+ *
+ * '*instp' will be set to the module instance handle if the function
+ * is successful.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOMEMORY
+ *\li Other errors are possible
+ */
+
+typedef void
+ns_plugin_destroy_t(void **instp);
+/*%<
+ * Destroy a plugin instance.
+ *
+ * '*instp' must be set to NULL by the function before it returns.
+ */
+
+typedef isc_result_t
+ns_plugin_check_t(const char *parameters, const void *cfg, const char *file,
+ unsigned long line, isc_mem_t *mctx, isc_log_t *lctx,
+ void *actx);
+/*%<
+ * Check the validity of 'parameters'.
+ */
+
+typedef int
+ns_plugin_version_t(void);
+/*%<
+ * Return the API version number a plugin was compiled with.
+ *
+ * If the returned version number is no greater than
+ * NS_PLUGIN_VERSION, and no less than NS_PLUGIN_VERSION - NS_PLUGIN_AGE,
+ * then the module is API-compatible with named.
+ */
+
+/*%
+ * Prototypes for API functions to be defined in each module.
+ */
+ns_plugin_check_t plugin_check;
+ns_plugin_destroy_t plugin_destroy;
+ns_plugin_register_t plugin_register;
+ns_plugin_version_t plugin_version;
+
+isc_result_t
+ns_plugin_expandpath(const char *src, char *dst, size_t dstsize);
+/*%<
+ * Prepare the plugin location to be passed to dlopen() based on the plugin
+ * path or filename found in the configuration file ('src'). Store the result
+ * in 'dst', which is 'dstsize' bytes large.
+ *
+ * On Unix systems, two classes of 'src' are recognized:
+ *
+ * - If 'src' is an absolute or relative path, it will be copied to 'dst'
+ * verbatim.
+ *
+ * - If 'src' is a filename (i.e. does not contain a path separator), the
+ * path to the directory into which named plugins are installed will be
+ * prepended to it and the result will be stored in 'dst'.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS Success
+ *\li #ISC_R_NOSPACE 'dst' is not large enough to hold the output string
+ *\li Other result snprintf() returned a negative value
+ */
+
+isc_result_t
+ns_plugin_register(const char *modpath, const char *parameters, const void *cfg,
+ const char *cfg_file, unsigned long cfg_line,
+ isc_mem_t *mctx, isc_log_t *lctx, void *actx,
+ dns_view_t *view);
+/*%<
+ * Load the plugin module specified from the file 'modpath', and
+ * register an instance using 'parameters'.
+ *
+ * 'cfg_file' and 'cfg_line' specify the location of the plugin
+ * declaration in the configuration file.
+ *
+ * 'cfg' and 'actx' are the configuration context and ACL configuration
+ * context, respectively; they are passed as void * here in order to
+ * prevent this library from having a dependency on libisccfg).
+ *
+ * 'instp' will be left pointing to the instance of the plugin
+ * created by the module's plugin_register function.
+ */
+
+isc_result_t
+ns_plugin_check(const char *modpath, const char *parameters, const void *cfg,
+ const char *cfg_file, unsigned long cfg_line, isc_mem_t *mctx,
+ isc_log_t *lctx, void *actx);
+/*%<
+ * Open the plugin module at 'modpath' and check the validity of
+ * 'parameters', logging any errors or warnings found, then
+ * close it without configuring it.
+ */
+
+void
+ns_plugins_create(isc_mem_t *mctx, ns_plugins_t **listp);
+/*%<
+ * Create and initialize a plugin list.
+ */
+
+void
+ns_plugins_free(isc_mem_t *mctx, void **listp);
+/*%<
+ * Close each plugin module in a plugin list, then free the list object.
+ */
+
+void
+ns_hooktable_free(isc_mem_t *mctx, void **tablep);
+/*%<
+ * Free a hook table.
+ */
+
+void
+ns_hook_add(ns_hooktable_t *hooktable, isc_mem_t *mctx,
+ ns_hookpoint_t hookpoint, const ns_hook_t *hook);
+/*%<
+ * Allocate (using memory context 'mctx') a copy of the 'hook' structure
+ * describing a hook action and append it to the list of hooks at 'hookpoint'
+ * in 'hooktable'.
+ *
+ * Requires:
+ *\li 'hooktable' is not NULL
+ *
+ *\li 'mctx' is not NULL
+ *
+ *\li 'hookpoint' is less than NS_QUERY_HOOKS_COUNT
+ *
+ *\li 'hook' is not NULL
+ */
+
+void
+ns_hooktable_init(ns_hooktable_t *hooktable);
+/*%<
+ * Initialize a hook table.
+ */
+
+isc_result_t
+ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep);
+/*%<
+ * Allocate and initialize a hook table.
+ */
diff --git a/lib/ns/include/ns/interfacemgr.h b/lib/ns/include/ns/interfacemgr.h
new file mode 100644
index 0000000..028f86d
--- /dev/null
+++ b/lib/ns/include/ns/interfacemgr.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file
+ * \brief
+ * The interface manager monitors the operating system's list
+ * of network interfaces, creating and destroying listeners
+ * as needed.
+ *
+ * Reliability:
+ *\li No impact expected.
+ *
+ * Resources:
+ *
+ * Security:
+ * \li The server will only be able to bind to the DNS port on
+ * newly discovered interfaces if it is running as root.
+ *
+ * Standards:
+ *\li The API for scanning varies greatly among operating systems.
+ * This module attempts to hide the differences.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <stdbool.h>
+
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/netmgr.h>
+#include <isc/refcount.h>
+#include <isc/result.h>
+
+#include <dns/geoip.h>
+
+#include <ns/listenlist.h>
+#include <ns/types.h>
+
+/***
+ *** Types
+ ***/
+
+#define IFACE_MAGIC ISC_MAGIC('I', ':', '-', ')')
+#define NS_INTERFACE_VALID(t) ISC_MAGIC_VALID(t, IFACE_MAGIC)
+
+#define NS_INTERFACEFLAG_ANYADDR 0x01U /*%< bound to "any" address */
+#define NS_INTERFACEFLAG_LISTENING 0x02U /*%< listening */
+#define MAX_UDP_DISPATCH \
+ 128 /*%< Maximum number of UDP dispatchers \
+ * to start per interface */
+/*% The nameserver interface structure */
+struct ns_interface {
+ unsigned int magic; /*%< Magic number. */
+ ns_interfacemgr_t *mgr; /*%< Interface manager. */
+ isc_mutex_t lock;
+ unsigned int generation; /*%< Generation number. */
+ isc_sockaddr_t addr; /*%< Address and port. */
+ unsigned int flags; /*%< Interface flags */
+ char name[32]; /*%< Null terminated. */
+ isc_nmsocket_t *udplistensocket;
+ isc_nmsocket_t *tcplistensocket;
+ isc_nmsocket_t *http_listensocket;
+ isc_nmsocket_t *http_secure_listensocket;
+ isc_quota_t *http_quota;
+ isc_refcount_t ntcpaccepting; /*%< Number of clients
+ * ready to accept new
+ * TCP connections on this
+ * interface */
+ isc_refcount_t ntcpactive; /*%< Number of clients
+ * servicing TCP queries
+ * (whether accepting or
+ * connected) */
+ ns_clientmgr_t *clientmgr; /*%< Client manager. */
+ ISC_LINK(ns_interface_t) link;
+};
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+ns_interfacemgr_create(isc_mem_t *mctx, ns_server_t *sctx,
+ isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr,
+ isc_nm_t *nm, dns_dispatchmgr_t *dispatchmgr,
+ isc_task_t *task, dns_geoip_databases_t *geoip,
+ int ncpus, bool scan, ns_interfacemgr_t **mgrp);
+/*%<
+ * Create a new interface manager.
+ *
+ * Initially, the new manager will not listen on any interfaces.
+ * Call ns_interfacemgr_setlistenon() and/or ns_interfacemgr_setlistenon6()
+ * to set nonempty listen-on lists.
+ */
+
+void
+ns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target);
+
+void
+ns_interfacemgr_detach(ns_interfacemgr_t **targetp);
+
+void
+ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr);
+
+void
+ns_interfacemgr_setbacklog(ns_interfacemgr_t *mgr, int backlog);
+/*%<
+ * Set the size of the listen() backlog queue.
+ */
+
+bool
+ns_interfacemgr_islistening(ns_interfacemgr_t *mgr);
+/*%<
+ * Return if the manager is listening on any interface. It can be called
+ * after a scan or adjust.
+ */
+
+isc_result_t
+ns_interfacemgr_scan(ns_interfacemgr_t *mgr, bool verbose, bool config);
+/*%<
+ * Scan the operatings system's list of network interfaces
+ * and create listeners when new interfaces are discovered.
+ * Shut down the sockets for interfaces that go away.
+ *
+ * When 'config' is true, also shut down and recreate any existing TLS and HTTPS
+ * interfaces in order to use their new configuration.
+ *
+ * This should be called once on server startup and then
+ * periodically according to the 'interface-interval' option
+ * in named.conf.
+ */
+
+void
+ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value);
+/*%<
+ * Set the IPv4 "listen-on" list of 'mgr' to 'value'.
+ * The previous IPv4 listen-on list is freed.
+ */
+
+void
+ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value);
+/*%<
+ * Set the IPv6 "listen-on" list of 'mgr' to 'value'.
+ * The previous IPv6 listen-on list is freed.
+ */
+
+dns_aclenv_t *
+ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr);
+
+void
+ns_interface_shutdown(ns_interface_t *ifp);
+/*%<
+ * Stop listening for queries on interface 'ifp'.
+ * May safely be called multiple times.
+ */
+
+void
+ns_interfacemgr_dumprecursing(FILE *f, ns_interfacemgr_t *mgr);
+
+bool
+ns_interfacemgr_listeningon(ns_interfacemgr_t *mgr, const isc_sockaddr_t *addr);
+
+ns_server_t *
+ns_interfacemgr_getserver(ns_interfacemgr_t *mgr);
+/*%<
+ * Returns the ns_server object associated with the interface manager.
+ */
+
+ns_clientmgr_t *
+ns_interfacemgr_getclientmgr(ns_interfacemgr_t *mgr);
+/*%<
+ *
+ * Returns the client manager for the current worker thread.
+ * (This cannot be run from outside a network manager thread.)
+ */
diff --git a/lib/ns/include/ns/listenlist.h b/lib/ns/include/ns/listenlist.h
new file mode 100644
index 0000000..5d0a19b
--- /dev/null
+++ b/lib/ns/include/ns/listenlist.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file
+ * \brief
+ * "Listen lists", as in the "listen-on" configuration statement.
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <stdbool.h>
+
+#include <isc/net.h>
+#include <isc/tls.h>
+
+#include <dns/types.h>
+
+/***
+ *** Types
+ ***/
+
+typedef struct ns_listenelt ns_listenelt_t;
+typedef struct ns_listenlist ns_listenlist_t;
+
+struct ns_listenelt {
+ isc_mem_t *mctx;
+ in_port_t port;
+ bool is_http;
+ dns_acl_t *acl;
+ isc_tlsctx_t *sslctx;
+ isc_tlsctx_cache_t *sslctx_cache;
+ char **http_endpoints;
+ size_t http_endpoints_number;
+ uint32_t http_max_clients;
+ uint32_t max_concurrent_streams;
+ ISC_LINK(ns_listenelt_t) link;
+};
+
+struct ns_listenlist {
+ isc_mem_t *mctx;
+ int refcount;
+ ISC_LIST(ns_listenelt_t) elts;
+};
+
+typedef struct ns_listen_tls_params {
+ const char *name;
+ const char *key;
+ const char *cert;
+ const char *ca_file;
+ uint32_t protocols;
+ const char *dhparam_file;
+ const char *ciphers;
+ bool prefer_server_ciphers;
+ bool prefer_server_ciphers_set;
+ bool session_tickets;
+ bool session_tickets_set;
+} ns_listen_tls_params_t;
+
+/***
+ *** Functions
+ ***/
+
+isc_result_t
+ns_listenelt_create(isc_mem_t *mctx, in_port_t port, dns_acl_t *acl,
+ const uint16_t family, bool tls,
+ const ns_listen_tls_params_t *tls_params,
+ isc_tlsctx_cache_t *tlsctx_cache, ns_listenelt_t **target);
+/*%<
+ * Create a listen-on list element.
+ *
+ * Requires:
+ * \li 'targetp' is a valid pointer to a pointer containing 'NULL';
+ * \li 'tls_params' is a valid, non-'NULL' pointer if 'tls' equals 'true'.
+ * \li 'tlsctx_cache' is a valid, non-'NULL' pointer if 'tls' equals 'true'.
+ */
+
+isc_result_t
+ns_listenelt_create_http(isc_mem_t *mctx, in_port_t http_port, dns_acl_t *acl,
+ const uint16_t family, bool tls,
+ const ns_listen_tls_params_t *tls_params,
+ isc_tlsctx_cache_t *tlsctx_cache, char **endpoints,
+ size_t nendpoints, const uint32_t max_clients,
+ const uint32_t max_streams, ns_listenelt_t **target);
+/*%<
+ * Create a listen-on list element for HTTP(S).
+ */
+
+void
+ns_listenelt_destroy(ns_listenelt_t *elt);
+/*%<
+ * Destroy a listen-on list element.
+ */
+
+isc_result_t
+ns_listenlist_create(isc_mem_t *mctx, ns_listenlist_t **target);
+/*%<
+ * Create a new, empty listen-on list.
+ */
+
+void
+ns_listenlist_attach(ns_listenlist_t *source, ns_listenlist_t **target);
+/*%<
+ * Attach '*target' to '*source'.
+ */
+
+void
+ns_listenlist_detach(ns_listenlist_t **listp);
+/*%<
+ * Detach 'listp'.
+ */
+
+isc_result_t
+ns_listenlist_default(isc_mem_t *mctx, in_port_t port, bool enabled,
+ const uint16_t family, ns_listenlist_t **target);
+/*%<
+ * Create a listen-on list with default contents, matching
+ * all addresses with port 'port' (if 'enabled' is true),
+ * or no addresses (if 'enabled' is false).
+ */
diff --git a/lib/ns/include/ns/log.h b/lib/ns/include/ns/log.h
new file mode 100644
index 0000000..3ade016
--- /dev/null
+++ b/lib/ns/include/ns/log.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <isc/log.h>
+#include <isc/types.h>
+
+extern isc_log_t *ns_lctx;
+extern isc_logcategory_t ns_categories[];
+extern isc_logmodule_t ns_modules[];
+
+#define NS_LOGCATEGORY_CLIENT (&ns_categories[0])
+#define NS_LOGCATEGORY_NETWORK (&ns_categories[1])
+#define NS_LOGCATEGORY_UPDATE (&ns_categories[2])
+#define NS_LOGCATEGORY_QUERIES (&ns_categories[3])
+#define NS_LOGCATEGORY_UPDATE_SECURITY (&ns_categories[4])
+#define NS_LOGCATEGORY_QUERY_ERRORS (&ns_categories[5])
+#define NS_LOGCATEGORY_TAT (&ns_categories[6])
+#define NS_LOGCATEGORY_SERVE_STALE (&ns_categories[7])
+
+/*
+ * Backwards compatibility.
+ */
+#define NS_LOGCATEGORY_GENERAL ISC_LOGCATEGORY_GENERAL
+
+#define NS_LOGMODULE_CLIENT (&ns_modules[0])
+#define NS_LOGMODULE_QUERY (&ns_modules[1])
+#define NS_LOGMODULE_INTERFACEMGR (&ns_modules[2])
+#define NS_LOGMODULE_UPDATE (&ns_modules[3])
+#define NS_LOGMODULE_XFER_IN (&ns_modules[4])
+#define NS_LOGMODULE_XFER_OUT (&ns_modules[5])
+#define NS_LOGMODULE_NOTIFY (&ns_modules[6])
+#define NS_LOGMODULE_HOOKS (&ns_modules[7])
+
+void
+ns_log_init(isc_log_t *lctx);
+/*%<
+ * Make the libns categories and modules available for use with the
+ * ISC logging library.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ *
+ *\li ns_log_init() is called only once.
+ *
+ * Ensures:
+ *\li The categories and modules defined above are available for
+ * use by isc_log_usechannnel() and isc_log_write().
+ */
+
+void
+ns_log_setcontext(isc_log_t *lctx);
+/*%<
+ * Make the libns library use the provided context for logging internal
+ * messages.
+ *
+ * Requires:
+ *\li lctx is a valid logging context.
+ */
diff --git a/lib/ns/include/ns/notify.h b/lib/ns/include/ns/notify.h
new file mode 100644
index 0000000..b7e6f7c
--- /dev/null
+++ b/lib/ns/include/ns/notify.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+#include <ns/client.h>
+
+/***
+ *** Module Info
+ ***/
+
+/*! \file
+ * \brief
+ * RFC1996
+ * A Mechanism for Prompt Notification of Zone Changes (DNS NOTIFY)
+ */
+
+/***
+ *** Functions.
+ ***/
+
+void
+ns_notify_start(ns_client_t *client, isc_nmhandle_t *handle);
+
+/*%<
+ * Examines the incoming message to determine appropriate zone.
+ * Returns FORMERR if there is not exactly one question.
+ * Returns REFUSED if we do not serve the listed zone.
+ * Pass the message to the zone module for processing
+ * and returns the return status.
+ *
+ * Requires
+ *\li client to be valid.
+ */
diff --git a/lib/ns/include/ns/query.h b/lib/ns/include/ns/query.h
new file mode 100644
index 0000000..37e5567
--- /dev/null
+++ b/lib/ns/include/ns/query.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <stdbool.h>
+
+#include <isc/buffer.h>
+#include <isc/netaddr.h>
+#include <isc/task.h>
+#include <isc/types.h>
+
+#include <dns/rdataset.h>
+#include <dns/resolver.h>
+#include <dns/rpz.h>
+#include <dns/types.h>
+
+#include <ns/types.h>
+
+/*% nameserver database version structure */
+typedef struct ns_dbversion {
+ dns_db_t *db;
+ dns_dbversion_t *version;
+ bool acl_checked;
+ bool queryok;
+ ISC_LINK(struct ns_dbversion) link;
+} ns_dbversion_t;
+
+/*%
+ * nameserver recursion parameters, to uniquely identify a recursion
+ * query; this is used to detect a recursion loop
+ */
+typedef struct ns_query_recparam {
+ dns_rdatatype_t qtype;
+ dns_name_t *qname;
+ dns_fixedname_t fqname;
+ dns_name_t *qdomain;
+ dns_fixedname_t fqdomain;
+} ns_query_recparam_t;
+
+/*% nameserver query structure */
+struct ns_query {
+ unsigned int attributes;
+ unsigned int restarts;
+ bool timerset;
+ dns_name_t *qname;
+ dns_name_t *origqname;
+ dns_rdatatype_t qtype;
+ unsigned int dboptions;
+ unsigned int fetchoptions;
+ dns_db_t *gluedb;
+ dns_db_t *authdb;
+ dns_zone_t *authzone;
+ bool authdbset;
+ bool isreferral;
+ isc_mutex_t fetchlock;
+ dns_fetch_t *fetch;
+ dns_fetch_t *prefetch;
+ ns_hookasync_t *hookactx;
+ dns_rpz_st_t *rpz_st;
+ isc_bufferlist_t namebufs;
+ ISC_LIST(ns_dbversion_t) activeversions;
+ ISC_LIST(ns_dbversion_t) freeversions;
+ dns_rdataset_t *dns64_aaaa;
+ dns_rdataset_t *dns64_sigaaaa;
+ bool *dns64_aaaaok;
+ unsigned int dns64_aaaaoklen;
+ unsigned int dns64_options;
+ unsigned int dns64_ttl;
+
+ struct {
+ dns_db_t *db;
+ dns_zone_t *zone;
+ dns_dbnode_t *node;
+ dns_rdatatype_t qtype;
+ dns_name_t *fname;
+ dns_fixedname_t fixed;
+ isc_result_t result;
+ dns_rdataset_t *rdataset;
+ dns_rdataset_t *sigrdataset;
+ bool authoritative;
+ bool is_zone;
+ } redirect;
+
+ ns_query_recparam_t recparam;
+
+ dns_keytag_t root_key_sentinel_keyid;
+ bool root_key_sentinel_is_ta;
+ bool root_key_sentinel_not_ta;
+};
+
+#define NS_QUERYATTR_RECURSIONOK 0x000001
+#define NS_QUERYATTR_CACHEOK 0x000002
+#define NS_QUERYATTR_PARTIALANSWER 0x000004
+#define NS_QUERYATTR_NAMEBUFUSED 0x000008
+#define NS_QUERYATTR_RECURSING 0x000010
+#define NS_QUERYATTR_QUERYOKVALID 0x000040
+#define NS_QUERYATTR_QUERYOK 0x000080
+#define NS_QUERYATTR_WANTRECURSION 0x000100
+#define NS_QUERYATTR_SECURE 0x000200
+#define NS_QUERYATTR_NOAUTHORITY 0x000400
+#define NS_QUERYATTR_NOADDITIONAL 0x000800
+#define NS_QUERYATTR_CACHEACLOKVALID 0x001000
+#define NS_QUERYATTR_CACHEACLOK 0x002000
+#define NS_QUERYATTR_DNS64 0x004000
+#define NS_QUERYATTR_DNS64EXCLUDE 0x008000
+#define NS_QUERYATTR_RRL_CHECKED 0x010000
+#define NS_QUERYATTR_REDIRECT 0x020000
+#define NS_QUERYATTR_ANSWERED 0x040000
+#define NS_QUERYATTR_STALEOK 0x080000
+#define NS_QUERYATTR_STALEPENDING 0x100000
+
+typedef struct query_ctx query_ctx_t;
+
+/* query context structure */
+struct query_ctx {
+ isc_buffer_t *dbuf; /* name buffer */
+ dns_name_t *fname; /* found name from DB lookup */
+ dns_name_t *tname; /* temporary name, used
+ * when processing ANY
+ * queries */
+ dns_rdataset_t *rdataset; /* found rdataset */
+ dns_rdataset_t *sigrdataset; /* found sigrdataset */
+ dns_rdataset_t *noqname; /* rdataset needing
+ * NOQNAME proof */
+ dns_rdatatype_t qtype;
+ dns_rdatatype_t type;
+
+ unsigned int options; /* DB lookup options */
+
+ bool redirected; /* nxdomain redirected? */
+ bool is_zone; /* is DB a zone DB? */
+ bool is_staticstub_zone;
+ bool resuming; /* resumed from recursion? */
+ bool dns64, dns64_exclude, rpz;
+ bool authoritative; /* authoritative query? */
+ bool want_restart; /* CNAME chain or other
+ * restart needed */
+ bool refresh_rrset; /* stale RRset refresh needed */
+ bool need_wildcardproof; /* wildcard proof needed */
+ bool nxrewrite; /* negative answer from RPZ */
+ bool findcoveringnsec; /* lookup covering NSEC */
+ bool answer_has_ns; /* NS is in answer */
+ dns_fixedname_t wildcardname; /* name needing wcard proof */
+ dns_fixedname_t dsname; /* name needing DS */
+
+ ns_client_t *client; /* client object */
+ bool detach_client; /* client needs detaching */
+
+ dns_fetchevent_t *event; /* recursion event */
+
+ dns_db_t *db; /* zone or cache database */
+ dns_dbversion_t *version; /* DB version */
+ dns_dbnode_t *node; /* DB node */
+
+ dns_db_t *zdb; /* zone DB values, saved */
+ dns_dbnode_t *znode; /* while searching cache */
+ dns_name_t *zfname; /* for a better answer */
+ dns_dbversion_t *zversion;
+ dns_rdataset_t *zrdataset;
+ dns_rdataset_t *zsigrdataset;
+
+ dns_rpz_st_t *rpz_st; /* RPZ state */
+ dns_zone_t *zone; /* zone to search */
+
+ dns_view_t *view; /* client view */
+
+ isc_result_t result; /* query result */
+ int line; /* line to report error */
+};
+
+typedef isc_result_t (*ns_query_starthookasync_t)(
+ query_ctx_t *qctx, isc_mem_t *mctx, void *arg, isc_task_t *task,
+ isc_taskaction_t action, void *evarg, ns_hookasync_t **ctxp);
+
+/*
+ * The following functions are expected to be used only within query.c
+ * and query modules.
+ */
+
+isc_result_t
+ns_query_done(query_ctx_t *qctx);
+/*%<
+ * Finalize this phase of the query process:
+ *
+ * - Clean up.
+ * - If we have an answer ready (positive or negative), send it.
+ * - If we need to restart for a chaining query, call ns__query_start() again.
+ * - If we've started recursion, then just clean up; things will be
+ * restarted via fetch_callback()/query_resume().
+ */
+
+isc_result_t
+ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
+ dns_name_t *qdomain, dns_rdataset_t *nameservers,
+ bool resuming);
+/*%<
+ * Prepare client for recursion, then create a resolver fetch, with
+ * the event callback set to fetch_callback(). Afterward we terminate
+ * this phase of the query, and resume with a new query context when
+ * recursion completes.
+ */
+
+isc_result_t
+ns_query_hookasync(query_ctx_t *qctx, ns_query_starthookasync_t runasync,
+ void *arg);
+/*%<
+ * Prepare the client for an asynchronous hook action, then call the
+ * specified 'runasync' function to start an asynchronous process running
+ * in the background. This function works similarly to ns_query_recurse(),
+ * but is expected to be called from a query hook action to support
+ * asynchronous event handling in a hook. A typical use case would be for
+ * a plugin to initiate recursion, but it may also be used to carry out
+ * other time-consuming tasks without blocking the caller or the worker
+ * thread.
+ *
+ * The calling plugin action must pass 'qctx' as passed from the query
+ * module.
+ *
+ * Once a plugin action calls this function, the ownership of 'qctx' is
+ * essentially transferred to the query module. Regardless of the return
+ * value of this function, the hook must not use 'qctx' anymore.
+ *
+ * This function must not be called after ns_query_recurse() is called,
+ * until the fetch is completed, as it needs resources that
+ * ns_query_recurse() would also use.
+ *
+ * See hooks.h for details about how 'runasync' is supposed to work, and
+ * other aspects of hook-triggered asynchronous event handling.
+ */
+
+isc_result_t
+ns_query_init(ns_client_t *client);
+
+void
+ns_query_free(ns_client_t *client);
+
+void
+ns_query_start(ns_client_t *client, isc_nmhandle_t *handle);
+
+void
+ns_query_cancel(ns_client_t *client);
+
+/*
+ * 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);
+/*%<
+ * (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.)
+ */
diff --git a/lib/ns/include/ns/server.h b/lib/ns/include/ns/server.h
new file mode 100644
index 0000000..206c495
--- /dev/null
+++ b/lib/ns/include/ns/server.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include <isc/fuzz.h>
+#include <isc/log.h>
+#include <isc/magic.h>
+#include <isc/quota.h>
+#include <isc/random.h>
+#include <isc/sockaddr.h>
+#include <isc/types.h>
+
+#include <dns/acl.h>
+#include <dns/types.h>
+
+#include <ns/events.h>
+#include <ns/types.h>
+
+#define NS_SERVER_LOGQUERIES 0x00000001U /*%< log queries */
+#define NS_SERVER_NOAA 0x00000002U /*%< -T noaa */
+#define NS_SERVER_NOSOA 0x00000004U /*%< -T nosoa */
+#define NS_SERVER_NONEAREST 0x00000008U /*%< -T nonearest */
+#define NS_SERVER_NOEDNS 0x00000020U /*%< -T noedns */
+#define NS_SERVER_DROPEDNS 0x00000040U /*%< -T dropedns */
+#define NS_SERVER_NOTCP 0x00000080U /*%< -T notcp */
+#define NS_SERVER_DISABLE4 0x00000100U /*%< -6 */
+#define NS_SERVER_DISABLE6 0x00000200U /*%< -4 */
+#define NS_SERVER_FIXEDLOCAL 0x00000400U /*%< -T fixedlocal */
+#define NS_SERVER_SIGVALINSECS 0x00000800U /*%< -T sigvalinsecs */
+#define NS_SERVER_EDNSFORMERR 0x00001000U /*%< -T ednsformerr (STD13) */
+#define NS_SERVER_EDNSNOTIMP 0x00002000U /*%< -T ednsnotimp */
+#define NS_SERVER_EDNSREFUSED 0x00004000U /*%< -T ednsrefused */
+#define NS_SERVER_TRANSFERINSECS 0x00008000U /*%< -T transferinsecs */
+#define NS_SERVER_TRANSFERSLOWLY 0x00010000U /*%< -T transferslowly */
+#define NS_SERVER_TRANSFERSTUCK 0x00020000U /*%< -T transferstuck */
+
+/*%
+ * Type for callback function to get hostname.
+ */
+typedef isc_result_t (*ns_hostnamecb_t)(char *buf, size_t len);
+
+/*%
+ * Type for callback function to signal the fuzzer thread
+ * when built with AFL.
+ */
+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, isc_result_t *sigresultp, dns_view_t **viewp);
+
+/*%
+ * Server context.
+ */
+struct ns_server {
+ unsigned int magic;
+ isc_mem_t *mctx;
+
+ isc_refcount_t references;
+
+ /*% Server cookie secret and algorithm */
+ unsigned char secret[32];
+ ns_cookiealg_t cookiealg;
+ ns_altsecretlist_t altsecrets;
+ bool answercookie;
+
+ /*% Quotas */
+ isc_quota_t recursionquota;
+ isc_quota_t tcpquota;
+ isc_quota_t xfroutquota;
+ isc_quota_t updquota;
+ ISC_LIST(isc_quota_t) http_quotas;
+ isc_mutex_t http_quotas_lock;
+
+ /*% Test options and other configurables */
+ uint32_t options;
+
+ dns_acl_t *blackholeacl;
+ dns_acl_t *keepresporder;
+ uint16_t udpsize;
+ uint16_t transfer_tcp_message_size;
+ bool interface_auto;
+ dns_tkeyctx_t *tkeyctx;
+
+ /*% Server id for NSID */
+ char *server_id;
+ bool usehostname;
+
+ /*% Fuzzer callback */
+ isc_fuzztype_t fuzztype;
+ ns_fuzzcb_t fuzznotify;
+
+ /*% Callback to find a matching view for a query */
+ ns_matchview_t matchingview;
+
+ /*% Stats counters */
+ ns_stats_t *nsstats;
+ dns_stats_t *rcvquerystats;
+ dns_stats_t *opcodestats;
+ dns_stats_t *rcodestats;
+
+ isc_stats_t *udpinstats4;
+ isc_stats_t *udpoutstats4;
+ isc_stats_t *udpinstats6;
+ isc_stats_t *udpoutstats6;
+
+ isc_stats_t *tcpinstats4;
+ isc_stats_t *tcpoutstats4;
+ isc_stats_t *tcpinstats6;
+ isc_stats_t *tcpoutstats6;
+};
+
+struct ns_altsecret {
+ ISC_LINK(ns_altsecret_t) link;
+ unsigned char secret[32];
+};
+
+isc_result_t
+ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview,
+ ns_server_t **sctxp);
+/*%<
+ * Create a server context object with default settings.
+ */
+
+void
+ns_server_attach(ns_server_t *src, ns_server_t **dest);
+/*%<
+ * Attach a server context.
+ *
+ * Requires:
+ *\li 'src' is valid.
+ */
+
+void
+ns_server_detach(ns_server_t **sctxp);
+/*%<
+ * Detach from a server context. If its reference count drops to zero, destroy
+ * it, freeing its memory.
+ *
+ * Requires:
+ *\li '*sctxp' is valid.
+ * Ensures:
+ *\li '*sctxp' is NULL on return.
+ */
+
+isc_result_t
+ns_server_setserverid(ns_server_t *sctx, const char *serverid);
+/*%<
+ * Set sctx->server_id to 'serverid'. If it was set previously, free the memory.
+ *
+ * Requires:
+ *\li 'sctx' is valid.
+ */
+
+void
+ns_server_setoption(ns_server_t *sctx, unsigned int option, bool value);
+/*%<
+ * Set the given options on (if 'value' == #true)
+ * or off (if 'value' == #false).
+ *
+ * Requires:
+ *\li 'sctx' is valid
+ */
+
+bool
+ns_server_getoption(ns_server_t *sctx, unsigned int option);
+/*%<
+ * Returns the current value of the specified server option.
+ *
+ * Requires:
+ *\li 'sctx' is valid.
+ */
+
+void
+ns_server_append_http_quota(ns_server_t *sctx, isc_quota_t *http_quota);
+/*%<
+ * Add a quota to the list of HTTP quotas to destroy it safely later.
+ *
+ * Requires:
+ *\li 'sctx' is valid;
+ *\li 'http_quota' is not 'NULL'.
+ */
diff --git a/lib/ns/include/ns/sortlist.h b/lib/ns/include/ns/sortlist.h
new file mode 100644
index 0000000..3333e9c
--- /dev/null
+++ b/lib/ns/include/ns/sortlist.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+/*! \file */
+
+#include <isc/types.h>
+
+#include <dns/acl.h>
+#include <dns/types.h>
+
+/*%
+ * Type for callback functions that rank addresses.
+ */
+typedef int (*dns_addressorderfunc_t)(const isc_netaddr_t *address,
+ const void *arg);
+
+/*%
+ * Return value type for setup_sortlist.
+ */
+typedef enum {
+ NS_SORTLISTTYPE_NONE,
+ NS_SORTLISTTYPE_1ELEMENT,
+ NS_SORTLISTTYPE_2ELEMENT
+} ns_sortlisttype_t;
+
+ns_sortlisttype_t
+ns_sortlist_setup(dns_acl_t *acl, dns_aclenv_t *env, isc_netaddr_t *clientaddr,
+ void **argp);
+/*%<
+ * Find the sortlist statement in 'acl' (for ACL environment 'env')
+ * that applies to 'clientaddr', if any.
+ *
+ * If a 1-element sortlist item applies, return NS_SORTLISTTYPE_1ELEMENT and
+ * make '*argp' point to the matching subelement.
+ *
+ * If a 2-element sortlist item applies, return NS_SORTLISTTYPE_2ELEMENT and
+ * make '*argp' point to ACL that forms the second element.
+ *
+ * If no sortlist item applies, return NS_SORTLISTTYPE_NONE and set '*argp'
+ * to NULL.
+ */
+
+int
+ns_sortlist_addrorder1(const isc_netaddr_t *addr, const void *arg);
+/*%<
+ * Find the sort order of 'addr' in 'arg', the matching element
+ * of a 1-element top-level sortlist statement.
+ */
+
+int
+ns_sortlist_addrorder2(const isc_netaddr_t *addr, const void *arg);
+/*%<
+ * Find the sort order of 'addr' in 'arg', a topology-like
+ * ACL forming the second element in a 2-element top-level
+ * sortlist statement.
+ */
+
+void
+ns_sortlist_byaddrsetup(dns_acl_t *sortlist_acl, dns_aclenv_t *env,
+ isc_netaddr_t *client_addr,
+ dns_addressorderfunc_t *orderp, void **argp);
+/*%<
+ * Find the sortlist statement in 'acl' that applies to 'clientaddr', if any.
+ * If a sortlist statement applies, return in '*orderp' a pointer to a function
+ * for ranking network addresses based on that sortlist statement, and in
+ * '*argp' an argument to pass to said function. If no sortlist statement
+ * applies, set '*orderp' and '*argp' to NULL.
+ */
diff --git a/lib/ns/include/ns/stats.h b/lib/ns/include/ns/stats.h
new file mode 100644
index 0000000..c235384
--- /dev/null
+++ b/lib/ns/include/ns/stats.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+/*! \file include/ns/stats.h */
+
+#include <ns/types.h>
+
+/*%
+ * Server statistics counters. Used as isc_statscounter_t values.
+ */
+enum {
+ ns_statscounter_requestv4 = 0,
+ ns_statscounter_requestv6 = 1,
+ ns_statscounter_edns0in = 2,
+ ns_statscounter_badednsver = 3,
+ ns_statscounter_tsigin = 4,
+ ns_statscounter_sig0in = 5,
+ ns_statscounter_invalidsig = 6,
+ ns_statscounter_requesttcp = 7,
+
+ ns_statscounter_authrej = 8,
+ ns_statscounter_recurserej = 9,
+ ns_statscounter_xfrrej = 10,
+ ns_statscounter_updaterej = 11,
+
+ ns_statscounter_response = 12,
+ ns_statscounter_truncatedresp = 13,
+ ns_statscounter_edns0out = 14,
+ ns_statscounter_tsigout = 15,
+ ns_statscounter_sig0out = 16,
+
+ ns_statscounter_success = 17,
+ ns_statscounter_authans = 18,
+ ns_statscounter_nonauthans = 19,
+ ns_statscounter_referral = 20,
+ ns_statscounter_nxrrset = 21,
+ ns_statscounter_servfail = 22,
+ ns_statscounter_formerr = 23,
+ ns_statscounter_nxdomain = 24,
+ ns_statscounter_recursion = 25,
+ ns_statscounter_duplicate = 26,
+ ns_statscounter_dropped = 27,
+ ns_statscounter_failure = 28,
+
+ ns_statscounter_xfrdone = 29,
+
+ ns_statscounter_updatereqfwd = 30,
+ ns_statscounter_updaterespfwd = 31,
+ ns_statscounter_updatefwdfail = 32,
+ ns_statscounter_updatedone = 33,
+ ns_statscounter_updatefail = 34,
+ ns_statscounter_updatebadprereq = 35,
+
+ ns_statscounter_recursclients = 36,
+
+ ns_statscounter_dns64 = 37,
+
+ ns_statscounter_ratedropped = 38,
+ ns_statscounter_rateslipped = 39,
+
+ ns_statscounter_rpz_rewrites = 40,
+
+ ns_statscounter_udp = 41,
+ ns_statscounter_tcp = 42,
+
+ ns_statscounter_nsidopt = 43,
+ ns_statscounter_expireopt = 44,
+ ns_statscounter_otheropt = 45,
+ ns_statscounter_ecsopt = 46,
+ ns_statscounter_padopt = 47,
+ ns_statscounter_keepaliveopt = 48,
+
+ ns_statscounter_nxdomainredirect = 49,
+ ns_statscounter_nxdomainredirect_rlookup = 50,
+
+ ns_statscounter_cookiein = 51,
+ ns_statscounter_cookiebadsize = 52,
+ ns_statscounter_cookiebadtime = 53,
+ ns_statscounter_cookienomatch = 54,
+ ns_statscounter_cookiematch = 55,
+ ns_statscounter_cookienew = 56,
+ ns_statscounter_badcookie = 57,
+
+ ns_statscounter_nxdomainsynth = 58,
+ ns_statscounter_nodatasynth = 59,
+ ns_statscounter_wildcardsynth = 60,
+
+ ns_statscounter_trystale = 61,
+ ns_statscounter_usedstale = 62,
+
+ ns_statscounter_prefetch = 63,
+ ns_statscounter_keytagopt = 64,
+
+ ns_statscounter_tcphighwater = 65,
+
+ ns_statscounter_reclimitdropped = 66,
+
+ ns_statscounter_updatequota = 67,
+
+ ns_statscounter_max = 68,
+};
+
+void
+ns_stats_attach(ns_stats_t *stats, ns_stats_t **statsp);
+
+void
+ns_stats_detach(ns_stats_t **statsp);
+
+isc_result_t
+ns_stats_create(isc_mem_t *mctx, int ncounters, ns_stats_t **statsp);
+
+void
+ns_stats_increment(ns_stats_t *stats, isc_statscounter_t counter);
+
+void
+ns_stats_decrement(ns_stats_t *stats, isc_statscounter_t counter);
+
+isc_stats_t *
+ns_stats_get(ns_stats_t *stats);
+
+void
+ns_stats_update_if_greater(ns_stats_t *stats, isc_statscounter_t counter,
+ isc_statscounter_t value);
+
+isc_statscounter_t
+ns_stats_get_counter(ns_stats_t *stats, isc_statscounter_t counter);
diff --git a/lib/ns/include/ns/types.h b/lib/ns/include/ns/types.h
new file mode 100644
index 0000000..85205d7
--- /dev/null
+++ b/lib/ns/include/ns/types.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+/*! \file */
+
+typedef struct ns_altsecret ns_altsecret_t;
+typedef ISC_LIST(ns_altsecret_t) ns_altsecretlist_t;
+typedef struct ns_client ns_client_t;
+typedef struct ns_clientmgr ns_clientmgr_t;
+typedef struct ns_plugin ns_plugin_t;
+typedef ISC_LIST(ns_plugin_t) ns_plugins_t;
+typedef struct ns_interface ns_interface_t;
+typedef struct ns_interfacemgr ns_interfacemgr_t;
+typedef struct ns_query ns_query_t;
+typedef struct ns_server ns_server_t;
+typedef struct ns_stats ns_stats_t;
+typedef struct ns_hookasync ns_hookasync_t;
+
+typedef enum { ns_cookiealg_aes, ns_cookiealg_siphash24 } ns_cookiealg_t;
+
+#define NS_COOKIE_VERSION_1 1
diff --git a/lib/ns/include/ns/update.h b/lib/ns/include/ns/update.h
new file mode 100644
index 0000000..fbabdf9
--- /dev/null
+++ b/lib/ns/include/ns/update.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file
+ * \brief
+ * RFC2136 Dynamic Update
+ */
+
+/***
+ *** Imports
+ ***/
+
+#include <isc/result.h>
+
+#include <dns/types.h>
+
+/***
+ *** Types.
+ ***/
+
+/***
+ *** Functions
+ ***/
+
+void
+ns_update_start(ns_client_t *client, isc_nmhandle_t *handle,
+ isc_result_t sigresult);
diff --git a/lib/ns/include/ns/xfrout.h b/lib/ns/include/ns/xfrout.h
new file mode 100644
index 0000000..d36060e
--- /dev/null
+++ b/lib/ns/include/ns/xfrout.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * 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 https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+/*****
+***** Module Info
+*****/
+
+/*! \file
+ * \brief
+ * Outgoing zone transfers (AXFR + IXFR).
+ */
+
+/***
+ *** Functions
+ ***/
+
+void
+ns_xfr_start(ns_client_t *client, dns_rdatatype_t xfrtype);