diff --git a/.gitignore b/.gitignore index 5c781e9..1aa39e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/unbound-1.16.2.tar.gz +unbound-1.20.0.tar.gz diff --git a/.unbound.metadata b/.unbound.metadata deleted file mode 100644 index c8b7a90..0000000 --- a/.unbound.metadata +++ /dev/null @@ -1 +0,0 @@ -9aea0e923b9d6779b5bc360094e24a4017e2bb25 SOURCES/unbound-1.16.2.tar.gz diff --git a/SOURCES/remote-control.conf b/SOURCES/remote-control.conf deleted file mode 100644 index 90072d3..0000000 --- a/SOURCES/remote-control.conf +++ /dev/null @@ -1,9 +0,0 @@ -# Remote control config section update. -# Previous defaults allowed any process to change settings, CVE-2024-1488 -remote-control: - # set to an absolute path to use a unix local name pipe, certificates - # are not used for that, so key and cert files need not be present. - control-interface: "/run/unbound/control" - - # For local sockets this option is ignored, and TLS is not used. - control-use-cert: "yes" diff --git a/SOURCES/tmpfiles-unbound.conf b/SOURCES/tmpfiles-unbound.conf deleted file mode 100644 index bb88f01..0000000 --- a/SOURCES/tmpfiles-unbound.conf +++ /dev/null @@ -1 +0,0 @@ -D /run/unbound 0755 unbound unbound - diff --git a/SOURCES/unbound-1.15-source-compat.patch b/SOURCES/unbound-1.15-source-compat.patch deleted file mode 100644 index bb0a1de..0000000 --- a/SOURCES/unbound-1.15-source-compat.patch +++ /dev/null @@ -1,85 +0,0 @@ -From fbde301c2706a5d0c9c3942fe84693f2b7a6b16c Mon Sep 17 00:00:00 2001 -From: Petr Mensik -Date: Sat, 7 May 2022 10:05:33 +0200 -Subject: [PATCH] Use reserved RCODE, fake source version - -Use RCODE value assigned for a private use. Previous value were possible -returned value. - -Fake source version to be still 1.7.x. Hide real version into micro -version component and export it also in a proper way with _REAL -suffixes. Should workaround any source code detection to support correct -callback format. Fixes compilation error in libreswan. - -Use preprocessed unbound.h to prevent failures - -Swig complains about wrong @ variable formats. Make it use preprocessed -header instead of a template. ---- - libunbound/python/libunbound.i | 4 ++-- - libunbound/unbound.h | 13 ++++++++++--- - services/mesh.h | 2 +- - 3 files changed, 13 insertions(+), 6 deletions(-) - -diff --git a/libunbound/python/libunbound.i b/libunbound/python/libunbound.i -index c9549bf90..f01e9111e 100644 ---- a/libunbound/python/libunbound.i -+++ b/libunbound/python/libunbound.i -@@ -53,7 +53,7 @@ - #ifdef HAVE_ARPA_INET_H - #include - #endif -- #include "libunbound/unbound.h" -+ #include "unbound.h" - %} - - %pythoncode %{ -@@ -855,7 +855,7 @@ Result: ['74.125.43.147', '74.125.43.99', '74.125.43.103', '74.125.43.104'] - //printf("resolve_stop()\n"); - %} - --%include "libunbound/unbound.h" -+%include "unbound.h" - - %inline %{ - //SWIG will see the ub_ctx as a class -diff --git a/libunbound/unbound.h b/libunbound/unbound.h -index c822d3f89..82660bd51 100644 ---- a/libunbound/unbound.h -+++ b/libunbound/unbound.h -@@ -102,9 +102,16 @@ extern "C" { - #endif - - /** the version of this header file */ --#define UNBOUND_VERSION_MAJOR @UNBOUND_VERSION_MAJOR@ --#define UNBOUND_VERSION_MINOR @UNBOUND_VERSION_MINOR@ --#define UNBOUND_VERSION_MICRO @UNBOUND_VERSION_MICRO@ -+/* Because of RHEL compat change, callback type remains at -+ * 1.7.3 version. To prevent source-level incompatibility, -+ * fake still old version. Export real version in _REAL -+ * suffix definitions. */ -+#define UNBOUND_VERSION_MAJOR 1 -+#define UNBOUND_VERSION_MINOR 7 -+#define UNBOUND_VERSION_MICRO @UNBOUND_VERSION_MAJOR@@UNBOUND_VERSION_MINOR@@UNBOUND_VERSION_MICRO@ -+#define UNBOUND_VERSION_MAJOR_REAL @UNBOUND_VERSION_MAJOR@ -+#define UNBOUND_VERSION_MINOR_REAL @UNBOUND_VERSION_MINOR@ -+#define UNBOUND_VERSION_MICRO_REAL @UNBOUND_VERSION_MICRO@ - - /** - * The validation context is created to hold the resolver status, -diff --git a/services/mesh.h b/services/mesh.h -index 9c6f958ff..c0cbf355e 100644 ---- a/services/mesh.h -+++ b/services/mesh.h -@@ -237,7 +237,7 @@ struct mesh_reply { - /* RHEL 8 compatibility layer. - * Special rcode to send was_ratelimited to callback without adding - * extra parameter. It is ORed to the rcode parameter of the callback. */ --#define LDNS_RCODE_RATELIMITED 0x100 -+#define LDNS_RCODE_RATELIMITED 0xf80 - #define RCODE_IS_RATELIMITED(rcode) ((rcode & LDNS_RCODE_RATELIMITED) != 0) - #define RCODE_NOT_RATELIMITED(rcode) (rcode & ~LDNS_RCODE_RATELIMITED) - --- -2.34.1 - diff --git a/SOURCES/unbound-1.15-soversion2-compat.patch b/SOURCES/unbound-1.15-soversion2-compat.patch deleted file mode 100644 index 897e243..0000000 --- a/SOURCES/unbound-1.15-soversion2-compat.patch +++ /dev/null @@ -1,471 +0,0 @@ -From 605d66f0b6b8f7c308010f455058299d25c1d2ee Mon Sep 17 00:00:00 2001 -From: Petr Mensik -Date: Fri, 6 May 2022 16:36:39 +0200 -Subject: [PATCH] Rework ABI breaking change to compatible way - -Upstream commit 749d1b9ebc6fcb79824afd0471a1cfc12ca861b1 introduced -was_ratelimited variable to every async callback. Such change led to ABI -break and increase of soname of libunbound. - -Use rcode to pass that boolean inside rcode variable. Allows keeping -original callback prototype, but does not lose data. Extra integer bit -operations should be very small price. Much better than ABI break. - -Make current version compatible back to .2 version. ---- - unbound-1.16.2/configure.ac | 2 +- - unbound-1.16.2/daemon/worker.c | 6 ++-- - unbound-1.16.2/libunbound/libworker.c | 34 +++++++++++++++-------- - unbound-1.16.2/libunbound/unbound-event.h | 3 +- - unbound-1.16.2/libunbound/unbound.h | 13 +++++---- - unbound-1.16.2/libunbound/worker.h | 6 ++-- - unbound-1.16.2/services/authzone.c | 11 ++++---- - unbound-1.16.2/services/authzone.h | 9 ++---- - unbound-1.16.2/services/mesh.c | 17 ++++++++---- - unbound-1.16.2/services/mesh.h | 9 +++++- - unbound-1.16.2/smallapp/worker_cb.c | 6 ++-- - unbound-1.16.2/validator/autotrust.c | 2 +- - unbound-1.16.2/validator/autotrust.h | 2 +- - 13 files changed, 72 insertions(+), 48 deletions(-) - -diff --git a/unbound-1.16.2/configure.ac b/unbound-1.16.2/configure.ac -index 224501b..71f066c 100644 ---- a/unbound-1.16.2/configure.ac -+++ b/unbound-1.16.2/configure.ac -@@ -19,7 +19,7 @@ AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO]) - - LIBUNBOUND_CURRENT=9 - LIBUNBOUND_REVISION=18 --LIBUNBOUND_AGE=1 -+LIBUNBOUND_AGE=7 - # 1.0.0 had 0:12:0 - # 1.0.1 had 0:13:0 - # 1.0.2 had 0:14:0 -diff --git a/unbound-1.16.2/daemon/worker.c b/unbound-1.16.2/daemon/worker.c -index 010c4dc..2b87a41 100644 ---- a/unbound-1.16.2/daemon/worker.c -+++ b/unbound-1.16.2/daemon/worker.c -@@ -2268,21 +2268,21 @@ void libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), - - void libworker_fg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), - sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), -- char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) -+ char* ATTR_UNUSED(why_bogus)) - { - log_assert(0); - } - - void libworker_bg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), - sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), -- char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) -+ char* ATTR_UNUSED(why_bogus)) - { - log_assert(0); - } - - void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), - sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), -- char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) -+ char* ATTR_UNUSED(why_bogus)) - { - log_assert(0); - } -diff --git a/unbound-1.16.2/libunbound/libworker.c b/unbound-1.16.2/libunbound/libworker.c -index 11bf5f9..6895119 100644 ---- a/unbound-1.16.2/libunbound/libworker.c -+++ b/unbound-1.16.2/libunbound/libworker.c -@@ -549,9 +549,10 @@ libworker_enter_result(struct ub_result* res, sldns_buffer* buf, - /** fillup fg results */ - static void - libworker_fillup_fg(struct ctx_query* q, int rcode, sldns_buffer* buf, -- enum sec_status s, char* why_bogus, int was_ratelimited) -+ enum sec_status s, char* why_bogus) - { -- q->res->was_ratelimited = was_ratelimited; -+ q->res->was_ratelimited = RCODE_IS_RATELIMITED(rcode); -+ rcode = RCODE_NOT_RATELIMITED(rcode); - if(why_bogus) - q->res->why_bogus = strdup(why_bogus); - if(rcode != 0) { -@@ -575,13 +576,13 @@ libworker_fillup_fg(struct ctx_query* q, int rcode, sldns_buffer* buf, - - void - libworker_fg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s, -- char* why_bogus, int was_ratelimited) -+ char* why_bogus) - { - struct ctx_query* q = (struct ctx_query*)arg; - /* fg query is done; exit comm base */ - comm_base_exit(q->w->base); - -- libworker_fillup_fg(q, rcode, buf, s, why_bogus, was_ratelimited); -+ libworker_fillup_fg(q, rcode, buf, s, why_bogus); - } - - /** setup qinfo and edns */ -@@ -634,7 +635,7 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q) - NULL, 0, NULL, 0, NULL)) { - regional_free_all(w->env->scratch); - libworker_fillup_fg(q, LDNS_RCODE_NOERROR, -- w->back->udp_buff, sec_status_insecure, NULL, 0); -+ w->back->udp_buff, sec_status_insecure, NULL); - libworker_delete(w); - free(qinfo.qname); - return UB_NOERROR; -@@ -643,7 +644,7 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q) - w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) { - regional_free_all(w->env->scratch); - libworker_fillup_fg(q, LDNS_RCODE_NOERROR, -- w->back->udp_buff, sec_status_insecure, NULL, 0); -+ w->back->udp_buff, sec_status_insecure, NULL); - libworker_delete(w); - free(qinfo.qname); - return UB_NOERROR; -@@ -665,7 +666,7 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q) - - void - libworker_event_done_cb(void* arg, int rcode, sldns_buffer* buf, -- enum sec_status s, char* why_bogus, int was_ratelimited) -+ enum sec_status s, char* why_bogus) - { - struct ctx_query* q = (struct ctx_query*)arg; - ub_event_callback_type cb = q->cb_event; -@@ -688,7 +689,7 @@ libworker_event_done_cb(void* arg, int rcode, sldns_buffer* buf, - else if(s == sec_status_secure) - sec = 2; - (*cb)(cb_arg, rcode, (buf?(void*)sldns_buffer_begin(buf):NULL), -- (buf?(int)sldns_buffer_limit(buf):0), sec, why_bogus, was_ratelimited); -+ (buf?(int)sldns_buffer_limit(buf):0), sec, why_bogus); - } - } - -@@ -715,7 +716,7 @@ int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q, - regional_free_all(w->env->scratch); - free(qinfo.qname); - libworker_event_done_cb(q, LDNS_RCODE_NOERROR, -- w->back->udp_buff, sec_status_insecure, NULL, 0); -+ w->back->udp_buff, sec_status_insecure, NULL); - return UB_NOERROR; - } - if(ctx->env->auth_zones && auth_zones_answer(ctx->env->auth_zones, -@@ -723,7 +724,7 @@ int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q, - regional_free_all(w->env->scratch); - free(qinfo.qname); - libworker_event_done_cb(q, LDNS_RCODE_NOERROR, -- w->back->udp_buff, sec_status_insecure, NULL, 0); -+ w->back->udp_buff, sec_status_insecure, NULL); - return UB_NOERROR; - } - /* process new query */ -@@ -788,12 +789,23 @@ add_bg_result(struct libworker* w, struct ctx_query* q, sldns_buffer* pkt, - } - } - -+ -+void -+libworker_bg_done_cb_compat(void* arg, int rcode, sldns_buffer* buf, enum sec_status s, -+ char* why_bogus) -+{ -+ rcode = RCODE_NOT_RATELIMITED(rcode); -+ libworker_bg_done_cb(arg, rcode, buf, s, why_bogus); -+} -+ - void - libworker_bg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s, -- char* why_bogus, int was_ratelimited) -+ char* why_bogus) - { -+ int was_ratelimited = RCODE_IS_RATELIMITED(rcode); - struct ctx_query* q = (struct ctx_query*)arg; - -+ rcode = RCODE_NOT_RATELIMITED(rcode); - if(q->cancelled || q->w->back->want_to_quit) { - if(q->w->is_bg_thread) { - /* delete it now */ -diff --git a/unbound-1.16.2/libunbound/unbound-event.h b/unbound-1.16.2/libunbound/unbound-event.h -index a5d5c03..70aa4c8 100644 ---- a/unbound-1.16.2/libunbound/unbound-event.h -+++ b/unbound-1.16.2/libunbound/unbound-event.h -@@ -170,7 +170,8 @@ struct ub_event { - struct ub_event_vmt* vmt; - }; - --typedef void (*ub_event_callback_type)(void*, int, void*, int, int, char*, int); -+/* Uses define LDNS_RCODE_RATELIMITED from services/mesh.h */ -+typedef void (*ub_event_callback_type)(void*, int, void*, int, int, char*); - - /** - * Create a resolving and validation context. -diff --git a/unbound-1.16.2/libunbound/unbound.h b/unbound-1.16.2/libunbound/unbound.h -index c779d18..f6d5c7c 100644 ---- a/unbound-1.16.2/libunbound/unbound.h -+++ b/unbound-1.16.2/libunbound/unbound.h -@@ -203,18 +203,19 @@ struct ub_result { - */ - char* why_bogus; - -+ /** -+ * TTL for the result, in seconds. If the security is bogus, then -+ * you also cannot trust this value. -+ */ -+ int ttl; -+ - /** - * If the query or one of its subqueries was ratelimited. Useful if - * ratelimiting is enabled and answer to the client is SERVFAIL as a - * result. -+ * RHEL8 Change, moved after ttl. - */ - int was_ratelimited; -- -- /** -- * TTL for the result, in seconds. If the security is bogus, then -- * you also cannot trust this value. -- */ -- int ttl; - }; - - /** -diff --git a/unbound-1.16.2/libunbound/worker.h b/unbound-1.16.2/libunbound/worker.h -index 0fa5bfa..8b64b4d 100644 ---- a/unbound-1.16.2/libunbound/worker.h -+++ b/unbound-1.16.2/libunbound/worker.h -@@ -90,15 +90,15 @@ void libworker_handle_control_cmd(struct tube* tube, uint8_t* msg, size_t len, - - /** mesh callback with fg results */ - void libworker_fg_done_cb(void* arg, int rcode, sldns_buffer* buf, -- enum sec_status s, char* why_bogus, int was_ratelimited); -+ enum sec_status s, char* why_bogus); - - /** mesh callback with bg results */ - void libworker_bg_done_cb(void* arg, int rcode, sldns_buffer* buf, -- enum sec_status s, char* why_bogus, int was_ratelimited); -+ enum sec_status s, char* why_bogus); - - /** mesh callback with event results */ - void libworker_event_done_cb(void* arg, int rcode, struct sldns_buffer* buf, -- enum sec_status s, char* why_bogus, int was_ratelimited); -+ enum sec_status s, char* why_bogus); - - /** - * Worker signal handler function. User argument is the worker itself. -diff --git a/unbound-1.16.2/services/authzone.c b/unbound-1.16.2/services/authzone.c -index b9e0b11..c72949f 100644 ---- a/unbound-1.16.2/services/authzone.c -+++ b/unbound-1.16.2/services/authzone.c -@@ -5656,8 +5656,7 @@ xfr_master_add_addrs(struct auth_master* m, struct ub_packed_rrset_key* rrset, - - /** callback for task_transfer lookup of host name, of A or AAAA */ - void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf, -- enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus), -- int ATTR_UNUSED(was_ratelimited)) -+ enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus)) - { - struct auth_xfer* xfr = (struct auth_xfer*)arg; - struct module_env* env; -@@ -5669,6 +5668,7 @@ void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf, - return; /* stop on quit */ - } - -+ rcode = RCODE_NOT_RATELIMITED(rcode); - /* process result */ - if(rcode == LDNS_RCODE_NOERROR) { - uint16_t wanted_qtype = LDNS_RR_TYPE_A; -@@ -6717,8 +6717,7 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env) - - /** callback for task_probe lookup of host name, of A or AAAA */ - void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf, -- enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus), -- int ATTR_UNUSED(was_ratelimited)) -+ enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus)) - { - struct auth_xfer* xfr = (struct auth_xfer*)arg; - struct module_env* env; -@@ -6730,6 +6729,7 @@ void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf, - return; /* stop on quit */ - } - -+ rcode = RCODE_NOT_RATELIMITED(rcode); - /* process result */ - if(rcode == LDNS_RCODE_NOERROR) { - uint16_t wanted_qtype = LDNS_RR_TYPE_A; -@@ -8212,7 +8212,7 @@ auth_zone_verify_zonemd_key_with_ds(struct auth_zone* z, - - /** callback for ZONEMD lookup of DNSKEY */ - void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf, -- enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited)) -+ enum sec_status sec, char* why_bogus) - { - struct auth_zone* z = (struct auth_zone*)arg; - struct module_env* env; -@@ -8234,6 +8234,7 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf, - if(z->zonemd_callback_qtype == LDNS_RR_TYPE_DS) - typestr = "DS"; - downprot = env->cfg->harden_algo_downgrade; -+ rcode = RCODE_NOT_RATELIMITED(rcode); - - /* process result */ - if(sec == sec_status_bogus) { -diff --git a/unbound-1.16.2/services/authzone.h b/unbound-1.16.2/services/authzone.h -index 07614ed..b339fc1 100644 ---- a/unbound-1.16.2/services/authzone.h -+++ b/unbound-1.16.2/services/authzone.h -@@ -690,12 +690,10 @@ void auth_xfer_probe_timer_callback(void* arg); - void auth_xfer_transfer_timer_callback(void* arg); - /** mesh callback for task_probe on lookup of host names */ - void auth_xfer_probe_lookup_callback(void* arg, int rcode, -- struct sldns_buffer* buf, enum sec_status sec, char* why_bogus, -- int was_ratelimited); -+ struct sldns_buffer* buf, enum sec_status sec, char* why_bogus); - /** mesh callback for task_transfer on lookup of host names */ - void auth_xfer_transfer_lookup_callback(void* arg, int rcode, -- struct sldns_buffer* buf, enum sec_status sec, char* why_bogus, -- int was_ratelimited); -+ struct sldns_buffer* buf, enum sec_status sec, char* why_bogus); - - /* - * Compares two 32-bit serial numbers as defined in RFC1982. Returns -@@ -774,8 +772,7 @@ void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env, - - /** mesh callback for zonemd on lookup of dnskey */ - void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, -- struct sldns_buffer* buf, enum sec_status sec, char* why_bogus, -- int was_ratelimited); -+ struct sldns_buffer* buf, enum sec_status sec, char* why_bogus); - - /** - * Check the ZONEMD records that need online DNSSEC chain lookups, -diff --git a/unbound-1.16.2/services/mesh.c b/unbound-1.16.2/services/mesh.c -index 30bcf7c..fc3c690 100644 ---- a/unbound-1.16.2/services/mesh.c -+++ b/unbound-1.16.2/services/mesh.c -@@ -63,6 +63,7 @@ - #include "util/data/dname.h" - #include "respip/respip.h" - #include "services/listen_dnsport.h" -+#include "libunbound/unbound-event.h" - - #ifdef CLIENT_SUBNET - #include "edns-subnet/subnetmod.h" -@@ -1012,7 +1013,7 @@ mesh_state_cleanup(struct mesh_state* mstate) - mstate->cb_list = cb->next; - fptr_ok(fptr_whitelist_mesh_cb(cb->cb)); - (*cb->cb)(cb->cb_arg, LDNS_RCODE_SERVFAIL, NULL, -- sec_status_unchecked, NULL, 0); -+ sec_status_unchecked, NULL); - log_assert(mesh->num_reply_addrs > 0); - mesh->num_reply_addrs--; - } -@@ -1268,8 +1269,9 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, - r->edns.opt_list_inplace_cb_out = NULL; - } - fptr_ok(fptr_whitelist_mesh_cb(r->cb)); -- (*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked, NULL, -- was_ratelimited); -+ if (was_ratelimited) -+ rcode |= LDNS_RCODE_RATELIMITED; -+ (*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked, NULL); - } else { - size_t udp_size = r->edns.udp_size; - sldns_buffer_clear(r->buf); -@@ -1287,11 +1289,14 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, - { - fptr_ok(fptr_whitelist_mesh_cb(r->cb)); - (*r->cb)(r->cb_arg, LDNS_RCODE_SERVFAIL, r->buf, -- sec_status_unchecked, NULL, 0); -+ sec_status_unchecked, NULL); - } else { - fptr_ok(fptr_whitelist_mesh_cb(r->cb)); -- (*r->cb)(r->cb_arg, LDNS_RCODE_NOERROR, r->buf, -- rep->security, reason, was_ratelimited); -+ rcode = LDNS_RCODE_NOERROR; -+ if (was_ratelimited) -+ rcode |= LDNS_RCODE_RATELIMITED; -+ (*r->cb)(r->cb_arg, rcode, r->buf, -+ rep->security, reason); - } - } - free(reason); -diff --git a/unbound-1.16.2/services/mesh.h b/unbound-1.16.2/services/mesh.h -index 3be9b63..5050d6c 100644 ---- a/unbound-1.16.2/services/mesh.h -+++ b/unbound-1.16.2/services/mesh.h -@@ -234,13 +234,20 @@ struct mesh_reply { - struct http2_stream* h2_stream; - }; - -+/* RHEL 8 compatibility layer. -+ * Special rcode to send was_ratelimited to callback without adding -+ * extra parameter. It is ORed to the rcode parameter of the callback. */ -+#define LDNS_RCODE_RATELIMITED 0x100 -+#define RCODE_IS_RATELIMITED(rcode) ((rcode & LDNS_RCODE_RATELIMITED) != 0) -+#define RCODE_NOT_RATELIMITED(rcode) (rcode & ~LDNS_RCODE_RATELIMITED) -+ - /** - * Mesh result callback func. - * called as func(cb_arg, rcode, buffer_with_reply, security, why_bogus, - * was_ratelimited); - */ - typedef void (*mesh_cb_func_type)(void* cb_arg, int rcode, struct sldns_buffer*, -- enum sec_status, char* why_bogus, int was_ratelimited); -+ enum sec_status, char* why_bogus); - - /** - * Callback to result routine -diff --git a/unbound-1.16.2/smallapp/worker_cb.c b/unbound-1.16.2/smallapp/worker_cb.c -index c689817..c7b1653 100644 ---- a/unbound-1.16.2/smallapp/worker_cb.c -+++ b/unbound-1.16.2/smallapp/worker_cb.c -@@ -159,21 +159,21 @@ void libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), - - void libworker_fg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), - struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), -- char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) -+ char* ATTR_UNUSED(why_bogus)) - { - log_assert(0); - } - - void libworker_bg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), - struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), -- char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) -+ char* ATTR_UNUSED(why_bogus)) - { - log_assert(0); - } - - void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), - struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), -- char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) -+ char* ATTR_UNUSED(why_bogus)) - { - log_assert(0); - } -diff --git a/unbound-1.16.2/validator/autotrust.c b/unbound-1.16.2/validator/autotrust.c -index 3cdf9ce..40b3e35 100644 ---- a/unbound-1.16.2/validator/autotrust.c -+++ b/unbound-1.16.2/validator/autotrust.c -@@ -2331,7 +2331,7 @@ autr_debug_print(struct val_anchors* anchors) - - void probe_answer_cb(void* arg, int ATTR_UNUSED(rcode), - sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(sec), -- char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited)) -+ char* ATTR_UNUSED(why_bogus)) - { - /* retry was set before the query was done, - * re-querytime is set when query succeeded, but that may not -diff --git a/unbound-1.16.2/validator/autotrust.h b/unbound-1.16.2/validator/autotrust.h -index 057f2b6..c549798 100644 ---- a/unbound-1.16.2/validator/autotrust.h -+++ b/unbound-1.16.2/validator/autotrust.h -@@ -206,6 +206,6 @@ void autr_debug_print(struct val_anchors* anchors); - - /** callback for query answer to 5011 probe */ - void probe_answer_cb(void* arg, int rcode, struct sldns_buffer* buf, -- enum sec_status sec, char* errinf, int was_ratelimited); -+ enum sec_status sec, char* errinf); - - #endif /* VALIDATOR_AUTOTRUST_H */ --- -2.37.1 - diff --git a/SOURCES/unbound-1.16-CVE-2022-3204.patch b/SOURCES/unbound-1.16-CVE-2022-3204.patch deleted file mode 100644 index 2d2da91..0000000 --- a/SOURCES/unbound-1.16-CVE-2022-3204.patch +++ /dev/null @@ -1,218 +0,0 @@ -From 7af485f0fc9926425681ba0280ab6c2c8dd04530 Mon Sep 17 00:00:00 2001 -From: "W.C.A. Wijngaards" -Date: Wed, 21 Sep 2022 11:10:38 +0200 -Subject: [PATCH] - Patch for CVE-2022-3204 Non-Responsive Delegation Attack. - ---- - unbound-1.16.2/iterator/iter_delegpt.c | 3 +++ - unbound-1.16.2/iterator/iter_delegpt.h | 2 ++ - unbound-1.16.2/iterator/iter_utils.c | 3 +++ - unbound-1.16.2/iterator/iter_utils.h | 9 +++++++ - unbound-1.16.2/iterator/iterator.c | 36 +++++++++++++++++++++++++- - unbound-1.16.2/services/cache/dns.c | 3 +++ - unbound-1.16.2/services/mesh.c | 7 +++++ - unbound-1.16.2/services/mesh.h | 11 ++++++++ - 8 files changed, 73 insertions(+), 1 deletion(-) - -diff --git a/unbound-1.16.2/iterator/iter_delegpt.c b/unbound-1.16.2/iterator/iter_delegpt.c -index 4bffa1b..fd07aaa 100644 ---- a/unbound-1.16.2/iterator/iter_delegpt.c -+++ b/unbound-1.16.2/iterator/iter_delegpt.c -@@ -78,6 +78,7 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region) - if(!delegpt_add_ns(copy, region, ns->name, ns->lame, - ns->tls_auth_name, ns->port)) - return NULL; -+ copy->nslist->cache_lookup_count = ns->cache_lookup_count; - copy->nslist->resolved = ns->resolved; - copy->nslist->got4 = ns->got4; - copy->nslist->got6 = ns->got6; -@@ -121,6 +122,7 @@ delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name, - ns->namelen = len; - dp->nslist = ns; - ns->name = regional_alloc_init(region, name, ns->namelen); -+ ns->cache_lookup_count = 0; - ns->resolved = 0; - ns->got4 = 0; - ns->got6 = 0; -@@ -620,6 +622,7 @@ int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame, - } - ns->next = dp->nslist; - dp->nslist = ns; -+ ns->cache_lookup_count = 0; - ns->resolved = 0; - ns->got4 = 0; - ns->got6 = 0; -diff --git a/unbound-1.16.2/iterator/iter_delegpt.h b/unbound-1.16.2/iterator/iter_delegpt.h -index 62c8edc..586597a 100644 ---- a/unbound-1.16.2/iterator/iter_delegpt.h -+++ b/unbound-1.16.2/iterator/iter_delegpt.h -@@ -101,6 +101,8 @@ struct delegpt_ns { - uint8_t* name; - /** length of name */ - size_t namelen; -+ /** number of cache lookups for the name */ -+ int cache_lookup_count; - /** - * If the name has been resolved. false if not queried for yet. - * true if the A, AAAA queries have been generated. -diff --git a/unbound-1.16.2/iterator/iter_utils.c b/unbound-1.16.2/iterator/iter_utils.c -index 3e13e59..56b184a 100644 ---- a/unbound-1.16.2/iterator/iter_utils.c -+++ b/unbound-1.16.2/iterator/iter_utils.c -@@ -1209,6 +1209,9 @@ int iter_lookup_parent_glue_from_cache(struct module_env* env, - struct delegpt_ns* ns; - size_t num = delegpt_count_targets(dp); - for(ns = dp->nslist; ns; ns = ns->next) { -+ if(ns->cache_lookup_count > ITERATOR_NAME_CACHELOOKUP_MAX_PSIDE) -+ continue; -+ ns->cache_lookup_count++; - /* get cached parentside A */ - akey = rrset_cache_lookup(env->rrset_cache, ns->name, - ns->namelen, LDNS_RR_TYPE_A, qinfo->qclass, -diff --git a/unbound-1.16.2/iterator/iter_utils.h b/unbound-1.16.2/iterator/iter_utils.h -index 8583fde..850be96 100644 ---- a/unbound-1.16.2/iterator/iter_utils.h -+++ b/unbound-1.16.2/iterator/iter_utils.h -@@ -62,6 +62,15 @@ struct ub_packed_rrset_key; - struct module_stack; - struct outside_network; - -+/* max number of lookups in the cache for target nameserver names. -+ * This stops, for large delegations, N*N lookups in the cache. */ -+#define ITERATOR_NAME_CACHELOOKUP_MAX 3 -+/* max number of lookups in the cache for parentside glue for nameserver names -+ * This stops, for larger delegations, N*N lookups in the cache. -+ * It is a little larger than the nonpside max, so it allows a couple extra -+ * lookups of parent side glue. */ -+#define ITERATOR_NAME_CACHELOOKUP_MAX_PSIDE 5 -+ - /** - * Process config options and set iterator module state. - * Sets default values if no config is found. -diff --git a/unbound-1.16.2/iterator/iterator.c b/unbound-1.16.2/iterator/iterator.c -index 25e5cfe..da9b799 100644 ---- a/unbound-1.16.2/iterator/iterator.c -+++ b/unbound-1.16.2/iterator/iterator.c -@@ -1218,6 +1218,15 @@ generate_dnskey_prefetch(struct module_qstate* qstate, - (qstate->query_flags&BIT_RD) && !(qstate->query_flags&BIT_CD)){ - return; - } -+ /* we do not generate this prefetch when the query list is full, -+ * the query is fetched, if needed, when the validator wants it. -+ * At that time the validator waits for it, after spawning it. -+ * This means there is one state that uses cpu and a socket, the -+ * spawned while this one waits, and not several at the same time, -+ * if we had created the lookup here. And this helps to keep -+ * the total load down, but the query still succeeds to resolve. */ -+ if(mesh_jostle_exceeded(qstate->env->mesh)) -+ return; - - /* if the DNSKEY is in the cache this lookup will stop quickly */ - log_nametypeclass(VERB_ALGO, "schedule dnskey prefetch", -@@ -1911,6 +1920,14 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq, - return 0; - } - query_count++; -+ /* If the mesh query list is full, exit the loop here. -+ * This makes the routine spawn one query at a time, -+ * and this means there is no query state load -+ * increase, because the spawned state uses cpu and a -+ * socket while this state waits for that spawned -+ * state. Next time we can look up further targets */ -+ if(mesh_jostle_exceeded(qstate->env->mesh)) -+ break; - } - /* Send the A request. */ - if(ie->supports_ipv4 && -@@ -1925,6 +1942,9 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq, - return 0; - } - query_count++; -+ /* If the mesh query list is full, exit the loop. */ -+ if(mesh_jostle_exceeded(qstate->env->mesh)) -+ break; - } - - /* mark this target as in progress. */ -@@ -2085,6 +2105,15 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, - } - ns->done_pside6 = 1; - query_count++; -+ if(mesh_jostle_exceeded(qstate->env->mesh)) { -+ /* Wait for the lookup; do not spawn multiple -+ * lookups at a time. */ -+ verbose(VERB_ALGO, "try parent-side glue lookup"); -+ iq->num_target_queries += query_count; -+ target_count_increase(iq, query_count); -+ qstate->ext_state[id] = module_wait_subquery; -+ return 0; -+ } - } - if(ie->supports_ipv4 && !ns->done_pside4) { - /* Send the A request. */ -@@ -2560,7 +2589,12 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, - if(iq->depth < ie->max_dependency_depth - && iq->num_target_queries == 0 - && (!iq->target_count || iq->target_count[TARGET_COUNT_NX]==0) -- && iq->sent_count < TARGET_FETCH_STOP) { -+ && iq->sent_count < TARGET_FETCH_STOP -+ /* if the mesh query list is full, then do not waste cpu -+ * and sockets to fetch promiscuous targets. They can be -+ * looked up when needed. */ -+ && !mesh_jostle_exceeded(qstate->env->mesh) -+ ) { - tf_policy = ie->target_fetch_policy[iq->depth]; - } - -diff --git a/unbound-1.16.2/services/cache/dns.c b/unbound-1.16.2/services/cache/dns.c -index 6bca8d8..b6e5697 100644 ---- a/unbound-1.16.2/services/cache/dns.c -+++ b/unbound-1.16.2/services/cache/dns.c -@@ -404,6 +404,9 @@ cache_fill_missing(struct module_env* env, uint16_t qclass, - struct ub_packed_rrset_key* akey; - time_t now = *env->now; - for(ns = dp->nslist; ns; ns = ns->next) { -+ if(ns->cache_lookup_count > ITERATOR_NAME_CACHELOOKUP_MAX) -+ continue; -+ ns->cache_lookup_count++; - akey = rrset_cache_lookup(env->rrset_cache, ns->name, - ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0); - if(akey) { -diff --git a/unbound-1.16.2/services/mesh.c b/unbound-1.16.2/services/mesh.c -index 30bcf7c..2a41194 100644 ---- a/unbound-1.16.2/services/mesh.c -+++ b/unbound-1.16.2/services/mesh.c -@@ -2240,3 +2240,10 @@ mesh_serve_expired_callback(void* arg) - mesh_do_callback(mstate, LDNS_RCODE_NOERROR, msg->rep, c, &tv); - } - } -+ -+int mesh_jostle_exceeded(struct mesh_area* mesh) -+{ -+ if(mesh->all.count < mesh->max_reply_states) -+ return 0; -+ return 1; -+} -diff --git a/unbound-1.16.2/services/mesh.h b/unbound-1.16.2/services/mesh.h -index 3be9b63..25121a6 100644 ---- a/unbound-1.16.2/services/mesh.h -+++ b/unbound-1.16.2/services/mesh.h -@@ -685,4 +685,15 @@ struct dns_msg* - mesh_serve_expired_lookup(struct module_qstate* qstate, - struct query_info* lookup_qinfo); - -+/** -+ * See if the mesh has space for more queries. You can allocate queries -+ * anyway, but this checks for the allocated space. -+ * @param mesh: mesh area. -+ * @return true if the query list is full. -+ * It checks the number of all queries, not just number of reply states, -+ * that have a client address. So that spawned queries count too, -+ * that were created by the iterator, or other modules. -+ */ -+int mesh_jostle_exceeded(struct mesh_area* mesh); -+ - #endif /* SERVICES_MESH_H */ --- -2.37.3 - diff --git a/SOURCES/unbound-1.16-CVE-2023-50387-CVE-2023-50868.patch b/SOURCES/unbound-1.16-CVE-2023-50387-CVE-2023-50868.patch deleted file mode 100644 index b2e1ca5..0000000 --- a/SOURCES/unbound-1.16-CVE-2023-50387-CVE-2023-50868.patch +++ /dev/null @@ -1,2304 +0,0 @@ -commit cc3259547f5f1c4a8206e169cf579d08f95d5178 -Author: Tomas Korbar -Date: Wed Feb 14 13:37:21 2024 +0100 - - Fix CVE-2023-50387 and CVE-2023-50868 - -diff --git a/unbound-1.16.2/services/authzone.c b/unbound-1.16.2/services/authzone.c -index b9e0b11..04527c3 100644 ---- a/unbound-1.16.2/services/authzone.c -+++ b/unbound-1.16.2/services/authzone.c -@@ -7766,6 +7766,7 @@ static int zonemd_dnssec_verify_rrset(struct auth_zone* z, - enum sec_status sec; - struct val_env* ve; - int m; -+ int verified = 0; - m = modstack_find(mods, "validator"); - if(m == -1) { - auth_zone_log(z->name, VERB_ALGO, "zonemd dnssec verify: have " -@@ -7789,7 +7790,7 @@ static int zonemd_dnssec_verify_rrset(struct auth_zone* z, - "zonemd: verify %s RRset with DNSKEY", typestr); - } - sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, sigalg, why_bogus, NULL, -- LDNS_SECTION_ANSWER, NULL); -+ LDNS_SECTION_ANSWER, NULL, &verified); - if(sec == sec_status_secure) { - return 1; - } -diff --git a/unbound-1.16.2/services/cache/dns.c b/unbound-1.16.2/services/cache/dns.c -index b6e5697..0d75595 100644 ---- a/unbound-1.16.2/services/cache/dns.c -+++ b/unbound-1.16.2/services/cache/dns.c -@@ -695,6 +695,24 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r, - return msg; - } - -+struct dns_msg* -+dns_msg_deepcopy_region(struct dns_msg* origin, struct regional* region) -+{ -+ size_t i; -+ struct dns_msg* res = NULL; -+ res = gen_dns_msg(region, &origin->qinfo, origin->rep->rrset_count); -+ if(!res) return NULL; -+ *res->rep = *origin->rep; -+ for(i=0; irep->rrset_count; i++) { -+ res->rep->rrsets[i] = packed_rrset_copy_region( -+ origin->rep->rrsets[i], region, 0); -+ if(!res->rep->rrsets[i]) { -+ return NULL; -+ } -+ } -+ return res; -+} -+ - /** synthesize RRset-only response from cached RRset item */ - static struct dns_msg* - rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region, -diff --git a/unbound-1.16.2/services/cache/dns.h b/unbound-1.16.2/services/cache/dns.h -index 147f992..c2bf23c 100644 ---- a/unbound-1.16.2/services/cache/dns.h -+++ b/unbound-1.16.2/services/cache/dns.h -@@ -164,6 +164,15 @@ struct dns_msg* tomsg(struct module_env* env, struct query_info* q, - struct reply_info* r, struct regional* region, time_t now, - int allow_expired, struct regional* scratch); - -+/** -+ * Deep copy a dns_msg to a region. -+ * @param origin: the dns_msg to copy. -+ * @param region: the region to copy all the data to. -+ * @return the new dns_msg or NULL on malloc error. -+ */ -+struct dns_msg* dns_msg_deepcopy_region(struct dns_msg* origin, -+ struct regional* region); -+ - /** - * Find cached message - * @param env: module environment with the DNS cache. -diff --git a/unbound-1.16.2/testcode/unitverify.c b/unbound-1.16.2/testcode/unitverify.c -index ff069a1..395b4c2 100644 ---- a/unbound-1.16.2/testcode/unitverify.c -+++ b/unbound-1.16.2/testcode/unitverify.c -@@ -180,6 +180,7 @@ verifytest_rrset(struct module_env* env, struct val_env* ve, - enum sec_status sec; - char* reason = NULL; - uint8_t sigalg[ALGO_NEEDS_MAX+1]; -+ int verified = 0; - if(vsig) { - log_nametypeclass(VERB_QUERY, "verify of rrset", - rrset->rk.dname, ntohs(rrset->rk.type), -@@ -188,7 +189,7 @@ verifytest_rrset(struct module_env* env, struct val_env* ve, - setup_sigalg(dnskey, sigalg); /* check all algorithms in the dnskey */ - /* ok to give null as qstate here, won't be used for answer section. */ - sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason, NULL, -- LDNS_SECTION_ANSWER, NULL); -+ LDNS_SECTION_ANSWER, NULL, &verified); - if(vsig) { - printf("verify outcome is: %s %s\n", sec_status_to_string(sec), - reason?reason:""); -@@ -442,9 +443,9 @@ nsec3_hash_test_entry(struct entry* e, rbtree_type* ct, - - ret = nsec3_hash_name(ct, region, buf, nsec3, 0, qname, - qinfo.qname_len, &hash); -- if(ret != 1) { -+ if(ret < 1) { - printf("Bad nsec3_hash_name retcode %d\n", ret); -- unit_assert(ret == 1); -+ unit_assert(ret == 1 || ret == 2); - } - unit_assert(hash->dname && hash->hash && hash->hash_len && - hash->b32 && hash->b32_len); -diff --git a/unbound-1.16.2/testdata/val_any.rpl b/unbound-1.16.2/testdata/val_any.rpl -index 4ce1951..90263af 100644 ---- a/unbound-1.16.2/testdata/val_any.rpl -+++ b/unbound-1.16.2/testdata/val_any.rpl -@@ -161,6 +161,9 @@ SECTION QUESTION - example.com. IN ANY - ENTRY_END - -+; Allow validation resuming for the RRSIGs -+STEP 2 TIME_PASSES ELAPSE 0.05 -+ - ; recursion happens here. - STEP 10 CHECK_ANSWER - ENTRY_BEGIN -diff --git a/unbound-1.16.2/testdata/val_any_dname.rpl b/unbound-1.16.2/testdata/val_any_dname.rpl -index 6ab3cde..dd65e97 100644 ---- a/unbound-1.16.2/testdata/val_any_dname.rpl -+++ b/unbound-1.16.2/testdata/val_any_dname.rpl -@@ -163,6 +163,9 @@ SECTION QUESTION - example.com. IN ANY - ENTRY_END - -+; Allow validation resuming for the RRSIGs -+STEP 2 TIME_PASSES ELAPSE 0.05 -+ - ; recursion happens here. - STEP 10 CHECK_ANSWER - ENTRY_BEGIN -diff --git a/unbound-1.16.2/testdata/val_nx_nsec3_collision.rpl b/unbound-1.16.2/testdata/val_nx_nsec3_collision.rpl -index 8ff7e4b..87a55f5 100644 ---- a/unbound-1.16.2/testdata/val_nx_nsec3_collision.rpl -+++ b/unbound-1.16.2/testdata/val_nx_nsec3_collision.rpl -@@ -156,6 +156,9 @@ SECTION QUESTION - www.example.com. IN A - ENTRY_END - -+; Allow validation resuming for NSEC3 hash calculations -+STEP 2 TIME_PASSES ELAPSE 0.05 -+ - ; recursion happens here. - STEP 10 CHECK_ANSWER - ENTRY_BEGIN -diff --git a/unbound-1.16.2/util/fptr_wlist.c b/unbound-1.16.2/util/fptr_wlist.c -index 05a22d4..5b198b2 100644 ---- a/unbound-1.16.2/util/fptr_wlist.c -+++ b/unbound-1.16.2/util/fptr_wlist.c -@@ -131,6 +131,7 @@ fptr_whitelist_comm_timer(void (*fptr)(void*)) - else if(fptr == &pending_udp_timer_delay_cb) return 1; - else if(fptr == &worker_stat_timer_cb) return 1; - else if(fptr == &worker_probe_timer_cb) return 1; -+ else if(fptr == &validate_suspend_timer_cb) return 1; - #ifdef UB_ON_WINDOWS - else if(fptr == &wsvc_cron_cb) return 1; - #endif -diff --git a/unbound-1.16.2/validator/val_nsec.c b/unbound-1.16.2/validator/val_nsec.c -index 876bfab..5871db9 100644 ---- a/unbound-1.16.2/validator/val_nsec.c -+++ b/unbound-1.16.2/validator/val_nsec.c -@@ -180,6 +180,7 @@ nsec_verify_rrset(struct module_env* env, struct val_env* ve, - { - struct packed_rrset_data* d = (struct packed_rrset_data*) - nsec->entry.data; -+ int verified = 0; - if(!d) return 0; - if(d->security == sec_status_secure) - return 1; -@@ -187,7 +188,7 @@ nsec_verify_rrset(struct module_env* env, struct val_env* ve, - if(d->security == sec_status_secure) - return 1; - d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason, -- NULL, LDNS_SECTION_AUTHORITY, qstate); -+ NULL, LDNS_SECTION_AUTHORITY, qstate, &verified); - if(d->security == sec_status_secure) { - rrset_update_sec_status(env->rrset_cache, nsec, *env->now); - return 1; -diff --git a/unbound-1.16.2/validator/val_nsec3.c b/unbound-1.16.2/validator/val_nsec3.c -index a2b3794..95d1e4d 100644 ---- a/unbound-1.16.2/validator/val_nsec3.c -+++ b/unbound-1.16.2/validator/val_nsec3.c -@@ -57,6 +57,19 @@ - /* we include nsec.h for the bitmap_has_type function */ - #include "validator/val_nsec.h" - #include "sldns/sbuffer.h" -+#include "util/config_file.h" -+ -+/** -+ * Max number of NSEC3 calculations at once, suspend query for later. -+ * 8 is low enough and allows for cases where multiple proofs are needed. -+ */ -+#define MAX_NSEC3_CALCULATIONS 8 -+/** -+ * When all allowed NSEC3 calculations at once resulted in error treat as -+ * bogus. NSEC3 hash errors are not cached and this helps breaks loops with -+ * erroneous data. -+ */ -+#define MAX_NSEC3_ERRORS -1 - - /** - * This function we get from ldns-compat or from base system -@@ -532,6 +545,17 @@ nsec3_hash_cmp(const void* c1, const void* c2) - return memcmp(s1, s2, s1len); - } - -+int -+nsec3_cache_table_init(struct nsec3_cache_table* ct, struct regional* region) -+{ -+ if(ct->ct) return 1; -+ ct->ct = (rbtree_type*)regional_alloc(region, sizeof(*ct->ct)); -+ if(!ct->ct) return 0; -+ ct->region = region; -+ rbtree_init(ct->ct, &nsec3_hash_cmp); -+ return 1; -+} -+ - size_t - nsec3_get_hashed(sldns_buffer* buf, uint8_t* nm, size_t nmlen, int algo, - size_t iter, uint8_t* salt, size_t saltlen, uint8_t* res, size_t max) -@@ -646,7 +670,7 @@ nsec3_hash_name(rbtree_type* table, struct regional* region, sldns_buffer* buf, - c = (struct nsec3_cached_hash*)rbtree_search(table, &looki); - if(c) { - *hash = c; -- return 1; -+ return 2; - } - /* create a new entry */ - c = (struct nsec3_cached_hash*)regional_alloc(region, sizeof(*c)); -@@ -658,10 +682,10 @@ nsec3_hash_name(rbtree_type* table, struct regional* region, sldns_buffer* buf, - c->dname_len = dname_len; - r = nsec3_calc_hash(region, buf, c); - if(r != 1) -- return r; -+ return r; /* returns -1 or 0 */ - r = nsec3_calc_b32(region, buf, c); - if(r != 1) -- return r; -+ return r; /* returns 0 */ - #ifdef UNBOUND_DEBUG - n = - #else -@@ -704,6 +728,7 @@ nsec3_hash_matches_owner(struct nsec3_filter* flt, - struct nsec3_cached_hash* hash, struct ub_packed_rrset_key* s) - { - uint8_t* nm = s->rk.dname; -+ if(!hash) return 0; /* please clang */ - /* compare, does hash of name based on params in this NSEC3 - * match the owner name of this NSEC3? - * name must be: base32 . zone name -@@ -730,34 +755,50 @@ nsec3_hash_matches_owner(struct nsec3_filter* flt, - * @param nmlen: length of name. - * @param rrset: nsec3 that matches is returned here. - * @param rr: rr number in nsec3 rrset that matches. -+ * @param calculations: current hash calculations. - * @return true if a matching NSEC3 is found, false if not. - */ - static int - find_matching_nsec3(struct module_env* env, struct nsec3_filter* flt, -- rbtree_type* ct, uint8_t* nm, size_t nmlen, -- struct ub_packed_rrset_key** rrset, int* rr) -+ struct nsec3_cache_table* ct, uint8_t* nm, size_t nmlen, -+ struct ub_packed_rrset_key** rrset, int* rr, -+ int* calculations) - { - size_t i_rs; - int i_rr; - struct ub_packed_rrset_key* s; - struct nsec3_cached_hash* hash = NULL; - int r; -+ int calc_errors = 0; - - /* this loop skips other-zone and unknown NSEC3s, also non-NSEC3 RRs */ - for(s=filter_first(flt, &i_rs, &i_rr); s; - s=filter_next(flt, &i_rs, &i_rr)) { -+ /* check if we are allowed more calculations */ -+ if(*calculations >= MAX_NSEC3_CALCULATIONS) { -+ if(calc_errors == *calculations) { -+ *calculations = MAX_NSEC3_ERRORS; -+ } -+ break; -+ } - /* get name hashed for this NSEC3 RR */ -- r = nsec3_hash_name(ct, env->scratch, env->scratch_buffer, -+ r = nsec3_hash_name(ct->ct, ct->region, env->scratch_buffer, - s, i_rr, nm, nmlen, &hash); - if(r == 0) { - log_err("nsec3: malloc failure"); - break; /* alloc failure */ -- } else if(r != 1) -- continue; /* malformed NSEC3 */ -- else if(nsec3_hash_matches_owner(flt, hash, s)) { -- *rrset = s; /* rrset with this name */ -- *rr = i_rr; /* matches hash with these parameters */ -- return 1; -+ } else if(r < 0) { -+ /* malformed NSEC3 */ -+ calc_errors++; -+ (*calculations)++; -+ continue; -+ } else { -+ if(r == 1) (*calculations)++; -+ if(nsec3_hash_matches_owner(flt, hash, s)) { -+ *rrset = s; /* rrset with this name */ -+ *rr = i_rr; /* matches hash with these parameters */ -+ return 1; -+ } - } - } - *rrset = NULL; -@@ -775,6 +816,7 @@ nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash, - if(!nsec3_get_nextowner(rrset, rr, &next, &nextlen)) - return 0; /* malformed RR proves nothing */ - -+ if(!hash) return 0; /* please clang */ - /* check the owner name is a hashed value . apex - * base32 encoded values must have equal length. - * hash_value and next hash value must have equal length. */ -@@ -823,35 +865,51 @@ nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash, - * @param nmlen: length of name. - * @param rrset: covering NSEC3 rrset is returned here. - * @param rr: rr of cover is returned here. -+ * @param calculations: current hash calculations. - * @return true if a covering NSEC3 is found, false if not. - */ - static int - find_covering_nsec3(struct module_env* env, struct nsec3_filter* flt, -- rbtree_type* ct, uint8_t* nm, size_t nmlen, -- struct ub_packed_rrset_key** rrset, int* rr) -+ struct nsec3_cache_table* ct, uint8_t* nm, size_t nmlen, -+ struct ub_packed_rrset_key** rrset, int* rr, -+ int* calculations) - { - size_t i_rs; - int i_rr; - struct ub_packed_rrset_key* s; - struct nsec3_cached_hash* hash = NULL; - int r; -+ int calc_errors = 0; - - /* this loop skips other-zone and unknown NSEC3s, also non-NSEC3 RRs */ - for(s=filter_first(flt, &i_rs, &i_rr); s; - s=filter_next(flt, &i_rs, &i_rr)) { -+ /* check if we are allowed more calculations */ -+ if(*calculations >= MAX_NSEC3_CALCULATIONS) { -+ if(calc_errors == *calculations) { -+ *calculations = MAX_NSEC3_ERRORS; -+ } -+ break; -+ } - /* get name hashed for this NSEC3 RR */ -- r = nsec3_hash_name(ct, env->scratch, env->scratch_buffer, -+ r = nsec3_hash_name(ct->ct, ct->region, env->scratch_buffer, - s, i_rr, nm, nmlen, &hash); - if(r == 0) { - log_err("nsec3: malloc failure"); - break; /* alloc failure */ -- } else if(r != 1) -- continue; /* malformed NSEC3 */ -- else if(nsec3_covers(flt->zone, hash, s, i_rr, -- env->scratch_buffer)) { -- *rrset = s; /* rrset with this name */ -- *rr = i_rr; /* covers hash with these parameters */ -- return 1; -+ } else if(r < 0) { -+ /* malformed NSEC3 */ -+ calc_errors++; -+ (*calculations)++; -+ continue; -+ } else { -+ if(r == 1) (*calculations)++; -+ if(nsec3_covers(flt->zone, hash, s, i_rr, -+ env->scratch_buffer)) { -+ *rrset = s; /* rrset with this name */ -+ *rr = i_rr; /* covers hash with these parameters */ -+ return 1; -+ } - } - } - *rrset = NULL; -@@ -869,11 +927,13 @@ find_covering_nsec3(struct module_env* env, struct nsec3_filter* flt, - * @param ct: cached hashes table. - * @param qinfo: query that is verified for. - * @param ce: closest encloser information is returned in here. -+ * @param calculations: current hash calculations. - * @return true if a closest encloser candidate is found, false if not. - */ - static int --nsec3_find_closest_encloser(struct module_env* env, struct nsec3_filter* flt, -- rbtree_type* ct, struct query_info* qinfo, struct ce_response* ce) -+nsec3_find_closest_encloser(struct module_env* env, struct nsec3_filter* flt, -+ struct nsec3_cache_table* ct, struct query_info* qinfo, -+ struct ce_response* ce, int* calculations) - { - uint8_t* nm = qinfo->qname; - size_t nmlen = qinfo->qname_len; -@@ -888,8 +948,12 @@ nsec3_find_closest_encloser(struct module_env* env, struct nsec3_filter* flt, - * may be the case. */ - - while(dname_subdomain_c(nm, flt->zone)) { -+ if(*calculations >= MAX_NSEC3_CALCULATIONS || -+ *calculations == MAX_NSEC3_ERRORS) { -+ return 0; -+ } - if(find_matching_nsec3(env, flt, ct, nm, nmlen, -- &ce->ce_rrset, &ce->ce_rr)) { -+ &ce->ce_rrset, &ce->ce_rr, calculations)) { - ce->ce = nm; - ce->ce_len = nmlen; - return 1; -@@ -933,22 +997,38 @@ next_closer(uint8_t* qname, size_t qnamelen, uint8_t* ce, - * If set true, and the return value is true, then you can be - * certain that the ce.nc_rrset and ce.nc_rr are set properly. - * @param ce: closest encloser information is returned in here. -+ * @param calculations: pointer to the current NSEC3 hash calculations. - * @return bogus if no closest encloser could be proven. - * secure if a closest encloser could be proven, ce is set. - * insecure if the closest-encloser candidate turns out to prove - * that an insecure delegation exists above the qname. -+ * unchecked if no more hash calculations are allowed at this point. - */ - static enum sec_status --nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt, -- rbtree_type* ct, struct query_info* qinfo, int prove_does_not_exist, -- struct ce_response* ce) -+nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt, -+ struct nsec3_cache_table* ct, struct query_info* qinfo, -+ int prove_does_not_exist, struct ce_response* ce, int* calculations) - { - uint8_t* nc; - size_t nc_len; - /* robust: clean out ce, in case it gets abused later */ - memset(ce, 0, sizeof(*ce)); - -- if(!nsec3_find_closest_encloser(env, flt, ct, qinfo, ce)) { -+ if(!nsec3_find_closest_encloser(env, flt, ct, qinfo, ce, calculations)) { -+ if(*calculations == MAX_NSEC3_ERRORS) { -+ verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could " -+ "not find a candidate for the closest " -+ "encloser; all attempted hash calculations " -+ "were erroneous; bogus"); -+ return sec_status_bogus; -+ } else if(*calculations >= MAX_NSEC3_CALCULATIONS) { -+ verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could " -+ "not find a candidate for the closest " -+ "encloser; reached MAX_NSEC3_CALCULATIONS " -+ "(%d); unchecked still", -+ MAX_NSEC3_CALCULATIONS); -+ return sec_status_unchecked; -+ } - verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could " - "not find a candidate for the closest encloser."); - return sec_status_bogus; -@@ -989,9 +1069,23 @@ nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt, - /* Otherwise, we need to show that the next closer name is covered. */ - next_closer(qinfo->qname, qinfo->qname_len, ce->ce, &nc, &nc_len); - if(!find_covering_nsec3(env, flt, ct, nc, nc_len, -- &ce->nc_rrset, &ce->nc_rr)) { -+ &ce->nc_rrset, &ce->nc_rr, calculations)) { -+ if(*calculations == MAX_NSEC3_ERRORS) { -+ verbose(VERB_ALGO, "nsec3: Could not find proof that the " -+ "candidate encloser was the closest encloser; " -+ "all attempted hash calculations were " -+ "erroneous; bogus"); -+ return sec_status_bogus; -+ } else if(*calculations >= MAX_NSEC3_CALCULATIONS) { -+ verbose(VERB_ALGO, "nsec3: Could not find proof that the " -+ "candidate encloser was the closest encloser; " -+ "reached MAX_NSEC3_CALCULATIONS (%d); " -+ "unchecked still", -+ MAX_NSEC3_CALCULATIONS); -+ return sec_status_unchecked; -+ } - verbose(VERB_ALGO, "nsec3: Could not find proof that the " -- "candidate encloser was the closest encloser"); -+ "candidate encloser was the closest encloser"); - return sec_status_bogus; - } - return sec_status_secure; -@@ -1019,8 +1113,8 @@ nsec3_ce_wildcard(struct regional* region, uint8_t* ce, size_t celen, - - /** Do the name error proof */ - static enum sec_status --nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt, -- rbtree_type* ct, struct query_info* qinfo) -+nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt, -+ struct nsec3_cache_table* ct, struct query_info* qinfo, int* calc) - { - struct ce_response ce; - uint8_t* wc; -@@ -1032,11 +1126,15 @@ nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt, - /* First locate and prove the closest encloser to qname. We will - * use the variant that fails if the closest encloser turns out - * to be qname. */ -- sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce); -+ sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce, calc); - if(sec != sec_status_secure) { - if(sec == sec_status_bogus) - verbose(VERB_ALGO, "nsec3 nameerror proof: failed " - "to prove a closest encloser"); -+ else if(sec == sec_status_unchecked) -+ verbose(VERB_ALGO, "nsec3 nameerror proof: will " -+ "continue proving closest encloser after " -+ "suspend"); - else verbose(VERB_ALGO, "nsec3 nameerror proof: closest " - "nsec3 is an insecure delegation"); - return sec; -@@ -1046,9 +1144,27 @@ nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt, - /* At this point, we know that qname does not exist. Now we need - * to prove that the wildcard does not exist. */ - log_assert(ce.ce); -- wc = nsec3_ce_wildcard(env->scratch, ce.ce, ce.ce_len, &wclen); -- if(!wc || !find_covering_nsec3(env, flt, ct, wc, wclen, -- &wc_rrset, &wc_rr)) { -+ wc = nsec3_ce_wildcard(ct->region, ce.ce, ce.ce_len, &wclen); -+ if(!wc) { -+ verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove " -+ "that the applicable wildcard did not exist."); -+ return sec_status_bogus; -+ } -+ if(!find_covering_nsec3(env, flt, ct, wc, wclen, &wc_rrset, &wc_rr, calc)) { -+ if(*calc == MAX_NSEC3_ERRORS) { -+ verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove " -+ "that the applicable wildcard did not exist; " -+ "all attempted hash calculations were " -+ "erroneous; bogus"); -+ return sec_status_bogus; -+ } else if(*calc >= MAX_NSEC3_CALCULATIONS) { -+ verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove " -+ "that the applicable wildcard did not exist; " -+ "reached MAX_NSEC3_CALCULATIONS (%d); " -+ "unchecked still", -+ MAX_NSEC3_CALCULATIONS); -+ return sec_status_unchecked; -+ } - verbose(VERB_ALGO, "nsec3 nameerror proof: could not prove " - "that the applicable wildcard did not exist."); - return sec_status_bogus; -@@ -1064,14 +1180,13 @@ nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt, - enum sec_status - nsec3_prove_nameerror(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key** list, size_t num, -- struct query_info* qinfo, struct key_entry_key* kkey) -+ struct query_info* qinfo, struct key_entry_key* kkey, -+ struct nsec3_cache_table* ct, int* calc) - { -- rbtree_type ct; - struct nsec3_filter flt; - - if(!list || num == 0 || !kkey || !key_entry_isgood(kkey)) - return sec_status_bogus; /* no valid NSEC3s, bogus */ -- rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */ - filter_init(&flt, list, num, qinfo); /* init RR iterator */ - if(!flt.zone) - return sec_status_bogus; /* no RRs */ -@@ -1079,7 +1194,7 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve, - return sec_status_insecure; /* iteration count too high */ - log_nametypeclass(VERB_ALGO, "start nsec3 nameerror proof, zone", - flt.zone, 0, 0); -- return nsec3_do_prove_nameerror(env, &flt, &ct, qinfo); -+ return nsec3_do_prove_nameerror(env, &flt, ct, qinfo, calc); - } - - /* -@@ -1089,8 +1204,9 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve, - - /** Do the nodata proof */ - static enum sec_status --nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, -- rbtree_type* ct, struct query_info* qinfo) -+nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, -+ struct nsec3_cache_table* ct, struct query_info* qinfo, -+ int* calc) - { - struct ce_response ce; - uint8_t* wc; -@@ -1100,7 +1216,7 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, - enum sec_status sec; - - if(find_matching_nsec3(env, flt, ct, qinfo->qname, qinfo->qname_len, -- &rrset, &rr)) { -+ &rrset, &rr, calc)) { - /* cases 1 and 2 */ - if(nsec3_has_type(rrset, rr, qinfo->qtype)) { - verbose(VERB_ALGO, "proveNodata: Matching NSEC3 " -@@ -1144,11 +1260,23 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, - } - return sec_status_secure; - } -+ if(*calc == MAX_NSEC3_ERRORS) { -+ verbose(VERB_ALGO, "proveNodata: all attempted hash " -+ "calculations were erroneous while finding a matching " -+ "NSEC3, bogus"); -+ return sec_status_bogus; -+ } else if(*calc >= MAX_NSEC3_CALCULATIONS) { -+ verbose(VERB_ALGO, "proveNodata: reached " -+ "MAX_NSEC3_CALCULATIONS (%d) while finding a " -+ "matching NSEC3; unchecked still", -+ MAX_NSEC3_CALCULATIONS); -+ return sec_status_unchecked; -+ } - - /* For cases 3 - 5, we need the proven closest encloser, and it - * can't match qname. Although, at this point, we know that it - * won't since we just checked that. */ -- sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce); -+ sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce, calc); - if(sec == sec_status_bogus) { - verbose(VERB_ALGO, "proveNodata: did not match qname, " - "nor found a proven closest encloser."); -@@ -1157,14 +1285,17 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, - verbose(VERB_ALGO, "proveNodata: closest nsec3 is insecure " - "delegation."); - return sec_status_insecure; -+ } else if(sec==sec_status_unchecked) { -+ return sec_status_unchecked; - } - - /* Case 3: removed */ - - /* Case 4: */ - log_assert(ce.ce); -- wc = nsec3_ce_wildcard(env->scratch, ce.ce, ce.ce_len, &wclen); -- if(wc && find_matching_nsec3(env, flt, ct, wc, wclen, &rrset, &rr)) { -+ wc = nsec3_ce_wildcard(ct->region, ce.ce, ce.ce_len, &wclen); -+ if(wc && find_matching_nsec3(env, flt, ct, wc, wclen, &rrset, &rr, -+ calc)) { - /* found wildcard */ - if(nsec3_has_type(rrset, rr, qinfo->qtype)) { - verbose(VERB_ALGO, "nsec3 nodata proof: matching " -@@ -1195,6 +1326,18 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, - } - return sec_status_secure; - } -+ if(*calc == MAX_NSEC3_ERRORS) { -+ verbose(VERB_ALGO, "nsec3 nodata proof: all attempted hash " -+ "calculations were erroneous while matching " -+ "wildcard, bogus"); -+ return sec_status_bogus; -+ } else if(*calc >= MAX_NSEC3_CALCULATIONS) { -+ verbose(VERB_ALGO, "nsec3 nodata proof: reached " -+ "MAX_NSEC3_CALCULATIONS (%d) while matching " -+ "wildcard, unchecked still", -+ MAX_NSEC3_CALCULATIONS); -+ return sec_status_unchecked; -+ } - - /* Case 5: */ - /* Due to forwarders, cnames, and other collating effects, we -@@ -1223,28 +1366,27 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, - enum sec_status - nsec3_prove_nodata(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key** list, size_t num, -- struct query_info* qinfo, struct key_entry_key* kkey) -+ struct query_info* qinfo, struct key_entry_key* kkey, -+ struct nsec3_cache_table* ct, int* calc) - { -- rbtree_type ct; - struct nsec3_filter flt; - - if(!list || num == 0 || !kkey || !key_entry_isgood(kkey)) - return sec_status_bogus; /* no valid NSEC3s, bogus */ -- rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */ - filter_init(&flt, list, num, qinfo); /* init RR iterator */ - if(!flt.zone) - return sec_status_bogus; /* no RRs */ - if(nsec3_iteration_count_high(ve, &flt, kkey)) - return sec_status_insecure; /* iteration count too high */ -- return nsec3_do_prove_nodata(env, &flt, &ct, qinfo); -+ return nsec3_do_prove_nodata(env, &flt, ct, qinfo, calc); - } - - enum sec_status - nsec3_prove_wildcard(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key** list, size_t num, -- struct query_info* qinfo, struct key_entry_key* kkey, uint8_t* wc) -+ struct query_info* qinfo, struct key_entry_key* kkey, uint8_t* wc, -+ struct nsec3_cache_table* ct, int* calc) - { -- rbtree_type ct; - struct nsec3_filter flt; - struct ce_response ce; - uint8_t* nc; -@@ -1254,7 +1396,6 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve, - - if(!list || num == 0 || !kkey || !key_entry_isgood(kkey)) - return sec_status_bogus; /* no valid NSEC3s, bogus */ -- rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */ - filter_init(&flt, list, num, qinfo); /* init RR iterator */ - if(!flt.zone) - return sec_status_bogus; /* no RRs */ -@@ -1272,8 +1413,22 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve, - /* Now we still need to prove that the original data did not exist. - * Otherwise, we need to show that the next closer name is covered. */ - next_closer(qinfo->qname, qinfo->qname_len, ce.ce, &nc, &nc_len); -- if(!find_covering_nsec3(env, &flt, &ct, nc, nc_len, -- &ce.nc_rrset, &ce.nc_rr)) { -+ if(!find_covering_nsec3(env, &flt, ct, nc, nc_len, -+ &ce.nc_rrset, &ce.nc_rr, calc)) { -+ if(*calc == MAX_NSEC3_ERRORS) { -+ verbose(VERB_ALGO, "proveWildcard: did not find a " -+ "covering NSEC3 that covered the next closer " -+ "name; all attempted hash calculations were " -+ "erroneous; bogus"); -+ return sec_status_bogus; -+ } else if(*calc >= MAX_NSEC3_CALCULATIONS) { -+ verbose(VERB_ALGO, "proveWildcard: did not find a " -+ "covering NSEC3 that covered the next closer " -+ "name; reached MAX_NSEC3_CALCULATIONS " -+ "(%d); unchecked still", -+ MAX_NSEC3_CALCULATIONS); -+ return sec_status_unchecked; -+ } - verbose(VERB_ALGO, "proveWildcard: did not find a covering " - "NSEC3 that covered the next closer name."); - return sec_status_bogus; -@@ -1294,6 +1449,7 @@ list_is_secure(struct module_env* env, struct val_env* ve, - { - struct packed_rrset_data* d; - size_t i; -+ int verified = 0; - for(i=0; ientry.data; - if(list[i]->rk.type != htons(LDNS_RR_TYPE_NSEC3)) -@@ -1304,7 +1460,8 @@ list_is_secure(struct module_env* env, struct val_env* ve, - if(d->security == sec_status_secure) - continue; - d->security = val_verify_rrset_entry(env, ve, list[i], kkey, -- reason, reason_bogus, LDNS_SECTION_AUTHORITY, qstate); -+ reason, reason_bogus, LDNS_SECTION_AUTHORITY, qstate, -+ &verified); - if(d->security != sec_status_secure) { - verbose(VERB_ALGO, "NSEC3 did not verify"); - return 0; -@@ -1318,13 +1475,16 @@ enum sec_status - nsec3_prove_nods(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key** list, size_t num, - struct query_info* qinfo, struct key_entry_key* kkey, char** reason, -- sldns_ede_code* reason_bogus, struct module_qstate* qstate) -+ sldns_ede_code* reason_bogus, struct module_qstate* qstate, -+ struct nsec3_cache_table* ct) - { -- rbtree_type ct; - struct nsec3_filter flt; - struct ce_response ce; - struct ub_packed_rrset_key* rrset; - int rr; -+ int calc = 0; -+ enum sec_status sec; -+ - log_assert(qinfo->qtype == LDNS_RR_TYPE_DS); - - if(!list || num == 0 || !kkey || !key_entry_isgood(kkey)) { -@@ -1335,7 +1495,6 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve, - *reason = "not all NSEC3 records secure"; - return sec_status_bogus; /* not all NSEC3 records secure */ - } -- rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */ - filter_init(&flt, list, num, qinfo); /* init RR iterator */ - if(!flt.zone) { - *reason = "no NSEC3 records"; -@@ -1346,8 +1505,8 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve, - - /* Look for a matching NSEC3 to qname -- this is the normal - * NODATA case. */ -- if(find_matching_nsec3(env, &flt, &ct, qinfo->qname, qinfo->qname_len, -- &rrset, &rr)) { -+ if(find_matching_nsec3(env, &flt, ct, qinfo->qname, qinfo->qname_len, -+ &rrset, &rr, &calc)) { - /* If the matching NSEC3 has the SOA bit set, it is from - * the wrong zone (the child instead of the parent). If - * it has the DS bit set, then we were lied to. */ -@@ -1370,10 +1529,24 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve, - /* Otherwise, this proves no DS. */ - return sec_status_secure; - } -+ if(calc == MAX_NSEC3_ERRORS) { -+ verbose(VERB_ALGO, "nsec3 provenods: all attempted hash " -+ "calculations were erroneous while finding a matching " -+ "NSEC3, bogus"); -+ return sec_status_bogus; -+ } else if(calc >= MAX_NSEC3_CALCULATIONS) { -+ verbose(VERB_ALGO, "nsec3 provenods: reached " -+ "MAX_NSEC3_CALCULATIONS (%d) while finding a " -+ "matching NSEC3, unchecked still", -+ MAX_NSEC3_CALCULATIONS); -+ return sec_status_unchecked; -+ } - - /* Otherwise, we are probably in the opt-out case. */ -- if(nsec3_prove_closest_encloser(env, &flt, &ct, qinfo, 1, &ce) -- != sec_status_secure) { -+ sec = nsec3_prove_closest_encloser(env, &flt, ct, qinfo, 1, &ce, &calc); -+ if(sec == sec_status_unchecked) { -+ return sec_status_unchecked; -+ } else if(sec != sec_status_secure) { - /* an insecure delegation *above* the qname does not prove - * anything about this qname exactly, and bogus is bogus */ - verbose(VERB_ALGO, "nsec3 provenods: did not match qname, " -@@ -1407,17 +1580,16 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve, - - enum sec_status - nsec3_prove_nxornodata(struct module_env* env, struct val_env* ve, -- struct ub_packed_rrset_key** list, size_t num, -- struct query_info* qinfo, struct key_entry_key* kkey, int* nodata) -+ struct ub_packed_rrset_key** list, size_t num, -+ struct query_info* qinfo, struct key_entry_key* kkey, int* nodata, -+ struct nsec3_cache_table* ct, int* calc) - { - enum sec_status sec, secnx; -- rbtree_type ct; - struct nsec3_filter flt; - *nodata = 0; - - if(!list || num == 0 || !kkey || !key_entry_isgood(kkey)) - return sec_status_bogus; /* no valid NSEC3s, bogus */ -- rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */ - filter_init(&flt, list, num, qinfo); /* init RR iterator */ - if(!flt.zone) - return sec_status_bogus; /* no RRs */ -@@ -1427,16 +1599,20 @@ nsec3_prove_nxornodata(struct module_env* env, struct val_env* ve, - /* try nxdomain and nodata after another, while keeping the - * hash cache intact */ - -- secnx = nsec3_do_prove_nameerror(env, &flt, &ct, qinfo); -+ secnx = nsec3_do_prove_nameerror(env, &flt, ct, qinfo, calc); - if(secnx==sec_status_secure) - return sec_status_secure; -- sec = nsec3_do_prove_nodata(env, &flt, &ct, qinfo); -+ else if(secnx == sec_status_unchecked) -+ return sec_status_unchecked; -+ sec = nsec3_do_prove_nodata(env, &flt, ct, qinfo, calc); - if(sec==sec_status_secure) { - *nodata = 1; - } else if(sec == sec_status_insecure) { - *nodata = 1; - } else if(secnx == sec_status_insecure) { - sec = sec_status_insecure; -+ } else if(sec == sec_status_unchecked) { -+ return sec_status_unchecked; - } - return sec; - } -diff --git a/unbound-1.16.2/validator/val_nsec3.h b/unbound-1.16.2/validator/val_nsec3.h -index 7676fc8..8ca9129 100644 ---- a/unbound-1.16.2/validator/val_nsec3.h -+++ b/unbound-1.16.2/validator/val_nsec3.h -@@ -98,6 +98,15 @@ struct sldns_buffer; - /** The SHA1 hash algorithm for NSEC3 */ - #define NSEC3_HASH_SHA1 0x01 - -+/** -+* Cache table for NSEC3 hashes. -+* It keeps a *pointer* to the region its items are allocated. -+*/ -+struct nsec3_cache_table { -+ rbtree_type* ct; -+ struct regional* region; -+}; -+ - /** - * Determine if the set of NSEC3 records provided with a response prove NAME - * ERROR. This means that the NSEC3s prove a) the closest encloser exists, -@@ -110,14 +119,18 @@ struct sldns_buffer; - * @param num: number of RRsets in the array to examine. - * @param qinfo: query that is verified for. - * @param kkey: key entry that signed the NSEC3s. -+ * @param ct: cached hashes table. -+ * @param calc: current hash calculations. - * @return: - * sec_status SECURE of the Name Error is proven by the NSEC3 RRs, -- * BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored. -+ * BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored, -+ * UNCHECKED if no more hash calculations are allowed at this point. - */ - enum sec_status - nsec3_prove_nameerror(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key** list, size_t num, -- struct query_info* qinfo, struct key_entry_key* kkey); -+ struct query_info* qinfo, struct key_entry_key* kkey, -+ struct nsec3_cache_table* ct, int* calc); - - /** - * Determine if the NSEC3s provided in a response prove the NOERROR/NODATA -@@ -144,15 +157,18 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve, - * @param num: number of RRsets in the array to examine. - * @param qinfo: query that is verified for. - * @param kkey: key entry that signed the NSEC3s. -+ * @param ct: cached hashes table. -+ * @param calc: current hash calculations. - * @return: - * sec_status SECURE of the proposition is proven by the NSEC3 RRs, -- * BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored. -+ * BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored, -+ * UNCHECKED if no more hash calculations are allowed at this point. - */ - enum sec_status - nsec3_prove_nodata(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key** list, size_t num, -- struct query_info* qinfo, struct key_entry_key* kkey); -- -+ struct query_info* qinfo, struct key_entry_key* kkey, -+ struct nsec3_cache_table* ct, int* calc); - - /** - * Prove that a positive wildcard match was appropriate (no direct match -@@ -166,14 +182,18 @@ nsec3_prove_nodata(struct module_env* env, struct val_env* ve, - * @param kkey: key entry that signed the NSEC3s. - * @param wc: The purported wildcard that matched. This is the wildcard name - * as *.wildcard.name., with the *. label already removed. -+ * @param ct: cached hashes table. -+ * @param calc: current hash calculations. - * @return: - * sec_status SECURE of the proposition is proven by the NSEC3 RRs, -- * BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored. -+ * BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored, -+ * UNCHECKED if no more hash calculations are allowed at this point. - */ - enum sec_status - nsec3_prove_wildcard(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key** list, size_t num, -- struct query_info* qinfo, struct key_entry_key* kkey, uint8_t* wc); -+ struct query_info* qinfo, struct key_entry_key* kkey, uint8_t* wc, -+ struct nsec3_cache_table* ct, int* calc); - - /** - * Prove that a DS response either had no DS, or wasn't a delegation point. -@@ -189,17 +209,20 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve, - * @param reason: string for bogus result. - * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. - * @param qstate: qstate with region. -+ * @param ct: cached hashes table. - * @return: - * sec_status SECURE of the proposition is proven by the NSEC3 RRs, - * BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored. - * or if there was no DS in an insecure (i.e., opt-in) way, -- * INDETERMINATE if it was clear that this wasn't a delegation point. -+ * INDETERMINATE if it was clear that this wasn't a delegation point, -+ * UNCHECKED if no more hash calculations are allowed at this point. - */ - enum sec_status - nsec3_prove_nods(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key** list, size_t num, - struct query_info* qinfo, struct key_entry_key* kkey, char** reason, -- sldns_ede_code* reason_bogus, struct module_qstate* qstate); -+ sldns_ede_code* reason_bogus, struct module_qstate* qstate, -+ struct nsec3_cache_table* ct); - - /** - * Prove NXDOMAIN or NODATA. -@@ -212,14 +235,18 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve, - * @param kkey: key entry that signed the NSEC3s. - * @param nodata: if return value is secure, this indicates if nodata or - * nxdomain was proven. -+ * @param ct: cached hashes table. -+ * @param calc: current hash calculations. - * @return: - * sec_status SECURE of the proposition is proven by the NSEC3 RRs, -- * BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored. -+ * BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored, -+ * UNCHECKED if no more hash calculations are allowed at this point. - */ - enum sec_status - nsec3_prove_nxornodata(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key** list, size_t num, -- struct query_info* qinfo, struct key_entry_key* kkey, int* nodata); -+ struct query_info* qinfo, struct key_entry_key* kkey, int* nodata, -+ struct nsec3_cache_table* ct, int* calc); - - /** - * The NSEC3 hash result storage. -@@ -256,6 +283,14 @@ struct nsec3_cached_hash { - */ - int nsec3_hash_cmp(const void* c1, const void* c2); - -+/** -+ * Initialise the NSEC3 cache table. -+ * @param ct: the nsec3 cache table. -+ * @param region: the region where allocations for the table will happen. -+ * @return true on success, false on malloc error. -+ */ -+int nsec3_cache_table_init(struct nsec3_cache_table* ct, struct regional* region); -+ - /** - * Obtain the hash of an owner name. - * Used internally by the nsec3 proof functions in this file. -@@ -272,7 +307,8 @@ int nsec3_hash_cmp(const void* c1, const void* c2); - * @param dname_len: the length of the name. - * @param hash: the hash node is returned on success. - * @return: -- * 1 on success, either from cache or newly hashed hash is returned. -+ * 2 on success, hash from cache is returned. -+ * 1 on success, newly computed hash is returned. - * 0 on a malloc failure. - * -1 if the NSEC3 rr was badly formatted (i.e. formerr). - */ -diff --git a/unbound-1.16.2/validator/val_sigcrypt.c b/unbound-1.16.2/validator/val_sigcrypt.c -index 5ab21e2..8600a68 100644 ---- a/unbound-1.16.2/validator/val_sigcrypt.c -+++ b/unbound-1.16.2/validator/val_sigcrypt.c -@@ -78,6 +78,9 @@ - #include - #endif - -+/** Maximum number of RRSIG validations for an RRset. */ -+#define MAX_VALIDATE_RRSIGS 8 -+ - /** return number of rrs in an rrset */ - static size_t - rrset_get_count(struct ub_packed_rrset_key* rrset) -@@ -541,6 +544,8 @@ int algo_needs_missing(struct algo_needs* n) - * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. - * @param section: section of packet where this rrset comes from. - * @param qstate: qstate with region. -+ * @param numverified: incremented when the number of RRSIG validations -+ * increases. - * @return secure if any key signs *this* signature. bogus if no key signs it, - * unchecked on error, or indeterminate if all keys are not supported by - * the crypto library (openssl3+ only). -@@ -551,7 +556,8 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key* dnskey, size_t sig_idx, - struct rbtree_type** sortree, - char** reason, sldns_ede_code *reason_bogus, -- sldns_pkt_section section, struct module_qstate* qstate) -+ sldns_pkt_section section, struct module_qstate* qstate, -+ int* numverified) - { - /* find matching keys and check them */ - enum sec_status sec = sec_status_bogus; -@@ -575,6 +581,7 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, - tag != dnskey_calc_keytag(dnskey, i)) - continue; - numchecked ++; -+ (*numverified)++; - - /* see if key verifies */ - sec = dnskey_verify_rrset_sig(env->scratch, -@@ -585,6 +592,13 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, - return sec; - else if(sec == sec_status_indeterminate) - numindeterminate ++; -+ if(*numverified > MAX_VALIDATE_RRSIGS) { -+ *reason = "too many RRSIG validations"; -+ if(reason_bogus) -+ *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; -+ verbose(VERB_ALGO, "verify sig: too many RRSIG validations"); -+ return sec_status_bogus; -+ } - } - if(numchecked == 0) { - *reason = "signatures from unknown keys"; -@@ -608,7 +622,7 @@ enum sec_status - dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, - uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, -- sldns_pkt_section section, struct module_qstate* qstate) -+ sldns_pkt_section section, struct module_qstate* qstate, int* verified) - { - enum sec_status sec; - size_t i, num; -@@ -616,6 +630,7 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, - /* make sure that for all DNSKEY algorithms there are valid sigs */ - struct algo_needs needs; - int alg; -+ *verified = 0; - - num = rrset_get_sigcount(rrset); - if(num == 0) { -@@ -640,7 +655,7 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, - for(i=0; inow, rrset, - dnskey, i, &sortree, reason, reason_bogus, -- section, qstate); -+ section, qstate, verified); - /* see which algorithm has been fixed up */ - if(sec == sec_status_secure) { - if(!sigalg) -@@ -652,6 +667,13 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, - algo_needs_set_bogus(&needs, - (uint8_t)rrset_get_sig_algo(rrset, i)); - } -+ if(*verified > MAX_VALIDATE_RRSIGS) { -+ verbose(VERB_QUERY, "rrset failed to verify, too many RRSIG validations"); -+ *reason = "too many RRSIG validations"; -+ if(reason_bogus) -+ *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; -+ return sec_status_bogus; -+ } - } - if(sigalg && (alg=algo_needs_missing(&needs)) != 0) { - verbose(VERB_ALGO, "rrset failed to verify: " -@@ -690,6 +712,7 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve, - int buf_canon = 0; - uint16_t tag = dnskey_calc_keytag(dnskey, dnskey_idx); - int algo = dnskey_get_algo(dnskey, dnskey_idx); -+ int numverified = 0; - - num = rrset_get_sigcount(rrset); - if(num == 0) { -@@ -713,8 +736,16 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve, - if(sec == sec_status_secure) - return sec; - numchecked ++; -+ numverified ++; - if(sec == sec_status_indeterminate) - numindeterminate ++; -+ if(numverified > MAX_VALIDATE_RRSIGS) { -+ verbose(VERB_QUERY, "rrset failed to verify, too many RRSIG validations"); -+ *reason = "too many RRSIG validations"; -+ if(reason_bogus) -+ *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; -+ return sec_status_bogus; -+ } - } - verbose(VERB_ALGO, "rrset failed to verify: all signatures are bogus"); - if(!numchecked) { -diff --git a/unbound-1.16.2/validator/val_sigcrypt.h b/unbound-1.16.2/validator/val_sigcrypt.h -index 7f52b71..1a3d8fc 100644 ---- a/unbound-1.16.2/validator/val_sigcrypt.h -+++ b/unbound-1.16.2/validator/val_sigcrypt.h -@@ -260,6 +260,7 @@ uint16_t dnskey_get_flags(struct ub_packed_rrset_key* k, size_t idx); - * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. - * @param section: section of packet where this rrset comes from. - * @param qstate: qstate with region. -+ * @param verified: if not NULL the number of RRSIG validations is returned. - * @return SECURE if one key in the set verifies one rrsig. - * UNCHECKED on allocation errors, unsupported algorithms, malformed data, - * and BOGUS on verification failures (no keys match any signatures). -@@ -268,7 +269,7 @@ enum sec_status dnskeyset_verify_rrset(struct module_env* env, - struct val_env* ve, struct ub_packed_rrset_key* rrset, - struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, - char** reason, sldns_ede_code *reason_bogus, -- sldns_pkt_section section, struct module_qstate* qstate); -+ sldns_pkt_section section, struct module_qstate* qstate, int* verified); - - - /** -diff --git a/unbound-1.16.2/validator/val_utils.c b/unbound-1.16.2/validator/val_utils.c -index e2319ee..cb37ea0 100644 ---- a/unbound-1.16.2/validator/val_utils.c -+++ b/unbound-1.16.2/validator/val_utils.c -@@ -58,6 +58,10 @@ - #include "sldns/wire2str.h" - #include "sldns/parseutil.h" - -+/** Maximum allowed digest match failures per DS, for DNSKEYs with the same -+ * properties */ -+#define MAX_DS_MATCH_FAILURES 4 -+ - enum val_classification - val_classify_response(uint16_t query_flags, struct query_info* origqinf, - struct query_info* qinf, struct reply_info* rep, size_t skip) -@@ -336,7 +340,8 @@ static enum sec_status - val_verify_rrset(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys, - uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, -- sldns_pkt_section section, struct module_qstate* qstate) -+ sldns_pkt_section section, struct module_qstate* qstate, -+ int *verified) - { - enum sec_status sec; - struct packed_rrset_data* d = (struct packed_rrset_data*)rrset-> -@@ -346,6 +351,7 @@ val_verify_rrset(struct module_env* env, struct val_env* ve, - log_nametypeclass(VERB_ALGO, "verify rrset cached", - rrset->rk.dname, ntohs(rrset->rk.type), - ntohs(rrset->rk.rrset_class)); -+ *verified = 0; - return d->security; - } - /* check in the cache if verification has already been done */ -@@ -354,12 +360,13 @@ val_verify_rrset(struct module_env* env, struct val_env* ve, - log_nametypeclass(VERB_ALGO, "verify rrset from cache", - rrset->rk.dname, ntohs(rrset->rk.type), - ntohs(rrset->rk.rrset_class)); -+ *verified = 0; - return d->security; - } - log_nametypeclass(VERB_ALGO, "verify rrset", rrset->rk.dname, - ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class)); - sec = dnskeyset_verify_rrset(env, ve, rrset, keys, sigalg, reason, -- reason_bogus, section, qstate); -+ reason_bogus, section, qstate, verified); - verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec)); - regional_free_all(env->scratch); - -@@ -393,7 +400,8 @@ enum sec_status - val_verify_rrset_entry(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey, - char** reason, sldns_ede_code *reason_bogus, -- sldns_pkt_section section, struct module_qstate* qstate) -+ sldns_pkt_section section, struct module_qstate* qstate, -+ int* verified) - { - /* temporary dnskey rrset-key */ - struct ub_packed_rrset_key dnskey; -@@ -407,7 +415,7 @@ val_verify_rrset_entry(struct module_env* env, struct val_env* ve, - dnskey.entry.key = &dnskey; - dnskey.entry.data = kd->rrset_data; - sec = val_verify_rrset(env, ve, rrset, &dnskey, kd->algo, reason, -- reason_bogus, section, qstate); -+ reason_bogus, section, qstate, verified); - return sec; - } - -@@ -439,6 +447,12 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve, - if(!ds_digest_match_dnskey(env, dnskey_rrset, i, ds_rrset, - ds_idx)) { - verbose(VERB_ALGO, "DS match attempt failed"); -+ if(numchecked > numhashok + MAX_DS_MATCH_FAILURES) { -+ verbose(VERB_ALGO, "DS match attempt reached " -+ "MAX_DS_MATCH_FAILURES (%d); bogus", -+ MAX_DS_MATCH_FAILURES); -+ return sec_status_bogus; -+ } - continue; - } - numhashok++; -diff --git a/unbound-1.16.2/validator/val_utils.h b/unbound-1.16.2/validator/val_utils.h -index 83e3d0a..e8cdcef 100644 ---- a/unbound-1.16.2/validator/val_utils.h -+++ b/unbound-1.16.2/validator/val_utils.h -@@ -124,12 +124,14 @@ void val_find_signer(enum val_classification subtype, - * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. - * @param section: section of packet where this rrset comes from. - * @param qstate: qstate with region. -+ * @param verified: if not NULL, the number of RRSIG validations is returned. - * @return security status of verification. - */ - enum sec_status val_verify_rrset_entry(struct module_env* env, - struct val_env* ve, struct ub_packed_rrset_key* rrset, - struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus, -- sldns_pkt_section section, struct module_qstate* qstate); -+ sldns_pkt_section section, struct module_qstate* qstate, -+ int* verified); - - /** - * Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but -diff --git a/unbound-1.16.2/validator/validator.c b/unbound-1.16.2/validator/validator.c -index 1723afe..01303a8 100644 ---- a/unbound-1.16.2/validator/validator.c -+++ b/unbound-1.16.2/validator/validator.c -@@ -64,10 +64,15 @@ - #include "sldns/wire2str.h" - #include "sldns/str2wire.h" - -+/** Max number of RRSIGs to validate at once, suspend query for later. */ -+#define MAX_VALIDATE_AT_ONCE 8 -+/** Max number of validation suspends allowed, error out otherwise. */ -+#define MAX_VALIDATION_SUSPENDS 16 -+ - /* forward decl for cache response and normal super inform calls of a DS */ - static void process_ds_response(struct module_qstate* qstate, - struct val_qstate* vq, int id, int rcode, struct dns_msg* msg, -- struct query_info* qinfo, struct sock_list* origin); -+ struct query_info* qinfo, struct sock_list* origin, int* suspend); - - - /* Updates the suplied EDE (RFC8914) code selectively so we don't loose -@@ -281,6 +286,21 @@ val_new(struct module_qstate* qstate, int id) - return val_new_getmsg(qstate, vq); - } - -+/** reset validator query state for query restart */ -+static void -+val_restart(struct val_qstate* vq) -+{ -+ struct comm_timer* temp_timer; -+ int restart_count; -+ if(!vq) return; -+ temp_timer = vq->suspend_timer; -+ restart_count = vq->restart_count+1; -+ memset(vq, 0, sizeof(*vq)); -+ vq->suspend_timer = temp_timer; -+ vq->restart_count = restart_count; -+ vq->state = VAL_INIT_STATE; -+} -+ - /** - * Exit validation with an error status - * -@@ -587,30 +607,42 @@ prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq, - * completed. - * - * @param qstate: query state. -+ * @param vq: validator query state. - * @param env: module env for verify. - * @param ve: validator env for verify. - * @param qchase: query that was made. - * @param chase_reply: answer to validate. - * @param key_entry: the key entry, which is trusted, and which matches - * the signer of the answer. The key entry isgood(). -+ * @param suspend: returned true if the task takes too long and needs to -+ * suspend to continue the effort later. - * @return false if any of the rrsets in the an or ns sections of the message - * fail to verify. The message is then set to bogus. - */ - static int --validate_msg_signatures(struct module_qstate* qstate, struct module_env* env, -- struct val_env* ve, struct query_info* qchase, -- struct reply_info* chase_reply, struct key_entry_key* key_entry) -+validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq, -+ struct module_env* env, struct val_env* ve, struct query_info* qchase, -+ struct reply_info* chase_reply, struct key_entry_key* key_entry, -+ int* suspend) - { - uint8_t* sname; - size_t i, slen; - struct ub_packed_rrset_key* s; - enum sec_status sec; -- int dname_seen = 0; -+ int dname_seen = 0, num_verifies = 0, verified, have_state = 0; - char* reason = NULL; - sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS; -+ *suspend = 0; -+ if(vq->msg_signatures_state) { -+ /* Pick up the state, and reset it, may not be needed now. */ -+ vq->msg_signatures_state = 0; -+ have_state = 1; -+ } - - /* validate the ANSWER section */ - for(i=0; ian_numrrsets; i++) { -+ if(have_state && i <= vq->msg_signatures_index) -+ continue; - s = chase_reply->rrsets[i]; - /* Skip the CNAME following a (validated) DNAME. - * Because of the normalization routines in the iterator, -@@ -629,7 +661,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env, - - /* Verify the answer rrset */ - sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason, -- &reason_bogus, LDNS_SECTION_ANSWER, qstate); -+ &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified); - /* If the (answer) rrset failed to validate, then this - * message is BAD. */ - if(sec != sec_status_secure) { -@@ -654,14 +686,33 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env, - ntohs(s->rk.type) == LDNS_RR_TYPE_DNAME) { - dname_seen = 1; - } -+ num_verifies += verified; -+ if(num_verifies > MAX_VALIDATE_AT_ONCE && -+ i+1 < (env->cfg->val_clean_additional? -+ chase_reply->an_numrrsets+chase_reply->ns_numrrsets: -+ chase_reply->rrset_count)) { -+ /* If the number of RRSIGs exceeds the maximum in -+ * one go, suspend. Only suspend if there is a next -+ * rrset to verify, i+1msg_signatures_state = 1; -+ vq->msg_signatures_index = i; -+ verbose(VERB_ALGO, "msg signature validation " -+ "suspended"); -+ return 0; -+ } - } - - /* validate the AUTHORITY section */ - for(i=chase_reply->an_numrrsets; ian_numrrsets+ - chase_reply->ns_numrrsets; i++) { -+ if(have_state && i <= vq->msg_signatures_index) -+ continue; - s = chase_reply->rrsets[i]; - sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason, -- &reason_bogus, LDNS_SECTION_AUTHORITY, qstate); -+ &reason_bogus, LDNS_SECTION_AUTHORITY, qstate, -+ &verified); - /* If anything in the authority section fails to be secure, - * we have a bad message. */ - if(sec != sec_status_secure) { -@@ -675,6 +726,18 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env, - update_reason_bogus(chase_reply, reason_bogus); - return 0; - } -+ num_verifies += verified; -+ if(num_verifies > MAX_VALIDATE_AT_ONCE && -+ i+1 < (env->cfg->val_clean_additional? -+ chase_reply->an_numrrsets+chase_reply->ns_numrrsets: -+ chase_reply->rrset_count)) { -+ *suspend = 1; -+ vq->msg_signatures_state = 1; -+ vq->msg_signatures_index = i; -+ verbose(VERB_ALGO, "msg signature validation " -+ "suspended"); -+ return 0; -+ } - } - - /* If set, the validator should clean the additional section of -@@ -684,22 +747,103 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env, - /* attempt to validate the ADDITIONAL section rrsets */ - for(i=chase_reply->an_numrrsets+chase_reply->ns_numrrsets; - irrset_count; i++) { -+ if(have_state && i <= vq->msg_signatures_index) -+ continue; - s = chase_reply->rrsets[i]; - /* only validate rrs that have signatures with the key */ - /* leave others unchecked, those get removed later on too */ - val_find_rrset_signer(s, &sname, &slen); - -+ verified = 0; - if(sname && query_dname_compare(sname, key_entry->name)==0) - (void)val_verify_rrset_entry(env, ve, s, key_entry, -- &reason, NULL, LDNS_SECTION_ADDITIONAL, qstate); -+ &reason, NULL, LDNS_SECTION_ADDITIONAL, qstate, -+ &verified); - /* the additional section can fail to be secure, - * it is optional, check signature in case we need - * to clean the additional section later. */ -+ num_verifies += verified; -+ if(num_verifies > MAX_VALIDATE_AT_ONCE && -+ i+1 < chase_reply->rrset_count) { -+ *suspend = 1; -+ vq->msg_signatures_state = 1; -+ vq->msg_signatures_index = i; -+ verbose(VERB_ALGO, "msg signature validation " -+ "suspended"); -+ return 0; -+ } - } - - return 1; - } - -+void -+validate_suspend_timer_cb(void* arg) -+{ -+ struct module_qstate* qstate = (struct module_qstate*)arg; -+ verbose(VERB_ALGO, "validate_suspend timer, continue"); -+ mesh_run(qstate->env->mesh, qstate->mesh_info, module_event_pass, -+ NULL); -+} -+ -+/** Setup timer to continue validation of msg signatures later */ -+static int -+validate_suspend_setup_timer(struct module_qstate* qstate, -+ struct val_qstate* vq, int id, enum val_state resume_state) -+{ -+ struct timeval tv; -+ int usec, slack, base; -+ if(vq->suspend_count >= MAX_VALIDATION_SUSPENDS) { -+ verbose(VERB_ALGO, "validate_suspend timer: " -+ "reached MAX_VALIDATION_SUSPENDS (%d); error out", -+ MAX_VALIDATION_SUSPENDS); -+ errinf(qstate, "max validation suspends reached, " -+ "too many RRSIG validations"); -+ return 0; -+ } -+ verbose(VERB_ALGO, "validate_suspend timer, set for suspend"); -+ vq->state = resume_state; -+ qstate->ext_state[id] = module_wait_reply; -+ if(!vq->suspend_timer) { -+ vq->suspend_timer = comm_timer_create( -+ qstate->env->worker_base, -+ validate_suspend_timer_cb, qstate); -+ if(!vq->suspend_timer) { -+ log_err("validate_suspend_setup_timer: " -+ "out of memory for comm_timer_create"); -+ return 0; -+ } -+ } -+ /* The timer is activated later, after other events in the event -+ * loop have been processed. The query state can also be deleted, -+ * when the list is full and query states are dropped. */ -+ /* Extend wait time if there are a lot of queries or if this one -+ * is taking long, to keep around cpu time for ordinary queries. */ -+ usec = 50000; /* 50 msec */ -+ slack = 0; -+ if(qstate->env->mesh->all.count >= qstate->env->mesh->max_reply_states) -+ slack += 3; -+ else if(qstate->env->mesh->all.count >= qstate->env->mesh->max_reply_states/2) -+ slack += 2; -+ else if(qstate->env->mesh->all.count >= qstate->env->mesh->max_reply_states/4) -+ slack += 1; -+ if(vq->suspend_count > 3) -+ slack += 3; -+ else if(vq->suspend_count > 0) -+ slack += vq->suspend_count; -+ if(slack != 0 && slack <= 12 /* No numeric overflow. */) { -+ usec = usec << slack; -+ } -+ /* Spread such timeouts within 90%-100% of the original timer. */ -+ base = usec * 9/10; -+ usec = base + ub_random_max(qstate->env->rnd, usec-base); -+ tv.tv_usec = (usec % 1000000); -+ tv.tv_sec = (usec / 1000000); -+ vq->suspend_count ++; -+ comm_timer_set(vq->suspend_timer, &tv); -+ return 1; -+} -+ - /** - * Detect wrong truncated response (say from BIND 9.6.1 that is forwarding - * and saw the NS record without signatures from a referral). -@@ -798,11 +942,17 @@ remove_spurious_authority(struct reply_info* chase_reply, - * @param chase_reply: answer to that query to validate. - * @param kkey: the key entry, which is trusted, and which matches - * the signer of the answer. The key entry isgood(). -+ * @param qstate: query state for the region. -+ * @param vq: validator state for the nsec3 cache table. -+ * @param nsec3_calculations: current nsec3 hash calculations. -+ * @param suspend: returned true if the task takes too long and needs to -+ * suspend to continue the effort later. - */ - static void - validate_positive_response(struct module_env* env, struct val_env* ve, - struct query_info* qchase, struct reply_info* chase_reply, -- struct key_entry_key* kkey) -+ struct key_entry_key* kkey, struct module_qstate* qstate, -+ struct val_qstate* vq, int* nsec3_calculations, int* suspend) - { - uint8_t* wc = NULL; - size_t wl; -@@ -811,6 +961,7 @@ validate_positive_response(struct module_env* env, struct val_env* ve, - int nsec3s_seen = 0; - size_t i; - struct ub_packed_rrset_key* s; -+ *suspend = 0; - - /* validate the ANSWER section - this will be the answer itself */ - for(i=0; ian_numrrsets; i++) { -@@ -862,17 +1013,23 @@ validate_positive_response(struct module_env* env, struct val_env* ve, - /* If this was a positive wildcard response that we haven't already - * proven, and we have NSEC3 records, try to prove it using the NSEC3 - * records. */ -- if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) { -- enum sec_status sec = nsec3_prove_wildcard(env, ve, -+ if(wc != NULL && !wc_NSEC_ok && nsec3s_seen && -+ nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) { -+ enum sec_status sec = nsec3_prove_wildcard(env, ve, - chase_reply->rrsets+chase_reply->an_numrrsets, -- chase_reply->ns_numrrsets, qchase, kkey, wc); -+ chase_reply->ns_numrrsets, qchase, kkey, wc, -+ &vq->nsec3_cache_table, nsec3_calculations); - if(sec == sec_status_insecure) { - verbose(VERB_ALGO, "Positive wildcard response is " - "insecure"); - chase_reply->security = sec_status_insecure; - return; -- } else if(sec == sec_status_secure) -+ } else if(sec == sec_status_secure) { - wc_NSEC_ok = 1; -+ } else if(sec == sec_status_unchecked) { -+ *suspend = 1; -+ return; -+ } - } - - /* If after all this, we still haven't proven the positive wildcard -@@ -904,11 +1061,17 @@ validate_positive_response(struct module_env* env, struct val_env* ve, - * @param chase_reply: answer to that query to validate. - * @param kkey: the key entry, which is trusted, and which matches - * the signer of the answer. The key entry isgood(). -+ * @param qstate: query state for the region. -+ * @param vq: validator state for the nsec3 cache table. -+ * @param nsec3_calculations: current nsec3 hash calculations. -+ * @param suspend: returned true if the task takes too long and needs to -+ * suspend to continue the effort later. - */ - static void - validate_nodata_response(struct module_env* env, struct val_env* ve, - struct query_info* qchase, struct reply_info* chase_reply, -- struct key_entry_key* kkey) -+ struct key_entry_key* kkey, struct module_qstate* qstate, -+ struct val_qstate* vq, int* nsec3_calculations, int* suspend) - { - /* Since we are here, there must be nothing in the ANSWER section to - * validate. */ -@@ -925,6 +1088,7 @@ validate_nodata_response(struct module_env* env, struct val_env* ve, - int nsec3s_seen = 0; /* nsec3s seen */ - struct ub_packed_rrset_key* s; - size_t i; -+ *suspend = 0; - - for(i=chase_reply->an_numrrsets; ian_numrrsets+ - chase_reply->ns_numrrsets; i++) { -@@ -963,16 +1127,23 @@ validate_nodata_response(struct module_env* env, struct val_env* ve, - } - } - -- if(!has_valid_nsec && nsec3s_seen) { -+ if(!has_valid_nsec && nsec3s_seen && -+ nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) { - enum sec_status sec = nsec3_prove_nodata(env, ve, - chase_reply->rrsets+chase_reply->an_numrrsets, -- chase_reply->ns_numrrsets, qchase, kkey); -+ chase_reply->ns_numrrsets, qchase, kkey, -+ &vq->nsec3_cache_table, nsec3_calculations); - if(sec == sec_status_insecure) { - verbose(VERB_ALGO, "NODATA response is insecure"); - chase_reply->security = sec_status_insecure; - return; -- } else if(sec == sec_status_secure) -+ } else if(sec == sec_status_secure) { - has_valid_nsec = 1; -+ } else if(sec == sec_status_unchecked) { -+ /* check is incomplete; suspend */ -+ *suspend = 1; -+ return; -+ } - } - - if(!has_valid_nsec) { -@@ -1004,11 +1175,18 @@ validate_nodata_response(struct module_env* env, struct val_env* ve, - * @param kkey: the key entry, which is trusted, and which matches - * the signer of the answer. The key entry isgood(). - * @param rcode: adjusted RCODE, in case of RCODE/proof mismatch leniency. -+ * @param qstate: query state for the region. -+ * @param vq: validator state for the nsec3 cache table. -+ * @param nsec3_calculations: current nsec3 hash calculations. -+ * @param suspend: returned true if the task takes too long and needs to -+ * suspend to continue the effort later. - */ - static void - validate_nameerror_response(struct module_env* env, struct val_env* ve, - struct query_info* qchase, struct reply_info* chase_reply, -- struct key_entry_key* kkey, int* rcode) -+ struct key_entry_key* kkey, int* rcode, -+ struct module_qstate* qstate, struct val_qstate* vq, -+ int* nsec3_calculations, int* suspend) - { - int has_valid_nsec = 0; - int has_valid_wnsec = 0; -@@ -1018,6 +1196,7 @@ validate_nameerror_response(struct module_env* env, struct val_env* ve, - uint8_t* ce; - int ce_labs = 0; - int prev_ce_labs = 0; -+ *suspend = 0; - - for(i=chase_reply->an_numrrsets; ian_numrrsets+ - chase_reply->ns_numrrsets; i++) { -@@ -1047,13 +1226,18 @@ validate_nameerror_response(struct module_env* env, struct val_env* ve, - nsec3s_seen = 1; - } - -- if((!has_valid_nsec || !has_valid_wnsec) && nsec3s_seen) { -+ if((!has_valid_nsec || !has_valid_wnsec) && nsec3s_seen && -+ nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) { - /* use NSEC3 proof, both answer and auth rrsets, in case - * NSEC3s end up in the answer (due to qtype=NSEC3 or so) */ - chase_reply->security = nsec3_prove_nameerror(env, ve, - chase_reply->rrsets, chase_reply->an_numrrsets+ -- chase_reply->ns_numrrsets, qchase, kkey); -- if(chase_reply->security != sec_status_secure) { -+ chase_reply->ns_numrrsets, qchase, kkey, -+ &vq->nsec3_cache_table, nsec3_calculations); -+ if(chase_reply->security == sec_status_unchecked) { -+ *suspend = 1; -+ return; -+ } else if(chase_reply->security != sec_status_secure) { - verbose(VERB_QUERY, "NameError response failed nsec, " - "nsec3 proof was %s", sec_status_to_string( - chase_reply->security)); -@@ -1065,26 +1249,34 @@ validate_nameerror_response(struct module_env* env, struct val_env* ve, - - /* If the message fails to prove either condition, it is bogus. */ - if(!has_valid_nsec) { -+ validate_nodata_response(env, ve, qchase, chase_reply, kkey, -+ qstate, vq, nsec3_calculations, suspend); -+ if(*suspend) return; - verbose(VERB_QUERY, "NameError response has failed to prove: " - "qname does not exist"); -- chase_reply->security = sec_status_bogus; -- update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); - /* Be lenient with RCODE in NSEC NameError responses */ -- validate_nodata_response(env, ve, qchase, chase_reply, kkey); -- if (chase_reply->security == sec_status_secure) -+ if(chase_reply->security == sec_status_secure) { - *rcode = LDNS_RCODE_NOERROR; -+ } else { -+ chase_reply->security = sec_status_bogus; -+ update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); -+ } - return; - } - - if(!has_valid_wnsec) { -+ validate_nodata_response(env, ve, qchase, chase_reply, kkey, -+ qstate, vq, nsec3_calculations, suspend); -+ if(*suspend) return; - verbose(VERB_QUERY, "NameError response has failed to prove: " - "covering wildcard does not exist"); -- chase_reply->security = sec_status_bogus; -- update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); - /* Be lenient with RCODE in NSEC NameError responses */ -- validate_nodata_response(env, ve, qchase, chase_reply, kkey); -- if (chase_reply->security == sec_status_secure) -+ if (chase_reply->security == sec_status_secure) { - *rcode = LDNS_RCODE_NOERROR; -+ } else { -+ chase_reply->security = sec_status_bogus; -+ update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); -+ } - return; - } - -@@ -1144,11 +1336,17 @@ validate_referral_response(struct reply_info* chase_reply) - * @param chase_reply: answer to that query to validate. - * @param kkey: the key entry, which is trusted, and which matches - * the signer of the answer. The key entry isgood(). -+ * @param qstate: query state for the region. -+ * @param vq: validator state for the nsec3 cache table. -+ * @param nsec3_calculations: current nsec3 hash calculations. -+ * @param suspend: returned true if the task takes too long and needs to -+ * suspend to continue the effort later. - */ - static void - validate_any_response(struct module_env* env, struct val_env* ve, - struct query_info* qchase, struct reply_info* chase_reply, -- struct key_entry_key* kkey) -+ struct key_entry_key* kkey, struct module_qstate* qstate, -+ struct val_qstate* vq, int* nsec3_calculations, int* suspend) - { - /* all answer and auth rrsets already verified */ - /* but check if a wildcard response is given, then check NSEC/NSEC3 -@@ -1159,6 +1357,7 @@ validate_any_response(struct module_env* env, struct val_env* ve, - int nsec3s_seen = 0; - size_t i; - struct ub_packed_rrset_key* s; -+ *suspend = 0; - - if(qchase->qtype != LDNS_RR_TYPE_ANY) { - log_err("internal error: ANY validation called for non-ANY"); -@@ -1213,19 +1412,25 @@ validate_any_response(struct module_env* env, struct val_env* ve, - /* If this was a positive wildcard response that we haven't already - * proven, and we have NSEC3 records, try to prove it using the NSEC3 - * records. */ -- if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) { -+ if(wc != NULL && !wc_NSEC_ok && nsec3s_seen && -+ nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) { - /* look both in answer and auth section for NSEC3s */ -- enum sec_status sec = nsec3_prove_wildcard(env, ve, -+ enum sec_status sec = nsec3_prove_wildcard(env, ve, - chase_reply->rrsets, -- chase_reply->an_numrrsets+chase_reply->ns_numrrsets, -- qchase, kkey, wc); -+ chase_reply->an_numrrsets+chase_reply->ns_numrrsets, -+ qchase, kkey, wc, &vq->nsec3_cache_table, -+ nsec3_calculations); - if(sec == sec_status_insecure) { - verbose(VERB_ALGO, "Positive ANY wildcard response is " - "insecure"); - chase_reply->security = sec_status_insecure; - return; -- } else if(sec == sec_status_secure) -+ } else if(sec == sec_status_secure) { - wc_NSEC_ok = 1; -+ } else if(sec == sec_status_unchecked) { -+ *suspend = 1; -+ return; -+ } - } - - /* If after all this, we still haven't proven the positive wildcard -@@ -1258,11 +1463,17 @@ validate_any_response(struct module_env* env, struct val_env* ve, - * @param chase_reply: answer to that query to validate. - * @param kkey: the key entry, which is trusted, and which matches - * the signer of the answer. The key entry isgood(). -+ * @param qstate: query state for the region. -+ * @param vq: validator state for the nsec3 cache table. -+ * @param nsec3_calculations: current nsec3 hash calculations. -+ * @param suspend: returned true if the task takes too long and needs to -+ * suspend to continue the effort later. - */ - static void - validate_cname_response(struct module_env* env, struct val_env* ve, - struct query_info* qchase, struct reply_info* chase_reply, -- struct key_entry_key* kkey) -+ struct key_entry_key* kkey, struct module_qstate* qstate, -+ struct val_qstate* vq, int* nsec3_calculations, int* suspend) - { - uint8_t* wc = NULL; - size_t wl; -@@ -1270,6 +1481,7 @@ validate_cname_response(struct module_env* env, struct val_env* ve, - int nsec3s_seen = 0; - size_t i; - struct ub_packed_rrset_key* s; -+ *suspend = 0; - - /* validate the ANSWER section - this will be the CNAME (+DNAME) */ - for(i=0; ian_numrrsets; i++) { -@@ -1334,17 +1546,23 @@ validate_cname_response(struct module_env* env, struct val_env* ve, - /* If this was a positive wildcard response that we haven't already - * proven, and we have NSEC3 records, try to prove it using the NSEC3 - * records. */ -- if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) { -- enum sec_status sec = nsec3_prove_wildcard(env, ve, -+ if(wc != NULL && !wc_NSEC_ok && nsec3s_seen && -+ nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) { -+ enum sec_status sec = nsec3_prove_wildcard(env, ve, - chase_reply->rrsets+chase_reply->an_numrrsets, -- chase_reply->ns_numrrsets, qchase, kkey, wc); -+ chase_reply->ns_numrrsets, qchase, kkey, wc, -+ &vq->nsec3_cache_table, nsec3_calculations); - if(sec == sec_status_insecure) { - verbose(VERB_ALGO, "wildcard CNAME response is " - "insecure"); - chase_reply->security = sec_status_insecure; - return; -- } else if(sec == sec_status_secure) -+ } else if(sec == sec_status_secure) { - wc_NSEC_ok = 1; -+ } else if(sec == sec_status_unchecked) { -+ *suspend = 1; -+ return; -+ } - } - - /* If after all this, we still haven't proven the positive wildcard -@@ -1375,11 +1593,17 @@ validate_cname_response(struct module_env* env, struct val_env* ve, - * @param chase_reply: answer to that query to validate. - * @param kkey: the key entry, which is trusted, and which matches - * the signer of the answer. The key entry isgood(). -+ * @param qstate: query state for the region. -+ * @param vq: validator state for the nsec3 cache table. -+ * @param nsec3_calculations: current nsec3 hash calculations. -+ * @param suspend: returned true if the task takes too long and needs to -+ * suspend to continue the effort later. - */ - static void - validate_cname_noanswer_response(struct module_env* env, struct val_env* ve, - struct query_info* qchase, struct reply_info* chase_reply, -- struct key_entry_key* kkey) -+ struct key_entry_key* kkey, struct module_qstate* qstate, -+ struct val_qstate* vq, int* nsec3_calculations, int* suspend) - { - int nodata_valid_nsec = 0; /* If true, then NODATA has been proven.*/ - uint8_t* ce = NULL; /* for wildcard nodata responses. This is the -@@ -1393,6 +1617,7 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve, - uint8_t* nsec_ce; /* Used to find the NSEC with the longest ce */ - int ce_labs = 0; - int prev_ce_labs = 0; -+ *suspend = 0; - - /* the AUTHORITY section */ - for(i=chase_reply->an_numrrsets; ian_numrrsets+ -@@ -1458,11 +1683,13 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve, - update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); - return; - } -- if(!nodata_valid_nsec && !nxdomain_valid_nsec && nsec3s_seen) { -+ if(!nodata_valid_nsec && !nxdomain_valid_nsec && nsec3s_seen && -+ nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) { - int nodata; - enum sec_status sec = nsec3_prove_nxornodata(env, ve, - chase_reply->rrsets+chase_reply->an_numrrsets, -- chase_reply->ns_numrrsets, qchase, kkey, &nodata); -+ chase_reply->ns_numrrsets, qchase, kkey, &nodata, -+ &vq->nsec3_cache_table, nsec3_calculations); - if(sec == sec_status_insecure) { - verbose(VERB_ALGO, "CNAMEchain to noanswer response " - "is insecure"); -@@ -1472,6 +1699,9 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve, - if(nodata) - nodata_valid_nsec = 1; - else nxdomain_valid_nsec = 1; -+ } else if(sec == sec_status_unchecked) { -+ *suspend = 1; -+ return; - } - } - -@@ -1822,13 +2052,37 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) - * Uses negative cache for NSEC3 lookup of DS responses. */ - /* only if cache not blacklisted, of course */ - struct dns_msg* msg; -- if(!qstate->blacklist && !vq->chain_blacklist && -+ int suspend; -+ if(vq->sub_ds_msg) { -+ /* We have a suspended DS reply from a sub-query; -+ * process it. */ -+ verbose(VERB_ALGO, "Process suspended sub DS response"); -+ msg = vq->sub_ds_msg; -+ process_ds_response(qstate, vq, id, LDNS_RCODE_NOERROR, -+ msg, &msg->qinfo, NULL, &suspend); -+ if(suspend) { -+ /* we'll come back here later to continue */ -+ if(!validate_suspend_setup_timer(qstate, vq, -+ id, VAL_FINDKEY_STATE)) -+ return val_error(qstate, id); -+ return 0; -+ } -+ vq->sub_ds_msg = NULL; -+ return 1; /* continue processing ds-response results */ -+ } else if(!qstate->blacklist && !vq->chain_blacklist && - (msg=val_find_DS(qstate->env, target_key_name, - target_key_len, vq->qchase.qclass, qstate->region, - vq->key_entry->name)) ) { - verbose(VERB_ALGO, "Process cached DS response"); - process_ds_response(qstate, vq, id, LDNS_RCODE_NOERROR, -- msg, &msg->qinfo, NULL); -+ msg, &msg->qinfo, NULL, &suspend); -+ if(suspend) { -+ /* we'll come back here later to continue */ -+ if(!validate_suspend_setup_timer(qstate, vq, -+ id, VAL_FINDKEY_STATE)) -+ return val_error(qstate, id); -+ return 0; -+ } - return 1; /* continue processing ds-response results */ - } - if(!generate_request(qstate, id, target_key_name, -@@ -1871,7 +2125,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, - struct val_env* ve, int id) - { - enum val_classification subtype; -- int rcode; -+ int rcode, suspend, nsec3_calculations = 0; - - if(!vq->key_entry) { - verbose(VERB_ALGO, "validate: no key entry, failed"); -@@ -1926,8 +2180,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, - - /* check signatures in the message; - * answer and authority must be valid, additional is only checked. */ -- if(!validate_msg_signatures(qstate, qstate->env, ve, &vq->qchase, -- vq->chase_reply, vq->key_entry)) { -+ if(!validate_msg_signatures(qstate, vq, qstate->env, ve, &vq->qchase, -+ vq->chase_reply, vq->key_entry, &suspend)) { -+ if(suspend) { -+ if(!validate_suspend_setup_timer(qstate, vq, -+ id, VAL_VALIDATE_STATE)) -+ return val_error(qstate, id); -+ return 0; -+ } - /* workaround bad recursor out there that truncates (even - * with EDNS4k) to 512 by removing RRSIG from auth section - * for positive replies*/ -@@ -1956,7 +2216,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, - case VAL_CLASS_POSITIVE: - verbose(VERB_ALGO, "Validating a positive response"); - validate_positive_response(qstate->env, ve, -- &vq->qchase, vq->chase_reply, vq->key_entry); -+ &vq->qchase, vq->chase_reply, vq->key_entry, -+ qstate, vq, &nsec3_calculations, &suspend); -+ if(suspend) { -+ if(!validate_suspend_setup_timer(qstate, -+ vq, id, VAL_VALIDATE_STATE)) -+ return val_error(qstate, id); -+ return 0; -+ } - verbose(VERB_DETAIL, "validate(positive): %s", - sec_status_to_string( - vq->chase_reply->security)); -@@ -1965,7 +2232,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, - case VAL_CLASS_NODATA: - verbose(VERB_ALGO, "Validating a nodata response"); - validate_nodata_response(qstate->env, ve, -- &vq->qchase, vq->chase_reply, vq->key_entry); -+ &vq->qchase, vq->chase_reply, vq->key_entry, -+ qstate, vq, &nsec3_calculations, &suspend); -+ if(suspend) { -+ if(!validate_suspend_setup_timer(qstate, -+ vq, id, VAL_VALIDATE_STATE)) -+ return val_error(qstate, id); -+ return 0; -+ } - verbose(VERB_DETAIL, "validate(nodata): %s", - sec_status_to_string( - vq->chase_reply->security)); -@@ -1975,7 +2249,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, - rcode = (int)FLAGS_GET_RCODE(vq->orig_msg->rep->flags); - verbose(VERB_ALGO, "Validating a nxdomain response"); - validate_nameerror_response(qstate->env, ve, -- &vq->qchase, vq->chase_reply, vq->key_entry, &rcode); -+ &vq->qchase, vq->chase_reply, vq->key_entry, &rcode, -+ qstate, vq, &nsec3_calculations, &suspend); -+ if(suspend) { -+ if(!validate_suspend_setup_timer(qstate, -+ vq, id, VAL_VALIDATE_STATE)) -+ return val_error(qstate, id); -+ return 0; -+ } - verbose(VERB_DETAIL, "validate(nxdomain): %s", - sec_status_to_string( - vq->chase_reply->security)); -@@ -1986,7 +2267,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, - case VAL_CLASS_CNAME: - verbose(VERB_ALGO, "Validating a cname response"); - validate_cname_response(qstate->env, ve, -- &vq->qchase, vq->chase_reply, vq->key_entry); -+ &vq->qchase, vq->chase_reply, vq->key_entry, -+ qstate, vq, &nsec3_calculations, &suspend); -+ if(suspend) { -+ if(!validate_suspend_setup_timer(qstate, -+ vq, id, VAL_VALIDATE_STATE)) -+ return val_error(qstate, id); -+ return 0; -+ } - verbose(VERB_DETAIL, "validate(cname): %s", - sec_status_to_string( - vq->chase_reply->security)); -@@ -1996,7 +2284,14 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, - verbose(VERB_ALGO, "Validating a cname noanswer " - "response"); - validate_cname_noanswer_response(qstate->env, ve, -- &vq->qchase, vq->chase_reply, vq->key_entry); -+ &vq->qchase, vq->chase_reply, vq->key_entry, -+ qstate, vq, &nsec3_calculations, &suspend); -+ if(suspend) { -+ if(!validate_suspend_setup_timer(qstate, -+ vq, id, VAL_VALIDATE_STATE)) -+ return val_error(qstate, id); -+ return 0; -+ } - verbose(VERB_DETAIL, "validate(cname_noanswer): %s", - sec_status_to_string( - vq->chase_reply->security)); -@@ -2013,8 +2308,15 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, - case VAL_CLASS_ANY: - verbose(VERB_ALGO, "Validating a positive ANY " - "response"); -- validate_any_response(qstate->env, ve, &vq->qchase, -- vq->chase_reply, vq->key_entry); -+ validate_any_response(qstate->env, ve, &vq->qchase, -+ vq->chase_reply, vq->key_entry, qstate, vq, -+ &nsec3_calculations, &suspend); -+ if(suspend) { -+ if(!validate_suspend_setup_timer(qstate, -+ vq, id, VAL_VALIDATE_STATE)) -+ return val_error(qstate, id); -+ return 0; -+ } - verbose(VERB_DETAIL, "validate(positive_any): %s", - sec_status_to_string( - vq->chase_reply->security)); -@@ -2123,16 +2425,13 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq, - if(vq->orig_msg->rep->security == sec_status_bogus) { - /* see if we can try again to fetch data */ - if(vq->restart_count < ve->max_restart) { -- int restart_count = vq->restart_count+1; - verbose(VERB_ALGO, "validation failed, " - "blacklist and retry to fetch data"); - val_blacklist(&qstate->blacklist, qstate->region, - qstate->reply_origin, 0); - qstate->reply_origin = NULL; - qstate->errinf = NULL; -- memset(vq, 0, sizeof(*vq)); -- vq->restart_count = restart_count; -- vq->state = VAL_INIT_STATE; -+ val_restart(vq); - verbose(VERB_ALGO, "pass back to next module"); - qstate->ext_state[id] = module_restart_next; - return 0; -@@ -2440,7 +2739,10 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset, - * DS response indicated an end to secure space, is_good if the DS - * validated. It returns ke=NULL if the DS response indicated that the - * request wasn't a delegation point. -- * @return 0 on servfail error (malloc failure). -+ * @return -+ * 0 on success, -+ * 1 on servfail error (malloc failure), -+ * 2 on NSEC3 suspend. - */ - static int - ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, -@@ -2451,6 +2753,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, - char* reason = NULL; - sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS; - enum val_classification subtype; -+ int verified; - if(rcode != LDNS_RCODE_NOERROR) { - char rc[16]; - rc[0]=0; -@@ -2479,7 +2782,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, - /* Verify only returns BOGUS or SECURE. If the rrset is - * bogus, then we are done. */ - sec = val_verify_rrset_entry(qstate->env, ve, ds, -- vq->key_entry, &reason, &reason_bogus, LDNS_SECTION_ANSWER, qstate); -+ vq->key_entry, &reason, &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified); - if(sec != sec_status_secure) { - verbose(VERB_DETAIL, "DS rrset in DS response did " - "not verify"); -@@ -2499,7 +2802,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, - *ke = key_entry_create_null(qstate->region, - qinfo->qname, qinfo->qname_len, qinfo->qclass, - ub_packed_rrset_ttl(ds), *qstate->env->now); -- return (*ke) != NULL; -+ return (*ke) == NULL; - } - - /* Otherwise, we return the positive response. */ -@@ -2507,7 +2810,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, - *ke = key_entry_create_rrset(qstate->region, - qinfo->qname, qinfo->qname_len, qinfo->qclass, ds, - NULL, *qstate->env->now); -- return (*ke) != NULL; -+ return (*ke) == NULL; - } else if(subtype == VAL_CLASS_NODATA || - subtype == VAL_CLASS_NAMEERROR) { - /* NODATA means that the qname exists, but that there was -@@ -2539,12 +2842,12 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, - qinfo->qname, qinfo->qname_len, - qinfo->qclass, proof_ttl, - *qstate->env->now); -- return (*ke) != NULL; -+ return (*ke) == NULL; - case sec_status_insecure: - verbose(VERB_DETAIL, "NSEC RRset for the " - "referral proved not a delegation point"); - *ke = NULL; -- return 1; -+ return 0; - case sec_status_bogus: - verbose(VERB_DETAIL, "NSEC RRset for the " - "referral did not prove no DS."); -@@ -2556,10 +2859,17 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, - break; - } - -+ if(!nsec3_cache_table_init(&vq->nsec3_cache_table, qstate->region)) { -+ log_err("malloc failure in ds_response_to_ke for " -+ "NSEC3 cache"); -+ reason = "malloc failure"; -+ errinf_ede(qstate, reason, 0); -+ goto return_bogus; -+ } - sec = nsec3_prove_nods(qstate->env, ve, - msg->rep->rrsets + msg->rep->an_numrrsets, - msg->rep->ns_numrrsets, qinfo, vq->key_entry, &reason, -- &reason_bogus, qstate); -+ &reason_bogus, qstate, &vq->nsec3_cache_table); - switch(sec) { - case sec_status_insecure: - /* case insecure also continues to unsigned -@@ -2572,18 +2882,19 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, - qinfo->qname, qinfo->qname_len, - qinfo->qclass, proof_ttl, - *qstate->env->now); -- return (*ke) != NULL; -+ return (*ke) == NULL; - case sec_status_indeterminate: - verbose(VERB_DETAIL, "NSEC3s for the " - "referral proved no delegation"); - *ke = NULL; -- return 1; -+ return 0; - case sec_status_bogus: - verbose(VERB_DETAIL, "NSEC3s for the " - "referral did not prove no DS."); - errinf_ede(qstate, reason, reason_bogus); - goto return_bogus; - case sec_status_unchecked: -+ return 2; - default: - /* NSEC3 proof did not work */ - break; -@@ -2620,13 +2931,13 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, - goto return_bogus; - } - sec = val_verify_rrset_entry(qstate->env, ve, cname, -- vq->key_entry, &reason, NULL, LDNS_SECTION_ANSWER, qstate); -+ vq->key_entry, &reason, NULL, LDNS_SECTION_ANSWER, qstate, &verified); - if(sec == sec_status_secure) { - verbose(VERB_ALGO, "CNAME validated, " - "proof that DS does not exist"); - /* and that it is not a referral point */ - *ke = NULL; -- return 1; -+ return 0; - } - errinf(qstate, "CNAME in DS response was not secure."); - errinf(qstate, reason); -@@ -2649,7 +2960,7 @@ return_bogus: - *ke = key_entry_create_bad(qstate->region, qinfo->qname, - qinfo->qname_len, qinfo->qclass, - BOGUS_KEY_TTL, *qstate->env->now); -- return (*ke) != NULL; -+ return (*ke) == NULL; - } - - /** -@@ -2670,17 +2981,31 @@ return_bogus: - static void - process_ds_response(struct module_qstate* qstate, struct val_qstate* vq, - int id, int rcode, struct dns_msg* msg, struct query_info* qinfo, -- struct sock_list* origin) -+ struct sock_list* origin, int* suspend) - { - struct val_env* ve = (struct val_env*)qstate->env->modinfo[id]; - struct key_entry_key* dske = NULL; - uint8_t* olds = vq->empty_DS_name; -+ int ret; -+ *suspend = 0; - vq->empty_DS_name = NULL; -- if(!ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske)) { -+ ret = ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske); -+ if(ret != 0) { -+ switch(ret) { -+ case 1: - log_err("malloc failure in process_ds_response"); - vq->key_entry = NULL; /* make it error */ - vq->state = VAL_VALIDATE_STATE; - return; -+ case 2: -+ *suspend = 1; -+ return; -+ default: -+ log_err("unhandled error value for ds_response_to_ke"); -+ vq->key_entry = NULL; /* make it error */ -+ vq->state = VAL_VALIDATE_STATE; -+ return; -+ } - } - if(dske == NULL) { - vq->empty_DS_name = regional_alloc_init(qstate->region, -@@ -2927,9 +3252,26 @@ val_inform_super(struct module_qstate* qstate, int id, - return; - } - if(qstate->qinfo.qtype == LDNS_RR_TYPE_DS) { -+ int suspend; - process_ds_response(super, vq, id, qstate->return_rcode, -- qstate->return_msg, &qstate->qinfo, -- qstate->reply_origin); -+ qstate->return_msg, &qstate->qinfo, -+ qstate->reply_origin, &suspend); -+ /* If NSEC3 was needed during validation, NULL the NSEC3 cache; -+ * it will be re-initiated if needed later on. -+ * Validation (and the cache table) are happening/allocated in -+ * the super qstate whilst the RRs are allocated (and pointed -+ * to) in this sub qstate. */ -+ if(vq->nsec3_cache_table.ct) { -+ vq->nsec3_cache_table.ct = NULL; -+ } -+ if(suspend) { -+ /* deep copy the return_msg to vq->sub_ds_msg; it will -+ * be resumed later in the super state with the caveat -+ * that the initial calculations will be re-caclulated -+ * and re-suspended there before continuing. */ -+ vq->sub_ds_msg = dns_msg_deepcopy_region( -+ qstate->return_msg, super->region); -+ } - return; - } else if(qstate->qinfo.qtype == LDNS_RR_TYPE_DNSKEY) { - process_dnskey_response(super, vq, id, qstate->return_rcode, -@@ -2943,8 +3285,15 @@ val_inform_super(struct module_qstate* qstate, int id, - void - val_clear(struct module_qstate* qstate, int id) - { -+ struct val_qstate* vq; - if(!qstate) - return; -+ vq = (struct val_qstate*)qstate->minfo[id]; -+ if(vq) { -+ if(vq->suspend_timer) { -+ comm_timer_delete(vq->suspend_timer); -+ } -+ } - /* everything is allocated in the region, so assign NULL */ - qstate->minfo[id] = NULL; - } -diff --git a/unbound-1.16.2/validator/validator.h b/unbound-1.16.2/validator/validator.h -index 694e4c8..72f44b1 100644 ---- a/unbound-1.16.2/validator/validator.h -+++ b/unbound-1.16.2/validator/validator.h -@@ -45,11 +45,13 @@ - #include "util/module.h" - #include "util/data/msgreply.h" - #include "validator/val_utils.h" -+#include "validator/val_nsec3.h" - struct val_anchors; - struct key_cache; - struct key_entry_key; - struct val_neg_cache; - struct config_strlist; -+struct comm_timer; - - /** - * This is the TTL to use when a trust anchor fails to prime. A trust anchor -@@ -215,6 +217,19 @@ struct val_qstate { - - /** true if this state is waiting to prime a trust anchor */ - int wait_prime_ta; -+ -+ /** State to continue with RRSIG validation in a message later */ -+ int msg_signatures_state; -+ /** The rrset index for the msg signatures to continue from */ -+ size_t msg_signatures_index; -+ /** Cache table for NSEC3 hashes */ -+ struct nsec3_cache_table nsec3_cache_table; -+ /** DS message from sub if it got suspended from NSEC3 calculations */ -+ struct dns_msg* sub_ds_msg; -+ /** The timer to resume processing msg signatures */ -+ struct comm_timer* suspend_timer; -+ /** Number of suspends */ -+ int suspend_count; - }; - - /** -@@ -262,4 +277,7 @@ void val_clear(struct module_qstate* qstate, int id); - */ - size_t val_get_mem(struct module_env* env, int id); - -+/** Timer callback for msg signatures continue timer */ -+void validate_suspend_timer_cb(void* arg); -+ - #endif /* VALIDATOR_VALIDATOR_H */ diff --git a/SOURCES/unbound-1.16.2.tar.gz.asc b/SOURCES/unbound-1.16.2.tar.gz.asc deleted file mode 100644 index 0f94fb9..0000000 --- a/SOURCES/unbound-1.16.2.tar.gz.asc +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PGP SIGNATURE----- - -iQIzBAABCAAdFiEE7fqj8spObrBWga+On28cLX4EX40FAmLnudYACgkQn28cLX4E -X43GmRAAoROXbktLR2AXGEECgPCFlHag9oNZosa3J5yR2vaV4e8eA6AMzPyZbl7P -LnLon8PZZR+pTW+dDRqakvzJIwXkLeONFgEdvd0cAghWAtPrKCDZIkCyeQj0OOv3 -wt1pRRl2PXUKNZZf0bzpTUIhVsHF/w5f5T/mFAZm49rUDboj77xgokmaFK4kei0I -Gz4W8Vx3TIwwJc8nea8GtCYIg3UKmR/TMznMFExAoKdMllzKuJnGx5lR/eU0+NRc -uwWEQhNJrHXZyWethp9swLCrOmDHcgBJOd04TqcDwSIZrw9VuT3/Uza3Tw73N7kr -PZvF2xSOASL+i91QP6tnkmQD5pAORVpUFN3NePEWV5922iG/pVipaYBbEyV3dfph -Y4QGwj8G6ppcfjV7gmlxsAOM2gnhD3rDqFmkxau6zB1kktHnV2aqlzIQo396ZBJQ -hKyIAJlNvpTiFaACD7/cFkE80awJnCD/qvXATN//BWHKytgO8eYg7fZGrxjbpIQk -XV/vVlOJWRXPyPBnp8MQyCIDe2eq2ELlMfYw62/TNDuj2qKsM/W03cem3GlveOa6 -tw8RVfFFjwZlCLbXSbmsKo+mWJ3jCAvb3/gql52vJDE5FuRz7MvptIVU6DVE1O+J -mQ3AoQ2Mq9iHsZePfze4sq531DMlWTgBMwqfBTWqMaTC/8VH5rg= -=Ax9n ------END PGP SIGNATURE----- diff --git a/SOURCES/unbound-1.21-CVE-2024-8508.patch b/SOURCES/unbound-1.21-CVE-2024-8508.patch deleted file mode 100644 index 36b3cdd..0000000 --- a/SOURCES/unbound-1.21-CVE-2024-8508.patch +++ /dev/null @@ -1,249 +0,0 @@ -From 34de24d58bb5aa6fe3551512fc17cac08f65d93e Mon Sep 17 00:00:00 2001 -From: Yorgos Thessalonikefs -Date: Thu, 3 Oct 2024 14:46:57 +0200 -Subject: [PATCH] - Fix CVE-2024-8508, unbounded name compression could lead to - denial of service. - ---- - unbound-1.16.2/util/data/msgencode.c | 77 +++++++++++++++++----------- - 1 file changed, 46 insertions(+), 31 deletions(-) - -diff --git a/unbound-1.16.2/util/data/msgencode.c b/unbound-1.16.2/util/data/msgencode.c -index fe21cfb..f9e95e6 100644 ---- a/unbound-1.16.2/util/data/msgencode.c -+++ b/unbound-1.16.2/util/data/msgencode.c -@@ -62,6 +62,10 @@ - #define RETVAL_TRUNC -4 - /** return code that means all is peachy keen. Equal to DNS rcode NOERROR */ - #define RETVAL_OK 0 -+/** Max compressions we are willing to perform; more than that will result -+ * in semi-compressed messages, or truncated even on TCP for huge messages, to -+ * avoid locking the CPU for long */ -+#define MAX_COMPRESSION_PER_MESSAGE 120 - - /** - * Data structure to help domain name compression in outgoing messages. -@@ -284,15 +288,17 @@ write_compressed_dname(sldns_buffer* pkt, uint8_t* dname, int labs, - - /** compress owner name of RR, return RETVAL_OUTMEM RETVAL_TRUNC */ - static int --compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt, -- struct regional* region, struct compress_tree_node** tree, -- size_t owner_pos, uint16_t* owner_ptr, int owner_labs) -+compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt, -+ struct regional* region, struct compress_tree_node** tree, -+ size_t owner_pos, uint16_t* owner_ptr, int owner_labs, -+ size_t* compress_count) - { - struct compress_tree_node* p; - struct compress_tree_node** insertpt = NULL; - if(!*owner_ptr) { - /* compress first time dname */ -- if((p = compress_tree_lookup(tree, key->rk.dname, -+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE && -+ (p = compress_tree_lookup(tree, key->rk.dname, - owner_labs, &insertpt))) { - if(p->labs == owner_labs) - /* avoid ptr chains, since some software is -@@ -301,6 +307,7 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt, - if(!write_compressed_dname(pkt, key->rk.dname, - owner_labs, p)) - return RETVAL_TRUNC; -+ (*compress_count)++; - /* check if typeclass+4 ttl + rdatalen is available */ - if(sldns_buffer_remaining(pkt) < 4+4+2) - return RETVAL_TRUNC; -@@ -313,7 +320,8 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt, - if(owner_pos <= PTR_MAX_OFFSET) - *owner_ptr = htons(PTR_CREATE(owner_pos)); - } -- if(!compress_tree_store(key->rk.dname, owner_labs, -+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE && -+ !compress_tree_store(key->rk.dname, owner_labs, - owner_pos, region, p, insertpt)) - return RETVAL_OUTMEM; - } else { -@@ -333,20 +341,24 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt, - - /** compress any domain name to the packet, return RETVAL_* */ - static int --compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs, -- struct regional* region, struct compress_tree_node** tree) -+compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs, -+ struct regional* region, struct compress_tree_node** tree, -+ size_t* compress_count) - { - struct compress_tree_node* p; - struct compress_tree_node** insertpt = NULL; - size_t pos = sldns_buffer_position(pkt); -- if((p = compress_tree_lookup(tree, dname, labs, &insertpt))) { -+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE && -+ (p = compress_tree_lookup(tree, dname, labs, &insertpt))) { - if(!write_compressed_dname(pkt, dname, labs, p)) - return RETVAL_TRUNC; -+ (*compress_count)++; - } else { - if(!dname_buffer_write(pkt, dname)) - return RETVAL_TRUNC; - } -- if(!compress_tree_store(dname, labs, pos, region, p, insertpt)) -+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE && -+ !compress_tree_store(dname, labs, pos, region, p, insertpt)) - return RETVAL_OUTMEM; - return RETVAL_OK; - } -@@ -364,9 +376,9 @@ type_rdata_compressable(struct ub_packed_rrset_key* key) - - /** compress domain names in rdata, return RETVAL_* */ - static int --compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen, -- struct regional* region, struct compress_tree_node** tree, -- const sldns_rr_descriptor* desc) -+compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen, -+ struct regional* region, struct compress_tree_node** tree, -+ const sldns_rr_descriptor* desc, size_t* compress_count) - { - int labs, r, rdf = 0; - size_t dname_len, len, pos = sldns_buffer_position(pkt); -@@ -380,8 +392,8 @@ compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen, - switch(desc->_wireformat[rdf]) { - case LDNS_RDF_TYPE_DNAME: - labs = dname_count_size_labels(rdata, &dname_len); -- if((r=compress_any_dname(rdata, pkt, labs, region, -- tree)) != RETVAL_OK) -+ if((r=compress_any_dname(rdata, pkt, labs, region, -+ tree, compress_count)) != RETVAL_OK) - return r; - rdata += dname_len; - todolen -= dname_len; -@@ -449,7 +461,8 @@ static int - packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt, - uint16_t* num_rrs, time_t timenow, struct regional* region, - int do_data, int do_sig, struct compress_tree_node** tree, -- sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset) -+ sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset, -+ size_t* compress_count) - { - size_t i, j, owner_pos; - int r, owner_labs; -@@ -477,9 +490,9 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt, - for(i=0; icount; i++) { - /* rrset roundrobin */ - j = (i + rr_offset) % data->count; -- if((r=compress_owner(key, pkt, region, tree, -- owner_pos, &owner_ptr, owner_labs)) -- != RETVAL_OK) -+ if((r=compress_owner(key, pkt, region, tree, -+ owner_pos, &owner_ptr, owner_labs, -+ compress_count)) != RETVAL_OK) - return r; - sldns_buffer_write(pkt, &key->rk.type, 2); - sldns_buffer_write(pkt, &key->rk.rrset_class, 2); -@@ -489,8 +502,8 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt, - else sldns_buffer_write_u32(pkt, data->rr_ttl[j]-adjust); - if(c) { - if((r=compress_rdata(pkt, data->rr_data[j], -- data->rr_len[j], region, tree, c)) -- != RETVAL_OK) -+ data->rr_len[j], region, tree, c, -+ compress_count)) != RETVAL_OK) - return r; - } else { - if(sldns_buffer_remaining(pkt) < data->rr_len[j]) -@@ -510,9 +523,9 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt, - return RETVAL_TRUNC; - sldns_buffer_write(pkt, &owner_ptr, 2); - } else { -- if((r=compress_any_dname(key->rk.dname, -- pkt, owner_labs, region, tree)) -- != RETVAL_OK) -+ if((r=compress_any_dname(key->rk.dname, -+ pkt, owner_labs, region, tree, -+ compress_count)) != RETVAL_OK) - return r; - if(sldns_buffer_remaining(pkt) < - 4+4+data->rr_len[i]) -@@ -544,7 +557,8 @@ static int - insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, - sldns_buffer* pkt, size_t rrsets_before, time_t timenow, - struct regional* region, struct compress_tree_node** tree, -- sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset) -+ sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset, -+ size_t* compress_count) - { - int r; - size_t i, setstart; -@@ -560,7 +574,7 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, - setstart = sldns_buffer_position(pkt); - if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], - pkt, num_rrs, timenow, region, 1, 1, tree, -- s, qtype, dnssec, rr_offset)) -+ s, qtype, dnssec, rr_offset, compress_count)) - != RETVAL_OK) { - /* Bad, but if due to size must set TC bit */ - /* trim off the rrset neatly. */ -@@ -573,7 +587,7 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, - setstart = sldns_buffer_position(pkt); - if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], - pkt, num_rrs, timenow, region, 1, 0, tree, -- s, qtype, dnssec, rr_offset)) -+ s, qtype, dnssec, rr_offset, compress_count)) - != RETVAL_OK) { - sldns_buffer_set_position(pkt, setstart); - return r; -@@ -584,7 +598,7 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, - setstart = sldns_buffer_position(pkt); - if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], - pkt, num_rrs, timenow, region, 0, 1, tree, -- s, qtype, dnssec, rr_offset)) -+ s, qtype, dnssec, rr_offset, compress_count)) - != RETVAL_OK) { - sldns_buffer_set_position(pkt, setstart); - return r; -@@ -677,6 +691,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, - struct compress_tree_node* tree = 0; - int r; - size_t rr_offset; -+ size_t compress_count=0; - - sldns_buffer_clear(buffer); - if(udpsize < sldns_buffer_limit(buffer)) -@@ -723,7 +738,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, - arep.rrsets = &qinfo->local_alias->rrset; - if((r=insert_section(&arep, 1, &ancount, buffer, 0, - timezero, region, &tree, LDNS_SECTION_ANSWER, -- qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { -+ qinfo->qtype, dnssec, rr_offset, &compress_count)) != RETVAL_OK) { - if(r == RETVAL_TRUNC) { - /* create truncated message */ - sldns_buffer_write_u16_at(buffer, 6, ancount); -@@ -738,7 +753,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, - /* insert answer section */ - if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, - 0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, -- dnssec, rr_offset)) != RETVAL_OK) { -+ dnssec, rr_offset, &compress_count)) != RETVAL_OK) { - if(r == RETVAL_TRUNC) { - /* create truncated message */ - sldns_buffer_write_u16_at(buffer, 6, ancount); -@@ -756,7 +771,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, - if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, - rep->an_numrrsets, timenow, region, &tree, - LDNS_SECTION_AUTHORITY, qinfo->qtype, -- dnssec, rr_offset)) != RETVAL_OK) { -+ dnssec, rr_offset, &compress_count)) != RETVAL_OK) { - if(r == RETVAL_TRUNC) { - /* create truncated message */ - sldns_buffer_write_u16_at(buffer, 8, nscount); -@@ -773,7 +788,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, - if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, - rep->an_numrrsets + rep->ns_numrrsets, timenow, region, - &tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype, -- dnssec, rr_offset)) != RETVAL_OK) { -+ dnssec, rr_offset, &compress_count)) != RETVAL_OK) { - if(r == RETVAL_TRUNC) { - /* no need to set TC bit, this is the additional */ - sldns_buffer_write_u16_at(buffer, 10, arcount); --- -2.47.0 - diff --git a/SOURCES/unbound-anchor.service b/SOURCES/unbound-anchor.service deleted file mode 100644 index cd949e5..0000000 --- a/SOURCES/unbound-anchor.service +++ /dev/null @@ -1,9 +0,0 @@ -[Unit] -Description=update of the root trust anchor for DNSSEC validation in unbound -Documentation=man:unbound-anchor(8) - -[Service] -Type=oneshot -User=unbound -ExecStart=/usr/sbin/unbound-anchor -a /var/lib/unbound/root.key -c /etc/unbound/icannbundle.pem -f /etc/resolv.conf -R -SuccessExitStatus=1 diff --git a/SOURCES/unbound.conf b/SOURCES/unbound.conf deleted file mode 100644 index 18fad43..0000000 --- a/SOURCES/unbound.conf +++ /dev/null @@ -1,1227 +0,0 @@ -# -# Example configuration file. -# -# See unbound.conf(5) man page -# -# this is a comment. - -# Use this anywhere in the file to include other text into this file. -#include: "otherfile.conf" - -# Use this anywhere in the file to include other text, that explicitly starts a -# clause, into this file. Text after this directive needs to start a clause. -#include-toplevel: "otherfile.conf" - -# The server clause sets the main parameters. -server: - # whitespace is not necessary, but looks cleaner. - - # verbosity number, 0 is least verbose. 1 is default. - verbosity: 1 - - # print statistics to the log (for every thread) every N seconds. - # Set to "" or 0 to disable. Default is disabled. - # Needs to be disabled for munin plugin - statistics-interval: 0 - - # enable shm for stats, default no. if you enable also enable - # statistics-interval, every time it also writes stats to the - # shared memory segment keyed with shm-key. - # shm-enable: no - - # shm for stats uses this key, and key+1 for the shared mem segment. - # shm-key: 11777 - - # enable cumulative statistics, without clearing them after printing. - # Needs to be disabled for munin plugin - statistics-cumulative: no - - # enable extended statistics (query types, answer codes, status) - # printed from unbound-control. default off, because of speed. - # Needs to be enabled for munin plugin - extended-statistics: yes - - # number of threads to create. 1 disables threading. - num-threads: 4 - - # specify the interfaces to answer queries from by ip-address. - # The default is to listen to localhost (127.0.0.1 and ::1). - # specify 0.0.0.0 and ::0 to bind to all available interfaces. - # specify every interface[@port] on a new 'interface:' labelled line. - # The listen interfaces are not changed on reload, only on restart. - # interface: 0.0.0.0 - # interface: ::0 - # interface: 192.0.2.153 - # interface: 192.0.2.154 - # interface: 192.0.2.154@5003 - # interface: 2001:DB8::5 - # - # for dns over tls and raw dns over port 80 - # interface: 0.0.0.0@443 - # interface: ::0@443 - # interface: 0.0.0.0@80 - # interface: ::0@80 - - # enable this feature to copy the source address of queries to reply. - # Socket options are not supported on all platforms. experimental. - # interface-automatic: yes - # - # NOTE: Enable this option when specifying interface 0.0.0.0 or ::0 - # NOTE: Disabled per Fedora policy not to listen to * on default install - # NOTE: If deploying on non-default port, eg 80/443, this needs to be disabled - interface-automatic: no - - # port to answer queries from - # port: 53 - - # specify the interfaces to send outgoing queries to authoritative - # server from by ip-address. If none, the default (all) interface - # is used. Specify every interface on a 'outgoing-interface:' line. - # outgoing-interface: 192.0.2.153 - # outgoing-interface: 2001:DB8::5 - # outgoing-interface: 2001:DB8::6 - - # Specify a netblock to use remainder 64 bits as random bits for - # upstream queries. Uses freebind option (Linux). - # outgoing-interface: 2001:DB8::/64 - # Also (Linux:) ip -6 addr add 2001:db8::/64 dev lo - # And: ip -6 route add local 2001:db8::/64 dev lo - # And set prefer-ip6: yes to use the ip6 randomness from a netblock. - # Set this to yes to prefer ipv6 upstream servers over ipv4. - # prefer-ip6: no - - # Prefer ipv4 upstream servers, even if ipv6 is available. - # prefer-ip4: no - - # number of ports to allocate per thread, determines the size of the - # port range that can be open simultaneously. About double the - # num-queries-per-thread, or, use as many as the OS will allow you. - # outgoing-range: 4096 - - # permit Unbound to use this port number or port range for - # making outgoing queries, using an outgoing interface. - # Only ephemeral ports are allowed by SElinux - outgoing-port-permit: 32768-60999 - - # deny Unbound the use this of port number or port range for - # making outgoing queries, using an outgoing interface. - # Use this to make sure Unbound does not grab a UDP port that some - # other server on this computer needs. The default is to avoid - # IANA-assigned port numbers. - # If multiple outgoing-port-permit and outgoing-port-avoid options - # are present, they are processed in order. - # Our SElinux policy does not allow non-ephemeral ports to be used - outgoing-port-avoid: 0-32767 - outgoing-port-avoid: 61000-65535 - - # number of outgoing simultaneous tcp buffers to hold per thread. - # outgoing-num-tcp: 10 - - # number of incoming simultaneous tcp buffers to hold per thread. - # incoming-num-tcp: 10 - - # buffer size for UDP port 53 incoming (SO_RCVBUF socket option). - # 0 is system default. Use 4m to catch query spikes for busy servers. - # so-rcvbuf: 0 - - # buffer size for UDP port 53 outgoing (SO_SNDBUF socket option). - # 0 is system default. Use 4m to handle spikes on very busy servers. - # so-sndbuf: 0 - - # use SO_REUSEPORT to distribute queries over threads. - # at extreme load it could be better to turn it off to distribute even. - so-reuseport: yes - - # use IP_TRANSPARENT so the interface: addresses can be non-local - # and you can config non-existing IPs that are going to work later on - # (uses IP_BINDANY on FreeBSD). - ip-transparent: yes - - # use IP_FREEBIND so the interface: addresses can be non-local - # and you can bind to nonexisting IPs and interfaces that are down. - # Linux only. On Linux you also have ip-transparent that is similar. - # ip-freebind: no - - # the value of the Differentiated Services Codepoint (DSCP) - # in the differentiated services field (DS) of the outgoing - # IP packets - # ip-dscp: 0 - - # EDNS reassembly buffer to advertise to UDP peers (the actual buffer - # is set with msg-buffer-size). 1472 can solve fragmentation (timeouts) - # edns-buffer-size: 1232 - - # Maximum UDP response size (not applied to TCP response). - # Suggested values are 512 to 4096. Default is 4096. 65536 disables it. - # 3072 causes +dnssec any isc.org queries to need TC=1. - # Helps mitigating DDOS - max-udp-size: 3072 - - # max memory to use for stream(tcp and tls) waiting result buffers. - # stream-wait-size: 4m - - # buffer size for handling DNS data. No messages larger than this - # size can be sent or received, by UDP or TCP. In bytes. - # msg-buffer-size: 65552 - - # the amount of memory to use for the message cache. - # plain value in bytes or you can append k, m or G. default is "4Mb". - # msg-cache-size: 4m - - # the number of slabs to use for the message cache. - # the number of slabs must be a power of 2. - # more slabs reduce lock contention, but fragment memory usage. - # msg-cache-slabs: 4 - - # the number of queries that a thread gets to service. - # num-queries-per-thread: 1024 - - # if very busy, 50% queries run to completion, 50% get timeout in msec - # jostle-timeout: 200 - - # msec to wait before close of port on timeout UDP. 0 disables. - # delay-close: 0 - - # perform connect for UDP sockets to mitigate ICMP side channel. - # udp-connect: yes - - # msec for waiting for an unknown server to reply. Increase if you - # are behind a slow satellite link, to eg. 1128. - # unknown-server-time-limit: 376 - - # the amount of memory to use for the RRset cache. - # plain value in bytes or you can append k, m or G. default is "4Mb". - # rrset-cache-size: 4m - - # the number of slabs to use for the RRset cache. - # the number of slabs must be a power of 2. - # more slabs reduce lock contention, but fragment memory usage. - # rrset-cache-slabs: 4 - - # the time to live (TTL) value lower bound, in seconds. Default 0. - # If more than an hour could easily give trouble due to stale data. - # cache-min-ttl: 0 - - # the time to live (TTL) value cap for RRsets and messages in the - # cache. Items are not cached for longer. In seconds. - # cache-max-ttl: 86400 - - # the time to live (TTL) value cap for negative responses in the cache - # cache-max-negative-ttl: 3600 - - # the time to live (TTL) value for cached roundtrip times, lameness and - # EDNS version information for hosts. In seconds. - # infra-host-ttl: 900 - - # minimum wait time for responses, increase if uplink is long. In msec. - # infra-cache-min-rtt: 50 - - # enable to make server probe down hosts more frequently. - # infra-keep-probing: no - - # the number of slabs to use for the Infrastructure cache. - # the number of slabs must be a power of 2. - # more slabs reduce lock contention, but fragment memory usage. - # infra-cache-slabs: 4 - - # the maximum number of hosts that are cached (roundtrip, EDNS, lame). - # infra-cache-numhosts: 10000 - - # define a number of tags here, use with local-zone, access-control. - # repeat the define-tag statement to add additional tags. - # define-tag: "tag1 tag2 tag3" - - # Enable IPv4, "yes" or "no". - # do-ip4: yes - - # Enable IPv6, "yes" or "no". - # do-ip6: yes - - # Enable UDP, "yes" or "no". - # NOTE: if setting up an Unbound on tls443 for public use, you might want to - # disable UDP to avoid being used in DNS amplification attacks. - # do-udp: yes - - # Enable TCP, "yes" or "no". - # do-tcp: yes - - # upstream connections use TCP only (and no UDP), "yes" or "no" - # useful for tunneling scenarios, default no. - # tcp-upstream: no - - # upstream connections also use UDP (even if do-udp is no). - # useful if if you want UDP upstream, but don't provide UDP downstream. - # udp-upstream-without-downstream: no - - # Maximum segment size (MSS) of TCP socket on which the server - # responds to queries. Default is 0, system default MSS. - # tcp-mss: 0 - - # Maximum segment size (MSS) of TCP socket for outgoing queries. - # Default is 0, system default MSS. - # outgoing-tcp-mss: 0 - - # Idle TCP timeout, connection closed in milliseconds - # tcp-idle-timeout: 30000 - - # Enable EDNS TCP keepalive option. - edns-tcp-keepalive: yes - - # Timeout for EDNS TCP keepalive, in msec. - # edns-tcp-keepalive-timeout: 120000 - - # Fedora note: do not activate this - can cause a crash - # Use systemd socket activation for UDP, TCP, and control sockets. - # use-systemd: no - - # Detach from the terminal, run in background, "yes" or "no". - # Set the value to "no" when Unbound runs as systemd service. - # do-daemonize: yes - - # control which clients are allowed to make (recursive) queries - # to this server. Specify classless netblocks with /size and action. - # By default everything is refused, except for localhost. - # Choose deny (drop message), refuse (polite error reply), - # allow (recursive ok), allow_setrd (recursive ok, rd bit is forced on), - # allow_snoop (recursive and nonrecursive ok) - # deny_non_local (drop queries unless can be answered from local-data) - # refuse_non_local (like deny_non_local but polite error reply). - # access-control: 0.0.0.0/0 refuse - # access-control: 127.0.0.0/8 allow - # access-control: ::0/0 refuse - # access-control: ::1 allow - # access-control: ::ffff:127.0.0.1 allow - - # tag access-control with list of tags (in "" with spaces between) - # Clients using this access control element use localzones that - # are tagged with one of these tags. - # access-control-tag: 192.0.2.0/24 "tag2 tag3" - - # set action for particular tag for given access control element - # if you have multiple tag values, the tag used to lookup the action - # is the first tag match between access-control-tag and local-zone-tag - # where "first" comes from the order of the define-tag values. - # access-control-tag-action: 192.0.2.0/24 tag3 refuse - - # set redirect data for particular tag for access control element - # access-control-tag-data: 192.0.2.0/24 tag2 "A 127.0.0.1" - - # Set view for access control element - # access-control-view: 192.0.2.0/24 viewname - - # if given, a chroot(2) is done to the given directory. - # i.e. you can chroot to the working directory, for example, - # for extra security, but make sure all files are in that directory. - # - # If chroot is enabled, you should pass the configfile (from the - # commandline) as a full path from the original root. After the - # chroot has been performed the now defunct portion of the config - # file path is removed to be able to reread the config after a reload. - # - # All other file paths (working dir, logfile, roothints, and - # key files) can be specified in several ways: - # o as an absolute path relative to the new root. - # o as a relative path to the working directory. - # o as an absolute path relative to the original root. - # In the last case the path is adjusted to remove the unused portion. - # - # The pid file can be absolute and outside of the chroot, it is - # written just prior to performing the chroot and dropping permissions. - # - # Additionally, Unbound may need to access /dev/urandom (for entropy). - # How to do this is specific to your OS. - # - # If you give "" no chroot is performed. The path must not end in a /. - # chroot: "/var/lib/unbound" - chroot: "" - - # if given, user privileges are dropped (after binding port), - # and the given username is assumed. Default is user "unbound". - # If you give "" no privileges are dropped. - username: "unbound" - - # the working directory. The relative files in this config are - # relative to this directory. If you give "" the working directory - # is not changed. - # If you give a server: directory: dir before include: file statements - # then those includes can be relative to the working directory. - directory: "/etc/unbound" - - # the log file, "" means log to stderr. - # Use of this option sets use-syslog to "no". - # logfile: "" - - # Log to syslog(3) if yes. The log facility LOG_DAEMON is used to - # log to. If yes, it overrides the logfile. - # use-syslog: yes - - # Log identity to report. if empty, defaults to the name of argv[0] - # (usually "unbound"). - # log-identity: "" - - # print UTC timestamp in ascii to logfile, default is epoch in seconds. - log-time-ascii: yes - - # print one line with time, IP, name, type, class for every query. - # log-queries: no - - # print one line per reply, with time, IP, name, type, class, rcode, - # timetoresolve, fromcache and responsesize. - # log-replies: no - - # log with tag 'query' and 'reply' instead of 'info' for - # filtering log-queries and log-replies from the log. - # log-tag-queryreply: no - - # log the local-zone actions, like local-zone type inform is enabled - # also for the other local zone types. - # log-local-actions: no - - # print log lines that say why queries return SERVFAIL to clients. - # log-servfail: no - - # the pid file. Can be an absolute path outside of chroot/work dir. - pidfile: "/var/run/unbound/unbound.pid" - - # file to read root hints from. - # get one from https://www.internic.net/domain/named.cache - # root-hints: "" - - # enable to not answer id.server and hostname.bind queries. - # hide-identity: no - - # enable to not answer version.server and version.bind queries. - # hide-version: no - - # enable to not set the User-Agent HTTP header. - # hide-http-user-agent: no - - # enable to not answer trustanchor.unbound queries. - # hide-trustanchor: no - - # enable to not set the User-Agent HTTP header. - # hide-http-user-agent: no - - # the identity to report. Leave "" or default to return hostname. - # identity: "" - - # the version to report. Leave "" or default to return package version. - # version: "" - - # NSID identity (hex string, or "ascii_somestring"). default disabled. - # nsid: "aabbccdd" - - # User-Agent HTTP header to use. Leave "" or default to use package name - # and version. - # http-user-agent: "" - - # the target fetch policy. - # series of integers describing the policy per dependency depth. - # The number of values in the list determines the maximum dependency - # depth the recursor will pursue before giving up. Each integer means: - # -1 : fetch all targets opportunistically, - # 0: fetch on demand, - # positive value: fetch that many targets opportunistically. - # Enclose the list of numbers between quotes (""). - # target-fetch-policy: "3 2 1 0 0" - - # Harden against very small EDNS buffer sizes. - # harden-short-bufsize: yes - - # Harden against unseemly large queries. - # harden-large-queries: no - - # Harden against out of zone rrsets, to avoid spoofing attempts. - harden-glue: yes - - # Harden against receiving dnssec-stripped data. If you turn it - # off, failing to validate dnskey data for a trustanchor will - # trigger insecure mode for that zone (like without a trustanchor). - # Default on, which insists on dnssec data for trust-anchored zones. - harden-dnssec-stripped: yes - - # Harden against queries that fall under dnssec-signed nxdomain names. - harden-below-nxdomain: yes - - # Harden the referral path by performing additional queries for - # infrastructure data. Validates the replies (if possible). - # Default off, because the lookups burden the server. Experimental - # implementation of draft-wijngaards-dnsext-resolver-side-mitigation. - harden-referral-path: yes - - # Harden against algorithm downgrade when multiple algorithms are - # advertised in the DS record. If no, allows the weakest algorithm - # to validate the zone. - # harden-algo-downgrade: no - - # Sent minimum amount of information to upstream servers to enhance - # privacy. Only sent minimum required labels of the QNAME and set QTYPE - # to A when possible. - qname-minimisation: yes - - # QNAME minimisation in strict mode. Do not fall-back to sending full - # QNAME to potentially broken nameservers. A lot of domains will not be - # resolvable when this option in enabled. - # This option only has effect when qname-minimisation is enabled. - # qname-minimisation-strict: no - - # Aggressive NSEC uses the DNSSEC NSEC chain to synthesize NXDOMAIN - # and other denials, using information from previous NXDOMAINs answers. - aggressive-nsec: yes - - # Use 0x20-encoded random bits in the query to foil spoof attempts. - # This feature is an experimental implementation of draft dns-0x20. - # use-caps-for-id: no - - # Domains (and domains in them) without support for dns-0x20 and - # the fallback fails because they keep sending different answers. - # caps-exempt: "licdn.com" - # caps-exempt: "senderbase.org" - - # Enforce privacy of these addresses. Strips them away from answers. - # It may cause DNSSEC validation to additionally mark it as bogus. - # Protects against 'DNS Rebinding' (uses browser as network proxy). - # Only 'private-domain' and 'local-data' names are allowed to have - # these private addresses. No default. - # private-address: 10.0.0.0/8 - # private-address: 172.16.0.0/12 - # private-address: 192.168.0.0/16 - # private-address: 169.254.0.0/16 - # private-address: fd00::/8 - # private-address: fe80::/10 - # private-address: ::ffff:0:0/96 - - # Allow the domain (and its subdomains) to contain private addresses. - # local-data statements are allowed to contain private addresses too. - # private-domain: "example.com" - - # If nonzero, unwanted replies are not only reported in statistics, - # but also a running total is kept per thread. If it reaches the - # threshold, a warning is printed and a defensive action is taken, - # the cache is cleared to flush potential poison out of it. - # A suggested value is 10000000, the default is 0 (turned off). - unwanted-reply-threshold: 10000000 - - # Do not query the following addresses. No DNS queries are sent there. - # List one address per entry. List classless netblocks with /size, - # do-not-query-address: 127.0.0.1/8 - # do-not-query-address: ::1 - - # if yes, the above default do-not-query-address entries are present. - # if no, localhost can be queried (for testing and debugging). - # do-not-query-localhost: yes - - # if yes, perform prefetching of almost expired message cache entries. - prefetch: yes - - # if yes, perform key lookups adjacent to normal lookups. - prefetch-key: yes - - # deny queries of type ANY with an empty response. - deny-any: yes - - # if yes, Unbound rotates RRSet order in response. - rrset-roundrobin: yes - - # if yes, Unbound doesn't insert authority/additional sections - # into response messages when those sections are not required. - minimal-responses: yes - - # true to disable DNSSEC lameness check in iterator. - # disable-dnssec-lame-check: no - - # module configuration of the server. A string with identifiers - # separated by spaces. Syntax: "[dns64] [validator] iterator" - # most modules have to be listed at the beginning of the line, - # except cachedb(just before iterator), and python (at the beginning, - # or, just before the iterator). - module-config: "ipsecmod validator iterator" - - # File with trusted keys, kept uptodate using RFC5011 probes, - # initial file like trust-anchor-file, then it stores metadata. - # Use several entries, one per domain name, to track multiple zones. - # - # If you want to perform DNSSEC validation, run unbound-anchor before - # you start Unbound (i.e. in the system boot scripts). And enable: - # Please note usage of unbound-anchor root anchor is at your own risk - # and under the terms of our LICENSE (see that file in the source). - # auto-trust-anchor-file: "/var/lib/unbound/root.key" - - # trust anchor signaling sends a RFC8145 key tag query after priming. - trust-anchor-signaling: yes - - # Root key trust anchor sentinel (draft-ietf-dnsop-kskroll-sentinel) - root-key-sentinel: yes - - # File with trusted keys for validation. Specify more than one file - # with several entries, one file per entry. - # Zone file format, with DS and DNSKEY entries. - # Note this gets out of date, use auto-trust-anchor-file please. - # trust-anchor-file: "" - - # Trusted key for validation. DS or DNSKEY. specify the RR on a - # single line, surrounded by "". TTL is ignored. class is IN default. - # Note this gets out of date, use auto-trust-anchor-file please. - # (These examples are from August 2007 and may not be valid anymore). - # trust-anchor: "nlnetlabs.nl. DNSKEY 257 3 5 AQPzzTWMz8qSWIQlfRnPckx2BiVmkVN6LPupO3mbz7FhLSnm26n6iG9N Lby97Ji453aWZY3M5/xJBSOS2vWtco2t8C0+xeO1bc/d6ZTy32DHchpW 6rDH1vp86Ll+ha0tmwyy9QP7y2bVw5zSbFCrefk8qCUBgfHm9bHzMG1U BYtEIQ==" - # trust-anchor: "jelte.nlnetlabs.nl. DS 42860 5 1 14D739EB566D2B1A5E216A0BA4D17FA9B038BE4A" - - # File with trusted keys for validation. Specify more than one file - # with several entries, one file per entry. Like trust-anchor-file - # but has a different file format. Format is BIND-9 style format, - # the trusted-keys { name flag proto algo "key"; }; clauses are read. - # you need external update procedures to track changes in keys. - # trusted-keys-file: "" - # - trusted-keys-file: /etc/unbound/keys.d/*.key - auto-trust-anchor-file: "/var/lib/unbound/root.key" - - # Ignore chain of trust. Domain is treated as insecure. - # domain-insecure: "example.com" - - # Override the date for validation with a specific fixed date. - # Do not set this unless you are debugging signature inception - # and expiration. "" or "0" turns the feature off. -1 ignores date. - # val-override-date: "" - - # The time to live for bogus data, rrsets and messages. This avoids - # some of the revalidation, until the time interval expires. in secs. - # val-bogus-ttl: 60 - - # The signature inception and expiration dates are allowed to be off - # by 10% of the signature lifetime (expir-incep) from our local clock. - # This leeway is capped with a minimum and a maximum. In seconds. - # val-sig-skew-min: 3600 - # val-sig-skew-max: 86400 - - # The maximum number the validator should restart validation with - # another authority in case of failed validation. - # val-max-restart: 5 - - # Should additional section of secure message also be kept clean of - # unsecure data. Useful to shield the users of this validator from - # potential bogus data in the additional section. All unsigned data - # in the additional section is removed from secure messages. - val-clean-additional: yes - - # Turn permissive mode on to permit bogus messages. Thus, messages - # for which security checks failed will be returned to clients, - # instead of SERVFAIL. It still performs the security checks, which - # result in interesting log files and possibly the AD bit in - # replies if the message is found secure. The default is off. - # NOTE: TURNING THIS ON DISABLES ALL DNSSEC SECURITY - val-permissive-mode: no - - # Ignore the CD flag in incoming queries and refuse them bogus data. - # Enable it if the only clients of Unbound are legacy servers (w2008) - # that set CD but cannot validate themselves. - # ignore-cd-flag: no - - # Serve expired responses from cache, with serve-expired-reply-ttl in - # the response, and then attempt to fetch the data afresh. - serve-expired: yes - # - # Limit serving of expired responses to configured seconds after - # expiration. 0 disables the limit. - serve-expired-ttl: 14400 - # - # Set the TTL of expired records to the serve-expired-ttl value after a - # failed attempt to retrieve the record from upstream. This makes sure - # that the expired records will be served as long as there are queries - # for it. - # serve-expired-ttl-reset: no - # - # TTL value to use when replying with expired data. - # serve-expired-reply-ttl: 30 - # - # Time in milliseconds before replying to the client with expired data. - # This essentially enables the serve-stale behavior as specified in - # RFC 8767 that first tries to resolve before - # immediately responding with expired data. 0 disables this behavior. - # A recommended value is 1800. - # serve-expired-client-timeout: 0 - - # Return the original TTL as received from the upstream name server rather - # than the decrementing TTL as stored in the cache. Enabling this feature - # does not impact cache expiry, it only changes the TTL Unbound embeds in - # responses to queries. Note that enabling this feature implicitly disables - # enforcement of the configured minimum and maximum TTL. - # serve-original-ttl: no - - # Have the validator log failed validations for your diagnosis. - # 0: off. 1: A line per failed user query. 2: With reason and bad IP. - val-log-level: 1 - - # It is possible to configure NSEC3 maximum iteration counts per - # keysize. Keep this table very short, as linear search is done. - # A message with an NSEC3 with larger count is marked insecure. - # List in ascending order the keysize and count values. - # val-nsec3-keysize-iterations: "1024 150 2048 150 4096 150" - - # if enabled, ZONEMD verification failures do not block the zone. - # zonemd-permissive-mode: no - - # instruct the auto-trust-anchor-file probing to add anchors after ttl. - # add-holddown: 2592000 # 30 days - - # instruct the auto-trust-anchor-file probing to del anchors after ttl. - # del-holddown: 2592000 # 30 days - - # auto-trust-anchor-file probing removes missing anchors after ttl. - # If the value 0 is given, missing anchors are not removed. - # keep-missing: 31622400 # 366 days - - # debug option that allows very small holddown times for key rollover, - # otherwise the RFC mandates probe intervals must be at least 1 hour. - # permit-small-holddown: no - - # the amount of memory to use for the key cache. - # plain value in bytes or you can append k, m or G. default is "4Mb". - # key-cache-size: 4m - - # the number of slabs to use for the key cache. - # the number of slabs must be a power of 2. - # more slabs reduce lock contention, but fragment memory usage. - # key-cache-slabs: 4 - - # the amount of memory to use for the negative cache. - # plain value in bytes or you can append k, m or G. default is "1Mb". - # neg-cache-size: 1m - - # By default, for a number of zones a small default 'nothing here' - # reply is built-in. Query traffic is thus blocked. If you - # wish to serve such zone you can unblock them by uncommenting one - # of the nodefault statements below. - # You may also have to use domain-insecure: zone to make DNSSEC work, - # unless you have your own trust anchors for this zone. - # local-zone: "localhost." nodefault - # local-zone: "127.in-addr.arpa." nodefault - # local-zone: "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.0.0.0.ip6.arpa." nodefault - # local-zone: "onion." nodefault - # local-zone: "test." nodefault - # local-zone: "invalid." nodefault - # local-zone: "10.in-addr.arpa." nodefault - # local-zone: "16.172.in-addr.arpa." nodefault - # local-zone: "17.172.in-addr.arpa." nodefault - # local-zone: "18.172.in-addr.arpa." nodefault - # local-zone: "19.172.in-addr.arpa." nodefault - # local-zone: "20.172.in-addr.arpa." nodefault - # local-zone: "21.172.in-addr.arpa." nodefault - # local-zone: "22.172.in-addr.arpa." nodefault - # local-zone: "23.172.in-addr.arpa." nodefault - # local-zone: "24.172.in-addr.arpa." nodefault - # local-zone: "25.172.in-addr.arpa." nodefault - # local-zone: "26.172.in-addr.arpa." nodefault - # local-zone: "27.172.in-addr.arpa." nodefault - # local-zone: "28.172.in-addr.arpa." nodefault - # local-zone: "29.172.in-addr.arpa." nodefault - # local-zone: "30.172.in-addr.arpa." nodefault - # local-zone: "31.172.in-addr.arpa." nodefault - # local-zone: "168.192.in-addr.arpa." nodefault - # local-zone: "0.in-addr.arpa." nodefault - # local-zone: "254.169.in-addr.arpa." nodefault - # local-zone: "2.0.192.in-addr.arpa." nodefault - # local-zone: "100.51.198.in-addr.arpa." nodefault - # local-zone: "113.0.203.in-addr.arpa." nodefault - # local-zone: "255.255.255.255.in-addr.arpa." nodefault - # local-zone: "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.0.0.0.0.ip6.arpa." nodefault - # local-zone: "d.f.ip6.arpa." nodefault - # local-zone: "8.e.f.ip6.arpa." nodefault - # local-zone: "9.e.f.ip6.arpa." nodefault - # local-zone: "a.e.f.ip6.arpa." nodefault - # local-zone: "b.e.f.ip6.arpa." nodefault - # local-zone: "8.b.d.0.1.0.0.2.ip6.arpa." nodefault - # And for 64.100.in-addr.arpa. to 127.100.in-addr.arpa. - - # Add example.com into ipset - # local-zone: "example.com" ipset - - # If Unbound is running service for the local host then it is useful - # to perform lan-wide lookups to the upstream, and unblock the - # long list of local-zones above. If this Unbound is a dns server - # for a network of computers, disabled is better and stops information - # leakage of local lan information. - # unblock-lan-zones: no - - # The insecure-lan-zones option disables validation for - # these zones, as if they were all listed as domain-insecure. - # insecure-lan-zones: no - - # a number of locally served zones can be configured. - # local-zone: - # local-data: "" - # o deny serves local data (if any), else, drops queries. - # o refuse serves local data (if any), else, replies with error. - # o static serves local data, else, nxdomain or nodata answer. - # o transparent gives local data, but resolves normally for other names - # o redirect serves the zone data for any subdomain in the zone. - # o nodefault can be used to normally resolve AS112 zones. - # o typetransparent resolves normally for other types and other names - # o inform acts like transparent, but logs client IP address - # o inform_deny drops queries and logs client IP address - # o inform_redirect redirects queries and logs client IP address - # o always_transparent, always_refuse, always_nxdomain, always_nodata, - # always_deny resolve in that way but ignore local data for - # that name - # o always_null returns 0.0.0.0 or ::0 for any name in the zone. - # o noview breaks out of that view towards global local-zones. - # - # defaults are localhost address, reverse for 127.0.0.1 and ::1 - # and nxdomain for AS112 zones. If you configure one of these zones - # the default content is omitted, or you can omit it with 'nodefault'. - # - # If you configure local-data without specifying local-zone, by - # default a transparent local-zone is created for the data. - # - # You can add locally served data with - # local-zone: "local." static - # local-data: "mycomputer.local. IN A 192.0.2.51" - # local-data: 'mytext.local TXT "content of text record"' - # - # You can override certain queries with - # local-data: "adserver.example.com A 127.0.0.1" - # - # You can redirect a domain to a fixed address with - # (this makes example.com, www.example.com, etc, all go to 192.0.2.3) - # local-zone: "example.com" redirect - # local-data: "example.com A 192.0.2.3" - # - # Shorthand to make PTR records, "IPv4 name" or "IPv6 name". - # You can also add PTR records using local-data directly, but then - # you need to do the reverse notation yourself. - # local-data-ptr: "192.0.2.3 www.example.com" - - include: /etc/unbound/local.d/*.conf - - # tag a localzone with a list of tag names (in "" with spaces between) - # local-zone-tag: "example.com" "tag2 tag3" - - # add a netblock specific override to a localzone, with zone type - # local-zone-override: "example.com" 192.0.2.0/24 refuse - - # service clients over TLS (on the TCP sockets) with plain DNS inside - # the TLS stream, and over HTTPS using HTTP/2 as specified in RFC8484. - # Give the certificate to use and private key. - # default is "" (disabled). requires restart to take effect. - # tls-service-key: "/etc/unbound/unbound_server.key" - # tls-service-pem: "/etc/unbound/unbound_server.pem" - # tls-port: 853 - # https-port: 443 - - # cipher setting for TLSv1.2 - # tls-ciphers: "DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256" - # cipher setting for TLSv1.3 - # tls-ciphersuites: "TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" - # Fedora/RHEL: use system-wide crypto policies - tls-ciphers: "PROFILE=SYSTEM" - # TODO: ask system-wide crypto people what to use here - #tls-ciphersuites: "PROFILE=SYSTEM" # does not work - - # Pad responses to padded queries received over TLS - # pad-responses: yes - - # Padded responses will be padded to the closest multiple of this size. - # pad-responses-block-size: 468 - - # Use the SNI extension for TLS connections. Default is yes. - # Changing the value requires a reload. - # tls-use-sni: yes - - # Add the secret file for TLS Session Ticket. - # Secret file must be 80 bytes of random data. - # First key use to encrypt and decrypt TLS session tickets. - # Other keys use to decrypt only. - # requires restart to take effect. - # tls-session-ticket-keys: "path/to/secret_file1" - # tls-session-ticket-keys: "path/to/secret_file2" - - # request upstream over TLS (with plain DNS inside the TLS stream). - # Default is no. Can be turned on and off with unbound-control. - # tls-upstream: no - - # Certificates used to authenticate connections made upstream. - # tls-cert-bundle: "" - - # Add system certs to the cert bundle, from the Windows Cert Store - # tls-win-cert: no - - # Pad queries over TLS upstreams - # pad-queries: yes - - # Padded queries will be padded to the closest multiple of this size. - # pad-queries-block-size: 128 - - # Also serve tls on these port numbers (eg. 443, ...), by listing - # tls-additional-port: portno for each of the port numbers. - - # HTTP endpoint to provide DNS-over-HTTPS service on. - # http-endpoint: "/dns-query" - - # HTTP/2 SETTINGS_MAX_CONCURRENT_STREAMS value to use. - # http-max-streams: 100 - - # Maximum number of bytes used for all HTTP/2 query buffers. - # http-query-buffer-size: 4m - - # Maximum number of bytes used for all HTTP/2 response buffers. - # http-response-buffer-size: 4m - - # Set TCP_NODELAY socket option on sockets used for DNS-over-HTTPS - # service. - # http-nodelay: yes - - # Disable TLS for DNS-over-HTTP downstream service. - # http-notls-downstream: no - - # DNS64 prefix. Must be specified when DNS64 is use. - # Enable dns64 in module-config. Used to synthesize IPv6 from IPv4. - # dns64-prefix: 64:ff9b::0/96 - - # DNS64 ignore AAAA records for these domains and use A instead. - # dns64-ignore-aaaa: "example.com" - - # ratelimit for uncached, new queries, this limits recursion effort. - # ratelimiting is experimental, and may help against randomqueryflood. - # if 0(default) it is disabled, otherwise state qps allowed per zone. - # ratelimit: 0 - - # ratelimits are tracked in a cache, size in bytes of cache (or k,m). - # ratelimit-size: 4m - # ratelimit cache slabs, reduces lock contention if equal to cpucount. - # ratelimit-slabs: 4 - - # 0 blocks when ratelimited, otherwise let 1/xth traffic through - # ratelimit-factor: 10 - - # override the ratelimit for a specific domain name. - # give this setting multiple times to have multiple overrides. - # ratelimit-for-domain: example.com 1000 - # override the ratelimits for all domains below a domain name - # can give this multiple times, the name closest to the zone is used. - # ratelimit-below-domain: com 1000 - - # global query ratelimit for all ip addresses. - # feature is experimental. - # if 0(default) it is disabled, otherwise states qps allowed per ip address - # ip-ratelimit: 0 - - # ip ratelimits are tracked in a cache, size in bytes of cache (or k,m). - # ip-ratelimit-size: 4m - # ip ratelimit cache slabs, reduces lock contention if equal to cpucount. - # ip-ratelimit-slabs: 4 - - # 0 blocks when ip is ratelimited, otherwise let 1/xth traffic through - # ip-ratelimit-factor: 10 - - # Limit the number of connections simultaneous from a netblock - # tcp-connection-limit: 192.0.2.0/24 12 - - # select from the fastest servers this many times out of 1000. 0 means - # the fast server select is disabled. prefetches are not sped up. - # fast-server-permil: 0 - # the number of servers that will be used in the fast server selection. - # fast-server-num: 3 - - # Specific options for ipsecmod. Unbound needs to be configured with - # --enable-ipsecmod for these to take effect. - # - # Enable or disable ipsecmod (it still needs to be defined in - # module-config above). Can be used when ipsecmod needs to be - # enabled/disabled via remote-control(below). - # Fedora: module will be enabled on-demand by libreswan - ipsecmod-enabled: no - - # Path to executable external hook. It must be defined when ipsecmod is - # listed in module-config (above). - # ipsecmod-hook: "./my_executable" - ipsecmod-hook:/usr/libexec/ipsec/_unbound-hook - - # When enabled Unbound will reply with SERVFAIL if the return value of - # the ipsecmod-hook is not 0. - # ipsecmod-strict: no - # - # Maximum time to live (TTL) for cached A/AAAA records with IPSECKEY. - # ipsecmod-max-ttl: 3600 - # - # Reply with A/AAAA even if the relevant IPSECKEY is bogus. Mainly used for - # testing. - # ipsecmod-ignore-bogus: no - # - # Domains for which ipsecmod will be triggered. If not defined (default) - # all domains are treated as being allowed. - # ipsecmod-allow: "example.com" - # ipsecmod-allow: "nlnetlabs.nl" - - # Timeout for REUSE entries in milliseconds. - # tcp-reuse-timeout: 60000 - # Max number of queries on a reuse connection. - # max-reuse-tcp-queries: 200 - # Timeout in milliseconds for TCP queries to auth servers. - # tcp-auth-query-timeout: 3000 - -# Python config section. To enable: -# o use --with-pythonmodule to configure before compiling. -# o list python in the module-config string (above) to enable. -# It can be at the start, it gets validated results, or just before -# the iterator and process before DNSSEC validation. -# o and give a python-script to run. -python: - # Script file to load - # python-script: "/etc/unbound/ubmodule-tst.py" - -# Dynamic library config section. To enable: -# o use --with-dynlibmodule to configure before compiling. -# o list dynlib in the module-config string (above) to enable. -# It can be placed anywhere, the dynlib module is only a very thin wrapper -# to load modules dynamically. -# o and give a dynlib-file to run. If more than one dynlib entry is listed in -# the module-config then you need one dynlib-file per instance. -dynlib: - # Script file to load - # dynlib-file: "/etc/unbound/dynlib.so" - -# Remote control config section. -remote-control: - # Enable remote control with unbound-control(8) here. - # set up the keys and certificates with unbound-control-setup. - # Note: required for unbound-munin package - control-enable: yes - - # Set to no and use an absolute path as control-interface to use - # a unix local named pipe for unbound-control. - # For local sockets this option is ignored, and TLS is not used. - # control-use-cert: yes - - # what interfaces are listened to for remote control. - # give 0.0.0.0 and ::0 to listen to all interfaces. - # set to an absolute path to use a unix local name pipe, certificates - # are not used for that, so key and cert files need not be present. - # control-interface: 127.0.0.1 - # control-interface: ::1 - # moved to /etc/unbound/conf.d/remote-control.conf - - # port number for remote control operations. - # control-port: 8953 - - # Unbound server key file. - server-key-file: "/etc/unbound/unbound_server.key" - - # Unbound server certificate file. - server-cert-file: "/etc/unbound/unbound_server.pem" - - # unbound-control key file. - control-key-file: "/etc/unbound/unbound_control.key" - - # unbound-control certificate file. - control-cert-file: "/etc/unbound/unbound_control.pem" - -# Stub and Forward zones -include: /etc/unbound/conf.d/*.conf - -# Stub zones. -# Create entries like below, to make all queries for 'example.com' and -# 'example.org' go to the given list of nameservers. list zero or more -# nameservers by hostname or by ipaddress. If you set stub-prime to yes, -# the list is treated as priming hints (default is no). -# With stub-first yes, it attempts without the stub if it fails. -# Consider adding domain-insecure: name and local-zone: name nodefault -# to the server: section if the stub is a locally served zone. -# stub-zone: -# name: "example.com" -# stub-addr: 192.0.2.68 -# stub-prime: no -# stub-first: no -# stub-tls-upstream: no -# stub-no-cache: no -# stub-zone: -# name: "example.org" -# stub-host: ns.example.com. - -# You can now also dynamically create and delete stub-zone's using -# unbound-control stub_add domain.com 1.2.3.4 5.6.7.8 -# unbound-control stub_remove domain.com 1.2.3.4 5.6.7.8 - -# Forward zones -# Create entries like below, to make all queries for 'example.com' and -# 'example.org' go to the given list of servers. These servers have to handle -# recursion to other nameservers. List zero or more nameservers by hostname -# or by ipaddress. Use an entry with name "." to forward all queries. -# If you enable forward-first, it attempts without the forward if it fails. -# forward-zone: -# name: "example.com" -# forward-addr: 192.0.2.68 -# forward-addr: 192.0.2.73@5355 # forward to port 5355. -# forward-first: no -# forward-tls-upstream: no -# forward-no-cache: no -# forward-zone: -# name: "example.org" -# forward-host: fwd.example.com -# -# You can now also dynamically create and delete forward-zone's using -# unbound-control forward_add domain.com 1.2.3.4 5.6.7.8 -# unbound-control forward_remove domain.com 1.2.3.4 5.6.7.8 - -# Authority zones -# The data for these zones is kept locally, from a file or downloaded. -# The data can be served to downstream clients, or used instead of the -# upstream (which saves a lookup to the upstream). The first example -# has a copy of the root for local usage. The second serves example.org -# authoritatively. zonefile: reads from file (and writes to it if you also -# download it), master: fetches with AXFR and IXFR, or url to zonefile. -# With allow-notify: you can give additional (apart from masters) sources of -# notifies. -auth-zone: - name: "." - primary: 199.9.14.201 # b.root-servers.net - primary: 192.33.4.12 # c.root-servers.net - primary: 199.7.91.13 # d.root-servers.net - primary: 192.5.5.241 # f.root-servers.net - primary: 192.112.36.4 # g.root-servers.net - primary: 193.0.14.129 # k.root-servers.net - primary: 192.0.47.132 # xfr.cjr.dns.icann.org - primary: 192.0.32.132 # xfr.lax.dns.icann.org - primary: 2001:500:200::b # b.root-servers.net - primary: 2001:500:2::c # c.root-servers.net - primary: 2001:500:2d::d # d.root-servers.net - primary: 2001:500:2f::f # f.root-servers.net - primary: 2001:500:12::d0d # g.root-servers.net - primary: 2001:7fd::1 # k.root-servers.net - primary: 2620:0:2830:202::132 # xfr.cjr.dns.icann.org - primary: 2620:0:2d0:202::132 # xfr.lax.dns.icann.org - fallback-enabled: yes - for-downstream: no - for-upstream: yes - -# auth-zone: -# name: "example.org" -# for-downstream: yes -# for-upstream: yes -# zonemd-check: no -# zonemd-reject-absence: no -# zonefile: "example.org.zone" - -# Views -# Create named views. Name must be unique. Map views to requests using -# the access-control-view option. Views can contain zero or more local-zone -# and local-data options. Options from matching views will override global -# options. Global options will be used if no matching view is found. -# With view-first yes, it will try to answer using the global local-zone and -# local-data elements if there is no view specific match. -# view: -# name: "viewname" -# local-zone: "example.com" redirect -# local-data: "example.com A 192.0.2.3" -# local-data-ptr: "192.0.2.3 www.example.com" -# view-first: no -# view: -# name: "anotherview" -# local-zone: "example.com" refuse - -# Fedora: DNSCrypt support not enabled since it requires linking to -# another crypto library -# -# DNSCrypt -# Caveats: -# 1. the keys/certs cannot be produced by Unbound. You can use dnscrypt-wrapper -# for this: https://github.com/cofyc/dnscrypt-wrapper/blob/master/README.md#usage -# 2. dnscrypt channel attaches to an interface. you MUST set interfaces to -# listen on `dnscrypt-port` with the follo0wing snippet: -# server: -# interface: 0.0.0.0@443 -# interface: ::0@443 -# -# Finally, `dnscrypt` config has its own section. -# dnscrypt: -# dnscrypt-enable: yes -# dnscrypt-port: 443 -# dnscrypt-provider: 2.dnscrypt-cert.example.com. -# dnscrypt-secret-key: /path/unbound-conf/keys1/1.key -# dnscrypt-secret-key: /path/unbound-conf/keys2/1.key -# dnscrypt-provider-cert: /path/unbound-conf/keys1/1.cert -# dnscrypt-provider-cert: /path/unbound-conf/keys2/1.cert - -# CacheDB -# Enable external backend DB as auxiliary cache. Specify the backend name -# (default is "testframe", which has no use other than for debugging and -# testing) and backend-specific options. The 'cachedb' module must be -# included in module-config, just before the iterator module. -# cachedb: -# backend: "testframe" -# # secret seed string to calculate hashed keys -# secret-seed: "default" -# -# # For "redis" backend: -# # redis server's IP address or host name -# redis-server-host: 127.0.0.1 -# # redis server's TCP port -# redis-server-port: 6379 -# # timeout (in ms) for communication with the redis server -# redis-timeout: 100 -# # set timeout on redis records based on DNS response TTL -# redis-expire-records: no - -# IPSet -# Add specify domain into set via ipset. -# Note: To enable ipset Unbound needs to run as root user. -# ipset: -# # set name for ip v4 addresses -# name-v4: "list-v4" -# # set name for ip v6 addresses -# name-v6: "list-v6" -# - -# Dnstap logging support, if compiled in. To enable, set the dnstap-enable -# to yes and also some of dnstap-log-..-messages to yes. And select an -# upstream log destination, by socket path, TCP or TLS destination. -# dnstap: -# dnstap-enable: no -# # if set to yes frame streams will be used in bidirectional mode -# dnstap-bidirectional: yes -# dnstap-socket-path: "/etc/unbound/dnstap.sock" -# # if "" use the unix socket in dnstap-socket-path, otherwise, -# # set it to "IPaddress[@port]" of the destination. -# dnstap-ip: "" -# # if set to yes if you want to use TLS to dnstap-ip, no for TCP. -# dnstap-tls: yes -# # name for authenticating the upstream server. or "" disabled. -# dnstap-tls-server-name: "" -# # if "", it uses the cert bundle from the main Unbound config. -# dnstap-tls-cert-bundle: "" -# # key file for client authentication, or "" disabled. -# dnstap-tls-client-key-file: "" -# # cert file for client authentication, or "" disabled. -# dnstap-tls-client-cert-file: "" -# dnstap-send-identity: no -# dnstap-send-version: no -# # if "" it uses the hostname. -# dnstap-identity: "" -# # if "" it uses the package version. -# dnstap-version: "" -# dnstap-log-resolver-query-messages: no -# dnstap-log-resolver-response-messages: no -# dnstap-log-client-query-messages: no -# dnstap-log-client-response-messages: no -# dnstap-log-forwarder-query-messages: no -# dnstap-log-forwarder-response-messages: no - -# Response Policy Zones -# RPZ policies. Applied in order of configuration. QNAME, Response IP -# Address, nsdname, nsip and clientip triggers are supported. Supported -# actions are: NXDOMAIN, NODATA, PASSTHRU, DROP, Local Data, tcp-only -# and drop. Policies can be loaded from a file, or using zone -# transfer, or using HTTP. The respip module needs to be added -# to the module-config, e.g.: module-config: "respip validator iterator". -# rpz: -# name: "rpz.example.com" -# zonefile: "rpz.example.com" -# primary: 192.0.2.0 -# allow-notify: 192.0.2.0/32 -# url: http://www.example.com/rpz.example.org.zone -# rpz-action-override: cname -# rpz-cname-override: www.example.org -# rpz-log: yes -# rpz-log-name: "example policy" -# rpz-signal-nxdomain-ra: no -# for-downstream: no -# tags: "example" diff --git a/SOURCES/unbound.sysconfig b/SOURCES/unbound.sysconfig deleted file mode 100644 index fae3306..0000000 --- a/SOURCES/unbound.sysconfig +++ /dev/null @@ -1,3 +0,0 @@ -# for extra debug, add "-v -v" or change verbosity: in unbound.conf - -UNBOUND_OPTIONS="" diff --git a/SOURCES/block-example.com.conf b/block-example.com.conf similarity index 100% rename from SOURCES/block-example.com.conf rename to block-example.com.conf diff --git a/SOURCES/example.com.conf b/example.com.conf similarity index 100% rename from SOURCES/example.com.conf rename to example.com.conf diff --git a/SOURCES/example.com.key b/example.com.key similarity index 100% rename from SOURCES/example.com.key rename to example.com.key diff --git a/fedora-defaults.conf b/fedora-defaults.conf new file mode 100644 index 0000000..5fee76f --- /dev/null +++ b/fedora-defaults.conf @@ -0,0 +1,226 @@ +# Fedora distribution defaults + +server: + # verbosity number, 0 is least verbose. 1 is default. + verbosity: 1 + + # print statistics to the log (for every thread) every N seconds. + # Set to "" or 0 to disable. Default is disabled. + # Needs to be disabled for munin plugin + statistics-interval: 0 + + # enable cumulative statistics, without clearing them after printing. + # Needs to be disabled for munin plugin + statistics-cumulative: no + + # enable extended statistics (query types, answer codes, status) + # Needs to be enabled for munin plugin + extended-statistics: yes + + # number of threads to create. 1 disables threading. + # num-threads: 1 + num-threads: 4 + + # specify the interfaces to answer queries from by ip-address. + # The default is to listen to localhost (127.0.0.1 and ::1). + # specify 0.0.0.0 and ::0 to bind to all available interfaces. + # specify every interface[@port] on a new 'interface:' labelled line. + # The listen interfaces are not changed on reload, only on restart. + # interface: 0.0.0.0 + # interface: ::0 + # interface: 192.0.2.153 + # interface: 192.0.2.154 + # interface: 192.0.2.154@5003 + # interface: 2001:DB8::5 + # interface: eth0@5003 + # + # for dns over tls and raw dns over port 80 + # interface: 0.0.0.0@443 + # interface: ::0@443 + # interface: 0.0.0.0@80 + # interface: ::0@80 + + # enable this feature to copy the source address of queries to reply. + # Socket options are not supported on all platforms. experimental. + # interface-automatic: yes + # + # NOTE: Enable this option when specifying interface 0.0.0.0 or ::0 + # NOTE: Disabled per Fedora policy not to listen to * on default install + # NOTE: If deploying on non-default port, eg 80/443, this needs to be disabled + interface-automatic: no + + # permit Unbound to use this port number or port range for + # making outgoing queries, using an outgoing interface. + # Only ephemeral ports are allowed by SElinux + outgoing-port-permit: 32768-60999 + + # IANA-assigned port numbers. + # If multiple outgoing-port-permit and outgoing-port-avoid options + # are present, they are processed in order. + # Our SElinux policy does not allow non-ephemeral ports to be used + outgoing-port-avoid: 0-32767 + outgoing-port-avoid: 61000-65535 + + # use SO_REUSEPORT to distribute queries over threads. + # at extreme load it could be better to turn it off to distribute even. + so-reuseport: yes + + # use IP_TRANSPARENT so the interface: addresses can be non-local + # and you can config non-existing IPs that are going to work later on + # (uses IP_BINDANY on FreeBSD). + ip-transparent: yes + + # Enable UDP, "yes" or "no". + # NOTE: if setting up an Unbound on tls443 for public use, you might want to + # disable UDP to avoid being used in DNS amplification attacks. + # do-udp: yes + + # Enable EDNS TCP keepalive option. + edns-tcp-keepalive: yes + + # Fedora note: do not activate this - not compiled in because + # it causes frequent unbound crashes. Also, socket activation + # is bad when you have things like dnsmasq also running with libvirt. + # Use systemd socket activation for UDP, TCP, and control sockets. + # use-systemd: no + + # If you give "" no chroot is performed. The path must not end in a /. + # chroot: "/etc/unbound" + chroot: "" + + # If you give a server: directory: dir before include: file statements + # then those includes can be relative to the working directory. + directory: "/etc/unbound" + + # print UTC timestamp in ascii to logfile, default is epoch in seconds. + log-time-ascii: yes + + # Harden against unseemly large queries. + harden-large-queries: yes + + # Default off, because the lookups burden the server. Experimental + # implementation of draft-wijngaards-dnsext-resolver-side-mitigation. + harden-referral-path: yes + + # Sent minimum amount of information to upstream servers to enhance + # privacy. Only sent minimum required labels of the QNAME and set QTYPE + # to A when possible. + qname-minimisation: yes + + # Aggressive NSEC uses the DNSSEC NSEC chain to synthesize NXDOMAIN + # and other denials, using information from previous NXDOMAINs answers. + aggressive-nsec: yes + + # threshold, a warning is printed and a defensive action is taken, + # the cache is cleared to flush potential poison out of it. + # A suggested value is 10000000, the default is 0 (turned off). + unwanted-reply-threshold: 10000000 + + # if yes, perform prefetching of almost expired message cache entries. + prefetch: yes + + # if yes, perform key lookups adjacent to normal lookups. + prefetch-key: yes + + # deny queries of type ANY with an empty response. + deny-any: yes + + # if yes, Unbound rotates RRSet order in response. + rrset-roundrobin: yes + + # if yes, Unbound doesn't insert authority/additional sections + # into response messages when those sections are not required. + minimal-responses: yes + + # module configuration of the server. A string with identifiers + # separated by spaces. Syntax: "[dns64] [validator] iterator" + # most modules have to be listed at the beginning of the line, + # except cachedb(just before iterator), and python (at the beginning, + # or, just before the iterator). + # For redis cachedb use: + # "ipsecmod validator cachedb iterator" + module-config: "ipsecmod validator iterator" + + # trust anchor signaling sends a RFC8145 key tag query after priming. + trust-anchor-signaling: yes + + # Root key trust anchor sentinel (draft-ietf-dnsop-kskroll-sentinel) + root-key-sentinel: yes + + # the trusted-keys { name flag proto algo "key"; }; clauses are read. + # you need external update procedures to track changes in keys. + # trusted-keys-file: "" + # + trusted-keys-file: /etc/unbound/keys.d/*.key + auto-trust-anchor-file: "/var/lib/unbound/root.key" + + # Should additional section of secure message also be kept clean of + # unsecure data. Useful to shield the users of this validator from + # potential bogus data in the additional section. All unsigned data + # in the additional section is removed from secure messages. + val-clean-additional: yes + + # Turn permissive mode on to permit bogus messages. Thus, messages + # for which security checks failed will be returned to clients, + # instead of SERVFAIL. It still performs the security checks, which + # result in interesting log files and possibly the AD bit in + # replies if the message is found secure. The default is off. + # NOTE: TURNING THIS ON DISABLES ALL DNSSEC SECURITY + val-permissive-mode: no + + # Serve expired responses from cache, with serve-expired-reply-ttl in + # the response, and then attempt to fetch the data afresh. + serve-expired: yes + + # Limit serving of expired responses to configured seconds after + # expiration. 0 disables the limit. + serve-expired-ttl: 14400 + + # Have the validator log failed validations for your diagnosis. + # 0: off. 1: A line per failed user query. 2: With reason and bad IP. + val-log-level: 1 + + # service clients over TLS (on the TCP sockets) with plain DNS inside + # the TLS stream, and over HTTPS using HTTP/2 as specified in RFC8484. + # Give the certificate to use and private key. + # default is "" (disabled). requires restart to take effect. + # tls-service-key: "/etc/unbound/unbound_server.key" + # tls-service-pem: "/etc/unbound/unbound_server.pem" + + # Fedora/RHEL: use system-wide crypto policies + tls-ciphers: "PROFILE=SYSTEM" + + # Enable to attach Extended DNS Error codes (RFC8914) to responses. + # Fedora defaults to yes. + ede: yes + + # Enable to attach an Extended DNS Error (RFC8914) Code 3 - Stale + # Answer as EDNS0 option to expired responses. + # Note that the ede option above needs to be enabled for this to work. + # Fedora defaults to yes. + ede-serve-expired: yes + + # Enable or disable ipsecmod (it still needs to be defined in + # module-config above). Can be used when ipsecmod needs to be + # enabled/disabled via remote-control(below). + # Fedora: module will be enabled on-demand by libreswan + ipsecmod-enabled: no + + # Path to executable external hook. It must be defined when ipsecmod is + # listed in module-config (above). + ipsecmod-hook: /usr/libexec/ipsec/_unbound-hook + +python: + # Script file to load + # python-script: "/etc/unbound/ubmodule-tst.py" + +# Remote control config section moved into own remote-control.conf + +# the module-config then you need one dynlib-file per instance. +dynlib: + # Script file to load + # dynlib-file: "/etc/unbound/dynlib.so" + +# Fedora: DNSCrypt support not enabled since it requires linking to +# another crypto library +# diff --git a/SOURCES/icannbundle.pem b/icannbundle.pem similarity index 100% rename from SOURCES/icannbundle.pem rename to icannbundle.pem diff --git a/module-setup.sh b/module-setup.sh new file mode 100644 index 0000000..439bc6d --- /dev/null +++ b/module-setup.sh @@ -0,0 +1,44 @@ +#!/usr/bin/bash + +check() { + require_binaries unbound unbound-checkconf unbound-control || return 1 + # the module will be only included if explicitly required either + # by configuration or another module + return 255 +} + +depends() { + # because of pid file we need sysusers to create unbound user + echo systemd systemd-sysusers + return 0 +} + +install() { + # We have to make unbound wanted by network-online target to make sure + # there is a synchronization point when other services are able + # to make queries + inst_simple "$moddir"/unbound-initrd.conf /etc/systemd/system/unbound.service.d/unbound-initrd.conf + + # /etc and /var/lib do not have its variables + inst_multiple -o \ + "$systemdsystemunitdir"/unbound.service \ + /etc/unbound/conf.d/remote-control.conf \ + /etc/unbound/openssl-sha1.conf \ + /usr/share/unbound/fedora-defaults.conf \ + /usr/share/unbound/conf.d/*.conf \ + /etc/unbound/local.d/*.conf \ + /etc/unbound/keys.d/*.key \ + /etc/unbound/unbound.conf \ + /etc/unbound/unbound_control.key \ + /etc/unbound/unbound_control.pem \ + /etc/unbound/unbound_server.key \ + /etc/unbound/unbound_server.pem \ + "$sysusers"/unbound.conf \ + "$tmpfilesdir"/unbound.conf \ + /var/lib/unbound/root.key \ + unbound \ + unbound-checkconf \ + unbound-control + + $SYSTEMCTL -q --root "$initdir" enable unbound.service +} diff --git a/remote-control-include.conf b/remote-control-include.conf new file mode 100644 index 0000000..5688480 --- /dev/null +++ b/remote-control-include.conf @@ -0,0 +1,4 @@ +# Previous defaults allowed any process to change settings, CVE-2023-1488 +# If you want to modify remote configuration, replace this file with +# contents of included file and modify afterwards. +include: "/usr/share/unbound/conf.d/remote-control.conf" diff --git a/remote-control.conf b/remote-control.conf new file mode 100644 index 0000000..6f6942e --- /dev/null +++ b/remote-control.conf @@ -0,0 +1,26 @@ +# Remote control config section update. +# Previous defaults allowed any process to change settings, CVE-2023-1488 +# This file can be used also by: unbound-control -c +remote-control: + # Enable remote control with unbound-control(8) here. + # set up the keys and certificates with unbound-control-setup. + control-enable: yes + + # set to an absolute path to use a unix local name pipe, certificates + # are not used for that, so key and cert files need not be present. + control-interface: "/run/unbound/control" + + # For local sockets this option is ignored, and TLS is not used. + control-use-cert: "yes" + + # Unbound server key file. + server-key-file: "/etc/unbound/unbound_server.key" + + # Unbound server certificate file. + server-cert-file: "/etc/unbound/unbound_server.pem" + + # unbound-control key file. + control-key-file: "/etc/unbound/unbound_control.key" + + # unbound-control certificate file. + control-cert-file: "/etc/unbound/unbound_control.pem" diff --git a/SOURCES/root.anchor b/root.anchor similarity index 100% rename from SOURCES/root.anchor rename to root.anchor diff --git a/SOURCES/root.key b/root.key similarity index 99% rename from SOURCES/root.key rename to root.key index a0b1bef..6c5622c 100644 --- a/SOURCES/root.key +++ b/root.key @@ -2,4 +2,5 @@ ; // named, unbound, et. For libunbound, use ub_ctx_trustedkeys() to load this trusted-keys { "." 257 3 8 "AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU="; // key id = 20326 + }; diff --git a/sources b/sources new file mode 100644 index 0000000..3198758 --- /dev/null +++ b/sources @@ -0,0 +1 @@ +SHA512 (unbound-1.20.0.tar.gz) = 2f6bc76c03b71ca1c2cd2331dc72d62f51493d15e17c59af46b400e542fcabff22e6b9d33f750a3e5f918a0116f45afa760651b2d5aa2feadac151cbbd71b0bd diff --git a/tmpfiles-unbound.conf b/tmpfiles-unbound.conf new file mode 100644 index 0000000..c09cc75 --- /dev/null +++ b/tmpfiles-unbound.conf @@ -0,0 +1 @@ +D /run/unbound 0775 unbound root - diff --git a/unbound-1.20.0.tar.gz.asc b/unbound-1.20.0.tar.gz.asc new file mode 100644 index 0000000..c15832a --- /dev/null +++ b/unbound-1.20.0.tar.gz.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCAAdFiEE7fqj8spObrBWga+On28cLX4EX40FAmY7MtIACgkQn28cLX4E +X43TZw//UOLWFXCT36DydXV2gi8vAB9xIFOGj7LbfOSIu8mg2gOvxaBFcC3qb8iB +Wh4prktm+ANRyrmaDq5jlhG2JS0JGYCAGXntN8O09IZt8cx5s1N4UWOOOHp/XEcF +spQpohJlJMnDl+WuIW0rGUnME4mytEBd/HwIM2Q4XyhXOEQj4hEW1tGlNF1qNq5b +8KV5AbRa1OMPeaOaLUb3rg4Wll90twKnlVsdAga1GzYHYHIjbrvso8TbEAZQOzk1 +Vu20zwNV1mFNRQcBhhkRBSirmZQ3p73HDT3j3yZZ7D2VaZyi1TQSNxCKAkBpM7NX +ZXBXHpYjf/9kei8vMeQBE4pIoXgcSAASyHh1FNZ8vzyklR8lP8grNtgn1R7ACryN +U1W+0Mh4gjZLjK4sgfouunqpuDpKnpb7a/b19D4fqGBYen+V/BBwARbdxPABs2fK +Y5kMnSIM3eZPZD2PnLEL8uqfuES1QZ9OkhGvEX9jhO3plYWzUDa7J/5eFqyUEpPc +zkAlQvJySW1T18U7YWPLM7ipsVIZc7XPkvEHpit6cSj7f4wUPurJio2glOHwXafZ ++mmzb7nFahTE6tmvOF3dBbvxRpzYtHI6qa1tNTVR9EFJsc8Bm9a8dcI6Jd4e6M2i +XWA32DOSppyEdLz3aEmpIQLT3VpSPRHuLB+slfi+xsBcwNJHL4w= +=mEBa +-----END PGP SIGNATURE----- diff --git a/unbound-anchor.service b/unbound-anchor.service new file mode 100644 index 0000000..1116243 --- /dev/null +++ b/unbound-anchor.service @@ -0,0 +1,10 @@ +[Unit] +Description=update of the root trust anchor for DNSSEC validation in unbound +Documentation=man:unbound-anchor(8) + +[Service] +Type=oneshot +User=unbound +EnvironmentFile=-/etc/sysconfig/unbound +ExecStart=/bin/bash -c 'if [ "$DISABLE_UNBOUND_ANCHOR" = "yes" ] || [ -f /run/unbound/anchor-disable ]; then echo "Updates of root keys with unbound-anchor is disabled"; else /usr/sbin/unbound-anchor $UNBOUND_ANCHOR_OPTIONS; fi' +SuccessExitStatus=1 diff --git a/SOURCES/unbound-anchor.timer b/unbound-anchor.timer similarity index 100% rename from SOURCES/unbound-anchor.timer rename to unbound-anchor.timer diff --git a/unbound-as112-networks.conf b/unbound-as112-networks.conf new file mode 100644 index 0000000..96c291f --- /dev/null +++ b/unbound-as112-networks.conf @@ -0,0 +1,118 @@ +# Allow forwarding of private ranges, which are marked forwardable by IANA +# https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml +# https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml +# https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml +# RFC 6303: Locally Served DNS Zones (https://www.rfc-editor.org/rfc/rfc6303.html) +# +# Using this configuration file will simplify forwarding to potentially private ranges. +# Enables forwarding of networks marked as forwardable at IANA special registry. +# This is useful when upstream forwarder may be still inside private network. That is the case +# when unbound works as a localhost DNS cache, not network wide resolver. + +server: + # RFC 8375: Special-Use Domain 'home.arpa.' + local-zone: "home.arpa." nodefault + + # RFC 1918: Address Allocation for Private Internets + local-zone: "10.in-addr.arpa." nodefault + local-zone: "16.172.in-addr.arpa." nodefault + local-zone: "17.172.in-addr.arpa." nodefault + local-zone: "18.172.in-addr.arpa." nodefault + local-zone: "19.172.in-addr.arpa." nodefault + local-zone: "20.172.in-addr.arpa." nodefault + local-zone: "21.172.in-addr.arpa." nodefault + local-zone: "22.172.in-addr.arpa." nodefault + local-zone: "23.172.in-addr.arpa." nodefault + local-zone: "24.172.in-addr.arpa." nodefault + local-zone: "25.172.in-addr.arpa." nodefault + local-zone: "26.172.in-addr.arpa." nodefault + local-zone: "27.172.in-addr.arpa." nodefault + local-zone: "28.172.in-addr.arpa." nodefault + local-zone: "29.172.in-addr.arpa." nodefault + local-zone: "30.172.in-addr.arpa." nodefault + local-zone: "31.172.in-addr.arpa." nodefault + local-zone: "168.192.in-addr.arpa." nodefault + # RFC 6598: IANA-Reserved IPv4 Prefix for Shared Address Space + local-zone: "64.100.in-addr.arpa." nodefault + local-zone: "65.100.in-addr.arpa." nodefault + local-zone: "66.100.in-addr.arpa." nodefault + local-zone: "67.100.in-addr.arpa." nodefault + local-zone: "68.100.in-addr.arpa." nodefault + local-zone: "69.100.in-addr.arpa." nodefault + local-zone: "70.100.in-addr.arpa." nodefault + local-zone: "71.100.in-addr.arpa." nodefault + local-zone: "72.100.in-addr.arpa." nodefault + local-zone: "73.100.in-addr.arpa." nodefault + local-zone: "74.100.in-addr.arpa." nodefault + local-zone: "75.100.in-addr.arpa." nodefault + local-zone: "76.100.in-addr.arpa." nodefault + local-zone: "77.100.in-addr.arpa." nodefault + local-zone: "78.100.in-addr.arpa." nodefault + local-zone: "79.100.in-addr.arpa." nodefault + local-zone: "80.100.in-addr.arpa." nodefault + local-zone: "81.100.in-addr.arpa." nodefault + local-zone: "82.100.in-addr.arpa." nodefault + local-zone: "83.100.in-addr.arpa." nodefault + local-zone: "84.100.in-addr.arpa." nodefault + local-zone: "85.100.in-addr.arpa." nodefault + local-zone: "86.100.in-addr.arpa." nodefault + local-zone: "87.100.in-addr.arpa." nodefault + local-zone: "88.100.in-addr.arpa." nodefault + local-zone: "89.100.in-addr.arpa." nodefault + local-zone: "90.100.in-addr.arpa." nodefault + local-zone: "91.100.in-addr.arpa." nodefault + local-zone: "92.100.in-addr.arpa." nodefault + local-zone: "93.100.in-addr.arpa." nodefault + local-zone: "94.100.in-addr.arpa." nodefault + local-zone: "95.100.in-addr.arpa." nodefault + local-zone: "96.100.in-addr.arpa." nodefault + local-zone: "97.100.in-addr.arpa." nodefault + local-zone: "98.100.in-addr.arpa." nodefault + local-zone: "99.100.in-addr.arpa." nodefault + local-zone: "100.100.in-addr.arpa." nodefault + local-zone: "101.100.in-addr.arpa." nodefault + local-zone: "102.100.in-addr.arpa." nodefault + local-zone: "103.100.in-addr.arpa." nodefault + local-zone: "104.100.in-addr.arpa." nodefault + local-zone: "105.100.in-addr.arpa." nodefault + local-zone: "106.100.in-addr.arpa." nodefault + local-zone: "107.100.in-addr.arpa." nodefault + local-zone: "108.100.in-addr.arpa." nodefault + local-zone: "109.100.in-addr.arpa." nodefault + local-zone: "110.100.in-addr.arpa." nodefault + local-zone: "111.100.in-addr.arpa." nodefault + local-zone: "112.100.in-addr.arpa." nodefault + local-zone: "113.100.in-addr.arpa." nodefault + local-zone: "114.100.in-addr.arpa." nodefault + local-zone: "115.100.in-addr.arpa." nodefault + local-zone: "116.100.in-addr.arpa." nodefault + local-zone: "117.100.in-addr.arpa." nodefault + local-zone: "118.100.in-addr.arpa." nodefault + local-zone: "119.100.in-addr.arpa." nodefault + local-zone: "120.100.in-addr.arpa." nodefault + local-zone: "121.100.in-addr.arpa." nodefault + local-zone: "122.100.in-addr.arpa." nodefault + local-zone: "123.100.in-addr.arpa." nodefault + local-zone: "124.100.in-addr.arpa." nodefault + local-zone: "125.100.in-addr.arpa." nodefault + local-zone: "126.100.in-addr.arpa." nodefault + local-zone: "127.100.in-addr.arpa." nodefault + + # RFC 4193: Unique Local IPv6 Unicast Addresses + local-zone: "d.f.ip6.arpa." nodefault + + # RFC 2606: Reserved Top Level DNS Names + local-zone: "test." nodefault + domain-insecure: "test" + domain-insecure: "example" + + # RFC 6762: Multicast DNS, Appendix G + domain-insecure: "local" + domain-insecure: "intranet" + domain-insecure: "private" + domain-insecure: "corp" + domain-insecure: "home" + domain-insecure: "lan" + + # draft-davies-internal-tld + domain-insecure: "internal" diff --git a/unbound-fedora-config.patch b/unbound-fedora-config.patch new file mode 100644 index 0000000..ff93159 --- /dev/null +++ b/unbound-fedora-config.patch @@ -0,0 +1,113 @@ +From 56187754cbd38f3623b56d9dc97fbe4b5b5d87e8 Mon Sep 17 00:00:00 2001 +From: Tomas Korbar +Date: Tue, 4 Feb 2025 09:48:12 +0100 +Subject: [PATCH 1/1] Customize unbound.conf for Fedora defaults + +Set some Fedora/RHEL specific changes to example configuration file. By +patching upstream provided config file we would not need to manually +update external copy in source RPM. +--- + unbound-1.20.0/doc/example.conf.in | 33 ++++++++++++++++++++++++++++-- + 1 file changed, 31 insertions(+), 2 deletions(-) + +diff --git a/unbound-1.20.0/doc/example.conf.in b/unbound-1.20.0/doc/example.conf.in +index 0368c8d..3ca085e 100644 +--- a/unbound-1.20.0/doc/example.conf.in ++++ b/unbound-1.20.0/doc/example.conf.in +@@ -51,11 +51,19 @@ server: + # specify 0.0.0.0 and ::0 to bind to all available interfaces. + # specify every interface[@port] on a new 'interface:' labelled line. + # The listen interfaces are not changed on reload, only on restart. ++ # interface: 0.0.0.0 ++ # interface: ::0 + # interface: 192.0.2.153 + # interface: 192.0.2.154 + # interface: 192.0.2.154@5003 + # interface: 2001:DB8::5 + # interface: eth0@5003 ++ # ++ # for dns over tls and raw dns over port 80 ++ # interface: 0.0.0.0@443 ++ # interface: ::0@443 ++ # interface: 0.0.0.0@80 ++ # interface: ::0@80 + + # enable this feature to copy the source address of queries to reply. + # Socket options are not supported on all platforms. experimental. +@@ -276,6 +284,8 @@ server: + # nat64-prefix: 64:ff9b::0/96 + + # Enable UDP, "yes" or "no". ++ # NOTE: if setting up an Unbound on tls443 for public use, you might want to ++ # disable UDP to avoid being used in DNS amplification attacks. + # do-udp: yes + + # Enable TCP, "yes" or "no". +@@ -311,6 +321,9 @@ server: + # can be dropped. Default is 0, disabled. In seconds, such as 3. + # sock-queue-timeout: 0 + ++ # Fedora note: do not activate this - not compiled in because ++ # it causes frequent unbound crashes. Also, socket activation ++ # is bad when you have things like dnsmasq also running with libvirt. + # Use systemd socket activation for UDP, TCP, and control sockets. + # use-systemd: no + +@@ -890,6 +903,8 @@ server: + # you need to do the reverse notation yourself. + # local-data-ptr: "192.0.2.3 www.example.com" + ++ include: /etc/unbound/local.d/*.conf ++ + # tag a localzone with a list of tag names (in "" with spaces between) + # local-zone-tag: "example.com" "tag2 tag3" + +@@ -900,8 +915,8 @@ server: + # the TLS stream, and over HTTPS using HTTP/2 as specified in RFC8484. + # Give the certificate to use and private key. + # default is "" (disabled). requires restart to take effect. +- # tls-service-key: "path/to/privatekeyfile.key" +- # tls-service-pem: "path/to/publiccertfile.pem" ++ # tls-service-key: "/etc/unbound/unbound_server.key" ++ # tls-service-pem: "/etc/unbound/unbound_server.pem" + # tls-port: 853 + # https-port: 443 + +@@ -1141,6 +1156,12 @@ remote-control: + # unbound-control certificate file. + # control-cert-file: "@UNBOUND_RUN_DIR@/unbound_control.pem" + ++# Default Fedora settings ++include: "@UNBOUND_SHARE_DIR@/fedora-defaults.conf" ++ ++# Stub and Forward zones ++include: "@sysconfdir@/unbound/conf.d/*.conf" ++ + # Stub zones. + # Create entries like below, to make all queries for 'example.com' and + # 'example.org' go to the given list of nameservers. list zero or more +@@ -1161,6 +1182,10 @@ remote-control: + # name: "example.org" + # stub-host: ns.example.com. + ++# You can now also dynamically create and delete stub-zone's using ++# unbound-control stub_add domain.com 1.2.3.4 5.6.7.8 ++# unbound-control stub_remove domain.com 1.2.3.4 5.6.7.8 ++ + # Forward zones + # Create entries like below, to make all queries for 'example.com' and + # 'example.org' go to the given list of servers. These servers have to handle +@@ -1178,6 +1203,10 @@ remote-control: + # forward-zone: + # name: "example.org" + # forward-host: fwd.example.com ++# ++# You can now also dynamically create and delete forward-zone's using ++# unbound-control forward_add domain.com 1.2.3.4 5.6.7.8 ++# unbound-control forward_remove domain.com 1.2.3.4 5.6.7.8 + + # Authority zones + # The data for these zones is kept locally, from a file or downloaded. +-- +2.48.1 + diff --git a/unbound-initrd.conf b/unbound-initrd.conf new file mode 100644 index 0000000..7838b3d --- /dev/null +++ b/unbound-initrd.conf @@ -0,0 +1,5 @@ +[Unit] +Before=network-online.target + +[Install] +WantedBy=network-online.target diff --git a/SOURCES/unbound-keygen.service b/unbound-keygen.service similarity index 100% rename from SOURCES/unbound-keygen.service rename to unbound-keygen.service diff --git a/unbound-local-root.conf b/unbound-local-root.conf new file mode 100644 index 0000000..4ba5e9d --- /dev/null +++ b/unbound-local-root.conf @@ -0,0 +1,30 @@ +# Authority zones +# The data for these zones is kept locally, from a file or downloaded. +# The data can be served to downstream clients, or used instead of the +# upstream (which saves a lookup to the upstream). +# +# Download local root copy and answer TLD queries from it. Because +# auth-zone has higher precedence, defined forward-zones to internal +# only TLD will not work. Use stub-zone or disable this zone. +# Good for a network-wide resolvers, worse for a localhost caching forwarder. +auth-zone: + name: "." + primary: 170.247.170.2 # b.root-servers.net + primary: 192.33.4.12 # c.root-servers.net + primary: 199.7.91.13 # d.root-servers.net + primary: 192.5.5.241 # f.root-servers.net + primary: 192.112.36.4 # g.root-servers.net + primary: 193.0.14.129 # k.root-servers.net + primary: 192.0.47.132 # xfr.cjr.dns.icann.org + primary: 192.0.32.132 # xfr.lax.dns.icann.org + primary: 2801:1b8:10::b # b.root-servers.net + primary: 2001:500:2::c # c.root-servers.net + primary: 2001:500:2d::d # d.root-servers.net + primary: 2001:500:2f::f # f.root-servers.net + primary: 2001:500:12::d0d # g.root-servers.net + primary: 2001:7fd::1 # k.root-servers.net + primary: 2620:0:2830:202::132 # xfr.cjr.dns.icann.org + primary: 2620:0:2d0:202::132 # xfr.lax.dns.icann.org + fallback-enabled: yes + for-downstream: no + for-upstream: yes diff --git a/SOURCES/unbound-munin.README b/unbound-munin.README similarity index 100% rename from SOURCES/unbound-munin.README rename to unbound-munin.README diff --git a/SOURCES/unbound.munin b/unbound.munin similarity index 100% rename from SOURCES/unbound.munin rename to unbound.munin diff --git a/SOURCES/unbound.service b/unbound.service similarity index 57% rename from SOURCES/unbound.service rename to unbound.service index 49dc7bd..d476504 100644 --- a/SOURCES/unbound.service +++ b/unbound.service @@ -1,19 +1,23 @@ [Unit] Description=Unbound recursive Domain Name Server After=network.target +# Use ip-freebind: yes or add After=network-online.target, rhbz#2338429, +# if interface: specifies exact address, not localhost nor wildcard +#After=network-online.target After=unbound-keygen.service Wants=unbound-keygen.service -Wants=unbound-anchor.timer +After=unbound-anchor.service +Wants=unbound-anchor.service Before=nss-lookup.target Wants=nss-lookup.target [Service] -Type=simple +Type=notify EnvironmentFile=-/etc/sysconfig/unbound ExecStartPre=/usr/sbin/unbound-checkconf -ExecStartPre=/bin/bash -c 'if [ ! "$DISABLE_UNBOUND_ANCHOR" == "yes" ]; then /usr/sbin/unbound-anchor -a /var/lib/unbound/root.key -c /etc/unbound/icannbundle.pem -f /etc/resolv.conf -R; else echo "Updates of root keys with unbound-anchor is disabled"; fi' ExecStart=/usr/sbin/unbound -d $UNBOUND_OPTIONS ExecReload=/usr/sbin/unbound-control reload +Restart=on-abnormal [Install] WantedBy=multi-user.target diff --git a/SPECS/unbound.spec b/unbound.spec similarity index 69% rename from SPECS/unbound.spec rename to unbound.spec index e5e3dba..abf3676 100644 --- a/SPECS/unbound.spec +++ b/unbound.spec @@ -1,6 +1,20 @@ +## START: Set by rpmautospec +## (rpmautospec version 0.6.5) +## RPMAUTOSPEC: autorelease, autochangelog +%define autorelease(e:s:pb:n) %{?-p:0.}%{lua: + release_number = 9; + base_release_number = tonumber(rpm.expand("%{?-b*}%{!?-b:1}")); + print(release_number + base_release_number - 1); +}%{?-e:.%{-e*}}%{?-s:.%{-s*}}%{!?-n:%{?dist}} +## END: Set by rpmautospec + %{?!with_python2: %global with_python2 0} %{?!with_python3: %global with_python3 1} %{?!with_munin: %global with_munin 1} +%bcond_without dnstap +%bcond_without systemd +%bcond_without doh +%bcond_with redis %global _hardened_build 1 @@ -8,38 +22,30 @@ %if 0%{with_python2} %global python_primary %{__python2} -%endif # with_python2 +%endif %if 0%{with_python3} %global python_primary %{__python3} -%endif # with_python3 +%endif %if 0%{?rhel} %global with_munin 0 -%if 0%{?with_python2} && 0%{?rhel} <= 6 -# needed just for EPEL -%{!?__python2: %global __python2 /usr/bin/python2} -%{!?python2_sitelib: %global python2_sitelib %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")} -%{!?python2_sitearch: %global python2_sitearch %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")} -%endif # with_python2 && rhel <= 6 - %if 0%{?rhel} <= 7 %global with_python3 0 %else %global with_python2 0 -%endif # rhel <= 7 -%endif # rhel +%endif +%endif Summary: Validating, recursive, and caching DNS(SEC) resolver Name: unbound -Version: 1.16.2 -Release: 5.8%{?extra_version:.%{extra_version}}%{?dist} -License: BSD -Url: https://www.unbound.net/ -Source: https://www.unbound.net/downloads/%{name}-%{version}%{?extra_version}.tar.gz +Version: 1.20.0 +Release: %autorelease %{?extra_version:-e %{extra_version}} +License: BSD-3-Clause +Url: https://nlnetlabs.nl/projects/unbound/ +Source: https://nlnetlabs.nl/downloads/%{name}/%{name}-%{version}%{?extra_version}.tar.gz Source1: unbound.service -Source2: unbound.conf Source3: unbound.munin Source4: unbound_munin_ Source5: root.key @@ -55,38 +61,58 @@ Source15: unbound-anchor.timer Source16: unbound-munin.README Source17: unbound-anchor.service Source18: https://nlnetlabs.nl/downloads/%{name}/%{name}-%{version}%{?extra_version}.tar.gz.asc +# source: https://nlnetlabs.nl/people/ +Source19: https://keys.openpgp.org/pks/lookup?op=get&search=0x9F6F1C2D7E045F8D#/wouter.nlnetlabs.nl.key +Source20: unbound.sysusers Source21: remote-control.conf +Source22: unbound-as112-networks.conf +Source23: unbound-local-root.conf +Source24: remote-control-include.conf +Source25: fedora-defaults.conf +Source26: module-setup.sh +Source27: unbound-initrd.conf -# Reverts ABI change done in version 1.8.0 (bz#2027735) -# Makes possible backward binary compatibility with a new features -Patch1: unbound-1.15-soversion2-compat.patch -Patch2: unbound-1.15-source-compat.patch -# https://github.com/NLnetLabs/unbound/commit/137719522a8ea5b380fbb6206d2466f402f5b554 -Patch3: unbound-1.16-CVE-2022-3204.patch -# https://nlnetlabs.nl/downloads/unbound/patch_CVE-2023-50387_CVE-2023-50868.diff -Patch4: unbound-1.16-CVE-2023-50387-CVE-2023-50868.patch -# https://github.com/NLnetLabs/unbound/commit/b7c61d7cc256d6a174e6179622c7fa968272c259 -Patch5: unbound-1.21-CVE-2024-8508.patch +# Downstream configuration changes +Patch1: unbound-fedora-config.patch -BuildRequires: gdb BuildRequires: gcc, make -BuildRequires: byacc, flex, openssl-devel +BuildRequires: flex, openssl-devel BuildRequires: libevent-devel expat-devel BuildRequires: pkgconfig +%if 0%{?fedora} +BuildRequires: gnupg2 +%endif %if 0%{with_python2} BuildRequires: python2-devel swig -%endif # with_python +%endif %if 0%{with_python3} BuildRequires: python3-devel swig -%endif # with_python3 +%endif +%if %{with dnstap} +BuildRequires: fstrm-devel protobuf-c-devel +%endif +%if %{with systemd} +BuildRequires: systemd-devel +%endif +%if %{with doh} +BuildRequires: libnghttp2-devel +%endif +%if %{with redis} +BuildRequires: hiredis-devel +%endif +%if 0%{?fedora} >= 30 || 0%{?rhel} >= 9 +BuildRequires: systemd-rpm-macros +%else BuildRequires: systemd +%endif # Required for SVN versions -BuildRequires: bison -BuildRequires: automake autoconf libtool +# BuildRequires: bison +# BuildRequires: automake autoconf libtool -%{?systemd_requires} # Needed because /usr/sbin/unbound links unbound libs staticly Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Requires: %{name}-anchor%{?_isa} = %{version}-%{release} +Recommends: %{name}-utils%{?_isa} = %{version}-%{release} # unbound-keygen.service requires it, bug #2116790 Requires: openssl @@ -122,11 +148,31 @@ The devel package contains the unbound library and the include files %package libs Summary: Libraries used by the unbound server and client applications -%{?systemd_requires} -Requires(pre): shadow-utils +Recommends: %{name}-anchor +%{?sysusers_requires_compat} +%if ! 0%{with_python2} +# Make explicit conflict with no longer provided python package +Obsoletes: python2-unbound < 1.9.3 +%endif %description libs -Contains libraries used by the unbound server and client applications +Contains libraries used by the unbound server and client applications. + +%package anchor +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Summary: DNSSEC trust anchor maintaining tool + +%description anchor +Contains tool maintaining trust anchor using RFC 5011 key rollover algorithm. + +%package utils +Requires: %{name}-libs%{?_isa} = %{version}-%{release} +Summary: Unbound DNS lookup utilities + +%description utils +Contains tools for making DNS queries. Can make queries to DNS servers +also over TLS connection or validate DNSSEC signatures. Similar to +bind-utils. %if 0%{with_python2} %package -n python2-unbound @@ -138,19 +184,34 @@ Obsoletes: unbound-python < %{version}-%{release} %description -n python2-unbound Python 2 modules and extensions for unbound -%endif # with_python +%endif %if 0%{with_python3} %package -n python3-unbound Summary: Python 3 modules and extensions for unbound Requires: %{name}-libs%{?_isa} = %{version}-%{release} +%if ! 0%{with_python2} +# Make explicit conflict with no longer provided python package +Conflicts: python2-unbound < 1.9.3 +%endif %description -n python3-unbound Python 3 modules and extensions for unbound -%endif # with_python3 +%endif +%package dracut +Summary: Unbound dracut module +Requires: dracut%{?_isa} +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description dracut +Unbound dracut module allowing use of Unbound for name resolution +in initramfs. %prep +%if 0%{?fedora} +%{gpgverify} --keyring='%{SOURCE19}' --signature='%{SOURCE18}' --data='%{SOURCE0}' +%endif %global pkgname %{name}-%{version}%{?extra_version} %if 0%{with_python2} && 0%{with_python3} @@ -160,21 +221,28 @@ Python 3 modules and extensions for unbound %global python_secondary %{__python2} %else %global dir_primary %{pkgname} -%endif # with_python2 && with_python3 +%endif -%setup -qcn %{pkgname} +%autosetup -c -N -n %{pkgname} pushd %{pkgname} +# patches go here +%autopatch -p2 -%patch1 -p2 -b .solib2-compat -%patch2 -p1 -b .srccompat -%patch3 -p2 -b .CVE-2022-3204 -%patch4 -p2 -b .CVE-2023-50387-CVE-2023-50868 -%patch5 -p2 -b .CVE-2024-8508 - +# only for snapshots +# autoreconf -iv # copy common doc files - after here, since it may be patched cp -pr doc pythonmod libunbound ../ + +%if 0%{?rhel} > 8 + # SHA-1 breaks some tests. Disable just some tests because of that. + # This got broken in ELN + ls testdata/*.rpl + for TEST in autotrust_init_fail autotrust_init_failsig; do + mv testdata/${TEST}.rpl{,-disabled} + done +%endif popd %if 0%{with_python2} && 0%{with_python3} @@ -183,30 +251,49 @@ cp -a %{dir_primary} %{dir_secondary} %endif %build +# This is needed to rebuild the configure script to support Python 3.x +# autoreconf -iv + # ./configure script common arguments %global configure_args --with-libevent --with-pthreads --with-ssl \\\ --disable-rpath --disable-static \\\ --enable-relro-now --enable-pie \\\ --enable-subnet --enable-ipsecmod \\\ --with-conf-file=%{_sysconfdir}/%{name}/unbound.conf \\\ - --with-pidfile=%{_localstatedir}/run/%{name}/%{name}.pid \\\ + --with-share-dir=%{_datadir}/%{name} \\\ + --with-pidfile=%{_rundir}/%{name}/%{name}.pid \\\ --enable-sha2 --disable-gost --enable-ecdsa \\\ - --with-rootkey-file=%{_sharedstatedir}/unbound/root.key \\\ - --enable-linux-ip-local-port-range + --with-rootkey-file=%{_sharedstatedir}/%{name}/root.key \\\ + --with-username=unbound \\\ + --enable-linux-ip-local-port-range \\\ + pushd %{dir_primary} -# configure.ac is modified, force refresh -autoreconf -fiv - %configure \ %if 0%{?python_primary:1} --with-pythonmodule --with-pyunbound PYTHON=%{python_primary} \ -%endif # python_primary +%endif +%if %{with dnstap} + --enable-dnstap \ +%endif +%if %{with systemd} + --enable-systemd \ +%endif +%if %{with doh} + --with-libnghttp2 \ +%endif +%if 0%{?rhel} + --disable-sha1 \ +%endif +%if %{with redis} + --with-libhiredis \ + --enable-cachedb \ +%endif %{configure_args} -%{__make} %{?_smp_mflags} -%{__make} %{?_smp_mflags} streamtcp +%make_build +%make_build streamtcp popd @@ -214,11 +301,17 @@ popd pushd %{dir_secondary} %configure \ --with-pythonmodule --with-pyunbound PYTHON=%{python_secondary} \ +%if %{with dnstap} + --enable-dnstap \ +%endif +%if %{with systemd} + --enable-systemd \ +%endif %{configure_args} -%{__make} %{?_smp_mflags} +%make_build popd -%endif # python_secondary +%endif %install @@ -227,13 +320,14 @@ install -p -m 0644 %{SOURCE16} . %if 0%{?python_secondary:1} # install first secondary build. It will be overwritten by primary pushd %{dir_secondary} -%{__make} DESTDIR=%{buildroot} unbound-event-install install +%make_install unbound-event-install popd -%endif # python_secondary +%endif pushd %{dir_primary} -%{__make} DESTDIR=%{buildroot} unbound-event-install install +%make_install unbound-event-install install -m 0755 streamtcp %{buildroot}%{_sbindir}/unbound-streamtcp +install -p -m 0755 doc/example.conf %{buildroot}%{_sysconfdir}/unbound/unbound.conf popd install -d -m 0755 %{buildroot}%{_unitdir} %{buildroot}%{_sysconfdir}/sysconfig @@ -241,9 +335,9 @@ install -p -m 0644 %{SOURCE1} %{buildroot}%{_unitdir}/unbound.service install -p -m 0644 %{SOURCE7} %{buildroot}%{_unitdir}/unbound-keygen.service install -p -m 0644 %{SOURCE15} %{buildroot}%{_unitdir}/unbound-anchor.timer install -p -m 0644 %{SOURCE17} %{buildroot}%{_unitdir}/unbound-anchor.service -install -p -m 0755 %{SOURCE2} %{buildroot}%{_sysconfdir}/unbound install -p -m 0644 %{SOURCE12} %{buildroot}%{_sysconfdir}/unbound install -p -m 0644 %{SOURCE14} %{buildroot}%{_sysconfdir}/sysconfig/unbound +install -p -D -m 0644 %{SOURCE20} %{buildroot}%{_sysusersdir}/%{name}.conf %if %{with_munin} # Install munin plugin and its softlinks install -d -m 0755 %{buildroot}%{_sysconfdir}/munin/plugin-conf.d @@ -268,7 +362,12 @@ install -m 0644 %{SOURCE8} %{buildroot}%{_tmpfilesdir}/unbound.conf # install root - we keep a copy of the root key in old location, # in case user has changed the configuration and we wouldn't update it there install -m 0644 %{SOURCE5} %{buildroot}%{_sysconfdir}/unbound/ -install -m 0644 %{SOURCE13} %{buildroot}%{_sharedstatedir}/unbound/root.key +install -m 0644 %{SOURCE13} %{buildroot}%{_sysconfdir}/unbound/dnssec-root.key +# make initial key static +pushd %{buildroot}%{_sharedstatedir}/unbound + KEYPATH=$(realpath --relative-to="%{buildroot}%{_sharedstatedir}/unbound" "%{buildroot}%{_sysconfdir}/unbound/dnssec-root.key") + ln -s "$KEYPATH" root.key +popd # remove static library from install (fedora packaging guidelines) rm %{buildroot}%{_libdir}/*.la @@ -276,13 +375,13 @@ rm %{buildroot}%{_libdir}/*.la %if 0%{with_python2} rm %{buildroot}%{python2_sitearch}/*.la -%endif # with_python +%endif %if 0%{with_python3} rm %{buildroot}%{python3_sitearch}/*.la -%endif # with_python3 +%endif -mkdir -p %{buildroot}%{_localstatedir}/run/unbound +mkdir -p %{buildroot}%{_rundir}/unbound # Install directories for easier config file drop in @@ -290,25 +389,32 @@ mkdir -p %{buildroot}%{_sysconfdir}/unbound/{keys.d,conf.d,local.d} install -p %{SOURCE9} %{buildroot}%{_sysconfdir}/unbound/keys.d/ install -p %{SOURCE10} %{buildroot}%{_sysconfdir}/unbound/conf.d/ install -p %{SOURCE11} %{buildroot}%{_sysconfdir}/unbound/local.d/ -install -p -m 0644 %{SOURCE21} %{buildroot}%{_sysconfdir}/unbound/conf.d/ +install -p -m 0644 %{SOURCE24} %{buildroot}%{_sysconfdir}/unbound/conf.d/remote-control.conf + +mkdir -p %{buildroot}%{_datadir}/%{name}/conf.d +install -p -m 0644 %{SOURCE21} %{buildroot}%{_datadir}/%{name}/conf.d/ +install -p -m 0644 %{SOURCE22} %{buildroot}%{_datadir}/%{name}/conf.d/ +install -p -m 0644 %{SOURCE23} %{buildroot}%{_datadir}/%{name}/conf.d/ +install -p -m 0644 %{SOURCE25} %{buildroot}%{_datadir}/%{name}/ # Link unbound-control-setup.8 manpage to unbound-control.8 echo ".so man8/unbound-control.8" > %{buildroot}/%{_mandir}/man8/unbound-control-setup.8 +# install dracut module +mkdir -p %{buildroot}%{_prefix}/lib/dracut/modules.d/99unbound + +install -p -m 0755 %{SOURCE26} %{buildroot}%{_prefix}/lib/dracut/modules.d/99unbound +install -p -m 0644 %{SOURCE27} %{buildroot}%{_prefix}/lib/dracut/modules.d/99unbound %pre libs -getent group unbound >/dev/null || groupadd -r unbound -getent passwd unbound >/dev/null || \ -useradd -r -g unbound -d %{_sysconfdir}/unbound -s /sbin/nologin \ --c "Unbound DNS resolver" unbound +%sysusers_create_compat %{SOURCE20} %post %systemd_post unbound.service %systemd_post unbound-keygen.service -%post libs -%{?ldconfig} -%systemd_post unbound-anchor.timer +%post anchor +%systemd_post unbound-anchor.service unbound-anchor.timer # start the timer only if installing the package to prevent starting it, if it was stopped on purpose if [ "$1" -eq 1 ]; then # the Unit is in presets, but would be started after reboot @@ -319,27 +425,15 @@ fi %systemd_preun unbound.service %systemd_preun unbound-keygen.service -%preun libs -%systemd_preun unbound-anchor.timer +%preun anchor +%systemd_preun unbound-anchor.service unbound-anchor.timer %postun %systemd_postun_with_restart unbound.service %systemd_postun unbound-keygen.service -%postun libs -%{?ldconfig} -%systemd_postun_with_restart unbound-anchor.timer - -%triggerun -- unbound < 1.4.12-4 -# Save the current service runlevel info -# User must manually run systemd-sysv-convert --apply unbound -# to migrate them to systemd targets -/usr/bin/systemd-sysv-convert --save unbound >/dev/null 2>&1 ||: - -# Run these because the SysV package being removed won't do them -/sbin/chkconfig --del unbound >/dev/null 2>&1 || : -/bin/systemctl try-restart unbound.service >/dev/null 2>&1 || : -/bin/systemctl try-restart unbound-keygen.service >/dev/null 2>&1 || : +%postun anchor +%systemd_postun_with_restart unbound-anchor.service unbound-anchor.timer %check pushd %{dir_primary} @@ -358,17 +452,16 @@ pushd %{dir_secondary} #popd make check popd -%endif # python_secondary +%endif %files %doc doc/CREDITS doc/FEATURES %{_unitdir}/%{name}.service %{_unitdir}/%{name}-keygen.service -%attr(0755,unbound,unbound) %dir %{_localstatedir}/run/%{name} +%attr(0775,unbound,root) %dir %{_rundir}/%{name} %attr(0644,root,root) %{_tmpfilesdir}/unbound.conf %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/%{name}/unbound.conf -%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/sysconfig/%{name} %dir %attr(0755,root,unbound) %{_sysconfdir}/%{name}/keys.d %attr(0644,root,unbound) %config(noreplace) %{_sysconfdir}/%{name}/keys.d/*.key %dir %attr(0755,root,unbound) %{_sysconfdir}/%{name}/conf.d @@ -383,9 +476,7 @@ popd %{_sbindir}/unbound-checkconf %{_sbindir}/unbound-control %{_sbindir}/unbound-control-setup -%{_sbindir}/unbound-host -%{_sbindir}/unbound-streamtcp -%{_mandir}/man1/* +%{_datadir}/%{name}/ %{_mandir}/man5/* %exclude %{_mandir}/man8/unbound-anchor* %{_mandir}/man8/* @@ -424,114 +515,299 @@ popd %doc doc/README %license doc/LICENSE %attr(0755,root,root) %dir %{_sysconfdir}/%{name} -%{_sbindir}/unbound-anchor -%{_libdir}/libunbound.so.* -%{_mandir}/man8/unbound-anchor* -%{_sysconfdir}/%{name}/icannbundle.pem -%{_unitdir}/unbound-anchor.timer -%{_unitdir}/unbound-anchor.service +%{_sysusersdir}/%{name}.conf +%{_libdir}/libunbound.so.8* %dir %attr(0755,unbound,unbound) %{_sharedstatedir}/%{name} -%attr(0644,unbound,unbound) %config %{_sharedstatedir}/%{name}/root.key +%config(noreplace) %verify(not link user group) %{_sharedstatedir}/%{name}/root.key # just left for backwards compat with user changed unbound.conf files - format is different! %attr(0644,root,root) %config %{_sysconfdir}/%{name}/root.key -# modification of root.key is maintained by unbound-achor.service and is intentional, so let rpm know -%verify(not md5 size mtime) %{_sharedstatedir}/%{name}/root.key +%attr(0644,root,root) %config %{_sysconfdir}/%{name}/dnssec-root.key + +%files anchor +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/sysconfig/%{name} +%{_sbindir}/unbound-anchor +%{_mandir}/man8/unbound-anchor* +# icannbundle and root.key(s) should be replaced from package +# intentionally not using noreplace +%config %{_sysconfdir}/%{name}/icannbundle.pem +%{_unitdir}/unbound-anchor.timer +%{_unitdir}/unbound-anchor.service + +%files utils +%{_sbindir}/unbound-host +%{_sbindir}/unbound-streamtcp +%{_mandir}/man1/unbound-* + +%files dracut +%{_prefix}/lib/dracut/modules.d/99unbound %changelog -* Tue Nov 12 2024 Petr Menšík - 1.16.2-5.8 -- Prevent unbounded name compression (CVE-2024-8508) +## START: Generated by rpmautospec +* Mon Feb 10 2025 Tomas Korbar - 1.20.0-9 +- Add possibility to disable unbound-anchor by file presence -* Tue May 28 2024 Petr Menšík - 1.16.2-5.7 -- Rebuild to propagate to CentOS Stream (RHEL-25500) +* Fri Feb 07 2025 Tomas Korbar - 1.20.0-8 +- Change service type to notify -* Mon Mar 11 2024 Petr Menšík - 1.16.2-5.6 -- Ensure group access correction reaches also updated configs (CVE-2024-1488) +* Tue Feb 04 2025 Tomas Korbar - 1.20.0-7 +- Enabled libsystemd and change unbound service type to notify-reload -* Wed Feb 28 2024 Petr Menšík - 1.16.2-5.3 -- Ensure only unbound group can change configuration (CVE-2024-1488) +* Tue Feb 04 2025 Tomas Korbar - 1.20.0-6 +- Add dracut module -* Fri Feb 16 2024 Tomas Korbar - 1.16.2-5.1 -- Fix KeyTrap - Extreme CPU consumption in DNSSEC validator CVE-2023-50387 -- Fix Preparing an NSEC3 closest encloser proof can exhaust CPU resources CVE-2023-50868 -- Resolves: RHEL-25428 -- Resolves: RHEL-25423 +* Tue Feb 04 2025 Tomas Korbar - 1.20.0-5 +- Use ip-freebind: yes or add After=network-online.target -* Sat Oct 15 2022 Petr Menšík - 1.16.2-5 -- Stop creating wrong devel manual pages (#2135322) +* Tue Feb 04 2025 Tomas Korbar - 1.20.0-4 +- Move defaults to separate configuration file -* Sat Oct 15 2022 Petr Menšík - 1.16.2-4 -- Apply correctly previous change (CVE-2022-3204) +* Tue Feb 04 2025 Tomas Korbar - 1.20.0-3 +- Deactivate automatic root zone fetching -* Tue Oct 11 2022 Petr Menšík - 1.16.2-3 -- Fix NRDelegation attack leading to uncontrolled resource consumption - (CVE-2022-3204) +* Tue Oct 29 2024 Troy Dawson - 1.20.0-2 +- Bump release for October 2024 mass rebuild: + +* Tue Jul 02 2024 Petr Menšík - 1.20.0-1 +- Update to 1.20.0 + +* Mon Jun 24 2024 Troy Dawson - 1.19.0-10 +- Bump release for June 2024 mass rebuild + +* Tue May 28 2024 psklenar@redhat.com - 1.19.0-9 +- c10s init plans for unbound + +* Mon Jan 29 2024 Petr Menšík - 1.19.0-8 +- Always auto-restart on crash events + +* Mon Jan 29 2024 Petr Menšík - 1.19.0-7 +- Update address of b.root-servers.net (#2253461) + +* Sat Jan 27 2024 Fedora Release Engineering - 1.19.0-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Thu Nov 02 2023 Petr Menšík - 1.19.0-1 +- Update to 1.19.0 (#2248686) + +* Wed Sep 06 2023 Petr Menšík - 1.18.0-2 +- Skip failing tests on ELN builds + +* Fri Sep 01 2023 Petr Menšík - 1.18.0-1 +- Update to 1.18.0 (#2236097) + +* Sat Jul 22 2023 Fedora Release Engineering - 1.17.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild + +* Tue Jun 13 2023 Python Maint - 1.17.1-3 +- Rebuilt for Python 3.12 + +* Sat Jan 21 2023 Fedora Release Engineering - 1.17.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild + +* Fri Jan 13 2023 Paul Wouters - 1.17.0-2 +- Move unbound user creation to libs (#2149036) +- Use systemd-sysusers for user creation (#2105416) +- Keep original DNSSEC root key as config (#2132103) + +* Tue Nov 01 2022 Petr Menšík - 1.17.0-1 +- Update to 1.17.0 (#2134348) + +* Wed Oct 05 2022 Petr Menšík - 1.16.3-3 +- Correct issues made by unbound-anchor package split (#2110858) + +* Fri Sep 30 2022 Petr Menšík - 1.16.3-2 +- Update License tag to SPDX identifier + +* Fri Sep 23 2022 Petr Menšík - 1.16.3-1 +- Update to 1.16.3 (#2128638) + +* Tue Aug 09 2022 Paul Wouters - 1.16.2-3 +- sync up to upstream unbound.conf +- Enable Extended DNS Error codes (RFC8914) * Tue Aug 09 2022 Petr Menšík - 1.16.2-2 -- Require openssl tool for unbound-keygen (#2018806) +- Require openssl tool for unbound-keygen (#2116790) * Wed Aug 03 2022 Petr Menšík - 1.16.2-1 -- Update to 1.16.2 (#2027735) +- Update to 1.16.2 (#2105947) for CVE-2022-30698 and CVE-2022-30699 -* Wed Jun 15 2022 Petr Menšík - 1.16.0-2 -- Restart keygen service before every unbound start (#1959468) +* Sat Jul 23 2022 Fedora Release Engineering - 1.16.0-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild -* Wed Jun 15 2022 Petr Menšík - 1.16.0-1 -- Upgrade to 9.16.0 (#2027735) -- Update to recent version with compatibility with RHEL8 (#2027735) -- Ensure also source level compatibility with previous version +* Mon Jun 27 2022 Petr Menšík - 1.16.0-6 +- Move unbound-anchor to separate package +- Move unbound-host and unbound-streamtcp to unbound-utils package -* Thu May 19 2022 Richard Lescak - 1.7.3-18 -- Change file mode before owner when configuring remote control unix socket to avoid AVC denials -- Resolves: rhbz#2038251 +* Mon Jun 13 2022 Python Maint - 1.16.0-5 +- Rebuilt for Python 3.11 -* Mon Apr 26 2021 Artem Egorenkov - 1.7.3-17 +* Tue Jun 07 2022 Petr Menšík - 1.16.0-4 +- Restart keygen service before every unbound start + +* Sat Jun 04 2022 Petr Menšík - 1.16.0-1 +- Update to 1.16.0 + +* Tue Apr 26 2022 Petr Menšík - 1.15.0-3 +- Stop creating wrong devel manual pages (#2078929) + +* Wed Apr 20 2022 Petr Menšík - 1.15.0-2 +- Update icannbundle.pem + +* Tue Mar 29 2022 Petr Menšík - 1.15.0-1 +- Update to 1.15.0 (#2030608) + +* Sat Jan 22 2022 Fedora Release Engineering - 1.13.2-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild + +* Sat Nov 06 2021 Adrian Reber - 1.13.2-4 +- Rebuilt for protobuf 3.19.0 + +* Mon Oct 25 2021 Adrian Reber - 1.13.2-3 +- Rebuilt for protobuf 3.18.1 + +* Tue Sep 14 2021 Sahana Prasad - 1.13.2-2 +- Rebuilt with OpenSSL 3.0.0 + +* Thu Aug 12 2021 Paul Wouters - 1.13.2-1 +- Resolves: rhbz#1992985 unbound-1.13.2 is available +- Use system-wide crypto policies + +* Fri Jul 23 2021 Fedora Release Engineering - 1.13.1-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild + +* Wed Jun 02 2021 Python Maint - 1.13.1-7 +- Rebuilt for Python 3.10 + +* Fri Apr 23 2021 Artem Egorenkov - 1.13.1-6 - Option --enable-linux-ip-local-port-range added to use system configured port range for libunbound on Linux -- Resolves: rhbz#1830625 +- Resolves: rhbz#1935101 -* Tue Apr 06 2021 Artem Egorenkov - 1.7.3-16 +* Tue Apr 13 2021 Paul Wouters - 1.13.1-5 +- Fix unbound.service to use After=network-online.target + +* Tue Apr 06 2021 Artem Egorenkov - 1.13.1-4 - Don't start unbound-anchor before unbound service if DISABLE_UNBOUND_ANCHOR environment variable equals to "yes" -- Resolves: rhbz#1922448 -* Tue Sep 01 2020 Anna Khaitovich - 1.7.3-15 -- Fix SPEC file to not check md5 mtime and size of /var/lib/unbound/root.key -- Resolves: rhbz#1714175 -- Use system-wide crypto policy setting (PROFILE=SYSTEM) instead of custom setting -- Resolves: rhbz#1842837 -- Enable additional logging in unbound -- Resolves: rhbz#1850460 -- security hardening from x41 report -- Resolves: rhbz#1859933 -- symbolic link traversal when writing PID file -- Resolves: rhbz#1899058 +* Tue Mar 02 2021 Zbigniew Jędrzejewski-Szmek - 1.13.1-3 +- Rebuilt for updated systemd-rpm-macros + See https://pagure.io/fesco/issue/2583. -* Thu May 28 2020 Anna Khaitovich - 1.7.3-14 -- Fix unbound-1.7.3-amplifying-an-incoming-query.patch patch -- Resolves: rhbz#1839178 (CVE-2020-12662) +* Mon Feb 15 2021 Victor Stinner - 1.13.1-2 +- Fix build on Python 3.10 (rhbz#1889726). -* Mon May 25 2020 Anna Khaitovich - 1.7.3-13 -- Fix two previous patches and add missing patch lines to %%prep -- Fix amplifying an incoming query into a large number of queries directed to a target -- Resolves: rhbz#1839178 (CVE-2020-12662) +* Wed Feb 10 2021 Paul Wouters - 1.13.1-1 +- Resolves rhbz#1860887 unbound-1.13.1 is available +- Fixup unbound.conf -* Tue Apr 21 2020 Anna Khaitovich - 1.7.3-12 -- Remove KSK-2010 from configuration files -- Resolves: rhbz#1665502 -- Replace legacy directory /var/run/ with /run -- Resolves: rhbz#1766463 -- Resolves: rhbz#1805978 -- Fix memory leak when DNS over TLS forwarding is configured -- Resolves: rhbz#1819870 +* Wed Jan 27 2021 Fedora Release Engineering - 1.13.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild -* Thu Apr 16 2020 Artem Egorenkov - 1.7.3-11 -- Resolves bz1818761. unbound crash fixed. +* Thu Dec 10 2020 Petr Menšík - 1.13.0-1 +- Update to 1.13.0 -* Tue Dec 10 2019 Tomas Korbar - 1.7.3-10 -- Secure ipsec mode (#1772061) -- CVE-2019-18934 +* Tue Oct 13 2020 Petr Menšík - 1.12.0-1 +- Update to 1.12.0 (#1860887) -* Tue Dec 10 2019 Tomas Korbar - 1.7.3-9 -- Use pthread_mutex_t locks when dealing with I/O operations (#1775708) +* Tue Sep 15 2020 Petr Menšík - 1.10.1-5 +- Move command line tools to utils subpackage + +* Wed Jul 29 2020 Fedora Release Engineering - 1.10.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Tue Jul 14 2020 Tom Stellard - 1.10.1-3 +- Use make macros +- https://fedoraproject.org/wiki/Changes/UseMakeBuildInstallMacro + +* Fri May 22 2020 Miro Hrončok - 1.10.1-2 +- Rebuilt for Python 3.9 + +* Tue May 19 2020 Paul Wouters - 1.10.1-1 +- Resolves: rhbz#1837279 unbound-1.10.1 is available +- Resolves: rhbz#1837598 CVE-2020-12662 unbound: insufficient control of network message volume leads to DoS +- Resolves: rhbz#1837609 CVE-2020-12663 unbound: infinite loop via malformed DNS answers received from upstream servers +- Updated unbound.conf for new options in 1.10.1 + +* Wed Apr 29 2020 Paul Wouters - 1.10.0-3 +- Resolves: rhbz#1667742 SELinux is preventing unbound from 'name_bind' accesses on the udp_socket port 61000. + +* Thu Apr 16 2020 Artem Egorenkov - 1.10.0-2 +- Resolves: rhbz#1824536 unbound crash + +* Thu Mar 19 2020 Petr Menšík - 1.10.0-1 +- Update to 1.10.0 (#1805199) + +* Fri Jan 31 2020 Fedora Release Engineering - 1.9.6-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Fri Dec 13 2019 Paul Wouters - 1.9.6-1 +- Resolves: rhbz#1758107 unbound-1.9.5 is available +- Resolves: CVE-2019-18934 + +* Fri Nov 01 2019 Paul Wouters - 1.9.4-1 +- Fix build on rhel/centos systems +- Resolves: rhbz#1767955 (CVE-2019-16866) uninitialized memory accesses leads to crash via a crafted NOTIFY query + +* Thu Sep 26 2019 Petr Menšík - 1.9.3-2 +- Obsolete no longer provided python2 subpackage (#1749400) + +* Tue Aug 27 2019 Paul Wouters - 1.9.3-1 +- Updated to 1.9.3 +- Resolves: rhbz#1672578 unbound-1.9.2 is available +- Resolves: rhbz#1694831 [/usr/lib/tmpfiles.d/unbound.conf:1] Line references path below legacy directory /var/run/ +- Resolves: rhbz# 1667387 [abrt] unbound: memmove(): unbound killed by SIGABRT + +* Thu Aug 22 2019 Miro Hrončok - 1.8.3-8 +- Subpackage python2-unbound has been removed + See https://fedoraproject.org/wiki/Changes/Mass_Python_2_Package_Removal + +* Thu Aug 15 2019 Miro Hrončok - 1.8.3-7 +- Rebuilt for Python 3.8 + +* Mon Aug 5 2019 Zbigniew Jędrzejewski-Szmek - 1.8.3-6 +- Drop install-time requirements on systemd (#1723777) + +* Sat Jul 27 2019 Fedora Release Engineering - 1.8.3-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Sun Feb 03 2019 Fedora Release Engineering - 1.8.3-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Fri Jan 11 2019 Paul Wouters - 1.8.3-3 +- Remove KSK-2010 from configs - it has been revoked + +* Wed Dec 12 2018 Paul Wouters - 1.8.3-2 +- Another dns64 fixup + +* Wed Dec 12 2018 Paul Wouters - 1.8.3-1 +- Updated to 1.8.3 with fixes the dns64 bug and has some other minor fixes + +* Mon Dec 10 2018 Paul Wouters - 1.8.2-2 +- Fix dns64 allocation in wrong region for returned internal queries. + +* Tue Dec 04 2018 Paul Wouters - 1.8.2-1 +- Updated to 1.8.2. +- Enabled deny ANY query support and edns-tcp-keepalive +- Set serve-stale timeout to 4h +- Updated unbound.conf for latest options + +* Mon Oct 22 2018 Petr Menšík - 1.8.1-2 +- Allow group by default to unbound-control (#1640259) + +* Mon Oct 08 2018 Petr Menšík - 1.8.1-1 +- Update to 1.8.1 + +* Mon Oct 01 2018 Petr Menšík - 1.8.0-2 +- Skip ipv6 forwarders without ipv6 support (#1633874) + +* Wed Sep 19 2018 Petr Menšík - 1.8.0-1 +- Rebase to 1.8.0 + +* Tue Aug 14 2018 Paul Wouters - 1.7.3-9 +- Fix for restarting unbound service after deleting key/pem files for remote control * Tue Jul 31 2018 Petr Menšík - 1.7.3-8 - Release memory in unbound-host @@ -560,8 +836,16 @@ popd * Wed Jun 27 2018 Petr Menšík - 1.7.2-3 - Remove last python2 dependency from python3 build -* Mon Jun 25 2018 Tomas Hozza - 1.7.0-6 -- Disable Python2 support +* Tue Jun 19 2018 Miro Hrončok - 1.7.2-2 +- Rebuilt for Python 3.7 + +* Mon Jun 11 2018 Paul Wouters - 1.7.2-1 +- Resolves rhbz#1589807 unbound-1.7.2 is available +- Add patch to fix stub/forward zone not returning ServFail when TTL expires +- Enabled the new root-key-sentinel option + +* Wed May 30 2018 Petr Menšík - 1.7.1-1 +- Update to 1.7.1 (#1574495) * Mon Apr 09 2018 Petr Menšík - 1.7.0-5 - Require gcc and make on build @@ -616,7 +900,7 @@ popd * Fri Sep 22 2017 Paul Wouters - 1.6.6-1 - Resolves: rhbz#1483572 unbound-1.6.6 is available -- Resolves: rhbz#1465575 unbound fails to start up, complains about missing ipsecmod-hook (edit) +- Resolves: rhbz#1465575 unbound fails to start up, complains about missing ipsecmod-hook (edit) * Wed Aug 16 2017 Paul Wouters - 1.6.4-4 - Rebuilt with KSK2017 added to root.key and root.anchor @@ -820,7 +1104,7 @@ popd - run test suite during the build * Thu Sep 19 2013 Paul Wouters - 1.4.21-1 -- Updated to 1.4.21, +- Updated to 1.4.21, - Enabled new max-udp-size: 3072 (so ANY isc.org won't fit) - Removed patched merged in by upstream - Enable statistics-cumulative for munin-plugin @@ -943,7 +1227,7 @@ popd - Updated to 1.4.17 (which mostly brings in patches we already applied from svn trunk) -* Wed Feb 29 2012 Paul Wouters - 1.4.16-3 +* Wed Feb 29 2012 Paul Wouters - 1.4.16-3 - Since the daemon links to the libs staticly, add Requires: (this is rhbz#745288) - Package up streamtcp as unbound-streamtcp (for monitoring) @@ -1036,7 +1320,7 @@ popd - Upgraded to 1.4.5 * Mon May 31 2010 Paul Wouters - 1.4.4-2 -- Added accidentally omitted svn patches to cvs +- Added accidentally omitted svn patches to cvs * Mon May 31 2010 Paul Wouters - 1.4.4-1 - Upgraded to 1.4.4 with svn patches @@ -1046,7 +1330,7 @@ popd - Update to 1.4.3 that fixes 64bit crasher * Tue Mar 09 2010 Paul Wouters - 1.4.2-1 -- Updated to 1.4.2 +- Updated to 1.4.2 - Updated unbound.conf with new options - Enabled pre-fetching DNSKEY records (DNSSEC speedup) - Enabled re-fetching popular records before they expire @@ -1195,7 +1479,7 @@ popd causes unbound to listen on 0.0.0.0 instead of 127.0.0.1 * Sun Oct 19 2008 Paul Wouters - 1.0.2-3 -- Split off unbound-libs, make build verbose +- Split off unbound-libs, make build verbose * Thu Oct 9 2008 Paul Wouters - 1.0.2-2 - FSB compliance, chroot fixes, initscript fixes @@ -1218,3 +1502,5 @@ popd * Wed Apr 23 2008 Wouter Wijngaards - 0.11 - Initial version. + +## END: Generated by rpmautospec diff --git a/unbound.sysconfig b/unbound.sysconfig new file mode 100644 index 0000000..adcf8fd --- /dev/null +++ b/unbound.sysconfig @@ -0,0 +1,7 @@ +# uncomment following line to skip anchor refresh before unbound start +#DISABLE_UNBOUND_ANCHOR=yes +# Better way is systemctl mask unbound-anchor.service +UNBOUND_ANCHOR_OPTIONS="-f /etc/resolv.conf -R" + +# for extra debug, add "-v -v" or change verbosity: in unbound.conf +UNBOUND_OPTIONS="" diff --git a/unbound.sysusers b/unbound.sysusers new file mode 100644 index 0000000..6614682 --- /dev/null +++ b/unbound.sysusers @@ -0,0 +1 @@ +u unbound - "Unbound DNS resolver" /var/lib/unbound /sbin/nologin diff --git a/SOURCES/unbound_munin_ b/unbound_munin_ similarity index 100% rename from SOURCES/unbound_munin_ rename to unbound_munin_ diff --git a/wouter.nlnetlabs.nl.key b/wouter.nlnetlabs.nl.key new file mode 100644 index 0000000..603e620 --- /dev/null +++ b/wouter.nlnetlabs.nl.key @@ -0,0 +1,123 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +xsFNBE2v/RwBEACyQpJlpCeSZBV1QUH7jNEp5xGdo6OnX2h9XoZ4ZPsb+u6OT+xE +SH45ncnISUh8rPCygbeWOoPR/yOBzh+lYoGxQ5iUHtwRrhHq04sQe/qFpXDO2xs6 +1pTcPU2PnH7Rsr2qp6fZLPHuXLolD7NJfaSib8sVeMM0/ecyl/L2bBg9NpaGDX0x +TQh95M8o6AFo6UKWApBpgsvEZr2aH/B8b9KnCWFhfJyheEM7DamksdZNsKxXQyq3 +l/ROfdsMLZGF8vPbYV/v11G4keyaLpn8AbBpybIiw9SYDwf2ENk3+e1NFfMaiiyE +qn9+aaLTKCY87TMUuoN3s3jWOOy5tHXzf6DbKhub4Awsby3DH5YpPhi4N2vj2pAX +Vpl5+m78cH29JLzT+HAoyZ4tq1r3m0P5QogNqYwqxkKWYOjDilNDBiKiDdgtrLYG +x+ABovKG/FvToJoaCL4AFaVCzWmL2uHkSgyBN0FPHatCB1UeEkcQit6T8E2NQqmF +WjUMXSWHHajSMG95+L5PdLHz/Ku0o3Csvlt2pkElYZmzJBfnOM9JevdsmKr/ruJC +/DCZAn5w2S/9ZF5qfo2F9HUKIwE/dChR29HcN8V4nqZs9oCvEMfFhHmrfwDc5hed +hvb6mAkvSFFtKIrygLIVeWRj3FE9sGp6sr4VwOLYTFRNk7mAsWD1rZApeQARAQAB +zSdXLkMuQS4gV2lqbmdhYXJkcyA8d291dGVyQG5sbmV0bGFicy5ubD7CwX4EEwEC +ACgFAk2v/RwCGyMFCQlmAYAGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEJ9v +HC1+BF+N3yoQAIynfrvZ/8RNAv9lLcSc2PX3fvG7oRJEJSy9uMyIbMtb/a1BVCeh +XjR8GhHJ5D/Z3jRWBQKw1rLLvOqbuBGkpKMR100ZVF4z/8e6CWtTAOFy28f1JQw2 +8kilN7K6vjno21S1JJ1XJAdoFdicyb1SW2r+KYod6fjSyF0lb71od+sdnSE9O/xd +Cqyyu6cX+AwfDcuJ6Y8iOWu8CeWAz41LR1QBUQkCb/08mVfCEu+Cj+M31jjPDZEy +UAw219vr4QFe0o3t+Msv0AUZvcRkW6+8qP5lO6I5we/33WBLZH70lhFvYtobM7HO +MCjheRZguSzvRqEETfTjia1uVi3Yz2qM4CFdJIZF6Er79yKcB3jYquultrnlHdXZ +/IZsHVRk6JfiqFkz9u1T9PkvMoQ452aUomGTg9xQchnKpe1E8osKgLulaY+izTEq +Z8pH/HWWJ/YT13/n8pxK9EbC/8SkVhyXNehOSAGDZar+tjVBofgzS8r+GDyv+pBT +SmjitIrVXZNuhigLp1o7Tvs4kjKlcFnLhfDHJ+yb5JyiZd01bVvaqnfRhACqXfWl +oC0uslRbegoYwJUgX0BOrsOuHGH2SfGjd/QnA0bcEXM2kp1Dp1gqtcEd5Qitm647 +Yz+leWkhrmMmtTwqumXoAcvgzthJFUPcAzuhXZNfqQJMOGRxAGVI0P97wsF+BBMB +AgAoAhsjBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAUCVu+rZAUJDQIVSAAKCRCf +bxwtfgRfjdrWEACMQK0xYtZtAvLL/8CCcCi92Oi1rtXRGWnRy7JX020hftmWliMq +4P0F3CJKVLhgZ/ldp8OOqmfDfmwLMVSaCQ86Ubqn7Ofrf8Ku8SGQuIMxY2ODB97h +ouY4bnDHaM2Cqi6JkBN+G1tgdwqN/kcecF2tq3ql2k7eX91++A+F5ApIu1silzJP +L4Z8W6MVOdKrtzEM7t61hRlsbpEPj72vbVBZ1hmTiIL4VWwdxQYamxBoOeneskyD +DG+iMCI3P1GG3EQkk+9Aect/iH9uruE0mxn2aKN8cfuoR93cPF/ozCxS5ItwAVnN +e39WRO1GT2zYaFgYm0lf9czcpRsRzNbGw938lZ3iPUiZe+ybKgLKkVmvrkM59ljH +T99SrC14VXxgQwSs4gS3rdzbY9tPps62Z1q+xCVfTx1IY5P4nt59xwQV0Iw+pV9S +/mVcOnPXl1UKb0ttOdYJErrq3RpF/D2g/NDtL0OWqIa8LvrBlyQYmWPKvKw76vt4 +bJ3NU31jSc0ow/j7EOVjOst86s629zmtnbJjWVr6LOy5EDUPusmqHv1t4Z4RMjf8 +OrJdNbFJoRXZv8FbW4NzXeGtMf8k6vKeejpdMH4+eLuoZG7dchU1JccfgqfwWpy0 +ojmb59drJcaQgVC6Jvw9l0TmGPNIsE4UrIWocaFgv4dOKvHA2hcnMDM8rsLBlQQT +AQIAPwIbIwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AWIQTt+qPyyk5usFaBr46f +bxwtfgRfjQUCWaU4BQUJEZjVaQAKCRCfbxwtfgRfjb1YEACjkhtkyZkYURUmSZNL +2IK/Zencv7DZGRfFrzijROFtHbe//H8o2ZhlyiaFSA/dT1ehjsukkR0oFkYadA+q +Ui06WpxGmd/jf8hP4yTUZkwOhQAesWoNmnhKePNaVMKY8DP57bA+N2pdCcGu7gUt +Yzq2JoTAtV+P/PE2w+H9eyBAulv6iUckM5/qvGfJPl8HB9BtgOpGN79otVWO6ebM +4TQ3cZYI9BDQnt9cF2pviex+z1iLZVJ8UeRxSxYhrBKPJioi0Q1OgcKyO56t7Eot +zxKl5TzprgvdX4cdls+lehD8StlE2Xv/TScHvdOhJuVBrn3a3QjZPb4qSsz74leW +5/EIQmozBy+qf8AHcCmTXwb2U7oHOct7cVyS5+bFx+ThpV5OK0rjTH1LMNiuTeAN +46c1y3prjZRpQUlgVwj06q3Zz/fzDyueUS/r4lW4nAf/VNZy/rTS2HYPoZbHZVCt +GpDIfag6fV6V97Pd3zfhTf2wmsJsw9Xhktp/o7rMBRSMhvL4oevOXb0JSG2583Q/ +JnCCceB4NxRRxsgkRYHwdnXN9FnOPSa4NyvF4rzpPksLGZrhvm+lBvzVn/e40Q/K +lxvSlnn2vW/WBM4pBq1jsoJrd/JkTdijZV7mt7HQ2bCLXAPgfZjy7n79WiCQVHg7 +iYnNikiNWR5TR7JcvdkxOdiA/8LBlQQTAQgAPwIbIwYLCQgHAwIGFQgCCQoLBBYC +AwECHgECF4AWIQTt+qPyyk5usFaBr46fbxwtfgRfjQUCXe4JdQUJGaQN2QAKCRCf +bxwtfgRfjQ8gEACe+49aDQHRuZdDHK1VCJKzhb+MvfdIjvl8eQxljpG9Uz5Y17Bx +4SWfuLHCeGlh1m6IOAWeW4g6Wowm1ec1PkVa79TdrkKb0MxfLSat6iDbiuVjDxy2 +bWokW0/cPzJ/FoWDtEC0H9UTAMb5QGBDZUbLuwX7ZjvMkAhH15/hO9Gj4RHoH1RJ +GJALRtZzjtzsJqL53kW/EV59V1T79Nocyx018iw50Jn02mI8wYJZ9HZc5C7D+K59 +vcqLRZgkrJrObw0sEv3YFOBYp/1DemH2nHPMBSKMmN5RAcr32guUjd4BEWf2Q7Ao ++Qnhdi161W0YKCW4JAmOoQ4bQ0wfE9Q5aUIGhUF52L+ac8Hy7dByaCExCA/WTqQQ +/iVPybmpJQhFonWt/fmpxbE2wKThSEOHTO67e5e3JfUb0vNKssyZojao4h1MF5nv +aPNKoybWwKnpNM0ORcyl+aogKwW7E15TEU0TE5//gAsFwRDcCnSEKnksgM0321m1 +7RDfJbCajIv47DHDYE3yvhRZjCJCaw0Gow1sDRWjdOFpmIixD5/vx5uxyqSHPuGA +sXlEvl+Z3Rdc5bQ7pAWu7UNpR3hnJPfg8KL2xqOF75VKG9/NjLE80yj8wdVoCfDv +vizrBtOXnHI49gCMCfNqbGIb5yVhmTdeo7li+Te9hlJ2DrHnujGJlFe+p87BTQRN +r/0cARAApvDKeVLiSazESdTY9KsSWsqoB38pvOsu25M49tEjc5TtY5LwKNckqkeR +lJ83O8dFG7UBVuGwLKaf/6OR/pe24upZ27eOOWW7sXvQNv5aXlOYfF+mjIhUINqj +q4pKDmO1c9J7h5d+auOVfzcgfotg3BVCaKn56ucjiQJ059uUMfgWTvVlibnoJ7de +Zcgt8v7VcLK9jv+P8QJHTIyDzJd+JjdjuHXqC/A37T5G9Z84x8wYrQY6mZmOIYaM +jwIKdgFeN+nLk5henARUz4MTFUW4j9hHpuyAFomDQ93/wkHZ9IEChTxdZnfvsd// +Z45vfcX9dQM+tuR8XCYThVsScI1TnwR46hi5NkfmHo3HVxwB8/owJ+FZDsTNBbJd +7AVy27Xk4L5hLe7BwLDtFMyOp4lOipCM7//mtFB9mTzqnOwiSSyTRlwGUBJkzQFW +Qa0Z6bfYwA6+y1dn19H519GW49irtl+2+W8W4N8oLriIjPvqrQOyaELFcRfV6FfL +i09HPhHVbejOqIEbOtfuN0+mjrrGAwortfTBjfw80N+W90BTvta4K2SyjHcJTkDY +ehfOo/5IMpGtDsOgvsCbDaFRnNJuYtSqQmvWk1KIPIw6CkdJtZa3+q3YA7D7ovOV +H1OBTKNdBjc+X4W8L5R9MCymXWvgiP+52Sv1VIcZmsnCBrwK490AEQEAAcLBZQQY +AQIADwUCTa/9HAIbDAUJCWYBgAAKCRCfbxwtfgRfjTY/D/9+kX8LeqBhwDdwy3ud +V67KmVmytwGMfzBHbAyBdy84X06ip/If/VkjL+2Sv5Uml/cOOzGZT7y/KEt0uXQz +gOZhGP5Y0OREf4kSzfb7tsGu3ZjTp5uJe7HiJr8uqYGfx94TQG/A3x1C7MlxOGmW +DK/Eh/eNVeNd+3yyDEzl2p7a0yUhI8LtzllVrEDX+G4rz+mdDw4tfPDqzRPzPvVt +PfqnfofHP5r2dshGe7+pCTC+o0jHWpaiFkEiIrR3PbZ9tV6+F5LzCUJJP5nepz6C +ShpLHq9ST6qZiw5ZpdznHW0kVl96YxgynJq9Y4dqD/8nOfTzdHhXXEogGvRfcxat +xeZF7YNFhUU2p+CswAjRKCUzZAz0hDAu+dJ+fw4Odx7ii8uiwhEnEHoo8rPETkXw +UK1je4MCzMRSy0Gippzk/oZ7noIml+Njas/UygavUOQm8bcPqGfWeFqvM2C7ZobL +2iV0fX/bhEmQyosiWJ0nHuKdwDYygYs/4LtZLxwiKli/lm6IDz1028j6/98Z81gG +oltXWokTYAPEgcBuhyiSLSQ1wojTVMYt9rPKMBakTzP+0FoWqoNafWOlHovP6iUB +2Igll2ZT3AvrBQ8jAbRbuUl46QpBaKsl+pBo86az0fRkMxv0N4dQv4Q7Z0g71u9N +Tpaq1vtAZOwc0kl3uGNK18PnV8LBZQQYAQIADwIbDAUCVu+raQUJDQIVTQAKCRCf +bxwtfgRfjVnYEACZ1E/FfLDi4vLUd9diImmNN/zWDHxTsO/VG3lt50rSoJM5NGB4 +RlwcbUKhah2fD44FFiIqGIvKD9hRgB51dVRIkaR3ozVtXRBKxJJqWj38wf2FDLtU +XC5/JHYb0sjAc3ad2sA9xEmEBVO1lWK3J6h4gKZiAGlWz3oeOSve3vrTKsBlP0Cu +rUeb4WTVpw4drBJD7cDh8SJ4/Cq76UFx8lW0xR+pHZHcd0/Ir5v5HnnEgbnut4Ix +eY3/CGBfQfSQHylK7ifmPWq+dflC/ZdfHY1V96EHKPM44ZLwiczoY3qp5nkmEc3B +Y6+P8Ch5gddOYaY18wpedarswnpOLQD2Xbsj66Eh0IZuuuZGyfOqJNaWbP33L27e +g35XQNTgyhuZmDyRKL6yAbhU74TXCCvze/kkfqDn2ouCtM8/kqLX1v0+NkBxlhZU +kTTVDyclZtwu6Vypus3+j2Zqk8sXeUZI64sjXpzwOcMZxdl3QuyxMktExWzk9Q5D +YqO+pj/YGt1vp2M0YgSUWNWCvfBcjEPFgaljyqz3BdvR/LYohnXuQL9SWObF+sIF +c9D0w/yORYQcKP5kSWVC/qwFdC61OGeSDnQ/0o0T5PefhYS82gsIrjQ+HIJ7CLUT +k7kBNljvtfpoWegH02feR0kSRoCXA6x+YHT4fmB41pW8S1V5a5dEltA/JMLBfAQY +AQIAJgIbDBYhBO36o/LKTm6wVoGvjp9vHC1+BF+NBQJZpTgKBQkRmNVuAAoJEJ9v +HC1+BF+NyNQP/A3h+cOOkYUxyKpNHdtlIfCn8db5tHXSCbE19Qi7EK1SiK5atjo+ +VoRtB+L01kH6GCx5oZjeIhUdzYFwEUsdCDgwD6r0dKFwKIGa4TFcfnx+Z5B+HZgL +Yc6ac5PEHF1qZVXZH9GSGeNw5h2yyqf4yhvetSN6L2id14m5XXJV5e7NfOgmaSnG +0Z+wQvPSiu+Q00XpENT8HFSTSCjRATjk12rpy6TPeeC52NK1gLhGDRHN0k6m+vm4 +yoC+Nd6iPQpnc+5xs7NDnq2dFuSTp7UTGebzPhhdSQgujEFuYLwzQMZu1h5amtA+ +v9j7BYEJkOMC7bm1PNNA2QQ6QfH8Hf+mJeINyJO8A5KS3ceP+eo3SLR8T0hPzu9g +ZuZ22Hn3DXQh1VNRshaLKgNvoXpL3dQ48d1SFFKhEDpy2HSXUq2fs5rH0uszFGes +G7K6EQRAYRcDrCkt9fdfkvCSxAFw9d+472xThzgKcN+MkOec+SaY+xlVULjEfCWy +RVC8Opam4mTm/XT4mVLxP/qnsy7kEhLoc/ouB+lY/ks06LpZJvCXL6WfA9You1Fi +1Mg7GhSh9JKg6X6E8Trm+N4dxJGut1xbbGmmKXqfi4pej9KlkdeM9t1df/vWKlPa +7Hzd8H0btgJx066wC4yt0ghxtsJXBsCDxWLfzaSRZ2/eP16mHqxDjsQQwsF8BBgB +CAAmAhsMFiEE7fqj8spObrBWga+On28cLX4EX40FAl3uCX0FCRmkDeEACgkQn28c +LX4EX43TQA/+JV8ReMRJCn3Cfqbe5ycFn8p6dIVnJiQuhiEyu5yzdpSkKyzcVFJO +bQcqw7s50FJuLUbxdvbcuGIaoTu7dhBoUXO5tOuIQAsKTfGfgoOgelJm+/q2h645 +EnAVINGbMDXrmo4/UFJkNjUMA6SQi/yiam7N0y58eoDC4sGmBKuN2EW2MoWahlXw +8SS1+Ab9qVBs/RqbSy6f1nJL39aPpPDmvyJOSYtHnNSFlYWVhr0zGAi5rnswlFGr +ECGbHpr5FajUK7zcmtNPbi7F30K48xfF3XnDIeIBcerrEBQMaPUZcBlddGhmSVVJ +ZU/YhR35JNgPnmp33gOuZaRiW9lauZFwsMQBIBkLpJWoUtu8QLkyC0HmJzVRep0/ +s1RkzaJ+1G1BzXTQiXaLaUQWG5h3pcMD8fxY5qp9KbG/+10bY0sRbRBXgS6mz7dd +HaBtg/E8ty2nEB1HDXA9HAHu7KlH9e96sPZjz9C46ZiOXe6ZAOk6wBYts4RG4bCQ +9pGORJ+P2Jr2pz1NZQbs1AhnjJixTsfZfsGZ5lHxGLjIyxtdGB/irLEqNTIMek2y +p4CShmWoZwN0V3aGYMe/rC4tSXG79IeKNwF3Vd5MHtB+hcJG2qztBtKQuW29rbRA +5bNxwTWe8skwOKsxXnP9RC974k0XkPS+VwgmVgNN1ewS/0oHvmEP71Q= +=Oqje +-----END PGP PUBLIC KEY BLOCK-----