git: f44e67d120ad - main - MFV d60fa10fd872db7e3d8cb1e161cfdae026c43b14:
Cy Schubert
cy at FreeBSD.org
Wed Feb 10 04:27:43 UTC 2021
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 at FreeBSD.org>
AuthorDate: 2021-02-10 04:25:05 +0000
Commit: Cy Schubert <cy at 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 ***
More information about the dev-commits-src-all
mailing list