diff options
Diffstat (limited to '')
107 files changed, 32238 insertions, 0 deletions
diff --git a/lib/dns/include/.clang-format b/lib/dns/include/.clang-format new file mode 120000 index 0000000..0e62f72 --- /dev/null +++ b/lib/dns/include/.clang-format @@ -0,0 +1 @@ +../../../.clang-format.headers
\ No newline at end of file diff --git a/lib/dns/include/Makefile.in b/lib/dns/include/Makefile.in new file mode 100644 index 0000000..cf869c0 --- /dev/null +++ b/lib/dns/include/Makefile.in @@ -0,0 +1,19 @@ +# 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. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +SUBDIRS = dns dst +TARGETS = + +@BIND9_MAKE_RULES@ diff --git a/lib/dns/include/dns/Makefile.in b/lib/dns/include/dns/Makefile.in new file mode 100644 index 0000000..88b9bcf --- /dev/null +++ b/lib/dns/include/dns/Makefile.in @@ -0,0 +1,63 @@ +# 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. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +VERSION=@BIND9_VERSION@ + +HEADERS = acl.h adb.h badcache.h bit.h byaddr.h \ + cache.h callbacks.h catz.h cert.h \ + client.h clientinfo.h compress.h \ + db.h dbiterator.h dbtable.h diff.h dispatch.h \ + dlz.h dlz_dlopen.h dns64.h dnsrps.h dnssec.h ds.h dsdigest.h \ + dnstap.h dyndb.h ecs.h \ + edns.h ecdb.h events.h fixedname.h forward.h geoip.h \ + ipkeylist.h iptable.h \ + journal.h kasp.h keydata.h keyflags.h keymgr.h keytable.h \ + keyvalues.h lib.h librpz.h lmdb.h lookup.h log.h \ + master.h masterdump.h message.h \ + name.h ncache.h nsec.h nsec3.h nta.h opcode.h order.h \ + peer.h portlist.h private.h \ + rbt.h rcode.h rdata.h rdataclass.h rdatalist.h \ + rdataset.h rdatasetiter.h rdataslab.h rdatatype.h request.h \ + resolver.h result.h rootns.h rpz.h rriterator.h rrl.h \ + sdb.h sdlz.h secalg.h secproto.h soa.h ssu.h stats.h \ + tcpmsg.h time.h timer.h tkey.h tsec.h tsig.h ttl.h types.h \ + update.h validator.h version.h view.h xfrin.h \ + zone.h zonekey.h zoneverify.h zt.h + +GENHEADERS = enumclass.h enumtype.h rdatastruct.h + +SUBDIRS = +TARGETS = + +@BIND9_MAKE_RULES@ + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/dns + +install:: installdirs + for i in ${HEADERS}; do \ + ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/dns || exit 1; \ + done + for i in ${GENHEADERS}; do \ + ${INSTALL_DATA} $$i ${DESTDIR}${includedir}/dns || exit 1; \ + done + +uninstall:: + for i in ${GENHEADERS}; do \ + rm -f ${DESTDIR}${includedir}/dns/$$i || exit 1; \ + done + for i in ${HEADERS}; do \ + rm -f ${DESTDIR}${includedir}/dns/$$i || exit 1; \ + done diff --git a/lib/dns/include/dns/acl.h b/lib/dns/include/dns/acl.h new file mode 100644 index 0000000..43fe15b --- /dev/null +++ b/lib/dns/include/dns/acl.h @@ -0,0 +1,253 @@ +/* + * 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. + */ + +#ifndef DNS_ACL_H +#define DNS_ACL_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/acl.h + * \brief + * Address match list handling. + */ + +/*** + *** Imports + ***/ + +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/netaddr.h> +#include <isc/refcount.h> + +#include <dns/geoip.h> +#include <dns/iptable.h> +#include <dns/name.h> +#include <dns/types.h> + +/*** + *** Types + ***/ + +typedef enum { + dns_aclelementtype_ipprefix, + dns_aclelementtype_keyname, + dns_aclelementtype_nestedacl, + dns_aclelementtype_localhost, + dns_aclelementtype_localnets, +#if defined(HAVE_GEOIP2) + dns_aclelementtype_geoip, +#endif /* HAVE_GEOIP2 */ + dns_aclelementtype_any +} dns_aclelementtype_t; + +typedef struct dns_aclipprefix dns_aclipprefix_t; + +struct dns_aclipprefix { + isc_netaddr_t address; /* IP4/IP6 */ + unsigned int prefixlen; +}; + +struct dns_aclelement { + dns_aclelementtype_t type; + bool negative; + dns_name_t keyname; +#if defined(HAVE_GEOIP2) + dns_geoip_elem_t geoip_elem; +#endif /* HAVE_GEOIP2 */ + dns_acl_t *nestedacl; + int node_num; +}; + +#define dns_acl_node_count(acl) acl->iptable->radix->num_added_node + +struct dns_acl { + unsigned int magic; + isc_mem_t *mctx; + isc_refcount_t refcount; + dns_iptable_t *iptable; + dns_aclelement_t *elements; + bool has_negatives; + unsigned int alloc; /*%< Elements allocated */ + unsigned int length; /*%< Elements initialized */ + char *name; /*%< Temporary use only */ + ISC_LINK(dns_acl_t) nextincache; /*%< Ditto */ +}; + +struct dns_aclenv { + dns_acl_t *localhost; + dns_acl_t *localnets; + bool match_mapped; +#if defined(HAVE_GEOIP2) + dns_geoip_databases_t *geoip; +#endif /* HAVE_GEOIP2 */ +}; + +#define DNS_ACL_MAGIC ISC_MAGIC('D', 'a', 'c', 'l') +#define DNS_ACL_VALID(a) ISC_MAGIC_VALID(a, DNS_ACL_MAGIC) + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_acl_create(isc_mem_t *mctx, int n, dns_acl_t **target); +/*%< + * Create a new ACL, including an IP table and an array with room + * for 'n' ACL elements. The elements are uninitialized and the + * length is 0. + */ + +isc_result_t +dns_acl_any(isc_mem_t *mctx, dns_acl_t **target); +/*%< + * Create a new ACL that matches everything. + */ + +isc_result_t +dns_acl_none(isc_mem_t *mctx, dns_acl_t **target); +/*%< + * Create a new ACL that matches nothing. + */ + +bool +dns_acl_isany(dns_acl_t *acl); +/*%< + * Test whether ACL is set to "{ any; }" + */ + +bool +dns_acl_isnone(dns_acl_t *acl); +/*%< + * Test whether ACL is set to "{ none; }" + */ + +isc_result_t +dns_acl_merge(dns_acl_t *dest, dns_acl_t *source, bool pos); +/*%< + * Merge the contents of one ACL into another. Call dns_iptable_merge() + * for the IP tables, then concatenate the element arrays. + * + * If pos is set to false, then the nested ACL is to be negated. This + * means reverse the sense of each *positive* element or IP table node, + * but leave negatives alone, so as to prevent a double-negative causing + * an unexpected positive match in the parent ACL. + */ + +void +dns_acl_attach(dns_acl_t *source, dns_acl_t **target); +/*%< + * Attach to acl 'source'. + * + * Requires: + *\li 'source' to be a valid acl. + *\li 'target' to be non NULL and '*target' to be NULL. + */ + +void +dns_acl_detach(dns_acl_t **aclp); +/*%< + * Detach the acl. On final detach the acl must not be linked on any + * list. + * + * Requires: + *\li '*aclp' to be a valid acl. + * + * Insists: + *\li '*aclp' is not linked on final detach. + */ + +bool +dns_acl_isinsecure(const dns_acl_t *a); +/*%< + * Return #true iff the acl 'a' is considered insecure, that is, + * if it contains IP addresses other than those of the local host. + * This is intended for applications such as printing warning + * messages for suspect ACLs; it is not intended for making access + * control decisions. We make no guarantee that an ACL for which + * this function returns #false is safe. + */ + +bool +dns_acl_allowed(isc_netaddr_t *addr, const dns_name_t *signer, dns_acl_t *acl, + dns_aclenv_t *aclenv); +/*%< + * Return #true iff the 'addr', 'signer', or ECS values are + * permitted by 'acl' in environment 'aclenv'. + */ + +isc_result_t +dns_aclenv_init(isc_mem_t *mctx, dns_aclenv_t *env); +/*%< + * Initialize ACL environment, setting up localhost and localnets ACLs + */ + +void +dns_aclenv_copy(dns_aclenv_t *t, dns_aclenv_t *s); + +void +dns_aclenv_destroy(dns_aclenv_t *env); + +isc_result_t +dns_acl_match(const isc_netaddr_t *reqaddr, const dns_name_t *reqsigner, + const dns_acl_t *acl, const dns_aclenv_t *env, int *match, + const dns_aclelement_t **matchelt); +/*%< + * General, low-level ACL matching. This is expected to + * be useful even for weird stuff like the topology and sortlist statements. + * + * Match the address 'reqaddr', and optionally the key name 'reqsigner', + * against 'acl'. 'reqsigner' may be NULL. + * + * If there is a match, '*match' will be set to an integer whose absolute + * value corresponds to the order in which the matching value was inserted + * into the ACL. For a positive match, this value will be positive; for a + * negative match, it will be negative. + * + * If there is no match, *match will be set to zero. + * + * If there is a match in the element list (either positive or negative) + * and 'matchelt' is non-NULL, *matchelt will be pointed to the matching + * element. + * + * 'env' points to the current ACL environment, including the + * current values of localhost and localnets and (if applicable) + * the GeoIP context. + * + * Returns: + *\li #ISC_R_SUCCESS Always succeeds. + */ + +bool +dns_aclelement_match(const isc_netaddr_t *reqaddr, const dns_name_t *reqsigner, + const dns_aclelement_t *e, const dns_aclenv_t *env, + const dns_aclelement_t **matchelt); +/*%< + * Like dns_acl_match, but matches against the single ACL element 'e' + * rather than a complete ACL, and returns true iff it matched. + * + * To determine whether the match was positive or negative, the + * caller should examine e->negative. Since the element 'e' may be + * a reference to a named ACL or a nested ACL, a matching element + * returned through 'matchelt' is not necessarily 'e' itself. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_ACL_H */ diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h new file mode 100644 index 0000000..4e05fd6 --- /dev/null +++ b/lib/dns/include/dns/adb.h @@ -0,0 +1,835 @@ +/* + * 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. + */ + +#ifndef DNS_ADB_H +#define DNS_ADB_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/adb.h + *\brief + * DNS Address Database + * + * This module implements an address database (ADB) for mapping a name + * to an isc_sockaddr_t. It also provides statistical information on + * how good that address might be. + * + * A client will pass in a dns_name_t, and the ADB will walk through + * the rdataset looking up addresses associated with the name. If it + * is found on the internal lists, a structure is filled in with the + * address information and stats for found addresses. + * + * If the name cannot be found on the internal lists, a new entry will + * be created for a name if all the information needed can be found + * in the zone table or cache. This new address will then be returned. + * + * If a request must be made to remote servers to satisfy a name lookup, + * this module will start fetches to try to complete these addresses. When + * at least one more completes, an event is sent to the caller. If none of + * them resolve before the fetch times out, an event indicating this is + * sent instead. + * + * Records are stored internally until a timer expires. The timer is the + * smaller of the TTL or signature validity period. + * + * Lameness is stored per <qname,qtype> tuple, and this data hangs off each + * address field. When an address is marked lame for a given tuple the address + * will not be returned to a caller. + * + * + * MP: + * + *\li The ADB takes care of all necessary locking. + * + *\li Only the task which initiated the name lookup can cancel the lookup. + * + * + * Security: + * + *\li None, since all data stored is required to be pre-filtered. + * (Cache needs to be sane, fetches return bounds-checked and sanity- + * checked data, caller passes a good dns_name_t for the zone, etc) + */ + +/*** + *** Imports + ***/ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/mem.h> +#include <isc/sockaddr.h> + +#include <dns/types.h> +#include <dns/view.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Magic number checks + ***/ + +#define DNS_ADBFIND_MAGIC ISC_MAGIC('a', 'd', 'b', 'H') +#define DNS_ADBFIND_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFIND_MAGIC) +#define DNS_ADBADDRINFO_MAGIC ISC_MAGIC('a', 'd', 'A', 'I') +#define DNS_ADBADDRINFO_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBADDRINFO_MAGIC) + +/*** + *** TYPES + ***/ + +typedef struct dns_adbname dns_adbname_t; + +/*! + *\brief + * Represents a lookup for a single name. + * + * On return, the client can safely use "list", and can reorder the list. + * Items may not be _deleted_ from this list, however, or added to it + * other than by using the dns_adb_*() API. + */ +struct dns_adbfind { + /* Public */ + unsigned int magic; /*%< RO: magic */ + dns_adbaddrinfolist_t list; /*%< RO: list of addrs */ + unsigned int query_pending; /*%< RO: partial list */ + unsigned int partial_result; /*%< RO: addrs missing */ + unsigned int options; /*%< RO: options */ + isc_result_t result_v4; /*%< RO: v4 result */ + isc_result_t result_v6; /*%< RO: v6 result */ + ISC_LINK(dns_adbfind_t) publink; /*%< RW: client use */ + + /* Private */ + isc_mutex_t lock; /* locks all below */ + in_port_t port; + int name_bucket; + unsigned int flags; + dns_adbname_t *adbname; + dns_adb_t *adb; + isc_event_t event; + ISC_LINK(dns_adbfind_t) plink; +}; + +/* + * _INET: + * _INET6: + * return addresses of that type. + * + * _EMPTYEVENT: + * Only schedule an event if no addresses are known. + * Must set _WANTEVENT for this to be meaningful. + * + * _WANTEVENT: + * An event is desired. Check this bit in the returned find to see + * if one will actually be generated. + * + * _AVOIDFETCHES: + * If set, fetches will not be generated unless no addresses are + * available in any of the address families requested. + * + * _STARTATZONE: + * Fetches will start using the closest zone data or use the root servers. + * This is useful for reestablishing glue that has expired. + * + * _GLUEOK: + * _HINTOK: + * Glue or hints are ok. These are used when matching names already + * in the adb, and when dns databases are searched. + * + * _RETURNLAME: + * Return lame servers in a find, so that all addresses are returned. + * + * _LAMEPRUNED: + * At least one address was omitted from the list because it was lame. + * This bit will NEVER be set if _RETURNLAME is set in the createfind(). + */ +/*% Return addresses of type INET. */ +#define DNS_ADBFIND_INET 0x00000001 +/*% Return addresses of type INET6. */ +#define DNS_ADBFIND_INET6 0x00000002 +#define DNS_ADBFIND_ADDRESSMASK 0x00000003 +/*% + * Only schedule an event if no addresses are known. + * Must set _WANTEVENT for this to be meaningful. + */ +#define DNS_ADBFIND_EMPTYEVENT 0x00000004 +/*% + * An event is desired. Check this bit in the returned find to see + * if one will actually be generated. + */ +#define DNS_ADBFIND_WANTEVENT 0x00000008 +/*% + * If set, fetches will not be generated unless no addresses are + * available in any of the address families requested. + */ +#define DNS_ADBFIND_AVOIDFETCHES 0x00000010 +/*% + * Fetches will start using the closest zone data or use the root servers. + * This is useful for reestablishing glue that has expired. + */ +#define DNS_ADBFIND_STARTATZONE 0x00000020 +/*% + * Glue or hints are ok. These are used when matching names already + * in the adb, and when dns databases are searched. + */ +#define DNS_ADBFIND_GLUEOK 0x00000040 +/*% + * Glue or hints are ok. These are used when matching names already + * in the adb, and when dns databases are searched. + */ +#define DNS_ADBFIND_HINTOK 0x00000080 +/*% + * Return lame servers in a find, so that all addresses are returned. + */ +#define DNS_ADBFIND_RETURNLAME 0x00000100 +/*% + * Only schedule an event if no addresses are known. + * Must set _WANTEVENT for this to be meaningful. + */ +#define DNS_ADBFIND_LAMEPRUNED 0x00000200 +/*% + * The server's fetch quota is exceeded; it will be treated as + * lame for this query. + */ +#define DNS_ADBFIND_OVERQUOTA 0x00000400 +/*% + * Don't perform a fetch even if there are no address records available. + */ +#define DNS_ADBFIND_NOFETCH 0x00000800 + +/*% + * The answers to queries come back as a list of these. + */ +struct dns_adbaddrinfo { + unsigned int magic; /*%< private */ + + isc_sockaddr_t sockaddr; /*%< [rw] */ + unsigned int srtt; /*%< [rw] microsecs */ + isc_dscp_t dscp; + + unsigned int flags; /*%< [rw] */ + dns_adbentry_t *entry; /*%< private */ + ISC_LINK(dns_adbaddrinfo_t) publink; +}; + +/*!< + * The event sent to the caller task is just a plain old isc_event_t. It + * contains no data other than a simple status, passed in the "type" field + * to indicate that another address resolved, or all partially resolved + * addresses have failed to resolve. + * + * "sender" is the dns_adbfind_t used to issue this query. + * + * This is simply a standard event, with the "type" set to: + * + *\li #DNS_EVENT_ADBMOREADDRESSES -- another address resolved. + *\li #DNS_EVENT_ADBNOMOREADDRESSES -- all pending addresses failed, + * were canceled, or otherwise will + * not be usable. + *\li #DNS_EVENT_ADBCANCELED -- The request was canceled by a + * 3rd party. + *\li #DNS_EVENT_ADBNAMEDELETED -- The name was deleted, so this request + * was canceled. + * + * In each of these cases, the addresses returned by the initial call + * to dns_adb_createfind() can still be used until they are no longer needed. + */ + +/**** +**** FUNCTIONS +****/ + +isc_result_t +dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *tmgr, + isc_taskmgr_t *taskmgr, dns_adb_t **newadb); +/*%< + * Create a new ADB. + * + * Notes: + * + *\li Generally, applications should not create an ADB directly, but + * should instead call dns_view_createresolver(). + * + * Requires: + * + *\li 'mem' must be a valid memory context. + * + *\li 'view' be a pointer to a valid view. + * + *\li 'tmgr' be a pointer to a valid timer manager. + * + *\li 'taskmgr' be a pointer to a valid task manager. + * + *\li 'newadb' != NULL && '*newadb' == NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS after happiness. + *\li #ISC_R_NOMEMORY after resource allocation failure. + */ + +void +dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbp); +/*% + * Attach to an 'adb' to 'adbp'. + * + * Requires: + *\li 'adb' to be a valid dns_adb_t, created via dns_adb_create(). + *\li 'adbp' to be a valid pointer to a *dns_adb_t which is initialized + * to NULL. + */ + +void +dns_adb_detach(dns_adb_t **adb); +/*% + * Delete the ADB. Sets *ADB to NULL. Cancels any outstanding requests. + * + * Requires: + * + *\li 'adb' be non-NULL and '*adb' be a valid dns_adb_t, created via + * dns_adb_create(). + */ + +void +dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp); +/*% + * Send '*eventp' to 'task' when 'adb' has shutdown. + * + * Requires: + * + *\li '*adb' is a valid dns_adb_t. + * + *\li eventp != NULL && *eventp is a valid event. + * + * Ensures: + * + *\li *eventp == NULL + * + *\li The event's sender field is set to the value of adb when the event + * is sent. + */ + +void +dns_adb_shutdown(dns_adb_t *adb); +/*%< + * Shutdown 'adb'. + * + * Requires: + * + * \li '*adb' is a valid dns_adb_t. + */ + +isc_result_t +dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, + void *arg, const dns_name_t *name, const dns_name_t *qname, + dns_rdatatype_t qtype, unsigned int options, + isc_stdtime_t now, dns_name_t *target, in_port_t port, + unsigned int depth, isc_counter_t *qc, dns_adbfind_t **find); +/*%< + * Main interface for clients. The adb will look up the name given in + * "name" and will build up a list of found addresses, and perhaps start + * internal fetches to resolve names that are unknown currently. + * + * If other addresses resolve after this call completes, an event will + * be sent to the <task, taskaction, arg> with the sender of that event + * set to a pointer to the dns_adbfind_t returned by this function. + * + * If no events will be generated, the *find->result_v4 and/or result_v6 + * members may be examined for address lookup status. The usual #ISC_R_SUCCESS, + * #ISC_R_FAILURE, #DNS_R_NXDOMAIN, and #DNS_R_NXRRSET are returned, along with + * #ISC_R_NOTFOUND meaning the ADB has not _yet_ found the values. In this + * latter case, retrying may produce more addresses. + * + * If events will be returned, the result_v[46] members are only valid + * when that event is actually returned. + * + * The list of addresses returned is unordered. The caller must impose + * any ordering required. The list will not contain "known bad" addresses, + * however. For instance, it will not return hosts that are known to be + * lame for the zone in question. + * + * The caller cannot (directly) modify the contents of the address list's + * fields other than the "link" field. All values can be read at any + * time, however. + * + * The "now" parameter is used only for determining which entries that + * have a specific time to live or expire time should be removed from + * the running database. If specified as zero, the current time will + * be retrieved and used. + * + * If 'target' is not NULL and 'name' is an alias (i.e. the name is + * CNAME'd or DNAME'd to another name), then 'target' will be updated with + * the domain name that 'name' is aliased to. + * + * All addresses returned will have the sockaddr's port set to 'port.' + * The caller may change them directly in the dns_adbaddrinfo_t since + * they are copies of the internal address only. + * + * XXXMLG Document options, especially the flags which control how + * events are sent. + * + * Requires: + * + *\li *adb be a valid isc_adb_t object. + * + *\li If events are to be sent, *task be a valid task, + * and isc_taskaction_t != NULL. + * + *\li *name is a valid dns_name_t. + * + *\li qname != NULL and *qname be a valid dns_name_t. + * + *\li target == NULL or target is a valid name with a buffer. + * + *\li find != NULL && *find == NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS Addresses might have been returned, and events will be + * delivered for unresolved addresses. + *\li #ISC_R_NOMORE Addresses might have been returned, but no events + * will ever be posted for this context. This is only + * returned if task != NULL. + *\li #ISC_R_NOMEMORY insufficient resources + *\li #DNS_R_ALIAS 'name' is an alias for another name. + * + * Calls, and returns error codes from: + * + *\li isc_stdtime_get() + * + * Notes: + * + *\li No internal reference to "name" exists after this function + * returns. + */ + +void +dns_adb_cancelfind(dns_adbfind_t *find); +/*%< + * Cancels the find, and sends the event off to the caller. + * + * It is an error to call dns_adb_cancelfind() on a find where + * no event is wanted, or will ever be sent. + * + * Note: + * + *\li It is possible that the real completion event was posted just + * before the dns_adb_cancelfind() call was made. In this case, + * dns_adb_cancelfind() will do nothing. The event callback needs + * to be prepared to find this situation (i.e. result is valid but + * the caller expects it to be canceled). + * + * Requires: + * + *\li 'find' be a valid dns_adbfind_t pointer. + * + *\li events would have been posted to the task. This can be checked + * with (find->options & DNS_ADBFIND_WANTEVENT). + * + * Ensures: + * + *\li The event was posted to the task. + */ + +void +dns_adb_destroyfind(dns_adbfind_t **find); +/*%< + * Destroys the find reference. + * + * Note: + * + *\li This can only be called after the event was delivered for a + * find. Additionally, the event MUST have been freed via + * isc_event_free() BEFORE this function is called. + * + * Requires: + * + *\li 'find' != NULL and *find be valid dns_adbfind_t pointer. + * + * Ensures: + * + *\li No "address found" events will be posted to the originating task + * after this function returns. + */ + +void +dns_adb_dump(dns_adb_t *adb, FILE *f); +/*%< + * This function is only used for debugging. It will dump as much of the + * state of the running system as possible. + * + * Requires: + * + *\li adb be valid. + * + *\li f != NULL, and is a file open for writing. + */ + +void +dns_adb_dumpfind(dns_adbfind_t *find, FILE *f); +/*%< + * This function is only used for debugging. Dump the data associated + * with a find. + * + * Requires: + * + *\li find is valid. + * + * \li f != NULL, and is a file open for writing. + */ + +isc_result_t +dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, + const dns_name_t *qname, dns_rdatatype_t type, + isc_stdtime_t expire_time); +/*%< + * Mark the given address as lame for the <qname,qtype>. expire_time should + * be set to the time when the entry should expire. That is, if it is to + * expire 10 minutes in the future, it should set it to (now + 10 * 60). + * + * Requires: + * + *\li adb be valid. + * + *\li addr be valid. + * + *\li qname be the qname used in the dns_adb_createfind() call. + * + * Returns: + * + *\li #ISC_R_SUCCESS -- all is well. + *\li #ISC_R_NOMEMORY -- could not mark address as lame. + */ + +/* + * Reasonable defaults for RTT adjustments + * + * (Note: these values function both as scaling factors and as + * indicators of the type of RTT adjustment operation taking place. + * Adjusting the scaling factors is fine, as long as they all remain + * unique values.) + */ +#define DNS_ADB_RTTADJDEFAULT 7 /*%< default scale */ +#define DNS_ADB_RTTADJREPLACE 0 /*%< replace with our rtt */ +#define DNS_ADB_RTTADJAGE 10 /*%< age this rtt */ + +void +dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int rtt, + unsigned int factor); +/*%< + * Mix the round trip time into the existing smoothed rtt. + * + * Requires: + * + *\li adb be valid. + * + *\li addr be valid. + * + *\li 0 <= factor <= 10 + * + * Note: + * + *\li The srtt in addr will be updated to reflect the new global + * srtt value. This may include changes made by others. + */ + +void +dns_adb_agesrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr, isc_stdtime_t now); +/* + * dns_adb_agesrtt is equivalent to dns_adb_adjustsrtt with factor + * equal to DNS_ADB_RTTADJAGE and the current time passed in. + * + * Requires: + * + *\li adb be valid. + * + *\li addr be valid. + * + * Note: + * + *\li The srtt in addr will be updated to reflect the new global + * srtt value. This may include changes made by others. + */ + +void +dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int bits, + unsigned int mask); +/*% + * Change Flags. + * + * Set the flags as given by: + * + *\li newflags = (oldflags & ~mask) | (bits & mask); + * + * Requires: + * + *\li adb be valid. + * + *\li addr be valid. + */ + +void +dns_adb_setudpsize(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int size); +/*% + * Update seen UDP response size. The largest seen will be returned by + * dns_adb_getudpsize(). + * + * Requires: + * + *\li adb be valid. + * + *\li addr be valid. + */ + +unsigned int +dns_adb_getudpsize(dns_adb_t *adb, dns_adbaddrinfo_t *addr); +/*% + * Return the largest seen UDP response size. + * + * Requires: + * + *\li adb be valid. + * + *\li addr be valid. + */ + +unsigned int +dns_adb_probesize(dns_adb_t *adb, dns_adbaddrinfo_t *addr, int lookups); +/*% + * Return suggested EDNS UDP size based on observed responses / failures. + * 'lookups' is the number of times the current lookup has been attempted. + * + * Requires: + * + *\li adb be valid. + * + *\li addr be valid. + */ + +void +dns_adb_plainresponse(dns_adb_t *adb, dns_adbaddrinfo_t *addr); +/*% + * Record a successful plain DNS response. + * + * Requires: + * + *\li adb be valid. + * + *\li addr be valid. + */ + +void +dns_adb_timeout(dns_adb_t *adb, dns_adbaddrinfo_t *addr); +/*% + * Record a plain DNS UDP query failed. + * + * Requires: + * + *\li adb be valid. + * + *\li addr be valid. + */ + +void +dns_adb_ednsto(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int size); +/*% + * Record a failed EDNS UDP response and the advertised EDNS UDP buffer size + * used. + * + * Requires: + * + *\li adb be valid. + * + *\li addr be valid. + */ + +bool +dns_adb_noedns(dns_adb_t *adb, dns_adbaddrinfo_t *addr); +/*% + * Return whether EDNS should be disabled for this server. + * + * Requires: + * + *\li adb be valid. + * + *\li addr be valid. + */ + +isc_result_t +dns_adb_findaddrinfo(dns_adb_t *adb, const isc_sockaddr_t *sa, + dns_adbaddrinfo_t **addrp, isc_stdtime_t now); +/*%< + * Return a dns_adbaddrinfo_t that is associated with address 'sa'. + * + * Requires: + * + *\li adb is valid. + * + *\li sa is valid. + * + *\li addrp != NULL && *addrp == NULL + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_SHUTTINGDOWN + */ + +void +dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp); +/*%< + * Free a dns_adbaddrinfo_t allocated by dns_adb_findaddrinfo(). + * + * Requires: + * + *\li adb is valid. + * + *\li *addrp is a valid dns_adbaddrinfo_t *. + */ + +void +dns_adb_flush(dns_adb_t *adb); +/*%< + * Flushes all cached data from the adb. + * + * Requires: + *\li adb is valid. + */ + +void +dns_adb_setadbsize(dns_adb_t *adb, size_t size); +/*%< + * Set a target memory size. If memory usage exceeds the target + * size entries will be removed before they would have expired on + * a random basis. + * + * If 'size' is 0 then memory usage is unlimited. + * + * Requires: + *\li 'adb' is valid. + */ + +void +dns_adb_flushname(dns_adb_t *adb, const dns_name_t *name); +/*%< + * Flush 'name' from the adb cache. + * + * Requires: + *\li 'adb' is valid. + *\li 'name' is valid. + */ + +void +dns_adb_flushnames(dns_adb_t *adb, const dns_name_t *name); +/*%< + * Flush 'name' and all subdomains from the adb cache. + * + * Requires: + *\li 'adb' is valid. + *\li 'name' is valid. + */ + +void +dns_adb_setcookie(dns_adb_t *adb, dns_adbaddrinfo_t *addr, + const unsigned char *cookie, size_t len); +/*%< + * Record the COOKIE associated with this address. If + * cookie is NULL or len is zero the recorded COOKIE is cleared. + * + * Requires: + *\li 'adb' is valid. + *\li 'addr' is valid. + */ + +size_t +dns_adb_getcookie(dns_adb_t *adb, dns_adbaddrinfo_t *addr, + unsigned char *cookie, size_t len); +/* + * Retrieve the saved COOKIE value and store it in 'cookie' which has + * size 'len'. + * + * Requires: + *\li 'adb' is valid. + *\li 'addr' is valid. + * + * Returns: + * The size of the cookie or zero if it doesn't fit in the buffer + * or it doesn't exist. + */ + +void +dns_adb_setquota(dns_adb_t *adb, uint32_t quota, uint32_t freq, double low, + double high, double discount); +/*%< + * Set the baseline ADB quota, and configure parameters for the + * quota adjustment algorithm. + * + * If the number of fetches currently waiting for responses from this + * address exceeds the current quota, then additional fetches are spilled. + * + * 'quota' is the highest permissible quota; it will adjust itself + * downward in response to detected congestion. + * + * After every 'freq' fetches have either completed or timed out, an + * exponentially weighted moving average of the ratio of timeouts + * to responses is calculated. If the EWMA goes above a 'high' + * threshold, then the quota is adjusted down one step; if it drops + * below a 'low' threshold, then the quota is adjusted back up one + * step. + * + * The quota adjustment is based on the function (1 / 1 + (n/10)^(3/2)), + * for values of n from 0 to 99. It starts at 100% of the baseline + * quota, and descends after 100 steps to 2%. + * + * 'discount' represents the discount rate of the moving average. Higher + * values cause older values to be discounted sooner, providing a faster + * response to changes in the timeout ratio. + * + * Requires: + *\li 'adb' is valid. + */ + +bool +dns_adbentry_overquota(dns_adbentry_t *entry); +/*%< + * Returns true if the specified ADB has too many active fetches. + * + * Requires: + *\li 'entry' is valid. + */ + +void +dns_adb_beginudpfetch(dns_adb_t *adb, dns_adbaddrinfo_t *addr); +void +dns_adb_endudpfetch(dns_adb_t *adb, dns_adbaddrinfo_t *addr); +/*% + * Begin/end a UDP fetch on a particular address. + * + * These functions increment or decrement the fetch counter for + * the ADB entry so that the fetch quota can be enforced. + * + * Requires: + * + *\li adb be valid. + * + *\li addr be valid. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_ADB_H */ diff --git a/lib/dns/include/dns/badcache.h b/lib/dns/include/dns/badcache.h new file mode 100644 index 0000000..c45ea0c --- /dev/null +++ b/lib/dns/include/dns/badcache.h @@ -0,0 +1,152 @@ +/* + * 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. + */ + +#ifndef DNS_BADCACHE_H +#define DNS_BADCACHE_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/badcache.h + * \brief + * Defines dns_badcache_t, the "bad cache" object. + * + * Notes: + *\li A bad cache object is a hash table of name/type tuples, + * indicating whether a given tuple known to be "bad" in some + * sense (e.g., queries for that name and type have been + * returning SERVFAIL). This is used for both the "bad server + * cache" in the resolver and for the "servfail cache" in + * the view. + * + * Reliability: + * + * Resources: + * + * Security: + * + * Standards: + */ + +/*** + *** Imports + ***/ + +#include <inttypes.h> +#include <stdbool.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Functions + ***/ + +isc_result_t +dns_badcache_init(isc_mem_t *mctx, unsigned int size, dns_badcache_t **bcp); +/*% + * Allocate and initialize a badcache and store it in '*bcp'. + * + * Requires: + * \li mctx != NULL + * \li bcp != NULL + * \li *bcp == NULL + */ + +void +dns_badcache_destroy(dns_badcache_t **bcp); +/*% + * Flush and then free badcache in 'bcp'. '*bcp' is set to NULL on return. + * + * Requires: + * \li '*bcp' to be a valid badcache + */ + +void +dns_badcache_add(dns_badcache_t *bc, const dns_name_t *name, + dns_rdatatype_t type, bool update, uint32_t flags, + isc_time_t *expire); +/*% + * Adds a badcache entry to the badcache 'bc' for name 'name' and + * type 'type'. If an entry already exists, then it will be updated if + * 'update' is true. The entry will be stored with flags 'flags' + * and expiration date 'expire'. + * + * Requires: + * \li bc to be a valid badcache. + * \li name != NULL + * \li expire != NULL + */ + +bool +dns_badcache_find(dns_badcache_t *bc, const dns_name_t *name, + dns_rdatatype_t type, uint32_t *flagp, isc_time_t *now); +/*% + * Returns true if a record is found in the badcache 'bc' matching + * 'name' and 'type', with an expiration date later than 'now'. + * If 'flagp' is not NULL, then '*flagp' is updated to the flags + * that were stored in the badcache entry. Returns false if + * no matching record is found. + * + * Requires: + * \li bc to be a valid badcache. + * \li name != NULL + * \li now != NULL + */ + +void +dns_badcache_flush(dns_badcache_t *bc); +/*% + * Flush the entire bad cache. + * + * Requires: + * \li bc to be a valid badcache + */ + +void +dns_badcache_flushname(dns_badcache_t *bc, const dns_name_t *name); +/*% + * Flush the bad cache of all entries at 'name'. + * + * Requires: + * \li bc to be a valid badcache + * \li name != NULL + */ + +void +dns_badcache_flushtree(dns_badcache_t *bc, const dns_name_t *name); +/*% + * Flush the bad cache of all entries at or below 'name'. + * + * Requires: + * \li bc to be a valid badcache + * \li name != NULL + */ + +void +dns_badcache_print(dns_badcache_t *bc, const char *cachename, FILE *fp); +/*% + * Print the contents of badcache 'bc' (headed by the title 'cachename') + * to file pointer 'fp'. + * + * Requires: + * \li bc to be a valid badcache + * \li cachename != NULL + * \li fp != NULL + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_BADCACHE_H */ diff --git a/lib/dns/include/dns/bit.h b/lib/dns/include/dns/bit.h new file mode 100644 index 0000000..55696e2 --- /dev/null +++ b/lib/dns/include/dns/bit.h @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#ifndef DNS_BIT_H +#define DNS_BIT_H 1 + +/*! \file dns/bit.h */ + +#include <inttypes.h> + +typedef uint64_t dns_bitset_t; + +#define DNS_BIT_SET(bit, bitset) (*(bitset) |= ((dns_bitset_t)1 << (bit))) +#define DNS_BIT_CLEAR(bit, bitset) (*(bitset) &= ~((dns_bitset_t)1 << (bit))) +#define DNS_BIT_CHECK(bit, bitset) \ + ((*(bitset) & ((dns_bitset_t)1 << (bit))) == ((dns_bitset_t)1 << (bit))) + +#endif /* DNS_BIT_H */ diff --git a/lib/dns/include/dns/byaddr.h b/lib/dns/include/dns/byaddr.h new file mode 100644 index 0000000..f527ed3 --- /dev/null +++ b/lib/dns/include/dns/byaddr.h @@ -0,0 +1,152 @@ +/* + * 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. + */ + +#ifndef DNS_BYADDR_H +#define DNS_BYADDR_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/byaddr.h + * \brief + * The byaddr module provides reverse lookup services for IPv4 and IPv6 + * addresses. + * + * MP: + *\li The module ensures appropriate synchronization of data structures it + * creates and manipulates. + * + * Reliability: + *\li No anticipated impact. + * + * Resources: + *\li TBS + * + * Security: + *\li No anticipated impact. + * + * Standards: + *\li RFCs: 1034, 1035, 2181, TBS + *\li Drafts: TBS + */ + +#include <isc/event.h> +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/*% + * A 'dns_byaddrevent_t' is returned when a byaddr completes. + * The sender field will be set to the byaddr that completed. If 'result' + * is ISC_R_SUCCESS, then 'names' will contain a list of names associated + * with the address. The recipient of the event must not change the list + * and must not refer to any of the name data after the event is freed. + */ +typedef struct dns_byaddrevent { + ISC_EVENT_COMMON(struct dns_byaddrevent); + isc_result_t result; + dns_namelist_t names; +} dns_byaddrevent_t; + +isc_result_t +dns_byaddr_create(isc_mem_t *mctx, const isc_netaddr_t *address, + dns_view_t *view, unsigned int options, isc_task_t *task, + isc_taskaction_t action, void *arg, dns_byaddr_t **byaddrp); +/*%< + * Find the domain name of 'address'. + * + * Notes: + * + *\li There is a reverse lookup format for IPv6 addresses, 'nibble' + * + *\li The 'nibble' format for that address is + * + * \code + * 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa. + * \endcode + * + * Requires: + * + *\li 'mctx' is a valid mctx. + * + *\li 'address' is a valid IPv4 or IPv6 address. + * + *\li 'view' is a valid view which has a resolver. + * + *\li 'task' is a valid task. + * + *\li byaddrp != NULL && *byaddrp == NULL + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + * + *\li Any resolver-related error (e.g. #ISC_R_SHUTTINGDOWN) may also be + * returned. + */ + +void +dns_byaddr_cancel(dns_byaddr_t *byaddr); +/*%< + * Cancel 'byaddr'. + * + * Notes: + * + *\li If 'byaddr' has not completed, post its #DNS_EVENT_BYADDRDONE + * event with a result code of #ISC_R_CANCELED. + * + * Requires: + * + *\li 'byaddr' is a valid byaddr. + */ + +void +dns_byaddr_destroy(dns_byaddr_t **byaddrp); +/*%< + * Destroy 'byaddr'. + * + * Requires: + * + *\li '*byaddrp' is a valid byaddr. + * + *\li The caller has received the #DNS_EVENT_BYADDRDONE event (either because + * the byaddr completed or because dns_byaddr_cancel() was called). + * + * Ensures: + * + *\li *byaddrp == NULL. + */ + +isc_result_t +dns_byaddr_createptrname(const isc_netaddr_t *address, unsigned int options, + dns_name_t *name); +/*%< + * Creates a name that would be used in a PTR query for this address. The + * nibble flag indicates that the 'nibble' format is to be used if an IPv6 + * address is provided, instead of the 'bitstring' format. Since we dropped + * the support of the bitstring labels, it is expected that the flag is always + * set. 'options' are the same as for dns_byaddr_create(). + * + * Requires: + * + * \li 'address' is a valid address. + * \li 'name' is a valid name with a dedicated buffer. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_BYADDR_H */ diff --git a/lib/dns/include/dns/cache.h b/lib/dns/include/dns/cache.h new file mode 100644 index 0000000..b840a54 --- /dev/null +++ b/lib/dns/include/dns/cache.h @@ -0,0 +1,360 @@ +/* + * 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. + */ + +#ifndef DNS_CACHE_H +#define DNS_CACHE_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/cache.h + * \brief + * Defines dns_cache_t, the cache object. + * + * Notes: + *\li A cache object contains DNS data of a single class. + * Multiple classes will be handled by creating multiple + * views, each with a different class and its own cache. + * + * MP: + *\li See notes at the individual functions. + * + * Reliability: + * + * Resources: + * + * Security: + * + * Standards: + */ + +/*** + *** Imports + ***/ + +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/stats.h> +#include <isc/stdtime.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Functions + ***/ +isc_result_t +dns_cache_create(isc_mem_t *cmctx, isc_mem_t *hmctx, isc_taskmgr_t *taskmgr, + isc_timermgr_t *timermgr, dns_rdataclass_t rdclass, + const char *cachename, const char *db_type, + unsigned int db_argc, char **db_argv, dns_cache_t **cachep); +/*%< + * Create a new DNS cache. + * + * dns_cache_create2() will create a named cache. + * + * dns_cache_create3() will create a named cache using two separate memory + * contexts, one for cache data which can be cleaned and a separate one for + * memory allocated for the heap (which can grow without an upper limit and + * has no mechanism for shrinking). + * + * dns_cache_create() is a backward compatible version that internally + * specifies an empty cache name and a single memory context. + * + * Requires: + * + *\li 'cmctx' (and 'hmctx' if applicable) is a valid memory context. + * + *\li 'taskmgr' is a valid task manager and 'timermgr' is a valid timer + * manager, or both are NULL. If NULL, no periodic cleaning of the + * cache will take place. + * + *\li 'cachename' is a valid string. This must not be NULL. + * + *\li 'cachep' is a valid pointer, and *cachep == NULL + * + * Ensures: + * + *\li '*cachep' is attached to the newly created cache + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +void +dns_cache_attach(dns_cache_t *cache, dns_cache_t **targetp); +/*%< + * Attach *targetp to cache. + * + * Requires: + * + *\li 'cache' is a valid cache. + * + *\li 'targetp' points to a NULL dns_cache_t *. + * + * Ensures: + * + *\li *targetp is attached to cache. + */ + +void +dns_cache_detach(dns_cache_t **cachep); +/*%< + * Detach *cachep from its cache. + * + * Requires: + * + *\li 'cachep' points to a valid cache. + * + * Ensures: + * + *\li *cachep is NULL. + * + *\li If '*cachep' is the last reference to the cache, + * all resources used by the cache will be freed + */ + +void +dns_cache_attachdb(dns_cache_t *cache, dns_db_t **dbp); +/*%< + * Attach *dbp to the cache's database. + * + * Notes: + * + *\li This may be used to get a reference to the database for + * the purpose of cache lookups (XXX currently it is also + * the way to add data to the cache, but having a + * separate dns_cache_add() interface instead would allow + * more control over memory usage). + * The caller should call dns_db_detach() on the reference + * when it is no longer needed. + * + * Requires: + * + *\li 'cache' is a valid cache. + * + *\li 'dbp' points to a NULL dns_db *. + * + * Ensures: + * + *\li *dbp is attached to the database. + */ + +isc_result_t +dns_cache_setfilename(dns_cache_t *cache, const char *filename); +/*%< + * If 'filename' is non-NULL, make the cache persistent. + * The cache's data will be stored in the given file. + * If 'filename' is NULL, make the cache non-persistent. + * Files that are no longer used are not unlinked automatically. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li Various file-related failures + */ + +isc_result_t +dns_cache_load(dns_cache_t *cache); +/*%< + * If the cache has a file name, load the cache contents from the file. + * Previous cache contents are not discarded. + * If no file name has been set, do nothing and return success. + * + * MT: + *\li Multiple simultaneous attempts to load or dump the cache + * will be serialized with respect to one another, but + * the cache may be read and updated while the dump is + * in progress. Updates performed during loading + * may or may not be preserved, and reads may return + * either the old or the newly loaded data. + * + * Returns: + * + *\li #ISC_R_SUCCESS + * \li Various failures depending on the database implementation type + */ + +isc_result_t +dns_cache_dump(dns_cache_t *cache); +/*%< + * If the cache has a file name, write the cache contents to disk, + * overwriting any preexisting file. If no file name has been set, + * do nothing and return success. + * + * MT: + *\li Multiple simultaneous attempts to load or dump the cache + * will be serialized with respect to one another, but + * the cache may be read and updated while the dump is + * in progress. Updates performed during the dump may + * or may not be reflected in the dumped file. + * + * Returns: + * + *\li #ISC_R_SUCCESS + * \li Various failures depending on the database implementation type + */ + +isc_result_t +dns_cache_clean(dns_cache_t *cache, isc_stdtime_t now); +/*%< + * Force immediate cleaning of the cache, freeing all rdatasets + * whose TTL has expired as of 'now' and that have no pending + * references. + */ + +const char * +dns_cache_getname(dns_cache_t *cache); +/*%< + * Get the cache name. + */ + +void +dns_cache_setcachesize(dns_cache_t *cache, size_t size); +/*%< + * Set the maximum cache size. 0 means unlimited. + */ + +size_t +dns_cache_getcachesize(dns_cache_t *cache); +/*%< + * Get the maximum cache size. + */ + +void +dns_cache_setservestalettl(dns_cache_t *cache, dns_ttl_t ttl); +/*%< + * Sets the maximum length of time that cached answers may be retained + * past their normal TTL. Default value for the library is 0, disabling + * the use of stale data. + * + * Requires: + *\li 'cache' to be valid. + */ + +dns_ttl_t +dns_cache_getservestalettl(dns_cache_t *cache); +/*%< + * Gets the maximum length of time that cached answers may be kept past + * normal expiry. + * + * Requires: + *\li 'cache' to be valid. + */ + +void +dns_cache_setservestalerefresh(dns_cache_t *cache, dns_ttl_t interval); +/*%< + * Sets the length of time to wait before attempting to refresh a rrset + * if a previous attempt in doing so has failed. + * During this time window if stale rrset are available in cache they + * will be directly returned to client. + * + * Requires: + *\li 'cache' to be valid. + */ + +dns_ttl_t +dns_cache_getservestalerefresh(dns_cache_t *cache); +/*%< + * Gets the 'stale-refresh-time' value, set by a previous call to + * 'dns_cache_setservestalerefresh'. + * + * Requires: + *\li 'cache' to be valid. + */ + +isc_result_t +dns_cache_flush(dns_cache_t *cache); +/*%< + * Flushes all data from the cache. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +isc_result_t +dns_cache_flushnode(dns_cache_t *cache, const dns_name_t *name, bool tree); +/* + * Flush a given name from the cache. If 'tree' is true, then + * also flush all names under 'name'. + * + * Requires: + *\li 'cache' to be valid. + *\li 'name' to be valid. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li other error returns. + */ + +isc_result_t +dns_cache_flushname(dns_cache_t *cache, const dns_name_t *name); +/* + * Flush a given name from the cache. Equivalent to + * dns_cache_flushpartial(cache, name, false). + * + * Requires: + *\li 'cache' to be valid. + *\li 'name' to be valid. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li other error returns. + */ + +isc_stats_t * +dns_cache_getstats(dns_cache_t *cache); +/* + * Return a pointer to the stats collection object for 'cache' + */ + +void +dns_cache_dumpstats(dns_cache_t *cache, FILE *fp); +/* + * Dump cache statistics and status in text to 'fp' + */ + +void +dns_cache_updatestats(dns_cache_t *cache, isc_result_t result); +/* + * Update cache statistics based on result code in 'result' + */ + +#ifdef HAVE_LIBXML2 +int +dns_cache_renderxml(dns_cache_t *cache, void *writer0); +/* + * Render cache statistics and status in XML for 'writer'. + */ +#endif /* HAVE_LIBXML2 */ + +#ifdef HAVE_JSON_C +isc_result_t +dns_cache_renderjson(dns_cache_t *cache, void *cstats0); +/* + * Render cache statistics and status in JSON + */ +#endif /* HAVE_JSON_C */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_CACHE_H */ diff --git a/lib/dns/include/dns/callbacks.h b/lib/dns/include/dns/callbacks.h new file mode 100644 index 0000000..4d71915 --- /dev/null +++ b/lib/dns/include/dns/callbacks.h @@ -0,0 +1,103 @@ +/* + * 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. + */ + +#ifndef DNS_CALLBACKS_H +#define DNS_CALLBACKS_H 1 + +/*! \file dns/callbacks.h */ + +/*** + *** Imports + ***/ + +#include <isc/lang.h> +#include <isc/magic.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Types + ***/ + +#define DNS_CALLBACK_MAGIC ISC_MAGIC('C', 'L', 'L', 'B') +#define DNS_CALLBACK_VALID(cb) ISC_MAGIC_VALID(cb, DNS_CALLBACK_MAGIC) + +struct dns_rdatacallbacks { + unsigned int magic; + + /*% + * dns_load_master calls this when it has rdatasets to commit. + */ + dns_addrdatasetfunc_t add; + + /*% + * This is called when reading in a database image from a 'map' + * format zone file. + */ + dns_deserializefunc_t deserialize; + + /*% + * dns_master_load*() call this when loading a raw zonefile, + * to pass back information obtained from the file header + */ + dns_rawdatafunc_t rawdata; + dns_zone_t *zone; + + /*% + * dns_load_master / dns_rdata_fromtext call this to issue a error. + */ + void (*error)(struct dns_rdatacallbacks *, const char *, ...); + /*% + * dns_load_master / dns_rdata_fromtext call this to issue a warning. + */ + void (*warn)(struct dns_rdatacallbacks *, const char *, ...); + /*% + * Private data handles for use by the above callback functions. + */ + void *add_private; + void *deserialize_private; + void *error_private; + void *warn_private; +}; + +/*** + *** Initialization + ***/ + +void +dns_rdatacallbacks_init(dns_rdatacallbacks_t *callbacks); +/*%< + * Initialize 'callbacks'. + * + * \li 'magic' is set to DNS_CALLBACK_MAGIC + * + * \li 'error' and 'warn' are set to default callbacks that print the + * error message through the DNS library log context. + * + *\li All other elements are initialized to NULL. + * + * Requires: + * \li 'callbacks' is a valid dns_rdatacallbacks_t, + */ + +void +dns_rdatacallbacks_init_stdio(dns_rdatacallbacks_t *callbacks); +/*%< + * Like dns_rdatacallbacks_init, but logs to stdio. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_CALLBACKS_H */ diff --git a/lib/dns/include/dns/catz.h b/lib/dns/include/dns/catz.h new file mode 100644 index 0000000..7502829 --- /dev/null +++ b/lib/dns/include/dns/catz.h @@ -0,0 +1,473 @@ +/* + * 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. + */ + +#ifndef DNS_CATZ_H +#define DNS_CATZ_H 1 + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/ht.h> +#include <isc/lang.h> +#include <isc/refcount.h> +#include <isc/rwlock.h> +#include <isc/time.h> +#include <isc/timer.h> + +#include <dns/db.h> +#include <dns/fixedname.h> +#include <dns/ipkeylist.h> +#include <dns/rdata.h> +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +#define DNS_CATZ_ERROR_LEVEL ISC_LOG_WARNING +#define DNS_CATZ_INFO_LEVEL ISC_LOG_INFO +#define DNS_CATZ_DEBUG_LEVEL1 ISC_LOG_DEBUG(1) +#define DNS_CATZ_DEBUG_LEVEL2 ISC_LOG_DEBUG(2) +#define DNS_CATZ_DEBUG_LEVEL3 ISC_LOG_DEBUG(3) +#define DNS_CATZ_DEBUG_QUIET (DNS_CATZ_DEBUG_LEVEL3 + 1) + +/* + * Catalog Zones functions and structures. + */ + +/* + * Options for a member zone in a catalog + */ +struct dns_catz_entry_options { + /* + * Options that can be overridden in catalog zone + */ + /* default-masters definition */ + dns_ipkeylist_t masters; + + /* both as text in config format, NULL if none */ + isc_buffer_t *allow_query; + isc_buffer_t *allow_transfer; + + /* + * Options that are only set in named.conf + */ + /* zone-directory definition */ + char *zonedir; + + /* zone should not be stored on disk (no 'file' statement in def */ + bool in_memory; + /* + * Minimal interval between catalog zone updates, if a new version + * of catalog zone is received before this time the update will be + * postponed. This is a global option for the whole catalog zone. + */ + uint32_t min_update_interval; +}; + +void +dns_catz_options_init(dns_catz_options_t *options); +/*%< + * Initialize 'options' to NULL values. + * + * Requires: + * \li 'options' to be non NULL. + */ + +void +dns_catz_options_free(dns_catz_options_t *options, isc_mem_t *mctx); +/*%< + * Free 'options' contents into 'mctx'. ('options' itself is not freed.) + * + * Requires: + * \li 'options' to be non NULL. + * \li 'mctx' to be a valid memory context. + */ + +isc_result_t +dns_catz_options_copy(isc_mem_t *mctx, const dns_catz_options_t *opts, + dns_catz_options_t *nopts); +/*%< + * Duplicate 'opts' into 'nopts', allocating space from 'mctx'. + * + * Requires: + * \li 'mctx' to be a valid memory context. + * \li 'options' to be non NULL and valid options. + * \li 'nopts' to be non NULL. + */ + +isc_result_t +dns_catz_options_setdefault(isc_mem_t *mctx, const dns_catz_options_t *defaults, + dns_catz_options_t *opts); +/*%< + * Replace empty values in 'opts' with values from 'defaults' + * + * Requires: + * \li 'mctx' to be a valid memory context. + * \li 'defaults' to be non NULL and valid options. + * \li 'opts' to be non NULL. + */ + +dns_name_t * +dns_catz_entry_getname(dns_catz_entry_t *entry); +/*%< + * Get domain name for 'entry' + * + * Requires: + * \li 'entry' to be non NULL. + * + * Returns: + * \li domain name for entry. + */ + +isc_result_t +dns_catz_entry_new(isc_mem_t *mctx, const dns_name_t *domain, + dns_catz_entry_t **nentryp); +/*%< + * Allocate a new catz_entry on 'mctx', with the name 'domain' + * + * Requires: + * \li 'mctx' to be a valid memory context. + * \li 'domain' to be valid dns_name or NULL. + * \li 'nentryp' to be non NULL, *nentryp to be NULL. + * + * Returns: + * \li ISC_R_SUCCESS on success + * \li ISC_R_NOMEMORY on allocation failure + */ + +isc_result_t +dns_catz_entry_copy(dns_catz_zone_t *zone, const dns_catz_entry_t *entry, + dns_catz_entry_t **nentryp); +/*%< + * Allocate a new catz_entry and deep copy 'entry' into 'nentryp'. + * + * Requires: + * \li 'mctx' to be a valid memory context. + * \li 'entry' to be non NULL. + * \li 'nentryp' to be non NULL, *nentryp to be NULL. + * + * Returns: + * \li ISC_R_SUCCESS on success + * \li ISC_R_NOMEMORY on allocation failure + */ + +void +dns_catz_entry_attach(dns_catz_entry_t *entry, dns_catz_entry_t **entryp); +/*%< + * Attach an entry + * + * Requires: + * \li 'entry' is a valid dns_catz_entry_t. + * \li 'entryp' is not NULL and '*entryp' is NULL. + */ + +void +dns_catz_entry_detach(dns_catz_zone_t *zone, dns_catz_entry_t **entryp); +/*%< + * Detach an entry, free if no further references + * + * Requires: + * \li 'zone' is a valid dns_catz_zone_t. + * \li 'entryp' is not NULL and '*entryp' is not NULL. + */ + +bool +dns_catz_entry_validate(const dns_catz_entry_t *entry); +/*%< + * Validate whether entry is correct. + * (NOT YET IMPLEMENTED: always returns true) + * + * Requires: + *\li 'entry' is a valid dns_catz_entry_t. + */ + +bool +dns_catz_entry_cmp(const dns_catz_entry_t *ea, const dns_catz_entry_t *eb); +/*%< + * Deep compare two entries + * + * Requires: + * \li 'ea' is a valid dns_catz_entry_t. + * \li 'eb' is a valid dns_catz_entry_t. + * + * Returns: + * \li 'true' if entries are the same. + * \li 'false' if the entries differ. + */ + +void +dns_catz_zone_attach(dns_catz_zone_t *zone, dns_catz_zone_t **zonep); +/*%< + * Attach a catzone + * + * Requires: + * \li 'zone' is a valid dns_catz_zone_t. + * \li 'zonep' is not NULL and '*zonep' is NULL. + */ + +void +dns_catz_zone_detach(dns_catz_zone_t **zonep); +/*%< + * Detach a zone, free if no further references + * + * Requires: + * \li 'zonep' is not NULL and '*zonep' is not NULL. + */ + +isc_result_t +dns_catz_new_zone(dns_catz_zones_t *catzs, dns_catz_zone_t **zonep, + const dns_name_t *name); +/*%< + * Allocate a new catz zone on catzs mctx + * + * Requires: + * \li 'catzs' is a valid dns_catz_zones_t. + * \li 'zonep' is not NULL and '*zonep' is NULL. + * \li 'name' is a valid dns_name_t. + * + */ + +dns_name_t * +dns_catz_zone_getname(dns_catz_zone_t *zone); +/*%< + * Get catalog zone name + * + * Requires: + * \li 'zone' is a valid dns_catz_zone_t. + */ + +dns_catz_options_t * +dns_catz_zone_getdefoptions(dns_catz_zone_t *zone); +/*%< + * Get default member zone options for catalog zone 'zone' + * + * Requires: + * \li 'zone' is a valid dns_catz_zone_t. + */ + +void +dns_catz_zone_resetdefoptions(dns_catz_zone_t *zone); +/*%< + * Reset the default member zone options for catalog zone 'zone' to + * the default values. + * + * Requires: + * \li 'zone' is a valid dns_catz_zone_t. + */ + +isc_result_t +dns_catz_zones_merge(dns_catz_zone_t *target, dns_catz_zone_t *newzone); +/*%< + * Merge 'newzone' into 'target', calling addzone/delzone/modzone + * (from zone->catzs->zmm) for appropriate member zones. + * + * Requires: + * \li 'orig' is a valid dns_catz_zone_t. + * \li 'newzone' is not NULL and '*newzone' is not NULL. + * + */ + +isc_result_t +dns_catz_update_process(dns_catz_zones_t *catzs, dns_catz_zone_t *zone, + const dns_name_t *src_name, dns_rdataset_t *rdataset); +/*%< + * Process a single rdataset from a catalog zone 'zone' update, src_name is the + * record name. + * + * Requires: + * \li 'catzs' is a valid dns_catz_zones_t. + * \li 'zone' is a valid dns_catz_zone_t. + * \li 'src_name' is a valid dns_name_t. + * \li 'rdataset' is valid rdataset. + */ + +isc_result_t +dns_catz_generate_masterfilename(dns_catz_zone_t *zone, dns_catz_entry_t *entry, + isc_buffer_t **buffer); +/*%< + * Generate master file name and put it into *buffer (might be reallocated). + * The general format of the file name is: + * __catz__catalog.zone.name__member_zone_name.db + * But if it's too long it's shortened to: + * __catz__unique_hash_generated_from_the_above.db + * + * Requires: + * \li 'zone' is a valid dns_catz_zone_t. + * \li 'entry' is a valid dns_catz_entry_t. + * \li 'buffer' is not NULL and '*buffer' is not NULL. + */ + +isc_result_t +dns_catz_generate_zonecfg(dns_catz_zone_t *zone, dns_catz_entry_t *entry, + isc_buffer_t **buf); +/*%< + * Generate a zone config entry (in text form) from dns_catz_entry and puts + * it into *buf. buf might be reallocated. + * + * Requires: + * \li 'zone' is a valid dns_catz_zone_t. + * \li 'entry' is a valid dns_catz_entry_t. + * \li 'buf' is not NULL and '*buf' is NULL. + * + */ + +/* Methods provided by named to dynamically modify the member zones */ +/* xxxwpk TODO config! */ +typedef isc_result_t (*dns_catz_zoneop_fn_t)(dns_catz_entry_t *entry, + dns_catz_zone_t *origin, + dns_view_t *view, + isc_taskmgr_t *taskmgr, + void *udata); +struct dns_catz_zonemodmethods { + dns_catz_zoneop_fn_t addzone; + dns_catz_zoneop_fn_t modzone; + dns_catz_zoneop_fn_t delzone; + void *udata; +}; + +isc_result_t +dns_catz_new_zones(dns_catz_zones_t **catzsp, dns_catz_zonemodmethods_t *zmm, + isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + isc_timermgr_t *timermgr); +/*%< + * Allocate a new catz_zones object, a collection storing all catalog zones + * for a view. + * + * Requires: + * \li 'catzsp' is not NULL and '*catzsp' is NULL. + * \li 'zmm' is not NULL. + * + */ + +isc_result_t +dns_catz_add_zone(dns_catz_zones_t *catzs, const dns_name_t *name, + dns_catz_zone_t **catzp); +/*%< + * Allocate a new catz named 'name' and put it in 'catzs' collection. + * + * Requires: + * \li 'catzs' is a valid dns_catz_zones_t. + * \li 'name' is a valid dns_name_t. + * \li 'zonep' is not NULL and *zonep is NULL. + * + */ + +dns_catz_zone_t * +dns_catz_get_zone(dns_catz_zones_t *catzs, const dns_name_t *name); +/*%< + * Returns a zone named 'name' from collection 'catzs' + * + * Requires: + * \li 'catzs' is a valid dns_catz_zones_t. + * \li 'name' is a valid dns_name_t. + */ + +void +dns_catz_catzs_attach(dns_catz_zones_t *catzs, dns_catz_zones_t **catzsp); +/*%< + * Attach 'catzs' to 'catzsp'. + * + * Requires: + * \li 'catzs' is a valid dns_catz_zones_t. + * \li 'catzsp' is not NULL and *catzsp is NULL. + */ + +void +dns_catz_catzs_detach(dns_catz_zones_t **catzsp); +/*%< + * Detach 'catzsp', free if no further references. + * + * Requires: + * \li 'catzsp' is not NULL and *catzsp is not NULL. + */ + +void +dns_catz_catzs_set_view(dns_catz_zones_t *catzs, dns_view_t *view); +/*%< + * Set a view for 'catzs'. + * + * Requires: + * \li 'catzs' is a valid dns_catz_zones_t. + * \li 'catzs->view' is NULL or 'catzs->view' == 'view'. + */ + +isc_result_t +dns_catz_dbupdate_callback(dns_db_t *db, void *fn_arg); +/*%< + * Callback for update of catalog zone database. + * If there was no catalog zone update recently it launches an + * update_taskaction immediately. + * If there was an update recently it schedules update_taskaction for some time + * in the future. + * If there is an update scheduled it replaces old db version with a new one. + * + * Requires: + * \li 'db' is a valid database. + * \li 'fn_arg' is not NULL (casted to dns_catz_zones_t*). + */ + +void +dns_catz_update_taskaction(isc_task_t *task, isc_event_t *event); +/*%< + * Task that launches dns_catz_update_from_db. + * + * Requires: + * \li 'event' is not NULL. + */ + +void +dns_catz_update_from_db(dns_db_t *db, dns_catz_zones_t *catzs); +/*%< + * Process an updated database for a catalog zone. + * It creates a new catz, iterates over database to fill it with content, and + * then merges new catz into old catz. + * + * Requires: + * \li 'db' is a valid DB. + * \li 'catzs' is a valid dns_catz_zones_t. + * + */ + +void +dns_catz_prereconfig(dns_catz_zones_t *catzs); +/*%< + * Called before reconfig, clears 'active' flag on all the zones in set + * + * Requires: + * \li 'catzs' is a valid dns_catz_zones_t. + * + */ + +void +dns_catz_postreconfig(dns_catz_zones_t *catzs); +/*%< + * Called after reconfig, walks through all zones in set, removes those + * inactive and force reload of those with changed configuration. + * + * Requires: + * \li 'catzs' is a valid dns_catz_zones_t. + */ + +void +dns_catz_get_iterator(dns_catz_zone_t *catz, isc_ht_iter_t **itp); +/*%< + * Get the hashtable iterator on catalog zone members, point '*itp' to it. + * + * Requires: + * \li 'catzs' is a valid dns_catz_zones_t. + * \li 'itp' is not NULL and '*itp' is NULL. + * + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_CATZ_H_ */ diff --git a/lib/dns/include/dns/cert.h b/lib/dns/include/dns/cert.h new file mode 100644 index 0000000..cdfa245 --- /dev/null +++ b/lib/dns/include/dns/cert.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#ifndef DNS_CERT_H +#define DNS_CERT_H 1 + +/*! \file dns/cert.h */ + +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_cert_fromtext(dns_cert_t *certp, isc_textregion_t *source); +/*%< + * Convert the text 'source' refers to into a certificate type. + * The text may contain either a mnemonic type name or a decimal type number. + * + * Requires: + *\li 'certp' is a valid pointer. + * + *\li 'source' is a valid text region. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #ISC_R_RANGE numeric type is out of range + *\li #DNS_R_UNKNOWN mnemonic type is unknown + */ + +isc_result_t +dns_cert_totext(dns_cert_t cert, isc_buffer_t *target); +/*%< + * Put a textual representation of certificate type 'cert' into 'target'. + * + * Requires: + *\li 'cert' is a valid cert. + * + *\li 'target' is a valid text buffer. + * + * Ensures: + *\li If the result is success: + * The used space in 'target' is updated. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #ISC_R_NOSPACE target buffer is too small + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_CERT_H */ diff --git a/lib/dns/include/dns/client.h b/lib/dns/include/dns/client.h new file mode 100644 index 0000000..fdcb698 --- /dev/null +++ b/lib/dns/include/dns/client.h @@ -0,0 +1,476 @@ +/* + * 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. + */ + +#ifndef DNS_CLIENT_H +#define DNS_CLIENT_H 1 + +/***** +***** Module Info +*****/ + +/*! \file + * + * \brief + * The DNS client module provides convenient programming interfaces to various + * DNS services, such as name resolution with or without DNSSEC validation or + * dynamic DNS update. This module is primarily expected to be used by other + * applications than BIND9-related ones that need such advanced DNS features. + * + * MP: + *\li In the typical usage of this module, application threads will not share + * the same data structures created and manipulated in this module. + * However, the module still ensures appropriate synchronization of such + * data structures. + * + * Resources: + *\li TBS + * + * Security: + *\li This module does not handle any low-level data directly, and so no + * security issue specific to this module is anticipated. + */ + +#include <isc/event.h> +#include <isc/sockaddr.h> + +#include <dns/tsig.h> +#include <dns/types.h> + +#include <dst/dst.h> + +typedef enum { + updateop_none = 0, + updateop_add = 1, + updateop_delete = 2, + updateop_exist = 3, + updateop_notexist = 4, + updateop_max = 5 +} dns_client_updateop_t; + +ISC_LANG_BEGINDECLS + +/*** + *** Types + ***/ + +/*% + * Optional flags for dns_client_create(x). + */ +/*%< Enable caching resolution results (experimental). */ +#define DNS_CLIENTCREATEOPT_USECACHE 0x8000 + +/*% + * Optional flags for dns_client_(start)resolve. + */ +/*%< Do not return DNSSEC data (e.g. RRSIGS) with response. */ +#define DNS_CLIENTRESOPT_NODNSSEC 0x01 +/*%< Allow running external context. */ +#define DNS_CLIENTRESOPT_RESERVED 0x02 +/*%< Don't validate responses. */ +#define DNS_CLIENTRESOPT_NOVALIDATE 0x04 +/*%< Don't set the CD flag on upstream queries. */ +#define DNS_CLIENTRESOPT_NOCDFLAG 0x08 +/*%< Use TCP transport. */ +#define DNS_CLIENTRESOPT_TCP 0x10 + +/*% + * Optional flags for dns_client_(start)request. + */ +/*%< Allow running external context. */ +#define DNS_CLIENTREQOPT_RESERVED 0x01 +/*%< Use TCP transport. */ +#define DNS_CLIENTREQOPT_TCP 0x02 + +/*% + * Optional flags for dns_client_(start)update. + */ +/*%< Allow running external context. */ +#define DNS_CLIENTUPDOPT_RESERVED 0x01 +/*%< Use TCP transport. */ +#define DNS_CLIENTUPDOPT_TCP 0x02 + +/*% + * View name used in dns_client. + */ +#define DNS_CLIENTVIEW_NAME "_dnsclient" + +/*% + * A dns_clientresevent_t is sent when name resolution performed by a client + * completes. 'result' stores the result code of the entire resolution + * procedure. 'vresult' specifically stores the result code of DNSSEC + * validation if it is performed. When name resolution successfully completes, + * 'answerlist' is typically non empty, containing answer names along with + * RRsets. It is the receiver's responsibility to free this list by calling + * dns_client_freeresanswer() before freeing the event structure. + */ +typedef struct dns_clientresevent { + ISC_EVENT_COMMON(struct dns_clientresevent); + isc_result_t result; + isc_result_t vresult; + dns_namelist_t answerlist; +} dns_clientresevent_t; /* too long? */ + +/*% + * A dns_clientreqevent_t is sent when a DNS request is completed by a client. + * 'result' stores the result code of the entire transaction. + * If the transaction is successfully completed but the response packet cannot + * be parsed, 'result' will store the result code of dns_message_parse(). + * If the response packet is received, 'rmessage' will contain the response + * message, whether it is successfully parsed or not. + */ +typedef struct dns_clientreqevent { + ISC_EVENT_COMMON(struct dns_clientreqevent); + isc_result_t result; + dns_message_t *rmessage; +} dns_clientreqevent_t; /* too long? */ + +isc_result_t +dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, + isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, + unsigned int options, dns_client_t **clientp, + const isc_sockaddr_t *localaddr4, + const isc_sockaddr_t *localaddr6); +/*%< + * Create a DNS client object with minimal internal resources, such as + * a default view for the IN class and IPv4/IPv6 dispatches for the view. + * + * dns_client_create() takes 'manager' arguments so that the caller can + * control the behavior of the client through the underlying event framework. + * 'localaddr4' and 'localaddr6' specify the local addresses to use for + * each address family; if both are set to NULL, then wildcard addresses + * will be used for both families. If only one is NULL, then the other + * address will be used as the local address, and the NULL protocol family + * will not be used. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li 'actx' is a valid application context. + * + *\li 'taskmgr' is a valid task manager. + * + *\li 'socketmgr' is a valid socket manager. + * + *\li 'timermgr' is a valid timer manager. + * + *\li clientp != NULL && *clientp == NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + */ + +void +dns_client_destroy(dns_client_t **clientp); +/*%< + * Destroy 'client'. + * + * Requires: + * + *\li '*clientp' is a valid client. + * + * Ensures: + * + *\li *clientp == NULL. + */ + +isc_result_t +dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass, + const dns_name_t *name_space, isc_sockaddrlist_t *addrs); +/*%< + * Specify a list of addresses of recursive name servers that the client will + * use for name resolution. A view for the 'rdclass' class must be created + * beforehand. If 'name_space' is non NULL, the specified server will be used + * if and only if the query name is a subdomain of 'name_space'. When servers + * for multiple 'name_space's are provided, and a query name is covered by + * more than one 'name_space', the servers for the best (longest) matching + * name_space will be used. If 'name_space' is NULL, it works as if + * dns_rootname (.) were specified. + * + * Requires: + * + *\li 'client' is a valid client. + * + *\li 'name_space' is NULL or a valid name. + * + *\li 'addrs' != NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + */ + +isc_result_t +dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass, + const dns_name_t *name_space); +/*%< + * Remove configured recursive name servers for the 'rdclass' and 'name_space' + * from the client. See the description of dns_client_setservers() for + * the requirements about 'rdclass' and 'name_space'. + * + * Requires: + * + *\li 'client' is a valid client. + * + *\li 'name_space' is NULL or a valid name. + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + */ + +isc_result_t +dns_client_resolve(dns_client_t *client, const dns_name_t *name, + dns_rdataclass_t rdclass, dns_rdatatype_t type, + unsigned int options, dns_namelist_t *namelist); + +isc_result_t +dns_client_startresolve(dns_client_t *client, const dns_name_t *name, + dns_rdataclass_t rdclass, dns_rdatatype_t type, + unsigned int options, isc_task_t *task, + isc_taskaction_t action, void *arg, + dns_clientrestrans_t **transp); +/*%< + * Perform name resolution for 'name', 'rdclass', and 'type'. + * + * If any trusted keys are configured and the query name is considered to + * belong to a secure zone, these functions also validate the responses + * using DNSSEC by default. If the DNS_CLIENTRESOPT_NOVALIDATE flag is set + * in 'options', DNSSEC validation is disabled regardless of the configured + * trusted keys or the query name. With DNS_CLIENTRESOPT_NODNSSEC + * DNSSEC data is not returned with response. DNS_CLIENTRESOPT_NOCDFLAG + * disables the CD flag on queries, DNS_CLIENTRESOPT_TCP switches to + * the TCP (vs. UDP) transport. + * + * dns_client_resolve() provides a synchronous service. This function starts + * name resolution internally and blocks until it completes. On success, + * 'namelist' will contain a list of answer names, each of which has + * corresponding RRsets. The caller must provide a valid empty list, and + * is responsible for freeing the list content via dns_client_freeresanswer(). + * If the name resolution fails due to an error in DNSSEC validation, + * dns_client_resolve() returns the result code indicating the validation + * error. Otherwise, it returns the result code of the entire resolution + * process, either success or failure. + * + * It is expected that the client object passed to dns_client_resolve() was + * created via dns_client_create() and has external managers and contexts. + * + * dns_client_startresolve() is an asynchronous version of dns_client_resolve() + * and does not block. When name resolution is completed, 'action' will be + * called with the argument of a 'dns_clientresevent_t' object, which contains + * the resulting list of answer names (on success). On return, '*transp' is + * set to an opaque transaction ID so that the caller can cancel this + * resolution process. + * + * Requires: + * + *\li 'client' is a valid client. + * + *\li 'addrs' != NULL. + * + *\li 'name' is a valid name. + * + *\li 'namelist' != NULL and is not empty. + * + *\li 'task' is a valid task. + * + *\li 'transp' != NULL && *transp == NULL; + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + */ + +void +dns_client_cancelresolve(dns_clientrestrans_t *trans); +/*%< + * Cancel an ongoing resolution procedure started via + * dns_client_startresolve(). + * + * Notes: + * + *\li If the resolution procedure has not completed, post its CLIENTRESDONE + * event with a result code of #ISC_R_CANCELED. + * + * Requires: + * + *\li 'trans' is a valid transaction ID. + */ + +void +dns_client_destroyrestrans(dns_clientrestrans_t **transp); +/*%< + * Destroy name resolution transaction state identified by '*transp'. + * + * Requires: + * + *\li '*transp' is a valid transaction ID. + * + *\li The caller has received the CLIENTRESDONE event (either because the + * resolution completed or because dns_client_cancelresolve() was called). + * + * Ensures: + * + *\li *transp == NULL. + */ + +void +dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist); +/*%< + * Free resources allocated for the content of 'namelist'. + * + * Requires: + * + *\li 'client' is a valid client. + * + *\li 'namelist' != NULL. + */ + +isc_result_t +dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass, + dns_rdatatype_t rdtype, const dns_name_t *keyname, + isc_buffer_t *keydatabuf); +/*%< + * Add a DNSSEC trusted key for the 'rdclass' class. A view for the 'rdclass' + * class must be created beforehand. 'rdtype' is the type of the RR data + * for the key, either DNSKEY or DS. 'keyname' is the DNS name of the key, + * and 'keydatabuf' stores the RR data. + * + * Requires: + * + *\li 'client' is a valid client. + * + *\li 'keyname' is a valid name. + * + *\li 'keydatabuf' is a valid buffer. + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + */ + +isc_result_t +dns_client_request(dns_client_t *client, dns_message_t *qmessage, + dns_message_t *rmessage, const isc_sockaddr_t *server, + unsigned int options, unsigned int parseoptions, + dns_tsec_t *tsec, unsigned int timeout, + unsigned int udptimeout, unsigned int udpretries); + +isc_result_t +dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage, + dns_message_t *rmessage, const isc_sockaddr_t *server, + unsigned int options, unsigned int parseoptions, + dns_tsec_t *tsec, unsigned int timeout, + unsigned int udptimeout, unsigned int udpretries, + isc_task_t *task, isc_taskaction_t action, void *arg, + dns_clientreqtrans_t **transp); + +/*%< + * Send a DNS request containing a query message 'query' to 'server'. + * + * 'parseoptions' will be used when the response packet is parsed, and will be + * passed to dns_message_parse() via dns_request_getresponse(). See + * dns_message_parse() for more details. + * + * 'tsec' is a transaction security object containing, e.g. a TSIG key for + * authenticating the request/response transaction. This is optional and can + * be NULL, in which case this library performs the transaction without any + * transaction authentication. + * + * 'timeout', 'udptimeout', and 'udpretries' are passed to + * dns_request_createvia3(). See dns_request_createvia3() for more details. + * + * dns_client_request() provides a synchronous service. This function sends + * the request and blocks until a response is received. On success, + * 'rmessage' will contain the response message. The caller must provide a + * valid initialized message. + * + * It is expected that the client object passed to dns_client_request() was + * created via dns_client_create() and has external managers and contexts. + * + * dns_client_startrequest() is an asynchronous version of dns_client_request() + * and does not block. When the transaction is completed, 'action' will be + * called with the argument of a 'dns_clientreqevent_t' object, which contains + * the response message (on success). On return, '*transp' is set to an opaque + * transaction ID so that the caller can cancel this request. + * + * DNS_CLIENTREQOPT_TCP switches to the TCP (vs. UDP) transport. + * + * Requires: + * + *\li 'client' is a valid client. + * + *\li 'qmessage' and 'rmessage' are valid initialized message. + * + *\li 'server' is a valid socket address structure. + * + *\li 'task' is a valid task. + * + *\li 'transp' != NULL && *transp == NULL; + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + * + *\li Any result that dns_message_parse() can return. + */ + +void +dns_client_cancelrequest(dns_clientreqtrans_t *transp); +/*%< + * Cancel an ongoing DNS request procedure started via + * dns_client_startrequest(). + * + * Notes: + * + *\li If the request procedure has not completed, post its CLIENTREQDONE + * event with a result code of #ISC_R_CANCELED. + * + * Requires: + * + *\li 'trans' is a valid transaction ID. + */ + +void +dns_client_destroyreqtrans(dns_clientreqtrans_t **transp); +/*% + * Destroy DNS request transaction state identified by '*transp'. + * + * Requires: + * + *\li '*transp' is a valid transaction ID. + * + *\li The caller has received the CLIENTREQDONE event (either because the + * request completed or because dns_client_cancelrequest() was called). + * + * Ensures: + * + *\li *transp == NULL. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_CLIENT_H */ diff --git a/lib/dns/include/dns/clientinfo.h b/lib/dns/include/dns/clientinfo.h new file mode 100644 index 0000000..3928d21 --- /dev/null +++ b/lib/dns/include/dns/clientinfo.h @@ -0,0 +1,95 @@ +/* + * 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. + */ + +#ifndef DNS_CLIENTINFO_H +#define DNS_CLIENTINFO_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/clientinfo.h + * \brief + * The DNS clientinfo interface allows libdns to retrieve information + * about the client from the caller. + * + * The clientinfo interface is used by the DNS DB and DLZ interfaces; + * it allows databases to modify their answers on the basis of information + * about the client, such as source IP address. + * + * dns_clientinfo_t contains a pointer to an opaque structure containing + * client information in some form. dns_clientinfomethods_t contains a + * list of methods which operate on that opaque structure to return + * potentially useful data. Both structures also contain versioning + * information. + */ + +/***** +***** Imports +*****/ + +#include <inttypes.h> + +#include <isc/sockaddr.h> +#include <isc/types.h> + +#include <dns/ecs.h> + +ISC_LANG_BEGINDECLS + +/***** +***** Types +*****/ + +#define DNS_CLIENTINFO_VERSION 3 +/* + * Any updates to this structure should also be applied in + * contrib/modules/dlz/dlz_minmal.h. + */ +typedef struct dns_clientinfo { + uint16_t version; + void *data; + void *dbversion; + dns_ecs_t ecs; +} dns_clientinfo_t; + +typedef isc_result_t (*dns_clientinfo_sourceip_t)(dns_clientinfo_t *client, + isc_sockaddr_t **addrp); + +#define DNS_CLIENTINFOMETHODS_VERSION 2 +#define DNS_CLIENTINFOMETHODS_AGE 1 + +/* + * Any updates to this structure should also be applied in + * contrib/modules/dlz/dlz_minmal.h. + */ +typedef struct dns_clientinfomethods { + uint16_t version; + uint16_t age; + dns_clientinfo_sourceip_t sourceip; +} dns_clientinfomethods_t; + +/***** +***** Methods +*****/ +void +dns_clientinfomethods_init(dns_clientinfomethods_t *methods, + dns_clientinfo_sourceip_t sourceip); + +void +dns_clientinfo_init(dns_clientinfo_t *ci, void *data, dns_ecs_t *ecs, + void *versionp); + +ISC_LANG_ENDDECLS + +#endif /* DNS_CLIENTINFO_H */ diff --git a/lib/dns/include/dns/compress.h b/lib/dns/include/dns/compress.h new file mode 100644 index 0000000..7e19af6 --- /dev/null +++ b/lib/dns/include/dns/compress.h @@ -0,0 +1,302 @@ +/* + * 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. + */ + +#ifndef DNS_COMPRESS_H +#define DNS_COMPRESS_H 1 + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/region.h> + +#include <dns/name.h> +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/*! \file dns/compress.h + * Direct manipulation of the structures is strongly discouraged. + * + * A name compression context handles compression of multiple DNS names + * in relation to a single DNS message. The context can be used to + * selectively turn on/off compression for specific names (depending on + * the RR type) by using \c dns_compress_setmethods(). Alternately, + * compression can be disabled completely using \c + * dns_compress_disable(). + * + * \c dns_compress_setmethods() is intended for use by RDATA towire() + * implementations, whereas \c dns_compress_disable() is intended to be + * used by a nameserver's configuration manager. + */ + +#define DNS_COMPRESS_NONE 0x00 /*%< no compression */ +#define DNS_COMPRESS_GLOBAL14 0x01 /*%< "normal" compression. */ +#define DNS_COMPRESS_ALL 0x01 /*%< all compression. */ +#define DNS_COMPRESS_CASESENSITIVE 0x02 /*%< case sensitive compression. */ +#define DNS_COMPRESS_ENABLED 0x04 + +/* + * DNS_COMPRESS_TABLESIZE must be a power of 2. The compress code + * utilizes this assumption. + */ +#define DNS_COMPRESS_TABLEBITS 6 +#define DNS_COMPRESS_TABLESIZE (1U << DNS_COMPRESS_TABLEBITS) +#define DNS_COMPRESS_TABLEMASK (DNS_COMPRESS_TABLESIZE - 1) +#define DNS_COMPRESS_INITIALNODES 24 +#define DNS_COMPRESS_ARENA_SIZE 640 + +typedef struct dns_compressnode dns_compressnode_t; + +struct dns_compressnode { + dns_compressnode_t *next; + uint16_t offset; + uint16_t count; + isc_region_t r; + dns_name_t name; +}; + +struct dns_compress { + unsigned int magic; /*%< Magic number. */ + unsigned int allowed; /*%< Allowed methods. */ + int edns; /*%< Edns version or -1. */ + /*% Global compression table. */ + dns_compressnode_t *table[DNS_COMPRESS_TABLESIZE]; + /*% Preallocated arena for names. */ + unsigned char arena[DNS_COMPRESS_ARENA_SIZE]; + off_t arena_off; + /*% Preallocated nodes for the table. */ + dns_compressnode_t initialnodes[DNS_COMPRESS_INITIALNODES]; + uint16_t count; /*%< Number of nodes. */ + isc_mem_t *mctx; /*%< Memory context. */ +}; + +typedef enum { + DNS_DECOMPRESS_ANY, /*%< Any compression */ + DNS_DECOMPRESS_STRICT, /*%< Allowed compression */ + DNS_DECOMPRESS_NONE /*%< No compression */ +} dns_decompresstype_t; + +struct dns_decompress { + unsigned int magic; /*%< Magic number. */ + unsigned int allowed; /*%< Allowed methods. */ + int edns; /*%< Edns version or -1. */ + dns_decompresstype_t type; /*%< Strict checking */ +}; + +isc_result_t +dns_compress_init(dns_compress_t *cctx, int edns, isc_mem_t *mctx); +/*%< + * Initialise the compression context structure pointed to by + * 'cctx'. A freshly initialized context has name compression + * enabled, but no methods are set. Please use \c + * dns_compress_setmethods() to set a compression method. + * + * Requires: + * \li 'cctx' is a valid dns_compress_t structure. + * \li 'mctx' is an initialized memory context. + * Ensures: + * \li cctx->global is initialized. + * + * Returns: + * \li #ISC_R_SUCCESS + */ + +void +dns_compress_invalidate(dns_compress_t *cctx); + +/*%< + * Invalidate the compression structure pointed to by cctx. + * + * Requires: + *\li 'cctx' to be initialized. + */ + +void +dns_compress_setmethods(dns_compress_t *cctx, unsigned int allowed); + +/*%< + * Sets allowed compression methods. + * + * Requires: + *\li 'cctx' to be initialized. + */ + +unsigned int +dns_compress_getmethods(dns_compress_t *cctx); + +/*%< + * Gets allowed compression methods. + * + * Requires: + *\li 'cctx' to be initialized. + * + * Returns: + *\li allowed compression bitmap. + */ + +void +dns_compress_disable(dns_compress_t *cctx); +/*%< + * Disables all name compression in the context. Once disabled, + * name compression cannot currently be re-enabled. + * + * Requires: + *\li 'cctx' to be initialized. + * + */ + +void +dns_compress_setsensitive(dns_compress_t *cctx, bool sensitive); + +/* + * Preserve the case of compressed domain names. + * + * Requires: + * 'cctx' to be initialized. + */ + +bool +dns_compress_getsensitive(dns_compress_t *cctx); +/* + * Return whether case is to be preserved when compressing + * domain names. + * + * Requires: + * 'cctx' to be initialized. + */ + +int +dns_compress_getedns(dns_compress_t *cctx); + +/*%< + * Gets edns value. + * + * Requires: + *\li 'cctx' to be initialized. + * + * Returns: + *\li -1 .. 255 + */ + +bool +dns_compress_findglobal(dns_compress_t *cctx, const dns_name_t *name, + dns_name_t *prefix, uint16_t *offset); +/*%< + * Finds longest possible match of 'name' in the global compression table. + * + * Requires: + *\li 'cctx' to be initialized. + *\li 'name' to be a absolute name. + *\li 'prefix' to be initialized. + *\li 'offset' to point to an uint16_t. + * + * Ensures: + *\li 'prefix' and 'offset' are valid if true is returned. + * + * Returns: + *\li #true / #false + */ + +void +dns_compress_add(dns_compress_t *cctx, const dns_name_t *name, + const dns_name_t *prefix, uint16_t offset); +/*%< + * Add compression pointers for 'name' to the compression table, + * not replacing existing pointers. + * + * Requires: + *\li 'cctx' initialized + * + *\li 'name' must be initialized and absolute, and must remain + * valid until the message compression is complete. + * + *\li 'prefix' must be a prefix returned by + * dns_compress_findglobal(), or the same as 'name'. + */ + +void +dns_compress_rollback(dns_compress_t *cctx, uint16_t offset); + +/*%< + * Remove any compression pointers from global table >= offset. + * + * Requires: + *\li 'cctx' is initialized. + */ + +void +dns_decompress_init(dns_decompress_t *dctx, int edns, + dns_decompresstype_t type); + +/*%< + * Initializes 'dctx'. + * Records 'edns' and 'type' into the structure. + * + * Requires: + *\li 'dctx' to be a valid pointer. + */ + +void +dns_decompress_invalidate(dns_decompress_t *dctx); + +/*%< + * Invalidates 'dctx'. + * + * Requires: + *\li 'dctx' to be initialized + */ + +void +dns_decompress_setmethods(dns_decompress_t *dctx, unsigned int allowed); + +/*%< + * Sets 'dctx->allowed' to 'allowed'. + * + * Requires: + *\li 'dctx' to be initialized + */ + +unsigned int +dns_decompress_getmethods(dns_decompress_t *dctx); + +/*%< + * Returns 'dctx->allowed' + * + * Requires: + *\li 'dctx' to be initialized + */ + +int +dns_decompress_edns(dns_decompress_t *dctx); + +/*%< + * Returns 'dctx->edns' + * + * Requires: + *\li 'dctx' to be initialized + */ + +dns_decompresstype_t +dns_decompress_type(dns_decompress_t *dctx); + +/*%< + * Returns 'dctx->type' + * + * Requires: + *\li 'dctx' to be initialized + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_COMPRESS_H */ diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h new file mode 100644 index 0000000..84b1cb1 --- /dev/null +++ b/lib/dns/include/dns/db.h @@ -0,0 +1,1800 @@ +/* + * 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. + */ + +#ifndef DNS_DB_H +#define DNS_DB_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/db.h + * \brief + * The DNS DB interface allows named rdatasets to be stored and retrieved. + * + * The dns_db_t type is like a "virtual class". To actually use + * DBs, an implementation of the class is required. + * + * XXX more XXX + * + * MP: + * \li The module ensures appropriate synchronization of data structures it + * creates and manipulates. + * + * Reliability: + * \li No anticipated impact. + * + * Resources: + * \li TBS + * + * Security: + * \li No anticipated impact. + * + * Standards: + * \li None. + */ + +/***** +***** Imports +*****/ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/deprecated.h> +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/stats.h> +#include <isc/stdtime.h> + +#include <dns/clientinfo.h> +#include <dns/fixedname.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/rdataset.h> +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/***** +***** Types +*****/ + +typedef struct dns_dbmethods { + void (*attach)(dns_db_t *source, dns_db_t **targetp); + void (*detach)(dns_db_t **dbp); + isc_result_t (*beginload)(dns_db_t *db, + dns_rdatacallbacks_t *callbacks); + isc_result_t (*endload)(dns_db_t *db, dns_rdatacallbacks_t *callbacks); + isc_result_t (*serialize)(dns_db_t *db, dns_dbversion_t *version, + FILE *file); + isc_result_t (*dump)(dns_db_t *db, dns_dbversion_t *version, + const char *filename, + dns_masterformat_t masterformat); + void (*currentversion)(dns_db_t *db, dns_dbversion_t **versionp); + isc_result_t (*newversion)(dns_db_t *db, dns_dbversion_t **versionp); + void (*attachversion)(dns_db_t *db, dns_dbversion_t *source, + dns_dbversion_t **targetp); + void (*closeversion)(dns_db_t *db, dns_dbversion_t **versionp, + bool commit); + isc_result_t (*findnode)(dns_db_t *db, const dns_name_t *name, + bool create, dns_dbnode_t **nodep); + isc_result_t (*find)(dns_db_t *db, const dns_name_t *name, + dns_dbversion_t *version, dns_rdatatype_t type, + unsigned int options, isc_stdtime_t now, + dns_dbnode_t **nodep, dns_name_t *foundname, + dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset); + isc_result_t (*findzonecut)(dns_db_t *db, const dns_name_t *name, + unsigned int options, isc_stdtime_t now, + dns_dbnode_t **nodep, dns_name_t *foundname, + dns_name_t *dcname, + dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset); + void (*attachnode)(dns_db_t *db, dns_dbnode_t *source, + dns_dbnode_t **targetp); + void (*detachnode)(dns_db_t *db, dns_dbnode_t **targetp); + isc_result_t (*expirenode)(dns_db_t *db, dns_dbnode_t *node, + isc_stdtime_t now); + void (*printnode)(dns_db_t *db, dns_dbnode_t *node, FILE *out); + isc_result_t (*createiterator)(dns_db_t *db, unsigned int options, + dns_dbiterator_t **iteratorp); + isc_result_t (*findrdataset)(dns_db_t *db, dns_dbnode_t *node, + dns_dbversion_t *version, + dns_rdatatype_t type, + dns_rdatatype_t covers, isc_stdtime_t now, + dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset); + isc_result_t (*allrdatasets)(dns_db_t *db, dns_dbnode_t *node, + dns_dbversion_t *version, + unsigned int options, isc_stdtime_t now, + dns_rdatasetiter_t **iteratorp); + isc_result_t (*addrdataset)(dns_db_t *db, dns_dbnode_t *node, + dns_dbversion_t *version, isc_stdtime_t now, + dns_rdataset_t *rdataset, + unsigned int options, + dns_rdataset_t *addedrdataset); + isc_result_t (*subtractrdataset)(dns_db_t *db, dns_dbnode_t *node, + dns_dbversion_t *version, + dns_rdataset_t *rdataset, + unsigned int options, + dns_rdataset_t *newrdataset); + isc_result_t (*deleterdataset)(dns_db_t *db, dns_dbnode_t *node, + dns_dbversion_t *version, + dns_rdatatype_t type, + dns_rdatatype_t covers); + bool (*issecure)(dns_db_t *db); + unsigned int (*nodecount)(dns_db_t *db); + bool (*ispersistent)(dns_db_t *db); + void (*overmem)(dns_db_t *db, bool overmem); + void (*settask)(dns_db_t *db, isc_task_t *); + isc_result_t (*getoriginnode)(dns_db_t *db, dns_dbnode_t **nodep); + void (*transfernode)(dns_db_t *db, dns_dbnode_t **sourcep, + dns_dbnode_t **targetp); + isc_result_t (*getnsec3parameters)(dns_db_t *db, + dns_dbversion_t *version, + dns_hash_t *hash, uint8_t *flags, + uint16_t *iterations, + unsigned char *salt, + size_t *salt_len); + isc_result_t (*findnsec3node)(dns_db_t *db, const dns_name_t *name, + bool create, dns_dbnode_t **nodep); + isc_result_t (*setsigningtime)(dns_db_t *db, dns_rdataset_t *rdataset, + isc_stdtime_t resign); + isc_result_t (*getsigningtime)(dns_db_t *db, dns_rdataset_t *rdataset, + dns_name_t *name); + void (*resigned)(dns_db_t *db, dns_rdataset_t *rdataset, + dns_dbversion_t *version); + bool (*isdnssec)(dns_db_t *db); + dns_stats_t *(*getrrsetstats)(dns_db_t *db); + void (*rpz_attach)(dns_db_t *db, void *rpzs, uint8_t rpz_num); + isc_result_t (*rpz_ready)(dns_db_t *db); + isc_result_t (*findnodeext)(dns_db_t *db, const dns_name_t *name, + bool create, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo, + dns_dbnode_t **nodep); + isc_result_t (*findext)(dns_db_t *db, const dns_name_t *name, + dns_dbversion_t *version, dns_rdatatype_t type, + unsigned int options, isc_stdtime_t now, + dns_dbnode_t **nodep, dns_name_t *foundname, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo, + dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset); + isc_result_t (*setcachestats)(dns_db_t *db, isc_stats_t *stats); + size_t (*hashsize)(dns_db_t *db); + isc_result_t (*nodefullname)(dns_db_t *db, dns_dbnode_t *node, + dns_name_t *name); + isc_result_t (*getsize)(dns_db_t *db, dns_dbversion_t *version, + uint64_t *records, uint64_t *bytes); + isc_result_t (*setservestalettl)(dns_db_t *db, dns_ttl_t ttl); + isc_result_t (*getservestalettl)(dns_db_t *db, dns_ttl_t *ttl); + isc_result_t (*setservestalerefresh)(dns_db_t *db, uint32_t interval); + isc_result_t (*getservestalerefresh)(dns_db_t *db, uint32_t *interval); + isc_result_t (*setgluecachestats)(dns_db_t *db, isc_stats_t *stats); + isc_result_t (*adjusthashsize)(dns_db_t *db, size_t size); +} dns_dbmethods_t; + +typedef isc_result_t (*dns_dbcreatefunc_t)(isc_mem_t *mctx, + const dns_name_t *name, + dns_dbtype_t type, + dns_rdataclass_t rdclass, + unsigned int argc, char *argv[], + void *driverarg, dns_db_t **dbp); + +typedef isc_result_t (*dns_dbupdate_callback_t)(dns_db_t *db, void *fn_arg); + +#define DNS_DB_MAGIC ISC_MAGIC('D', 'N', 'S', 'D') +#define DNS_DB_VALID(db) ISC_MAGIC_VALID(db, DNS_DB_MAGIC) + +/*% + * This structure is actually just the common prefix of a DNS db + * implementation's version of a dns_db_t. + * \brief + * Direct use of this structure by clients is forbidden. DB implementations + * may change the structure. 'magic' must be DNS_DB_MAGIC for any of the + * dns_db_ routines to work. DB implementations must maintain all DB + * invariants. + */ +struct dns_db { + unsigned int magic; + unsigned int impmagic; + dns_dbmethods_t *methods; + uint16_t attributes; + dns_rdataclass_t rdclass; + dns_name_t origin; + isc_mem_t *mctx; + ISC_LIST(dns_dbonupdatelistener_t) update_listeners; +}; + +#define DNS_DBATTR_CACHE 0x01 +#define DNS_DBATTR_STUB 0x02 + +struct dns_dbonupdatelistener { + dns_dbupdate_callback_t onupdate; + void *onupdate_arg; + ISC_LINK(dns_dbonupdatelistener_t) link; +}; + +/*@{*/ +/*% + * Options that can be specified for dns_db_find(). + */ +#define DNS_DBFIND_GLUEOK 0x0001 +#define DNS_DBFIND_VALIDATEGLUE 0x0002 +#define DNS_DBFIND_NOWILD 0x0004 +#define DNS_DBFIND_PENDINGOK 0x0008 +#define DNS_DBFIND_NOEXACT 0x0010 +#define DNS_DBFIND_FORCENSEC 0x0020 +#define DNS_DBFIND_COVERINGNSEC 0x0040 +#define DNS_DBFIND_FORCENSEC3 0x0080 +#define DNS_DBFIND_ADDITIONALOK 0x0100 +#define DNS_DBFIND_NOZONECUT 0x0200 + +/* + * DNS_DBFIND_STALEOK: This flag is set when BIND fails to refresh a RRset due + * to timeout (resolver-query-timeout). Its intent is to try to look for stale + * data in cache as a fallback, but only if stale answers are enabled in + * configuration. + */ +#define DNS_DBFIND_STALEOK 0x0400 + +/* + * DNS_DBFIND_STALEENABLED: This flag is used as a hint to the database that + * it may use stale data. It is always set during query lookup if stale + * answers are enabled, but only effectively used during stale-refresh-time + * window. Also during this window, the resolver will not try to resolve the + * query, in other words no attempt to refresh the data in cache is made when + * the stale-refresh-time window is active. + */ +#define DNS_DBFIND_STALEENABLED 0x0800 + +/* + * DNS_DBFIND_STALETIMEOUT: This flag is used when we want stale data from the + * database, but not due to a failure in resolution, it also doesn't require + * stale-refresh-time window timer to be active. As long as there is stale + * data available, it should be returned. + */ +#define DNS_DBFIND_STALETIMEOUT 0x1000 + +/* + * DNS_DBFIND_STALESTART: This flag is used to activate stale-refresh-time + * window. + */ +#define DNS_DBFIND_STALESTART 0x2000 +/*@}*/ + +/*@{*/ +/*% + * Options that can be specified for dns_db_addrdataset(). + */ +#define DNS_DBADD_MERGE 0x01 +#define DNS_DBADD_FORCE 0x02 +#define DNS_DBADD_EXACT 0x04 +#define DNS_DBADD_EXACTTTL 0x08 +#define DNS_DBADD_PREFETCH 0x10 +/*@}*/ + +/*% + * Options that can be specified for dns_db_subtractrdataset(). + */ +#define DNS_DBSUB_EXACT 0x01 +#define DNS_DBSUB_WANTOLD 0x02 + +/*@{*/ +/*% + * Iterator options + */ +#define DNS_DB_RELATIVENAMES 0x1 +#define DNS_DB_NSEC3ONLY 0x2 +#define DNS_DB_NONSEC3 0x4 +/*@}*/ + +#define DNS_DB_STALEOK 0x01 +#define DNS_DB_EXPIREDOK 0x02 + +/***** +***** Methods +*****/ + +/*** + *** Basic DB Methods + ***/ + +isc_result_t +dns_db_create(isc_mem_t *mctx, const char *db_type, const dns_name_t *origin, + dns_dbtype_t type, dns_rdataclass_t rdclass, unsigned int argc, + char *argv[], dns_db_t **dbp); +/*%< + * Create a new database using implementation 'db_type'. + * + * Notes: + * \li All names in the database must be subdomains of 'origin' and in class + * 'rdclass'. The database makes its own copy of the origin, so the + * caller may do whatever they like with 'origin' and its storage once the + * call returns. + * + * \li DB implementation-specific parameters are passed using argc and argv. + * + * Requires: + * + * \li dbp != NULL and *dbp == NULL + * + * \li 'origin' is a valid absolute domain name. + * + * \li mctx is a valid memory context + * + * Ensures: + * + * \li A copy of 'origin' has been made for the databases use, and the + * caller is free to do whatever they want with the name and storage + * associated with 'origin'. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + * \li #ISC_R_NOTFOUND db_type not found + * + * \li Many other errors are possible, depending on what db_type was + * specified. + */ + +void +dns_db_attach(dns_db_t *source, dns_db_t **targetp); +/*%< + * Attach *targetp to source. + * + * Requires: + * + * \li 'source' is a valid database. + * + * \li 'targetp' points to a NULL dns_db_t *. + * + * Ensures: + * + * \li *targetp is attached to source. + */ + +void +dns_db_detach(dns_db_t **dbp); +/*%< + * Detach *dbp from its database. + * + * Requires: + * + * \li 'dbp' points to a valid database. + * + * Ensures: + * + * \li *dbp is NULL. + * + * \li If '*dbp' is the last reference to the database, + * all resources used by the database will be freed + */ + +bool +dns_db_iscache(dns_db_t *db); +/*%< + * Does 'db' have cache semantics? + * + * Requires: + * + * \li 'db' is a valid database. + * + * Returns: + * \li #true 'db' has cache semantics + * \li #false otherwise + */ + +bool +dns_db_iszone(dns_db_t *db); +/*%< + * Does 'db' have zone semantics? + * + * Requires: + * + * \li 'db' is a valid database. + * + * Returns: + * \li #true 'db' has zone semantics + * \li #false otherwise + */ + +bool +dns_db_isstub(dns_db_t *db); +/*%< + * Does 'db' have stub semantics? + * + * Requires: + * + * \li 'db' is a valid database. + * + * Returns: + * \li #true 'db' has zone semantics + * \li #false otherwise + */ + +bool +dns_db_issecure(dns_db_t *db); +/*%< + * Is 'db' secure? + * + * Requires: + * + * \li 'db' is a valid database with zone semantics. + * + * Returns: + * \li #true 'db' is secure. + * \li #false 'db' is not secure. + */ + +bool +dns_db_isdnssec(dns_db_t *db); +/*%< + * Is 'db' secure or partially secure? + * + * Requires: + * + * \li 'db' is a valid database with zone semantics. + * + * Returns: + * \li #true 'db' is secure or is partially. + * \li #false 'db' is not secure. + */ + +dns_name_t * +dns_db_origin(dns_db_t *db); +/*%< + * The origin of the database. + * + * Note: caller must not try to change this name. + * + * Requires: + * + * \li 'db' is a valid database. + * + * Returns: + * + * \li The origin of the database. + */ + +dns_rdataclass_t +dns_db_class(dns_db_t *db); +/*%< + * The class of the database. + * + * Requires: + * + * \li 'db' is a valid database. + * + * Returns: + * + * \li The class of the database. + */ + +isc_result_t +dns_db_beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks); +/*%< + * Begin loading 'db'. + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li This is the first attempt to load 'db'. + * + * \li 'callbacks' is a pointer to an initialized dns_rdatacallbacks_t + * structure. + * + * Ensures: + * + * \li On success, callbacks->add will be a valid dns_addrdatasetfunc_t + * suitable for loading records into 'db' from a raw or text zone + * file. callbacks->add_private will be a valid DB load context + * which should be used as 'arg' when callbacks->add is called. + * callbacks->deserialize will be a valid dns_deserialize_func_t + * suitable for loading 'db' from a map format zone file. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + * + * \li Other results are possible, depending upon the database + * implementation used, syntax errors in the master file, etc. + */ + +isc_result_t +dns_db_endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks); +/*%< + * Finish loading 'db'. + * + * Requires: + * + * \li 'db' is a valid database that is being loaded. + * + * \li 'callbacks' is a valid dns_rdatacallbacks_t structure. + * + * \li callbacks->add_private is not NULL and is a valid database load context. + * + * Ensures: + * + * \li 'callbacks' is returned to its state prior to calling dns_db_beginload() + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + * + * \li Other results are possible, depending upon the database + * implementation used, syntax errors in the master file, etc. + */ + +isc_result_t +dns_db_load(dns_db_t *db, const char *filename, dns_masterformat_t format, + unsigned int options); +/*%< + * Load master file 'filename' into 'db'. + * + * Notes: + * \li This routine is equivalent to calling + * + *\code + * dns_db_beginload(); + * dns_master_loadfile(); + * dns_db_endload(); + *\endcode + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li This is the first attempt to load 'db'. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + * + * \li Other results are possible, depending upon the database + * implementation used, syntax errors in the master file, etc. + */ + +isc_result_t +dns_db_serialize(dns_db_t *db, dns_dbversion_t *version, FILE *rbtfile); +/*%< + * Dump version 'version' of 'db' to map-format file 'filename'. + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li 'version' is a valid version. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + * + * \li Other results are possible, depending upon the database + * implementation used, OS file errors, etc. + */ + +isc_result_t +dns_db_dump(dns_db_t *db, dns_dbversion_t *version, const char *filename); +/*%< + * Dump version 'version' of 'db' to master file 'filename'. + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li 'version' is a valid version. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + * + * \li Other results are possible, depending upon the database + * implementation used, OS file errors, etc. + */ + +/*** + *** Version Methods + ***/ + +void +dns_db_currentversion(dns_db_t *db, dns_dbversion_t **versionp); +/*%< + * Open the current version for reading. + * + * Requires: + * + * \li 'db' is a valid database with zone semantics. + * + * \li versionp != NULL && *verisonp == NULL + * + * Ensures: + * + * \li On success, '*versionp' is attached to the current version. + * + */ + +isc_result_t +dns_db_newversion(dns_db_t *db, dns_dbversion_t **versionp); +/*%< + * Open a new version for reading and writing. + * + * Requires: + * + * \li 'db' is a valid database with zone semantics. + * + * \li versionp != NULL && *verisonp == NULL + * + * Ensures: + * + * \li On success, '*versionp' is attached to the current version. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + * + * \li Other results are possible, depending upon the database + * implementation used. + */ + +void +dns_db_attachversion(dns_db_t *db, dns_dbversion_t *source, + dns_dbversion_t **targetp); +/*%< + * Attach '*targetp' to 'source'. + * + * Requires: + * + * \li 'db' is a valid database with zone semantics. + * + * \li source is a valid open version + * + * \li targetp != NULL && *targetp == NULL + * + * Ensures: + * + * \li '*targetp' is attached to source. + */ + +void +dns_db_closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit); +/*%< + * Close version '*versionp'. + * + * Note: if '*versionp' is a read-write version and 'commit' is true, + * then all changes made in the version will take effect, otherwise they + * will be rolled back. The value of 'commit' is ignored for read-only + * versions. + * + * Requires: + * + * \li 'db' is a valid database with zone semantics. + * + * \li '*versionp' refers to a valid version. + * + * \li If committing a writable version, then there must be no other + * outstanding references to the version (e.g. an active rdataset + * iterator). + * + * Ensures: + * + * \li *versionp == NULL + * + * \li If *versionp is a read-write version, and commit is true, then + * the version will become the current version. If !commit, then all + * changes made in the version will be undone, and the version will + * not become the current version. + */ + +/*** + *** Node Methods + ***/ + +isc_result_t +dns_db_findnode(dns_db_t *db, const dns_name_t *name, bool create, + dns_dbnode_t **nodep); + +isc_result_t +dns_db_findnodeext(dns_db_t *db, const dns_name_t *name, bool create, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo, dns_dbnode_t **nodep); +/*%< + * Find the node with name 'name'. + * + * dns_db_findnodeext() (findnode extended) also accepts parameters + * 'methods' and 'clientinfo', which, when provided, enable the database to + * retrieve information about the client from the caller, and modify its + * response on the basis of that information. + * + * Notes: + * \li If 'create' is true and no node with name 'name' exists, then + * such a node will be created. + * + * \li This routine is for finding or creating a node with the specified + * name. There are no partial matches. It is not suitable for use + * in building responses to ordinary DNS queries; clients which wish + * to do that should use dns_db_find() instead. + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li 'name' is a valid, non-empty, absolute name. + * + * \li nodep != NULL && *nodep == NULL + * + * Ensures: + * + * \li On success, *nodep is attached to the node with name 'name'. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTFOUND If !create and name not found. + * \li #ISC_R_NOMEMORY Can only happen if create is true. + * + * \li Other results are possible, depending upon the database + * implementation used. + */ + +isc_result_t +dns_db_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, + dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, + dns_dbnode_t **nodep, dns_name_t *foundname, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset); + +isc_result_t +dns_db_findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, + dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, + dns_dbnode_t **nodep, dns_name_t *foundname, + dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset); +/*%< + * Find the best match for 'name' and 'type' in version 'version' of 'db'. + * + * dns_db_findext() (find extended) also accepts parameters 'methods' + * and 'clientinfo', which when provided enable the database to retrieve + * information about the client from the caller, and modify its response + * on the basis of this information. + * + * Notes: + * + * \li If type == dns_rdataset_any, then rdataset will not be bound. + * + * \li If 'options' does not have #DNS_DBFIND_GLUEOK set, then no glue will + * be returned. For zone databases, glue is as defined in RFC2181. + * For cache databases, glue is any rdataset with a trust of + * dns_trust_glue. + * + * \li If 'options' does not have #DNS_DBFIND_ADDITIONALOK set, then no + * additional records will be returned. Only caches can have + * rdataset with trust dns_trust_additional. + * + * \li If 'options' does not have #DNS_DBFIND_PENDINGOK set, then no + * pending data will be returned. This option is only meaningful for + * cache databases. + * + * \li If the #DNS_DBFIND_NOWILD option is set, then wildcard matching will + * be disabled. This option is only meaningful for zone databases. + * + * \li If the #DNS_DBFIND_NOZONECUT option is set, the database is + * assumed to contain no zone cuts above 'name'. An implementation + * may therefore choose to search for a match beginning at 'name' + * rather than walking down the tree to check check for delegations. + * If #DNS_DBFIND_NOWILD is not set, wildcard matching will be + * attempted at each node starting at the direct ancestor of 'name' + * and working up to the zone origin. This option is only meaningful + * when querying redirect zones. + * + * \li If the #DNS_DBFIND_FORCENSEC option is set, the database is assumed to + * have NSEC records, and these will be returned when appropriate. This + * is only necessary when querying a database that was not secure + * when created. + * + * \li If the DNS_DBFIND_COVERINGNSEC option is set, then look for a + * NSEC record that potentially covers 'name' if a answer cannot + * be found. Note the returned NSEC needs to be checked to ensure + * that it is correct. This only affects answers returned from the + * cache. + * + * \li If the #DNS_DBFIND_FORCENSEC3 option is set, then we are looking + * in the NSEC3 tree and not the main tree. Without this option being + * set NSEC3 records will not be found. + * + * \li To respond to a query for SIG records, the caller should create a + * rdataset iterator and extract the signatures from each rdataset. + * + * \li Making queries of type ANY with #DNS_DBFIND_GLUEOK is not recommended, + * because the burden of determining whether a given rdataset is valid + * glue or not falls upon the caller. + * + * \li The 'now' field is ignored if 'db' is a zone database. If 'db' is a + * cache database, an rdataset will not be found unless it expires after + * 'now'. Any ANY query will not match unless at least one rdataset at + * the node expires after 'now'. If 'now' is zero, then the current time + * will be used. + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li 'type' is not SIG, or a meta-RR type other than 'ANY' (e.g. 'OPT'). + * + * \li 'nodep' is NULL, or nodep is a valid pointer and *nodep == NULL. + * + * \li 'foundname' is a valid name with a dedicated buffer. + * + * \li 'rdataset' is NULL, or is a valid unassociated rdataset. + * + * Ensures, + * on a non-error completion: + * + * \li If nodep != NULL, then it is bound to the found node. + * + * \li If foundname != NULL, then it contains the full name of the + * found node. + * + * \li If rdataset != NULL and type != dns_rdatatype_any, then + * rdataset is bound to the found rdataset. + * + * Non-error results are: + * + * \li #ISC_R_SUCCESS The desired node and type were + * found. + * + * \li #DNS_R_GLUE The desired node and type were + * found, but are glue. This + * result can only occur if + * the DNS_DBFIND_GLUEOK option + * is set. This result can only + * occur if 'db' is a zone + * database. If type == + * dns_rdatatype_any, then the + * node returned may contain, or + * consist entirely of invalid + * glue (i.e. data occluded by a + * zone cut). The caller must + * take care not to return invalid + * glue to a client. + * + * \li #DNS_R_DELEGATION The data requested is beneath + * a zone cut. node, foundname, + * and rdataset reference the + * NS RRset of the zone cut. + * If 'db' is a cache database, + * then this is the deepest known + * delegation. + * + * \li #DNS_R_ZONECUT type == dns_rdatatype_any, and + * the desired node is a zonecut. + * The caller must take care not + * to return inappropriate glue + * to a client. This result can + * only occur if 'db' is a zone + * database and DNS_DBFIND_GLUEOK + * is set. + * + * \li #DNS_R_DNAME The data requested is beneath + * a DNAME. node, foundname, + * and rdataset reference the + * DNAME RRset. + * + * \li #DNS_R_CNAME The rdataset requested was not + * found, but there is a CNAME + * at the desired name. node, + * foundname, and rdataset + * reference the CNAME RRset. + * + * \li #DNS_R_NXDOMAIN The desired name does not + * exist. + * + * \li #DNS_R_NXRRSET The desired name exists, but + * the desired type does not. + * + * \li #ISC_R_NOTFOUND The desired name does not + * exist, and no delegation could + * be found. This result can only + * occur if 'db' is a cache + * database. The caller should + * use its nameserver(s) of last + * resort (e.g. root hints). + * + * \li #DNS_R_NCACHENXDOMAIN The desired name does not + * exist. 'node' is bound to the + * cache node with the desired + * name, and 'rdataset' contains + * the negative caching proof. + * + * \li #DNS_R_NCACHENXRRSET The desired type does not + * exist. 'node' is bound to the + * cache node with the desired + * name, and 'rdataset' contains + * the negative caching proof. + * + * \li #DNS_R_EMPTYNAME The name exists but there is + * no data at the name. + * + * \li #DNS_R_COVERINGNSEC The returned data is a NSEC + * that potentially covers 'name'. + * + * \li #DNS_R_EMPTYWILD The name is a wildcard without + * resource records. + * + * Error results: + * + * \li #ISC_R_NOMEMORY + * + * \li #DNS_R_BADDB Data that is required to be + * present in the DB, e.g. an NSEC + * record in a secure zone, is not + * present. + * + * \li Other results are possible, and should all be treated as + * errors. + */ + +isc_result_t +dns_db_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, + isc_stdtime_t now, dns_dbnode_t **nodep, + dns_name_t *foundname, dns_name_t *dcname, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset); +/*%< + * Find the deepest known zonecut which encloses 'name' in 'db'. + * + * Notes: + * + * \li If the #DNS_DBFIND_NOEXACT option is set, then the zonecut returned + * (if any) will be the deepest known ancestor of 'name'. + * + * \li If 'now' is zero, then the current time will be used. + * + * Requires: + * + * \li 'db' is a valid database with cache semantics. + * + * \li 'nodep' is NULL, or nodep is a valid pointer and *nodep == NULL. + * + * \li 'foundname' is a valid name with a dedicated buffer. + * + * \li 'dcname' is a valid name with a dedicated buffer. + * + * \li 'rdataset' is NULL, or is a valid unassociated rdataset. + * + * Ensures, on a non-error completion: + * + * \li If nodep != NULL, then it is bound to the found node. + * + * \li If foundname != NULL, then it contains the full name of the + * found node. + * + * \li If dcname != NULL, then it contains the deepest cached name + * that exists in the database. + * + * \li If rdataset != NULL and type != dns_rdatatype_any, then + * rdataset is bound to the found rdataset. + * + * Non-error results are: + * + * \li #ISC_R_SUCCESS + * + * \li #ISC_R_NOTFOUND + * + * \li Other results are possible, and should all be treated as + * errors. + */ + +void +dns_db_attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp); +/*%< + * Attach *targetp to source. + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li 'source' is a valid node. + * + * \li 'targetp' points to a NULL dns_dbnode_t *. + * + * Ensures: + * + * \li *targetp is attached to source. + */ + +void +dns_db_detachnode(dns_db_t *db, dns_dbnode_t **nodep); +/*%< + * Detach *nodep from its node. + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li 'nodep' points to a valid node. + * + * Ensures: + * + * \li *nodep is NULL. + */ + +void +dns_db_transfernode(dns_db_t *db, dns_dbnode_t **sourcep, + dns_dbnode_t **targetp); +/*%< + * Transfer a node between pointer. + * + * This is equivalent to calling dns_db_attachnode() then dns_db_detachnode(). + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li '*sourcep' is a valid node. + * + * \li 'targetp' points to a NULL dns_dbnode_t *. + * + * Ensures: + * + * \li '*sourcep' is NULL. + */ + +isc_result_t +dns_db_expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now); +/*%< + * Mark as stale all records at 'node' which expire at or before 'now'. + * + * Note: if 'now' is zero, then the current time will be used. + * + * Requires: + * + * \li 'db' is a valid cache database. + * + * \li 'node' is a valid node. + */ + +void +dns_db_printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out); +/*%< + * Print a textual representation of the contents of the node to + * 'out'. + * + * Note: this function is intended for debugging, not general use. + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li 'node' is a valid node. + */ + +/*** + *** DB Iterator Creation + ***/ + +isc_result_t +dns_db_createiterator(dns_db_t *db, unsigned int options, + dns_dbiterator_t **iteratorp); +/*%< + * Create an iterator for version 'version' of 'db'. + * + * Notes: + * + * \li One or more of the following options can be set. + * #DNS_DB_RELATIVENAMES + * #DNS_DB_NSEC3ONLY + * #DNS_DB_NONSEC3 + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li iteratorp != NULL && *iteratorp == NULL + * + * Ensures: + * + * \li On success, *iteratorp will be a valid database iterator. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + */ + +/*** + *** Rdataset Methods + ***/ + +/* + * XXXRTH Should we check for glue and pending data in dns_db_findrdataset()? + */ + +isc_result_t +dns_db_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + dns_rdatatype_t type, dns_rdatatype_t covers, + isc_stdtime_t now, dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset); + +/*%< + * Search for an rdataset of type 'type' at 'node' that are in version + * 'version' of 'db'. If found, make 'rdataset' refer to it. + * + * Notes: + * + * \li If 'version' is NULL, then the current version will be used. + * + * \li Care must be used when using this routine to build a DNS response: + * 'node' should have been found with dns_db_find(), not + * dns_db_findnode(). No glue checking is done. No checking for + * pending data is done. + * + * \li The 'now' field is ignored if 'db' is a zone database. If 'db' is a + * cache database, an rdataset will not be found unless it expires after + * 'now'. If 'now' is zero, then the current time will be used. + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li 'node' is a valid node. + * + * \li 'rdataset' is a valid, disassociated rdataset. + * + * \li 'sigrdataset' is a valid, disassociated rdataset, or it is NULL. + * + * \li If 'covers' != 0, 'type' must be RRSIG. + * + * \li 'type' is not a meta-RR type such as 'ANY' or 'OPT'. + * + * Ensures: + * + * \li On success, 'rdataset' is associated with the found rdataset. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTFOUND + * + * \li Other results are possible, depending upon the database + * implementation used. + */ + +isc_result_t +dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + unsigned int options, isc_stdtime_t now, + dns_rdatasetiter_t **iteratorp); +/*%< + * Make '*iteratorp' an rdataset iterator for all rdatasets at 'node' in + * version 'version' of 'db'. + * + * Notes: + * + * \li If 'version' is NULL, then the current version will be used. + * + * \li 'options' controls which rdatasets are selected when interating over + * the node. + * 'DNS_DB_STALEOK' return stale rdatasets as well as current rdatasets. + * 'DNS_DB_EXPIREDOK' return expired rdatasets as well as current + * rdatasets. + * + * \li The 'now' field is ignored if 'db' is a zone database. If 'db' is a + * cache database, an rdataset will not be found unless it expires after + * 'now'. Any ANY query will not match unless at least one rdataset at + * the node expires after 'now'. If 'now' is zero, then the current time + * will be used. + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li 'node' is a valid node. + * + * \li iteratorp != NULL && *iteratorp == NULL + * + * Ensures: + * + * \li On success, '*iteratorp' is a valid rdataset iterator. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTFOUND + * + * \li Other results are possible, depending upon the database + * implementation used. + */ + +isc_result_t +dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, + isc_stdtime_t now, dns_rdataset_t *rdataset, + unsigned int options, dns_rdataset_t *addedrdataset); +/*%< + * Add 'rdataset' to 'node' in version 'version' of 'db'. + * + * Notes: + * + * \li If the database has zone semantics, the #DNS_DBADD_MERGE option is set, + * and an rdataset of the same type as 'rdataset' already exists at + * 'node' then the contents of 'rdataset' will be merged with the existing + * rdataset. If the option is not set, then rdataset will replace any + * existing rdataset of the same type. If not merging and the + * #DNS_DBADD_FORCE option is set, then the data will update the database + * without regard to trust levels. If not forcing the data, then the + * rdataset will only be added if its trust level is >= the trust level of + * any existing rdataset. Forcing is only meaningful for cache databases. + * If #DNS_DBADD_EXACT is set then there must be no rdata in common between + * the old and new rdata sets. If #DNS_DBADD_EXACTTTL is set then both + * the old and new rdata sets must have the same ttl. + * + * \li The 'now' field is ignored if 'db' is a zone database. If 'db' is + * a cache database, then the added rdataset will expire no later than + * now + rdataset->ttl. + * + * \li If 'addedrdataset' is not NULL, then it will be attached to the + * resulting new rdataset in the database, or to the existing data if + * the existing data was better. + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li 'node' is a valid node. + * + * \li 'rdataset' is a valid, associated rdataset with the same class + * as 'db'. + * + * \li 'addedrdataset' is NULL, or a valid, unassociated rdataset. + * + * \li The database has zone semantics and 'version' is a valid + * read-write version, or the database has cache semantics + * and version is NULL. + * + * \li If the database has cache semantics, the #DNS_DBADD_MERGE option must + * not be set. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #DNS_R_UNCHANGED The operation did not change + * anything. \li #ISC_R_NOMEMORY \li #DNS_R_NOTEXACT + * + * \li Other results are possible, depending upon the database + * implementation used. + */ + +isc_result_t +dns_db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node, + dns_dbversion_t *version, dns_rdataset_t *rdataset, + unsigned int options, dns_rdataset_t *newrdataset); +/*%< + * Remove any rdata in 'rdataset' from 'node' in version 'version' of + * 'db'. + * + * Notes: + * + * \li If 'newrdataset' is not NULL, then it will be attached to the + * resulting new rdataset in the database, unless the rdataset has + * become nonexistent. If DNS_DBSUB_EXACT is set then all elements + * of 'rdataset' must exist at 'node'. + * + *\li If DNS_DBSUB_WANTOLD is set and the entire rdataset was deleted + * then return the original rdatatset in newrdataset if that existed. + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li 'node' is a valid node. + * + * \li 'rdataset' is a valid, associated rdataset with the same class + * as 'db'. + * + * \li 'newrdataset' is NULL, or a valid, unassociated rdataset. + * + * \li The database has zone semantics and 'version' is a valid + * read-write version. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #DNS_R_UNCHANGED The operation did not change + * anything. \li #DNS_R_NXRRSET All rdata of the same + *type as + * those in 'rdataset' have been deleted. \li #DNS_R_NOTEXACT + * Some part of 'rdataset' did not exist and DNS_DBSUB_EXACT was set. + * + * \li Other results are possible, depending upon the database + * implementation used. + */ + +isc_result_t +dns_db_deleterdataset(dns_db_t *db, dns_dbnode_t *node, + dns_dbversion_t *version, dns_rdatatype_t type, + dns_rdatatype_t covers); +/*%< + * Make it so that no rdataset of type 'type' exists at 'node' in version + * version 'version' of 'db'. + * + * Notes: + * + * \li If 'type' is dns_rdatatype_any, then no rdatasets will exist in + * 'version' (provided that the dns_db_deleterdataset() isn't followed + * by one or more dns_db_addrdataset() calls). + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li 'node' is a valid node. + * + * \li The database has zone semantics and 'version' is a valid + * read-write version, or the database has cache semantics + * and version is NULL. + * + * \li 'type' is not a meta-RR type, except for dns_rdatatype_any, which is + * allowed. + * + * \li If 'covers' != 0, 'type' must be SIG. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #DNS_R_UNCHANGED No rdatasets of 'type' existed + * before the operation was attempted. + * + * \li Other results are possible, depending upon the database + * implementation used. + */ + +isc_result_t +dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, uint32_t *serialp); +/*%< + * Get the current SOA serial number from a zone database. + * + * Requires: + * \li 'db' is a valid database with zone semantics. + * \li 'ver' is a valid version. + */ + +void +dns_db_overmem(dns_db_t *db, bool overmem); +/*%< + * Enable / disable aggressive cache cleaning. + */ + +unsigned int +dns_db_nodecount(dns_db_t *db); +/*%< + * Count the number of nodes in 'db'. + * + * Requires: + * + * \li 'db' is a valid database. + * + * Returns: + * \li The number of nodes in the database + */ + +size_t +dns_db_hashsize(dns_db_t *db); +/*%< + * For database implementations using a hash table, report the + * current number of buckets. + * + * Requires: + * + * \li 'db' is a valid database. + * + * Returns: + * \li The number of buckets in the database's hash table, or + * 0 if not implemented. + */ + +isc_result_t +dns_db_adjusthashsize(dns_db_t *db, size_t size); +/*%< + * For database implementations using a hash table, adjust the size of + * the hash table to store objects with a maximum total memory footprint + * of 'size' bytes. If 'size' is set to 0, it means no finite limit is + * requested. + * + * Requires: + * + * \li 'db' is a valid database. + * \li 'size' is maximum memory footprint of the database in bytes + * + * Returns: + * \li #ISC_R_SUCCESS The registration succeeded + * \li #ISC_R_NOMEMORY Out of memory + */ + +void +dns_db_settask(dns_db_t *db, isc_task_t *task); +/*%< + * If task is set then the final detach maybe performed asynchronously. + * + * Requires: + * \li 'db' is a valid database. + * \li 'task' to be valid or NULL. + */ + +bool +dns_db_ispersistent(dns_db_t *db); +/*%< + * Is 'db' persistent? A persistent database does not need to be loaded + * from disk or written to disk. + * + * Requires: + * + * \li 'db' is a valid database. + * + * Returns: + * \li #true 'db' is persistent. + * \li #false 'db' is not persistent. + */ + +isc_result_t +dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg, + isc_mem_t *mctx, dns_dbimplementation_t **dbimp); + +/*%< + * Register a new database implementation and add it to the list of + * supported implementations. + * + * Requires: + * + * \li 'name' is not NULL + * \li 'order' is a valid function pointer + * \li 'mctx' is a valid memory context + * \li dbimp != NULL && *dbimp == NULL + * + * Returns: + * \li #ISC_R_SUCCESS The registration succeeded + * \li #ISC_R_NOMEMORY Out of memory + * \li #ISC_R_EXISTS A database implementation with the same name exists + * + * Ensures: + * + * \li *dbimp points to an opaque structure which must be passed to + * dns_db_unregister(). + */ + +void +dns_db_unregister(dns_dbimplementation_t **dbimp); +/*%< + * Remove a database implementation from the list of supported + * implementations. No databases of this type can be active when this + * is called. + * + * Requires: + * \li dbimp != NULL && *dbimp == NULL + * + * Ensures: + * + * \li Any memory allocated in *dbimp will be freed. + */ + +isc_result_t +dns_db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep); +/*%< + * Get the origin DB node corresponding to the DB's zone. This function + * should typically succeed unless the underlying DB implementation doesn't + * support the feature. + * + * Requires: + * + * \li 'db' is a valid zone database. + * \li 'nodep' != NULL && '*nodep' == NULL + * + * Ensures: + * \li On success, '*nodep' will point to the DB node of the zone's origin. + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTFOUND - the DB implementation does not support this feature. + */ + +isc_result_t +dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, + dns_hash_t *hash, uint8_t *flags, + uint16_t *iterations, unsigned char *salt, + size_t *salt_length); +/*%< + * Get the NSEC3 parameters that are associated with this zone. + * + * Requires: + * \li 'db' is a valid zone database. + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTFOUND - the DB implementation does not support this feature + * or this zone does not have NSEC3 records. + */ + +isc_result_t +dns_db_getsize(dns_db_t *db, dns_dbversion_t *version, uint64_t *records, + uint64_t *xfrsize); +/*%< + * On success if 'records' is not NULL, it is set to the number of records + * in the given version of the database. If 'xfrisize' is not NULL, it is + * set to the approximate number of bytes needed to transfer the records, + * counting name, TTL, type, class, and rdata for each RR. (This is meant + * to be a rough approximation of the size of a full zone transfer, though + * it does not take into account DNS message overhead or name compression.) + * + * Requires: + * \li 'db' is a valid zone database. + * \li 'version' is NULL or a valid version. + * \li 'records' is NULL or a pointer to return the record count in. + * \li 'xfrsize' is NULL or a pointer to return the byte count in. + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTIMPLEMENTED + */ + +isc_result_t +dns_db_findnsec3node(dns_db_t *db, const dns_name_t *name, bool create, + dns_dbnode_t **nodep); +/*%< + * Find the NSEC3 node with name 'name'. + * + * Notes: + * \li If 'create' is true and no node with name 'name' exists, then + * such a node will be created. + * + * Requires: + * + * \li 'db' is a valid database. + * + * \li 'name' is a valid, non-empty, absolute name. + * + * \li nodep != NULL && *nodep == NULL + * + * Ensures: + * + * \li On success, *nodep is attached to the node with name 'name'. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTFOUND If !create and name not found. + * \li #ISC_R_NOMEMORY Can only happen if create is true. + * + * \li Other results are possible, depending upon the database + * implementation used. + */ + +isc_result_t +dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, + isc_stdtime_t resign); +/*%< + * Sets the re-signing time associated with 'rdataset' to 'resign'. + * + * Requires: + * \li 'db' is a valid zone database. + * \li 'rdataset' is or is to be associated with 'db'. + * \li 'rdataset' is not pending removed from the heap via an + * uncommitted call to dns_db_resigned(). + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + * \li #ISC_R_NOTIMPLEMENTED - Not supported by this DB implementation. + */ + +isc_result_t +dns_db_getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *name); +/*%< + * Return the rdataset with the earliest signing time in the zone. + * Note: the rdataset is version agnostic. + * + * Requires: + * \li 'db' is a valid zone database. + * \li 'rdataset' to be initialized but not associated. + * \li 'name' to be NULL or have a buffer associated with it. + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTFOUND - No dataset exists. + */ + +void +dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset, + dns_dbversion_t *version); +/*%< + * Mark 'rdataset' as not being available to be returned by + * dns_db_getsigningtime(). If the changes associated with 'version' + * are committed this will be permanent. If the version is not committed + * this change will be rolled back when the version is closed. Until + * 'version' is either committed or rolled back, 'rdataset' can no longer + * be acted upon by dns_db_setsigningtime(). + * + * Requires: + * \li 'db' is a valid zone database. + * \li 'rdataset' to be associated with 'db'. + * \li 'version' to be open for writing. + */ + +dns_stats_t * +dns_db_getrrsetstats(dns_db_t *db); +/*%< + * Get statistics information counting RRsets stored in the DB, when available. + * The statistics may not be available depending on the DB implementation. + * + * Requires: + * + * \li 'db' is a valid database (cache only). + * + * Returns: + * \li when available, a pointer to a statistics object created by + * dns_rdatasetstats_create(); otherwise NULL. + */ + +isc_result_t +dns_db_setcachestats(dns_db_t *db, isc_stats_t *stats); +/*%< + * Set the location in which to collect cache statistics. + * This option may not exist depending on the DB implementation. + * + * Requires: + * + * \li 'db' is a valid database (cache only). + * + * Returns: + * \li when available, a pointer to a statistics object created by + * dns_rdatasetstats_create(); otherwise NULL. + */ + +void +dns_db_rpz_attach(dns_db_t *db, void *rpzs, uint8_t rpz_num) ISC_DEPRECATED; +/*%< + * Attach the response policy information for a view to a database for a + * zone for the view. + */ + +isc_result_t +dns_db_rpz_ready(dns_db_t *db) ISC_DEPRECATED; +/*%< + * Finish loading a response policy zone. + */ + +isc_result_t +dns_db_updatenotify_register(dns_db_t *db, dns_dbupdate_callback_t fn, + void *fn_arg); +/*%< + * Register a notify-on-update callback function to a database. + * Duplicate callbacks are suppressed. + * + * Requires: + * + * \li 'db' is a valid database + * \li 'fn' is not NULL + * + */ + +isc_result_t +dns_db_updatenotify_unregister(dns_db_t *db, dns_dbupdate_callback_t fn, + void *fn_arg); +/*%< + * Unregister a notify-on-update callback. + * + * Requires: + * + * \li 'db' is a valid database + * \li 'db' has update callback registered + * + */ + +isc_result_t +dns_db_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name); +/*%< + * Get the name associated with a database node. + * + * Requires: + * + * \li 'db' is a valid database + * \li 'node' and 'name' are not NULL + */ + +isc_result_t +dns_db_setservestalettl(dns_db_t *db, dns_ttl_t ttl); +/*%< + * Sets the maximum length of time that cached answers may be retained + * past their normal TTL. Default value for the library is 0, disabling + * the use of stale data. + * + * Requires: + * \li 'db' is a valid cache database. + * \li 'ttl' is the number of seconds to retain data past its normal expiry. + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTIMPLEMENTED - Not supported by this DB implementation. + */ + +isc_result_t +dns_db_getservestalettl(dns_db_t *db, dns_ttl_t *ttl); +/*%< + * Gets maximum length of time that cached answers may be kept past + * normal TTL expiration. + * + * Requires: + * \li 'db' is a valid cache database. + * \li 'ttl' is the number of seconds to retain data past its normal expiry. + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTIMPLEMENTED - Not supported by this DB implementation. + */ + +isc_result_t +dns_db_setservestalerefresh(dns_db_t *db, uint32_t interval); +/*%< + * Sets the length of time to wait before attempting to refresh a rrset + * if a previous attempt in doing so has failed. + * During this time window if stale rrset are available in cache they + * will be directly returned to client. + * + * Requires: + * \li 'db' is a valid cache database. + * \li 'interval' is number of seconds before attempting to refresh data. + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTIMPLEMENTED - Not supported by this DB implementation. + */ + +isc_result_t +dns_db_getservestalerefresh(dns_db_t *db, uint32_t *interval); +/*%< + * Gets the length of time in which stale answers are directly returned from + * cache before attempting to refresh them, in case a previous attempt in + * doing so has failed. + * + * Requires: + * \li 'db' is a valid cache database. + * \li 'interval' is number of seconds before attempting to refresh data. + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTIMPLEMENTED - Not supported by this DB implementation. + */ + +isc_result_t +dns_db_setgluecachestats(dns_db_t *db, isc_stats_t *stats); +/*%< + * Set the location in which to collect glue cache statistics. + * This option may not exist depending on the DB implementation. + * + * Requires: + * + * \li 'db' is a valid database (cache only). + * + * Returns: + * \li when available, a pointer to a statistics object created by + * dns_rdatasetstats_create(); otherwise NULL. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_DB_H */ diff --git a/lib/dns/include/dns/dbiterator.h b/lib/dns/include/dns/dbiterator.h new file mode 100644 index 0000000..32f204a --- /dev/null +++ b/lib/dns/include/dns/dbiterator.h @@ -0,0 +1,293 @@ +/* + * 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. + */ + +#ifndef DNS_DBITERATOR_H +#define DNS_DBITERATOR_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/dbiterator.h + * \brief + * The DNS DB Iterator interface allows iteration of all of the nodes in a + * database. + * + * The dns_dbiterator_t type is like a "virtual class". To actually use + * it, an implementation of the class is required. This implementation is + * supplied by the database. + * + * It is the client's responsibility to call dns_db_detachnode() on all + * nodes returned. + * + * XXX <more> XXX + * + * MP: + *\li The iterator itself is not locked. The caller must ensure + * synchronization. + * + *\li The iterator methods ensure appropriate database locking. + * + * Reliability: + *\li No anticipated impact. + * + * Resources: + *\li TBS + * + * Security: + *\li No anticipated impact. + * + * Standards: + *\li None. + */ + +/***** +***** Imports +*****/ + +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/magic.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/***** +***** Types +*****/ + +typedef struct dns_dbiteratormethods { + void (*destroy)(dns_dbiterator_t **iteratorp); + isc_result_t (*first)(dns_dbiterator_t *iterator); + isc_result_t (*last)(dns_dbiterator_t *iterator); + isc_result_t (*seek)(dns_dbiterator_t *iterator, + const dns_name_t *name); + isc_result_t (*prev)(dns_dbiterator_t *iterator); + isc_result_t (*next)(dns_dbiterator_t *iterator); + isc_result_t (*current)(dns_dbiterator_t *iterator, + dns_dbnode_t **nodep, dns_name_t *name); + isc_result_t (*pause)(dns_dbiterator_t *iterator); + isc_result_t (*origin)(dns_dbiterator_t *iterator, dns_name_t *name); +} dns_dbiteratormethods_t; + +#define DNS_DBITERATOR_MAGIC ISC_MAGIC('D', 'N', 'S', 'I') +#define DNS_DBITERATOR_VALID(dbi) ISC_MAGIC_VALID(dbi, DNS_DBITERATOR_MAGIC) +/*% + * This structure is actually just the common prefix of a DNS db + * implementation's version of a dns_dbiterator_t. + * + * Clients may use the 'db' field of this structure. Except for that field, + * direct use of this structure by clients is forbidden. DB implementations + * may change the structure. 'magic' must be DNS_DBITERATOR_MAGIC for any of + * the dns_dbiterator routines to work. DB iterator implementations must + * maintain all DB iterator invariants. + */ +struct dns_dbiterator { + /* Unlocked. */ + unsigned int magic; + dns_dbiteratormethods_t *methods; + dns_db_t *db; + bool relative_names; + bool cleaning; +}; + +void +dns_dbiterator_destroy(dns_dbiterator_t **iteratorp); +/*%< + * Destroy '*iteratorp'. + * + * Requires: + * + *\li '*iteratorp' is a valid iterator. + * + * Ensures: + * + *\li All resources used by the iterator are freed. + * + *\li *iteratorp == NULL. + */ + +isc_result_t +dns_dbiterator_first(dns_dbiterator_t *iterator); +/*%< + * Move the node cursor to the first node in the database (if any). + * + * Requires: + *\li 'iterator' is a valid iterator. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMORE There are no nodes in the database. + * + *\li Other results are possible, depending on the DB implementation. + */ + +isc_result_t +dns_dbiterator_last(dns_dbiterator_t *iterator); +/*%< + * Move the node cursor to the last node in the database (if any). + * + * Requires: + *\li 'iterator' is a valid iterator. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMORE There are no nodes in the database. + * + *\li Other results are possible, depending on the DB implementation. + */ + +isc_result_t +dns_dbiterator_seek(dns_dbiterator_t *iterator, const dns_name_t *name); +/*%< + * Move the node cursor to the node with name 'name'. + * + * Requires: + *\li 'iterator' is a valid iterator. + * + *\li 'name' is a valid name. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOTFOUND + *\li #DNS_R_PARTIALMATCH + * (node is at name above requested named when name has children) + * + *\li Other results are possible, depending on the DB implementation. + */ + +isc_result_t +dns_dbiterator_prev(dns_dbiterator_t *iterator); +/*%< + * Move the node cursor to the previous node in the database (if any). + * + * Requires: + *\li 'iterator' is a valid iterator. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMORE There are no more nodes in the + * database. + * + *\li Other results are possible, depending on the DB implementation. + */ + +isc_result_t +dns_dbiterator_next(dns_dbiterator_t *iterator); +/*%< + * Move the node cursor to the next node in the database (if any). + * + * Requires: + *\li 'iterator' is a valid iterator. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMORE There are no more nodes in the + * database. + * + *\li Other results are possible, depending on the DB implementation. + */ + +isc_result_t +dns_dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep, + dns_name_t *name); +/*%< + * Return the current node. + * + * Notes: + *\li If 'name' is not NULL, it will be set to the name of the node. + * + * Requires: + *\li 'iterator' is a valid iterator. + * + *\li nodep != NULL && *nodep == NULL + * + *\li The node cursor of 'iterator' is at a valid location (i.e. the + * result of last call to a cursor movement command was ISC_R_SUCCESS). + * + *\li 'name' is NULL, or is a valid name with a dedicated buffer. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #DNS_R_NEWORIGIN If this iterator was created + * with 'relative_names' set to true, then #DNS_R_NEWORIGIN will be returned + *when + * the origin the names are relative to changes. This result can occur only + *when + *'name' is not NULL. This is also a successful result. + * + *\li Other results are possible, depending on the DB implementation. + */ + +isc_result_t +dns_dbiterator_pause(dns_dbiterator_t *iterator); +/*%< + * Pause iteration. + * + * Calling a cursor movement method or dns_dbiterator_current() may cause + * database locks to be acquired. Rather than reacquire these locks every + * time one of these routines is called, the locks may simply be held. + * Calling dns_dbiterator_pause() releases any such locks. Iterator clients + * should call this routine any time they are not going to execute another + * iterator method in the immediate future. + * + * Requires: + *\li 'iterator' is a valid iterator. + * + * Ensures: + *\li Any database locks being held for efficiency of iterator access are + * released. + * + * Returns: + *\li #ISC_R_SUCCESS + * + *\li Other results are possible, depending on the DB implementation. + */ + +isc_result_t +dns_dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name); +/*%< + * Return the origin to which returned node names are relative. + * + * Requires: + * + *\li 'iterator' is a valid relative_names iterator. + * + *\li 'name' is a valid name with a dedicated buffer. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOSPACE + * + *\li Other results are possible, depending on the DB implementation. + */ + +void +dns_dbiterator_setcleanmode(dns_dbiterator_t *iterator, bool mode); +/*%< + * Indicate that the given iterator is/is not cleaning the DB. + * + * Notes: + *\li When 'mode' is true, + * + * Requires: + *\li 'iterator' is a valid iterator. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_DBITERATOR_H */ diff --git a/lib/dns/include/dns/dbtable.h b/lib/dns/include/dns/dbtable.h new file mode 100644 index 0000000..dc1a991 --- /dev/null +++ b/lib/dns/include/dns/dbtable.h @@ -0,0 +1,159 @@ +/* + * 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. + */ + +#ifndef DNS_DBTABLE_H +#define DNS_DBTABLE_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/dbtable.h + * \brief + * DNS DB Tables + * + * XXX TBS XXX + * + * MP: + *\li The module ensures appropriate synchronization of data structures it + * creates and manipulates. + * + * Reliability: + *\li No anticipated impact. + * + * Resources: + *\li None. + * + * Security: + *\li No anticipated impact. + * + * Standards: + *\li None. + */ + +#include <isc/lang.h> + +#include <dns/types.h> + +#define DNS_DBTABLEFIND_NOEXACT 0x01 + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_dbtable_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, + dns_dbtable_t **dbtablep); +/*%< + * Make a new dbtable of class 'rdclass' + * + * Requires: + *\li mctx != NULL + * \li dbtablep != NULL && *dptablep == NULL + *\li 'rdclass' is a valid class + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_UNEXPECTED + */ + +void +dns_dbtable_attach(dns_dbtable_t *source, dns_dbtable_t **targetp); +/*%< + * Attach '*targetp' to 'source'. + * + * Requires: + * + *\li 'source' is a valid dbtable. + * + *\li 'targetp' points to a NULL dns_dbtable_t *. + * + * Ensures: + * + *\li *targetp is attached to source. + */ + +void +dns_dbtable_detach(dns_dbtable_t **dbtablep); +/*%< + * Detach *dbtablep from its dbtable. + * + * Requires: + * + *\li '*dbtablep' points to a valid dbtable. + * + * Ensures: + * + *\li *dbtablep is NULL. + * + *\li If '*dbtablep' is the last reference to the dbtable, + * all resources used by the dbtable will be freed + */ + +isc_result_t +dns_dbtable_add(dns_dbtable_t *dbtable, dns_db_t *db); +/*%< + * Add 'db' to 'dbtable'. + * + * Requires: + *\li 'dbtable' is a valid dbtable. + * + *\li 'db' is a valid database with the same class as 'dbtable' + */ + +void +dns_dbtable_remove(dns_dbtable_t *dbtable, dns_db_t *db); +/*%< + * Remove 'db' from 'dbtable'. + * + * Requires: + *\li 'db' was previously added to 'dbtable'. + */ + +void +dns_dbtable_adddefault(dns_dbtable_t *dbtable, dns_db_t *db); +/*%< + * Use 'db' as the result of a dns_dbtable_find() if no better match is + * available. + */ + +void +dns_dbtable_getdefault(dns_dbtable_t *dbtable, dns_db_t **db); +/*%< + * Get the 'db' used as the result of a dns_dbtable_find() + * if no better match is available. + */ + +void +dns_dbtable_removedefault(dns_dbtable_t *dbtable); +/*%< + * Remove the default db from 'dbtable'. + */ + +isc_result_t +dns_dbtable_find(dns_dbtable_t *dbtable, const dns_name_t *name, + unsigned int options, dns_db_t **dbp); +/*%< + * Find the deepest match to 'name' in the dbtable, and return it + * + * Notes: + *\li If the DNS_DBTABLEFIND_NOEXACT option is set, the best partial + * match (if any) to 'name' will be returned. + * + * Returns: + * \li #ISC_R_SUCCESS on success + *\li something else: no default and match + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_DBTABLE_H */ diff --git a/lib/dns/include/dns/diff.h b/lib/dns/include/dns/diff.h new file mode 100644 index 0000000..48e1b2e --- /dev/null +++ b/lib/dns/include/dns/diff.h @@ -0,0 +1,282 @@ +/* + * 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. + */ + +#ifndef DNS_DIFF_H +#define DNS_DIFF_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/diff.h + * \brief + * A diff is a convenience type representing a list of changes to be + * made to a database. + */ + +/*** + *** Imports + ***/ + +#include <isc/lang.h> +#include <isc/magic.h> + +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/types.h> + +/*** + *** Types + ***/ + +/*% + * A dns_difftuple_t represents a single RR being added or deleted. + * The RR type and class are in the 'rdata' member; the class is always + * the real one, not a DynDNS meta-class, so that the rdatas can be + * compared using dns_rdata_compare(). The TTL is significant + * even for deletions, because a deletion/addition pair cannot + * be canceled out if the TTL differs (it might be an explicit + * TTL update). + * + * Tuples are also used to represent complete RRs with owner + * names for a couple of other purposes, such as the + * individual RRs of a "RRset exists (value dependent)" + * prerequisite set. In this case, op==DNS_DIFFOP_EXISTS, + * and the TTL is ignored. + * + * DNS_DIFFOP_*RESIGN will cause the 'resign' attribute of the resulting + * RRset to be recomputed to be 'resign' seconds before the earliest RRSIG + * timeexpire. + */ + +typedef enum { + DNS_DIFFOP_ADD = 0, /*%< Add an RR. */ + DNS_DIFFOP_DEL = 1, /*%< Delete an RR. */ + DNS_DIFFOP_EXISTS = 2, /*%< Assert RR existence. */ + DNS_DIFFOP_ADDRESIGN = 4, /*%< ADD + RESIGN. */ + DNS_DIFFOP_DELRESIGN = 5 /*%< DEL + RESIGN. */ +} dns_diffop_t; + +typedef struct dns_difftuple dns_difftuple_t; +typedef ISC_LIST(dns_difftuple_t) dns_difftuplelist_t; + +#define DNS_DIFFTUPLE_MAGIC ISC_MAGIC('D', 'I', 'F', 'T') +#define DNS_DIFFTUPLE_VALID(t) ISC_MAGIC_VALID(t, DNS_DIFFTUPLE_MAGIC) + +struct dns_difftuple { + unsigned int magic; + isc_mem_t *mctx; + dns_diffop_t op; + dns_name_t name; + dns_ttl_t ttl; + dns_rdata_t rdata; + ISC_LINK(dns_difftuple_t) link; + /* Variable-size name data and rdata follows. */ +}; + +/*% + * A dns_diff_t represents a set of changes being applied to + * a zone. Diffs are also used to represent "RRset exists + * (value dependent)" prerequisites. + */ +typedef struct dns_diff dns_diff_t; + +#define DNS_DIFF_MAGIC ISC_MAGIC('D', 'I', 'F', 'F') +#define DNS_DIFF_VALID(t) ISC_MAGIC_VALID(t, DNS_DIFF_MAGIC) + +struct dns_diff { + unsigned int magic; + isc_mem_t *mctx; + dns_difftuplelist_t tuples; +}; + +/* Type of comparison function for sorting diffs. */ +typedef int +dns_diff_compare_func(const void *, const void *); + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +/**************************************************************************/ +/* + * Manipulation of diffs and tuples. + */ + +isc_result_t +dns_difftuple_create(isc_mem_t *mctx, dns_diffop_t op, const dns_name_t *name, + dns_ttl_t ttl, dns_rdata_t *rdata, dns_difftuple_t **tp); +/*%< + * Create a tuple. Deep copies are made of the name and rdata, so + * they need not remain valid after the call. + * + * Requires: + *\li *tp != NULL && *tp == NULL. + * + * Returns: + *\li ISC_R_SUCCESS + * \li ISC_R_NOMEMORY + */ + +void +dns_difftuple_free(dns_difftuple_t **tp); +/*%< + * Free a tuple. + * + * Requires: + * \li **tp is a valid tuple. + * + * Ensures: + * \li *tp == NULL + * \li All memory used by the tuple is freed. + */ + +isc_result_t +dns_difftuple_copy(dns_difftuple_t *orig, dns_difftuple_t **copyp); +/*%< + * Copy a tuple. + * + * Requires: + * \li 'orig' points to a valid tuple + *\li copyp != NULL && *copyp == NULL + */ + +void +dns_diff_init(isc_mem_t *mctx, dns_diff_t *diff); +/*%< + * Initialize a diff. + * + * Requires: + * \li 'diff' points to an uninitialized dns_diff_t + * \li allocated by the caller. + * + * Ensures: + * \li '*diff' is a valid, empty diff. + */ + +void +dns_diff_clear(dns_diff_t *diff); +/*%< + * Clear a diff, destroying all its tuples. + * + * Requires: + * \li 'diff' points to a valid dns_diff_t. + * + * Ensures: + * \li Any tuples in the diff are destroyed. + * The diff now empty, but it is still valid + * and may be reused without calling dns_diff_init + * again. The only memory used is that of the + * dns_diff_t structure itself. + * + * Notes: + * \li Managing the memory of the dns_diff_t structure itself + * is the caller's responsibility. + */ + +void +dns_diff_append(dns_diff_t *diff, dns_difftuple_t **tuple); +/*%< + * Append a single tuple to a diff. + * + *\li 'diff' is a valid diff. + * \li '*tuple' is a valid tuple. + * + * Ensures: + *\li *tuple is NULL. + *\li The tuple has been freed, or will be freed when the diff is cleared. + */ + +void +dns_diff_appendminimal(dns_diff_t *diff, dns_difftuple_t **tuple); +/*%< + * Append 'tuple' to 'diff', removing any duplicate + * or conflicting updates as needed to create a minimal diff. + * + * Requires: + *\li 'diff' is a minimal diff. + * + * Ensures: + *\li 'diff' is still a minimal diff. + * \li *tuple is NULL. + * \li The tuple has been freed, or will be freed when the diff is + * cleared. + * + */ + +isc_result_t +dns_diff_sort(dns_diff_t *diff, dns_diff_compare_func *compare); +/*%< + * Sort 'diff' in-place according to the comparison function 'compare'. + */ + +isc_result_t +dns_diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver); +isc_result_t +dns_diff_applysilently(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver); +/*%< + * Apply 'diff' to the database 'db'. + * + * dns_diff_apply() logs warnings about updates with no effect or + * with inconsistent TTLs; dns_diff_applysilently() does not. + * + * For efficiency, the diff should be sorted by owner name. + * If it is not sorted, operation will still be correct, + * but less efficient. + * + * Requires: + *\li *diff is a valid diff (possibly empty), containing + * tuples of type #DNS_DIFFOP_ADD and/or + * For #DNS_DIFFOP_DEL tuples, the TTL is ignored. + * + */ + +isc_result_t +dns_diff_load(dns_diff_t *diff, dns_addrdatasetfunc_t addfunc, + void *add_private); +/*%< + * Like dns_diff_apply, but for use when loading a new database + * instead of modifying an existing one. This bypasses the + * database transaction mechanisms. + * + * Requires: + *\li 'addfunc' is a valid dns_addradatasetfunc_t obtained from + * dns_db_beginload() + * + *\li 'add_private' points to a corresponding dns_dbload_t * + * (XXX why is it a void pointer, then?) + */ + +isc_result_t +dns_diff_print(dns_diff_t *diff, FILE *file); + +/*%< + * Print the differences to 'file' or if 'file' is NULL via the + * logging system. + * + * Require: + *\li 'diff' to be valid. + *\li 'file' to refer to a open file or NULL. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_UNEXPECTED + *\li any error from dns_rdataset_totext() + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_DIFF_H */ diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h new file mode 100644 index 0000000..6061843 --- /dev/null +++ b/lib/dns/include/dns/dispatch.h @@ -0,0 +1,586 @@ +/* + * 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. + */ + +#ifndef DNS_DISPATCH_H +#define DNS_DISPATCH_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/dispatch.h + * \brief + * DNS Dispatch Management + * Shared UDP and single-use TCP dispatches for queries and responses. + * + * MP: + * + *\li All locking is performed internally to each dispatch. + * Restrictions apply to dns_dispatch_removeresponse(). + * + * Reliability: + * + * Resources: + * + * Security: + * + *\li Depends on the isc_socket_t and dns_message_t for prevention of + * buffer overruns. + * + * Standards: + * + *\li None. + */ + +/*** + *** Imports + ***/ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/buffer.h> +#include <isc/lang.h> +#include <isc/mutex.h> +#include <isc/socket.h> +#include <isc/types.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/*% + * This event is sent to a task when a response comes in. + * No part of this structure should ever be modified by the caller, + * other than parts of the buffer. The holy parts of the buffer are + * the base and size of the buffer. All other parts of the buffer may + * be used. On event delivery the used region contains the packet. + * + * "id" is the received message id, + * + * "addr" is the host that sent it to us, + * + * "buffer" holds state on the received data. + * + * The "free" routine for this event will clean up itself as well as + * any buffer space allocated from common pools. + */ + +struct dns_dispatchevent { + ISC_EVENT_COMMON(dns_dispatchevent_t); /*%< standard event common */ + isc_result_t result; /*%< result code */ + int32_t id; /*%< message id */ + isc_sockaddr_t addr; /*%< address recv'd from */ + struct in6_pktinfo pktinfo; /*%< reply info for v6 */ + isc_buffer_t buffer; /*%< data buffer */ + uint32_t attributes; /*%< mirrored from socket.h */ +}; + +/*% + * This is a set of one or more dispatches which can be retrieved + * round-robin fashion. + */ +struct dns_dispatchset { + isc_mem_t *mctx; + dns_dispatch_t **dispatches; + int ndisp; + int cur; + isc_mutex_t lock; +}; + +/*@{*/ +/*% + * Attributes for added dispatchers. + * + * Values with the mask 0xffff0000 are application defined. + * Values with the mask 0x0000ffff are library defined. + * + * Insane values (like setting both TCP and UDP) are not caught. Don't + * do that. + * + * _PRIVATE + * The dispatcher cannot be shared. + * + * _TCP, _UDP + * The dispatcher is a TCP or UDP socket. + * + * _IPV4, _IPV6 + * The dispatcher uses an IPv4 or IPv6 socket. + * + * _NOLISTEN + * The dispatcher should not listen on the socket. + * + * _MAKEQUERY + * The dispatcher can be used to issue queries to other servers, and + * accept replies from them. + * + * _RANDOMPORT + * Previously used to indicate that the port of a dispatch UDP must be + * chosen randomly. This behavior now always applies and the attribute + * is obsoleted. + * + * _EXCLUSIVE + * A separate socket will be used on-demand for each transaction. + */ +#define DNS_DISPATCHATTR_PRIVATE 0x00000001U +#define DNS_DISPATCHATTR_TCP 0x00000002U +#define DNS_DISPATCHATTR_UDP 0x00000004U +#define DNS_DISPATCHATTR_IPV4 0x00000008U +#define DNS_DISPATCHATTR_IPV6 0x00000010U +#define DNS_DISPATCHATTR_NOLISTEN 0x00000020U +#define DNS_DISPATCHATTR_MAKEQUERY 0x00000040U +#define DNS_DISPATCHATTR_CONNECTED 0x00000080U +#define DNS_DISPATCHATTR_FIXEDID 0x00000100U +#define DNS_DISPATCHATTR_EXCLUSIVE 0x00000200U +#define DNS_DISPATCHATTR_CANREUSE 0x00000400U +/*@}*/ + +/* + */ +#define DNS_DISPATCHOPT_FIXEDID 0x00000001U + +isc_result_t +dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp); +/*%< + * Creates a new dispatchmgr object. + * + * Requires: + *\li "mctx" be a valid memory context. + * + *\li mgrp != NULL && *mgrp == NULL + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure + */ + +void +dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp); +/*%< + * Destroys the dispatchmgr when it becomes empty. This could be + * immediately. + * + * Requires: + *\li mgrp != NULL && *mgrp is a valid dispatchmgr. + */ + +void +dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole); +/*%< + * Sets the dispatcher's "blackhole list," a list of addresses that will + * be ignored by all dispatchers created by the dispatchmgr. + * + * Requires: + * \li mgrp is a valid dispatchmgr + * \li blackhole is a valid acl + */ + +dns_acl_t * +dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr); +/*%< + * Gets a pointer to the dispatcher's current blackhole list, + * without incrementing its reference count. + * + * Requires: + *\li mgr is a valid dispatchmgr + * Returns: + *\li A pointer to the current blackhole list, or NULL. + */ + +void +dns_dispatchmgr_setblackportlist(dns_dispatchmgr_t *mgr, + dns_portlist_t *portlist); +/*%< + * This function is deprecated. Use dns_dispatchmgr_setavailports() instead. + * + * Requires: + *\li mgr is a valid dispatchmgr + */ + +dns_portlist_t * +dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr); +/*%< + * This function is deprecated and always returns NULL. + * + * Requires: + *\li mgr is a valid dispatchmgr + */ + +isc_result_t +dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, + isc_portset_t *v6portset); +/*%< + * Sets a list of UDP ports that can be used for outgoing UDP messages. + * + * Requires: + *\li mgr is a valid dispatchmgr + *\li v4portset is NULL or a valid port set + *\li v6portset is NULL or a valid port set + */ + +void +dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats); +/*%< + * Sets statistics counter for the dispatchmgr. This function is expected to + * be called only on zone creation (when necessary). + * Once installed, it cannot be removed or replaced. Also, there is no + * interface to get the installed stats from the zone; the caller must keep the + * stats to reference (e.g. dump) it later. + * + * Requires: + *\li mgr is a valid dispatchmgr with no managed dispatch. + *\li stats is a valid statistics supporting resolver statistics counters + * (see dns/stats.h). + */ + +isc_result_t +dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, + isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, + unsigned int buffersize, unsigned int maxbuffers, + unsigned int maxrequests, unsigned int buckets, + unsigned int increment, unsigned int attributes, + unsigned int mask, dns_dispatch_t **dispp); + +isc_result_t +dns_dispatch_getudp_dup(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, + isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, + unsigned int buffersize, unsigned int maxbuffers, + unsigned int maxrequests, unsigned int buckets, + unsigned int increment, unsigned int attributes, + unsigned int mask, dns_dispatch_t **dispp, + dns_dispatch_t *dup); +/*%< + * Attach to existing dns_dispatch_t if one is found with dns_dispatchmgr_find, + * otherwise create a new UDP dispatch. + * + * Requires: + *\li All pointer parameters be valid for their respective types. + * + *\li dispp != NULL && *disp == NULL + * + *\li 512 <= buffersize <= 64k + * + *\li maxbuffers > 0 + * + *\li buckets < 2097169 + * + *\li increment > buckets + * + *\li (attributes & DNS_DISPATCHATTR_TCP) == 0 + * + * Returns: + *\li ISC_R_SUCCESS -- success. + * + *\li Anything else -- failure. + */ + +isc_result_t +dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, + isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, + const isc_sockaddr_t *destaddr, unsigned int buffersize, + unsigned int maxbuffers, unsigned int maxrequests, + unsigned int buckets, unsigned int increment, + unsigned int attributes, dns_dispatch_t **dispp); +/*%< + * Create a new dns_dispatch and attach it to the provided isc_socket_t. + * + * For all dispatches, "buffersize" is the maximum packet size we will + * accept. + * + * "maxbuffers" and "maxrequests" control the number of buffers in the + * overall system and the number of buffers which can be allocated to + * requests. + * + * "buckets" is the number of buckets to use, and should be prime. + * + * "increment" is used in a collision avoidance function, and needs to be + * a prime > buckets, and not 2. + * + * Requires: + * + *\li mgr is a valid dispatch manager. + * + *\li sock is a valid. + * + *\li task is a valid task that can be used internally to this dispatcher. + * + * \li 512 <= buffersize <= 64k + * + *\li maxbuffers > 0. + * + *\li maxrequests <= maxbuffers. + * + *\li buckets < 2097169 (the next prime after 65536 * 32) + * + *\li increment > buckets (and prime). + * + *\li attributes includes #DNS_DISPATCHATTR_TCP and does not include + * #DNS_DISPATCHATTR_UDP. + * + * Returns: + *\li ISC_R_SUCCESS -- success. + * + *\li Anything else -- failure. + */ + +void +dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp); +/*%< + * Attach to a dispatch handle. + * + * Requires: + *\li disp is valid. + * + *\li dispp != NULL && *dispp == NULL + */ + +void +dns_dispatch_detach(dns_dispatch_t **dispp); +/*%< + * Detaches from the dispatch. + * + * Requires: + *\li dispp != NULL and *dispp be a valid dispatch. + */ + +void +dns_dispatch_starttcp(dns_dispatch_t *disp); +/*%< + * Start processing of a TCP dispatch once the socket connects. + * + * Requires: + *\li 'disp' is valid. + */ + +isc_result_t +dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, + const isc_sockaddr_t *localaddr, bool *connected, + dns_dispatch_t **dispp); +/* + * Attempt to connect to a existing TCP connection (connection completed + * if connected == NULL). + */ + +isc_result_t +dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, + const isc_sockaddr_t *dest, isc_task_t *task, + isc_taskaction_t action, void *arg, uint16_t *idp, + dns_dispentry_t **resp, isc_socketmgr_t *sockmgr); +/*%< + * Add a response entry for this dispatch. + * + * "*idp" is filled in with the assigned message ID, and *resp is filled in + * to contain the magic token used to request event flow stop. + * + * Arranges for the given task to get a callback for response packets. When + * the event is delivered, it must be returned using dns_dispatch_freeevent() + * or through dns_dispatch_removeresponse() for another to be delivered. + * + * Requires: + *\li "idp" be non-NULL. + * + *\li "task" "action" and "arg" be set as appropriate. + * + *\li "dest" be non-NULL and valid. + * + *\li "resp" be non-NULL and *resp be NULL + * + *\li "sockmgr" be NULL or a valid socket manager. If 'disp' has + * the DNS_DISPATCHATTR_EXCLUSIVE attribute, this must not be NULL, + * which also means dns_dispatch_addresponse() cannot be used. + * + * Ensures: + * + *\li <id, dest> is a unique tuple. That means incoming messages + * are identifiable. + * + * Returns: + * + *\li ISC_R_SUCCESS -- all is well. + *\li ISC_R_NOMEMORY -- memory could not be allocated. + *\li ISC_R_NOMORE -- no more message ids can be allocated + * for this destination. + */ + +void +dns_dispatch_removeresponse(dns_dispentry_t **resp, + dns_dispatchevent_t **sockevent); +/*%< + * Stops the flow of responses for the provided id and destination. + * If "sockevent" is non-NULL, the dispatch event and associated buffer is + * also returned to the system. + * + * Requires: + *\li "resp" != NULL and "*resp" contain a value previously allocated + * by dns_dispatch_addresponse(); + * + *\li May only be called from within the task given as the 'task' + * argument to dns_dispatch_addresponse() when allocating '*resp'. + */ + +isc_socket_t * +dns_dispatch_getentrysocket(dns_dispentry_t *resp); + +isc_socket_t * +dns_dispatch_getsocket(dns_dispatch_t *disp); +/*%< + * Return the socket associated with this dispatcher. + * + * Requires: + *\li disp is valid. + * + * Returns: + *\li The socket the dispatcher is using. + */ + +isc_result_t +dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp); +/*%< + * Return the local address for this dispatch. + * This currently only works for dispatches using UDP sockets. + * + * Requires: + *\li disp is valid. + *\li addrp to be non null. + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOTIMPLEMENTED + */ + +void +dns_dispatch_cancel(dns_dispatch_t *disp); +/*%< + * cancel outstanding clients + * + * Requires: + *\li disp is valid. + */ + +unsigned int +dns_dispatch_getattributes(dns_dispatch_t *disp); +/*%< + * Return the attributes (DNS_DISPATCHATTR_xxx) of this dispatch. Only the + * non-changeable attributes are expected to be referenced by the caller. + * + * Requires: + *\li disp is valid. + */ + +void +dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes, + unsigned int mask); +/*%< + * Set the bits described by "mask" to the corresponding values in + * "attributes". + * + * That is: + * + * \code + * new = (old & ~mask) | (attributes & mask) + * \endcode + * + * This function has a side effect when #DNS_DISPATCHATTR_NOLISTEN changes. + * When the flag becomes off, the dispatch will start receiving on the + * corresponding socket. When the flag becomes on, receive events on the + * corresponding socket will be canceled. + * + * Requires: + *\li disp is valid. + * + *\li attributes are reasonable for the dispatch. That is, setting the UDP + * attribute on a TCP socket isn't reasonable. + */ + +void +dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event); +/*%< + * Inform the dispatcher of a socket receive. This is used for sockets + * shared between dispatchers and clients. If the dispatcher fails to copy + * or send the event, nothing happens. + * + * If the attribute DNS_DISPATCHATTR_NOLISTEN is not set, then + * the dispatch is already handling a recv; return immediately. + * + * Requires: + *\li disp is valid, and the attribute DNS_DISPATCHATTR_NOLISTEN is set. + * event != NULL + */ + +dns_dispatch_t * +dns_dispatchset_get(dns_dispatchset_t *dset); +/*%< + * Retrieve the next dispatch from dispatch set 'dset', and increment + * the round-robin counter. + * + * Requires: + *\li dset != NULL + */ + +isc_result_t +dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, + isc_taskmgr_t *taskmgr, dns_dispatch_t *source, + dns_dispatchset_t **dsetp, int n); +/*%< + * Given a valid dispatch 'source', create a dispatch set containing + * 'n' UDP dispatches, with the remainder filled out by clones of the + * source. + * + * Requires: + *\li source is a valid UDP dispatcher + *\li dsetp != NULL, *dsetp == NULL + */ + +void +dns_dispatchset_cancelall(dns_dispatchset_t *dset, isc_task_t *task); +/*%< + * Cancel socket operations for the dispatches in 'dset'. + */ + +void +dns_dispatchset_destroy(dns_dispatchset_t **dsetp); +/*%< + * Dereference all the dispatches in '*dsetp', free the dispatchset + * memory, and set *dsetp to NULL. + * + * Requires: + *\li dset is valid + */ + +void +dns_dispatch_setdscp(dns_dispatch_t *disp, isc_dscp_t dscp); +isc_dscp_t +dns_dispatch_getdscp(dns_dispatch_t *disp); +/*%< + * Set/get the DSCP value to be used when sending responses to clients, + * as defined in the "listen-on" or "listen-on-v6" statements. + * + * Requires: + *\li disp is valid. + */ + +isc_result_t +dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent); +/*%< + * Free the sockevent and trigger the sending of the next item off the + * dispatch queue if present. + * + * Requires: + *\li resp is valid + *\li *sockevent to be valid + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_DISPATCH_H */ diff --git a/lib/dns/include/dns/dlz.h b/lib/dns/include/dns/dlz.h new file mode 100644 index 0000000..962db29 --- /dev/null +++ b/lib/dns/include/dns/dlz.h @@ -0,0 +1,336 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 AND ISC + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE + * USE OR PERFORMANCE OF THIS SOFTWARE. + * + * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was + * conceived and contributed by Rob Butler. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE + * USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/*! \file dns/dlz.h */ + +#ifndef DLZ_H +#define DLZ_H 1 + +/***** +***** Module Info +*****/ + +/* + * DLZ Interface + * + * The DLZ interface allows zones to be looked up using a driver instead of + * Bind's default in memory zone table. + * + * + * Reliability: + * No anticipated impact. + * + * Resources: + * + * Security: + * No anticipated impact. + * + * Standards: + * None. + */ + +/***** +***** Imports +*****/ + +#include <stdbool.h> + +#include <isc/lang.h> + +#include <dns/clientinfo.h> +#include <dns/name.h> +#include <dns/types.h> +#include <dns/view.h> + +#include <dst/dst.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Types + ***/ + +#define DNS_DLZ_MAGIC ISC_MAGIC('D', 'L', 'Z', 'D') +#define DNS_DLZ_VALID(dlz) ISC_MAGIC_VALID(dlz, DNS_DLZ_MAGIC) + +typedef isc_result_t (*dns_dlzallowzonexfr_t)(void *driverarg, void *dbdata, + isc_mem_t *mctx, + dns_rdataclass_t rdclass, + const dns_name_t *name, + const isc_sockaddr_t *clientaddr, + dns_db_t **dbp); + +/*%< + * Method prototype. Drivers implementing the DLZ interface MUST + * supply an allow zone transfer method. This method is called when + * the DNS server is performing a zone transfer query. The driver's + * method should return ISC_R_SUCCESS and a database pointer to the + * name server if the zone is supported by the database, and zone + * transfer is allowed. If the view's transfer acl should be used, + * then the driver's method should return ISC_R_DEFAULT. Otherwise, + * it should return ISC_R_NOTFOUND if the zone is not supported by + * the database, or ISC_R_NOPERM if zone transfers are not allowed. + * If an error occurs, the result code should indicate the type of error. + */ + +typedef isc_result_t (*dns_dlzcreate_t)(isc_mem_t *mctx, const char *dlzname, + unsigned int argc, char *argv[], + void *driverarg, void **dbdata); + +/*%< + * Method prototype. Drivers implementing the DLZ interface MUST + * supply a create method. This method is called when the DNS server + * is starting up and creating drivers for use later. + */ + +typedef void (*dns_dlzdestroy_t)(void *driverarg, void **dbdata); + +/*%< + * Method prototype. Drivers implementing the DLZ interface MUST + * supply a destroy method. This method is called when the DNS server + * is shutting down and no longer needs the driver. + */ + +typedef isc_result_t (*dns_dlzfindzone_t)(void *driverarg, void *dbdata, + isc_mem_t *mctx, + dns_rdataclass_t rdclass, + const dns_name_t *name, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo, + dns_db_t **dbp); + +/*%< + * Method prototype. Drivers implementing the DLZ interface MUST + * supply a find zone method. This method is called when the DNS + * server is performing a query. The find zone method will be called + * with the longest possible name first, and continue to be called + * with successively shorter domain names, until any of the following + * occur: + * + * \li 1) a match is found, and the function returns (ISC_R_SUCCESS) + * + * \li 2) a problem occurs, and the functions returns anything other + * than (ISC_R_NOTFOUND) + * \li 3) we run out of domain name labels. I.E. we have tried the + * shortest domain name + * \li 4) the number of labels in the domain name is less than + * min_labels for dns_dlzfindzone + * + * The driver's find zone method should return ISC_R_SUCCESS and a + * database pointer to the name server if the zone is supported by the + * database. Otherwise it will return ISC_R_NOTFOUND, and a null + * pointer if the zone is not supported. If an error occurs it should + * return a result code indicating the type of error. + */ + +typedef isc_result_t (*dns_dlzconfigure_t)(void *driverarg, void *dbdata, + dns_view_t *view, + dns_dlzdb_t *dlzdb); +/*%< + * Method prototype. Drivers implementing the DLZ interface may + * optionally supply a configure method. If supplied, this will be + * called immediately after the create method is called. The driver + * may call configuration functions during the configure call + */ + +typedef bool (*dns_dlzssumatch_t)(const dns_name_t *signer, + const dns_name_t *name, + const isc_netaddr_t *tcpaddr, + dns_rdatatype_t type, const dst_key_t *key, + void *driverarg, void *dbdata); +/*%< + * Method prototype. Drivers implementing the DLZ interface may + * optionally supply a ssumatch method. If supplied, this will be + * called to authorize update requests + */ + +/*% the methods supplied by a DLZ driver */ +typedef struct dns_dlzmethods { + dns_dlzcreate_t create; + dns_dlzdestroy_t destroy; + dns_dlzfindzone_t findzone; + dns_dlzallowzonexfr_t allowzonexfr; + dns_dlzconfigure_t configure; + dns_dlzssumatch_t ssumatch; +} dns_dlzmethods_t; + +/*% information about a DLZ driver */ +struct dns_dlzimplementation { + const char *name; + const dns_dlzmethods_t *methods; + isc_mem_t *mctx; + void *driverarg; + ISC_LINK(dns_dlzimplementation_t) link; +}; + +typedef isc_result_t (*dlzconfigure_callback_t)(dns_view_t *, dns_dlzdb_t *, + dns_zone_t *); + +/*% An instance of a DLZ driver */ +struct dns_dlzdb { + unsigned int magic; + isc_mem_t *mctx; + dns_dlzimplementation_t *implementation; + void *dbdata; + dlzconfigure_callback_t configure_callback; + bool search; + char *dlzname; + ISC_LINK(dns_dlzdb_t) link; + dns_ssutable_t *ssutable; +}; + +/*** + *** Method declarations + ***/ + +isc_result_t +dns_dlzallowzonexfr(dns_view_t *view, const dns_name_t *name, + const isc_sockaddr_t *clientaddr, dns_db_t **dbp); + +/*%< + * This method is called when the DNS server is performing a zone + * transfer query. It will call the DLZ driver's allow zone transfer + * method. + */ + +isc_result_t +dns_dlzcreate(isc_mem_t *mctx, const char *dlzname, const char *drivername, + unsigned int argc, char *argv[], dns_dlzdb_t **dbp); + +/*%< + * This method is called when the DNS server is starting up and + * creating drivers for use later. It will search the DLZ driver list + * for 'drivername' and return a DLZ driver via dbp if a match is + * found. If the DLZ driver supplies a create method, this function + * will call it. + */ + +void +dns_dlzdestroy(dns_dlzdb_t **dbp); + +/*%< + * This method is called when the DNS server is shutting down and no + * longer needs the driver. If the DLZ driver supplies a destroy + * methods, this function will call it. + */ + +isc_result_t +dns_dlzregister(const char *drivername, const dns_dlzmethods_t *methods, + void *driverarg, isc_mem_t *mctx, + dns_dlzimplementation_t **dlzimp); + +/*%< + * Register a dynamically loadable zones (DLZ) driver for the database + * type 'drivername', implemented by the functions in '*methods'. + * + * dlzimp must point to a NULL dlz_implementation_t pointer. That is, + * dlzimp != NULL && *dlzimp == NULL. It will be assigned a value that + * will later be used to identify the driver when deregistering it. + */ + +isc_result_t +dns_dlzstrtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp); + +/*%< + * This method is called when the name server is starting up to parse + * the DLZ driver command line from named.conf. Basically it splits + * up a string into and argc / argv. The primary difference of this + * method is items between braces { } are considered only 1 word. for + * example the command line "this is { one grouped phrase } and this + * isn't" would be parsed into: + * + * \li argv[0]: "this" + * \li argv[1]: "is" + * \li argv{2]: " one grouped phrase " + * \li argv[3]: "and" + * \li argv[4]: "this" + * \li argv{5}: "isn't" + * + * braces should NOT be nested, more than one grouping in the command + * line is allowed. Notice, argv[2] has an extra space at the + * beginning and end. Extra spaces are not stripped between a + * grouping. You can do so in your driver if needed, or be sure not + * to put extra spaces before / after the braces. + */ + +void +dns_dlzunregister(dns_dlzimplementation_t **dlzimp); + +/*%< + * Removes the dlz driver from the list of registered dlz drivers. + * There must be no active dlz drivers of this type when this function + * is called. + */ + +typedef isc_result_t +dns_dlz_writeablezone_t(dns_view_t *view, dns_dlzdb_t *dlzdb, + const char *zone_name); +dns_dlz_writeablezone_t dns_dlz_writeablezone; +/*%< + * creates a writeable DLZ zone. Must be called from within the + * configure() method of a DLZ driver. + */ + +isc_result_t +dns_dlzconfigure(dns_view_t *view, dns_dlzdb_t *dlzdb, + dlzconfigure_callback_t callback); +/*%< + * call a DLZ drivers configure method, if supplied + */ + +bool +dns_dlz_ssumatch(dns_dlzdb_t *dlzdatabase, const dns_name_t *signer, + const dns_name_t *name, const isc_netaddr_t *tcpaddr, + dns_rdatatype_t type, const dst_key_t *key); +/*%< + * call a DLZ drivers ssumatch method, if supplied. Otherwise return false + */ + +ISC_LANG_ENDDECLS + +#endif /* DLZ_H */ diff --git a/lib/dns/include/dns/dlz_dlopen.h b/lib/dns/include/dns/dlz_dlopen.h new file mode 100644 index 0000000..058a23e --- /dev/null +++ b/lib/dns/include/dns/dlz_dlopen.h @@ -0,0 +1,159 @@ +/* + * 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. + */ + +/*! \file dns/dlz_dlopen.h */ + +#ifndef DLZ_DLOPEN_H +#define DLZ_DLOPEN_H + +#include <inttypes.h> +#include <stdbool.h> + +#include <dns/sdlz.h> + +ISC_LANG_BEGINDECLS + +/* + * This header provides a minimal set of defines and typedefs needed + * for the entry points of an external DLZ module for bind9. + */ + +#define DLZ_DLOPEN_VERSION 3 +#define DLZ_DLOPEN_AGE 0 + +/* + * dlz_dlopen_version() is required for all DLZ external drivers. It + * should return DLZ_DLOPEN_VERSION + */ +typedef int +dlz_dlopen_version_t(unsigned int *flags); + +/* + * dlz_dlopen_create() is required for all DLZ external drivers. + */ +typedef isc_result_t +dlz_dlopen_create_t(const char *dlzname, unsigned int argc, char *argv[], + void **dbdata, ...); + +/* + * dlz_dlopen_destroy() is optional, and will be called when the + * driver is unloaded if supplied + */ +typedef void +dlz_dlopen_destroy_t(void *dbdata); + +/* + * dlz_dlopen_findzonedb() is required for all DLZ external drivers + */ +typedef isc_result_t +dlz_dlopen_findzonedb_t(void *dbdata, const char *name, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo); + +/* + * dlz_dlopen_lookup() is required for all DLZ external drivers + */ +typedef isc_result_t +dlz_dlopen_lookup_t(const char *zone, const char *name, void *dbdata, + dns_sdlzlookup_t *lookup, dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo); + +/* + * dlz_dlopen_authority is optional() if dlz_dlopen_lookup() + * supplies authority information for the dns record + */ +typedef isc_result_t +dlz_dlopen_authority_t(const char *zone, void *dbdata, + dns_sdlzlookup_t *lookup); + +/* + * dlz_dlopen_allowzonexfr() is optional, and should be supplied if + * you want to support zone transfers + */ +typedef isc_result_t +dlz_dlopen_allowzonexfr_t(void *dbdata, const char *name, const char *client); + +/* + * dlz_dlopen_allnodes() is optional, but must be supplied if supply a + * dlz_dlopen_allowzonexfr() function + */ +typedef isc_result_t +dlz_dlopen_allnodes_t(const char *zone, void *dbdata, + dns_sdlzallnodes_t *allnodes); + +/* + * dlz_dlopen_newversion() is optional. It should be supplied if you + * want to support dynamic updates. + */ +typedef isc_result_t +dlz_dlopen_newversion_t(const char *zone, void *dbdata, void **versionp); + +/* + * dlz_closeversion() is optional, but must be supplied if you supply + * a dlz_newversion() function + */ +typedef void +dlz_dlopen_closeversion_t(const char *zone, bool commit, void *dbdata, + void **versionp); + +/* + * dlz_dlopen_configure() is optional, but must be supplied if you + * want to support dynamic updates + */ +typedef isc_result_t +dlz_dlopen_configure_t(dns_view_t *view, dns_dlzdb_t *dlzdb, void *dbdata); + +/* + * dlz_dlopen_setclientcallback() is optional, but must be supplied if you + * want to retrieve information about the client (e.g., source address) + * before sending a replay. + */ +typedef isc_result_t +dlz_dlopen_setclientcallback_t(dns_view_t *view, void *dbdata); + +/* + * dlz_dlopen_ssumatch() is optional, but must be supplied if you want + * to support dynamic updates + */ +typedef bool +dlz_dlopen_ssumatch_t(const char *signer, const char *name, const char *tcpaddr, + const char *type, const char *key, uint32_t keydatalen, + unsigned char *keydata, void *dbdata); + +/* + * dlz_dlopen_addrdataset() is optional, but must be supplied if you + * want to support dynamic updates + */ +typedef isc_result_t +dlz_dlopen_addrdataset_t(const char *name, const char *rdatastr, void *dbdata, + void *version); + +/* + * dlz_dlopen_subrdataset() is optional, but must be supplied if you + * want to support dynamic updates + */ +typedef isc_result_t +dlz_dlopen_subrdataset_t(const char *name, const char *rdatastr, void *dbdata, + void *version); + +/* + * dlz_dlopen_delrdataset() is optional, but must be supplied if you + * want to support dynamic updates + */ +typedef isc_result_t +dlz_dlopen_delrdataset_t(const char *name, const char *type, void *dbdata, + void *version); + +ISC_LANG_ENDDECLS + +#endif /* ifndef DLZ_DLOPEN_H */ diff --git a/lib/dns/include/dns/dns64.h b/lib/dns/include/dns/dns64.h new file mode 100644 index 0000000..07bc06f --- /dev/null +++ b/lib/dns/include/dns/dns64.h @@ -0,0 +1,174 @@ +/* + * 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. + */ + +#ifndef DNS_DNS64_H +#define DNS_DNS64_H 1 + +#include <stdbool.h> + +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/* + * dns_dns64_create() flags. + */ +#define DNS_DNS64_RECURSIVE_ONLY \ + 0x01 /* If set then this record \ + * only applies to recursive \ + * queries. \ + */ +#define DNS_DNS64_BREAK_DNSSEC \ + 0x02 /* If set then still perform \ + * DNSSEC synthesis even \ + * though the result would \ + * fail validation. \ + */ + +/* + * dns_dns64_aaaaok() and dns_dns64_aaaafroma() flags. + */ +#define DNS_DNS64_RECURSIVE 0x01 /* Recursive query. */ +#define DNS_DNS64_DNSSEC 0x02 /* DNSSEC sensitive query. */ + +isc_result_t +dns_dns64_create(isc_mem_t *mctx, const isc_netaddr_t *prefix, + unsigned int prefixlen, const isc_netaddr_t *suffix, + dns_acl_t *client, dns_acl_t *mapped, dns_acl_t *excluded, + unsigned int flags, dns_dns64_t **dns64); +/* + * Create a dns64 record which is used to identify the set of clients + * it applies to and how to perform the DNS64 synthesis. + * + * 'prefix' and 'prefixlen' defined the leading bits of the AAAA records + * to be synthesised. 'suffix' defines the bits after the A records bits. + * If suffix is NULL zeros will be used for these bits. 'client' defines + * for which clients this record applies. If 'client' is NULL then all + * clients apply. 'mapped' defines which A records are candidated for + * mapping. If 'mapped' is NULL then all A records will be mapped. + * 'excluded' defines which AAAA are to be treated as non-existent for the + * purposed of determining whether to perform synthesis. If 'excluded' is + * NULL then no AAAA records prevent synthesis. + * + * If DNS_DNS64_RECURSIVE_ONLY is set then the record will only match if + * DNS_DNS64_RECURSIVE is set when calling dns_dns64_aaaaok() and + * dns_dns64_aaaafroma(). + * + * If DNS_DNS64_BREAK_DNSSEC is set then the record will still apply if + * DNS_DNS64_DNSSEC is set when calling dns_dns64_aaaaok() and + * dns_dns64_aaaafroma() otherwise the record will be ignored. + * + * Requires: + * 'mctx' to be valid. + * 'prefix' to be valid and the address family to AF_INET6. + * 'prefixlen' to be one of 32, 40, 48, 56, 72 and 96. + * the bits not covered by prefixlen in prefix to + * be zero. + * 'suffix' to be NULL or the address family be set to AF_INET6 + * and the leading 'prefixlen' + 32 bits of the 'suffix' + * to be zero. If 'prefixlen' is 40, 48 or 56 then the + * the leading 'prefixlen' + 40 bits of 'suffix' must be + * zero. + * 'client' to be NULL or a valid acl. + * 'mapped' to be NULL or a valid acl. + * 'excluded' to be NULL or a valid acl. + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_NOMEMORY + */ + +void +dns_dns64_destroy(dns_dns64_t **dns64p); +/* + * Destroys a dns64 record. + * + * Requires the record to not be linked. + */ + +isc_result_t +dns_dns64_aaaafroma(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr, + const dns_name_t *reqsigner, const dns_aclenv_t *env, + unsigned int flags, unsigned char *a, unsigned char *aaaa); +/* + * dns_dns64_aaaafroma() determines whether to perform a DNS64 address + * synthesis from 'a' based on 'dns64', 'reqaddr', 'reqsigner', 'env', + * 'flags' and 'aaaa'. If synthesis is performed then the result is + * written to '*aaaa'. + * + * The synthesised address will be of the form: + * + * <prefix bits><a bits><suffix bits> + * + * If <a bits> straddle bits 64-71 of the AAAA record, then 8 zero bits will + * be inserted at bits 64-71. + * + * Requires: + * 'dns64' to be valid. + * 'reqaddr' to be valid. + * 'reqsigner' to be NULL or valid. + * 'env' to be valid. + * 'a' to point to a IPv4 address in network order. + * 'aaaa' to point to a IPv6 address buffer in network order. + * + * Returns: + * ISC_R_SUCCESS if synthesis was performed. + * DNS_R_DISALLOWED if there is no match. + */ + +dns_dns64_t * +dns_dns64_next(dns_dns64_t *dns64); +/* + * Return the next dns64 record in the list. + */ + +void +dns_dns64_append(dns_dns64list_t *list, dns_dns64_t *dns64); +/* + * Append the dns64 record to the list. + */ + +void +dns_dns64_unlink(dns_dns64list_t *list, dns_dns64_t *dns64); +/* + * Unlink the dns64 record from the list. + */ + +bool +dns_dns64_aaaaok(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr, + const dns_name_t *reqsigner, const dns_aclenv_t *env, + unsigned int flags, dns_rdataset_t *rdataset, bool *aaaaok, + size_t aaaaoklen); +/* + * Determine if there are any non-excluded AAAA records in from the + * matching dns64 records in the list starting at 'dns64'. If there + * is a non-excluded address return true. If all addresses are + * excluded in the matched records return false. If no records + * match then return true. + * + * If aaaaok is defined then dns_dns64_aaaaok() return a array of which + * addresses in 'rdataset' were deemed to not be exclude by any matching + * record. If there are no matching records then all entries are set + * to true. + * + * Requires + * 'rdataset' to be valid and to be for type AAAA and class IN. + * 'aaaaoklen' must match the number of records in 'rdataset' + * if 'aaaaok' in non NULL. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_DNS64_H */ diff --git a/lib/dns/include/dns/dnsrps.h b/lib/dns/include/dns/dnsrps.h new file mode 100644 index 0000000..aa903b8 --- /dev/null +++ b/lib/dns/include/dns/dnsrps.h @@ -0,0 +1,115 @@ +/* + * 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. + */ + +#ifndef DNS_DNSRPS_H +#define DNS_DNSRPS_H + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/lang.h> + +#include <dns/types.h> + +#ifdef USE_DNSRPS + +#include <dns/librpz.h> +#include <dns/rpz.h> + +/* + * Error message if dlopen(librpz) failed. + */ +extern librpz_emsg_t librpz_lib_open_emsg; + +/* + * These shim BIND9 database, node, and rdataset are handles on RRs from librpz. + * + * All of these structures are used by a single thread and so need no locks. + * + * rpsdb_t holds the state for a set of RPZ queries. + * + * rpsnode_t is a link to the rpsdb_t for the set of RPZ queries + * and a flag saying whether it is pretending to be a node with RRs for + * the qname or the node with the SOA for the zone containing the rewritten + * RRs or justifying NXDOMAIN. + */ +typedef struct { + uint8_t unused; +} rpsnode_t; +typedef struct rpsdb { + dns_db_t common; + int ref_cnt; + librpz_result_id_t hit_id; + librpz_result_t result; + librpz_rsp_t *rsp; + librpz_domain_buf_t origin_buf; + const dns_name_t *qname; + rpsnode_t origin_node; + rpsnode_t data_node; +} rpsdb_t; + +/* + * Convert a dnsrps policy to a classic BIND9 RPZ policy. + */ +dns_rpz_policy_t +dns_dnsrps_2policy(librpz_policy_t rps_policy); + +/* + * Convert a dnsrps trigger to a classic BIND9 RPZ rewrite or trigger type. + */ +dns_rpz_type_t +dns_dnsrps_trig2type(librpz_trig_t trig); + +/* + * Convert a classic BIND9 RPZ rewrite or trigger type to a librpz trigger type. + */ +librpz_trig_t +dns_dnsrps_type2trig(dns_rpz_type_t type); + +/* + * Start dnsrps for the entire server. + */ +isc_result_t +dns_dnsrps_server_create(void); + +/* + * Stop dnsrps for the entire server. + */ +void +dns_dnsrps_server_destroy(void); + +/* + * Ready dnsrps for a view. + */ +isc_result_t +dns_dnsrps_view_init(dns_rpz_zones_t *new, char *rps_cstr); + +/* + * Connect to and start the dnsrps daemon, dnsrpzd. + */ +isc_result_t +dns_dnsrps_connect(dns_rpz_zones_t *rpzs); + +/* + * Get ready to try dnsrps rewriting. + */ +isc_result_t +dns_dnsrps_rewrite_init(librpz_emsg_t *emsg, dns_rpz_st_t *st, + dns_rpz_zones_t *rpzs, const dns_name_t *qname, + isc_mem_t *mctx, bool have_rd); + +#endif /* USE_DNSRPS */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_DNSRPS_H */ diff --git a/lib/dns/include/dns/dnssec.h b/lib/dns/include/dns/dnssec.h new file mode 100644 index 0000000..9791ef1 --- /dev/null +++ b/lib/dns/include/dns/dnssec.h @@ -0,0 +1,401 @@ +/* + * 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. + */ + +#ifndef DNS_DNSSEC_H +#define DNS_DNSSEC_H 1 + +/*! \file dns/dnssec.h */ + +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/stats.h> +#include <isc/stdtime.h> + +#include <dns/diff.h> +#include <dns/types.h> + +#include <dst/dst.h> + +ISC_LANG_BEGINDECLS + +LIBDNS_EXTERNAL_DATA extern isc_stats_t *dns_dnssec_stats; + +/*%< Maximum number of keys supported in a zone. */ +#define DNS_MAXZONEKEYS 32 + +/* + * Indicates how the signer found this key: in the key repository, at the + * zone apex, or specified by the user. + */ +typedef enum { + dns_keysource_unknown, + dns_keysource_repository, + dns_keysource_zoneapex, + dns_keysource_user +} dns_keysource_t; + +/* + * A DNSSEC key and hints about its intended use gleaned from metadata + */ +struct dns_dnsseckey { + dst_key_t *key; + bool hint_publish; /*% metadata says to publish */ + bool force_publish; /*% publish regardless of metadata + * */ + bool hint_sign; /*% metadata says to sign with this + * key */ + bool force_sign; /*% sign with key regardless of + * metadata */ + bool hint_revoke; /*% metadata says revoke key */ + bool hint_remove; /*% metadata says *don't* publish */ + bool is_active; /*% key is already active */ + bool first_sign; /*% key is newly becoming active */ + bool purge; /*% remove key files */ + unsigned int prepublish; /*% how long until active? */ + dns_keysource_t source; /*% how the key was found */ + bool ksk; /*% this is a key-signing key */ + bool zsk; /*% this is a zone-signing key */ + bool legacy; /*% this is old-style key with no + * metadata (possibly generated by + * an older version of BIND9) and + * should be ignored when searching + * for keys to import into the zone */ + unsigned int index; /*% position in list */ + ISC_LINK(dns_dnsseckey_t) link; +}; + +isc_result_t +dns_dnssec_keyfromrdata(const dns_name_t *name, const dns_rdata_t *rdata, + isc_mem_t *mctx, dst_key_t **key); +/*%< + * Creates a DST key from a DNS record. Basically a wrapper around + * dst_key_fromdns(). + * + * Requires: + *\li 'name' is not NULL + *\li 'rdata' is not NULL + *\li 'mctx' is not NULL + *\li 'key' is not NULL + *\li '*key' is NULL + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li DST_R_INVALIDPUBLICKEY + *\li various errors from dns_name_totext + */ + +isc_result_t +dns_dnssec_sign(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + isc_stdtime_t *inception, isc_stdtime_t *expire, + isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata); +/*%< + * Generates a RRSIG record covering this rdataset. This has no effect + * on existing RRSIG records. + * + * Requires: + *\li 'name' (the owner name of the record) is a valid name + *\li 'set' is a valid rdataset + *\li 'key' is a valid key + *\li 'inception' is not NULL + *\li 'expire' is not NULL + *\li 'mctx' is not NULL + *\li 'buffer' is not NULL + *\li 'sigrdata' is not NULL + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_NOSPACE + *\li #DNS_R_INVALIDTIME - the expiration is before the inception + *\li #DNS_R_KEYUNAUTHORIZED - the key cannot sign this data (either + * it is not a zone key or its flags prevent + * authentication) + *\li DST_R_* + */ + +isc_result_t +dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + bool ignoretime, unsigned int maxbits, isc_mem_t *mctx, + dns_rdata_t *sigrdata, dns_name_t *wild); +/*%< + * Verifies the RRSIG record covering this rdataset signed by a specific + * key. This does not determine if the key's owner is authorized to sign + * this record, as this requires a resolver or database. + * If 'ignoretime' is true, temporal validity will not be checked. + * + * 'maxbits' specifies the maximum number of rsa exponent bits accepted. + * + * Requires: + *\li 'name' (the owner name of the record) is a valid name + *\li 'set' is a valid rdataset + *\li 'key' is a valid key + *\li 'mctx' is not NULL + *\li 'sigrdata' is a valid rdata containing a SIG record + *\li 'wild' if non-NULL then is a valid and has a buffer. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #DNS_R_FROMWILDCARD - the signature is valid and is from + * a wildcard expansion. dns_dnssec_verify2() only. + * 'wild' contains the name of the wildcard if non-NULL. + *\li #DNS_R_SIGINVALID - the signature fails to verify + *\li #DNS_R_SIGEXPIRED - the signature has expired + *\li #DNS_R_SIGFUTURE - the signature's validity period has not begun + *\li #DNS_R_KEYUNAUTHORIZED - the key cannot sign this data (either + * it is not a zone key or its flags prevent + * authentication) + *\li DST_R_* + */ + +/*@{*/ +isc_result_t +dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node, + const dns_name_t *name, const char *directory, + isc_stdtime_t now, isc_mem_t *mctx, + unsigned int maxkeys, dst_key_t **keys, + unsigned int *nkeys); + +/*%< + * Finds a set of zone keys. + * XXX temporary - this should be handled in dns_zone_t. + */ +/*@}*/ + +bool +dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now); +/*%< + * + * Returns true if 'key' is active as of the time specified + * in 'now' (i.e., if the activation date has passed, inactivation or + * deletion date has not yet been reached, and the key is not revoked + * -- or if it is a legacy key without metadata). Otherwise returns + * false. + * + * Requires: + *\li 'key' is a valid key + */ + +isc_result_t +dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key); +/*%< + * Signs a message with a SIG(0) record. This is implicitly called by + * dns_message_renderend() if msg->sig0key is not NULL. + * + * Requires: + *\li 'msg' is a valid message + *\li 'key' is a valid key that can be used for signing + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li DST_R_* + */ + +isc_result_t +dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg, + dst_key_t *key); +/*%< + * Verifies a message signed by a SIG(0) record. This is not + * called implicitly by dns_message_parse(). If dns_message_signer() + * is called before dns_dnssec_verifymessage(), it will return + * #DNS_R_NOTVERIFIEDYET. dns_dnssec_verifymessage() will set + * the verified_sig0 flag in msg if the verify succeeds, and + * the sig0status field otherwise. + * + * Requires: + *\li 'source' is a valid buffer containing the unparsed message + *\li 'msg' is a valid message + *\li 'key' is a valid key + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_NOTFOUND - no SIG(0) was found + *\li #DNS_R_SIGINVALID - the SIG record is not well-formed or + * was not generated by the key. + *\li DST_R_* + */ + +bool +dns_dnssec_selfsigns(dns_rdata_t *rdata, const dns_name_t *name, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, + bool ignoretime, isc_mem_t *mctx); + +bool +dns_dnssec_signs(dns_rdata_t *rdata, const dns_name_t *name, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, + bool ignoretime, isc_mem_t *mctx); +/*%< + * Verify that 'rdataset' is validly signed in 'sigrdataset' by + * the key in 'rdata'. + * + * dns_dnssec_selfsigns() requires that rdataset be a DNSKEY or KEY + * rrset. dns_dnssec_signs() works on any rrset. + */ + +isc_result_t +dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey, + dns_dnsseckey_t **dkp); +/*%< + * Create and initialize a dns_dnsseckey_t structure. + * + * Requires: + *\li 'dkp' is not NULL and '*dkp' is NULL. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +void +dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp); +/*%< + * Reclaim a dns_dnsseckey_t structure. + * + * Requires: + *\li 'dkp' is not NULL and '*dkp' is not NULL. + * + * Ensures: + *\li '*dkp' is NULL. + */ + +void +dns_dnssec_get_hints(dns_dnsseckey_t *key, isc_stdtime_t now); +/*%< + * Get hints on DNSSEC key whether this key can be published + * and/or is active. Timing metadata is compared to 'now'. + * + * Requires: + *\li 'key' is a pointer to a DNSSEC key and is not NULL. + */ + +isc_result_t +dns_dnssec_findmatchingkeys(const dns_name_t *origin, const char *directory, + isc_stdtime_t now, isc_mem_t *mctx, + dns_dnsseckeylist_t *keylist); +/*%< + * Search 'directory' for K* key files matching the name in 'origin'. + * Append all such keys, along with use hints gleaned from their + * metadata, onto 'keylist'. Skip any unsupported algorithms. + * + * Requires: + *\li 'keylist' is not NULL + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOTFOUND + *\li #ISC_R_NOMEMORY + *\li any error returned by dns_name_totext(), isc_dir_open(), or + * dst_key_fromnamedfile() + * + * Ensures: + *\li On error, keylist is unchanged + */ + +isc_result_t +dns_dnssec_keylistfromrdataset(const dns_name_t *origin, const char *directory, + isc_mem_t *mctx, dns_rdataset_t *keyset, + dns_rdataset_t *keysigs, dns_rdataset_t *soasigs, + bool savekeys, bool publickey, + dns_dnsseckeylist_t *keylist); +/*%< + * Append the contents of a DNSKEY rdataset 'keyset' to 'keylist'. + * Omit duplicates. If 'publickey' is false, search 'directory' for + * matching key files, and load the private keys that go with + * the public ones. If 'savekeys' is true, mark the keys so + * they will not be deleted or inactivated regardless of metadata. + * + * 'keysigs' and 'soasigs', if not NULL and associated, contain the + * RRSIGS for the DNSKEY and SOA records respectively and are used to mark + * whether a key is already active in the zone. + */ + +isc_result_t +dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys, + dns_dnsseckeylist_t *removed, const dns_name_t *origin, + dns_ttl_t hint_ttl, dns_diff_t *diff, isc_mem_t *mctx, + void (*report)(const char *, ...)); +/*%< + * Update the list of keys in 'keys' with new key information in 'newkeys'. + * + * For each key in 'newkeys', see if it has a match in 'keys'. + * - If not, and if the metadata says the key should be published: + * add it to 'keys', and place a dns_difftuple into 'diff' so + * the key can be added to the DNSKEY set. If the metadata says it + * should be active, set the first_sign flag. + * - If so, and if the metadata says it should be removed: + * remove it from 'keys', and place a dns_difftuple into 'diff' so + * the key can be removed from the DNSKEY set. if 'removed' is non-NULL, + * copy the key into that list; otherwise destroy it. + * - Otherwise, make sure keys has current metadata. + * + * 'hint_ttl' is the TTL to use for the DNSKEY RRset if there is no + * existing RRset, and if none of the keys to be added has a default TTL + * (in which case we would use the shortest one). If the TTL is longer + * than the time until a new key will be activated, then we have to delay + * the key's activation. + * + * 'report' points to a function for reporting status. + * + * On completion, any remaining keys in 'newkeys' are freed. + */ + +isc_result_t +dns_dnssec_syncupdate(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *rmkeys, + dns_rdataset_t *cds, dns_rdataset_t *cdnskey, + isc_stdtime_t now, dns_ttl_t hint_ttl, dns_diff_t *diff, + isc_mem_t *mctx); +/*%< + * Update the CDS and CDNSKEY RRsets, adding and removing keys as needed. + * + * Returns: + *\li ISC_R_SUCCESS + *\li Other values indicate error + */ + +isc_result_t +dns_dnssec_syncdelete(dns_rdataset_t *cds, dns_rdataset_t *cdnskey, + dns_name_t *origin, dns_rdataclass_t zclass, + dns_ttl_t ttl, dns_diff_t *diff, isc_mem_t *mctx, + bool expect_cds_delete, bool expect_cdnskey_delete); +/*%< + * Add or remove the CDS DELETE record and the CDNSKEY DELETE record. + * If 'expect_cds_delete' is true, the CDS DELETE record should be present. + * Otherwise, the CDS DELETE record must be removed from the RRsets (if + * present). If 'expect_cdnskey_delete' is true, the CDNSKEY DELETE record + * should be present. Otherwise, the CDNSKEY DELETE record must be removed + * from the RRsets (if present). + * + * Returns: + *\li ISC_R_SUCCESS + *\li Other values indicate error + */ + +isc_result_t +dns_dnssec_matchdskey(dns_name_t *name, dns_rdata_t *dsrdata, + dns_rdataset_t *keyset, dns_rdata_t *keyrdata); +/*%< + * Given a DS rdata and a DNSKEY RRset, find the DNSKEY rdata that matches + * the DS, and place it in 'keyrdata'. + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOTFOUND + *\li Other values indicate error + */ +ISC_LANG_ENDDECLS + +#endif /* DNS_DNSSEC_H */ diff --git a/lib/dns/include/dns/dnstap.h b/lib/dns/include/dns/dnstap.h new file mode 100644 index 0000000..e1da53d --- /dev/null +++ b/lib/dns/include/dns/dnstap.h @@ -0,0 +1,396 @@ +/* + * 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. + */ + +#ifndef _DNSTAP_H +#define _DNSTAP_H + +/***** +***** Module Info +*****/ + +/*! \file + * \brief + * The dt (dnstap) module provides fast passive logging of DNS messages. + * Protocol Buffers. The protobuf schema for Dnstap messages is in the + * file dnstap.proto, which is compiled to dnstap.pb-c.c and dnstap.pb-c.h. + */ + +#include <inttypes.h> +#include <stdbool.h> + +struct fstrm_iothr_options; + +#include <isc/log.h> +#include <isc/refcount.h> +#include <isc/region.h> +#include <isc/sockaddr.h> +#include <isc/time.h> +#include <isc/types.h> + +#include <dns/name.h> +#include <dns/rdataclass.h> +#include <dns/rdatatype.h> +#include <dns/types.h> + +/*% + * Dnstap message types: + * + * STUB QUERY: SQ + * STUB RESPONSE: SR + * CLIENT QUERY: CQ + * CLIENT RESPONSE: CR + * AUTH QUERY: AQ + * AUTH RESPONSE: AR + * RESOLVER QUERY: RQ + * RESOLVER RESPONSE: RR + * FORWARDER QUERY: FQ + * FORWARDER RESPONSE: FR + */ + +#define DNS_DTTYPE_SQ 0x0001 +#define DNS_DTTYPE_SR 0x0002 +#define DNS_DTTYPE_CQ 0x0004 +#define DNS_DTTYPE_CR 0x0008 +#define DNS_DTTYPE_AQ 0x0010 +#define DNS_DTTYPE_AR 0x0020 +#define DNS_DTTYPE_RQ 0x0040 +#define DNS_DTTYPE_RR 0x0080 +#define DNS_DTTYPE_FQ 0x0100 +#define DNS_DTTYPE_FR 0x0200 +#define DNS_DTTYPE_TQ 0x0400 +#define DNS_DTTYPE_TR 0x0800 +#define DNS_DTTYPE_UQ 0x1000 +#define DNS_DTTYPE_UR 0x2000 + +#define DNS_DTTYPE_QUERY \ + (DNS_DTTYPE_SQ | DNS_DTTYPE_CQ | DNS_DTTYPE_AQ | DNS_DTTYPE_RQ | \ + DNS_DTTYPE_FQ | DNS_DTTYPE_TQ | DNS_DTTYPE_UQ) +#define DNS_DTTYPE_RESPONSE \ + (DNS_DTTYPE_SR | DNS_DTTYPE_CR | DNS_DTTYPE_AR | DNS_DTTYPE_RR | \ + DNS_DTTYPE_FR | DNS_DTTYPE_TR | DNS_DTTYPE_UR) +#define DNS_DTTYPE_ALL (DNS_DTTYPE_QUERY | DNS_DTTYPE_RESPONSE) + +typedef enum { + dns_dtmode_none = 0, + dns_dtmode_file, + dns_dtmode_unix +} dns_dtmode_t; + +typedef struct dns_dthandle dns_dthandle_t; + +#ifdef HAVE_DNSTAP +struct dns_dtdata { + isc_mem_t *mctx; + + void *frame; + + bool query; + bool tcp; + dns_dtmsgtype_t type; + + isc_time_t qtime; + isc_time_t rtime; + + isc_region_t qaddr; + isc_region_t raddr; + + uint32_t qport; + uint32_t rport; + + isc_region_t msgdata; + dns_message_t *msg; + + char namebuf[DNS_NAME_FORMATSIZE]; + char typebuf[DNS_RDATATYPE_FORMATSIZE]; + char classbuf[DNS_RDATACLASS_FORMATSIZE]; +}; +#endif /* HAVE_DNSTAP */ + +isc_result_t +dns_dt_create(isc_mem_t *mctx, dns_dtmode_t mode, const char *path, + struct fstrm_iothr_options **foptp, isc_task_t *reopen_task, + dns_dtenv_t **envp); +/*%< + * Create and initialize the dnstap environment. + * + * There should be a single global dnstap environment for the server; + * copies of it will be attached to each view. + * + * Notes: + * + *\li 'path' refers to a UNIX domain socket by default. It may + * optionally be prepended with "socket:" or "file:". If prepended + * with "file:", then dnstap logs are sent to a file instead of a + * socket. + * + *\li '*foptp' set the options for fstrm_iothr_init(). '*foptp' must have + * have had the number of input queues set and this should be set + * to the number of worker threads. Additionally the queue model + * should also be set. Other options may be set if desired. + * If dns_dt_create succeeds the *foptp is set to NULL. + * + *\li 'reopen_task' needs to be set to the task in the context of which + * dns_dt_reopen() will be called. This is not an optional parameter: + * using dns_dt_create() (which sets 'reopen_task' to NULL) is only + * allowed in unit tests. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li 'path' is a valid C string. + * + *\li 'foptp' is non NULL. + * + *\li envp != NULL && *envp == NULL + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + * + *\li Other errors are possible. + */ + +isc_result_t +dns_dt_setupfile(dns_dtenv_t *env, uint64_t max_size, int rolls, + isc_log_rollsuffix_t suffix); +/*%< + * Sets up the dnstap logfile limits. + * + * 'max_size' is the size a log file may grow before it is rolled + * + * 'rolls' is the number of rolled files to retain. + * + * 'suffix' is the logfile suffix setting, increment or timestamp. + * + * Requires: + * + *\li 'env' is a valid dnstap environment. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #ISC_R_INVALIDFILE if dnstap is set to use a UNIX domain socket + */ + +isc_result_t +dns_dt_reopen(dns_dtenv_t *env, int roll); +/*%< + * Reopens files established by dns_dt_create2(). + * + * If 'roll' is non-negative and 'env->mode' is dns_dtmode_file, + * then the file is automatically rolled over before reopening. + * The value of 'roll' indicates the number of backup log files to + * keep. If 'roll' is negative, or if 'env->mode' is dns_dtmode_unix, + * then the channel is simply reopened. + * + * Note: dns_dt_reopen() uses task-exclusive mode and must be run in the + * context of env->reopen_task. + * + * Requires: + *\li 'env' is a valid dnstap environment. + */ + +isc_result_t +dns_dt_setidentity(dns_dtenv_t *env, const char *identity); +isc_result_t +dns_dt_setversion(dns_dtenv_t *env, const char *version); +/*%< + * Set the "identity" and "version" strings to be sent in dnstap messages. + * + * Requires: + * + *\li 'env' is a valid dnstap environment. + */ + +void +dns_dt_attach(dns_dtenv_t *source, dns_dtenv_t **destp); +/*%< + * Attach '*destp' to 'source', incrementing the reference counter. + * + * Requires: + * + *\li 'source' is a valid dnstap environment. + * + *\li 'destp' is not NULL and '*destp' is NULL. + * + *\li *destp is attached to source. + */ + +void +dns_dt_detach(dns_dtenv_t **envp); +/*%< + * Detach '*envp', decrementing the reference counter. + * + * Requires: + * + *\li '*envp' is a valid dnstap environment. + * + * Ensures: + * + *\li '*envp' will be destroyed when the number of references reaches zero. + * + *\li '*envp' is NULL. + */ + +isc_result_t +dns_dt_getstats(dns_dtenv_t *env, isc_stats_t **statsp); +/*%< + * Attach to the stats struct if it exists. + * + * Requires: + * + *\li 'env' is a valid dnstap environment. + * + *\li 'statsp' is non NULL and '*statsp' is NULL. + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li ISC_R_NOTFOUND + */ + +void +dns_dt_send(dns_view_t *view, dns_dtmsgtype_t msgtype, isc_sockaddr_t *qaddr, + isc_sockaddr_t *dstaddr, bool tcp, isc_region_t *zone, + isc_time_t *qtime, isc_time_t *rtime, isc_buffer_t *buf); +/*%< + * Sends a dnstap message to the log, if 'msgtype' is one of the message + * types represented in 'view->dttypes'. + * + * Parameters are: 'qaddr' (query address, i.e, the address of the + * query initiator); 'raddr' (response address, i.e., the address of + * the query responder); 'tcp' (boolean indicating whether the transaction + * was over TCP); 'zone' (the authoritative zone or bailiwick, in + * uncompressed wire format), 'qtime' and 'rtime' (query and response + * times; if NULL, they are set to the current time); and 'buf' (the + * DNS message being logged, in wire format). + * + * Requires: + * + *\li 'view' is a valid view, and 'view->dtenv' is NULL or is a + * valid dnstap environment. + */ + +isc_result_t +dns_dt_parse(isc_mem_t *mctx, isc_region_t *src, dns_dtdata_t **destp); +/*%< + * Converts a raw dnstap frame in 'src' to a parsed dnstap data structure + * in '*destp'. + * + * Requires: + *\li 'src' is not NULL + * + *\li 'destp' is not NULL and '*destp' points to a valid buffer. + * + * Returns: + *\li #ISC_R_SUCCESS on success + * + *\li Other errors are possible. + */ + +isc_result_t +dns_dt_datatotext(dns_dtdata_t *d, isc_buffer_t **dest); +/*%< + * Converts a parsed dnstap data structure 'd' to text, storing + * the result in the buffer 'dest'. If 'dest' points to a dynamically + * allocated buffer, then it may be reallocated as needed. + * + * (XXX: add a 'long_form' option to generate a detailed listing of + * dnstap data instead * of a one-line summary.) + * + * Requires: + *\li 'd' is not NULL + * + *\li 'dest' is not NULL and '*dest' points to a valid buffer. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #ISC_R_NOSPACE if buffer is not dynamic and runs out of space + *\li #ISC_R_NOMEMORY if buffer is dynamic but memory could not be allocated + * + *\li Other errors are possible. + */ + +void +dns_dtdata_free(dns_dtdata_t **dp); +/*%< + * Frees the specified dns_dtdata structure and all its members, + * and sets *dp to NULL. + */ + +isc_result_t +dns_dt_open(const char *filename, dns_dtmode_t mode, isc_mem_t *mctx, + dns_dthandle_t **handlep); +/*%< + * Opens a dnstap framestream at 'filename' and stores a pointer to the + * reader object in a dns_dthandle_t structure. + * + * The caller is responsible for allocating the handle structure. + * + * (XXX: Currently only file readers are supported, not unix-domain socket + * readers.) + * + * Requires: + * + *\li 'filename' is not NULL. + * + *\li 'handlep' is not NULL and '*handlep' is NULL. + * + *\li '*mctx' is not a valid memory context. + * + * Returns: + * + *\li #ISC_R_SUCCESS on success + *\li #ISC_R_NOTIMPLEMENTED if 'mode' is not dns_dtmode_file. (XXX) + *\li #ISC_R_NOMEMORY if the fstrm library was unable to allocate a + * reader or options structure + *\li #ISC_R_FAILURE if 'filename' could not be opened. + *\li #DNS_R_BADDNSTAP if 'filename' does not contain a dnstap + * framestream. + */ + +isc_result_t +dns_dt_getframe(dns_dthandle_t *handle, uint8_t **bufp, size_t *sizep); +/*%< + * Read a dnstap frame from the framstream reader in 'handle', storing + * a pointer to it in '*bufp' and its size in '*sizep'. + * + * Requires: + * + *\li 'handle' is not NULL + *\li 'bufp' is not NULL + *\li 'sizep' is not NULL + * + * Ensures: + * \li if returning ISC_R_SUCCESS then '*bufp' is not NULL + * + * Returns: + * + *\li #ISC_R_SUCCESS on success + *\li #ISC_R_NOMORE at the end of the frame stream + *\li #ISC_R_FAILURE for any other failure + */ + +void +dns_dt_close(dns_dthandle_t **handlep); +/*%< + * Closes the dnstap file referenced by 'handle'. + * + * Requires: + * + *\li '*handlep' is not NULL + */ + +#endif /* _DNSTAP_H */ diff --git a/lib/dns/include/dns/ds.h b/lib/dns/include/dns/ds.h new file mode 100644 index 0000000..6e02d4c --- /dev/null +++ b/lib/dns/include/dns/ds.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#ifndef DNS_DS_H +#define DNS_DS_H 1 + +#include <isc/lang.h> + +#include <dns/rdatastruct.h> +#include <dns/types.h> + +#define DNS_DSDIGEST_SHA1 (1) +#define DNS_DSDIGEST_SHA256 (2) +#define DNS_DSDIGEST_GOST (3) +#define DNS_DSDIGEST_SHA384 (4) + +/* + * Assuming SHA-384 digest type. + */ +#define DNS_DS_BUFFERSIZE (52) + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_ds_fromkeyrdata(const dns_name_t *owner, dns_rdata_t *key, + dns_dsdigest_t digest_type, unsigned char *digest, + dns_rdata_ds_t *dsrdata); +/*%< + * Build a DS rdata structure from a key. + * + * Requires: + *\li key Points to a valid DNSKEY or CDNSKEY record. + *\li buffer Points to a buffer of at least + * #ISC_MAX_MD_SIZE bytes. + */ + +isc_result_t +dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, + dns_dsdigest_t digest_type, unsigned char *buffer, + dns_rdata_t *rdata); +/*%< + * Similar to dns_ds_fromkeyrdata(), but copies the DS into a + * dns_rdata object. + * + * Requires: + *\li key Points to a valid DNSKEY or CDNSKEY record. + *\li buffer Points to a buffer of at least + * #DNS_DS_BUFFERSIZE bytes. + *\li rdata Points to an initialized dns_rdata_t. + * + * Ensures: + * \li *rdata Contains a valid DS rdata. The 'data' member refers + * to 'buffer'. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_DS_H */ diff --git a/lib/dns/include/dns/dsdigest.h b/lib/dns/include/dns/dsdigest.h new file mode 100644 index 0000000..b466fed --- /dev/null +++ b/lib/dns/include/dns/dsdigest.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. + */ + +#ifndef DNS_DSDIGEST_H +#define DNS_DSDIGEST_H 1 + +/*! \file dns/dsdigest.h */ + +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_dsdigest_fromtext(dns_dsdigest_t *dsdigestp, isc_textregion_t *source); +/*%< + * Convert the text 'source' refers to into a DS digest type value. + * The text may contain either a mnemonic digest name or a decimal + * digest number. + * + * Requires: + *\li 'dsdigestp' is a valid pointer. + * + *\li 'source' is a valid text region. + * + * Returns: + *\li ISC_R_SUCCESS on success + *\li ISC_R_RANGE numeric type is out of range + *\li DNS_R_UNKNOWN mnemonic type is unknown + */ + +isc_result_t +dns_dsdigest_totext(dns_dsdigest_t dsdigest, isc_buffer_t *target); +/*%< + * Put a textual representation of the DS digest type 'dsdigest' + * into 'target'. + * + * Requires: + *\li 'dsdigest' is a valid dsdigest. + * + *\li 'target' is a valid text buffer. + * + * Ensures, + * if the result is success: + *\li The used space in 'target' is updated. + * + * Returns: + *\li ISC_R_SUCCESS on success + *\li ISC_R_NOSPACE target buffer is too small + */ + +#define DNS_DSDIGEST_FORMATSIZE 20 +void +dns_dsdigest_format(dns_dsdigest_t typ, char *cp, unsigned int size); +/*%< + * Wrapper for dns_dsdigest_totext(), writing text into 'cp' + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_DSDIGEST_H */ diff --git a/lib/dns/include/dns/dyndb.h b/lib/dns/include/dns/dyndb.h new file mode 100644 index 0000000..cc2820a --- /dev/null +++ b/lib/dns/include/dns/dyndb.h @@ -0,0 +1,162 @@ +/* + * 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. + */ + +#ifndef DNS_DYNDB_H +#define DNS_DYNDB_H + +#include <stdbool.h> + +#include <isc/types.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/*! + * \brief + * Context for initializing a dyndb module. + * + * This structure passes global server data to which a dyndb + * module will need access -- the server memory context, hash + * initializer, log context, etc. The structure doesn't persist + * beyond configuring the dyndb module. The module's register function + * should attach to all reference-counted variables and its destroy + * function should detach from them. + */ +struct dns_dyndbctx { + unsigned int magic; + const void *hashinit; + isc_mem_t *mctx; + isc_log_t *lctx; + dns_view_t *view; + dns_zonemgr_t *zmgr; + isc_task_t *task; + isc_timermgr_t *timermgr; + unsigned int *memdebug; +}; + +#define DNS_DYNDBCTX_MAGIC ISC_MAGIC('D', 'd', 'b', 'c') +#define DNS_DYNDBCTX_VALID(d) ISC_MAGIC_VALID(d, DNS_DYNDBCTX_MAGIC) + +/* + * API version + * + * When the API changes, increment DNS_DYNDB_VERSION. If the + * change is backward-compatible (e.g., adding a new function call + * but not changing or removing an old one), increment DNS_DYNDB_AGE; + * if not, set DNS_DYNDB_AGE to 0. + */ +#ifndef DNS_DYNDB_VERSION +#define DNS_DYNDB_VERSION 1 +#define DNS_DYNDB_AGE 0 +#endif /* ifndef DNS_DYNDB_VERSION */ + +typedef isc_result_t +dns_dyndb_register_t(isc_mem_t *mctx, const char *name, const char *parameters, + const char *file, unsigned long line, + const dns_dyndbctx_t *dctx, void **instp); +/*% + * Called when registering a new driver instance. 'name' must be unique. + * 'parameters' contains the driver configuration text. 'dctx' is the + * initialization context set up in dns_dyndb_createctx(). + * + * '*instp' will be set to the driver instance handle if the function + * is successful. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li Other errors are possible + */ + +typedef void +dns_dyndb_destroy_t(void **instp); +/*% + * Destroy a driver instance. Dereference any reference-counted + * variables passed in 'dctx' and 'inst' in the register function. + * + * \c *instp must be set to \c NULL by the function before it returns. + */ + +typedef int +dns_dyndb_version_t(unsigned int *flags); +/*% + * Return the API version number a dyndb module was compiled with. + * + * If the returned version number is no greater than than + * DNS_DYNDB_VERSION, and no less than DNS_DYNDB_VERSION - DNS_DYNDB_AGE, + * then the module is API-compatible with named. + * + * 'flags' is currently unused and may be NULL, but could be used in + * the future to pass back driver capabilities or other information. + */ + +isc_result_t +dns_dyndb_load(const char *libname, const char *name, const char *parameters, + const char *file, unsigned long line, isc_mem_t *mctx, + const dns_dyndbctx_t *dctx); +/*% + * Load a dyndb module. + * + * This loads a dyndb module using dlopen() or equivalent, calls its register + * function (see dns_dyndb_register_t above), and if successful, adds + * the instance handle to a list of dyndb instances so it can be cleaned + * up later. + * + * 'file' and 'line' can be used to indicate the name of the file and + * the line number from which the parameters were taken, so that logged + * error messages, if any, will display the correct locations. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li Other errors are possible + */ + +void +dns_dyndb_cleanup(bool exiting); +/*% + * Shut down and destroy all running dyndb modules. + * + * 'exiting' indicates whether the server is shutting down, + * as opposed to merely being reconfigured. + */ + +isc_result_t +dns_dyndb_createctx(isc_mem_t *mctx, const void *hashinit, isc_log_t *lctx, + dns_view_t *view, dns_zonemgr_t *zmgr, isc_task_t *task, + isc_timermgr_t *tmgr, dns_dyndbctx_t **dctxp); +/*% + * Create a dyndb initialization context structure, with + * pointers to structures in the server that the dyndb module will + * need to access (view, zone manager, memory context, hash initializer, + * etc). This structure is expected to last only until all dyndb + * modules have been loaded and initialized; after that it will be + * destroyed with dns_dyndb_destroyctx(). + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li Other errors are possible + */ + +void +dns_dyndb_destroyctx(dns_dyndbctx_t **dctxp); +/*% + * Destroys a dyndb initialization context structure; all + * reference-counted members are detached and the structure is freed. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_DYNDB_H */ diff --git a/lib/dns/include/dns/ecdb.h b/lib/dns/include/dns/ecdb.h new file mode 100644 index 0000000..d94cbac --- /dev/null +++ b/lib/dns/include/dns/ecdb.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#ifndef DNS_ECDB_H +#define DNS_ECDB_H 1 + +/***** +***** Module Info +*****/ + +/* TBD */ + +/*** + *** Imports + ***/ + +#include <dns/types.h> + +/*** + *** Types + ***/ + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +/* TBD: describe those */ + +isc_result_t +dns_ecdb_register(isc_mem_t *mctx, dns_dbimplementation_t **dbimp); + +void +dns_ecdb_unregister(dns_dbimplementation_t **dbimp); + +ISC_LANG_ENDDECLS + +#endif /* DNS_ECDB_H */ diff --git a/lib/dns/include/dns/ecs.h b/lib/dns/include/dns/ecs.h new file mode 100644 index 0000000..b4b0d6b --- /dev/null +++ b/lib/dns/include/dns/ecs.h @@ -0,0 +1,84 @@ +/* + * 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. + */ + +#ifndef DNS_ECS_H +#define DNS_ECS_H 1 + +#include <inttypes.h> + +#include <isc/lang.h> +#include <isc/netaddr.h> +#include <isc/types.h> + +#include <dns/rdatatype.h> +#include <dns/types.h> + +/*% + * Maximum scope values for IPv4 and IPv6. + */ +#ifndef ECS_MAX_V4_SCOPE +#define ECS_MAX_V4_SCOPE 24 +#endif + +#ifndef ECS_MAX_V6_SCOPE +#define ECS_MAX_V6_SCOPE 56 +#endif + +/* + * Any updates to this structure should also be applied in + * contrib/modules/dlz/dlz_minmal.h. + */ +struct dns_ecs { + isc_netaddr_t addr; + uint8_t source; + uint8_t scope; +}; + +/* <address>/NNN/NNN */ +#define DNS_ECS_FORMATSIZE (ISC_NETADDR_FORMATSIZE + 9) + +ISC_LANG_BEGINDECLS + +void +dns_ecs_init(dns_ecs_t *ecs); +/*%< + * Initialize a DNS ECS structure. + * + * Requires: + * \li 'ecs' is not NULL and points to a valid dns_ecs structure. + */ + +bool +dns_ecs_equals(const dns_ecs_t *ecs1, const dns_ecs_t *ecs2); +/*%< + * Determine whether two ECS address prefixes are equal (except the + * scope prefix-length field). + * + * 'ecs1->source' must exactly match 'ecs2->source'; the address families + * must match; and the first 'ecs1->source' bits of the addresses must + * match. Subsequent address bits and the 'scope' values are ignored. + */ + +void +dns_ecs_format(const dns_ecs_t *ecs, char *buf, size_t size); +/*%< + * Format an ECS record as text. Result is guaranteed to be null-terminated. + * + * Requires: + * \li 'ecs' is not NULL. + * \li 'buf' is not NULL. + * \li 'size' is at least DNS_ECS_FORMATSIZE + */ +ISC_LANG_ENDDECLS + +#endif /* DNS_ECS_H */ diff --git a/lib/dns/include/dns/edns.h b/lib/dns/include/dns/edns.h new file mode 100644 index 0000000..214abe8 --- /dev/null +++ b/lib/dns/include/dns/edns.h @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#ifndef DNS_EDNS_H +#define DNS_EDNS_H 1 + +/*% + * The maximum version on EDNS supported by this build. + */ +#define DNS_EDNS_VERSION 0 +#ifdef DRAFT_ANDREWS_EDNS1 +#undef DNS_EDNS_VERSION +/* + * Warning: this currently disables sending COOKIE requests in resolver.c + */ +#define DNS_EDNS_VERSION 1 /* draft-andrews-edns1 */ +#endif /* ifdef DRAFT_ANDREWS_EDNS1 */ + +#endif /* ifndef DNS_EDNS_H */ diff --git a/lib/dns/include/dns/events.h b/lib/dns/include/dns/events.h new file mode 100644 index 0000000..608f35f --- /dev/null +++ b/lib/dns/include/dns/events.h @@ -0,0 +1,90 @@ +/* + * 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. + */ + +#ifndef DNS_EVENTS_H +#define DNS_EVENTS_H 1 + +#include <isc/eventclass.h> + +/*! \file dns/events.h + * \brief + * Registry of DNS event numbers. + */ + +#define DNS_EVENT_FETCHCONTROL (ISC_EVENTCLASS_DNS + 0) +#define DNS_EVENT_FETCHDONE (ISC_EVENTCLASS_DNS + 1) +#define DNS_EVENT_VIEWRESSHUTDOWN (ISC_EVENTCLASS_DNS + 2) +#define DNS_EVENT_VIEWADBSHUTDOWN (ISC_EVENTCLASS_DNS + 3) +#define DNS_EVENT_UPDATE (ISC_EVENTCLASS_DNS + 4) +#define DNS_EVENT_UPDATEDONE (ISC_EVENTCLASS_DNS + 5) +#define DNS_EVENT_DISPATCH (ISC_EVENTCLASS_DNS + 6) +#define DNS_EVENT_TCPMSG (ISC_EVENTCLASS_DNS + 7) +#define DNS_EVENT_ADBMOREADDRESSES (ISC_EVENTCLASS_DNS + 8) +#define DNS_EVENT_ADBNOMOREADDRESSES (ISC_EVENTCLASS_DNS + 9) +#define DNS_EVENT_ADBCANCELED (ISC_EVENTCLASS_DNS + 10) +#define DNS_EVENT_ADBNAMEDELETED (ISC_EVENTCLASS_DNS + 11) +#define DNS_EVENT_ADBSHUTDOWN (ISC_EVENTCLASS_DNS + 12) +#define DNS_EVENT_ADBEXPIRED (ISC_EVENTCLASS_DNS + 13) +#define DNS_EVENT_ADBCONTROL (ISC_EVENTCLASS_DNS + 14) +#define DNS_EVENT_CACHECLEAN (ISC_EVENTCLASS_DNS + 15) +#define DNS_EVENT_BYADDRDONE (ISC_EVENTCLASS_DNS + 16) +#define DNS_EVENT_ZONECONTROL (ISC_EVENTCLASS_DNS + 17) +#define DNS_EVENT_DBDESTROYED (ISC_EVENTCLASS_DNS + 18) +#define DNS_EVENT_VALIDATORDONE (ISC_EVENTCLASS_DNS + 19) +#define DNS_EVENT_REQUESTDONE (ISC_EVENTCLASS_DNS + 20) +#define DNS_EVENT_VALIDATORSTART (ISC_EVENTCLASS_DNS + 21) +#define DNS_EVENT_VIEWREQSHUTDOWN (ISC_EVENTCLASS_DNS + 22) +#define DNS_EVENT_NOTIFYSENDTOADDR (ISC_EVENTCLASS_DNS + 23) +#define DNS_EVENT_ZONE (ISC_EVENTCLASS_DNS + 24) +#define DNS_EVENT_ZONESTARTXFRIN (ISC_EVENTCLASS_DNS + 25) +#define DNS_EVENT_MASTERQUANTUM (ISC_EVENTCLASS_DNS + 26) +#define DNS_EVENT_CACHEOVERMEM (ISC_EVENTCLASS_DNS + 27) +#define DNS_EVENT_MASTERNEXTZONE (ISC_EVENTCLASS_DNS + 28) +#define DNS_EVENT_IOREADY (ISC_EVENTCLASS_DNS + 29) +#define DNS_EVENT_LOOKUPDONE (ISC_EVENTCLASS_DNS + 30) +#define DNS_EVENT_RBTDEADNODES (ISC_EVENTCLASS_DNS + 31) +#define DNS_EVENT_DISPATCHCONTROL (ISC_EVENTCLASS_DNS + 32) +#define DNS_EVENT_REQUESTCONTROL (ISC_EVENTCLASS_DNS + 33) +#define DNS_EVENT_DUMPQUANTUM (ISC_EVENTCLASS_DNS + 34) +#define DNS_EVENT_IMPORTRECVDONE (ISC_EVENTCLASS_DNS + 35) +#define DNS_EVENT_FREESTORAGE (ISC_EVENTCLASS_DNS + 36) +#define DNS_EVENT_VIEWACACHESHUTDOWN (ISC_EVENTCLASS_DNS + 37) +#define DNS_EVENT_ACACHECONTROL (ISC_EVENTCLASS_DNS + 38) +#define DNS_EVENT_ACACHECLEAN (ISC_EVENTCLASS_DNS + 39) +#define DNS_EVENT_ACACHEOVERMEM (ISC_EVENTCLASS_DNS + 40) +#define DNS_EVENT_RBTPRUNE (ISC_EVENTCLASS_DNS + 41) +#define DNS_EVENT_MANAGEKEYS (ISC_EVENTCLASS_DNS + 42) +#define DNS_EVENT_CLIENTRESDONE (ISC_EVENTCLASS_DNS + 43) +#define DNS_EVENT_CLIENTREQDONE (ISC_EVENTCLASS_DNS + 44) +#define DNS_EVENT_ADBGROWENTRIES (ISC_EVENTCLASS_DNS + 45) +#define DNS_EVENT_ADBGROWNAMES (ISC_EVENTCLASS_DNS + 46) +#define DNS_EVENT_ZONESECURESERIAL (ISC_EVENTCLASS_DNS + 47) +#define DNS_EVENT_ZONESECUREDB (ISC_EVENTCLASS_DNS + 48) +#define DNS_EVENT_ZONELOAD (ISC_EVENTCLASS_DNS + 49) +#define DNS_EVENT_KEYDONE (ISC_EVENTCLASS_DNS + 50) +#define DNS_EVENT_SETNSEC3PARAM (ISC_EVENTCLASS_DNS + 51) +#define DNS_EVENT_SETSERIAL (ISC_EVENTCLASS_DNS + 52) +#define DNS_EVENT_CATZUPDATED (ISC_EVENTCLASS_DNS + 53) +#define DNS_EVENT_CATZADDZONE (ISC_EVENTCLASS_DNS + 54) +#define DNS_EVENT_CATZMODZONE (ISC_EVENTCLASS_DNS + 55) +#define DNS_EVENT_CATZDELZONE (ISC_EVENTCLASS_DNS + 56) +#define DNS_EVENT_RPZUPDATED (ISC_EVENTCLASS_DNS + 57) +#define DNS_EVENT_STARTUPDATE (ISC_EVENTCLASS_DNS + 58) +#define DNS_EVENT_TRYSTALE (ISC_EVENTCLASS_DNS + 59) +#define DNS_EVENT_ZONEFLUSH (ISC_EVENTCLASS_DNS + 60) +#define DNS_EVENT_CHECKDSSENDTOADDR (ISC_EVENTCLASS_DNS + 61) + +#define DNS_EVENT_FIRSTEVENT (ISC_EVENTCLASS_DNS + 0) +#define DNS_EVENT_LASTEVENT (ISC_EVENTCLASS_DNS + 65535) + +#endif /* DNS_EVENTS_H */ diff --git a/lib/dns/include/dns/fixedname.h b/lib/dns/include/dns/fixedname.h new file mode 100644 index 0000000..edd55f4 --- /dev/null +++ b/lib/dns/include/dns/fixedname.h @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#ifndef DNS_FIXEDNAME_H +#define DNS_FIXEDNAME_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/fixedname.h + * \brief + * Fixed-size Names + * + * dns_fixedname_t is a convenience type containing a name, an offsets + * table, and a dedicated buffer big enough for the longest possible + * name. This is typically used for stack-allocated names. + * + * MP: + *\li The caller must ensure any required synchronization. + * + * Reliability: + *\li No anticipated impact. + * + * Resources: + *\li Per dns_fixedname_t: + *\code + * sizeof(dns_name_t) + sizeof(dns_offsets_t) + + * sizeof(isc_buffer_t) + 255 bytes + structure padding + *\endcode + * + * Security: + *\li No anticipated impact. + * + * Standards: + *\li None. + */ + +/***** +***** Imports +*****/ + +#include <isc/buffer.h> +#include <isc/lang.h> + +#include <dns/name.h> + +/***** +***** Types +*****/ + +struct dns_fixedname { + dns_name_t name; + dns_offsets_t offsets; + isc_buffer_t buffer; + unsigned char data[DNS_NAME_MAXWIRE]; +}; + +ISC_LANG_BEGINDECLS + +void +dns_fixedname_init(dns_fixedname_t *fixed); + +void +dns_fixedname_invalidate(dns_fixedname_t *fixed); + +dns_name_t * +dns_fixedname_name(dns_fixedname_t *fixed); + +dns_name_t * +dns_fixedname_initname(dns_fixedname_t *fixed); + +ISC_LANG_ENDDECLS + +#endif /* DNS_FIXEDNAME_H */ diff --git a/lib/dns/include/dns/forward.h b/lib/dns/include/dns/forward.h new file mode 100644 index 0000000..12430c3 --- /dev/null +++ b/lib/dns/include/dns/forward.h @@ -0,0 +1,124 @@ +/* + * 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. + */ + +#ifndef DNS_FORWARD_H +#define DNS_FORWARD_H 1 + +/*! \file dns/forward.h */ + +#include <isc/lang.h> +#include <isc/result.h> +#include <isc/sockaddr.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +struct dns_forwarder { + isc_sockaddr_t addr; + isc_dscp_t dscp; + ISC_LINK(dns_forwarder_t) link; +}; + +typedef ISC_LIST(struct dns_forwarder) dns_forwarderlist_t; + +struct dns_forwarders { + dns_forwarderlist_t fwdrs; + dns_fwdpolicy_t fwdpolicy; +}; + +isc_result_t +dns_fwdtable_create(isc_mem_t *mctx, dns_fwdtable_t **fwdtablep); +/*%< + * Creates a new forwarding table. + * + * Requires: + * \li mctx is a valid memory context. + * \li fwdtablep != NULL && *fwdtablep == NULL + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + */ + +isc_result_t +dns_fwdtable_addfwd(dns_fwdtable_t *fwdtable, const dns_name_t *name, + dns_forwarderlist_t *fwdrs, dns_fwdpolicy_t policy); +isc_result_t +dns_fwdtable_add(dns_fwdtable_t *fwdtable, const dns_name_t *name, + isc_sockaddrlist_t *addrs, dns_fwdpolicy_t policy); +/*%< + * Adds an entry to the forwarding table. The entry associates + * a domain with a list of forwarders and a forwarding policy. The + * addrs/fwdrs list is copied if not empty, so the caller should free + * its copy. + * + * Requires: + * \li fwdtable is a valid forwarding table. + * \li name is a valid name + * \li addrs/fwdrs is a valid list of isc_sockaddr/dns_forwarder + * structures, which may be empty. + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + */ + +isc_result_t +dns_fwdtable_delete(dns_fwdtable_t *fwdtable, const dns_name_t *name); +/*%< + * Removes an entry for 'name' from the forwarding table. If an entry + * that exactly matches 'name' does not exist, ISC_R_NOTFOUND will be returned. + * + * Requires: + * \li fwdtable is a valid forwarding table. + * \li name is a valid name + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTFOUND + */ + +isc_result_t +dns_fwdtable_find(dns_fwdtable_t *fwdtable, const dns_name_t *name, + dns_name_t *foundname, dns_forwarders_t **forwardersp); +/*%< + * Finds a domain in the forwarding table. The closest matching parent + * domain is returned. + * + * Requires: + * \li fwdtable is a valid forwarding table. + * \li name is a valid name + * \li forwardersp != NULL && *forwardersp == NULL + * \li foundname to be NULL or a valid name with buffer. + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTFOUND + */ + +void +dns_fwdtable_destroy(dns_fwdtable_t **fwdtablep); +/*%< + * Destroys a forwarding table. + * + * Requires: + * \li fwtablep != NULL && *fwtablep != NULL + * + * Ensures: + * \li all memory associated with the forwarding table is freed. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_FORWARD_H */ diff --git a/lib/dns/include/dns/geoip.h b/lib/dns/include/dns/geoip.h new file mode 100644 index 0000000..721c297 --- /dev/null +++ b/lib/dns/include/dns/geoip.h @@ -0,0 +1,114 @@ +/* + * 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. + */ + +#ifndef DNS_GEOIP_H +#define DNS_GEOIP_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/geoip.h + * \brief + * GeoIP/GeoIP2 data types and function prototypes. + */ + +#if defined(HAVE_GEOIP2) + +/*** + *** Imports + ***/ + +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/netaddr.h> +#include <isc/refcount.h> + +#include <dns/iptable.h> +#include <dns/name.h> +#include <dns/types.h> + +/*** + *** Types + ***/ + +typedef enum { + dns_geoip_countrycode, + dns_geoip_countrycode3, + dns_geoip_countryname, + dns_geoip_continentcode, + dns_geoip_continent, + dns_geoip_region, + dns_geoip_regionname, + dns_geoip_country_code, + dns_geoip_country_code3, + dns_geoip_country_name, + dns_geoip_country_continentcode, + dns_geoip_country_continent, + dns_geoip_region_countrycode, + dns_geoip_region_code, + dns_geoip_region_name, + dns_geoip_city_countrycode, + dns_geoip_city_countrycode3, + dns_geoip_city_countryname, + dns_geoip_city_region, + dns_geoip_city_regionname, + dns_geoip_city_name, + dns_geoip_city_postalcode, + dns_geoip_city_metrocode, + dns_geoip_city_areacode, + dns_geoip_city_continentcode, + dns_geoip_city_continent, + dns_geoip_city_timezonecode, + dns_geoip_isp_name, + dns_geoip_org_name, + dns_geoip_as_asnum, + dns_geoip_domain_name, + dns_geoip_netspeed_id +} dns_geoip_subtype_t; + +typedef struct dns_geoip_elem { + dns_geoip_subtype_t subtype; + void *db; + union { + char as_string[256]; + int as_int; + }; +} dns_geoip_elem_t; + +struct dns_geoip_databases { + void *country; /* GeoIP2-Country or GeoLite2-Country */ + void *city; /* GeoIP2-CIty or GeoLite2-City */ + void *domain; /* GeoIP2-Domain */ + void *isp; /* GeoIP2-ISP */ + void *as; /* GeoIP2-ASN or GeoLite2-ASN */ +}; + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +bool +dns_geoip_match(const isc_netaddr_t *reqaddr, + const dns_geoip_databases_t *geoip, + const dns_geoip_elem_t *elt); + +ISC_LANG_ENDDECLS + +#endif /* HAVE_GEOIP2 */ + +#endif /* DNS_GEOIP_H */ diff --git a/lib/dns/include/dns/ipkeylist.h b/lib/dns/include/dns/ipkeylist.h new file mode 100644 index 0000000..b3dbfb6 --- /dev/null +++ b/lib/dns/include/dns/ipkeylist.h @@ -0,0 +1,90 @@ +/* + * 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. + */ + +#ifndef DNS_IPKEYLIST_H +#define DNS_IPKEYLIST_H 1 + +#include <inttypes.h> + +#include <isc/types.h> + +#include <dns/types.h> + +/*% + * A structure holding a list of addresses, dscps and keys. Used to + * store masters for a slave zone, created by parsing config options. + */ +struct dns_ipkeylist { + isc_sockaddr_t *addrs; + isc_dscp_t *dscps; + dns_name_t **keys; + dns_name_t **labels; + uint32_t count; + uint32_t allocated; +}; + +void +dns_ipkeylist_init(dns_ipkeylist_t *ipkl); +/*%< + * Reset ipkl to empty state + * + * Requires: + *\li 'ipkl' to be non NULL. + */ + +void +dns_ipkeylist_clear(isc_mem_t *mctx, dns_ipkeylist_t *ipkl); +/*%< + * Free `ipkl` contents using `mctx`. + * + * After this call, `ipkl` is a freshly cleared structure with all + * pointers set to `NULL` and count set to 0. + * + * Requires: + *\li 'mctx' to be a valid memory context. + *\li 'ipkl' to be non NULL. + */ + +isc_result_t +dns_ipkeylist_copy(isc_mem_t *mctx, const dns_ipkeylist_t *src, + dns_ipkeylist_t *dst); +/*%< + * Deep copy `src` into empty `dst`, allocating `dst`'s contents. + * + * Requires: + *\li 'mctx' to be a valid memory context. + *\li 'src' to be non NULL + *\li 'dst' to be non NULL and point to an empty \ref dns_ipkeylist_t + * with all pointers set to `NULL` and count set to 0. + * + * Returns: + *\li #ISC_R_SUCCESS -- success + *\li any other value -- failure + */ +isc_result_t +dns_ipkeylist_resize(isc_mem_t *mctx, dns_ipkeylist_t *ipkl, unsigned int n); +/*%< + * Resize ipkl to contain n elements. Size (count) is not changed, and the + * added space is zeroed. + * + * Requires: + * \li 'mctx' to be a valid memory context. + * \li 'ipk' to be non NULL + * \li 'n' >= ipkl->count + * + * Returns: + * \li #ISC_R_SUCCESS if success + * \li #ISC_R_NOMEMORY if there's no memory, ipkeylist is left untouched + */ + +#endif /* ifndef DNS_IPKEYLIST_H */ diff --git a/lib/dns/include/dns/iptable.h b/lib/dns/include/dns/iptable.h new file mode 100644 index 0000000..83ecf04 --- /dev/null +++ b/lib/dns/include/dns/iptable.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + +#ifndef DNS_IPTABLE_H +#define DNS_IPTABLE_H 1 + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/radix.h> + +#include <dns/types.h> + +struct dns_iptable { + unsigned int magic; + isc_mem_t *mctx; + isc_refcount_t refcount; + isc_radix_tree_t *radix; + ISC_LINK(dns_iptable_t) nextincache; +}; + +#define DNS_IPTABLE_MAGIC ISC_MAGIC('T', 'a', 'b', 'l') +#define DNS_IPTABLE_VALID(a) ISC_MAGIC_VALID(a, DNS_IPTABLE_MAGIC) + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_iptable_create(isc_mem_t *mctx, dns_iptable_t **target); +/* + * Create a new IP table and the underlying radix structure + */ + +isc_result_t +dns_iptable_addprefix(dns_iptable_t *tab, const isc_netaddr_t *addr, + uint16_t bitlen, bool pos); +/* + * Add an IP prefix to an existing IP table + */ + +isc_result_t +dns_iptable_merge(dns_iptable_t *tab, dns_iptable_t *source, bool pos); +/* + * Merge one IP table into another one. + */ + +void +dns_iptable_attach(dns_iptable_t *source, dns_iptable_t **target); + +void +dns_iptable_detach(dns_iptable_t **tabp); + +ISC_LANG_ENDDECLS + +#endif /* DNS_IPTABLE_H */ diff --git a/lib/dns/include/dns/journal.h b/lib/dns/include/dns/journal.h new file mode 100644 index 0000000..2b9875e --- /dev/null +++ b/lib/dns/include/dns/journal.h @@ -0,0 +1,341 @@ +/* + * 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. + */ + +#ifndef DNS_JOURNAL_H +#define DNS_JOURNAL_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/journal.h + * \brief + * Database journaling. + */ + +/*** + *** Imports + ***/ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/magic.h> + +#include <dns/diff.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/types.h> + +/*** + *** Defines. + ***/ +#define DNS_JOURNALOPT_RESIGN 0x00000001 + +#define DNS_JOURNAL_READ 0x00000000 /* false */ +#define DNS_JOURNAL_CREATE 0x00000001 /* true */ +#define DNS_JOURNAL_WRITE 0x00000002 + +#define DNS_JOURNAL_SIZE_MAX INT32_MAX +#define DNS_JOURNAL_SIZE_MIN 4096 + +/*% Print transaction header data */ +#define DNS_JOURNAL_PRINTXHDR 0x0001 + +/*% Rewrite whole journal file instead of compacting */ +#define DNS_JOURNAL_COMPACTALL 0x0001 +#define DNS_JOURNAL_VERSION1 0x0002 + +/*** + *** Types + ***/ + +/*% + * A dns_journal_t represents an open journal file. This is an opaque type. + * + * A particular dns_journal_t object may be opened for writing, in which case + * it can be used for writing transactions to a journal file, or it can be + * opened for reading, in which case it can be used for reading transactions + * from (iterating over) a journal file. A single dns_journal_t object may + * not be used for both purposes. + */ +typedef struct dns_journal dns_journal_t; + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +/**************************************************************************/ + +isc_result_t +dns_db_createsoatuple(dns_db_t *db, dns_dbversion_t *ver, isc_mem_t *mctx, + dns_diffop_t op, dns_difftuple_t **tp); +/*!< brief + * Create a diff tuple for the current database SOA. + * XXX this probably belongs somewhere else. + */ + +/*@{*/ +#define DNS_SERIAL_GT(a, b) ((int)(((a) - (b)) & 0xFFFFFFFF) > 0) +#define DNS_SERIAL_GE(a, b) ((int)(((a) - (b)) & 0xFFFFFFFF) >= 0) +/*!< brief + * Compare SOA serial numbers. DNS_SERIAL_GT(a, b) returns true iff + * a is "greater than" b where "greater than" is as defined in RFC1982. + * DNS_SERIAL_GE(a, b) returns true iff a is "greater than or equal to" b. + */ +/*@}*/ + +/**************************************************************************/ +/* + * Journal object creation and destruction. + */ + +isc_result_t +dns_journal_open(isc_mem_t *mctx, const char *filename, unsigned int mode, + dns_journal_t **journalp); +/*%< + * Open the journal file 'filename' and create a dns_journal_t object for it. + * + * DNS_JOURNAL_CREATE open the journal for reading and writing and create + * the journal if it does not exist. + * DNS_JOURNAL_WRITE open the journal for reading and writing. + * DNS_JOURNAL_READ open the journal for reading only. + */ + +void +dns_journal_destroy(dns_journal_t **journalp); +/*%< + * Destroy a dns_journal_t, closing any open files and freeing its memory. + */ + +/**************************************************************************/ +/* + * Writing transactions to journals. + */ + +isc_result_t +dns_journal_begin_transaction(dns_journal_t *j); +/*%< + * Prepare to write a new transaction to the open journal file 'j'. + * + * Requires: + * \li 'j' is open for writing. + */ + +isc_result_t +dns_journal_writediff(dns_journal_t *j, dns_diff_t *diff); +/*%< + * Write 'diff' to the current transaction of journal file 'j'. + * + * Requires: + * \li 'j' is open for writing and dns_journal_begin_transaction() + * has been called. + * + *\li 'diff' is a full or partial, correctly ordered IXFR + * difference sequence. + */ + +isc_result_t +dns_journal_commit(dns_journal_t *j); +/*%< + * Commit the current transaction of journal file 'j'. + * + * Requires: + * \li 'j' is open for writing and dns_journal_begin_transaction() + * has been called. + * + * \li dns_journal_writediff() has been called one or more times + * to form a complete, correctly ordered IXFR difference + * sequence. + */ + +isc_result_t +dns_journal_write_transaction(dns_journal_t *j, dns_diff_t *diff); +/*% + * Write a complete transaction at once to a journal file, + * sorting it if necessary, and commit it. Equivalent to calling + * dns_diff_sort(), dns_journal_begin_transaction(), + * dns_journal_writediff(), and dns_journal_commit(). + * + * Requires: + *\li 'j' is open for writing. + * + * \li 'diff' contains exactly one SOA deletion, one SOA addition + * with a greater serial number, and possibly other changes, + * in arbitrary order. + */ + +/**************************************************************************/ +/* + * Reading transactions from journals. + */ + +bool +dns_journal_empty(dns_journal_t *j); +/*< + * Find out if a journal is empty. + */ + +bool +dns_journal_recovered(dns_journal_t *j); +/*< + * Find out if the journal could be opened using old journal format + */ + +uint32_t +dns_journal_first_serial(dns_journal_t *j); +uint32_t +dns_journal_last_serial(dns_journal_t *j); +/*%< + * Get the first and last addressable serial number in the journal. + */ + +isc_result_t +dns_journal_iter_init(dns_journal_t *j, uint32_t begin_serial, + uint32_t end_serial, size_t *xfrsizep); +/*%< + * Prepare to iterate over the transactions that will bring the database + * from SOA serial number 'begin_serial' to 'end_serial'. + * + * If 'xfrsizep' is not NULL, then on success it will be set to the + * total size of all records in the iteration (excluding headers). This + * is meant to be a rough approximation of the size of an incremental + * zone transfer, though it does not account for DNS message overhead + * or name compression.) + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_RANGE begin_serial is outside the addressable range. + *\li ISC_R_NOTFOUND begin_serial is within the range of addressable + * serial numbers covered by the journal, but + * this particular serial number does not exist. + */ + +/*@{*/ +isc_result_t +dns_journal_first_rr(dns_journal_t *j); +isc_result_t +dns_journal_next_rr(dns_journal_t *j); +/*%< + * Position the iterator at the first/next RR in a journal + * transaction sequence established using dns_journal_iter_init(). + * + * Requires: + * \li dns_journal_iter_init() has been called. + * + */ +/*@}*/ + +void +dns_journal_current_rr(dns_journal_t *j, dns_name_t **name, uint32_t *ttl, + dns_rdata_t **rdata); +/*%< + * Get the name, ttl, and rdata of the current journal RR. + * + * Requires: + * \li The last call to dns_journal_first_rr() or dns_journal_next_rr() + * returned ISC_R_SUCCESS. + */ + +/**************************************************************************/ +/* + * Database roll-forward. + */ + +isc_result_t +dns_journal_rollforward(dns_journal_t *j, dns_db_t *db, unsigned int options); +/*%< + * Roll forward (play back) the journal file "filename" into the + * database "db". This should be called when the server starts + * after a shutdown or crash. + * + * Requires: + *\li 'journal' is a valid journal + *\li 'db' is a valid database which does not have a version + * open for writing. + * + * Returns: + *\li ISC_R_NOTFOUND when current serial in not in journal. + *\li ISC_R_RANGE when current serial in not in journals range. + *\li DNS_R_UPTODATE when the database was already up to date. + *\li ISC_R_SUCCESS journal has been applied successfully to the + * database without any issues. + * + * others + */ + +isc_result_t +dns_journal_print(isc_mem_t *mctx, uint32_t flags, const char *filename, + FILE *file); +/* For debugging not general use */ + +isc_result_t +dns_db_diff(isc_mem_t *mctx, dns_db_t *dba, dns_dbversion_t *dbvera, + dns_db_t *dbb, dns_dbversion_t *dbverb, + const char *journal_filename); + +isc_result_t +dns_db_diffx(dns_diff_t *diff, dns_db_t *dba, dns_dbversion_t *dbvera, + dns_db_t *dbb, dns_dbversion_t *dbverb, + const char *journal_filename); +/*%< + * Compare the databases 'dba' and 'dbb' and generate a diff/journal + * entry containing the changes to make 'dba' from 'dbb' (note + * the order). This journal entry will consist of a single, + * possibly very large transaction. Append the journal + * entry to the journal file specified by 'journal_filename' if + * non-NULL. + */ + +isc_result_t +dns_journal_compact(isc_mem_t *mctx, char *filename, uint32_t serial, + uint32_t flags, uint32_t target_size); +/*%< + * Attempt to compact the journal if it is greater that 'target_size'. + * Changes from 'serial' onwards will be preserved. Changes prior than + * that may be dropped in order to get the journal below `target_size`. + * + * If 'flags' includes DNS_JOURNAL_COMPACTALL, the entire journal is copied. + * In this case, `serial` is ignored. This flag is used when upgrading or + * downgrading the format version of the journal. If 'flags' also includes + * DNS_JOURNAL_VERSION1, then the journal is copied out in the original + * format used prior to BIND 9.16.12; otherwise it is copied in the + * current format. + * + * If _COMPACTALL is not in use, and the journal file exists and is + * non-empty, then 'serial' must exist in the journal. + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_RANGE serial is outside the range existing in the journal + * + * Other errors may be returned from file operations. + */ + +bool +dns_journal_get_sourceserial(dns_journal_t *j, uint32_t *sourceserial); +void +dns_journal_set_sourceserial(dns_journal_t *j, uint32_t sourceserial); +/*%< + * Get and set source serial. + * + * Returns: + * true if sourceserial has previously been set. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_JOURNAL_H */ diff --git a/lib/dns/include/dns/kasp.h b/lib/dns/include/dns/kasp.h new file mode 100644 index 0000000..48d773a --- /dev/null +++ b/lib/dns/include/dns/kasp.h @@ -0,0 +1,717 @@ +/* + * 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. + */ + +#ifndef DNS_KASP_H +#define DNS_KASP_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/kasp.h + * \brief + * DNSSEC Key and Signing Policy (KASP) + * + * A "kasp" is a DNSSEC policy, that determines how a zone should be + * signed and maintained. + */ + +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/mutex.h> +#include <isc/refcount.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/* Stores a KASP key */ +struct dns_kasp_key { + isc_mem_t *mctx; + + /* Locked by themselves. */ + isc_refcount_t references; + + /* Under owner's locking control. */ + ISC_LINK(struct dns_kasp_key) link; + + /* Configuration */ + uint32_t lifetime; + uint8_t algorithm; + int length; + uint8_t role; +}; + +struct dns_kasp_nsec3param { + uint8_t saltlen; + uint8_t algorithm; + uint8_t iterations; + bool optout; +}; + +/* Stores a DNSSEC policy */ +struct dns_kasp { + unsigned int magic; + isc_mem_t *mctx; + char *name; + + /* Internals. */ + isc_mutex_t lock; + bool frozen; + + /* Locked by themselves. */ + isc_refcount_t references; + + /* Under owner's locking control. */ + ISC_LINK(struct dns_kasp) link; + + /* Configuration: signatures */ + uint32_t signatures_refresh; + uint32_t signatures_validity; + uint32_t signatures_validity_dnskey; + + /* Configuration: Keys */ + dns_kasp_keylist_t keys; + dns_ttl_t dnskey_ttl; + + /* Configuration: Denial of existence */ + bool nsec3; + dns_kasp_nsec3param_t nsec3param; + + /* Configuration: Timings */ + uint32_t publish_safety; + uint32_t retire_safety; + uint32_t purge_keys; + + /* Zone settings */ + dns_ttl_t zone_max_ttl; + uint32_t zone_propagation_delay; + + /* Parent settings */ + dns_ttl_t parent_ds_ttl; + uint32_t parent_propagation_delay; +}; + +#define DNS_KASP_MAGIC ISC_MAGIC('K', 'A', 'S', 'P') +#define DNS_KASP_VALID(kasp) ISC_MAGIC_VALID(kasp, DNS_KASP_MAGIC) + +/* Defaults */ +#define DNS_KASP_SIG_REFRESH (86400 * 5) +#define DNS_KASP_SIG_VALIDITY (86400 * 14) +#define DNS_KASP_SIG_VALIDITY_DNSKEY (86400 * 14) +#define DNS_KASP_KEY_TTL (3600) +#define DNS_KASP_DS_TTL (86400) +#define DNS_KASP_PUBLISH_SAFETY (3600) +#define DNS_KASP_PURGE_KEYS (86400 * 90) +#define DNS_KASP_RETIRE_SAFETY (3600) +#define DNS_KASP_ZONE_MAXTTL (86400) +#define DNS_KASP_ZONE_PROPDELAY (300) +#define DNS_KASP_PARENT_PROPDELAY (3600) + +/* Key roles */ +#define DNS_KASP_KEY_ROLE_KSK 0x01 +#define DNS_KASP_KEY_ROLE_ZSK 0x02 + +isc_result_t +dns_kasp_create(isc_mem_t *mctx, const char *name, dns_kasp_t **kaspp); +/*%< + * Create a KASP. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li 'name' is a valid C string. + * + *\li kaspp != NULL && *kaspp == NULL + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + * + *\li Other errors are possible. + */ + +void +dns_kasp_attach(dns_kasp_t *source, dns_kasp_t **targetp); +/*%< + * Attach '*targetp' to 'source'. + * + * Requires: + * + *\li 'source' is a valid, frozen kasp. + * + *\li 'targetp' points to a NULL dns_kasp_t *. + * + * Ensures: + * + *\li *targetp is attached to source. + * + *\li While *targetp is attached, the kasp will not shut down. + */ + +void +dns_kasp_detach(dns_kasp_t **kaspp); +/*%< + * Detach KASP. + * + * Requires: + * + *\li 'kaspp' points to a valid dns_kasp_t * + * + * Ensures: + * + *\li *kaspp is NULL. + */ + +void +dns_kasp_freeze(dns_kasp_t *kasp); +/*%< + * Freeze kasp. No changes can be made to kasp configuration while frozen. + * + * Requires: + * + *\li 'kasp' is a valid, unfrozen kasp. + * + * Ensures: + * + *\li 'kasp' is frozen. + */ + +void +dns_kasp_thaw(dns_kasp_t *kasp); +/*%< + * Thaw kasp. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Ensures: + * + *\li 'kasp' is no longer frozen. + */ + +const char * +dns_kasp_getname(dns_kasp_t *kasp); +/*%< + * Get kasp name. + * + * Requires: + * + *\li 'kasp' is a valid kasp. + * + * Returns: + * + *\li name of 'kasp'. + */ + +uint32_t +dns_kasp_signdelay(dns_kasp_t *kasp); +/*%< + * Get the delay that is needed to ensure that all existing RRsets have been + * re-signed with a successor key. This is the signature validity minus the + * signature refresh time (that indicates how far before signature expiry an + * RRSIG should be refreshed). + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Returns: + * + *\li signature refresh interval. + */ + +uint32_t +dns_kasp_sigrefresh(dns_kasp_t *kasp); +/*%< + * Get signature refresh interval. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Returns: + * + *\li signature refresh interval. + */ + +void +dns_kasp_setsigrefresh(dns_kasp_t *kasp, uint32_t value); +/*%< + * Set signature refresh interval. + * + * Requires: + * + *\li 'kasp' is a valid, thawed kasp. + */ + +uint32_t +dns_kasp_sigvalidity(dns_kasp_t *kasp); +uint32_t +dns_kasp_sigvalidity_dnskey(dns_kasp_t *kasp); +/*%< + * Get signature validity. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Returns: + * + *\li signature validity. + */ + +void +dns_kasp_setsigvalidity(dns_kasp_t *kasp, uint32_t value); +void +dns_kasp_setsigvalidity_dnskey(dns_kasp_t *kasp, uint32_t value); +/*%< + * Set signature validity. + * + * Requires: + * + *\li 'kasp' is a valid, thawed kasp. + */ + +dns_ttl_t +dns_kasp_dnskeyttl(dns_kasp_t *kasp); +/*%< + * Get DNSKEY TTL. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Returns: + * + *\li DNSKEY TTL. + */ + +void +dns_kasp_setdnskeyttl(dns_kasp_t *kasp, dns_ttl_t ttl); +/*%< + * Set DNSKEY TTL. + * + * Requires: + * + *\li 'kasp' is a valid, thawed kasp. + */ + +uint32_t +dns_kasp_purgekeys(dns_kasp_t *kasp); +/*%< + * Get purge keys interval. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Returns: + * + *\li Purge keys interval. + */ + +void +dns_kasp_setpurgekeys(dns_kasp_t *kasp, uint32_t value); +/*%< + * Set purge keys interval. + * + * Requires: + * + *\li 'kasp' is a valid, thawed kasp. + */ + +uint32_t +dns_kasp_publishsafety(dns_kasp_t *kasp); +/*%< + * Get publish safety interval. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Returns: + * + *\li Publish safety interval. + */ + +void +dns_kasp_setpublishsafety(dns_kasp_t *kasp, uint32_t value); +/*%< + * Set publish safety interval. + * + * Requires: + * + *\li 'kasp' is a valid, thawed kasp. + */ + +uint32_t +dns_kasp_retiresafety(dns_kasp_t *kasp); +/*%< + * Get retire safety interval. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Returns: + * + *\li Retire safety interval. + */ + +void +dns_kasp_setretiresafety(dns_kasp_t *kasp, uint32_t value); +/*%< + * Set retire safety interval. + * + * Requires: + * + *\li 'kasp' is a valid, thawed kasp. + */ + +dns_ttl_t +dns_kasp_zonemaxttl(dns_kasp_t *kasp); +/*%< + * Get maximum zone TTL. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Returns: + * + *\li Maximum zone TTL. + */ + +void +dns_kasp_setzonemaxttl(dns_kasp_t *kasp, dns_ttl_t ttl); +/*%< + * Set maximum zone TTL. + * + * Requires: + * + *\li 'kasp' is a valid, thawed kasp. + */ + +uint32_t +dns_kasp_zonepropagationdelay(dns_kasp_t *kasp); +/*%< + * Get zone propagation delay. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Returns: + * + *\li Zone propagation delay. + */ + +void +dns_kasp_setzonepropagationdelay(dns_kasp_t *kasp, uint32_t value); +/*%< + * Set zone propagation delay. + * + * Requires: + * + *\li 'kasp' is a valid, thawed kasp. + */ + +dns_ttl_t +dns_kasp_dsttl(dns_kasp_t *kasp); +/*%< + * Get DS TTL (should match that of the parent DS record). + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Returns: + * + *\li Expected parent DS TTL. + */ + +void +dns_kasp_setdsttl(dns_kasp_t *kasp, dns_ttl_t ttl); +/*%< + * Set DS TTL. + * + * Requires: + * + *\li 'kasp' is a valid, thawed kasp. + */ + +uint32_t +dns_kasp_parentpropagationdelay(dns_kasp_t *kasp); +/*%< + * Get parent zone propagation delay. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Returns: + * + *\li Parent zone propagation delay. + */ + +void +dns_kasp_setparentpropagationdelay(dns_kasp_t *kasp, uint32_t value); +/*%< + * Set parent propagation delay. + * + * Requires: + * + *\li 'kasp' is a valid, thawed kasp. + */ + +isc_result_t +dns_kasplist_find(dns_kasplist_t *list, const char *name, dns_kasp_t **kaspp); +/*%< + * Search for a kasp with name 'name' in 'list'. + * If found, '*kaspp' is (strongly) attached to it. + * + * Requires: + * + *\li 'kaspp' points to a NULL dns_kasp_t *. + * + * Returns: + * + *\li #ISC_R_SUCCESS A matching kasp was found. + *\li #ISC_R_NOTFOUND No matching kasp was found. + */ + +dns_kasp_keylist_t +dns_kasp_keys(dns_kasp_t *kasp); +/*%< + * Get the list of kasp keys. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + * + *\li Other errors are possible. + */ + +bool +dns_kasp_keylist_empty(dns_kasp_t *kasp); +/*%< + * Check if the keylist is empty. + * + * Requires: + * + *\li 'kasp' is a valid kasp. + * + * Returns: + * + *\li true if the keylist is empty, false otherwise. + */ + +void +dns_kasp_addkey(dns_kasp_t *kasp, dns_kasp_key_t *key); +/*%< + * Add a key. + * + * Requires: + * + *\li 'kasp' is a valid, thawed kasp. + *\li 'key' is not NULL. + */ + +isc_result_t +dns_kasp_key_create(dns_kasp_t *kasp, dns_kasp_key_t **keyp); +/*%< + * Create a key inside a KASP. + * + * Requires: + * + *\li 'kasp' is a valid kasp. + * + *\li keyp != NULL && *keyp == NULL + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + * + *\li Other errors are possible. + */ + +void +dns_kasp_key_destroy(dns_kasp_key_t *key); +/*%< + * Destroy a KASP key. + * + * Requires: + * + *\li key != NULL + */ + +uint32_t +dns_kasp_key_algorithm(dns_kasp_key_t *key); +/*%< + * Get the key algorithm. + * + * Requires: + * + *\li key != NULL + * + * Returns: + * + *\li Key algorithm. + */ + +unsigned int +dns_kasp_key_size(dns_kasp_key_t *key); +/*%< + * Get the key size. + * + * Requires: + * + *\li key != NULL + * + * Returns: + * + *\li Configured key size, or default key size for key algorithm if no size + * configured. + */ + +uint32_t +dns_kasp_key_lifetime(dns_kasp_key_t *key); +/*%< + * The lifetime of this key (how long may this key be active?) + * + * Requires: + * + *\li key != NULL + * + * Returns: + * + *\li Lifetime of key. + * + */ + +bool +dns_kasp_key_ksk(dns_kasp_key_t *key); +/*%< + * Does this key act as a KSK? + * + * Requires: + * + *\li key != NULL + * + * Returns: + * + *\li True, if the key role has DNS_KASP_KEY_ROLE_KSK set. + *\li False, otherwise. + * + */ + +bool +dns_kasp_key_zsk(dns_kasp_key_t *key); +/*%< + * Does this key act as a ZSK? + * + * Requires: + * + *\li key != NULL + * + * Returns: + * + *\li True, if the key role has DNS_KASP_KEY_ROLE_ZSK set. + *\li False, otherwise. + * + */ + +bool +dns_kasp_nsec3(dns_kasp_t *kasp); +/*%< + * Return true if NSEC3 chain should be used. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + */ + +uint8_t +dns_kasp_nsec3iter(dns_kasp_t *kasp); +/*%< + * The number of NSEC3 iterations to use. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + *\li 'kasp->nsec3' is true. + * + */ + +uint8_t +dns_kasp_nsec3flags(dns_kasp_t *kasp); +/*%< + * The NSEC3 flags field value. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + *\li 'kasp->nsec3' is true. + * + */ + +uint8_t +dns_kasp_nsec3saltlen(dns_kasp_t *kasp); +/*%< + * The NSEC3 salt length. + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + *\li 'kasp->nsec3' is true. + * + */ + +void +dns_kasp_setnsec3(dns_kasp_t *kasp, bool nsec3); +/*%< + * Set to use NSEC3 if 'nsec3' is 'true', otherwise policy will use NSEC. + * + * Requires: + * + *\li 'kasp' is a valid, unfrozen kasp. + * + */ + +void +dns_kasp_setnsec3param(dns_kasp_t *kasp, uint8_t iter, bool optout, + uint8_t saltlen); +/*%< + * Set the desired NSEC3 parameters. + * + * Requires: + * + *\li 'kasp' is a valid, unfrozen kasp. + *\li 'kasp->nsec3' is true. + * + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_KASP_H */ diff --git a/lib/dns/include/dns/keydata.h b/lib/dns/include/dns/keydata.h new file mode 100644 index 0000000..43a3ef7 --- /dev/null +++ b/lib/dns/include/dns/keydata.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +#ifndef DNS_KEYDATA_H +#define DNS_KEYDATA_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/keydata.h + * \brief + * KEYDATA utilities. + */ + +/*** + *** Imports + ***/ + +#include <inttypes.h> + +#include <isc/lang.h> +#include <isc/types.h> + +#include <dns/rdatastruct.h> +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_keydata_todnskey(dns_rdata_keydata_t *keydata, dns_rdata_dnskey_t *dnskey, + isc_mem_t *mctx); + +isc_result_t +dns_keydata_fromdnskey(dns_rdata_keydata_t *keydata, dns_rdata_dnskey_t *dnskey, + uint32_t refresh, uint32_t addhd, uint32_t removehd, + isc_mem_t *mctx); + +ISC_LANG_ENDDECLS + +#endif /* DNS_KEYDATA_H */ diff --git a/lib/dns/include/dns/keyflags.h b/lib/dns/include/dns/keyflags.h new file mode 100644 index 0000000..a603b6f --- /dev/null +++ b/lib/dns/include/dns/keyflags.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#ifndef DNS_KEYFLAGS_H +#define DNS_KEYFLAGS_H 1 + +/*! \file dns/keyflags.h */ + +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_keyflags_fromtext(dns_keyflags_t *flagsp, isc_textregion_t *source); +/*%< + * Convert the text 'source' refers to into a DNSSEC KEY flags value. + * The text may contain either a set of flag mnemonics separated by + * vertical bars or a decimal flags value. For compatibility with + * older versions of BIND and the DNSSEC signer, octal values + * prefixed with a zero and hexadecimal values prefixed with "0x" + * are also accepted. + * + * Requires: + *\li 'flagsp' is a valid pointer. + * + *\li 'source' is a valid text region. + * + * Returns: + *\li ISC_R_SUCCESS on success + *\li ISC_R_RANGE numeric flag value is out of range + *\li DNS_R_UNKNOWN mnemonic flag is unknown + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_KEYFLAGS_H */ diff --git a/lib/dns/include/dns/keymgr.h b/lib/dns/include/dns/keymgr.h new file mode 100644 index 0000000..7b31eb8 --- /dev/null +++ b/lib/dns/include/dns/keymgr.h @@ -0,0 +1,134 @@ +/* + * 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. + */ + +#ifndef DNS_KEYMGR_H +#define DNS_KEYMGR_H 1 + +/*! \file dns/keymgr.h */ + +#include <isc/lang.h> +#include <isc/stdtime.h> + +#include <dns/types.h> + +#include <dst/dst.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, + const char *directory, isc_mem_t *mctx, + dns_dnsseckeylist_t *keyring, dns_dnsseckeylist_t *dnskeys, + dns_kasp_t *kasp, isc_stdtime_t now, isc_stdtime_t *nexttime); +/*%< + * Manage keys in 'keyring' and update timing data according to 'kasp' policy. + * Create new keys for 'origin' if necessary in 'directory'. Append all such + * keys, along with use hints gleaned from their metadata, onto 'keyring'. + * + * Update key states and store changes back to disk. Store when to run next + * in 'nexttime'. + * + * Requires: + *\li 'origin' is a valid FQDN. + *\li 'mctx' is a valid memory context. + *\li 'keyring' is not NULL. + *\li 'kasp' is not NULL. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li any error returned by dst_key_generate(), isc_dir_open(), + * dst_key_to_file(), or dns_dnsseckey_create(). + * + * Ensures: + *\li On error, keypool is unchanged + */ + +isc_result_t +dns_keymgr_checkds(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring, + const char *directory, isc_stdtime_t now, isc_stdtime_t when, + bool dspublish); +isc_result_t +dns_keymgr_checkds_id(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring, + const char *directory, isc_stdtime_t now, + isc_stdtime_t when, bool dspublish, dns_keytag_t id, + unsigned int algorithm); +/*%< + * Check DS for one key in 'keyring'. The key must have the KSK role. + * If 'dspublish' is set to true, set the DS Publish time to 'now'. + * If 'dspublish' is set to false, set the DS Removed time to 'now'. + * If a specific key 'id' is given it must match the keytag. + * If the 'algorithm' is non-zero, it must match the key's algorithm. + * The result is stored in the key state file. + * + * Requires: + *\li 'kasp' is not NULL. + *\li 'keyring' is not NULL. + * + * Returns: + *\li #ISC_R_SUCCESS (No error). + *\li #DNS_R_NOKEYMATCH (No matching keys found). + *\li #DNS_R_TOOMANYKEYS (More than one matching keys found). + * + */ + +isc_result_t +dns_keymgr_rollover(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring, + const char *directory, isc_stdtime_t now, + isc_stdtime_t when, dns_keytag_t id, + unsigned int algorithm); +/*%< + * Rollover key with given 'id'. If the 'algorithm' is non-zero, it must + * match the key's algorithm. The changes are stored in the key state file. + * + * A rollover means adjusting the key metadata so that keymgr will start the + * actual rollover on the next run. Update the 'inactive' time and adjust + * key lifetime to match the 'when' to rollover time. + * + * The 'when' time may be in the past. In that case keymgr will roll the + * key as soon as possible. + * + * The 'when' time may be in the future. This may extend the lifetime, + * overriding the default lifetime from the policy. + * + * Requires: + *\li 'kasp' is not NULL. + *\li 'keyring' is not NULL. + * + * Returns: + *\li #ISC_R_SUCCESS (No error). + *\li #DNS_R_NOKEYMATCH (No matching keys found). + *\li #DNS_R_TOOMANYKEYS (More than one matching keys found). + *\li #DNS_R_KEYNOTACTIVE (Key is not active). + * + */ + +void +dns_keymgr_status(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring, + isc_stdtime_t now, char *out, size_t out_len); +/*%< + * Retrieve the status of given 'kasp' policy and keys in the + * 'keyring' and store the printable output in the 'out' buffer. + * + * Requires: + *\li 'kasp' is not NULL. + *\li 'keyring' is not NULL. + *\li 'out' is not NULL. + * + * Returns: + *\li Printable status in 'out'. + * + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_KEYMGR_H */ diff --git a/lib/dns/include/dns/keytable.h b/lib/dns/include/dns/keytable.h new file mode 100644 index 0000000..9557ab8 --- /dev/null +++ b/lib/dns/include/dns/keytable.h @@ -0,0 +1,350 @@ +/* + * 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. + */ + +#ifndef DNS_KEYTABLE_H +#define DNS_KEYTABLE_H 1 + +/***** +***** Module Info +*****/ + +/*! \file + * \brief + * The keytable module provides services for storing and retrieving DNSSEC + * trusted keys, as well as the ability to find the deepest matching key + * for a given domain name. + * + * MP: + *\li The module ensures appropriate synchronization of data structures it + * creates and manipulates. + * + * Resources: + *\li TBS + * + * Security: + *\li No anticipated impact. + */ + +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/refcount.h> +#include <isc/rwlock.h> +#include <isc/stdtime.h> + +#include <dns/rdatastruct.h> +#include <dns/types.h> + +#include <dst/dst.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep); +/*%< + * Create a keytable. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li keytablep != NULL && *keytablep == NULL + * + * Ensures: + * + *\li On success, *keytablep is a valid, empty key table. + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li Any other result indicates failure. + */ + +void +dns_keytable_attach(dns_keytable_t *source, dns_keytable_t **targetp); +/*%< + * Attach *targetp to source. + * + * Requires: + * + *\li 'source' is a valid keytable. + * + *\li 'targetp' points to a NULL dns_keytable_t *. + * + * Ensures: + * + *\li *targetp is attached to source. + */ + +void +dns_keytable_detach(dns_keytable_t **keytablep); +/*%< + * Detach *keytablep from its keytable. + * + * Requires: + * + *\li 'keytablep' points to a valid keytable. + * + * Ensures: + * + *\li *keytablep is NULL. + * + *\li If '*keytablep' is the last reference to the keytable, + * all resources used by the keytable will be freed + */ + +isc_result_t +dns_keytable_add(dns_keytable_t *keytable, bool managed, bool initial, + dns_name_t *name, dns_rdata_ds_t *ds); +/*%< + * Add a key to 'keytable'. The keynode associated with 'name' + * is updated with the DS specified in 'ds'. + * + * The value of keynode->managed is set to 'managed', and the + * value of keynode->initial is set to 'initial'. (Note: 'initial' + * should only be used when adding managed-keys from configuration. + * This indicates the key is in "initializing" state, and has not yet + * been confirmed with a key refresh query. Once a key refresh query + * has validated, we update the keynode with initial == false.) + * + * Notes: + * + *\li If the key already exists in the table, adding it again + * has no effect and ISC_R_SUCCESS is returned. + * + * Requires: + * + *\li 'keytable' points to a valid keytable. + *\li 'ds' is not NULL. + *\li if 'initial' is true then 'managed' must also be true. + * + * Returns: + * + *\li ISC_R_SUCCESS + *\li ISC_R_EXISTS + * + *\li Any other result indicates failure. + */ + +isc_result_t +dns_keytable_marksecure(dns_keytable_t *keytable, const dns_name_t *name); +/*%< + * Add a null key to 'keytable' for name 'name'. This marks the + * name as a secure domain, but doesn't supply any key data to allow the + * domain to be validated. (Used when automated trust anchor management + * has gotten broken by a zone misconfiguration; for example, when the + * active key has been revoked but the stand-by key was still in its 30-day + * waiting period for validity.) + * + * Notes: + * + *\li If a key already exists in the table, ISC_R_EXISTS is + * returned and nothing is done. + * + * Requires: + * + *\li 'keytable' points to a valid keytable. + * + *\li keyp != NULL && *keyp is a valid dst_key_t *. + * + * Returns: + * + *\li ISC_R_SUCCESS + *\li ISC_R_EXISTS + * + *\li Any other result indicates failure. + */ + +isc_result_t +dns_keytable_delete(dns_keytable_t *keytable, const dns_name_t *keyname); +/*%< + * Delete all trust anchors from 'keytable' matching name 'keyname' + * + * Requires: + * + *\li 'keytable' points to a valid keytable. + * + *\li 'name' is not NULL + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li Any other result indicates failure. + */ + +isc_result_t +dns_keytable_deletekey(dns_keytable_t *keytable, const dns_name_t *keyname, + dns_rdata_dnskey_t *dnskey); +/*%< + * Remove the trust anchor matching the name 'keyname' and the DNSKEY + * rdata struct 'dnskey' from 'keytable'. + * + * Requires: + * + *\li 'keytable' points to a valid keytable. + *\li 'dnskey' is not NULL + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li Any other result indicates failure. + */ + +isc_result_t +dns_keytable_find(dns_keytable_t *keytable, const dns_name_t *keyname, + dns_keynode_t **keynodep); +/*%< + * Search for the first instance of a trust anchor named 'name' in + * 'keytable', without regard to keyid and algorithm. + * + * Requires: + * + *\li 'keytable' is a valid keytable. + * + *\li 'name' is a valid absolute name. + * + *\li keynodep != NULL && *keynodep == NULL + * + * Returns: + * + *\li ISC_R_SUCCESS + *\li ISC_R_NOTFOUND + * + *\li Any other result indicates an error. + */ + +isc_result_t +dns_keytable_finddeepestmatch(dns_keytable_t *keytable, const dns_name_t *name, + dns_name_t *foundname); +/*%< + * Search for the deepest match of 'name' in 'keytable'. + * + * Requires: + * + *\li 'keytable' is a valid keytable. + * + *\li 'name' is a valid absolute name. + * + *\li 'foundname' is a name with a dedicated buffer. + * + * Returns: + * + *\li ISC_R_SUCCESS + *\li ISC_R_NOTFOUND + * + *\li Any other result indicates an error. + */ + +void +dns_keytable_detachkeynode(dns_keytable_t *keytable, dns_keynode_t **keynodep); +/*%< + * Detach a keynode found via dns_keytable_find(). + * + * Requires: + * + *\li *keynodep is a valid keynode returned by a call to dns_keytable_find(). + * + * Ensures: + * + *\li *keynodep == NULL + */ + +isc_result_t +dns_keytable_issecuredomain(dns_keytable_t *keytable, const dns_name_t *name, + dns_name_t *foundname, bool *wantdnssecp); +/*%< + * Is 'name' at or beneath a trusted key? + * + * Requires: + * + *\li 'keytable' is a valid keytable. + * + *\li 'name' is a valid absolute name. + * + *\li 'foundanme' is NULL or is a pointer to an initialized dns_name_t + * + *\li '*wantsdnssecp' is a valid bool. + * + * Ensures: + * + *\li On success, *wantsdnssecp will be true if and only if 'name' + * is at or beneath a trusted key. If 'foundname' is not NULL, then + * it will be updated to contain the name of the closest enclosing + * trust anchor. + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li Any other result is an error. + */ + +isc_result_t +dns_keytable_dump(dns_keytable_t *keytable, FILE *fp); +/*%< + * Dump the keytable on fp. + */ + +isc_result_t +dns_keytable_totext(dns_keytable_t *keytable, isc_buffer_t **buf); +/*%< + * Dump the keytable to buffer at 'buf' + */ + +bool +dns_keynode_dsset(dns_keynode_t *keynode, dns_rdataset_t *rdataset); +/*%< + * Clone the DS RRset associated with 'keynode' into 'rdataset' if + * it exists. 'dns_rdataset_disassociate(rdataset)' needs to be + * called when done. + * + * Returns: + *\li true if there is a DS RRset. + *\li false if there isn't DS RRset. + * + * Requires: + *\li 'keynode' is valid. + *\li 'rdataset' is valid or NULL. + */ + +bool +dns_keynode_managed(dns_keynode_t *keynode); +/*%< + * Is this flagged as a managed key? + */ + +bool +dns_keynode_initial(dns_keynode_t *keynode); +/*%< + * Is this flagged as an initializing key? + */ + +void +dns_keynode_trust(dns_keynode_t *keynode); +/*%< + * Sets keynode->initial to false in order to mark the key as + * trusted: no longer an initializing key. + */ + +isc_result_t +dns_keytable_forall(dns_keytable_t *keytable, + void (*func)(dns_keytable_t *, dns_keynode_t *, + dns_name_t *, void *), + void *arg); +ISC_LANG_ENDDECLS + +#endif /* DNS_KEYTABLE_H */ diff --git a/lib/dns/include/dns/keyvalues.h b/lib/dns/include/dns/keyvalues.h new file mode 100644 index 0000000..e27ada1 --- /dev/null +++ b/lib/dns/include/dns/keyvalues.h @@ -0,0 +1,107 @@ +/* + * 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. + */ + +#ifndef DNS_KEYVALUES_H +#define DNS_KEYVALUES_H 1 + +/*! \file dns/keyvalues.h */ + +/* + * Flags field of the KEY RR rdata + */ +#define DNS_KEYFLAG_TYPEMASK 0xC000 /*%< Mask for "type" bits */ +#define DNS_KEYTYPE_AUTHCONF 0x0000 /*%< Key usable for both */ +#define DNS_KEYTYPE_CONFONLY 0x8000 /*%< Key usable for confidentiality */ +#define DNS_KEYTYPE_AUTHONLY 0x4000 /*%< Key usable for authentication */ +#define DNS_KEYTYPE_NOKEY 0xC000 /*%< No key usable for either; no key */ +#define DNS_KEYTYPE_NOAUTH DNS_KEYTYPE_CONFONLY +#define DNS_KEYTYPE_NOCONF DNS_KEYTYPE_AUTHONLY + +#define DNS_KEYFLAG_RESERVED2 0x2000 /*%< reserved - must be zero */ +#define DNS_KEYFLAG_EXTENDED 0x1000 /*%< key has extended flags */ +#define DNS_KEYFLAG_RESERVED4 0x0800 /*%< reserved - must be zero */ +#define DNS_KEYFLAG_RESERVED5 0x0400 /*%< reserved - must be zero */ +#define DNS_KEYFLAG_OWNERMASK 0x0300 /*%< these bits determine the type */ +#define DNS_KEYOWNER_USER 0x0000 /*%< key is assoc. with user */ +#define DNS_KEYOWNER_ENTITY 0x0200 /*%< key is assoc. with entity eg host */ +#define DNS_KEYOWNER_ZONE 0x0100 /*%< key is zone key */ +#define DNS_KEYOWNER_RESERVED 0x0300 /*%< reserved meaning */ +#define DNS_KEYFLAG_REVOKE 0x0080 /*%< key revoked (per rfc5011) */ +#define DNS_KEYFLAG_RESERVED9 0x0040 /*%< reserved - must be zero */ +#define DNS_KEYFLAG_RESERVED10 0x0020 /*%< reserved - must be zero */ +#define DNS_KEYFLAG_RESERVED11 0x0010 /*%< reserved - must be zero */ +#define DNS_KEYFLAG_SIGNATORYMASK \ + 0x000F /*%< key can sign RR's of same name \ + */ + +#define DNS_KEYFLAG_RESERVEDMASK \ + (DNS_KEYFLAG_RESERVED2 | DNS_KEYFLAG_RESERVED4 | \ + DNS_KEYFLAG_RESERVED5 | DNS_KEYFLAG_RESERVED9 | \ + DNS_KEYFLAG_RESERVED10 | DNS_KEYFLAG_RESERVED11) +#define DNS_KEYFLAG_KSK 0x0001 /*%< key signing key */ + +#define DNS_KEYFLAG_RESERVEDMASK2 0xFFFF /*%< no bits defined here */ + +/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */ +#define DNS_KEYALG_RSAMD5 1 /*%< RSA with MD5 */ +#define DNS_KEYALG_RSA 1 /*%< Used just for tagging */ +#define DNS_KEYALG_DH 2 /*%< Diffie Hellman KEY */ +#define DNS_KEYALG_DSA 3 /*%< DSA KEY */ +#define DNS_KEYALG_NSEC3DSA 6 +#define DNS_KEYALG_DSS DNS_ALG_DSA +#define DNS_KEYALG_ECC 4 +#define DNS_KEYALG_RSASHA1 5 +#define DNS_KEYALG_NSEC3RSASHA1 7 +#define DNS_KEYALG_RSASHA256 8 +#define DNS_KEYALG_RSASHA512 10 +#define DNS_KEYALG_ECCGOST 12 +#define DNS_KEYALG_ECDSA256 13 +#define DNS_KEYALG_ECDSA384 14 +#define DNS_KEYALG_ED25519 15 +#define DNS_KEYALG_ED448 16 +#define DNS_KEYALG_INDIRECT 252 +#define DNS_KEYALG_PRIVATEDNS 253 +#define DNS_KEYALG_PRIVATEOID 254 /*%< Key begins with OID giving alg */ +#define DNS_KEYALG_MAX 255 + +/* Protocol values */ +#define DNS_KEYPROTO_RESERVED 0 +#define DNS_KEYPROTO_TLS 1 +#define DNS_KEYPROTO_EMAIL 2 +#define DNS_KEYPROTO_DNSSEC 3 +#define DNS_KEYPROTO_IPSEC 4 +#define DNS_KEYPROTO_ANY 255 + +/* Signatures */ +#define DNS_SIG_RSAMINBITS 512 /*%< Size of a mod or exp in bits */ +#define DNS_SIG_RSAMAXBITS 2552 +/* Total of binary mod and exp */ +#define DNS_SIG_RSAMAXBYTES ((DNS_SIG_RSAMAXBITS + 7 / 8) * 2 + 3) +/*%< Max length of text sig block */ +#define DNS_SIG_RSAMAXBASE64 (((DNS_SIG_RSAMAXBYTES + 2) / 3) * 4) +#define DNS_SIG_RSAMINSIZE ((DNS_SIG_RSAMINBITS + 7) / 8) +#define DNS_SIG_RSAMAXSIZE ((DNS_SIG_RSAMAXBITS + 7) / 8) + +#define DNS_SIG_ECDSA256SIZE 64 +#define DNS_SIG_ECDSA384SIZE 96 + +#define DNS_KEY_ECDSA256SIZE 64 +#define DNS_KEY_ECDSA384SIZE 96 + +#define DNS_SIG_ED25519SIZE 64 +#define DNS_SIG_ED448SIZE 114 + +#define DNS_KEY_ED25519SIZE 32 +#define DNS_KEY_ED448SIZE 57 + +#endif /* DNS_KEYVALUES_H */ diff --git a/lib/dns/include/dns/lib.h b/lib/dns/include/dns/lib.h new file mode 100644 index 0000000..649b483 --- /dev/null +++ b/lib/dns/include/dns/lib.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#ifndef DNS_LIB_H +#define DNS_LIB_H 1 + +/*! \file dns/lib.h */ + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +/*% + * Tuning: external query load in packets per seconds. + */ +LIBDNS_EXTERNAL_DATA extern unsigned int dns_pps; + +isc_result_t +dns_lib_init(void); +/*%< + * A set of initialization procedures used in the DNS library. This function + * is provided for an application that is not aware of the underlying ISC or + * DNS libraries much. + */ + +void +dns_lib_shutdown(void); +/*%< + * Free temporary resources allocated in dns_lib_init(). + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_LIB_H */ diff --git a/lib/dns/include/dns/librpz.h b/lib/dns/include/dns/librpz.h new file mode 100644 index 0000000..110b798 --- /dev/null +++ b/lib/dns/include/dns/librpz.h @@ -0,0 +1,956 @@ +/* + * 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. + */ + +/* + * Define the interface from a DNS resolver to the Response Policy Zone + * library, librpz. + * + * This file should be included only the interface functions between the + * resolver and librpz to avoid name space pollution. + * + * Copyright (c) 2016-2017 Farsight Security, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * version 1.2.12 + */ + +#ifndef LIBRPZ_H +#define LIBRPZ_H + +#include <inttypes.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> + +#include <arpa/nameser.h> +#include <netinet/in.h> +#include <sys/types.h> + +/* + * Allow either ordinary or dlopen() linking. + */ +#ifdef LIBRPZ_INTERNAL +#define LIBDEF(t, s) extern t s; +#define LIBDEF_F(f) LIBDEF(librpz_##f##_t, librpz_##f) +#else /* ifdef LIBRPZ_INTERNAL */ +#define LIBDEF(t, s) +#define LIBDEF_F(f) +#endif /* ifdef LIBRPZ_INTERNAL */ + +/* + * Response Policy Zone triggers. + * Comparisons of trigger precedences require + * LIBRPZ_TRIG_CLIENT_IP < LIBRPZ_TRIG_QNAME < LIBRPZ_TRIG_IP + * < LIBRPZ_TRIG_NSDNAME < LIBRPZ_TRIG_NSIP} + */ +typedef enum { + LIBRPZ_TRIG_BAD = 0, + LIBRPZ_TRIG_CLIENT_IP = 1, + LIBRPZ_TRIG_QNAME = 2, + LIBRPZ_TRIG_IP = 3, + LIBRPZ_TRIG_NSDNAME = 4, + LIBRPZ_TRIG_NSIP = 5 +} librpz_trig_t; +#define LIBRPZ_TRIG_SIZE 3 /* sizeof librpz_trig_t in bits */ +typedef uint8_t librpz_tbit_t; /* one bit for each of the TRIGS_NUM + * trigger types */ + +/* + * Response Policy Zone Actions or policies + */ +typedef enum { + LIBRPZ_POLICY_UNDEFINED = 0, /* an empty entry or no decision yet */ + LIBRPZ_POLICY_DELETED = 1, /* placeholder for a deleted policy */ + + LIBRPZ_POLICY_PASSTHRU = 2, /* 'passthru': do not rewrite */ + LIBRPZ_POLICY_DROP = 3, /* 'drop': do not respond */ + LIBRPZ_POLICY_TCP_ONLY = 4, /* 'tcp-only': answer UDP with TC=1 */ + LIBRPZ_POLICY_NXDOMAIN = 5, /* 'nxdomain': answer with NXDOMAIN */ + LIBRPZ_POLICY_NODATA = 6, /* 'nodata': answer with ANCOUNT=0 */ + LIBRPZ_POLICY_RECORD = 7, /* rewrite with the policy's RR */ + + /* only in client configurations to override the zone */ + LIBRPZ_POLICY_GIVEN, /* 'given': what policy record says */ + LIBRPZ_POLICY_DISABLED, /* at most log */ + LIBRPZ_POLICY_CNAME, /* answer with 'cname x' */ +} librpz_policy_t; +#define LIBRPZ_POLICY_BITS 4 + +/* + * Special policies that appear as targets of CNAMEs + * NXDOMAIN is signaled by a CNAME with a "." target. + * NODATA is signaled by a CNAME with a "*." target. + */ +#define LIBRPZ_RPZ_PREFIX "rpz-" +#define LIBRPZ_RPZ_PASSTHRU LIBRPZ_RPZ_PREFIX "passthru" +#define LIBRPZ_RPZ_DROP LIBRPZ_RPZ_PREFIX "drop" +#define LIBRPZ_RPZ_TCP_ONLY LIBRPZ_RPZ_PREFIX "tcp-only" + +typedef uint16_t librpz_dznum_t; /* dnsrpzd zone # in [0,DZNUM_MAX] */ +typedef uint8_t librpz_cznum_t; /* client zone # in [0,CZNUM_MAX] */ + +/* + * CIDR block + */ +typedef struct librpz_prefix { + union { + struct in_addr in; + struct in6_addr in6; + } addr; + uint8_t family; + uint8_t len; +} librpz_prefix_t; + +/* + * A domain + */ +typedef uint8_t librpz_dsize_t; +typedef struct librpz_domain { + librpz_dsize_t size; /* of only .d */ + uint8_t d[0]; /* variable length wire format */ +} librpz_domain_t; + +/* + * A maximal domain buffer + */ +typedef struct librpz_domain_buf { + librpz_dsize_t size; + uint8_t d[NS_MAXCDNAME]; +} librpz_domain_buf_t; + +/* + * A resource record without the owner name. + * C compilers say that sizeof(librpz_rr_t)=12 instead of 10. + */ +typedef struct { + uint16_t type; /* network byte order */ + uint16_t class; /* network byte order */ + uint32_t ttl; /* network byte order */ + uint16_t rdlength; /* network byte order */ + uint8_t rdata[0]; /* variable length */ +} librpz_rr_t; + +/* + * The database file might be mapped with different starting addresses + * by concurrent clients (resolvers), and so all pointers are offsets. + */ +typedef uint32_t librpz_idx_t; +#define LIBRPZ_IDX_NULL 0 +#define LIBRPZ_IDX_MIN 1 +#define LIBRPZ_IDX_BAD ((librpz_idx_t)-1) +/** + * Partial decoded results of a set of RPZ queries for a single DNS response + * or iteration through the mapped file. + */ +typedef int16_t librpz_result_id_t; +typedef struct librpz_result { + librpz_idx_t next_rr; + librpz_result_id_t hit_id; /* trigger ID from resolver */ + librpz_policy_t zpolicy; /* policy from zone */ + librpz_policy_t policy; /* adjusted by client configuration */ + librpz_dznum_t dznum; /* dnsrpzd zone number */ + librpz_cznum_t cznum; /* librpz client zone number */ + librpz_trig_t trig : LIBRPZ_TRIG_SIZE; + bool log : 1; /* log rewrite given librpz_log_level + * */ +} librpz_result_t; + +/** + * librpz trace or log levels. + */ +typedef enum { + LIBRPZ_LOG_FATAL = 0, /* always print fatal errors */ + LIBRPZ_LOG_ERROR = 1, /* errors have this level */ + LIBRPZ_LOG_TRACE1 = 2, /* big events such as dnsrpzd starts */ + LIBRPZ_LOG_TRACE2 = 3, /* smaller dnsrpzd zone transfers */ + LIBRPZ_LOG_TRACE3 = 4, /* librpz hits */ + LIBRPZ_LOG_TRACE4 = 5, /* librpz lookups */ + LIBRPZ_LOG_INVALID = 999, +} librpz_log_level_t; +typedef librpz_log_level_t(librpz_log_level_val_t)(librpz_log_level_t level); +LIBDEF_F(log_level_val) + +/** + * Logging function that can be supplied by the resolver. + * @param level is one of librpz_log_level_t + * @param ctx is for use by the resolver's logging system. + * NULL mean a context-free message. + */ +typedef void(librpz_log_fnc_t)(librpz_log_level_t level, void *ctx, + const char *buf); + +/** + * Point librpz logging functions to the resolver's choice. + */ +typedef void(librpz_set_log_t)(librpz_log_fnc_t *new_log, const char *prog_nm); +LIBDEF_F(set_log) + +/** + * librpz error messages are put in these buffers. + * Use a structure instead of naked char* to let the compiler check the length. + * A function defined with "foo(char buf[120])" can be called with + * "char sbuf[2]; foo(sbuf)" and suffer a buffer overrun. + */ +typedef struct { + char c[120]; +} librpz_emsg_t; + +#ifdef LIBRPZ_HAVE_ATTR +#define LIBRPZ_UNUSED __attribute__((unused)) +#define LIBRPZ_PF(f, l) __attribute__((format(printf, f, l))) +#define LIBRPZ_NORET __attribute__((__noreturn__)) +#else /* ifdef LIBRPZ_HAVE_ATTR */ +#define LIBRPZ_UNUSED +#define LIBRPZ_PF(f, l) +#define LIBRPZ_NORET +#endif /* ifdef LIBRPZ_HAVE_ATTR */ + +#ifdef HAVE_BUILTIN_EXPECT +#define LIBRPZ_LIKELY(c) __builtin_expect(!!(c), 1) +#define LIBRPZ_UNLIKELY(c) __builtin_expect(!!(c), 0) +#else /* ifdef HAVE_BUILTIN_EXPECT */ +#define LIBRPZ_LIKELY(c) (c) +#define LIBRPZ_UNLIKELY(c) (c) +#endif /* ifdef HAVE_BUILTIN_EXPECT */ + +typedef bool(librpz_parse_log_opt_t)(librpz_emsg_t *emsg, const char *arg); +LIBDEF_F(parse_log_opt) + +typedef void(librpz_vpemsg_t)(librpz_emsg_t *emsg, const char *p, va_list args); +LIBDEF_F(vpemsg) +typedef void(librpz_pemsg_t)(librpz_emsg_t *emsg, const char *p, ...) + LIBRPZ_PF(2, 3); +LIBDEF_F(pemsg) + +typedef void(librpz_vlog_t)(librpz_log_level_t level, void *ctx, const char *p, + va_list args); +LIBDEF_F(vlog) +typedef void(librpz_log_t)(librpz_log_level_t level, void *ctx, const char *p, + ...) LIBRPZ_PF(3, 4); +LIBDEF_F(log) + +typedef void(librpz_fatal_t)(int ex_code, const char *p, ...) LIBRPZ_PF(2, 3); +extern void +librpz_fatal(int ex_code, const char *p, ...) LIBRPZ_PF(2, 3) LIBRPZ_NORET; + +typedef void(librpz_rpz_assert_t)(const char *file, unsigned line, + const char *p, ...) LIBRPZ_PF(3, 4); +extern void +librpz_rpz_assert(const char *file, unsigned line, const char *p, ...) + LIBRPZ_PF(3, 4) LIBRPZ_NORET; + +typedef void(librpz_rpz_vassert_t)(const char *file, uint line, const char *p, + va_list args); +extern void +librpz_rpz_vassert(const char *file, uint line, const char *p, + va_list args) LIBRPZ_NORET; + +/* + * As far as clients are concerned, all relative pointers or indexes in a + * version of the mapped file except trie node parent pointers remain valid + * forever. A client must release a version so that it can be garbage + * collected by the file system. When dnsrpzd needs to expand the file, + * it copies the old file to a new, larger file. Clients can continue + * using the old file. + * + * Versions can also appear in a single file. Old nodes and trie values + * within the file are not destroyed until all clients using the version + * that contained the old values release the version. + * + * A client is marked as using version by connecting to the daemon. It is + * marked as using all subsequent versions. A client releases all versions + * by closing the connection or a range of versions by updating is slot + * in the shared memory version table. + * + * As far as clients are concerned, there are the following possible librpz + * failures: + * - malloc() or other fatal internal librpz problems indicated by + * a failing return from a librpz function + * All operations will fail until client handle is destroyed and + * recreated with librpz_client_detach() and librpz_client_create(). + * - corrupt database detected by librpz code, corrupt database detected + * by dnsrpzd, or disconnection from the daemon. + * Current operations will fail. + * + * Clients assume that the file has already been unlinked before + * the corrupt flag is set so that they do not race with the server + * over the corruption of a single file. A client that finds the + * corrupt set knows that dnsrpzd has already crashed with + * abort() and is restarting. The client can re-connect to dnsrpzd + * and retransmit its configuration, backing off as usual if anything + * goes wrong. + * + * Searches of the database by a client do not need locks against dnsrpzd or + * other clients, but a lock is used to protect changes to the connection + * by competing threads in the client. The client provides functions + * to serialize the concurrent use of any single client handle. + * Functions that do nothing are appropriate for applications that are + * not "threaded" or that do not share client handles among threads. + * Otherwise, functions must be provided to librpz_clientcreate(). + * Something like the following works with pthreads: + * + * static void + * lock(void *mutex) { assert(pthread_mutex_lock(mutex) == 0); } + * + * static void + * unlock(void *mutex) { assert(pthread_mutex_unlock(mutex) == 0); } + * + * static void + * mutex_destroy(void *mutex) { assert(pthread_mutex_destroy(mutex) == 0); } + * + * + * + * At every instant, all of the data and pointers in the mapped file are valid. + * Changes to trie node or other data are always made so that it and + * all pointers in and to it remain valid for a time. Old versions are + * eventually discarded. + * + * Dnsrpzd periodically defines a new version by setting aside all changes + * made since the previous version was defined. Subsequent changes + * made (only!) by dnsrpzd will be part of the next version. + * + * To discard an old version, dnsrpzd must know that all clients have stopped + * using that version. Clients do that by using part of the mapped file + * to tell dnsrpzd the oldest version that each client is using. + * Dnsrpzd assigns each connecting client an entry in the cversions array + * in the mapped file. The client puts version numbers into that entry + * to signal to dnsrpzd which versions that can be discarded. + * Dnsrpzd is free, as far as that client is concerned, to discard all + * numerically smaller versions. A client can disclaim all versions with + * the version number VERSIONS_ALL or 0. + * + * The race between a client changing its entry and dnsrpzd discarding a + * version is resolved by allowing dnsrpzd to discard all versions + * smaller or equal to the client's version number. If dnsrpzd is in + * the midst of discarding or about to discard version N when the + * client asserts N, no harm is done. The client depends only on + * the consistency of version N+1. + * + * This version mechanism depends in part on not being exercised too frequently + * Version numbers are 32 bits long and dnsrpzd creates new versions + * at most once every 30 seconds. + */ + +/* + * Lock functions for concurrent use of a single librpz_client_t client handle. + */ +typedef void(librpz_mutex_t)(void *mutex); + +/* + * List of connections to dnsrpzd daemons. + */ +typedef struct librpz_clist librpz_clist_t; + +/* + * Client's handle on dnsrpzd. + */ +typedef struct librpz_client librpz_client_t; + +/** + * Create the list of connections to the dnsrpzd daemon. + * @param[out] emsg: error message + * @param lock: start exclusive access to the client handle + * @param unlock: end exclusive access to the client handle + * @param mutex_destroy: release the lock + * @param mutex: pointer to the lock for the client handle + * @param log_ctx: NULL or resolver's context log messages + */ +typedef librpz_clist_t *(librpz_clist_create_t)(librpz_emsg_t *emsg, + librpz_mutex_t *lock, + librpz_mutex_t *unlock, + librpz_mutex_t *mutex_destroy, + void *mutex, void *log_ctx); +LIBDEF_F(clist_create) + +/** + * Release the list of dnsrpzd connections. + */ +typedef void(librpz_clist_detach_t)(librpz_clist_t **clistp); +LIBDEF_F(clist_detach) + +/** + * Create a librpz client handle. + * @param[out] emsg: error message + * @param clist: of dnsrpzd connections + * @param cstr: string of configuration settings separated by ';' or '\n' + * @param use_expired: true to not ignore expired zones + * @return client handle or NULL if the handle could not be created + */ +typedef librpz_client_t *(librpz_client_create_t)(librpz_emsg_t *emsg, + librpz_clist_t *clist, + const char *cstr, + bool use_expired); +LIBDEF_F(client_create) + +/** + * Start (if necessary) dnsrpzd and connect to it. + * @param[out] emsg: error message + * @param client handle + * @param optional: true if it is ok if starting the daemon is not allowed + */ +typedef bool(librpz_connect_t)(librpz_emsg_t *emsg, librpz_client_t *client, + bool optional); +LIBDEF_F(connect) + +/** + * Start to destroy a librpz client handle. + * It will not be destroyed until the last set of RPZ queries represented + * by a librpz_rsp_t ends. + * @param client handle to be released + * @return false on error + */ +typedef void(librpz_client_detach_t)(librpz_client_t **clientp); +LIBDEF_F(client_detach) + +/** + * State for a set of RPZ queries for a single DNS response + * or for listing the database. + */ +typedef struct librpz_rsp librpz_rsp_t; + +/** + * Start a set of RPZ queries for a single DNS response. + * @param[out] emsg: error message for false return or *rspp=NULL + * @param[out] rspp created context or NULL + * @param[out] min_ns_dotsp: NULL or pointer to configured MIN-NS-DOTS value + * @param client state + * @param have_rd: RD=1 in the DNS request + * @param have_do: DO=1 in the DNS request + * @return false on error + */ +typedef bool(librpz_rsp_create_t)(librpz_emsg_t *emsg, librpz_rsp_t **rspp, + int *min_ns_dotsp, librpz_client_t *client, + bool have_rd, bool have_do); +LIBDEF_F(rsp_create) + +/** + * Finish RPZ work for a DNS response. + */ +typedef void(librpz_rsp_detach_t)(librpz_rsp_t **rspp); +LIBDEF_F(rsp_detach) + +/** + * Get the final, accumulated result of a set of RPZ queries. + * Yield LIBRPZ_POLICY_UNDEFINED if + * - there were no hits, + * - there was a dispositive hit, be we have not recursed and are required + * to recurse so that evil DNS authorities will not know we are using RPZ + * - we have a hit and have recursed, but later data such as NSIP could + * override + * @param[out] emsg + * @param[out] result describes the hit + * or result->policy=LIBRPZ_POLICY_UNDEFINED without a hit + * @param[out] result: current policy rewrite values + * @param recursed: recursion has now been done even if it was not done + * when the hit was found + * @param[in,out] rsp state from librpz_itr_start() + * @return false on error + */ +typedef bool(librpz_rsp_result_t)(librpz_emsg_t *emsg, librpz_result_t *result, + bool recursed, const librpz_rsp_t *rsp); +LIBDEF_F(rsp_result) + +/** + * Might looking for a trigger be worthwhile? + * @param trig: look for this type of trigger + * @param ipv6: true if trig is LIBRPZ_TRIG_CLIENT_IP, LIBRPZ_TRIG_IP, + * or LIBRPZ_TRIG_NSIP and the IP address is IPv6 + * @return: true if looking could be worthwhile + */ +typedef bool(librpz_have_trig_t)(librpz_trig_t trig, bool ipv6, + const librpz_rsp_t *rsp); +LIBDEF_F(have_trig) + +/** + * Might looking for NSDNAME and NSIP triggers be worthwhile? + * @return: true if looking could be worthwhile + */ +typedef bool(librpz_have_ns_trig_t)(const librpz_rsp_t *rsp); +LIBDEF_F(have_ns_trig) + +/** + * Convert the found client IP trie key to a CIDR block + * @param[out] emsg + * @param[out] prefix trigger + * @param[in,out] rsp state from librpz_itr_start() + * @return false on error + */ +typedef bool(librpz_rsp_clientip_prefix_t)(librpz_emsg_t *emsg, + librpz_prefix_t *prefix, + librpz_rsp_t *rsp); +LIBDEF_F(rsp_clientip_prefix) + +/** + * Compute the owner name of the found or result trie key, usually to log it. + * An IP address key might be returned as 8.0.0.0.127.rpz-client-ip. + * example.com. might be a qname trigger. example.com.rpz-nsdname. could + * be an NSDNAME trigger. + * @param[out] emsg + * @param[out] owner domain + * @param[in,out] rsp state from librpz_itr_start() + * @return false on error + */ +typedef bool(librpz_rsp_domain_t)(librpz_emsg_t *emsg, + librpz_domain_buf_t *owner, + librpz_rsp_t *rsp); +LIBDEF_F(rsp_domain) + +/** + * Get the next RR of the LIBRPZ_POLICY_RECORD result after an initial use of + * librpz_rsp_result() or librpz_itr_node() or after a previous use of + * librpz_rsp_rr(). The RR is in uncompressed wire format including type, + * class, ttl and length in network byte order. + * @param[out] emsg + * @param[out] typep: optional host byte order record type or ns_t_invalid (0) + * @param[out] classp: class such as ns_c_in + * @param[out] ttlp: TTL + * @param[out] rrp: optional malloc() buffer containing the next RR or + * NULL after the last RR + * @param[out] result: current policy rewrite values + * @param qname: used construct a wildcard CNAME + * @param qname_size + * @param[in,out] rsp state from librpz_itr_start() + * @return false on error + */ +typedef bool(librpz_rsp_rr_t)(librpz_emsg_t *emsg, uint16_t *typep, + uint16_t *classp, uint32_t *ttlp, + librpz_rr_t **rrp, librpz_result_t *result, + const uint8_t *qname, size_t qname_size, + librpz_rsp_t *rsp); +LIBDEF_F(rsp_rr) + +/** + * Get the next RR of the LIBRPZ_POLICY_RECORD result. + * @param[out] emsg + * @param[out] ttlp: TTL + * @param[out] rrp: malloc() buffer with SOA RR without owner name + * @param[out] result: current policy rewrite values + * @param[out] origin: SOA owner name + * @param[out] origin_size + * @param[in,out] rsp state from librpz_itr_start() + * @return false on error + */ +typedef bool(librpz_rsp_soa_t)(librpz_emsg_t *emsg, uint32_t *ttlp, + librpz_rr_t **rrp, librpz_domain_buf_t *origin, + librpz_result_t *result, librpz_rsp_t *rsp); +LIBDEF_F(rsp_soa) + +/** + * Get the SOA serial number for a policy zone to compare with a known value + * to check whether a zone transfer is complete. + */ +typedef bool(librpz_soa_serial_t)(librpz_emsg_t *emsg, uint32_t *serialp, + const char *domain_nm, librpz_rsp_t *rsp); +LIBDEF_F(soa_serial) + +/** + * Save the current policy checking state. + * @param[out] emsg + * @param[in,out] rsp state from librpz_itr_start() + * @return false on error + */ +typedef bool(librpz_rsp_push_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp); +LIBDEF_F(rsp_push) +#define LIBRPZ_RSP_STACK_DEPTH 3 + +/** + * Restore the previous policy checking state. + * @param[out] emsg + * @param[out] result: NULL or restored policy rewrite values + * @param[in,out] rsp state from librpz_itr_start() + * @return false on error + */ +typedef bool(librpz_rsp_pop_t)(librpz_emsg_t *emsg, librpz_result_t *result, + librpz_rsp_t *rsp); +LIBDEF_F(rsp_pop) + +/** + * Discard the most recently save policy checking state. + * @param[out] emsg + * @param[out] result: NULL or restored policy rewrite values + * @return false on error + */ +typedef bool(librpz_rsp_pop_discard_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp); +LIBDEF_F(rsp_pop_discard) + +/** + * Disable a zone. + * @param[out] emsg + * @param znum + * @param[in,out] rsp state from librpz_itr_start() + * @return false on error + */ +typedef bool(librpz_rsp_forget_zone_t)(librpz_emsg_t *emsg, librpz_cznum_t znum, + librpz_rsp_t *rsp); +LIBDEF_F(rsp_forget_zone) + +/** + * Apply RPZ to an IP address. + * @param[out] emsg + * @param addr: address to check + * @param ipv6: true for 16 byte IPv6 instead of 4 byte IPv4 + * @param trig LIBRPZ_TRIG_CLIENT_IP, LIBRPZ_TRIG_IP, or LIBRPZ_TRIG_NSIP + * @param hit_id: caller chosen + * @param recursed: recursion has been done + * @param[in,out] rsp state from librpz_itr_start() + * @return false on error + */ +typedef bool(librpz_ck_ip_t)(librpz_emsg_t *emsg, const void *addr, uint family, + librpz_trig_t trig, librpz_result_id_t hit_id, + bool recursed, librpz_rsp_t *rsp); +LIBDEF_F(ck_ip) + +/** + * Apply RPZ to a wire-format domain. + * @param[out] emsg + * @param domain in wire format + * @param domain_size + * @param trig LIBRPZ_TRIG_QNAME or LIBRPZ_TRIG_NSDNAME + * @param hit_id: caller chosen + * @param recursed: recursion has been done + * @param[in,out] rsp state from librpz_itr_start() + * @return false on error + */ +typedef bool(librpz_ck_domain_t)(librpz_emsg_t *emsg, const uint8_t *domain, + size_t domain_size, librpz_trig_t trig, + librpz_result_id_t hit_id, bool recursed, + librpz_rsp_t *rsp); +LIBDEF_F(ck_domain) + +/** + * Ask dnsrpzd to refresh a zone. + * @param[out] emsg error message + * @param librpz_domain_t domain to refresh + * @param client context + * @return false after error + */ +typedef bool(librpz_zone_refresh_t)(librpz_emsg_t *emsg, const char *domain, + librpz_rsp_t *rsp); +LIBDEF_F(zone_refresh) + +/** + * Get a string describing the database + * @param license: include the license + * @param cfiles: include the configuration file names + * @param listens: include the local notify IP addresses + * @param[out] emsg error message if the result is null + * @param client context + * @return malloc'ed string or NULL after error + */ +typedef char *(librpz_db_info_t)(librpz_emsg_t *emsg, bool license, bool cfiles, + bool listens, librpz_rsp_t *rsp); +LIBDEF_F(db_info) + +/** + * Start a context for listing the nodes and/or zones in the mapped file + * @param[out] emsg: error message for false return or *rspp=NULL + * @param[out] rspp: created context or NULL + * @param client context + * @return false after error + */ +typedef bool(librpz_itr_start_t)(librpz_emsg_t *emsg, librpz_rsp_t **rspp, + librpz_client_t *client); +LIBDEF_F(itr_start) + +/** + * Get mapped file memory allocation statistics. + * @param[out] emsg: error message + * @param rsp state from librpz_itr_start() + * @return malloc'ed string or NULL after error + */ +typedef char *(librpz_mf_stats_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp); +LIBDEF_F(mf_stats) + +/** + * Get versions currently used by clients. + * @param[out] emsg: error message + * @param[in,out] rsp: state from librpz_itr_start() + * @return malloc'ed string or NULL after error + */ +typedef char *(librpz_vers_stats_t)(librpz_emsg_t *emsg, librpz_rsp_t *rsp); +LIBDEF_F(vers_stats) + +/** + * Allocate a string describing the next zone or "" after the last zone. + * @param[out] emsg + * @param all_zones to list all instead of only requested zones + * @param[in,out] rsp state from librpz_rsp_start() + * @return malloc'ed string or NULL after error + */ +typedef char *(librpz_itr_zone_t)(librpz_emsg_t *emsg, bool all_zones, + librpz_rsp_t *rsp); +LIBDEF_F(itr_zone) + +/** + * Describe the next trie node while dumping the database. + * @param[out] emsg + * @param[out] result describes node + * or result->policy=LIBRPZ_POLICY_UNDEFINED after the last node. + * @param all_zones to list all instead of only requested zones + * @param[in,out] rsp state from librpz_itr_start() + * @return: false on error + */ +typedef bool(librpz_itr_node_t)(librpz_emsg_t *emsg, librpz_result_t *result, + bool all_zones, librpz_rsp_t *rsp); +LIBDEF_F(itr_node) + +/** + * RPZ policy to string with a backup buffer of POLICY2STR_SIZE size + */ +typedef const char *(librpz_policy2str_t)(librpz_policy_t policy, char *buf, + size_t buf_size); +#define POLICY2STR_SIZE sizeof("policy xxxxxx") +LIBDEF_F(policy2str) + +/** + * Trigger type to string. + */ +typedef const char *(librpz_trig2str_t)(librpz_trig_t trig); +LIBDEF_F(trig2str) + +/** + * Convert a number of seconds to a zone file duration string + */ +typedef const char *(librpz_secs2str_t)(time_t secs, char *buf, + size_t buf_size); +#define SECS2STR_SIZE sizeof("1234567w7d24h59m59s") +LIBDEF_F(secs2str) + +/** + * Parse a duration with 's', 'm', 'h', 'd', and 'w' units. + */ +typedef bool(librpz_str2secs_t)(librpz_emsg_t *emsg, time_t *val, + const char *str0); +LIBDEF_F(str2secs) + +/** + * Translate selected rtypes to strings + */ +typedef const char *(librpz_rtype2str_t)(uint type, char *buf, size_t buf_size); +#define RTYPE2STR_SIZE sizeof("type xxxxx") +LIBDEF_F(rtype2str) + +/** + * Local version of ns_name_ntop() for portability. + */ +typedef int(librpz_domain_ntop_t)(const u_char *src, char *dst, size_t dstsiz); +LIBDEF_F(domain_ntop) + +/** + * Local version of ns_name_pton(). + */ +typedef int(librpz_domain_pton2_t)(const char *src, u_char *dst, size_t dstsiz, + size_t *dstlen, bool lower); +LIBDEF_F(domain_pton2) + +typedef union socku socku_t; +typedef socku_t *(librpz_mk_inet_su_t)(socku_t *su, const struct in_addr *addrp, + in_port_t port); +LIBDEF_F(mk_inet_su) + +typedef socku_t *(librpz_mk_inet6_su_t)(socku_t *su, + const struct in6_addr *addrp, + uint32_t scope_id, in_port_t port); +LIBDEF_F(mk_inet6_su) + +typedef bool(librpz_str2su_t)(socku_t *sup, const char *str); +LIBDEF_F(str2su) + +typedef char *(librpz_su2str_t)(char *str, size_t str_len, const socku_t *su); +LIBDEF_F(su2str) +#define SU2STR_SIZE (INET6_ADDRSTRLEN + 1 + 6 + 1) + +/** + * default path to dnsrpzd + */ +LIBDEF(const char *, librpz_dnsrpzd_path) + +#undef LIBDEF + +/* + * This is the dlopen() interface to librpz. + */ +typedef const struct { + const char *dnsrpzd_path; + const char *version; + librpz_parse_log_opt_t *parse_log_opt; + librpz_log_level_val_t *log_level_val; + librpz_set_log_t *set_log; + librpz_vpemsg_t *vpemsg; + librpz_pemsg_t *pemsg; + librpz_vlog_t *vlog; + librpz_log_t *log; + librpz_fatal_t *fatal LIBRPZ_NORET; + librpz_rpz_assert_t *rpz_assert LIBRPZ_NORET; + librpz_rpz_vassert_t *rpz_vassert LIBRPZ_NORET; + librpz_clist_create_t *clist_create; + librpz_clist_detach_t *clist_detach; + librpz_client_create_t *client_create; + librpz_connect_t *connect; + librpz_client_detach_t *client_detach; + librpz_rsp_create_t *rsp_create; + librpz_rsp_detach_t *rsp_detach; + librpz_rsp_result_t *rsp_result; + librpz_have_trig_t *have_trig; + librpz_have_ns_trig_t *have_ns_trig; + librpz_rsp_clientip_prefix_t *rsp_clientip_prefix; + librpz_rsp_domain_t *rsp_domain; + librpz_rsp_rr_t *rsp_rr; + librpz_rsp_soa_t *rsp_soa; + librpz_soa_serial_t *soa_serial; + librpz_rsp_push_t *rsp_push; + librpz_rsp_pop_t *rsp_pop; + librpz_rsp_pop_discard_t *rsp_pop_discard; + librpz_rsp_forget_zone_t *rsp_forget_zone; + librpz_ck_ip_t *ck_ip; + librpz_ck_domain_t *ck_domain; + librpz_zone_refresh_t *zone_refresh; + librpz_db_info_t *db_info; + librpz_itr_start_t *itr_start; + librpz_mf_stats_t *mf_stats; + librpz_vers_stats_t *vers_stats; + librpz_itr_zone_t *itr_zone; + librpz_itr_node_t *itr_node; + librpz_policy2str_t *policy2str; + librpz_trig2str_t *trig2str; + librpz_secs2str_t *secs2str; + librpz_str2secs_t *str2secs; + librpz_rtype2str_t *rtype2str; + librpz_domain_ntop_t *domain_ntop; + librpz_domain_pton2_t *domain_pton2; + librpz_mk_inet_su_t *mk_inet_su; + librpz_mk_inet6_su_t *mk_inet6_su; + librpz_str2su_t *str2su; + librpz_su2str_t *su2str; +} librpz_0_t; +extern librpz_0_t librpz_def_0; + +/* + * Future versions can be upward compatible by defining LIBRPZ_DEF as + * librpz_X_t. + */ +#define LIBRPZ_DEF librpz_def_0 +#define LIBRPZ_DEF_STR "librpz_def_0" + +typedef librpz_0_t librpz_t; +extern librpz_t *librpz; + +#if LIBRPZ_LIB_OPEN == 2 +#include <dlfcn.h> + +/** + * link-load librpz + * @param[out] emsg: error message + * @param[in,out] dl_handle: NULL or pointer to new dlopen handle + * @param[in] path: librpz.so path + * @return address of interface structure or NULL on failure + */ +static inline librpz_t * +librpz_lib_open(librpz_emsg_t *emsg, void **dl_handle, const char *path) { + void *handle; + librpz_t *new_librpz; + + emsg->c[0] = '\0'; + + /* + * Close a previously opened handle on librpz.so. + */ + if (dl_handle != NULL && *dl_handle != NULL) { + if (dlclose(*dl_handle) != 0) { + snprintf(emsg->c, sizeof(librpz_emsg_t), + "dlopen(NULL): %s", dlerror()); + return (NULL); + } + *dl_handle = NULL; + } + + /* + * First try the main executable of the process in case it was + * linked to librpz. + * Do not worry if we cannot search the main executable of the process. + */ + handle = dlopen(NULL, RTLD_NOW | RTLD_LOCAL); + if (handle != NULL) { + new_librpz = dlsym(handle, LIBRPZ_DEF_STR); + if (new_librpz != NULL) { + if (dl_handle != NULL) { + *dl_handle = handle; + } + return (new_librpz); + } + if (dlclose(handle) != 0) { + snprintf(emsg->c, sizeof(librpz_emsg_t), + "dlsym(NULL, " LIBRPZ_DEF_STR "): %s", + dlerror()); + return (NULL); + } + } + + if (path == NULL || path[0] == '\0') { + snprintf(emsg->c, sizeof(librpz_emsg_t), + "librpz not linked and no dlopen() path provided"); + return (NULL); + } + + handle = dlopen(path, RTLD_NOW | RTLD_LOCAL); + if (handle == NULL) { + snprintf(emsg->c, sizeof(librpz_emsg_t), "dlopen(%s): %s", path, + dlerror()); + return (NULL); + } + new_librpz = dlsym(handle, LIBRPZ_DEF_STR); + if (new_librpz != NULL) { + if (dl_handle != NULL) { + *dl_handle = handle; + } + return (new_librpz); + } + snprintf(emsg->c, sizeof(librpz_emsg_t), + "dlsym(%s, " LIBRPZ_DEF_STR "): %s", path, dlerror()); + dlclose(handle); + return (NULL); +} +#elif defined(LIBRPZ_LIB_OPEN) +/* + * Statically link to the librpz.so DSO on systems without dlopen() + */ +static inline librpz_t * +librpz_lib_open(librpz_emsg_t *emsg, void **dl_handle, const char *path) { + (void)(path); + + if (dl_handle != NULL) { + *dl_handle = NULL; + } + +#if LIBRPZ_LIB_OPEN == 1 + emsg->c[0] = '\0'; + return (&LIBRPZ_DEF); +#else /* if LIBRPZ_LIB_OPEN == 1 */ + snprintf(emsg->c, sizeof(librpz_emsg_t), + "librpz not available via ./configure"); + return (NULL); +#endif /* LIBRPZ_LIB_OPEN */ +} +#endif /* LIBRPZ_LIB_OPEN */ + +#endif /* LIBRPZ_H */ diff --git a/lib/dns/include/dns/lmdb.h b/lib/dns/include/dns/lmdb.h new file mode 100644 index 0000000..f6986cf --- /dev/null +++ b/lib/dns/include/dns/lmdb.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 + +#define DNS_LMDB_COMMON_FLAGS (MDB_CREATE | MDB_NOSUBDIR | MDB_NOLOCK) +#ifndef __OpenBSD__ +#define DNS_LMDB_FLAGS (DNS_LMDB_COMMON_FLAGS) +#else /* __OpenBSD__ */ +/* + * OpenBSD does not have a unified buffer cache, which requires both reads and + * writes to be performed using mmap(). + */ +#define DNS_LMDB_FLAGS (DNS_LMDB_COMMON_FLAGS | MDB_WRITEMAP) +#endif /* __OpenBSD__ */ diff --git a/lib/dns/include/dns/log.h b/lib/dns/include/dns/log.h new file mode 100644 index 0000000..d78dda6 --- /dev/null +++ b/lib/dns/include/dns/log.h @@ -0,0 +1,114 @@ +/* + * 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. + */ + +/*! \file dns/log.h + */ + +#ifndef DNS_LOG_H +#define DNS_LOG_H 1 + +#include <isc/lang.h> +#include <isc/log.h> + +LIBDNS_EXTERNAL_DATA extern isc_log_t *dns_lctx; +LIBDNS_EXTERNAL_DATA extern isc_logcategory_t dns_categories[]; +LIBDNS_EXTERNAL_DATA extern isc_logmodule_t dns_modules[]; + +#define DNS_LOGCATEGORY_NOTIFY (&dns_categories[0]) +#define DNS_LOGCATEGORY_DATABASE (&dns_categories[1]) +#define DNS_LOGCATEGORY_SECURITY (&dns_categories[2]) +/* DNS_LOGCATEGORY_CONFIG superseded by CFG_LOGCATEGORY_CONFIG */ +#define DNS_LOGCATEGORY_DNSSEC (&dns_categories[4]) +#define DNS_LOGCATEGORY_RESOLVER (&dns_categories[5]) +#define DNS_LOGCATEGORY_XFER_IN (&dns_categories[6]) +#define DNS_LOGCATEGORY_XFER_OUT (&dns_categories[7]) +#define DNS_LOGCATEGORY_DISPATCH (&dns_categories[8]) +#define DNS_LOGCATEGORY_LAME_SERVERS (&dns_categories[9]) +#define DNS_LOGCATEGORY_DELEGATION_ONLY (&dns_categories[10]) +#define DNS_LOGCATEGORY_EDNS_DISABLED (&dns_categories[11]) +#define DNS_LOGCATEGORY_RPZ (&dns_categories[12]) +#define DNS_LOGCATEGORY_RRL (&dns_categories[13]) +#define DNS_LOGCATEGORY_CNAME (&dns_categories[14]) +#define DNS_LOGCATEGORY_SPILL (&dns_categories[15]) +#define DNS_LOGCATEGORY_DNSTAP (&dns_categories[16]) +#define DNS_LOGCATEGORY_ZONELOAD (&dns_categories[17]) +#define DNS_LOGCATEGORY_NSID (&dns_categories[18]) + +/* Backwards compatibility. */ +#define DNS_LOGCATEGORY_GENERAL ISC_LOGCATEGORY_GENERAL + +#define DNS_LOGMODULE_DB (&dns_modules[0]) +#define DNS_LOGMODULE_RBTDB (&dns_modules[1]) +#define DNS_LOGMODULE_RBT (&dns_modules[2]) +#define DNS_LOGMODULE_RDATA (&dns_modules[3]) +#define DNS_LOGMODULE_MASTER (&dns_modules[4]) +#define DNS_LOGMODULE_MESSAGE (&dns_modules[5]) +#define DNS_LOGMODULE_CACHE (&dns_modules[6]) +#define DNS_LOGMODULE_CONFIG (&dns_modules[7]) +#define DNS_LOGMODULE_RESOLVER (&dns_modules[8]) +#define DNS_LOGMODULE_ZONE (&dns_modules[9]) +#define DNS_LOGMODULE_JOURNAL (&dns_modules[10]) +#define DNS_LOGMODULE_ADB (&dns_modules[11]) +#define DNS_LOGMODULE_XFER_IN (&dns_modules[12]) +#define DNS_LOGMODULE_XFER_OUT (&dns_modules[13]) +#define DNS_LOGMODULE_ACL (&dns_modules[14]) +#define DNS_LOGMODULE_VALIDATOR (&dns_modules[15]) +#define DNS_LOGMODULE_DISPATCH (&dns_modules[16]) +#define DNS_LOGMODULE_REQUEST (&dns_modules[17]) +#define DNS_LOGMODULE_MASTERDUMP (&dns_modules[18]) +#define DNS_LOGMODULE_TSIG (&dns_modules[19]) +#define DNS_LOGMODULE_TKEY (&dns_modules[20]) +#define DNS_LOGMODULE_SDB (&dns_modules[21]) +#define DNS_LOGMODULE_DIFF (&dns_modules[22]) +#define DNS_LOGMODULE_HINTS (&dns_modules[23]) +#define DNS_LOGMODULE_UNUSED1 (&dns_modules[24]) +#define DNS_LOGMODULE_DLZ (&dns_modules[25]) +#define DNS_LOGMODULE_DNSSEC (&dns_modules[26]) +#define DNS_LOGMODULE_CRYPTO (&dns_modules[27]) +#define DNS_LOGMODULE_PACKETS (&dns_modules[28]) +#define DNS_LOGMODULE_NTA (&dns_modules[29]) +#define DNS_LOGMODULE_DYNDB (&dns_modules[30]) +#define DNS_LOGMODULE_DNSTAP (&dns_modules[31]) +#define DNS_LOGMODULE_SSU (&dns_modules[32]) + +ISC_LANG_BEGINDECLS + +void +dns_log_init(isc_log_t *lctx); +/*% + * Make the libdns categories and modules available for use with the + * ISC logging library. + * + * Requires: + *\li lctx is a valid logging context. + * + *\li dns_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 +dns_log_setcontext(isc_log_t *lctx); +/*% + * Make the libdns library use the provided context for logging internal + * messages. + * + * Requires: + *\li lctx is a valid logging context. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_LOG_H */ diff --git a/lib/dns/include/dns/lookup.h b/lib/dns/include/dns/lookup.h new file mode 100644 index 0000000..2d1ce13 --- /dev/null +++ b/lib/dns/include/dns/lookup.h @@ -0,0 +1,131 @@ +/* + * 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. + */ + +#ifndef DNS_LOOKUP_H +#define DNS_LOOKUP_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/lookup.h + * \brief + * The lookup module performs simple DNS lookups. It implements + * the full resolver algorithm, both looking for local data and + * resolving external names as necessary. + * + * MP: + *\li The module ensures appropriate synchronization of data structures it + * creates and manipulates. + * + * Reliability: + *\li No anticipated impact. + * + * Resources: + *\li TBS + * + * Security: + *\li No anticipated impact. + * + * Standards: + *\li RFCs: 1034, 1035, 2181, TBS + *\li Drafts: TBS + */ + +#include <isc/event.h> +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/*% + * A 'dns_lookupevent_t' is returned when a lookup completes. + * The sender field will be set to the lookup that completed. If 'result' + * is ISC_R_SUCCESS, then 'names' will contain a list of names associated + * with the address. The recipient of the event must not change the list + * and must not refer to any of the name data after the event is freed. + */ +typedef struct dns_lookupevent { + ISC_EVENT_COMMON(struct dns_lookupevent); + isc_result_t result; + dns_name_t *name; + dns_rdataset_t *rdataset; + dns_rdataset_t *sigrdataset; + dns_db_t *db; + dns_dbnode_t *node; +} dns_lookupevent_t; + +isc_result_t +dns_lookup_create(isc_mem_t *mctx, const dns_name_t *name, dns_rdatatype_t type, + dns_view_t *view, unsigned int options, isc_task_t *task, + isc_taskaction_t action, void *arg, dns_lookup_t **lookupp); +/*%< + * Finds the rrsets matching 'name' and 'type'. + * + * Requires: + * + *\li 'mctx' is a valid mctx. + * + *\li 'name' is a valid name. + * + *\li 'view' is a valid view which has a resolver. + * + *\li 'task' is a valid task. + * + *\li lookupp != NULL && *lookupp == NULL + * + * Returns: + * + *\li ISC_R_SUCCESS + *\li ISC_R_NOMEMORY + * + *\li Any resolver-related error (e.g. ISC_R_SHUTTINGDOWN) may also be + * returned. + */ + +void +dns_lookup_cancel(dns_lookup_t *lookup); +/*%< + * Cancel 'lookup'. + * + * Notes: + * + *\li If 'lookup' has not completed, post its LOOKUPDONE event with a + * result code of ISC_R_CANCELED. + * + * Requires: + * + *\li 'lookup' is a valid lookup. + */ + +void +dns_lookup_destroy(dns_lookup_t **lookupp); +/*%< + * Destroy 'lookup'. + * + * Requires: + * + *\li '*lookupp' is a valid lookup. + * + *\li The caller has received the LOOKUPDONE event (either because the + * lookup completed or because dns_lookup_cancel() was called). + * + * Ensures: + * + *\li *lookupp == NULL. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_LOOKUP_H */ diff --git a/lib/dns/include/dns/master.h b/lib/dns/include/dns/master.h new file mode 100644 index 0000000..78ebadd --- /dev/null +++ b/lib/dns/include/dns/master.h @@ -0,0 +1,264 @@ +/* + * 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. + */ + +#ifndef DNS_MASTER_H +#define DNS_MASTER_H 1 + +/*! \file dns/master.h */ + +/*** + *** Imports + ***/ + +#include <inttypes.h> +#include <stdio.h> + +#include <isc/lang.h> + +#include <dns/types.h> + +/* + * Flags to be passed in the 'options' argument in the functions below. + */ +#define DNS_MASTER_AGETTL 0x00000001 /*%< Age the ttl based on $DATE. */ +#define DNS_MASTER_MANYERRORS \ + 0x00000002 /*%< Continue processing on errors. \ + */ +#define DNS_MASTER_NOINCLUDE 0x00000004 /*%< Disallow $INCLUDE directives. */ +#define DNS_MASTER_ZONE 0x00000008 /*%< Loading a zone master file. */ +#define DNS_MASTER_HINT 0x00000010 /*%< Loading a hint master file. */ +#define DNS_MASTER_SLAVE 0x00000020 /*%< Loading a slave master file. */ +#define DNS_MASTER_CHECKNS \ + 0x00000040 /*%< \ + * Check NS records to see \ + * if they are an address \ + */ +#define DNS_MASTER_FATALNS \ + 0x00000080 /*%< \ + * Treat DNS_MASTER_CHECKNS \ + * matches as fatal \ + */ +#define DNS_MASTER_CHECKNAMES 0x00000100 +#define DNS_MASTER_CHECKNAMESFAIL 0x00000200 +#define DNS_MASTER_CHECKWILDCARD \ + 0x00000400 /* Check for internal wildcards. \ + */ +#define DNS_MASTER_CHECKMX 0x00000800 +#define DNS_MASTER_CHECKMXFAIL 0x00001000 + +#define DNS_MASTER_RESIGN 0x00002000 +#define DNS_MASTER_KEY 0x00004000 /*%< Loading a key zone master file. */ +#define DNS_MASTER_NOTTL 0x00008000 /*%< Don't require ttl. */ +#define DNS_MASTER_CHECKTTL 0x00010000 /*%< Check max-zone-ttl */ + +ISC_LANG_BEGINDECLS + +/* + * Structures that implement the "raw" format for master dump. + * These are provided for a reference purpose only; in the actual + * encoding, we directly read/write each field so that the encoded data + * is always "packed", regardless of the hardware architecture. + */ +#define DNS_RAWFORMAT_VERSION 1 + +/* + * Flags to indicate the status of the data in the raw file header + */ +#define DNS_MASTERRAW_COMPAT 0x01 +#define DNS_MASTERRAW_SOURCESERIALSET 0x02 +#define DNS_MASTERRAW_LASTXFRINSET 0x04 + +/* Common header */ +struct dns_masterrawheader { + uint32_t format; /* must be + * dns_masterformat_raw + * or + * dns_masterformat_map */ + uint32_t version; /* compatibility for future + * extensions */ + uint32_t dumptime; /* timestamp on creation + * (currently unused) */ + uint32_t flags; /* Flags */ + uint32_t sourceserial; /* Source serial number (used + * by inline-signing zones) */ + uint32_t lastxfrin; /* timestamp of last transfer + * (used by slave zones) */ +}; + +/* The structure for each RRset */ +typedef struct { + uint32_t totallen; /* length of the data for this + * RRset, including the + * "header" part */ + dns_rdataclass_t rdclass; /* 16-bit class */ + dns_rdatatype_t type; /* 16-bit type */ + dns_rdatatype_t covers; /* same as type */ + dns_ttl_t ttl; /* 32-bit TTL */ + uint32_t nrdata; /* number of RRs in this set */ + /* followed by encoded owner name, and then rdata */ +} dns_masterrawrdataset_t; + +/* + * Method prototype: a callback to register each include file as + * it is encountered. + */ +typedef void (*dns_masterincludecb_t)(const char *file, void *arg); + +/*** + *** Function + ***/ + +isc_result_t +dns_master_loadfile(const char *master_file, dns_name_t *top, + dns_name_t *origin, dns_rdataclass_t zclass, + unsigned int options, uint32_t resign, + dns_rdatacallbacks_t *callbacks, + dns_masterincludecb_t include_cb, void *include_arg, + isc_mem_t *mctx, dns_masterformat_t format, + dns_ttl_t maxttl); + +isc_result_t +dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin, + dns_rdataclass_t zclass, unsigned int options, + dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx); + +isc_result_t +dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top, dns_name_t *origin, + dns_rdataclass_t zclass, unsigned int options, + dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx); + +isc_result_t +dns_master_loadlexer(isc_lex_t *lex, dns_name_t *top, dns_name_t *origin, + dns_rdataclass_t zclass, unsigned int options, + dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx); + +isc_result_t +dns_master_loadfileinc(const char *master_file, dns_name_t *top, + dns_name_t *origin, dns_rdataclass_t zclass, + unsigned int options, uint32_t resign, + dns_rdatacallbacks_t *callbacks, isc_task_t *task, + dns_loaddonefunc_t done, void *done_arg, + dns_loadctx_t **ctxp, dns_masterincludecb_t include_cb, + void *include_arg, isc_mem_t *mctx, + dns_masterformat_t format, uint32_t maxttl); + +isc_result_t +dns_master_loadstreaminc(FILE *stream, dns_name_t *top, dns_name_t *origin, + dns_rdataclass_t zclass, unsigned int options, + dns_rdatacallbacks_t *callbacks, isc_task_t *task, + dns_loaddonefunc_t done, void *done_arg, + dns_loadctx_t **ctxp, isc_mem_t *mctx); + +isc_result_t +dns_master_loadbufferinc(isc_buffer_t *buffer, dns_name_t *top, + dns_name_t *origin, dns_rdataclass_t zclass, + unsigned int options, dns_rdatacallbacks_t *callbacks, + isc_task_t *task, dns_loaddonefunc_t done, + void *done_arg, dns_loadctx_t **ctxp, isc_mem_t *mctx); + +isc_result_t +dns_master_loadlexerinc(isc_lex_t *lex, dns_name_t *top, dns_name_t *origin, + dns_rdataclass_t zclass, unsigned int options, + dns_rdatacallbacks_t *callbacks, isc_task_t *task, + dns_loaddonefunc_t done, void *done_arg, + dns_loadctx_t **ctxp, isc_mem_t *mctx); + +/*%< + * Loads a RFC1305 master file from a file, stream, buffer, or existing + * lexer into rdatasets and then calls 'callbacks->commit' to commit the + * rdatasets. Rdata memory belongs to dns_master_load and will be + * reused / released when the callback completes. dns_load_master will + * abort if callbacks->commit returns any value other than ISC_R_SUCCESS. + * + * If 'DNS_MASTER_AGETTL' is set and the master file contains one or more + * $DATE directives, the TTLs of the data will be aged accordingly. + * + * 'callbacks->commit' is assumed to call 'callbacks->error' or + * 'callbacks->warn' to generate any error messages required. + * + * 'done' is called with 'done_arg' and a result code when the loading + * is completed or has failed. If the initial setup fails 'done' is + * not called. + * + * 'resign' the number of seconds before a RRSIG expires that it should + * be re-signed. 0 is used if not provided. + * + * Requires: + *\li 'master_file' points to a valid string. + *\li 'lexer' points to a valid lexer. + *\li 'top' points to a valid name. + *\li 'origin' points to a valid name. + *\li 'callbacks->commit' points to a valid function. + *\li 'callbacks->error' points to a valid function. + *\li 'callbacks->warn' points to a valid function. + *\li 'mctx' points to a valid memory context. + *\li 'task' and 'done' to be valid. + *\li 'lmgr' to be valid. + *\li 'ctxp != NULL && ctxp == NULL'. + * + * Returns: + *\li ISC_R_SUCCESS upon successfully loading the master file. + *\li ISC_R_SEENINCLUDE upon successfully loading the master file with + * a $INCLUDE statement. + *\li ISC_R_NOMEMORY out of memory. + *\li ISC_R_UNEXPECTEDEND expected to be able to read a input token and + * there was not one. + *\li ISC_R_UNEXPECTED + *\li DNS_R_NOOWNER failed to specify a ownername. + *\li DNS_R_NOTTL failed to specify a ttl. + *\li DNS_R_BADCLASS record class did not match zone class. + *\li DNS_R_CONTINUE load still in progress (dns_master_load*inc() only). + *\li Any dns_rdata_fromtext() error code. + *\li Any error code from callbacks->commit(). + */ + +void +dns_loadctx_detach(dns_loadctx_t **ctxp); +/*%< + * Detach from the load context. + * + * Requires: + *\li '*ctxp' to be valid. + * + * Ensures: + *\li '*ctxp == NULL' + */ + +void +dns_loadctx_attach(dns_loadctx_t *source, dns_loadctx_t **target); +/*%< + * Attach to the load context. + * + * Requires: + *\li 'source' to be valid. + *\li 'target != NULL && *target == NULL'. + */ + +void +dns_loadctx_cancel(dns_loadctx_t *ctx); +/*%< + * Cancel loading the zone file associated with this load context. + * + * Requires: + *\li 'ctx' to be valid + */ + +void +dns_master_initrawheader(dns_masterrawheader_t *header); +/*%< + * Initializes the header for a raw master file, setting all + * values to zero. + */ +ISC_LANG_ENDDECLS + +#endif /* DNS_MASTER_H */ diff --git a/lib/dns/include/dns/masterdump.h b/lib/dns/include/dns/masterdump.h new file mode 100644 index 0000000..917e31f --- /dev/null +++ b/lib/dns/include/dns/masterdump.h @@ -0,0 +1,364 @@ +/* + * 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. + */ + +#ifndef DNS_MASTERDUMP_H +#define DNS_MASTERDUMP_H 1 + +/*! \file dns/masterdump.h */ + +/*** + *** Imports + ***/ + +#include <stdio.h> + +#include <isc/lang.h> + +#include <dns/types.h> + +/*** + *** Types + ***/ + +typedef struct dns_master_style dns_master_style_t; + +/*** + *** Definitions + ***/ + +/* + * Flags affecting master file formatting. Flags 0x0000FFFF + * define the formatting of the rdata part and are defined in + * rdata.h. + */ + +/*% Omit the owner name when possible. */ +#define DNS_STYLEFLAG_OMIT_OWNER 0x000010000ULL + +/*% + * Omit the TTL when possible. If DNS_STYLEFLAG_TTL is + * also set, this means no TTLs are ever printed + * because $TTL directives are generated before every + * change in the TTL. In this case, no columns need to + * be reserved for the TTL. Master files generated with + * these options will be rejected by BIND 4.x because it + * does not recognize the $TTL directive. + * + * If DNS_STYLEFLAG_TTL is not also set, the TTL will be + * omitted when it is equal to the previous TTL. + * This is correct according to RFC1035, but the + * TTLs may be silently misinterpreted by older + * versions of BIND which use the SOA MINTTL as a + * default TTL value. + */ +#define DNS_STYLEFLAG_OMIT_TTL 0x000020000ULL + +/*% Omit the class when possible. */ +#define DNS_STYLEFLAG_OMIT_CLASS 0x000040000ULL + +/*% Output $TTL directives. */ +#define DNS_STYLEFLAG_TTL 0x000080000ULL + +/*% + * Output $ORIGIN directives and print owner names relative to + * the origin when possible. + */ +#define DNS_STYLEFLAG_REL_OWNER 0x000100000ULL + +/*% Print domain names in RR data in relative form when possible. + * For this to take effect, DNS_STYLEFLAG_REL_OWNER must also be set. */ +#define DNS_STYLEFLAG_REL_DATA 0x000200000ULL + +/*% Print the trust level of each rdataset. */ +#define DNS_STYLEFLAG_TRUST 0x000400000ULL + +/*% Print negative caching entries. */ +#define DNS_STYLEFLAG_NCACHE 0x000800000ULL + +/*% Never print the TTL. */ +#define DNS_STYLEFLAG_NO_TTL 0x001000000ULL + +/*% Never print the CLASS. */ +#define DNS_STYLEFLAG_NO_CLASS 0x002000000ULL + +/*% Report re-signing time. */ +#define DNS_STYLEFLAG_RESIGN 0x004000000ULL + +/*% Don't printout the cryptographic parts of DNSSEC records. */ +#define DNS_STYLEFLAG_NOCRYPTO 0x008000000ULL + +/*% Comment out data by prepending with ";" */ +#define DNS_STYLEFLAG_COMMENTDATA 0x010000000ULL + +/*% Print TTL with human-readable units. */ +#define DNS_STYLEFLAG_TTL_UNITS 0x020000000ULL + +/*% Indent output. */ +#define DNS_STYLEFLAG_INDENT 0x040000000ULL + +/*% Output in YAML style. */ +#define DNS_STYLEFLAG_YAML 0x080000000ULL + +/*% Print ECS cache entries as comments (reserved for future use). */ +#define DNS_STYLEFLAG_ECSCACHE 0x100000000ULL + +/*% Print expired cache entries. */ +#define DNS_STYLEFLAG_EXPIRED 0x200000000ULL + +ISC_LANG_BEGINDECLS + +/*** + *** Constants + ***/ + +/*% + * The default master file style. + * + * This uses $TTL directives to avoid the need to dedicate a + * tab stop for the TTL. The class is only printed for the first + * rrset in the file and shares a tab stop with the RR type. + */ +LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_default; + +/*% + * A master file style that dumps zones to a very generic format easily + * imported/checked with external tools. + */ +LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_full; + +/*% + * A master file style that prints explicit TTL values on each + * record line, never using $TTL statements. The TTL has a tab + * stop of its own, but the class and type share one. + */ +LIBDNS_EXTERNAL_DATA extern const dns_master_style_t + dns_master_style_explicitttl; + +/*% + * A master style format designed for cache files. It prints explicit TTL + * values on each record line and never uses $ORIGIN or relative names. + */ +LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_cache; + +/*% + * A master style format designed for cache files. The same as above but + * this also prints expired entries. + */ +LIBDNS_EXTERNAL_DATA extern const dns_master_style_t + dns_master_style_cache_with_expired; + +/*% + * A master style that prints name, ttl, class, type, and value on + * every line. Similar to explicitttl above, but more verbose. + * Intended for generating master files which can be easily parsed + * by perl scripts and similar applications. + */ +LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_simple; + +/*% + * The style used for debugging, "dig" output, etc. + */ +LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_debug; + +/*% + * Similar to dns_master_style_debug but data is prepended with ";" + */ +LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_comment; + +/*% + * Similar to dns_master_style_debug but data is indented with "\t" (tab) + */ +LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_indent; + +/*% + * The style used for dumping "key" zones. + */ +LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_keyzone; + +/*% + * YAML-compatible output + */ +LIBDNS_EXTERNAL_DATA extern const dns_master_style_t dns_master_style_yaml; + +/*** + *** Functions + ***/ + +void +dns_dumpctx_attach(dns_dumpctx_t *source, dns_dumpctx_t **target); +/*%< + * Attach to a dump context. + * + * Require: + *\li 'source' to be valid. + *\li 'target' to be non NULL and '*target' to be NULL. + */ + +void +dns_dumpctx_detach(dns_dumpctx_t **dctxp); +/*%< + * Detach from a dump context. + * + * Require: + *\li 'dctxp' to point to a valid dump context. + * + * Ensures: + *\li '*dctxp' is NULL. + */ + +void +dns_dumpctx_cancel(dns_dumpctx_t *dctx); +/*%< + * Cancel a in progress dump. + * + * Require: + *\li 'dctx' to be valid. + */ + +dns_dbversion_t * +dns_dumpctx_version(dns_dumpctx_t *dctx); +/*%< + * Return the version handle (if any) of the database being dumped. + * + * Require: + *\li 'dctx' to be valid. + */ + +dns_db_t * +dns_dumpctx_db(dns_dumpctx_t *dctx); +/*%< + * Return the database being dumped. + * + * Require: + *\li 'dctx' to be valid. + */ + +/*@{*/ +isc_result_t +dns_master_dumptostreamasync(isc_mem_t *mctx, dns_db_t *db, + dns_dbversion_t *version, + const dns_master_style_t *style, FILE *f, + isc_task_t *task, dns_dumpdonefunc_t done, + void *done_arg, dns_dumpctx_t **dctxp); + +isc_result_t +dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, + const dns_master_style_t *style, + dns_masterformat_t format, + dns_masterrawheader_t *header, FILE *f); +/*%< + * Dump the database 'db' to the steam 'f' in the specified format by + * 'format'. If the format is dns_masterformat_text (the RFC1035 format), + * 'style' specifies the file style (e.g., &dns_master_style_default). + * + * If 'format' is dns_masterformat_raw, then 'header' can contain + * information to be written to the file header. + * + * Temporary dynamic memory may be allocated from 'mctx'. + * + * Require: + *\li 'task' to be valid. + *\li 'done' to be non NULL. + *\li 'dctxp' to be non NULL && '*dctxp' to be NULL. + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOMEMORY + *\li Any database or rrset iterator error. + *\li Any dns_rdata_totext() error code. + */ +/*@}*/ + +/*@{*/ + +isc_result_t +dns_master_dumpasync(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, + const dns_master_style_t *style, const char *filename, + isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg, + dns_dumpctx_t **dctxp, dns_masterformat_t format, + dns_masterrawheader_t *header); + +isc_result_t +dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, + const dns_master_style_t *style, const char *filename, + dns_masterformat_t format, dns_masterrawheader_t *header); + +/*%< + * Dump the database 'db' to the file 'filename' in the specified format by + * 'format'. If the format is dns_masterformat_text (the RFC1035 format), + * 'style' specifies the file style (e.g., &dns_master_style_default). + * + * If 'format' is dns_masterformat_raw, then 'header' can contain + * information to be written to the file header. + * + * Temporary dynamic memory may be allocated from 'mctx'. + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOMEMORY + *\li Any database or rrset iterator error. + *\li Any dns_rdata_totext() error code. + */ +/*@}*/ + +isc_result_t +dns_master_rdatasettotext(const dns_name_t *owner_name, + dns_rdataset_t *rdataset, + const dns_master_style_t *style, dns_indent_t *indent, + isc_buffer_t *target); +/*%< + * Convert 'rdataset' to text format, storing the result in 'target'. + * + * Notes: + *\li The rdata cursor position will be changed. + * + * Requires: + *\li 'rdataset' is a valid non-question rdataset. + * + *\li 'rdataset' is not empty. + */ + +isc_result_t +dns_master_questiontotext(const dns_name_t *owner_name, + dns_rdataset_t *rdataset, + const dns_master_style_t *style, + isc_buffer_t *target); + +isc_result_t +dns_master_dumpnodetostream(isc_mem_t *mctx, dns_db_t *db, + dns_dbversion_t *version, dns_dbnode_t *node, + const dns_name_t *name, + const dns_master_style_t *style, FILE *f); + +isc_result_t +dns_master_dumpnode(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version, + dns_dbnode_t *node, const dns_name_t *name, + const dns_master_style_t *style, const char *filename); + +dns_masterstyle_flags_t +dns_master_styleflags(const dns_master_style_t *style); + +isc_result_t +dns_master_stylecreate(dns_master_style_t **style, + dns_masterstyle_flags_t flags, unsigned int ttl_column, + unsigned int class_column, unsigned int type_column, + unsigned int rdata_column, unsigned int line_length, + unsigned int tab_width, unsigned int split_width, + isc_mem_t *mctx); + +void +dns_master_styledestroy(dns_master_style_t **style, isc_mem_t *mctx); + +ISC_LANG_ENDDECLS + +#endif /* DNS_MASTERDUMP_H */ diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h new file mode 100644 index 0000000..8214021 --- /dev/null +++ b/lib/dns/include/dns/message.h @@ -0,0 +1,1492 @@ +/* + * 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 + +/*** + *** Imports + ***/ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/refcount.h> + +#include <dns/compress.h> +#include <dns/masterdump.h> +#include <dns/types.h> + +#include <dst/dst.h> + +/*! \file dns/message.h + * \brief Message Handling Module + * + * How this beast works: + * + * When a dns message is received in a buffer, dns_message_parse() is called + * on the memory region. Various items are checked including the format + * of the message (if counts are right, if counts consume the entire sections, + * and if sections consume the entire message) and known pseudo-RRs in the + * additional data section are analyzed and removed. + * + * TSIG checking is also done at this layer, and any DNSSEC transaction + * signatures should also be checked here. + * + * Notes on using the gettemp*() and puttemp*() functions: + * + * These functions return items (names, rdatasets, etc) allocated from some + * internal state of the dns_message_t. + * + * Names and rdatasets must be put back into the dns_message_t in + * one of two ways. Assume a name was allocated via + * dns_message_gettempname(): + * + *\li (1) insert it into a section, using dns_message_addname(). + * + *\li (2) return it to the message using dns_message_puttempname(). + * + * The same applies to rdatasets. + * + * On the other hand, offsets, rdatalists and rdatas allocated using + * dns_message_gettemp*() will always be freed automatically + * when the message is reset or destroyed; calling dns_message_puttemp*() + * on rdatalists and rdatas is optional and serves only to enable the item + * to be reused multiple times during the lifetime of the message; offsets + * cannot be reused. + * + * Buffers allocated using isc_buffer_allocate() can be automatically freed + * as well by giving the buffer to the message using dns_message_takebuffer(). + * Doing this will cause the buffer to be freed using isc_buffer_free() + * when the section lists are cleared, such as in a reset or in a destroy. + * Since the buffer itself exists until the message is destroyed, this sort + * of code can be written: + * + * \code + * buffer = isc_buffer_allocate(mctx, 512); + * name = NULL; + * result = dns_message_gettempname(message, &name); + * result = dns_name_fromtext(name, &source, dns_rootname, 0, buffer); + * dns_message_takebuffer(message, &buffer); + * \endcode + * + * + * TODO: + * + * XXX Needed: ways to set and retrieve EDNS information, add rdata to a + * section, move rdata from one section to another, remove rdata, etc. + */ + +#define DNS_MESSAGEFLAG_QR 0x8000U +#define DNS_MESSAGEFLAG_AA 0x0400U +#define DNS_MESSAGEFLAG_TC 0x0200U +#define DNS_MESSAGEFLAG_RD 0x0100U +#define DNS_MESSAGEFLAG_RA 0x0080U +#define DNS_MESSAGEFLAG_AD 0x0020U +#define DNS_MESSAGEFLAG_CD 0x0010U + +/*%< EDNS0 extended message flags */ +#define DNS_MESSAGEEXTFLAG_DO 0x8000U + +/*%< EDNS0 extended OPT codes */ +#define DNS_OPT_LLQ 1 /*%< LLQ opt code */ +#define DNS_OPT_NSID 3 /*%< NSID opt code */ +#define DNS_OPT_CLIENT_SUBNET 8 /*%< client subnet opt code */ +#define DNS_OPT_EXPIRE 9 /*%< EXPIRE opt code */ +#define DNS_OPT_COOKIE 10 /*%< COOKIE opt code */ +#define DNS_OPT_TCP_KEEPALIVE 11 /*%< TCP keepalive opt code */ +#define DNS_OPT_PAD 12 /*%< PAD opt code */ +#define DNS_OPT_KEY_TAG 14 /*%< Key tag opt code */ +#define DNS_OPT_EDE 15 /*%< Extended DNS Error opt code */ +#define DNS_OPT_CLIENT_TAG 16 /*%< Client tag opt code */ +#define DNS_OPT_SERVER_TAG 17 /*%< Server tag opt code */ + +/*%< Experimental options [65001...65534] as per RFC6891 */ + +/*%< The number of EDNS options we know about. */ +#define DNS_EDNSOPTIONS 7 + +#define DNS_MESSAGE_REPLYPRESERVE (DNS_MESSAGEFLAG_RD | DNS_MESSAGEFLAG_CD) +#define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO) + +#define DNS_MESSAGE_HEADERLEN 12 /*%< 6 uint16_t's */ + +#define DNS_MESSAGE_MAGIC ISC_MAGIC('M', 'S', 'G', '@') +#define DNS_MESSAGE_VALID(msg) ISC_MAGIC_VALID(msg, DNS_MESSAGE_MAGIC) + +/* + * Ordering here matters. DNS_SECTION_ANY must be the lowest and negative, + * and DNS_SECTION_MAX must be one greater than the last used section. + */ +typedef int dns_section_t; +#define DNS_SECTION_ANY (-1) +#define DNS_SECTION_QUESTION 0 +#define DNS_SECTION_ANSWER 1 +#define DNS_SECTION_AUTHORITY 2 +#define DNS_SECTION_ADDITIONAL 3 +#define DNS_SECTION_MAX 4 + +typedef int dns_pseudosection_t; +#define DNS_PSEUDOSECTION_ANY (-1) +#define DNS_PSEUDOSECTION_OPT 0 +#define DNS_PSEUDOSECTION_TSIG 1 +#define DNS_PSEUDOSECTION_SIG0 2 +#define DNS_PSEUDOSECTION_MAX 3 + +typedef int dns_messagetextflag_t; +#define DNS_MESSAGETEXTFLAG_NOCOMMENTS 0x0001 +#define DNS_MESSAGETEXTFLAG_NOHEADERS 0x0002 +#define DNS_MESSAGETEXTFLAG_ONESOA 0x0004 +#define DNS_MESSAGETEXTFLAG_OMITSOA 0x0008 + +/* + * Dynamic update names for these sections. + */ +#define DNS_SECTION_ZONE DNS_SECTION_QUESTION +#define DNS_SECTION_PREREQUISITE DNS_SECTION_ANSWER +#define DNS_SECTION_UPDATE DNS_SECTION_AUTHORITY + +/* + * These tell the message library how the created dns_message_t will be used. + */ +#define DNS_MESSAGE_INTENTUNKNOWN 0 /*%< internal use only */ +#define DNS_MESSAGE_INTENTPARSE 1 /*%< parsing messages */ +#define DNS_MESSAGE_INTENTRENDER 2 /*%< rendering */ + +/* + * Control behavior of parsing + */ +#define DNS_MESSAGEPARSE_PRESERVEORDER 0x0001 /*%< preserve rdata order */ +#define DNS_MESSAGEPARSE_BESTEFFORT \ + 0x0002 /*%< return a message if a \ + * recoverable parse error \ + * occurs */ +#define DNS_MESSAGEPARSE_CLONEBUFFER \ + 0x0004 /*%< save a copy of the \ + * source buffer */ +#define DNS_MESSAGEPARSE_IGNORETRUNCATION \ + 0x0008 /*%< truncation errors are \ + * not fatal. */ + +/* + * Control behavior of rendering + */ +#define DNS_MESSAGERENDER_ORDERED 0x0001 /*%< don't change order */ +#define DNS_MESSAGERENDER_PARTIAL 0x0002 /*%< allow a partial rdataset */ +#define DNS_MESSAGERENDER_OMITDNSSEC 0x0004 /*%< omit DNSSEC records */ +#define DNS_MESSAGERENDER_PREFER_A \ + 0x0008 /*%< prefer A records in \ + * additional section. */ +#define DNS_MESSAGERENDER_PREFER_AAAA \ + 0x0010 /*%< prefer AAAA records in \ + * additional section. */ +/* Obsolete: DNS_MESSAGERENDER_FILTER_AAAA 0x0020 */ + +typedef struct dns_msgblock dns_msgblock_t; + +struct dns_sortlist_arg { + dns_aclenv_t *env; + const dns_acl_t *acl; + const dns_aclelement_t *element; +}; + +struct dns_message { + /* public from here down */ + unsigned int magic; + isc_refcount_t refcount; + + dns_messageid_t id; + unsigned int flags; + dns_rcode_t rcode; + dns_opcode_t opcode; + dns_rdataclass_t rdclass; + + /* 4 real, 1 pseudo */ + unsigned int counts[DNS_SECTION_MAX]; + + /* private from here down */ + dns_namelist_t sections[DNS_SECTION_MAX]; + dns_name_t *cursors[DNS_SECTION_MAX]; + dns_rdataset_t *opt; + dns_rdataset_t *sig0; + dns_rdataset_t *tsig; + + int state; + unsigned int from_to_wire : 2; + unsigned int header_ok : 1; + unsigned int question_ok : 1; + unsigned int tcp_continuation : 1; + unsigned int verified_sig : 1; + unsigned int verify_attempted : 1; + unsigned int free_query : 1; + unsigned int free_saved : 1; + unsigned int cc_ok : 1; + unsigned int cc_bad : 1; + unsigned int tkey : 1; + unsigned int rdclass_set : 1; + + unsigned int opt_reserved; + unsigned int sig_reserved; + unsigned int reserved; /* reserved space (render) */ + + uint16_t padding; + unsigned int padding_off; + + isc_buffer_t *buffer; + dns_compress_t *cctx; + + isc_mem_t *mctx; + isc_mempool_t *namepool; + isc_mempool_t *rdspool; + + isc_bufferlist_t scratchpad; + isc_bufferlist_t cleanup; + + ISC_LIST(dns_msgblock_t) rdatas; + ISC_LIST(dns_msgblock_t) rdatalists; + ISC_LIST(dns_msgblock_t) offsets; + + ISC_LIST(dns_rdata_t) freerdata; + ISC_LIST(dns_rdatalist_t) freerdatalist; + + dns_rcode_t tsigstatus; + dns_rcode_t querytsigstatus; + dns_name_t *tsigname; /* Owner name of TSIG, if any + * */ + dns_rdataset_t *querytsig; + dns_tsigkey_t *tsigkey; + dst_context_t *tsigctx; + int sigstart; + int timeadjust; + + dns_name_t *sig0name; /* Owner name of SIG0, if any + * */ + dst_key_t *sig0key; + dns_rcode_t sig0status; + isc_region_t query; + isc_region_t saved; + + dns_rdatasetorderfunc_t order; + dns_sortlist_arg_t order_arg; + + dns_indent_t indent; +}; + +struct dns_ednsopt { + uint16_t code; + uint16_t length; + unsigned char *value; +}; + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +void +dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp); + +/*%< + * Create msg structure. + * + * This function will allocate some internal blocks of memory that are + * expected to be needed for parsing or rendering nearly any type of message. + * + * Requires: + *\li 'mctx' be a valid memory context. + * + *\li 'msgp' be non-null and '*msg' be NULL. + * + *\li 'intent' must be one of DNS_MESSAGE_INTENTPARSE or + * #DNS_MESSAGE_INTENTRENDER. + * + * Ensures: + *\li The data in "*msg" is set to indicate an unused and empty msg + * structure. + * + * Returns: + *\li #ISC_R_NOMEMORY -- out of memory + *\li #ISC_R_SUCCESS -- success + */ + +void +dns_message_reset(dns_message_t *msg, unsigned int intent); +/*%< + * Reset a message structure to default state. All internal lists are freed + * or reset to a default state as well. This is simply a more efficient + * way to call dns_message_detach() (assuming last reference is hold), + * followed by dns_message_create(), since it avoid many memory allocations. + * + * If any data loanouts (buffers, names, rdatas, etc) were requested, + * the caller must no longer use them after this call. + * + * The intended next use of the message will be 'intent'. + * + * Requires: + * + *\li 'msg' be valid. + * + *\li 'intent' is DNS_MESSAGE_INTENTPARSE or DNS_MESSAGE_INTENTRENDER + */ + +void +dns_message_attach(dns_message_t *source, dns_message_t **target); +/*%< + * Attach to message 'source'. + * + * Requires: + *\li 'source' to be a valid message. + *\li 'target' to be non NULL and '*target' to be NULL. + */ + +void +dns_message_detach(dns_message_t **messagep); +/*%< + * Detach *messagep from its message. + * list. + * + * Requires: + *\li '*messagep' to be a valid message. + */ + +isc_result_t +dns_message_sectiontotext(dns_message_t *msg, dns_section_t section, + const dns_master_style_t *style, + dns_messagetextflag_t flags, isc_buffer_t *target); + +isc_result_t +dns_message_pseudosectiontotext(dns_message_t *msg, dns_pseudosection_t section, + const dns_master_style_t *style, + dns_messagetextflag_t flags, + isc_buffer_t *target); +/*%< + * Convert section 'section' or 'pseudosection' of message 'msg' to + * a cleartext representation + * + * Notes: + * \li See dns_message_totext for meanings of flags. + * + * Requires: + * + *\li 'msg' is a valid message. + * + *\li 'style' is a valid master dump style. + * + *\li 'target' is a valid buffer. + * + *\li 'section' is a valid section label. + * + * Ensures: + * + *\li If the result is success: + * The used space in 'target' is updated. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOSPACE + *\li #ISC_R_NOMORE + * + *\li Note: On error return, *target may be partially filled with data. + */ + +isc_result_t +dns_message_headertotext(dns_message_t *msg, const dns_master_style_t *style, + dns_messagetextflag_t flags, isc_buffer_t *target); +/*%< + * Convert the header section of message 'msg' to a cleartext + * representation. This is called from dns_message_totext(). + * + * Notes on flags: + *\li If #DNS_MESSAGETEXTFLAG_NOHEADERS is set, header lines will be + * suppressed and this function is a no-op. + * + * Requires: + * + *\li 'msg' is a valid message. + * + *\li 'target' is a valid buffer. + * + * Ensures: + * + *\li If the result is success: + * The used space in 'target' is updated. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOSPACE + *\li #ISC_R_NOMORE + * + *\li Note: On error return, *target may be partially filled with data. + */ + +isc_result_t +dns_message_totext(dns_message_t *msg, const dns_master_style_t *style, + dns_messagetextflag_t flags, isc_buffer_t *target); +/*%< + * Convert all sections of message 'msg' to a cleartext representation + * + * Notes on flags: + *\li If #DNS_MESSAGETEXTFLAG_NOCOMMENTS is cleared, lines beginning with + * ";;" will be emitted indicating section name. + *\li If #DNS_MESSAGETEXTFLAG_NOHEADERS is cleared, header lines will be + * emitted. + *\li If #DNS_MESSAGETEXTFLAG_ONESOA is set then only print the first + * SOA record in the answer section. + *\li If *#DNS_MESSAGETEXTFLAG_OMITSOA is set don't print any SOA records + * in the answer section. + * + * The SOA flags are useful for suppressing the display of the second + * SOA record in an AXFR by setting #DNS_MESSAGETEXTFLAG_ONESOA on the + * first message in an AXFR stream and #DNS_MESSAGETEXTFLAG_OMITSOA on + * subsequent messages. + * + * Requires: + * + *\li 'msg' is a valid message. + * + *\li 'style' is a valid master dump style. + * + *\li 'target' is a valid buffer. + * + * Ensures: + * + *\li If the result is success: + * The used space in 'target' is updated. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOSPACE + *\li #ISC_R_NOMORE + * + *\li Note: On error return, *target may be partially filled with data. + */ + +isc_result_t +dns_message_parse(dns_message_t *msg, isc_buffer_t *source, + unsigned int options); +/*%< + * Parse raw wire data in 'source' as a DNS message. + * + * OPT records are detected and stored in the pseudo-section "opt". + * TSIGs are detected and stored in the pseudo-section "tsig". + * + * If #DNS_MESSAGEPARSE_PRESERVEORDER is set, or if the opcode of the message + * is UPDATE, a separate dns_name_t object will be created for each RR in the + * message. Each such dns_name_t will have a single rdataset containing the + * single RR, and the order of the RRs in the message is preserved. + * Otherwise, only one dns_name_t object will be created for each unique + * owner name in the section, and each such dns_name_t will have a list + * of rdatasets. To access the names and their data, use + * dns_message_firstname() and dns_message_nextname(). + * + * If #DNS_MESSAGEPARSE_BESTEFFORT is set, errors in message content will + * not be considered FORMERRs. If the entire message can be parsed, it + * will be returned and DNS_R_RECOVERABLE will be returned. + * + * If #DNS_MESSAGEPARSE_IGNORETRUNCATION is set then return as many complete + * RR's as possible, DNS_R_RECOVERABLE will be returned. + * + * OPT and TSIG records are always handled specially, regardless of the + * 'preserve_order' setting. + * + * Requires: + *\li "msg" be valid. + * + *\li "buffer" be a wire format buffer. + * + * Ensures: + *\li The buffer's data format is correct. + * + *\li The buffer's contents verify as correct regarding header bits, buffer + * and rdata sizes, etc. + * + * Returns: + *\li #ISC_R_SUCCESS -- all is well + *\li #ISC_R_NOMEMORY -- no memory + *\li #DNS_R_RECOVERABLE -- the message parsed properly, but contained + * errors. + *\li Many other errors possible XXXMLG + */ + +isc_result_t +dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx, + isc_buffer_t *buffer); +/*%< + * Begin rendering on a message. Only one call can be made to this function + * per message. + * + * The compression context is "owned" by the message library until + * dns_message_renderend() is called. It must be invalidated by the caller. + * + * The buffer is "owned" by the message library until dns_message_renderend() + * is called. + * + * Requires: + * + *\li 'msg' be valid. + * + *\li 'cctx' be valid. + * + *\li 'buffer' is a valid buffer. + * + * Side Effects: + * + *\li The buffer is cleared before it is used. + * + * Returns: + *\li #ISC_R_SUCCESS -- all is well + *\li #ISC_R_NOSPACE -- output buffer is too small + */ + +isc_result_t +dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer); +/*%< + * Reset the buffer. This can be used after growing the old buffer + * on a ISC_R_NOSPACE return from most of the render functions. + * + * On successful completion, the old buffer is no longer used by the + * library. The new buffer is owned by the library until + * dns_message_renderend() is called. + * + * Requires: + * + *\li 'msg' be valid. + * + *\li dns_message_renderbegin() was called. + * + *\li buffer != NULL. + * + * Returns: + *\li #ISC_R_NOSPACE -- new buffer is too small + *\li #ISC_R_SUCCESS -- all is well. + */ + +isc_result_t +dns_message_renderreserve(dns_message_t *msg, unsigned int space); +/*%< + * XXXMLG should use size_t rather than unsigned int once the buffer + * API is cleaned up + * + * Reserve "space" bytes in the given buffer. + * + * Requires: + * + *\li 'msg' be valid. + * + *\li dns_message_renderbegin() was called. + * + * Returns: + *\li #ISC_R_SUCCESS -- all is well. + *\li #ISC_R_NOSPACE -- not enough free space in the buffer. + */ + +void +dns_message_renderrelease(dns_message_t *msg, unsigned int space); +/*%< + * XXXMLG should use size_t rather than unsigned int once the buffer + * API is cleaned up + * + * Release "space" bytes in the given buffer that was previously reserved. + * + * Requires: + * + *\li 'msg' be valid. + * + *\li 'space' is less than or equal to the total amount of space reserved + * via prior calls to dns_message_renderreserve(). + * + *\li dns_message_renderbegin() was called. + */ + +isc_result_t +dns_message_rendersection(dns_message_t *msg, dns_section_t section, + unsigned int options); +/*%< + * Render all names, rdatalists, etc from the given section at the + * specified priority or higher. + * + * Requires: + *\li 'msg' be valid. + * + *\li 'section' be a valid section. + * + *\li dns_message_renderbegin() was called. + * + * Returns: + *\li #ISC_R_SUCCESS -- all records were written, and there are + * no more records for this section. + *\li #ISC_R_NOSPACE -- Not enough room in the buffer to write + * all records requested. + *\li #DNS_R_MOREDATA -- All requested records written, and there + * are records remaining for this section. + */ + +void +dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target); +/*%< + * Render the message header. This is implicitly called by + * dns_message_renderend(). + * + * Requires: + * + *\li 'msg' be a valid message. + * + *\li dns_message_renderbegin() was called. + * + *\li 'target' is a valid buffer with enough space to hold a message header + */ + +isc_result_t +dns_message_renderend(dns_message_t *msg); +/*%< + * Finish rendering to the buffer. Note that more data can be in the + * 'msg' structure. Destroying the structure will free this, or in a multi- + * part EDNS1 message this data can be rendered to another buffer later. + * + * Requires: + * + *\li 'msg' be a valid message. + * + *\li dns_message_renderbegin() was called. + * + * Returns: + *\li #ISC_R_SUCCESS -- all is well. + */ + +void +dns_message_renderreset(dns_message_t *msg); +/*%< + * Reset the message so that it may be rendered again. + * + * Notes: + * + *\li If dns_message_renderbegin() has been called, dns_message_renderend() + * must be called before calling this function. + * + * Requires: + * + *\li 'msg' be a valid message with rendering intent. + */ + +isc_result_t +dns_message_firstname(dns_message_t *msg, dns_section_t section); +/*%< + * Set internal per-section name pointer to the beginning of the section. + * + * The functions dns_message_firstname() and dns_message_nextname() may + * be used for iterating over the owner names in a section. + * + * Requires: + * + *\li 'msg' be valid. + * + *\li 'section' be a valid section. + * + * Returns: + *\li #ISC_R_SUCCESS -- All is well. + *\li #ISC_R_NOMORE -- No names on given section. + */ + +isc_result_t +dns_message_nextname(dns_message_t *msg, dns_section_t section); +/*%< + * Sets the internal per-section name pointer to point to the next name + * in that section. + * + * Requires: + * + * \li 'msg' be valid. + * + *\li 'section' be a valid section. + * + *\li dns_message_firstname() must have been called on this section, + * and the result was ISC_R_SUCCESS. + * + * Returns: + *\li #ISC_R_SUCCESS -- All is well. + *\li #ISC_R_NOMORE -- No more names in given section. + */ + +void +dns_message_currentname(dns_message_t *msg, dns_section_t section, + dns_name_t **name); +/*%< + * Sets 'name' to point to the name where the per-section internal name + * pointer is currently set. + * + * This function returns the name in the database, so any data associated + * with it (via the name's "list" member) contains the actual rdatasets. + * + * Requires: + * + *\li 'msg' be valid. + * + *\li 'name' be non-NULL, and *name be NULL. + * + *\li 'section' be a valid section. + * + *\li dns_message_firstname() must have been called on this section, + * and the result of it and any dns_message_nextname() calls was + * #ISC_R_SUCCESS. + */ + +isc_result_t +dns_message_findname(dns_message_t *msg, dns_section_t section, + const dns_name_t *target, dns_rdatatype_t type, + dns_rdatatype_t covers, dns_name_t **foundname, + dns_rdataset_t **rdataset); +/*%< + * Search for a name in the specified section. If it is found, *name is + * set to point to the name, and *rdataset is set to point to the found + * rdataset (if type is specified as other than dns_rdatatype_any). + * + * Requires: + *\li 'msg' be valid. + * + *\li 'section' be a valid section. + * + *\li If a pointer to the name is desired, 'foundname' should be non-NULL. + * If it is non-NULL, '*foundname' MUST be NULL. + * + *\li If a type other than dns_datatype_any is searched for, 'rdataset' + * may be non-NULL, '*rdataset' be NULL, and will point at the found + * rdataset. If the type is dns_datatype_any, 'rdataset' must be NULL. + * + *\li 'target' be a valid name. + * + *\li 'type' be a valid type. + * + *\li If 'type' is dns_rdatatype_rrsig, 'covers' must be a valid type. + * Otherwise it should be 0. + * + * Returns: + *\li #ISC_R_SUCCESS -- all is well. + *\li #DNS_R_NXDOMAIN -- name does not exist in that section. + *\li #DNS_R_NXRRSET -- The name does exist, but the desired + * type does not. + */ + +isc_result_t +dns_message_findtype(const dns_name_t *name, dns_rdatatype_t type, + dns_rdatatype_t covers, dns_rdataset_t **rdataset); +/*%< + * Search the name for the specified type. If it is found, *rdataset is + * filled in with a pointer to that rdataset. + * + * Requires: + *\li if '**rdataset' is non-NULL, *rdataset needs to be NULL. + * + *\li 'type' be a valid type, and NOT dns_rdatatype_any. + * + *\li If 'type' is dns_rdatatype_rrsig, 'covers' must be a valid type. + * Otherwise it should be 0. + * + * Returns: + *\li #ISC_R_SUCCESS -- all is well. + *\li #ISC_R_NOTFOUND -- the desired type does not exist. + */ + +isc_result_t +dns_message_find(const dns_name_t *name, dns_rdataclass_t rdclass, + dns_rdatatype_t type, dns_rdatatype_t covers, + dns_rdataset_t **rdataset); +/*%< + * Search the name for the specified rdclass and type. If it is found, + * *rdataset is filled in with a pointer to that rdataset. + * + * Requires: + *\li if '**rdataset' is non-NULL, *rdataset needs to be NULL. + * + *\li 'type' be a valid type, and NOT dns_rdatatype_any. + * + *\li If 'type' is dns_rdatatype_rrsig, 'covers' must be a valid type. + * Otherwise it should be 0. + * + * Returns: + *\li #ISC_R_SUCCESS -- all is well. + *\li #ISC_R_NOTFOUND -- the desired type does not exist. + */ + +void +dns_message_movename(dns_message_t *msg, dns_name_t *name, + dns_section_t fromsection, dns_section_t tosection); +/*%< + * Move a name from one section to another. + * + * Requires: + * + *\li 'msg' be valid. + * + *\li 'name' must be a name already in 'fromsection'. + * + *\li 'fromsection' must be a valid section. + * + *\li 'tosection' must be a valid section. + */ + +void +dns_message_addname(dns_message_t *msg, dns_name_t *name, + dns_section_t section); +/*%< + * Adds the name to the given section. + * + * It is the caller's responsibility to enforce any unique name requirements + * in a section. + * + * Requires: + * + *\li 'msg' be valid, and be a renderable message. + * + *\li 'name' be a valid absolute name. + * + *\li 'section' be a named section. + */ + +void +dns_message_removename(dns_message_t *msg, dns_name_t *name, + dns_section_t section); +/*%< + * Remove a existing name from a given section. + * + * It is the caller's responsibility to ensure the name is part of the + * given section. + * + * Requires: + * + *\li 'msg' be valid, and be a renderable message. + * + *\li 'name' be a valid absolute name. + * + *\li 'section' be a named section. + */ + +/* + * LOANOUT FUNCTIONS + * + * Each of these functions loan a particular type of data to the caller. + * The storage for these will vanish when the message is destroyed or + * reset, and must NOT be used after these operations. + */ + +isc_result_t +dns_message_gettempname(dns_message_t *msg, dns_name_t **item); +/*%< + * Return a name that can be used for any temporary purpose, including + * inserting into the message's linked lists. The name must be returned + * to the message code using dns_message_puttempname() or inserted into + * one of the message's sections before the message is destroyed. + * + * The name will be associated with a dns_fixedname object, and will + * be initialized. + * + * Requires: + *\li msg be a valid message + * + *\li item != NULL && *item == NULL + * + * Returns: + *\li #ISC_R_SUCCESS -- All is well. + *\li #ISC_R_NOMEMORY -- No item can be allocated. + */ + +isc_result_t +dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item); +/*%< + * Return a rdata that can be used for any temporary purpose, including + * inserting into the message's linked lists. The rdata will be freed + * when the message is destroyed or reset. + * + * Requires: + *\li msg be a valid message + * + *\li item != NULL && *item == NULL + * + * Returns: + *\li #ISC_R_SUCCESS -- All is well. + *\li #ISC_R_NOMEMORY -- No item can be allocated. + */ + +isc_result_t +dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item); +/*%< + * Return a rdataset that can be used for any temporary purpose, including + * inserting into the message's linked lists. The name must be returned + * to the message code using dns_message_puttempname() or inserted into + * one of the message's sections before the message is destroyed. + * + * Requires: + *\li msg be a valid message + * + *\li item != NULL && *item == NULL + * + * Returns: + *\li #ISC_R_SUCCESS -- All is well. + *\li #ISC_R_NOMEMORY -- No item can be allocated. + */ + +isc_result_t +dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item); +/*%< + * Return a rdatalist that can be used for any temporary purpose, including + * inserting into the message's linked lists. The rdatalist will be + * destroyed when the message is destroyed or reset. + * + * Requires: + *\li msg be a valid message + * + *\li item != NULL && *item == NULL + * + * Returns: + *\li #ISC_R_SUCCESS -- All is well. + *\li #ISC_R_NOMEMORY -- No item can be allocated. + */ + +void +dns_message_puttempname(dns_message_t *msg, dns_name_t **item); +/*%< + * Return a borrowed name to the message's name free list. + * + * Requires: + *\li msg be a valid message + * + *\li item != NULL && *item point to a name returned by + * dns_message_gettempname() + * + * Ensures: + *\li *item == NULL + */ + +void +dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item); +/*%< + * Return a borrowed rdata to the message's rdata free list. + * + * Requires: + *\li msg be a valid message + * + *\li item != NULL && *item point to a rdata returned by + * dns_message_gettemprdata() + * + * Ensures: + *\li *item == NULL + */ + +void +dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item); +/*%< + * Return a borrowed rdataset to the message's rdataset free list. + * + * Requires: + *\li msg be a valid message + * + *\li item != NULL && *item point to a rdataset returned by + * dns_message_gettemprdataset() + * + * Ensures: + *\li *item == NULL + */ + +void +dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item); +/*%< + * Return a borrowed rdatalist to the message's rdatalist free list. + * + * Requires: + *\li msg be a valid message + * + *\li item != NULL && *item point to a rdatalist returned by + * dns_message_gettemprdatalist() + * + * Ensures: + *\li *item == NULL + */ + +isc_result_t +dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp, + unsigned int *flagsp); +/*%< + * Assume the remaining region of "source" is a DNS message. Peek into + * it and fill in "*idp" with the message id, and "*flagsp" with the flags. + * + * Requires: + * + *\li source != NULL + * + * Ensures: + * + *\li if (idp != NULL) *idp == message id. + * + *\li if (flagsp != NULL) *flagsp == message flags. + * + * Returns: + * + *\li #ISC_R_SUCCESS -- all is well. + * + *\li #ISC_R_UNEXPECTEDEND -- buffer doesn't contain enough for a header. + */ + +isc_result_t +dns_message_reply(dns_message_t *msg, bool want_question_section); +/*%< + * Start formatting a reply to the query in 'msg'. + * + * Requires: + * + *\li 'msg' is a valid message with parsing intent, and contains a query. + * + * Ensures: + * + *\li The message will have a rendering intent. If 'want_question_section' + * is true, the message opcode is query or notify, and the question + * section is present and properly formatted, then the question section + * will be included in the reply. All other sections will be cleared. + * The QR flag will be set, the RD flag will be preserved, and all other + * flags will be cleared. + * + * Returns: + * + *\li #ISC_R_SUCCESS -- all is well. + * + *\li #DNS_R_FORMERR -- the header or question section of the + * message is invalid, replying is impossible. + * If DNS_R_FORMERR is returned when + * want_question_section is false, then + * it's the header section that's bad; + * otherwise either of the header or question + * sections may be bad. + */ + +dns_rdataset_t * +dns_message_getopt(dns_message_t *msg); +/*%< + * Get the OPT record for 'msg'. + * + * Requires: + * + *\li 'msg' is a valid message. + * + * Returns: + * + *\li The OPT rdataset of 'msg', or NULL if there isn't one. + */ + +isc_result_t +dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt); +/*%< + * Set the OPT record for 'msg'. + * + * Requires: + * + *\li 'msg' is a valid message with rendering intent + * and no sections have been rendered. + * + *\li 'opt' is a valid OPT record. + * + * Ensures: + * + *\li The OPT record has either been freed or ownership of it has + * been transferred to the message. + * + *\li If ISC_R_SUCCESS was returned, the OPT record will be rendered + * when dns_message_renderend() is called. + * + * Returns: + * + *\li #ISC_R_SUCCESS -- all is well. + * + *\li #ISC_R_NOSPACE -- there is no space for the OPT record. + */ + +dns_rdataset_t * +dns_message_gettsig(dns_message_t *msg, const dns_name_t **owner); +/*%< + * Get the TSIG record and owner for 'msg'. + * + * Requires: + * + *\li 'msg' is a valid message. + *\li 'owner' is NULL or *owner is NULL. + * + * Returns: + * + *\li The TSIG rdataset of 'msg', or NULL if there isn't one. + * + * Ensures: + * + * \li If 'owner' is not NULL, it will point to the owner name. + */ + +isc_result_t +dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key); +/*%< + * Set the tsig key for 'msg'. This is only necessary for when rendering a + * query or parsing a response. The key (if non-NULL) is attached to, and + * will be detached when the message is destroyed. + * + * Requires: + * + *\li 'msg' is a valid message with rendering intent, + * dns_message_renderbegin() has been called, and no sections have been + * rendered. + *\li 'key' is a valid tsig key or NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS -- all is well. + * + *\li #ISC_R_NOSPACE -- there is no space for the TSIG record. + */ + +dns_tsigkey_t * +dns_message_gettsigkey(dns_message_t *msg); +/*%< + * Gets the tsig key for 'msg'. + * + * Requires: + * + *\li 'msg' is a valid message + */ + +isc_result_t +dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig); +/*%< + * Indicates that 'querytsig' is the TSIG from the signed query for which + * 'msg' is the response. This is also used for chained TSIGs in TCP + * responses. + * + * Requires: + * + *\li 'querytsig' is a valid buffer as returned by dns_message_getquerytsig() + * or NULL + * + *\li 'msg' is a valid message + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +isc_result_t +dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx, + isc_buffer_t **querytsig); +/*%< + * Gets the tsig from the TSIG from the signed query 'msg'. This is also used + * for chained TSIGs in TCP responses. Unlike dns_message_gettsig, this makes + * a copy of the data, so can be used if the message is destroyed. + * + * Requires: + * + *\li 'msg' is a valid signed message + *\li 'mctx' is a valid memory context + *\li querytsig != NULL && *querytsig == NULL + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + * + * Ensures: + *\li 'tsig' points to NULL or an allocated buffer which must be freed + * by the caller. + */ + +dns_rdataset_t * +dns_message_getsig0(dns_message_t *msg, const dns_name_t **owner); +/*%< + * Get the SIG(0) record and owner for 'msg'. + * + * Requires: + * + *\li 'msg' is a valid message. + *\li 'owner' is NULL or *owner is NULL. + * + * Returns: + * + *\li The SIG(0) rdataset of 'msg', or NULL if there isn't one. + * + * Ensures: + * + * \li If 'owner' is not NULL, it will point to the owner name. + */ + +isc_result_t +dns_message_setsig0key(dns_message_t *msg, dst_key_t *key); +/*%< + * Set the SIG(0) key for 'msg'. + * + * Requires: + * + *\li 'msg' is a valid message with rendering intent, + * dns_message_renderbegin() has been called, and no sections have been + * rendered. + *\li 'key' is a valid sig key or NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS -- all is well. + * + *\li #ISC_R_NOSPACE -- there is no space for the SIG(0) record. + */ + +dst_key_t * +dns_message_getsig0key(dns_message_t *msg); +/*%< + * Gets the SIG(0) key for 'msg'. + * + * Requires: + * + *\li 'msg' is a valid message + */ + +void +dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer); +/*%< + * Give the *buffer to the message code to clean up when it is no + * longer needed. This is usually when the message is reset or + * destroyed. + * + * Requires: + * + *\li msg be a valid message. + * + *\li buffer != NULL && *buffer is a valid isc_buffer_t, which was + * dynamically allocated via isc_buffer_allocate(). + */ + +isc_result_t +dns_message_signer(dns_message_t *msg, dns_name_t *signer); +/*%< + * If this message was signed, return the identity of the signer. + * Unless ISC_R_NOTFOUND is returned, signer will reflect the name of the + * key that signed the message. + * + * Requires: + * + *\li msg is a valid parsed message. + *\li signer is a valid name + * + * Returns: + * + *\li #ISC_R_SUCCESS - the message was signed, and *signer + * contains the signing identity + * + *\li #ISC_R_NOTFOUND - no TSIG or SIG(0) record is present in the + * message + * + *\li #DNS_R_TSIGVERIFYFAILURE - the message was signed by a TSIG, but + * the signature failed to verify + * + *\li #DNS_R_TSIGERRORSET - the message was signed by a TSIG and + * verified, but the query was rejected by + * the server + * + *\li #DNS_R_NOIDENTITY - the message was signed by a TSIG and + * verified, but the key has no identity since + * it was generated by an unsigned TKEY process + * + *\li #DNS_R_SIGINVALID - the message was signed by a SIG(0), but + * the signature failed to verify + * + *\li #DNS_R_NOTVERIFIEDYET - the message was signed by a TSIG or SIG(0), + * but the signature has not been verified yet + */ + +isc_result_t +dns_message_checksig(dns_message_t *msg, dns_view_t *view); +/*%< + * If this message was signed, verify the signature. + * + * Requires: + * + *\li msg is a valid parsed message. + *\li view is a valid view or NULL + * + * Returns: + * + *\li #ISC_R_SUCCESS - the message was unsigned, or the message + * was signed correctly. + * + *\li #DNS_R_EXPECTEDTSIG - A TSIG was expected, but not seen + *\li #DNS_R_UNEXPECTEDTSIG - A TSIG was seen but not expected + *\li #DNS_R_TSIGVERIFYFAILURE - The TSIG failed to verify + */ + +isc_result_t +dns_message_rechecksig(dns_message_t *msg, dns_view_t *view); +/*%< + * Reset the signature state and then if the message was signed, + * verify the message. + * + * Requires: + * + *\li msg is a valid parsed message. + *\li view is a valid view or NULL + * + * Returns: + * + *\li #ISC_R_SUCCESS - the message was unsigned, or the message + * was signed correctly. + * + *\li #DNS_R_EXPECTEDTSIG - A TSIG was expected, but not seen + *\li #DNS_R_UNEXPECTEDTSIG - A TSIG was seen but not expected + *\li #DNS_R_TSIGVERIFYFAILURE - The TSIG failed to verify + */ + +void +dns_message_resetsig(dns_message_t *msg); +/*%< + * Reset the signature state. + * + * Requires: + *\li 'msg' is a valid parsed message. + */ + +isc_region_t * +dns_message_getrawmessage(dns_message_t *msg); +/*%< + * Retrieve the raw message in compressed wire format. The message must + * have been successfully parsed for it to have been saved. + * + * Requires: + *\li msg is a valid parsed message. + * + * Returns: + *\li NULL if there is no saved message. + * a pointer to a region which refers the dns message. + */ + +void +dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order, + dns_aclenv_t *env, const dns_acl_t *acl, + const dns_aclelement_t *element); +/*%< + * Define the order in which RR sets get rendered by + * dns_message_rendersection() to be the ascending order + * defined by the integer value returned by 'order' when + * given each RR and a ns_sortlist_arg_t constructed from 'env', + * 'acl', and 'element' as arguments. + * + * If 'order' is NULL, a default order is used. + * + * Requires: + *\li msg be a valid message. + *\li If 'env' is NULL, 'order' must be NULL. + *\li If 'env' is not NULL, 'order' must not be NULL and at least one of + * 'acl' and 'element' must also not be NULL. + */ + +void +dns_message_settimeadjust(dns_message_t *msg, int timeadjust); +/*%< + * Adjust the time used to sign/verify a message by timeadjust. + * Currently only TSIG. + * + * Requires: + *\li msg be a valid message. + */ + +int +dns_message_gettimeadjust(dns_message_t *msg); +/*%< + * Return the current time adjustment. + * + * Requires: + *\li msg be a valid message. + */ + +void +dns_message_logpacket(dns_message_t *message, const char *description, + const isc_sockaddr_t *address, + isc_logcategory_t *category, isc_logmodule_t *module, + int level, isc_mem_t *mctx); + +void +dns_message_logfmtpacket(dns_message_t *message, const char *description, + const isc_sockaddr_t *address, + isc_logcategory_t *category, isc_logmodule_t *module, + const dns_master_style_t *style, int level, + isc_mem_t *mctx); +/*%< + * Log 'message' at the specified logging parameters. + * + * For dns_message_logpacket and dns_message_logfmtpacket expect the + * 'description' to end in a newline. + * + * For dns_message_logpacket2 and dns_message_logfmtpacket2 + * 'description' will be emitted at the start of the message followed + * by the formatted address and a newline. + * + * Requires: + * \li message be a valid. + * \li description to be non NULL. + * \li address to be non NULL. + * \li category to be valid. + * \li module to be valid. + * \li style to be valid. + * \li mctx to be a valid. + */ + +isc_result_t +dns_message_buildopt(dns_message_t *msg, dns_rdataset_t **opt, + unsigned int version, uint16_t udpsize, unsigned int flags, + dns_ednsopt_t *ednsopts, size_t count); +/*%< + * Built a opt record. + * + * Requires: + * \li msg be a valid message. + * \li opt to be a non NULL and *opt to be NULL. + * + * Returns: + * \li ISC_R_SUCCESS on success. + * \li ISC_R_NOMEMORY + * \li ISC_R_NOSPACE + * \li other. + */ + +void +dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass); +/*%< + * Set the expected class of records in the response. + * + * Requires: + * \li msg be a valid message with parsing intent. + */ + +void +dns_message_setpadding(dns_message_t *msg, uint16_t padding); +/*%< + * Set the padding block size in the response. + * 0 means no padding (default). + * + * Requires: + * \li msg be a valid message. + */ + +void +dns_message_clonebuffer(dns_message_t *msg); +/*%< + * Clone the query or saved buffers if they where not cloned + * when parsing. + * + * Requires: + * \li msg be a valid message. + */ + +ISC_LANG_ENDDECLS diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h new file mode 100644 index 0000000..683f71d --- /dev/null +++ b/lib/dns/include/dns/name.h @@ -0,0 +1,1410 @@ +/* + * 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. + */ + +#ifndef DNS_NAME_H +#define DNS_NAME_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/name.h + * \brief + * Provides facilities for manipulating DNS names and labels, including + * conversions to and from wire format and text format. + * + * Given the large number of names possible in a nameserver, and because + * names occur in rdata, it was important to come up with a very efficient + * way of storing name data, but at the same time allow names to be + * manipulated. The decision was to store names in uncompressed wire format, + * and not to make them fully abstracted objects; i.e. certain parts of the + * server know names are stored that way. This saves a lot of memory, and + * makes adding names to messages easy. Having much of the server know + * the representation would be perilous, and we certainly don't want each + * user of names to be manipulating such a low-level structure. This is + * where the Names and Labels module comes in. The module allows name or + * label handles to be created and attached to uncompressed wire format + * regions. All name operations and conversions are done through these + * handles. + * + * MP: + *\li Clients of this module must impose any required synchronization. + * + * Reliability: + *\li This module deals with low-level byte streams. Errors in any of + * the functions are likely to crash the server or corrupt memory. + * + * Resources: + *\li None. + * + * Security: + * + *\li *** WARNING *** + * + *\li dns_name_fromwire() deals with raw network data. An error in + * this routine could result in the failure or hijacking of the server. + * + * Standards: + *\li RFC1035 + *\li Draft EDNS0 (0) + *\li Draft Binary Labels (2) + * + */ + +/*** + *** Imports + ***/ + +#include <inttypes.h> +#include <stdbool.h> +#include <stdio.h> + +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/region.h> /* Required for storage size of dns_label_t. */ + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/***** +***** Labels +***** +***** A 'label' is basically a region. It contains one DNS wire format +***** label of type 00 (ordinary). +*****/ + +/***** +***** Names +***** +***** A 'name' is a handle to a binary region. It contains a sequence of one +***** or more DNS wire format labels of type 00 (ordinary). +***** Note that all names are not required to end with the root label, +***** as they are in the actual DNS wire protocol. +*****/ + +/*** + *** Types + ***/ + +/*% + * Clients are strongly discouraged from using this type directly, with + * the exception of the 'link' and 'list' fields which may be used directly + * for whatever purpose the client desires. + */ +struct dns_name { + unsigned int magic; + unsigned char *ndata; + unsigned int length; + unsigned int labels; + unsigned int attributes; + unsigned char *offsets; + isc_buffer_t *buffer; + ISC_LINK(dns_name_t) link; + ISC_LIST(dns_rdataset_t) list; +}; + +#define DNS_NAME_MAGIC ISC_MAGIC('D', 'N', 'S', 'n') + +#define DNS_NAMEATTR_ABSOLUTE 0x00000001 +#define DNS_NAMEATTR_READONLY 0x00000002 +#define DNS_NAMEATTR_DYNAMIC 0x00000004 +#define DNS_NAMEATTR_DYNOFFSETS 0x00000008 +#define DNS_NAMEATTR_NOCOMPRESS 0x00000010 +/* + * Attributes below 0x0100 reserved for name.c usage. + */ +#define DNS_NAMEATTR_CACHE 0x00000100 /*%< Used by resolver. */ +#define DNS_NAMEATTR_ANSWER 0x00000200 /*%< Used by resolver. */ +#define DNS_NAMEATTR_NCACHE 0x00000400 /*%< Used by resolver. */ +#define DNS_NAMEATTR_CHAINING 0x00000800 /*%< Used by resolver. */ +#define DNS_NAMEATTR_CHASE 0x00001000 /*%< Used by resolver. */ +#define DNS_NAMEATTR_WILDCARD 0x00002000 /*%< Used by server. */ +#define DNS_NAMEATTR_PREREQUISITE 0x00004000 /*%< Used by client. */ +#define DNS_NAMEATTR_UPDATE 0x00008000 /*%< Used by client. */ +#define DNS_NAMEATTR_HASUPDATEREC 0x00010000 /*%< Used by client. */ + +/* + * Various flags. + */ +#define DNS_NAME_DOWNCASE 0x0001 +#define DNS_NAME_CHECKNAMES 0x0002 /*%< Used by rdata. */ +#define DNS_NAME_CHECKNAMESFAIL 0x0004 /*%< Used by rdata. */ +#define DNS_NAME_CHECKREVERSE 0x0008 /*%< Used by rdata. */ +#define DNS_NAME_CHECKMX 0x0010 /*%< Used by rdata. */ +#define DNS_NAME_CHECKMXFAIL 0x0020 /*%< Used by rdata. */ + +LIBDNS_EXTERNAL_DATA extern const dns_name_t *dns_rootname; +LIBDNS_EXTERNAL_DATA extern const dns_name_t *dns_wildcardname; + +/*%< + * DNS_NAME_INITNONABSOLUTE and DNS_NAME_INITABSOLUTE are macros for + * initializing dns_name_t structures. + * + * Note[1]: 'length' is set to (sizeof(A) - 1) in DNS_NAME_INITNONABSOLUTE + * and sizeof(A) in DNS_NAME_INITABSOLUTE to allow C strings to be used + * to initialize 'ndata'. + * + * Note[2]: The final value of offsets for DNS_NAME_INITABSOLUTE should + * match (sizeof(A) - 1) which is the offset of the root label. + * + * Typical usage: + * unsigned char data[] = "\005value"; + * unsigned char offsets[] = { 0 }; + * dns_name_t value = DNS_NAME_INITNONABSOLUTE(data, offsets); + * + * unsigned char data[] = "\005value"; + * unsigned char offsets[] = { 0, 6 }; + * dns_name_t value = DNS_NAME_INITABSOLUTE(data, offsets); + */ +#define DNS_NAME_INITNONABSOLUTE(A, B) \ + { \ + DNS_NAME_MAGIC, A, (sizeof(A) - 1), sizeof(B), \ + DNS_NAMEATTR_READONLY, B, NULL, \ + { (void *)-1, (void *)-1 }, { \ + NULL, NULL \ + } \ + } + +#define DNS_NAME_INITABSOLUTE(A, B) \ + { \ + DNS_NAME_MAGIC, A, sizeof(A), sizeof(B), \ + DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, B, \ + NULL, { (void *)-1, (void *)-1 }, { \ + NULL, NULL \ + } \ + } + +#define DNS_NAME_INITEMPTY \ + { \ + DNS_NAME_MAGIC, NULL, 0, 0, 0, NULL, NULL, \ + { (void *)-1, (void *)-1 }, { \ + NULL, NULL \ + } \ + } + +/*% + * Standard size of a wire format name + */ +#define DNS_NAME_MAXWIRE 255 + +/* + * Text output filter procedure. + * 'target' is the buffer to be converted. The region to be converted + * is from 'buffer'->base + 'used_org' to the end of the used region. + */ +typedef isc_result_t(dns_name_totextfilter_t)(isc_buffer_t *target, + unsigned int used_org); + +/*** + *** Initialization + ***/ + +void +dns_name_init(dns_name_t *name, unsigned char *offsets); +/*%< + * Initialize 'name'. + * + * Notes: + * \li 'offsets' is never required to be non-NULL, but specifying a + * dns_offsets_t for 'offsets' will improve the performance of most + * name operations if the name is used more than once. + * + * Requires: + * \li 'name' is not NULL and points to a struct dns_name. + * + * \li offsets == NULL or offsets is a dns_offsets_t. + * + * Ensures: + * \li 'name' is a valid name. + * \li dns_name_countlabels(name) == 0 + * \li dns_name_isabsolute(name) == false + */ + +void +dns_name_reset(dns_name_t *name); +/*%< + * Reinitialize 'name'. + * + * Notes: + * \li This function distinguishes itself from dns_name_init() in two + * key ways: + * + * \li + If any buffer is associated with 'name' (via dns_name_setbuffer() + * or by being part of a dns_fixedname_t) the link to the buffer + * is retained but the buffer itself is cleared. + * + * \li + Of the attributes associated with 'name', all are retained except + * DNS_NAMEATTR_ABSOLUTE. + * + * Requires: + * \li 'name' is a valid name. + * + * Ensures: + * \li 'name' is a valid name. + * \li dns_name_countlabels(name) == 0 + * \li dns_name_isabsolute(name) == false + */ + +void +dns_name_invalidate(dns_name_t *name); +/*%< + * Make 'name' invalid. + * + * Requires: + * \li 'name' is a valid name. + * + * Ensures: + * \li If assertion checking is enabled, future attempts to use 'name' + * without initializing it will cause an assertion failure. + * + * \li If the name had a dedicated buffer, that association is ended. + */ + +bool +dns_name_isvalid(const dns_name_t *name); +/*%< + * Check whether 'name' points to a valid dns_name + */ + +/*** + *** Dedicated Buffers + ***/ + +void +dns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer); +/*%< + * Dedicate a buffer for use with 'name'. + * + * Notes: + * \li Specification of a target buffer in dns_name_fromwire(), + * dns_name_fromtext(), and dns_name_concatenate() is optional if + * 'name' has a dedicated buffer. + * + * \li The caller must not write to buffer until the name has been + * invalidated or is otherwise known not to be in use. + * + * \li If buffer is NULL and the name previously had a dedicated buffer, + * than that buffer is no longer dedicated to use with this name. + * The caller is responsible for ensuring that the storage used by + * the name remains valid. + * + * Requires: + * \li 'name' is a valid name. + * + * \li 'buffer' is a valid binary buffer and 'name' doesn't have a + * dedicated buffer already, or 'buffer' is NULL. + */ + +bool +dns_name_hasbuffer(const dns_name_t *name); +/*%< + * Does 'name' have a dedicated buffer? + * + * Requires: + * \li 'name' is a valid name. + * + * Returns: + * \li true 'name' has a dedicated buffer. + * \li false 'name' does not have a dedicated buffer. + */ + +/*** + *** Properties + ***/ + +bool +dns_name_isabsolute(const dns_name_t *name); +/*%< + * Does 'name' end in the root label? + * + * Requires: + * \li 'name' is a valid name + * + * Returns: + * \li TRUE The last label in 'name' is the root label. + * \li FALSE The last label in 'name' is not the root label. + */ + +bool +dns_name_iswildcard(const dns_name_t *name); +/*%< + * Is 'name' a wildcard name? + * + * Requires: + * \li 'name' is a valid name + * + * \li dns_name_countlabels(name) > 0 + * + * Returns: + * \li TRUE The least significant label of 'name' is '*'. + * \li FALSE The least significant label of 'name' is not '*'. + */ + +unsigned int +dns_name_hash(const dns_name_t *name, bool case_sensitive); +/*%< + * Provide a hash value for 'name'. + * + * Note: if 'case_sensitive' is false, then names which differ only in + * case will have the same hash value. + * + * Requires: + * \li 'name' is a valid name + * + * Returns: + * \li A hash value + */ + +unsigned int +dns_name_fullhash(const dns_name_t *name, bool case_sensitive); +/*%< + * Provide a hash value for 'name'. Unlike dns_name_hash(), this function + * always takes into account of the entire name to calculate the hash value. + * + * Note: if 'case_sensitive' is false, then names which differ only in + * case will have the same hash value. + * + * Requires: + *\li 'name' is a valid name + * + * Returns: + *\li A hash value + */ + +/* + *** Comparisons + ***/ + +dns_namereln_t +dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2, + int *orderp, unsigned int *nlabelsp); +/*%< + * Determine the relative ordering under the DNSSEC order relation of + * 'name1' and 'name2', and also determine the hierarchical + * relationship of the names. + * + * Note: It makes no sense for one of the names to be relative and the + * other absolute. If both names are relative, then to be meaningfully + * compared the caller must ensure that they are both relative to the + * same domain. + * + * Requires: + *\li 'name1' is a valid name + * + *\li dns_name_countlabels(name1) > 0 + * + *\li 'name2' is a valid name + * + *\li dns_name_countlabels(name2) > 0 + * + *\li orderp and nlabelsp are valid pointers. + * + *\li Either name1 is absolute and name2 is absolute, or neither is. + * + * Ensures: + * + *\li *orderp is < 0 if name1 < name2, 0 if name1 = name2, > 0 if + * name1 > name2. + * + *\li *nlabelsp is the number of common significant labels. + * + * Returns: + *\li dns_namereln_none There's no hierarchical relationship + * between name1 and name2. + *\li dns_namereln_contains name1 properly contains name2; i.e. + * name2 is a proper subdomain of name1. + *\li dns_namereln_subdomain name1 is a proper subdomain of name2. + *\li dns_namereln_equal name1 and name2 are equal. + *\li dns_namereln_commonancestor name1 and name2 share a common + * ancestor. + */ + +int +dns_name_compare(const dns_name_t *name1, const dns_name_t *name2); +/*%< + * Determine the relative ordering under the DNSSEC order relation of + * 'name1' and 'name2'. + * + * Note: It makes no sense for one of the names to be relative and the + * other absolute. If both names are relative, then to be meaningfully + * compared the caller must ensure that they are both relative to the + * same domain. + * + * Requires: + * \li 'name1' is a valid name + * + * \li 'name2' is a valid name + * + * \li Either name1 is absolute and name2 is absolute, or neither is. + * + * Returns: + * \li < 0 'name1' is less than 'name2' + * \li 0 'name1' is equal to 'name2' + * \li > 0 'name1' is greater than 'name2' + */ + +bool +dns_name_equal(const dns_name_t *name1, const dns_name_t *name2); +/*%< + * Are 'name1' and 'name2' equal? + * + * Notes: + * \li Because it only needs to test for equality, dns_name_equal() can be + * significantly faster than dns_name_fullcompare() or dns_name_compare(). + * + * \li Offsets tables are not used in the comparison. + * + * \li It makes no sense for one of the names to be relative and the + * other absolute. If both names are relative, then to be meaningfully + * compared the caller must ensure that they are both relative to the + * same domain. + * + * Requires: + * \li 'name1' is a valid name + * + * \li 'name2' is a valid name + * + * \li Either name1 is absolute and name2 is absolute, or neither is. + * + * Returns: + * \li true 'name1' and 'name2' are equal + * \li false 'name1' and 'name2' are not equal + */ + +bool +dns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2); +/*%< + * Case sensitive version of dns_name_equal(). + */ + +int +dns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2); +/*%< + * Compare two names as if they are part of rdata in DNSSEC canonical + * form. + * + * Requires: + * \li 'name1' is a valid absolute name + * + * \li dns_name_countlabels(name1) > 0 + * + * \li 'name2' is a valid absolute name + * + * \li dns_name_countlabels(name2) > 0 + * + * Returns: + * \li < 0 'name1' is less than 'name2' + * \li 0 'name1' is equal to 'name2' + * \li > 0 'name1' is greater than 'name2' + */ + +bool +dns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2); +/*%< + * Is 'name1' a subdomain of 'name2'? + * + * Notes: + * \li name1 is a subdomain of name2 if name1 is contained in name2, or + * name1 equals name2. + * + * \li It makes no sense for one of the names to be relative and the + * other absolute. If both names are relative, then to be meaningfully + * compared the caller must ensure that they are both relative to the + * same domain. + * + * Requires: + * \li 'name1' is a valid name + * + * \li 'name2' is a valid name + * + * \li Either name1 is absolute and name2 is absolute, or neither is. + * + * Returns: + * \li TRUE 'name1' is a subdomain of 'name2' + * \li FALSE 'name1' is not a subdomain of 'name2' + */ + +bool +dns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname); +/*%< + * Does 'name' match the wildcard specified in 'wname'? + * + * Notes: + * \li name matches the wildcard specified in wname if all labels + * following the wildcard in wname are identical to the same number + * of labels at the end of name. + * + * \li It makes no sense for one of the names to be relative and the + * other absolute. If both names are relative, then to be meaningfully + * compared the caller must ensure that they are both relative to the + * same domain. + * + * Requires: + * \li 'name' is a valid name + * + * \li dns_name_countlabels(name) > 0 + * + * \li 'wname' is a valid name + * + * \li dns_name_countlabels(wname) > 0 + * + * \li dns_name_iswildcard(wname) is true + * + * \li Either name is absolute and wname is absolute, or neither is. + * + * Returns: + * \li TRUE 'name' matches the wildcard specified in 'wname' + * \li FALSE 'name' does not match the wildcard specified in 'wname' + */ + +/*** + *** Labels + ***/ + +unsigned int +dns_name_countlabels(const dns_name_t *name); +/*%< + * How many labels does 'name' have? + * + * Notes: + * \li In this case, as in other places, a 'label' is an ordinary label. + * + * Requires: + * \li 'name' is a valid name + * + * Ensures: + * \li The result is <= 128. + * + * Returns: + * \li The number of labels in 'name'. + */ + +void +dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label); +/*%< + * Make 'label' refer to the 'n'th least significant label of 'name'. + * + * Notes: + * \li Numbering starts at 0. + * + * \li Given "rc.vix.com.", the label 0 is "rc", and label 3 is the + * root label. + * + * \li 'label' refers to the same memory as 'name', so 'name' must not + * be changed while 'label' is still in use. + * + * Requires: + * \li n < dns_name_countlabels(name) + */ + +void +dns_name_getlabelsequence(const dns_name_t *source, unsigned int first, + unsigned int n, dns_name_t *target); +/*%< + * Make 'target' refer to the 'n' labels including and following 'first' + * in 'source'. + * + * Notes: + * \li Numbering starts at 0. + * + * \li Given "rc.vix.com.", the label 0 is "rc", and label 3 is the + * root label. + * + * \li 'target' refers to the same memory as 'source', so 'source' + * must not be changed while 'target' is still in use. + * + * Requires: + * \li 'source' and 'target' are valid names. + * + * \li first < dns_name_countlabels(name) + * + * \li first + n <= dns_name_countlabels(name) + */ + +void +dns_name_clone(const dns_name_t *source, dns_name_t *target); +/*%< + * Make 'target' refer to the same name as 'source'. + * + * Notes: + * + * \li 'target' refers to the same memory as 'source', so 'source' + * must not be changed or freed while 'target' is still in use. + * + * \li This call is functionally equivalent to: + * + * \code + * dns_name_getlabelsequence(source, 0, + * dns_name_countlabels(source), + * target); + * \endcode + * + * but is more efficient. Also, dns_name_clone() works even if 'source' + * is empty. + * + * Requires: + * + * \li 'source' is a valid name. + * + * \li 'target' is a valid name that is not read-only. + */ + +/*** + *** Conversions + ***/ + +void +dns_name_fromregion(dns_name_t *name, const isc_region_t *r); +/*%< + * Make 'name' refer to region 'r'. + * + * Note: + * \li If the conversion encounters a root label before the end of the + * region the conversion stops and the length is set to the length + * so far converted. A maximum of 255 bytes is converted. + * + * Requires: + * \li The data in 'r' is a sequence of one or more type 00 or type 01000001 + * labels. + */ + +void +dns_name_toregion(const dns_name_t *name, isc_region_t *r); +/*%< + * Make 'r' refer to 'name'. + * + * Requires: + * + * \li 'name' is a valid name. + * + * \li 'r' is a valid region. + */ + +isc_result_t +dns_name_fromwire(dns_name_t *name, isc_buffer_t *source, + dns_decompress_t *dctx, unsigned int options, + isc_buffer_t *target); +/*%< + * Copy the possibly-compressed name at source (active region) into target, + * decompressing it. + * + * Notes: + * \li Decompression policy is controlled by 'dctx'. + * + * \li If DNS_NAME_DOWNCASE is set, any uppercase letters in 'source' will be + * downcased when they are copied into 'target'. + * + * Security: + * + * \li *** WARNING *** + * + * \li This routine will often be used when 'source' contains raw network + * data. A programming error in this routine could result in a denial + * of service, or in the hijacking of the server. + * + * Requires: + * + * \li 'name' is a valid name. + * + * \li 'source' is a valid buffer and the first byte of the active + * region should be the first byte of a DNS wire format domain name. + * + * \li 'target' is a valid buffer or 'target' is NULL and 'name' has + * a dedicated buffer. + * + * \li 'dctx' is a valid decompression context. + * + * Ensures: + * + * If result is success: + * \li If 'target' is not NULL, 'name' is attached to it. + * + * \li Uppercase letters are downcased in the copy iff + * DNS_NAME_DOWNCASE is set in options. + * + * \li The current location in source is advanced, and the used space + * in target is updated. + * + * Result: + * \li Success + * \li Bad Form: Label Length + * \li Bad Form: Unknown Label Type + * \li Bad Form: Name Length + * \li Bad Form: Compression type not allowed + * \li Bad Form: Bad compression pointer + * \li Bad Form: Input too short + * \li Resource Limit: Too many compression pointers + * \li Resource Limit: Not enough space in buffer + */ + +isc_result_t +dns_name_towire(const dns_name_t *name, dns_compress_t *cctx, + isc_buffer_t *target); +isc_result_t +dns_name_towire2(const dns_name_t *name, dns_compress_t *cctx, + isc_buffer_t *target, uint16_t *comp_offsetp); +/*%< + * Convert 'name' into wire format, compressing it as specified by the + * compression context 'cctx', and storing the result in 'target'. + * + * Notes: + * \li If the compression context allows global compression, then the + * global compression table may be updated. + * + * Requires: + * \li 'name' is a valid name + * + * \li dns_name_countlabels(name) > 0 + * + * \li dns_name_isabsolute(name) == TRUE + * + * \li target is a valid buffer. + * + * \li Any offsets specified in a global compression table are valid + * for buffer. + * + * Ensures: + * + * If the result is success: + * + * \li The used space in target is updated. + * + * Returns: + * \li Success + * \li Resource Limit: Not enough space in buffer + */ + +isc_result_t +dns_name_fromtext(dns_name_t *name, isc_buffer_t *source, + const dns_name_t *origin, unsigned int options, + isc_buffer_t *target); +/*%< + * Convert the textual representation of a DNS name at source + * into uncompressed wire form stored in target. + * + * Notes: + * \li Relative domain names will have 'origin' appended to them + * unless 'origin' is NULL, in which case relative domain names + * will remain relative. + * + * \li If DNS_NAME_DOWNCASE is set in 'options', any uppercase letters + * in 'source' will be downcased when they are copied into 'target'. + * + * Requires: + * + * \li 'name' is a valid name. + * + * \li 'source' is a valid buffer. + * + * \li 'target' is a valid buffer or 'target' is NULL and 'name' has + * a dedicated buffer. + * + * Ensures: + * + * If result is success: + * \li If 'target' is not NULL, 'name' is attached to it. + * + * \li Uppercase letters are downcased in the copy iff + * DNS_NAME_DOWNCASE is set in 'options'. + * + * \li The current location in source is advanced, and the used space + * in target is updated. + * + * Result: + *\li #ISC_R_SUCCESS + *\li #DNS_R_EMPTYLABEL + *\li #DNS_R_LABELTOOLONG + *\li #DNS_R_BADESCAPE + *\li #DNS_R_BADDOTTEDQUAD + *\li #ISC_R_NOSPACE + *\li #ISC_R_UNEXPECTEDEND + */ + +#define DNS_NAME_OMITFINALDOT 0x01U +#define DNS_NAME_MASTERFILE 0x02U /* escape $ and @ */ + +isc_result_t +dns_name_toprincipal(const dns_name_t *name, isc_buffer_t *target); + +isc_result_t +dns_name_totext(const dns_name_t *name, bool omit_final_dot, + isc_buffer_t *target); + +isc_result_t +dns_name_totext2(const dns_name_t *name, unsigned int options, + isc_buffer_t *target); +/*%< + * Convert 'name' into text format, storing the result in 'target'. + * + * Notes: + *\li If 'omit_final_dot' is true, then the final '.' in absolute + * names other than the root name will be omitted. + * + *\li If DNS_NAME_OMITFINALDOT is set in options, then the final '.' + * in absolute names other than the root name will be omitted. + * + *\li If DNS_NAME_MASTERFILE is set in options, '$' and '@' will also + * be escaped. + * + *\li If dns_name_countlabels == 0, the name will be "@", representing the + * current origin as described by RFC1035. + * + *\li The name is not NUL terminated. + * + * Requires: + * + *\li 'name' is a valid name + * + *\li 'target' is a valid buffer. + * + *\li if dns_name_isabsolute == FALSE, then omit_final_dot == FALSE + * + * Ensures: + * + *\li If the result is success: + * the used space in target is updated. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOSPACE + */ + +#define DNS_NAME_MAXTEXT 1023 +/*%< + * The maximum length of the text representation of a domain + * name as generated by dns_name_totext(). This does not + * include space for a terminating NULL. + * + * This definition is conservative - the actual maximum + * is 1004, derived as follows: + * + * A backslash-decimal escaped character takes 4 bytes. + * A wire-encoded name can be up to 255 bytes and each + * label is one length byte + at most 63 bytes of data. + * Maximizing the label lengths gives us a name of + * three 63-octet labels, one 61-octet label, and the + * root label: + * + * 1 + 63 + 1 + 63 + 1 + 63 + 1 + 61 + 1 = 255 + * + * When printed, this is (3 * 63 + 61) * 4 + * bytes for the escaped label data + 4 bytes for the + * dot terminating each label = 1004 bytes total. + */ + +isc_result_t +dns_name_tofilenametext(const dns_name_t *name, bool omit_final_dot, + isc_buffer_t *target); +/*%< + * Convert 'name' into an alternate text format appropriate for filenames, + * storing the result in 'target'. The name data is downcased, guaranteeing + * that the filename does not depend on the case of the converted name. + * + * Notes: + *\li If 'omit_final_dot' is true, then the final '.' in absolute + * names other than the root name will be omitted. + * + *\li The name is not NUL terminated. + * + * Requires: + * + *\li 'name' is a valid absolute name + * + *\li 'target' is a valid buffer. + * + * Ensures: + * + *\li If the result is success: + * the used space in target is updated. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOSPACE + */ + +isc_result_t +dns_name_downcase(const dns_name_t *source, dns_name_t *name, + isc_buffer_t *target); +/*%< + * Downcase 'source'. + * + * Requires: + * + *\li 'source' and 'name' are valid names. + * + *\li If source == name, then + * 'source' must not be read-only + * + *\li Otherwise, + * 'target' is a valid buffer or 'target' is NULL and + * 'name' has a dedicated buffer. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOSPACE + * + * Note: if source == name, then the result will always be ISC_R_SUCCESS. + */ + +isc_result_t +dns_name_concatenate(const dns_name_t *prefix, const dns_name_t *suffix, + dns_name_t *name, isc_buffer_t *target); +/*%< + * Concatenate 'prefix' and 'suffix'. + * + * Requires: + * + *\li 'prefix' is a valid name or NULL. + * + *\li 'suffix' is a valid name or NULL. + * + *\li 'name' is a valid name or NULL. + * + *\li 'target' is a valid buffer or 'target' is NULL and 'name' has + * a dedicated buffer. + * + *\li If 'prefix' is absolute, 'suffix' must be NULL or the empty name. + * + * Ensures: + * + *\li On success, + * If 'target' is not NULL and 'name' is not NULL, then 'name' + * is attached to it. + * The used space in target is updated. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOSPACE + *\li #DNS_R_NAMETOOLONG + */ + +void +dns_name_split(const dns_name_t *name, unsigned int suffixlabels, + dns_name_t *prefix, dns_name_t *suffix); +/*%< + * + * Split 'name' into two pieces on a label boundary. + * + * Notes: + * \li 'name' is split such that 'suffix' holds the most significant + * 'suffixlabels' labels. All other labels are stored in 'prefix'. + * + *\li Copying name data is avoided as much as possible, so 'prefix' + * and 'suffix' will end up pointing at the data for 'name'. + * + *\li It is legitimate to pass a 'prefix' or 'suffix' that has + * its name data stored someplace other than the dedicated buffer. + * This is useful to avoid name copying in the calling function. + * + *\li It is also legitimate to pass a 'prefix' or 'suffix' that is + * the same dns_name_t as 'name'. + * + * Requires: + *\li 'name' is a valid name. + * + *\li 'suffixlabels' cannot exceed the number of labels in 'name'. + * + * \li 'prefix' is a valid name or NULL, and cannot be read-only. + * + *\li 'suffix' is a valid name or NULL, and cannot be read-only. + * + * Ensures: + * + *\li On success: + * If 'prefix' is not NULL it will contain the least significant + * labels. + * If 'suffix' is not NULL it will contain the most significant + * labels. dns_name_countlabels(suffix) will be equal to + * suffixlabels. + * + *\li On failure: + * Either 'prefix' or 'suffix' is invalidated (depending + * on which one the problem was encountered with). + * + * Returns: + *\li #ISC_R_SUCCESS No worries. (This function should always success). + */ + +void +dns_name_dup(const dns_name_t *source, isc_mem_t *mctx, dns_name_t *target); +/*%< + * Make 'target' a dynamically allocated copy of 'source'. + * + * Requires: + * + *\li 'source' is a valid non-empty name. + * + *\li 'target' is a valid name that is not read-only. + * + *\li 'mctx' is a valid memory context. + */ + +isc_result_t +dns_name_dupwithoffsets(const dns_name_t *source, isc_mem_t *mctx, + dns_name_t *target); +/*%< + * Make 'target' a read-only dynamically allocated copy of 'source'. + * 'target' will also have a dynamically allocated offsets table. + * + * Requires: + * + *\li 'source' is a valid non-empty name. + * + *\li 'target' is a valid name that is not read-only. + * + *\li 'target' has no offsets table. + * + *\li 'mctx' is a valid memory context. + */ + +void +dns_name_free(dns_name_t *name, isc_mem_t *mctx); +/*%< + * Free 'name'. + * + * Requires: + * + *\li 'name' is a valid name created previously in 'mctx' by dns_name_dup(). + * + *\li 'mctx' is a valid memory context. + * + * Ensures: + * + *\li All dynamic resources used by 'name' are freed and the name is + * invalidated. + */ + +isc_result_t +dns_name_digest(const dns_name_t *name, dns_digestfunc_t digest, void *arg); +/*%< + * Send 'name' in DNSSEC canonical form to 'digest'. + * + * Requires: + * + *\li 'name' is a valid name. + * + *\li 'digest' is a valid dns_digestfunc_t. + * + * Ensures: + * + *\li If successful, the DNSSEC canonical form of 'name' will have been + * sent to 'digest'. + * + *\li If digest() returns something other than ISC_R_SUCCESS, that result + * will be returned as the result of dns_name_digest(). + * + * Returns: + * + *\li #ISC_R_SUCCESS + * + *\li Many other results are possible if not successful. + * + */ + +bool +dns_name_dynamic(const dns_name_t *name); +/*%< + * Returns whether there is dynamic memory associated with this name. + * + * Requires: + * + *\li 'name' is a valid name. + * + * Returns: + * + *\li 'true' if the name is dynamic otherwise 'false'. + */ + +isc_result_t +dns_name_print(const dns_name_t *name, FILE *stream); +/*%< + * Print 'name' on 'stream'. + * + * Requires: + * + *\li 'name' is a valid name. + * + *\li 'stream' is a valid stream. + * + * Returns: + * + *\li #ISC_R_SUCCESS + * + *\li Any error that dns_name_totext() can return. + */ + +void +dns_name_format(const dns_name_t *name, char *cp, unsigned int size); +/*%< + * Format 'name' as text appropriate for use in log messages. + * + * Store the formatted name at 'cp', writing no more than + * 'size' bytes. The resulting string is guaranteed to be + * null terminated. + * + * The formatted name will have a terminating dot only if it is + * the root. + * + * This function cannot fail, instead any errors are indicated + * in the returned text. + * + * Requires: + * + *\li 'name' is a valid name. + * + *\li 'cp' points a valid character array of size 'size'. + * + *\li 'size' > 0. + * + */ + +isc_result_t +dns_name_tostring(const dns_name_t *source, char **target, isc_mem_t *mctx); +/*%< + * Convert 'name' to string format, allocating sufficient memory to + * hold it (free with isc_mem_free()). + * + * Differs from dns_name_format in that it allocates its own memory. + * + * Requires: + * + *\li 'name' is a valid name. + *\li 'target' is not NULL. + *\li '*target' is NULL. + * + * Returns: + * + *\li ISC_R_SUCCESS + *\li ISC_R_NOMEMORY + * + *\li Any error that dns_name_totext() can return. + */ + +isc_result_t +dns_name_fromstring(dns_name_t *target, const char *src, unsigned int options, + isc_mem_t *mctx); +isc_result_t +dns_name_fromstring2(dns_name_t *target, const char *src, + const dns_name_t *origin, unsigned int options, + isc_mem_t *mctx); +/*%< + * Convert a string to a name and place it in target, allocating memory + * as necessary. 'options' has the same semantics as that of + * dns_name_fromtext(). + * + * If 'target' has a buffer then the name will be copied into it rather than + * memory being allocated. + * + * Requires: + * + * \li 'target' is a valid name that is not read-only. + * \li 'src' is not NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS + * + *\li Any error that dns_name_fromtext() can return. + * + *\li Any error that dns_name_dup() can return. + */ + +isc_result_t +dns_name_settotextfilter(dns_name_totextfilter_t *proc); +/*%< + * Set / clear a thread specific function 'proc' to be called at the + * end of dns_name_totext(). + * + * Note: Under Windows you need to call "dns_name_settotextfilter(NULL);" + * prior to exiting the thread otherwise memory will be leaked. + * For other platforms, which are pthreads based, this is still a good + * idea but not required. + * + * Returns + *\li #ISC_R_SUCCESS + *\li #ISC_R_UNEXPECTED + */ + +#define DNS_NAME_FORMATSIZE (DNS_NAME_MAXTEXT + 1) +/*%< + * Suggested size of buffer passed to dns_name_format(). + * Includes space for the terminating NULL. + */ + +isc_result_t +dns_name_copy(const dns_name_t *source, dns_name_t *dest, isc_buffer_t *target); +/*%< + * Copies the name in 'source' into 'dest'. The name data is copied to + * the 'target' buffer, which is then set as the buffer for 'dest'. + * + * Requires: + * \li 'source' is a valid name. + * + * \li 'dest' is an initialized name. + * + * \li 'target' is an initialized buffer. + * + * Ensures: + * + *\li On success, the used space in target is updated. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOSPACE + */ + +void +dns_name_copynf(const dns_name_t *source, dns_name_t *dest); +/*%< + * Copies the name in 'source' into 'dest'. The name data is copied to + * the dedicated buffer for 'dest'. + * + * Requires: + * \li 'source' is a valid name. + * + * \li 'dest' is an initialized name with a dedicated buffer. + */ + +bool +dns_name_ishostname(const dns_name_t *name, bool wildcard); +/*%< + * Return if 'name' is a valid hostname. RFC 952 / RFC 1123. + * If 'wildcard' is true then allow the first label of name to + * be a wildcard. + * The root is also accepted. + * + * Requires: + * 'name' to be valid. + */ + +bool +dns_name_ismailbox(const dns_name_t *name); +/*%< + * Return if 'name' is a valid mailbox. RFC 821. + * + * Requires: + * \li 'name' to be valid. + */ + +bool +dns_name_internalwildcard(const dns_name_t *name); +/*%< + * Return if 'name' contains a internal wildcard name. + * + * Requires: + * \li 'name' to be valid. + */ + +bool +dns_name_isdnssd(const dns_name_t *owner); +/*%< + * Determine if the 'owner' is a DNS-SD prefix. + */ + +bool +dns_name_isrfc1918(const dns_name_t *owner); +/*%< + * Determine if the 'name' is in the RFC 1918 reverse namespace. + */ + +bool +dns_name_isula(const dns_name_t *owner); +/*%< + * Determine if the 'name' is in the ULA reverse namespace. + */ + +bool +dns_name_istat(const dns_name_t *name); +/* + * Determine if 'name' is a potential 'trust-anchor-telemetry' name. + */ + +ISC_LANG_ENDDECLS + +/* + *** High Performance Macros + ***/ + +/* + * WARNING: Use of these macros by applications may require recompilation + * of the application in some situations where calling the function + * would not. + * + * WARNING: No assertion checking is done for these macros. + */ + +#define DNS_NAME_INIT(n, o) \ + do { \ + dns_name_t *_n = (n); \ + /* memset(_n, 0, sizeof(*_n)); */ \ + _n->magic = DNS_NAME_MAGIC; \ + _n->ndata = NULL; \ + _n->length = 0; \ + _n->labels = 0; \ + _n->attributes = 0; \ + _n->offsets = (o); \ + _n->buffer = NULL; \ + ISC_LINK_INIT(_n, link); \ + ISC_LIST_INIT(_n->list); \ + } while (0) + +#define DNS_NAME_RESET(n) \ + do { \ + (n)->ndata = NULL; \ + (n)->length = 0; \ + (n)->labels = 0; \ + (n)->attributes &= ~DNS_NAMEATTR_ABSOLUTE; \ + if ((n)->buffer != NULL) \ + isc_buffer_clear((n)->buffer); \ + } while (0) + +#define DNS_NAME_SETBUFFER(n, b) (n)->buffer = (b) + +#define DNS_NAME_ISABSOLUTE(n) \ + (((n)->attributes & DNS_NAMEATTR_ABSOLUTE) != 0 ? true : false) + +#define DNS_NAME_COUNTLABELS(n) ((n)->labels) + +#define DNS_NAME_TOREGION(n, r) \ + do { \ + (r)->base = (n)->ndata; \ + (r)->length = (n)->length; \ + } while (0) + +#define DNS_NAME_SPLIT(n, l, p, s) \ + do { \ + dns_name_t *_n = (n); \ + dns_name_t *_p = (p); \ + dns_name_t *_s = (s); \ + unsigned int _l = (l); \ + if (_p != NULL) \ + dns_name_getlabelsequence(_n, 0, _n->labels - _l, _p); \ + if (_s != NULL) \ + dns_name_getlabelsequence(_n, _n->labels - _l, _l, \ + _s); \ + } while (0) + +#ifdef DNS_NAME_USEINLINE + +#define dns_name_init(n, o) DNS_NAME_INIT(n, o) +#define dns_name_reset(n) DNS_NAME_RESET(n) +#define dns_name_setbuffer(n, b) DNS_NAME_SETBUFFER(n, b) +#define dns_name_countlabels(n) DNS_NAME_COUNTLABELS(n) +#define dns_name_isabsolute(n) DNS_NAME_ISABSOLUTE(n) +#define dns_name_toregion(n, r) DNS_NAME_TOREGION(n, r) +#define dns_name_split(n, l, p, s) DNS_NAME_SPLIT(n, l, p, s) + +#endif /* DNS_NAME_USEINLINE */ + +#endif /* DNS_NAME_H */ diff --git a/lib/dns/include/dns/ncache.h b/lib/dns/include/dns/ncache.h new file mode 100644 index 0000000..783808c --- /dev/null +++ b/lib/dns/include/dns/ncache.h @@ -0,0 +1,187 @@ +/* + * 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. + */ + +#ifndef DNS_NCACHE_H +#define DNS_NCACHE_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/ncache.h + *\brief + * DNS Ncache + * + * XXX TBS XXX + * + * MP: + *\li The caller must ensure any required synchronization. + * + * Reliability: + *\li No anticipated impact. + * + * Resources: + *\li TBS + * + * Security: + *\li No anticipated impact. + * + * Standards: + *\li RFC2308 + */ + +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/stdtime.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/*% + * _OMITDNSSEC: + * Omit DNSSEC records when rendering. + */ +#define DNS_NCACHETOWIRE_OMITDNSSEC 0x0001 + +isc_result_t +dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, + dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl, + dns_ttl_t maxttl, dns_rdataset_t *addedrdataset); +isc_result_t +dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache, + dns_dbnode_t *node, dns_rdatatype_t covers, + isc_stdtime_t now, dns_ttl_t minttl, dns_ttl_t maxttl, + bool optout, dns_rdataset_t *addedrdataset); +/*%< + * Convert the authority data from 'message' into a negative cache + * rdataset, and store it in 'cache' at 'node' with a TTL limited to + * 'maxttl'. + * + * \li dns_ncache_add produces a negative cache entry with a trust of no + * more than answer + * \li dns_ncache_addoptout produces a negative cache entry which will have + * a trust of secure if all the records that make up the entry are secure. + * + * The 'covers' argument is the RR type whose nonexistence we are caching, + * or dns_rdatatype_any when caching a NXDOMAIN response. + * + * 'optout' indicates a DNS_RDATASETATTR_OPTOUT should be set. + * + * Note: + *\li If 'addedrdataset' is not NULL, then it will be attached to the added + * rdataset. See dns_db_addrdataset() for more details. + * + * Requires: + *\li 'message' is a valid message with a properly formatting negative cache + * authority section. + * + *\li The requirements of dns_db_addrdataset() apply to 'cache', 'node', + * 'now', and 'addedrdataset'. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOSPACE + * + *\li Any result code of dns_db_addrdataset() is a possible result code + * of dns_ncache_add(). + */ + +isc_result_t +dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx, + isc_buffer_t *target, unsigned int options, + unsigned int *countp); +/*%< + * Convert the negative caching rdataset 'rdataset' to wire format, + * compressing names as specified in 'cctx', and storing the result in + * 'target'. If 'omit_dnssec' is set, DNSSEC records will not + * be added to 'target'. + * + * Notes: + *\li The number of RRs added to target will be added to *countp. + * + * Requires: + *\li 'rdataset' is a valid negative caching rdataset. + * + *\li 'rdataset' is not empty. + * + *\li 'countp' is a valid pointer. + * + * Ensures: + *\li On a return of ISC_R_SUCCESS, 'target' contains a wire format + * for the data contained in 'rdataset'. Any error return leaves + * the buffer unchanged. + * + *\li *countp has been incremented by the number of RRs added to + * target. + * + * Returns: + *\li #ISC_R_SUCCESS - all ok + *\li #ISC_R_NOSPACE - 'target' doesn't have enough room + * + *\li Any error returned by dns_rdata_towire(), dns_rdataset_next(), + * dns_name_towire(). + */ + +isc_result_t +dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, + dns_rdatatype_t type, dns_rdataset_t *rdataset); +/*%< + * Search the negative caching rdataset for an rdataset with the + * specified name and type. + * + * Requires: + *\li 'ncacherdataset' is a valid negative caching rdataset. + * + *\li 'ncacherdataset' is not empty. + * + *\li 'name' is a valid name. + * + *\li 'type' is not SIG, or a meta-RR type. + * + *\li 'rdataset' is a valid disassociated rdataset. + * + * Ensures: + *\li On a return of ISC_R_SUCCESS, 'rdataset' is bound to the found + * rdataset. + * + * Returns: + *\li #ISC_R_SUCCESS - the rdataset was found. + *\li #ISC_R_NOTFOUND - the rdataset was not found. + * + */ + +isc_result_t +dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, + dns_rdatatype_t covers, dns_rdataset_t *rdataset); +/*%< + * Similar to dns_ncache_getrdataset() but get the rrsig that matches. + */ + +void +dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found, + dns_rdataset_t *rdataset); + +/*%< + * Extract the current rdataset and name from a ncache entry. + * + * Requires: + * \li 'ncacherdataset' to be valid and to be a negative cache entry + * \li 'found' to be valid. + * \li 'rdataset' to be unassociated. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_NCACHE_H */ diff --git a/lib/dns/include/dns/nsec.h b/lib/dns/include/dns/nsec.h new file mode 100644 index 0000000..efe2f94 --- /dev/null +++ b/lib/dns/include/dns/nsec.h @@ -0,0 +1,114 @@ +/* + * 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. + */ + +#ifndef DNS_NSEC_H +#define DNS_NSEC_H 1 + +/*! \file dns/nsec.h */ + +#include <stdbool.h> + +#include <isc/lang.h> + +#include <dns/name.h> +#include <dns/types.h> + +#define DNS_NSEC_BUFFERSIZE (DNS_NAME_MAXWIRE + 8192 + 512) + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_nsec_buildrdata(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, + const dns_name_t *target, unsigned char *buffer, + dns_rdata_t *rdata); +/*%< + * Build the rdata of a NSEC record. + * + * Requires: + *\li buffer Points to a temporary buffer of at least + * DNS_NSEC_BUFFERSIZE bytes. + *\li rdata Points to an initialized dns_rdata_t. + * + * Ensures: + * \li *rdata Contains a valid NSEC rdata. The 'data' member refers + * to 'buffer'. + */ + +isc_result_t +dns_nsec_build(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, + const dns_name_t *target, dns_ttl_t ttl); +/*%< + * Build a NSEC record and add it to a database. + */ + +bool +dns_nsec_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type); +/*%< + * Determine if a type is marked as present in an NSEC record. + * + * Requires: + *\li 'nsec' points to a valid rdataset of type NSEC + */ + +isc_result_t +dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version, bool *answer); +/* + * Report whether the DNSKEY RRset has a NSEC only algorithm. Unknown + * algorithms are assumed to support NSEC3. If DNSKEY is not found, + * *answer is set to false, and ISC_R_NOTFOUND is returned. + * + * Requires: + * 'answer' to be non NULL. + */ + +unsigned int +dns_nsec_compressbitmap(unsigned char *map, const unsigned char *raw, + unsigned int max_type); +/*%< + * Convert a raw bitmap into a compressed windowed bit map. 'map' and 'raw' + * may overlap. + * + * Returns the length of the compressed windowed bit map. + */ + +void +dns_nsec_setbit(unsigned char *array, unsigned int type, unsigned int bit); +/*%< + * Set type bit in raw 'array' to 'bit'. + */ + +bool +dns_nsec_isset(const unsigned char *array, unsigned int type); +/*%< + * Test if the corresponding 'type' bit is set in 'array'. + */ + +isc_result_t +dns_nsec_noexistnodata(dns_rdatatype_t type, const dns_name_t *name, + const dns_name_t *nsecname, dns_rdataset_t *nsecset, + bool *exists, bool *data, dns_name_t *wild, + dns_nseclog_t log, void *arg); +/*% + * Return ISC_R_SUCCESS if we can determine that the name doesn't exist + * or we can determine whether there is data or not at the name. + * If the name does not exist return the wildcard name. + * + * Return DNS_R_DNAME when the NSEC indicates that name is covered by + * a DNAME. 'wild' is not set in this case. + * + * Return ISC_R_IGNORE when the NSEC is not the appropriate one. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_NSEC_H */ diff --git a/lib/dns/include/dns/nsec3.h b/lib/dns/include/dns/nsec3.h new file mode 100644 index 0000000..3f20816 --- /dev/null +++ b/lib/dns/include/dns/nsec3.h @@ -0,0 +1,272 @@ +/* + * 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. + */ + +#ifndef DNS_NSEC3_H +#define DNS_NSEC3_H 1 + +#include <stdbool.h> + +#include <isc/iterated_hash.h> +#include <isc/lang.h> +#include <isc/log.h> + +#include <dns/db.h> +#include <dns/diff.h> +#include <dns/name.h> +#include <dns/rdatastruct.h> +#include <dns/types.h> + +#define DNS_NSEC3_SALTSIZE 255 +#define DNS_NSEC3_MAXITERATIONS 150U + +/* + * hash = 1, flags =1, iterations = 2, salt length = 1, salt = 255 (max) + * hash length = 1, hash = 255 (max), bitmap = 8192 + 512 (max) + */ +#define DNS_NSEC3_BUFFERSIZE (6 + 255 + 255 + 8192 + 512) +/* + * hash = 1, flags = 1, iterations = 2, salt length = 1, salt = 255 (max) + */ +#define DNS_NSEC3PARAM_BUFFERSIZE (5 + 255) + +/* + * Test "unknown" algorithm. Is mapped to dns_hash_sha1. + */ +#define DNS_NSEC3_UNKNOWNALG ((dns_hash_t)245U) + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_nsec3_buildrdata(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, + unsigned int hashalg, unsigned int optin, + unsigned int iterations, const unsigned char *salt, + size_t salt_length, const unsigned char *nexthash, + size_t hash_length, unsigned char *buffer, + dns_rdata_t *rdata); +/*%< + * Build the rdata of a NSEC3 record for the data at 'node'. + * Note: 'node' is not the node where the NSEC3 record will be stored. + * + * Requires: + * buffer Points to a temporary buffer of at least + * DNS_NSEC_BUFFERSIZE bytes. + * rdata Points to an initialized dns_rdata_t. + * + * Ensures: + * *rdata Contains a valid NSEC3 rdata. The 'data' member refers + * to 'buffer'. + */ + +bool +dns_nsec3_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type); +/*%< + * Determine if a type is marked as present in an NSEC3 record. + * + * Requires: + * 'nsec' points to a valid rdataset of type NSEC3 + */ + +isc_result_t +dns_nsec3_generate_salt(unsigned char *salt, size_t saltlen); +/*%< + * Generate a salt with the given salt length. + */ + +isc_result_t +dns_nsec3_hashname(dns_fixedname_t *result, + unsigned char rethash[NSEC3_MAX_HASH_LENGTH], + size_t *hash_length, const dns_name_t *name, + const dns_name_t *origin, dns_hash_t hashalg, + unsigned int iterations, const unsigned char *salt, + size_t saltlength); +/*%< + * Make a hashed domain name from an unhashed one. If rethash is not NULL + * the raw hash is stored there. + */ + +unsigned int +dns_nsec3_hashlength(dns_hash_t hash); +/*%< + * Return the length of the hash produced by the specified algorithm + * or zero when unknown. + */ + +bool +dns_nsec3_supportedhash(dns_hash_t hash); +/*%< + * Return whether we support this hash algorithm or not. + */ + +isc_result_t +dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version, + const dns_name_t *name, + const dns_rdata_nsec3param_t *nsec3param, dns_ttl_t nsecttl, + bool unsecure, dns_diff_t *diff); + +isc_result_t +dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version, + const dns_name_t *name, dns_ttl_t nsecttl, bool unsecure, + dns_diff_t *diff); + +isc_result_t +dns_nsec3_addnsec3sx(dns_db_t *db, dns_dbversion_t *version, + const dns_name_t *name, dns_ttl_t nsecttl, bool unsecure, + dns_rdatatype_t private, dns_diff_t *diff); +/*%< + * Add NSEC3 records for 'name', recording the change in 'diff'. + * Adjust previous NSEC3 records, if any, to reflect the addition. + * The existing NSEC3 records are removed. + * + * dns_nsec3_addnsec3() will only add records to the chain identified by + * 'nsec3param'. + * + * 'unsecure' should be set to reflect if this is a potentially + * unsecure delegation (no DS record). + * + * dns_nsec3_addnsec3s() will examine the NSEC3PARAM RRset to determine which + * chains to be updated. NSEC3PARAM records with the DNS_NSEC3FLAG_CREATE + * will be preferentially chosen over NSEC3PARAM records without + * DNS_NSEC3FLAG_CREATE set. NSEC3PARAM records with DNS_NSEC3FLAG_REMOVE + * set will be ignored by dns_nsec3_addnsec3s(). If DNS_NSEC3FLAG_CREATE + * is set then the new NSEC3 will have OPTOUT set to match the that in the + * NSEC3PARAM record otherwise OPTOUT will be inherited from the previous + * record in the chain. + * + * dns_nsec3_addnsec3sx() is similar to dns_nsec3_addnsec3s() but 'private' + * specifies the type of the private rdataset to be checked in addition to + * the nsec3param rdataset at the zone apex. + * + * Requires: + * 'db' to be valid. + * 'version' to be valid or NULL. + * 'name' to be valid. + * 'nsec3param' to be valid. + * 'diff' to be valid. + */ + +isc_result_t +dns_nsec3_delnsec3(dns_db_t *db, dns_dbversion_t *version, + const dns_name_t *name, + const dns_rdata_nsec3param_t *nsec3param, dns_diff_t *diff); + +isc_result_t +dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, + const dns_name_t *name, dns_diff_t *diff); + +isc_result_t +dns_nsec3_delnsec3sx(dns_db_t *db, dns_dbversion_t *version, + const dns_name_t *name, dns_rdatatype_t private, + dns_diff_t *diff); +/*%< + * Remove NSEC3 records for 'name', recording the change in 'diff'. + * Adjust previous NSEC3 records, if any, to reflect the removal. + * + * dns_nsec3_delnsec3() performs the above for the chain identified by + * 'nsec3param'. + * + * dns_nsec3_delnsec3s() examines the NSEC3PARAM RRset in a similar manner + * to dns_nsec3_addnsec3s(). Unlike dns_nsec3_addnsec3s() updated NSEC3 + * records have the OPTOUT flag preserved. + * + * dns_nsec3_delnsec3sx() is similar to dns_nsec3_delnsec3s() but 'private' + * specifies the type of the private rdataset to be checked in addition to + * the nsec3param rdataset at the zone apex. + * + * Requires: + * 'db' to be valid. + * 'version' to be valid or NULL. + * 'name' to be valid. + * 'nsec3param' to be valid. + * 'diff' to be valid. + */ + +isc_result_t +dns_nsec3_active(dns_db_t *db, dns_dbversion_t *version, bool complete, + bool *answer); + +isc_result_t +dns_nsec3_activex(dns_db_t *db, dns_dbversion_t *version, bool complete, + dns_rdatatype_t private, bool *answer); +/*%< + * Check if there are any complete/to be built NSEC3 chains. + * If 'complete' is true only complete chains will be recognized. + * + * dns_nsec3_activex() is similar to dns_nsec3_active() but 'private' + * specifies the type of the private rdataset to be checked in addition to + * the nsec3param rdataset at the zone apex. + * + * Requires: + * 'db' to be valid. + * 'version' to be valid or NULL. + * 'answer' to be non NULL. + */ + +unsigned int +dns_nsec3_maxiterations(void); +/*%< + * Return the maximum permissible number of NSEC3 iterations. + */ + +bool +dns_nsec3param_fromprivate(dns_rdata_t *src, dns_rdata_t *target, + unsigned char *buf, size_t buflen); +/*%< + * Convert a private rdata to a nsec3param rdata. + * + * Return true if 'src' could be successfully converted. + * + * 'buf' should be at least DNS_NSEC3PARAM_BUFFERSIZE in size. + */ + +void +dns_nsec3param_toprivate(dns_rdata_t *src, dns_rdata_t *target, + dns_rdatatype_t privatetype, unsigned char *buf, + size_t buflen); +/*%< + * Convert a nsec3param rdata to a private rdata. + * + * 'buf' should be at least src->length + 1 in size. + */ + +isc_result_t +dns_nsec3param_salttotext(dns_rdata_nsec3param_t *nsec3param, char *dst, + size_t dstlen); +/*%< + * Convert the salt of given NSEC3PARAM RDATA into hex-encoded, NULL-terminated + * text stored at "dst". + * + * Requires: + * + *\li "dst" to have enough space (as indicated by "dstlen") to hold the + * resulting text and its NULL-terminating byte. + */ + +isc_result_t +dns_nsec3param_deletechains(dns_db_t *db, dns_dbversion_t *ver, + dns_zone_t *zone, bool nonsec, dns_diff_t *diff); + +/*%< + * Mark NSEC3PARAM for deletion. + */ + +isc_result_t +dns_nsec3_noexistnodata(dns_rdatatype_t type, const dns_name_t *name, + const dns_name_t *nsec3name, dns_rdataset_t *nsec3set, + dns_name_t *zonename, bool *exists, bool *data, + bool *optout, bool *unknown, bool *setclosest, + bool *setnearest, dns_name_t *closest, + dns_name_t *nearest, dns_nseclog_t logit, void *arg); + +ISC_LANG_ENDDECLS + +#endif /* DNS_NSEC3_H */ diff --git a/lib/dns/include/dns/nta.h b/lib/dns/include/dns/nta.h new file mode 100644 index 0000000..905bf64 --- /dev/null +++ b/lib/dns/include/dns/nta.h @@ -0,0 +1,218 @@ +/* + * 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. + */ + +#ifndef DNS_NTA_H +#define DNS_NTA_H 1 + +/***** +***** Module Info +*****/ + +/*! \file + * \brief + * The NTA module provides services for storing and retrieving negative + * trust anchors, and determine whether a given domain is subject to + * DNSSEC validation. + */ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/buffer.h> +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/refcount.h> +#include <isc/rwlock.h> +#include <isc/stdtime.h> +#include <isc/task.h> +#include <isc/timer.h> + +#include <dns/rdataset.h> +#include <dns/resolver.h> +#include <dns/types.h> +#include <dns/view.h> + +ISC_LANG_BEGINDECLS + +struct dns_ntatable { + /* Unlocked. */ + unsigned int magic; + dns_view_t *view; + isc_rwlock_t rwlock; + isc_taskmgr_t *taskmgr; + isc_timermgr_t *timermgr; + isc_task_t *task; + /* Protected by atomics */ + isc_refcount_t references; + /* Locked by rwlock. */ + dns_rbt_t *table; + bool shuttingdown; +}; + +#define NTATABLE_MAGIC ISC_MAGIC('N', 'T', 'A', 't') +#define VALID_NTATABLE(nt) ISC_MAGIC_VALID(nt, NTATABLE_MAGIC) + +isc_result_t +dns_ntatable_create(dns_view_t *view, isc_taskmgr_t *taskmgr, + isc_timermgr_t *timermgr, dns_ntatable_t **ntatablep); +/*%< + * Create an NTA table in view 'view'. + * + * Requires: + * + *\li 'view' is a valid view. + * + *\li 'tmgr' is a valid timer manager. + * + *\li ntatablep != NULL && *ntatablep == NULL + * + * Ensures: + * + *\li On success, *ntatablep is a valid, empty NTA table. + * + * Returns: + * + *\li ISC_R_SUCCESS + *\li Any other result indicates failure. + */ + +void +dns_ntatable_attach(dns_ntatable_t *source, dns_ntatable_t **targetp); +/*%< + * Attach *targetp to source. + * + * Requires: + * + *\li 'source' is a valid ntatable. + * + *\li 'targetp' points to a NULL dns_ntatable_t *. + * + * Ensures: + * + *\li *targetp is attached to source. + */ + +void +dns_ntatable_detach(dns_ntatable_t **ntatablep); +/*%< + * Detach *ntatablep from its ntatable. + * + * Requires: + * + *\li 'ntatablep' points to a valid ntatable. + * + * Ensures: + * + *\li *ntatablep is NULL. + * + *\li If '*ntatablep' is the last reference to the ntatable, + * all resources used by the ntatable will be freed + */ + +isc_result_t +dns_ntatable_add(dns_ntatable_t *ntatable, const dns_name_t *name, bool force, + isc_stdtime_t now, uint32_t lifetime); +/*%< + * Add a negative trust anchor to 'ntatable' for name 'name', + * which will expire at time 'now' + 'lifetime'. If 'force' is true, + * then the NTA will persist for the entire specified lifetime. + * If it is false, then the name will be queried periodically and + * validation will be attempted to see whether it's still bogus; + * if validation is successful, the NTA will be allowed to expire + * early and validation below the NTA will resume. + * + * Notes: + * + *\li If an NTA already exists in the table, its expiry time + * is updated. + * + * Requires: + * + *\li 'ntatable' points to a valid ntatable. + * + *\li 'name' points to a valid name. + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li Any other result indicates failure. + */ + +isc_result_t +dns_ntatable_delete(dns_ntatable_t *ntatable, const dns_name_t *keyname); +/*%< + * Delete node(s) from 'ntatable' matching name 'keyname' + * + * Requires: + * + *\li 'ntatable' points to a valid ntatable. + * + *\li 'name' is not NULL + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li Any other result indicates failure. + */ + +bool +dns_ntatable_covered(dns_ntatable_t *ntatable, isc_stdtime_t now, + const dns_name_t *name, const dns_name_t *anchor); +/*%< + * Return true if 'name' is below a non-expired negative trust + * anchor which in turn is at or below 'anchor'. + * + * If 'ntatable' has not been initialized, return false. + * + * Requires: + * + *\li 'ntatable' is NULL or is a valid ntatable. + * + *\li 'name' is a valid absolute name. + */ + +isc_result_t +dns_ntatable_totext(dns_ntatable_t *ntatable, const char *view, + isc_buffer_t **buf); +/*%< + * Dump the NTA table to buffer at 'buf', with view names + * + * Requires: + * \li "ntatable" is a valid table. + * + * \li "*buf" is a valid buffer. + */ + +isc_result_t +dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp); +/*%< + * Dump the NTA table to the file opened as 'fp'. + */ + +isc_result_t +dns_ntatable_save(dns_ntatable_t *ntatable, FILE *fp); +/*%< + * Save the NTA table to the file opened as 'fp', for later loading. + */ + +void +dns_ntatable_shutdown(dns_ntatable_t *ntatable); +/*%< + * Cancel future checks to see if NTAs can be removed. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_NTA_H */ diff --git a/lib/dns/include/dns/opcode.h b/lib/dns/include/dns/opcode.h new file mode 100644 index 0000000..8fc5020 --- /dev/null +++ b/lib/dns/include/dns/opcode.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#ifndef DNS_OPCODE_H +#define DNS_OPCODE_H 1 + +/*! \file dns/opcode.h */ + +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target); +/*%< + * Put a textual representation of error 'opcode' into 'target'. + * + * Requires: + *\li 'opcode' is a valid opcode. + * + *\li 'target' is a valid text buffer. + * + * Ensures: + *\li If the result is success: + * The used space in 'target' is updated. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #ISC_R_NOSPACE target buffer is too small + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_OPCODE_H */ diff --git a/lib/dns/include/dns/order.h b/lib/dns/include/dns/order.h new file mode 100644 index 0000000..0d6c267 --- /dev/null +++ b/lib/dns/include/dns/order.h @@ -0,0 +1,93 @@ +/* + * 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. + */ + +#ifndef DNS_ORDER_H +#define DNS_ORDER_H 1 + +/*! \file dns/order.h */ + +#include <isc/lang.h> +#include <isc/types.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_order_create(isc_mem_t *mctx, dns_order_t **orderp); +/*%< + * Create a order object. + * + * Requires: + * \li 'orderp' to be non NULL and '*orderp == NULL'. + *\li 'mctx' to be valid. + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOMEMORY + */ + +isc_result_t +dns_order_add(dns_order_t *order, const dns_name_t *name, + dns_rdatatype_t rdtype, dns_rdataclass_t rdclass, + unsigned int mode); +/*%< + * Add a entry to the end of the order list. + * + * Requires: + * \li 'order' to be valid. + *\li 'name' to be valid. + *\li 'mode' to be one of #DNS_RDATASETATTR_RANDOMIZE, + * #DNS_RDATASETATTR_FIXEDORDER or zero (#DNS_RDATASETATTR_CYCLIC). + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +unsigned int +dns_order_find(dns_order_t *order, const dns_name_t *name, + dns_rdatatype_t rdtype, dns_rdataclass_t rdclass); +/*%< + * Find the first matching entry on the list. + * + * Requires: + *\li 'order' to be valid. + *\li 'name' to be valid. + * + * Returns the mode set by dns_order_add() or zero. + */ + +void +dns_order_attach(dns_order_t *source, dns_order_t **target); +/*%< + * Attach to the 'source' object. + * + * Requires: + * \li 'source' to be valid. + *\li 'target' to be non NULL and '*target == NULL'. + */ + +void +dns_order_detach(dns_order_t **orderp); +/*%< + * Detach from the object. Clean up if last this was the last + * reference. + * + * Requires: + *\li '*orderp' to be valid. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_ORDER_H */ diff --git a/lib/dns/include/dns/peer.h b/lib/dns/include/dns/peer.h new file mode 100644 index 0000000..5f9a4de --- /dev/null +++ b/lib/dns/include/dns/peer.h @@ -0,0 +1,279 @@ +/* + * 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. + */ + +#ifndef DNS_PEER_H +#define DNS_PEER_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/peer.h + * \brief + * Data structures for peers (e.g. a 'server' config file statement) + */ + +/*** + *** Imports + ***/ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/netaddr.h> +#include <isc/refcount.h> + +#include <dns/types.h> + +#define DNS_PEERLIST_MAGIC ISC_MAGIC('s', 'e', 'R', 'L') +#define DNS_PEER_MAGIC ISC_MAGIC('S', 'E', 'r', 'v') + +#define DNS_PEERLIST_VALID(ptr) ISC_MAGIC_VALID(ptr, DNS_PEERLIST_MAGIC) +#define DNS_PEER_VALID(ptr) ISC_MAGIC_VALID(ptr, DNS_PEER_MAGIC) + +/*** + *** Types + ***/ + +struct dns_peerlist { + unsigned int magic; + isc_refcount_t refs; + + isc_mem_t *mem; + + ISC_LIST(dns_peer_t) elements; +}; + +struct dns_peer { + unsigned int magic; + isc_refcount_t refs; + + isc_mem_t *mem; + + isc_netaddr_t address; + unsigned int prefixlen; + bool bogus; + dns_transfer_format_t transfer_format; + uint32_t transfers; + bool support_ixfr; + bool provide_ixfr; + bool request_ixfr; + bool support_edns; + bool request_nsid; + bool send_cookie; + bool request_expire; + bool force_tcp; + bool tcp_keepalive; + dns_name_t *key; + isc_sockaddr_t *transfer_source; + isc_dscp_t transfer_dscp; + isc_sockaddr_t *notify_source; + isc_dscp_t notify_dscp; + isc_sockaddr_t *query_source; + isc_dscp_t query_dscp; + uint16_t udpsize; /* receive size */ + uint16_t maxudp; /* transmit size */ + uint16_t padding; /* pad block size */ + uint8_t ednsversion; /* edns version */ + + uint32_t bitflags; + + ISC_LINK(dns_peer_t) next; +}; + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_peerlist_new(isc_mem_t *mem, dns_peerlist_t **list); + +void +dns_peerlist_attach(dns_peerlist_t *source, dns_peerlist_t **target); + +void +dns_peerlist_detach(dns_peerlist_t **list); + +/* + * After return caller still holds a reference to peer. + */ +void +dns_peerlist_addpeer(dns_peerlist_t *peers, dns_peer_t *peer); + +/* + * Ditto. */ +isc_result_t +dns_peerlist_peerbyaddr(dns_peerlist_t *peers, const isc_netaddr_t *addr, + dns_peer_t **retval); + +/* + * What he said. + */ +isc_result_t +dns_peerlist_currpeer(dns_peerlist_t *peers, dns_peer_t **retval); + +isc_result_t +dns_peer_new(isc_mem_t *mem, const isc_netaddr_t *ipaddr, dns_peer_t **peer); + +isc_result_t +dns_peer_newprefix(isc_mem_t *mem, const isc_netaddr_t *ipaddr, + unsigned int prefixlen, dns_peer_t **peer); + +void +dns_peer_attach(dns_peer_t *source, dns_peer_t **target); + +void +dns_peer_detach(dns_peer_t **list); + +isc_result_t +dns_peer_setbogus(dns_peer_t *peer, bool newval); + +isc_result_t +dns_peer_getbogus(dns_peer_t *peer, bool *retval); + +isc_result_t +dns_peer_setrequestixfr(dns_peer_t *peer, bool newval); + +isc_result_t +dns_peer_getrequestixfr(dns_peer_t *peer, bool *retval); + +isc_result_t +dns_peer_setprovideixfr(dns_peer_t *peer, bool newval); + +isc_result_t +dns_peer_getprovideixfr(dns_peer_t *peer, bool *retval); + +isc_result_t +dns_peer_setrequestnsid(dns_peer_t *peer, bool newval); + +isc_result_t +dns_peer_getrequestnsid(dns_peer_t *peer, bool *retval); + +isc_result_t +dns_peer_setsendcookie(dns_peer_t *peer, bool newval); + +isc_result_t +dns_peer_getsendcookie(dns_peer_t *peer, bool *retval); + +isc_result_t +dns_peer_setrequestexpire(dns_peer_t *peer, bool newval); + +isc_result_t +dns_peer_getrequestexpire(dns_peer_t *peer, bool *retval); + +isc_result_t +dns_peer_setsupportedns(dns_peer_t *peer, bool newval); + +isc_result_t +dns_peer_getforcetcp(dns_peer_t *peer, bool *retval); + +isc_result_t +dns_peer_setforcetcp(dns_peer_t *peer, bool newval); + +isc_result_t +dns_peer_gettcpkeepalive(dns_peer_t *peer, bool *retval); + +isc_result_t +dns_peer_settcpkeepalive(dns_peer_t *peer, bool newval); + +isc_result_t +dns_peer_getsupportedns(dns_peer_t *peer, bool *retval); + +isc_result_t +dns_peer_settransfers(dns_peer_t *peer, uint32_t newval); + +isc_result_t +dns_peer_gettransfers(dns_peer_t *peer, uint32_t *retval); + +isc_result_t +dns_peer_settransferformat(dns_peer_t *peer, dns_transfer_format_t newval); + +isc_result_t +dns_peer_gettransferformat(dns_peer_t *peer, dns_transfer_format_t *retval); + +isc_result_t +dns_peer_setkeybycharp(dns_peer_t *peer, const char *keyval); + +isc_result_t +dns_peer_getkey(dns_peer_t *peer, dns_name_t **retval); + +isc_result_t +dns_peer_setkey(dns_peer_t *peer, dns_name_t **keyval); + +isc_result_t +dns_peer_settransfersource(dns_peer_t *peer, + const isc_sockaddr_t *transfer_source); + +isc_result_t +dns_peer_gettransfersource(dns_peer_t *peer, isc_sockaddr_t *transfer_source); + +isc_result_t +dns_peer_setudpsize(dns_peer_t *peer, uint16_t udpsize); + +isc_result_t +dns_peer_getudpsize(dns_peer_t *peer, uint16_t *udpsize); + +isc_result_t +dns_peer_setmaxudp(dns_peer_t *peer, uint16_t maxudp); + +isc_result_t +dns_peer_getmaxudp(dns_peer_t *peer, uint16_t *maxudp); + +isc_result_t +dns_peer_setpadding(dns_peer_t *peer, uint16_t padding); + +isc_result_t +dns_peer_getpadding(dns_peer_t *peer, uint16_t *padding); + +isc_result_t +dns_peer_setnotifysource(dns_peer_t *peer, const isc_sockaddr_t *notify_source); + +isc_result_t +dns_peer_getnotifysource(dns_peer_t *peer, isc_sockaddr_t *notify_source); + +isc_result_t +dns_peer_setquerysource(dns_peer_t *peer, const isc_sockaddr_t *query_source); + +isc_result_t +dns_peer_getquerysource(dns_peer_t *peer, isc_sockaddr_t *query_source); + +isc_result_t +dns_peer_setnotifydscp(dns_peer_t *peer, isc_dscp_t dscp); + +isc_result_t +dns_peer_getnotifydscp(dns_peer_t *peer, isc_dscp_t *dscpp); + +isc_result_t +dns_peer_settransferdscp(dns_peer_t *peer, isc_dscp_t dscp); + +isc_result_t +dns_peer_gettransferdscp(dns_peer_t *peer, isc_dscp_t *dscpp); + +isc_result_t +dns_peer_setquerydscp(dns_peer_t *peer, isc_dscp_t dscp); + +isc_result_t +dns_peer_getquerydscp(dns_peer_t *peer, isc_dscp_t *dscpp); + +isc_result_t +dns_peer_setednsversion(dns_peer_t *peer, uint8_t ednsversion); + +isc_result_t +dns_peer_getednsversion(dns_peer_t *peer, uint8_t *ednsversion); +ISC_LANG_ENDDECLS + +#endif /* DNS_PEER_H */ diff --git a/lib/dns/include/dns/portlist.h b/lib/dns/include/dns/portlist.h new file mode 100644 index 0000000..03306db --- /dev/null +++ b/lib/dns/include/dns/portlist.h @@ -0,0 +1,102 @@ +/* + * 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. + */ + +/*! \file dns/portlist.h */ + +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/net.h> +#include <isc/types.h> + +#include <dns/types.h> + +#ifndef DNS_PORTLIST_H +#define DNS_PORTLIST_H 1 + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_portlist_create(isc_mem_t *mctx, dns_portlist_t **portlistp); +/*%< + * Create a port list. + * + * Requires: + *\li 'mctx' to be valid. + *\li 'portlistp' to be non NULL and '*portlistp' to be NULL; + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_UNEXPECTED + */ + +isc_result_t +dns_portlist_add(dns_portlist_t *portlist, int af, in_port_t port); +/*%< + * Add the given <port,af> tuple to the portlist. + * + * Requires: + *\li 'portlist' to be valid. + *\li 'af' to be AF_INET or AF_INET6 + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +void +dns_portlist_remove(dns_portlist_t *portlist, int af, in_port_t port); +/*%< + * Remove the given <port,af> tuple to the portlist. + * + * Requires: + *\li 'portlist' to be valid. + *\li 'af' to be AF_INET or AF_INET6 + */ + +bool +dns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port); +/*%< + * Find the given <port,af> tuple to the portlist. + * + * Requires: + *\li 'portlist' to be valid. + *\li 'af' to be AF_INET or AF_INET6 + * + * Returns + * \li #true if the tuple is found, false otherwise. + */ + +void +dns_portlist_attach(dns_portlist_t *portlist, dns_portlist_t **portlistp); +/*%< + * Attach to a port list. + * + * Requires: + *\li 'portlist' to be valid. + *\li 'portlistp' to be non NULL and '*portlistp' to be NULL; + */ + +void +dns_portlist_detach(dns_portlist_t **portlistp); +/*%< + * Detach from a port list. + * + * Requires: + *\li '*portlistp' to be valid. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_PORTLIST_H */ diff --git a/lib/dns/include/dns/private.h b/lib/dns/include/dns/private.h new file mode 100644 index 0000000..8e1c4c7 --- /dev/null +++ b/lib/dns/include/dns/private.h @@ -0,0 +1,69 @@ +/* + * 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. + */ + +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/types.h> + +#include <dns/db.h> +#include <dns/types.h> + +#ifndef DNS_PRIVATE_H +#define DNS_PRIVATE_H + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_private_chains(dns_db_t *db, dns_dbversion_t *ver, + dns_rdatatype_t privatetype, bool *build_nsec, + bool *build_nsec3); +/*%< + * Examine the NSEC, NSEC3PARAM and privatetype RRsets at the apex of the + * database to determine which of NSEC or NSEC3 chains we are currently + * maintaining. In normal operations only one of NSEC or NSEC3 is being + * maintained but when we are transitiong between NSEC and NSEC3 we need + * to update both sets of chains. If 'privatetype' is zero then the + * privatetype RRset will not be examined. + * + * Requires: + * \li 'db' is valid. + * \li 'version' is valid or NULL. + * \li 'build_nsec' is a pointer to a bool or NULL. + * \li 'build_nsec3' is a pointer to a bool or NULL. + * + * Returns: + * \li ISC_R_SUCCESS, 'build_nsec' and 'build_nsec3' will be valid. + * \li other on error + */ + +isc_result_t +dns_private_totext(dns_rdata_t *privaterdata, isc_buffer_t *buffer); +/*%< + * Convert a private-type RR 'privaterdata' to human-readable form, + * and place the result in 'buffer'. The text should indicate + * which action the private-type record specifies and whether the + * action has been completed. + * + * Requires: + * \li 'privaterdata' is a valid rdata containing at least five bytes + * \li 'buffer' is a valid buffer + * + * Returns: + * \li ISC_R_SUCCESS + * \li other on error + */ + +ISC_LANG_ENDDECLS + +#endif /* ifndef DNS_PRIVATE_H */ diff --git a/lib/dns/include/dns/rbt.h b/lib/dns/include/dns/rbt.h new file mode 100644 index 0000000..4a6b078 --- /dev/null +++ b/lib/dns/include/dns/rbt.h @@ -0,0 +1,1060 @@ +/* + * 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. + */ + +#ifndef DNS_RBT_H +#define DNS_RBT_H 1 + +/*! \file dns/rbt.h */ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/assertions.h> +#include <isc/crc64.h> +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/refcount.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/*@{*/ +/*% + * Option values for dns_rbt_findnode() and dns_rbt_findname(). + * These are used to form a bitmask. + */ +#define DNS_RBTFIND_NOOPTIONS 0x00 +#define DNS_RBTFIND_EMPTYDATA 0x01 +#define DNS_RBTFIND_NOEXACT 0x02 +#define DNS_RBTFIND_NOPREDECESSOR 0x04 +/*@}*/ + +#define DNS_RBT_USEMAGIC 1 + +#define DNS_RBT_LOCKLENGTH (sizeof(((dns_rbtnode_t *)0)->locknum) * 8) + +#define DNS_RBTNODE_MAGIC ISC_MAGIC('R', 'B', 'N', 'O') +#if DNS_RBT_USEMAGIC +#define DNS_RBTNODE_VALID(n) ISC_MAGIC_VALID(n, DNS_RBTNODE_MAGIC) +#else /* if DNS_RBT_USEMAGIC */ +#define DNS_RBTNODE_VALID(n) true +#endif /* if DNS_RBT_USEMAGIC */ + +/*% + * This is the structure that is used for each node in the red/black + * tree of trees. NOTE WELL: the implementation manages this as a variable + * length structure, with the actual wire-format name and other data + * appended to this structure. Allocating a contiguous block of memory for + * multiple dns_rbtnode structures will not work. + */ +typedef struct dns_rbtnode dns_rbtnode_t; +enum { + DNS_RBT_NSEC_NORMAL = 0, /* in main tree */ + DNS_RBT_NSEC_HAS_NSEC = 1, /* also has node in nsec tree */ + DNS_RBT_NSEC_NSEC = 2, /* in nsec tree */ + DNS_RBT_NSEC_NSEC3 = 3 /* in nsec3 tree */ +}; +struct dns_rbtnode { +#if DNS_RBT_USEMAGIC + unsigned int magic; +#endif /* if DNS_RBT_USEMAGIC */ + /*@{*/ + /*! + * The following bitfields add up to a total bitwidth of 32. + * The range of values necessary for each item is indicated, + * but in the case of "attributes" the field is wider to accommodate + * possible future expansion. + * + * In each case below the "range" indicated is what's _necessary_ for + * the bitfield to hold, not what it actually _can_ hold. + * + * Note: Tree lock must be held before modifying these + * bit-fields. + * + * Note: The two "unsigned int :0;" unnamed bitfields on either + * side of the bitfields below are scaffolding that border the + * set of bitfields which are accessed after acquiring the tree + * lock. Please don't insert any other bitfield members between + * the unnamed bitfields unless they should also be accessed + * after acquiring the tree lock. + */ + unsigned int : 0; /* start of bitfields c/o tree lock */ + unsigned int is_root : 1; /*%< range is 0..1 */ + unsigned int color : 1; /*%< range is 0..1 */ + unsigned int find_callback : 1; /*%< range is 0..1 */ + unsigned int attributes : 3; /*%< range is 0..2 */ + unsigned int nsec : 2; /*%< range is 0..3 */ + unsigned int namelen : 8; /*%< range is 1..255 */ + unsigned int offsetlen : 8; /*%< range is 1..128 */ + unsigned int oldnamelen : 8; /*%< range is 1..255 */ + /*@}*/ + + /* flags needed for serialization to file */ + unsigned int is_mmapped : 1; + unsigned int parent_is_relative : 1; + unsigned int left_is_relative : 1; + unsigned int right_is_relative : 1; + unsigned int down_is_relative : 1; + unsigned int data_is_relative : 1; + + /* + * full name length; set during serialization, and used + * during deserialization to calculate database size. + * should be cleared after use. + */ + unsigned int fullnamelen : 8; /*%< range is 1..255 */ + + /* node needs to be cleaned from rpz */ + unsigned int rpz : 1; + unsigned int : 0; /* end of bitfields c/o tree lock */ + + /*% + * These are needed for hashing. The 'uppernode' points to the + * node's superdomain node in the parent subtree, so that it can + * be reached from a child that was found by a hash lookup. + */ + unsigned int hashval; + dns_rbtnode_t *uppernode; + dns_rbtnode_t *hashnext; + + dns_rbtnode_t *parent; + dns_rbtnode_t *left; + dns_rbtnode_t *right; + dns_rbtnode_t *down; + + /*% + * Used for LRU cache. This linked list is used to mark nodes which + * have no data any longer, but we cannot unlink at that exact moment + * because we did not or could not obtain a write lock on the tree. + */ + ISC_LINK(dns_rbtnode_t) deadlink; + + /*@{*/ + /*! + * These values are used in the RBT DB implementation. The appropriate + * node lock must be held before accessing them. + * + * Note: The two "unsigned int :0;" unnamed bitfields on either + * side of the bitfields below are scaffolding that border the + * set of bitfields which are accessed after acquiring the node + * lock. Please don't insert any other bitfield members between + * the unnamed bitfields unless they should also be accessed + * after acquiring the node lock. + * + * NOTE: Do not merge these fields into bitfields above, as + * they'll all be put in the same qword that could be accessed + * without the node lock as it shares the qword with other + * members. Leave these members here so that they occupy a + * separate region of memory. + */ + void *data; + uint8_t : 0; /* start of bitfields c/o node lock */ + uint8_t dirty : 1; + uint8_t wild : 1; + uint8_t : 0; /* end of bitfields c/o node lock */ + uint16_t locknum; /* note that this is not in the bitfield */ + isc_refcount_t references; + /*@}*/ +}; + +typedef isc_result_t (*dns_rbtfindcallback_t)(dns_rbtnode_t *node, + dns_name_t *name, + void *callback_arg); + +typedef isc_result_t (*dns_rbtdatawriter_t)(FILE *file, unsigned char *data, + void *arg, uint64_t *crc); + +typedef isc_result_t (*dns_rbtdatafixer_t)(dns_rbtnode_t *rbtnode, void *base, + size_t offset, void *arg, + uint64_t *crc); + +typedef void (*dns_rbtdeleter_t)(void *, void *); + +/***** +***** Chain Info +*****/ + +/*! + * A chain is used to keep track of the sequence of nodes to reach any given + * node from the root of the tree. Originally nodes did not have parent + * pointers in them (for memory usage reasons) so there was no way to find + * the path back to the root from any given node. Now that nodes have parent + * pointers, chains might be going away in a future release, though the + * movement functionality would remain. + * + * Chains may be used to iterate over a tree of trees. After setting up the + * chain's structure using dns_rbtnodechain_init(), it needs to be initialized + * to point to the lexically first or lexically last node in the tree of trees + * using dns_rbtnodechain_first() or dns_rbtnodechain_last(), respectively. + * Calling dns_rbtnodechain_next() or dns_rbtnodechain_prev() then moves the + * chain over to the next or previous node, respectively. + * + * In any event, parent information, whether via parent pointers or chains, is + * necessary information for iterating through the tree or for basic internal + * tree maintenance issues (ie, the rotations that are done to rebalance the + * tree when a node is added). The obvious implication of this is that for a + * chain to remain valid, the tree has to be locked down against writes for the + * duration of the useful life of the chain, because additions or removals can + * change the path from the root to the node the chain has targeted. + * + * The dns_rbtnodechain_ functions _first, _last, _prev and _next all take + * dns_name_t parameters for the name and the origin, which can be NULL. If + * non-NULL, 'name' will end up pointing to the name data and offsets that are + * stored at the node (and thus it will be read-only), so it should be a + * regular dns_name_t that has been initialized with dns_name_init. When + * 'origin' is non-NULL, it will get the name of the origin stored in it, so it + * needs to have its own buffer space and offsets, which is most easily + * accomplished with a dns_fixedname_t. It is _not_ necessary to reinitialize + * either 'name' or 'origin' between calls to the chain functions. + * + * NOTE WELL: even though the name data at the root of the tree of trees will + * be absolute (typically just "."), it will will be made into a relative name + * with an origin of "." -- an empty name when the node is ".". This is + * because a common on operation on 'name' and 'origin' is to use + * dns_name_concatenate() on them to generate the complete name. An empty name + * can be detected when dns_name_countlabels == 0, and is printed by + * dns_name_totext()/dns_name_format() as "@", consistent with RFC1035's + * definition of "@" as the current origin. + * + * dns_rbtnodechain_current is similar to the _first, _last, _prev and _next + * functions but additionally can provide the node to which the chain points. + */ + +/*% + * The number of level blocks to allocate at a time. Currently the maximum + * number of levels is allocated directly in the structure, but future + * revisions of this code might have a static initial block with dynamic + * growth. Allocating space for 256 levels when the tree is almost never that + * deep is wasteful, but it's not clear that it matters, since the waste is + * only 2MB for 1000 concurrently active chains on a system with 64-bit + * pointers. + */ +#define DNS_RBT_LEVELBLOCK 254 + +typedef struct dns_rbtnodechain { + unsigned int magic; + /*% + * The terminal node of the chain. It is not in levels[]. + * This is ostensibly private ... but in a pinch it could be + * used tell that the chain points nowhere without needing to + * call dns_rbtnodechain_current(). + */ + dns_rbtnode_t *end; + /*% + * The maximum number of labels in a name is 128; bitstrings mean + * a conceptually very large number (which I have not bothered to + * compute) of logical levels because splitting can potentially occur + * at each bit. However, DNSSEC restricts the number of "logical" + * labels in a name to 255, meaning only 254 pointers are needed + * in the worst case. + */ + dns_rbtnode_t *levels[DNS_RBT_LEVELBLOCK]; + /*% + * level_count indicates how deep the chain points into the + * tree of trees, and is the index into the levels[] array. + * Thus, levels[level_count - 1] is the last level node stored. + * A chain that points to the top level of the tree of trees has + * a level_count of 0, the first level has a level_count of 1, and + * so on. + */ + unsigned int level_count; + /*% + * level_matches tells how many levels matched above the node + * returned by dns_rbt_findnode(). A match (partial or exact) found + * in the first level thus results in level_matches being set to 1. + * This is used by the rbtdb to set the start point for a recursive + * search of superdomains until the RR it is looking for is found. + */ + unsigned int level_matches; +} dns_rbtnodechain_t; + +/***** +***** Public interfaces. +*****/ +isc_result_t +dns_rbt_create(isc_mem_t *mctx, dns_rbtdeleter_t deleter, void *deleter_arg, + dns_rbt_t **rbtp); +/*%< + * Initialize a red-black tree of trees. + * + * Notes: + *\li The deleter argument, if non-null, points to a function that is + * responsible for cleaning up any memory associated with the data + * pointer of a node when the node is deleted. It is passed the + * deleted node's data pointer as its first argument and deleter_arg + * as its second argument. + * + * Requires: + * \li mctx is a pointer to a valid memory context. + *\li rbtp != NULL && *rbtp == NULL + *\li arg == NULL iff deleter == NULL + * + * Ensures: + *\li If result is ISC_R_SUCCESS: + * *rbtp points to a valid red-black tree manager + * + *\li If result is failure: + * *rbtp does not point to a valid red-black tree manager. + * + * Returns: + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_NOMEMORY Resource limit: Out of Memory + */ + +isc_result_t +dns_rbt_addname(dns_rbt_t *rbt, const dns_name_t *name, void *data); +/*%< + * Add 'name' to the tree of trees, associated with 'data'. + * + * Notes: + *\li 'data' is never required to be non-NULL, but specifying it + * when the name is added is faster than searching for 'name' + * again and then setting the data pointer. The lack of a data pointer + * for a node also has other ramifications regarding whether + * dns_rbt_findname considers a node to exist, or dns_rbt_deletename + * joins nodes. + * + * Requires: + *\li rbt is a valid rbt manager. + *\li dns_name_isabsolute(name) == TRUE + * + * Ensures: + *\li 'name' is not altered in any way. + * + *\li Any external references to nodes in the tree are unaffected by + * node splits that are necessary to insert the new name. + * + *\li If result is #ISC_R_SUCCESS: + * 'name' is findable in the red/black tree of trees in O(log N). + * The data pointer of the node for 'name' is set to 'data'. + * + *\li If result is #ISC_R_EXISTS or #ISC_R_NOSPACE: + * The tree of trees is unaltered. + * + *\li If result is #ISC_R_NOMEMORY: + * No guarantees. + * + * Returns: + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_EXISTS The name already exists with associated data. + *\li #ISC_R_NOSPACE The name had more logical labels than are allowed. + *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory + */ + +isc_result_t +dns_rbt_addnode(dns_rbt_t *rbt, const dns_name_t *name, dns_rbtnode_t **nodep); + +/*%< + * Just like dns_rbt_addname, but returns the address of the node. + * + * Requires: + *\li rbt is a valid rbt structure. + *\li dns_name_isabsolute(name) == TRUE + *\li nodep != NULL && *nodep == NULL + * + * Ensures: + *\li 'name' is not altered in any way. + * + *\li Any external references to nodes in the tree are unaffected by + * node splits that are necessary to insert the new name. + * + *\li If result is ISC_R_SUCCESS: + * 'name' is findable in the red/black tree of trees in O(log N). + * *nodep is the node that was added for 'name'. + * + *\li If result is ISC_R_EXISTS: + * The tree of trees is unaltered. + * *nodep is the existing node for 'name'. + * + *\li If result is ISC_R_NOMEMORY: + * No guarantees. + * + * Returns: + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_EXISTS The name already exists, possibly without data. + *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory + */ + +isc_result_t +dns_rbt_findname(dns_rbt_t *rbt, const dns_name_t *name, unsigned int options, + dns_name_t *foundname, void **data); +/*%< + * Get the data pointer associated with 'name'. + * + * Notes: + *\li When #DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is + * returned (also subject to #DNS_RBTFIND_EMPTYDATA), even when there is + * an exact match in the tree. + * + *\li A node that has no data is considered not to exist for this function, + * unless the #DNS_RBTFIND_EMPTYDATA option is set. + * + * Requires: + *\li rbt is a valid rbt manager. + *\li dns_name_isabsolute(name) == TRUE + *\li data != NULL && *data == NULL + * + * Ensures: + *\li 'name' and the tree are not altered in any way. + * + *\li If result is ISC_R_SUCCESS: + * *data is the data associated with 'name'. + * + *\li If result is DNS_R_PARTIALMATCH: + * *data is the data associated with the deepest superdomain + * of 'name' which has data. + * + *\li If result is ISC_R_NOTFOUND: + * Neither the name nor a superdomain was found with data. + * + * Returns: + *\li #ISC_R_SUCCESS Success + *\li #DNS_R_PARTIALMATCH Superdomain found with data + *\li #ISC_R_NOTFOUND No match + *\li #ISC_R_NOSPACE Concatenating nodes to form foundname failed + */ + +isc_result_t +dns_rbt_findnode(dns_rbt_t *rbt, const dns_name_t *name, dns_name_t *foundname, + dns_rbtnode_t **node, dns_rbtnodechain_t *chain, + unsigned int options, dns_rbtfindcallback_t callback, + void *callback_arg); +/*%< + * Find the node for 'name'. + * + * Notes: + *\li A node that has no data is considered not to exist for this function, + * unless the DNS_RBTFIND_EMPTYDATA option is set. This applies to both + * exact matches and partial matches. + * + *\li If the chain parameter is non-NULL, then the path through the tree + * to the DNSSEC predecessor of the searched for name is maintained, + * unless the DNS_RBTFIND_NOPREDECESSOR or DNS_RBTFIND_NOEXACT option + * is used. (For more details on those options, see below.) + * + *\li If there is no predecessor, then the chain will point to nowhere, as + * indicated by chain->end being NULL or dns_rbtnodechain_current + * returning ISC_R_NOTFOUND. Note that in a normal Internet DNS RBT + * there will always be a predecessor for all names except the root + * name, because '.' will exist and '.' is the predecessor of + * everything. But you can certainly construct a trivial tree and a + * search for it that has no predecessor. + * + *\li Within the chain structure, the 'levels' member of the structure holds + * the root node of each level except the first. + * + *\li The 'level_count' of the chain indicates how deep the chain to the + * predecessor name is, as an index into the 'levels[]' array. It does + * not count name elements, per se, but only levels of the tree of trees, + * the distinction arising because multiple labels from a name can be + * stored on only one level. It is also does not include the level + * that has the node, since that level is not stored in levels[]. + * + *\li The chain's 'level_matches' is not directly related to the predecessor. + * It is the number of levels above the level of the found 'node', + * regardless of whether it was a partial match or exact match. When + * the node is found in the top level tree, or no node is found at all, + * level_matches is 0. + * + *\li When DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is + * returned (also subject to DNS_RBTFIND_EMPTYDATA), even when + * there is an exact match in the tree. In this case, the chain + * will not point to the DNSSEC predecessor, but will instead point + * to the exact match, if there was any. Thus the preceding paragraphs + * should have "exact match" substituted for "predecessor" to describe + * how the various elements of the chain are set. This was done to + * ensure that the chain's state was sane, and to prevent problems that + * occurred when running the predecessor location code under conditions + * it was not designed for. It is not clear *where* the chain should + * point when DNS_RBTFIND_NOEXACT is set, so if you end up using a chain + * with this option because you want a particular node, let us know + * where you want the chain pointed, so this can be made more firm. + * + * Requires: + *\li rbt is a valid rbt manager. + *\li dns_name_isabsolute(name) == TRUE. + *\li node != NULL && *node == NULL. + *\li #DNS_RBTFIND_NOEXACT and DNS_RBTFIND_NOPREDECESSOR are mutually + * exclusive. + * + * Ensures: + *\li 'name' and the tree are not altered in any way. + * + *\li If result is ISC_R_SUCCESS: + *\verbatim + * *node is the terminal node for 'name'. + * + * 'foundname' and 'name' represent the same name (though not + * the same memory). + * + * 'chain' points to the DNSSEC predecessor, if any, of 'name'. + * + * chain->level_matches and chain->level_count are equal. + *\endverbatim + * + * If result is DNS_R_PARTIALMATCH: + *\verbatim + * *node is the data associated with the deepest superdomain + * of 'name' which has data. + * + * 'foundname' is the name of deepest superdomain (which has + * data, unless the DNS_RBTFIND_EMPTYDATA option is set). + * + * 'chain' points to the DNSSEC predecessor, if any, of 'name'. + *\endverbatim + * + *\li If result is ISC_R_NOTFOUND: + *\verbatim + * Neither the name nor a superdomain was found. *node is NULL. + * + * 'chain' points to the DNSSEC predecessor, if any, of 'name'. + * + * chain->level_matches is 0. + *\endverbatim + * + * Returns: + *\li #ISC_R_SUCCESS Success + *\li #DNS_R_PARTIALMATCH Superdomain found with data + *\li #ISC_R_NOTFOUND No match, or superdomain with no data + *\li #ISC_R_NOSPACE Concatenating nodes to form foundname failed + */ + +isc_result_t +dns_rbt_deletename(dns_rbt_t *rbt, const dns_name_t *name, bool recurse); +/*%< + * Delete 'name' from the tree of trees. + * + * Notes: + *\li When 'name' is removed, if recurse is true then all of its + * subnames are removed too. + * + * Requires: + *\li rbt is a valid rbt manager. + *\li dns_name_isabsolute(name) == TRUE + * + * Ensures: + *\li 'name' is not altered in any way. + * + *\li Does NOT ensure that any external references to nodes in the tree + * are unaffected by node joins. + * + *\li If result is ISC_R_SUCCESS: + * 'name' does not appear in the tree with data; however, + * the node for the name might still exist which can be + * found with dns_rbt_findnode (but not dns_rbt_findname). + * + *\li If result is ISC_R_NOTFOUND: + * 'name' does not appear in the tree with data, because + * it did not appear in the tree before the function was called. + * + *\li If result is something else: + * See result codes for dns_rbt_findnode (if it fails, the + * node is not deleted) or dns_rbt_deletenode (if it fails, + * the node is deleted, but the tree is not optimized when + * it could have been). + * + * Returns: + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_NOTFOUND No match + *\li something_else Any return code from dns_rbt_findnode except + * DNS_R_PARTIALMATCH (which causes ISC_R_NOTFOUND + * to be returned instead), and any code from + * dns_rbt_deletenode. + */ + +isc_result_t +dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, bool recurse); +/*%< + * Delete 'node' from the tree of trees. + * + * Notes: + *\li When 'node' is removed, if recurse is true then all nodes + * in levels down from it are removed too. + * + * Requires: + *\li rbt is a valid rbt manager. + *\li node != NULL. + * + * Ensures: + *\li Does NOT ensure that any external references to nodes in the tree + * are unaffected by node joins. + * + *\li If result is ISC_R_SUCCESS: + * 'node' does not appear in the tree with data; however, + * the node might still exist if it serves as a pointer to + * a lower tree level as long as 'recurse' was false, hence + * the node could can be found with dns_rbt_findnode when + * that function's empty_data_ok parameter is true. + * + *\li If result is ISC_R_NOMEMORY or ISC_R_NOSPACE: + * The node was deleted, but the tree structure was not + * optimized. + * + * Returns: + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory when joining nodes. + *\li #ISC_R_NOSPACE dns_name_concatenate failed when joining nodes. + */ + +void +dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name); +/*%< + * Convert the sequence of labels stored at 'node' into a 'name'. + * + * Notes: + *\li This function does not return the full name, from the root, but + * just the labels at the indicated node. + * + *\li The name data pointed to by 'name' is the information stored + * in the node, not a copy. Altering the data at this pointer + * will likely cause grief. + * + * Requires: + * \li name->offsets == NULL + * + * Ensures: + * \li 'name' is DNS_NAMEATTR_READONLY. + * + * \li 'name' will point directly to the labels stored after the + * dns_rbtnode_t struct. + * + * \li 'name' will have offsets that also point to the information stored + * as part of the node. + */ + +isc_result_t +dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name); +/*%< + * Like dns_rbt_namefromnode, but returns the full name from the root. + * + * Notes: + * \li Unlike dns_rbt_namefromnode, the name will not point directly + * to node data. Rather, dns_name_concatenate will be used to copy + * the name data from each node into the 'name' argument. + * + * Requires: + * \li name != NULL + * \li name has a dedicated buffer. + * + * Returns: + * \li ISC_R_SUCCESS + * \li ISC_R_NOSPACE (possible via dns_name_concatenate) + * \li DNS_R_NAMETOOLONG (possible via dns_name_concatenate) + */ + +char * +dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname, unsigned int size); +/*%< + * Format the full name of a node for printing, using dns_name_format(). + * + * Notes: + * \li 'size' is the length of the printname buffer. This should be + * DNS_NAME_FORMATSIZE or larger. + * + * Requires: + * \li node and printname are not NULL. + * + * Returns: + * \li The 'printname' pointer. + */ + +unsigned int +dns_rbt_nodecount(dns_rbt_t *rbt); +/*%< + * Obtain the number of nodes in the tree of trees. + * + * Requires: + * \li rbt is a valid rbt manager. + */ + +size_t +dns_rbt_hashsize(dns_rbt_t *rbt); +/*%< + * Obtain the current number of buckets in the 'rbt' hash table. + * + * Requires: + * \li rbt is a valid rbt manager. + */ + +isc_result_t +dns_rbt_adjusthashsize(dns_rbt_t *rbt, size_t size); +/*%< + * Adjust the number of buckets in the 'rbt' hash table, according to the + * expected maximum size of the rbt database. + * + * Requires: + * \li rbt is a valid rbt manager. + * \li size is expected maximum memory footprint of rbt. + */ + +void +dns_rbt_destroy(dns_rbt_t **rbtp); +isc_result_t +dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum); +/*%< + * Stop working with a red-black tree of trees. + * If 'quantum' is zero then the entire tree will be destroyed. + * If 'quantum' is non zero then up to 'quantum' nodes will be destroyed + * allowing the rbt to be incrementally destroyed by repeated calls to + * dns_rbt_destroy2(). Once dns_rbt_destroy2() has been called no other + * operations than dns_rbt_destroy()/dns_rbt_destroy2() should be + * performed on the tree of trees. + * + * Requires: + * \li *rbt is a valid rbt manager. + * + * Ensures on ISC_R_SUCCESS: + * \li All space allocated by the RBT library has been returned. + * + * \li *rbt is invalidated as an rbt manager. + * + * Returns: + * \li ISC_R_SUCCESS + * \li ISC_R_QUOTA if 'quantum' nodes have been destroyed. + */ + +off_t +dns_rbt_serialize_align(off_t target); +/*%< + * Align the provided integer to a pointer-size boundary. + * This should be used if, during serialization of data to a will-be + * mmap()ed file, a pointer alignment is needed for some data. + */ + +isc_result_t +dns_rbt_serialize_tree(FILE *file, dns_rbt_t *rbt, + dns_rbtdatawriter_t datawriter, void *writer_arg, + off_t *offset); +/*%< + * Write out the RBT structure and its data to a file. + * + * Notes: + * \li The file must be an actual file which allows seek() calls, so it cannot + * be a stream. Returns ISC_R_INVALIDFILE if not. + */ + +isc_result_t +dns_rbt_deserialize_tree(void *base_address, size_t filesize, + off_t header_offset, isc_mem_t *mctx, + dns_rbtdeleter_t deleter, void *deleter_arg, + dns_rbtdatafixer_t datafixer, void *fixer_arg, + dns_rbtnode_t **originp, dns_rbt_t **rbtp); +/*%< + * Read a RBT structure and its data from a file. + * + * If 'originp' is not NULL, then it is pointed to the root node of the RBT. + * + * Notes: + * \li The file must be an actual file which allows seek() calls, so it cannot + * be a stream. This condition is not checked in the code. + */ + +void +dns_rbt_printtext(dns_rbt_t *rbt, void (*data_printer)(FILE *, void *), + FILE *f); +/*%< + * Print an ASCII representation of the internal structure of the red-black + * tree of trees to the passed stream. + * + * data_printer is a callback function that is called to print the data + * in a node. It should print it to the passed FILE stream. + * + * Notes: + * \li The name stored at each node, along with the node's color, is printed. + * Then the down pointer, left and right pointers are displayed + * recursively in turn. NULL down pointers are silently omitted; + * NULL left and right pointers are printed. + */ + +void +dns_rbt_printdot(dns_rbt_t *rbt, bool show_pointers, FILE *f); +/*%< + * Print a GraphViz dot representation of the internal structure of the + * red-black tree of trees to the passed stream. + * + * If show_pointers is TRUE, pointers are also included in the generated + * graph. + * + * Notes: + * \li The name stored at each node, along with the node's color is displayed. + * Then the down pointer, left and right pointers are displayed + * recursively in turn. NULL left, right and down pointers are + * silently omitted. + */ + +void +dns_rbt_printnodeinfo(dns_rbtnode_t *n, FILE *f); +/*%< + * Print out various information about a node + * + * Requires: + *\li 'n' is a valid pointer. + * + *\li 'f' points to a valid open FILE structure that allows writing. + */ + +size_t +dns__rbt_getheight(dns_rbt_t *rbt); +/*%< + * Return the maximum height of sub-root nodes found in the red-black + * forest. + * + * The height of a node is defined as the number of nodes in the longest + * path from the node to a leaf. For each subtree in the forest, this + * function determines the height of its root node. Then it returns the + * maximum such height in the forest. + * + * Note: This function exists for testing purposes. Non-test code must + * not use it. + * + * Requires: + * \li rbt is a valid rbt manager. + */ + +bool +dns__rbt_checkproperties(dns_rbt_t *rbt); +/*%< + * Check red-black properties of the forest. + * + * Note: This function exists for testing purposes. Non-test code must + * not use it. + * + * Requires: + * \li rbt is a valid rbt manager. + */ + +size_t +dns__rbtnode_getdistance(dns_rbtnode_t *node); +/*%< + * Return the distance (in nodes) from the node to its upper node of its + * subtree. The root node has a distance of 1. A child of the root node + * has a distance of 2. + */ + +/***** +***** Chain Functions +*****/ + +void +dns_rbtnodechain_init(dns_rbtnodechain_t *chain); +/*%< + * Initialize 'chain'. + * + * Requires: + *\li 'chain' is a valid pointer. + * + * Ensures: + *\li 'chain' is suitable for use. + */ + +void +dns_rbtnodechain_reset(dns_rbtnodechain_t *chain); +/*%< + * Free any dynamic storage associated with 'chain', and then reinitialize + * 'chain'. + * + * Requires: + *\li 'chain' is a valid pointer. + * + * Ensures: + *\li 'chain' is suitable for use, and uses no dynamic storage. + */ + +void +dns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain); +/*%< + * Free any dynamic storage associated with 'chain', and then invalidates it. + * + * Notes: + *\li Future calls to any dns_rbtnodechain_ function will need to call + * dns_rbtnodechain_init on the chain first (except, of course, + * dns_rbtnodechain_init itself). + * + * Requires: + *\li 'chain' is a valid chain. + * + * Ensures: + *\li 'chain' is no longer suitable for use, and uses no dynamic storage. + */ + +isc_result_t +dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name, + dns_name_t *origin, dns_rbtnode_t **node); +/*%< + * Provide the name, origin and node to which the chain is currently pointed. + * + * Notes: + *\li The tree need not have be locked against additions for the chain + * to remain valid, however there are no guarantees if any deletion + * has been made since the chain was established. + * + * Requires: + *\li 'chain' is a valid chain. + * + * Ensures: + *\li 'node', if non-NULL, is the node to which the chain was pointed + * by dns_rbt_findnode, dns_rbtnodechain_first or dns_rbtnodechain_last. + * If none were called for the chain since it was initialized or reset, + * or if the was no predecessor to the name searched for with + * dns_rbt_findnode, then '*node' is NULL and ISC_R_NOTFOUND is returned. + * + *\li 'name', if non-NULL, is the name stored at the terminal level of + * the chain. This is typically a single label, like the "www" of + * "www.isc.org", but need not be so. At the root of the tree of trees, + * if the node is "." then 'name' is ".", otherwise it is relative to ".". + * (Minimalist and atypical case: if the tree has just the name + * "isc.org." then the root node's stored name is "isc.org." but 'name' + * will be "isc.org".) + * + *\li 'origin', if non-NULL, is the sequence of labels in the levels + * above the terminal level, such as "isc.org." in the above example. + * 'origin' is always "." for the root node. + * + * + * Returns: + *\li #ISC_R_SUCCESS name, origin & node were successfully set. + *\li #ISC_R_NOTFOUND The chain does not point to any node. + *\li <something_else> Any error return from dns_name_concatenate. + */ + +isc_result_t +dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt, + dns_name_t *name, dns_name_t *origin); +/*%< + * Set the chain to the lexically first node in the tree of trees. + * + * Notes: + *\li By the definition of ordering for DNS names, the root of the tree of + * trees is the very first node, since everything else in the megatree + * uses it as a common suffix. + * + * Requires: + *\li 'chain' is a valid chain. + *\li 'rbt' is a valid rbt manager. + * + * Ensures: + *\li The chain points to the very first node of the tree. + * + *\li 'name' and 'origin', if non-NULL, are set as described for + * dns_rbtnodechain_current. Thus 'origin' will always be ".". + * + * Returns: + *\li #DNS_R_NEWORIGIN The name & origin were successfully set. + *\li <something_else> Any error result from dns_rbtnodechain_current. + */ + +isc_result_t +dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt, + dns_name_t *name, dns_name_t *origin); +/*%< + * Set the chain to the lexically last node in the tree of trees. + * + * Requires: + *\li 'chain' is a valid chain. + *\li 'rbt' is a valid rbt manager. + * + * Ensures: + *\li The chain points to the very last node of the tree. + * + *\li 'name' and 'origin', if non-NULL, are set as described for + * dns_rbtnodechain_current. + * + * Returns: + *\li #DNS_R_NEWORIGIN The name & origin were successfully set. + *\li #ISC_R_NOMEMORY Resource Limit: Out of Memory building chain. + *\li <something_else> Any error result from dns_name_concatenate. + */ + +isc_result_t +dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name, + dns_name_t *origin); +/*%< + * Adjusts chain to point the DNSSEC predecessor of the name to which it + * is currently pointed. + * + * Requires: + *\li 'chain' is a valid chain. + *\li 'chain' has been pointed somewhere in the tree with dns_rbt_findnode, + * dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that + * dns_rbt_findnode is not guaranteed to point the chain somewhere, + * since there may have been no predecessor to the searched for name. + * + * Ensures: + *\li The chain is pointed to the predecessor of its current target. + * + *\li 'name' and 'origin', if non-NULL, are set as described for + * dns_rbtnodechain_current. + * + *\li 'origin' is only if a new origin was found. + * + * Returns: + *\li #ISC_R_SUCCESS The predecessor was found and 'name' was set. + *\li #DNS_R_NEWORIGIN The predecessor was found with a + * different origin and 'name' and 'origin' were set. \li #ISC_R_NOMORE There + * was no predecessor. \li <something_else> Any error result from + * dns_rbtnodechain_current. + */ + +isc_result_t +dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name, + dns_name_t *origin); +/*%< + * Adjusts chain to point the DNSSEC successor of the name to which it + * is currently pointed. + * + * Requires: + *\li 'chain' is a valid chain. + *\li 'chain' has been pointed somewhere in the tree with dns_rbt_findnode, + * dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that + * dns_rbt_findnode is not guaranteed to point the chain somewhere, + * since there may have been no predecessor to the searched for name. + * + * Ensures: + *\li The chain is pointed to the successor of its current target. + * + *\li 'name' and 'origin', if non-NULL, are set as described for + * dns_rbtnodechain_current. + * + *\li 'origin' is only if a new origin was found. + * + * Returns: + *\li #ISC_R_SUCCESS The successor was found and 'name' was set. + *\li #DNS_R_NEWORIGIN The successor was found with a different + * origin and 'name' and 'origin' were set. + *\li #ISC_R_NOMORE There was no successor. + *\li <something_else> Any error result from dns_name_concatenate. + */ + +isc_result_t +dns_rbtnodechain_down(dns_rbtnodechain_t *chain, dns_name_t *name, + dns_name_t *origin); +/*%< + * Descend down if possible. + */ + +isc_result_t +dns_rbtnodechain_nextflat(dns_rbtnodechain_t *chain, dns_name_t *name); +/*%< + * Find the next node at the current depth in DNSSEC order. + */ + +unsigned int +dns__rbtnode_namelen(dns_rbtnode_t *node); +/*%< + * Returns the length of the full name of the node. Used only internally + * and in unit tests. + */ +ISC_LANG_ENDDECLS + +#endif /* DNS_RBT_H */ diff --git a/lib/dns/include/dns/rcode.h b/lib/dns/include/dns/rcode.h new file mode 100644 index 0000000..dbc2dfe --- /dev/null +++ b/lib/dns/include/dns/rcode.h @@ -0,0 +1,110 @@ +/* + * 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. + */ + +#ifndef DNS_RCODE_H +#define DNS_RCODE_H 1 + +/*! \file dns/rcode.h */ + +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_rcode_fromtext(dns_rcode_t *rcodep, isc_textregion_t *source); +/*%< + * Convert the text 'source' refers to into a DNS error value. + * + * Requires: + *\li 'rcodep' is a valid pointer. + * + *\li 'source' is a valid text region. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #DNS_R_UNKNOWN type is unknown + */ + +isc_result_t +dns_rcode_totext(dns_rcode_t rcode, isc_buffer_t *target); +/*%< + * Put a textual representation of error 'rcode' into 'target'. + * + * Requires: + *\li 'rcode' is a valid rcode. + * + *\li 'target' is a valid text buffer. + * + * Ensures: + *\li If the result is success: + * The used space in 'target' is updated. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #ISC_R_NOSPACE target buffer is too small + */ + +isc_result_t +dns_tsigrcode_fromtext(dns_rcode_t *rcodep, isc_textregion_t *source); +/*%< + * Convert the text 'source' refers to into a TSIG/TKEY error value. + * + * Requires: + *\li 'rcodep' is a valid pointer. + * + *\li 'source' is a valid text region. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #DNS_R_UNKNOWN type is unknown + */ + +isc_result_t +dns_tsigrcode_totext(dns_rcode_t rcode, isc_buffer_t *target); +/*%< + * Put a textual representation of TSIG/TKEY error 'rcode' into 'target'. + * + * Requires: + *\li 'rcode' is a valid TSIG/TKEY error code. + * + *\li 'target' is a valid text buffer. + * + * Ensures: + *\li If the result is success: + * The used space in 'target' is updated. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #ISC_R_NOSPACE target buffer is too small + */ + +isc_result_t +dns_hashalg_fromtext(unsigned char *hashalg, isc_textregion_t *source); +/*%< + * Convert the text 'source' refers to into a has algorithm value. + * + * Requires: + *\li 'hashalg' is a valid pointer. + * + *\li 'source' is a valid text region. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #DNS_R_UNKNOWN type is unknown + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_RCODE_H */ diff --git a/lib/dns/include/dns/rdata.h b/lib/dns/include/dns/rdata.h new file mode 100644 index 0000000..2118dc4 --- /dev/null +++ b/lib/dns/include/dns/rdata.h @@ -0,0 +1,812 @@ +/* + * 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. + */ + +#ifndef DNS_RDATA_H +#define DNS_RDATA_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/rdata.h + * \brief + * Provides facilities for manipulating DNS rdata, including conversions to + * and from wire format and text format. + * + * Given the large amount of rdata possible in a nameserver, it was important + * to come up with a very efficient way of storing rdata, but at the same + * time allow it to be manipulated. + * + * The decision was to store rdata in uncompressed wire format, + * and not to make it a fully abstracted object; i.e. certain parts of the + * server know rdata is stored that way. This saves a lot of memory, and + * makes adding rdata to messages easy. Having much of the server know + * the representation would be perilous, and we certainly don't want each + * user of rdata to be manipulating such a low-level structure. This is + * where the rdata module comes in. The module allows rdata handles to be + * created and attached to uncompressed wire format regions. All rdata + * operations and conversions are done through these handles. + * + * Implementation Notes: + * + *\li The routines in this module are expected to be synthesized by the + * build process from a set of source files, one per rdata type. For + * portability, it's probably best that the building be done by a C + * program. Adding a new rdata type will be a simple matter of adding + * a file to a directory and rebuilding the server. *All* knowledge of + * the format of a particular rdata type is in this file. + * + * MP: + *\li Clients of this module must impose any required synchronization. + * + * Reliability: + *\li This module deals with low-level byte streams. Errors in any of + * the functions are likely to crash the server or corrupt memory. + * + *\li Rdata is typed, and the caller must know what type of rdata it has. + * A caller that gets this wrong could crash the server. + * + *\li The fromstruct() and tostruct() routines use a void * pointer to + * represent the structure. The caller must ensure that it passes a + * pointer to the appropriate type, or the server could crash or memory + * could be corrupted. + * + * Resources: + *\li None. + * + * Security: + * + *\li *** WARNING *** + * dns_rdata_fromwire() deals with raw network data. An error in + * this routine could result in the failure or hijacking of the server. + * + * Standards: + *\li RFC1035 + *\li Draft EDNS0 (0) + *\li Draft EDNS1 (0) + *\li Draft Binary Labels (2) + *\li Draft Local Compression (1) + *\li Various RFCs for particular types; these will be documented in the + * sources files of the types. + * + */ + +/*** + *** Imports + ***/ + +#include <stdbool.h> + +#include <isc/lang.h> + +#include <dns/message.h> +#include <dns/name.h> +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Types + ***/ + +/*% + ***** An 'rdata' is a handle to a binary region. The handle has an RR + ***** class and type, and the data in the binary region is in the format + ***** of the given class and type. + *****/ +/*% + * Clients are strongly discouraged from using this type directly, with + * the exception of the 'link' field which may be used directly for whatever + * purpose the client desires. + */ +struct dns_rdata { + unsigned char *data; + unsigned int length; + dns_rdataclass_t rdclass; + dns_rdatatype_t type; + unsigned int flags; + ISC_LINK(dns_rdata_t) link; +}; + +#define DNS_RDATA_INIT \ + { \ + NULL, 0, 0, 0, 0, { (void *)(-1), (void *)(-1) } \ + } + +#define DNS_RDATA_CHECKINITIALIZED +#ifdef DNS_RDATA_CHECKINITIALIZED +#define DNS_RDATA_INITIALIZED(rdata) \ + ((rdata)->data == NULL && (rdata)->length == 0 && \ + (rdata)->rdclass == 0 && (rdata)->type == 0 && (rdata)->flags == 0 && \ + !ISC_LINK_LINKED((rdata), link)) +#else /* ifdef DNS_RDATA_CHECKINITIALIZED */ +#ifdef ISC_LIST_CHECKINIT +#define DNS_RDATA_INITIALIZED(rdata) (!ISC_LINK_LINKED((rdata), link)) +#else /* ifdef ISC_LIST_CHECKINIT */ +#define DNS_RDATA_INITIALIZED(rdata) true +#endif /* ifdef ISC_LIST_CHECKINIT */ +#endif /* ifdef DNS_RDATA_CHECKINITIALIZED */ + +#define DNS_RDATA_UPDATE 0x0001 /*%< update pseudo record. */ +#define DNS_RDATA_OFFLINE 0x0002 /*%< RRSIG has a offline key. */ + +#define DNS_RDATA_VALIDFLAGS(rdata) \ + (((rdata)->flags & ~(DNS_RDATA_UPDATE | DNS_RDATA_OFFLINE)) == 0) + +/* + * The maximum length of a RDATA that can be sent on the wire. + * Max packet size (65535) less header (12), less name (1), type (2), + * class (2), ttl(4), length (2). + * + * None of the defined types that support name compression can exceed + * this and all new types are to be sent uncompressed. + */ + +#define DNS_RDATA_MAXLENGTH 65512U + +/* + * Flags affecting rdata formatting style. Flags 0xFFFF0000 + * are used by masterfile-level formatting and defined elsewhere. + * See additional comments at dns_rdata_tofmttext(). + */ + +/*% Split the rdata into multiple lines to try to keep it + * within the "width". */ +#define DNS_STYLEFLAG_MULTILINE 0x00000001ULL + +/*% Output explanatory comments. */ +#define DNS_STYLEFLAG_COMMENT 0x00000002ULL +#define DNS_STYLEFLAG_RRCOMMENT 0x00000004ULL + +/*% Output KEYDATA in human readable format. */ +#define DNS_STYLEFLAG_KEYDATA 0x00000008ULL + +/*% Output textual RR type and RDATA in RFC 3597 unknown format */ +#define DNS_STYLEFLAG_UNKNOWNFORMAT 0x00000010ULL + +/*% Print AAAA record fully expanded */ +#define DNS_STYLEFLAG_EXPANDAAAA 0x00000020ULL + +#define DNS_RDATA_DOWNCASE DNS_NAME_DOWNCASE +#define DNS_RDATA_CHECKNAMES DNS_NAME_CHECKNAMES +#define DNS_RDATA_CHECKNAMESFAIL DNS_NAME_CHECKNAMESFAIL +#define DNS_RDATA_CHECKREVERSE DNS_NAME_CHECKREVERSE +#define DNS_RDATA_CHECKMX DNS_NAME_CHECKMX +#define DNS_RDATA_CHECKMXFAIL DNS_NAME_CHECKMXFAIL +#define DNS_RDATA_UNKNOWNESCAPE 0x80000000 + +/*** + *** Initialization + ***/ + +void +dns_rdata_init(dns_rdata_t *rdata); +/*%< + * Make 'rdata' empty. + * + * Requires: + * 'rdata' is a valid rdata (i.e. not NULL, points to a struct dns_rdata) + */ + +void +dns_rdata_reset(dns_rdata_t *rdata); +/*%< + * Make 'rdata' empty. + * + * Requires: + *\li 'rdata' is a previously initialized rdata and is not linked. + */ + +void +dns_rdata_clone(const dns_rdata_t *src, dns_rdata_t *target); +/*%< + * Clone 'target' from 'src'. + * + * Requires: + *\li 'src' to be initialized. + *\li 'target' to be initialized. + */ + +/*** + *** Comparisons + ***/ + +int +dns_rdata_compare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2); +/*%< + * Determine the relative ordering under the DNSSEC order relation of + * 'rdata1' and 'rdata2'. + * + * Requires: + * + *\li 'rdata1' is a valid, non-empty rdata + * + *\li 'rdata2' is a valid, non-empty rdata + * + * Returns: + *\li < 0 'rdata1' is less than 'rdata2' + *\li 0 'rdata1' is equal to 'rdata2' + *\li > 0 'rdata1' is greater than 'rdata2' + */ + +int +dns_rdata_casecompare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2); +/*%< + * dns_rdata_casecompare() is similar to dns_rdata_compare() but also + * compares domain names case insensitively in known rdata types that + * are treated as opaque data by dns_rdata_compare(). + * + * Requires: + * + *\li 'rdata1' is a valid, non-empty rdata + * + *\li 'rdata2' is a valid, non-empty rdata + * + * Returns: + *\li < 0 'rdata1' is less than 'rdata2' + *\li 0 'rdata1' is equal to 'rdata2' + *\li > 0 'rdata1' is greater than 'rdata2' + */ + +/*** + *** Conversions + ***/ + +void +dns_rdata_fromregion(dns_rdata_t *rdata, dns_rdataclass_t rdclass, + dns_rdatatype_t type, isc_region_t *r); +/*%< + * Make 'rdata' refer to region 'r'. + * + * Requires: + * + *\li The data in 'r' is properly formatted for whatever type it is. + */ + +void +dns_rdata_toregion(const dns_rdata_t *rdata, isc_region_t *r); +/*%< + * Make 'r' refer to 'rdata'. + */ + +isc_result_t +dns_rdata_fromwire(dns_rdata_t *rdata, dns_rdataclass_t rdclass, + dns_rdatatype_t type, isc_buffer_t *source, + dns_decompress_t *dctx, unsigned int options, + isc_buffer_t *target); +/*%< + * Copy the possibly-compressed rdata at source into the target region. + * + * Notes: + *\li Name decompression policy is controlled by 'dctx'. + * + * 'options' + *\li DNS_RDATA_DOWNCASE downcase domain names when they are copied + * into target. + * + * Requires: + * + *\li 'rdclass' and 'type' are valid. + * + *\li 'source' is a valid buffer, and the active region of 'source' + * references the rdata to be processed. + * + *\li 'target' is a valid buffer. + * + *\li 'dctx' is a valid decompression context. + * + * Ensures, + * if result is success: + * \li If 'rdata' is not NULL, it is attached to the target. + * \li The conditions dns_name_fromwire() ensures for names hold + * for all names in the rdata. + * \li The current location in source is advanced, and the used space + * in target is updated. + * + * Result: + *\li Success + *\li Any non-success status from dns_name_fromwire() + *\li Various 'Bad Form' class failures depending on class and type + *\li Bad Form: Input too short + *\li Resource Limit: Not enough space + */ + +isc_result_t +dns_rdata_towire(dns_rdata_t *rdata, dns_compress_t *cctx, + isc_buffer_t *target); +/*%< + * Convert 'rdata' into wire format, compressing it as specified by the + * compression context 'cctx', and storing the result in 'target'. + * + * Notes: + *\li If the compression context allows global compression, then the + * global compression table may be updated. + * + * Requires: + *\li 'rdata' is a valid, non-empty rdata + * + *\li target is a valid buffer + * + *\li Any offsets specified in a global compression table are valid + * for target. + * + * Ensures, + * if the result is success: + * \li The used space in target is updated. + * + * Returns: + *\li Success + *\li Any non-success status from dns_name_towire() + *\li Resource Limit: Not enough space + */ + +isc_result_t +dns_rdata_fromtext(dns_rdata_t *rdata, dns_rdataclass_t rdclass, + dns_rdatatype_t type, isc_lex_t *lexer, + const dns_name_t *origin, unsigned int options, + isc_mem_t *mctx, isc_buffer_t *target, + dns_rdatacallbacks_t *callbacks); +/*%< + * Convert the textual representation of a DNS rdata into uncompressed wire + * form stored in the target region. Tokens constituting the text of the rdata + * are taken from 'lexer'. + * + * Notes: + *\li Relative domain names in the rdata will have 'origin' appended to them. + * A NULL origin implies "origin == dns_rootname". + * + * + * 'options' + *\li DNS_RDATA_DOWNCASE downcase domain names when they are copied + * into target. + *\li DNS_RDATA_CHECKNAMES perform checknames checks. + *\li DNS_RDATA_CHECKNAMESFAIL fail if the checknames check fail. If + * not set a warning will be issued. + *\li DNS_RDATA_CHECKREVERSE this should set if the owner name ends + * in IP6.ARPA, IP6.INT or IN-ADDR.ARPA. + * + * Requires: + * + *\li 'rdclass' and 'type' are valid. + * + *\li 'lexer' is a valid isc_lex_t. + * + *\li 'mctx' is a valid isc_mem_t. + * + *\li 'target' is a valid region. + * + *\li 'origin' if non NULL it must be absolute. + * + *\li 'callbacks' to be NULL or callbacks->warn and callbacks->error be + * initialized. + * + * Ensures, + * if result is success: + *\li If 'rdata' is not NULL, it is attached to the target. + * + *\li The conditions dns_name_fromtext() ensures for names hold + * for all names in the rdata. + * + *\li The used space in target is updated. + * + * Result: + *\li Success + *\li Translated result codes from isc_lex_gettoken + *\li Various 'Bad Form' class failures depending on class and type + *\li Bad Form: Input too short + *\li Resource Limit: Not enough space + *\li Resource Limit: Not enough memory + */ + +isc_result_t +dns_rdata_totext(dns_rdata_t *rdata, const dns_name_t *origin, + isc_buffer_t *target); +/*%< + * Convert 'rdata' into text format, storing the result in 'target'. + * The text will consist of a single line, with fields separated by + * single spaces. + * + * Notes: + *\li If 'origin' is not NULL, then any names in the rdata that are + * subdomains of 'origin' will be made relative it. + * + *\li XXX Do we *really* want to support 'origin'? I'm inclined towards "no" + * at the moment. + * + * Requires: + * + *\li 'rdata' is a valid, non-empty rdata + * + *\li 'origin' is NULL, or is a valid name + * + *\li 'target' is a valid text buffer + * + * Ensures, + * if the result is success: + * + * \li The used space in target is updated. + * + * Returns: + *\li Success + *\li Any non-success status from dns_name_totext() + *\li Resource Limit: Not enough space + */ + +isc_result_t +dns_rdata_tofmttext(dns_rdata_t *rdata, const dns_name_t *origin, + dns_masterstyle_flags_t flags, unsigned int width, + unsigned int split_width, const char *linebreak, + isc_buffer_t *target); +/*%< + * Like dns_rdata_totext, but do formatted output suitable for + * database dumps. This is intended for use by dns_db_dump(); + * library users are discouraged from calling it directly. + * + * If (flags & #DNS_STYLEFLAG_MULTILINE) != 0, attempt to stay + * within 'width' by breaking the text into multiple lines. + * The string 'linebreak' is inserted between lines, and parentheses + * are added when necessary. Because RRs contain unbreakable elements + * such as domain names whose length is variable, unpredictable, and + * potentially large, there is no guarantee that the lines will + * not exceed 'width' anyway. + * + * If (flags & #DNS_STYLEFLAG_MULTILINE) == 0, the rdata is always + * printed as a single line, and no parentheses are used. + * The 'width' and 'linebreak' arguments are ignored. + * + * If (flags & #DNS_STYLEFLAG_COMMENT) != 0, output explanatory + * comments next to things like the SOA timer fields. Some + * comments (e.g., the SOA ones) are only printed when multiline + * output is selected. + * + * base64 rdata text (e.g., DNSKEY records) will be split into chunks + * of 'split_width' characters. If split_width == 0, the text will + * not be split at all. If split_width == UINT_MAX (0xffffffff), then + * it is undefined and falls back to the default value of 'width' + */ + +isc_result_t +dns_rdata_fromstruct(dns_rdata_t *rdata, dns_rdataclass_t rdclass, + dns_rdatatype_t type, void *source, isc_buffer_t *target); +/*%< + * Convert the C structure representation of an rdata into uncompressed wire + * format in 'target'. + * + * XXX Should we have a 'size' parameter as a sanity check on target? + * + * Requires: + * + *\li 'rdclass' and 'type' are valid. + * + *\li 'source' points to a valid C struct for the class and type. + * + *\li 'target' is a valid buffer. + * + *\li All structure pointers to memory blocks should be NULL if their + * corresponding length values are zero. + * + * Ensures, + * if result is success: + * \li If 'rdata' is not NULL, it is attached to the target. + * + * \li The used space in 'target' is updated. + * + * Result: + *\li Success + *\li Various 'Bad Form' class failures depending on class and type + *\li Resource Limit: Not enough space + */ + +isc_result_t +dns_rdata_tostruct(const dns_rdata_t *rdata, void *target, isc_mem_t *mctx); +/*%< + * Convert an rdata into its C structure representation. + * + * If 'mctx' is NULL then 'rdata' must persist while 'target' is being used. + * + * If 'mctx' is non NULL then memory will be allocated if required. + * + * Requires: + * + *\li 'rdata' is a valid, non-empty, non-pseudo rdata. + * + *\li 'target' to point to a valid pointer for the type and class. + * + * Result: + *\li Success + *\li Resource Limit: Not enough memory + */ + +void +dns_rdata_freestruct(void *source); +/*%< + * Free dynamic memory attached to 'source' (if any). + * + * Requires: + * + *\li 'source' to point to the structure previously filled in by + * dns_rdata_tostruct(). + */ + +bool +dns_rdatatype_ismeta(dns_rdatatype_t type); +/*%< + * Return true iff the rdata type 'type' is a meta-type + * like ANY or AXFR. + */ + +bool +dns_rdatatype_issingleton(dns_rdatatype_t type); +/*%< + * Return true iff the rdata type 'type' is a singleton type, + * like CNAME or SOA. + * + * Requires: + * \li 'type' is a valid rdata type. + * + */ + +bool +dns_rdataclass_ismeta(dns_rdataclass_t rdclass); +/*%< + * Return true iff the rdata class 'rdclass' is a meta-class + * like ANY or NONE. + */ + +bool +dns_rdatatype_isdnssec(dns_rdatatype_t type); +/*%< + * Return true iff 'type' is one of the DNSSEC + * rdata types that may exist alongside a CNAME record. + * + * Requires: + * \li 'type' is a valid rdata type. + */ + +bool +dns_rdatatype_iszonecutauth(dns_rdatatype_t type); +/*%< + * Return true iff rdata of type 'type' is considered authoritative + * data (not glue) in the NSEC chain when it occurs in the parent zone + * at a zone cut. + * + * Requires: + * \li 'type' is a valid rdata type. + * + */ + +bool +dns_rdatatype_isknown(dns_rdatatype_t type); +/*%< + * Return true iff the rdata type 'type' is known. + * + * Requires: + * \li 'type' is a valid rdata type. + * + */ + +isc_result_t +dns_rdata_additionaldata(dns_rdata_t *rdata, dns_additionaldatafunc_t add, + void *arg); +/*%< + * Call 'add' for each name and type from 'rdata' which is subject to + * additional section processing. + * + * Requires: + * + *\li 'rdata' is a valid, non-empty rdata. + * + *\li 'add' is a valid dns_additionalfunc_t. + * + * Ensures: + * + *\li If successful, then add() will have been called for each name + * and type subject to additional section processing. + * + *\li If add() returns something other than #ISC_R_SUCCESS, that result + * will be returned as the result of dns_rdata_additionaldata(). + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li Many other results are possible if not successful. + */ + +isc_result_t +dns_rdata_digest(dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg); +/*%< + * Send 'rdata' in DNSSEC canonical form to 'digest'. + * + * Note: + *\li 'digest' may be called more than once by dns_rdata_digest(). The + * concatenation of all the regions, in the order they were given + * to 'digest', will be the DNSSEC canonical form of 'rdata'. + * + * Requires: + * + *\li 'rdata' is a valid, non-empty rdata. + * + *\li 'digest' is a valid dns_digestfunc_t. + * + * Ensures: + * + *\li If successful, then all of the rdata's data has been sent, in + * DNSSEC canonical form, to 'digest'. + * + *\li If digest() returns something other than ISC_R_SUCCESS, that result + * will be returned as the result of dns_rdata_digest(). + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li Many other results are possible if not successful. + */ + +bool +dns_rdatatype_questiononly(dns_rdatatype_t type); +/*%< + * Return true iff rdata of type 'type' can only appear in the question + * section of a properly formatted message. + * + * Requires: + * \li 'type' is a valid rdata type. + * + */ + +bool +dns_rdatatype_notquestion(dns_rdatatype_t type); +/*%< + * Return true iff rdata of type 'type' can not appear in the question + * section of a properly formatted message. + * + * Requires: + * \li 'type' is a valid rdata type. + * + */ + +bool +dns_rdatatype_atparent(dns_rdatatype_t type); +/*%< + * Return true iff rdata of type 'type' should appear at the parent of + * a zone cut. + * + * Requires: + * \li 'type' is a valid rdata type. + * + */ + +bool +dns_rdatatype_atcname(dns_rdatatype_t type); +/*%< + * Return true iff rdata of type 'type' can appear beside a cname. + * + * Requires: + * \li 'type' is a valid rdata type. + * + */ + +bool +dns_rdatatype_followadditional(dns_rdatatype_t type); +/*%< + * Return true if adding a record of type 'type' to the ADDITIONAL section + * of a message can itself trigger the addition of still more data to the + * additional section. + * + * (For example: adding SRV to the ADDITIONAL section may trigger + * the addition of address records associated with that SRV.) + * + * Requires: + * \li 'type' is a valid rdata type. + * + */ + +unsigned int +dns_rdatatype_attributes(dns_rdatatype_t rdtype); +/*%< + * Return attributes for the given type. + * + * Requires: + *\li 'rdtype' are known. + * + * Returns: + *\li a bitmask consisting of the following flags. + */ + +/*% only one may exist for a name */ +#define DNS_RDATATYPEATTR_SINGLETON 0x00000001U +/*% requires no other data be present */ +#define DNS_RDATATYPEATTR_EXCLUSIVE 0x00000002U +/*% Is a meta type */ +#define DNS_RDATATYPEATTR_META 0x00000004U +/*% Is a DNSSEC type, like RRSIG or NSEC */ +#define DNS_RDATATYPEATTR_DNSSEC 0x00000008U +/*% Is a zone cut authority type */ +#define DNS_RDATATYPEATTR_ZONECUTAUTH 0x00000010U +/*% Is reserved (unusable) */ +#define DNS_RDATATYPEATTR_RESERVED 0x00000020U +/*% Is an unknown type */ +#define DNS_RDATATYPEATTR_UNKNOWN 0x00000040U +/*% Is META, and can only be in a question section */ +#define DNS_RDATATYPEATTR_QUESTIONONLY 0x00000080U +/*% Is META, and can NOT be in a question section */ +#define DNS_RDATATYPEATTR_NOTQUESTION 0x00000100U +/*% Is present at zone cuts in the parent, not the child */ +#define DNS_RDATATYPEATTR_ATPARENT 0x00000200U +/*% Can exist along side a CNAME */ +#define DNS_RDATATYPEATTR_ATCNAME 0x00000400U +/*% Follow additional */ +#define DNS_RDATATYPEATTR_FOLLOWADDITIONAL 0x00000800U + +dns_rdatatype_t +dns_rdata_covers(dns_rdata_t *rdata); +/*%< + * Return the rdatatype that this type covers. + * + * Requires: + *\li 'rdata' is a valid, non-empty rdata. + * + *\li 'rdata' is a type that covers other rdata types. + * + * Returns: + *\li The type covered. + */ + +bool +dns_rdata_checkowner(const dns_name_t *name, dns_rdataclass_t rdclass, + dns_rdatatype_t type, bool wildcard); +/* + * Returns whether this is a valid ownername for this <type,class>. + * If wildcard is true allow the first label to be a wildcard if + * appropriate. + * + * Requires: + * 'name' is a valid name. + */ + +bool +dns_rdata_checknames(dns_rdata_t *rdata, const dns_name_t *owner, + dns_name_t *bad); +/* + * Returns whether 'rdata' contains valid domain names. The checks are + * sensitive to the owner name. + * + * If 'bad' is non-NULL and a domain name fails the check the + * the offending name will be return in 'bad' by cloning from + * the 'rdata' contents. + * + * Requires: + * 'rdata' to be valid. + * 'owner' to be valid. + * 'bad' to be NULL or valid. + */ + +void +dns_rdata_exists(dns_rdata_t *rdata, dns_rdatatype_t type); + +void +dns_rdata_notexist(dns_rdata_t *rdata, dns_rdatatype_t type); + +void +dns_rdata_deleterrset(dns_rdata_t *rdata, dns_rdatatype_t type); + +void +dns_rdata_makedelete(dns_rdata_t *rdata); + +const char * +dns_rdata_updateop(dns_rdata_t *rdata, dns_section_t section); + +ISC_LANG_ENDDECLS + +#endif /* DNS_RDATA_H */ diff --git a/lib/dns/include/dns/rdataclass.h b/lib/dns/include/dns/rdataclass.h new file mode 100644 index 0000000..033d08d --- /dev/null +++ b/lib/dns/include/dns/rdataclass.h @@ -0,0 +1,94 @@ +/* + * 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. + */ + +#ifndef DNS_RDATACLASS_H +#define DNS_RDATACLASS_H 1 + +/*! \file dns/rdataclass.h */ + +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_rdataclass_fromtext(dns_rdataclass_t *classp, isc_textregion_t *source); +/*%< + * Convert the text 'source' refers to into a DNS class. + * + * Requires: + *\li 'classp' is a valid pointer. + * + *\li 'source' is a valid text region. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #DNS_R_UNKNOWN class is unknown + */ + +isc_result_t +dns_rdataclass_totext(dns_rdataclass_t rdclass, isc_buffer_t *target); +/*%< + * Put a textual representation of class 'rdclass' into 'target'. + * + * Requires: + *\li 'rdclass' is a valid class. + * + *\li 'target' is a valid text buffer. + * + * Ensures, + * if the result is success: + *\li The used space in 'target' is updated. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #ISC_R_NOSPACE target buffer is too small + */ + +isc_result_t +dns_rdataclass_tounknowntext(dns_rdataclass_t rdclass, isc_buffer_t *target); +/*%< + * Put textual RFC3597 CLASSXXXX representation of class 'rdclass' into + * 'target'. + * + * Requires: + *\li 'rdclass' is a valid class. + * + *\li 'target' is a valid text buffer. + * + * Ensures, + * if the result is success: + *\li The used space in 'target' is updated. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #ISC_R_NOSPACE target buffer is too small + */ + +void +dns_rdataclass_format(dns_rdataclass_t rdclass, char *array, unsigned int size); +/*%< + * Format a human-readable representation of the class 'rdclass' + * into the character array 'array', which is of size 'size'. + * The resulting string is guaranteed to be null-terminated. + */ + +#define DNS_RDATACLASS_FORMATSIZE sizeof("CLASS65535") +/*%< + * Minimum size of array to pass to dns_rdataclass_format(). + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_RDATACLASS_H */ diff --git a/lib/dns/include/dns/rdatalist.h b/lib/dns/include/dns/rdatalist.h new file mode 100644 index 0000000..3d49064 --- /dev/null +++ b/lib/dns/include/dns/rdatalist.h @@ -0,0 +1,123 @@ +/* + * 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. + */ + +#ifndef DNS_RDATALIST_H +#define DNS_RDATALIST_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/rdatalist.h + * \brief + * A DNS rdatalist is a list of rdata of a common type and class. + * + * MP: + *\li Clients of this module must impose any required synchronization. + * + * Reliability: + *\li No anticipated impact. + * + * Resources: + *\li TBS + * + * Security: + *\li No anticipated impact. + * + * Standards: + *\li None. + */ + +#include <isc/lang.h> + +#include <dns/types.h> + +/*% + * Clients may use this type directly. + */ +struct dns_rdatalist { + dns_rdataclass_t rdclass; + dns_rdatatype_t type; + dns_rdatatype_t covers; + dns_ttl_t ttl; + ISC_LIST(dns_rdata_t) rdata; + ISC_LINK(dns_rdatalist_t) link; + /*%< + * Case vector. If the bit is set then the corresponding + * character in the owner name needs to be AND'd with 0x20, + * rendering that character upper case. + */ + unsigned char upper[32]; +}; + +ISC_LANG_BEGINDECLS + +void +dns_rdatalist_init(dns_rdatalist_t *rdatalist); +/*%< + * Initialize rdatalist. + * + * Ensures: + *\li All fields of rdatalist have been initialized to their default + * values. + */ + +isc_result_t +dns_rdatalist_tordataset(dns_rdatalist_t *rdatalist, dns_rdataset_t *rdataset); +/*%< + * Make 'rdataset' refer to the rdata in 'rdatalist'. + * + * Note: + *\li The caller must ensure that 'rdatalist' remains valid and unchanged + * while 'rdataset' is associated with it. + * + * Requires: + * + *\li 'rdatalist' is a valid rdatalist. + * + *\li 'rdataset' is a valid rdataset that is not currently associated with + * any rdata. + * + * Ensures, + * on success, + * + *\li 'rdataset' is associated with the rdata in rdatalist. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +isc_result_t +dns_rdatalist_fromrdataset(dns_rdataset_t *rdataset, + dns_rdatalist_t **rdatalist); +/*%< + * Point 'rdatalist' to the rdatalist in 'rdataset'. + * + * Requires: + * + *\li 'rdatalist' is a pointer to a NULL dns_rdatalist_t pointer. + * + *\li 'rdataset' is a valid rdataset associated with an rdatalist. + * + * Ensures, + * on success, + * + *\li 'rdatalist' is pointed to the rdatalist in rdataset. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_RDATALIST_H */ diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h new file mode 100644 index 0000000..de3f638 --- /dev/null +++ b/lib/dns/include/dns/rdataset.h @@ -0,0 +1,615 @@ +/* + * 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. + */ + +#ifndef DNS_RDATASET_H +#define DNS_RDATASET_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/rdataset.h + * \brief + * A DNS rdataset is a handle that can be associated with a collection of + * rdata all having a common owner name, class, and type. + * + * The dns_rdataset_t type is like a "virtual class". To actually use + * rdatasets, an implementation of the method suite (e.g. "slabbed rdata") is + * required. + * + * XXX <more> XXX + * + * MP: + *\li Clients of this module must impose any required synchronization. + * + * Reliability: + *\li No anticipated impact. + * + * Resources: + *\li TBS + * + * Security: + *\li No anticipated impact. + * + * Standards: + *\li None. + */ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/stdtime.h> + +#include <dns/rdatastruct.h> +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +typedef enum { + dns_rdatasetadditional_fromauth, + dns_rdatasetadditional_fromcache, + dns_rdatasetadditional_fromglue +} dns_rdatasetadditional_t; + +typedef struct dns_rdatasetmethods { + void (*disassociate)(dns_rdataset_t *rdataset); + isc_result_t (*first)(dns_rdataset_t *rdataset); + isc_result_t (*next)(dns_rdataset_t *rdataset); + void (*current)(dns_rdataset_t *rdataset, dns_rdata_t *rdata); + void (*clone)(dns_rdataset_t *source, dns_rdataset_t *target); + unsigned int (*count)(dns_rdataset_t *rdataset); + isc_result_t (*addnoqname)(dns_rdataset_t *rdataset, + const dns_name_t *name); + isc_result_t (*getnoqname)(dns_rdataset_t *rdataset, dns_name_t *name, + dns_rdataset_t *neg, dns_rdataset_t *negsig); + isc_result_t (*addclosest)(dns_rdataset_t *rdataset, + const dns_name_t *name); + isc_result_t (*getclosest)(dns_rdataset_t *rdataset, dns_name_t *name, + dns_rdataset_t *neg, dns_rdataset_t *negsig); + void (*settrust)(dns_rdataset_t *rdataset, dns_trust_t trust); + void (*expire)(dns_rdataset_t *rdataset); + void (*clearprefetch)(dns_rdataset_t *rdataset); + void (*setownercase)(dns_rdataset_t *rdataset, const dns_name_t *name); + void (*getownercase)(const dns_rdataset_t *rdataset, dns_name_t *name); + isc_result_t (*addglue)(dns_rdataset_t *rdataset, + dns_dbversion_t *version, dns_message_t *msg); +} dns_rdatasetmethods_t; + +#define DNS_RDATASET_MAGIC ISC_MAGIC('D', 'N', 'S', 'R') +#define DNS_RDATASET_VALID(set) ISC_MAGIC_VALID(set, DNS_RDATASET_MAGIC) + +/*% + * Direct use of this structure by clients is strongly discouraged, except + * for the 'link' field which may be used however the client wishes. The + * 'private', 'current', and 'index' fields MUST NOT be changed by clients. + * rdataset implementations may change any of the fields. + */ +struct dns_rdataset { + unsigned int magic; + dns_rdatasetmethods_t *methods; + ISC_LINK(dns_rdataset_t) link; + + /* + * XXX do we need these, or should they be retrieved by methods? + * Leaning towards the latter, since they are not frequently required + * once you have the rdataset. + */ + dns_rdataclass_t rdclass; + dns_rdatatype_t type; + dns_ttl_t ttl; + + dns_trust_t trust; + dns_rdatatype_t covers; + + /* + * attributes + */ + unsigned int attributes; + + /*% + * the counter provides the starting point in the "cyclic" order. + * The value UINT32_MAX has a special meaning of "picking up a + * random value." in order to take care of databases that do not + * increment the counter. + */ + uint32_t count; + + /* + * This RRSIG RRset should be re-generated around this time. + * Only valid if DNS_RDATASETATTR_RESIGN is set in attributes. + */ + isc_stdtime_t resign; + + /*@{*/ + /*% + * These are for use by the rdataset implementation, and MUST NOT + * be changed by clients. + */ + void *private1; + void *private2; + void *private3; + unsigned int privateuint4; + void *private5; + const void *private6; + const void *private7; + /*@}*/ +}; + +/*! + * \def DNS_RDATASETATTR_RENDERED + * Used by message.c to indicate that the rdataset was rendered. + * + * \def DNS_RDATASETATTR_TTLADJUSTED + * Used by message.c to indicate that the rdataset's rdata had differing + * TTL values, and the rdataset->ttl holds the smallest. + * + * \def DNS_RDATASETATTR_LOADORDER + * Output the RRset in load order. + * + * \def DNS_RDATASETATTR_STALE_ADDED + * Set on rdatasets that were added during a stale-answer-client-timeout + * lookup. In other words, the RRset was added during a lookup of stale + * data and does not necessarily mean that the rdataset itself is stale. + */ + +#define DNS_RDATASETATTR_NONE 0x00000000 /*%< No ordering. */ +#define DNS_RDATASETATTR_QUESTION 0x00000001 +#define DNS_RDATASETATTR_RENDERED 0x00000002 /*%< Used by message.c */ +#define DNS_RDATASETATTR_ANSWERED 0x00000004 /*%< Used by server. */ +#define DNS_RDATASETATTR_CACHE 0x00000008 /*%< Used by resolver. */ +#define DNS_RDATASETATTR_ANSWER 0x00000010 /*%< Used by resolver. */ +#define DNS_RDATASETATTR_ANSWERSIG 0x00000020 /*%< Used by resolver. */ +#define DNS_RDATASETATTR_EXTERNAL 0x00000040 /*%< Used by resolver. */ +#define DNS_RDATASETATTR_NCACHE 0x00000080 /*%< Used by resolver. */ +#define DNS_RDATASETATTR_CHAINING 0x00000100 /*%< Used by resolver. */ +#define DNS_RDATASETATTR_TTLADJUSTED 0x00000200 /*%< Used by message.c */ +#define DNS_RDATASETATTR_FIXEDORDER 0x00000400 /*%< Fixed ordering. */ +#define DNS_RDATASETATTR_RANDOMIZE 0x00000800 /*%< Random ordering. */ +#define DNS_RDATASETATTR_CHASE 0x00001000 /*%< Used by resolver. */ +#define DNS_RDATASETATTR_NXDOMAIN 0x00002000 +#define DNS_RDATASETATTR_NOQNAME 0x00004000 +#define DNS_RDATASETATTR_CHECKNAMES 0x00008000 /*%< Used by resolver. */ +#define DNS_RDATASETATTR_REQUIRED 0x00010000 +#define DNS_RDATASETATTR_REQUIREDGLUE DNS_RDATASETATTR_REQUIRED +#define DNS_RDATASETATTR_LOADORDER 0x00020000 +#define DNS_RDATASETATTR_RESIGN 0x00040000 +#define DNS_RDATASETATTR_CLOSEST 0x00080000 +#define DNS_RDATASETATTR_OPTOUT 0x00100000 /*%< OPTOUT proof */ +#define DNS_RDATASETATTR_NEGATIVE 0x00200000 +#define DNS_RDATASETATTR_PREFETCH 0x00400000 +#define DNS_RDATASETATTR_CYCLIC 0x00800000 /*%< Cyclic ordering. */ +#define DNS_RDATASETATTR_STALE 0x01000000 +#define DNS_RDATASETATTR_ANCIENT 0x02000000 +#define DNS_RDATASETATTR_STALE_WINDOW 0x04000000 +#define DNS_RDATASETATTR_STALE_ADDED 0x08000000 + +/*% + * _OMITDNSSEC: + * Omit DNSSEC records when rendering ncache records. + */ +#define DNS_RDATASETTOWIRE_OMITDNSSEC 0x0001 + +void +dns_rdataset_init(dns_rdataset_t *rdataset); +/*%< + * Make 'rdataset' a valid, disassociated rdataset. + * + * Requires: + *\li 'rdataset' is not NULL. + * + * Ensures: + *\li 'rdataset' is a valid, disassociated rdataset. + */ + +void +dns_rdataset_invalidate(dns_rdataset_t *rdataset); +/*%< + * Invalidate 'rdataset'. + * + * Requires: + *\li 'rdataset' is a valid, disassociated rdataset. + * + * Ensures: + *\li If assertion checking is enabled, future attempts to use 'rdataset' + * without initializing it will cause an assertion failure. + */ + +void +dns_rdataset_disassociate(dns_rdataset_t *rdataset); +/*%< + * Disassociate 'rdataset' from its rdata, allowing it to be reused. + * + * Notes: + *\li The client must ensure it has no references to rdata in the rdataset + * before disassociating. + * + * Requires: + *\li 'rdataset' is a valid, associated rdataset. + * + * Ensures: + *\li 'rdataset' is a valid, disassociated rdataset. + */ + +bool +dns_rdataset_isassociated(dns_rdataset_t *rdataset); +/*%< + * Is 'rdataset' associated? + * + * Requires: + *\li 'rdataset' is a valid rdataset. + * + * Returns: + *\li #true 'rdataset' is associated. + *\li #false 'rdataset' is not associated. + */ + +void +dns_rdataset_makequestion(dns_rdataset_t *rdataset, dns_rdataclass_t rdclass, + dns_rdatatype_t type); +/*%< + * Make 'rdataset' a valid, associated, question rdataset, with a + * question class of 'rdclass' and type 'type'. + * + * Notes: + *\li Question rdatasets have a class and type, but no rdata. + * + * Requires: + *\li 'rdataset' is a valid, disassociated rdataset. + * + * Ensures: + *\li 'rdataset' is a valid, associated, question rdataset. + */ + +void +dns_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target); +/*%< + * Make 'target' refer to the same rdataset as 'source'. + * + * Requires: + *\li 'source' is a valid, associated rdataset. + * + *\li 'target' is a valid, dissociated rdataset. + * + * Ensures: + *\li 'target' references the same rdataset as 'source'. + */ + +unsigned int +dns_rdataset_count(dns_rdataset_t *rdataset); +/*%< + * Return the number of records in 'rdataset'. + * + * Requires: + *\li 'rdataset' is a valid, associated rdataset. + * + * Returns: + *\li The number of records in 'rdataset'. + */ + +isc_result_t +dns_rdataset_first(dns_rdataset_t *rdataset); +/*%< + * Move the rdata cursor to the first rdata in the rdataset (if any). + * + * Requires: + *\li 'rdataset' is a valid, associated rdataset. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMORE There are no rdata in the set. + */ + +isc_result_t +dns_rdataset_next(dns_rdataset_t *rdataset); +/*%< + * Move the rdata cursor to the next rdata in the rdataset (if any). + * + * Requires: + *\li 'rdataset' is a valid, associated rdataset. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMORE There are no more rdata in the set. + */ + +void +dns_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata); +/*%< + * Make 'rdata' refer to the current rdata. + * + * Notes: + * + *\li The data returned in 'rdata' is valid for the life of the + * rdataset; in particular, subsequent changes in the cursor position + * do not invalidate 'rdata'. + * + * Requires: + *\li 'rdataset' is a valid, associated rdataset. + * + *\li The rdata cursor of 'rdataset' is at a valid location (i.e. the + * result of last call to a cursor movement command was ISC_R_SUCCESS). + * + * Ensures: + *\li 'rdata' refers to the rdata at the rdata cursor location of + *\li 'rdataset'. + */ + +isc_result_t +dns_rdataset_totext(dns_rdataset_t *rdataset, const dns_name_t *owner_name, + bool omit_final_dot, bool question, isc_buffer_t *target); +/*%< + * Convert 'rdataset' to text format, storing the result in 'target'. + * + * Notes: + *\li The rdata cursor position will be changed. + * + *\li The 'question' flag should normally be #false. If it is + * #true, the TTL and rdata fields are not printed. This is + * for use when printing an rdata representing a question section. + * + *\li This interface is deprecated; use dns_master_rdatasettottext() + * and/or dns_master_questiontotext() instead. + * + * Requires: + *\li 'rdataset' is a valid rdataset. + * + *\li 'rdataset' is not empty. + */ + +isc_result_t +dns_rdataset_towire(dns_rdataset_t *rdataset, const dns_name_t *owner_name, + dns_compress_t *cctx, isc_buffer_t *target, + unsigned int options, unsigned int *countp); +/*%< + * Convert 'rdataset' to wire format, compressing names as specified + * in 'cctx', and storing the result in 'target'. + * + * Notes: + *\li The rdata cursor position will be changed. + * + *\li The number of RRs added to target will be added to *countp. + * + * Requires: + *\li 'rdataset' is a valid rdataset. + * + *\li 'rdataset' is not empty. + * + *\li 'countp' is a valid pointer. + * + * Ensures: + *\li On a return of ISC_R_SUCCESS, 'target' contains a wire format + * for the data contained in 'rdataset'. Any error return leaves + * the buffer unchanged. + * + *\li *countp has been incremented by the number of RRs added to + * target. + * + * Returns: + *\li #ISC_R_SUCCESS - all ok + *\li #ISC_R_NOSPACE - 'target' doesn't have enough room + * + *\li Any error returned by dns_rdata_towire(), dns_rdataset_next(), + * dns_name_towire(). + */ + +isc_result_t +dns_rdataset_towiresorted(dns_rdataset_t *rdataset, + const dns_name_t *owner_name, dns_compress_t *cctx, + isc_buffer_t *target, dns_rdatasetorderfunc_t order, + const void *order_arg, unsigned int options, + unsigned int *countp); +/*%< + * Like dns_rdataset_towire(), but sorting the rdatasets according to + * the integer value returned by 'order' when called with the rdataset + * and 'order_arg' as arguments. + * + * Requires: + *\li All the requirements of dns_rdataset_towire(), and + * that order_arg is NULL if and only if order is NULL. + */ + +isc_result_t +dns_rdataset_towirepartial(dns_rdataset_t *rdataset, + const dns_name_t *owner_name, dns_compress_t *cctx, + isc_buffer_t *target, dns_rdatasetorderfunc_t order, + const void *order_arg, unsigned int options, + unsigned int *countp, void **state); +/*%< + * Like dns_rdataset_towiresorted() except that a partial rdataset + * may be written. + * + * Requires: + *\li All the requirements of dns_rdataset_towiresorted(). + * If 'state' is non NULL then the current position in the + * rdataset will be remembered if the rdataset in not + * completely written and should be passed on on subsequent + * calls (NOT CURRENTLY IMPLEMENTED). + * + * Returns: + *\li #ISC_R_SUCCESS if all of the records were written. + *\li #ISC_R_NOSPACE if unable to fit in all of the records. *countp + * will be updated to reflect the number of records + * written. + */ + +isc_result_t +dns_rdataset_additionaldata(dns_rdataset_t *rdataset, + dns_additionaldatafunc_t add, void *arg); +/*%< + * For each rdata in rdataset, call 'add' for each name and type in the + * rdata which is subject to additional section processing. + * + * Requires: + * + *\li 'rdataset' is a valid, non-question rdataset. + * + *\li 'add' is a valid dns_additionaldatafunc_t + * + * Ensures: + * + *\li If successful, dns_rdata_additionaldata() will have been called for + * each rdata in 'rdataset'. + * + *\li If a call to dns_rdata_additionaldata() is not successful, the + * result returned will be the result of dns_rdataset_additionaldata(). + * + * Returns: + * + *\li #ISC_R_SUCCESS + * + *\li Any error that dns_rdata_additionaldata() can return. + */ + +isc_result_t +dns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, + dns_rdataset_t *neg, dns_rdataset_t *negsig); +/*%< + * Return the noqname proof for this record. + * + * Requires: + *\li 'rdataset' to be valid and #DNS_RDATASETATTR_NOQNAME to be set. + *\li 'name' to be valid. + *\li 'neg' and 'negsig' to be valid and not associated. + */ + +isc_result_t +dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name); +/*%< + * Associate a noqname proof with this record. + * Sets #DNS_RDATASETATTR_NOQNAME if successful. + * Adjusts the 'rdataset->ttl' to minimum of the 'rdataset->ttl' and + * the 'nsec'/'nsec3' and 'rrsig(nsec)'/'rrsig(nsec3)' ttl. + * + * Requires: + *\li 'rdataset' to be valid and #DNS_RDATASETATTR_NOQNAME to be set. + *\li 'name' to be valid and have NSEC or NSEC3 and associated RRSIG + * rdatasets. + */ + +isc_result_t +dns_rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, + dns_rdataset_t *nsec, dns_rdataset_t *nsecsig); +/*%< + * Return the closest encloser for this record. + * + * Requires: + *\li 'rdataset' to be valid and #DNS_RDATASETATTR_CLOSEST to be set. + *\li 'name' to be valid. + *\li 'nsec' and 'nsecsig' to be valid and not associated. + */ + +isc_result_t +dns_rdataset_addclosest(dns_rdataset_t *rdataset, const dns_name_t *name); +/*%< + * Associate a closest encloset proof with this record. + * Sets #DNS_RDATASETATTR_CLOSEST if successful. + * Adjusts the 'rdataset->ttl' to minimum of the 'rdataset->ttl' and + * the 'nsec' and 'rrsig(nsec)' ttl. + * + * Requires: + *\li 'rdataset' to be valid and #DNS_RDATASETATTR_CLOSEST to be set. + *\li 'name' to be valid and have NSEC3 and RRSIG(NSEC3) rdatasets. + */ + +void +dns_rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust); +/*%< + * Set the trust of the 'rdataset' to trust in any in the backing database. + * The local trust level of 'rdataset' is also set. + */ + +void +dns_rdataset_expire(dns_rdataset_t *rdataset); +/*%< + * Mark the rdataset to be expired in the backing database. + */ + +void +dns_rdataset_clearprefetch(dns_rdataset_t *rdataset); +/*%< + * Clear the PREFETCH attribute for the given rdataset in the + * underlying database. + * + * In the cache database, this signals that the rdataset is not + * eligible to be prefetched when the TTL is close to expiring. + * It has no function in other databases. + */ + +void +dns_rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name); +/*%< + * Store the casing of 'name', the owner name of 'rdataset', into + * a bitfield so that the name can be capitalized the same when when + * the rdataset is used later. This sets the CASESET attribute. + */ + +void +dns_rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name); +/*%< + * If the CASESET attribute is set, retrieve the case bitfield that was + * previously stored by dns_rdataset_getownername(), and capitalize 'name' + * according to it. If CASESET is not set, do nothing. + */ + +isc_result_t +dns_rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version, + dns_message_t *msg); +/*%< + * Add glue records for rdataset to the additional section of message in + * 'msg'. 'rdataset' must be of type NS. + * + * In case a successful result is not returned, the caller should try to + * add glue directly to the message by iterating for additional data. + * + * Requires: + * \li 'rdataset' is a valid NS rdataset. + * \li 'version' is the DB version. + * \li 'msg' is the DNS message to which the glue should be added. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOTIMPLEMENTED + *\li #ISC_R_FAILURE + *\li Any error that dns_rdata_additionaldata() can return. + */ + +void +dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, + dns_rdata_rrsig_t *rrsig, isc_stdtime_t now, + bool acceptexpired); +/*%< + * Trim the ttl of 'rdataset' and 'sigrdataset' so that they will expire + * at or before 'rrsig->expiretime'. If 'acceptexpired' is true and the + * signature has expired or will expire in the next 120 seconds, limit + * the ttl to be no more than 120 seconds. + * + * The ttl is further limited by the original ttl as stored in 'rrsig' + * and the original ttl values of 'rdataset' and 'sigrdataset'. + * + * Requires: + * \li 'rdataset' is a valid rdataset. + * \li 'sigrdataset' is a valid rdataset. + * \li 'rrsig' is non NULL. + */ + +const char * +dns_trust_totext(dns_trust_t trust); +/*%< + * Display trust in textual form. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_RDATASET_H */ diff --git a/lib/dns/include/dns/rdatasetiter.h b/lib/dns/include/dns/rdatasetiter.h new file mode 100644 index 0000000..2df4aad --- /dev/null +++ b/lib/dns/include/dns/rdatasetiter.h @@ -0,0 +1,164 @@ +/* + * 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. + */ + +#ifndef DNS_RDATASETITER_H +#define DNS_RDATASETITER_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/rdatasetiter.h + * \brief + * The DNS Rdataset Iterator interface allows iteration of all of the + * rdatasets at a node. + * + * The dns_rdatasetiter_t type is like a "virtual class". To actually use + * it, an implementation of the class is required. This implementation is + * supplied by the database. + * + * It is the client's responsibility to call dns_rdataset_disassociate() + * on all rdatasets returned. + * + * XXX more XXX + * + * MP: + *\li The iterator itself is not locked. The caller must ensure + * synchronization. + * + *\li The iterator methods ensure appropriate database locking. + * + * Reliability: + *\li No anticipated impact. + * + * Resources: + *\li TBS + * + * Security: + *\li No anticipated impact. + * + * Standards: + *\li None. + */ + +/***** +***** Imports +*****/ + +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/stdtime.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/***** +***** Types +*****/ + +typedef struct dns_rdatasetitermethods { + void (*destroy)(dns_rdatasetiter_t **iteratorp); + isc_result_t (*first)(dns_rdatasetiter_t *iterator); + isc_result_t (*next)(dns_rdatasetiter_t *iterator); + void (*current)(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset); +} dns_rdatasetitermethods_t; + +#define DNS_RDATASETITER_MAGIC ISC_MAGIC('D', 'N', 'S', 'i') +#define DNS_RDATASETITER_VALID(i) ISC_MAGIC_VALID(i, DNS_RDATASETITER_MAGIC) + +/*% + * This structure is actually just the common prefix of a DNS db + * implementation's version of a dns_rdatasetiter_t. + * \brief + * Direct use of this structure by clients is forbidden. DB implementations + * may change the structure. 'magic' must be #DNS_RDATASETITER_MAGIC for + * any of the dns_rdatasetiter routines to work. DB implementations must + * maintain all DB rdataset iterator invariants. + */ +struct dns_rdatasetiter { + /* Unlocked. */ + unsigned int magic; + dns_rdatasetitermethods_t *methods; + dns_db_t *db; + dns_dbnode_t *node; + dns_dbversion_t *version; + isc_stdtime_t now; + unsigned int options; +}; + +void +dns_rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp); +/*%< + * Destroy '*iteratorp'. + * + * Requires: + * + *\li '*iteratorp' is a valid iterator. + * + * Ensures: + * + *\li All resources used by the iterator are freed. + * + *\li *iteratorp == NULL. + */ + +isc_result_t +dns_rdatasetiter_first(dns_rdatasetiter_t *iterator); +/*%< + * Move the rdataset cursor to the first rdataset at the node (if any). + * + * Requires: + *\li 'iterator' is a valid iterator. + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOMORE There are no rdatasets at the node. + * + *\li Other results are possible, depending on the DB implementation. + */ + +isc_result_t +dns_rdatasetiter_next(dns_rdatasetiter_t *iterator); +/*%< + * Move the rdataset cursor to the next rdataset at the node (if any). + * + * Requires: + *\li 'iterator' is a valid iterator. + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOMORE There are no more rdatasets at the + * node. + * + *\li Other results are possible, depending on the DB implementation. + */ + +void +dns_rdatasetiter_current(dns_rdatasetiter_t *iterator, + dns_rdataset_t *rdataset); +/*%< + * Return the current rdataset. + * + * Requires: + *\li 'iterator' is a valid iterator. + * + *\li 'rdataset' is a valid, disassociated rdataset. + * + *\li The rdataset cursor of 'iterator' is at a valid location (i.e. the + * result of last call to a cursor movement command was #ISC_R_SUCCESS). + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_RDATASETITER_H */ diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h new file mode 100644 index 0000000..5a1c30f --- /dev/null +++ b/lib/dns/include/dns/rdataslab.h @@ -0,0 +1,173 @@ +/* + * 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. + */ + +#ifndef DNS_RDATASLAB_H +#define DNS_RDATASLAB_H 1 + +/*! \file dns/rdataslab.h + * \brief + * Implements storage of rdatasets into slabs of memory. + * + * MP: + *\li Clients of this module must impose any required synchronization. + * + * Reliability: + *\li This module deals with low-level byte streams. Errors in any of + * the functions are likely to crash the server or corrupt memory. + * + *\li If the caller passes invalid memory references, these functions are + * likely to crash the server or corrupt memory. + * + * Resources: + *\li None. + * + * Security: + *\li None. + * + * Standards: + *\li None. + */ + +/*** + *** Imports + ***/ + +#include <stdbool.h> + +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +#define DNS_RDATASLAB_FORCE 0x1 +#define DNS_RDATASLAB_EXACT 0x2 + +#define DNS_RDATASLAB_OFFLINE 0x01 /* RRSIG is for offline DNSKEY */ +#define DNS_RDATASLAB_WARNMASK \ + 0x0E /*%< RRSIG(DNSKEY) expired \ + * warnings number mask. */ +#define DNS_RDATASLAB_WARNSHIFT \ + 1 /*%< How many bits to shift to find \ + * remaining expired warning number. */ + +/*** + *** Functions + ***/ + +isc_result_t +dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, + isc_region_t *region, unsigned int reservelen); +/*%< + * Slabify a rdataset. The slab area will be allocated and returned + * in 'region'. + * + * Requires: + *\li 'rdataset' is valid. + * + * Ensures: + *\li 'region' will have base pointing to the start of allocated memory, + * with the slabified region beginning at region->base + reservelen. + * region->length contains the total length allocated. + * + * Returns: + *\li ISC_R_SUCCESS - successful completion + *\li ISC_R_NOMEMORY - no memory. + *\li XXX others + */ + +unsigned int +dns_rdataslab_size(unsigned char *slab, unsigned int reservelen); +/*%< + * Return the total size of an rdataslab. + * + * Requires: + *\li 'slab' points to a slab. + * + * Returns: + *\li The number of bytes in the slab, including the reservelen. + */ + +unsigned int +dns_rdataslab_rdatasize(unsigned char *slab, unsigned int reservelen); +/*%< + * Return the size of the rdata in an rdataslab. + * + * Requires: + *\li 'slab' points to a slab. + */ + +unsigned int +dns_rdataslab_count(unsigned char *slab, unsigned int reservelen); +/*%< + * Return the number of records in the rdataslab + * + * Requires: + *\li 'slab' points to a slab. + * + * Returns: + *\li The number of records in the slab. + */ + +isc_result_t +dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab, + unsigned int reservelen, isc_mem_t *mctx, + dns_rdataclass_t rdclass, dns_rdatatype_t type, + unsigned int flags, unsigned char **tslabp); +/*%< + * Merge 'oslab' and 'nslab'. + */ + +isc_result_t +dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab, + unsigned int reservelen, isc_mem_t *mctx, + dns_rdataclass_t rdclass, dns_rdatatype_t type, + unsigned int flags, unsigned char **tslabp); +/*%< + * Subtract 'sslab' from 'mslab'. If 'exact' is true then all elements + * of 'sslab' must exist in 'mslab'. + * + * XXX + * valid flags are DNS_RDATASLAB_EXACT + */ + +bool +dns_rdataslab_equal(unsigned char *slab1, unsigned char *slab2, + unsigned int reservelen); +/*%< + * Compare two rdataslabs for equality. This does _not_ do a full + * DNSSEC comparison. + * + * Requires: + *\li 'slab1' and 'slab2' point to slabs. + * + * Returns: + *\li true if the slabs are equal, false otherwise. + */ +bool +dns_rdataslab_equalx(unsigned char *slab1, unsigned char *slab2, + unsigned int reservelen, dns_rdataclass_t rdclass, + dns_rdatatype_t type); +/*%< + * Compare two rdataslabs for DNSSEC equality. + * + * Requires: + *\li 'slab1' and 'slab2' point to slabs. + * + * Returns: + *\li true if the slabs are equal, #false otherwise. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_RDATASLAB_H */ diff --git a/lib/dns/include/dns/rdatatype.h b/lib/dns/include/dns/rdatatype.h new file mode 100644 index 0000000..008f4da --- /dev/null +++ b/lib/dns/include/dns/rdatatype.h @@ -0,0 +1,97 @@ +/* + * 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. + */ + +#ifndef DNS_RDATATYPE_H +#define DNS_RDATATYPE_H 1 + +/*! \file dns/rdatatype.h */ + +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_rdatatype_fromtext(dns_rdatatype_t *typep, isc_textregion_t *source); +/*%< + * Convert the text 'source' refers to into a DNS rdata type. + * + * Requires: + *\li 'typep' is a valid pointer. + * + *\li 'source' is a valid text region. + * + * Returns: + *\li ISC_R_SUCCESS on success + *\li DNS_R_UNKNOWN type is unknown + */ + +isc_result_t +dns_rdatatype_totext(dns_rdatatype_t type, isc_buffer_t *target); +/*%< + * Put a textual representation of type 'type' into 'target'. + * + * Requires: + *\li 'type' is a valid type. + * + *\li 'target' is a valid text buffer. + * + * Ensures, + * if the result is success: + *\li The used space in 'target' is updated. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #ISC_R_NOSPACE target buffer is too small + */ + +isc_result_t +dns_rdatatype_tounknowntext(dns_rdatatype_t type, isc_buffer_t *target); +/*%< + * Put textual RFC3597 TYPEXXXX representation of type 'type' into + * 'target'. + * + * Requires: + *\li 'type' is a valid type. + * + *\li 'target' is a valid text buffer. + * + * Ensures, + * if the result is success: + *\li The used space in 'target' is updated. + * + * Returns: + *\li #ISC_R_SUCCESS on success + *\li #ISC_R_NOSPACE target buffer is too small + */ + +void +dns_rdatatype_format(dns_rdatatype_t rdtype, char *array, unsigned int size); +/*%< + * Format a human-readable representation of the type 'rdtype' + * into the character array 'array', which is of size 'size'. + * The resulting string is guaranteed to be null-terminated. + */ + +#define DNS_RDATATYPE_FORMATSIZE sizeof("NSEC3PARAM") + +/*%< + * Minimum size of array to pass to dns_rdatatype_format(). + * May need to be adjusted if a new RR type with a very long + * name is defined. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_RDATATYPE_H */ diff --git a/lib/dns/include/dns/request.h b/lib/dns/include/dns/request.h new file mode 100644 index 0000000..f745f02 --- /dev/null +++ b/lib/dns/include/dns/request.h @@ -0,0 +1,365 @@ +/* + * 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. + */ + +#ifndef DNS_REQUEST_H +#define DNS_REQUEST_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/request.h + * + * \brief + * The request module provides simple request/response services useful for + * sending SOA queries, DNS Notify messages, and dynamic update requests. + * + * MP: + *\li The module ensures appropriate synchronization of data structures it + * creates and manipulates. + * + * Resources: + *\li TBS + * + * Security: + *\li No anticipated impact. + */ + +#include <stdbool.h> + +#include <isc/event.h> +#include <isc/lang.h> + +#include <dns/types.h> + +#define DNS_REQUESTOPT_TCP 0x00000001U +#define DNS_REQUESTOPT_CASE 0x00000002U +#define DNS_REQUESTOPT_FIXEDID 0x00000004U +#define DNS_REQUESTOPT_SHARE 0x00000008U + +typedef struct dns_requestevent { + ISC_EVENT_COMMON(struct dns_requestevent); + isc_result_t result; + dns_request_t *request; +} dns_requestevent_t; + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, + isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, + dns_dispatchmgr_t *dispatchmgr, + dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, + dns_requestmgr_t **requestmgrp); +/*%< + * Create a request manager. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li 'timermgr' is a valid timer manager. + * + *\li 'socketmgr' is a valid socket manager. + * + *\li 'taskmgr' is a valid task manager. + * + *\li 'dispatchv4' is a valid dispatcher with an IPv4 UDP socket, or is NULL. + * + *\li 'dispatchv6' is a valid dispatcher with an IPv6 UDP socket, or is NULL. + * + *\li requestmgrp != NULL && *requestmgrp == NULL + * + * Ensures: + * + *\li On success, *requestmgrp is a valid request manager. + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li Any other result indicates failure. + */ + +void +dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task, + isc_event_t **eventp); +/*%< + * Send '*eventp' to 'task' when 'requestmgr' has completed shutdown. + * + * Notes: + * + *\li It is not safe to detach the last reference to 'requestmgr' until + * shutdown is complete. + * + * Requires: + * + *\li 'requestmgr' is a valid request manager. + * + *\li 'task' is a valid task. + * + *\li *eventp is a valid event. + * + * Ensures: + * + *\li *eventp == NULL. + */ + +void +dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr); +/*%< + * Start the shutdown process for 'requestmgr'. + * + * Notes: + * + *\li This call has no effect if the request manager is already shutting + * down. + * + * Requires: + * + *\li 'requestmgr' is a valid requestmgr. + */ + +void +dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp); +/*%< + * Attach to the request manager. dns_requestmgr_shutdown() must not + * have been called on 'source' prior to calling dns_requestmgr_attach(). + * + * Requires: + * + *\li 'source' is a valid requestmgr. + * + *\li 'targetp' to be non NULL and '*targetp' to be NULL. + */ + +void +dns_requestmgr_detach(dns_requestmgr_t **requestmgrp); +/*%< + * Detach from the given requestmgr. If this is the final detach + * requestmgr will be destroyed. dns_requestmgr_shutdown() must + * be called before the final detach. + * + * Requires: + * + *\li '*requestmgrp' is a valid requestmgr. + * + * Ensures: + *\li '*requestmgrp' is NULL. + */ + +isc_result_t +dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message, + const isc_sockaddr_t *address, unsigned int options, + dns_tsigkey_t *key, unsigned int timeout, isc_task_t *task, + isc_taskaction_t action, void *arg, + dns_request_t **requestp); +/*%< + * Create and send a request. + * + * Notes: + * + *\li 'message' will be rendered and sent to 'address'. If the + * #DNS_REQUESTOPT_TCP option is set, TCP will be used, + * #DNS_REQUESTOPT_SHARE option is set too, connecting TCP + * (vs. connected) will be shared too. The request + * will timeout after 'timeout' seconds. + * + *\li If the #DNS_REQUESTOPT_CASE option is set, use case sensitive + * compression. + * + *\li When the request completes, successfully, due to a timeout, or + * because it was canceled, a completion event will be sent to 'task'. + * + * Requires: + * + *\li 'message' is a valid DNS message. + * + *\li 'address' is a valid sockaddr. + * + *\li 'timeout' > 0 + * + *\li 'task' is a valid task. + * + *\li requestp != NULL && *requestp == NULL + */ + +isc_result_t +dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, + const isc_sockaddr_t *srcaddr, + const isc_sockaddr_t *destaddr, isc_dscp_t dscp, + unsigned int options, dns_tsigkey_t *key, + unsigned int timeout, unsigned int udptimeout, + unsigned int udpretries, isc_task_t *task, + isc_taskaction_t action, void *arg, + dns_request_t **requestp); +/*%< + * Create and send a request. + * + * Notes: + * + *\li 'message' will be rendered and sent to 'address'. If the + * #DNS_REQUESTOPT_TCP option is set, TCP will be used, + * #DNS_REQUESTOPT_SHARE option is set too, connecting TCP + * (vs. connected) will be shared too. The request + * will timeout after 'timeout' seconds. UDP requests will be resent + * at 'udptimeout' intervals if non-zero or 'udpretries' is non-zero. + * + *\li If the #DNS_REQUESTOPT_CASE option is set, use case sensitive + * compression. + * + *\li When the request completes, successfully, due to a timeout, or + * because it was canceled, a completion event will be sent to 'task'. + * + * Requires: + * + *\li 'message' is a valid DNS message. + * + *\li 'dstaddr' is a valid sockaddr. + * + *\li 'srcaddr' is a valid sockaddr or NULL. + * + *\li 'srcaddr' and 'dstaddr' are the same protocol family. + * + *\li 'timeout' > 0 + * + *\li 'task' is a valid task. + * + *\li requestp != NULL && *requestp == NULL + */ + +isc_result_t +dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, + const isc_sockaddr_t *srcaddr, + const isc_sockaddr_t *destaddr, isc_dscp_t dscp, + unsigned int options, unsigned int timeout, + unsigned int udptimeout, unsigned int udpretries, + isc_task_t *task, isc_taskaction_t action, void *arg, + dns_request_t **requestp); +/*!< + * \brief Create and send a request. + * + * Notes: + * + *\li 'msgbuf' will be sent to 'destaddr' after setting the id. If the + * #DNS_REQUESTOPT_TCP option is set, TCP will be used, + * #DNS_REQUESTOPT_SHARE option is set too, connecting TCP + * (vs. connected) will be shared too. The request + * will timeout after 'timeout' seconds. UDP requests will be resent + * at 'udptimeout' intervals if non-zero or if 'udpretries' is not zero. + * + *\li When the request completes, successfully, due to a timeout, or + * because it was canceled, a completion event will be sent to 'task'. + * + * Requires: + * + *\li 'msgbuf' is a valid DNS message in compressed wire format. + * + *\li 'destaddr' is a valid sockaddr. + * + *\li 'srcaddr' is a valid sockaddr or NULL. + * + *\li 'srcaddr' and 'dstaddr' are the same protocol family. + * + *\li 'timeout' > 0 + * + *\li 'task' is a valid task. + * + *\li requestp != NULL && *requestp == NULL + */ + +void +dns_request_cancel(dns_request_t *request); +/*%< + * Cancel 'request'. + * + * Requires: + * + *\li 'request' is a valid request. + * + * Ensures: + * + *\li If the completion event for 'request' has not yet been sent, it + * will be sent, and the result code will be ISC_R_CANCELED. + */ + +isc_result_t +dns_request_getresponse(dns_request_t *request, dns_message_t *message, + unsigned int options); +/*%< + * Get the response to 'request' by filling in 'message'. + * + * 'options' is passed to dns_message_parse(). See dns_message_parse() + * for more details. + * + * Requires: + * + *\li 'request' is a valid request for which the caller has received the + * completion event. + * + *\li The result code of the completion event was #ISC_R_SUCCESS. + * + * Returns: + * + *\li ISC_R_SUCCESS + * + *\li Any result that dns_message_parse() can return. + */ +isc_buffer_t * +dns_request_getanswer(dns_request_t *request); +/* + * Get the response to 'request' as a buffer. + * + * Requires: + * + *\li 'request' is a valid request for which the caller has received the + * completion event. + * + * Returns: + * + *\li a pointer to the answer buffer. + */ + +bool +dns_request_usedtcp(dns_request_t *request); +/*%< + * Return whether this query used TCP or not. Setting #DNS_REQUESTOPT_TCP + * in the call to dns_request_create() will cause the function to return + * #true, otherwise the result is based on the query message size. + * + * Requires: + *\li 'request' is a valid request. + * + * Returns: + *\li true if TCP was used. + *\li false if UDP was used. + */ + +void +dns_request_destroy(dns_request_t **requestp); +/*%< + * Destroy 'request'. + * + * Requires: + * + *\li 'request' is a valid request for which the caller has received the + * completion event. + * + * Ensures: + * + *\li *requestp == NULL + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_REQUEST_H */ diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h new file mode 100644 index 0000000..22ad9df --- /dev/null +++ b/lib/dns/include/dns/resolver.h @@ -0,0 +1,747 @@ +/* + * 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. + */ + +#ifndef DNS_RESOLVER_H +#define DNS_RESOLVER_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/resolver.h + * + * \brief + * This is the BIND 9 resolver, the module responsible for resolving DNS + * requests by iteratively querying authoritative servers and following + * referrals. This is a "full resolver", not to be confused with + * the stub resolvers most people associate with the word "resolver". + * The full resolver is part of the caching name server or resolver + * daemon the stub resolver talks to. + * + * MP: + *\li The module ensures appropriate synchronization of data structures it + * creates and manipulates. + * + * Reliability: + *\li No anticipated impact. + * + * Resources: + *\li TBS + * + * Security: + *\li No anticipated impact. + * + * Standards: + *\li RFCs: 1034, 1035, 2181, TBS + *\li Drafts: TBS + */ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/socket.h> +#include <isc/stats.h> + +#include <dns/fixedname.h> +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/*% + * A dns_fetchevent_t is sent when a 'fetch' completes. Any of 'db', + * 'node', 'rdataset', and 'sigrdataset' may be bound. It is the + * receiver's responsibility to detach before freeing the event. + * \brief + * 'rdataset', 'sigrdataset', 'client' and 'id' are the values that were + * supplied when dns_resolver_createfetch() was called. They are returned + * to the caller so that they may be freed. + */ +typedef struct dns_fetchevent { + ISC_EVENT_COMMON(struct dns_fetchevent); + dns_fetch_t *fetch; + isc_result_t result; + dns_rdatatype_t qtype; + dns_db_t *db; + dns_dbnode_t *node; + dns_rdataset_t *rdataset; + dns_rdataset_t *sigrdataset; + dns_fixedname_t foundname; + const isc_sockaddr_t *client; + dns_messageid_t id; + isc_result_t vresult; +} dns_fetchevent_t; + +/*% + * The two quota types (fetches-per-zone and fetches-per-server) + */ +typedef enum { dns_quotatype_zone = 0, dns_quotatype_server } dns_quotatype_t; + +/* + * Options that modify how a 'fetch' is done. + */ +#define DNS_FETCHOPT_TCP 0x00000001 /*%< Use TCP. */ +#define DNS_FETCHOPT_UNSHARED 0x00000002 /*%< See below. */ +#define DNS_FETCHOPT_RECURSIVE 0x00000004 /*%< Set RD? */ +#define DNS_FETCHOPT_NOEDNS0 0x00000008 /*%< Do not use EDNS. */ +#define DNS_FETCHOPT_FORWARDONLY 0x00000010 /*%< Only use forwarders. */ +#define DNS_FETCHOPT_NOVALIDATE 0x00000020 /*%< Disable validation. */ +#define DNS_FETCHOPT_EDNS512 \ + 0x00000040 /*%< Advertise a 512 byte \ + * UDP buffer. */ +#define DNS_FETCHOPT_WANTNSID 0x00000080 /*%< Request NSID */ +#define DNS_FETCHOPT_PREFETCH 0x00000100 /*%< Do prefetch */ +#define DNS_FETCHOPT_NOCDFLAG 0x00000200 /*%< Don't set CD flag. */ +#define DNS_FETCHOPT_NONTA 0x00000400 /*%< Ignore NTA table. */ +/* RESERVED ECS 0x00000000 */ +/* RESERVED ECS 0x00001000 */ +/* RESERVED ECS 0x00002000 */ +/* RESERVED TCPCLIENT 0x00004000 */ +#define DNS_FETCHOPT_NOCACHED 0x00008000 /*%< Force cache update. */ +#define DNS_FETCHOPT_QMINIMIZE \ + 0x00010000 /*%< Use qname \ + * minimization. */ +#define DNS_FETCHOPT_NOFOLLOW \ + 0x00020000 /*%< Don't follow \ + * delegations */ +#define DNS_FETCHOPT_QMIN_STRICT \ + 0x00040000 /*%< Do not work around \ + * servers that return \ + * errors on non-empty \ + * terminals. */ +#define DNS_FETCHOPT_QMIN_USE_A \ + 0x00080000 /*%< Use A type queries \ + * instead of NS when \ + * doing minimization */ +#define DNS_FETCHOPT_QMIN_SKIP_IP6A \ + 0x00100000 /*%< Skip some labels \ + * when doing qname \ + * minimization on \ + * ip6.arpa. */ +#define DNS_FETCHOPT_NOFORWARD \ + 0x00200000 /*%< Do not use forwarders \ + * if possible. */ + +/* Reserved in use by adb.c 0x00400000 */ +#define DNS_FETCHOPT_EDNSVERSIONSET 0x00800000 +#define DNS_FETCHOPT_EDNSVERSIONMASK 0xff000000 +#define DNS_FETCHOPT_EDNSVERSIONSHIFT 24 +#define DNS_FETCHOPT_TRYSTALE_ONTIMEOUT 0x01000000 + +/* + * Upper bounds of class of query RTT (ms). Corresponds to + * dns_resstatscounter_queryrttX statistics counters. + */ +#define DNS_RESOLVER_QRYRTTCLASS0 10 +#define DNS_RESOLVER_QRYRTTCLASS0STR "10" +#define DNS_RESOLVER_QRYRTTCLASS1 100 +#define DNS_RESOLVER_QRYRTTCLASS1STR "100" +#define DNS_RESOLVER_QRYRTTCLASS2 500 +#define DNS_RESOLVER_QRYRTTCLASS2STR "500" +#define DNS_RESOLVER_QRYRTTCLASS3 800 +#define DNS_RESOLVER_QRYRTTCLASS3STR "800" +#define DNS_RESOLVER_QRYRTTCLASS4 1600 +#define DNS_RESOLVER_QRYRTTCLASS4STR "1600" + +/* + * XXXRTH Should this API be made semi-private? (I.e. + * _dns_resolver_create()). + */ + +#define DNS_RESOLVER_CHECKNAMES 0x01 +#define DNS_RESOLVER_CHECKNAMESFAIL 0x02 + +#define DNS_QMIN_MAXLABELS 7 +#define DNS_QMIN_MAX_NO_DELEGATION 3 +#define DNS_MAX_LABELS 127 + +isc_result_t +dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, + unsigned int ntasks, unsigned int ndisp, + isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, + unsigned int options, dns_dispatchmgr_t *dispatchmgr, + dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, + dns_resolver_t **resp); + +/*%< + * Create a resolver. + * + * Notes: + * + *\li Generally, applications should not create a resolver directly, but + * should instead call dns_view_createresolver(). + * + * Requires: + * + *\li 'view' is a valid view. + * + *\li 'taskmgr' is a valid task manager. + * + *\li 'ntasks' > 0. + * + *\li 'socketmgr' is a valid socket manager. + * + *\li 'timermgr' is a valid timer manager. + * + *\li 'dispatchv4' is a dispatch with an IPv4 UDP socket, or is NULL. + * If not NULL, 'ndisp' clones of it will be created by the resolver. + * + *\li 'dispatchv6' is a dispatch with an IPv6 UDP socket, or is NULL. + * If not NULL, 'ndisp' clones of it will be created by the resolver. + * + *\li resp != NULL && *resp == NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + */ + +void +dns_resolver_freeze(dns_resolver_t *res); +/*%< + * Freeze resolver. + * + * Notes: + * + *\li Certain configuration changes cannot be made after the resolver + * is frozen. Fetches cannot be created until the resolver is frozen. + * + * Requires: + * + *\li 'res' is a valid resolver. + * + * Ensures: + * + *\li 'res' is frozen. + */ + +void +dns_resolver_prime(dns_resolver_t *res); +/*%< + * Prime resolver. + * + * Notes: + * + *\li Resolvers which have a forwarding policy other than dns_fwdpolicy_only + * need to be primed with the root nameservers, otherwise the root + * nameserver hints data may be used indefinitely. This function requests + * that the resolver start a priming fetch, if it isn't already priming. + * + * Requires: + * + *\li 'res' is a valid, frozen resolver. + */ + +void +dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task, + isc_event_t **eventp); +/*%< + * Send '*eventp' to 'task' when 'res' has completed shutdown. + * + * Notes: + * + *\li It is not safe to detach the last reference to 'res' until + * shutdown is complete. + * + * Requires: + * + *\li 'res' is a valid resolver. + * + *\li 'task' is a valid task. + * + *\li *eventp is a valid event. + * + * Ensures: + * + *\li *eventp == NULL. + */ + +void +dns_resolver_shutdown(dns_resolver_t *res); +/*%< + * Start the shutdown process for 'res'. + * + * Notes: + * + *\li This call has no effect if the resolver is already shutting down. + * + * Requires: + * + *\li 'res' is a valid resolver. + */ + +void +dns_resolver_attach(dns_resolver_t *source, dns_resolver_t **targetp); + +void +dns_resolver_detach(dns_resolver_t **resp); + +isc_result_t +dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name, + dns_rdatatype_t type, const dns_name_t *domain, + dns_rdataset_t *nameservers, + dns_forwarders_t *forwarders, + const isc_sockaddr_t *client, dns_messageid_t id, + unsigned int options, unsigned int depth, + isc_counter_t *qc, isc_task_t *task, + isc_taskaction_t action, void *arg, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, + dns_fetch_t **fetchp); +/*%< + * Recurse to answer a question. + * + * Notes: + * + *\li This call starts a query for 'name', type 'type'. + * + *\li The 'domain' is a parent domain of 'name' for which + * a set of name servers 'nameservers' is known. If no + * such name server information is available, set + * 'domain' and 'nameservers' to NULL. + * + *\li 'forwarders' is unimplemented, and subject to change when + * we figure out how selective forwarding will work. + * + *\li When the fetch completes (successfully or otherwise), a + * #DNS_EVENT_FETCHDONE event with action 'action' and arg 'arg' will be + * posted to 'task'. + * + *\li The values of 'rdataset' and 'sigrdataset' will be returned in + * the FETCHDONE event. + * + *\li 'client' and 'id' are used for duplicate query detection. '*client' + * must remain stable until after 'action' has been called or + * dns_resolver_cancelfetch() is called. + * + * Requires: + * + *\li 'res' is a valid resolver that has been frozen. + * + *\li 'name' is a valid name. + * + *\li 'type' is not a meta type other than ANY. + * + *\li 'domain' is a valid name or NULL. + * + *\li 'nameservers' is a valid NS rdataset (whose owner name is 'domain') + * iff. 'domain' is not NULL. + * + *\li 'forwarders' is NULL. + * + *\li 'client' is a valid sockaddr or NULL. + * + *\li 'options' contains valid options. + * + *\li 'rdataset' is a valid, disassociated rdataset. + * + *\li 'sigrdataset' is NULL, or is a valid, disassociated rdataset. + * + *\li fetchp != NULL && *fetchp == NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS Success + *\li #DNS_R_DUPLICATE + *\li #DNS_R_DROP + * + *\li Many other values are possible, all of which indicate failure. + */ + +void +dns_resolver_cancelfetch(dns_fetch_t *fetch); +/*%< + * Cancel 'fetch'. + * + * Notes: + * + *\li If 'fetch' has not completed, post its FETCHDONE event with a + * result code of #ISC_R_CANCELED. + * + * Requires: + * + *\li 'fetch' is a valid fetch. + */ + +void +dns_resolver_destroyfetch(dns_fetch_t **fetchp); +/*%< + * Destroy 'fetch'. + * + * Requires: + * + *\li '*fetchp' is a valid fetch. + * + *\li The caller has received the FETCHDONE event (either because the + * fetch completed or because dns_resolver_cancelfetch() was called). + * + * Ensures: + * + *\li *fetchp == NULL. + */ + +void +dns_resolver_logfetch(dns_fetch_t *fetch, isc_log_t *lctx, + isc_logcategory_t *category, isc_logmodule_t *module, + int level, bool duplicateok); +/*%< + * Dump a log message on internal state at the completion of given 'fetch'. + * 'lctx', 'category', 'module', and 'level' are used to write the log message. + * By default, only one log message is written even if the corresponding fetch + * context serves multiple clients; if 'duplicateok' is true the suppression + * is disabled and the message can be written every time this function is + * called. + * + * Requires: + * + *\li 'fetch' is a valid fetch, and has completed. + */ + +dns_dispatchmgr_t * +dns_resolver_dispatchmgr(dns_resolver_t *resolver); + +dns_dispatch_t * +dns_resolver_dispatchv4(dns_resolver_t *resolver); + +dns_dispatch_t * +dns_resolver_dispatchv6(dns_resolver_t *resolver); + +isc_socketmgr_t * +dns_resolver_socketmgr(dns_resolver_t *resolver); + +isc_taskmgr_t * +dns_resolver_taskmgr(dns_resolver_t *resolver); + +uint32_t +dns_resolver_getlamettl(dns_resolver_t *resolver); +/*%< + * Get the resolver's lame-ttl. zero => no lame processing. + * + * Requires: + *\li 'resolver' to be valid. + */ + +void +dns_resolver_setlamettl(dns_resolver_t *resolver, uint32_t lame_ttl); +/*%< + * Set the resolver's lame-ttl. zero => no lame processing. + * + * Requires: + *\li 'resolver' to be valid. + */ + +isc_result_t +dns_resolver_addalternate(dns_resolver_t *resolver, const isc_sockaddr_t *alt, + const dns_name_t *name, in_port_t port); +/*%< + * Add alternate addresses to be tried in the event that the nameservers + * for a zone are not available in the address families supported by the + * operating system. + * + * Require: + * \li only one of 'name' or 'alt' to be valid. + */ + +void +dns_resolver_setudpsize(dns_resolver_t *resolver, uint16_t udpsize); +/*%< + * Set the EDNS UDP buffer size advertised by the server. + */ + +uint16_t +dns_resolver_getudpsize(dns_resolver_t *resolver); +/*%< + * Get the current EDNS UDP buffer size. + */ + +void +dns_resolver_reset_algorithms(dns_resolver_t *resolver); +/*%< + * Clear the disabled DNSSEC algorithms. + */ + +void +dns_resolver_reset_ds_digests(dns_resolver_t *resolver); +/*%< + * Clear the disabled DS digest types. + */ + +isc_result_t +dns_resolver_disable_algorithm(dns_resolver_t *resolver, const dns_name_t *name, + unsigned int alg); +/*%< + * Mark the given DNSSEC algorithm as disabled and below 'name'. + * Valid algorithms are less than 256. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_RANGE + *\li #ISC_R_NOMEMORY + */ + +isc_result_t +dns_resolver_disable_ds_digest(dns_resolver_t *resolver, const dns_name_t *name, + unsigned int digest_type); +/*%< + * Mark the given DS digest type as disabled and below 'name'. + * Valid types are less than 256. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_RANGE + *\li #ISC_R_NOMEMORY + */ + +bool +dns_resolver_algorithm_supported(dns_resolver_t *resolver, + const dns_name_t *name, unsigned int alg); +/*%< + * Check if the given algorithm is supported by this resolver. + * This checks whether the algorithm has been disabled via + * dns_resolver_disable_algorithm(), then checks the underlying + * crypto libraries if it was not specifically disabled. + */ + +bool +dns_resolver_ds_digest_supported(dns_resolver_t *resolver, + const dns_name_t *name, + unsigned int digest_type); +/*%< + * Check if the given digest type is supported by this resolver. + * This checks whether the digest type has been disabled via + * dns_resolver_disable_ds_digest(), then checks the underlying + * crypto libraries if it was not specifically disabled. + */ + +void +dns_resolver_resetmustbesecure(dns_resolver_t *resolver); + +isc_result_t +dns_resolver_setmustbesecure(dns_resolver_t *resolver, const dns_name_t *name, + bool value); + +bool +dns_resolver_getmustbesecure(dns_resolver_t *resolver, const dns_name_t *name); + +void +dns_resolver_settimeout(dns_resolver_t *resolver, unsigned int timeout); +/*%< + * Set the length of time the resolver will work on a query, in milliseconds. + * + * 'timeout' was originally defined in seconds, and later redefined to be in + * milliseconds. Values less than or equal to 300 are treated as seconds. + * + * If timeout is 0, the default timeout will be applied. + * + * Requires: + * \li resolver to be valid. + */ + +unsigned int +dns_resolver_gettimeout(dns_resolver_t *resolver); +/*%< + * Get the current length of time the resolver will work on a query, + * in milliseconds. + * + * Requires: + * \li resolver to be valid. + */ + +void +dns_resolver_setclientsperquery(dns_resolver_t *resolver, uint32_t min, + uint32_t max); +void +dns_resolver_setfetchesperzone(dns_resolver_t *resolver, uint32_t clients); + +void +dns_resolver_getclientsperquery(dns_resolver_t *resolver, uint32_t *cur, + uint32_t *min, uint32_t *max); + +bool +dns_resolver_getzeronosoattl(dns_resolver_t *resolver); + +void +dns_resolver_setzeronosoattl(dns_resolver_t *resolver, bool state); + +unsigned int +dns_resolver_getretryinterval(dns_resolver_t *resolver); + +void +dns_resolver_setretryinterval(dns_resolver_t *resolver, unsigned int interval); +/*%< + * Sets the amount of time, in milliseconds, that is waited for a reply + * to a server before another server is tried. Interacts with the + * value of dns_resolver_getnonbackofftries() by trying that number of times + * at this interval, before doing exponential backoff and doubling the interval + * on each subsequent try, to a maximum of 10 seconds. Defaults to 800 ms; + * silently capped at 2000 ms. + * + * Requires: + * \li resolver to be valid. + * \li interval > 0. + */ + +unsigned int +dns_resolver_getnonbackofftries(dns_resolver_t *resolver); + +void +dns_resolver_setnonbackofftries(dns_resolver_t *resolver, unsigned int tries); +/*%< + * Sets the number of failures of getting a reply from remote servers for + * a query before backing off by doubling the retry interval for each + * subsequent request sent. Defaults to 3. + * + * Requires: + * \li resolver to be valid. + * \li tries > 0. + */ + +unsigned int +dns_resolver_getoptions(dns_resolver_t *resolver); +/*%< + * Get the resolver options. + * + * Requires: + * \li resolver to be valid. + */ + +void +dns_resolver_addbadcache(dns_resolver_t *resolver, const dns_name_t *name, + dns_rdatatype_t type, isc_time_t *expire); +/*%< + * Add a entry to the bad cache for <name,type> that will expire at 'expire'. + * + * Requires: + * \li resolver to be valid. + * \li name to be valid. + */ + +bool +dns_resolver_getbadcache(dns_resolver_t *resolver, const dns_name_t *name, + dns_rdatatype_t type, isc_time_t *now); +/*%< + * Check to see if there is a unexpired entry in the bad cache for + * <name,type>. + * + * Requires: + * \li resolver to be valid. + * \li name to be valid. + */ + +void +dns_resolver_flushbadcache(dns_resolver_t *resolver, const dns_name_t *name); +/*%< + * Flush the bad cache of all entries at 'name' if 'name' is non NULL. + * Flush the entire bad cache if 'name' is NULL. + * + * Requires: + * \li resolver to be valid. + */ + +void +dns_resolver_flushbadnames(dns_resolver_t *resolver, const dns_name_t *name); +/*%< + * Flush the bad cache of all entries at or below 'name'. + * + * Requires: + * \li resolver to be valid. + * \li name != NULL + */ + +void +dns_resolver_printbadcache(dns_resolver_t *resolver, FILE *fp); +/*% + * Print out the contents of the bad cache to 'fp'. + * + * Requires: + * \li resolver to be valid. + */ + +void +dns_resolver_setquerydscp4(dns_resolver_t *resolver, isc_dscp_t dscp); +isc_dscp_t +dns_resolver_getquerydscp4(dns_resolver_t *resolver); + +void +dns_resolver_setquerydscp6(dns_resolver_t *resolver, isc_dscp_t dscp); +isc_dscp_t +dns_resolver_getquerydscp6(dns_resolver_t *resolver); +/*% + * Get and set the DSCP values for the resolver's IPv4 and IPV6 query + * sources. + * + * Requires: + * \li resolver to be valid. + */ + +void +dns_resolver_setmaxdepth(dns_resolver_t *resolver, unsigned int maxdepth); +unsigned int +dns_resolver_getmaxdepth(dns_resolver_t *resolver); +/*% + * Get and set how many NS indirections will be followed when looking for + * nameserver addresses. + * + * Requires: + * \li resolver to be valid. + */ + +void +dns_resolver_setmaxqueries(dns_resolver_t *resolver, unsigned int queries); +unsigned int +dns_resolver_getmaxqueries(dns_resolver_t *resolver); +/*% + * Get and set how many iterative queries will be allowed before + * terminating a recursive query. + * + * Requires: + * \li resolver to be valid. + */ + +void +dns_resolver_setquotaresponse(dns_resolver_t *resolver, dns_quotatype_t which, + isc_result_t resp); +isc_result_t +dns_resolver_getquotaresponse(dns_resolver_t *resolver, dns_quotatype_t which); +/*% + * Get and set the result code that will be used when quotas + * are exceeded. If 'which' is set to quotatype "zone", then the + * result specified in 'resp' will be used when the fetches-per-zone + * quota is exceeded by a fetch. If 'which' is set to quotatype "server", + * then the result specified in 'resp' will be used when the + * fetches-per-server quota has been exceeded for all the + * authoritative servers for a zone. Valid choices are + * DNS_R_DROP or DNS_R_SERVFAIL. + * + * Requires: + * \li 'resolver' to be valid. + * \li 'which' to be dns_quotatype_zone or dns_quotatype_server + * \li 'resp' to be DNS_R_DROP or DNS_R_SERVFAIL. + */ + +void +dns_resolver_dumpfetches(dns_resolver_t *resolver, isc_statsformat_t format, + FILE *fp); + +#ifdef ENABLE_AFL +/*% + * Enable fuzzing of resolver, changes behaviour and eliminates retries + */ +void +dns_resolver_setfuzzing(void); +#endif /* ifdef ENABLE_AFL */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_RESOLVER_H */ diff --git a/lib/dns/include/dns/result.h b/lib/dns/include/dns/result.h new file mode 100644 index 0000000..0ec874b --- /dev/null +++ b/lib/dns/include/dns/result.h @@ -0,0 +1,212 @@ +/* + * 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. + */ + +#ifndef DNS_RESULT_H +#define DNS_RESULT_H 1 + +/*! \file dns/result.h */ + +#include <isc/lang.h> +#include <isc/resultclass.h> + +#include <dns/types.h> + +/* + * Nothing in this file truly depends on <isc/result.h>, but the + * DNS result codes are considered to be publicly derived from + * the ISC result codes, so including this file buys you the ISC_R_ + * namespace too. + */ +#include <isc/result.h> /* Contractual promise. */ + +/* + * DNS library result codes + */ +#define DNS_R_LABELTOOLONG (ISC_RESULTCLASS_DNS + 0) +#define DNS_R_BADESCAPE (ISC_RESULTCLASS_DNS + 1) +/* + * Since we dropped the support of bitstring labels, deprecate the related + * result codes too. + * + #define DNS_R_BADBITSTRING (ISC_RESULTCLASS_DNS + 2) + #define DNS_R_BITSTRINGTOOLONG (ISC_RESULTCLASS_DNS + 3) + */ +#define DNS_R_EMPTYLABEL (ISC_RESULTCLASS_DNS + 4) +#define DNS_R_BADDOTTEDQUAD (ISC_RESULTCLASS_DNS + 5) +#define DNS_R_INVALIDNS (ISC_RESULTCLASS_DNS + 6) +#define DNS_R_UNKNOWN (ISC_RESULTCLASS_DNS + 7) +#define DNS_R_BADLABELTYPE (ISC_RESULTCLASS_DNS + 8) +#define DNS_R_BADPOINTER (ISC_RESULTCLASS_DNS + 9) +#define DNS_R_TOOMANYHOPS (ISC_RESULTCLASS_DNS + 10) +#define DNS_R_DISALLOWED (ISC_RESULTCLASS_DNS + 11) +#define DNS_R_EXTRATOKEN (ISC_RESULTCLASS_DNS + 12) +#define DNS_R_EXTRADATA (ISC_RESULTCLASS_DNS + 13) +#define DNS_R_TEXTTOOLONG (ISC_RESULTCLASS_DNS + 14) +#define DNS_R_NOTZONETOP (ISC_RESULTCLASS_DNS + 15) +#define DNS_R_SYNTAX (ISC_RESULTCLASS_DNS + 16) +#define DNS_R_BADCKSUM (ISC_RESULTCLASS_DNS + 17) +#define DNS_R_BADAAAA (ISC_RESULTCLASS_DNS + 18) +#define DNS_R_NOOWNER (ISC_RESULTCLASS_DNS + 19) +#define DNS_R_NOTTL (ISC_RESULTCLASS_DNS + 20) +#define DNS_R_BADCLASS (ISC_RESULTCLASS_DNS + 21) +#define DNS_R_NAMETOOLONG (ISC_RESULTCLASS_DNS + 22) +#define DNS_R_PARTIALMATCH (ISC_RESULTCLASS_DNS + 23) +#define DNS_R_NEWORIGIN (ISC_RESULTCLASS_DNS + 24) +#define DNS_R_UNCHANGED (ISC_RESULTCLASS_DNS + 25) +#define DNS_R_BADTTL (ISC_RESULTCLASS_DNS + 26) +#define DNS_R_NOREDATA (ISC_RESULTCLASS_DNS + 27) +#define DNS_R_CONTINUE (ISC_RESULTCLASS_DNS + 28) +#define DNS_R_DELEGATION (ISC_RESULTCLASS_DNS + 29) +#define DNS_R_GLUE (ISC_RESULTCLASS_DNS + 30) +#define DNS_R_DNAME (ISC_RESULTCLASS_DNS + 31) +#define DNS_R_CNAME (ISC_RESULTCLASS_DNS + 32) +#define DNS_R_BADDB (ISC_RESULTCLASS_DNS + 33) +#define DNS_R_ZONECUT (ISC_RESULTCLASS_DNS + 34) +#define DNS_R_BADZONE (ISC_RESULTCLASS_DNS + 35) +#define DNS_R_MOREDATA (ISC_RESULTCLASS_DNS + 36) +#define DNS_R_UPTODATE (ISC_RESULTCLASS_DNS + 37) +#define DNS_R_TSIGVERIFYFAILURE (ISC_RESULTCLASS_DNS + 38) +#define DNS_R_TSIGERRORSET (ISC_RESULTCLASS_DNS + 39) +#define DNS_R_SIGINVALID (ISC_RESULTCLASS_DNS + 40) +#define DNS_R_SIGEXPIRED (ISC_RESULTCLASS_DNS + 41) +#define DNS_R_SIGFUTURE (ISC_RESULTCLASS_DNS + 42) +#define DNS_R_KEYUNAUTHORIZED (ISC_RESULTCLASS_DNS + 43) +#define DNS_R_INVALIDTIME (ISC_RESULTCLASS_DNS + 44) +#define DNS_R_EXPECTEDTSIG (ISC_RESULTCLASS_DNS + 45) +#define DNS_R_UNEXPECTEDTSIG (ISC_RESULTCLASS_DNS + 46) +#define DNS_R_INVALIDTKEY (ISC_RESULTCLASS_DNS + 47) +#define DNS_R_HINT (ISC_RESULTCLASS_DNS + 48) +#define DNS_R_DROP (ISC_RESULTCLASS_DNS + 49) +#define DNS_R_NOTLOADED (ISC_RESULTCLASS_DNS + 50) +#define DNS_R_NCACHENXDOMAIN (ISC_RESULTCLASS_DNS + 51) +#define DNS_R_NCACHENXRRSET (ISC_RESULTCLASS_DNS + 52) +#define DNS_R_WAIT (ISC_RESULTCLASS_DNS + 53) +#define DNS_R_NOTVERIFIEDYET (ISC_RESULTCLASS_DNS + 54) +#define DNS_R_NOIDENTITY (ISC_RESULTCLASS_DNS + 55) +#define DNS_R_NOJOURNAL (ISC_RESULTCLASS_DNS + 56) +#define DNS_R_ALIAS (ISC_RESULTCLASS_DNS + 57) +#define DNS_R_USETCP (ISC_RESULTCLASS_DNS + 58) +#define DNS_R_NOVALIDSIG (ISC_RESULTCLASS_DNS + 59) +#define DNS_R_NOVALIDNSEC (ISC_RESULTCLASS_DNS + 60) +#define DNS_R_NOTINSECURE (ISC_RESULTCLASS_DNS + 61) +#define DNS_R_UNKNOWNSERVICE (ISC_RESULTCLASS_DNS + 62) +#define DNS_R_RECOVERABLE (ISC_RESULTCLASS_DNS + 63) +#define DNS_R_UNKNOWNOPT (ISC_RESULTCLASS_DNS + 64) +#define DNS_R_UNEXPECTEDID (ISC_RESULTCLASS_DNS + 65) +#define DNS_R_SEENINCLUDE (ISC_RESULTCLASS_DNS + 66) +#define DNS_R_NOTEXACT (ISC_RESULTCLASS_DNS + 67) +#define DNS_R_BLACKHOLED (ISC_RESULTCLASS_DNS + 68) +#define DNS_R_BADALG (ISC_RESULTCLASS_DNS + 69) +#define DNS_R_METATYPE (ISC_RESULTCLASS_DNS + 70) +#define DNS_R_CNAMEANDOTHER (ISC_RESULTCLASS_DNS + 71) +#define DNS_R_SINGLETON (ISC_RESULTCLASS_DNS + 72) +#define DNS_R_HINTNXRRSET (ISC_RESULTCLASS_DNS + 73) +#define DNS_R_NOMASTERFILE (ISC_RESULTCLASS_DNS + 74) +#define DNS_R_UNKNOWNPROTO (ISC_RESULTCLASS_DNS + 75) +#define DNS_R_CLOCKSKEW (ISC_RESULTCLASS_DNS + 76) +#define DNS_R_BADIXFR (ISC_RESULTCLASS_DNS + 77) +#define DNS_R_NOTAUTHORITATIVE (ISC_RESULTCLASS_DNS + 78) +#define DNS_R_NOVALIDKEY (ISC_RESULTCLASS_DNS + 79) +#define DNS_R_OBSOLETE (ISC_RESULTCLASS_DNS + 80) +#define DNS_R_FROZEN (ISC_RESULTCLASS_DNS + 81) +#define DNS_R_UNKNOWNFLAG (ISC_RESULTCLASS_DNS + 82) +#define DNS_R_EXPECTEDRESPONSE (ISC_RESULTCLASS_DNS + 83) +#define DNS_R_NOVALIDDS (ISC_RESULTCLASS_DNS + 84) +#define DNS_R_NSISADDRESS (ISC_RESULTCLASS_DNS + 85) +#define DNS_R_REMOTEFORMERR (ISC_RESULTCLASS_DNS + 86) +#define DNS_R_TRUNCATEDTCP (ISC_RESULTCLASS_DNS + 87) +#define DNS_R_LAME (ISC_RESULTCLASS_DNS + 88) +#define DNS_R_UNEXPECTEDRCODE (ISC_RESULTCLASS_DNS + 89) +#define DNS_R_UNEXPECTEDOPCODE (ISC_RESULTCLASS_DNS + 90) +#define DNS_R_CHASEDSSERVERS (ISC_RESULTCLASS_DNS + 91) +#define DNS_R_EMPTYNAME (ISC_RESULTCLASS_DNS + 92) +#define DNS_R_EMPTYWILD (ISC_RESULTCLASS_DNS + 93) +#define DNS_R_BADBITMAP (ISC_RESULTCLASS_DNS + 94) +#define DNS_R_FROMWILDCARD (ISC_RESULTCLASS_DNS + 95) +#define DNS_R_BADOWNERNAME (ISC_RESULTCLASS_DNS + 96) +#define DNS_R_BADNAME (ISC_RESULTCLASS_DNS + 97) +#define DNS_R_DYNAMIC (ISC_RESULTCLASS_DNS + 98) +#define DNS_R_UNKNOWNCOMMAND (ISC_RESULTCLASS_DNS + 99) +#define DNS_R_MUSTBESECURE (ISC_RESULTCLASS_DNS + 100) +#define DNS_R_COVERINGNSEC (ISC_RESULTCLASS_DNS + 101) +#define DNS_R_MXISADDRESS (ISC_RESULTCLASS_DNS + 102) +#define DNS_R_DUPLICATE (ISC_RESULTCLASS_DNS + 103) +#define DNS_R_INVALIDNSEC3 (ISC_RESULTCLASS_DNS + 104) +#define DNS_R_NOTMASTER (ISC_RESULTCLASS_DNS + 105) +#define DNS_R_BROKENCHAIN (ISC_RESULTCLASS_DNS + 106) +#define DNS_R_EXPIRED (ISC_RESULTCLASS_DNS + 107) +#define DNS_R_NOTDYNAMIC (ISC_RESULTCLASS_DNS + 108) +#define DNS_R_BADEUI (ISC_RESULTCLASS_DNS + 109) +#define DNS_R_NTACOVERED (ISC_RESULTCLASS_DNS + 110) +#define DNS_R_BADCDS (ISC_RESULTCLASS_DNS + 111) +#define DNS_R_BADCDNSKEY (ISC_RESULTCLASS_DNS + 112) +#define DNS_R_OPTERR (ISC_RESULTCLASS_DNS + 113) +#define DNS_R_BADDNSTAP (ISC_RESULTCLASS_DNS + 114) +#define DNS_R_BADTSIG (ISC_RESULTCLASS_DNS + 115) +#define DNS_R_BADSIG0 (ISC_RESULTCLASS_DNS + 116) +#define DNS_R_TOOMANYRECORDS (ISC_RESULTCLASS_DNS + 117) +#define DNS_R_VERIFYFAILURE (ISC_RESULTCLASS_DNS + 118) +#define DNS_R_ATZONETOP (ISC_RESULTCLASS_DNS + 119) +#define DNS_R_NOKEYMATCH (ISC_RESULTCLASS_DNS + 120) +#define DNS_R_TOOMANYKEYS (ISC_RESULTCLASS_DNS + 121) +#define DNS_R_KEYNOTACTIVE (ISC_RESULTCLASS_DNS + 122) +#define DNS_R_NSEC3ITERRANGE (ISC_RESULTCLASS_DNS + 123) +#define DNS_R_NSEC3SALTRANGE (ISC_RESULTCLASS_DNS + 124) +#define DNS_R_NSEC3BADALG (ISC_RESULTCLASS_DNS + 125) +#define DNS_R_NSEC3RESALT (ISC_RESULTCLASS_DNS + 126) +#define DNS_R_INCONSISTENTRR (ISC_RESULTCLASS_DNS + 127) + +#define DNS_R_NRESULTS 128 /*%< Number of results */ + +/* + * DNS wire format rcodes. + * + * By making these their own class we can easily convert them into the + * wire-format rcode value simply by masking off the resultclass. + */ +#define DNS_R_NOERROR (ISC_RESULTCLASS_DNSRCODE + 0) +#define DNS_R_FORMERR (ISC_RESULTCLASS_DNSRCODE + 1) +#define DNS_R_SERVFAIL (ISC_RESULTCLASS_DNSRCODE + 2) +#define DNS_R_NXDOMAIN (ISC_RESULTCLASS_DNSRCODE + 3) +#define DNS_R_NOTIMP (ISC_RESULTCLASS_DNSRCODE + 4) +#define DNS_R_REFUSED (ISC_RESULTCLASS_DNSRCODE + 5) +#define DNS_R_YXDOMAIN (ISC_RESULTCLASS_DNSRCODE + 6) +#define DNS_R_YXRRSET (ISC_RESULTCLASS_DNSRCODE + 7) +#define DNS_R_NXRRSET (ISC_RESULTCLASS_DNSRCODE + 8) +#define DNS_R_NOTAUTH (ISC_RESULTCLASS_DNSRCODE + 9) +#define DNS_R_NOTZONE (ISC_RESULTCLASS_DNSRCODE + 10) +#define DNS_R_RCODE11 (ISC_RESULTCLASS_DNSRCODE + 11) +#define DNS_R_RCODE12 (ISC_RESULTCLASS_DNSRCODE + 12) +#define DNS_R_RCODE13 (ISC_RESULTCLASS_DNSRCODE + 13) +#define DNS_R_RCODE14 (ISC_RESULTCLASS_DNSRCODE + 14) +#define DNS_R_RCODE15 (ISC_RESULTCLASS_DNSRCODE + 15) +#define DNS_R_BADVERS (ISC_RESULTCLASS_DNSRCODE + 16) + +#define DNS_R_NRCODERESULTS 17 /*%< Number of rcode results */ + +#define DNS_RESULT_ISRCODE(result) \ + (ISC_RESULTCLASS_INCLASS(ISC_RESULTCLASS_DNSRCODE, (result))) + +ISC_LANG_BEGINDECLS + +const char *dns_result_totext(isc_result_t); + +void +dns_result_register(void); + +dns_rcode_t +dns_result_torcode(isc_result_t result); + +ISC_LANG_ENDDECLS + +#endif /* DNS_RESULT_H */ diff --git a/lib/dns/include/dns/rootns.h b/lib/dns/include/dns/rootns.h new file mode 100644 index 0000000..140538b --- /dev/null +++ b/lib/dns/include/dns/rootns.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef DNS_ROOTNS_H +#define DNS_ROOTNS_H 1 + +/*! \file dns/rootns.h */ + +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_rootns_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, + const char *filename, dns_db_t **target); + +void +dns_root_checkhints(dns_view_t *view, dns_db_t *hints, dns_db_t *db); +/* + * Reports differences between hints and the real roots. + * + * Requires view, hints and (cache) db to be valid. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_ROOTNS_H */ diff --git a/lib/dns/include/dns/rpz.h b/lib/dns/include/dns/rpz.h new file mode 100644 index 0000000..f0cc578 --- /dev/null +++ b/lib/dns/include/dns/rpz.h @@ -0,0 +1,435 @@ +/* + * 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. + */ + +#ifndef DNS_RPZ_H +#define DNS_RPZ_H 1 + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/deprecated.h> +#include <isc/event.h> +#include <isc/ht.h> +#include <isc/lang.h> +#include <isc/refcount.h> +#include <isc/rwlock.h> +#include <isc/time.h> +#include <isc/timer.h> + +#include <dns/fixedname.h> +#include <dns/rdata.h> +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +#define DNS_RPZ_PREFIX "rpz-" +/* + * Sub-zones of various trigger types. + */ +#define DNS_RPZ_CLIENT_IP_ZONE DNS_RPZ_PREFIX "client-ip" +#define DNS_RPZ_IP_ZONE DNS_RPZ_PREFIX "ip" +#define DNS_RPZ_NSIP_ZONE DNS_RPZ_PREFIX "nsip" +#define DNS_RPZ_NSDNAME_ZONE DNS_RPZ_PREFIX "nsdname" +/* + * Special policies. + */ +#define DNS_RPZ_PASSTHRU_NAME DNS_RPZ_PREFIX "passthru" +#define DNS_RPZ_DROP_NAME DNS_RPZ_PREFIX "drop" +#define DNS_RPZ_TCP_ONLY_NAME DNS_RPZ_PREFIX "tcp-only" + +typedef uint8_t dns_rpz_prefix_t; + +typedef enum { + DNS_RPZ_TYPE_BAD, + DNS_RPZ_TYPE_CLIENT_IP, + DNS_RPZ_TYPE_QNAME, + DNS_RPZ_TYPE_IP, + DNS_RPZ_TYPE_NSDNAME, + DNS_RPZ_TYPE_NSIP +} dns_rpz_type_t; + +/* + * Require DNS_RPZ_POLICY_PASSTHRU < DNS_RPZ_POLICY_DROP + * < DNS_RPZ_POLICY_TCP_ONLY DNS_RPZ_POLICY_NXDOMAIN < DNS_RPZ_POLICY_NODATA + * < DNS_RPZ_POLICY_CNAME to choose among competing policies. + */ +typedef enum { + DNS_RPZ_POLICY_GIVEN = 0, /* 'given': what policy record says */ + DNS_RPZ_POLICY_DISABLED = 1, /* log what would have happened */ + DNS_RPZ_POLICY_PASSTHRU = 2, /* 'passthru': do not rewrite */ + DNS_RPZ_POLICY_DROP = 3, /* 'drop': do not respond */ + DNS_RPZ_POLICY_TCP_ONLY = 4, /* 'tcp-only': answer UDP with TC=1 */ + DNS_RPZ_POLICY_NXDOMAIN = 5, /* 'nxdomain': answer with NXDOMAIN */ + DNS_RPZ_POLICY_NODATA = 6, /* 'nodata': answer with ANCOUNT=0 */ + DNS_RPZ_POLICY_CNAME = 7, /* 'cname x': answer with x's rrsets */ + DNS_RPZ_POLICY_DNS64, /* Apply DN64 to the A rewrite */ + DNS_RPZ_POLICY_RECORD, + DNS_RPZ_POLICY_WILDCNAME, + DNS_RPZ_POLICY_MISS, + DNS_RPZ_POLICY_ERROR +} dns_rpz_policy_t; + +typedef uint8_t dns_rpz_num_t; + +#define DNS_RPZ_MAX_ZONES 64 +/* + * Type dns_rpz_zbits_t must be an unsigned int wide enough to contain + * at least DNS_RPZ_MAX_ZONES bits. + */ +typedef uint64_t dns_rpz_zbits_t; + +#define DNS_RPZ_ALL_ZBITS ((dns_rpz_zbits_t)-1) + +#define DNS_RPZ_INVALID_NUM DNS_RPZ_MAX_ZONES + +#define DNS_RPZ_ZBIT(n) (((dns_rpz_zbits_t)1) << (dns_rpz_num_t)(n)) + +/* + * Mask of the specified and higher numbered policy zones + * Avoid hassles with (1<<33) or (1<<65) + */ +#define DNS_RPZ_ZMASK(n) \ + ((dns_rpz_zbits_t)((((n) >= DNS_RPZ_MAX_ZONES - 1) \ + ? 0 \ + : (1ULL << ((n) + 1))) - \ + 1)) + +/* + * The trigger counter type. + */ +typedef size_t dns_rpz_trigger_counter_t; + +/* + * The number of triggers of each type in a response policy zone. + */ +typedef struct dns_rpz_triggers dns_rpz_triggers_t; +struct dns_rpz_triggers { + dns_rpz_trigger_counter_t client_ipv4; + dns_rpz_trigger_counter_t client_ipv6; + dns_rpz_trigger_counter_t qname; + dns_rpz_trigger_counter_t ipv4; + dns_rpz_trigger_counter_t ipv6; + dns_rpz_trigger_counter_t nsdname; + dns_rpz_trigger_counter_t nsipv4; + dns_rpz_trigger_counter_t nsipv6; +}; + +/* + * A single response policy zone. + */ +typedef struct dns_rpz_zone dns_rpz_zone_t; +typedef struct dns_rpz_zones dns_rpz_zones_t; + +struct dns_rpz_zone { + isc_refcount_t refs; + dns_rpz_num_t num; /* ordinal in list of policy zones */ + dns_name_t origin; /* Policy zone name */ + dns_name_t client_ip; /* DNS_RPZ_CLIENT_IP_ZONE.origin. */ + dns_name_t ip; /* DNS_RPZ_IP_ZONE.origin. */ + dns_name_t nsdname; /* DNS_RPZ_NSDNAME_ZONE.origin */ + dns_name_t nsip; /* DNS_RPZ_NSIP_ZONE.origin. */ + dns_name_t passthru; /* DNS_RPZ_PASSTHRU_NAME. */ + dns_name_t drop; /* DNS_RPZ_DROP_NAME. */ + dns_name_t tcp_only; /* DNS_RPZ_TCP_ONLY_NAME. */ + dns_name_t cname; /* override value for ..._CNAME */ + dns_ttl_t max_policy_ttl; + dns_rpz_policy_t policy; /* DNS_RPZ_POLICY_GIVEN or override */ + + uint32_t min_update_interval; /* minimal interval between + * updates */ + isc_ht_t *nodes; /* entries in zone */ + dns_rpz_zones_t *rpzs; /* owner */ + isc_time_t lastupdated; /* last time the zone was processed + * */ + bool updatepending; /* there is an update + * pending/waiting */ + bool updaterunning; /* there is an update running */ + dns_db_t *db; /* zones database */ + dns_dbversion_t *dbversion; /* version we will be updating to */ + dns_db_t *updb; /* zones database we're working on */ + dns_dbversion_t *updbversion; /* version we're currently working + * on */ + dns_dbiterator_t *updbit; /* iterator to use when updating */ + isc_ht_t *newnodes; /* entries in zone being updated */ + bool db_registered; /* is the notify event + * registered? */ + bool addsoa; /* add soa to the additional section */ + isc_timer_t *updatetimer; + isc_event_t updateevent; +}; + +/* + * Radix tree node for response policy IP addresses + */ +typedef struct dns_rpz_cidr_node dns_rpz_cidr_node_t; + +/* + * Bitfields indicating which policy zones have policies of + * which type. + */ +typedef struct dns_rpz_have dns_rpz_have_t; +struct dns_rpz_have { + dns_rpz_zbits_t client_ipv4; + dns_rpz_zbits_t client_ipv6; + dns_rpz_zbits_t client_ip; + dns_rpz_zbits_t qname; + dns_rpz_zbits_t ipv4; + dns_rpz_zbits_t ipv6; + dns_rpz_zbits_t ip; + dns_rpz_zbits_t nsdname; + dns_rpz_zbits_t nsipv4; + dns_rpz_zbits_t nsipv6; + dns_rpz_zbits_t nsip; + dns_rpz_zbits_t qname_skip_recurse; +}; + +/* + * Policy options + */ +typedef struct dns_rpz_popt dns_rpz_popt_t; +struct dns_rpz_popt { + dns_rpz_zbits_t no_rd_ok; + dns_rpz_zbits_t no_log; + dns_rpz_zbits_t nsip_on; + dns_rpz_zbits_t nsdname_on; + bool dnsrps_enabled; + bool break_dnssec; + bool qname_wait_recurse; + bool nsip_wait_recurse; + unsigned int min_ns_labels; + dns_rpz_num_t num_zones; +}; + +/* + * Response policy zones known to a view. + */ +struct dns_rpz_zones { + dns_rpz_popt_t p; + dns_rpz_zone_t *zones[DNS_RPZ_MAX_ZONES]; + dns_rpz_triggers_t triggers[DNS_RPZ_MAX_ZONES]; + + /* + * RPZ policy version number. + * It is initially 0 and it increases whenever the server is + * reconfigured with new zones or policy. + */ + int rpz_ver; + + dns_rpz_zbits_t defined; + + /* + * The set of records for a policy zone are in one of these states: + * never loaded load_begun=0 have=0 + * during initial loading load_begun=1 have=0 + * and rbtdb->rpzsp == rbtdb->load_rpzsp + * after good load load_begun=1 have!=0 + * after failed initial load load_begun=1 have=0 + * and rbtdb->load_rpzsp == NULL + * reloading after failure load_begun=1 have=0 + * reloading after success + * main rpzs load_begun=1 have!=0 + * load rpzs load_begun=1 have=0 + */ + dns_rpz_zbits_t load_begun; + dns_rpz_have_t have; + + /* + * total_triggers maintains the total number of triggers in all + * policy zones in the view. It is only used to print summary + * statistics after a zone load of how the trigger counts + * changed. + */ + dns_rpz_triggers_t total_triggers; + + isc_mem_t *mctx; + isc_taskmgr_t *taskmgr; + isc_timermgr_t *timermgr; + isc_task_t *updater; + isc_refcount_t refs; + isc_refcount_t irefs; + /* + * One lock for short term read-only search that guarantees the + * consistency of the pointers. + * A second lock for maintenance that guarantees no other thread + * is adding or deleting nodes. + */ + isc_rwlock_t search_lock; + isc_mutex_t maint_lock; + + dns_rpz_cidr_node_t *cidr; + dns_rbt_t *rbt; + + /* + * DNSRPZ librpz configuration string and handle on librpz connection + */ + char *rps_cstr; + size_t rps_cstr_size; + struct librpz_client *rps_client; +}; + +/* + * context for finding the best policy + */ +typedef struct { + unsigned int state; +#define DNS_RPZ_REWRITTEN 0x0001 +#define DNS_RPZ_DONE_CLIENT_IP 0x0002 /* client IP address checked */ +#define DNS_RPZ_DONE_QNAME 0x0004 /* qname checked */ +#define DNS_RPZ_DONE_QNAME_IP 0x0008 /* IP addresses of qname checked */ +#define DNS_RPZ_DONE_NSDNAME 0x0010 /* NS name missed; checking addresses */ +#define DNS_RPZ_DONE_IPv4 0x0020 +#define DNS_RPZ_RECURSING 0x0040 +#define DNS_RPZ_ACTIVE 0x0080 + /* + * Best match so far. + */ + struct { + dns_rpz_type_t type; + dns_rpz_zone_t *rpz; + dns_rpz_prefix_t prefix; + dns_rpz_policy_t policy; + dns_ttl_t ttl; + isc_result_t result; + dns_zone_t *zone; + dns_db_t *db; + dns_dbversion_t *version; + dns_dbnode_t *node; + dns_rdataset_t *rdataset; + } m; + /* + * State for chasing IP addresses and NS names including recursion. + */ + struct { + unsigned int label; + dns_db_t *db; + dns_rdataset_t *ns_rdataset; + dns_rdatatype_t r_type; + isc_result_t r_result; + dns_rdataset_t *r_rdataset; + } r; + + /* + * State of real query while recursing for NSIP or NSDNAME. + */ + struct { + isc_result_t result; + bool is_zone; + bool authoritative; + dns_zone_t *zone; + dns_db_t *db; + dns_dbnode_t *node; + dns_rdataset_t *rdataset; + dns_rdataset_t *sigrdataset; + dns_rdatatype_t qtype; + } q; + + /* + * A copy of the 'have' and 'p' structures and the RPZ + * policy version as of the beginning of RPZ processing, + * used to avoid problems when policy is updated while + * RPZ recursion is ongoing. + */ + dns_rpz_have_t have; + dns_rpz_popt_t popt; + int rpz_ver; + + /* + * Shim db between BIND and DNRPS librpz. + */ + dns_db_t *rpsdb; + + /* + * p_name: current policy owner name + * r_name: recursing for this name to possible policy triggers + * f_name: saved found name from before recursion + */ + dns_name_t *p_name; + dns_name_t *r_name; + dns_name_t *fname; + dns_fixedname_t _p_namef; + dns_fixedname_t _r_namef; + dns_fixedname_t _fnamef; +} dns_rpz_st_t; + +#define DNS_RPZ_TTL_DEFAULT 5 +#define DNS_RPZ_MAX_TTL_DEFAULT DNS_RPZ_TTL_DEFAULT +#define DNS_RPZ_MINUPDATEINTERVAL_DEFAULT 60 + +/* + * So various response policy zone messages can be turned up or down. + */ +#define DNS_RPZ_ERROR_LEVEL ISC_LOG_WARNING +#define DNS_RPZ_INFO_LEVEL ISC_LOG_INFO +#define DNS_RPZ_DEBUG_LEVEL1 ISC_LOG_DEBUG(1) +#define DNS_RPZ_DEBUG_LEVEL2 ISC_LOG_DEBUG(2) +#define DNS_RPZ_DEBUG_LEVEL3 ISC_LOG_DEBUG(3) +#define DNS_RPZ_DEBUG_QUIET (DNS_RPZ_DEBUG_LEVEL3 + 1) + +const char * +dns_rpz_type2str(dns_rpz_type_t type); + +dns_rpz_policy_t +dns_rpz_str2policy(const char *str); + +const char * +dns_rpz_policy2str(dns_rpz_policy_t policy); + +dns_rpz_policy_t +dns_rpz_decode_cname(dns_rpz_zone_t *rpz, dns_rdataset_t *rdataset, + dns_name_t *selfname); + +isc_result_t +dns_rpz_new_zones(dns_rpz_zones_t **rpzsp, char *rps_cstr, size_t rps_cstr_size, + isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + isc_timermgr_t *timermgr); + +isc_result_t +dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp); + +isc_result_t +dns_rpz_dbupdate_callback(dns_db_t *db, void *fn_arg); + +void +dns_rpz_attach_rpzs(dns_rpz_zones_t *source, dns_rpz_zones_t **target); + +void +dns_rpz_detach_rpzs(dns_rpz_zones_t **rpzsp); + +isc_result_t +dns_rpz_beginload(dns_rpz_zones_t **load_rpzsp, dns_rpz_zones_t *rpzs, + dns_rpz_num_t rpz_num) ISC_DEPRECATED; + +isc_result_t +dns_rpz_ready(dns_rpz_zones_t *rpzs, dns_rpz_zones_t **load_rpzsp, + dns_rpz_num_t rpz_num) ISC_DEPRECATED; + +isc_result_t +dns_rpz_add(dns_rpz_zones_t *rpzs, dns_rpz_num_t rpz_num, + const dns_name_t *name); + +void +dns_rpz_delete(dns_rpz_zones_t *rpzs, dns_rpz_num_t rpz_num, + const dns_name_t *name); + +dns_rpz_num_t +dns_rpz_find_ip(dns_rpz_zones_t *rpzs, dns_rpz_type_t rpz_type, + dns_rpz_zbits_t zbits, const isc_netaddr_t *netaddr, + dns_name_t *ip_name, dns_rpz_prefix_t *prefixp); + +dns_rpz_zbits_t +dns_rpz_find_name(dns_rpz_zones_t *rpzs, dns_rpz_type_t rpz_type, + dns_rpz_zbits_t zbits, dns_name_t *trig_name); + +ISC_LANG_ENDDECLS + +#endif /* DNS_RPZ_H */ diff --git a/lib/dns/include/dns/rriterator.h b/lib/dns/include/dns/rriterator.h new file mode 100644 index 0000000..2294d69 --- /dev/null +++ b/lib/dns/include/dns/rriterator.h @@ -0,0 +1,182 @@ +/* + * 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. + */ + +#ifndef DNS_RRITERATOR_H +#define DNS_RRITERATOR_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/rriterator.h + * \brief + * Functions for "walking" a zone database, visiting each RR or RRset in turn. + */ + +/***** +***** Imports +*****/ + +#include <inttypes.h> + +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/stdtime.h> + +#include <dns/db.h> +#include <dns/dbiterator.h> +#include <dns/fixedname.h> +#include <dns/name.h> +#include <dns/rdata.h> +#include <dns/rdataset.h> +#include <dns/rdatasetiter.h> +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/***** +***** Types +*****/ + +/*% + * A dns_rriterator_t is an iterator that iterates over an entire database, + * returning one RR at a time, in some arbitrary order. + */ + +typedef struct dns_rriterator { + unsigned int magic; + isc_result_t result; + dns_db_t *db; + dns_dbiterator_t *dbit; + dns_dbversion_t *ver; + isc_stdtime_t now; + dns_dbnode_t *node; + dns_fixedname_t fixedname; + dns_rdatasetiter_t *rdatasetit; + dns_rdataset_t rdataset; + dns_rdata_t rdata; +} dns_rriterator_t; + +#define RRITERATOR_MAGIC ISC_MAGIC('R', 'R', 'I', 't') +#define VALID_RRITERATOR(m) ISC_MAGIC_VALID(m, RRITERATOR_MAGIC) + +isc_result_t +dns_rriterator_init(dns_rriterator_t *it, dns_db_t *db, dns_dbversion_t *ver, + isc_stdtime_t now); +/*% + * Initialize an rriterator; sets the cursor to the origin node + * of the database. + * + * Requires: + * + * \li 'db' is a valid database. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + */ + +isc_result_t +dns_rriterator_first(dns_rriterator_t *it); +/*%< + * Move the rriterator cursor to the first rdata in the database. + * + * Requires: + *\li 'it' is a valid, initialized rriterator + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMORE There are no rdata in the set. + */ + +isc_result_t +dns_rriterator_nextrrset(dns_rriterator_t *it); +/*%< + * Move the rriterator cursor to the next rrset in the database, + * skipping over any remaining records that have the same rdatatype + * as the current one. + * + * Requires: + *\li 'it' is a valid, initialized rriterator + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMORE No more rrsets in the database + */ + +isc_result_t +dns_rriterator_next(dns_rriterator_t *it); +/*%< + * Move the rriterator cursor to the next rrset in the database, + * skipping over any remaining records that have the same rdatatype + * as the current one. + * + * Requires: + *\li 'it' is a valid, initialized rriterator + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMORE No more records in the database + */ + +void +dns_rriterator_current(dns_rriterator_t *it, dns_name_t **name, uint32_t *ttl, + dns_rdataset_t **rdataset, dns_rdata_t **rdata); +/*%< + * Make '*name' refer to the current name. If 'rdataset' is not NULL, + * make '*rdataset' refer to the current * rdataset. If '*rdata' is not + * NULL, make '*rdata' refer to the current record. + * + * Requires: + *\li '*name' is a valid name object + *\li 'rdataset' is NULL or '*rdataset' is NULL + *\li 'rdata' is NULL or '*rdata' is NULL + * + * Ensures: + *\li 'rdata' refers to the rdata at the rdata cursor location of + *\li 'rdataset'. + */ + +void +dns_rriterator_pause(dns_rriterator_t *it); +/*%< + * Pause rriterator. Frees any locks held by the database iterator. + * Callers should use this routine any time they are not going to + * execute another rriterator method in the immediate future. + * + * Requires: + *\li 'it' is a valid iterator. + * + * Ensures: + *\li Any database locks being held for efficiency of iterator access are + * released. + */ + +void +dns_rriterator_destroy(dns_rriterator_t *it); +/*%< + * Shut down and free resources in rriterator 'it'. + * + * Requires: + * + *\li 'it' is a valid iterator. + * + * Ensures: + * + *\li All resources used by the rriterator are freed. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_RRITERATOR_H */ diff --git a/lib/dns/include/dns/rrl.h b/lib/dns/include/dns/rrl.h new file mode 100644 index 0000000..fabefa3 --- /dev/null +++ b/lib/dns/include/dns/rrl.h @@ -0,0 +1,272 @@ +/* + * 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. + */ + +#ifndef DNS_RRL_H +#define DNS_RRL_H 1 + +/* + * Rate limit DNS responses. + */ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/lang.h> + +#include <dns/fixedname.h> +#include <dns/rdata.h> +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/* + * Memory allocation or other failures. + */ +#define DNS_RRL_LOG_FAIL ISC_LOG_WARNING +/* + * dropped or slipped responses. + */ +#define DNS_RRL_LOG_DROP ISC_LOG_INFO +/* + * Major events in dropping or slipping. + */ +#define DNS_RRL_LOG_DEBUG1 ISC_LOG_DEBUG(3) +/* + * Limit computations. + */ +#define DNS_RRL_LOG_DEBUG2 ISC_LOG_DEBUG(4) +/* + * Even less interesting. + */ +#define DNS_RRL_LOG_DEBUG3 ISC_LOG_DEBUG(9) + +#define DNS_RRL_LOG_ERR_LEN 64 +#define DNS_RRL_LOG_BUF_LEN \ + (sizeof("would continue limiting") + DNS_RRL_LOG_ERR_LEN + \ + sizeof(" responses to ") + ISC_NETADDR_FORMATSIZE + \ + sizeof("/128 for IN ") + DNS_RDATATYPE_FORMATSIZE + \ + DNS_NAME_FORMATSIZE) + +typedef struct dns_rrl_hash dns_rrl_hash_t; + +/* + * Response types. + */ +typedef enum { + DNS_RRL_RTYPE_FREE = 0, + DNS_RRL_RTYPE_QUERY, + DNS_RRL_RTYPE_REFERRAL, + DNS_RRL_RTYPE_NODATA, + DNS_RRL_RTYPE_NXDOMAIN, + DNS_RRL_RTYPE_ERROR, + DNS_RRL_RTYPE_ALL, + DNS_RRL_RTYPE_TCP, +} dns_rrl_rtype_t; + +/* + * A rate limit bucket key. + * This should be small to limit the total size of the database. + * The hash of the qname should be wide enough to make the probability + * of collisions among requests from a single IP address block less than 50%. + * We need a 32-bit hash value for 10000 qps (e.g. random qnames forged + * by attacker) to collide with legitimate qnames from the target with + * probability at most 1%. + */ +#define DNS_RRL_MAX_PREFIX 64 +typedef union dns_rrl_key dns_rrl_key_t; +struct dns__rrl_key { + uint32_t ip[DNS_RRL_MAX_PREFIX / 32]; + uint32_t qname_hash; + dns_rdatatype_t qtype; + uint8_t qclass; + unsigned int rtype : 4; /* dns_rrl_rtype_t */ + unsigned int ipv6 : 1; +}; +union dns_rrl_key { + struct dns__rrl_key s; + uint16_t w[sizeof(struct dns__rrl_key) / sizeof(uint16_t)]; +}; + +/* + * A rate-limit entry. + * This should be small to limit the total size of the table of entries. + */ +typedef struct dns_rrl_entry dns_rrl_entry_t; +typedef ISC_LIST(dns_rrl_entry_t) dns_rrl_bin_t; +struct dns_rrl_entry { + ISC_LINK(dns_rrl_entry_t) lru; + ISC_LINK(dns_rrl_entry_t) hlink; + dns_rrl_key_t key; +#define DNS_RRL_RESPONSE_BITS 24 + signed int responses : DNS_RRL_RESPONSE_BITS; +#define DNS_RRL_QNAMES_BITS 8 + unsigned int log_qname : DNS_RRL_QNAMES_BITS; + +#define DNS_RRL_TS_GEN_BITS 2 + unsigned int ts_gen : DNS_RRL_TS_GEN_BITS; + unsigned int ts_valid : 1; +#define DNS_RRL_HASH_GEN_BITS 1 + unsigned int hash_gen : DNS_RRL_HASH_GEN_BITS; + unsigned int logged : 1; +#define DNS_RRL_LOG_BITS 11 + unsigned int log_secs : DNS_RRL_LOG_BITS; + +#define DNS_RRL_TS_BITS 12 + unsigned int ts : DNS_RRL_TS_BITS; + +#define DNS_RRL_MAX_SLIP 10 + unsigned int slip_cnt : 4; +}; + +#define DNS_RRL_MAX_TIME_TRAVEL 5 +#define DNS_RRL_FOREVER (1 << DNS_RRL_TS_BITS) +#define DNS_RRL_MAX_TS (DNS_RRL_FOREVER - 1) + +#define DNS_RRL_MAX_RESPONSES ((1 << (DNS_RRL_RESPONSE_BITS - 1)) - 1) +#define DNS_RRL_MAX_WINDOW 3600 +#if DNS_RRL_MAX_WINDOW >= DNS_RRL_MAX_TS +#error "DNS_RRL_MAX_WINDOW is too large" +#endif /* if DNS_RRL_MAX_WINDOW >= DNS_RRL_MAX_TS */ +#define DNS_RRL_MAX_RATE 1000 +#if DNS_RRL_MAX_RATE >= (DNS_RRL_MAX_RESPONSES / DNS_RRL_MAX_WINDOW) +#error "DNS_RRL_MAX_rate is too large" +#endif /* if DNS_RRL_MAX_RATE >= (DNS_RRL_MAX_RESPONSES / DNS_RRL_MAX_WINDOW) \ + */ + +#if (1 << DNS_RRL_LOG_BITS) >= DNS_RRL_FOREVER +#error DNS_RRL_LOG_BITS is too big +#endif /* if (1 << DNS_RRL_LOG_BITS) >= DNS_RRL_FOREVER */ +#define DNS_RRL_MAX_LOG_SECS 1800 +#if DNS_RRL_MAX_LOG_SECS >= (1 << DNS_RRL_LOG_BITS) +#error "DNS_RRL_MAX_LOG_SECS is too large" +#endif /* if DNS_RRL_MAX_LOG_SECS >= (1 << DNS_RRL_LOG_BITS) */ +#define DNS_RRL_STOP_LOG_SECS 60 +#if DNS_RRL_STOP_LOG_SECS >= (1 << DNS_RRL_LOG_BITS) +#error "DNS_RRL_STOP_LOG_SECS is too large" +#endif /* if DNS_RRL_STOP_LOG_SECS >= (1 << DNS_RRL_LOG_BITS) */ + +/* + * A hash table of rate-limit entries. + */ +struct dns_rrl_hash { + isc_stdtime_t check_time; + unsigned int gen : DNS_RRL_HASH_GEN_BITS; + int length; + dns_rrl_bin_t bins[1]; +}; + +/* + * A block of rate-limit entries. + */ +typedef struct dns_rrl_block dns_rrl_block_t; +struct dns_rrl_block { + ISC_LINK(dns_rrl_block_t) link; + int size; + dns_rrl_entry_t entries[1]; +}; + +/* + * A rate limited qname buffer. + */ +typedef struct dns_rrl_qname_buf dns_rrl_qname_buf_t; +struct dns_rrl_qname_buf { + ISC_LINK(dns_rrl_qname_buf_t) link; + const dns_rrl_entry_t *e; + unsigned int index; + dns_fixedname_t qname; +}; + +typedef struct dns_rrl_rate dns_rrl_rate_t; +struct dns_rrl_rate { + int r; + int scaled; + const char *str; +}; + +/* + * Per-view query rate limit parameters and a pointer to database. + */ +typedef struct dns_rrl dns_rrl_t; +struct dns_rrl { + isc_mutex_t lock; + isc_mem_t *mctx; + + bool log_only; + dns_rrl_rate_t responses_per_second; + dns_rrl_rate_t referrals_per_second; + dns_rrl_rate_t nodata_per_second; + dns_rrl_rate_t nxdomains_per_second; + dns_rrl_rate_t errors_per_second; + dns_rrl_rate_t all_per_second; + dns_rrl_rate_t slip; + int window; + double qps_scale; + int max_entries; + + dns_acl_t *exempt; + + int num_entries; + + int qps_responses; + isc_stdtime_t qps_time; + double qps; + + unsigned int probes; + unsigned int searches; + + ISC_LIST(dns_rrl_block_t) blocks; + ISC_LIST(dns_rrl_entry_t) lru; + + dns_rrl_hash_t *hash; + dns_rrl_hash_t *old_hash; + unsigned int hash_gen; + + unsigned int ts_gen; +#define DNS_RRL_TS_BASES (1 << DNS_RRL_TS_GEN_BITS) + isc_stdtime_t ts_bases[DNS_RRL_TS_BASES]; + + int ipv4_prefixlen; + uint32_t ipv4_mask; + int ipv6_prefixlen; + uint32_t ipv6_mask[4]; + + isc_stdtime_t log_stops_time; + dns_rrl_entry_t *last_logged; + int num_logged; + int num_qnames; + ISC_LIST(dns_rrl_qname_buf_t) qname_free; +#define DNS_RRL_QNAMES (1 << DNS_RRL_QNAMES_BITS) + dns_rrl_qname_buf_t *qnames[DNS_RRL_QNAMES]; +}; + +typedef enum { + DNS_RRL_RESULT_OK, + DNS_RRL_RESULT_DROP, + DNS_RRL_RESULT_SLIP, +} dns_rrl_result_t; + +dns_rrl_result_t +dns_rrl(dns_view_t *view, dns_zone_t *zone, const isc_sockaddr_t *client_addr, + bool is_tcp, dns_rdataclass_t rdclass, dns_rdatatype_t qtype, + const dns_name_t *qname, isc_result_t resp_result, isc_stdtime_t now, + bool wouldlog, char *log_buf, unsigned int log_buf_len); + +void +dns_rrl_view_destroy(dns_view_t *view); + +isc_result_t +dns_rrl_init(dns_rrl_t **rrlp, dns_view_t *view, int min_entries); + +ISC_LANG_ENDDECLS + +#endif /* DNS_RRL_H */ diff --git a/lib/dns/include/dns/sdb.h b/lib/dns/include/dns/sdb.h new file mode 100644 index 0000000..578d7cc --- /dev/null +++ b/lib/dns/include/dns/sdb.h @@ -0,0 +1,214 @@ +/* + * 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. + */ + +#ifndef DNS_SDB_H +#define DNS_SDB_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/sdb.h + * \brief + * Simple database API. + */ + +/*** + *** Imports + ***/ + +#include <inttypes.h> + +#include <isc/lang.h> + +#include <dns/clientinfo.h> +#include <dns/types.h> + +/*** + *** Types + ***/ + +/*% + * A simple database. This is an opaque type. + */ +typedef struct dns_sdb dns_sdb_t; + +/*% + * A simple database lookup in progress. This is an opaque type. + */ +typedef struct dns_sdblookup dns_sdblookup_t; + +/*% + * A simple database traversal in progress. This is an opaque type. + */ +typedef struct dns_sdballnodes dns_sdballnodes_t; + +typedef isc_result_t (*dns_sdblookupfunc_t)(const char *zone, const char *name, + void *dbdata, + dns_sdblookup_t *lookup, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo); +typedef isc_result_t (*dns_sdblookup2func_t)(const dns_name_t *zone, + const dns_name_t *name, + void *dbdata, + dns_sdblookup_t *lookup, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo); + +typedef isc_result_t (*dns_sdbauthorityfunc_t)(const char *zone, void *dbdata, + dns_sdblookup_t *); + +typedef isc_result_t (*dns_sdballnodesfunc_t)(const char *zone, void *dbdata, + dns_sdballnodes_t *allnodes); + +typedef isc_result_t (*dns_sdbcreatefunc_t)(const char *zone, int argc, + char **argv, void *driverdata, + void **dbdata); + +typedef void (*dns_sdbdestroyfunc_t)(const char *zone, void *driverdata, + void **dbdata); + +typedef struct dns_sdbmethods { + dns_sdblookupfunc_t lookup; + dns_sdbauthorityfunc_t authority; + dns_sdballnodesfunc_t allnodes; + dns_sdbcreatefunc_t create; + dns_sdbdestroyfunc_t destroy; + dns_sdblookup2func_t lookup2; +} dns_sdbmethods_t; + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +#define DNS_SDBFLAG_RELATIVEOWNER 0x00000001U +#define DNS_SDBFLAG_RELATIVERDATA 0x00000002U +#define DNS_SDBFLAG_THREADSAFE 0x00000004U +#define DNS_SDBFLAG_DNS64 0x00000008U + +isc_result_t +dns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods, + void *driverdata, unsigned int flags, isc_mem_t *mctx, + dns_sdbimplementation_t **sdbimp); +/*%< + * Register a simple database driver for the database type 'drivername', + * implemented by the functions in '*methods'. + * + * sdbimp must point to a NULL dns_sdbimplementation_t pointer. That is, + * sdbimp != NULL && *sdbimp == NULL. It will be assigned a value that + * will later be used to identify the driver when deregistering it. + * + * The name server will perform lookups in the database by calling the + * function 'lookup', passing it a printable zone name 'zone', a printable + * domain name 'name', and a copy of the argument 'dbdata' that + * was potentially returned by the create function. The 'dns_sdblookup_t' + * argument to 'lookup' and 'authority' is an opaque pointer to be passed to + * ns_sdb_putrr(). + * + * The lookup function returns the lookup results to the name server + * by calling ns_sdb_putrr() once for each record found. On success, + * the return value of the lookup function should be ISC_R_SUCCESS. + * If the domain name 'name' does not exist, the lookup function should + * ISC_R_NOTFOUND. Any other return value is treated as an error. + * + * Lookups at the zone apex will cause the server to also call the + * function 'authority' (if non-NULL), which must provide an SOA record + * and NS records for the zone by calling ns_sdb_putrr() once for each of + * these records. The 'authority' function may be NULL if invoking + * the 'lookup' function on the zone apex will return SOA and NS records. + * + * The allnodes function, if non-NULL, fills in an opaque structure to be + * used by a database iterator. This allows the zone to be transferred. + * This may use a considerable amount of memory for large zones, and the + * zone transfer may not be fully RFC1035 compliant if the zone is + * frequently changed. + * + * The create function will be called for each zone configured + * into the name server using this database type. It can be used + * to create a "database object" containing zone specific data, + * which can make use of the database arguments specified in the + * name server configuration. + * + * The destroy function will be called to free the database object + * when its zone is destroyed. + * + * The create and destroy functions may be NULL. + * + * If flags includes DNS_SDBFLAG_RELATIVEOWNER, the lookup and authority + * functions will be called with relative names rather than absolute names. + * The string "@" represents the zone apex in this case. + * + * If flags includes DNS_SDBFLAG_RELATIVERDATA, the rdata strings may + * include relative names. Otherwise, all names in the rdata string must + * be absolute. Be aware that if relative names are allowed, any + * absolute names must contain a trailing dot. + * + * If flags includes DNS_SDBFLAG_THREADSAFE, the driver must be able to + * handle multiple lookups in parallel. Otherwise, calls into the driver + * are serialized. + */ + +void +dns_sdb_unregister(dns_sdbimplementation_t **sdbimp); +/*%< + * Removes the simple database driver from the list of registered database + * types. There must be no active databases of this type when this function + * is called. + */ + +/*% See dns_sdb_putradata() */ +isc_result_t +dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl, + const char *data); +isc_result_t +dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t type, dns_ttl_t ttl, + const unsigned char *rdata, unsigned int rdlen); +/*%< + * Add a single resource record to the lookup structure to be + * returned in the query response. dns_sdb_putrr() takes the + * resource record in master file text format as a null-terminated + * string, and dns_sdb_putrdata() takes the raw RDATA in + * uncompressed wire format. + */ + +/*% See dns_sdb_putnamerdata() */ +isc_result_t +dns_sdb_putnamedrr(dns_sdballnodes_t *allnodes, const char *name, + const char *type, dns_ttl_t ttl, const char *data); +isc_result_t +dns_sdb_putnamedrdata(dns_sdballnodes_t *allnodes, const char *name, + dns_rdatatype_t type, dns_ttl_t ttl, const void *rdata, + unsigned int rdlen); +/*%< + * Add a single resource record to the allnodes structure to be + * included in a zone transfer response, in text or wire + * format as above. + */ + +isc_result_t +dns_sdb_putsoa(dns_sdblookup_t *lookup, const char *mname, const char *rname, + uint32_t serial); +/*%< + * This function may optionally be called from the 'authority' callback + * to simplify construction of the SOA record for 'zone'. It will + * provide a SOA listing 'mname' as as the master server and 'rname' as + * the responsible person mailbox. It is the responsibility of the + * driver to increment the serial number between responses if necessary. + * All other SOA fields will have reasonable default values. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_SDB_H */ diff --git a/lib/dns/include/dns/sdlz.h b/lib/dns/include/dns/sdlz.h new file mode 100644 index 0000000..6a06c98 --- /dev/null +++ b/lib/dns/include/dns/sdlz.h @@ -0,0 +1,359 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 AND ISC + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/* + * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE + * USE OR PERFORMANCE OF THIS SOFTWARE. + * + * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was + * conceived and contributed by Rob Butler. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE + * USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/*! \file dns/sdlz.h */ + +#ifndef SDLZ_H +#define SDLZ_H 1 + +#include <inttypes.h> +#include <stdbool.h> + +#include <dns/clientinfo.h> +#include <dns/dlz.h> + +ISC_LANG_BEGINDECLS + +#define DNS_SDLZFLAG_THREADSAFE 0x00000001U +#define DNS_SDLZFLAG_RELATIVEOWNER 0x00000002U +#define DNS_SDLZFLAG_RELATIVERDATA 0x00000004U + +/* A simple DLZ database. */ +typedef struct dns_sdlz_db dns_sdlz_db_t; + +/* A simple DLZ database lookup in progress. */ +typedef struct dns_sdlzlookup dns_sdlzlookup_t; + +/* A simple DLZ database traversal in progress. */ +typedef struct dns_sdlzallnodes dns_sdlzallnodes_t; + +typedef isc_result_t (*dns_sdlzallnodesfunc_t)(const char *zone, + void *driverarg, void *dbdata, + dns_sdlzallnodes_t *allnodes); +/*%< + * Method prototype. Drivers implementing the SDLZ interface may + * supply an all nodes method. This method is called when the DNS + * server is performing a zone transfer query, after the allow zone + * transfer method has been called. This method is only called if the + * allow zone transfer method returned ISC_R_SUCCESS. This method and + * the allow zone transfer method are both required for zone transfers + * to be supported. If the driver generates data dynamically (instead + * of searching in a database for it) it should not implement this + * function as a zone transfer would be meaningless. A SDLZ driver + * does not have to implement an all nodes method. + */ + +typedef isc_result_t (*dns_sdlzallowzonexfr_t)(void *driverarg, void *dbdata, + const char *name, + const char *client); + +/*%< + * Method prototype. Drivers implementing the SDLZ interface may + * supply an allow zone transfer method. This method is called when + * the DNS server is performing a zone transfer query, before the all + * nodes method can be called. This method and the all node method + * are both required for zone transfers to be supported. If the + * driver generates data dynamically (instead of searching in a + * database for it) it should not implement this function as a zone + * transfer would be meaningless. A SDLZ driver does not have to + * implement an allow zone transfer method. + * + * This method should return ISC_R_SUCCESS if the zone is supported by + * the database and a zone transfer is allowed for the specified + * client. If the zone is supported by the database, but zone + * transfers are not allowed for the specified client this method + * should return ISC_R_NOPERM.. Lastly the method should return + * ISC_R_NOTFOUND if the zone is not supported by the database. If an + * error occurs it should return a result code indicating the type of + * error. + */ + +typedef isc_result_t (*dns_sdlzauthorityfunc_t)(const char *zone, + void *driverarg, void *dbdata, + dns_sdlzlookup_t *lookup); + +/*%< + * Method prototype. Drivers implementing the SDLZ interface may + * supply an authority method. This method is called when the DNS + * server is performing a query, after both the find zone and lookup + * methods have been called. This method is required if the lookup + * function does not supply authority information for the dns + * record. A SDLZ driver does not have to implement an authority + * method. + */ + +typedef isc_result_t (*dns_sdlzcreate_t)(const char *dlzname, unsigned int argc, + char *argv[], void *driverarg, + void **dbdata); + +/*%< + * Method prototype. Drivers implementing the SDLZ interface may + * supply a create method. This method is called when the DNS server + * is starting up and creating drivers for use later. A SDLZ driver + * does not have to implement a create method. + */ + +typedef void (*dns_sdlzdestroy_t)(void *driverarg, void *dbdata); + +/*%< + * Method prototype. Drivers implementing the SDLZ interface may + * supply a destroy method. This method is called when the DNS server + * is shutting down and no longer needs the driver. A SDLZ driver does + * not have to implement a destroy method. + */ + +typedef isc_result_t (*dns_sdlzfindzone_t)(void *driverarg, void *dbdata, + const char *name, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo); +/*%< + * Method prototype. Drivers implementing the SDLZ interface MUST + * supply a find zone method. This method is called when the DNS + * server is performing a query to to determine if 'name' is a + * supported dns zone. The find zone method will be called with the + * longest possible name first, and continue to be called with + * successively shorter domain names, until any of the following + * occur: + * + * \li 1) the function returns (ISC_R_SUCCESS) indicating a zone name + * match. + * + * \li 2) a problem occurs, and the functions returns anything other than + * (ISC_R_NOTFOUND) + * + * \li 3) we run out of domain name labels. I.E. we have tried the + * shortest domain name + * + * \li 4) the number of labels in the domain name is less than min_labels + * for dns_dlzfindzone + * + * The driver's find zone method should return ISC_R_SUCCESS if the + * zone is supported by the database. Otherwise it should return + * ISC_R_NOTFOUND, if the zone is not supported. If an error occurs + * it should return a result code indicating the type of error. + */ + +typedef isc_result_t (*dns_sdlzlookupfunc_t)(const char *zone, const char *name, + void *driverarg, void *dbdata, + dns_sdlzlookup_t *lookup, + dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo); + +/*%< + * Method prototype. Drivers implementing the SDLZ interface MUST + * supply a lookup method. This method is called when the + * DNS server is performing a query, after the find zone and before any + * other methods have been called. This function returns DNS record + * information using the dns_sdlz_putrr and dns_sdlz_putsoa functions. + * If this function supplies authority information for the DNS record + * the authority method is not required. If it does not, the + * authority function is required. + * + * The 'methods' and 'clientinfo' args allow an SDLZ driver to retrieve + * information about the querying client (such as source IP address) + * from the caller. + */ + +typedef isc_result_t (*dns_sdlznewversion_t)(const char *zone, void *driverarg, + void *dbdata, void **versionp); +/*%< + * Method prototype. Drivers implementing the SDLZ interface may + * supply a newversion method. This method is called to start a + * write transaction on a zone and should only be implemented by + * writeable backends. + * When implemented, the driver should create a new transaction, and + * fill *versionp with a pointer to the transaction state. The + * closeversion function will be called to close the transaction. + */ + +typedef void (*dns_sdlzcloseversion_t)(const char *zone, bool commit, + void *driverarg, void *dbdata, + void **versionp); +/*%< + * Method prototype. Drivers implementing the SDLZ interface must + * supply a closeversion method if they supply a newversion method. + * When implemented, the driver should close the given transaction, + * committing changes if 'commit' is true. If 'commit' is not true + * then all changes should be discarded and the database rolled back. + * If the call is successful then *versionp should be set to NULL + */ + +typedef isc_result_t (*dns_sdlzconfigure_t)(dns_view_t *view, + dns_dlzdb_t *dlzdb, void *driverarg, + void *dbdata); +/*%< + * Method prototype. Drivers implementing the SDLZ interface may + * supply a configure method. When supplied, it will be called + * immediately after the create method to give the driver a chance + * to configure writeable zones + */ + +typedef bool (*dns_sdlzssumatch_t)(const char *signer, const char *name, + const char *tcpaddr, const char *type, + const char *key, uint32_t keydatalen, + unsigned char *keydata, void *driverarg, + void *dbdata); + +/*%< + * Method prototype. Drivers implementing the SDLZ interface may + * supply a ssumatch method. If supplied, then ssumatch will be + * called to authorize any zone updates. The driver should return + * true to allow the update, and false to deny it. For a DLZ + * controlled zone, this is the only access control on updates. + */ + +typedef isc_result_t (*dns_sdlzmodrdataset_t)(const char *name, + const char *rdatastr, + void *driverarg, void *dbdata, + void *version); +/*%< + * Method prototype. Drivers implementing the SDLZ interface may + * supply addrdataset and subtractrdataset methods. If supplied, then these + * will be called when rdatasets are added/subtracted during + * updates. The version parameter comes from a call to the sdlz + * newversion() method from the driver. The rdataset parameter is a + * linearise string representation of the rdataset change. The format + * is the same as used by dig when displaying records. The fields are + * tab delimited. + */ + +typedef isc_result_t (*dns_sdlzdelrdataset_t)(const char *name, + const char *type, void *driverarg, + void *dbdata, void *version); +/*%< + * Method prototype. Drivers implementing the SDLZ interface may + * supply a delrdataset method. If supplied, then this + * function will be called when rdatasets are deleted during + * updates. The call should remove all rdatasets of the given type for + * the specified name. + */ + +typedef struct dns_sdlzmethods { + dns_sdlzcreate_t create; + dns_sdlzdestroy_t destroy; + dns_sdlzfindzone_t findzone; + dns_sdlzlookupfunc_t lookup; + dns_sdlzauthorityfunc_t authority; + dns_sdlzallnodesfunc_t allnodes; + dns_sdlzallowzonexfr_t allowzonexfr; + dns_sdlznewversion_t newversion; + dns_sdlzcloseversion_t closeversion; + dns_sdlzconfigure_t configure; + dns_sdlzssumatch_t ssumatch; + dns_sdlzmodrdataset_t addrdataset; + dns_sdlzmodrdataset_t subtractrdataset; + dns_sdlzdelrdataset_t delrdataset; +} dns_sdlzmethods_t; + +isc_result_t +dns_sdlzregister(const char *drivername, const dns_sdlzmethods_t *methods, + void *driverarg, unsigned int flags, isc_mem_t *mctx, + dns_sdlzimplementation_t **sdlzimp); +/*%< + * Register a dynamically loadable zones (dlz) driver for the database + * type 'drivername', implemented by the functions in '*methods'. + * + * sdlzimp must point to a NULL dns_sdlzimplementation_t pointer. + * That is, sdlzimp != NULL && *sdlzimp == NULL. It will be assigned + * a value that will later be used to identify the driver when + * deregistering it. + */ + +void +dns_sdlzunregister(dns_sdlzimplementation_t **sdlzimp); + +/*%< + * Removes the sdlz driver from the list of registered sdlz drivers. + * There must be no active sdlz drivers of this type when this + * function is called. + */ + +typedef isc_result_t +dns_sdlz_putnamedrr_t(dns_sdlzallnodes_t *allnodes, const char *name, + const char *type, dns_ttl_t ttl, const char *data); +dns_sdlz_putnamedrr_t dns_sdlz_putnamedrr; + +/*%< + * Add a single resource record to the allnodes structure to be later + * parsed into a zone transfer response. + */ + +typedef isc_result_t +dns_sdlz_putrr_t(dns_sdlzlookup_t *lookup, const char *type, dns_ttl_t ttl, + const char *data); +dns_sdlz_putrr_t dns_sdlz_putrr; +/*%< + * Add a single resource record to the lookup structure to be later + * parsed into a query response. + */ + +typedef isc_result_t + dns_sdlz_putsoa_t(dns_sdlzlookup_t *lookup, const char *mname, + const char *rname, uint32_t serial); +dns_sdlz_putsoa_t dns_sdlz_putsoa; +/*%< + * This function may optionally be called from the 'authority' + * callback to simplify construction of the SOA record for 'zone'. It + * will provide a SOA listing 'mname' as as the master server and + * 'rname' as the responsible person mailbox. It is the + * responsibility of the driver to increment the serial number between + * responses if necessary. All other SOA fields will have reasonable + * default values. + */ + +typedef isc_result_t +dns_sdlz_setdb_t(dns_dlzdb_t *dlzdatabase, dns_rdataclass_t rdclass, + const dns_name_t *name, dns_db_t **dbp); +dns_sdlz_setdb_t dns_sdlz_setdb; +/*%< + * Create the database pointers for a writeable SDLZ zone + */ + +ISC_LANG_ENDDECLS + +#endif /* SDLZ_H */ diff --git a/lib/dns/include/dns/secalg.h b/lib/dns/include/dns/secalg.h new file mode 100644 index 0000000..6ca61cb --- /dev/null +++ b/lib/dns/include/dns/secalg.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. + */ + +#ifndef DNS_SECALG_H +#define DNS_SECALG_H 1 + +/*! \file dns/secalg.h */ + +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_secalg_fromtext(dns_secalg_t *secalgp, isc_textregion_t *source); +/*%< + * Convert the text 'source' refers to into a DNSSEC security algorithm value. + * The text may contain either a mnemonic algorithm name or a decimal algorithm + * number. + * + * Requires: + *\li 'secalgp' is a valid pointer. + * + *\li 'source' is a valid text region. + * + * Returns: + *\li ISC_R_SUCCESS on success + *\li ISC_R_RANGE numeric type is out of range + *\li DNS_R_UNKNOWN mnemonic type is unknown + */ + +isc_result_t +dns_secalg_totext(dns_secalg_t secalg, isc_buffer_t *target); +/*%< + * Put a textual representation of the DNSSEC security algorithm 'secalg' + * into 'target'. + * + * Requires: + *\li 'secalg' is a valid secalg. + * + *\li 'target' is a valid text buffer. + * + * Ensures, + * if the result is success: + *\li The used space in 'target' is updated. + * + * Returns: + *\li ISC_R_SUCCESS on success + *\li ISC_R_NOSPACE target buffer is too small + */ + +#define DNS_SECALG_FORMATSIZE 20 +void +dns_secalg_format(dns_secalg_t alg, char *cp, unsigned int size); +/*%< + * Wrapper for dns_secalg_totext(), writing text into 'cp' + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_SECALG_H */ diff --git a/lib/dns/include/dns/secproto.h b/lib/dns/include/dns/secproto.h new file mode 100644 index 0000000..7eccfab --- /dev/null +++ b/lib/dns/include/dns/secproto.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#ifndef DNS_SECPROTO_H +#define DNS_SECPROTO_H 1 + +/*! \file dns/secproto.h */ + +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_secproto_fromtext(dns_secproto_t *secprotop, isc_textregion_t *source); +/*%< + * Convert the text 'source' refers to into a DNSSEC security protocol value. + * The text may contain either a mnemonic protocol name or a decimal protocol + * number. + * + * Requires: + *\li 'secprotop' is a valid pointer. + * + *\li 'source' is a valid text region. + * + * Returns: + *\li ISC_R_SUCCESS on success + *\li ISC_R_RANGE numeric type is out of range + *\li DNS_R_UNKNOWN mnemonic type is unknown + */ + +isc_result_t +dns_secproto_totext(dns_secproto_t secproto, isc_buffer_t *target); +/*%< + * Put a textual representation of the DNSSEC security protocol 'secproto' + * into 'target'. + * + * Requires: + *\li 'secproto' is a valid secproto. + * + *\li 'target' is a valid text buffer. + * + * Ensures, + * if the result is success: + * \li The used space in 'target' is updated. + * + * Returns: + *\li ISC_R_SUCCESS on success + *\li ISC_R_NOSPACE target buffer is too small + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_SECPROTO_H */ diff --git a/lib/dns/include/dns/soa.h b/lib/dns/include/dns/soa.h new file mode 100644 index 0000000..a80a132 --- /dev/null +++ b/lib/dns/include/dns/soa.h @@ -0,0 +1,96 @@ +/* + * 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. + */ + +#ifndef DNS_SOA_H +#define DNS_SOA_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/soa.h + * \brief + * SOA utilities. + */ + +/*** + *** Imports + ***/ + +#include <inttypes.h> + +#include <isc/lang.h> +#include <isc/types.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +#define DNS_SOA_BUFFERSIZE ((2 * DNS_NAME_MAXWIRE) + (4 * 5)) + +isc_result_t +dns_soa_buildrdata(const dns_name_t *origin, const dns_name_t *contact, + dns_rdataclass_t rdclass, uint32_t serial, uint32_t refresh, + uint32_t retry, uint32_t expire, uint32_t minimum, + unsigned char *buffer, dns_rdata_t *rdata); +/*%< + * Build the rdata of an SOA record. + * + * Requires: + *\li buffer Points to a temporary buffer of at least + * DNS_SOA_BUFFERSIZE bytes. + *\li rdata Points to an initialized dns_rdata_t. + * + * Ensures: + * \li *rdata Contains a valid SOA rdata. The 'data' member + * refers to 'buffer'. + */ + +uint32_t +dns_soa_getserial(dns_rdata_t *rdata); +uint32_t +dns_soa_getrefresh(dns_rdata_t *rdata); +uint32_t +dns_soa_getretry(dns_rdata_t *rdata); +uint32_t +dns_soa_getexpire(dns_rdata_t *rdata); +uint32_t +dns_soa_getminimum(dns_rdata_t *rdata); +/* + * Extract an integer field from the rdata of a SOA record. + * + * Requires: + * rdata refers to the rdata of a well-formed SOA record. + */ + +void +dns_soa_setserial(uint32_t val, dns_rdata_t *rdata); +void +dns_soa_setrefresh(uint32_t val, dns_rdata_t *rdata); +void +dns_soa_setretry(uint32_t val, dns_rdata_t *rdata); +void +dns_soa_setexpire(uint32_t val, dns_rdata_t *rdata); +void +dns_soa_setminimum(uint32_t val, dns_rdata_t *rdata); +/* + * Change an integer field of a SOA record by modifying the + * rdata in-place. + * + * Requires: + * rdata refers to the rdata of a well-formed SOA record. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_SOA_H */ diff --git a/lib/dns/include/dns/ssu.h b/lib/dns/include/dns/ssu.h new file mode 100644 index 0000000..11d40f3 --- /dev/null +++ b/lib/dns/include/dns/ssu.h @@ -0,0 +1,243 @@ +/* + * 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. + */ + +#ifndef DNS_SSU_H +#define DNS_SSU_H 1 + +/*! \file dns/ssu.h */ + +#include <stdbool.h> + +#include <isc/lang.h> + +#include <dns/acl.h> +#include <dns/types.h> + +#include <dst/dst.h> + +ISC_LANG_BEGINDECLS + +typedef enum { + dns_ssumatchtype_name = 0, + dns_ssumatchtype_subdomain = 1, + dns_ssumatchtype_wildcard = 2, + dns_ssumatchtype_self = 3, + dns_ssumatchtype_selfsub = 4, + dns_ssumatchtype_selfwild = 5, + dns_ssumatchtype_selfkrb5 = 6, + dns_ssumatchtype_selfms = 7, + dns_ssumatchtype_subdomainms = 8, + dns_ssumatchtype_subdomainkrb5 = 9, + dns_ssumatchtype_tcpself = 10, + dns_ssumatchtype_6to4self = 11, + dns_ssumatchtype_external = 12, + dns_ssumatchtype_local = 13, + dns_ssumatchtype_selfsubms = 14, + dns_ssumatchtype_selfsubkrb5 = 15, + dns_ssumatchtype_max = 15, /* max value */ + + dns_ssumatchtype_dlz = 16 /* intentionally higher than _max */ +} dns_ssumatchtype_t; + +isc_result_t +dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **table); +/*%< + * Creates a table that will be used to store simple-secure-update rules. + * Note: all locking must be provided by the client. + * + * Requires: + *\li 'mctx' is a valid memory context + *\li 'table' is not NULL, and '*table' is NULL + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOMEMORY + */ + +isc_result_t +dns_ssutable_createdlz(isc_mem_t *mctx, dns_ssutable_t **tablep, + dns_dlzdb_t *dlzdatabase); +/*%< + * Create an SSU table that contains a dlzdatabase pointer, and a + * single rule with matchtype dns_ssumatchtype_dlz. This type of SSU + * table is used by writeable DLZ drivers to offload authorization for + * updates to the driver. + */ + +void +dns_ssutable_attach(dns_ssutable_t *source, dns_ssutable_t **targetp); +/*%< + * Attach '*targetp' to 'source'. + * + * Requires: + *\li 'source' is a valid SSU table + *\li 'targetp' points to a NULL dns_ssutable_t *. + * + * Ensures: + *\li *targetp is attached to source. + */ + +void +dns_ssutable_detach(dns_ssutable_t **tablep); +/*%< + * Detach '*tablep' from its simple-secure-update rule table. + * + * Requires: + *\li 'tablep' points to a valid dns_ssutable_t + * + * Ensures: + *\li *tablep is NULL + *\li If '*tablep' is the last reference to the SSU table, all + * resources used by the table will be freed. + */ + +isc_result_t +dns_ssutable_addrule(dns_ssutable_t *table, bool grant, + const dns_name_t *identity, dns_ssumatchtype_t matchtype, + const dns_name_t *name, unsigned int ntypes, + dns_rdatatype_t *types); +/*%< + * Adds a new rule to a simple-secure-update rule table. The rule + * either grants or denies update privileges of an identity (or set of + * identities) to modify a name (or set of names) or certain types present + * at that name. + * + * Notes: + *\li If 'matchtype' is of SELF type, this rule only matches if the + * name to be updated matches the signing identity. + * + *\li If 'ntypes' is 0, this rule applies to all types except + * NS, SOA, RRSIG, and NSEC. + * + *\li If 'types' includes ANY, this rule applies to all types + * except NSEC. + * + * Requires: + *\li 'table' is a valid SSU table + *\li 'identity' is a valid absolute name + *\li 'matchtype' must be one of the defined constants. + *\li 'name' is a valid absolute name + *\li If 'ntypes' > 0, 'types' must not be NULL + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOMEMORY + */ + +bool +dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer, + const dns_name_t *name, const isc_netaddr_t *addr, + bool tcp, const dns_aclenv_t *env, dns_rdatatype_t type, + const dst_key_t *key); +/*%< + * Checks that the attempted update of (name, type) is allowed according + * to the rules specified in the simple-secure-update rule table. If + * no rules are matched, access is denied. + * + * Notes: + * In dns_ssutable_checkrules(), 'addr' should only be + * set if the request received via TCP. This provides a + * weak assurance that the request was not spoofed. + * 'addr' is to to validate dns_ssumatchtype_tcpself + * and dns_ssumatchtype_6to4self rules. + * + * In dns_ssutable_checkrules2(), 'addr' can also be passed for + * UDP requests and TCP is specified via the 'tcp' parameter. + * In addition to dns_ssumatchtype_tcpself and + * tcp_ssumatchtype_6to4self rules, the address + * also be used to check dns_ssumatchtype_local rules. + * If 'addr' is set then 'env' must also be set so that + * requests from non-localhost addresses can be rejected. + * + * For dns_ssumatchtype_tcpself the addresses are mapped to + * the standard reverse names under IN-ADDR.ARPA and IP6.ARPA. + * RFC 1035, Section 3.5, "IN-ADDR.ARPA domain" and RFC 3596, + * Section 2.5, "IP6.ARPA Domain". + * + * For dns_ssumatchtype_6to4self, IPv4 address are converted + * to a 6to4 prefix (48 bits) per the rules in RFC 3056. Only + * the top 48 bits of the IPv6 address are mapped to the reverse + * name. This is independent of whether the most significant 16 + * bits match 2002::/16, assigned for 6to4 prefixes, or not. + * + * Requires: + *\li 'table' is a valid SSU table + *\li 'signer' is NULL or a valid absolute name + *\li 'addr' is NULL or a valid network address. + *\li 'aclenv' is NULL or a valid ACL environment. + *\li 'name' is a valid absolute name + *\li if 'addr' is not NULL, 'env' is not NULL. + */ + +/*% Accessor functions to extract rule components */ +bool +dns_ssurule_isgrant(const dns_ssurule_t *rule); +/*% Accessor functions to extract rule components */ +dns_name_t * +dns_ssurule_identity(const dns_ssurule_t *rule); +/*% Accessor functions to extract rule components */ +unsigned int +dns_ssurule_matchtype(const dns_ssurule_t *rule); +/*% Accessor functions to extract rule components */ +dns_name_t * +dns_ssurule_name(const dns_ssurule_t *rule); +/*% Accessor functions to extract rule components */ +unsigned int +dns_ssurule_types(const dns_ssurule_t *rule, dns_rdatatype_t **types); + +isc_result_t +dns_ssutable_firstrule(const dns_ssutable_t *table, dns_ssurule_t **rule); +/*%< + * Initiates a rule iterator. There is no need to maintain any state. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMORE + */ + +isc_result_t +dns_ssutable_nextrule(dns_ssurule_t *rule, dns_ssurule_t **nextrule); +/*%< + * Returns the next rule in the table. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMORE + */ + +bool +dns_ssu_external_match(const dns_name_t *identity, const dns_name_t *signer, + const dns_name_t *name, const isc_netaddr_t *tcpaddr, + dns_rdatatype_t type, const dst_key_t *key, + isc_mem_t *mctx); +/*%< + * Check a policy rule via an external application + */ + +isc_result_t +dns_ssu_mtypefromstring(const char *str, dns_ssumatchtype_t *mtype); +/*%< + * Set 'mtype' from 'str' + * + * Requires: + *\li 'str' is not NULL. + *\li 'mtype' is not NULL, + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOTFOUND + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_SSU_H */ diff --git a/lib/dns/include/dns/stats.h b/lib/dns/include/dns/stats.h new file mode 100644 index 0000000..fd1697e --- /dev/null +++ b/lib/dns/include/dns/stats.h @@ -0,0 +1,826 @@ +/* + * 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. + */ + +#ifndef DNS_STATS_H +#define DNS_STATS_H 1 + +/*! \file dns/stats.h */ + +#include <inttypes.h> + +#include <dns/types.h> + +/*% + * Statistics counters. Used as isc_statscounter_t values. + */ +enum { + /*% + * Resolver statistics counters. + */ + dns_resstatscounter_queryv4 = 0, + dns_resstatscounter_queryv6 = 1, + dns_resstatscounter_responsev4 = 2, + dns_resstatscounter_responsev6 = 3, + dns_resstatscounter_nxdomain = 4, + dns_resstatscounter_servfail = 5, + dns_resstatscounter_formerr = 6, + dns_resstatscounter_othererror = 7, + dns_resstatscounter_edns0fail = 8, + dns_resstatscounter_mismatch = 9, + dns_resstatscounter_truncated = 10, + dns_resstatscounter_lame = 11, + dns_resstatscounter_retry = 12, + dns_resstatscounter_gluefetchv4 = 13, + dns_resstatscounter_gluefetchv6 = 14, + dns_resstatscounter_gluefetchv4fail = 15, + dns_resstatscounter_gluefetchv6fail = 16, + dns_resstatscounter_val = 17, + dns_resstatscounter_valsuccess = 18, + dns_resstatscounter_valnegsuccess = 19, + dns_resstatscounter_valfail = 20, + dns_resstatscounter_dispabort = 21, + dns_resstatscounter_dispsockfail = 22, + dns_resstatscounter_querytimeout = 23, + dns_resstatscounter_queryrtt0 = 24, + dns_resstatscounter_queryrtt1 = 25, + dns_resstatscounter_queryrtt2 = 26, + dns_resstatscounter_queryrtt3 = 27, + dns_resstatscounter_queryrtt4 = 28, + dns_resstatscounter_queryrtt5 = 29, + dns_resstatscounter_nfetch = 30, + dns_resstatscounter_disprequdp = 31, + dns_resstatscounter_dispreqtcp = 32, + dns_resstatscounter_buckets = 33, + dns_resstatscounter_refused = 34, + dns_resstatscounter_cookienew = 35, + dns_resstatscounter_cookieout = 36, + dns_resstatscounter_cookiein = 37, + dns_resstatscounter_cookieok = 38, + dns_resstatscounter_badvers = 39, + dns_resstatscounter_badcookie = 40, + dns_resstatscounter_zonequota = 41, + dns_resstatscounter_serverquota = 42, + dns_resstatscounter_nextitem = 43, + dns_resstatscounter_priming = 44, + dns_resstatscounter_max = 45, + + /* + * DNSSEC stats. + */ + dns_dnssecstats_asis = 0, + dns_dnssecstats_downcase = 1, + dns_dnssecstats_wildcard = 2, + dns_dnssecstats_fail = 3, + + dns_dnssecstats_max = 4, + + /*% + * Zone statistics counters. + */ + dns_zonestatscounter_notifyoutv4 = 0, + dns_zonestatscounter_notifyoutv6 = 1, + dns_zonestatscounter_notifyinv4 = 2, + dns_zonestatscounter_notifyinv6 = 3, + dns_zonestatscounter_notifyrej = 4, + dns_zonestatscounter_soaoutv4 = 5, + dns_zonestatscounter_soaoutv6 = 6, + dns_zonestatscounter_axfrreqv4 = 7, + dns_zonestatscounter_axfrreqv6 = 8, + dns_zonestatscounter_ixfrreqv4 = 9, + dns_zonestatscounter_ixfrreqv6 = 10, + dns_zonestatscounter_xfrsuccess = 11, + dns_zonestatscounter_xfrfail = 12, + + dns_zonestatscounter_max = 13, + + /* + * Adb statistics values. + */ + dns_adbstats_nentries = 0, + dns_adbstats_entriescnt = 1, + dns_adbstats_nnames = 2, + dns_adbstats_namescnt = 3, + + dns_adbstats_max = 4, + + /* + * Cache statistics values. + */ + dns_cachestatscounter_hits = 1, + dns_cachestatscounter_misses = 2, + dns_cachestatscounter_queryhits = 3, + dns_cachestatscounter_querymisses = 4, + dns_cachestatscounter_deletelru = 5, + dns_cachestatscounter_deletettl = 6, + + dns_cachestatscounter_max = 7, + + /*% + * Query statistics counters (obsolete). + */ + dns_statscounter_success = 0, /*%< Successful lookup */ + dns_statscounter_referral = 1, /*%< Referral result */ + dns_statscounter_nxrrset = 2, /*%< NXRRSET result */ + dns_statscounter_nxdomain = 3, /*%< NXDOMAIN result */ + dns_statscounter_recursion = 4, /*%< Recursion was used */ + dns_statscounter_failure = 5, /*%< Some other failure */ + dns_statscounter_duplicate = 6, /*%< Duplicate query */ + dns_statscounter_dropped = 7, /*%< Duplicate query (dropped) */ + + /*% + * DNSTAP statistics counters. + */ + dns_dnstapcounter_success = 0, + dns_dnstapcounter_drop = 1, + dns_dnstapcounter_max = 2, + + /* + * Glue cache statistics counters. + */ + dns_gluecachestatscounter_hits_present = 0, + dns_gluecachestatscounter_hits_absent = 1, + dns_gluecachestatscounter_inserts_present = 2, + dns_gluecachestatscounter_inserts_absent = 3, + + dns_gluecachestatscounter_max = 4, +}; + +/*% + * Traffic size statistics counters. Used as isc_statscounter_t values. + */ +enum { + dns_sizecounter_in_0 = 0, + dns_sizecounter_in_16 = 1, + dns_sizecounter_in_32 = 2, + dns_sizecounter_in_48 = 3, + dns_sizecounter_in_64 = 4, + dns_sizecounter_in_80 = 5, + dns_sizecounter_in_96 = 6, + dns_sizecounter_in_112 = 7, + dns_sizecounter_in_128 = 8, + dns_sizecounter_in_144 = 9, + dns_sizecounter_in_160 = 10, + dns_sizecounter_in_176 = 11, + dns_sizecounter_in_192 = 12, + dns_sizecounter_in_208 = 13, + dns_sizecounter_in_224 = 14, + dns_sizecounter_in_240 = 15, + dns_sizecounter_in_256 = 16, + dns_sizecounter_in_272 = 17, + dns_sizecounter_in_288 = 18, + + dns_sizecounter_in_max = 19, +}; + +enum { + dns_sizecounter_out_0 = 0, + dns_sizecounter_out_16 = 1, + dns_sizecounter_out_32 = 2, + dns_sizecounter_out_48 = 3, + dns_sizecounter_out_64 = 4, + dns_sizecounter_out_80 = 5, + dns_sizecounter_out_96 = 6, + dns_sizecounter_out_112 = 7, + dns_sizecounter_out_128 = 8, + dns_sizecounter_out_144 = 9, + dns_sizecounter_out_160 = 10, + dns_sizecounter_out_176 = 11, + dns_sizecounter_out_192 = 12, + dns_sizecounter_out_208 = 13, + dns_sizecounter_out_224 = 14, + dns_sizecounter_out_240 = 15, + dns_sizecounter_out_256 = 16, + dns_sizecounter_out_272 = 17, + dns_sizecounter_out_288 = 18, + dns_sizecounter_out_304 = 19, + dns_sizecounter_out_320 = 20, + dns_sizecounter_out_336 = 21, + dns_sizecounter_out_352 = 22, + dns_sizecounter_out_368 = 23, + dns_sizecounter_out_384 = 24, + dns_sizecounter_out_400 = 25, + dns_sizecounter_out_416 = 26, + dns_sizecounter_out_432 = 27, + dns_sizecounter_out_448 = 28, + dns_sizecounter_out_464 = 29, + dns_sizecounter_out_480 = 30, + dns_sizecounter_out_496 = 31, + dns_sizecounter_out_512 = 32, + dns_sizecounter_out_528 = 33, + dns_sizecounter_out_544 = 34, + dns_sizecounter_out_560 = 35, + dns_sizecounter_out_576 = 36, + dns_sizecounter_out_592 = 37, + dns_sizecounter_out_608 = 38, + dns_sizecounter_out_624 = 39, + dns_sizecounter_out_640 = 40, + dns_sizecounter_out_656 = 41, + dns_sizecounter_out_672 = 42, + dns_sizecounter_out_688 = 43, + dns_sizecounter_out_704 = 44, + dns_sizecounter_out_720 = 45, + dns_sizecounter_out_736 = 46, + dns_sizecounter_out_752 = 47, + dns_sizecounter_out_768 = 48, + dns_sizecounter_out_784 = 49, + dns_sizecounter_out_800 = 50, + dns_sizecounter_out_816 = 51, + dns_sizecounter_out_832 = 52, + dns_sizecounter_out_848 = 53, + dns_sizecounter_out_864 = 54, + dns_sizecounter_out_880 = 55, + dns_sizecounter_out_896 = 56, + dns_sizecounter_out_912 = 57, + dns_sizecounter_out_928 = 58, + dns_sizecounter_out_944 = 59, + dns_sizecounter_out_960 = 60, + dns_sizecounter_out_976 = 61, + dns_sizecounter_out_992 = 62, + dns_sizecounter_out_1008 = 63, + dns_sizecounter_out_1024 = 64, + dns_sizecounter_out_1040 = 65, + dns_sizecounter_out_1056 = 66, + dns_sizecounter_out_1072 = 67, + dns_sizecounter_out_1088 = 68, + dns_sizecounter_out_1104 = 69, + dns_sizecounter_out_1120 = 70, + dns_sizecounter_out_1136 = 71, + dns_sizecounter_out_1152 = 72, + dns_sizecounter_out_1168 = 73, + dns_sizecounter_out_1184 = 74, + dns_sizecounter_out_1200 = 75, + dns_sizecounter_out_1216 = 76, + dns_sizecounter_out_1232 = 77, + dns_sizecounter_out_1248 = 78, + dns_sizecounter_out_1264 = 79, + dns_sizecounter_out_1280 = 80, + dns_sizecounter_out_1296 = 81, + dns_sizecounter_out_1312 = 82, + dns_sizecounter_out_1328 = 83, + dns_sizecounter_out_1344 = 84, + dns_sizecounter_out_1360 = 85, + dns_sizecounter_out_1376 = 86, + dns_sizecounter_out_1392 = 87, + dns_sizecounter_out_1408 = 88, + dns_sizecounter_out_1424 = 89, + dns_sizecounter_out_1440 = 90, + dns_sizecounter_out_1456 = 91, + dns_sizecounter_out_1472 = 92, + dns_sizecounter_out_1488 = 93, + dns_sizecounter_out_1504 = 94, + dns_sizecounter_out_1520 = 95, + dns_sizecounter_out_1536 = 96, + dns_sizecounter_out_1552 = 97, + dns_sizecounter_out_1568 = 98, + dns_sizecounter_out_1584 = 99, + dns_sizecounter_out_1600 = 100, + dns_sizecounter_out_1616 = 101, + dns_sizecounter_out_1632 = 102, + dns_sizecounter_out_1648 = 103, + dns_sizecounter_out_1664 = 104, + dns_sizecounter_out_1680 = 105, + dns_sizecounter_out_1696 = 106, + dns_sizecounter_out_1712 = 107, + dns_sizecounter_out_1728 = 108, + dns_sizecounter_out_1744 = 109, + dns_sizecounter_out_1760 = 110, + dns_sizecounter_out_1776 = 111, + dns_sizecounter_out_1792 = 112, + dns_sizecounter_out_1808 = 113, + dns_sizecounter_out_1824 = 114, + dns_sizecounter_out_1840 = 115, + dns_sizecounter_out_1856 = 116, + dns_sizecounter_out_1872 = 117, + dns_sizecounter_out_1888 = 118, + dns_sizecounter_out_1904 = 119, + dns_sizecounter_out_1920 = 120, + dns_sizecounter_out_1936 = 121, + dns_sizecounter_out_1952 = 122, + dns_sizecounter_out_1968 = 123, + dns_sizecounter_out_1984 = 124, + dns_sizecounter_out_2000 = 125, + dns_sizecounter_out_2016 = 126, + dns_sizecounter_out_2032 = 127, + dns_sizecounter_out_2048 = 128, + dns_sizecounter_out_2064 = 129, + dns_sizecounter_out_2080 = 130, + dns_sizecounter_out_2096 = 131, + dns_sizecounter_out_2112 = 132, + dns_sizecounter_out_2128 = 133, + dns_sizecounter_out_2144 = 134, + dns_sizecounter_out_2160 = 135, + dns_sizecounter_out_2176 = 136, + dns_sizecounter_out_2192 = 137, + dns_sizecounter_out_2208 = 138, + dns_sizecounter_out_2224 = 139, + dns_sizecounter_out_2240 = 140, + dns_sizecounter_out_2256 = 141, + dns_sizecounter_out_2272 = 142, + dns_sizecounter_out_2288 = 143, + dns_sizecounter_out_2304 = 144, + dns_sizecounter_out_2320 = 145, + dns_sizecounter_out_2336 = 146, + dns_sizecounter_out_2352 = 147, + dns_sizecounter_out_2368 = 148, + dns_sizecounter_out_2384 = 149, + dns_sizecounter_out_2400 = 150, + dns_sizecounter_out_2416 = 151, + dns_sizecounter_out_2432 = 152, + dns_sizecounter_out_2448 = 153, + dns_sizecounter_out_2464 = 154, + dns_sizecounter_out_2480 = 155, + dns_sizecounter_out_2496 = 156, + dns_sizecounter_out_2512 = 157, + dns_sizecounter_out_2528 = 158, + dns_sizecounter_out_2544 = 159, + dns_sizecounter_out_2560 = 160, + dns_sizecounter_out_2576 = 161, + dns_sizecounter_out_2592 = 162, + dns_sizecounter_out_2608 = 163, + dns_sizecounter_out_2624 = 164, + dns_sizecounter_out_2640 = 165, + dns_sizecounter_out_2656 = 166, + dns_sizecounter_out_2672 = 167, + dns_sizecounter_out_2688 = 168, + dns_sizecounter_out_2704 = 169, + dns_sizecounter_out_2720 = 170, + dns_sizecounter_out_2736 = 171, + dns_sizecounter_out_2752 = 172, + dns_sizecounter_out_2768 = 173, + dns_sizecounter_out_2784 = 174, + dns_sizecounter_out_2800 = 175, + dns_sizecounter_out_2816 = 176, + dns_sizecounter_out_2832 = 177, + dns_sizecounter_out_2848 = 178, + dns_sizecounter_out_2864 = 179, + dns_sizecounter_out_2880 = 180, + dns_sizecounter_out_2896 = 181, + dns_sizecounter_out_2912 = 182, + dns_sizecounter_out_2928 = 183, + dns_sizecounter_out_2944 = 184, + dns_sizecounter_out_2960 = 185, + dns_sizecounter_out_2976 = 186, + dns_sizecounter_out_2992 = 187, + dns_sizecounter_out_3008 = 188, + dns_sizecounter_out_3024 = 189, + dns_sizecounter_out_3040 = 190, + dns_sizecounter_out_3056 = 191, + dns_sizecounter_out_3072 = 192, + dns_sizecounter_out_3088 = 193, + dns_sizecounter_out_3104 = 194, + dns_sizecounter_out_3120 = 195, + dns_sizecounter_out_3136 = 196, + dns_sizecounter_out_3152 = 197, + dns_sizecounter_out_3168 = 198, + dns_sizecounter_out_3184 = 199, + dns_sizecounter_out_3200 = 200, + dns_sizecounter_out_3216 = 201, + dns_sizecounter_out_3232 = 202, + dns_sizecounter_out_3248 = 203, + dns_sizecounter_out_3264 = 204, + dns_sizecounter_out_3280 = 205, + dns_sizecounter_out_3296 = 206, + dns_sizecounter_out_3312 = 207, + dns_sizecounter_out_3328 = 208, + dns_sizecounter_out_3344 = 209, + dns_sizecounter_out_3360 = 210, + dns_sizecounter_out_3376 = 211, + dns_sizecounter_out_3392 = 212, + dns_sizecounter_out_3408 = 213, + dns_sizecounter_out_3424 = 214, + dns_sizecounter_out_3440 = 215, + dns_sizecounter_out_3456 = 216, + dns_sizecounter_out_3472 = 217, + dns_sizecounter_out_3488 = 218, + dns_sizecounter_out_3504 = 219, + dns_sizecounter_out_3520 = 220, + dns_sizecounter_out_3536 = 221, + dns_sizecounter_out_3552 = 222, + dns_sizecounter_out_3568 = 223, + dns_sizecounter_out_3584 = 224, + dns_sizecounter_out_3600 = 225, + dns_sizecounter_out_3616 = 226, + dns_sizecounter_out_3632 = 227, + dns_sizecounter_out_3648 = 228, + dns_sizecounter_out_3664 = 229, + dns_sizecounter_out_3680 = 230, + dns_sizecounter_out_3696 = 231, + dns_sizecounter_out_3712 = 232, + dns_sizecounter_out_3728 = 233, + dns_sizecounter_out_3744 = 234, + dns_sizecounter_out_3760 = 235, + dns_sizecounter_out_3776 = 236, + dns_sizecounter_out_3792 = 237, + dns_sizecounter_out_3808 = 238, + dns_sizecounter_out_3824 = 239, + dns_sizecounter_out_3840 = 240, + dns_sizecounter_out_3856 = 241, + dns_sizecounter_out_3872 = 242, + dns_sizecounter_out_3888 = 243, + dns_sizecounter_out_3904 = 244, + dns_sizecounter_out_3920 = 245, + dns_sizecounter_out_3936 = 246, + dns_sizecounter_out_3952 = 247, + dns_sizecounter_out_3968 = 248, + dns_sizecounter_out_3984 = 249, + dns_sizecounter_out_4000 = 250, + dns_sizecounter_out_4016 = 251, + dns_sizecounter_out_4032 = 252, + dns_sizecounter_out_4048 = 253, + dns_sizecounter_out_4064 = 254, + dns_sizecounter_out_4080 = 255, + dns_sizecounter_out_4096 = 256, + + dns_sizecounter_out_max = 257 +}; + +#define DNS_STATS_NCOUNTERS 8 + +#if 0 +/*%< + * Flag(s) for dns_xxxstats_dump(). DNS_STATSDUMP_VERBOSE is obsolete. + * ISC_STATSDUMP_VERBOSE should be used instead. These two values are + * intentionally defined to be the same value to ensure binary compatibility. + */ +#define DNS_STATSDUMP_VERBOSE 0x00000001 /*%< dump 0-value counters */ +#endif /* if 0 */ + +/*%< + * (Obsoleted) + */ +LIBDNS_EXTERNAL_DATA extern const char *dns_statscounter_names[]; + +/*% + * Attributes for statistics counters of RRset and Rdatatype types. + * + * _OTHERTYPE + * The rdata type is not explicitly supported and the corresponding counter + * is counted for other such types, too. When this attribute is set, + * the base type is of no use. + * + * _NXRRSET + * RRset type counters only. Indicates the RRset is non existent. + * + * _NXDOMAIN + * RRset type counters only. Indicates a non existent name. When this + * attribute is set, the base type is of no use. + * + * _STALE + * RRset type counters only. This indicates a record that is stale + * but may still be served. + * + * _ANCIENT + * RRset type counters only. This indicates a record that is marked for + * removal. + */ +#define DNS_RDATASTATSTYPE_ATTR_OTHERTYPE 0x0001 +#define DNS_RDATASTATSTYPE_ATTR_NXRRSET 0x0002 +#define DNS_RDATASTATSTYPE_ATTR_NXDOMAIN 0x0004 +#define DNS_RDATASTATSTYPE_ATTR_STALE 0x0008 +#define DNS_RDATASTATSTYPE_ATTR_ANCIENT 0x0010 + +/*%< + * Conversion macros among dns_rdatatype_t, attributes and isc_statscounter_t. + */ +#define DNS_RDATASTATSTYPE_BASE(type) ((dns_rdatatype_t)((type)&0xFFFF)) +#define DNS_RDATASTATSTYPE_ATTR(type) ((type) >> 16) +#define DNS_RDATASTATSTYPE_VALUE(b, a) (((a) << 16) | (b)) + +/*% + * Types of DNSSEC sign statistics operations. + */ +typedef enum { + dns_dnssecsignstats_sign = 1, + dns_dnssecsignstats_refresh = 2 +} dnssecsignstats_type_t; + +/*%< + * Types of dump callbacks. + */ +typedef void (*dns_generalstats_dumper_t)(isc_statscounter_t, uint64_t, void *); +typedef void (*dns_rdatatypestats_dumper_t)(dns_rdatastatstype_t, uint64_t, + void *); +typedef void (*dns_dnssecsignstats_dumper_t)(dns_keytag_t, uint64_t, void *); +typedef void (*dns_opcodestats_dumper_t)(dns_opcode_t, uint64_t, void *); +typedef void (*dns_rcodestats_dumper_t)(dns_rcode_t, uint64_t, void *); + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_generalstats_create(isc_mem_t *mctx, dns_stats_t **statsp, int ncounters); +/*%< + * Create a statistics counter structure of general type. It counts a general + * set of counters indexed by an ID between 0 and ncounters -1. + * This function is obsolete. A more general function, isc_stats_create(), + * should be used. + * + * Requires: + *\li 'mctx' must be a valid memory context. + * + *\li 'statsp' != NULL && '*statsp' == NULL. + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure + */ + +isc_result_t +dns_rdatatypestats_create(isc_mem_t *mctx, dns_stats_t **statsp); +/*%< + * Create a statistics counter structure per rdatatype. + * + * Requires: + *\li 'mctx' must be a valid memory context. + * + *\li 'statsp' != NULL && '*statsp' == NULL. + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure + */ + +isc_result_t +dns_rdatasetstats_create(isc_mem_t *mctx, dns_stats_t **statsp); +/*%< + * Create a statistics counter structure per RRset. + * + * Requires: + *\li 'mctx' must be a valid memory context. + * + *\li 'statsp' != NULL && '*statsp' == NULL. + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure + */ + +isc_result_t +dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp); +/*%< + * Create a statistics counter structure per opcode. + * + * Requires: + *\li 'mctx' must be a valid memory context. + * + *\li 'statsp' != NULL && '*statsp' == NULL. + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure + */ + +isc_result_t +dns_rcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp); +/*%< + * Create a statistics counter structure per assigned rcode. + * + * Requires: + *\li 'mctx' must be a valid memory context. + * + *\li 'statsp' != NULL && '*statsp' == NULL. + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure + */ + +isc_result_t +dns_dnssecsignstats_create(isc_mem_t *mctx, dns_stats_t **statsp); +/*%< + * Create a statistics counter structure per assigned DNSKEY id. + * + * Requires: + *\li 'mctx' must be a valid memory context. + * + *\li 'statsp' != NULL && '*statsp' == NULL. + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure + */ + +void +dns_stats_attach(dns_stats_t *stats, dns_stats_t **statsp); +/*%< + * Attach to a statistics set. + * + * Requires: + *\li 'stats' is a valid dns_stats_t. + * + *\li 'statsp' != NULL && '*statsp' == NULL + */ + +void +dns_stats_detach(dns_stats_t **statsp); +/*%< + * Detaches from the statistics set. + * + * Requires: + *\li 'statsp' != NULL and '*statsp' is a valid dns_stats_t. + */ + +void +dns_generalstats_increment(dns_stats_t *stats, isc_statscounter_t counter); +/*%< + * Increment the counter-th counter of stats. This function is obsolete. + * A more general function, isc_stats_increment(), should be used. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + * + *\li counter is less than the maximum available ID for the stats specified + * on creation. + */ + +void +dns_rdatatypestats_increment(dns_stats_t *stats, dns_rdatatype_t type); +/*%< + * Increment the statistics counter for 'type'. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_rdatatypestats_create(). + */ + +void +dns_rdatasetstats_increment(dns_stats_t *stats, dns_rdatastatstype_t rrsettype); +/*%< + * Increment the statistics counter for 'rrsettype'. + * + * Note: if 'rrsettype' has the _STALE attribute set the corresponding + * non-stale counter will be decremented. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_rdatasetstats_create(). + */ + +void +dns_rdatasetstats_decrement(dns_stats_t *stats, dns_rdatastatstype_t rrsettype); +/*%< + * Decrement the statistics counter for 'rrsettype'. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_rdatasetstats_create(). + */ + +void +dns_opcodestats_increment(dns_stats_t *stats, dns_opcode_t code); +/*%< + * Increment the statistics counter for 'code'. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_opcodestats_create(). + */ + +void +dns_rcodestats_increment(dns_stats_t *stats, dns_opcode_t code); +/*%< + * Increment the statistics counter for 'code'. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_rcodestats_create(). + */ + +void +dns_dnssecsignstats_increment(dns_stats_t *stats, dns_keytag_t id, uint8_t alg, + dnssecsignstats_type_t operation); +/*%< + * Increment the statistics counter for the DNSKEY 'id' with algorithm 'alg'. + * The 'operation' determines what counter is incremented. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_dnssecsignstats_create(). + */ + +void +dns_dnssecsignstats_clear(dns_stats_t *stats, dns_keytag_t id, uint8_t alg); +/*%< + * Clear the statistics counter for the DNSKEY 'id' with algorithm 'alg'. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_dnssecsignstats_create(). + */ + +void +dns_generalstats_dump(dns_stats_t *stats, dns_generalstats_dumper_t dump_fn, + void *arg, unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with its current value and the given argument + * arg. By default counters that have a value of 0 is skipped; if options has + * the ISC_STATSDUMP_VERBOSE flag, even such counters are dumped. + * + * This function is obsolete. A more general function, isc_stats_dump(), + * should be used. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + */ + +void +dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, + void *arg, unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with the corresponding type in the form of + * dns_rdatastatstype_t, the current counter value and the given argument + * arg. By default counters that have a value of 0 is skipped; if options has + * the ISC_STATSDUMP_VERBOSE flag, even such counters are dumped. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + */ + +void +dns_rdatasetstats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, + void *arg, unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with the corresponding type in the form of + * dns_rdatastatstype_t, the current counter value and the given argument + * arg. By default counters that have a value of 0 is skipped; if options has + * the ISC_STATSDUMP_VERBOSE flag, even such counters are dumped. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + */ + +void +dns_dnssecsignstats_dump(dns_stats_t *stats, dnssecsignstats_type_t operation, + dns_dnssecsignstats_dumper_t dump_fn, void *arg, + unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with the corresponding type in the form of + * dns_rdatastatstype_t, the current counter value and the given argument + * arg. By default counters that have a value of 0 is skipped; if options has + * the ISC_STATSDUMP_VERBOSE flag, even such counters are dumped. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + */ + +void +dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn, + void *arg, unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with the corresponding opcode, the current + * counter value and the given argument arg. By default counters that have a + * value of 0 is skipped; if options has the ISC_STATSDUMP_VERBOSE flag, even + * such counters are dumped. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + */ + +void +dns_rcodestats_dump(dns_stats_t *stats, dns_rcodestats_dumper_t dump_fn, + void *arg, unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with the corresponding rcode, the current + * counter value and the given argument arg. By default counters that have a + * value of 0 is skipped; if options has the ISC_STATSDUMP_VERBOSE flag, even + * such counters are dumped. + * + * Requires: + *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + */ + +isc_result_t +dns_stats_alloccounters(isc_mem_t *mctx, uint64_t **ctrp); +/*%< + * Allocate an array of query statistics counters from the memory + * context 'mctx'. + * + * This function is obsoleted. Use dns_xxxstats_create() instead. + */ + +void +dns_stats_freecounters(isc_mem_t *mctx, uint64_t **ctrp); +/*%< + * Free an array of query statistics counters allocated from the memory + * context 'mctx'. + * + * This function is obsoleted. Use dns_stats_destroy() instead. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_STATS_H */ diff --git a/lib/dns/include/dns/tcpmsg.h b/lib/dns/include/dns/tcpmsg.h new file mode 100644 index 0000000..df98cd7 --- /dev/null +++ b/lib/dns/include/dns/tcpmsg.h @@ -0,0 +1,143 @@ +/* + * 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. + */ + +#ifndef DNS_TCPMSG_H +#define DNS_TCPMSG_H 1 + +/*! \file dns/tcpmsg.h */ + +#include <inttypes.h> + +#include <isc/buffer.h> +#include <isc/lang.h> +#include <isc/socket.h> + +typedef struct dns_tcpmsg { + /* private (don't touch!) */ + unsigned int magic; + uint16_t size; + isc_buffer_t buffer; + unsigned int maxsize; + isc_mem_t *mctx; + isc_socket_t *sock; + isc_task_t *task; + isc_taskaction_t action; + void *arg; + isc_event_t event; + /* public (read-only) */ + isc_result_t result; + isc_sockaddr_t address; +} dns_tcpmsg_t; + +ISC_LANG_BEGINDECLS + +void +dns_tcpmsg_init(isc_mem_t *mctx, isc_socket_t *sock, dns_tcpmsg_t *tcpmsg); +/*%< + * Associate a tcp message state with a given memory context and + * TCP socket. + * + * Requires: + * + *\li "mctx" and "sock" be non-NULL and valid types. + * + *\li "sock" be a read/write TCP socket. + * + *\li "tcpmsg" be non-NULL and an uninitialized or invalidated structure. + * + * Ensures: + * + *\li "tcpmsg" is a valid structure. + */ + +void +dns_tcpmsg_setmaxsize(dns_tcpmsg_t *tcpmsg, unsigned int maxsize); +/*%< + * Set the maximum packet size to "maxsize" + * + * Requires: + * + *\li "tcpmsg" be valid. + * + *\li 512 <= "maxsize" <= 65536 + */ + +isc_result_t +dns_tcpmsg_readmessage(dns_tcpmsg_t *tcpmsg, isc_task_t *task, + isc_taskaction_t action, void *arg); +/*%< + * Schedule an event to be delivered when a DNS message is readable, or + * when an error occurs on the socket. + * + * Requires: + * + *\li "tcpmsg" be valid. + * + *\li "task", "taskaction", and "arg" be valid. + * + * Returns: + * + *\li ISC_R_SUCCESS -- no error + *\li Anything that the isc_socket_recv() call can return. XXXMLG + * + * Notes: + * + *\li The event delivered is a fully generic event. It will contain no + * actual data. The sender will be a pointer to the dns_tcpmsg_t. + * The result code inside that structure should be checked to see + * what the final result was. + */ + +void +dns_tcpmsg_cancelread(dns_tcpmsg_t *tcpmsg); +/*%< + * Cancel a readmessage() call. The event will still be posted with a + * CANCELED result code. + * + * Requires: + * + *\li "tcpmsg" be valid. + */ + +void +dns_tcpmsg_keepbuffer(dns_tcpmsg_t *tcpmsg, isc_buffer_t *buffer); +/*%< + * If a dns buffer is to be kept between calls, this function marks the + * internal state-machine buffer as invalid, and copies all the contents + * of the state into "buffer". + * + * Requires: + * + *\li "tcpmsg" be valid. + * + *\li "buffer" be non-NULL. + */ + +void +dns_tcpmsg_invalidate(dns_tcpmsg_t *tcpmsg); +/*%< + * Clean up all allocated state, and invalidate the structure. + * + * Requires: + * + *\li "tcpmsg" be valid. + * + * Ensures: + * + *\li "tcpmsg" is invalidated and disassociated with all memory contexts, + * sockets, etc. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_TCPMSG_H */ diff --git a/lib/dns/include/dns/time.h b/lib/dns/include/dns/time.h new file mode 100644 index 0000000..62e0fa0 --- /dev/null +++ b/lib/dns/include/dns/time.h @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#ifndef DNS_TIME_H +#define DNS_TIME_H 1 + +/*! \file dns/time.h */ + +/*** + *** Imports + ***/ + +#include <inttypes.h> + +#include <isc/buffer.h> +#include <isc/lang.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Functions + ***/ + +isc_result_t +dns_time64_fromtext(const char *source, int64_t *target); +/*%< + * Convert a date and time in YYYYMMDDHHMMSS text format at 'source' + * into to a 64-bit count of seconds since Jan 1 1970 0:00 GMT. + * Store the count at 'target'. + */ + +isc_result_t +dns_time32_fromtext(const char *source, uint32_t *target); +/*%< + * Like dns_time64_fromtext, but returns the second count modulo 2^32 + * as per RFC2535. + */ + +isc_result_t +dns_time64_totext(int64_t value, isc_buffer_t *target); +/*%< + * Convert a 64-bit count of seconds since Jan 1 1970 0:00 GMT into + * a YYYYMMDDHHMMSS text representation and append it to 'target'. + */ + +isc_result_t +dns_time32_totext(uint32_t value, isc_buffer_t *target); +/*%< + * Like dns_time64_totext, but for a 32-bit cyclic time value. + * Of those dates whose counts of seconds since Jan 1 1970 0:00 GMT + * are congruent with 'value' modulo 2^32, the one closest to the + * current date is chosen. + */ + +int64_t +dns_time64_from32(uint32_t value); +/*%< + * Covert a 32-bit cyclic time value into a 64 bit time stamp. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_TIME_H */ diff --git a/lib/dns/include/dns/timer.h b/lib/dns/include/dns/timer.h new file mode 100644 index 0000000..96fcd3b --- /dev/null +++ b/lib/dns/include/dns/timer.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#ifndef DNS_TIMER_H +#define DNS_TIMER_H 1 + +/*! \file dns/timer.h */ + +/*** + *** Imports + ***/ + +#include <stdbool.h> + +#include <isc/buffer.h> +#include <isc/lang.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Functions + ***/ + +isc_result_t +dns_timer_setidle(isc_timer_t *timer, unsigned int maxtime, + unsigned int idletime, bool purge); +/*%< + * Convenience function for setting up simple, one-second-granularity + * idle timers as used by zone transfers. + * \brief + * Set the timer 'timer' to go off after 'idletime' seconds of inactivity, + * or after 'maxtime' at the very latest. Events are purged iff + * 'purge' is true. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_TIMER_H */ diff --git a/lib/dns/include/dns/tkey.h b/lib/dns/include/dns/tkey.h new file mode 100644 index 0000000..23d95ae --- /dev/null +++ b/lib/dns/include/dns/tkey.h @@ -0,0 +1,246 @@ +/* + * 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. + */ + +#ifndef DNS_TKEY_H +#define DNS_TKEY_H 1 + +/*! \file dns/tkey.h */ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/lang.h> + +#include <dns/types.h> + +#include <dst/dst.h> +#include <dst/gssapi.h> + +ISC_LANG_BEGINDECLS + +/* Key agreement modes */ +#define DNS_TKEYMODE_SERVERASSIGNED 1 +#define DNS_TKEYMODE_DIFFIEHELLMAN 2 +#define DNS_TKEYMODE_GSSAPI 3 +#define DNS_TKEYMODE_RESOLVERASSIGNED 4 +#define DNS_TKEYMODE_DELETE 5 + +struct dns_tkeyctx { + dst_key_t *dhkey; + dns_name_t *domain; + dns_gss_cred_id_t gsscred; + isc_mem_t *mctx; + char *gssapi_keytab; +}; + +isc_result_t +dns_tkeyctx_create(isc_mem_t *mctx, dns_tkeyctx_t **tctxp); +/*%< + * Create an empty TKEY context. + * + * Requires: + *\li 'mctx' is not NULL + *\li 'tctx' is not NULL + *\li '*tctx' is NULL + * + * Returns + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li return codes from dns_name_fromtext() + */ + +void +dns_tkeyctx_destroy(dns_tkeyctx_t **tctxp); +/*%< + * Frees all data associated with the TKEY context + * + * Requires: + *\li 'tctx' is not NULL + *\li '*tctx' is not NULL + */ + +isc_result_t +dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx, + dns_tsig_keyring_t *ring); +/*%< + * Processes a query containing a TKEY record, adding or deleting TSIG + * keys if necessary, and modifies the message to contain the response. + * + * Requires: + *\li 'msg' is a valid message + *\li 'tctx' is a valid TKEY context + *\li 'ring' is a valid TSIG keyring + * + * Returns + *\li #ISC_R_SUCCESS msg was updated (the TKEY operation succeeded, + * or msg now includes a TKEY with an error set) + * DNS_R_FORMERR the packet was malformed (missing a TKEY + * or KEY). + *\li other An error occurred while processing the message + */ + +isc_result_t +dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, + const dns_name_t *name, const dns_name_t *algorithm, + isc_buffer_t *nonce, uint32_t lifetime); +/*%< + * Builds a query containing a TKEY that will generate a shared + * secret using a Diffie-Hellman key exchange. The shared key + * will be of the specified algorithm (only DNS_TSIG_HMACMD5_NAME + * is supported), and will be named either 'name', + * 'name' + server chosen domain, or random data + server chosen domain + * if 'name' == dns_rootname. If nonce is not NULL, it supplies + * random data used in the shared secret computation. The key is + * requested to have the specified lifetime (in seconds) + * + * + * Requires: + *\li 'msg' is a valid message + *\li 'key' is a valid Diffie Hellman dst key + *\li 'name' is a valid name + *\li 'algorithm' is a valid name + * + * Returns: + *\li #ISC_R_SUCCESS msg was successfully updated to include the + * query to be sent + *\li other an error occurred while building the message + */ + +isc_result_t +dns_tkey_buildgssquery(dns_message_t *msg, const dns_name_t *name, + const dns_name_t *gname, isc_buffer_t *intoken, + uint32_t lifetime, dns_gss_ctx_id_t *context, bool win2k, + isc_mem_t *mctx, char **err_message); +/*%< + * Builds a query containing a TKEY that will generate a GSSAPI context. + * The key is requested to have the specified lifetime (in seconds). + * + * Requires: + *\li 'msg' is a valid message + *\li 'name' is a valid name + *\li 'gname' is a valid name + *\li 'context' is a pointer to a valid gss_ctx_id_t + * (which may have the value GSS_C_NO_CONTEXT) + *\li 'win2k' when true says to turn on some hacks to work + * with the non-standard GSS-TSIG of Windows 2000 + * + * Returns: + *\li ISC_R_SUCCESS msg was successfully updated to include the + * query to be sent + *\li other an error occurred while building the message + *\li *err_message optional error message + */ + +isc_result_t +dns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key); +/*%< + * Builds a query containing a TKEY record that will delete the + * specified shared secret from the server. + * + * Requires: + *\li 'msg' is a valid message + *\li 'key' is a valid TSIG key + * + * Returns: + *\li #ISC_R_SUCCESS msg was successfully updated to include the + * query to be sent + *\li other an error occurred while building the message + */ + +isc_result_t +dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, + dst_key_t *key, isc_buffer_t *nonce, + dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring); +/*%< + * Processes a response to a query containing a TKEY that was + * designed to generate a shared secret using a Diffie-Hellman key + * exchange. If the query was successful, a new shared key + * is created and added to the list of shared keys. + * + * Requires: + *\li 'qmsg' is a valid message (the query) + *\li 'rmsg' is a valid message (the response) + *\li 'key' is a valid Diffie Hellman dst key + *\li 'outkey' is either NULL or a pointer to NULL + *\li 'ring' is a valid keyring or NULL + * + * Returns: + *\li #ISC_R_SUCCESS the shared key was successfully added + *\li #ISC_R_NOTFOUND an error occurred while looking for a + * component of the query or response + */ + +isc_result_t +dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, + const dns_name_t *gname, dns_gss_ctx_id_t *context, + isc_buffer_t *outtoken, dns_tsigkey_t **outkey, + dns_tsig_keyring_t *ring, char **err_message); +/*%< + * XXX + */ + +isc_result_t +dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg, + dns_tsig_keyring_t *ring); +/*%< + * Processes a response to a query containing a TKEY that was + * designed to delete a shared secret. If the query was successful, + * the shared key is deleted from the list of shared keys. + * + * Requires: + *\li 'qmsg' is a valid message (the query) + *\li 'rmsg' is a valid message (the response) + *\li 'ring' is not NULL + * + * Returns: + *\li #ISC_R_SUCCESS the shared key was successfully deleted + *\li #ISC_R_NOTFOUND an error occurred while looking for a + * component of the query or response + */ + +isc_result_t +dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, + const dns_name_t *server, dns_gss_ctx_id_t *context, + dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring, + bool win2k, char **err_message); + +/* + * Client side negotiation of GSS-TSIG. Process the response + * to a TKEY, and establish a TSIG key if negotiation was successful. + * Build a response to the input TKEY message. Can take multiple + * calls to successfully establish the context. + * + * Requires: + * 'qmsg' is a valid message, the original TKEY request; + * it will be filled with the new message to send + * 'rmsg' is a valid message, the incoming TKEY message + * 'server' is the server name + * 'context' is the input context handle + * 'outkey' receives the established key, if non-NULL; + * if non-NULL must point to NULL + * 'ring' is the keyring in which to establish the key, + * or NULL + * 'win2k' when true says to turn on some hacks to work + * with the non-standard GSS-TSIG of Windows 2000 + * + * Returns: + * ISC_R_SUCCESS context was successfully established + * ISC_R_NOTFOUND couldn't find a needed part of the query + * or response + * DNS_R_CONTINUE additional context negotiation is required; + * send the new qmsg to the server + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_TKEY_H */ diff --git a/lib/dns/include/dns/tsec.h b/lib/dns/include/dns/tsec.h new file mode 100644 index 0000000..5ea7b8a --- /dev/null +++ b/lib/dns/include/dns/tsec.h @@ -0,0 +1,132 @@ +/* + * 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. + */ + +#ifndef DNS_TSEC_H +#define DNS_TSEC_H 1 + +/***** +***** Module Info +*****/ + +/*! \file + * + * \brief + * The TSEC (Transaction Security) module is an abstraction layer for managing + * DNS transaction mechanisms such as TSIG or SIG(0). A TSEC structure is a + * mechanism-independent object containing key information specific to the + * mechanism, and is expected to be used as an argument to other modules + * that use transaction security in a mechanism-independent manner. + * + * MP: + *\li A TSEC structure is expected to be thread-specific. No inter-thread + * synchronization is ensured in multiple access to a single TSEC + * structure. + * + * Resources: + *\li TBS + * + * Security: + *\li This module does not handle any low-level data directly, and so no + * security issue specific to this module is anticipated. + */ + +#include <dns/types.h> + +#include <dst/dst.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Types + ***/ + +/*% + * Transaction security types. + */ +typedef enum { + dns_tsectype_none, + dns_tsectype_tsig, + dns_tsectype_sig0 +} dns_tsectype_t; + +isc_result_t +dns_tsec_create(isc_mem_t *mctx, dns_tsectype_t type, dst_key_t *key, + dns_tsec_t **tsecp); +/*%< + * Create a TSEC structure and stores a type-dependent key structure in it. + * For a TSIG key (type is dns_tsectype_tsig), dns_tsec_create() creates a + * TSIG key structure from '*key' and keeps it in the structure. For other + * types, this function simply retains '*key' in the structure. In either + * case, the ownership of '*key' is transferred to the TSEC module; the caller + * must not modify or destroy it after the call to dns_tsec_create(). + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li 'type' is a valid value of dns_tsectype_t (see above). + * + *\li 'key' is a valid key. + * + *\li tsecp != NULL && *tsecp == NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS On success. + * + *\li Anything else Failure. + */ + +void +dns_tsec_destroy(dns_tsec_t **tsecp); +/*%< + * Destroy the TSEC structure. The stored key is also detached or destroyed. + * + * Requires + * + *\li '*tsecp' is a valid TSEC structure. + * + * Ensures + * + *\li *tsecp == NULL. + * + */ + +dns_tsectype_t +dns_tsec_gettype(dns_tsec_t *tsec); +/*%< + * Return the TSEC type of '*tsec'. + * + * Requires + * + *\li 'tsec' is a valid TSEC structure. + * + */ + +void +dns_tsec_getkey(dns_tsec_t *tsec, void *keyp); +/*%< + * Return the TSEC key of '*tsec' in '*keyp'. + * + * Requires + * + *\li keyp != NULL + * + * Ensures + * + *\li *tsecp points to a valid key structure depending on the TSEC type. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_TSEC_H */ diff --git a/lib/dns/include/dns/tsig.h b/lib/dns/include/dns/tsig.h new file mode 100644 index 0000000..c908fa1 --- /dev/null +++ b/lib/dns/include/dns/tsig.h @@ -0,0 +1,297 @@ +/* + * 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. + */ + +#ifndef DNS_TSIG_H +#define DNS_TSIG_H 1 + +/*! \file dns/tsig.h */ + +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/refcount.h> +#include <isc/rwlock.h> +#include <isc/stdio.h> +#include <isc/stdtime.h> + +#include <dns/name.h> +#include <dns/types.h> + +#include <dst/dst.h> +#include <pk11/site.h> + +/* + * Algorithms. + */ +LIBDNS_EXTERNAL_DATA extern const dns_name_t *dns_tsig_hmacmd5_name; +#define DNS_TSIG_HMACMD5_NAME dns_tsig_hmacmd5_name +LIBDNS_EXTERNAL_DATA extern const dns_name_t *dns_tsig_gssapi_name; +#define DNS_TSIG_GSSAPI_NAME dns_tsig_gssapi_name +LIBDNS_EXTERNAL_DATA extern const dns_name_t *dns_tsig_gssapims_name; +#define DNS_TSIG_GSSAPIMS_NAME dns_tsig_gssapims_name +LIBDNS_EXTERNAL_DATA extern const dns_name_t *dns_tsig_hmacsha1_name; +#define DNS_TSIG_HMACSHA1_NAME dns_tsig_hmacsha1_name +LIBDNS_EXTERNAL_DATA extern const dns_name_t *dns_tsig_hmacsha224_name; +#define DNS_TSIG_HMACSHA224_NAME dns_tsig_hmacsha224_name +LIBDNS_EXTERNAL_DATA extern const dns_name_t *dns_tsig_hmacsha256_name; +#define DNS_TSIG_HMACSHA256_NAME dns_tsig_hmacsha256_name +LIBDNS_EXTERNAL_DATA extern const dns_name_t *dns_tsig_hmacsha384_name; +#define DNS_TSIG_HMACSHA384_NAME dns_tsig_hmacsha384_name +LIBDNS_EXTERNAL_DATA extern const dns_name_t *dns_tsig_hmacsha512_name; +#define DNS_TSIG_HMACSHA512_NAME dns_tsig_hmacsha512_name + +/*% + * Default fudge value. + */ +#define DNS_TSIG_FUDGE 300 + +struct dns_tsig_keyring { + dns_rbt_t *keys; + unsigned int writecount; + isc_rwlock_t lock; + isc_mem_t *mctx; + /* + * LRU list of generated key along with a count of the keys on the + * list and a maximum size. + */ + unsigned int generated; + unsigned int maxgenerated; + ISC_LIST(dns_tsigkey_t) lru; + isc_refcount_t references; +}; + +struct dns_tsigkey { + /* Unlocked */ + unsigned int magic; /*%< Magic number. */ + isc_mem_t *mctx; + dst_key_t *key; /*%< Key */ + dns_name_t name; /*%< Key name */ + const dns_name_t *algorithm; /*%< Algorithm name */ + dns_name_t *creator; /*%< name that created secret */ + bool generated; /*%< was this generated? */ + isc_stdtime_t inception; /*%< start of validity period */ + isc_stdtime_t expire; /*%< end of validity period */ + dns_tsig_keyring_t *ring; /*%< the enclosing keyring */ + isc_refcount_t refs; /*%< reference counter */ + ISC_LINK(dns_tsigkey_t) link; +}; + +ISC_LANG_BEGINDECLS + +const dns_name_t * +dns_tsigkey_identity(const dns_tsigkey_t *tsigkey); +/*%< + * Returns the identity of the provided TSIG key. + * + * Requires: + *\li 'tsigkey' is a valid TSIG key or NULL + * + * Returns: + *\li NULL if 'tsigkey' was NULL + *\li identity of the provided TSIG key + */ + +isc_result_t +dns_tsigkey_create(const dns_name_t *name, const dns_name_t *algorithm, + unsigned char *secret, int length, bool generated, + const dns_name_t *creator, isc_stdtime_t inception, + isc_stdtime_t expire, isc_mem_t *mctx, + dns_tsig_keyring_t *ring, dns_tsigkey_t **key); + +isc_result_t +dns_tsigkey_createfromkey(const dns_name_t *name, const dns_name_t *algorithm, + dst_key_t *dstkey, bool generated, + const dns_name_t *creator, isc_stdtime_t inception, + isc_stdtime_t expire, isc_mem_t *mctx, + dns_tsig_keyring_t *ring, dns_tsigkey_t **key); +/*%< + * Creates a tsig key structure and saves it in the keyring. If key is + * not NULL, *key will contain a copy of the key. The keys validity + * period is specified by (inception, expire), and will not expire if + * inception == expire. If the key was generated, the creating identity, + * if there is one, should be in the creator parameter. Specifying an + * unimplemented algorithm will cause failure only if dstkey != NULL; this + * allows a transient key with an invalid algorithm to exist long enough + * to generate a BADKEY response. + * + * If dns_tsigkey_createfromkey is successful a new reference to 'dstkey' + * will have been made. + * + * Requires: + *\li 'name' is a valid dns_name_t + *\li 'algorithm' is a valid dns_name_t + *\li 'secret' is a valid pointer + *\li 'length' is an integer >= 0 + *\li 'dstkey' is a valid dst key or NULL + *\li 'creator' points to a valid dns_name_t or is NULL + *\li 'mctx' is a valid memory context + *\li 'ring' is a valid TSIG keyring or NULL + *\li 'key' or '*key' must be NULL + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_EXISTS - a key with this name already exists + *\li #ISC_R_NOTIMPLEMENTED - algorithm is not implemented + *\li #ISC_R_NOMEMORY + */ + +void +dns_tsigkey_attach(dns_tsigkey_t *source, dns_tsigkey_t **targetp); +/*%< + * Attach '*targetp' to 'source'. + * + * Requires: + *\li 'key' is a valid TSIG key + * + * Ensures: + *\li *targetp is attached to source. + */ + +void +dns_tsigkey_detach(dns_tsigkey_t **keyp); +/*%< + * Detaches from the tsig key structure pointed to by '*key'. + * + * Requires: + *\li 'keyp' is not NULL and '*keyp' is a valid TSIG key + * + * Ensures: + *\li 'keyp' points to NULL + */ + +void +dns_tsigkey_setdeleted(dns_tsigkey_t *key); +/*%< + * Prevents this key from being used again. It will be deleted when + * no references exist. + * + * Requires: + *\li 'key' is a valid TSIG key on a keyring + */ + +isc_result_t +dns_tsig_sign(dns_message_t *msg); +/*%< + * Generates a TSIG record for this message + * + * Requires: + *\li 'msg' is a valid message + *\li 'msg->tsigkey' is a valid TSIG key + *\li 'msg->tsig' is NULL + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_NOSPACE + *\li #DNS_R_EXPECTEDTSIG + * - this is a response & msg->querytsig is NULL + */ + +isc_result_t +dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, + dns_tsig_keyring_t *ring1, dns_tsig_keyring_t *ring2); +/*%< + * Verifies the TSIG record in this message + * + * Requires: + *\li 'source' is a valid buffer containing the unparsed message + *\li 'msg' is a valid message + *\li 'msg->tsigkey' is a valid TSIG key if this is a response + *\li 'msg->tsig' is NULL + *\li 'msg->querytsig' is not NULL if this is a response + *\li 'ring1' and 'ring2' are each either a valid keyring or NULL + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #DNS_R_EXPECTEDTSIG - A TSIG was expected but not seen + *\li #DNS_R_UNEXPECTEDTSIG - A TSIG was seen but not expected + *\li #DNS_R_TSIGERRORSET - the TSIG verified but ->error was set + * and this is a query + *\li #DNS_R_CLOCKSKEW - the TSIG failed to verify because of + * the time was out of the allowed range. + *\li #DNS_R_TSIGVERIFYFAILURE - the TSIG failed to verify + *\li #DNS_R_EXPECTEDRESPONSE - the message was set over TCP and + * should have been a response, + * but was not. + */ + +isc_result_t +dns_tsigkey_find(dns_tsigkey_t **tsigkey, const dns_name_t *name, + const dns_name_t *algorithm, dns_tsig_keyring_t *ring); +/*%< + * Returns the TSIG key corresponding to this name and (possibly) + * algorithm. Also increments the key's reference counter. + * + * Requires: + *\li 'tsigkey' is not NULL + *\li '*tsigkey' is NULL + *\li 'name' is a valid dns_name_t + *\li 'algorithm' is a valid dns_name_t or NULL + *\li 'ring' is a valid keyring + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOTFOUND + */ + +isc_result_t +dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp); +/*%< + * Create an empty TSIG key ring. + * + * Requires: + *\li 'mctx' is not NULL + *\li 'ringp' is not NULL, and '*ringp' is NULL + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +isc_result_t +dns_tsigkeyring_add(dns_tsig_keyring_t *ring, const dns_name_t *name, + dns_tsigkey_t *tkey); +/*%< + * Place a TSIG key onto a key ring. + * + * Requires: + *\li 'ring', 'name' and 'tkey' are not NULL + * + * Returns: + *\li #ISC_R_SUCCESS + *\li Any other value indicates failure. + */ + +void +dns_tsigkeyring_attach(dns_tsig_keyring_t *source, dns_tsig_keyring_t **target); + +void +dns_tsigkeyring_detach(dns_tsig_keyring_t **ringp); + +isc_result_t +dns_tsigkeyring_dumpanddetach(dns_tsig_keyring_t **ringp, FILE *fp); + +/*%< + * Destroy a TSIG key ring. + * + * Requires: + *\li 'ringp' is not NULL + */ + +void +dns_keyring_restore(dns_tsig_keyring_t *ring, FILE *fp); + +ISC_LANG_ENDDECLS + +#endif /* DNS_TSIG_H */ diff --git a/lib/dns/include/dns/ttl.h b/lib/dns/include/dns/ttl.h new file mode 100644 index 0000000..2d718f4 --- /dev/null +++ b/lib/dns/include/dns/ttl.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. + */ + +#ifndef DNS_TTL_H +#define DNS_TTL_H 1 + +/*! \file dns/ttl.h */ + +/*** + *** Imports + ***/ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Functions + ***/ + +isc_result_t +dns_ttl_totext(uint32_t src, bool verbose, bool upcase, isc_buffer_t *target); +/*%< + * Output a TTL or other time interval in a human-readable form. + * The time interval is given as a count of seconds in 'src'. + * The text representation is appended to 'target'. + * + * If 'verbose' is false, use the terse BIND 8 style, like "1w2d3h4m5s". + * + * If 'verbose' is true, use a verbose style like the SOA comments + * in "dig", like "1 week 2 days 3 hours 4 minutes 5 seconds". + * + * If 'upcase' is true, we conform to the BIND 8 style in which + * the unit letter is capitalized if there is only a single unit + * letter to print (for example, "1m30s", but "2M") + * + * If 'upcase' is false, unit letters are always in lower case. + * + * Returns: + * \li ISC_R_SUCCESS + * \li ISC_R_NOSPACE + */ + +isc_result_t +dns_counter_fromtext(isc_textregion_t *source, uint32_t *ttl); +/*%< + * Converts a counter from either a plain number or a BIND 8 style value. + * + * Returns: + *\li ISC_R_SUCCESS + *\li DNS_R_SYNTAX + */ + +isc_result_t +dns_ttl_fromtext(isc_textregion_t *source, uint32_t *ttl); +/*%< + * Converts a ttl from either a plain number or a BIND 8 style value. + * + * Returns: + *\li ISC_R_SUCCESS + *\li DNS_R_BADTTL + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_TTL_H */ diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h new file mode 100644 index 0000000..641d81f --- /dev/null +++ b/lib/dns/include/dns/types.h @@ -0,0 +1,438 @@ +/* + * 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. + */ + +#ifndef DNS_TYPES_H +#define DNS_TYPES_H 1 + +/*! \file dns/types.h + * \brief + * Including this file gives you type declarations suitable for use in + * .h files, which lets us avoid circular type reference problems. + * \brief + * To actually use a type or get declarations of its methods, you must + * include the appropriate .h file too. + */ + +#include <inttypes.h> +#include <stdbool.h> +#include <stdio.h> + +#include <isc/types.h> + +typedef struct dns_acl dns_acl_t; +typedef struct dns_aclelement dns_aclelement_t; +typedef struct dns_aclenv dns_aclenv_t; +typedef struct dns_adb dns_adb_t; +typedef struct dns_adbaddrinfo dns_adbaddrinfo_t; +typedef ISC_LIST(dns_adbaddrinfo_t) dns_adbaddrinfolist_t; +typedef struct dns_adbentry dns_adbentry_t; +typedef struct dns_adbfind dns_adbfind_t; +typedef ISC_LIST(dns_adbfind_t) dns_adbfindlist_t; +typedef struct dns_badcache dns_badcache_t; +typedef struct dns_byaddr dns_byaddr_t; +typedef struct dns_catz_zonemodmethods dns_catz_zonemodmethods_t; +typedef struct dns_catz_entry_options dns_catz_options_t; +typedef struct dns_catz_entry dns_catz_entry_t; +typedef struct dns_catz_zone dns_catz_zone_t; +typedef struct dns_catz_changed dns_catz_changed_t; +typedef struct dns_catz_zones dns_catz_zones_t; +typedef struct dns_client dns_client_t; +typedef void dns_clientrestrans_t; +typedef void dns_clientreqtrans_t; +typedef void dns_clientupdatetrans_t; +typedef struct dns_cache dns_cache_t; +typedef uint16_t dns_cert_t; +typedef struct dns_compress dns_compress_t; +typedef struct dns_db dns_db_t; +typedef struct dns_dbimplementation dns_dbimplementation_t; +typedef struct dns_dbiterator dns_dbiterator_t; +typedef void dns_dbload_t; +typedef void dns_dbnode_t; +typedef struct dns_dbonupdatelistener dns_dbonupdatelistener_t; +typedef struct dns_dbtable dns_dbtable_t; +typedef void dns_dbversion_t; +typedef struct dns_dlzimplementation dns_dlzimplementation_t; +typedef struct dns_dlzdb dns_dlzdb_t; +typedef ISC_LIST(dns_dlzdb_t) dns_dlzdblist_t; +typedef struct dns_dyndbctx dns_dyndbctx_t; +typedef struct dns_sdlzimplementation dns_sdlzimplementation_t; +typedef struct dns_decompress dns_decompress_t; +typedef struct dns_dispatch dns_dispatch_t; +typedef struct dns_dispatchevent dns_dispatchevent_t; +typedef struct dns_dispatchlist dns_dispatchlist_t; +typedef struct dns_dispatchset dns_dispatchset_t; +typedef struct dns_dispatchmgr dns_dispatchmgr_t; +typedef struct dns_dispentry dns_dispentry_t; +typedef struct dns_dns64 dns_dns64_t; +typedef ISC_LIST(dns_dns64_t) dns_dns64list_t; +typedef struct dns_dnsseckey dns_dnsseckey_t; +typedef ISC_LIST(dns_dnsseckey_t) dns_dnsseckeylist_t; +typedef uint8_t dns_dsdigest_t; +typedef struct dns_dtdata dns_dtdata_t; +typedef struct dns_dtenv dns_dtenv_t; +typedef struct dns_dtmsg dns_dtmsg_t; +typedef uint16_t dns_dtmsgtype_t; +typedef struct dns_dumpctx dns_dumpctx_t; +typedef struct dns_ecs dns_ecs_t; +typedef struct dns_ednsopt dns_ednsopt_t; +typedef struct dns_fetch dns_fetch_t; +typedef struct dns_fixedname dns_fixedname_t; +typedef struct dns_forwarders dns_forwarders_t; +typedef struct dns_forwarder dns_forwarder_t; +typedef struct dns_fwdtable dns_fwdtable_t; +typedef struct dns_geoip_databases dns_geoip_databases_t; +typedef struct dns_iptable dns_iptable_t; +typedef uint32_t dns_iterations_t; +typedef struct dns_kasp dns_kasp_t; +typedef ISC_LIST(dns_kasp_t) dns_kasplist_t; +typedef struct dns_kasp_key dns_kasp_key_t; +typedef ISC_LIST(dns_kasp_key_t) dns_kasp_keylist_t; +typedef struct dns_kasp_nsec3param dns_kasp_nsec3param_t; +typedef uint16_t dns_keyflags_t; +typedef struct dns_keynode dns_keynode_t; +typedef ISC_LIST(dns_keynode_t) dns_keynodelist_t; +typedef struct dns_keytable dns_keytable_t; +typedef uint16_t dns_keytag_t; +typedef struct dns_loadctx dns_loadctx_t; +typedef struct dns_loadmgr dns_loadmgr_t; +typedef struct dns_masterrawheader dns_masterrawheader_t; +typedef uint64_t dns_masterstyle_flags_t; +typedef struct dns_message dns_message_t; +typedef uint16_t dns_messageid_t; +typedef isc_region_t dns_label_t; +typedef struct dns_lookup dns_lookup_t; +typedef struct dns_name dns_name_t; +typedef ISC_LIST(dns_name_t) dns_namelist_t; +typedef struct dns_nta dns_nta_t; +typedef struct dns_ntatable dns_ntatable_t; +typedef uint16_t dns_opcode_t; +typedef unsigned char dns_offsets_t[128]; +typedef struct dns_order dns_order_t; +typedef struct dns_peer dns_peer_t; +typedef struct dns_peerlist dns_peerlist_t; +typedef struct dns_portlist dns_portlist_t; +typedef struct dns_rbt dns_rbt_t; +typedef uint16_t dns_rcode_t; +typedef struct dns_rdata dns_rdata_t; +typedef struct dns_rdatacallbacks dns_rdatacallbacks_t; +typedef uint16_t dns_rdataclass_t; +typedef struct dns_rdatalist dns_rdatalist_t; +typedef struct dns_rdataset dns_rdataset_t; +typedef ISC_LIST(dns_rdataset_t) dns_rdatasetlist_t; +typedef struct dns_rdatasetiter dns_rdatasetiter_t; +typedef uint16_t dns_rdatatype_t; +typedef struct dns_request dns_request_t; +typedef struct dns_requestmgr dns_requestmgr_t; +typedef struct dns_resolver dns_resolver_t; +typedef struct dns_sdbimplementation dns_sdbimplementation_t; +typedef uint8_t dns_secalg_t; +typedef uint8_t dns_secproto_t; +typedef struct dns_signature dns_signature_t; +typedef struct dns_sortlist_arg dns_sortlist_arg_t; +typedef struct dns_ssurule dns_ssurule_t; +typedef struct dns_ssutable dns_ssutable_t; +typedef struct dns_stats dns_stats_t; +typedef uint32_t dns_rdatastatstype_t; +typedef struct dns_tkeyctx dns_tkeyctx_t; +typedef uint16_t dns_trust_t; +typedef struct dns_tsec dns_tsec_t; +typedef struct dns_tsig_keyring dns_tsig_keyring_t; +typedef struct dns_tsigkey dns_tsigkey_t; +typedef uint32_t dns_ttl_t; +typedef struct dns_update_state dns_update_state_t; +typedef struct dns_validator dns_validator_t; +typedef struct dns_view dns_view_t; +typedef ISC_LIST(dns_view_t) dns_viewlist_t; +typedef struct dns_zone dns_zone_t; +typedef ISC_LIST(dns_zone_t) dns_zonelist_t; +typedef struct dns_zonemgr dns_zonemgr_t; +typedef struct dns_zt dns_zt_t; +typedef struct dns_ipkeylist dns_ipkeylist_t; + +/* + * If we are not using GSSAPI, define the types we use as opaque types here. + */ +#ifndef GSSAPI +typedef struct not_defined_gss_cred_id *gss_cred_id_t; +typedef struct not_defined_gss_ctx *gss_ctx_id_t; +#endif /* ifndef GSSAPI */ +typedef struct dst_gssapi_signverifyctx dst_gssapi_signverifyctx_t; + +typedef enum { dns_hash_sha1 = 1 } dns_hash_t; + +typedef enum { + dns_fwdpolicy_none = 0, + dns_fwdpolicy_first = 1, + dns_fwdpolicy_only = 2 +} dns_fwdpolicy_t; + +typedef enum { + dns_namereln_none = 0, + dns_namereln_contains = 1, + dns_namereln_subdomain = 2, + dns_namereln_equal = 3, + dns_namereln_commonancestor = 4 +} dns_namereln_t; + +typedef enum { dns_one_answer, dns_many_answers } dns_transfer_format_t; + +typedef enum { + dns_dbtype_zone = 0, + dns_dbtype_cache = 1, + dns_dbtype_stub = 3 +} dns_dbtype_t; + +typedef enum { + dns_notifytype_no = 0, + dns_notifytype_yes = 1, + dns_notifytype_explicit = 2, + dns_notifytype_masteronly = 3 +} dns_notifytype_t; + +typedef enum { + dns_minimal_no = 0, + dns_minimal_yes = 1, + dns_minimal_noauth = 2, + dns_minimal_noauthrec = 3 +} dns_minimaltype_t; + +typedef enum { + dns_dialuptype_no = 0, + dns_dialuptype_yes = 1, + dns_dialuptype_notify = 2, + dns_dialuptype_notifypassive = 3, + dns_dialuptype_refresh = 4, + dns_dialuptype_passive = 5 +} dns_dialuptype_t; + +typedef enum { + dns_masterformat_none = 0, + dns_masterformat_text = 1, + dns_masterformat_raw = 2, + dns_masterformat_map = 3 +} dns_masterformat_t; + +/* + * These are generated by gen.c. + */ +#include <dns/enumclass.h> /* Provides dns_rdataclass_t. */ +#include <dns/enumtype.h> /* Provides dns_rdatatype_t. */ + +/*% + * rcodes. + */ +enum { + /* + * Standard rcodes. + */ + dns_rcode_noerror = 0, +#define dns_rcode_noerror ((dns_rcode_t)dns_rcode_noerror) + dns_rcode_formerr = 1, +#define dns_rcode_formerr ((dns_rcode_t)dns_rcode_formerr) + dns_rcode_servfail = 2, +#define dns_rcode_servfail ((dns_rcode_t)dns_rcode_servfail) + dns_rcode_nxdomain = 3, +#define dns_rcode_nxdomain ((dns_rcode_t)dns_rcode_nxdomain) + dns_rcode_notimp = 4, +#define dns_rcode_notimp ((dns_rcode_t)dns_rcode_notimp) + dns_rcode_refused = 5, +#define dns_rcode_refused ((dns_rcode_t)dns_rcode_refused) + dns_rcode_yxdomain = 6, +#define dns_rcode_yxdomain ((dns_rcode_t)dns_rcode_yxdomain) + dns_rcode_yxrrset = 7, +#define dns_rcode_yxrrset ((dns_rcode_t)dns_rcode_yxrrset) + dns_rcode_nxrrset = 8, +#define dns_rcode_nxrrset ((dns_rcode_t)dns_rcode_nxrrset) + dns_rcode_notauth = 9, +#define dns_rcode_notauth ((dns_rcode_t)dns_rcode_notauth) + dns_rcode_notzone = 10, +#define dns_rcode_notzone ((dns_rcode_t)dns_rcode_notzone) + /* + * Extended rcodes. + */ + dns_rcode_badvers = 16, +#define dns_rcode_badvers ((dns_rcode_t)dns_rcode_badvers) + dns_rcode_badcookie = 23 +#define dns_rcode_badcookie ((dns_rcode_t)dns_rcode_badcookie) + /* + * Update dns_rcodestats_create() and + *dns_rcodestats_increment() + * and this comment if a rcode > + *dns_rcode_badcookie is assigned. + */ + /* Private space [3841..4095] */ +}; + +/*% + * TSIG errors. + */ +enum { + dns_tsigerror_badsig = 16, + dns_tsigerror_badkey = 17, + dns_tsigerror_badtime = 18, + dns_tsigerror_badmode = 19, + dns_tsigerror_badname = 20, + dns_tsigerror_badalg = 21, + dns_tsigerror_badtrunc = 22 +}; + +/*% + * Opcodes. + */ +enum { + dns_opcode_query = 0, +#define dns_opcode_query ((dns_opcode_t)dns_opcode_query) + dns_opcode_iquery = 1, +#define dns_opcode_iquery ((dns_opcode_t)dns_opcode_iquery) + dns_opcode_status = 2, +#define dns_opcode_status ((dns_opcode_t)dns_opcode_status) + dns_opcode_notify = 4, +#define dns_opcode_notify ((dns_opcode_t)dns_opcode_notify) + dns_opcode_update = 5 /* dynamic update */ +#define dns_opcode_update ((dns_opcode_t)dns_opcode_update) +}; + +/*% + * Trust levels. Must be kept in sync with trustnames[] in masterdump.c. + */ +enum { + /* Sentinel value; no data should have this trust level. */ + dns_trust_none = 0, +#define dns_trust_none ((dns_trust_t)dns_trust_none) + + /*% + * Subject to DNSSEC validation but has not yet been validated + * dns_trust_pending_additional (from the additional section). + */ + dns_trust_pending_additional = 1, +#define dns_trust_pending_additional ((dns_trust_t)dns_trust_pending_additional) + + dns_trust_pending_answer = 2, +#define dns_trust_pending_answer ((dns_trust_t)dns_trust_pending_answer) + + /*% Received in the additional section of a response. */ + dns_trust_additional = 3, +#define dns_trust_additional ((dns_trust_t)dns_trust_additional) + + /* Received in a referral response. */ + dns_trust_glue = 4, +#define dns_trust_glue ((dns_trust_t)dns_trust_glue) + + /* Answer from a non-authoritative server */ + dns_trust_answer = 5, +#define dns_trust_answer ((dns_trust_t)dns_trust_answer) + + /* Received in the authority section as part of an + * authoritative response */ + dns_trust_authauthority = 6, +#define dns_trust_authauthority ((dns_trust_t)dns_trust_authauthority) + + /* Answer from an authoritative server */ + dns_trust_authanswer = 7, +#define dns_trust_authanswer ((dns_trust_t)dns_trust_authanswer) + + /* Successfully DNSSEC validated */ + dns_trust_secure = 8, +#define dns_trust_secure ((dns_trust_t)dns_trust_secure) + + /* This server is authoritative */ + dns_trust_ultimate = 9 +#define dns_trust_ultimate ((dns_trust_t)dns_trust_ultimate) +}; + +#define DNS_TRUST_PENDING(x) \ + ((x) == dns_trust_pending_answer || (x) == dns_trust_pending_additional) +#define DNS_TRUST_ADDITIONAL(x) \ + ((x) == dns_trust_additional || (x) == dns_trust_pending_additional) +#define DNS_TRUST_GLUE(x) ((x) == dns_trust_glue) +#define DNS_TRUST_ANSWER(x) ((x) == dns_trust_answer) + +/*% + * Name checking severities. + */ +typedef enum { + dns_severity_ignore, + dns_severity_warn, + dns_severity_fail +} dns_severity_t; + +/*% + * DNS Serial Number Update Method. + * + * \li _none: Keep the current serial. + * \li _increment: Add one to the current serial, skipping 0. + * \li _unixtime: Set to the seconds since 00:00 Jan 1, 1970, + * if possible. + * \li _date: Set to today's date in YYYYMMDDVV format: + * (Year, Month, Day, Version) + */ +typedef enum { + dns_updatemethod_none = 0, + dns_updatemethod_increment, + dns_updatemethod_unixtime, + dns_updatemethod_date +} dns_updatemethod_t; + +typedef enum { + dns_stale_answer_no, + dns_stale_answer_yes, + dns_stale_answer_conf +} dns_stale_answer_t; + +typedef struct { + const char *string; + size_t count; +} dns_indent_t; + +/* + * Functions. + */ +typedef void (*dns_dumpdonefunc_t)(void *, isc_result_t); + +typedef void (*dns_loaddonefunc_t)(void *, isc_result_t); + +typedef void (*dns_rawdatafunc_t)(dns_zone_t *, dns_masterrawheader_t *); + +typedef isc_result_t (*dns_addrdatasetfunc_t)(void *, const dns_name_t *, + dns_rdataset_t *); + +typedef isc_result_t (*dns_additionaldatafunc_t)(void *, const dns_name_t *, + dns_rdatatype_t); + +typedef isc_result_t (*dns_digestfunc_t)(void *, isc_region_t *); + +typedef void (*dns_xfrindone_t)(dns_zone_t *, isc_result_t); + +typedef void (*dns_updatecallback_t)(void *, isc_result_t, dns_message_t *); + +typedef int (*dns_rdatasetorderfunc_t)(const dns_rdata_t *, const void *); + +typedef bool (*dns_checkmxfunc_t)(dns_zone_t *, const dns_name_t *, + const dns_name_t *); + +typedef bool (*dns_checksrvfunc_t)(dns_zone_t *, const dns_name_t *, + const dns_name_t *); + +typedef bool (*dns_checknsfunc_t)(dns_zone_t *, const dns_name_t *, + const dns_name_t *, dns_rdataset_t *, + dns_rdataset_t *); + +typedef bool (*dns_isselffunc_t)(dns_view_t *, dns_tsigkey_t *, + const isc_sockaddr_t *, const isc_sockaddr_t *, + dns_rdataclass_t, void *); + +typedef isc_result_t (*dns_deserializefunc_t)(void *, FILE *, off_t); + +typedef void (*dns_nseclog_t)(void *val, int, const char *, ...); + +#endif /* DNS_TYPES_H */ diff --git a/lib/dns/include/dns/update.h b/lib/dns/include/dns/update.h new file mode 100644 index 0000000..aca9e71 --- /dev/null +++ b/lib/dns/include/dns/update.h @@ -0,0 +1,75 @@ +/* + * 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. + */ + +#ifndef DNS_UPDATE_H +#define DNS_UPDATE_H 1 + +/*! \file dns/update.h */ + +/*** + *** Imports + ***/ + +#include <inttypes.h> + +#include <isc/lang.h> + +#include <dns/diff.h> +#include <dns/types.h> + +typedef struct { + void (*func)(void *arg, dns_zone_t *zone, int level, + const char *message); + void *arg; +} dns_update_log_t; + +ISC_LANG_BEGINDECLS + +/*** + *** Functions + ***/ + +uint32_t +dns_update_soaserial(uint32_t serial, dns_updatemethod_t method, + dns_updatemethod_t *used); +/*%< + * Return the next serial number after 'serial', depending on the + * update method 'method': + * + *\li * dns_updatemethod_increment increments the serial number by one + *\li * dns_updatemethod_date sets the serial number to YYYYMMDD00 + *\li * dns_updatemethod_unixtime sets the serial number to the current + * time (seconds since UNIX epoch) + *\li * dns_updatemethod_none just returns the given serial + * + * NOTE: The dns_updatemethod_increment will be used if dns_updatemethod_date or + * dns_updatemethod_unixtime is used and the new serial number would be lower + * than current serial number. + * + * Sets *used to the method that was used. + */ + +isc_result_t +dns_update_signatures(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db, + dns_dbversion_t *oldver, dns_dbversion_t *newver, + dns_diff_t *diff, uint32_t sigvalidityinterval); + +isc_result_t +dns_update_signaturesinc(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db, + dns_dbversion_t *oldver, dns_dbversion_t *newver, + dns_diff_t *diff, uint32_t sigvalidityinterval, + dns_update_state_t **state); + +ISC_LANG_ENDDECLS + +#endif /* DNS_UPDATE_H */ diff --git a/lib/dns/include/dns/validator.h b/lib/dns/include/dns/validator.h new file mode 100644 index 0000000..b435cd6 --- /dev/null +++ b/lib/dns/include/dns/validator.h @@ -0,0 +1,243 @@ +/* + * 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. + */ + +#ifndef DNS_VALIDATOR_H +#define DNS_VALIDATOR_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/validator.h + * + * \brief + * DNS Validator + * This is the BIND 9 validator, the module responsible for validating the + * rdatasets and negative responses (messages). It makes use of zones in + * the view and may fetch RRset to complete trust chains. It implements + * DNSSEC as specified in RFC 4033, 4034 and 4035. + * + * Correct operation is critical to preventing spoofed answers from secure + * zones being accepted. + * + * MP: + *\li The module ensures appropriate synchronization of data structures it + * creates and manipulates. + * + * Reliability: + *\li No anticipated impact. + * + * Resources: + *\li TBS + * + * Security: + *\li No anticipated impact. + * + * Standards: + *\li RFCs: 1034, 1035, 2181, 4033, 4034, 4035. + */ + +#include <stdbool.h> + +#include <isc/event.h> +#include <isc/lang.h> +#include <isc/mutex.h> + +#include <dns/fixedname.h> +#include <dns/rdataset.h> +#include <dns/rdatastruct.h> /* for dns_rdata_rrsig_t */ +#include <dns/types.h> + +#include <dst/dst.h> + +/*% + * A dns_validatorevent_t is sent when a 'validation' completes. + * \brief + * 'name', 'rdataset', 'sigrdataset', and 'message' are the values that were + * supplied when dns_validator_create() was called. They are returned to the + * caller so that they may be freed. + * + * If the RESULT is ISC_R_SUCCESS and the answer is secure then + * proofs[] will contain the names of the NSEC records that hold the + * various proofs. Note the same name may appear multiple times. + */ +typedef struct dns_validatorevent { + ISC_EVENT_COMMON(struct dns_validatorevent); + dns_validator_t *validator; + isc_result_t result; + /* + * Name and type of the response to be validated. + */ + dns_name_t *name; + dns_rdatatype_t type; + /* + * Rdata and RRSIG (if any) for positive responses. + */ + dns_rdataset_t *rdataset; + dns_rdataset_t *sigrdataset; + /* + * The full response. Required for negative responses. + * Also required for positive wildcard responses. + */ + dns_message_t *message; + /* + * Proofs to be cached. + */ + dns_name_t *proofs[4]; + /* + * Optout proof seen. + */ + bool optout; + /* + * Answer is secure. + */ + bool secure; +} dns_validatorevent_t; + +#define DNS_VALIDATOR_NOQNAMEPROOF 0 +#define DNS_VALIDATOR_NODATAPROOF 1 +#define DNS_VALIDATOR_NOWILDCARDPROOF 2 +#define DNS_VALIDATOR_CLOSESTENCLOSER 3 + +/*% + * A validator object represents a validation in progress. + * \brief + * Clients are strongly discouraged from using this type directly, with + * the exception of the 'link' field, which may be used directly for + * whatever purpose the client desires. + */ +struct dns_validator { + /* Unlocked. */ + unsigned int magic; + isc_mutex_t lock; + dns_view_t *view; + /* Locked by lock. */ + unsigned int options; + unsigned int attributes; + dns_validatorevent_t *event; + dns_fetch_t *fetch; + dns_validator_t *subvalidator; + dns_validator_t *parent; + dns_keytable_t *keytable; + dst_key_t *key; + dns_rdata_rrsig_t *siginfo; + isc_task_t *task; + isc_taskaction_t action; + void *arg; + unsigned int labels; + dns_rdataset_t *currentset; + dns_rdataset_t *keyset; + dns_rdataset_t *dsset; + dns_rdataset_t fdsset; + dns_rdataset_t frdataset; + dns_rdataset_t fsigrdataset; + dns_fixedname_t fname; + dns_fixedname_t wild; + dns_fixedname_t closest; + ISC_LINK(dns_validator_t) link; + bool mustbesecure; + unsigned int depth; + unsigned int authcount; + unsigned int authfail; + isc_stdtime_t start; +}; + +/*% + * dns_validator_create() options. + */ +/* obsolete: #define DNS_VALIDATOR_DLV 0x0001U */ +#define DNS_VALIDATOR_DEFER 0x0002U +#define DNS_VALIDATOR_NOCDFLAG 0x0004U +#define DNS_VALIDATOR_NONTA 0x0008U /*% Ignore NTA table */ + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, + dns_message_t *message, unsigned int options, + isc_task_t *task, isc_taskaction_t action, void *arg, + dns_validator_t **validatorp); +/*%< + * Start a DNSSEC validation. + * + * This validates a response to the question given by + * 'name' and 'type'. + * + * To validate a positive response, the response data is + * given by 'rdataset' and 'sigrdataset'. If 'sigrdataset' + * is NULL, the data is presumed insecure and an attempt + * is made to prove its insecurity by finding the appropriate + * null key. + * + * The complete response message may be given in 'message', + * to make available any authority section NSECs that may be + * needed for validation of a response resulting from a + * wildcard expansion (though no such wildcard validation + * is implemented yet). If the complete response message + * is not available, 'message' is NULL. + * + * To validate a negative response, the complete negative response + * message is given in 'message'. The 'rdataset', and + * 'sigrdataset' arguments must be NULL, but the 'name' and 'type' + * arguments must be provided. + * + * The validation is performed in the context of 'view'. + * + * When the validation finishes, a dns_validatorevent_t with + * the given 'action' and 'arg' are sent to 'task'. + * Its 'result' field will be ISC_R_SUCCESS iff the + * response was successfully proven to be either secure or + * part of a known insecure domain. + */ + +void +dns_validator_send(dns_validator_t *validator); +/*%< + * Send a deferred validation request + * + * Requires: + * 'validator' to points to a valid DNSSEC validator. + */ + +void +dns_validator_cancel(dns_validator_t *validator); +/*%< + * Cancel a DNSSEC validation in progress. + * + * Requires: + *\li 'validator' points to a valid DNSSEC validator, which + * may or may not already have completed. + * + * Ensures: + *\li It the validator has not already sent its completion + * event, it will send it with result code ISC_R_CANCELED. + */ + +void +dns_validator_destroy(dns_validator_t **validatorp); +/*%< + * Destroy a DNSSEC validator. + * + * Requires: + *\li '*validatorp' points to a valid DNSSEC validator. + * \li The validator must have completed and sent its completion + * event. + * + * Ensures: + *\li All resources used by the validator are freed. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_VALIDATOR_H */ diff --git a/lib/dns/include/dns/version.h b/lib/dns/include/dns/version.h new file mode 100644 index 0000000..0f5ec7e --- /dev/null +++ b/lib/dns/include/dns/version.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. + */ + +/*! \file dns/version.h */ + +#ifndef DNS_VERSION_H +#define DNS_VERSION_H 1 + +#include <isc/platform.h> + +LIBDNS_EXTERNAL_DATA extern const char dns_version[]; +LIBDNS_EXTERNAL_DATA extern const char dns_major[]; +LIBDNS_EXTERNAL_DATA extern const char dns_mapapi[]; + +#endif /* DNS_VERSION_H */ diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h new file mode 100644 index 0000000..d6e7f10 --- /dev/null +++ b/lib/dns/include/dns/view.h @@ -0,0 +1,1359 @@ +/* + * 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. + */ + +#ifndef DNS_VIEW_H +#define DNS_VIEW_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/view.h + * \brief + * DNS View + * + * A "view" is a DNS namespace, together with an optional resolver and a + * forwarding policy. A "DNS namespace" is a (possibly empty) set of + * authoritative zones together with an optional cache and optional + * "hints" information. + * + * Views start out "unfrozen". In this state, core attributes like + * the cache, set of zones, and forwarding policy may be set. While + * "unfrozen", the caller (e.g. nameserver configuration loading + * code), must ensure exclusive access to the view. When the view is + * "frozen", the core attributes become immutable, and the view module + * will ensure synchronization. Freezing allows the view's core attributes + * to be accessed without locking. + * + * MP: + *\li Before the view is frozen, the caller must ensure synchronization. + * + *\li After the view is frozen, the module guarantees appropriate + * synchronization of any data structures it creates and manipulates. + * + * Reliability: + *\li No anticipated impact. + * + * Resources: + *\li TBS + * + * Security: + *\li No anticipated impact. + * + * Standards: + *\li None. + */ + +#include <inttypes.h> +#include <stdbool.h> +#include <stdio.h> + +#include <isc/event.h> +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/mutex.h> +#include <isc/net.h> +#include <isc/refcount.h> +#include <isc/rwlock.h> +#include <isc/stdtime.h> + +#include <dns/acl.h> +#include <dns/catz.h> +#include <dns/clientinfo.h> +#include <dns/dnstap.h> +#include <dns/fixedname.h> +#include <dns/rdatastruct.h> +#include <dns/rpz.h> +#include <dns/rrl.h> +#include <dns/types.h> +#include <dns/zt.h> + +ISC_LANG_BEGINDECLS + +struct dns_view { + /* Unlocked. */ + unsigned int magic; + isc_mem_t *mctx; + dns_rdataclass_t rdclass; + char *name; + dns_zt_t *zonetable; + dns_resolver_t *resolver; + dns_adb_t *adb; + dns_requestmgr_t *requestmgr; + dns_cache_t *cache; + dns_db_t *cachedb; + dns_db_t *hints; + + /* + * security roots and negative trust anchors. + * internal use only; access via * dns_view_getsecroots() + */ + dns_keytable_t *secroots_priv; + dns_ntatable_t *ntatable_priv; + + isc_mutex_t lock; + bool frozen; + isc_task_t *task; + isc_event_t resevent; + isc_event_t adbevent; + isc_event_t reqevent; + isc_stats_t *adbstats; + isc_stats_t *resstats; + dns_stats_t *resquerystats; + bool cacheshared; + + /* Configurable data. */ + dns_tsig_keyring_t *statickeys; + dns_tsig_keyring_t *dynamickeys; + dns_peerlist_t *peers; + dns_order_t *order; + dns_fwdtable_t *fwdtable; + bool recursion; + bool qminimization; + bool qmin_strict; + bool auth_nxdomain; + bool use_glue_cache; + bool minimal_any; + dns_minimaltype_t minimalresponses; + bool enablevalidation; + bool acceptexpired; + bool requireservercookie; + bool synthfromdnssec; + bool trust_anchor_telemetry; + bool root_key_sentinel; + dns_transfer_format_t transfer_format; + dns_acl_t *cacheacl; + dns_acl_t *cacheonacl; + dns_acl_t *queryacl; + dns_acl_t *queryonacl; + dns_acl_t *recursionacl; + dns_acl_t *recursiononacl; + dns_acl_t *sortlist; + dns_acl_t *notifyacl; + dns_acl_t *transferacl; + dns_acl_t *updateacl; + dns_acl_t *upfwdacl; + dns_acl_t *denyansweracl; + dns_acl_t *nocasecompress; + bool msgcompression; + dns_rbt_t *answeracl_exclude; + dns_rbt_t *denyanswernames; + dns_rbt_t *answernames_exclude; + dns_rrl_t *rrl; + bool provideixfr; + bool requestnsid; + bool sendcookie; + dns_ttl_t maxcachettl; + dns_ttl_t maxncachettl; + dns_ttl_t mincachettl; + dns_ttl_t minncachettl; + uint32_t nta_lifetime; + uint32_t nta_recheck; + char *nta_file; + dns_ttl_t prefetch_trigger; + dns_ttl_t prefetch_eligible; + in_port_t dstport; + dns_aclenv_t aclenv; + dns_rdatatype_t preferred_glue; + bool flush; + dns_namelist_t *delonly; + bool rootdelonly; + dns_namelist_t *rootexclude; + bool checknames; + uint16_t maxudp; + dns_ttl_t staleanswerttl; + dns_stale_answer_t staleanswersok; /* rndc setting */ + bool staleanswersenable; /* named.conf setting + * */ + uint32_t staleanswerclienttimeout; + uint16_t nocookieudp; + uint16_t padding; + dns_acl_t *pad_acl; + unsigned int maxbits; + dns_dns64list_t dns64; + unsigned int dns64cnt; + dns_rpz_zones_t *rpzs; + dns_catz_zones_t *catzs; + dns_dlzdblist_t dlz_searched; + dns_dlzdblist_t dlz_unsearched; + uint32_t fail_ttl; + dns_badcache_t *failcache; + + /* + * Configurable data for server use only, + * locked by server configuration lock. + */ + dns_acl_t *matchclients; + dns_acl_t *matchdestinations; + bool matchrecursiveonly; + + /* Locked by themselves. */ + isc_refcount_t references; + isc_refcount_t weakrefs; + atomic_uint_fast32_t attributes; + + /* Under owner's locking control. */ + ISC_LINK(struct dns_view) link; + dns_viewlist_t *viewlist; + + dns_zone_t *managed_keys; + dns_zone_t *redirect; + dns_name_t *redirectzone; /* points to + * redirectfixed + * when valid */ + dns_fixedname_t redirectfixed; + + /* + * File and configuration data for zones added at runtime + * (only used in BIND9). + * + * XXX: This should be a pointer to an opaque type that + * named implements. + */ + char *new_zone_dir; + char *new_zone_file; + char *new_zone_db; + void *new_zone_dbenv; + uint64_t new_zone_mapsize; + void *new_zone_config; + void (*cfg_destroy)(void **); + isc_mutex_t new_zone_lock; + + unsigned char secret[32]; /* Client secret */ + unsigned int v6bias; + + dns_dtenv_t *dtenv; /* Dnstap environment */ + dns_dtmsgtype_t dttypes; /* Dnstap message types + * to log */ + + /* Registered module instances */ + void *plugins; + void (*plugins_free)(isc_mem_t *, void **); + + /* Hook table */ + void *hooktable; /* ns_hooktable */ + void (*hooktable_free)(isc_mem_t *, void **); +}; + +#define DNS_VIEW_MAGIC ISC_MAGIC('V', 'i', 'e', 'w') +#define DNS_VIEW_VALID(view) ISC_MAGIC_VALID(view, DNS_VIEW_MAGIC) + +#define DNS_VIEWATTR_RESSHUTDOWN 0x01 +#define DNS_VIEWATTR_ADBSHUTDOWN 0x02 +#define DNS_VIEWATTR_REQSHUTDOWN 0x04 + +isc_result_t +dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, const char *name, + dns_view_t **viewp); +/*%< + * Create a view. + * + * Notes: + * + *\li The newly created view has no cache, no resolver, and an empty + * zone table. The view is not frozen. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li 'rdclass' is a valid class. + * + *\li 'name' is a valid C string. + * + *\li viewp != NULL && *viewp == NULL + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + * + *\li Other errors are possible. + */ + +void +dns_view_attach(dns_view_t *source, dns_view_t **targetp); +/*%< + * Attach '*targetp' to 'source'. + * + * Requires: + * + *\li 'source' is a valid, frozen view. + * + *\li 'targetp' points to a NULL dns_view_t *. + * + * Ensures: + * + *\li *targetp is attached to source. + * + *\li While *targetp is attached, the view will not shut down. + */ + +void +dns_view_detach(dns_view_t **viewp); +/*%< + * Detach '*viewp' from its view. + * + * Requires: + * + *\li 'viewp' points to a valid dns_view_t * + * + * Ensures: + * + *\li *viewp is NULL. + */ + +void +dns_view_flushanddetach(dns_view_t **viewp); +/*%< + * Detach '*viewp' from its view. If this was the last reference + * uncommitted changed in zones will be flushed to disk. + * + * Requires: + * + *\li 'viewp' points to a valid dns_view_t * + * + * Ensures: + * + *\li *viewp is NULL. + */ + +void +dns_view_weakattach(dns_view_t *source, dns_view_t **targetp); +/*%< + * Weakly attach '*targetp' to 'source'. + * + * Requires: + * + *\li 'source' is a valid, frozen view. + * + *\li 'targetp' points to a NULL dns_view_t *. + * + * Ensures: + * + *\li *targetp is attached to source. + * + * \li While *targetp is attached, the view will not be freed. + */ + +void +dns_view_weakdetach(dns_view_t **targetp); +/*%< + * Detach '*viewp' from its view. + * + * Requires: + * + *\li 'viewp' points to a valid dns_view_t *. + * + * Ensures: + * + *\li *viewp is NULL. + */ + +isc_result_t +dns_view_createzonetable(dns_view_t *view); +/*%< + * Create a zonetable for the view. + * + * Requires: + * + *\li 'view' is a valid, unfrozen view. + * + *\li 'view' does not have a zonetable already. + * + * Returns: + * + *\li #ISC_R_SUCCESS + * + *\li Any error that dns_zt_create() can return. + */ + +isc_result_t +dns_view_createresolver(dns_view_t *view, isc_taskmgr_t *taskmgr, + unsigned int ntasks, unsigned int ndisp, + isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, + unsigned int options, dns_dispatchmgr_t *dispatchmgr, + dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6); +/*%< + * Create a resolver and address database for the view. + * + * Requires: + * + *\li 'view' is a valid, unfrozen view. + * + *\li 'view' does not have a resolver already. + * + *\li The requirements of dns_resolver_create() apply to 'taskmgr', + * 'ntasks', 'socketmgr', 'timermgr', 'options', 'dispatchv4', and + * 'dispatchv6'. + * + * Returns: + * + *\li #ISC_R_SUCCESS + * + *\li Any error that dns_resolver_create() can return. + */ + +void +dns_view_setcache(dns_view_t *view, dns_cache_t *cache, bool shared); +/*%< + * Set the view's cache database. If 'shared' is true, this means the cache + * is created by another view and is shared with that view. dns_view_setcache() + * is a backward compatible version equivalent to setcache2(..., false). + * + * Requires: + * + *\li 'view' is a valid, unfrozen view. + * + *\li 'cache' is a valid cache. + * + * Ensures: + * + * \li The cache of 'view' is 'cached. + * + *\li If this is not the first call to dns_view_setcache() for this + * view, then previously set cache is detached. + */ + +void +dns_view_sethints(dns_view_t *view, dns_db_t *hints); +/*%< + * Set the view's hints database. + * + * Requires: + * + *\li 'view' is a valid, unfrozen view, whose hints database has not been + * set. + * + *\li 'hints' is a valid zone database. + * + * Ensures: + * + * \li The hints database of 'view' is 'hints'. + */ + +void +dns_view_setkeyring(dns_view_t *view, dns_tsig_keyring_t *ring); +void +dns_view_setdynamickeyring(dns_view_t *view, dns_tsig_keyring_t *ring); +/*%< + * Set the view's static TSIG keys + * + * Requires: + * + * \li 'view' is a valid, unfrozen view, whose static TSIG keyring has not + * been set. + * + *\li 'ring' is a valid TSIG keyring + * + * Ensures: + * + *\li The static TSIG keyring of 'view' is 'ring'. + */ + +void +dns_view_getdynamickeyring(dns_view_t *view, dns_tsig_keyring_t **ringp); +/*%< + * Return the views dynamic keys. + * + * \li 'view' is a valid, unfrozen view. + * \li 'ringp' != NULL && ringp == NULL. + */ + +void +dns_view_setdstport(dns_view_t *view, in_port_t dstport); +/*%< + * Set the view's destination port. This is the port to + * which outgoing queries are sent. The default is 53, + * the standard DNS port. + * + * Requires: + * + *\li 'view' is a valid view. + * + *\li 'dstport' is a valid TCP/UDP port number. + * + * Ensures: + *\li External name servers will be assumed to be listening + * on 'dstport'. For servers whose address has already + * obtained obtained at the time of the call, the view may + * continue to use the previously set port until the address + * times out from the view's address database. + */ + +isc_result_t +dns_view_addzone(dns_view_t *view, dns_zone_t *zone); +/*%< + * Add zone 'zone' to 'view'. + * + * Requires: + * + *\li 'view' is a valid, unfrozen view. + * + *\li 'zone' is a valid zone. + */ + +void +dns_view_freeze(dns_view_t *view); +/*%< + * Freeze view. No changes can be made to view configuration while frozen. + * + * Requires: + * + *\li 'view' is a valid, unfrozen view. + * + * Ensures: + * + *\li 'view' is frozen. + */ + +void +dns_view_thaw(dns_view_t *view); +/*%< + * Thaw view. This allows zones to be added or removed at runtime. This is + * NOT thread-safe; the caller MUST have run isc_task_exclusive() prior to + * thawing the view. + * + * Requires: + * + *\li 'view' is a valid, frozen view. + * + * Ensures: + * + *\li 'view' is no longer frozen. + */ + +isc_result_t +dns_view_find(dns_view_t *view, const dns_name_t *name, dns_rdatatype_t type, + isc_stdtime_t now, unsigned int options, bool use_hints, + bool use_static_stub, dns_db_t **dbp, dns_dbnode_t **nodep, + dns_name_t *foundname, dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset); +/*%< + * Find an rdataset whose owner name is 'name', and whose type is + * 'type'. + * In general, this function first searches view's zone and cache DBs for the + * best match data against 'name'. If nothing found there, and if 'use_hints' + * is true, the view's hint DB (if configured) is searched. + * If the view is configured with a static-stub zone which gives the longest + * match for 'name' among the zones, however, the cache DB is not consulted + * unless 'use_static_stub' is false (see below about this argument). + * + * dns_view_find() is a backward compatible version equivalent to + * dns_view_find2() with use_static_stub argument being false. + * + * Notes: + * + *\li See the description of dns_db_find() for information about 'options'. + * If the caller sets #DNS_DBFIND_GLUEOK, it must ensure that 'name' + * and 'type' are appropriate for glue retrieval. + * + *\li If 'now' is zero, then the current time will be used. + * + *\li If 'use_hints' is true, and the view has a hints database, then + * it will be searched last. If the answer is found in the hints + * database, the result code will be DNS_R_HINT. If the name is found + * in the hints database but not the type, the result code will be + * #DNS_R_HINTNXRRSET. + * + *\li If 'use_static_stub' is false and the longest match zone for 'name' + * is a static-stub zone, it's ignored and the cache and/or hints will be + * searched. In the majority of the cases this argument should be + * false. The only known usage of this argument being true is + * if this search is for a "bailiwick" glue A or AAAA RRset that may + * best match a static-stub zone. Consider the following example: + * this view is configured with a static-stub zone "example.com", + * and an attempt of recursive resolution needs to send a query for the + * zone. In this case it's quite likely that the resolver is trying to + * find A/AAAA RRs for the apex name "example.com". And, to honor the + * static-stub configuration it needs to return the glue RRs in the + * static-stub zone even if that exact RRs coming from the authoritative + * zone has been cached. + * In other general cases, the requested data is better to be + * authoritative, either locally configured or retrieved from an external + * server, and the data in the static-stub zone should better be ignored. + * + *\li 'foundname' must meet the requirements of dns_db_find(). + * + *\li If 'sigrdataset' is not NULL, and there is a SIG rdataset which + * covers 'type', then 'sigrdataset' will be bound to it. + * + * Requires: + * + *\li 'view' is a valid, frozen view. + * + *\li 'name' is valid name. + * + *\li 'type' is a valid dns_rdatatype_t, and is not a meta query type + * except dns_rdatatype_any. + * + *\li dbp == NULL || *dbp == NULL + * + *\li nodep == NULL || *nodep == NULL. If nodep != NULL, dbp != NULL. + * + *\li 'foundname' is a valid name with a dedicated buffer or NULL. + * + *\li 'rdataset' is a valid, disassociated rdataset. + * + *\li 'sigrdataset' is NULL, or is a valid, disassociated rdataset. + * + * Ensures: + * + *\li In successful cases, 'rdataset', and possibly 'sigrdataset', are + * bound to the found data. + * + *\li If dbp != NULL, it points to the database containing the data. + * + *\li If nodep != NULL, it points to the database node containing the data. + * + *\li If foundname != NULL, it contains the full name of the found data. + * + * Returns: + * + *\li Any result that dns_db_find() can return, with the exception of + * #DNS_R_DELEGATION. + */ + +isc_result_t +dns_view_simplefind(dns_view_t *view, const dns_name_t *name, + dns_rdatatype_t type, isc_stdtime_t now, + unsigned int options, bool use_hints, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset); +/*%< + * Find an rdataset whose owner name is 'name', and whose type is + * 'type'. + * + * Notes: + * + *\li This routine is appropriate for simple, exact-match queries of the + * view. 'name' must be a canonical name; there is no DNAME or CNAME + * processing. + * + *\li See the description of dns_db_find() for information about 'options'. + * If the caller sets DNS_DBFIND_GLUEOK, it must ensure that 'name' + * and 'type' are appropriate for glue retrieval. + * + *\li If 'now' is zero, then the current time will be used. + * + *\li If 'use_hints' is true, and the view has a hints database, then + * it will be searched last. If the answer is found in the hints + * database, the result code will be DNS_R_HINT. If the name is found + * in the hints database but not the type, the result code will be + * DNS_R_HINTNXRRSET. + * + *\li If 'sigrdataset' is not NULL, and there is a SIG rdataset which + * covers 'type', then 'sigrdataset' will be bound to it. + * + * Requires: + * + *\li 'view' is a valid, frozen view. + * + *\li 'name' is valid name. + * + *\li 'type' is a valid dns_rdatatype_t, and is not a meta query type + * (e.g. dns_rdatatype_any), or dns_rdatatype_rrsig. + * + *\li 'rdataset' is a valid, disassociated rdataset. + * + *\li 'sigrdataset' is NULL, or is a valid, disassociated rdataset. + * + * Ensures: + * + *\li In successful cases, 'rdataset', and possibly 'sigrdataset', are + * bound to the found data. + * + * Returns: + * + *\li #ISC_R_SUCCESS Success; result is desired type. + *\li DNS_R_GLUE Success; result is glue. + *\li DNS_R_HINT Success; result is a hint. + *\li DNS_R_NCACHENXDOMAIN Success; result is a ncache entry. + *\li DNS_R_NCACHENXRRSET Success; result is a ncache entry. + *\li DNS_R_NXDOMAIN The name does not exist. + *\li DNS_R_NXRRSET The rrset does not exist. + *\li #ISC_R_NOTFOUND No matching data found, + * or an error occurred. + */ + +isc_result_t +dns_view_findzonecut(dns_view_t *view, const dns_name_t *name, + dns_name_t *fname, dns_name_t *dcname, isc_stdtime_t now, + unsigned int options, bool use_hints, bool use_cache, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset); +/*%< + * Find the best known zonecut containing 'name'. + * + * This uses local authority, cache, and optionally hints data. + * No external queries are performed. + * + * Notes: + * + *\li If 'now' is zero, then the current time will be used. + * + *\li If 'use_hints' is true, and the view has a hints database, then + * it will be searched last. + * + *\li If 'use_cache' is true, and the view has a cache, then it will be + * searched. + * + *\li If 'sigrdataset' is not NULL, and there is a SIG rdataset which + * covers 'type', then 'sigrdataset' will be bound to it. + * + *\li If the DNS_DBFIND_NOEXACT option is set, then the zonecut returned + * (if any) will be the deepest known ancestor of 'name'. + * + *\li If dcname is not NULL the deepest cached name is copied to it. + * + * Requires: + * + *\li 'view' is a valid, frozen view. + * + *\li 'name' is valid name. + * + *\li 'rdataset' is a valid, disassociated rdataset. + * + *\li 'sigrdataset' is NULL, or is a valid, disassociated rdataset. + * + * Returns: + * + *\li #ISC_R_SUCCESS Success. + * + *\li Many other results are possible. + */ + +isc_result_t +dns_viewlist_find(dns_viewlist_t *list, const char *name, + dns_rdataclass_t rdclass, dns_view_t **viewp); +/*%< + * Search for a view with name 'name' and class 'rdclass' in 'list'. + * If found, '*viewp' is (strongly) attached to it. + * + * Requires: + * + *\li 'viewp' points to a NULL dns_view_t *. + * + * Returns: + * + *\li #ISC_R_SUCCESS A matching view was found. + *\li #ISC_R_NOTFOUND No matching view was found. + */ + +isc_result_t +dns_viewlist_findzone(dns_viewlist_t *list, const dns_name_t *name, + bool allclasses, dns_rdataclass_t rdclass, + dns_zone_t **zonep); + +/*%< + * Search zone with 'name' in view with 'rdclass' in viewlist 'list' + * If found, zone is returned in *zonep. If allclasses is set rdclass is ignored + * + * Returns: + *\li #ISC_R_SUCCESS A matching zone was found. + *\li #ISC_R_NOTFOUND No matching zone was found. + *\li #ISC_R_MULTIPLE Multiple zones with the same name were found. + */ + +isc_result_t +dns_view_findzone(dns_view_t *view, const dns_name_t *name, dns_zone_t **zonep); +/*%< + * Search for the zone 'name' in the zone table of 'view'. + * If found, 'zonep' is (strongly) attached to it. There + * are no partial matches. + * + * Requires: + * + *\li 'zonep' points to a NULL dns_zone_t *. + * + * Returns: + *\li #ISC_R_SUCCESS A matching zone was found. + *\li #ISC_R_NOTFOUND No matching zone was found. + *\li others An error occurred. + */ + +isc_result_t +dns_view_load(dns_view_t *view, bool stop, bool newonly); + +isc_result_t +dns_view_asyncload(dns_view_t *view, bool newonly, dns_zt_allloaded_t callback, + void *arg); +/*%< + * Load zones attached to this view. dns_view_load() loads + * all zones whose master file has changed since the last + * load + * + * dns_view_asyncload() loads zones asynchronously. When all zones + * in the view have finished loading, 'callback' is called with argument + * 'arg' to inform the caller. + * + * If 'stop' is true, stop on the first error and return it. + * If 'stop' is false (or we are loading asynchronously), ignore errors. + * + * If 'newonly' is true load only zones that were never loaded. + * + * Requires: + * + *\li 'view' is valid. + */ + +isc_result_t +dns_view_gettsig(dns_view_t *view, const dns_name_t *keyname, + dns_tsigkey_t **keyp); +/*%< + * Find the TSIG key configured in 'view' with name 'keyname', + * if any. + * + * Requires: + *\li keyp points to a NULL dns_tsigkey_t *. + * + * Returns: + *\li #ISC_R_SUCCESS A key was found and '*keyp' now points to it. + *\li #ISC_R_NOTFOUND No key was found. + *\li others An error occurred. + */ + +isc_result_t +dns_view_getpeertsig(dns_view_t *view, const isc_netaddr_t *peeraddr, + dns_tsigkey_t **keyp); +/*%< + * Find the TSIG key configured in 'view' for the server whose + * address is 'peeraddr', if any. + * + * Requires: + * keyp points to a NULL dns_tsigkey_t *. + * + * Returns: + *\li #ISC_R_SUCCESS A key was found and '*keyp' now points to it. + *\li #ISC_R_NOTFOUND No key was found. + *\li others An error occurred. + */ + +isc_result_t +dns_view_checksig(dns_view_t *view, isc_buffer_t *source, dns_message_t *msg); +/*%< + * Verifies the signature of a message. + * + * Requires: + * + *\li 'view' is a valid view. + *\li 'source' is a valid buffer containing the message + *\li 'msg' is a valid message + * + * Returns: + *\li see dns_tsig_verify() + */ + +void +dns_view_dialup(dns_view_t *view); +/*%< + * Perform dialup-time maintenance on the zones of 'view'. + */ + +isc_result_t +dns_view_dumpdbtostream(dns_view_t *view, FILE *fp); +/*%< + * Dump the current state of the view 'view' to the stream 'fp' + * for purposes of analysis or debugging. + * + * Currently the dumped state includes the view's cache; in the future + * it may also include other state such as the address database. + * It will not not include authoritative data since it is voluminous and + * easily obtainable by other means. + * + * Requires: + * + *\li 'view' is valid. + * + *\li 'fp' refers to a file open for writing. + * + * Returns: + * \li ISC_R_SUCCESS The cache was successfully dumped. + * \li others An error occurred (see dns_master_dump) + */ + +isc_result_t +dns_view_flushcache(dns_view_t *view, bool fixuponly); +/*%< + * Flush the view's cache (and ADB). If 'fixuponly' is true, it only updates + * the internal reference to the cache DB with omitting actual flush operation. + * 'fixuponly' is intended to be used for a view that shares a cache with + * a different view. dns_view_flushcache() is a backward compatible version + * that always sets fixuponly to false. + * + * Requires: + * 'view' is valid. + * + * No other tasks are executing. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +isc_result_t +dns_view_flushnode(dns_view_t *view, const dns_name_t *name, bool tree); +/*%< + * Flush the given name from the view's cache (and optionally ADB/badcache). + * + * Flush the given name from the cache, ADB, and bad cache. If 'tree' + * is true, also flush all subdomains of 'name'. + * + * Requires: + *\li 'view' is valid. + *\li 'name' is valid. + * + * Returns: + *\li #ISC_R_SUCCESS + * other returns are failures. + */ + +isc_result_t +dns_view_flushname(dns_view_t *view, const dns_name_t *name); +/*%< + * Flush the given name from the view's cache, ADB and badcache. + * Equivalent to dns_view_flushnode(view, name, false). + * + * + * Requires: + *\li 'view' is valid. + *\li 'name' is valid. + * + * Returns: + *\li #ISC_R_SUCCESS + * other returns are failures. + */ + +isc_result_t +dns_view_adddelegationonly(dns_view_t *view, const dns_name_t *name); +/*%< + * Add the given name to the delegation only table. + * + * Requires: + *\li 'view' is valid. + *\li 'name' is valid. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +isc_result_t +dns_view_excludedelegationonly(dns_view_t *view, const dns_name_t *name); +/*%< + * Add the given name to be excluded from the root-delegation-only. + * + * + * Requires: + *\li 'view' is valid. + *\li 'name' is valid. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +bool +dns_view_isdelegationonly(dns_view_t *view, const dns_name_t *name); +/*%< + * Check if 'name' is in the delegation only table or if + * rootdelonly is set that name is not being excluded. + * + * Requires: + *\li 'view' is valid. + *\li 'name' is valid. + * + * Returns: + *\li #true if the name is the table. + *\li #false otherwise. + */ + +void +dns_view_setrootdelonly(dns_view_t *view, bool value); +/*%< + * Set the root delegation only flag. + * + * Requires: + *\li 'view' is valid. + */ + +bool +dns_view_getrootdelonly(dns_view_t *view); +/*%< + * Get the root delegation only flag. + * + * Requires: + *\li 'view' is valid. + */ + +isc_result_t +dns_view_freezezones(dns_view_t *view, bool freeze); +/*%< + * Freeze/thaw updates to master zones. + * + * Requires: + * \li 'view' is valid. + */ + +void +dns_view_setadbstats(dns_view_t *view, isc_stats_t *stats); +/*%< + * Set a adb statistics set 'stats' for 'view'. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li stats is a valid statistics supporting adb statistics + * (see dns/stats.h). + */ + +void +dns_view_getadbstats(dns_view_t *view, isc_stats_t **statsp); +/*%< + * Get the adb statistics counter set for 'view'. If a statistics set is + * set '*statsp' will be attached to the set; otherwise, '*statsp' will be + * untouched. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li 'statsp' != NULL && '*statsp' != NULL + */ + +void +dns_view_setresstats(dns_view_t *view, isc_stats_t *stats); +/*%< + * Set a general resolver statistics counter set 'stats' for 'view'. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li stats is a valid statistics supporting resolver statistics counters + * (see dns/stats.h). + */ + +void +dns_view_getresstats(dns_view_t *view, isc_stats_t **statsp); +/*%< + * Get the general statistics counter set for 'view'. If a statistics set is + * set '*statsp' will be attached to the set; otherwise, '*statsp' will be + * untouched. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li 'statsp' != NULL && '*statsp' != NULL + */ + +void +dns_view_setresquerystats(dns_view_t *view, dns_stats_t *stats); +/*%< + * Set a statistics counter set of rdata type, 'stats', for 'view'. Once the + * statistic set is installed, view's resolver will count outgoing queries + * per rdata type. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li stats is a valid statistics created by dns_rdatatypestats_create(). + */ + +void +dns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp); +/*%< + * Get the rdatatype statistics counter set for 'view'. If a statistics set is + * set '*statsp' will be attached to the set; otherwise, '*statsp' will be + * untouched. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li 'statsp' != NULL && '*statsp' != NULL + */ + +bool +dns_view_iscacheshared(dns_view_t *view); +/*%< + * Check if the view shares the cache created by another view. + * + * Requires: + * \li 'view' is valid. + * + * Returns: + *\li #true if the cache is shared. + *\li #false otherwise. + */ + +isc_result_t +dns_view_initntatable(dns_view_t *view, isc_taskmgr_t *taskmgr, + isc_timermgr_t *timermgr); +/*%< + * Initialize the negative trust anchor table for the view. + * + * Requires: + * \li 'view' is valid. + * + * Returns: + *\li ISC_R_SUCCESS + *\li Any other result indicates failure + */ + +isc_result_t +dns_view_getntatable(dns_view_t *view, dns_ntatable_t **ntp); +/*%< + * Get the negative trust anchor table for this view. Returns + * ISC_R_NOTFOUND if the table not been initialized for the view. + * + * '*ntp' is attached on success; the caller is responsible for + * detaching it with dns_ntatable_detach(). + * + * Requires: + * \li 'view' is valid. + * \li 'nta' is not NULL and '*nta' is NULL. + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOTFOUND + */ + +isc_result_t +dns_view_initsecroots(dns_view_t *view, isc_mem_t *mctx); +/*%< + * Initialize security roots for the view, detaching any previously + * existing security roots first. (Note that secroots_priv is + * NULL until this function is called, so any function using + * security roots must check that they have been initialized first. + * One way to do this is use dns_view_getsecroots() and check its + * return value.) + * + * Requires: + * \li 'view' is valid. + * + * Returns: + *\li ISC_R_SUCCESS + *\li Any other result indicates failure + */ + +isc_result_t +dns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp); +/*%< + * Get the security roots for this view. Returns ISC_R_NOTFOUND if + * the security roots keytable has not been initialized for the view. + * + * '*ktp' is attached on success; the caller is responsible for + * detaching it with dns_keytable_detach(). + * + * Requires: + * \li 'view' is valid. + * \li 'ktp' is not NULL and '*ktp' is NULL. + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOTFOUND + */ + +isc_result_t +dns_view_issecuredomain(dns_view_t *view, const dns_name_t *name, + isc_stdtime_t now, bool checknta, bool *ntap, + bool *secure_domain); +/*%< + * Is 'name' at or beneath a trusted key, and not covered by a valid + * negative trust anchor? Put answer in '*secure_domain'. + * + * If 'checknta' is false, ignore the NTA table in determining + * whether this is a secure domain. If 'checknta' is not false, and if + * 'ntap' is non-NULL, then '*ntap' will be updated with true if the + * name is covered by an NTA. + * + * Requires: + * \li 'view' is valid. + * + * Returns: + *\li ISC_R_SUCCESS + *\li Any other value indicates failure + */ + +bool +dns_view_ntacovers(dns_view_t *view, isc_stdtime_t now, const dns_name_t *name, + const dns_name_t *anchor); +/*%< + * Is there a current negative trust anchor above 'name' and below 'anchor'? + * + * Requires: + * \li 'view' is valid. + * + * Returns: + *\li ISC_R_TRUE + *\li ISC_R_FALSE + */ + +void +dns_view_untrust(dns_view_t *view, const dns_name_t *keyname, + const dns_rdata_dnskey_t *dnskey); +/*%< + * Remove keys that match 'keyname' and 'dnskey' from the views trust + * anchors. + * + * (NOTE: If the configuration specifies that there should be a + * trust anchor at 'keyname', but no keys are left after this + * operation, that is an error. We fail closed, inserting a NULL + * key so as to prevent validation until a legimitate key has been + * provided.) + * + * Requires: + * \li 'view' is valid. + * \li 'keyname' is valid. + * \li 'dnskey' is valid. + */ + +bool +dns_view_istrusted(dns_view_t *view, const dns_name_t *keyname, + const dns_rdata_dnskey_t *dnskey); +/*%< + * Determine if the key defined by 'keyname' and 'dnskey' is + * trusted by 'view'. + * + * Requires: + * \li 'view' is valid. + * \li 'keyname' is valid. + * \li 'dnskey' is valid. + */ + +isc_result_t +dns_view_setnewzones(dns_view_t *view, bool allow, void *cfgctx, + void (*cfg_destroy)(void **), uint64_t mapsize); +/*%< + * Set whether or not to allow zones to be created or deleted at runtime. + * + * If 'allow' is true, determines the filename into which new zone + * configuration will be written. Preserves the configuration context + * (a pointer to which is passed in 'cfgctx') for use when parsing new + * zone configuration. 'cfg_destroy' points to a callback routine to + * destroy the configuration context when the view is destroyed. (This + * roundabout method is used in order to avoid libdns having a dependency + * on libisccfg and libbind9.) + * + * If 'allow' is false, removes any existing references to + * configuration context and frees any memory. + * + * Requires: + * \li 'view' is valid. + * + * Returns: + * \li ISC_R_SUCCESS + * \li ISC_R_NOSPACE + */ + +void +dns_view_setnewzonedir(dns_view_t *view, const char *dir); +const char * +dns_view_getnewzonedir(dns_view_t *view); +/*%< + * Set/get the path to the directory in which NZF or NZD files should + * be stored. If the path was previously set to a non-NULL value, + * the previous value is freed. + * + * Requires: + * \li 'view' is valid. + */ + +void +dns_view_restorekeyring(dns_view_t *view); + +isc_result_t +dns_view_searchdlz(dns_view_t *view, const dns_name_t *name, + unsigned int minlabels, dns_clientinfomethods_t *methods, + dns_clientinfo_t *clientinfo, dns_db_t **dbp); + +/*%< + * Search through the DLZ database(s) in view->dlz_searched to find + * one that can answer a query for 'name', using the DLZ driver's + * findzone method. If successful, '*dbp' is set to point to the + * DLZ database. + * + * Returns: + * \li ISC_R_SUCCESS + * \li ISC_R_NOTFOUND + * + * Requires: + * \li 'view' is valid. + * \li 'name' is not NULL. + * \li 'dbp' is not NULL and *dbp is NULL. + */ + +uint32_t +dns_view_getfailttl(dns_view_t *view); +/*%< + * Get the view's servfail-ttl. zero => no servfail caching. + * + * Requires: + *\li 'view' to be valid. + */ + +void +dns_view_setfailttl(dns_view_t *view, uint32_t failttl); +/*%< + * Set the view's servfail-ttl. zero => no servfail caching. + * + * Requires: + *\li 'view' to be valid. + */ + +isc_result_t +dns_view_saventa(dns_view_t *view); +/*%< + * Save NTA for names in this view to a file. + * + * Requires: + *\li 'view' to be valid. + */ + +isc_result_t +dns_view_loadnta(dns_view_t *view); +/*%< + * Loads NTA for names in this view from a file. + * + * Requires: + *\li 'view' to be valid. + */ + +void +dns_view_setviewcommit(dns_view_t *view); +/*%< + * Commit dns_zone_setview() calls previously made for all zones in this + * view. + * + * Requires: + *\li 'view' to be valid. + */ + +void +dns_view_setviewrevert(dns_view_t *view); +/*%< + * Revert dns_zone_setview() calls previously made for all zones in this + * view. + * + * Requires: + *\li 'view' to be valid. + */ + +bool +dns_view_staleanswerenabled(dns_view_t *view); +/*%< + * Check if stale answers are enabled for this view. + * + * Requires: + *\li 'view' to be valid. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_VIEW_H */ diff --git a/lib/dns/include/dns/xfrin.h b/lib/dns/include/dns/xfrin.h new file mode 100644 index 0000000..2c0f530 --- /dev/null +++ b/lib/dns/include/dns/xfrin.h @@ -0,0 +1,98 @@ +/* + * 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. + */ + +#ifndef DNS_XFRIN_H +#define DNS_XFRIN_H 1 + +/***** +***** Module Info +*****/ + +/*! \file dns/xfrin.h + * \brief + * Incoming zone transfers (AXFR + IXFR). + */ + +/*** + *** Imports + ***/ + +#include <isc/lang.h> + +#include <dns/types.h> + +/*** + *** Types + ***/ + +/*% + * A transfer in progress. This is an opaque type. + */ +typedef struct dns_xfrin_ctx dns_xfrin_ctx_t; + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +isc_result_t +dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype, + const isc_sockaddr_t *masteraddr, + const isc_sockaddr_t *sourceaddr, isc_dscp_t dscp, + dns_tsigkey_t *tsigkey, isc_mem_t *mctx, + isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, + isc_task_t *task, dns_xfrindone_t done, + dns_xfrin_ctx_t **xfrp); +/*%< + * Attempt to start an incoming zone transfer of 'zone' + * from 'masteraddr', creating a dns_xfrin_ctx_t object to + * manage it. Attach '*xfrp' to the newly created object. + * + * Iff ISC_R_SUCCESS is returned, '*done' is guaranteed to be + * called in the context of 'task', with 'zone' and a result + * code as arguments when the transfer finishes. + * + * Requires: + *\li 'xfrtype' is dns_rdatatype_axfr, dns_rdatatype_ixfr + * or dns_rdatatype_soa (soa query followed by axfr if + * serial is greater than current serial). + * + *\li If 'xfrtype' is dns_rdatatype_ixfr or dns_rdatatype_soa, + * the zone has a database. + */ + +void +dns_xfrin_shutdown(dns_xfrin_ctx_t *xfr); +/*%< + * If the zone transfer 'xfr' has already finished, + * do nothing. Otherwise, abort it and cause it to call + * its done callback with a status of ISC_R_CANCELED. + */ + +void +dns_xfrin_detach(dns_xfrin_ctx_t **xfrp); +/*%< + * Detach a reference to a zone transfer object. + * Caller to maintain external locking if required. + */ + +void +dns_xfrin_attach(dns_xfrin_ctx_t *source, dns_xfrin_ctx_t **target); +/*%< + * Caller to maintain external locking if required. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_XFRIN_H */ diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h new file mode 100644 index 0000000..4bdc936 --- /dev/null +++ b/lib/dns/include/dns/zone.h @@ -0,0 +1,2726 @@ +/* + * 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. + */ + +#ifndef DNS_ZONE_H +#define DNS_ZONE_H 1 + +/*! \file dns/zone.h */ + +/*** + *** Imports + ***/ + +#include <inttypes.h> +#include <stdbool.h> +#include <stdio.h> + +#include <isc/formatcheck.h> +#include <isc/lang.h> +#include <isc/rwlock.h> + +#include <dns/catz.h> +#include <dns/master.h> +#include <dns/masterdump.h> +#include <dns/rdatastruct.h> +#include <dns/rpz.h> +#include <dns/types.h> +#include <dns/zt.h> + +typedef enum { + dns_zone_none, + dns_zone_primary, + dns_zone_secondary, + dns_zone_mirror, + dns_zone_stub, + dns_zone_staticstub, + dns_zone_key, + dns_zone_dlz, + dns_zone_redirect +} dns_zonetype_t; + +#ifndef dns_zone_master +#define dns_zone_master dns_zone_primary +#endif /* dns_zone_master */ + +#ifndef dns_zone_slave +#define dns_zone_slave dns_zone_secondary +#endif /* dns_zone_slave */ + +typedef enum { + dns_zonestat_none = 0, + dns_zonestat_terse, + dns_zonestat_full +} dns_zonestat_level_t; + +typedef enum { + DNS_ZONEOPT_MANYERRORS = 1 << 0, /*%< return many errors on load */ + DNS_ZONEOPT_IXFRFROMDIFFS = 1 << 1, /*%< calculate differences */ + DNS_ZONEOPT_NOMERGE = 1 << 2, /*%< don't merge journal */ + DNS_ZONEOPT_CHECKNS = 1 << 3, /*%< check if NS's are addresses */ + DNS_ZONEOPT_FATALNS = 1 << 4, /*%< DNS_ZONEOPT_CHECKNS is fatal */ + DNS_ZONEOPT_MULTIMASTER = 1 << 5, /*%< this zone has multiple + primaries */ + DNS_ZONEOPT_USEALTXFRSRC = 1 << 6, /*%< use alternate transfer sources + */ + DNS_ZONEOPT_CHECKNAMES = 1 << 7, /*%< check-names */ + DNS_ZONEOPT_CHECKNAMESFAIL = 1 << 8, /*%< fatal check-name failures */ + DNS_ZONEOPT_CHECKWILDCARD = 1 << 9, /*%< check for internal wildcards */ + DNS_ZONEOPT_CHECKMX = 1 << 10, /*%< check-mx */ + DNS_ZONEOPT_CHECKMXFAIL = 1 << 11, /*%< fatal check-mx failures */ + DNS_ZONEOPT_CHECKINTEGRITY = 1 << 12, /*%< perform integrity checks */ + DNS_ZONEOPT_CHECKSIBLING = 1 << 13, /*%< perform sibling glue checks */ + DNS_ZONEOPT_NOCHECKNS = 1 << 14, /*%< disable IN NS address checks */ + DNS_ZONEOPT_WARNMXCNAME = 1 << 15, /*%< warn on MX CNAME check */ + DNS_ZONEOPT_IGNOREMXCNAME = 1 << 16, /*%< ignore MX CNAME check */ + DNS_ZONEOPT_WARNSRVCNAME = 1 << 17, /*%< warn on SRV CNAME check */ + DNS_ZONEOPT_IGNORESRVCNAME = 1 << 18, /*%< ignore SRV CNAME check */ + DNS_ZONEOPT_UPDATECHECKKSK = 1 << 19, /*%< check dnskey KSK flag */ + DNS_ZONEOPT_TRYTCPREFRESH = 1 << 20, /*%< try tcp refresh on udp failure + */ + DNS_ZONEOPT_NOTIFYTOSOA = 1 << 21, /*%< Notify the SOA MNAME */ + DNS_ZONEOPT_NSEC3TESTZONE = 1 << 22, /*%< nsec3-test-zone */ + DNS_ZONEOPT_SECURETOINSECURE = 1 << 23, /*%< dnssec-secure-to-insecure + */ + DNS_ZONEOPT_DNSKEYKSKONLY = 1 << 24, /*%< dnssec-dnskey-kskonly */ + DNS_ZONEOPT_CHECKDUPRR = 1 << 25, /*%< check-dup-records */ + DNS_ZONEOPT_CHECKDUPRRFAIL = 1 << 26, /*%< fatal check-dup-records + * failures */ + DNS_ZONEOPT_CHECKSPF = 1 << 27, /*%< check SPF records */ + DNS_ZONEOPT_CHECKTTL = 1 << 28, /*%< check max-zone-ttl */ + DNS_ZONEOPT_AUTOEMPTY = 1 << 29, /*%< automatic empty zone */ + DNS_ZONEOPT___MAX = UINT64_MAX, /* trick to make the ENUM 64-bit wide */ +} dns_zoneopt_t; + +/* + * Zone key maintenance options + */ +typedef enum { + DNS_ZONEKEY_ALLOW = 0x00000001U, /*%< fetch keys on command */ + DNS_ZONEKEY_MAINTAIN = 0x00000002U, /*%< publish/sign on schedule */ + DNS_ZONEKEY_CREATE = 0x00000004U, /*%< make keys when needed */ + DNS_ZONEKEY_FULLSIGN = 0x00000008U, /*%< roll to new keys immediately */ + DNS_ZONEKEY_NORESIGN = 0x00000010U, /*%< no automatic resigning */ + DNS_ZONEKEY___MAX = UINT64_MAX, /* trick to make the ENUM 64-bit wide */ +} dns_zonekey_t; + +#ifndef DNS_ZONE_MINREFRESH +#define DNS_ZONE_MINREFRESH 300 /*%< 5 minutes */ +#endif /* ifndef DNS_ZONE_MINREFRESH */ +#ifndef DNS_ZONE_MAXREFRESH +#define DNS_ZONE_MAXREFRESH 2419200 /*%< 4 weeks */ +#endif /* ifndef DNS_ZONE_MAXREFRESH */ +#ifndef DNS_ZONE_DEFAULTREFRESH +#define DNS_ZONE_DEFAULTREFRESH 3600 /*%< 1 hour */ +#endif /* ifndef DNS_ZONE_DEFAULTREFRESH */ +#ifndef DNS_ZONE_MINRETRY +#define DNS_ZONE_MINRETRY 300 /*%< 5 minutes */ +#endif /* ifndef DNS_ZONE_MINRETRY */ +#ifndef DNS_ZONE_MAXRETRY +#define DNS_ZONE_MAXRETRY 1209600 /*%< 2 weeks */ +#endif /* ifndef DNS_ZONE_MAXRETRY */ +#ifndef DNS_ZONE_DEFAULTRETRY +#define DNS_ZONE_DEFAULTRETRY \ + 60 /*%< 1 minute, subject to \ + * exponential backoff */ +#endif /* ifndef DNS_ZONE_DEFAULTRETRY */ + +#define DNS_ZONESTATE_XFERRUNNING 1 +#define DNS_ZONESTATE_XFERDEFERRED 2 +#define DNS_ZONESTATE_SOAQUERY 3 +#define DNS_ZONESTATE_ANY 4 +#define DNS_ZONESTATE_AUTOMATIC 5 + +ISC_LANG_BEGINDECLS + +/*** + *** Functions + ***/ + +isc_result_t +dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx); +/*%< + * Creates a new empty zone and attach '*zonep' to it. + * + * Requires: + *\li 'zonep' to point to a NULL pointer. + *\li 'mctx' to be a valid memory context. + * + * Ensures: + *\li '*zonep' refers to a valid zone. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_UNEXPECTED + */ + +void +dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass); +/*%< + * Sets the class of a zone. This operation can only be performed + * once on a zone. + * + * Require: + *\li 'zone' to be a valid zone. + *\li dns_zone_setclass() not to have been called since the zone was + * created. + *\li 'rdclass' != dns_rdataclass_none. + */ + +dns_rdataclass_t +dns_zone_getclass(dns_zone_t *zone); +/*%< + * Returns the current zone class. + * + * Requires: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_getserial(dns_zone_t *zone, uint32_t *serialp); +/*%< + * Returns the current serial number of the zone. On success, the SOA + * serial of the zone will be copied into '*serialp'. + * + * Requires: + *\li 'zone' to be a valid zone. + *\li 'serialp' to be non NULL + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #DNS_R_NOTLOADED zone DB is not loaded + */ + +void +dns_zone_settype(dns_zone_t *zone, dns_zonetype_t type); +/*%< + * Sets the zone type. This operation can only be performed once on + * a zone. + * + * Requires: + *\li 'zone' to be a valid zone. + *\li dns_zone_settype() not to have been called since the zone was + * created. + *\li 'type' != dns_zone_none + */ + +void +dns_zone_setview(dns_zone_t *zone, dns_view_t *view); +/*%< + * Associate the zone with a view. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +dns_view_t * +dns_zone_getview(dns_zone_t *zone); +/*%< + * Returns the zone's associated view. + * + * Requires: + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_setviewcommit(dns_zone_t *zone); +/*%< + * Commit the previous view saved internally via dns_zone_setview(). + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_setviewrevert(dns_zone_t *zone); +/*%< + * Revert the most recent dns_zone_setview() on this zone, + * restoring the previous view. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_setorigin(dns_zone_t *zone, const dns_name_t *origin); +/*%< + * Sets the zones origin to 'origin'. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'origin' to be non NULL. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +dns_name_t * +dns_zone_getorigin(dns_zone_t *zone); +/*%< + * Returns the value of the origin. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_setfile(dns_zone_t *zone, const char *file, dns_masterformat_t format, + const dns_master_style_t *style); +/*%< + * Sets the name of the master file in the format of 'format' from which + * the zone loads its database to 'file'. + * + * For zones that have no associated master file, 'file' will be NULL. + * + * For zones with persistent databases, the file name + * setting is ignored. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li #ISC_R_NOMEMORY + *\li #ISC_R_SUCCESS + */ + +const char * +dns_zone_getfile(dns_zone_t *zone); +/*%< + * Gets the name of the zone's master file, if any. + * + * Requires: + *\li 'zone' to be valid initialised zone. + * + * Returns: + *\li Pointer to null-terminated file name, or NULL. + */ + +void +dns_zone_setmaxrecords(dns_zone_t *zone, uint32_t records); +/*%< + * Sets the maximum number of records permitted in a zone. + * 0 implies unlimited. + * + * Requires: + *\li 'zone' to be valid initialised zone. + * + * Returns: + *\li void + */ + +uint32_t +dns_zone_getmaxrecords(dns_zone_t *zone); +/*%< + * Gets the maximum number of records permitted in a zone. + * 0 implies unlimited. + * + * Requires: + *\li 'zone' to be valid initialised zone. + * + * Returns: + *\li uint32_t maxrecords. + */ + +void +dns_zone_setmaxttl(dns_zone_t *zone, uint32_t maxttl); +/*%< + * Sets the max ttl of the zone. + * + * Requires: + *\li 'zone' to be valid initialised zone. + * + * Returns: + *\li void + */ + +dns_ttl_t +dns_zone_getmaxttl(dns_zone_t *zone); +/*%< + * Gets the max ttl of the zone. + * + * Requires: + *\li 'zone' to be valid initialised zone. + * + * Returns: + *\li dns_ttl_t maxttl. + */ + +void +dns_zone_lock_keyfiles(dns_zone_t *zone); +/*%< + * Lock associated keyfiles for this zone. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_unlock_keyfiles(dns_zone_t *zone); +/*%< + * Unlock associated keyfiles for this zone. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_load(dns_zone_t *zone, bool newonly); + +isc_result_t +dns_zone_loadandthaw(dns_zone_t *zone); + +/*%< + * Cause the database to be loaded from its backing store. + * Confirm that the minimum requirements for the zone type are + * met, otherwise DNS_R_BADZONE is returned. + * + * If newonly is set dns_zone_load() only loads new zones. + * dns_zone_loadandthaw() is similar to dns_zone_load() but will + * also re-enable DNS UPDATEs when the load completes. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li #ISC_R_UNEXPECTED + *\li #ISC_R_SUCCESS + *\li DNS_R_CONTINUE Incremental load has been queued. + *\li DNS_R_UPTODATE The zone has already been loaded based on + * file system timestamps. + *\li DNS_R_BADZONE + *\li Any result value from dns_db_load(). + */ + +isc_result_t +dns_zone_asyncload(dns_zone_t *zone, bool newonly, dns_zt_zoneloaded_t done, + void *arg); +/*%< + * Cause the database to be loaded from its backing store asynchronously. + * Other zone maintenance functions are suspended until this is complete. + * When finished, 'done' is called to inform the caller, with 'arg' as + * its first argument and 'zone' as its second. (Normally, 'arg' is + * expected to point to the zone table but is left undefined for testing + * purposes.) + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li #ISC_R_ALREADYRUNNING + *\li #ISC_R_SUCCESS + *\li #ISC_R_FAILURE + *\li #ISC_R_NOMEMORY + */ + +bool +dns__zone_loadpending(dns_zone_t *zone); +/*%< + * Indicates whether the zone is waiting to be loaded asynchronously. + * (Not currently intended for use outside of this module and associated + * tests.) + */ + +void +dns_zone_attach(dns_zone_t *source, dns_zone_t **target); +/*%< + * Attach '*target' to 'source' incrementing its external + * reference count. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'target' to be non NULL and '*target' to be NULL. + */ + +void +dns_zone_detach(dns_zone_t **zonep); +/*%< + * Detach from a zone decrementing its external reference count. + * If this was the last external reference to the zone it will be + * shut down and eventually freed. + * + * Require: + *\li 'zonep' to point to a valid zone. + */ + +void +dns_zone_iattach(dns_zone_t *source, dns_zone_t **target); +/*%< + * Attach '*target' to 'source' incrementing its internal + * reference count. This is intended for use by operations + * such as zone transfers that need to prevent the zone + * object from being freed but not from shutting down. + * + * Require: + *\li The caller is running in the context of the zone's task. + *\li 'zone' to be a valid zone. + *\li 'target' to be non NULL and '*target' to be NULL. + */ + +void +dns_zone_idetach(dns_zone_t **zonep); +/*%< + * Detach from a zone decrementing its internal reference count. + * If there are no more internal or external references to the + * zone, it will be freed. + * + * Require: + *\li The caller is running in the context of the zone's task. + *\li 'zonep' to point to a valid zone. + */ + +isc_result_t +dns_zone_getdb(dns_zone_t *zone, dns_db_t **dbp); +/*%< + * Attach '*dbp' to the database to if it exists otherwise + * return DNS_R_NOTLOADED. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'dbp' to be != NULL && '*dbp' == NULL. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li DNS_R_NOTLOADED + */ + +void +dns_zone_setdb(dns_zone_t *zone, dns_db_t *db); +/*%< + * Sets the zone database to 'db'. + * + * This function is expected to be used to configure a zone with a + * database which is not loaded from a file or zone transfer. + * It can be used for a general purpose zone, but right now its use + * is limited to static-stub zones to avoid possible undiscovered + * problems in the general cases. + * + * Require: + *\li 'zone' to be a valid zone of static-stub. + *\li zone doesn't have a database. + */ + +void +dns_zone_setdbtype(dns_zone_t *zone, unsigned int dbargc, + const char *const *dbargv); +/*%< + * Sets the database type to dbargv[0] and database arguments + * to subsequent dbargv elements. + * 'db_type' is not checked to see if it is a valid database type. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'database' to be non NULL. + *\li 'dbargc' to be >= 1 + *\li 'dbargv' to point to dbargc NULL-terminated strings + */ + +isc_result_t +dns_zone_getdbtype(dns_zone_t *zone, char ***argv, isc_mem_t *mctx); +/*%< + * Returns the current dbtype. isc_mem_free() should be used + * to free 'argv' after use. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'argv' to be non NULL and *argv to be NULL. + *\li 'mctx' to be valid. + * + * Returns: + *\li #ISC_R_NOMEMORY + *\li #ISC_R_SUCCESS + */ + +void +dns_zone_markdirty(dns_zone_t *zone); +/*%< + * Mark a zone as 'dirty'. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_expire(dns_zone_t *zone); +/*%< + * Mark the zone as expired. If the zone requires dumping cause it to + * be initiated. Set the refresh and retry intervals to there default + * values and unload the zone. + * + * Require + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_refresh(dns_zone_t *zone); +/*%< + * Initiate zone up to date checks. The zone must already be being + * managed. + * + * Require + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_flush(dns_zone_t *zone); +/*%< + * Write the zone to database if there are uncommitted changes. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_dump(dns_zone_t *zone); +/*%< + * Write the zone to database. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_dumptostream(dns_zone_t *zone, FILE *fd, dns_masterformat_t format, + const dns_master_style_t *style, + const uint32_t rawversion); +/*%< + * Write the zone to stream 'fd' in the specified 'format'. + * If the 'format' is dns_masterformat_text (RFC1035), 'style' also + * specifies the file style (e.g., &dns_master_style_default). + * + * dns_zone_dumptostream() is a backward-compatible form of + * dns_zone_dumptostream2(), which always uses the dns_masterformat_text + * format and the dns_master_style_default style. + * + * dns_zone_dumptostream2() is a backward-compatible form of + * dns_zone_dumptostream3(), which always uses the current + * default raw file format version. + * + * Note that dns_zone_dumptostream3() is the most flexible form. It + * can also provide the functionality of dns_zone_fulldumptostream(). + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'fd' to be a stream open for writing. + */ + +void +dns_zone_maintenance(dns_zone_t *zone); +/*%< + * Perform regular maintenance on the zone. This is called as a + * result of a zone being managed. + * + * Require + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_setprimaries(dns_zone_t *zone, const isc_sockaddr_t *primaries, + uint32_t count); +isc_result_t +dns_zone_setprimarieswithkeys(dns_zone_t *zone, const isc_sockaddr_t *primaries, + dns_name_t **keynames, uint32_t count); +/*%< + * Set the list of master servers for the zone. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'primaries' array of isc_sockaddr_t with port set or NULL. + *\li 'count' the number of primaries. + *\li 'keynames' array of dns_name_t's for tsig keys or NULL. + * + *\li If 'primaries' is NULL then 'count' must be zero. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li Any result dns_name_dup() can return, if keynames!=NULL + */ + +isc_result_t +dns_zone_setparentals(dns_zone_t *zone, const isc_sockaddr_t *parentals, + dns_name_t **keynames, uint32_t count); +/*%< + * Set the list of parental agents for the zone. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'parentals' array of isc_sockaddr_t with port set or NULL. + *\li 'count' the number of primaries. + *\li 'keynames' array of dns_name_t's for tsig keys or NULL. + * + *\li If 'parentals' is NULL then 'count' must be zero. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li Any result dns_name_dup() can return, if keynames!=NULL + */ + +isc_result_t +dns_zone_setalsonotify(dns_zone_t *zone, const isc_sockaddr_t *notify, + uint32_t count); +isc_result_t +dns_zone_setalsonotifywithkeys(dns_zone_t *zone, const isc_sockaddr_t *notify, + dns_name_t **keynames, uint32_t count); +isc_result_t +dns_zone_setalsonotifydscpkeys(dns_zone_t *zone, const isc_sockaddr_t *notify, + const isc_dscp_t *dscps, dns_name_t **keynames, + uint32_t count); +/*%< + * Set the list of additional servers to be notified when + * a zone changes. To clear the list use 'count = 0'. + * + * dns_zone_alsonotifywithkeys() allows each notify address to + * be associated with a TSIG key. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'notify' to be non-NULL if count != 0. + *\li 'count' to be the number of notifiees. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +void +dns_zone_unload(dns_zone_t *zone); +/*%< + * detach the database from the zone structure. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +dns_kasp_t * +dns_zone_getkasp(dns_zone_t *zone); +/*%< + * Returns the current kasp. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_setkasp(dns_zone_t *zone, dns_kasp_t *kasp); +/*%< + * Set kasp for zone. If a kasp is already set, it will be detached. + * + * Requires: + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_setoption(dns_zone_t *zone, dns_zoneopt_t option, bool value); +/*%< + * Set the given options on ('value' == true) or off + * ('value' == #false). + * + * Require: + *\li 'zone' to be a valid zone. + */ + +dns_zoneopt_t +dns_zone_getoptions(dns_zone_t *zone); +/*%< + * Returns the current zone options. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_setkeyopt(dns_zone_t *zone, unsigned int option, bool value); +/*%< + * Set key options on ('value' == true) or off ('value' == + * #false). + * + * Require: + *\li 'zone' to be a valid zone. + */ + +unsigned int +dns_zone_getkeyopts(dns_zone_t *zone); +/*%< + * Returns the current zone key options. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_setminrefreshtime(dns_zone_t *zone, uint32_t val); +/*%< + * Set the minimum refresh time. + * + * Requires: + *\li 'zone' is valid. + *\li val > 0. + */ + +void +dns_zone_setmaxrefreshtime(dns_zone_t *zone, uint32_t val); +/*%< + * Set the maximum refresh time. + * + * Requires: + *\li 'zone' is valid. + *\li val > 0. + */ + +void +dns_zone_setminretrytime(dns_zone_t *zone, uint32_t val); +/*%< + * Set the minimum retry time. + * + * Requires: + *\li 'zone' is valid. + *\li val > 0. + */ + +void +dns_zone_setmaxretrytime(dns_zone_t *zone, uint32_t val); +/*%< + * Set the maximum retry time. + * + * Requires: + *\li 'zone' is valid. + * val > 0. + */ + +isc_result_t +dns_zone_setxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *xfrsource); +isc_result_t +dns_zone_setaltxfrsource4(dns_zone_t *zone, const isc_sockaddr_t *xfrsource); +/*%< + * Set the source address to be used in IPv4 zone transfers. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'xfrsource' to contain the address. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +isc_sockaddr_t * +dns_zone_getxfrsource4(dns_zone_t *zone); +isc_sockaddr_t * +dns_zone_getaltxfrsource4(dns_zone_t *zone); +/*%< + * Returns the source address set by a previous dns_zone_setxfrsource4 + * call, or the default of inaddr_any, port 0. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_setxfrsource4dscp(dns_zone_t *zone, isc_dscp_t dscp); +isc_result_t +dns_zone_setaltxfrsource4dscp(dns_zone_t *zone, isc_dscp_t dscp); +/*%< + * Set the DSCP value associated with the transfer/alt-transfer source. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +isc_dscp_t +dns_zone_getxfrsource4dscp(dns_zone_t *zone); +isc_dscp_t +dns_zone_getaltxfrsource4dscp(dns_zone_t *zone); +/*%/ + * Get the DSCP value associated with the transfer/alt-transfer source. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_setxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource); +isc_result_t +dns_zone_setaltxfrsource6(dns_zone_t *zone, const isc_sockaddr_t *xfrsource); +/*%< + * Set the source address to be used in IPv6 zone transfers. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'xfrsource' to contain the address. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +isc_sockaddr_t * +dns_zone_getxfrsource6(dns_zone_t *zone); +isc_sockaddr_t * +dns_zone_getaltxfrsource6(dns_zone_t *zone); +/*%< + * Returns the source address set by a previous dns_zone_setxfrsource6 + * call, or the default of in6addr_any, port 0. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_dscp_t +dns_zone_getxfrsource6dscp(dns_zone_t *zone); +isc_dscp_t +dns_zone_getaltxfrsource6dscp(dns_zone_t *zone); +/*%/ + * Get the DSCP value associated with the transfer/alt-transfer source. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_setxfrsource6dscp(dns_zone_t *zone, isc_dscp_t dscp); +isc_result_t +dns_zone_setaltxfrsource6dscp(dns_zone_t *zone, isc_dscp_t dscp); +/*%< + * Set the DSCP value associated with the transfer/alt-transfer source. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +isc_result_t +dns_zone_setparentalsrc4(dns_zone_t *zone, const isc_sockaddr_t *parentalsrc); +/*%< + * Set the source address to be used with IPv4 parental DS queries. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'parentalsrc' to contain the address. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +isc_sockaddr_t * +dns_zone_getparentalsrc4(dns_zone_t *zone); +/*%< + * Returns the source address set by a previous dns_zone_setparentalsrc4 + * call, or the default of inaddr_any, port 0. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_dscp_t +dns_zone_getparentalsrc4dscp(dns_zone_t *zone); +/*%/ + * Get the DSCP value associated with the IPv4 parental source. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_setparentalsrc4dscp(dns_zone_t *zone, isc_dscp_t dscp); +/*%< + * Set the DSCP value associated with the IPv4 parental source. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +isc_result_t +dns_zone_setparentalsrc6(dns_zone_t *zone, const isc_sockaddr_t *parentalsrc); +/*%< + * Set the source address to be used with IPv6 parental DS queries. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'parentalsrc' to contain the address. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +isc_sockaddr_t * +dns_zone_getparentalsrc6(dns_zone_t *zone); +/*%< + * Returns the source address set by a previous dns_zone_setparentalsrc6 + * call, or the default of in6addr_any, port 0. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_dscp_t +dns_zone_getparentalsrc6dscp(dns_zone_t *zone); +/*%/ + * Get the DSCP value associated with the IPv6 parental source. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_setparentalsrc6dscp(dns_zone_t *zone, isc_dscp_t dscp); +/*%< + * Set the DSCP value associated with the IPv6 parental source. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +isc_result_t +dns_zone_setnotifysrc4(dns_zone_t *zone, const isc_sockaddr_t *notifysrc); +/*%< + * Set the source address to be used with IPv4 NOTIFY messages. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'notifysrc' to contain the address. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +isc_sockaddr_t * +dns_zone_getnotifysrc4(dns_zone_t *zone); +/*%< + * Returns the source address set by a previous dns_zone_setnotifysrc4 + * call, or the default of inaddr_any, port 0. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_dscp_t +dns_zone_getnotifysrc4dscp(dns_zone_t *zone); +/*%/ + * Get the DSCP value associated with the IPv4 notify source. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_setnotifysrc4dscp(dns_zone_t *zone, isc_dscp_t dscp); +/*%< + * Set the DSCP value associated with the IPv4 notify source. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +isc_result_t +dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc); +/*%< + * Set the source address to be used with IPv6 NOTIFY messages. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'notifysrc' to contain the address. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +isc_sockaddr_t * +dns_zone_getnotifysrc6(dns_zone_t *zone); +/*%< + * Returns the source address set by a previous dns_zone_setnotifysrc6 + * call, or the default of in6addr_any, port 0. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_dscp_t +dns_zone_getnotifysrc6dscp(dns_zone_t *zone); +/*%/ + * Get the DSCP value associated with the IPv6 notify source. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_setnotifysrc6dscp(dns_zone_t *zone, isc_dscp_t dscp); +/*%< + * Set the DSCP value associated with the IPv6 notify source. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li #ISC_R_SUCCESS + */ + +void +dns_zone_setnotifyacl(dns_zone_t *zone, dns_acl_t *acl); +/*%< + * Sets the notify acl list for the zone. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'acl' to be a valid acl. + */ + +void +dns_zone_setqueryacl(dns_zone_t *zone, dns_acl_t *acl); +/*%< + * Sets the query acl list for the zone. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'acl' to be a valid acl. + */ + +void +dns_zone_setqueryonacl(dns_zone_t *zone, dns_acl_t *acl); +/*%< + * Sets the query-on acl list for the zone. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'acl' to be a valid acl. + */ + +void +dns_zone_setupdateacl(dns_zone_t *zone, dns_acl_t *acl); +/*%< + * Sets the update acl list for the zone. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'acl' to be valid acl. + */ + +void +dns_zone_setforwardacl(dns_zone_t *zone, dns_acl_t *acl); +/*%< + * Sets the forward unsigned updates acl list for the zone. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'acl' to be valid acl. + */ + +void +dns_zone_setxfracl(dns_zone_t *zone, dns_acl_t *acl); +/*%< + * Sets the transfer acl list for the zone. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'acl' to be valid acl. + */ + +dns_acl_t * +dns_zone_getnotifyacl(dns_zone_t *zone); +/*%< + * Returns the current notify acl or NULL. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li acl a pointer to the acl. + *\li NULL + */ + +dns_acl_t * +dns_zone_getqueryacl(dns_zone_t *zone); +/*%< + * Returns the current query acl or NULL. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li acl a pointer to the acl. + *\li NULL + */ + +dns_acl_t * +dns_zone_getqueryonacl(dns_zone_t *zone); +/*%< + * Returns the current query-on acl or NULL. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li acl a pointer to the acl. + *\li NULL + */ + +dns_acl_t * +dns_zone_getupdateacl(dns_zone_t *zone); +/*%< + * Returns the current update acl or NULL. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li acl a pointer to the acl. + *\li NULL + */ + +dns_acl_t * +dns_zone_getforwardacl(dns_zone_t *zone); +/*%< + * Returns the current forward unsigned updates acl or NULL. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li acl a pointer to the acl. + *\li NULL + */ + +dns_acl_t * +dns_zone_getxfracl(dns_zone_t *zone); +/*%< + * Returns the current transfer acl or NULL. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li acl a pointer to the acl. + *\li NULL + */ + +void +dns_zone_clearupdateacl(dns_zone_t *zone); +/*%< + * Clear the current update acl. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_clearforwardacl(dns_zone_t *zone); +/*%< + * Clear the current forward unsigned updates acl. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_clearnotifyacl(dns_zone_t *zone); +/*%< + * Clear the current notify acl. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_clearqueryacl(dns_zone_t *zone); +/*%< + * Clear the current query acl. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_clearqueryonacl(dns_zone_t *zone); +/*%< + * Clear the current query-on acl. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_clearxfracl(dns_zone_t *zone); +/*%< + * Clear the current transfer acl. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +bool +dns_zone_getupdatedisabled(dns_zone_t *zone); +/*%< + * Return update disabled. + * Transient unless called when running in isc_task_exclusive() mode. + */ + +void +dns_zone_setupdatedisabled(dns_zone_t *zone, bool state); +/*%< + * Set update disabled. + * Should only be called only when running in isc_task_exclusive() mode. + * Failure to do so may result in updates being committed after the + * call has been made. + */ + +bool +dns_zone_getzeronosoattl(dns_zone_t *zone); +/*%< + * Return zero-no-soa-ttl status. + */ + +void +dns_zone_setzeronosoattl(dns_zone_t *zone, bool state); +/*%< + * Set zero-no-soa-ttl status. + */ + +void +dns_zone_setchecknames(dns_zone_t *zone, dns_severity_t severity); +/*%< + * Set the severity of name checking when loading a zone. + * + * Require: + * \li 'zone' to be a valid zone. + */ + +dns_severity_t +dns_zone_getchecknames(dns_zone_t *zone); +/*%< + * Return the current severity of name checking. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void +dns_zone_setjournalsize(dns_zone_t *zone, int32_t size); +/*%< + * Sets the journal size for the zone. + * + * Requires: + *\li 'zone' to be a valid zone. + */ + +int32_t +dns_zone_getjournalsize(dns_zone_t *zone); +/*%< + * Return the journal size as set with a previous call to + * dns_zone_setjournalsize(). + * + * Requires: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, + isc_sockaddr_t *to, dns_message_t *msg); +/*%< + * Tell the zone that it has received a NOTIFY message from another + * server. This may cause some zone maintenance activity to occur. + * + * Requires: + *\li 'zone' to be a valid zone. + *\li '*from' to contain the address of the server from which 'msg' + * was received. + *\li 'msg' a message with opcode NOTIFY and qr clear. + * + * Returns: + *\li DNS_R_REFUSED + *\li DNS_R_NOTIMP + *\li DNS_R_FORMERR + *\li DNS_R_SUCCESS + */ + +void +dns_zone_setmaxxfrin(dns_zone_t *zone, uint32_t maxxfrin); +/*%< + * Set the maximum time (in seconds) that a zone transfer in (AXFR/IXFR) + * of this zone will use before being aborted. + * + * Requires: + * \li 'zone' to be valid initialised zone. + */ + +uint32_t +dns_zone_getmaxxfrin(dns_zone_t *zone); +/*%< + * Returns the maximum transfer time for this zone. This will be + * either the value set by the last call to dns_zone_setmaxxfrin() or + * the default value of 1 hour. + * + * Requires: + *\li 'zone' to be valid initialised zone. + */ + +void +dns_zone_setmaxxfrout(dns_zone_t *zone, uint32_t maxxfrout); +/*%< + * Set the maximum time (in seconds) that a zone transfer out (AXFR/IXFR) + * of this zone will use before being aborted. + * + * Requires: + * \li 'zone' to be valid initialised zone. + */ + +uint32_t +dns_zone_getmaxxfrout(dns_zone_t *zone); +/*%< + * Returns the maximum transfer time for this zone. This will be + * either the value set by the last call to dns_zone_setmaxxfrout() or + * the default value of 1 hour. + * + * Requires: + *\li 'zone' to be valid initialised zone. + */ + +isc_result_t +dns_zone_setjournal(dns_zone_t *zone, const char *myjournal); +/*%< + * Sets the filename used for journaling updates / IXFR transfers. + * The default journal name is set by dns_zone_setfile() to be + * "file.jnl". If 'myjournal' is NULL, the zone will have no + * journal name. + * + * Requires: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +char * +dns_zone_getjournal(dns_zone_t *zone); +/*%< + * Returns the journal name associated with this zone. + * If no journal has been set this will be NULL. + * + * Requires: + *\li 'zone' to be valid initialised zone. + */ + +dns_zonetype_t +dns_zone_gettype(dns_zone_t *zone); +/*%< + * Returns the type of the zone (master/slave/etc.) + * + * Requires: + *\li 'zone' to be valid initialised zone. + */ + +dns_zonetype_t +dns_zone_getredirecttype(dns_zone_t *zone); +/*%< + * Returns whether the redirect zone is configured as a master or a + * slave zone. + * + * Requires: + *\li 'zone' to be valid initialised zone. + *\li 'zone' to be a redirect zone. + * + * Returns: + *\li 'dns_zone_primary' + *\li 'dns_zone_secondary' + */ + +void +dns_zone_settask(dns_zone_t *zone, isc_task_t *task); +/*%< + * Give a zone a task to work with. Any current task will be detached. + * + * Requires: + *\li 'zone' to be valid. + *\li 'task' to be valid. + */ + +void +dns_zone_gettask(dns_zone_t *zone, isc_task_t **target); +/*%< + * Attach '*target' to the zone's task. + * + * Requires: + *\li 'zone' to be valid initialised zone. + *\li 'zone' to have a task. + *\li 'target' to be != NULL && '*target' == NULL. + */ + +void +dns_zone_notify(dns_zone_t *zone); +/*%< + * Generate notify events for this zone. + * + * Requires: + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_replacedb(dns_zone_t *zone, dns_db_t *db, bool dump); +/*%< + * Replace the database of "zone" with a new database "db". + * + * If "dump" is true, then the new zone contents are dumped + * into to the zone's master file for persistence. When replacing + * a zone database by one just loaded from a master file, set + * "dump" to false to avoid a redundant redump of the data just + * loaded. Otherwise, it should be set to true. + * + * If the "diff-on-reload" option is enabled in the configuration file, + * the differences between the old and the new database are added to the + * journal file, and the master file dump is postponed. + * + * Requires: + * \li 'zone' to be a valid zone. + * + * Returns: + * \li DNS_R_SUCCESS + * \li DNS_R_BADZONE zone failed basic consistency checks: + * * a single SOA must exist + * * some NS records must exist. + * Others + */ + +uint32_t +dns_zone_getidlein(dns_zone_t *zone); +/*%< + * Requires: + * \li 'zone' to be a valid zone. + * + * Returns: + * \li number of seconds of idle time before we abort the transfer in. + */ + +void +dns_zone_setidlein(dns_zone_t *zone, uint32_t idlein); +/*%< + * \li Set the idle timeout for transfer the. + * \li Zero set the default value, 1 hour. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +uint32_t +dns_zone_getidleout(dns_zone_t *zone); +/*%< + * + * Requires: + * \li 'zone' to be a valid zone. + * + * Returns: + * \li number of seconds of idle time before we abort a transfer out. + */ + +void +dns_zone_setidleout(dns_zone_t *zone, uint32_t idleout); +/*%< + * \li Set the idle timeout for transfers out. + * \li Zero set the default value, 1 hour. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +void +dns_zone_getssutable(dns_zone_t *zone, dns_ssutable_t **table); +/*%< + * Get the simple-secure-update policy table. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +void +dns_zone_setssutable(dns_zone_t *zone, dns_ssutable_t *table); +/*%< + * Set / clear the simple-secure-update policy table. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +isc_mem_t * +dns_zone_getmctx(dns_zone_t *zone); +/*%< + * Get the memory context of a zone. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +dns_zonemgr_t * +dns_zone_getmgr(dns_zone_t *zone); +/*%< + * If 'zone' is managed return the zone manager otherwise NULL. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +void +dns_zone_setsigvalidityinterval(dns_zone_t *zone, uint32_t interval); +/*%< + * Set the zone's general signature validity interval. This is the length + * of time for which DNSSEC signatures created as a result of dynamic + * updates to secure zones will remain valid, in seconds. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +uint32_t +dns_zone_getsigvalidityinterval(dns_zone_t *zone); +/*%< + * Get the zone's general signature validity interval. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +void +dns_zone_setkeyvalidityinterval(dns_zone_t *zone, uint32_t interval); +/*%< + * Set the zone's DNSKEY signature validity interval. This is the length + * of time for which DNSSEC signatures created for DNSKEY records + * will remain valid, in seconds. + * + * If this value is set to zero, then the regular signature validity + * interval (see dns_zone_setsigvalidityinterval(), above) is used + * for all RRSIGs. However, if this value is nonzero, then it is used + * as the validity interval for RRSIGs covering DNSKEY and CDNSKEY + * RRsets. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +uint32_t +dns_zone_getkeyvalidityinterval(dns_zone_t *zone); +/*%< + * Get the zone's DNSKEY signature validity interval. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +void +dns_zone_setsigresigninginterval(dns_zone_t *zone, uint32_t interval); +/*%< + * Set the zone's RRSIG re-signing interval. A dynamic zone's RRSIG's + * will be re-signed 'interval' amount of time before they expire. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +uint32_t +dns_zone_getsigresigninginterval(dns_zone_t *zone); +/*%< + * Get the zone's RRSIG re-signing interval. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +void +dns_zone_setnotifytype(dns_zone_t *zone, dns_notifytype_t notifytype); +/*%< + * Sets zone notify method to "notifytype" + */ + +isc_result_t +dns_zone_forwardupdate(dns_zone_t *zone, dns_message_t *msg, + dns_updatecallback_t callback, void *callback_arg); +/*%< + * Forward 'msg' to each master in turn until we get an answer or we + * have exhausted the list of primaries. 'callback' will be called with + * ISC_R_SUCCESS if we get an answer and the returned message will be + * passed as 'answer_message', otherwise a non ISC_R_SUCCESS result code + * will be passed and answer_message will be NULL. The callback function + * is responsible for destroying 'answer_message'. + * (callback)(callback_arg, result, answer_message); + * + * Require: + *\li 'zone' to be valid + *\li 'msg' to be valid. + *\li 'callback' to be non NULL. + * Returns: + *\li #ISC_R_SUCCESS if the message has been forwarded, + *\li #ISC_R_NOMEMORY + *\li Others + */ + +isc_result_t +dns_zone_next(dns_zone_t *zone, dns_zone_t **next); +/*%< + * Find the next zone in the list of managed zones. + * + * Requires: + *\li 'zone' to be valid + *\li The zone manager for the indicated zone MUST be locked + * by the caller. This is not checked. + *\li 'next' be non-NULL, and '*next' be NULL. + * + * Ensures: + *\li 'next' points to a valid zone (result ISC_R_SUCCESS) or to NULL + * (result ISC_R_NOMORE). + */ + +isc_result_t +dns_zone_first(dns_zonemgr_t *zmgr, dns_zone_t **first); +/*%< + * Find the first zone in the list of managed zones. + * + * Requires: + *\li 'zonemgr' to be valid + *\li The zone manager for the indicated zone MUST be locked + * by the caller. This is not checked. + *\li 'first' be non-NULL, and '*first' be NULL + * + * Ensures: + *\li 'first' points to a valid zone (result ISC_R_SUCCESS) or to NULL + * (result ISC_R_NOMORE). + */ + +isc_result_t +dns_zone_setkeydirectory(dns_zone_t *zone, const char *directory); +/*%< + * Sets the name of the directory where private keys used for + * online signing of dynamic zones are found. + * + * Require: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li #ISC_R_NOMEMORY + *\li #ISC_R_SUCCESS + */ + +const char * +dns_zone_getkeydirectory(dns_zone_t *zone); +/*%< + * Gets the name of the directory where private keys used for + * online signing of dynamic zones are found. + * + * Requires: + *\li 'zone' to be valid initialised zone. + * + * Returns: + * Pointer to null-terminated file name, or NULL. + */ + +isc_result_t +dns_zone_getdnsseckeys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, + isc_stdtime_t now, dns_dnsseckeylist_t *keys); +/*% + * Find DNSSEC keys used for signing with dnssec-policy. Load these keys + * into 'keys'. + * + * Requires: + *\li 'zone' to be valid initialised zone. + *\li 'keys' to be an initialised DNSSEC keylist. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li Error + */ + +isc_result_t +dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, + dns_zonemgr_t **zmgrp); +/*%< + * Create a zone manager. Note: the zone manager will not be able to + * manage any zones until dns_zonemgr_setsize() has been run. + * + * Requires: + *\li 'mctx' to be a valid memory context. + *\li 'taskmgr' to be a valid task manager. + *\li 'timermgr' to be a valid timer manager. + *\li 'zmgrp' to point to a NULL pointer. + */ + +isc_result_t +dns_zonemgr_setsize(dns_zonemgr_t *zmgr, int num_zones); +/*%< + * Set the size of the zone manager task pool. This must be run + * before zmgr can be used for managing zones. Currently, it can only + * be run once; the task pool cannot be resized. + * + * Requires: + *\li zmgr is a valid zone manager. + *\li zmgr->zonetasks has been initialized. + */ + +isc_result_t +dns_zonemgr_createzone(dns_zonemgr_t *zmgr, dns_zone_t **zonep); +/*%< + * Allocate a new zone using a memory context from the + * zone manager's memory context pool. + * + * Require: + *\li 'zmgr' to be a valid zone manager. + *\li 'zonep' != NULL and '*zonep' == NULL. + */ + +isc_result_t +dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone); +/*%< + * Bring the zone under control of a zone manager. + * + * Require: + *\li 'zmgr' to be a valid zone manager. + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zonemgr_forcemaint(dns_zonemgr_t *zmgr); +/*%< + * Force zone maintenance of all loaded zones managed by 'zmgr' + * to take place at the system's earliest convenience. + */ + +void +dns__zonemgr_run(isc_task_t *task, isc_event_t *event); +/*%< + * Event handler to call dns_zonemgr_forcemaint(); used to start + * zone operations from a unit test. Not intended for use outside + * libdns or related tests. + */ + +void +dns_zonemgr_resumexfrs(dns_zonemgr_t *zmgr); +/*%< + * Attempt to start any stalled zone transfers. + */ + +void +dns_zonemgr_shutdown(dns_zonemgr_t *zmgr); +/*%< + * Shut down the zone manager. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + */ + +void +dns_zonemgr_attach(dns_zonemgr_t *source, dns_zonemgr_t **target); +/*%< + * Attach '*target' to 'source' incrementing its external + * reference count. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'target' to be non NULL and '*target' to be NULL. + */ + +void +dns_zonemgr_detach(dns_zonemgr_t **zmgrp); +/*%< + * Detach from a zone manager. + * + * Requires: + *\li '*zmgrp' is a valid, non-NULL zone manager pointer. + * + * Ensures: + *\li '*zmgrp' is NULL. + */ + +void +dns_zonemgr_releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone); +/*%< + * Release 'zone' from the managed by 'zmgr'. 'zmgr' is implicitly + * detached from 'zone'. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + *\li 'zone' to be a valid zone. + *\li 'zmgr' == 'zone->zmgr' + * + * Ensures: + *\li 'zone->zmgr' == NULL; + */ + +isc_taskmgr_t * +dns_zonemgr_gettaskmgr(dns_zonemgr_t *zmgr); +/*% + * Get the tasmkgr object attached to 'zmgr'. + */ + +void +dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, uint32_t value); +/*%< + * Set the maximum number of simultaneous transfers in allowed by + * the zone manager. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + */ + +uint32_t +dns_zonemgr_getttransfersin(dns_zonemgr_t *zmgr); +/*%< + * Return the maximum number of simultaneous transfers in allowed. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + */ + +void +dns_zonemgr_settransfersperns(dns_zonemgr_t *zmgr, uint32_t value); +/*%< + * Set the number of zone transfers allowed per nameserver. + * + * Requires: + *\li 'zmgr' to be a valid zone manager + */ + +uint32_t +dns_zonemgr_getttransfersperns(dns_zonemgr_t *zmgr); +/*%< + * Return the number of transfers allowed per nameserver. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + */ + +void +dns_zonemgr_setiolimit(dns_zonemgr_t *zmgr, uint32_t iolimit); +/*%< + * Set the number of simultaneous file descriptors available for + * reading and writing masterfiles. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + *\li 'iolimit' to be positive. + */ + +uint32_t +dns_zonemgr_getiolimit(dns_zonemgr_t *zmgr); +/*%< + * Get the number of simultaneous file descriptors available for + * reading and writing masterfiles. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + */ + +void +dns_zonemgr_setcheckdsrate(dns_zonemgr_t *zmgr, unsigned int value); +/*%< + * Set the number of parental DS queries sent per second. + * + * Requires: + *\li 'zmgr' to be a valid zone manager + */ + +void +dns_zonemgr_setnotifyrate(dns_zonemgr_t *zmgr, unsigned int value); +/*%< + * Set the number of NOTIFY requests sent per second. + * + * Requires: + *\li 'zmgr' to be a valid zone manager + */ + +void +dns_zonemgr_setstartupnotifyrate(dns_zonemgr_t *zmgr, unsigned int value); +/*%< + * Set the number of startup NOTIFY requests sent per second. + * + * Requires: + *\li 'zmgr' to be a valid zone manager + */ + +void +dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value); +/*%< + * Set the number of SOA queries sent per second. + * + * Requires: + *\li 'zmgr' to be a valid zone manager + */ + +unsigned int +dns_zonemgr_getnotifyrate(dns_zonemgr_t *zmgr); +/*%< + * Return the number of NOTIFY requests sent per second. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + */ + +unsigned int +dns_zonemgr_getstartupnotifyrate(dns_zonemgr_t *zmgr); +/*%< + * Return the number of startup NOTIFY requests sent per second. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + */ + +unsigned int +dns_zonemgr_getserialqueryrate(dns_zonemgr_t *zmgr); +/*%< + * Return the number of SOA queries sent per second. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + */ + +unsigned int +dns_zonemgr_getcount(dns_zonemgr_t *zmgr, int state); +/*%< + * Returns the number of zones in the specified state. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + *\li 'state' to be a valid DNS_ZONESTATE_ constant. + */ + +void +dns_zonemgr_unreachableadd(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, + isc_sockaddr_t *local, isc_time_t *now); +/*%< + * Add the pair of addresses to the unreachable cache. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + *\li 'remote' to be a valid sockaddr. + *\li 'local' to be a valid sockaddr. + */ + +bool +dns_zonemgr_unreachable(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, + isc_sockaddr_t *local, isc_time_t *now); +/*%< + * Returns true if the given local/remote address pair + * is found in the zone maanger's unreachable cache. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + *\li 'remote' to be a valid sockaddr. + *\li 'local' to be a valid sockaddr. + *\li 'now' != NULL + */ + +void +dns_zonemgr_unreachabledel(dns_zonemgr_t *zmgr, isc_sockaddr_t *remote, + isc_sockaddr_t *local); +/*%< + * Remove the pair of addresses from the unreachable cache. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + *\li 'remote' to be a valid sockaddr. + *\li 'local' to be a valid sockaddr. + */ + +void +dns_zone_forcereload(dns_zone_t *zone); +/*%< + * Force a reload of specified zone. + * + * Requires: + *\li 'zone' to be a valid zone. + */ + +bool +dns_zone_isforced(dns_zone_t *zone); +/*%< + * Check if the zone is waiting a forced reload. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zone_setstatistics(dns_zone_t *zone, bool on); +/*%< + * This function is obsoleted by dns_zone_setrequeststats(). + */ + +uint64_t * +dns_zone_getstatscounters(dns_zone_t *zone); +/*%< + * This function is obsoleted by dns_zone_getrequeststats(). + */ + +void +dns_zone_setstats(dns_zone_t *zone, isc_stats_t *stats); +/*%< + * Set a general zone-maintenance statistics set 'stats' for 'zone'. This + * function is expected to be called only on zone creation (when necessary). + * Once installed, it cannot be removed or replaced. Also, there is no + * interface to get the installed stats from the zone; the caller must keep the + * stats to reference (e.g. dump) it later. + * + * Requires: + * \li 'zone' to be a valid zone and does not have a statistics set already + * installed. + * + *\li stats is a valid statistics supporting zone statistics counters + * (see dns/stats.h). + */ + +void +dns_zone_setrequeststats(dns_zone_t *zone, isc_stats_t *stats); + +void +dns_zone_setrcvquerystats(dns_zone_t *zone, dns_stats_t *stats); + +void +dns_zone_setdnssecsignstats(dns_zone_t *zone, dns_stats_t *stats); +/*%< + * Set additional statistics sets to zone. These are attached to the zone + * but are not counted in the zone module; only the caller updates the + * counters. + * + * Requires: + * \li 'zone' to be a valid zone. + * + *\li stats is a valid statistics. + */ + +isc_stats_t * +dns_zone_getrequeststats(dns_zone_t *zone); + +dns_stats_t * +dns_zone_getrcvquerystats(dns_zone_t *zone); + +dns_stats_t * +dns_zone_getdnssecsignstats(dns_zone_t *zone); +/*%< + * Get the additional statistics for zone, if one is installed. + * + * Requires: + * \li 'zone' to be a valid zone. + * + * Returns: + * \li when available, a pointer to the statistics set installed in zone; + * otherwise NULL. + */ + +void +dns_zone_dialup(dns_zone_t *zone); +/*%< + * Perform dialup-time maintenance on 'zone'. + */ + +void +dns_zone_setdialup(dns_zone_t *zone, dns_dialuptype_t dialup); +/*%< + * Set the dialup type of 'zone' to 'dialup'. + * + * Requires: + * \li 'zone' to be valid initialised zone. + *\li 'dialup' to be a valid dialup type. + */ + +void +dns_zone_logv(dns_zone_t *zone, isc_logcategory_t *category, int level, + const char *prefix, const char *msg, va_list ap); +/*%< + * Log the message 'msg...' at 'level' using log category 'category', including + * text that identifies the message as applying to 'zone'. If the (optional) + * 'prefix' is not NULL, it will be placed at the start of the entire log line. + */ + +void +dns_zone_log(dns_zone_t *zone, int level, const char *msg, ...) + ISC_FORMAT_PRINTF(3, 4); +/*%< + * Log the message 'msg...' at 'level', including text that identifies + * the message as applying to 'zone'. + */ + +void +dns_zone_logc(dns_zone_t *zone, isc_logcategory_t *category, int level, + const char *msg, ...) ISC_FORMAT_PRINTF(4, 5); +/*%< + * Log the message 'msg...' at 'level', including text that identifies + * the message as applying to 'zone'. + */ + +void +dns_zone_name(dns_zone_t *zone, char *buf, size_t len); +/*%< + * Return the name of the zone with class and view. + * + * Requires: + *\li 'zone' to be valid. + *\li 'buf' to be non NULL. + */ + +void +dns_zone_nameonly(dns_zone_t *zone, char *buf, size_t len); +/*%< + * Return the name of the zone only. + * + * Requires: + *\li 'zone' to be valid. + *\li 'buf' to be non NULL. + */ + +isc_result_t +dns_zone_checknames(dns_zone_t *zone, const dns_name_t *name, + dns_rdata_t *rdata); +/*%< + * Check if this record meets the check-names policy. + * + * Requires: + * 'zone' to be valid. + * 'name' to be valid. + * 'rdata' to be valid. + * + * Returns: + * DNS_R_SUCCESS passed checks. + * DNS_R_BADOWNERNAME failed ownername checks. + * DNS_R_BADNAME failed rdata checks. + */ + +void +dns_zone_setcheckmx(dns_zone_t *zone, dns_checkmxfunc_t checkmx); +/*%< + * Set the post load integrity callback function 'checkmx'. + * 'checkmx' will be called if the MX TARGET is not within the zone. + * + * Require: + * 'zone' to be a valid zone. + */ + +void +dns_zone_setchecksrv(dns_zone_t *zone, dns_checkmxfunc_t checksrv); +/*%< + * Set the post load integrity callback function 'checksrv'. + * 'checksrv' will be called if the SRV TARGET is not within the zone. + * + * Require: + * 'zone' to be a valid zone. + */ + +void +dns_zone_setcheckns(dns_zone_t *zone, dns_checknsfunc_t checkns); +/*%< + * Set the post load integrity callback function 'checkns'. + * 'checkns' will be called if the NS TARGET is not within the zone. + * + * Require: + * 'zone' to be a valid zone. + */ + +void +dns_zone_setnotifydelay(dns_zone_t *zone, uint32_t delay); +/*%< + * Set the minimum delay between sets of notify messages. + * + * Requires: + * 'zone' to be valid. + */ + +uint32_t +dns_zone_getnotifydelay(dns_zone_t *zone); +/*%< + * Get the minimum delay between sets of notify messages. + * + * Requires: + * 'zone' to be valid. + */ + +void +dns_zone_setisself(dns_zone_t *zone, dns_isselffunc_t isself, void *arg); +/*%< + * Set the isself callback function and argument. + * + * bool + * isself(dns_view_t *myview, dns_tsigkey_t *mykey, + * const isc_netaddr_t *srcaddr, const isc_netaddr_t *destaddr, + * dns_rdataclass_t rdclass, void *arg); + * + * 'isself' returns true if a non-recursive query from 'srcaddr' to + * 'destaddr' with optional key 'mykey' for class 'rdclass' would be + * delivered to 'myview'. + */ + +void +dns_zone_setnodes(dns_zone_t *zone, uint32_t nodes); +/*%< + * Set the number of nodes that will be checked per quantum. + */ + +void +dns_zone_setsignatures(dns_zone_t *zone, uint32_t signatures); +/*%< + * Set the number of signatures that will be generated per quantum. + */ + +uint32_t +dns_zone_getsignatures(dns_zone_t *zone); +/*%< + * Get the number of signatures that will be generated per quantum. + */ + +isc_result_t +dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, uint16_t keyid, + bool deleteit); +/*%< + * Initiate/resume signing of the entire zone with the zone DNSKEY(s) + * that match the given algorithm and keyid. + */ + +isc_result_t +dns_zone_addnsec3chain(dns_zone_t *zone, dns_rdata_nsec3param_t *nsec3param); +/*%< + * Incrementally add a NSEC3 chain that corresponds to 'nsec3param'. + */ + +void +dns_zone_setprivatetype(dns_zone_t *zone, dns_rdatatype_t type); +dns_rdatatype_t +dns_zone_getprivatetype(dns_zone_t *zone); +/* + * Get/Set the private record type. It is expected that these interfaces + * will not be permanent. + */ + +void +dns_zone_rekey(dns_zone_t *zone, bool fullsign); +/*%< + * Update the zone's DNSKEY set from the key repository. + * + * If 'fullsign' is true, trigger an immediate full signing of + * the zone with the new key. Otherwise, if there are no keys or + * if the new keys are for algorithms that have already signed the + * zone, then the zone can be re-signed incrementally. + */ + +isc_result_t +dns_zone_nscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, + unsigned int *errors); +/*% + * Check if the name servers for the zone are sane (have address, don't + * refer to CNAMEs/DNAMEs. The number of constiancy errors detected in + * returned in '*errors' + * + * Requires: + * \li 'zone' to be valid. + * \li 'db' to be valid. + * \li 'version' to be valid or NULL. + * \li 'errors' to be non NULL. + * + * Returns: + * ISC_R_SUCCESS if there were no errors examining the zone contents. + */ + +isc_result_t +dns_zone_cdscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version); +/*% + * Check if CSD, CDNSKEY and DNSKEY are consistent. + * + * Requires: + * \li 'zone' to be valid. + * \li 'db' to be valid. + * \li 'version' to be valid or NULL. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #DNS_R_BADCDS + *\li #DNS_R_BADCDNSKEY + * Others + */ + +void +dns_zone_setadded(dns_zone_t *zone, bool added); +/*% + * Sets the value of zone->added, which should be true for + * zones that were originally added by "rndc addzone". + * + * Requires: + * \li 'zone' to be valid. + */ + +bool +dns_zone_getadded(dns_zone_t *zone); +/*% + * Returns true if the zone was originally added at runtime + * using "rndc addzone". + * + * Requires: + * \li 'zone' to be valid. + */ + +void +dns_zone_setautomatic(dns_zone_t *zone, bool automatic); +/*% + * Sets the value of zone->automatic, which should be true for + * zones that were automatically added by named. + * + * Requires: + * \li 'zone' to be valid. + */ + +bool +dns_zone_getautomatic(dns_zone_t *zone); +/*% + * Returns true if the zone was added automatically by named. + * + * Requires: + * \li 'zone' to be valid. + */ + +isc_result_t +dns_zone_dlzpostload(dns_zone_t *zone, dns_db_t *db); +/*% + * Load the origin names for a writeable DLZ database. + */ + +bool +dns_zone_isdynamic(dns_zone_t *zone, bool ignore_freeze); +/*% + * Return true iff the zone is "dynamic", in the sense that the zone's + * master file (if any) is written by the server, rather than being + * updated manually and read by the server. + * + * This is true for slave zones, stub zones, key zones, and zones that + * allow dynamic updates either by having an update policy ("ssutable") + * or an "allow-update" ACL with a value other than exactly "{ none; }". + * + * If 'ignore_freeze' is true, then the zone which has had updates disabled + * will still report itself to be dynamic. + * + * Requires: + * \li 'zone' to be valid. + */ + +isc_result_t +dns_zone_setrefreshkeyinterval(dns_zone_t *zone, uint32_t interval); +/*% + * Sets the frequency, in minutes, with which the key repository will be + * checked to see if the keys for this zone have been updated. Any value + * higher than 1440 minutes (24 hours) will be silently reduced. A + * value of zero will return an out-of-range error. + * + * Requires: + * \li 'zone' to be valid. + */ + +bool +dns_zone_getrequestexpire(dns_zone_t *zone); +/*% + * Returns the true/false value of the request-expire option in the zone. + * + * Requires: + * \li 'zone' to be valid. + */ + +void +dns_zone_setrequestexpire(dns_zone_t *zone, bool flag); +/*% + * Sets the request-expire option for the zone. Either true or false. The + * default value is determined by the setting of this option in the view. + * + * Requires: + * \li 'zone' to be valid. + */ + +bool +dns_zone_getrequestixfr(dns_zone_t *zone); +/*% + * Returns the true/false value of the request-ixfr option in the zone. + * + * Requires: + * \li 'zone' to be valid. + */ + +void +dns_zone_setrequestixfr(dns_zone_t *zone, bool flag); +/*% + * Sets the request-ixfr option for the zone. Either true or false. The + * default value is determined by the setting of this option in the view. + * + * Requires: + * \li 'zone' to be valid. + */ + +uint32_t +dns_zone_getixfrratio(dns_zone_t *zone); +/*% + * Returns the zone's current IXFR ratio. + * + * Requires: + * \li 'zone' to be valid. + */ + +void +dns_zone_setixfrratio(dns_zone_t *zone, uint32_t ratio); +/*% + * Sets the ratio of IXFR size to zone size above which we use an AXFR + * response, expressed as a percentage. Cannot exceed 100. + * + * Requires: + * \li 'zone' to be valid. + */ + +void +dns_zone_setserialupdatemethod(dns_zone_t *zone, dns_updatemethod_t method); +/*% + * Sets the update method to use when incrementing the zone serial number + * due to a DDNS update. Valid options are dns_updatemethod_increment + * and dns_updatemethod_unixtime. + * + * Requires: + * \li 'zone' to be valid. + */ + +dns_updatemethod_t +dns_zone_getserialupdatemethod(dns_zone_t *zone); +/*% + * Returns the update method to be used when incrementing the zone serial + * number due to a DDNS update. + * + * Requires: + * \li 'zone' to be valid. + */ + +isc_result_t +dns_zone_link(dns_zone_t *zone, dns_zone_t *raw); + +void +dns_zone_getraw(dns_zone_t *zone, dns_zone_t **raw); + +isc_result_t +dns_zone_keydone(dns_zone_t *zone, const char *data); + +isc_result_t +dns_zone_setnsec3param(dns_zone_t *zone, uint8_t hash, uint8_t flags, + uint16_t iter, uint8_t saltlen, unsigned char *salt, + bool replace, bool resalt); +/*% + * Set the NSEC3 parameters for the zone. + * + * If 'replace' is true, then the existing NSEC3 chain, if any, will + * be replaced with the new one. If 'hash' is zero, then the replacement + * chain will be NSEC rather than NSEC3. If 'resalt' is true, or if 'salt' + * is NULL, generate a new salt with the given salt length. + * + * Requires: + * \li 'zone' to be valid. + */ + +void +dns_zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *header); +/*% + * Set the data to be included in the header when the zone is dumped in + * binary format. + */ + +isc_result_t +dns_zone_synckeyzone(dns_zone_t *zone); +/*% + * Force the managed key zone to synchronize, and start the key + * maintenance timer. + */ + +isc_result_t +dns_zone_getloadtime(dns_zone_t *zone, isc_time_t *loadtime); +/*% + * Return the time when the zone was last loaded. + */ + +isc_result_t +dns_zone_getrefreshtime(dns_zone_t *zone, isc_time_t *refreshtime); +/*% + * Return the time when the (slave) zone will need to be refreshed. + */ + +isc_result_t +dns_zone_getexpiretime(dns_zone_t *zone, isc_time_t *expiretime); +/*% + * Return the time when the (slave) zone will expire. + */ + +isc_result_t +dns_zone_getrefreshkeytime(dns_zone_t *zone, isc_time_t *refreshkeytime); +/*% + * Return the time of the next scheduled DNSSEC key event. + */ + +unsigned int +dns_zone_getincludes(dns_zone_t *zone, char ***includesp); +/*% + * Return the number include files that were encountered + * during load. If the number is greater than zero, 'includesp' + * will point to an array containing the filenames. + * + * The array and its contents need to be freed using isc_mem_free. + */ + +isc_result_t +dns_zone_rpz_enable(dns_zone_t *zone, dns_rpz_zones_t *rpzs, + dns_rpz_num_t rpz_num); +/*% + * Set the response policy associated with a zone. + */ + +void +dns_zone_rpz_enable_db(dns_zone_t *zone, dns_db_t *db); +/*% + * If a zone is a response policy zone, mark its new database. + */ + +dns_rpz_num_t +dns_zone_get_rpz_num(dns_zone_t *zone); + +void +dns_zone_catz_enable(dns_zone_t *zone, dns_catz_zones_t *catzs); +/*%< + * Enable zone as catalog zone. + * + * Requires: + * + * \li 'zone' is a valid zone object + * \li 'catzs' is not NULL + * \li prior to calling, zone->catzs is NULL or is equal to 'catzs' + */ + +void +dns_zone_catz_disable(dns_zone_t *zone); +/*%< + * Disable zone as catalog zone, if it is one. Also disables any + * registered callbacks for the catalog zone. + * + * Requires: + * + * \li 'zone' is a valid zone object + */ + +bool +dns_zone_catz_is_enabled(dns_zone_t *zone); +/*%< + * Return a boolean indicating whether the zone is enabled as catalog zone. + * + * Requires: + * + * \li 'zone' is a valid zone object + */ + +void +dns_zone_catz_enable_db(dns_zone_t *zone, dns_db_t *db); +/*%< + * If 'zone' is a catalog zone, then set up a notify-on-update trigger + * in its database. (If not a catalog zone, this function has no effect.) + * + * Requires: + * + * \li 'zone' is a valid zone object + * \li 'db' is not NULL + */ +void +dns_zone_set_parentcatz(dns_zone_t *zone, dns_catz_zone_t *catz); +/*%< + * Set parent catalog zone for this zone + * + * Requires: + * + * \li 'zone' is a valid zone object + * \li 'catz' is not NULL + */ + +dns_catz_zone_t * +dns_zone_get_parentcatz(const dns_zone_t *zone); +/*%< + * Get parent catalog zone for this zone + * + * Requires: + * + * \li 'zone' is a valid zone object + */ + +void +dns_zone_setstatlevel(dns_zone_t *zone, dns_zonestat_level_t level); + +dns_zonestat_level_t +dns_zone_getstatlevel(dns_zone_t *zone); +/*% + * Set and get the statistics reporting level for the zone; + * full, terse, or none. + */ + +isc_result_t +dns_zone_setserial(dns_zone_t *zone, uint32_t serial); +/*% + * Set the zone's serial to 'serial'. + */ +ISC_LANG_ENDDECLS + +isc_stats_t * +dns_zone_getgluecachestats(dns_zone_t *zone); +/*%< + * Get the glue cache statistics for zone. + * + * Requires: + * \li 'zone' to be a valid zone. + * + * Returns: + * \li if present, a pointer to the statistics set installed in zone; + * otherwise NULL. + */ + +bool +dns_zone_isloaded(dns_zone_t *zone); +/*%< + * Return true if 'zone' was loaded and has not expired yet, return + * false otherwise. + */ + +isc_result_t +dns_zone_verifydb(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver); +/*%< + * If 'zone' is a mirror zone, perform DNSSEC validation of version 'ver' of + * its database, 'db'. Ensure that the DNSKEY RRset at zone apex is signed by + * at least one trust anchor specified for the view that 'zone' is assigned to. + * If 'ver' is NULL, use the current version of 'db'. + * + * If 'zone' is not a mirror zone, return ISC_R_SUCCESS immediately. + * + * Returns: + * + * \li #ISC_R_SUCCESS either 'zone' is not a mirror zone or 'zone' is + * a mirror zone and all DNSSEC checks succeeded + * and the DNSKEY RRset at zone apex is signed by + * a trusted key + * + * \li #DNS_R_VERIFYFAILURE any other case + */ + +const char * +dns_zonetype_name(dns_zonetype_t type); +/*%< + * Return the name of the zone type 'type'. + */ + +#endif /* DNS_ZONE_H */ diff --git a/lib/dns/include/dns/zonekey.h b/lib/dns/include/dns/zonekey.h new file mode 100644 index 0000000..f03f0a5 --- /dev/null +++ b/lib/dns/include/dns/zonekey.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#ifndef DNS_ZONEKEY_H +#define DNS_ZONEKEY_H 1 + +/*! \file dns/zonekey.h */ + +#include <stdbool.h> + +#include <isc/lang.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +bool +dns_zonekey_iszonekey(dns_rdata_t *keyrdata); +/*%< + * Determines if the key record contained in the rdata is a zone key. + * + * Requires: + * 'keyrdata' is not NULL. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_ZONEKEY_H */ diff --git a/lib/dns/include/dns/zoneverify.h b/lib/dns/include/dns/zoneverify.h new file mode 100644 index 0000000..22a680a --- /dev/null +++ b/lib/dns/include/dns/zoneverify.h @@ -0,0 +1,50 @@ +/* + * 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 dns/zoneverify.h */ + +#include <stdbool.h> + +#include <isc/types.h> + +#include <dns/types.h> + +ISC_LANG_BEGINDECLS + +/*% + * Verify that certain things are sane: + * + * The apex has a DNSKEY record with at least one KSK, and at least + * one ZSK if the -x flag was not used. + * + * The DNSKEY record was signed with at least one of the KSKs in this + * set. + * + * The rest of the zone was signed with at least one of the ZSKs + * present in the DNSKEY RRSET. + * + * Mark all RRsets correctly signed by one of the keys in the DNSKEY RRset at + * zone apex as secure. + * + * If 'secroots' is not NULL, mark the DNSKEY RRset as secure if it is + * correctly signed by at least one key present in 'secroots'. + */ +isc_result_t +dns_zoneverify_dnssec(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, + dns_name_t *origin, dns_keytable_t *secroots, + isc_mem_t *mctx, bool ignore_kskflag, bool keyset_kskonly, + void (*report)(const char *, ...)); + +ISC_LANG_ENDDECLS diff --git a/lib/dns/include/dns/zt.h b/lib/dns/include/dns/zt.h new file mode 100644 index 0000000..2964fc9 --- /dev/null +++ b/lib/dns/include/dns/zt.h @@ -0,0 +1,224 @@ +/* + * 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. + */ + +#ifndef DNS_ZT_H +#define DNS_ZT_H 1 + +/*! \file dns/zt.h */ + +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/rwlock.h> + +#include <dns/types.h> + +#define DNS_ZTFIND_NOEXACT 0x01 +#define DNS_ZTFIND_MIRROR 0x02 + +ISC_LANG_BEGINDECLS + +typedef isc_result_t (*dns_zt_allloaded_t)(void *arg); +/*%< + * Method prototype: when all pending zone loads are complete, + * the zone table can inform the caller via a callback function with + * this signature. + */ + +typedef isc_result_t (*dns_zt_zoneloaded_t)(dns_zt_t *zt, dns_zone_t *zone, + isc_task_t *task); +/*%< + * Method prototype: when a zone finishes loading, the zt object + * can be informed via a callback function with this signature. + */ + +isc_result_t +dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **zt); +/*%< + * Creates a new zone table. + * + * Requires: + * \li 'mctx' to be initialized. + * + * Returns: + * \li #ISC_R_SUCCESS on success. + * \li #ISC_R_NOMEMORY + */ + +isc_result_t +dns_zt_mount(dns_zt_t *zt, dns_zone_t *zone); +/*%< + * Mounts the zone on the zone table. + * + * Requires: + * \li 'zt' to be valid + * \li 'zone' to be valid + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_EXISTS + * \li #ISC_R_NOSPACE + * \li #ISC_R_NOMEMORY + */ + +isc_result_t +dns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone); +/*%< + * Unmount the given zone from the table. + * + * Requires: + * 'zt' to be valid + * \li 'zone' to be valid + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTFOUND + * \li #ISC_R_NOMEMORY + */ + +isc_result_t +dns_zt_find(dns_zt_t *zt, const dns_name_t *name, unsigned int options, + dns_name_t *foundname, dns_zone_t **zone); +/*%< + * Find the best match for 'name' in 'zt'. If foundname is non NULL + * then the name of the zone found is returned. + * + * Notes: + * \li If the DNS_ZTFIND_NOEXACT is set, the best partial match (if any) + * to 'name' will be returned. + * + * Requires: + * \li 'zt' to be valid + * \li 'name' to be valid + * \li 'foundname' to be initialized and associated with a fixedname or NULL + * \li 'zone' to be non NULL and '*zone' to be NULL + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #DNS_R_PARTIALMATCH + * \li #ISC_R_NOTFOUND + * \li #ISC_R_NOSPACE + */ + +void +dns_zt_detach(dns_zt_t **ztp); +/*%< + * Detach the given zonetable, if the reference count goes to zero the + * zonetable will be freed. In either case 'ztp' is set to NULL. + * + * Requires: + * \li '*ztp' to be valid + */ + +void +dns_zt_flushanddetach(dns_zt_t **ztp); +/*%< + * Detach the given zonetable, if the reference count goes to zero the + * zonetable will be flushed and then freed. In either case 'ztp' is + * set to NULL. + * + * Requires: + * \li '*ztp' to be valid + */ + +void +dns_zt_attach(dns_zt_t *zt, dns_zt_t **ztp); +/*%< + * Attach 'zt' to '*ztp'. + * + * Requires: + * \li 'zt' to be valid + * \li '*ztp' to be NULL + */ + +isc_result_t +dns_zt_load(dns_zt_t *zt, bool stop, bool newonly); + +isc_result_t +dns_zt_asyncload(dns_zt_t *zt, bool newonly, dns_zt_allloaded_t alldone, + void *arg); +/*%< + * Load all zones in the table. If 'stop' is true, + * stop on the first error and return it. If 'stop' + * is false, ignore errors. + * + * if newonly is set only zones that were never loaded are loaded. + * dns_zt_asyncload() loads zones asynchronously; when all + * zones in the zone table have finished loaded (or failed due + * to errors), the caller is informed by calling 'alldone' + * with an argument of 'arg'. + * + * Requires: + * \li 'zt' to be valid + */ + +isc_result_t +dns_zt_freezezones(dns_zt_t *zt, dns_view_t *view, bool freeze); +/*%< + * Freeze/thaw updates to master zones. + * Any pending updates will be flushed. + * Zones will be reloaded on thaw. + */ + +isc_result_t +dns_zt_apply(dns_zt_t *zt, isc_rwlocktype_t lock, bool stop, isc_result_t *sub, + isc_result_t (*action)(dns_zone_t *, void *), void *uap); +/*%< + * Apply a given 'action' to all zone zones in the table. + * If 'stop' is 'true' then walking the zone tree will stop if + * 'action' does not return ISC_R_SUCCESS. + * + * Requires: + * \li 'zt' to be valid. + * \li 'action' to be non NULL. + * + * Returns: + * \li ISC_R_SUCCESS if action was applied to all nodes. If 'stop' is + * false and 'sub' is non NULL then the first error (if any) + * reported by 'action' is returned in '*sub'; + * any error code from 'action'. + */ + +bool +dns_zt_loadspending(dns_zt_t *zt); +/*%< + * Returns true if and only if there are zones still waiting to + * be loaded in zone table 'zt'. + * + * Requires: + * \li 'zt' to be valid. + */ + +void +dns_zt_setviewcommit(dns_zt_t *zt); +/*%< + * Commit dns_zone_setview() calls previously made for all zones in this + * zone table. + * + * Requires: + *\li 'view' to be valid. + */ + +void +dns_zt_setviewrevert(dns_zt_t *zt); +/*%< + * Revert dns_zone_setview() calls previously made for all zones in this + * zone table. + * + * Requires: + *\li 'view' to be valid. + */ + +ISC_LANG_ENDDECLS + +#endif /* DNS_ZT_H */ diff --git a/lib/dns/include/dst/Makefile.in b/lib/dns/include/dst/Makefile.in new file mode 100644 index 0000000..e4dad59 --- /dev/null +++ b/lib/dns/include/dst/Makefile.in @@ -0,0 +1,36 @@ +# 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. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +VERSION=@BIND9_VERSION@ + +HEADERS = dst.h gssapi.h result.h + +SUBDIRS = +TARGETS = + +@BIND9_MAKE_RULES@ + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/dst + +install:: installdirs + for i in ${HEADERS}; do \ + ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/dst || exit 1; \ + done + +uninstall:: + for i in ${HEADERS}; do \ + rm -f ${DESTDIR}${includedir}/dst/$$i || exit 1; \ + done diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h new file mode 100644 index 0000000..3185e9f --- /dev/null +++ b/lib/dns/include/dst/dst.h @@ -0,0 +1,1227 @@ +/* + * 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. + */ + +#ifndef DST_DST_H +#define DST_DST_H 1 + +/*! \file dst/dst.h */ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/lang.h> +#include <isc/stdtime.h> + +#include <dns/ds.h> +#include <dns/dsdigest.h> +#include <dns/log.h> +#include <dns/name.h> +#include <dns/secalg.h> +#include <dns/types.h> + +#include <dst/gssapi.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Types + ***/ + +/*% + * The dst_key structure is opaque. Applications should use the accessor + * functions provided to retrieve key attributes. If an application needs + * to set attributes, new accessor functions will be written. + */ + +typedef struct dst_key dst_key_t; +typedef struct dst_context dst_context_t; + +/*% + * Key states for the DNSSEC records related to a key: DNSKEY, RRSIG (ksk), + * RRSIG (zsk), and DS. + * + * DST_KEY_STATE_HIDDEN: Records of this type are not published in zone. + * This may be because the key parts were never + * introduced in the zone, or because the key has + * retired and has no records of this type left in + * the zone. + * DST_KEY_STATE_RUMOURED: Records of this type are published in zone, but + * not long enough to ensure all resolvers know + * about it. + * DST_KEY_STATE_OMNIPRESENT: Records of this type are published in zone long + * enough so that all resolvers that know about + * these records, no longer have outdated data. + * DST_KEY_STATE_UNRETENTIVE: Records of this type have been removed from the + * zone, but there may be resolvers that still have + * have predecessor records cached. Note that RRSIG + * records in this state may actually still be in the + * zone because they are reused, but retired RRSIG + * records will never be refreshed: A successor key + * is used to create signatures. + * DST_KEY_STATE_NA: The state is not applicable for this record type. + */ +typedef enum dst_key_state { + DST_KEY_STATE_HIDDEN = 0, + DST_KEY_STATE_RUMOURED = 1, + DST_KEY_STATE_OMNIPRESENT = 2, + DST_KEY_STATE_UNRETENTIVE = 3, + DST_KEY_STATE_NA = 4 +} dst_key_state_t; + +/* DST algorithm codes */ +#define DST_ALG_UNKNOWN 0 +#define DST_ALG_RSA 1 /* Used for parsing RSASHA1, RSASHA256 and RSASHA512 */ +#define DST_ALG_RSAMD5 1 +#define DST_ALG_DH 2 +#define DST_ALG_DSA 3 +#define DST_ALG_ECC 4 +#define DST_ALG_RSASHA1 5 +#define DST_ALG_NSEC3DSA 6 +#define DST_ALG_NSEC3RSASHA1 7 +#define DST_ALG_RSASHA256 8 +#define DST_ALG_RSASHA512 10 +#define DST_ALG_ECCGOST 12 +#define DST_ALG_ECDSA256 13 +#define DST_ALG_ECDSA384 14 +#define DST_ALG_ED25519 15 +#define DST_ALG_ED448 16 +#define DST_ALG_HMACMD5 157 +#define DST_ALG_GSSAPI 160 +#define DST_ALG_HMACSHA1 161 /* XXXMPA */ +#define DST_ALG_HMACSHA224 162 /* XXXMPA */ +#define DST_ALG_HMACSHA256 163 /* XXXMPA */ +#define DST_ALG_HMACSHA384 164 /* XXXMPA */ +#define DST_ALG_HMACSHA512 165 /* XXXMPA */ +#define DST_ALG_INDIRECT 252 +#define DST_ALG_PRIVATE 254 +#define DST_MAX_ALGS 256 + +/*% A buffer of this size is large enough to hold any key */ +#define DST_KEY_MAXSIZE 1280 + +/*% + * A buffer of this size is large enough to hold the textual representation + * of any key + */ +#define DST_KEY_MAXTEXTSIZE 2048 + +/*% 'Type' for dst_read_key() */ +#define DST_TYPE_KEY 0x1000000 /* KEY key */ +#define DST_TYPE_PRIVATE 0x2000000 +#define DST_TYPE_PUBLIC 0x4000000 +#define DST_TYPE_STATE 0x8000000 + +/* Key timing metadata definitions */ +#define DST_TIME_CREATED 0 +#define DST_TIME_PUBLISH 1 +#define DST_TIME_ACTIVATE 2 +#define DST_TIME_REVOKE 3 +#define DST_TIME_INACTIVE 4 +#define DST_TIME_DELETE 5 +#define DST_TIME_DSPUBLISH 6 +#define DST_TIME_SYNCPUBLISH 7 +#define DST_TIME_SYNCDELETE 8 +#define DST_TIME_DNSKEY 9 +#define DST_TIME_ZRRSIG 10 +#define DST_TIME_KRRSIG 11 +#define DST_TIME_DS 12 +#define DST_TIME_DSDELETE 13 +#define DST_MAX_TIMES 13 + +/* Numeric metadata definitions */ +#define DST_NUM_PREDECESSOR 0 +#define DST_NUM_SUCCESSOR 1 +#define DST_NUM_MAXTTL 2 +#define DST_NUM_ROLLPERIOD 3 +#define DST_NUM_LIFETIME 4 +#define DST_NUM_DSPUBCOUNT 5 +#define DST_NUM_DSDELCOUNT 6 +#define DST_MAX_NUMERIC 6 + +/* Boolean metadata definitions */ +#define DST_BOOL_KSK 0 +#define DST_BOOL_ZSK 1 +#define DST_MAX_BOOLEAN 1 + +/* Key state metadata definitions */ +#define DST_KEY_DNSKEY 0 +#define DST_KEY_ZRRSIG 1 +#define DST_KEY_KRRSIG 2 +#define DST_KEY_DS 3 +#define DST_KEY_GOAL 4 +#define DST_MAX_KEYSTATES 4 + +/* + * Current format version number of the private key parser. + * + * When parsing a key file with the same major number but a higher minor + * number, the key parser will ignore any fields it does not recognize. + * Thus, DST_MINOR_VERSION should be incremented whenever new + * fields are added to the private key file (such as new metadata). + * + * When rewriting these keys, those fields will be dropped, and the + * format version set back to the current one.. + * + * When a key is seen with a higher major number, the key parser will + * reject it as invalid. Thus, DST_MAJOR_VERSION should be incremented + * and DST_MINOR_VERSION set to zero whenever there is a format change + * which is not backward compatible to previous versions of the dst_key + * parser, such as change in the syntax of an existing field, the removal + * of a currently mandatory field, or a new field added which would + * alter the functioning of the key if it were absent. + */ +#define DST_MAJOR_VERSION 1 +#define DST_MINOR_VERSION 3 + +/*** + *** Functions + ***/ +isc_result_t +dst_lib_init(isc_mem_t *mctx, const char *engine); +/*%< + * Initializes the DST subsystem. + * + * Requires: + * \li "mctx" is a valid memory context + * + * Returns: + * \li ISC_R_SUCCESS + * \li ISC_R_NOMEMORY + * \li DST_R_NOENGINE + * + * Ensures: + * \li DST is properly initialized. + */ + +void +dst_lib_destroy(void); +/*%< + * Releases all resources allocated by DST. + */ + +bool +dst_algorithm_supported(unsigned int alg); +/*%< + * Checks that a given algorithm is supported by DST. + * + * Returns: + * \li true + * \li false + */ + +bool +dst_ds_digest_supported(unsigned int digest_type); +/*%< + * Checks that a given digest algorithm is supported by DST. + * + * Returns: + * \li true + * \li false + */ + +isc_result_t +dst_context_create(dst_key_t *key, isc_mem_t *mctx, isc_logcategory_t *category, + bool useforsigning, int maxbits, dst_context_t **dctxp); +/*%< + * Creates a context to be used for a sign or verify operation. + * + * Requires: + * \li "key" is a valid key. + * \li "mctx" is a valid memory context. + * \li dctxp != NULL && *dctxp == NULL + * + * Returns: + * \li ISC_R_SUCCESS + * \li ISC_R_NOMEMORY + * + * Ensures: + * \li *dctxp will contain a usable context. + */ + +void +dst_context_destroy(dst_context_t **dctxp); +/*%< + * Destroys all memory associated with a context. + * + * Requires: + * \li *dctxp != NULL && *dctxp == NULL + * + * Ensures: + * \li *dctxp == NULL + */ + +isc_result_t +dst_context_adddata(dst_context_t *dctx, const isc_region_t *data); +/*%< + * Incrementally adds data to the context to be used in a sign or verify + * operation. + * + * Requires: + * \li "dctx" is a valid context + * \li "data" is a valid region + * + * Returns: + * \li ISC_R_SUCCESS + * \li DST_R_SIGNFAILURE + * \li all other errors indicate failure + */ + +isc_result_t +dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig); +/*%< + * Computes a signature using the data and key stored in the context. + * + * Requires: + * \li "dctx" is a valid context. + * \li "sig" is a valid buffer. + * + * Returns: + * \li ISC_R_SUCCESS + * \li DST_R_VERIFYFAILURE + * \li all other errors indicate failure + * + * Ensures: + * \li "sig" will contain the signature + */ + +isc_result_t +dst_context_verify(dst_context_t *dctx, isc_region_t *sig); + +isc_result_t +dst_context_verify2(dst_context_t *dctx, unsigned int maxbits, + isc_region_t *sig); +/*%< + * Verifies the signature using the data and key stored in the context. + * + * 'maxbits' specifies the maximum number of bits permitted in the RSA + * exponent. + * + * Requires: + * \li "dctx" is a valid context. + * \li "sig" is a valid region. + * + * Returns: + * \li ISC_R_SUCCESS + * \li all other errors indicate failure + * + * Ensures: + * \li "sig" will contain the signature + */ + +isc_result_t +dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv, + isc_buffer_t *secret); +/*%< + * Computes a shared secret from two (Diffie-Hellman) keys. + * + * Requires: + * \li "pub" is a valid key that can be used to derive a shared secret + * \li "priv" is a valid private key that can be used to derive a shared secret + * \li "secret" is a valid buffer + * + * Returns: + * \li ISC_R_SUCCESS + * \li any other result indicates failure + * + * Ensures: + * \li If successful, secret will contain the derived shared secret. + */ + +isc_result_t +dst_key_getfilename(dns_name_t *name, dns_keytag_t id, unsigned int alg, + int type, const char *directory, isc_mem_t *mctx, + isc_buffer_t *buf); +/*%< + * Generates a key filename for the name, algorithm, and + * id, and places it in the buffer 'buf'. If directory is NULL, the + * current directory is assumed. + * + * Requires: + * \li "name" is a valid absolute dns name. + * \li "id" is a valid key tag identifier. + * \li "alg" is a supported key algorithm. + * \li "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or the bitwise union. + * DST_TYPE_KEY look for a KEY record otherwise DNSKEY + * \li "mctx" is a valid memory context. + * \li "buf" is not NULL. + * + * Returns: + * \li ISC_R_SUCCESS + * \li any other result indicates failure + */ + +isc_result_t +dst_key_fromfile(dns_name_t *name, dns_keytag_t id, unsigned int alg, int type, + const char *directory, isc_mem_t *mctx, dst_key_t **keyp); +/*%< + * Reads a key from permanent storage. The key can either be a public or + * private key, or a key state. It specified by name, algorithm, and id. If + * a private key or key state is specified, the public key must also be + * present. If directory is NULL, the current directory is assumed. + * + * Requires: + * \li "name" is a valid absolute dns name. + * \li "id" is a valid key tag identifier. + * \li "alg" is a supported key algorithm. + * \li "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE or the bitwise union. + * DST_TYPE_KEY look for a KEY record otherwise DNSKEY. + * DST_TYPE_STATE to also read the key state. + * \li "mctx" is a valid memory context. + * \li "keyp" is not NULL and "*keyp" is NULL. + * + * Returns: + * \li ISC_R_SUCCESS + * \li any other result indicates failure + * + * Ensures: + * \li If successful, *keyp will contain a valid key. + */ + +isc_result_t +dst_key_fromnamedfile(const char *filename, const char *dirname, int type, + isc_mem_t *mctx, dst_key_t **keyp); +/*%< + * Reads a key from permanent storage. The key can either be a public or + * private key, or a key state. It is specified by filename. If a private key + * or key state is specified, the public key must also be present. + * + * If 'dirname' is not NULL, and 'filename' is a relative path, + * then the file is looked up relative to the given directory. + * If 'filename' is an absolute path, 'dirname' is ignored. + * + * Requires: + * \li "filename" is not NULL + * \li "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or the bitwise union. + * DST_TYPE_KEY look for a KEY record otherwise DNSKEY. + * DST_TYPE_STATE to also read the key state. + * \li "mctx" is a valid memory context + * \li "keyp" is not NULL and "*keyp" is NULL. + * + * Returns: + * \li ISC_R_SUCCESS + * \li any other result indicates failure + * + * Ensures: + * \li If successful, *keyp will contain a valid key. + */ + +isc_result_t +dst_key_read_public(const char *filename, int type, isc_mem_t *mctx, + dst_key_t **keyp); +/*%< + * Reads a public key from permanent storage. The key must be a public key. + * + * Requires: + * \li "filename" is not NULL. + * \li "type" is DST_TYPE_KEY look for a KEY record otherwise DNSKEY. + * \li "mctx" is a valid memory context. + * \li "keyp" is not NULL and "*keyp" is NULL. + * + * Returns: + * \li ISC_R_SUCCESS + * \li DST_R_BADKEYTYPE if the key type is not the expected one + * \li ISC_R_UNEXPECTEDTOKEN if the file can not be parsed as a public key + * \li any other result indicates failure + * + * Ensures: + * \li If successful, *keyp will contain a valid key. + */ + +isc_result_t +dst_key_read_state(const char *filename, isc_mem_t *mctx, dst_key_t **keyp); +/*%< + * Reads a key state from permanent storage. + * + * Requires: + * \li "filename" is not NULL. + * \li "mctx" is a valid memory context. + * \li "keyp" is not NULL and "*keyp" is NULL. + * + * Returns: + * \li ISC_R_SUCCESS + * \li ISC_R_UNEXPECTEDTOKEN if the file can not be parsed as a public key + * \li any other result indicates failure + */ + +isc_result_t +dst_key_tofile(const dst_key_t *key, int type, const char *directory); +/*%< + * Writes a key to permanent storage. The key can either be a public or + * private key. Public keys are written in DNS format and private keys + * are written as a set of base64 encoded values. If directory is NULL, + * the current directory is assumed. + * + * Requires: + * \li "key" is a valid key. + * \li "type" is DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or the bitwise union + * + * Returns: + * \li ISC_R_SUCCESS + * \li any other result indicates failure + */ + +isc_result_t +dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass, + isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp); +/*%< + * Converts a DNS KEY record into a DST key. + * + * Requires: + * \li "name" is a valid absolute dns name. + * \li "source" is a valid buffer. There must be at least 4 bytes available. + * \li "mctx" is a valid memory context. + * \li "keyp" is not NULL and "*keyp" is NULL. + * + * Returns: + * \li ISC_R_SUCCESS + * \li any other result indicates failure + * + * Ensures: + * \li If successful, *keyp will contain a valid key, and the consumed + * pointer in data will be advanced. + */ + +isc_result_t +dst_key_todns(const dst_key_t *key, isc_buffer_t *target); +/*%< + * Converts a DST key into a DNS KEY record. + * + * Requires: + * \li "key" is a valid key. + * \li "target" is a valid buffer. There must be at least 4 bytes unused. + * + * Returns: + * \li ISC_R_SUCCESS + * \li any other result indicates failure + * + * Ensures: + * \li If successful, the used pointer in 'target' is advanced by at least 4. + */ + +isc_result_t +dst_key_frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags, + unsigned int protocol, dns_rdataclass_t rdclass, + isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp); +/*%< + * Converts a buffer containing DNS KEY RDATA into a DST key. + * + * Requires: + *\li "name" is a valid absolute dns name. + *\li "alg" is a supported key algorithm. + *\li "source" is a valid buffer. + *\li "mctx" is a valid memory context. + *\li "keyp" is not NULL and "*keyp" is NULL. + * + * Returns: + *\li ISC_R_SUCCESS + * \li any other result indicates failure + * + * Ensures: + *\li If successful, *keyp will contain a valid key, and the consumed + * pointer in source will be advanced. + */ + +isc_result_t +dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target); +/*%< + * Converts a DST key into DNS KEY RDATA format. + * + * Requires: + *\li "key" is a valid key. + *\li "target" is a valid buffer. + * + * Returns: + *\li ISC_R_SUCCESS + * \li any other result indicates failure + * + * Ensures: + *\li If successful, the used pointer in 'target' is advanced. + */ + +isc_result_t +dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer); +/*%< + * Converts a public key into a private key, reading the private key + * information from the buffer. The buffer should contain the same data + * as the .private key file would. + * + * Requires: + *\li "key" is a valid public key. + *\li "buffer" is not NULL. + * + * Returns: + *\li ISC_R_SUCCESS + * \li any other result indicates failure + * + * Ensures: + *\li If successful, key will contain a valid private key. + */ + +dns_gss_ctx_id_t +dst_key_getgssctx(const dst_key_t *key); +/*%< + * Returns the opaque key data. + * Be cautions when using this value unless you know what you are doing. + * + * Requires: + *\li "key" is not NULL. + * + * Returns: + *\li gssctx key data, possibly NULL. + */ + +isc_result_t +dst_key_fromgssapi(const dns_name_t *name, dns_gss_ctx_id_t gssctx, + isc_mem_t *mctx, dst_key_t **keyp, isc_region_t *intoken); +/*%< + * Converts a GSSAPI opaque context id into a DST key. + * + * Requires: + *\li "name" is a valid absolute dns name. + *\li "gssctx" is a GSSAPI context id. + *\li "mctx" is a valid memory context. + *\li "keyp" is not NULL and "*keyp" is NULL. + * + * Returns: + *\li ISC_R_SUCCESS + * \li any other result indicates failure + * + * Ensures: + *\li If successful, *keyp will contain a valid key and be responsible for + * the context id. + */ + +#ifdef DST_KEY_INTERNAL +isc_result_t +dst_key_buildinternal(const dns_name_t *name, unsigned int alg, + unsigned int bits, unsigned int flags, + unsigned int protocol, dns_rdataclass_t rdclass, + void *data, isc_mem_t *mctx, dst_key_t **keyp); +#endif /* ifdef DST_KEY_INTERNAL */ + +isc_result_t +dst_key_fromlabel(const dns_name_t *name, int alg, unsigned int flags, + unsigned int protocol, dns_rdataclass_t rdclass, + const char *engine, const char *label, const char *pin, + isc_mem_t *mctx, dst_key_t **keyp); + +isc_result_t +dst_key_generate(const dns_name_t *name, unsigned int alg, unsigned int bits, + unsigned int param, unsigned int flags, unsigned int protocol, + dns_rdataclass_t rdclass, isc_mem_t *mctx, dst_key_t **keyp, + void (*callback)(int)); + +/*%< + * Generate a DST key (or keypair) with the supplied parameters. The + * interpretation of the "param" field depends on the algorithm: + * \code + * RSA: exponent + * 0 use exponent 3 + * !0 use Fermat4 (2^16 + 1) + * DH: generator + * 0 default - use well known prime if bits == 768 or 1024, + * otherwise use 2 as the generator. + * !0 use this value as the generator. + * DSA: unused + * HMACMD5: entropy + * 0 default - require good entropy + * !0 lack of good entropy is ok + *\endcode + * + * Requires: + *\li "name" is a valid absolute dns name. + *\li "keyp" is not NULL and "*keyp" is NULL. + * + * Returns: + *\li ISC_R_SUCCESS + * \li any other result indicates failure + * + * Ensures: + *\li If successful, *keyp will contain a valid key. + */ + +bool +dst_key_compare(const dst_key_t *key1, const dst_key_t *key2); +/*%< + * Compares two DST keys. Returns true if they match, false otherwise. + * + * Keys ARE NOT considered to match if one of them is the revoked version + * of the other. + * + * Requires: + *\li "key1" is a valid key. + *\li "key2" is a valid key. + * + * Returns: + *\li true + * \li false + */ + +bool +dst_key_pubcompare(const dst_key_t *key1, const dst_key_t *key2, + bool match_revoked_key); +/*%< + * Compares only the public portions of two DST keys. Returns true + * if they match, false otherwise. This allows us, for example, to + * determine whether a public key found in a zone matches up with a + * key pair found on disk. + * + * If match_revoked_key is TRUE, then keys ARE considered to match if one + * of them is the revoked version of the other. Otherwise, they are not. + * + * Requires: + *\li "key1" is a valid key. + *\li "key2" is a valid key. + * + * Returns: + *\li true + * \li false + */ + +bool +dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2); +/*%< + * Compares the parameters of two DST keys. This is used to determine if + * two (Diffie-Hellman) keys can be used to derive a shared secret. + * + * Requires: + *\li "key1" is a valid key. + *\li "key2" is a valid key. + * + * Returns: + *\li true + * \li false + */ + +void +dst_key_attach(dst_key_t *source, dst_key_t **target); +/* + * Attach to a existing key increasing the reference count. + * + * Requires: + *\li 'source' to be a valid key. + *\li 'target' to be non-NULL and '*target' to be NULL. + */ + +void +dst_key_free(dst_key_t **keyp); +/*%< + * Decrement the key's reference counter and, when it reaches zero, + * release all memory associated with the key. + * + * Requires: + *\li "keyp" is not NULL and "*keyp" is a valid key. + *\li reference counter greater than zero. + * + * Ensures: + *\li All memory associated with "*keyp" will be freed. + *\li *keyp == NULL + */ + +/*%< + * Accessor functions to obtain key fields. + * + * Require: + *\li "key" is a valid key. + */ +dns_name_t * +dst_key_name(const dst_key_t *key); + +unsigned int +dst_key_size(const dst_key_t *key); + +unsigned int +dst_key_proto(const dst_key_t *key); + +unsigned int +dst_key_alg(const dst_key_t *key); + +uint32_t +dst_key_flags(const dst_key_t *key); + +dns_keytag_t +dst_key_id(const dst_key_t *key); + +dns_keytag_t +dst_key_rid(const dst_key_t *key); + +dns_rdataclass_t +dst_key_class(const dst_key_t *key); + +bool +dst_key_isprivate(const dst_key_t *key); + +bool +dst_key_iszonekey(const dst_key_t *key); + +bool +dst_key_isnullkey(const dst_key_t *key); + +isc_result_t +dst_key_buildfilename(const dst_key_t *key, int type, const char *directory, + isc_buffer_t *out); +/*%< + * Generates the filename used by dst to store the specified key. + * If directory is NULL, the current directory is assumed. + * + * Requires: + *\li "key" is a valid key + *\li "type" is either DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or 0 for no suffix. + *\li "out" is a valid buffer + * + * Ensures: + *\li the file name will be written to "out", and the used pointer will + * be advanced. + */ + +isc_result_t +dst_key_sigsize(const dst_key_t *key, unsigned int *n); +/*%< + * Computes the size of a signature generated by the given key. + * + * Requires: + *\li "key" is a valid key. + *\li "n" is not NULL + * + * Returns: + *\li #ISC_R_SUCCESS + *\li DST_R_UNSUPPORTEDALG + * + * Ensures: + *\li "n" stores the size of a generated signature + */ + +isc_result_t +dst_key_secretsize(const dst_key_t *key, unsigned int *n); +/*%< + * Computes the size of a shared secret generated by the given key. + * + * Requires: + *\li "key" is a valid key. + *\li "n" is not NULL + * + * Returns: + *\li #ISC_R_SUCCESS + *\li DST_R_UNSUPPORTEDALG + * + * Ensures: + *\li "n" stores the size of a generated shared secret + */ + +uint16_t +dst_region_computeid(const isc_region_t *source); +uint16_t +dst_region_computerid(const isc_region_t *source); +/*%< + * Computes the (revoked) key id of the key stored in the provided + * region. + * + * Requires: + *\li "source" contains a valid, non-NULL region. + * + * Returns: + *\li the key id + */ + +uint16_t +dst_key_getbits(const dst_key_t *key); +/*%< + * Get the number of digest bits required (0 == MAX). + * + * Requires: + * "key" is a valid key. + */ + +void +dst_key_setbits(dst_key_t *key, uint16_t bits); +/*%< + * Set the number of digest bits required (0 == MAX). + * + * Requires: + * "key" is a valid key. + */ + +void +dst_key_setttl(dst_key_t *key, dns_ttl_t ttl); +/*%< + * Set the default TTL to use when converting the key + * to a KEY or DNSKEY RR. + * + * Requires: + * "key" is a valid key. + */ + +dns_ttl_t +dst_key_getttl(const dst_key_t *key); +/*%< + * Get the default TTL to use when converting the key + * to a KEY or DNSKEY RR. + * + * Requires: + * "key" is a valid key. + */ + +isc_result_t +dst_key_setflags(dst_key_t *key, uint32_t flags); +/* + * Set the key flags, and recompute the key ID. + * + * Requires: + * "key" is a valid key. + */ + +isc_result_t +dst_key_getbool(const dst_key_t *key, int type, bool *valuep); +/*%< + * Get a member of the boolean metadata array and place it in '*valuep'. + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_BOOLEAN + * "valuep" is not null. + */ + +void +dst_key_setbool(dst_key_t *key, int type, bool value); +/*%< + * Set a member of the boolean metadata array. + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_BOOLEAN + */ + +void +dst_key_unsetbool(dst_key_t *key, int type); +/*%< + * Flag a member of the boolean metadata array as "not set". + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_BOOLEAN + */ + +isc_result_t +dst_key_getnum(const dst_key_t *key, int type, uint32_t *valuep); +/*%< + * Get a member of the numeric metadata array and place it in '*valuep'. + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_NUMERIC + * "valuep" is not null. + */ + +void +dst_key_setnum(dst_key_t *key, int type, uint32_t value); +/*%< + * Set a member of the numeric metadata array. + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_NUMERIC + */ + +void +dst_key_unsetnum(dst_key_t *key, int type); +/*%< + * Flag a member of the numeric metadata array as "not set". + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_NUMERIC + */ + +isc_result_t +dst_key_gettime(const dst_key_t *key, int type, isc_stdtime_t *timep); +/*%< + * Get a member of the timing metadata array and place it in '*timep'. + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_TIMES + * "timep" is not null. + */ + +void +dst_key_settime(dst_key_t *key, int type, isc_stdtime_t when); +/*%< + * Set a member of the timing metadata array. + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_TIMES + */ + +void +dst_key_unsettime(dst_key_t *key, int type); +/*%< + * Flag a member of the timing metadata array as "not set". + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_TIMES + */ + +isc_result_t +dst_key_getstate(const dst_key_t *key, int type, dst_key_state_t *statep); +/*%< + * Get a member of the keystate metadata array and place it in '*statep'. + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_KEYSTATES + * "statep" is not null. + */ + +void +dst_key_setstate(dst_key_t *key, int type, dst_key_state_t state); +/*%< + * Set a member of the keystate metadata array. + * + * Requires: + * "key" is a valid key. + * "state" is a valid state. + * "type" is no larger than DST_MAX_KEYSTATES + */ + +void +dst_key_unsetstate(dst_key_t *key, int type); +/*%< + * Flag a member of the keystate metadata array as "not set". + * + * Requires: + * "key" is a valid key. + * "type" is no larger than DST_MAX_KEYSTATES + */ + +isc_result_t +dst_key_getprivateformat(const dst_key_t *key, int *majorp, int *minorp); +/*%< + * Get the private key format version number. (If the key does not have + * a private key associated with it, the version will be 0.0.) The major + * version number is placed in '*majorp', and the minor version number in + * '*minorp'. + * + * Requires: + * "key" is a valid key. + * "majorp" is not NULL. + * "minorp" is not NULL. + */ + +void +dst_key_setprivateformat(dst_key_t *key, int major, int minor); +/*%< + * Set the private key format version number. + * + * Requires: + * "key" is a valid key. + */ + +#define DST_KEY_FORMATSIZE (DNS_NAME_FORMATSIZE + DNS_SECALG_FORMATSIZE + 7) + +void +dst_key_format(const dst_key_t *key, char *cp, unsigned int size); +/*%< + * Write the uniquely identifying information about the key (name, + * algorithm, key ID) into a string 'cp' of size 'size'. + */ + +isc_buffer_t * +dst_key_tkeytoken(const dst_key_t *key); +/*%< + * Return the token from the TKEY request, if any. If this key was + * not negotiated via TKEY, return NULL. + * + * Requires: + * "key" is a valid key. + */ + +isc_result_t +dst_key_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length); +/*%< + * Allocate 'buffer' and dump the key into it in base64 format. The buffer + * is not NUL terminated. The length of the buffer is returned in *length. + * + * 'buffer' needs to be freed using isc_mem_put(mctx, buffer, length); + * + * Requires: + * 'buffer' to be non NULL and *buffer to be NULL. + * 'length' to be non NULL and *length to be zero. + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_NOMEMORY + * ISC_R_NOTIMPLEMENTED + * others. + */ + +isc_result_t +dst_key_restore(dns_name_t *name, unsigned int alg, unsigned int flags, + unsigned int protocol, dns_rdataclass_t rdclass, + isc_mem_t *mctx, const char *keystr, dst_key_t **keyp); + +bool +dst_key_inactive(const dst_key_t *key); +/*%< + * Determines if the private key is missing due the key being deemed inactive. + * + * Requires: + * 'key' to be valid. + */ + +void +dst_key_setinactive(dst_key_t *key, bool inactive); +/*%< + * Set key inactive state. + * + * Requires: + * 'key' to be valid. + */ + +void +dst_key_setexternal(dst_key_t *key, bool value); +/*%< + * Set key external state. + * + * Requires: + * 'key' to be valid. + */ + +bool +dst_key_isexternal(dst_key_t *key); +/*%< + * Check if this is an external key. + * + * Requires: + * 'key' to be valid. + */ + +void +dst_key_setmodified(dst_key_t *key, bool value); +/*%< + * If 'value' is true, this marks the key to indicate that key file metadata + * has been modified. If 'value' is false, this resets the value, for example + * after you have written the key to file. + * + * Requires: + * 'key' to be valid. + */ + +bool +dst_key_ismodified(const dst_key_t *key); +/*%< + * Check if the key file has been modified. + * + * Requires: + * 'key' to be valid. + */ + +bool +dst_key_haskasp(dst_key_t *key); +/*%< + * Check if this key has state (and thus uses KASP). + * + * Requires: + * 'key' to be valid. + */ + +bool +dst_key_is_unused(dst_key_t *key); +/*%< + * Check if this key is unused. + * + * Requires: + * 'key' to be valid. + */ + +bool +dst_key_is_published(dst_key_t *key, isc_stdtime_t now, isc_stdtime_t *publish); +/*%< + * Check if it is safe to publish this key (e.g. put the DNSKEY in the zone). + * + * Requires: + * 'key' to be valid. + */ + +bool +dst_key_is_active(dst_key_t *key, isc_stdtime_t now); +/*%< + * Check if this key is active. This means that it is creating RRSIG records + * (ZSK), or that it is used to create a chain of trust (KSK), or both (CSK). + * + * Requires: + * 'key' to be valid. + */ + +bool +dst_key_is_signing(dst_key_t *key, int role, isc_stdtime_t now, + isc_stdtime_t *active); +/*%< + * Check if it is safe to use this key for signing, given the role. + * + * Requires: + * 'key' to be valid. + */ + +bool +dst_key_is_revoked(dst_key_t *key, isc_stdtime_t now, isc_stdtime_t *revoke); +/*%< + * Check if this key is revoked. + * + * Requires: + * 'key' to be valid. + */ + +bool +dst_key_is_removed(dst_key_t *key, isc_stdtime_t now, isc_stdtime_t *remove); +/*%< + * Check if this key is removed from the zone (e.g. the DNSKEY record should + * no longer be in the zone). + * + * Requires: + * 'key' to be valid. + */ + +dst_key_state_t +dst_key_goal(dst_key_t *key); +/*%< + * Get the key goal. Should be OMNIPRESENT or HIDDEN. + * This can be used to determine if the key is being introduced or + * is on its way out. + * + * Requires: + * 'key' to be valid. + */ + +isc_result_t +dst_key_role(dst_key_t *key, bool *ksk, bool *zsk); +/*%< + * Get the key role. A key can have the KSK or the ZSK role, or both. + * + * Requires: + * 'key' to be valid. + */ + +void +dst_key_copy_metadata(dst_key_t *to, dst_key_t *from); +/*%< + * Copy key metadata from one key to another. + * + * Requires: + * 'to' and 'from' to be valid. + */ + +ISC_LANG_ENDDECLS + +#endif /* DST_DST_H */ diff --git a/lib/dns/include/dst/gssapi.h b/lib/dns/include/dst/gssapi.h new file mode 100644 index 0000000..e783f20 --- /dev/null +++ b/lib/dns/include/dst/gssapi.h @@ -0,0 +1,196 @@ +/* + * 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. + */ + +#ifndef DST_GSSAPI_H +#define DST_GSSAPI_H 1 + +/*! \file dst/gssapi.h */ + +#include <inttypes.h> +#include <stdbool.h> + +#include <isc/formatcheck.h> +#include <isc/lang.h> +#include <isc/platform.h> +#include <isc/types.h> + +#include <dns/types.h> + +typedef void *dns_gss_cred_id_t; +typedef void *dns_gss_ctx_id_t; + +ISC_LANG_BEGINDECLS + +/*** + *** Types + ***/ + +/*** + *** Functions + ***/ + +isc_result_t +dst_gssapi_acquirecred(const dns_name_t *name, bool initiate, + dns_gss_cred_id_t *cred); +/* + * Acquires GSS credentials. + * + * Requires: + * 'name' is a valid name, preferably one known by the GSS provider + * 'initiate' indicates whether the credentials are for initiating or + * accepting contexts + * 'cred' is a pointer to NULL, which will be allocated with the + * credential handle. Call dst_gssapi_releasecred to free + * the memory. + * + * Returns: + * ISC_R_SUCCESS msg was successfully updated to include the + * query to be sent + * other an error occurred while building the message + */ + +isc_result_t +dst_gssapi_releasecred(dns_gss_cred_id_t *cred); +/* + * Releases GSS credentials. Calling this function does release the + * memory allocated for the credential in dst_gssapi_acquirecred() + * + * Requires: + * 'mctx' is a valid memory context + * 'cred' is a pointer to the credential to be released + * + * Returns: + * ISC_R_SUCCESS credential was released successfully + * other an error occurred while releaseing + * the credential + */ + +isc_result_t +dst_gssapi_initctx(const dns_name_t *name, isc_buffer_t *intoken, + isc_buffer_t *outtoken, dns_gss_ctx_id_t *gssctx, + isc_mem_t *mctx, char **err_message); +/* + * Initiates a GSS context. + * + * Requires: + * 'name' is a valid name, preferably one known by the GSS + * provider + * 'intoken' is a token received from the acceptor, or NULL if + * there isn't one + * 'outtoken' is a buffer to receive the token generated by + * gss_init_sec_context() to be sent to the acceptor + * 'context' is a pointer to a valid dns_gss_ctx_id_t + * (which may have the value GSS_C_NO_CONTEXT) + * + * Returns: + * ISC_R_SUCCESS msg was successfully updated to include the + * query to be sent + * other an error occurred while building the message + * *err_message optional error message + */ + +isc_result_t +dst_gssapi_acceptctx(dns_gss_cred_id_t cred, const char *gssapi_keytab, + isc_region_t *intoken, isc_buffer_t **outtoken, + dns_gss_ctx_id_t *context, dns_name_t *principal, + isc_mem_t *mctx); +/* + * Accepts a GSS context. + * + * Requires: + * 'mctx' is a valid memory context + * 'cred' is the acceptor's valid GSS credential handle + * 'intoken' is a token received from the initiator + * 'outtoken' is a pointer a buffer pointer used to return the token + * generated by gss_accept_sec_context() to be sent to the + * initiator + * 'context' is a valid pointer to receive the generated context handle. + * On the initial call, it should be a pointer to NULL, which + * will be allocated as a dns_gss_ctx_id_t. Subsequent calls + * should pass in the handle generated on the first call. + * Call dst_gssapi_releasecred to delete the context and free + * the memory. + * + * Requires: + * 'outtoken' to != NULL && *outtoken == NULL. + * + * Returns: + * ISC_R_SUCCESS msg was successfully updated to include the + * query to be sent + * DNS_R_CONTINUE transaction still in progress + * other an error occurred while building the message + */ + +isc_result_t +dst_gssapi_deletectx(isc_mem_t *mctx, dns_gss_ctx_id_t *gssctx); +/* + * Destroys a GSS context. This function deletes the context from the GSS + * provider and then frees the memory used by the context pointer. + * + * Requires: + * 'mctx' is a valid memory context + * 'context' is a valid GSS context + * + * Returns: + * ISC_R_SUCCESS + */ + +void +gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); +/* + * Logging function for GSS. + * + * Requires + * 'level' is the log level to be used, as an integer + * 'fmt' is a printf format specifier + */ + +char * +gss_error_tostring(uint32_t major, uint32_t minor, char *buf, size_t buflen); +/* + * Render a GSS major status/minor status pair into a string + * + * Requires: + * 'major' is a GSS major status code + * 'minor' is a GSS minor status code + * + * Returns: + * A string containing the text representation of the error codes. + * Users should copy the string if they wish to keep it. + */ + +bool +dst_gssapi_identitymatchesrealmkrb5(const dns_name_t *signer, + const dns_name_t *name, + const dns_name_t *realm, bool subdomain); +/* + * Compare a "signer" (in the format of a Kerberos-format Kerberos5 + * principal: host/example.com@EXAMPLE.COM) to the realm name stored + * in "name" (which represents the realm name). + * + */ + +bool +dst_gssapi_identitymatchesrealmms(const dns_name_t *signer, + const dns_name_t *name, + const dns_name_t *realm, bool subdomain); +/* + * Compare a "signer" (in the format of a Kerberos-format Kerberos5 + * principal: host/example.com@EXAMPLE.COM) to the realm name stored + * in "name" (which represents the realm name). + * + */ + +ISC_LANG_ENDDECLS + +#endif /* DST_GSSAPI_H */ diff --git a/lib/dns/include/dst/result.h b/lib/dns/include/dst/result.h new file mode 100644 index 0000000..b909f55 --- /dev/null +++ b/lib/dns/include/dst/result.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#ifndef DST_RESULT_H +#define DST_RESULT_H 1 + +/*! \file dst/result.h */ + +#include <isc/lang.h> +#include <isc/resultclass.h> + +/* + * Nothing in this file truly depends on <isc/result.h>, but the + * DST result codes are considered to be publicly derived from + * the ISC result codes, so including this file buys you the ISC_R_ + * namespace too. + */ +#include <isc/result.h> /* Contractual promise. */ + +#define DST_R_UNSUPPORTEDALG (ISC_RESULTCLASS_DST + 0) +#define DST_R_CRYPTOFAILURE (ISC_RESULTCLASS_DST + 1) +/* compat */ +#define DST_R_OPENSSLFAILURE DST_R_CRYPTOFAILURE +#define DST_R_NOCRYPTO (ISC_RESULTCLASS_DST + 2) +#define DST_R_NULLKEY (ISC_RESULTCLASS_DST + 3) +#define DST_R_INVALIDPUBLICKEY (ISC_RESULTCLASS_DST + 4) +#define DST_R_INVALIDPRIVATEKEY (ISC_RESULTCLASS_DST + 5) +/* 6 is unused */ +#define DST_R_WRITEERROR (ISC_RESULTCLASS_DST + 7) +#define DST_R_INVALIDPARAM (ISC_RESULTCLASS_DST + 8) +/* 9 is unused */ +/* 10 is unused */ +#define DST_R_SIGNFAILURE (ISC_RESULTCLASS_DST + 11) +/* 12 is unused */ +/* 13 is unused */ +#define DST_R_VERIFYFAILURE (ISC_RESULTCLASS_DST + 14) +#define DST_R_NOTPUBLICKEY (ISC_RESULTCLASS_DST + 15) +#define DST_R_NOTPRIVATEKEY (ISC_RESULTCLASS_DST + 16) +#define DST_R_KEYCANNOTCOMPUTESECRET (ISC_RESULTCLASS_DST + 17) +#define DST_R_COMPUTESECRETFAILURE (ISC_RESULTCLASS_DST + 18) +#define DST_R_NORANDOMNESS (ISC_RESULTCLASS_DST + 19) +#define DST_R_BADKEYTYPE (ISC_RESULTCLASS_DST + 20) +#define DST_R_NOENGINE (ISC_RESULTCLASS_DST + 21) +#define DST_R_EXTERNALKEY (ISC_RESULTCLASS_DST + 22) + +#define DST_R_NRESULTS 23 /* Number of results */ + +ISC_LANG_BEGINDECLS + +const char *dst_result_totext(isc_result_t); + +void +dst_result_register(void); + +ISC_LANG_ENDDECLS + +#endif /* DST_RESULT_H */ |