unwind(8): update bundled libunbound to 1.9.2

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

unwind(8): update bundled libunbound to 1.9.2

Florian Obser-2

All the heavy lifting was done by sthen while updating unbound,
thanks!

I'll put this in sometimes during the weekend, but tests
would still be welcome.

diff --git libunbound/config.h libunbound/config.h
index 7b0ba84679b..8c7028b6ab9 100644
--- libunbound/config.h
+++ libunbound/config.h
@@ -87,6 +87,10 @@
    if you don't. */
 #define HAVE_DECL_ARC4RANDOM_UNIFORM 1
 
+/* Define to 1 if you have the declaration of `evsignal_assign', and to 0 if
+   you don't. */
+#define HAVE_DECL_EVSIGNAL_ASSIGN 0
+
 /* Define to 1 if you have the declaration of `inet_ntop', and to 0 if you
    don't. */
 #define HAVE_DECL_INET_NTOP 1
@@ -167,6 +171,9 @@
 /* Define to 1 if you have the `ERR_load_crypto_strings' function. */
 #define HAVE_ERR_LOAD_CRYPTO_STRINGS 1
 
+/* Define to 1 if you have the `event_assign' function. */
+/* #undef HAVE_EVENT_ASSIGN */
+
 /* Define to 1 if you have the `event_base_free' function. */
 #define HAVE_EVENT_BASE_FREE 1
 
@@ -407,7 +414,7 @@
 /* Define to 1 if you have the `RAND_cleanup' function. */
 #define HAVE_RAND_CLEANUP 1
 
-/* Define to 1 if you have the `reallocarray' function. */
+/* If we have reallocarray(3) */
 #define HAVE_REALLOCARRAY 1
 
 /* Define to 1 if you have the `recvmsg' function. */
@@ -664,7 +671,7 @@
 #define PACKAGE_NAME "unbound"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "unbound 1.9.1"
+#define PACKAGE_STRING "unbound 1.9.2"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "unbound"
@@ -673,7 +680,7 @@
 #define PACKAGE_URL ""
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "1.9.1"
+#define PACKAGE_VERSION "1.9.2"
 
 /* default pidfile location */
 #define PIDFILE ""
@@ -695,7 +702,7 @@
 #define ROOT_CERT_FILE "/var/unbound/etc/icannbundle.pem"
 
 /* version number for resource files */
-#define RSRC_PACKAGE_VERSION 1,9,1,0
+#define RSRC_PACKAGE_VERSION 1,9,2,0
 
 /* Directory to chdir to */
 #define RUN_DIR "/var/unbound/etc"
@@ -966,8 +973,14 @@
 
 
 
+#ifndef _OPENBSD_SOURCE
+#define _OPENBSD_SOURCE 1
+#endif
+
 #ifndef UNBOUND_DEBUG
+# ifndef NDEBUG
 #  define NDEBUG
+# endif
 #endif
 
 /** Use small-ldns codebase */
diff --git libunbound/iterator/iter_utils.c libunbound/iterator/iter_utils.c
index be7965a60e3..2ab55ceb497 100644
--- libunbound/iterator/iter_utils.c
+++ libunbound/iterator/iter_utils.c
@@ -1211,6 +1211,19 @@ iter_scrub_ds(struct dns_msg* msg, struct ub_packed_rrset_key* ns, uint8_t* z)
  }
 }
 
+void
+iter_scrub_nxdomain(struct dns_msg* msg)
+{
+ if(msg->rep->an_numrrsets == 0)
+ return;
+
+ memmove(msg->rep->rrsets, msg->rep->rrsets+msg->rep->an_numrrsets,
+ sizeof(struct ub_packed_rrset_key*) *
+ (msg->rep->rrset_count-msg->rep->an_numrrsets));
+ msg->rep->rrset_count -= msg->rep->an_numrrsets;
+ msg->rep->an_numrrsets = 0;
+}
+
 void iter_dec_attempts(struct delegpt* dp, int d)
 {
  struct delegpt_addr* a;
diff --git libunbound/iterator/iter_utils.h libunbound/iterator/iter_utils.h
index ccfb280224b..f771930bba2 100644
--- libunbound/iterator/iter_utils.h
+++ libunbound/iterator/iter_utils.h
@@ -334,6 +334,13 @@ int iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd,
 void iter_scrub_ds(struct dns_msg* msg, struct ub_packed_rrset_key* ns,
  uint8_t* z);
 
+/**
+ * Prepare an NXDOMAIN message to be used for a subdomain answer by removing all
+ * RRs from the ANSWER section.
+ * @param msg: the response to scrub.
+ */
+void iter_scrub_nxdomain(struct dns_msg* msg);
+
 /**
  * Remove query attempts from all available ips. For 0x20.
  * @param dp: delegpt.
diff --git libunbound/iterator/iterator.c libunbound/iterator/iterator.c
index c73fb517748..c906c271448 100644
--- libunbound/iterator/iterator.c
+++ libunbound/iterator/iterator.c
@@ -2718,8 +2718,15 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
  && !(iq->chase_flags & BIT_RD)) {
  if(FLAGS_GET_RCODE(iq->response->rep->flags) !=
  LDNS_RCODE_NOERROR) {
- if(qstate->env->cfg->qname_minimisation_strict)
- return final_state(iq);
+ if(qstate->env->cfg->qname_minimisation_strict) {
+ if(FLAGS_GET_RCODE(iq->response->rep->flags) ==
+ LDNS_RCODE_NXDOMAIN) {
+ iter_scrub_nxdomain(iq->response);
+ return final_state(iq);
+ }
+ return error_response(qstate, id,
+ LDNS_RCODE_SERVFAIL);
+ }
  /* Best effort qname-minimisation.
  * Stop minimising and send full query when
  * RCODE is not NOERROR. */
diff --git libunbound/services/authzone.c libunbound/services/authzone.c
index a87c2274fb9..1426f423a1b 100644
--- libunbound/services/authzone.c
+++ libunbound/services/authzone.c
@@ -2042,11 +2042,13 @@ auth_xfer_delete(struct auth_xfer* xfr)
  if(xfr->task_probe) {
  auth_free_masters(xfr->task_probe->masters);
  comm_point_delete(xfr->task_probe->cp);
+ comm_timer_delete(xfr->task_probe->timer);
  free(xfr->task_probe);
  }
  if(xfr->task_transfer) {
  auth_free_masters(xfr->task_transfer->masters);
  comm_point_delete(xfr->task_transfer->cp);
+ comm_timer_delete(xfr->task_transfer->timer);
  if(xfr->task_transfer->chunks_first) {
  auth_chunks_delete(xfr->task_transfer);
  }
@@ -2746,6 +2748,7 @@ az_nsec3_insert(struct auth_zone* z, struct regional* region,
  * that is an exact match that should exist for it.
  * If that does not exist, a higher exact match + nxproof is enabled
  * (for some sort of opt-out empty nonterminal cases).
+ * nodataproof: search for exact match and include that instead.
  * ceproof: include ce proof NSEC3 (omitted for wildcard replies).
  * nxproof: include denial of the qname.
  * wcproof: include denial of wildcard (wildcard.ce).
@@ -2753,7 +2756,8 @@ az_nsec3_insert(struct auth_zone* z, struct regional* region,
 static int
 az_add_nsec3_proof(struct auth_zone* z, struct regional* region,
  struct dns_msg* msg, uint8_t* cenm, size_t cenmlen, uint8_t* qname,
- size_t qname_len, int ceproof, int nxproof, int wcproof)
+ size_t qname_len, int nodataproof, int ceproof, int nxproof,
+ int wcproof)
 {
  int algo;
  size_t iter, saltlen;
@@ -2764,6 +2768,19 @@ az_add_nsec3_proof(struct auth_zone* z, struct regional* region,
  /* find parameters of nsec3 proof */
  if(!az_nsec3_param(z, &algo, &iter, &salt, &saltlen))
  return 1; /* no nsec3 */
+ if(nodataproof) {
+ /* see if the node has a hash of itself for the nodata
+ * proof nsec3, this has to be an exact match nsec3. */
+ struct auth_data* match;
+ match = az_nsec3_find_exact(z, qname, qname_len, algo,
+ iter, salt, saltlen);
+ if(match) {
+ if(!az_nsec3_insert(z, region, msg, match))
+ return 0;
+ /* only nodata NSEC3 needed, no CE or others. */
+ return 1;
+ }
+ }
  /* find ce that has an NSEC3 */
  if(ceproof) {
  node = az_nsec3_find_ce(z, &cenm, &cenmlen, &no_exact_ce,
@@ -2916,7 +2933,7 @@ az_generate_notype_answer(struct auth_zone* z, struct regional* region,
  /* DNSSEC denial NSEC3 */
  if(!az_add_nsec3_proof(z, region, msg, node->name,
  node->namelen, msg->qinfo.qname,
- msg->qinfo.qname_len, 1, 0, 0))
+ msg->qinfo.qname_len, 1, 1, 0, 0))
  return 0;
  }
  return 1;
@@ -2943,7 +2960,7 @@ az_generate_referral_answer(struct auth_zone* z, struct regional* region,
  } else {
  if(!az_add_nsec3_proof(z, region, msg, ce->name,
  ce->namelen, msg->qinfo.qname,
- msg->qinfo.qname_len, 1, 0, 0))
+ msg->qinfo.qname_len, 1, 1, 0, 0))
  return 0;
  }
  }
@@ -2982,6 +2999,7 @@ az_generate_wildcard_answer(struct auth_zone* z, struct query_info* qinfo,
  struct auth_data* wildcard, struct auth_data* node)
 {
  struct auth_rrset* rrset, *nsec;
+ int insert_ce = 0;
  if((rrset=az_domain_rrset(wildcard, qinfo->qtype)) != NULL) {
  /* wildcard has type, add it */
  if(!msg_add_rrset_an(z, region, msg, wildcard, rrset))
@@ -3008,6 +3026,10 @@ az_generate_wildcard_answer(struct auth_zone* z, struct query_info* qinfo,
  /* call other notype routine for dnssec notype denials */
  if(!az_generate_notype_answer(z, region, msg, wildcard))
  return 0;
+ /* because the notype, there is no positive data with an
+ * RRSIG that indicates the wildcard position.  Thus the
+ * wildcard qname denial needs to have a CE nsec3. */
+ insert_ce = 1;
  }
 
  /* ce and node for dnssec denial of wildcard original name */
@@ -3019,7 +3041,7 @@ az_generate_wildcard_answer(struct auth_zone* z, struct query_info* qinfo,
  dname_remove_label(&wildup, &wilduplen);
  if(!az_add_nsec3_proof(z, region, msg, wildup,
  wilduplen, msg->qinfo.qname,
- msg->qinfo.qname_len, 0, 1, 0))
+ msg->qinfo.qname_len, 0, insert_ce, 1, 0))
  return 0;
  }
 
@@ -3045,7 +3067,7 @@ az_generate_nxdomain_answer(struct auth_zone* z, struct regional* region,
  } else if(ce) {
  if(!az_add_nsec3_proof(z, region, msg, ce->name,
  ce->namelen, msg->qinfo.qname,
- msg->qinfo.qname_len, 1, 1, 1))
+ msg->qinfo.qname_len, 0, 1, 1, 1))
  return 0;
  }
  return 1;
@@ -4953,6 +4975,9 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env,
 static void
 xfr_transfer_disown(struct auth_xfer* xfr)
 {
+ /* remove timer (from this worker's event base) */
+ comm_timer_delete(xfr->task_transfer->timer);
+ xfr->task_transfer->timer = NULL;
  /* remove the commpoint */
  comm_point_delete(xfr->task_transfer->cp);
  xfr->task_transfer->cp = NULL;
@@ -5034,6 +5059,9 @@ xfr_transfer_init_fetch(struct auth_xfer* xfr, struct module_env* env)
  struct sockaddr_storage addr;
  socklen_t addrlen = 0;
  struct auth_master* master = xfr->task_transfer->master;
+ char *auth_name = NULL;
+ struct timeval t;
+ int timeout;
  if(!master) return 0;
  if(master->allow_notify) return 0; /* only for notify */
 
@@ -5042,7 +5070,7 @@ xfr_transfer_init_fetch(struct auth_xfer* xfr, struct module_env* env)
  addrlen = xfr->task_transfer->scan_addr->addrlen;
  memmove(&addr, &xfr->task_transfer->scan_addr->addr, addrlen);
  } else {
- if(!extstrtoaddr(master->host, &addr, &addrlen)) {
+ if(!authextstrtoaddr(master->host, &addr, &addrlen, &auth_name)) {
  /* the ones that are not in addr format are supposed
  * to be looked up.  The lookup has failed however,
  * so skip them */
@@ -5059,25 +5087,46 @@ xfr_transfer_init_fetch(struct auth_xfer* xfr, struct module_env* env)
  comm_point_delete(xfr->task_transfer->cp);
  xfr->task_transfer->cp = NULL;
  }
+ if(!xfr->task_transfer->timer) {
+ xfr->task_transfer->timer = comm_timer_create(env->worker_base,
+ auth_xfer_transfer_timer_callback, xfr);
+ if(!xfr->task_transfer->timer) {
+ log_err("malloc failure");
+ return 0;
+ }
+ }
+ timeout = AUTH_TRANSFER_TIMEOUT;
+#ifndef S_SPLINT_S
+        t.tv_sec = timeout/1000;
+        t.tv_usec = (timeout%1000)*1000;
+#endif
 
  if(master->http) {
  /* perform http fetch */
  /* store http port number into sockaddr,
  * unless someone used unbound's host@port notation */
+ xfr->task_transfer->on_ixfr = 0;
  if(strchr(master->host, '@') == NULL)
  sockaddr_store_port(&addr, addrlen, master->port);
  xfr->task_transfer->cp = outnet_comm_point_for_http(
  env->outnet, auth_xfer_transfer_http_callback, xfr,
- &addr, addrlen, AUTH_TRANSFER_TIMEOUT, master->ssl,
- master->host, master->file);
+ &addr, addrlen, -1, master->ssl, master->host,
+ master->file);
  if(!xfr->task_transfer->cp) {
- char zname[255+1];
+ char zname[255+1], as[256];
  dname_str(xfr->name, zname);
+ addr_to_str(&addr, addrlen, as, sizeof(as));
  verbose(VERB_ALGO, "cannot create http cp "
- "connection for %s to %s", zname,
- master->host);
+ "connection for %s to %s", zname, as);
  return 0;
  }
+ comm_timer_set(xfr->task_transfer->timer, &t);
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1], as[256];
+ dname_str(xfr->name, zname);
+ addr_to_str(&addr, addrlen, as, sizeof(as));
+ verbose(VERB_ALGO, "auth zone %s transfer next HTTP fetch from %s started", zname, as);
+ }
  return 1;
  }
 
@@ -5091,14 +5140,24 @@ xfr_transfer_init_fetch(struct auth_xfer* xfr, struct module_env* env)
  /* connect on fd */
  xfr->task_transfer->cp = outnet_comm_point_for_tcp(env->outnet,
  auth_xfer_transfer_tcp_callback, xfr, &addr, addrlen,
- env->scratch_buffer, AUTH_TRANSFER_TIMEOUT);
+ env->scratch_buffer, -1,
+ auth_name != NULL, auth_name);
  if(!xfr->task_transfer->cp) {
- char zname[255+1];
- dname_str(xfr->name, zname);
+ char zname[255+1], as[256];
+ dname_str(xfr->name, zname);
+ addr_to_str(&addr, addrlen, as, sizeof(as));
  verbose(VERB_ALGO, "cannot create tcp cp connection for "
- "xfr %s to %s", zname, master->host);
+ "xfr %s to %s", zname, as);
  return 0;
  }
+ comm_timer_set(xfr->task_transfer->timer, &t);
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1], as[256];
+ dname_str(xfr->name, zname);
+ addr_to_str(&addr, addrlen, as, sizeof(as));
+ verbose(VERB_ALGO, "auth zone %s transfer next %s fetch from %s started", zname,
+ (xfr->task_transfer->on_ixfr?"IXFR":"AXFR"), as);
+ }
  return 1;
 }
 
@@ -5116,6 +5175,11 @@ xfr_transfer_nexttarget_or_end(struct auth_xfer* xfr, struct module_env* env)
  * and we may then get an instant cache response,
  * and that calls the callback just like a full
  * lookup and lookup failures also call callback */
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(xfr->name, zname);
+ verbose(VERB_ALGO, "auth zone %s transfer next target lookup", zname);
+ }
  lock_basic_unlock(&xfr->lock);
  return;
  }
@@ -5134,6 +5198,11 @@ xfr_transfer_nexttarget_or_end(struct auth_xfer* xfr, struct module_env* env)
  /* failed to fetch, next master */
  xfr_transfer_nextmaster(xfr);
  }
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(xfr->name, zname);
+ verbose(VERB_ALGO, "auth zone %s transfer failed, wait", zname);
+ }
 
  /* we failed to fetch the zone, move to wait task
  * use the shorter retry timeout */
@@ -5231,8 +5300,26 @@ void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
  if(answer) {
  xfr_master_add_addrs(xfr->task_transfer->
  lookup_target, answer, wanted_qtype);
+ } else {
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(xfr->name, zname);
+ verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup has nodata", zname, xfr->task_transfer->lookup_target->host, (xfr->task_transfer->lookup_aaaa?"AAAA":"A"));
+ }
+ }
+ } else {
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(xfr->name, zname);
+ verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup has no answer", zname, xfr->task_transfer->lookup_target->host, (xfr->task_transfer->lookup_aaaa?"AAAA":"A"));
  }
  }
+ } else {
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(xfr->name, zname);
+ verbose(VERB_ALGO, "auth zone %s host %s type %s transfer lookup failed", zname, xfr->task_transfer->lookup_target->host, (xfr->task_transfer->lookup_aaaa?"AAAA":"A"));
+ }
  }
  if(xfr->task_transfer->lookup_target->list &&
  xfr->task_transfer->lookup_target == xfr_transfer_current_master(xfr))
@@ -5616,6 +5703,46 @@ process_list_end_transfer(struct auth_xfer* xfr, struct module_env* env)
  xfr_transfer_nexttarget_or_end(xfr, env);
 }
 
+/** callback for the task_transfer timer */
+void
+auth_xfer_transfer_timer_callback(void* arg)
+{
+ struct auth_xfer* xfr = (struct auth_xfer*)arg;
+ struct module_env* env;
+ int gonextonfail = 1;
+ log_assert(xfr->task_transfer);
+ lock_basic_lock(&xfr->lock);
+ env = xfr->task_transfer->env;
+ if(env->outnet->want_to_quit) {
+ lock_basic_unlock(&xfr->lock);
+ return; /* stop on quit */
+ }
+
+ verbose(VERB_ALGO, "xfr stopped, connection timeout to %s",
+ xfr->task_transfer->master->host);
+
+ /* see if IXFR caused the failure, if so, try AXFR */
+ if(xfr->task_transfer->on_ixfr) {
+ xfr->task_transfer->ixfr_possible_timeout_count++;
+ if(xfr->task_transfer->ixfr_possible_timeout_count >=
+ NUM_TIMEOUTS_FALLBACK_IXFR) {
+ verbose(VERB_ALGO, "xfr to %s, fallback "
+ "from IXFR to AXFR (because of timeouts)",
+ xfr->task_transfer->master->host);
+ xfr->task_transfer->ixfr_fail = 1;
+ gonextonfail = 0;
+ }
+ }
+
+ /* delete transferred data from list */
+ auth_chunks_delete(xfr->task_transfer);
+ comm_point_delete(xfr->task_transfer->cp);
+ xfr->task_transfer->cp = NULL;
+ if(gonextonfail)
+ xfr_transfer_nextmaster(xfr);
+ xfr_transfer_nexttarget_or_end(xfr, env);
+}
+
 /** callback for task_transfer tcp connections */
 int
 auth_xfer_transfer_tcp_callback(struct comm_point* c, void* arg, int err,
@@ -5632,6 +5759,8 @@ auth_xfer_transfer_tcp_callback(struct comm_point* c, void* arg, int err,
  lock_basic_unlock(&xfr->lock);
  return 0; /* stop on quit */
  }
+ /* stop the timer */
+ comm_timer_disable(xfr->task_transfer->timer);
 
  if(err != NETEVENT_NOERROR) {
  /* connection failed, closed, or timeout */
@@ -5712,6 +5841,8 @@ auth_xfer_transfer_http_callback(struct comm_point* c, void* arg, int err,
  return 0; /* stop on quit */
  }
  verbose(VERB_ALGO, "auth zone transfer http callback");
+ /* stop the timer */
+ comm_timer_disable(xfr->task_transfer->timer);
 
  if(err != NETEVENT_NOERROR && err != NETEVENT_DONE) {
  /* connection failed, closed, or timeout */
@@ -5809,6 +5940,7 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env,
  struct timeval t;
  /* pick master */
  struct auth_master* master = xfr_probe_current_master(xfr);
+ char *auth_name = NULL;
  if(!master) return 0;
  if(master->allow_notify) return 0; /* only for notify */
  if(master->http) return 0; /* only masters get SOA UDP probe,
@@ -5819,7 +5951,7 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env,
  addrlen = xfr->task_probe->scan_addr->addrlen;
  memmove(&addr, &xfr->task_probe->scan_addr->addr, addrlen);
  } else {
- if(!extstrtoaddr(master->host, &addr, &addrlen)) {
+ if(!authextstrtoaddr(master->host, &addr, &addrlen, &auth_name)) {
  /* the ones that are not in addr format are supposed
  * to be looked up.  The lookup has failed however,
  * so skip them */
@@ -5829,6 +5961,18 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env,
  zname, master->host);
  return 0;
  }
+ if (auth_name != NULL) {
+ if (addr.ss_family == AF_INET
+ &&  ntohs(((struct sockaddr_in *)&addr)->sin_port)
+            == env->cfg->ssl_port)
+ ((struct sockaddr_in *)&addr)->sin_port
+ = htons(env->cfg->port);
+ else if (addr.ss_family == AF_INET6
+ &&  ntohs(((struct sockaddr_in6 *)&addr)->sin6_port)
+            == env->cfg->ssl_port)
+                         ((struct sockaddr_in6 *)&addr)->sin6_port
+ = htons(env->cfg->port);
+ }
  }
 
  /* create packet */
@@ -5838,14 +5982,26 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env,
  xfr->task_probe->id = (uint16_t)(ub_random(env->rnd)&0xffff);
  xfr_create_soa_probe_packet(xfr, env->scratch_buffer,
  xfr->task_probe->id);
+ /* we need to remove the cp if we have a different ip4/ip6 type now */
+ if(xfr->task_probe->cp &&
+ ((xfr->task_probe->cp_is_ip6 && !addr_is_ip6(&addr, addrlen)) ||
+ (!xfr->task_probe->cp_is_ip6 && addr_is_ip6(&addr, addrlen)))
+ ) {
+ comm_point_delete(xfr->task_probe->cp);
+ xfr->task_probe->cp = NULL;
+ }
  if(!xfr->task_probe->cp) {
+ if(addr_is_ip6(&addr, addrlen))
+ xfr->task_probe->cp_is_ip6 = 1;
+ else xfr->task_probe->cp_is_ip6 = 0;
  xfr->task_probe->cp = outnet_comm_point_for_udp(env->outnet,
  auth_xfer_probe_udp_callback, xfr, &addr, addrlen);
  if(!xfr->task_probe->cp) {
- char zname[255+1];
+ char zname[255+1], as[256];
  dname_str(xfr->name, zname);
+ addr_to_str(&addr, addrlen, as, sizeof(as));
  verbose(VERB_ALGO, "cannot create udp cp for "
- "probe %s to %s", zname, master->host);
+ "probe %s to %s", zname, as);
  return 0;
  }
  }
@@ -5861,12 +6017,20 @@ xfr_probe_send_probe(struct auth_xfer* xfr, struct module_env* env,
  /* send udp packet */
  if(!comm_point_send_udp_msg(xfr->task_probe->cp, env->scratch_buffer,
  (struct sockaddr*)&addr, addrlen)) {
- char zname[255+1];
+ char zname[255+1], as[256];
  dname_str(xfr->name, zname);
+ addr_to_str(&addr, addrlen, as, sizeof(as));
  verbose(VERB_ALGO, "failed to send soa probe for %s to %s",
- zname, master->host);
+ zname, as);
  return 0;
  }
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1], as[256];
+ dname_str(xfr->name, zname);
+ addr_to_str(&addr, addrlen, as, sizeof(as));
+ verbose(VERB_ALGO, "auth zone %s soa probe sent to %s", zname,
+ as);
+ }
  xfr->task_probe->timeout = timeout;
 #ifndef S_SPLINT_S
  t.tv_sec = timeout/1000;
@@ -5891,6 +6055,11 @@ auth_xfer_probe_timer_callback(void* arg)
  return; /* stop on quit */
  }
 
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(xfr->name, zname);
+ verbose(VERB_ALGO, "auth zone %s soa probe timeout", zname);
+ }
  if(xfr->task_probe->timeout <= AUTH_PROBE_TIMEOUT_STOP) {
  /* try again with bigger timeout */
  if(xfr_probe_send_probe(xfr, env, xfr->task_probe->timeout*2)) {
@@ -6078,6 +6247,11 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env)
  * and we may then get an instant cache response,
  * and that calls the callback just like a full
  * lookup and lookup failures also call callback */
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(xfr->name, zname);
+ verbose(VERB_ALGO, "auth zone %s probe next target lookup", zname);
+ }
  lock_basic_unlock(&xfr->lock);
  return;
  }
@@ -6086,9 +6260,19 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env)
  /* probe of list has ended.  Create or refresh the list of of
  * allow_notify addrs */
  probe_copy_masters_for_allow_notify(xfr);
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(xfr->name, zname);
+ verbose(VERB_ALGO, "auth zone %s probe: notify addrs updated", zname);
+ }
  if(xfr->task_probe->only_lookup) {
  /* only wanted lookups for copy, stop probe and start wait */
  xfr->task_probe->only_lookup = 0;
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(xfr->name, zname);
+ verbose(VERB_ALGO, "auth zone %s probe: finished only_lookup", zname);
+ }
  xfr_probe_disown(xfr);
  if(xfr->task_nextprobe->worker == NULL)
  xfr_set_timeout(xfr, env, 0, 0);
@@ -6110,13 +6294,22 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env)
  /* done with probe sequence, wait */
  if(xfr->task_probe->have_new_lease) {
  /* if zone not updated, start the wait timer again */
- verbose(VERB_ALGO, "auth_zone unchanged, new lease, wait");
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(xfr->name, zname);
+ verbose(VERB_ALGO, "auth_zone %s unchanged, new lease, wait", zname);
+ }
  xfr_probe_disown(xfr);
  if(xfr->have_zone)
  xfr->lease_time = *env->now;
  if(xfr->task_nextprobe->worker == NULL)
  xfr_set_timeout(xfr, env, 0, 0);
  } else {
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(xfr->name, zname);
+ verbose(VERB_ALGO, "auth zone %s soa probe failed, wait to retry", zname);
+ }
  /* we failed to send this as well, move to the wait task,
  * use the shorter retry timeout */
  xfr_probe_disown(xfr);
@@ -6161,7 +6354,25 @@ void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
  if(answer) {
  xfr_master_add_addrs(xfr->task_probe->
  lookup_target, answer, wanted_qtype);
+ } else {
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(xfr->name, zname);
+ verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup has nodata", zname, xfr->task_probe->lookup_target->host, (xfr->task_probe->lookup_aaaa?"AAAA":"A"));
+ }
  }
+ } else {
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(xfr->name, zname);
+ verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup has no address", zname, xfr->task_probe->lookup_target->host, (xfr->task_probe->lookup_aaaa?"AAAA":"A"));
+ }
+ }
+ } else {
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(xfr->name, zname);
+ verbose(VERB_ALGO, "auth zone %s host %s type %s probe lookup failed", zname, xfr->task_probe->lookup_target->host, (xfr->task_probe->lookup_aaaa?"AAAA":"A"));
  }
  }
  if(xfr->task_probe->lookup_target->list &&
diff --git libunbound/services/authzone.h libunbound/services/authzone.h
index 4706803a86b..a695bd029b5 100644
--- libunbound/services/authzone.h
+++ libunbound/services/authzone.h
@@ -327,6 +327,8 @@ struct auth_probe {
  /** the SOA probe udp event.
  * on the workers event base. */
  struct comm_point* cp;
+ /** is the cp for ip6 or ip4 */
+ int cp_is_ip6;
  /** timeout for packets.
  * on the workers event base. */
  struct comm_timer* timer;
@@ -398,6 +400,9 @@ struct auth_transfer {
  /** the transfer (TCP) to the master.
  * on the workers event base. */
  struct comm_point* cp;
+ /** timeout for the transfer.
+ * on the workers event base. */
+ struct comm_timer* timer;
 };
 
 /** list of addresses */
@@ -647,6 +652,8 @@ int auth_xfer_transfer_http_callback(struct comm_point* c, void* arg, int err,
         struct comm_reply* repinfo);
 /** xfer probe timeout callback, part of task_probe */
 void auth_xfer_probe_timer_callback(void* arg);
+/** xfer transfer timeout callback, part of task_transfer */
+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,
diff --git libunbound/services/cache/dns.c libunbound/services/cache/dns.c
index 47611ac5aef..aa4efec73f4 100644
--- libunbound/services/cache/dns.c
+++ libunbound/services/cache/dns.c
@@ -40,6 +40,7 @@
  */
 #include "config.h"
 #include "iterator/iter_delegpt.h"
+#include "iterator/iter_utils.h"
 #include "validator/val_nsec.h"
 #include "validator/val_utils.h"
 #include "services/cache/dns.h"
@@ -728,6 +729,8 @@ fill_any(struct module_env* env,
  if(!msg) {
  return NULL;
  }
+ /* set NOTIMPL for RFC 8482 */
+ msg->rep->flags |= LDNS_RCODE_NOTIMPL;
  msg->rep->security = sec_status_indeterminate;
  return msg;
  }
@@ -912,12 +915,15 @@ dns_cache_lookup(struct module_env* env,
  struct dns_msg* msg;
  if(FLAGS_GET_RCODE(data->flags) == LDNS_RCODE_NXDOMAIN
   && data->security == sec_status_secure
+  && (data->an_numrrsets == 0 ||
+ ntohs(data->rrsets[0]->rk.type) != LDNS_RR_TYPE_CNAME)
   && (msg=tomsg(env, &k, data, region, now, scratch))){
  lock_rw_unlock(&e->lock);
  msg->qinfo.qname=qname;
  msg->qinfo.qname_len=qnamelen;
  /* check that DNSSEC really works out */
  msg->rep->security = sec_status_unchecked;
+ iter_scrub_nxdomain(msg);
  return msg;
  }
  lock_rw_unlock(&e->lock);
diff --git libunbound/services/listen_dnsport.c libunbound/services/listen_dnsport.c
index e74d1abcffc..7e2afd843be 100644
--- libunbound/services/listen_dnsport.c
+++ libunbound/services/listen_dnsport.c
@@ -851,13 +851,16 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
 #ifdef ENOPROTOOPT
  /* squelch ENOPROTOOPT: freebsd server mode with kernel support
    disabled, except when verbosity enabled for debugging */
- if(errno != ENOPROTOOPT || verbosity >= 3)
+ if(errno != ENOPROTOOPT || verbosity >= 3) {
 #endif
   if(errno == EPERM) {
    log_warn("Setting TCP Fast Open as server failed: %s ; this could likely be because sysctl net.inet.tcp.fastopen.enabled, net.inet.tcp.fastopen.server_enable, or net.ipv4.tcp_fastopen is disabled", strerror(errno));
   } else {
    log_err("Setting TCP Fast Open as server failed: %s", strerror(errno));
   }
+#ifdef ENOPROTOOPT
+ }
+#endif
  }
 #endif
  return s;
@@ -1749,6 +1752,7 @@ tcp_req_info_handle_readdone(struct tcp_req_info* req)
  req->is_drop = 0;
  req->is_reply = 0;
  req->in_worker_handle = 1;
+ sldns_buffer_set_limit(req->spool_buffer, 0);
  /* handle the current request */
  /* this calls the worker handle request routine that could give
  * a cache response, or localdata response, or drop the reply,
@@ -1771,24 +1775,12 @@ tcp_req_info_handle_readdone(struct tcp_req_info* req)
  * If mesh failed to add a new entry and called commpoint_drop_reply.
  * Then the mesh state has been cleared. */
  if(req->is_drop) {
- /* we can now call drop_reply without recursing into ourselves
- * whilst in the callback */
- /* we have to close the stream because there is no reply,
- * no servfail to send, but the query needs an action, for
- * a stream that is close the connection */
- sldns_buffer_clear(c->buffer);
- comm_point_drop_reply(&c->repinfo);
+ /* the reply has been dropped, stream has been closed. */
  return;
  }
  /* If mesh failed(mallocfail) and called commpoint_send_reply with
  * something like servfail then we pick up that reply below. */
  if(req->is_reply) {
- /* reply from mesh is in the spool_buffer */
- sldns_buffer_clear(c->buffer);
- sldns_buffer_write(c->buffer,
- sldns_buffer_begin(req->spool_buffer),
- sldns_buffer_limit(req->spool_buffer));
- sldns_buffer_flip(c->buffer);
  goto send_it;
  }
 
@@ -1867,7 +1859,14 @@ void
 tcp_req_info_send_reply(struct tcp_req_info* req)
 {
  if(req->in_worker_handle) {
- /* It is in the right buffer to answer straight away */
+ /* reply from mesh is in the spool_buffer */
+ /* copy now, so that the spool buffer is free for other tasks
+ * before the callback is done */
+ sldns_buffer_clear(req->cp->buffer);
+ sldns_buffer_write(req->cp->buffer,
+ sldns_buffer_begin(req->spool_buffer),
+ sldns_buffer_limit(req->spool_buffer));
+ sldns_buffer_flip(req->cp->buffer);
  req->is_reply = 1;
  return;
  }
diff --git libunbound/services/mesh.c libunbound/services/mesh.c
index bee0f76a4ad..59ee9a08ec0 100644
--- libunbound/services/mesh.c
+++ libunbound/services/mesh.c
@@ -354,6 +354,10 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
  int was_detached = 0;
  int was_noreply = 0;
  int added = 0;
+ struct sldns_buffer* r_buffer = rep->c->buffer;
+ if(rep->c->tcp_req_info) {
+ r_buffer = rep->c->tcp_req_info->spool_buffer;
+ }
  if(!unique)
  s = mesh_area_find(mesh, cinfo, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
  /* does this create a new reply state? */
@@ -389,7 +393,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
  if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL,
  LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
  edns->opt_list = NULL;
- error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
+ error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
  qinfo, qid, qflags, edns);
  comm_point_send_reply(rep);
  return;
@@ -405,7 +409,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
  if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL,
  NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
  edns->opt_list = NULL;
- error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
+ error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
  qinfo, qid, qflags, edns);
  comm_point_send_reply(rep);
  return;
@@ -434,7 +438,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
  if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s,
  NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
  edns->opt_list = NULL;
- error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
+ error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
  qinfo, qid, qflags, edns);
  comm_point_send_reply(rep);
  if(added)
@@ -1192,12 +1196,16 @@ void mesh_query_done(struct mesh_state* mstate)
  comm_point_drop_reply(&r->query_reply);
  else {
  struct sldns_buffer* r_buffer = r->query_reply.c->buffer;
- if(r->query_reply.c->tcp_req_info)
+ if(r->query_reply.c->tcp_req_info) {
  r_buffer = r->query_reply.c->tcp_req_info->spool_buffer;
+ prev_buffer = NULL;
+ }
  mesh_send_reply(mstate, mstate->s.return_rcode, rep,
  r, r_buffer, prev, prev_buffer);
- if(r->query_reply.c->tcp_req_info)
+ if(r->query_reply.c->tcp_req_info) {
  tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate);
+ r_buffer = NULL;
+ }
  prev = r;
  prev_buffer = r_buffer;
  }
@@ -1341,21 +1349,14 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
  log_assert(qinfo->local_alias->rrset->rk.dname ==
  sldns_buffer_at(rep->c->buffer, LDNS_HEADER_SIZE));
 
- d = regional_alloc_init(s->s.region, dsrc,
- sizeof(struct packed_rrset_data)
- + sizeof(size_t) + sizeof(uint8_t*) + sizeof(time_t));
+ /* the rrset is not packed, like in the cache, but it is
+ * individualy allocated with an allocator from localzone. */
+ d = regional_alloc_zero(s->s.region, sizeof(*d));
  if(!d)
  return 0;
  r->local_alias->rrset->entry.data = d;
- d->rr_len = (size_t*)((uint8_t*)d +
- sizeof(struct packed_rrset_data));
- d->rr_data = (uint8_t**)&(d->rr_len[1]);
- d->rr_ttl = (time_t*)&(d->rr_data[1]);
- d->rr_len[0] = dsrc->rr_len[0];
- d->rr_ttl[0] = dsrc->rr_ttl[0];
- d->rr_data[0] = regional_alloc_init(s->s.region,
- dsrc->rr_data[0], d->rr_len[0]);
- if(!d->rr_data[0])
+ if(!rrset_insert_rr(s->s.region, d, dsrc->rr_data[0],
+ dsrc->rr_len[0], dsrc->rr_ttl[0], "CNAME local alias"))
  return 0;
  } else
  r->local_alias = NULL;
diff --git libunbound/services/outside_network.c libunbound/services/outside_network.c
index 16d63df4395..0323f1b30c9 100644
--- libunbound/services/outside_network.c
+++ libunbound/services/outside_network.c
@@ -364,6 +364,8 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len)
  comm_point_close(pend->c);
  return 0;
  }
+ verbose(VERB_ALGO, "the query is using TLS encryption, for %s",
+ (w->tls_auth_name?w->tls_auth_name:"an unauthenticated connection"));
 #ifdef USE_WINSOCK
  comm_point_tcp_win_bio_cb(pend->c, pend->c->ssl);
 #endif
@@ -404,6 +406,8 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len)
  }
  SSL_set_verify(pend->c->ssl, SSL_VERIFY_PEER, NULL);
  }
+#else
+ verbose(VERB_ALGO, "the query has an auth_name, but libssl has no call to perform TLS authentication");
 #endif /* HAVE_SSL_SET1_HOST */
  }
  w->pkt = NULL;
@@ -2277,11 +2281,60 @@ outnet_comm_point_for_udp(struct outside_network* outnet,
  return cp;
 }
 
+/** setup SSL for comm point */
+static int
+setup_comm_ssl(struct comm_point* cp, struct outside_network* outnet,
+ int fd, char* host)
+{
+ cp->ssl = outgoing_ssl_fd(outnet->sslctx, fd);
+ if(!cp->ssl) {
+ log_err("cannot create SSL object");
+ return 0;
+ }
+#ifdef USE_WINSOCK
+ comm_point_tcp_win_bio_cb(cp, cp->ssl);
+#endif
+ cp->ssl_shake_state = comm_ssl_shake_write;
+ /* https verification */
+#ifdef HAVE_SSL_SET1_HOST
+ if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) {
+ /* because we set SSL_VERIFY_PEER, in netevent in
+ * ssl_handshake, it'll check if the certificate
+ * verification has succeeded */
+ /* SSL_VERIFY_PEER is set on the sslctx */
+ /* and the certificates to verify with are loaded into
+ * it with SSL_load_verify_locations or
+ * SSL_CTX_set_default_verify_paths */
+ /* setting the hostname makes openssl verify the
+ * host name in the x509 certificate in the
+ * SSL connection*/
+ if(!SSL_set1_host(cp->ssl, host)) {
+ log_err("SSL_set1_host failed");
+ return 0;
+ }
+ }
+#elif defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
+ /* openssl 1.0.2 has this function that can be used for
+ * set1_host like verification */
+ if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) {
+ X509_VERIFY_PARAM* param = SSL_get0_param(cp->ssl);
+ X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
+ if(!X509_VERIFY_PARAM_set1_host(param, host, strlen(host))) {
+ log_err("X509_VERIFY_PARAM_set1_host failed");
+ return 0;
+ }
+ }
+#else
+ (void)host;
+#endif /* HAVE_SSL_SET1_HOST */
+ return 1;
+}
+
 struct comm_point*
 outnet_comm_point_for_tcp(struct outside_network* outnet,
  comm_point_callback_type* cb, void* cb_arg,
  struct sockaddr_storage* to_addr, socklen_t to_addrlen,
- sldns_buffer* query, int timeout)
+ sldns_buffer* query, int timeout, int ssl, char* host)
 {
  struct comm_point* cp;
  int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss);
@@ -2301,6 +2354,16 @@ outnet_comm_point_for_tcp(struct outside_network* outnet,
  }
  cp->repinfo.addrlen = to_addrlen;
  memcpy(&cp->repinfo.addr, to_addr, to_addrlen);
+
+ /* setup for SSL (if needed) */
+ if(ssl) {
+ if(!setup_comm_ssl(cp, outnet, fd, host)) {
+ log_err("cannot setup XoT");
+ comm_point_delete(cp);
+ return NULL;
+ }
+ }
+
  /* set timeout on TCP connection */
  comm_point_start_listening(cp, fd, timeout);
  /* copy scratch buffer to cp->buffer */
@@ -2357,48 +2420,11 @@ outnet_comm_point_for_http(struct outside_network* outnet,
 
  /* setup for SSL (if needed) */
  if(ssl) {
- cp->ssl = outgoing_ssl_fd(outnet->sslctx, fd);
- if(!cp->ssl) {
+ if(!setup_comm_ssl(cp, outnet, fd, host)) {
  log_err("cannot setup https");
  comm_point_delete(cp);
  return NULL;
  }
-#ifdef USE_WINSOCK
- comm_point_tcp_win_bio_cb(cp, cp->ssl);
-#endif
- cp->ssl_shake_state = comm_ssl_shake_write;
- /* https verification */
-#ifdef HAVE_SSL_SET1_HOST
- if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) {
- /* because we set SSL_VERIFY_PEER, in netevent in
- * ssl_handshake, it'll check if the certificate
- * verification has succeeded */
- /* SSL_VERIFY_PEER is set on the sslctx */
- /* and the certificates to verify with are loaded into
- * it with SSL_load_verify_locations or
- * SSL_CTX_set_default_verify_paths */
- /* setting the hostname makes openssl verify the
- * host name in the x509 certificate in the
- * SSL connection*/
- if(!SSL_set1_host(cp->ssl, host)) {
- log_err("SSL_set1_host failed");
- comm_point_delete(cp);
- return NULL;
- }
- }
-#elif defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
- /* openssl 1.0.2 has this function that can be used for
- * set1_host like verification */
- if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) {
- X509_VERIFY_PARAM* param = SSL_get0_param(cp->ssl);
- X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
- if(!X509_VERIFY_PARAM_set1_host(param, host, strlen(host))) {
- log_err("X509_VERIFY_PARAM_set1_host failed");
- comm_point_delete(cp);
- return NULL;
- }
- }
-#endif /* HAVE_SSL_SET1_HOST */
  }
 
  /* set timeout on TCP connection */
diff --git libunbound/services/outside_network.h libunbound/services/outside_network.h
index 48ef03edba7..3456a3da38b 100644
--- libunbound/services/outside_network.h
+++ libunbound/services/outside_network.h
@@ -570,12 +570,14 @@ struct comm_point* outnet_comm_point_for_udp(struct outside_network* outnet,
  * @param timeout: timeout for the TCP connection.
  * timeout in milliseconds, or -1 for no (change to the) timeout.
  * So seconds*1000.
+ * @param ssl: set to true for TLS.
+ * @param host: hostname for host name verification of TLS (or NULL if no TLS).
  * @return tcp_out commpoint, or NULL.
  */
 struct comm_point* outnet_comm_point_for_tcp(struct outside_network* outnet,
  comm_point_callback_type* cb, void* cb_arg,
  struct sockaddr_storage* to_addr, socklen_t to_addrlen,
- struct sldns_buffer* query, int timeout);
+ struct sldns_buffer* query, int timeout, int ssl, char* host);
 
 /**
  * Create http commpoint suitable for communication to the destination.
diff --git libunbound/util/alloc.c libunbound/util/alloc.c
index 908b1f42361..7e9618931ca 100644
--- libunbound/util/alloc.c
+++ libunbound/util/alloc.c
@@ -376,6 +376,7 @@ void *unbound_stat_malloc(size_t size)
 {
  void* res;
  if(size == 0) size = 1;
+ log_assert(size <= SIZE_MAX-16);
  res = malloc(size+16);
  if(!res) return NULL;
  unbound_mem_alloc += size;
@@ -398,6 +399,7 @@ void *unbound_stat_calloc(size_t nmemb, size_t size)
  if(nmemb != 0 && INT_MAX/nmemb < size)
  return NULL; /* integer overflow check */
  s = (nmemb*size==0)?(size_t)1:nmemb*size;
+ log_assert(s <= SIZE_MAX-16);
  res = calloc(1, s+16);
  if(!res) return NULL;
  log_info("stat %p=calloc(%u, %u)", res+16, (unsigned)nmemb, (unsigned)size);
@@ -447,6 +449,7 @@ void *unbound_stat_realloc(void *ptr, size_t size)
  /* nothing changes */
  return ptr;
  }
+ log_assert(size <= SIZE_MAX-16);
  res = malloc(size+16);
  if(!res) return NULL;
  unbound_mem_alloc += size;
@@ -521,7 +524,9 @@ void *unbound_stat_malloc_lite(size_t size, const char* file, int line,
         const char* func)
 {
  /*  [prefix .. len .. actual data .. suffix] */
- void* res = malloc(size+lite_pad*2+sizeof(size_t));
+ void* res;
+ log_assert(size <= SIZE_MAX-(lite_pad*2+sizeof(size_t)));
+ res = malloc(size+lite_pad*2+sizeof(size_t));
  if(!res) return NULL;
  memmove(res, lite_pre, lite_pad);
  memmove(res+lite_pad, &size, sizeof(size_t));
@@ -538,6 +543,7 @@ void *unbound_stat_calloc_lite(size_t nmemb, size_t size, const char* file,
  if(nmemb != 0 && INT_MAX/nmemb < size)
  return NULL; /* integer overflow check */
  req = nmemb * size;
+ log_assert(req <= SIZE_MAX-(lite_pad*2+sizeof(size_t)));
  res = malloc(req+lite_pad*2+sizeof(size_t));
  if(!res) return NULL;
  memmove(res, lite_pre, lite_pad);
diff --git libunbound/util/data/msgreply.h libunbound/util/data/msgreply.h
index a455c4d2b37..8d75f9b12f3 100644
--- libunbound/util/data/msgreply.h
+++ libunbound/util/data/msgreply.h
@@ -157,7 +157,7 @@ struct reply_info {
  time_t prefetch_ttl;
 
  /**
- * Reply TTL extended with serve exipred TTL, to limit time to serve
+ * Reply TTL extended with serve expired TTL, to limit time to serve
  * expired message.
  */
  time_t serve_expired_ttl;
diff --git libunbound/util/fptr_wlist.c libunbound/util/fptr_wlist.c
index 02f85e8dc4a..94d23fa3a32 100644
--- libunbound/util/fptr_wlist.c
+++ libunbound/util/fptr_wlist.c
@@ -127,6 +127,7 @@ fptr_whitelist_comm_timer(void (*fptr)(void*))
 #endif
  else if(fptr == &auth_xfer_timer) return 1;
  else if(fptr == &auth_xfer_probe_timer_callback) return 1;
+ else if(fptr == &auth_xfer_transfer_timer_callback) return 1;
  return 0;
 }
 
diff --git libunbound/util/iana_ports.inc libunbound/util/iana_ports.inc
index 5ead47f0f66..aa972a67bd5 100644
--- libunbound/util/iana_ports.inc
+++ libunbound/util/iana_ports.inc
@@ -4768,6 +4768,7 @@
 8088,
 8097,
 8100,
+8111,
 8115,
 8116,
 8118,
@@ -4864,6 +4865,7 @@
 8805,
 8807,
 8808,
+8809,
 8873,
 8880,
 8883,
diff --git libunbound/util/net_help.c libunbound/util/net_help.c
index 2b1be92460b..13bcdf8085b 100644
--- libunbound/util/net_help.c
+++ libunbound/util/net_help.c
@@ -802,6 +802,16 @@ void* listen_sslctx_create(char* key, char* pem, char* verifypem)
  log_crypto_err("could not SSL_CTX_new");
  return NULL;
  }
+ if(!key || key[0] == 0) {
+ log_err("error: no tls-service-key file specified");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ if(!pem || pem[0] == 0) {
+ log_err("error: no tls-service-pem file specified");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
  if(!listen_sslctx_setup(ctx)) {
  SSL_CTX_free(ctx);
  return NULL;
@@ -1235,7 +1245,12 @@ listen_sslctx_delete_ticket_keys(void)
  struct tls_session_ticket_key *key;
  if(!ticket_keys) return;
  for(key = ticket_keys; key->key_name != NULL; key++) {
- memset(key->key_name, 0xdd, 80); /* wipe key data from memory*/
+ /* wipe key data from memory*/
+#ifdef HAVE_EXPLICIT_BZERO
+ explicit_bzero(key->key_name, 80);
+#else
+ memset(key->key_name, 0xdd, 80);
+#endif
  free(key->key_name);
  }
  free(ticket_keys);
diff --git libunbound/util/netevent.c libunbound/util/netevent.c
index f33e44058b1..9e2ba92b5fd 100644
--- libunbound/util/netevent.c
+++ libunbound/util/netevent.c
@@ -178,7 +178,7 @@ comm_base_create(int sigs)
  }
  ub_comm_base_now(b);
  ub_get_event_sys(b->eb->base, &evnm, &evsys, &evmethod);
- verbose(VERB_ALGO, "%s %s user %s method.", evnm, evsys, evmethod);
+ verbose(VERB_ALGO, "%s %s uses %s method.", evnm, evsys, evmethod);
  return b;
 }
 
@@ -926,6 +926,14 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg)
  }
  /* accept incoming connection. */
  c_hdl = c->tcp_free;
+ /* clear leftover flags from previous use, and then set the
+ * correct event base for the event structure for libevent */
+ ub_event_free(c_hdl->ev->ev);
+ c_hdl->ev->ev = ub_event_new(c_hdl->ev->base->eb->base, -1, UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT, comm_point_tcp_handle_callback, c_hdl);
+ if(!c_hdl->ev->ev) {
+ log_warn("could not ub_event_new, dropped tcp");
+ return;
+ }
  log_assert(fd != -1);
  (void)fd;
  new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.addr,
@@ -1184,6 +1192,10 @@ ssl_handle_read(struct comm_point* c)
  comm_point_listen_for_rw(c, 0, 1);
  return 1;
  } else if(want == SSL_ERROR_SYSCALL) {
+#ifdef ECONNRESET
+ if(errno == ECONNRESET && verbosity < 2)
+ return 0; /* silence reset by peer */
+#endif
  if(errno != 0)
  log_err("SSL_read syscall: %s",
  strerror(errno));
@@ -1228,6 +1240,10 @@ ssl_handle_read(struct comm_point* c)
  comm_point_listen_for_rw(c, 0, 1);
  return 1;
  } else if(want == SSL_ERROR_SYSCALL) {
+#ifdef ECONNRESET
+ if(errno == ECONNRESET && verbosity < 2)
+ return 0; /* silence reset by peer */
+#endif
  if(errno != 0)
  log_err("SSL_read syscall: %s",
  strerror(errno));
@@ -1288,13 +1304,17 @@ ssl_handle_write(struct comm_point* c)
  if(want == SSL_ERROR_ZERO_RETURN) {
  return 0; /* closed */
  } else if(want == SSL_ERROR_WANT_READ) {
- c->ssl_shake_state = comm_ssl_shake_read;
+ c->ssl_shake_state = comm_ssl_shake_hs_read;
  comm_point_listen_for_rw(c, 1, 0);
  return 1; /* wait for read condition */
  } else if(want == SSL_ERROR_WANT_WRITE) {
  ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
  return 1; /* write more later */
  } else if(want == SSL_ERROR_SYSCALL) {
+#ifdef EPIPE
+ if(errno == EPIPE && verbosity < 2)
+ return 0; /* silence 'broken pipe' */
+#endif
  if(errno != 0)
  log_err("SSL_write syscall: %s",
  strerror(errno));
@@ -1322,13 +1342,17 @@ ssl_handle_write(struct comm_point* c)
  if(want == SSL_ERROR_ZERO_RETURN) {
  return 0; /* closed */
  } else if(want == SSL_ERROR_WANT_READ) {
- c->ssl_shake_state = comm_ssl_shake_read;
+ c->ssl_shake_state = comm_ssl_shake_hs_read;
  comm_point_listen_for_rw(c, 1, 0);
  return 1; /* wait for read condition */
  } else if(want == SSL_ERROR_WANT_WRITE) {
  ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
  return 1; /* write more later */
  } else if(want == SSL_ERROR_SYSCALL) {
+#ifdef EPIPE
+ if(errno == EPIPE && verbosity < 2)
+ return 0; /* silence 'broken pipe' */
+#endif
  if(errno != 0)
  log_err("SSL_write syscall: %s",
  strerror(errno));
@@ -1543,7 +1567,6 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
  iov[1].iov_base = sldns_buffer_begin(buffer);
  iov[1].iov_len = sldns_buffer_limit(buffer);
  log_assert(iov[0].iov_len > 0);
- log_assert(iov[1].iov_len > 0);
  msg.msg_name = &c->repinfo.addr;
  msg.msg_namelen = c->repinfo.addrlen;
  msg.msg_iov = iov;
@@ -1610,7 +1633,6 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
  iov[1].iov_base = sldns_buffer_begin(buffer);
  iov[1].iov_len = sldns_buffer_limit(buffer);
  log_assert(iov[0].iov_len > 0);
- log_assert(iov[1].iov_len > 0);
  r = writev(fd, iov, 2);
 #else /* HAVE_WRITEV */
  r = send(fd, (void*)(((uint8_t*)&len)+c->tcp_byte_count),
@@ -1624,6 +1646,10 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
   #endif
  if(errno == EINTR || errno == EAGAIN)
  return 1;
+#ifdef ECONNRESET
+ if(errno == ECONNRESET && verbosity < 2)
+ return 0; /* silence reset by peer */
+#endif
 #  ifdef HAVE_WRITEV
  log_err_addr("tcp writev", strerror(errno),
  &c->repinfo.addr, c->repinfo.addrlen);
@@ -1641,6 +1667,8 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
  UB_EV_WRITE);
  return 1;
  }
+ if(WSAGetLastError() == WSAECONNRESET && verbosity < 2)
+ return 0; /* silence reset by peer */
  log_err_addr("tcp send s",
  wsa_strerror(WSAGetLastError()),
  &c->repinfo.addr, c->repinfo.addrlen);
@@ -1664,6 +1692,10 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
 #ifndef USE_WINSOCK
  if(errno == EINTR || errno == EAGAIN)
  return 1;
+#ifdef ECONNRESET
+ if(errno == ECONNRESET && verbosity < 2)
+ return 0; /* silence reset by peer */
+#endif
  log_err_addr("tcp send r", strerror(errno),
  &c->repinfo.addr, c->repinfo.addrlen);
 #else
@@ -1673,6 +1705,8 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c)
  ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
  return 1;
  }
+ if(WSAGetLastError() == WSAECONNRESET && verbosity < 2)
+ return 0; /* silence reset by peer */
  log_err_addr("tcp send r", wsa_strerror(WSAGetLastError()),
  &c->repinfo.addr, c->repinfo.addrlen);
 #endif
@@ -1738,6 +1772,16 @@ comm_point_tcp_handle_callback(int fd, short event, void* arg)
  }
 #endif
 
+ if(event&UB_EV_TIMEOUT) {
+ verbose(VERB_QUERY, "tcp took too long, dropped");
+ reclaim_tcp_handler(c);
+ if(!c->tcp_do_close) {
+ fptr_ok(fptr_whitelist_comm_point(c->callback));
+ (void)(*c->callback)(c, c->cb_arg,
+ NETEVENT_TIMEOUT, NULL);
+ }
+ return;
+ }
  if(event&UB_EV_READ) {
  int has_tcpq = (c->tcp_req_info != NULL);
  if(!comm_point_tcp_handle_read(fd, c, 0)) {
@@ -1768,16 +1812,6 @@ comm_point_tcp_handle_callback(int fd, short event, void* arg)
  tcp_req_info_read_again(fd, c);
  return;
  }
- if(event&UB_EV_TIMEOUT) {
- verbose(VERB_QUERY, "tcp took too long, dropped");
- reclaim_tcp_handler(c);
- if(!c->tcp_do_close) {
- fptr_ok(fptr_whitelist_comm_point(c->callback));
- (void)(*c->callback)(c, c->cb_arg,
- NETEVENT_TIMEOUT, NULL);
- }
- return;
- }
  log_err("Ignored event %d for tcphdl.", event);
 }
 
@@ -1826,6 +1860,10 @@ ssl_http_read_more(struct comm_point* c)
  comm_point_listen_for_rw(c, 0, 1);
  return 1;
  } else if(want == SSL_ERROR_SYSCALL) {
+#ifdef ECONNRESET
+ if(errno == ECONNRESET && verbosity < 2)
+ return 0; /* silence reset by peer */
+#endif
  if(errno != 0)
  log_err("SSL_read syscall: %s",
  strerror(errno));
@@ -2268,12 +2306,16 @@ ssl_http_write_more(struct comm_point* c)
  if(want == SSL_ERROR_ZERO_RETURN) {
  return 0; /* closed */
  } else if(want == SSL_ERROR_WANT_READ) {
- c->ssl_shake_state = comm_ssl_shake_read;
+ c->ssl_shake_state = comm_ssl_shake_hs_read;
  comm_point_listen_for_rw(c, 1, 0);
  return 1; /* wait for read condition */
  } else if(want == SSL_ERROR_WANT_WRITE) {
  return 1; /* write more later */
  } else if(want == SSL_ERROR_SYSCALL) {
+#ifdef EPIPE
+ if(errno == EPIPE && verbosity < 2)
+ return 0; /* silence 'broken pipe' */
+#endif
  if(errno != 0)
  log_err("SSL_write syscall: %s",
  strerror(errno));
@@ -2382,6 +2424,16 @@ comm_point_http_handle_callback(int fd, short event, void* arg)
  log_assert(c->type == comm_http);
  ub_comm_base_now(c->ev->base);
 
+ if(event&UB_EV_TIMEOUT) {
+ verbose(VERB_QUERY, "http took too long, dropped");
+ reclaim_http_handler(c);
+ if(!c->tcp_do_close) {
+ fptr_ok(fptr_whitelist_comm_point(c->callback));
+ (void)(*c->callback)(c, c->cb_arg,
+ NETEVENT_TIMEOUT, NULL);
+ }
+ return;
+ }
  if(event&UB_EV_READ) {
  if(!comm_point_http_handle_read(fd, c)) {
  reclaim_http_handler(c);
@@ -2406,16 +2458,6 @@ comm_point_http_handle_callback(int fd, short event, void* arg)
  }
  return;
  }
- if(event&UB_EV_TIMEOUT) {
- verbose(VERB_QUERY, "http took too long, dropped");
- reclaim_http_handler(c);
- if(!c->tcp_do_close) {
- fptr_ok(fptr_whitelist_comm_point(c->callback));
- (void)(*c->callback)(c, c->cb_arg,
- NETEVENT_TIMEOUT, NULL);
- }
- return;
- }
  log_err("Ignored event %d for httphdl.", event);
 }
 
@@ -3138,8 +3180,8 @@ comm_point_stop_listening(struct comm_point* c)
 void
 comm_point_start_listening(struct comm_point* c, int newfd, int msec)
 {
- verbose(VERB_ALGO, "comm point start listening %d",
- c->fd==-1?newfd:c->fd);
+ verbose(VERB_ALGO, "comm point start listening %d (%d msec)",
+ c->fd==-1?newfd:c->fd, msec);
  if(c->type == comm_tcp_accept && !c->tcp_free) {
  /* no use to start listening no free slots. */
  return;
diff --git libunbound/util/storage/lookup3.c libunbound/util/storage/lookup3.c
index cc110748156..bb25eb433c9 100644
--- libunbound/util/storage/lookup3.c
+++ libunbound/util/storage/lookup3.c
@@ -1,4 +1,7 @@
 /*
+  May 2019(Wouter) patch to enable the valgrind clean implementation all the
+     time.  This enables better security audit and checks, which is better
+     than the speedup.  Git issue #30.  Renamed the define ARRAY_CLEAN_ACCESS.
   February 2013(Wouter) patch defines for BSD endianness, from Brad Smith.
   January 2012(Wouter) added randomised initial value, fallout from 28c3.
   March 2007(Wouter) adapted from lookup3.c original, add config.h include.
@@ -44,6 +47,7 @@ on 1 byte), but shoehorning those bytes into integers efficiently is messy.
 -------------------------------------------------------------------------------
 */
 /*#define SELF_TEST 1*/
+#define ARRAY_CLEAN_ACCESS 1
 
 #include "config.h"
 #include "util/storage/lookup3.h"
@@ -336,7 +340,7 @@ uint32_t hashlittle( const void *key, size_t length, uint32_t initval)
   u.ptr = key;
   if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
     const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
-#ifdef VALGRIND
+#ifdef ARRAY_CLEAN_ACCESS
     const uint8_t  *k8;
 #endif
 
@@ -361,7 +365,7 @@ uint32_t hashlittle( const void *key, size_t length, uint32_t initval)
      * still catch it and complain.  The masking trick does make the hash
      * noticeably faster for short strings (like English words).
      */
-#ifndef VALGRIND
+#ifndef ARRAY_CLEAN_ACCESS
 
     switch(length)
     {
diff --git libunbound/util/ub_event.c libunbound/util/ub_event.c
index 78481a98205..e097fbc4015 100644
--- libunbound/util/ub_event.c
+++ libunbound/util/ub_event.c
@@ -295,11 +295,18 @@ ub_event_new(struct ub_event_base* base, int fd, short bits,
  if (!ev)
  return NULL;
 
+#ifndef HAVE_EVENT_ASSIGN
  event_set(ev, fd, NATIVE_BITS(bits), NATIVE_BITS_CB(cb), arg);
  if (event_base_set(AS_EVENT_BASE(base), ev) != 0) {
  free(ev);
  return NULL;
  }
+#else
+ if (event_assign(ev, AS_EVENT_BASE(base), fd, bits, cb, arg) != 0) {
+ free(ev);
+ return NULL;
+ }
+#endif
  return AS_UB_EVENT(ev);
 }
 
@@ -312,11 +319,18 @@ ub_signal_new(struct ub_event_base* base, int fd,
  if (!ev)
  return NULL;
 
+#if !HAVE_DECL_EVSIGNAL_ASSIGN
  signal_set(ev, fd, NATIVE_BITS_CB(cb), arg);
  if (event_base_set(AS_EVENT_BASE(base), ev) != 0) {
  free(ev);
  return NULL;
  }
+#else
+ if (evsignal_assign(ev, AS_EVENT_BASE(base), fd, cb, arg) != 0) {
+ free(ev);
+ return NULL;
+ }
+#endif
  return AS_UB_EVENT(ev);
 }
 


--
I'm not entirely sure you are real.