Date: Wed, 10 Feb 2021 04:27:42 GMT From: Cy Schubert <cy@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: f44e67d120ad - main - MFV d60fa10fd872db7e3d8cb1e161cfdae026c43b14: Message-ID: <202102100427.11A4RgTa070269@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by cy: URL: https://cgit.FreeBSD.org/src/commit/?id=f44e67d120ad78ef7894241b519ee79fd190a16e commit f44e67d120ad78ef7894241b519ee79fd190a16e Merge: 1e811efbc591 d60fa10fd872 Author: Cy Schubert <cy@FreeBSD.org> AuthorDate: 2021-02-10 04:25:05 +0000 Commit: Cy Schubert <cy@FreeBSD.org> CommitDate: 2021-02-10 04:27:25 +0000 MFV d60fa10fd872db7e3d8cb1e161cfdae026c43b14: Update unbound 1.13.0 --> 1.13.1. Includes numerous bugfixes documented at: https://www.nlnetlabs.nl/projects/unbound/download/#unbound-1-13-1 MFC after: 1 month contrib/unbound/Makefile.in | 516 ++++++++++++--------- contrib/unbound/aclocal.m4 | 8 +- contrib/unbound/acx_nlnetlabs.m4 | 60 ++- contrib/unbound/acx_python.m4 | 6 +- contrib/unbound/cachedb/cachedb.c | 1 + contrib/unbound/config.guess | 20 +- contrib/unbound/config.h.in | 3 +- contrib/unbound/config.sub | 20 +- contrib/unbound/configure | 137 +++--- contrib/unbound/configure.ac | 197 ++++---- .../contrib/build-unbound-localzone-from-hosts.pl | 0 .../unbound/contrib/create_unbound_ad_servers.sh | 0 contrib/unbound/contrib/parseunbound.pl | 0 contrib/unbound/contrib/unbound_cache.sh | 0 contrib/unbound/contrib/warmup.sh | 0 contrib/unbound/daemon/remote.c | 55 +++ contrib/unbound/daemon/worker.c | 22 +- contrib/unbound/dns64/dns64.c | 43 +- contrib/unbound/dnscrypt/dnscrypt.m4 | 2 +- contrib/unbound/dnstap/dnstap.m4 | 2 +- contrib/unbound/dnstap/unbound-dnstap-socket.c | 9 +- contrib/unbound/doc/Changelog | 131 +++++- contrib/unbound/doc/FEATURES | 1 + contrib/unbound/doc/README | 2 +- contrib/unbound/doc/TODO | 1 - contrib/unbound/doc/example.conf.in | 32 +- contrib/unbound/doc/libunbound.3.in | 4 +- contrib/unbound/doc/unbound-anchor.8.in | 2 +- contrib/unbound/doc/unbound-checkconf.8.in | 2 +- contrib/unbound/doc/unbound-control.8.in | 8 +- contrib/unbound/doc/unbound-host.1.in | 2 +- contrib/unbound/doc/unbound.8.in | 4 +- contrib/unbound/doc/unbound.conf.5.in | 60 ++- contrib/unbound/doc/unbound.doxygen | 6 +- contrib/unbound/dynlibmod/dynlibmod.c | 20 +- contrib/unbound/dynlibmod/dynlibmod.h | 4 +- contrib/unbound/dynlibmod/examples/helloworld.c | 14 +- contrib/unbound/ipset/ipset.c | 0 contrib/unbound/ipset/ipset.h | 0 contrib/unbound/libunbound/libworker.c | 4 + contrib/unbound/ltmain.sh | 0 contrib/unbound/respip/respip.c | 2 +- contrib/unbound/services/authzone.c | 17 +- contrib/unbound/services/cache/rrset.c | 2 + contrib/unbound/services/listen_dnsport.c | 14 +- contrib/unbound/services/listen_dnsport.h | 2 +- contrib/unbound/services/localzone.c | 107 ++++- contrib/unbound/services/localzone.h | 7 + contrib/unbound/services/mesh.c | 38 +- contrib/unbound/services/outside_network.c | 77 ++- contrib/unbound/services/outside_network.h | 2 + contrib/unbound/services/rpz.c | 21 +- contrib/unbound/services/rpz.h | 13 + contrib/unbound/smallapp/unbound-anchor.c | 67 +-- contrib/unbound/smallapp/unbound-control.c | 105 ++++- contrib/unbound/smallapp/worker_cb.c | 3 + contrib/unbound/util/config_file.c | 71 ++- contrib/unbound/util/config_file.h | 27 ++ contrib/unbound/util/configlexer.lex | 6 + contrib/unbound/util/configparser.y | 87 +++- contrib/unbound/util/configyyrename.h | 6 + contrib/unbound/util/data/msgencode.c | 63 ++- contrib/unbound/util/data/msgparse.c | 2 + contrib/unbound/util/data/msgparse.h | 4 + contrib/unbound/util/data/msgreply.c | 36 +- contrib/unbound/util/data/msgreply.h | 20 +- contrib/unbound/util/data/packed_rrset.c | 17 +- contrib/unbound/util/data/packed_rrset.h | 3 + contrib/unbound/util/edns.c | 16 + contrib/unbound/util/iana_ports.inc | 2 +- contrib/unbound/util/module.h | 4 +- contrib/unbound/util/net_help.c | 2 +- contrib/unbound/util/netevent.c | 122 ++++- contrib/unbound/util/netevent.h | 12 + contrib/unbound/util/storage/lruhash.c | 4 +- contrib/unbound/validator/autotrust.c | 1 + usr.sbin/unbound/config.h | 6 +- 77 files changed, 1700 insertions(+), 686 deletions(-) diff --cc contrib/unbound/contrib/build-unbound-localzone-from-hosts.pl index c11bbc330795,c11bbc330795..c11bbc330795 mode 100755,100644..100644 --- a/contrib/unbound/contrib/build-unbound-localzone-from-hosts.pl +++ b/contrib/unbound/contrib/build-unbound-localzone-from-hosts.pl diff --cc contrib/unbound/contrib/create_unbound_ad_servers.sh index 49fdbffedfaf,49fdbffedfaf..49fdbffedfaf mode 100755,100644..100644 --- a/contrib/unbound/contrib/create_unbound_ad_servers.sh +++ b/contrib/unbound/contrib/create_unbound_ad_servers.sh diff --cc contrib/unbound/contrib/parseunbound.pl index 1d294b13288d,1d294b13288d..1d294b13288d mode 100755,100644..100644 --- a/contrib/unbound/contrib/parseunbound.pl +++ b/contrib/unbound/contrib/parseunbound.pl diff --cc contrib/unbound/contrib/unbound_cache.sh index b3e876ba9012,b3e876ba9012..b3e876ba9012 mode 100755,100644..100644 --- a/contrib/unbound/contrib/unbound_cache.sh +++ b/contrib/unbound/contrib/unbound_cache.sh diff --cc contrib/unbound/contrib/warmup.sh index b4d9135a68dd,b4d9135a68dd..b4d9135a68dd mode 100755,100644..100644 --- a/contrib/unbound/contrib/warmup.sh +++ b/contrib/unbound/contrib/warmup.sh diff --cc contrib/unbound/doc/unbound-checkconf.8.in index abcd45c8b811,000000000000..ed9db8ffa82c mode 100644,000000..100644 --- a/contrib/unbound/doc/unbound-checkconf.8.in +++ b/contrib/unbound/doc/unbound-checkconf.8.in @@@ -1,52 -1,0 +1,52 @@@ - .TH "unbound-checkconf" "8" "Dec 3, 2020" "NLnet Labs" "unbound 1.13.0" ++.TH "unbound-checkconf" "8" "Feb 9, 2021" "NLnet Labs" "unbound 1.13.1" +.\" +.\" unbound-checkconf.8 -- unbound configuration checker manual +.\" +.\" Copyright (c) 2007, NLnet Labs. All rights reserved. +.\" +.\" See LICENSE for the license. +.\" +.\" +.SH "NAME" +.B unbound\-checkconf +\- Check unbound configuration file for errors. +.SH "SYNOPSIS" +.B unbound\-checkconf +.RB [ \-h ] +.RB [ \-f ] +.RB [ \-o +.IR option ] +.RI [ cfgfile ] +.SH "DESCRIPTION" +.B Unbound\-checkconf +checks the configuration file for the +\fIunbound\fR(8) +DNS resolver for syntax and other errors. +The config file syntax is described in +\fIunbound.conf\fR(5). +.P +The available options are: +.TP +.B \-h +Show the version and commandline option help. +.TP +.B \-f +Print full pathname, with chroot applied to it. Use with the \-o option. +.TP +.B \-o\fI option +If given, after checking the config file the value of this option is +printed to stdout. For "" (disabled) options an empty line is printed. +.TP +.I cfgfile +The config file to read with settings for unbound. It is checked. +If omitted, the config file at the default location is checked. +.SH "EXIT CODE" +The unbound\-checkconf program exits with status code 1 on error, +0 for a correct config file. +.SH "FILES" +.TP +.I @ub_conf_file@ +unbound configuration file. +.SH "SEE ALSO" +\fIunbound.conf\fR(5), +\fIunbound\fR(8). diff --cc contrib/unbound/ipset/ipset.c index f6e2c4a9d8a6,f6e2c4a9d8a6..f6e2c4a9d8a6 mode 100755,100644..100644 --- a/contrib/unbound/ipset/ipset.c +++ b/contrib/unbound/ipset/ipset.c diff --cc contrib/unbound/ipset/ipset.h index f60a8be8c837,f60a8be8c837..f60a8be8c837 mode 100755,100644..100644 --- a/contrib/unbound/ipset/ipset.h +++ b/contrib/unbound/ipset/ipset.h diff --cc contrib/unbound/ltmain.sh index 7f3523d335c5,7f3523d335c5..7f3523d335c5 mode 100755,100644..100644 --- a/contrib/unbound/ltmain.sh +++ b/contrib/unbound/ltmain.sh diff --cc contrib/unbound/services/authzone.c index a43a25def993,000000000000..ecd63ec144f5 mode 100644,000000..100644 --- a/contrib/unbound/services/authzone.c +++ b/contrib/unbound/services/authzone.c @@@ -1,6969 -1,0 +1,6974 @@@ +/* + * services/authzone.c - authoritative zone that is locally hosted. + * + * Copyright (c) 2017, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * This file contains the functions for an authority zone. This zone + * is queried by the iterator, just like a stub or forward zone, but then + * the data is locally held. + */ + +#include "config.h" +#include "services/authzone.h" +#include "util/data/dname.h" +#include "util/data/msgparse.h" +#include "util/data/msgreply.h" +#include "util/data/msgencode.h" +#include "util/data/packed_rrset.h" +#include "util/regional.h" +#include "util/net_help.h" +#include "util/netevent.h" +#include "util/config_file.h" +#include "util/log.h" +#include "util/module.h" +#include "util/random.h" +#include "services/cache/dns.h" +#include "services/outside_network.h" +#include "services/listen_dnsport.h" +#include "services/mesh.h" +#include "sldns/rrdef.h" +#include "sldns/pkthdr.h" +#include "sldns/sbuffer.h" +#include "sldns/str2wire.h" +#include "sldns/wire2str.h" +#include "sldns/parseutil.h" +#include "sldns/keyraw.h" +#include "validator/val_nsec3.h" +#include "validator/val_secalgo.h" +#include <ctype.h> + +/** bytes to use for NSEC3 hash buffer. 20 for sha1 */ +#define N3HASHBUFLEN 32 +/** max number of CNAMEs we are willing to follow (in one answer) */ +#define MAX_CNAME_CHAIN 8 +/** timeout for probe packets for SOA */ +#define AUTH_PROBE_TIMEOUT 100 /* msec */ +/** when to stop with SOA probes (when exponential timeouts exceed this) */ +#define AUTH_PROBE_TIMEOUT_STOP 1000 /* msec */ +/* auth transfer timeout for TCP connections, in msec */ +#define AUTH_TRANSFER_TIMEOUT 10000 /* msec */ +/* auth transfer max backoff for failed tranfers and probes */ +#define AUTH_TRANSFER_MAX_BACKOFF 86400 /* sec */ +/* auth http port number */ +#define AUTH_HTTP_PORT 80 +/* auth https port number */ +#define AUTH_HTTPS_PORT 443 +/* max depth for nested $INCLUDEs */ +#define MAX_INCLUDE_DEPTH 10 +/** number of timeouts before we fallback from IXFR to AXFR, + * because some versions of servers (eg. dnsmasq) drop IXFR packets. */ +#define NUM_TIMEOUTS_FALLBACK_IXFR 3 + +/** pick up nextprobe task to start waiting to perform transfer actions */ +static void xfr_set_timeout(struct auth_xfer* xfr, struct module_env* env, + int failure, int lookup_only); +/** move to sending the probe packets, next if fails. task_probe */ +static void xfr_probe_send_or_end(struct auth_xfer* xfr, + struct module_env* env); +/** pick up probe task with specified(or NULL) destination first, + * or transfer task if nothing to probe, or false if already in progress */ +static int xfr_start_probe(struct auth_xfer* xfr, struct module_env* env, + struct auth_master* spec); +/** delete xfer structure (not its tree entry) */ +static void auth_xfer_delete(struct auth_xfer* xfr); + +/** create new dns_msg */ +static struct dns_msg* +msg_create(struct regional* region, struct query_info* qinfo) +{ + struct dns_msg* msg = (struct dns_msg*)regional_alloc(region, + sizeof(struct dns_msg)); + if(!msg) + return NULL; + msg->qinfo.qname = regional_alloc_init(region, qinfo->qname, + qinfo->qname_len); + if(!msg->qinfo.qname) + return NULL; + msg->qinfo.qname_len = qinfo->qname_len; + msg->qinfo.qtype = qinfo->qtype; + msg->qinfo.qclass = qinfo->qclass; + msg->qinfo.local_alias = NULL; + /* non-packed reply_info, because it needs to grow the array */ + msg->rep = (struct reply_info*)regional_alloc_zero(region, + sizeof(struct reply_info)-sizeof(struct rrset_ref)); + if(!msg->rep) + return NULL; + msg->rep->flags = (uint16_t)(BIT_QR | BIT_AA); + msg->rep->authoritative = 1; + msg->rep->qdcount = 1; + /* rrsets is NULL, no rrsets yet */ + return msg; +} + +/** grow rrset array by one in msg */ +static int +msg_grow_array(struct regional* region, struct dns_msg* msg) +{ + if(msg->rep->rrsets == NULL) { + msg->rep->rrsets = regional_alloc_zero(region, + sizeof(struct ub_packed_rrset_key*)*(msg->rep->rrset_count+1)); + if(!msg->rep->rrsets) + return 0; + } else { + struct ub_packed_rrset_key** rrsets_old = msg->rep->rrsets; + msg->rep->rrsets = regional_alloc_zero(region, + sizeof(struct ub_packed_rrset_key*)*(msg->rep->rrset_count+1)); + if(!msg->rep->rrsets) + return 0; + memmove(msg->rep->rrsets, rrsets_old, + sizeof(struct ub_packed_rrset_key*)*msg->rep->rrset_count); + } + return 1; +} + +/** get ttl of rrset */ +static time_t +get_rrset_ttl(struct ub_packed_rrset_key* k) +{ + struct packed_rrset_data* d = (struct packed_rrset_data*) + k->entry.data; + return d->ttl; +} + +/** Copy rrset into region from domain-datanode and packet rrset */ +static struct ub_packed_rrset_key* +auth_packed_rrset_copy_region(struct auth_zone* z, struct auth_data* node, + struct auth_rrset* rrset, struct regional* region, time_t adjust) +{ + struct ub_packed_rrset_key key; + memset(&key, 0, sizeof(key)); + key.entry.key = &key; + key.entry.data = rrset->data; + key.rk.dname = node->name; + key.rk.dname_len = node->namelen; + key.rk.type = htons(rrset->type); + key.rk.rrset_class = htons(z->dclass); + key.entry.hash = rrset_key_hash(&key.rk); + return packed_rrset_copy_region(&key, region, adjust); +} + +/** fix up msg->rep TTL and prefetch ttl */ +static void +msg_ttl(struct dns_msg* msg) +{ + if(msg->rep->rrset_count == 0) return; + if(msg->rep->rrset_count == 1) { + msg->rep->ttl = get_rrset_ttl(msg->rep->rrsets[0]); + msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); + msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; + } else if(get_rrset_ttl(msg->rep->rrsets[msg->rep->rrset_count-1]) < + msg->rep->ttl) { + msg->rep->ttl = get_rrset_ttl(msg->rep->rrsets[ + msg->rep->rrset_count-1]); + msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); + msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; + } +} + +/** see if rrset is a duplicate in the answer message */ +static int +msg_rrset_duplicate(struct dns_msg* msg, uint8_t* nm, size_t nmlen, + uint16_t type, uint16_t dclass) +{ + size_t i; + for(i=0; i<msg->rep->rrset_count; i++) { + struct ub_packed_rrset_key* k = msg->rep->rrsets[i]; + if(ntohs(k->rk.type) == type && k->rk.dname_len == nmlen && + ntohs(k->rk.rrset_class) == dclass && + query_dname_compare(k->rk.dname, nm) == 0) + return 1; + } + return 0; +} + +/** add rrset to answer section (no auth, add rrsets yet) */ +static int +msg_add_rrset_an(struct auth_zone* z, struct regional* region, + struct dns_msg* msg, struct auth_data* node, struct auth_rrset* rrset) +{ + log_assert(msg->rep->ns_numrrsets == 0); + log_assert(msg->rep->ar_numrrsets == 0); + if(!rrset || !node) + return 1; + if(msg_rrset_duplicate(msg, node->name, node->namelen, rrset->type, + z->dclass)) + return 1; + /* grow array */ + if(!msg_grow_array(region, msg)) + return 0; + /* copy it */ + if(!(msg->rep->rrsets[msg->rep->rrset_count] = + auth_packed_rrset_copy_region(z, node, rrset, region, 0))) + return 0; + msg->rep->rrset_count++; + msg->rep->an_numrrsets++; + msg_ttl(msg); + return 1; +} + +/** add rrset to authority section (no additonal section rrsets yet) */ +static int +msg_add_rrset_ns(struct auth_zone* z, struct regional* region, + struct dns_msg* msg, struct auth_data* node, struct auth_rrset* rrset) +{ + log_assert(msg->rep->ar_numrrsets == 0); + if(!rrset || !node) + return 1; + if(msg_rrset_duplicate(msg, node->name, node->namelen, rrset->type, + z->dclass)) + return 1; + /* grow array */ + if(!msg_grow_array(region, msg)) + return 0; + /* copy it */ + if(!(msg->rep->rrsets[msg->rep->rrset_count] = + auth_packed_rrset_copy_region(z, node, rrset, region, 0))) + return 0; + msg->rep->rrset_count++; + msg->rep->ns_numrrsets++; + msg_ttl(msg); + return 1; +} + +/** add rrset to additional section */ +static int +msg_add_rrset_ar(struct auth_zone* z, struct regional* region, + struct dns_msg* msg, struct auth_data* node, struct auth_rrset* rrset) +{ + if(!rrset || !node) + return 1; + if(msg_rrset_duplicate(msg, node->name, node->namelen, rrset->type, + z->dclass)) + return 1; + /* grow array */ + if(!msg_grow_array(region, msg)) + return 0; + /* copy it */ + if(!(msg->rep->rrsets[msg->rep->rrset_count] = + auth_packed_rrset_copy_region(z, node, rrset, region, 0))) + return 0; + msg->rep->rrset_count++; + msg->rep->ar_numrrsets++; + msg_ttl(msg); + return 1; +} + +struct auth_zones* auth_zones_create(void) +{ + struct auth_zones* az = (struct auth_zones*)calloc(1, sizeof(*az)); + if(!az) { + log_err("out of memory"); + return NULL; + } + rbtree_init(&az->ztree, &auth_zone_cmp); + rbtree_init(&az->xtree, &auth_xfer_cmp); + lock_rw_init(&az->lock); + lock_protect(&az->lock, &az->ztree, sizeof(az->ztree)); + lock_protect(&az->lock, &az->xtree, sizeof(az->xtree)); + /* also lock protects the rbnode's in struct auth_zone, auth_xfer */ + lock_rw_init(&az->rpz_lock); + lock_protect(&az->rpz_lock, &az->rpz_first, sizeof(az->rpz_first)); + return az; +} + +int auth_zone_cmp(const void* z1, const void* z2) +{ + /* first sort on class, so that hierarchy can be maintained within + * a class */ + struct auth_zone* a = (struct auth_zone*)z1; + struct auth_zone* b = (struct auth_zone*)z2; + int m; + if(a->dclass != b->dclass) { + if(a->dclass < b->dclass) + return -1; + return 1; + } + /* sorted such that higher zones sort before lower zones (their + * contents) */ + return dname_lab_cmp(a->name, a->namelabs, b->name, b->namelabs, &m); +} + +int auth_data_cmp(const void* z1, const void* z2) +{ + struct auth_data* a = (struct auth_data*)z1; + struct auth_data* b = (struct auth_data*)z2; + int m; + /* canonical sort, because DNSSEC needs that */ + return dname_canon_lab_cmp(a->name, a->namelabs, b->name, + b->namelabs, &m); +} + +int auth_xfer_cmp(const void* z1, const void* z2) +{ + /* first sort on class, so that hierarchy can be maintained within + * a class */ + struct auth_xfer* a = (struct auth_xfer*)z1; + struct auth_xfer* b = (struct auth_xfer*)z2; + int m; + if(a->dclass != b->dclass) { + if(a->dclass < b->dclass) + return -1; + return 1; + } + /* sorted such that higher zones sort before lower zones (their + * contents) */ + return dname_lab_cmp(a->name, a->namelabs, b->name, b->namelabs, &m); +} + +/** delete auth rrset node */ +static void +auth_rrset_delete(struct auth_rrset* rrset) +{ + if(!rrset) return; + free(rrset->data); + free(rrset); +} + +/** delete auth data domain node */ +static void +auth_data_delete(struct auth_data* n) +{ + struct auth_rrset* p, *np; + if(!n) return; + p = n->rrsets; + while(p) { + np = p->next; + auth_rrset_delete(p); + p = np; + } + free(n->name); + free(n); +} + +/** helper traverse to delete zones */ +static void +auth_data_del(rbnode_type* n, void* ATTR_UNUSED(arg)) +{ + struct auth_data* z = (struct auth_data*)n->key; + auth_data_delete(z); +} + +/** delete an auth zone structure (tree remove must be done elsewhere) */ +static void +auth_zone_delete(struct auth_zone* z, struct auth_zones* az) +{ + if(!z) return; + lock_rw_destroy(&z->lock); + traverse_postorder(&z->data, auth_data_del, NULL); + + if(az && z->rpz) { + /* keep RPZ linked list intact */ + lock_rw_wrlock(&az->rpz_lock); + if(z->rpz_az_prev) + z->rpz_az_prev->rpz_az_next = z->rpz_az_next; + else + az->rpz_first = z->rpz_az_next; + if(z->rpz_az_next) + z->rpz_az_next->rpz_az_prev = z->rpz_az_prev; + lock_rw_unlock(&az->rpz_lock); + } + if(z->rpz) + rpz_delete(z->rpz); + free(z->name); + free(z->zonefile); + free(z); +} + +struct auth_zone* +auth_zone_create(struct auth_zones* az, uint8_t* nm, size_t nmlen, + uint16_t dclass) +{ + struct auth_zone* z = (struct auth_zone*)calloc(1, sizeof(*z)); + if(!z) { + return NULL; + } + z->node.key = z; + z->dclass = dclass; + z->namelen = nmlen; + z->namelabs = dname_count_labels(nm); + z->name = memdup(nm, nmlen); + if(!z->name) { + free(z); + return NULL; + } + rbtree_init(&z->data, &auth_data_cmp); + lock_rw_init(&z->lock); + lock_protect(&z->lock, &z->name, sizeof(*z)-sizeof(rbnode_type)- + sizeof(&z->rpz_az_next)-sizeof(&z->rpz_az_prev)); + lock_rw_wrlock(&z->lock); + /* z lock protects all, except rbtree itself and the rpz linked list + * pointers, which are protected using az->lock */ + if(!rbtree_insert(&az->ztree, &z->node)) { + lock_rw_unlock(&z->lock); + auth_zone_delete(z, NULL); + log_warn("duplicate auth zone"); + return NULL; + } + return z; +} + +struct auth_zone* +auth_zone_find(struct auth_zones* az, uint8_t* nm, size_t nmlen, + uint16_t dclass) +{ + struct auth_zone key; + key.node.key = &key; + key.dclass = dclass; + key.name = nm; + key.namelen = nmlen; + key.namelabs = dname_count_labels(nm); + return (struct auth_zone*)rbtree_search(&az->ztree, &key); +} + +struct auth_xfer* +auth_xfer_find(struct auth_zones* az, uint8_t* nm, size_t nmlen, + uint16_t dclass) +{ + struct auth_xfer key; + key.node.key = &key; + key.dclass = dclass; + key.name = nm; + key.namelen = nmlen; + key.namelabs = dname_count_labels(nm); + return (struct auth_xfer*)rbtree_search(&az->xtree, &key); +} + +/** find an auth zone or sorted less-or-equal, return true if exact */ +static int +auth_zone_find_less_equal(struct auth_zones* az, uint8_t* nm, size_t nmlen, + uint16_t dclass, struct auth_zone** z) +{ + struct auth_zone key; + key.node.key = &key; + key.dclass = dclass; + key.name = nm; + key.namelen = nmlen; + key.namelabs = dname_count_labels(nm); + return rbtree_find_less_equal(&az->ztree, &key, (rbnode_type**)z); +} + + +/** find the auth zone that is above the given name */ +struct auth_zone* +auth_zones_find_zone(struct auth_zones* az, uint8_t* name, size_t name_len, + uint16_t dclass) +{ + uint8_t* nm = name; + size_t nmlen = name_len; + struct auth_zone* z; + if(auth_zone_find_less_equal(az, nm, nmlen, dclass, &z)) { + /* exact match */ + return z; + } else { + /* less-or-nothing */ + if(!z) return NULL; /* nothing smaller, nothing above it */ + /* we found smaller name; smaller may be above the name, + * but not below it. */ + nm = dname_get_shared_topdomain(z->name, name); + dname_count_size_labels(nm, &nmlen); + z = NULL; + } + + /* search up */ + while(!z) { + z = auth_zone_find(az, nm, nmlen, dclass); + if(z) return z; + if(dname_is_root(nm)) break; + dname_remove_label(&nm, &nmlen); + } + return NULL; +} + +/** find or create zone with name str. caller must have lock on az. + * returns a wrlocked zone */ +static struct auth_zone* +auth_zones_find_or_add_zone(struct auth_zones* az, char* name) +{ + uint8_t nm[LDNS_MAX_DOMAINLEN+1]; + size_t nmlen = sizeof(nm); + struct auth_zone* z; + + if(sldns_str2wire_dname_buf(name, nm, &nmlen) != 0) { + log_err("cannot parse auth zone name: %s", name); + return 0; + } + z = auth_zone_find(az, nm, nmlen, LDNS_RR_CLASS_IN); + if(!z) { + /* not found, create the zone */ + z = auth_zone_create(az, nm, nmlen, LDNS_RR_CLASS_IN); + } else { + lock_rw_wrlock(&z->lock); + } + return z; +} + +/** find or create xfer zone with name str. caller must have lock on az. + * returns a locked xfer */ +static struct auth_xfer* +auth_zones_find_or_add_xfer(struct auth_zones* az, struct auth_zone* z) +{ + struct auth_xfer* x; + x = auth_xfer_find(az, z->name, z->namelen, z->dclass); + if(!x) { + /* not found, create the zone */ + x = auth_xfer_create(az, z); + } else { + lock_basic_lock(&x->lock); + } + return x; +} + +int +auth_zone_set_zonefile(struct auth_zone* z, char* zonefile) +{ + if(z->zonefile) free(z->zonefile); + if(zonefile == NULL) { + z->zonefile = NULL; + } else { + z->zonefile = strdup(zonefile); + if(!z->zonefile) { + log_err("malloc failure"); + return 0; + } + } + return 1; +} + +/** set auth zone fallback. caller must have lock on zone */ +int +auth_zone_set_fallback(struct auth_zone* z, char* fallbackstr) +{ + if(strcmp(fallbackstr, "yes") != 0 && strcmp(fallbackstr, "no") != 0){ + log_err("auth zone fallback, expected yes or no, got %s", + fallbackstr); + return 0; + } + z->fallback_enabled = (strcmp(fallbackstr, "yes")==0); + return 1; +} + +/** create domain with the given name */ +static struct auth_data* +az_domain_create(struct auth_zone* z, uint8_t* nm, size_t nmlen) +{ + struct auth_data* n = (struct auth_data*)malloc(sizeof(*n)); + if(!n) return NULL; + memset(n, 0, sizeof(*n)); + n->node.key = n; + n->name = memdup(nm, nmlen); + if(!n->name) { + free(n); + return NULL; + } + n->namelen = nmlen; + n->namelabs = dname_count_labels(nm); + if(!rbtree_insert(&z->data, &n->node)) { + log_warn("duplicate auth domain name"); + free(n->name); + free(n); + return NULL; + } + return n; +} + +/** find domain with exactly the given name */ +static struct auth_data* +az_find_name(struct auth_zone* z, uint8_t* nm, size_t nmlen) +{ + struct auth_zone key; + key.node.key = &key; + key.name = nm; + key.namelen = nmlen; + key.namelabs = dname_count_labels(nm); + return (struct auth_data*)rbtree_search(&z->data, &key); +} + +/** Find domain name (or closest match) */ +static void +az_find_domain(struct auth_zone* z, struct query_info* qinfo, int* node_exact, + struct auth_data** node) +{ + struct auth_zone key; + key.node.key = &key; + key.name = qinfo->qname; + key.namelen = qinfo->qname_len; + key.namelabs = dname_count_labels(key.name); + *node_exact = rbtree_find_less_equal(&z->data, &key, + (rbnode_type**)node); +} + +/** find or create domain with name in zone */ +static struct auth_data* +az_domain_find_or_create(struct auth_zone* z, uint8_t* dname, + size_t dname_len) +{ + struct auth_data* n = az_find_name(z, dname, dname_len); + if(!n) { + n = az_domain_create(z, dname, dname_len); + } + return n; +} + +/** find rrset of given type in the domain */ +static struct auth_rrset* +az_domain_rrset(struct auth_data* n, uint16_t t) +{ + struct auth_rrset* rrset; + if(!n) return NULL; + rrset = n->rrsets; + while(rrset) { + if(rrset->type == t) + return rrset; + rrset = rrset->next; + } + return NULL; +} + +/** remove rrset of this type from domain */ +static void +domain_remove_rrset(struct auth_data* node, uint16_t rr_type) +{ + struct auth_rrset* rrset, *prev; + if(!node) return; + prev = NULL; + rrset = node->rrsets; + while(rrset) { + if(rrset->type == rr_type) { + /* found it, now delete it */ + if(prev) prev->next = rrset->next; + else node->rrsets = rrset->next; + auth_rrset_delete(rrset); + return; + } + prev = rrset; + rrset = rrset->next; + } +} + +/** find an rrsig index in the rrset. returns true if found */ +static int +az_rrset_find_rrsig(struct packed_rrset_data* d, uint8_t* rdata, size_t len, + size_t* index) +{ + size_t i; + for(i=d->count; i<d->count + d->rrsig_count; i++) { + if(d->rr_len[i] != len) + continue; + if(memcmp(d->rr_data[i], rdata, len) == 0) { + *index = i; + return 1; + } + } + return 0; +} + +/** see if rdata is duplicate */ +static int +rdata_duplicate(struct packed_rrset_data* d, uint8_t* rdata, size_t len) +{ + size_t i; + for(i=0; i<d->count + d->rrsig_count; i++) { + if(d->rr_len[i] != len) + continue; + if(memcmp(d->rr_data[i], rdata, len) == 0) + return 1; + } + return 0; +} + +/** get rrsig type covered from rdata. + * @param rdata: rdata in wireformat, starting with 16bit rdlength. + * @param rdatalen: length of rdata buffer. + * @return type covered (or 0). + */ +static uint16_t +rrsig_rdata_get_type_covered(uint8_t* rdata, size_t rdatalen) +{ + if(rdatalen < 4) + return 0; + return sldns_read_uint16(rdata+2); +} + +/** remove RR from existing RRset. Also sig, if it is a signature. + * reallocates the packed rrset for a new one, false on alloc failure */ +static int +rrset_remove_rr(struct auth_rrset* rrset, size_t index) +{ + struct packed_rrset_data* d, *old = rrset->data; + size_t i; + if(index >= old->count + old->rrsig_count) + return 0; /* index out of bounds */ + d = (struct packed_rrset_data*)calloc(1, packed_rrset_sizeof(old) - ( + sizeof(size_t) + sizeof(uint8_t*) + sizeof(time_t) + + old->rr_len[index])); + if(!d) { + log_err("malloc failure"); + return 0; + } + d->ttl = old->ttl; + d->count = old->count; + d->rrsig_count = old->rrsig_count; + if(index < d->count) d->count--; + else d->rrsig_count--; + d->trust = old->trust; + d->security = old->security; + + /* set rr_len, needed for ptr_fixup */ + d->rr_len = (size_t*)((uint8_t*)d + + sizeof(struct packed_rrset_data)); + if(index > 0) + memmove(d->rr_len, old->rr_len, (index)*sizeof(size_t)); + if(index+1 < old->count+old->rrsig_count) + memmove(&d->rr_len[index], &old->rr_len[index+1], + (old->count+old->rrsig_count - (index+1))*sizeof(size_t)); + packed_rrset_ptr_fixup(d); + + /* move over ttls */ + if(index > 0) + memmove(d->rr_ttl, old->rr_ttl, (index)*sizeof(time_t)); + if(index+1 < old->count+old->rrsig_count) + memmove(&d->rr_ttl[index], &old->rr_ttl[index+1], + (old->count+old->rrsig_count - (index+1))*sizeof(time_t)); + + /* move over rr_data */ + for(i=0; i<d->count+d->rrsig_count; i++) { + size_t oldi; + if(i < index) oldi = i; + else oldi = i+1; + memmove(d->rr_data[i], old->rr_data[oldi], d->rr_len[i]); + } + + /* recalc ttl (lowest of remaining RR ttls) */ + if(d->count + d->rrsig_count > 0) + d->ttl = d->rr_ttl[0]; + for(i=0; i<d->count+d->rrsig_count; i++) { + if(d->rr_ttl[i] < d->ttl) + d->ttl = d->rr_ttl[i]; + } + + free(rrset->data); + rrset->data = d; *** 14663 LINES SKIPPED ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202102100427.11A4RgTa070269>