diff options
19 files changed, 508 insertions, 132 deletions
diff --git a/sbin/unwind/libunbound/config.h b/sbin/unwind/libunbound/config.h index 7b0ba84679b..8c7028b6ab9 100644 --- a/sbin/unwind/libunbound/config.h +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/iterator/iter_utils.c b/sbin/unwind/libunbound/iterator/iter_utils.c index be7965a60e3..2ab55ceb497 100644 --- a/sbin/unwind/libunbound/iterator/iter_utils.c +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/iterator/iter_utils.h b/sbin/unwind/libunbound/iterator/iter_utils.h index ccfb280224b..f771930bba2 100644 --- a/sbin/unwind/libunbound/iterator/iter_utils.h +++ b/sbin/unwind/libunbound/iterator/iter_utils.h @@ -335,6 +335,13 @@ 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. * @param d: decrease. diff --git a/sbin/unwind/libunbound/iterator/iterator.c b/sbin/unwind/libunbound/iterator/iterator.c index c73fb517748..c906c271448 100644 --- a/sbin/unwind/libunbound/iterator/iterator.c +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/services/authzone.c b/sbin/unwind/libunbound/services/authzone.c index a87c2274fb9..1426f423a1b 100644 --- a/sbin/unwind/libunbound/services/authzone.c +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/services/authzone.h b/sbin/unwind/libunbound/services/authzone.h index 4706803a86b..a695bd029b5 100644 --- a/sbin/unwind/libunbound/services/authzone.h +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/services/cache/dns.c b/sbin/unwind/libunbound/services/cache/dns.c index 47611ac5aef..aa4efec73f4 100644 --- a/sbin/unwind/libunbound/services/cache/dns.c +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/services/listen_dnsport.c b/sbin/unwind/libunbound/services/listen_dnsport.c index e74d1abcffc..7e2afd843be 100644 --- a/sbin/unwind/libunbound/services/listen_dnsport.c +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/services/mesh.c b/sbin/unwind/libunbound/services/mesh.c index bee0f76a4ad..59ee9a08ec0 100644 --- a/sbin/unwind/libunbound/services/mesh.c +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/services/outside_network.c b/sbin/unwind/libunbound/services/outside_network.c index 16d63df4395..0323f1b30c9 100644 --- a/sbin/unwind/libunbound/services/outside_network.c +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/services/outside_network.h b/sbin/unwind/libunbound/services/outside_network.h index 48ef03edba7..3456a3da38b 100644 --- a/sbin/unwind/libunbound/services/outside_network.h +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/util/alloc.c b/sbin/unwind/libunbound/util/alloc.c index 908b1f42361..7e9618931ca 100644 --- a/sbin/unwind/libunbound/util/alloc.c +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/util/data/msgreply.h b/sbin/unwind/libunbound/util/data/msgreply.h index a455c4d2b37..8d75f9b12f3 100644 --- a/sbin/unwind/libunbound/util/data/msgreply.h +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/util/fptr_wlist.c b/sbin/unwind/libunbound/util/fptr_wlist.c index 02f85e8dc4a..94d23fa3a32 100644 --- a/sbin/unwind/libunbound/util/fptr_wlist.c +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/util/iana_ports.inc b/sbin/unwind/libunbound/util/iana_ports.inc index 5ead47f0f66..aa972a67bd5 100644 --- a/sbin/unwind/libunbound/util/iana_ports.inc +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/util/net_help.c b/sbin/unwind/libunbound/util/net_help.c index 2b1be92460b..13bcdf8085b 100644 --- a/sbin/unwind/libunbound/util/net_help.c +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/util/netevent.c b/sbin/unwind/libunbound/util/netevent.c index f33e44058b1..9e2ba92b5fd 100644 --- a/sbin/unwind/libunbound/util/netevent.c +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/util/storage/lookup3.c b/sbin/unwind/libunbound/util/storage/lookup3.c index cc110748156..bb25eb433c9 100644 --- a/sbin/unwind/libunbound/util/storage/lookup3.c +++ b/sbin/unwind/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 a/sbin/unwind/libunbound/util/ub_event.c b/sbin/unwind/libunbound/util/ub_event.c index 78481a98205..e097fbc4015 100644 --- a/sbin/unwind/libunbound/util/ub_event.c +++ b/sbin/unwind/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); } |