Merge branch 'branch-1.25.2'

This commit is contained in:
W.C.A. Wijngaards
2026-07-22 11:33:54 +02:00
45 changed files with 1454 additions and 303 deletions
Vendored
+23
View File
@@ -23021,6 +23021,29 @@ printf "%s\n" "no" >&6; }
fi fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
ac_fn_check_decl "$LINENO" "CLOCK_MONOTONIC
" "ac_cv_have_decl_CLOCK_MONOTONIC_________" "$ac_includes_default
#ifdef TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
" "$ac_c_undeclared_builtin_options" "CFLAGS"
if test "x$ac_cv_have_decl_CLOCK_MONOTONIC_________" = xyes
then :
else $as_nop
as_fn_error $? "ngtcp2 for QUIC needs at least CLOCK_MONOTONIC on the system" "$LINENO" 5
fi
fi fi
# set static linking for uninstalled libraries if requested # set static linking for uninstalled libraries if requested
+16
View File
@@ -1747,6 +1747,22 @@ if test x_$withval = x_yes -o x_$withval != x_no; then
AC_MSG_RESULT(no) AC_MSG_RESULT(no)
]) ])
AC_CHECK_DECL([CLOCK_MONOTONIC]
, []
, [AC_MSG_ERROR([ngtcp2 for QUIC needs at least CLOCK_MONOTONIC on the system])]
, [AC_INCLUDES_DEFAULT
#ifdef TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
])
fi fi
# set static linking for uninstalled libraries if requested # set static linking for uninstalled libraries if requested
+8 -4
View File
@@ -79,6 +79,7 @@
#include "util/tcp_conn_limit.h" #include "util/tcp_conn_limit.h"
#include "util/edns.h" #include "util/edns.h"
#include "services/listen_dnsport.h" #include "services/listen_dnsport.h"
#include "services/outside_network.h"
#include "services/cache/rrset.h" #include "services/cache/rrset.h"
#include "services/cache/infra.h" #include "services/cache/infra.h"
#include "services/localzone.h" #include "services/localzone.h"
@@ -825,6 +826,10 @@ daemon_create_workers(struct daemon* daemon)
fatal_exit("out of memory during daemon init"); fatal_exit("out of memory during daemon init");
numport = daemon_get_shufport(daemon, shufport); numport = daemon_get_shufport(daemon, shufport);
verbose(VERB_ALGO, "total of %d outgoing ports available", numport); verbose(VERB_ALGO, "total of %d outgoing ports available", numport);
if(!(daemon->shared_ports = shared_ports_create(daemon->cfg->out_ifs,
daemon->cfg->num_out_ifs, daemon->cfg->do_ip4,
daemon->cfg->do_ip6, shufport, numport)))
fatal_exit("could not setup shared ports: out of memory");
#ifdef HAVE_NGTCP2 #ifdef HAVE_NGTCP2
if (cfg_has_quic(daemon->cfg)) { if (cfg_has_quic(daemon->cfg)) {
@@ -855,10 +860,7 @@ daemon_create_workers(struct daemon* daemon)
#endif #endif
} }
for(i=0; i<daemon->num; i++) { for(i=0; i<daemon->num; i++) {
if(!(daemon->workers[i] = worker_create(daemon, i, if(!(daemon->workers[i] = worker_create(daemon, i)))
shufport+numport*i/daemon->num,
numport*(i+1)/daemon->num - numport*i/daemon->num)))
/* the above is not ports/numthr, due to rounding */
fatal_exit("could not create worker"); fatal_exit("could not create worker");
} }
/* create per-worker alloc caches if not reusing existing ones. */ /* create per-worker alloc caches if not reusing existing ones. */
@@ -1219,6 +1221,8 @@ daemon_cleanup(struct daemon* daemon)
if(!daemon->reuse_cache || daemon->need_to_exit) if(!daemon->reuse_cache || daemon->need_to_exit)
daemon_clear_allocs(daemon); daemon_clear_allocs(daemon);
daemon->num = 0; daemon->num = 0;
shared_ports_delete(daemon->shared_ports);
daemon->shared_ports = NULL;
#ifdef USE_DNSTAP #ifdef USE_DNSTAP
dt_delete(daemon->dtenv); dt_delete(daemon->dtenv);
daemon->dtenv = NULL; daemon->dtenv = NULL;
+3
View File
@@ -62,6 +62,7 @@ struct doq_table;
struct cookie_secrets; struct cookie_secrets;
struct fast_reload_thread; struct fast_reload_thread;
struct fast_reload_printq; struct fast_reload_printq;
struct shared_ports;
#include "dnstap/dnstap_config.h" #include "dnstap/dnstap_config.h"
#ifdef USE_DNSTAP #ifdef USE_DNSTAP
@@ -97,6 +98,8 @@ struct daemon {
int rc_port; int rc_port;
/** listening ports for remote control */ /** listening ports for remote control */
struct listen_port* rc_ports; struct listen_port* rc_ports;
/** the shared ports structure, with random ports numbers. */
struct shared_ports* shared_ports;
/** remote control connections management (for first worker) */ /** remote control connections management (for first worker) */
struct daemon_remote* rc; struct daemon_remote* rc;
/** ssl context for listening to dnstcp over ssl */ /** ssl context for listening to dnstcp over ssl */
+16
View File
@@ -1735,6 +1735,14 @@ do_view_data_add(RES* ssl, struct worker* worker, char* arg)
ssl_printf(ssl,"error out of memory\n"); ssl_printf(ssl,"error out of memory\n");
return; return;
} }
if(!v->isfirst) {
/* Global local-zone is not used for this view,
* therefore add defaults to this view-specific
* local-zone. */
struct config_file lz_cfg;
memset(&lz_cfg, 0, sizeof(lz_cfg));
local_zone_enter_defaults(v->local_zones, &lz_cfg);
}
} }
do_data_add(ssl, v->local_zones, arg2); do_data_add(ssl, v->local_zones, arg2);
lock_rw_unlock(&v->lock); lock_rw_unlock(&v->lock);
@@ -1760,6 +1768,14 @@ do_view_datas_add(struct daemon_remote* rc, RES* ssl, struct worker* worker,
ssl_printf(ssl,"error out of memory\n"); ssl_printf(ssl,"error out of memory\n");
return; return;
} }
if(!v->isfirst) {
/* Global local-zone is not used for this view,
* therefore add defaults to this view-specific
* local-zone. */
struct config_file lz_cfg;
memset(&lz_cfg, 0, sizeof(lz_cfg));
local_zone_enter_defaults(v->local_zones, &lz_cfg);
}
} }
/* put the view name in the command buf */ /* put the view name in the command buf */
(void)snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s ", arg); (void)snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s ", arg);
+17 -13
View File
@@ -1555,6 +1555,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
return 0; return 0;
} }
query_error(c->buffer, LDNS_RCODE_FORMERR, 0); query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
sldns_buffer_copy(c->dnscrypt_buffer, c->buffer);
return 1; return 1;
} }
dname_str(qinfo.qname, buf); dname_str(qinfo.qname, buf);
@@ -1573,6 +1574,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
query_error(c->buffer, LDNS_RCODE_SERVFAIL, query_error(c->buffer, LDNS_RCODE_SERVFAIL,
qinfo.qname_len); qinfo.qname_len);
worker->stats.num_query_dnscrypt_cleartext++; worker->stats.num_query_dnscrypt_cleartext++;
sldns_buffer_copy(c->dnscrypt_buffer, c->buffer);
return 1; return 1;
} }
worker->stats.num_query_dnscrypt_cert++; worker->stats.num_query_dnscrypt_cert++;
@@ -1833,7 +1835,13 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
server_stats_insquery(&worker->stats, c, qinfo.qtype, server_stats_insquery(&worker->stats, c, qinfo.qtype,
qinfo.qclass, &edns, repinfo); qinfo.qclass, &edns, repinfo);
if(c->type != comm_udp) if(c->type != comm_udp)
#ifdef USE_DNSCRYPT
edns.udp_size = (c->dnscrypt && repinfo->is_dnscrypted)
? sldns_buffer_capacity(c->buffer) - DNSCRYPT_REPLY_HEADER_SIZE
: 65535;
#else
edns.udp_size = 65535; /* max size for TCP replies */ edns.udp_size = 65535; /* max size for TCP replies */
#endif
if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo, if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
&edns, repinfo, c->buffer)) { &edns, repinfo, c->buffer)) {
regional_free_all(worker->scratchpad); regional_free_all(worker->scratchpad);
@@ -2121,7 +2129,7 @@ send_reply_rc:
} }
} }
#ifdef USE_DNSCRYPT #ifdef USE_DNSCRYPT
if(!dnsc_handle_uncurved_request(repinfo)) { if(!dnsc_handle_uncurved_request(repinfo, c->buffer)) {
return 0; return 0;
} }
#endif #endif
@@ -2234,23 +2242,16 @@ void worker_probe_timer_cb(void* arg)
} }
struct worker* struct worker*
worker_create(struct daemon* daemon, int id, int* ports, int n) worker_create(struct daemon* daemon, int id)
{ {
unsigned int seed; unsigned int seed;
struct worker* worker = (struct worker*)calloc(1, struct worker* worker = (struct worker*)calloc(1,
sizeof(struct worker)); sizeof(struct worker));
if(!worker) if(!worker)
return NULL; return NULL;
worker->numports = n;
worker->ports = (int*)memdup(ports, sizeof(int)*n);
if(!worker->ports) {
free(worker);
return NULL;
}
worker->daemon = daemon; worker->daemon = daemon;
worker->thread_num = id; worker->thread_num = id;
if(!(worker->cmd = tube_create())) { if(!(worker->cmd = tube_create())) {
free(worker->ports);
free(worker); free(worker);
return NULL; return NULL;
} }
@@ -2258,7 +2259,6 @@ worker_create(struct daemon* daemon, int id, int* ports, int n)
if(!(worker->rndstate = ub_initstate(daemon->rand))) { if(!(worker->rndstate = ub_initstate(daemon->rand))) {
log_err("could not init random numbers."); log_err("could not init random numbers.");
tube_delete(worker->cmd); tube_delete(worker->cmd);
free(worker->ports);
free(worker); free(worker);
return NULL; return NULL;
} }
@@ -2357,14 +2357,14 @@ worker_init(struct worker* worker, struct config_file *cfg,
cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp, cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
worker->daemon->env->infra_cache, worker->rndstate, worker->daemon->env->infra_cache, worker->rndstate,
cfg->use_caps_bits_for_id, worker->ports, worker->numports, cfg->use_caps_bits_for_id,
cfg->unwanted_threshold, cfg->outgoing_tcp_mss, cfg->unwanted_threshold, cfg->outgoing_tcp_mss,
&worker_alloc_cleanup, worker, &worker_alloc_cleanup, worker,
cfg->do_udp || cfg->udp_upstream_without_downstream, cfg->do_udp || cfg->udp_upstream_without_downstream,
worker->daemon->connect_dot_sslctx, cfg->delay_close, worker->daemon->connect_dot_sslctx, cfg->delay_close,
cfg->tls_use_sni, dtenv, cfg->udp_connect, cfg->tls_use_sni, dtenv, cfg->udp_connect,
cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout, cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
cfg->tcp_auth_query_timeout); cfg->tcp_auth_query_timeout, worker->daemon->shared_ports);
if(!worker->back) { if(!worker->back) {
log_err("could not create outgoing sockets"); log_err("could not create outgoing sockets");
worker_delete(worker); worker_delete(worker);
@@ -2517,7 +2517,6 @@ worker_delete(struct worker* worker)
tube_delete(worker->cmd); tube_delete(worker->cmd);
comm_timer_delete(worker->stat_timer); comm_timer_delete(worker->stat_timer);
comm_timer_delete(worker->env.probe_timer); comm_timer_delete(worker->env.probe_timer);
free(worker->ports);
if(worker->thread_num == 0) { if(worker->thread_num == 0) {
#ifdef UB_ON_WINDOWS #ifdef UB_ON_WINDOWS
wsvc_desetup_worker(worker); wsvc_desetup_worker(worker);
@@ -2653,6 +2652,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
log_assert(0); log_assert(0);
} }
void libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
{
log_assert(0);
}
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
{ {
log_assert(0); log_assert(0);
+1 -7
View File
@@ -104,10 +104,6 @@ struct worker {
struct listen_dnsport* front; struct listen_dnsport* front;
/** the backside outside network interface to the auth servers */ /** the backside outside network interface to the auth servers */
struct outside_network* back; struct outside_network* back;
/** ports to be used by this worker. */
int* ports;
/** number of ports for this worker */
int numports;
/** the signal handler */ /** the signal handler */
struct comm_signal* comsig; struct comm_signal* comsig;
/** commpoint to listen to commands. */ /** commpoint to listen to commands. */
@@ -146,11 +142,9 @@ struct worker {
* with backpointers only. Use worker_init on it later. * with backpointers only. Use worker_init on it later.
* @param daemon: the daemon that this worker thread is part of. * @param daemon: the daemon that this worker thread is part of.
* @param id: the thread number from 0.. numthreads-1. * @param id: the thread number from 0.. numthreads-1.
* @param ports: the ports it is allowed to use, array.
* @param n: the number of ports.
* @return: the new worker or NULL on alloc failure. * @return: the new worker or NULL on alloc failure.
*/ */
struct worker* worker_create(struct daemon* daemon, int id, int* ports, int n); struct worker* worker_create(struct daemon* daemon, int id);
/** /**
* Initialize worker. * Initialize worker.
+23 -3
View File
@@ -474,10 +474,18 @@ dnscrypt_server_curve(const dnsccert *cert,
uint8_t *const buf = sldns_buffer_begin(buffer); uint8_t *const buf = sldns_buffer_begin(buffer);
size_t len = sldns_buffer_limit(buffer); size_t len = sldns_buffer_limit(buffer);
if(len + DNSCRYPT_REPLY_HEADER_SIZE > sldns_buffer_capacity(buffer))
return -1;
sldns_buffer_clear(buffer);
if(udp){ if(udp){
if (max_len > max_reply_size) if (max_len > max_reply_size)
max_len = max_reply_size; max_len = max_reply_size;
} }
if(max_len > sldns_buffer_capacity(buffer))
max_len = sldns_buffer_capacity(buffer);
if(max_len > 65535)
max_len = 65535;
memcpy(nonce, client_nonce, crypto_box_HALF_NONCEBYTES); memcpy(nonce, client_nonce, crypto_box_HALF_NONCEBYTES);
@@ -520,6 +528,7 @@ dnscrypt_server_curve(const dnsccert *cert,
DNSCRYPT_MAGIC_HEADER_LEN, DNSCRYPT_MAGIC_HEADER_LEN,
nonce, nonce,
crypto_box_NONCEBYTES); crypto_box_NONCEBYTES);
sldns_buffer_flip(buffer);
sldns_buffer_set_limit(buffer, len + DNSCRYPT_REPLY_HEADER_SIZE); sldns_buffer_set_limit(buffer, len + DNSCRYPT_REPLY_HEADER_SIZE);
return 0; return 0;
} }
@@ -663,6 +672,8 @@ dnsc_find_cert(struct dnsc_env* dnscenv, struct sldns_buffer* buffer)
} }
dnscrypt_header = (struct dnscrypt_query_header *)sldns_buffer_begin(buffer); dnscrypt_header = (struct dnscrypt_query_header *)sldns_buffer_begin(buffer);
for (i = 0U; i < dnscenv->signed_certs_count; i++) { for (i = 0U; i < dnscenv->signed_certs_count; i++) {
if(!certs[i].keypair)
continue;
if (memcmp(certs[i].magic_query, dnscrypt_header->magic_query, if (memcmp(certs[i].magic_query, dnscrypt_header->magic_query,
DNSCRYPT_MAGIC_HEADER_LEN) == 0) { DNSCRYPT_MAGIC_HEADER_LEN) == 0) {
return &certs[i]; return &certs[i];
@@ -804,6 +815,7 @@ dnsc_parse_keys(struct dnsc_env *env, struct config_file *cfg)
sizeof *env->keypairs); sizeof *env->keypairs);
env->certs = sodium_allocarray(env->signed_certs_count, env->certs = sodium_allocarray(env->signed_certs_count,
sizeof *env->certs); sizeof *env->certs);
memset(env->certs, 0, env->signed_certs_count * sizeof(*env->certs));
cert_id = 0U; cert_id = 0U;
keypair_id = 0U; keypair_id = 0U;
@@ -919,12 +931,13 @@ dnsc_handle_curved_request(struct dnsc_env* dnscenv,
} }
int int
dnsc_handle_uncurved_request(struct comm_reply *repinfo) dnsc_handle_uncurved_request(struct comm_reply *repinfo,
struct sldns_buffer* buffer)
{ {
if(!repinfo->c->dnscrypt) { if(!repinfo->c->dnscrypt) {
return 1; return 1;
} }
sldns_buffer_copy(repinfo->c->dnscrypt_buffer, repinfo->c->buffer); sldns_buffer_copy(repinfo->c->dnscrypt_buffer, buffer);
if(!repinfo->is_dnscrypted) { if(!repinfo->is_dnscrypted) {
return 1; return 1;
} }
@@ -970,12 +983,19 @@ dnsc_create(void)
int int
dnsc_apply_cfg(struct dnsc_env *env, struct config_file *cfg) dnsc_apply_cfg(struct dnsc_env *env, struct config_file *cfg)
{ {
int nkeys;
if(dnsc_parse_certs(env, cfg) <= 0) { if(dnsc_parse_certs(env, cfg) <= 0) {
fatal_exit("dnsc_apply_cfg: no cert file loaded"); fatal_exit("dnsc_apply_cfg: no cert file loaded");
} }
if(dnsc_parse_keys(env, cfg) <= 0) { nkeys = dnsc_parse_keys(env, cfg);
if(nkeys <= 0) {
fatal_exit("dnsc_apply_cfg: no key file loaded"); fatal_exit("dnsc_apply_cfg: no key file loaded");
} }
if((size_t)nkeys < env->signed_certs_count) {
fatal_exit("dnsc_apply_cfg: %u dnscrypt-provider-cert file(s) have no "
"matching dnscrypt-secret-key",
(unsigned)(env->signed_certs_count - (size_t)nkeys));
}
randombytes_buf(env->hash_key, sizeof env->hash_key); randombytes_buf(env->hash_key, sizeof env->hash_key);
env->provider_name = cfg->dnscrypt_provider; env->provider_name = cfg->dnscrypt_provider;
+2 -1
View File
@@ -128,7 +128,8 @@ int dnsc_handle_curved_request(struct dnsc_env* dnscenv,
* \return 0 in case of failure. * \return 0 in case of failure.
*/ */
int dnsc_handle_uncurved_request(struct comm_reply *repinfo); int dnsc_handle_uncurved_request(struct comm_reply *repinfo,
struct sldns_buffer* buffer);
/** /**
* Computes the size of the shared secret cache entry. * Computes the size of the shared secret cache entry.
+5
View File
@@ -1737,6 +1737,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
log_assert(0); log_assert(0);
} }
void libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
{
log_assert(0);
}
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
{ {
log_assert(0); log_assert(0);
+7
View File
@@ -2055,6 +2055,13 @@ These options are part of the ``server:`` section.
flushing away any poison. flushing away any poison.
A value of 10 million is suggested. A value of 10 million is suggested.
It is useful to add 0.0.0.0/8 and '::' to the
:ref:`do-not-query-address<unbound.conf.do-not-query-address>` list.
Otherwise they may be answered, from localhost, and the different source
makes an unwanted reply that unnecessarily ticks up.
The :ref:`do-not-query-localhost<unbound.conf.do-not-query-localhost>`
option includes them, the zero subnets, when it is enabled.
Default: 0 (disabled) Default: 0 (disabled)
+12
View File
@@ -132,6 +132,18 @@ donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg)
if(cfg->do_ip6) { if(cfg->do_ip6) {
if(!donotq_str_cfg(dq, "::1")) if(!donotq_str_cfg(dq, "::1"))
return 0; return 0;
if(!donotq_str_cfg(dq, "::ffff:127.0.0.0/104"))
return 0;
}
/* RFC 1122 3.2.1.3 / RFC 6890 / RFC 4291 2.5.2: not valid as
* destination; on Linux these route to the local host. */
if(!donotq_str_cfg(dq, "0.0.0.0/8"))
return 0;
if(cfg->do_ip6) {
if(!donotq_str_cfg(dq, "::"))
return 0;
if(!donotq_str_cfg(dq, "::ffff:0:0/96"))
return 0;
} }
} }
addr_tree_init_parents(&dq->tree); addr_tree_init_parents(&dq->tree);
+47 -20
View File
@@ -81,7 +81,8 @@ int BLACKLIST_PENALTY = (120000*4);
/** Timeout when only a single probe query per IP is allowed. */ /** Timeout when only a single probe query per IP is allowed. */
int PROBE_MAXRTO = PROBE_MAXRTO_DEFAULT; /* in msec */ int PROBE_MAXRTO = PROBE_MAXRTO_DEFAULT; /* in msec */
static void target_count_increase_nx(struct iter_qstate* iq, int num); static void target_count_increase_nx(struct module_qstate* qstate,
struct iter_qstate* iq, int num);
int int
iter_init(struct module_env* env, int id) iter_init(struct module_env* env, int id)
@@ -250,7 +251,7 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->nat64.use_nat64)) && if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->nat64.use_nat64)) &&
(dpns->got6 == 2 || !ie->supports_ipv6)) { (dpns->got6 == 2 || !ie->supports_ipv6)) {
dpns->resolved = 1; /* mark as failed */ dpns->resolved = 1; /* mark as failed */
target_count_increase_nx(super_iq, 1); target_count_increase_nx(super, super_iq, 1);
} }
} }
if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS) { if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS) {
@@ -734,7 +735,7 @@ is_caps_whitelisted(struct iter_env* ie, struct iter_qstate* iq)
* created for the parent query. * created for the parent query.
*/ */
static void static void
target_count_create(struct iter_qstate* iq) target_count_create(struct module_qstate* qstate, struct iter_qstate* iq)
{ {
if(!iq->target_count) { if(!iq->target_count) {
iq->target_count = (int*)calloc(TARGET_COUNT_MAX, sizeof(int)); iq->target_count = (int*)calloc(TARGET_COUNT_MAX, sizeof(int));
@@ -742,33 +743,57 @@ target_count_create(struct iter_qstate* iq)
if(iq->target_count) { if(iq->target_count) {
iq->target_count[TARGET_COUNT_REF] = 1; iq->target_count[TARGET_COUNT_REF] = 1;
iq->nxns_dp = (uint8_t**)calloc(1, sizeof(uint8_t*)); iq->nxns_dp = (uint8_t**)calloc(1, sizeof(uint8_t*));
/* continue global quota from where it was. */
if(qstate->global_quota_reached >
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA])
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] =
qstate->global_quota_reached;
} }
} }
} }
static void static void
target_count_increase(struct iter_qstate* iq, int num) target_count_store(struct module_qstate* qstate, struct iter_qstate* iq)
{ {
target_count_create(iq); if(iq->target_count) {
/* By storing the global quota counter, it stays
* there to be picked up if the module is restarted,
* eg. due to a validator retry, and then the
* target_count_create routine picks it up. */
if(iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] >
qstate->global_quota_reached)
qstate->global_quota_reached =
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA];
}
}
static void
target_count_increase(struct module_qstate* qstate,
struct iter_qstate* iq, int num)
{
target_count_create(qstate, iq);
if(iq->target_count) if(iq->target_count)
iq->target_count[TARGET_COUNT_QUERIES] += num; iq->target_count[TARGET_COUNT_QUERIES] += num;
iq->dp_target_count++; iq->dp_target_count++;
} }
static void static void
target_count_increase_nx(struct iter_qstate* iq, int num) target_count_increase_nx(struct module_qstate* qstate,
struct iter_qstate* iq, int num)
{ {
target_count_create(iq); target_count_create(qstate, iq);
if(iq->target_count) if(iq->target_count)
iq->target_count[TARGET_COUNT_NX] += num; iq->target_count[TARGET_COUNT_NX] += num;
} }
static void static void
target_count_increase_global_quota(struct iter_qstate* iq, int num) target_count_increase_global_quota(struct module_qstate* qstate,
struct iter_qstate* iq, int num)
{ {
target_count_create(iq); target_count_create(qstate, iq);
if(iq->target_count) if(iq->target_count)
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] += num; iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] += num;
target_count_store(qstate, iq);
} }
/** /**
@@ -861,7 +886,7 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
subiq = (struct iter_qstate*)subq->minfo[id]; subiq = (struct iter_qstate*)subq->minfo[id];
memset(subiq, 0, sizeof(*subiq)); memset(subiq, 0, sizeof(*subiq));
subiq->num_target_queries = 0; subiq->num_target_queries = 0;
target_count_create(iq); target_count_create(qstate, iq);
subiq->target_count = iq->target_count; subiq->target_count = iq->target_count;
if(iq->target_count) { if(iq->target_count) {
iq->target_count[TARGET_COUNT_REF] ++; /* extra reference */ iq->target_count[TARGET_COUNT_REF] ++; /* extra reference */
@@ -2235,7 +2260,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
} }
iq->num_target_queries += qs; iq->num_target_queries += qs;
target_count_increase(iq, qs); target_count_increase(qstate, iq, qs);
if(qs != 0) { if(qs != 0) {
qstate->ext_state[id] = module_wait_subquery; qstate->ext_state[id] = module_wait_subquery;
return 0; /* and wait for them */ return 0; /* and wait for them */
@@ -2291,7 +2316,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
* lookups at a time. */ * lookups at a time. */
verbose(VERB_ALGO, "try parent-side glue lookup"); verbose(VERB_ALGO, "try parent-side glue lookup");
iq->num_target_queries += query_count; iq->num_target_queries += query_count;
target_count_increase(iq, query_count); target_count_increase(qstate, iq, query_count);
qstate->ext_state[id] = module_wait_subquery; qstate->ext_state[id] = module_wait_subquery;
return 0; return 0;
} }
@@ -2311,7 +2336,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
if(query_count != 0) { /* suspend to await results */ if(query_count != 0) { /* suspend to await results */
verbose(VERB_ALGO, "try parent-side glue lookup"); verbose(VERB_ALGO, "try parent-side glue lookup");
iq->num_target_queries += query_count; iq->num_target_queries += query_count;
target_count_increase(iq, query_count); target_count_increase(qstate, iq, query_count);
qstate->ext_state[id] = module_wait_subquery; qstate->ext_state[id] = module_wait_subquery;
return 0; return 0;
} }
@@ -2795,7 +2820,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
} }
iq->num_target_queries += extra; iq->num_target_queries += extra;
target_count_increase(iq, extra); target_count_increase(qstate, iq, extra);
if(iq->num_target_queries > 0) { if(iq->num_target_queries > 0) {
/* wait to get all targets, we want to try em */ /* wait to get all targets, we want to try em */
verbose(VERB_ALGO, "wait for all targets for fallback"); verbose(VERB_ALGO, "wait for all targets for fallback");
@@ -2846,7 +2871,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
/* errors ignored, these targets are not strictly necessary for /* errors ignored, these targets are not strictly necessary for
* this result, we do not have to reply with SERVFAIL */ * this result, we do not have to reply with SERVFAIL */
iq->num_target_queries += extra; iq->num_target_queries += extra;
target_count_increase(iq, extra); target_count_increase(qstate, iq, extra);
} }
/* Add the current set of unused targets to our queue. */ /* Add the current set of unused targets to our queue. */
@@ -2969,7 +2994,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
LDNS_RCODE_SERVFAIL); LDNS_RCODE_SERVFAIL);
} }
iq->num_target_queries += qs; iq->num_target_queries += qs;
target_count_increase(iq, qs); target_count_increase(qstate, iq, qs);
} }
/* Since a target query might have been made, we /* Since a target query might have been made, we
* need to check again. */ * need to check again. */
@@ -3029,7 +3054,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
* this result, we do not have to reply with SERVFAIL */ * this result, we do not have to reply with SERVFAIL */
if(extra > 0) { if(extra > 0) {
iq->num_target_queries += extra; iq->num_target_queries += extra;
target_count_increase(iq, extra); target_count_increase(qstate, iq, extra);
check_waiting_queries(iq, qstate, id); check_waiting_queries(iq, qstate, id);
/* undo qname minimise step because we'll get back here /* undo qname minimise step because we'll get back here
* to do it again */ * to do it again */
@@ -3042,7 +3067,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
} }
} }
target_count_increase_global_quota(iq, 1); target_count_increase_global_quota(qstate, iq, 1);
if(iq->target_count && iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] if(iq->target_count && iq->target_count[TARGET_COUNT_GLOBAL_QUOTA]
> MAX_GLOBAL_QUOTA) { > MAX_GLOBAL_QUOTA) {
char s[LDNS_MAX_DOMAINLEN]; char s[LDNS_MAX_DOMAINLEN];
@@ -3897,7 +3922,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
/* no new addresses, increase the nxns counter, like /* no new addresses, increase the nxns counter, like
* this could be a list of wildcards with no new * this could be a list of wildcards with no new
* addresses */ * addresses */
target_count_increase_nx(foriq, 1); target_count_increase_nx(qstate, foriq, 1);
} }
verbose(VERB_ALGO, "added target response"); verbose(VERB_ALGO, "added target response");
delegpt_log(VERB_ALGO, foriq->dp); delegpt_log(VERB_ALGO, foriq->dp);
@@ -3909,7 +3934,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
dpns->resolved = 1; /* fail the target */ dpns->resolved = 1; /* fail the target */
/* do not count cached answers */ /* do not count cached answers */
if(qstate->reply_origin && qstate->reply_origin->len != 0) { if(qstate->reply_origin && qstate->reply_origin->len != 0) {
target_count_increase_nx(foriq, 1); target_count_increase_nx(qstate, foriq, 1);
} }
} }
} }
@@ -4159,6 +4184,7 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
iter_store_parentside_neg(qstate->env, &qstate->qinfo, iter_store_parentside_neg(qstate->env, &qstate->qinfo,
iq->deleg_msg?iq->deleg_msg->rep: iq->deleg_msg?iq->deleg_msg->rep:
(iq->response?iq->response->rep:NULL)); (iq->response?iq->response->rep:NULL));
target_count_store(qstate, iq);
if(!iq->response) { if(!iq->response) {
verbose(VERB_ALGO, "No response is set, servfail"); verbose(VERB_ALGO, "No response is set, servfail");
errinf(qstate, "(no response found at query finish)"); errinf(qstate, "(no response found at query finish)");
@@ -4577,6 +4603,7 @@ iter_clear(struct module_qstate* qstate, int id)
iq = (struct iter_qstate*)qstate->minfo[id]; iq = (struct iter_qstate*)qstate->minfo[id];
if(iq) { if(iq) {
outbound_list_clear(&iq->outlist); outbound_list_clear(&iq->outlist);
target_count_store(qstate, iq);
if(iq->target_count && --iq->target_count[TARGET_COUNT_REF] == 0) { if(iq->target_count && --iq->target_count[TARGET_COUNT_REF] == 0) {
free(iq->target_count); free(iq->target_count);
if(*iq->nxns_dp) free(*iq->nxns_dp); if(*iq->nxns_dp) free(*iq->nxns_dp);
+11 -2
View File
@@ -105,6 +105,7 @@ libworker_delete_env(struct libworker* w)
SSL_CTX_free(w->sslctx); SSL_CTX_free(w->sslctx);
#endif #endif
outside_network_delete(w->back); outside_network_delete(w->back);
shared_ports_delete(w->shared_ports);
} }
/** delete libworker struct */ /** delete libworker struct */
@@ -219,17 +220,25 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
libworker_delete(w); libworker_delete(w);
return NULL; return NULL;
} }
if(!(w->shared_ports = shared_ports_create(cfg->out_ifs,
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, ports, numports))) {
if(!w->is_bg || w->is_bg_thread) {
lock_basic_unlock(&ctx->cfglock);
}
libworker_delete(w);
return NULL;
}
w->back = outside_network_create(w->base, cfg->msg_buffer_size, w->back = outside_network_create(w->base, cfg->msg_buffer_size,
(size_t)cfg->outgoing_num_ports, cfg->out_ifs, (size_t)cfg->outgoing_num_ports, cfg->out_ifs,
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp, cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id, w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
ports, numports, cfg->unwanted_threshold, cfg->unwanted_threshold,
cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w, cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w,
cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx, cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx,
cfg->delay_close, cfg->tls_use_sni, NULL, cfg->udp_connect, cfg->delay_close, cfg->tls_use_sni, NULL, cfg->udp_connect,
cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout, cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
cfg->tcp_auth_query_timeout); cfg->tcp_auth_query_timeout, w->shared_ports);
w->env->outnet = w->back; w->env->outnet = w->back;
if(!w->is_bg || w->is_bg_thread) { if(!w->is_bg || w->is_bg_thread) {
lock_basic_unlock(&ctx->cfglock); lock_basic_unlock(&ctx->cfglock);
+3
View File
@@ -60,6 +60,7 @@ struct tube;
struct sldns_buffer; struct sldns_buffer;
struct ub_event_base; struct ub_event_base;
struct query_info; struct query_info;
struct shared_ports;
/** /**
* The library-worker status structure * The library-worker status structure
@@ -84,6 +85,8 @@ struct libworker {
struct comm_base* base; struct comm_base* base;
/** the backside outside network interface to the auth servers */ /** the backside outside network interface to the auth servers */
struct outside_network* back; struct outside_network* back;
/** shared ports structure */
struct shared_ports* shared_ports;
/** random() table for this worker. */ /** random() table for this worker. */
struct ub_randstate* rndstate; struct ub_randstate* rndstate;
/** sslcontext for SSL wrapped DNS over TCP queries */ /** sslcontext for SSL wrapped DNS over TCP queries */
+7 -1
View File
@@ -1121,7 +1121,13 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
if((qstate->qinfo.qtype == LDNS_RR_TYPE_A || if((qstate->qinfo.qtype == LDNS_RR_TYPE_A ||
qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA || qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA ||
qstate->qinfo.qtype == LDNS_RR_TYPE_ANY) && qstate->qinfo.qtype == LDNS_RR_TYPE_ANY) &&
qstate->return_msg && qstate->return_msg->rep) { qstate->return_msg && qstate->return_msg->rep &&
!(qstate->env->need_to_validate &&
(!(qstate->query_flags & BIT_CD)
|| qstate->env->cfg->ignore_cd) &&
(qstate->return_msg->rep->security <= sec_status_bogus
|| qstate->return_msg->rep->security ==
sec_status_secure_sentinel_fail))) {
struct reply_info* new_rep = qstate->return_msg->rep; struct reply_info* new_rep = qstate->return_msg->rep;
struct ub_packed_rrset_key* alias_rrset = NULL; struct ub_packed_rrset_key* alias_rrset = NULL;
struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL}; struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
+22 -6
View File
@@ -5880,8 +5880,7 @@ xfer_target_equals_answer_name(struct auth_master* lookup_target,
/** callback for task_transfer lookup of host name, of A or AAAA */ /** callback for task_transfer lookup of host name, of A or AAAA */
void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf, void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus), enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited))
int ATTR_UNUSED(was_ratelimited))
{ {
struct auth_xfer* xfr = (struct auth_xfer*)arg; struct auth_xfer* xfr = (struct auth_xfer*)arg;
struct module_env* env; struct module_env* env;
@@ -5894,7 +5893,16 @@ void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
} }
/* process result */ /* process result */
if(rcode == LDNS_RCODE_NOERROR) { if(sec == sec_status_bogus || sec == sec_status_secure_sentinel_fail) {
if(verbosity >= VERB_OPS) {
char zname[LDNS_MAX_DOMAINLEN];
dname_str(xfr->name, zname);
verbose(VERB_OPS, "auth zone %s: primary %s address lookup is DNSSEC bogus: %s",
zname, xfr->task_transfer->lookup_target->host,
(why_bogus?why_bogus:""));
}
/* fall through to next-lookup / next-master */
} else if(rcode == LDNS_RCODE_NOERROR) {
uint16_t wanted_qtype = LDNS_RR_TYPE_A; uint16_t wanted_qtype = LDNS_RR_TYPE_A;
struct regional* temp = env->scratch; struct regional* temp = env->scratch;
struct query_info rq; struct query_info rq;
@@ -7031,8 +7039,7 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env)
/** callback for task_probe lookup of host name, of A or AAAA */ /** callback for task_probe lookup of host name, of A or AAAA */
void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf, void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus), enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited))
int ATTR_UNUSED(was_ratelimited))
{ {
struct auth_xfer* xfr = (struct auth_xfer*)arg; struct auth_xfer* xfr = (struct auth_xfer*)arg;
struct module_env* env; struct module_env* env;
@@ -7045,7 +7052,16 @@ void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
} }
/* process result */ /* process result */
if(rcode == LDNS_RCODE_NOERROR) { if(sec == sec_status_bogus || sec == sec_status_secure_sentinel_fail) {
if(verbosity >= VERB_OPS) {
char zname[LDNS_MAX_DOMAINLEN];
dname_str(xfr->name, zname);
verbose(VERB_OPS, "auth zone %s: primary %s address probe lookup is DNSSEC bogus: %s",
zname, xfr->task_transfer->lookup_target->host,
(why_bogus?why_bogus:""));
}
/* fall through to next-lookup / next-master */
} else if(rcode == LDNS_RCODE_NOERROR) {
uint16_t wanted_qtype = LDNS_RR_TYPE_A; uint16_t wanted_qtype = LDNS_RR_TYPE_A;
struct regional* temp = env->scratch; struct regional* temp = env->scratch;
struct query_info rq; struct query_info rq;
+3 -1
View File
@@ -277,6 +277,8 @@ find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
/* snip off front label */ /* snip off front label */
lablen = *qname; lablen = *qname;
if(lablen == 0)
break;
qname += lablen + 1; qname += lablen + 1;
qnamelen -= lablen + 1; qnamelen -= lablen + 1;
} }
@@ -1075,7 +1077,7 @@ dns_cache_lookup(struct module_env* env,
if(env->cfg->harden_below_nxdomain) { if(env->cfg->harden_below_nxdomain) {
while(!dname_is_root(k.qname)) { while(!dname_is_root(k.qname)) {
if(dpname && dpnamelen if(dpname && dpnamelen
&& !dname_subdomain_c(k.qname, dpname)) && !dname_strict_subdomain_c(k.qname, dpname))
break; /* no synth nxdomain above the stub */ break; /* no synth nxdomain above the stub */
dname_remove_label(&k.qname, &k.qname_len); dname_remove_label(&k.qname, &k.qname_len);
h = query_info_hash(&k, flags); h = query_info_hash(&k, flags);
+41 -3
View File
@@ -50,6 +50,7 @@
#include "util/regional.h" #include "util/regional.h"
#include "util/alloc.h" #include "util/alloc.h"
#include "util/net_help.h" #include "util/net_help.h"
#include "validator/val_utils.h"
void void
rrset_markdel(void* key) rrset_markdel(void* key)
@@ -126,7 +127,8 @@ rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key,
/** see if rrset needs to be updated in the cache */ /** see if rrset needs to be updated in the cache */
static int static int
need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns) need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns,
int a_aaaa)
{ {
struct packed_rrset_data* newd = (struct packed_rrset_data*)nd; struct packed_rrset_data* newd = (struct packed_rrset_data*)nd;
struct packed_rrset_data* cached = (struct packed_rrset_data*)cd; struct packed_rrset_data* cached = (struct packed_rrset_data*)cd;
@@ -151,9 +153,13 @@ need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns)
return 0; return 0;
/* ghost-domain: never let an NS overwrite extend lifetime /* ghost-domain: never let an NS overwrite extend lifetime
* past the entry it replaces, regardless of trust. */ * past the entry it replaces, regardless of trust. */
if(ns && !TTL_IS_EXPIRED(cached->ttl, timenow) && /* Also for A/AAAA and it is glue. */
if((ns ||
(a_aaaa && cached->trust==rrset_trust_add_noAA))
&& !TTL_IS_EXPIRED(cached->ttl, timenow) &&
newd->ttl > cached->ttl) { newd->ttl > cached->ttl) {
size_t i; size_t i;
if(a_aaaa) newd->trust=rrset_trust_add_noAA;
newd->ttl = cached->ttl; newd->ttl = cached->ttl;
for(i=0; i<(newd->count+newd->rrsig_count); i++) for(i=0; i<(newd->count+newd->rrsig_count); i++)
if(newd->rr_ttl[i] > newd->ttl) if(newd->rr_ttl[i] > newd->ttl)
@@ -230,7 +236,8 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
equal = rrsetdata_equal((struct packed_rrset_data*)k->entry. equal = rrsetdata_equal((struct packed_rrset_data*)k->entry.
data, (struct packed_rrset_data*)e->data); data, (struct packed_rrset_data*)e->data);
if(!need_to_update_rrset(k->entry.data, e->data, timenow, if(!need_to_update_rrset(k->entry.data, e->data, timenow,
equal, (rrset_type==LDNS_RR_TYPE_NS))) { equal, (rrset_type==LDNS_RR_TYPE_NS),
(rrset_type==LDNS_RR_TYPE_A || rrset_type==LDNS_RR_TYPE_AAAA))) {
/* cache is superior, return that value */ /* cache is superior, return that value */
lock_rw_unlock(&e->lock); lock_rw_unlock(&e->lock);
ub_packed_rrset_parsedelete(k, alloc); ub_packed_rrset_parsedelete(k, alloc);
@@ -262,6 +269,29 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
return 0; return 0;
} }
/** See if the name is a within signer authority */
static int
dname_subdomain_rrsig_signers(uint8_t* dname,
struct ub_packed_rrset_key* rrset)
{
struct packed_rrset_data* d = (struct packed_rrset_data*)
rrset->entry.data;
size_t i;
if(!d || !d->rrsig_count)
return 0;
for(i=0; i<d->rrsig_count; i++) {
uint8_t* sname = NULL;
size_t slen = 0;
rrsig_get_signer(d->rr_data[d->count+i], d->rr_len[d->count+i],
&sname, &slen);
if(!sname || !slen)
return 0; /* malformed */
if(!dname_subdomain_c(dname, sname))
return 0; /* not a subdomain */
}
return 1;
}
void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache, void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache,
struct ub_packed_rrset_key* rrset, uint8_t* ce, size_t ce_len, struct ub_packed_rrset_key* rrset, uint8_t* ce, size_t ce_len,
struct alloc_cache* alloc, time_t timenow) struct alloc_cache* alloc, time_t timenow)
@@ -270,6 +300,14 @@ void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache,
uint8_t wc_dname[LDNS_MAX_DOMAINLEN+3]; uint8_t wc_dname[LDNS_MAX_DOMAINLEN+3];
uint8_t* new_dname; uint8_t* new_dname;
size_t new_dname_len; size_t new_dname_len;
/* See if the RRSIG signer name allows this wildcard,
* the new rrset should fall within the zone of the RRSIG signer(s). */
if(!dname_subdomain_rrsig_signers(ce, rrset)) {
verbose(VERB_ALGO, "wildcard canonical parent outside signer authority");
return;
}
rrset = packed_rrset_copy_alloc(rrset, alloc, timenow); rrset = packed_rrset_copy_alloc(rrset, alloc, timenow);
if(!rrset) { if(!rrset) {
log_err("malloc failure in rrset_cache_update_wildcard"); log_err("malloc failure in rrset_cache_update_wildcard");
+158 -75
View File
@@ -42,7 +42,6 @@
#ifdef HAVE_SYS_TYPES_H #ifdef HAVE_SYS_TYPES_H
# include <sys/types.h> # include <sys/types.h>
#endif #endif
#include <sys/time.h>
#include <limits.h> #include <limits.h>
#ifdef USE_TCP_FASTOPEN #ifdef USE_TCP_FASTOPEN
#include <netinet/tcp.h> #include <netinet/tcp.h>
@@ -2168,7 +2167,7 @@ void tcp_req_info_clear(struct tcp_req_info* req)
while(open) { while(open) {
nopen = open->next; nopen = open->next;
mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp, mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp,
NULL); NULL, NULL);
free(open); free(open);
open = nopen; open = nopen;
} }
@@ -3400,14 +3399,13 @@ doq_table_delete(struct doq_table* table)
} }
struct doq_timer* struct doq_timer*
doq_timer_find_time(struct doq_table* table, struct timeval* tv) doq_timer_find_time(struct doq_table* table, ngtcp2_tstamp ts)
{ {
struct doq_timer key; struct doq_timer key;
struct rbnode_type* node; struct rbnode_type* node;
log_assert(table != NULL); log_assert(table != NULL);
memset(&key, 0, sizeof(key)); memset(&key, 0, sizeof(key));
key.time.tv_sec = tv->tv_sec; key.time_mono = ts;
key.time.tv_usec = tv->tv_usec;
node = rbtree_search(table->timer_tree, &key); node = rbtree_search(table->timer_tree, &key);
if(node) if(node)
return (struct doq_timer*)node->key; return (struct doq_timer*)node->key;
@@ -3455,7 +3453,7 @@ doq_timer_list_remove(struct doq_table* table, struct doq_timer* timer)
if(!timer->timer_in_list) if(!timer->timer_in_list)
return; return;
/* The item in the rbtree has the list start and end. */ /* The item in the rbtree has the list start and end. */
rb_timer = doq_timer_find_time(table, &timer->time); rb_timer = doq_timer_find_time(table, timer->time_mono);
if(rb_timer) { if(rb_timer) {
if(timer->setlist_prev) if(timer->setlist_prev)
timer->setlist_prev->setlist_next = timer->setlist_next; timer->setlist_prev->setlist_next = timer->setlist_next;
@@ -3501,7 +3499,8 @@ doq_timer_unset(struct doq_table* table, struct doq_timer* timer)
} }
void doq_timer_set(struct doq_table* table, struct doq_timer* timer, void doq_timer_set(struct doq_table* table, struct doq_timer* timer,
struct doq_server_socket* worker_doq_socket, struct timeval* tv) struct doq_server_socket* worker_doq_socket, struct timeval* tv,
ngtcp2_tstamp ts)
{ {
struct doq_timer* rb_timer; struct doq_timer* rb_timer;
if(verbosity >= VERB_ALGO && timer->conn) { if(verbosity >= VERB_ALGO && timer->conn) {
@@ -3515,14 +3514,14 @@ void doq_timer_set(struct doq_table* table, struct doq_timer* timer,
(int)rel.tv_sec, (int)rel.tv_usec); (int)rel.tv_sec, (int)rel.tv_usec);
} }
if(timer->timer_in_tree || timer->timer_in_list) { if(timer->timer_in_tree || timer->timer_in_list) {
if(timer->time.tv_sec == tv->tv_sec && if(timer->time_mono == ts)
timer->time.tv_usec == tv->tv_usec)
return; /* already set on that time */ return; /* already set on that time */
doq_timer_unset(table, timer); doq_timer_unset(table, timer);
} }
timer->time.tv_sec = tv->tv_sec; timer->time_real.tv_sec = tv->tv_sec;
timer->time.tv_usec = tv->tv_usec; timer->time_real.tv_usec = tv->tv_usec;
rb_timer = doq_timer_find_time(table, tv); timer->time_mono = ts;
rb_timer = doq_timer_find_time(table, ts);
if(rb_timer) { if(rb_timer) {
/* There is a timeout already with this value. Timer is /* There is a timeout already with this value. Timer is
* added to the setlist. */ * added to the setlist. */
@@ -3598,15 +3597,29 @@ doq_conn_create(struct comm_point* c, struct doq_pkt_addr* paddr,
return conn; return conn;
} }
/** The arguments for doq stream tree del. */
struct doq_stream_tree_del_args {
/** The doq table. */
struct doq_table* table;
/** The doq connection for the stream. */
struct doq_conn* conn;
};
/** delete stream tree node */ /** delete stream tree node */
static void static void
stream_tree_del(rbnode_type* node, void* arg) stream_tree_del(rbnode_type* node, void* arg)
{ {
struct doq_table* table = (struct doq_table*)arg; struct doq_stream_tree_del_args* args = (struct doq_stream_tree_del_args*)arg;
struct doq_table* table = args->table;
struct doq_stream* stream; struct doq_stream* stream;
if(!node) if(!node)
return; return;
stream = (struct doq_stream*)node; stream = (struct doq_stream*)node;
if(stream->mesh_state) {
mesh_state_remove_reply(stream->mesh, stream->mesh_state,
args->conn->doq_socket->cp, NULL, stream);
stream->mesh_state = NULL;
}
if(stream->in) if(stream->in)
doq_table_quic_size_subtract(table, stream->inlen); doq_table_quic_size_subtract(table, stream->inlen);
if(stream->out) if(stream->out)
@@ -3629,7 +3642,11 @@ doq_conn_delete(struct doq_conn* conn, struct doq_table* table)
if(conn->ssl) if(conn->ssl)
SSL_set_app_data(conn->ssl, NULL); SSL_set_app_data(conn->ssl, NULL);
if(conn->stream_tree.count != 0) { if(conn->stream_tree.count != 0) {
traverse_postorder(&conn->stream_tree, stream_tree_del, table); struct doq_stream_tree_del_args args;
memset(&args, 0, sizeof(args));
args.table = table;
args.conn = conn;
traverse_postorder(&conn->stream_tree, stream_tree_del, &args);
} }
free(conn->key.dcid); free(conn->key.dcid);
SSL_free(conn->ssl); SSL_free(conn->ssl);
@@ -3702,13 +3719,9 @@ int doq_timer_cmp(const void* key1, const void* key2)
{ {
struct doq_timer* e = (struct doq_timer*)key1; struct doq_timer* e = (struct doq_timer*)key1;
struct doq_timer* f = (struct doq_timer*)key2; struct doq_timer* f = (struct doq_timer*)key2;
if(e->time.tv_sec < f->time.tv_sec) if(e->time_mono < f->time_mono)
return -1; return -1;
if(e->time.tv_sec > f->time.tv_sec) if(e->time_mono > f->time_mono)
return 1;
if(e->time.tv_usec < f->time.tv_usec)
return -1;
if(e->time.tv_usec > f->time.tv_usec)
return 1; return 1;
return 0; return 0;
} }
@@ -3942,6 +3955,11 @@ doq_stream_close(struct doq_conn* conn, struct doq_stream* stream,
if(stream->is_closed) if(stream->is_closed)
return 1; return 1;
stream->is_closed = 1; stream->is_closed = 1;
if(stream->mesh_state) {
mesh_state_remove_reply(stream->mesh, stream->mesh_state,
conn->doq_socket->cp, NULL, stream);
stream->mesh_state = NULL;
}
doq_stream_off_write_list(conn, stream); doq_stream_off_write_list(conn, stream);
if(send_shutdown) { if(send_shutdown) {
verbose(VERB_ALGO, "doq: shutdown stream_id %d with app_error_code %d", verbose(VERB_ALGO, "doq: shutdown stream_id %d with app_error_code %d",
@@ -3971,7 +3989,8 @@ doq_stream_close(struct doq_conn* conn, struct doq_stream* stream,
/** doq stream pick up answer data from buffer */ /** doq stream pick up answer data from buffer */
static int static int
doq_stream_pickup_answer(struct doq_stream* stream, struct sldns_buffer* buf) doq_stream_pickup_answer(struct doq_conn* conn, struct doq_stream* stream,
struct sldns_buffer* buf)
{ {
stream->is_answer_available = 1; stream->is_answer_available = 1;
if(stream->out) { if(stream->out) {
@@ -3981,6 +4000,11 @@ doq_stream_pickup_answer(struct doq_stream* stream, struct sldns_buffer* buf)
} }
stream->nwrite = 0; stream->nwrite = 0;
stream->outlen = sldns_buffer_limit(buf); stream->outlen = sldns_buffer_limit(buf);
if(!doq_table_quic_size_available(conn->doq_socket->table,
conn->doq_socket->cfg, stream->outlen)) {
verbose(VERB_ALGO, "doq stream: no space for reply length");
return 0;
}
/* For quic the output bytes have to stay allocated and available, /* For quic the output bytes have to stay allocated and available,
* for potential resends, until the remote end has acknowledged them. * for potential resends, until the remote end has acknowledged them.
* This includes the tcplen start uint16_t, in outlen_wire. */ * This includes the tcplen start uint16_t, in outlen_wire. */
@@ -4007,24 +4031,56 @@ doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream,
if(stream->out) if(stream->out)
doq_table_quic_size_subtract(conn->doq_socket->table, doq_table_quic_size_subtract(conn->doq_socket->table,
stream->outlen); stream->outlen);
if(!doq_stream_pickup_answer(stream, buf)) if(!doq_stream_pickup_answer(conn, stream, buf))
return 0; return 0;
doq_table_quic_size_add(conn->doq_socket->table, stream->outlen); doq_table_quic_size_add(conn->doq_socket->table, stream->outlen);
doq_stream_on_write_list(conn, stream); doq_stream_on_write_list(conn, stream);
doq_conn_write_enable(conn); doq_conn_write_enable(conn);
return 1; return 1;
} }
#endif /* HAVE_NGTCP2 */
void
doq_stream_add_meshstate(struct doq_stream* stream,
struct mesh_area* mesh, struct mesh_state* m)
{
#ifdef HAVE_NGTCP2
stream->mesh = mesh;
stream->mesh_state = m;
#else
(void)stream; (void)mesh; (void)m;
#endif
}
void
doq_stream_remove_mesh_state(struct doq_stream* stream)
{
#ifdef HAVE_NGTCP2
if(!stream)
return;
stream->mesh_state = NULL;
#else
(void)stream;
#endif
}
#ifdef HAVE_NGTCP2
/** doq stream data length has completed, allocations can be done. False on /** doq stream data length has completed, allocations can be done. False on
* allocation failure. */ * allocation failure. */
static int static int
doq_stream_datalen_complete(struct doq_stream* stream, struct doq_table* table) doq_stream_datalen_complete(struct doq_conn* conn, struct doq_stream* stream,
struct doq_table* table)
{ {
if(stream->inlen > 1024*1024) { if(stream->inlen > 1024*1024) {
log_err("doq stream in length too large %d", log_err("doq stream in length too large %d",
(int)stream->inlen); (int)stream->inlen);
return 0; return 0;
} }
if(!doq_table_quic_size_available(table, conn->doq_socket->cfg,
stream->inlen)) {
verbose(VERB_ALGO, "doq stream: no space for query length");
return 0;
}
stream->in = calloc(1, stream->inlen); stream->in = calloc(1, stream->inlen);
if(!stream->in) { if(!stream->in) {
log_err("doq could not read stream, calloc failed: " log_err("doq could not read stream, calloc failed: "
@@ -4069,6 +4125,7 @@ doq_stream_data_complete(struct doq_conn* conn, struct doq_stream* stream)
return 0; return 0;
} }
c->repinfo.doq_streamid = stream->stream_id; c->repinfo.doq_streamid = stream->stream_id;
c->repinfo.doq_stream = stream;
conn->doq_socket->current_conn = conn; conn->doq_socket->current_conn = conn;
fptr_ok(fptr_whitelist_comm_point(c->callback)); fptr_ok(fptr_whitelist_comm_point(c->callback));
if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo)) { if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo)) {
@@ -4085,8 +4142,9 @@ doq_stream_data_complete(struct doq_conn* conn, struct doq_stream* stream)
/** doq receive data for a stream, more bytes of the incoming data */ /** doq receive data for a stream, more bytes of the incoming data */
static int static int
doq_stream_recv_data(struct doq_stream* stream, const uint8_t* data, doq_stream_recv_data(struct doq_conn* conn, struct doq_stream* stream,
size_t datalen, int* recv_done, struct doq_table* table) const uint8_t* data, size_t datalen, int* recv_done,
struct doq_table* table)
{ {
int got_data = 0; int got_data = 0;
/* read the tcplength uint16_t at the start */ /* read the tcplength uint16_t at the start */
@@ -4107,7 +4165,7 @@ doq_stream_recv_data(struct doq_stream* stream, const uint8_t* data,
if(stream->nread == 2) { if(stream->nread == 2) {
/* the initial length value is completed */ /* the initial length value is completed */
stream->inlen = ntohs(tcplen); stream->inlen = ntohs(tcplen);
if(!doq_stream_datalen_complete(stream, table)) if(!doq_stream_datalen_complete(conn, stream, table))
return 0; return 0;
} else { } else {
/* store for later */ /* store for later */
@@ -4256,12 +4314,11 @@ doq_submit_new_token(struct doq_conn* conn)
ngtcp2_ssize tokenlen; ngtcp2_ssize tokenlen;
int ret; int ret;
const ngtcp2_path* path = ngtcp2_conn_get_path(conn->conn); const ngtcp2_path* path = ngtcp2_conn_get_path(conn->conn);
ngtcp2_tstamp ts = doq_get_timestamp_nanosec();
tokenlen = ngtcp2_crypto_generate_regular_token(token, tokenlen = ngtcp2_crypto_generate_regular_token(token,
conn->doq_socket->static_secret, conn->doq_socket->static_secret,
conn->doq_socket->static_secret_len, path->remote.addr, conn->doq_socket->static_secret_len, path->remote.addr,
path->remote.addrlen, ts); path->remote.addrlen, doq_get_timestamp_nanosec());
if(tokenlen < 0) { if(tokenlen < 0) {
log_err("doq ngtcp2_crypto_generate_regular_token failed"); log_err("doq ngtcp2_crypto_generate_regular_token failed");
return 1; return 1;
@@ -4324,8 +4381,7 @@ doq_stream_open_cb(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id,
verbose(VERB_ALGO, "doq: stream with this id already exists"); verbose(VERB_ALGO, "doq: stream with this id already exists");
return 0; return 0;
} }
if(stream_id != 0 && stream_id != 4 && /* allow one stream on a new connection */ if(!doq_table_quic_size_available(doq_conn->doq_socket->table,
!doq_table_quic_size_available(doq_conn->doq_socket->table,
doq_conn->doq_socket->cfg, sizeof(*stream) doq_conn->doq_socket->cfg, sizeof(*stream)
+ 100 /* estimated query in */ + 100 /* estimated query in */
+ 512 /* estimated response out */ + 512 /* estimated response out */
@@ -4383,8 +4439,8 @@ doq_recv_stream_data_cb(ngtcp2_conn* ATTR_UNUSED(conn), uint32_t flags,
return 0; return 0;
} }
if(datalen != 0) { if(datalen != 0) {
if(!doq_stream_recv_data(stream, data, datalen, &recv_done, if(!doq_stream_recv_data(doq_conn, stream, data, datalen,
doq_conn->doq_socket->table)) &recv_done, doq_conn->doq_socket->table))
return NGTCP2_ERR_CALLBACK_FAILURE; return NGTCP2_ERR_CALLBACK_FAILURE;
} }
if((flags&NGTCP2_STREAM_DATA_FLAG_FIN)!=0) { if((flags&NGTCP2_STREAM_DATA_FLAG_FIN)!=0) {
@@ -4453,6 +4509,29 @@ doq_stream_reset_cb(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id,
return 0; return 0;
} }
/** ngtcp2 extend_max_stream_data function */
int doq_extend_max_stream_data_cb(ngtcp2_conn* ATTR_UNUSED(conn),
int64_t stream_id, uint64_t max_data, void* user_data,
void* ATTR_UNUSED(stream_user_data))
{
struct doq_conn* doq_conn = (struct doq_conn*)user_data;
struct doq_stream* stream;
verbose(VERB_ALGO, "doq extend_max_stream_data stream id %d "
"max_data %d ", (int)stream_id, (int)max_data);
if(max_data == 0)
return 0;
stream = doq_stream_find(doq_conn, stream_id);
if(!stream) {
verbose(VERB_ALGO, "doq: unknown stream %d", (int)stream_id);
return 0;
}
if(!stream->is_answer_available)
return 0;
doq_stream_on_write_list(doq_conn, stream);
doq_conn_write_enable(doq_conn);
return 0;
}
/** ngtcp2 acked_stream_data_offset callback function */ /** ngtcp2 acked_stream_data_offset callback function */
static int static int
doq_acked_stream_data_offset_cb(ngtcp2_conn* ATTR_UNUSED(conn), doq_acked_stream_data_offset_cb(ngtcp2_conn* ATTR_UNUSED(conn),
@@ -4827,6 +4906,7 @@ doq_conn_setup(struct doq_conn* conn, uint8_t* scid, size_t scidlen,
callbacks.stream_open = doq_stream_open_cb; callbacks.stream_open = doq_stream_open_cb;
callbacks.stream_close = doq_stream_close_cb; callbacks.stream_close = doq_stream_close_cb;
callbacks.stream_reset = doq_stream_reset_cb; callbacks.stream_reset = doq_stream_reset_cb;
callbacks.extend_max_stream_data = doq_extend_max_stream_data_cb;
callbacks.acked_stream_data_offset = doq_acked_stream_data_offset_cb; callbacks.acked_stream_data_offset = doq_acked_stream_data_offset_cb;
callbacks.recv_stream_data = doq_recv_stream_data_cb; callbacks.recv_stream_data = doq_recv_stream_data_cb;
@@ -5104,23 +5184,30 @@ doq_conn_clear_conids(struct doq_conn* conn)
ngtcp2_tstamp doq_get_timestamp_nanosec(void) ngtcp2_tstamp doq_get_timestamp_nanosec(void)
{ {
#ifdef CLOCK_REALTIME
struct timespec tp; struct timespec tp;
memset(&tp, 0, sizeof(tp)); memset(&tp, 0, sizeof(tp));
/* Get a nanosecond time, that can be compared with the event base. */ #ifdef CLOCK_BOOTTIME
if(clock_gettime(CLOCK_REALTIME, &tp) == -1) { if(clock_gettime(CLOCK_BOOTTIME, &tp) == -1) {
log_err("clock_gettime failed: %s", strerror(errno)); #endif
if(clock_gettime(CLOCK_MONOTONIC, &tp) == -1) {
log_err("clock_gettime failed: %s", strerror(errno));
}
#ifdef CLOCK_BOOTTIME
} }
#endif
return ((uint64_t)tp.tv_sec)*((uint64_t)1000000000) + return ((uint64_t)tp.tv_sec)*((uint64_t)1000000000) +
((uint64_t)tp.tv_nsec); ((uint64_t)tp.tv_nsec);
#else }
static struct timeval doq_get_timevalue(void)
{
struct timeval tv; struct timeval tv;
memset(&tv, 0, sizeof(tv));
if(gettimeofday(&tv, NULL) < 0) { if(gettimeofday(&tv, NULL) < 0) {
log_err("gettimeofday failed: %s", strerror(errno)); log_err("gettimeofday failed: %s", strerror(errno));
memset(&tv, 0, sizeof(tv));
} }
return ((uint64_t)tv.tv_sec)*((uint64_t)1000000000) + return tv;
((uint64_t)tv.tv_usec)*((uint64_t)1000);
#endif /* CLOCK_REALTIME */
} }
/** doq start the closing period for the connection. */ /** doq start the closing period for the connection. */
@@ -5243,18 +5330,17 @@ doq_conn_recv(struct comm_point* c, struct doq_pkt_addr* paddr,
int* err_drop) int* err_drop)
{ {
int ret; int ret;
ngtcp2_tstamp ts;
struct ngtcp2_path path; struct ngtcp2_path path;
memset(&path, 0, sizeof(path)); memset(&path, 0, sizeof(path));
path.remote.addr = (struct sockaddr*)&paddr->addr; path.remote.addr = (struct sockaddr*)&paddr->addr;
path.remote.addrlen = paddr->addrlen; path.remote.addrlen = paddr->addrlen;
path.local.addr = (struct sockaddr*)&paddr->localaddr; path.local.addr = (struct sockaddr*)&paddr->localaddr;
path.local.addrlen = paddr->localaddrlen; path.local.addrlen = paddr->localaddrlen;
ts = doq_get_timestamp_nanosec();
ret = ngtcp2_conn_read_pkt(conn->conn, &path, pi, ret = ngtcp2_conn_read_pkt(conn->conn, &path, pi,
sldns_buffer_begin(c->doq_socket->pkt_buf), sldns_buffer_begin(c->doq_socket->pkt_buf),
sldns_buffer_limit(c->doq_socket->pkt_buf), ts); sldns_buffer_limit(c->doq_socket->pkt_buf),
doq_get_timestamp_nanosec());
if(ret != 0) { if(ret != 0) {
if(err_retry) if(err_retry)
*err_retry = 0; *err_retry = 0;
@@ -5342,7 +5428,6 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
{ {
struct doq_stream* stream = conn->stream_write_first; struct doq_stream* stream = conn->stream_write_first;
ngtcp2_path_storage ps; ngtcp2_path_storage ps;
ngtcp2_tstamp ts = doq_get_timestamp_nanosec();
size_t num_packets = 0, max_packets = 65535; size_t num_packets = 0, max_packets = 65535;
ngtcp2_path_storage_zero(&ps); ngtcp2_path_storage_zero(&ps);
@@ -5395,7 +5480,8 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
ret = ngtcp2_conn_writev_stream(conn->conn, &ps.path, &pi, ret = ngtcp2_conn_writev_stream(conn->conn, &ps.path, &pi,
sldns_buffer_begin(c->doq_socket->pkt_buf), sldns_buffer_begin(c->doq_socket->pkt_buf),
sldns_buffer_remaining(c->doq_socket->pkt_buf), sldns_buffer_remaining(c->doq_socket->pkt_buf),
&ndatalen, flags, stream_id, datav, datav_count, ts); &ndatalen, flags, stream_id, datav, datav_count,
doq_get_timestamp_nanosec());
if(ret < 0) { if(ret < 0) {
if(ret == NGTCP2_ERR_WRITE_MORE) { if(ret == NGTCP2_ERR_WRITE_MORE) {
verbose(VERB_ALGO, "doq: write more, ndatalen %d", (int)ndatalen); verbose(VERB_ALGO, "doq: write more, ndatalen %d", (int)ndatalen);
@@ -5410,26 +5496,20 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
continue; continue;
} else if(ret == NGTCP2_ERR_STREAM_DATA_BLOCKED) { } else if(ret == NGTCP2_ERR_STREAM_DATA_BLOCKED) {
verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_DATA_BLOCKED"); verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_DATA_BLOCKED");
#ifdef HAVE_NGTCP2_CCERR_DEFAULT if(stream) {
ngtcp2_ccerr_set_application_error( doq_stream_off_write_list(conn, stream);
&conn->ccerr, -1, NULL, 0); stream = stream->write_next;
#else continue;
ngtcp2_connection_close_error_set_application_error(&conn->last_error, -1, NULL, 0); } else {
#endif break;
if(err_drop)
*err_drop = 0;
if(!doq_conn_close_error(c, conn)) {
if(err_drop)
*err_drop = 1;
} }
return 0;
} else if(ret == NGTCP2_ERR_STREAM_SHUT_WR) { } else if(ret == NGTCP2_ERR_STREAM_SHUT_WR) {
verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_SHUT_WR"); verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_SHUT_WR");
#ifdef HAVE_NGTCP2_CCERR_DEFAULT #ifdef HAVE_NGTCP2_CCERR_DEFAULT
ngtcp2_ccerr_set_application_error( ngtcp2_ccerr_set_application_error(
&conn->ccerr, -1, NULL, 0); &conn->ccerr, DOQ_APP_ERROR_CODE, NULL, 0);
#else #else
ngtcp2_connection_close_error_set_application_error(&conn->last_error, -1, NULL, 0); ngtcp2_connection_close_error_set_application_error(&conn->last_error, DOQ_APP_ERROR_CODE, NULL, 0);
#endif #endif
if(err_drop) if(err_drop)
*err_drop = 0; *err_drop = 0;
@@ -5467,7 +5547,8 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
if(ret == 0) { if(ret == 0) {
/* congestion limited */ /* congestion limited */
doq_conn_write_disable(conn); doq_conn_write_disable(conn);
ngtcp2_conn_update_pkt_tx_time(conn->conn, ts); ngtcp2_conn_update_pkt_tx_time(conn->conn,
doq_get_timestamp_nanosec());
return 1; return 1;
} }
sldns_buffer_set_position(c->doq_socket->pkt_buf, ret); sldns_buffer_set_position(c->doq_socket->pkt_buf, ret);
@@ -5481,7 +5562,7 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
if(stream) if(stream)
stream = stream->write_next; stream = stream->write_next;
} }
ngtcp2_conn_update_pkt_tx_time(conn->conn, ts); ngtcp2_conn_update_pkt_tx_time(conn->conn, doq_get_timestamp_nanosec());
return 1; return 1;
} }
@@ -5558,32 +5639,35 @@ doq_table_pop_first(struct doq_table* table)
} }
int int
doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv) doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv, ngtcp2_tstamp* ts)
{ {
ngtcp2_tstamp expiry = ngtcp2_conn_get_expiry(conn->conn); ngtcp2_tstamp doq_expiry = ngtcp2_conn_get_expiry(conn->conn);
ngtcp2_tstamp now = doq_get_timestamp_nanosec(); ngtcp2_tstamp doq_now = doq_get_timestamp_nanosec();
ngtcp2_tstamp t; ngtcp2_tstamp t;
struct timeval now = doq_get_timevalue();
if(expiry <= now) { if(doq_expiry <= doq_now || doq_expiry == UINT64_MAX) {
/* UINT64_MAX means there is no next expiry. */
/* The timer has already expired, add with zero timeout. /* The timer has already expired, add with zero timeout.
* This should call the callback straight away. Calling it * This should call the callback straight away. Calling it
* from the event callbacks is cleaner than calling it here, * from the event callbacks is cleaner than calling it here,
* because then it is always called with the same locks and * because then it is always called with the same locks and
* so on. This routine only has the conn.lock. */ * so on. This routine only has the conn.lock. */
t = now; t = doq_now;
memcpy(tv, &now, sizeof(*tv));
} else { } else {
t = expiry; t = doq_expiry;
memset(tv, 0, sizeof(*tv));
tv->tv_sec = (doq_expiry - doq_now) / NGTCP2_SECONDS;
tv->tv_usec = ((doq_expiry - doq_now) / NGTCP2_MICROSECONDS)%1000000;
timeval_add(tv, &now);
} }
/* convert to timeval */ *ts = t;
memset(tv, 0, sizeof(*tv));
tv->tv_sec = t / NGTCP2_SECONDS;
tv->tv_usec = (t / NGTCP2_MICROSECONDS)%1000000;
/* If we already have a timer, is it the right value? */ /* If we already have a timer, is it the right value? */
if(conn->timer.timer_in_tree || conn->timer.timer_in_list) { if(conn->timer.timer_in_tree || conn->timer.timer_in_list) {
if(conn->timer.time.tv_sec == tv->tv_sec && if(conn->timer.time_mono == *ts)
conn->timer.time.tv_usec == tv->tv_usec)
return 0; return 0;
} }
return 1; return 1;
@@ -5604,13 +5688,12 @@ doq_conn_log_line(struct doq_conn* conn, char* s)
int int
doq_conn_handle_timeout(struct doq_conn* conn) doq_conn_handle_timeout(struct doq_conn* conn)
{ {
ngtcp2_tstamp now = doq_get_timestamp_nanosec();
int rv; int rv;
if(verbosity >= VERB_ALGO) if(verbosity >= VERB_ALGO)
doq_conn_log_line(conn, "timeout"); doq_conn_log_line(conn, "timeout");
rv = ngtcp2_conn_handle_expiry(conn->conn, now); rv = ngtcp2_conn_handle_expiry(conn->conn, doq_get_timestamp_nanosec());
if(rv != 0) { if(rv != 0) {
verbose(VERB_ALGO, "ngtcp2_conn_handle_expiry failed: %s", verbose(VERB_ALGO, "ngtcp2_conn_handle_expiry failed: %s",
ngtcp2_strerror(rv)); ngtcp2_strerror(rv));
+29 -8
View File
@@ -61,6 +61,8 @@ struct config_file;
struct addrinfo; struct addrinfo;
struct sldns_buffer; struct sldns_buffer;
struct tcl_list; struct tcl_list;
struct mesh_area;
struct mesh_state;
/** /**
* Listening for queries structure. * Listening for queries structure.
@@ -538,8 +540,11 @@ void doq_table_delete(struct doq_table* table);
struct doq_timer { struct doq_timer {
/** The rbnode in the tree sorted by timeout value. Key this struct. */ /** The rbnode in the tree sorted by timeout value. Key this struct. */
struct rbnode_type node; struct rbnode_type node;
/** The timeout value. Monotonic value used with ngtcp2.
* This time value is used for the tree operations. */
ngtcp2_tstamp time_mono;
/** The timeout value. Absolute time value. */ /** The timeout value. Absolute time value. */
struct timeval time; struct timeval time_real;
/** If the timer is in the time tree, with the node. */ /** If the timer is in the time tree, with the node. */
int timer_in_tree; int timer_in_tree;
/** If there are more timers with the exact same timeout value, /** If there are more timers with the exact same timeout value,
@@ -689,6 +694,11 @@ struct doq_stream {
uint8_t* out; uint8_t* out;
/** if the stream is on the write list */ /** if the stream is on the write list */
uint8_t on_write_list; uint8_t on_write_list;
/** The mesh area and mesh state, set when this stream's query was
* dispatched into the mesh; used to detach the reply on stream close */
struct mesh_area* mesh;
/** the mesh state for the query, is nonNULL when there is one. */
struct mesh_state* mesh_state;
/** the prev and next on the write list, if on the list */ /** the prev and next on the write list, if on the list */
struct doq_stream* write_prev, *write_next; struct doq_stream* write_prev, *write_next;
}; };
@@ -791,7 +801,16 @@ int doq_stream_close(struct doq_conn* conn, struct doq_stream* stream,
/** send reply for a connection */ /** send reply for a connection */
int doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream, int doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream,
struct sldns_buffer* buf); struct sldns_buffer* buf);
#endif /* HAVE_NGTCP2 */
/** add mesh state to doq stream */
void doq_stream_add_meshstate(struct doq_stream* stream,
struct mesh_area* mesh, struct mesh_state* m);
/** remove mesh state from doq stream */
void doq_stream_remove_mesh_state(struct doq_stream* stream);
#ifdef HAVE_NGTCP2
/** the connection has write interest, wants to write packets */ /** the connection has write interest, wants to write packets */
void doq_conn_write_enable(struct doq_conn* conn); void doq_conn_write_enable(struct doq_conn* conn);
@@ -813,10 +832,12 @@ struct doq_conn* doq_table_pop_first(struct doq_table* table);
* doq check if the timer for the conn needs to be changed. * doq check if the timer for the conn needs to be changed.
* @param conn: connection, caller must hold lock on it. * @param conn: connection, caller must hold lock on it.
* @param tv: time value, absolute time, returned. * @param tv: time value, absolute time, returned.
* @param ts: time stamp, absolute time, returned.
* @return true if timer needs to be set to tv, false if no change is needed * @return true if timer needs to be set to tv, false if no change is needed
* to the timer. The timer is already set to the right time in that case. * to the timer. The timer is already set to the right time in that case.
*/ */
int doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv); int doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv,
ngtcp2_tstamp* ts);
/** doq remove timer from tree */ /** doq remove timer from tree */
void doq_timer_tree_remove(struct doq_table* table, struct doq_timer* timer); void doq_timer_tree_remove(struct doq_table* table, struct doq_timer* timer);
@@ -829,11 +850,12 @@ void doq_timer_unset(struct doq_table* table, struct doq_timer* timer);
/** doq set the timer and add it. */ /** doq set the timer and add it. */
void doq_timer_set(struct doq_table* table, struct doq_timer* timer, void doq_timer_set(struct doq_table* table, struct doq_timer* timer,
struct doq_server_socket* worker_doq_socket, struct timeval* tv); struct doq_server_socket* worker_doq_socket, struct timeval* tv,
ngtcp2_tstamp ts);
/** doq find a timeout in the timer tree */ /** doq find a timeout in the timer tree */
struct doq_timer* doq_timer_find_time(struct doq_table* table, struct doq_timer* doq_timer_find_time(struct doq_table* table,
struct timeval* tv); ngtcp2_tstamp ts);
/** doq handle timeout for a connection. Pass conn locked. Returns false for /** doq handle timeout for a connection. Pass conn locked. Returns false for
* deletion. */ * deletion. */
@@ -851,6 +873,9 @@ int doq_table_quic_size_available(struct doq_table* table,
/** doq get the quic size value */ /** doq get the quic size value */
size_t doq_table_quic_size_get(struct doq_table* table); size_t doq_table_quic_size_get(struct doq_table* table);
/** get a timestamp in nanoseconds */
ngtcp2_tstamp doq_get_timestamp_nanosec(void);
#endif /* HAVE_NGTCP2 */ #endif /* HAVE_NGTCP2 */
char* set_ip_dscp(int socket, int addrfamily, int ds); char* set_ip_dscp(int socket, int addrfamily, int ds);
@@ -866,8 +891,4 @@ void doq_client_event_cb(int fd, short event, void* arg);
/** timer event callback for testcode/doqclient */ /** timer event callback for testcode/doqclient */
void doq_client_timer_cb(int fd, short event, void* arg); void doq_client_timer_cb(int fd, short event, void* arg);
#ifdef HAVE_NGTCP2
/** get a timestamp in nanoseconds */
ngtcp2_tstamp doq_get_timestamp_nanosec(void);
#endif
#endif /* LISTEN_DNSPORT_H */ #endif /* LISTEN_DNSPORT_H */
+1 -1
View File
@@ -573,7 +573,7 @@ enum respip_action {
respip_always_nxdomain = local_zone_always_nxdomain, respip_always_nxdomain = local_zone_always_nxdomain,
/** answer with nodata response */ /** answer with nodata response */
respip_always_nodata = local_zone_always_nodata, respip_always_nodata = local_zone_always_nodata,
/** answer with nodata response */ /** drop query */
respip_always_deny = local_zone_always_deny, respip_always_deny = local_zone_always_deny,
/** RPZ: truncate answer in order to force switch to tcp */ /** RPZ: truncate answer in order to force switch to tcp */
respip_truncate = local_zone_truncate, respip_truncate = local_zone_truncate,
+54 -14
View File
@@ -506,6 +506,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
"incoming query."); "incoming query.");
if(rep->c->use_h2) if(rep->c->use_h2)
http2_stream_remove_mesh_state(rep->c->h2_stream); http2_stream_remove_mesh_state(rep->c->h2_stream);
else if(rep->c->type == comm_doq && rep->doq_stream)
doq_stream_remove_mesh_state(rep->doq_stream);
comm_point_drop_reply(rep); comm_point_drop_reply(rep);
mesh->stats_dropped++; mesh->stats_dropped++;
return; return;
@@ -519,6 +521,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
"dropping incoming query."); "dropping incoming query.");
if(rep->c->use_h2) if(rep->c->use_h2)
http2_stream_remove_mesh_state(rep->c->h2_stream); http2_stream_remove_mesh_state(rep->c->h2_stream);
else if(rep->c->type == comm_doq && rep->doq_stream)
doq_stream_remove_mesh_state(rep->doq_stream);
comm_point_drop_reply(rep); comm_point_drop_reply(rep);
mesh->num_queries_replyaddr_limit++; mesh->num_queries_replyaddr_limit++;
return; return;
@@ -593,6 +597,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
added_tcp = 1; added_tcp = 1;
if(rep->c->use_h2) { if(rep->c->use_h2) {
http2_stream_add_meshstate(rep->c->h2_stream, mesh, s); http2_stream_add_meshstate(rep->c->h2_stream, mesh, s);
} else if(rep->c->type == comm_doq && rep->doq_stream) {
doq_stream_add_meshstate(rep->doq_stream, mesh, s);
} }
/* add serve expired timer if required and not already there */ /* add serve expired timer if required and not already there */
if(timeout && !mesh_serve_expired_init(s, timeout)) { if(timeout && !mesh_serve_expired_init(s, timeout)) {
@@ -648,6 +654,8 @@ servfail_mem:
qinfo, qid, qflags, edns); qinfo, qid, qflags, edns);
if(rep->c->use_h2) if(rep->c->use_h2)
http2_stream_remove_mesh_state(rep->c->h2_stream); http2_stream_remove_mesh_state(rep->c->h2_stream);
else if(rep->c->type == comm_doq && rep->doq_stream)
doq_stream_remove_mesh_state(rep->doq_stream);
comm_point_send_reply(rep); comm_point_send_reply(rep);
if(added_reply_without_accounting) { if(added_reply_without_accounting) {
mesh_remove_reply_without_accounting(s, repadded); mesh_remove_reply_without_accounting(s, repadded);
@@ -979,8 +987,7 @@ cfg_region_strlist_copy(struct regional* region, struct config_strlist* list)
return result; return result;
} }
/** Copy the client info to the query region. */ struct respip_client_info*
static struct respip_client_info*
mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo) mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo)
{ {
size_t i; size_t i;
@@ -1025,6 +1032,11 @@ mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo)
cinfo->view->name); cinfo->view->name);
if(!client_info->view_name) if(!client_info->view_name)
return NULL; return NULL;
} else if(cinfo->view_name) {
client_info->view_name = regional_strdup(region,
cinfo->view_name);
if(!client_info->view_name)
return NULL;
} }
return client_info; return client_info;
} }
@@ -1533,6 +1545,10 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
* for HTTP/2 stream to refer to mesh state, in case * for HTTP/2 stream to refer to mesh state, in case
* connection gets cleanup before HTTP/2 stream close. */ * connection gets cleanup before HTTP/2 stream close. */
r->h2_stream->mesh_state = NULL; r->h2_stream->mesh_state = NULL;
#ifdef HAVE_NGTCP2
} else if(r->query_reply.doq_stream) {
r->query_reply.doq_stream->mesh_state = NULL;
#endif
} }
/* send the reply */ /* send the reply */
/* We don't reuse the encoded answer if: /* We don't reuse the encoded answer if:
@@ -1687,9 +1703,9 @@ static void dns_error_reporting(struct module_qstate* qstate,
opt = edns_opt_list_find(qstate->edns_opts_back_in, opt = edns_opt_list_find(qstate->edns_opts_back_in,
LDNS_EDNS_REPORT_CHANNEL); LDNS_EDNS_REPORT_CHANNEL);
if(!opt) return; if(!opt) return;
agent_domain_len = opt->opt_len;
agent_domain = opt->opt_data; agent_domain = opt->opt_data;
if(dname_valid(agent_domain, agent_domain_len) < 3) { agent_domain_len = dname_valid(agent_domain, opt->opt_len);
if(agent_domain_len < 3) {
/* The agent domain needs to be a valid dname that is not the /* The agent domain needs to be a valid dname that is not the
* root; from RFC9567. */ * root; from RFC9567. */
return; return;
@@ -1827,6 +1843,8 @@ void mesh_query_done(struct mesh_state* mstate)
mstate->reply_list = NULL; mstate->reply_list = NULL;
if(r->query_reply.c->use_h2) if(r->query_reply.c->use_h2)
http2_stream_remove_mesh_state(r->h2_stream); http2_stream_remove_mesh_state(r->h2_stream);
else if(r->query_reply.doq_stream)
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
comm_point_drop_reply(&r->query_reply); comm_point_drop_reply(&r->query_reply);
mstate->reply_list = reply_list; mstate->reply_list = reply_list;
log_assert(mstate->s.env->mesh->num_reply_addrs > 0); log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
@@ -1864,6 +1882,8 @@ void mesh_query_done(struct mesh_state* mstate)
mstate->reply_list = NULL; mstate->reply_list = NULL;
if(r->query_reply.c->use_h2) { if(r->query_reply.c->use_h2) {
http2_stream_remove_mesh_state(r->h2_stream); http2_stream_remove_mesh_state(r->h2_stream);
} else if(r->query_reply.doq_stream) {
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
} }
comm_point_drop_reply(&r->query_reply); comm_point_drop_reply(&r->query_reply);
mstate->reply_list = reply_list; mstate->reply_list = reply_list;
@@ -2079,6 +2099,8 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
if(rep->c->use_h2) if(rep->c->use_h2)
r->h2_stream = rep->c->h2_stream; r->h2_stream = rep->c->h2_stream;
else r->h2_stream = NULL; else r->h2_stream = NULL;
if(rep->c->type != comm_doq)
r->query_reply.doq_stream = NULL;
/* Data related to local alias stored in 'qinfo' (if any) is ephemeral /* Data related to local alias stored in 'qinfo' (if any) is ephemeral
* and can be different for different original queries (even if the * and can be different for different original queries (even if the
@@ -2437,7 +2459,8 @@ void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp,
} }
void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
struct comm_point* cp, struct http2_stream* h2_stream) struct comm_point* cp, struct http2_stream* h2_stream,
struct doq_stream* doq_stream)
{ {
struct mesh_reply* n, *prev = NULL; struct mesh_reply* n, *prev = NULL;
n = m->reply_list; n = m->reply_list;
@@ -2446,7 +2469,9 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
if(!n) return; /* nothing to remove, also no accounting needed */ if(!n) return; /* nothing to remove, also no accounting needed */
while(n) { while(n) {
if(n->query_reply.c == cp if(n->query_reply.c == cp
&& (!h2_stream || n->h2_stream == h2_stream)) { && (!h2_stream || n->h2_stream == h2_stream)
&& (!doq_stream || n->query_reply.doq_stream == doq_stre
am)) {
/* unlink it */ /* unlink it */
if(prev) prev->next = n->next; if(prev) prev->next = n->next;
else m->reply_list = n->next; else m->reply_list = n->next;
@@ -2459,6 +2484,10 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
* share the same comm_point); make sure the streams * share the same comm_point); make sure the streams
* don't point back. */ * don't point back. */
if(n->h2_stream) n->h2_stream->mesh_state = NULL; if(n->h2_stream) n->h2_stream->mesh_state = NULL;
#ifdef HAVE_NGTCP2
if(n->query_reply.doq_stream)
n->query_reply.doq_stream->mesh_state = NULL;
#endif
/* prev = prev; */ /* prev = prev; */
n = n->next; n = n->next;
@@ -2499,9 +2528,10 @@ apply_respip_action(struct module_qstate* qstate,
/* xxx_deny actions mean dropping the reply, unless the original reply /* xxx_deny actions mean dropping the reply, unless the original reply
* was redirected to response-ip data. */ * was redirected to response-ip data. */
if((actinfo->action == respip_deny || if(actinfo->action == respip_always_deny ||
((actinfo->action == respip_deny ||
actinfo->action == respip_inform_deny) && actinfo->action == respip_inform_deny) &&
*encode_repp == rep) *encode_repp == rep))
*encode_repp = NULL; *encode_repp = NULL;
return 1; return 1;
@@ -2566,12 +2596,15 @@ mesh_serve_expired_callback(void* arg)
qstate->client_info, &actinfo, msg->rep, &alias_rrset, &encode_rep, qstate->client_info, &actinfo, msg->rep, &alias_rrset, &encode_rep,
qstate->env->auth_zones)) { qstate->env->auth_zones)) {
return; return;
} else if(partial_rep && } else if(partial_rep) {
!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep, if(!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep,
qstate->client_info, must_validate, &encode_rep, qstate->region, qstate->client_info, must_validate, &encode_rep, qstate->region,
qstate->env->auth_zones, qstate->env->views, qstate->env->auth_zones, qstate->env->views,
qstate->env->respip_set)) { qstate->env->respip_set)) {
return; return;
}
/* merge succeeded; final reply, no further alias pass */
partial_rep = NULL;
} }
if(!encode_rep || alias_rrset) { if(!encode_rep || alias_rrset) {
if(!encode_rep) { if(!encode_rep) {
@@ -2582,6 +2615,7 @@ mesh_serve_expired_callback(void* arg)
partial_rep = encode_rep; partial_rep = encode_rep;
} }
} }
msg->rep = encode_rep;
/* We've found a partial reply ending with an /* We've found a partial reply ending with an
* alias. Replace the lookup qinfo for the * alias. Replace the lookup qinfo for the
* alias target and lookup the cache again to * alias target and lookup the cache again to
@@ -2608,9 +2642,10 @@ mesh_serve_expired_callback(void* arg)
log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep); log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep);
for(r = mstate->reply_list; r; r = r->next) { for(r = mstate->reply_list; r; r = r->next) {
struct timeval old; if(mesh_is_udp(r)) {
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); struct timeval old;
if(mstate->s.env->cfg->discard_timeout != 0 && timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
if(mstate->s.env->cfg->discard_timeout != 0 &&
((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 > ((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 >
mstate->s.env->cfg->discard_timeout) { mstate->s.env->cfg->discard_timeout) {
/* Drop the reply, it is too old */ /* Drop the reply, it is too old */
@@ -2626,10 +2661,15 @@ mesh_serve_expired_callback(void* arg)
mstate->reply_list = NULL; mstate->reply_list = NULL;
if(r->query_reply.c->use_h2) if(r->query_reply.c->use_h2)
http2_stream_remove_mesh_state(r->h2_stream); http2_stream_remove_mesh_state(r->h2_stream);
else if(r->query_reply.doq_stream)
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
comm_point_drop_reply(&r->query_reply); comm_point_drop_reply(&r->query_reply);
mstate->reply_list = reply_list; mstate->reply_list = reply_list;
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
mstate->s.env->mesh->num_reply_addrs--;
mstate->s.env->mesh->num_queries_discard_timeout++; mstate->s.env->mesh->num_queries_discard_timeout++;
continue; continue;
}
} }
i++; i++;
+8 -1
View File
@@ -707,9 +707,12 @@ void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp,
* @param cp: the comm_point to remove from the list. * @param cp: the comm_point to remove from the list.
* @param h2_stream: if not NULL, it specifies the h2_stream to match * @param h2_stream: if not NULL, it specifies the h2_stream to match
* for the delete. * for the delete.
* @param doq_stream: if not NULL, it specifies the doq_stream to match
* for the delete.
*/ */
void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
struct comm_point* cp, struct http2_stream* h2_stream); struct comm_point* cp, struct http2_stream* h2_stream,
struct doq_stream* doq_stream);
/** Callback for when the serve expired client timer has run out. Tries to /** Callback for when the serve expired client timer has run out. Tries to
* find an expired answer in the cache and reply that to the client. * find an expired answer in the cache and reply that to the client.
@@ -761,4 +764,8 @@ void mesh_respond_serve_expired(struct mesh_state* mstate);
void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo, void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, mesh_cb_func_type cb, void* cb_arg, void* unique_info); uint16_t qflags, mesh_cb_func_type cb, void* cb_arg, void* unique_info);
/** Copy the client info to the query region. */
struct respip_client_info* mesh_copy_client_info(struct regional* region,
struct respip_client_info* cinfo);
#endif /* SERVICES_MESH_H */ #endif /* SERVICES_MESH_H */
+321 -67
View File
@@ -208,6 +208,7 @@ static void
waiting_tcp_delete(struct waiting_tcp* w) waiting_tcp_delete(struct waiting_tcp* w)
{ {
if(!w) return; if(!w) return;
free(w->tls_auth_name);
if(w->timer) if(w->timer)
comm_timer_delete(w->timer); comm_timer_delete(w->timer);
free(w); free(w);
@@ -1480,7 +1481,7 @@ portcomm_loweruse(struct outside_network* outnet, struct port_comm* pc)
pif = pc->pif; pif = pc->pif;
log_assert(pif->inuse > 0); log_assert(pif->inuse > 0);
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
pif->avail_ports[pif->avail_total - pif->inuse] = pc->number; shared_ports_return_port(outnet->shared_ports, pif->shpif, pc->number);
#endif #endif
pif->inuse--; pif->inuse--;
pif->out[pc->index] = pif->out[pif->inuse]; pif->out[pc->index] = pif->out[pif->inuse];
@@ -1694,15 +1695,9 @@ create_pending_tcp(struct outside_network* outnet, size_t bufsize)
} }
/** setup an outgoing interface, ready address */ /** setup an outgoing interface, ready address */
static int setup_if(struct port_if* pif, const char* addrstr, static int setup_if(struct port_if* pif, const char* addrstr, size_t numfd,
int* avail, int numavail, size_t numfd) struct shared_ports* shp)
{ {
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
pif->avail_total = numavail;
pif->avail_ports = (int*)memdup(avail, (size_t)numavail*sizeof(int));
if(!pif->avail_ports)
return 0;
#endif
if(!ipstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen) && if(!ipstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen) &&
!netblockstrtoaddr(addrstr, UNBOUND_DNS_PORT, !netblockstrtoaddr(addrstr, UNBOUND_DNS_PORT,
&pif->addr, &pif->addrlen, &pif->pfxlen)) &pif->addr, &pif->addrlen, &pif->pfxlen))
@@ -1712,6 +1707,12 @@ static int setup_if(struct port_if* pif, const char* addrstr,
log_err("num_ports exceeds INT_MAX"); log_err("num_ports exceeds INT_MAX");
return 0; return 0;
} }
#endif
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
pif->shpif = shared_ports_find_if(shp, &pif->addr, pif->addrlen,
pif->pfxlen);
#else
(void)shp;
#endif #endif
pif->maxout = (int)numfd; pif->maxout = (int)numfd;
pif->inuse = 0; pif->inuse = 0;
@@ -1726,12 +1727,12 @@ struct outside_network*
outside_network_create(struct comm_base *base, size_t bufsize, outside_network_create(struct comm_base *base, size_t bufsize,
size_t num_ports, char** ifs, int num_ifs, int do_ip4, size_t num_ports, char** ifs, int num_ifs, int do_ip4,
int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra, int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra,
struct ub_randstate* rnd, int use_caps_for_id, int* availports, struct ub_randstate* rnd, int use_caps_for_id,
int numavailports, size_t unwanted_threshold, int tcp_mss, size_t unwanted_threshold, int tcp_mss,
void (*unwanted_action)(void*), void* unwanted_param, int do_udp, void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
void* sslctx, int delayclose, int tls_use_sni, struct dt_env* dtenv, void* sslctx, int delayclose, int tls_use_sni, struct dt_env* dtenv,
int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout, int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout,
int tcp_auth_query_timeout) int tcp_auth_query_timeout, struct shared_ports* shared_ports)
{ {
struct outside_network* outnet = (struct outside_network*) struct outside_network* outnet = (struct outside_network*)
calloc(1, sizeof(struct outside_network)); calloc(1, sizeof(struct outside_network));
@@ -1766,6 +1767,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
outnet->do_udp = do_udp; outnet->do_udp = do_udp;
outnet->tcp_mss = tcp_mss; outnet->tcp_mss = tcp_mss;
outnet->ip_dscp = dscp; outnet->ip_dscp = dscp;
outnet->shared_ports = shared_ports;
#ifndef S_SPLINT_S #ifndef S_SPLINT_S
if(delayclose) { if(delayclose) {
outnet->delayclose = 1; outnet->delayclose = 1;
@@ -1776,7 +1778,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
if(udp_connect) { if(udp_connect) {
outnet->udp_connect = 1; outnet->udp_connect = 1;
} }
if(numavailports == 0 || num_ports == 0) { if(num_ports == 0) {
log_err("no outgoing ports available"); log_err("no outgoing ports available");
outside_network_delete(outnet); outside_network_delete(outnet);
return NULL; return NULL;
@@ -1844,13 +1846,13 @@ outside_network_create(struct comm_base *base, size_t bufsize,
/* allocate interfaces */ /* allocate interfaces */
if(num_ifs == 0) { if(num_ifs == 0) {
if(do_ip4 && !setup_if(&outnet->ip4_ifs[0], "0.0.0.0", if(do_ip4 && !setup_if(&outnet->ip4_ifs[0], "0.0.0.0",
availports, numavailports, num_ports)) { num_ports, outnet->shared_ports)) {
log_err("malloc failed"); log_err("malloc failed");
outside_network_delete(outnet); outside_network_delete(outnet);
return NULL; return NULL;
} }
if(do_ip6 && !setup_if(&outnet->ip6_ifs[0], "::", if(do_ip6 && !setup_if(&outnet->ip6_ifs[0], "::",
availports, numavailports, num_ports)) { num_ports, outnet->shared_ports)) {
log_err("malloc failed"); log_err("malloc failed");
outside_network_delete(outnet); outside_network_delete(outnet);
return NULL; return NULL;
@@ -1861,7 +1863,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
for(i=0; i<num_ifs; i++) { for(i=0; i<num_ifs; i++) {
if(str_is_ip6(ifs[i]) && do_ip6) { if(str_is_ip6(ifs[i]) && do_ip6) {
if(!setup_if(&outnet->ip6_ifs[done_6], ifs[i], if(!setup_if(&outnet->ip6_ifs[done_6], ifs[i],
availports, numavailports, num_ports)){ num_ports, outnet->shared_ports)){
log_err("malloc failed"); log_err("malloc failed");
outside_network_delete(outnet); outside_network_delete(outnet);
return NULL; return NULL;
@@ -1870,7 +1872,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
} }
if(!str_is_ip6(ifs[i]) && do_ip4) { if(!str_is_ip6(ifs[i]) && do_ip4) {
if(!setup_if(&outnet->ip4_ifs[done_4], ifs[i], if(!setup_if(&outnet->ip4_ifs[done_4], ifs[i],
availports, numavailports, num_ports)){ num_ports, outnet->shared_ports)){
log_err("malloc failed"); log_err("malloc failed");
outside_network_delete(outnet); outside_network_delete(outnet);
return NULL; return NULL;
@@ -1948,9 +1950,6 @@ outside_network_delete(struct outside_network* outnet)
comm_point_delete(pc->cp); comm_point_delete(pc->cp);
free(pc); free(pc);
} }
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
free(outnet->ip4_ifs[i].avail_ports);
#endif
free(outnet->ip4_ifs[i].out); free(outnet->ip4_ifs[i].out);
} }
free(outnet->ip4_ifs); free(outnet->ip4_ifs);
@@ -1964,9 +1963,6 @@ outside_network_delete(struct outside_network* outnet)
comm_point_delete(pc->cp); comm_point_delete(pc->cp);
free(pc); free(pc);
} }
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
free(outnet->ip6_ifs[i].avail_ports);
#endif
free(outnet->ip6_ifs[i].out); free(outnet->ip6_ifs[i].out);
} }
free(outnet->ip6_ifs); free(outnet->ip6_ifs);
@@ -2176,7 +2172,10 @@ static int
select_ifport(struct outside_network* outnet, struct pending* pend, select_ifport(struct outside_network* outnet, struct pending* pend,
int num_if, struct port_if* ifs) int num_if, struct port_if* ifs)
{ {
int my_if, my_port, fd, portno, inuse, tries=0; int my_if, fd, portno, inuse, tries=0;
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
int reused;
#endif
struct port_if* pif; struct port_if* pif;
/* randomly select interface and port */ /* randomly select interface and port */
if(num_if == 0) { if(num_if == 0) {
@@ -2190,37 +2189,35 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
my_if = ub_random_max(outnet->rnd, num_if); my_if = ub_random_max(outnet->rnd, num_if);
pif = &ifs[my_if]; pif = &ifs[my_if];
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
if(outnet->udp_connect) { if(!shared_ports_fetch_random(outnet->shared_ports,
/* if we connect() we cannot reuse fds for a port */ pif->shpif, outnet->rnd, outnet->udp_connect,
if(pif->inuse >= pif->avail_total) { pif->inuse, &portno, &reused)) {
tries++; tries++;
if(tries < MAX_PORT_RETRY) if(tries < MAX_PORT_RETRY)
continue; continue;
log_err("failed to find an open port, drop msg"); log_err("failed to find an open port, drop msg");
return 0; return 0;
} }
my_port = pif->inuse + ub_random_max(outnet->rnd, if(reused) {
pif->avail_total - pif->inuse); /* port already open */
} else { log_assert(portno < pif->inuse);
my_port = ub_random_max(outnet->rnd, pif->avail_total); pend->pc = pif->out[portno];
if(my_port < pif->inuse) { verbose(VERB_ALGO, "using UDP if=%d port=%d",
/* port already open */ my_if, pend->pc->number);
pend->pc = pif->out[my_port]; break;
verbose(VERB_ALGO, "using UDP if=%d port=%d",
my_if, pend->pc->number);
break;
}
} }
/* try to open new port, if fails, loop to try again */
log_assert(pif->inuse < pif->maxout);
portno = pif->avail_ports[my_port - pif->inuse];
#else #else
my_port = portno = 0; portno = 0;
#endif #endif
/* try to open new port, if fails, loop to try again */
fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen, fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen,
portno, &inuse, outnet->rnd, outnet->ip_dscp); portno, &inuse, outnet->rnd, outnet->ip_dscp);
if(fd == -1 && !inuse) { if(fd == -1 && !inuse) {
/* nonrecoverable error making socket */ /* nonrecoverable error making socket */
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
shared_ports_return_port(outnet->shared_ports,
pif->shpif, portno);
#endif
return 0; return 0;
} }
if(fd != -1) { if(fd != -1) {
@@ -2237,6 +2234,11 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
pend->addrlen); pend->addrlen);
} }
sock_close(fd); sock_close(fd);
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
shared_ports_return_port(
outnet->shared_ports,
pif->shpif, portno);
#endif
return 0; return 0;
} }
} }
@@ -2254,14 +2256,14 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
/* grab port in interface */ /* grab port in interface */
pif->out[pif->inuse] = pend->pc; pif->out[pif->inuse] = pend->pc;
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
pif->avail_ports[my_port - pif->inuse] =
pif->avail_ports[pif->avail_total-pif->inuse-1];
#endif
pif->inuse++; pif->inuse++;
break; break;
} }
/* failed, already in use */ /* failed, already in use */
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
shared_ports_return_port(outnet->shared_ports, pif->shpif,
portno);
#endif
verbose(VERB_QUERY, "port %d in use, trying another", portno); verbose(VERB_QUERY, "port %d in use, trying another", portno);
tries++; tries++;
if(tries == MAX_PORT_RETRY) { if(tries == MAX_PORT_RETRY) {
@@ -2553,7 +2555,16 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
w->cb = callback; w->cb = callback;
w->cb_arg = callback_arg; w->cb_arg = callback_arg;
w->ssl_upstream = sq->ssl_upstream; w->ssl_upstream = sq->ssl_upstream;
w->tls_auth_name = sq->tls_auth_name; if(sq->tls_auth_name) {
w->tls_auth_name = strdup(sq->tls_auth_name);
if(!w->tls_auth_name) {
comm_timer_delete(w->timer);
free(w);
return NULL;
}
} else {
w->tls_auth_name = NULL;
}
w->timeout = timeout; w->timeout = timeout;
w->id_node.key = NULL; w->id_node.key = NULL;
w->write_wait_prev = NULL; w->write_wait_prev = NULL;
@@ -3645,13 +3656,16 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
{ {
struct sockaddr_storage* addr; struct sockaddr_storage* addr;
socklen_t addrlen; socklen_t addrlen;
int i, try, pnum, dscp; int i, try, dscp;
struct port_if* pif; struct port_if* pif;
/* create fd */ /* create fd */
dscp = outnet->ip_dscp; dscp = outnet->ip_dscp;
for(try = 0; try<1000; try++) { for(try = 0; try<1000; try++) {
int port = 0; int port = 0;
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
int reused = 0;
#endif
int freebind = 0; int freebind = 0;
int noproto = 0; int noproto = 0;
int inuse = 0; int inuse = 0;
@@ -3680,16 +3694,18 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
addr = &pif->addr; addr = &pif->addr;
addrlen = pif->addrlen; addrlen = pif->addrlen;
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
pnum = ub_random_max(outnet->rnd, pif->avail_total); if(!shared_ports_fetch_random(outnet->shared_ports,
if(pnum < pif->inuse) { pif->shpif, outnet->rnd, 0, pif->inuse,
/* port already open */ &port, &reused)) {
port = pif->out[pnum]->number; /* try again, perhaps another interface. */
} else { continue;
/* unused ports in start part of array */ }
port = pif->avail_ports[pnum - pif->inuse]; if(reused) {
log_assert(port < pif->inuse);
port = pif->out[port]->number;
} }
#else #else
pnum = port = 0; port = 0;
#endif #endif
if(addr_is_ip6(to_addr, to_addrlen)) { if(addr_is_ip6(to_addr, to_addrlen)) {
struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr; struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr;
@@ -3704,6 +3720,14 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
(struct sockaddr*)addr, addrlen, 1, &inuse, &noproto, (struct sockaddr*)addr, addrlen, 1, &inuse, &noproto,
0, 0, 0, NULL, 0, freebind, 0, dscp); 0, 0, 0, NULL, 0, freebind, 0, dscp);
} }
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
if(!reused) {
/* Return the port to the pool, since the caller does
* not keep track of it, also have done fd, and bind. */
shared_ports_return_port(outnet->shared_ports,
pif->shpif, port);
}
#endif
if(fd != -1) { if(fd != -1) {
return fd; return fd;
} }
@@ -3961,11 +3985,7 @@ if_get_mem(struct port_if* pif)
{ {
size_t s; size_t s;
int i; int i;
s = sizeof(*pif) + s = sizeof(*pif) + sizeof(struct port_comm*)*pif->maxout;
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
sizeof(int)*pif->avail_total +
#endif
sizeof(struct port_comm*)*pif->maxout;
for(i=0; i<pif->inuse; i++) for(i=0; i<pif->inuse; i++)
s += sizeof(*pif->out[i]) + s += sizeof(*pif->out[i]) +
comm_point_get_mem(pif->out[i]->cp); comm_point_get_mem(pif->out[i]->cp);
@@ -4053,3 +4073,237 @@ serviced_get_mem(struct serviced_query* sq)
return s; return s;
} }
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
/** Setup shared port interface */
static int shared_ports_setup_if(struct shared_ports_if* shpif, char* str,
int* availports, int numavailports)
{
shpif->avail_ports = (int*)memdup(availports,
(size_t)numavailports*sizeof(int));
if(!shpif->avail_ports)
return 0;
shpif->avail_total = numavailports;
shpif->inuse = 0;
shpif->pfxlen = 0;
if(!ipstrtoaddr(str, UNBOUND_DNS_PORT, &shpif->addr, &shpif->addrlen) &&
!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &shpif->addr,
&shpif->addrlen, &shpif->pfxlen))
return 0;
return 1;
}
#endif
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
/** Allocate shared ports interfaces */
static int shared_ports_alloc_ifs(struct shared_ports* shp, char** ifs,
int num_ifs, int do_ip4, int do_ip6, int* availports,
int numavailports)
{
#ifndef INET6
do_ip6 = 0;
#endif
calc_num46(ifs, num_ifs, do_ip4, do_ip6,
&shp->num_ip4, &shp->num_ip6);
if(shp->num_ip4 != 0) {
if(!(shp->ip4_ifs = (struct shared_ports_if*)calloc(
(size_t)shp->num_ip4,
sizeof(struct shared_ports_if))))
return 0;
}
if(shp->num_ip6 != 0) {
if(!(shp->ip6_ifs = (struct shared_ports_if*)calloc(
(size_t)shp->num_ip6,
sizeof(struct shared_ports_if))))
return 0;
}
if(num_ifs == 0) {
if(do_ip4 && !shared_ports_setup_if(&shp->ip4_ifs[0],
"0.0.0.0", availports, numavailports))
return 0;
if(do_ip6 && !shared_ports_setup_if(&shp->ip6_ifs[0],
"::", availports, numavailports))
return 0;
} else {
size_t done_4 = 0, done_6 = 0;
int i;
for(i=0; i<num_ifs; i++) {
if(str_is_ip6(ifs[i]) && do_ip6) {
if(!shared_ports_setup_if(&shp->ip6_ifs[done_6],
ifs[i], availports, numavailports))
return 0;
done_6++;
}
if(!str_is_ip6(ifs[i]) && do_ip4) {
if(!shared_ports_setup_if(&shp->ip4_ifs[done_4],
ifs[i], availports, numavailports))
return 0;
done_4++;
}
}
}
return 1;
}
#endif
struct shared_ports* shared_ports_create(char** ifs, int num_ifs, int do_ip4,
int do_ip6, int* availports, int numavailports)
{
struct shared_ports* shp = calloc(1, sizeof(*shp));
if(!shp) {
log_err("malloc failed");
return NULL;
}
lock_basic_init(&shp->lock);
lock_protect(&shp->lock, shp, sizeof(*shp));
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
/* Allocate interfaces */
if(!shared_ports_alloc_ifs(shp, ifs, num_ifs, do_ip4, do_ip6,
availports, numavailports)) {
log_err("malloc failed");
shared_ports_delete(shp);
return NULL;
}
#else
(void)ifs; (void)num_ifs; (void)do_ip4; (void)do_ip6;
(void)availports; (void)numavailports;
#endif
return shp;
}
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
/** Delete shared ports interface structure */
static void shared_ports_if_delete(struct shared_ports_if* shpif)
{
if(!shpif)
return;
free(shpif->avail_ports);
}
#endif
void shared_ports_delete(struct shared_ports* shp)
{
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
int i;
#endif
if(!shp)
return;
lock_basic_destroy(&shp->lock);
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
for(i=0; i<shp->num_ip4; i++) {
shared_ports_if_delete(&shp->ip4_ifs[i]);
}
free(shp->ip4_ifs);
for(i=0; i<shp->num_ip6; i++) {
shared_ports_if_delete(&shp->ip6_ifs[i]);
}
free(shp->ip6_ifs);
#endif
free(shp);
}
struct shared_ports_if* shared_ports_find_if(struct shared_ports* shp,
struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen)
{
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
struct shared_ports_if* ret, *ifs = NULL;
int i, num_ifs = 0;
lock_basic_lock(&shp->lock);
if(addr_is_ip6(addr, addrlen)) {
ifs = shp->ip6_ifs;
num_ifs = shp->num_ip6;
} else {
ifs = shp->ip4_ifs;
num_ifs = shp->num_ip4;
}
for(i=0; i<num_ifs; i++) {
if(sockaddr_cmp(addr, addrlen, &ifs[i].addr,
ifs[i].addrlen) == 0
&& pfxlen == ifs[i].pfxlen) {
ret = &ifs[i];
lock_basic_unlock(&shp->lock);
return ret;
}
}
lock_basic_unlock(&shp->lock);
return NULL;
#else
(void)shp; (void)addr; (void)addrlen; (void)pfxlen;
return NULL;
#endif
}
int shared_ports_fetch_random(struct shared_ports* shp,
struct shared_ports_if* shpif, struct ub_randstate* rnd,
int udp_connect, int reusenum, int* port, int* reused)
{
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
int portno = 0, my_port = 0;
if(!shpif)
return 0;
lock_basic_lock(&shp->lock);
if(udp_connect) {
/* if we connect() we cannot reuse fds for a port. */
if(shpif->inuse >= shpif->avail_total) {
lock_basic_unlock(&shp->lock);
return 0;
}
my_port = ub_random_max(rnd,
shpif->avail_total - shpif->inuse);
} else {
/* select from free ports and open ports on this thread. */
if(shpif->inuse >= shpif->avail_total) {
lock_basic_unlock(&shp->lock);
if(reusenum == 0) {
return 0;
}
my_port = ub_random_max(rnd, reusenum);
*port = my_port;
*reused = 1;
return 1;
}
my_port = ub_random_max(rnd, shpif->avail_total - shpif->inuse
+ reusenum);
if(my_port < reusenum) {
/* port already open */
lock_basic_unlock(&shp->lock);
*port = my_port;
*reused = 1;
return 1;
}
my_port -= reusenum;
}
log_assert(shpif->inuse < shpif->avail_total);
log_assert(my_port >= 0 && my_port < shpif->avail_total);
portno = shpif->avail_ports[my_port];
shpif->avail_ports[my_port] =
shpif->avail_ports[shpif->avail_total-shpif->inuse-1];
shpif->inuse++;
lock_basic_unlock(&shp->lock);
*port = portno;
*reused = 0;
return 1;
#else
(void)shp; (void)shpif; (void)rnd; (void)udp_connect;
(void)reusenum;
*port = 0;
*reused = 0;
return 1;
#endif
}
void shared_ports_return_port(struct shared_ports* shp,
struct shared_ports_if* shpif, int port)
{
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
if(!shpif)
return;
lock_basic_lock(&shp->lock);
log_assert(shpif->inuse > 0);
shpif->avail_ports[shpif->avail_total - shpif->inuse] = port;
shpif->inuse--;
lock_basic_unlock(&shp->lock);
#else
(void)shp; (void)shpif; (void)port;
#endif
}
+96 -11
View File
@@ -70,6 +70,8 @@ struct module_env;
struct module_qstate; struct module_qstate;
struct query_info; struct query_info;
struct config_file; struct config_file;
struct shared_ports;
struct shared_ports_if;
/** /**
* Send queries to outside servers and wait for answers from servers. * Send queries to outside servers and wait for answers from servers.
@@ -119,6 +121,9 @@ struct outside_network {
int udp_connect; int udp_connect;
/** number of udp packets sent. */ /** number of udp packets sent. */
size_t num_udp_outgoing; size_t num_udp_outgoing;
/** the shared ports structure, with random ports numbers.
* This is a reference to the member in the daemon structure. */
struct shared_ports* shared_ports;
/** array of outgoing IP4 interfaces */ /** array of outgoing IP4 interfaces */
struct port_if* ip4_ifs; struct port_if* ip4_ifs;
@@ -211,11 +216,8 @@ struct port_if {
int pfxlen; int pfxlen;
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION #ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
/** the available ports array. These are unused. /** the shared port numbers for this interface. */
* Only the first total-inuse part is filled. */ struct shared_ports_if* shpif;
int* avail_ports;
/** the total number of available ports (size of the array) */
int avail_total;
#endif #endif
/** array of the commpoints currently in use. /** array of the commpoints currently in use.
@@ -245,6 +247,42 @@ struct port_comm {
struct comm_point* cp; struct comm_point* cp;
}; };
/**
* Shared ports, the list of ports shared across threads
*/
struct shared_ports {
/** mutex on the ports */
lock_basic_type lock;
/** array of IP4 interfaces */
struct shared_ports_if* ip4_ifs;
/** number of outgoing IP4 interfaces */
int num_ip4;
/** array of IP6 interfaces */
struct shared_ports_if* ip6_ifs;
/** number of outgoing IP6 interfaces */
int num_ip6;
};
/**
* Shared ports for an interface.
*/
struct shared_ports_if {
/** address ready to allocate new socket (except port no). */
struct sockaddr_storage addr;
/** length of addr field */
socklen_t addrlen;
/** if a netblock, the prefix */
int pfxlen;
/** the available ports array. These are unused.
* Only the first total-inuse part is filled. */
int* avail_ports;
/** the total number of available ports (size of the array) */
int avail_total;
/** the number in use. */
int inuse;
};
/** /**
* Reuse TCP connection, still open can be used again. * Reuse TCP connection, still open can be used again.
*/ */
@@ -419,7 +457,7 @@ struct waiting_tcp {
void* cb_arg; void* cb_arg;
/** if it uses ssl upstream */ /** if it uses ssl upstream */
int ssl_upstream; int ssl_upstream;
/** ref to the tls_auth_name from the serviced_query */ /** owned copy of the tls_auth_name (malloced) */
char* tls_auth_name; char* tls_auth_name;
/** the packet was involved in an error, to stop looping errors */ /** the packet was involved in an error, to stop looping errors */
int error_count; int error_count;
@@ -551,8 +589,6 @@ struct serviced_query {
* @param infra: pointer to infra cached used for serviced queries. * @param infra: pointer to infra cached used for serviced queries.
* @param rnd: stored to create random numbers for serviced queries. * @param rnd: stored to create random numbers for serviced queries.
* @param use_caps_for_id: enable to use 0x20 bits to encode id randomness. * @param use_caps_for_id: enable to use 0x20 bits to encode id randomness.
* @param availports: array of available ports.
* @param numavailports: number of available ports in array.
* @param unwanted_threshold: when to take defensive action. * @param unwanted_threshold: when to take defensive action.
* @param unwanted_action: the action to take. * @param unwanted_action: the action to take.
* @param unwanted_param: user parameter to action. * @param unwanted_param: user parameter to action.
@@ -567,17 +603,18 @@ struct serviced_query {
* @param max_reuse_tcp_queries: max number of queries on a reuse connection. * @param max_reuse_tcp_queries: max number of queries on a reuse connection.
* @param tcp_reuse_timeout: timeout for REUSE entries in milliseconds. * @param tcp_reuse_timeout: timeout for REUSE entries in milliseconds.
* @param tcp_auth_query_timeout: timeout in milliseconds for TCP queries to auth servers. * @param tcp_auth_query_timeout: timeout in milliseconds for TCP queries to auth servers.
* @param shared_ports: the shared_ports structure.
* @return: the new structure (with no pending answers) or NULL on error. * @return: the new structure (with no pending answers) or NULL on error.
*/ */
struct outside_network* outside_network_create(struct comm_base* base, struct outside_network* outside_network_create(struct comm_base* base,
size_t bufsize, size_t num_ports, char** ifs, int num_ifs, size_t bufsize, size_t num_ports, char** ifs, int num_ifs,
int do_ip4, int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra, int do_ip4, int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra,
struct ub_randstate* rnd, int use_caps_for_id, int* availports, struct ub_randstate* rnd, int use_caps_for_id,
int numavailports, size_t unwanted_threshold, int tcp_mss, size_t unwanted_threshold, int tcp_mss,
void (*unwanted_action)(void*), void* unwanted_param, int do_udp, void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
void* sslctx, int delayclose, int tls_use_sni, struct dt_env *dtenv, void* sslctx, int delayclose, int tls_use_sni, struct dt_env *dtenv,
int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout, int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout,
int tcp_auth_query_timeout); int tcp_auth_query_timeout, struct shared_ports* shared_ports);
/** /**
* Delete outside_network structure. * Delete outside_network structure.
@@ -822,6 +859,54 @@ struct comm_point* outnet_comm_point_for_http(struct outside_network* outnet,
/** connect tcp connection to addr, 0 on failure */ /** connect tcp connection to addr, 0 on failure */
int outnet_tcp_connect(int s, struct sockaddr_storage* addr, socklen_t addrlen); int outnet_tcp_connect(int s, struct sockaddr_storage* addr, socklen_t addrlen);
/**
* Create new shared ports structure.
* @param ifs: interface names (or NULL for default interface).
* These interfaces must be able to access all authoritative servers.
* @param num_ifs: number of names in array ifs.
* @param do_ip4: service IP4.
* @param do_ip6: service IP6.
* @param availports: array of available ports.
* @param numavailports: number of available ports in array.
* @return new, or NULL on failure.
*/
struct shared_ports* shared_ports_create(char** ifs, int num_ifs, int do_ip4,
int do_ip6, int* availports, int numavailports);
/**
* Delete shared ports structure.
* @param shp: shared ports structure.
*/
void shared_ports_delete(struct shared_ports* shp);
/** Find interface in shared ports. */
struct shared_ports_if* shared_ports_find_if(struct shared_ports* shp,
struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen);
/**
* Get a shared port from the list of random ports.
* @param shp: shared ports structure.
* @param shpif: the shared ports interface.
* @param rnd: used to make random numbers.
* @param udp_connect: set to true if no reuse is possible.
* @param reusenum: number of ports that can be reused (already open).
* @param port: the port number is returned.
* @param reused: if the port numer is reused, returned.
* @return false on failure. That can mean no more free ports to use.
*/
int shared_ports_fetch_random(struct shared_ports* shp,
struct shared_ports_if* shpif, struct ub_randstate* rnd,
int udp_connect, int reusenum, int* port, int* reused);
/**
* Return a shared port to the list of random ports.
* @param shp: shared ports structure.
* @param shpif: the shared ports interface.
* @param port: port number to return to be used again.
*/
void shared_ports_return_port(struct shared_ports* shp,
struct shared_ports_if* shpif, int port);
/** callback for incoming udp answers from the network */ /** callback for incoming udp answers from the network */
int outnet_udp_cb(struct comm_point* c, void* arg, int error, int outnet_udp_cb(struct comm_point* c, void* arg, int error,
struct comm_reply *reply_info); struct comm_reply *reply_info);
+6
View File
@@ -129,6 +129,12 @@ worker_alloc_cleanup(void* ATTR_UNUSED(arg))
log_assert(0); log_assert(0);
} }
void
libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
{
log_assert(0);
}
struct outbound_entry* libworker_send_query( struct outbound_entry* libworker_send_query(
struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags), struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags),
int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
+7 -2
View File
@@ -1522,9 +1522,9 @@ doq_client_send_pkt(struct doq_client_data* data, uint32_t ecn, uint8_t* buf,
} }
log_err("doq sendmsg: %s", strerror(errno)); log_err("doq sendmsg: %s", strerror(errno));
#ifdef HAVE_NGTCP2_CCERR_DEFAULT #ifdef HAVE_NGTCP2_CCERR_DEFAULT
ngtcp2_ccerr_set_application_error(&data->ccerr, -1, NULL, 0); ngtcp2_ccerr_set_application_error(&data->ccerr, 1, NULL, 0);
#else #else
ngtcp2_connection_close_error_set_application_error(&data->last_error, -1, NULL, 0); ngtcp2_connection_close_error_set_application_error(&data->last_error, 1, NULL, 0);
#endif #endif
return 0; return 0;
} }
@@ -2676,6 +2676,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
log_assert(0); log_assert(0);
} }
void libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
{
log_assert(0);
}
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
{ {
log_assert(0); log_assert(0);
+27 -3
View File
@@ -1126,15 +1126,16 @@ outside_network_create(struct comm_base* base, size_t bufsize,
int ATTR_UNUSED(dscp), int ATTR_UNUSED(dscp),
struct infra_cache* infra, struct infra_cache* infra,
struct ub_randstate* ATTR_UNUSED(rnd), struct ub_randstate* ATTR_UNUSED(rnd),
int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports), int ATTR_UNUSED(use_caps_for_id),
int ATTR_UNUSED(numavailports), size_t ATTR_UNUSED(unwanted_threshold), size_t ATTR_UNUSED(unwanted_threshold),
int ATTR_UNUSED(outgoing_tcp_mss), int ATTR_UNUSED(outgoing_tcp_mss),
void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param), void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param),
int ATTR_UNUSED(do_udp), void* ATTR_UNUSED(sslctx), int ATTR_UNUSED(do_udp), void* ATTR_UNUSED(sslctx),
int ATTR_UNUSED(delayclose), int ATTR_UNUSED(tls_use_sni), int ATTR_UNUSED(delayclose), int ATTR_UNUSED(tls_use_sni),
struct dt_env* ATTR_UNUSED(dtenv), int ATTR_UNUSED(udp_connect), struct dt_env* ATTR_UNUSED(dtenv), int ATTR_UNUSED(udp_connect),
int ATTR_UNUSED(max_reuse_tcp_queries), int ATTR_UNUSED(tcp_reuse_timeout), int ATTR_UNUSED(max_reuse_tcp_queries), int ATTR_UNUSED(tcp_reuse_timeout),
int ATTR_UNUSED(tcp_auth_query_timeout)) int ATTR_UNUSED(tcp_auth_query_timeout),
struct shared_ports* ATTR_UNUSED(shared_ports))
{ {
struct replay_runtime* runtime = (struct replay_runtime*)base; struct replay_runtime* runtime = (struct replay_runtime*)base;
struct outside_network* outnet = calloc(1, struct outside_network* outnet = calloc(1,
@@ -1981,6 +1982,20 @@ int outnet_tcp_connect(int ATTR_UNUSED(s), struct sockaddr_storage* ATTR_UNUSED(
return 0; return 0;
} }
struct shared_ports* shared_ports_create(char** ATTR_UNUSED(ifs),
int ATTR_UNUSED(num_ifs), int ATTR_UNUSED(do_ip4),
int ATTR_UNUSED(do_ip6), int* ATTR_UNUSED(availports),
int ATTR_UNUSED(numavailports))
{
return calloc(1, sizeof(struct shared_ports));
}
void shared_ports_delete(struct shared_ports* shp)
{
if(!shp) return;
free(shp);
}
int tcp_req_info_add_meshstate(struct tcp_req_info* ATTR_UNUSED(req), int tcp_req_info_add_meshstate(struct tcp_req_info* ATTR_UNUSED(req),
struct mesh_area* ATTR_UNUSED(mesh), struct mesh_state* ATTR_UNUSED(m)) struct mesh_area* ATTR_UNUSED(mesh), struct mesh_state* ATTR_UNUSED(m))
{ {
@@ -2022,6 +2037,15 @@ void http2_stream_remove_mesh_state(struct http2_stream* ATTR_UNUSED(h2_stream))
{ {
} }
void doq_stream_add_meshstate(struct doq_stream* ATTR_UNUSED(stream),
struct mesh_area* ATTR_UNUSED(mesh), struct mesh_state* ATTR_UNUSED(m))
{
}
void doq_stream_remove_mesh_state(struct doq_stream* ATTR_UNUSED(stream))
{
}
void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(event), void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(event),
void* ATTR_UNUSED(arg)) void* ATTR_UNUSED(arg))
{ {
+56
View File
@@ -1282,6 +1282,61 @@ static void localzone_test(void)
localzone_parents_test(); localzone_parents_test();
} }
#include "services/mesh.h"
/** mesh unit tests */
static void mesh_test(void)
{
struct regional* r2, *r3;
struct respip_client_info* c1, *c2, *c3;
unit_show_func("services/mesh.c", "mesh_copy_client_info");
r2 = regional_create();
r3 = regional_create();
if(!r2 || !r3) fatal_exit("out of memory");
c1 = calloc(1, sizeof(*c1));
if(!c1) fatal_exit("out of memory");
c1->view = calloc(1, sizeof(*c1->view));
if(!c1->view) fatal_exit("out of memory");
c1->view->name = strdup("view1");
if(!c1->view->name) fatal_exit("out of memory");
c2 = mesh_copy_client_info(r2, c1);
if(!c2) fatal_exit("out of memory");
c3 = mesh_copy_client_info(r3, c2);
if(!c3) fatal_exit("out of memory");
unit_assert(strcmp(c1->view->name, c2->view_name) == 0);
unit_assert(strcmp(c1->view->name, c3->view_name) == 0);
/* make sure that the c3 view_name is in the r3 region. */
unit_assert(r3->next == NULL); /* only the first chunk present atm */
if(strlen(c3->view_name) >= r3->large_object_size) {
char* a = r3->large_list;
int found = 0;
while(a) {
if(strcmp(c3->view_name,
a + /* ALIGNEMENT */ sizeof(uint64_t)) == 0) {
found = 1;
break;
}
a = *(char**)a;
}
unit_assert(found == 1);
} else {
/* The allocation is expected in the r3 region first chunk */
unit_assert((uint8_t*)c3->view_name < ((uint8_t*)r3)+r3->first_size);
}
regional_destroy(r2);
/* ASAN should complain for the freed access below */
unit_assert(strcmp(c1->view->name, c3->view_name) == 0);
regional_destroy(r3);
free(c1->view->name);
free(c1->view);
free(c1);
}
void unit_show_func(const char* file, const char* func) void unit_show_func(const char* file, const char* func)
{ {
printf("test %s:%s\n", file, func); printf("test %s:%s\n", file, func);
@@ -1356,6 +1411,7 @@ main(int argc, char* argv[])
msgparse_test(); msgparse_test();
edns_ede_answer_encode_test(); edns_ede_answer_encode_test();
localzone_test(); localzone_test();
mesh_test();
#ifdef CLIENT_SUBNET #ifdef CLIENT_SUBNET
ecs_test(); ecs_test();
#endif /* CLIENT_SUBNET */ #endif /* CLIENT_SUBNET */
+276
View File
@@ -41,6 +41,7 @@
#include "config.h" #include "config.h"
#include "testcode/unitmain.h" #include "testcode/unitmain.h"
#include "util/log.h" #include "util/log.h"
#include "util/net_help.h"
#include "util/random.h" #include "util/random.h"
#include "services/outside_network.h" #include "services/outside_network.h"
@@ -479,6 +480,278 @@ static void reuse_write_wait_test(void)
check_reuse_write_wait_removal(1, &reuse, store, 0, 1); check_reuse_write_wait_removal(1, &reuse, store, 0, 1);
} }
static void shared_port_test_ifs(void)
{
struct shared_ports* shp;
struct shared_ports_if* shpif;
char* ifs[] = {"1.2.3.4", "1.2.3.5", "::1:2", "::1:3"};
int availports[] = {1, 2, 3, 4};
struct sockaddr_storage addr;
socklen_t addrlen;
shp = shared_ports_create(ifs, 4, 1, 1, availports, 4);
unit_assert(shp);
if(!ipstrtoaddr("1.2.3.4", UNBOUND_DNS_PORT, &addr, &addrlen))
log_err("could not parse");
shpif = shared_ports_find_if(shp, &addr, addrlen, 0);
unit_assert(shpif);
if(!ipstrtoaddr("1.2.3.5", UNBOUND_DNS_PORT, &addr, &addrlen))
log_err("could not parse");
shpif = shared_ports_find_if(shp, &addr, addrlen, 0);
unit_assert(shpif);
if(!ipstrtoaddr("::1:2", UNBOUND_DNS_PORT, &addr, &addrlen))
log_err("could not parse");
shpif = shared_ports_find_if(shp, &addr, addrlen, 0);
unit_assert(shpif);
if(!ipstrtoaddr("::1:3", UNBOUND_DNS_PORT, &addr, &addrlen))
log_err("could not parse");
shpif = shared_ports_find_if(shp, &addr, addrlen, 0);
unit_assert(shpif);
shared_ports_delete(shp);
}
/** See if a port is on the shared_ports ports list */
static int
pif_list_contains(struct shared_ports_if* shpif, int item)
{
int i;
unit_assert(shpif->inuse >= 0 && shpif->inuse <= shpif->avail_total);
for(i=0; i< shpif->avail_total - shpif->inuse; i++) {
if(shpif->avail_ports[i] == item)
return 1;
}
return 0;
}
/** See if a number of ports are on the shared_ports list */
static int
pif_list_contains_items(struct shared_ports_if* shpif, int item1,
int item2, int item3, int item4)
{
if(item1 != -1 && !pif_list_contains(shpif, item1))
return 0;
if(item2 != -1 && !pif_list_contains(shpif, item2))
return 0;
if(item3 != -1 && !pif_list_contains(shpif, item3))
return 0;
if(item4 != -1 && !pif_list_contains(shpif, item4))
return 0;
return 1;
}
static void shared_port_test_port(void)
{
struct shared_ports* shp;
struct shared_ports_if* shpif;
char* ifs[] = {"1.2.3.4", "1.2.3.5"};
int availports[] = {1, 2, 3, 4};
struct sockaddr_storage addr;
socklen_t addrlen;
int p1, p2, p3, reused;
struct ub_randstate* rnd;
rnd = ub_initstate(NULL);
unit_assert(rnd);
shp = shared_ports_create(ifs, 2, 1, 1, availports, 4);
unit_assert(shp);
if(!ipstrtoaddr("1.2.3.4", UNBOUND_DNS_PORT, &addr, &addrlen))
log_err("could not parse");
shpif = shared_ports_find_if(shp, &addr, addrlen, 0);
unit_assert(shpif);
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 0);
unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4));
if(!shared_ports_fetch_random(shp, shpif, rnd,
0, 0, &p1, &reused)) {
unit_assert(0); /* should succeed */
}
unit_assert(reused == 0);
unit_assert(p1 != 0);
unit_assert(!pif_list_contains(shpif, p1));
if(p1 != 1) unit_assert(pif_list_contains(shpif, 1));
if(p1 != 2) unit_assert(pif_list_contains(shpif, 2));
if(p1 != 3) unit_assert(pif_list_contains(shpif, 3));
if(p1 != 4) unit_assert(pif_list_contains(shpif, 4));
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 1);
shared_ports_return_port(shp, shpif, p1);
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 0);
unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4));
/* pick up two items */
if(!shared_ports_fetch_random(shp, shpif, rnd,
0, 0, &p1, &reused)) {
unit_assert(0); /* should succeed */
}
unit_assert(reused == 0);
unit_assert(p1 != 0);
if(!shared_ports_fetch_random(shp, shpif, rnd,
0, 0, &p2, &reused)) {
unit_assert(0); /* should succeed */
}
unit_assert(reused == 0);
unit_assert(p2 != 0);
unit_assert(!pif_list_contains(shpif, p1));
unit_assert(!pif_list_contains(shpif, p2));
if(p1 != 1 && p2 != 1) unit_assert(pif_list_contains(shpif, 1));
if(p1 != 2 && p2 != 2) unit_assert(pif_list_contains(shpif, 2));
if(p1 != 3 && p2 != 3) unit_assert(pif_list_contains(shpif, 3));
if(p1 != 4 && p2 != 4) unit_assert(pif_list_contains(shpif, 4));
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 2);
shared_ports_return_port(shp, shpif, p1);
unit_assert(pif_list_contains(shpif, p1));
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 1);
shared_ports_return_port(shp, shpif, p2);
unit_assert(pif_list_contains(shpif, p2));
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 0);
unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4));
/* pick up three items */
if(!shared_ports_fetch_random(shp, shpif, rnd,
0, 0, &p1, &reused)) {
unit_assert(0); /* should succeed */
}
unit_assert(reused == 0);
unit_assert(p1 != 0);
if(!shared_ports_fetch_random(shp, shpif, rnd,
0, 0, &p2, &reused)) {
unit_assert(0); /* should succeed */
}
unit_assert(reused == 0);
unit_assert(p2 != 0);
if(!shared_ports_fetch_random(shp, shpif, rnd,
0, 0, &p3, &reused)) {
unit_assert(0); /* should succeed */
}
unit_assert(reused == 0);
unit_assert(p3 != 0);
unit_assert(!pif_list_contains(shpif, p1));
unit_assert(!pif_list_contains(shpif, p2));
unit_assert(!pif_list_contains(shpif, p3));
if(p1 != 1 && p2 != 1 && p3 != 1)
unit_assert(pif_list_contains(shpif, 1));
if(p1 != 2 && p2 != 2 && p3 != 2)
unit_assert(pif_list_contains(shpif, 2));
if(p1 != 3 && p2 != 3 && p3 != 3)
unit_assert(pif_list_contains(shpif, 3));
if(p1 != 4 && p2 != 4 && p3 != 4)
unit_assert(pif_list_contains(shpif, 4));
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 3);
shared_ports_return_port(shp, shpif, p1);
unit_assert(pif_list_contains(shpif, p1));
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 2);
shared_ports_return_port(shp, shpif, p2);
unit_assert(pif_list_contains(shpif, p2));
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 1);
shared_ports_return_port(shp, shpif, p3);
unit_assert(pif_list_contains(shpif, p3));
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 0);
unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4));
/* pick up all four items */
if(!shared_ports_fetch_random(shp, shpif, rnd,
0, 0, &p1, &reused)) {
unit_assert(0); /* should succeed */
}
unit_assert(reused == 0);
unit_assert(p1 != 0);
if(!shared_ports_fetch_random(shp, shpif, rnd,
0, 0, &p1, &reused)) {
unit_assert(0); /* should succeed */
}
unit_assert(reused == 0);
unit_assert(p1 != 0);
if(!shared_ports_fetch_random(shp, shpif, rnd,
0, 0, &p1, &reused)) {
unit_assert(0); /* should succeed */
}
unit_assert(reused == 0);
unit_assert(p1 != 0);
if(!shared_ports_fetch_random(shp, shpif, rnd,
0, 0, &p1, &reused)) {
unit_assert(0); /* should succeed */
}
unit_assert(reused == 0);
unit_assert(p1 != 0);
unit_assert(!pif_list_contains(shpif, 1));
unit_assert(!pif_list_contains(shpif, 2));
unit_assert(!pif_list_contains(shpif, 3));
unit_assert(!pif_list_contains(shpif, 4));
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 4);
/* more fetches fail, it is fully inuse. */
unit_assert(!shared_ports_fetch_random(shp, shpif, rnd, 0, 0, &p2,
&reused));
unit_assert(!shared_ports_fetch_random(shp, shpif, rnd, 0, 0, &p3,
&reused));
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 4);
/* reuse is then always the case */
if(!shared_ports_fetch_random(shp, shpif, rnd,
0 /* can reuse */, 4 /* reusenum */, &p1, &reused)) {
unit_assert(0); /* should succeed */
}
unit_assert(reused == 1);
unit_assert(p1 >= 0 && p1 < 4 /* reusenum */);
if(!shared_ports_fetch_random(shp, shpif, rnd,
0 /* can reuse */, 4 /* reusenum */, &p1, &reused)) {
unit_assert(0); /* should succeed */
}
unit_assert(reused == 1);
unit_assert(p1 >= 0 && p1 < 4 /* reusenum */);
/* return all the ports */
shared_ports_return_port(shp, shpif, 1);
unit_assert(pif_list_contains(shpif, 1));
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 3);
shared_ports_return_port(shp, shpif, 2);
unit_assert(pif_list_contains(shpif, 2));
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 2);
shared_ports_return_port(shp, shpif, 3);
unit_assert(pif_list_contains(shpif, 3));
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 1);
shared_ports_return_port(shp, shpif, 4);
unit_assert(pif_list_contains(shpif, 4));
unit_assert(shpif->avail_total == 4);
unit_assert(shpif->inuse == 0);
unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4));
shared_ports_delete(shp);
ub_randfree(rnd);
}
void tcpreuse_test(void) void tcpreuse_test(void)
{ {
unit_show_feature("tcp_reuse"); unit_show_feature("tcp_reuse");
@@ -486,4 +759,7 @@ void tcpreuse_test(void)
tcp_reuse_tree_list_test(); tcp_reuse_tree_list_test();
waiting_tcp_list_test(); waiting_tcp_list_test();
reuse_write_wait_test(); reuse_write_wait_test();
unit_show_feature("shared_ports");
shared_port_test_ifs();
shared_port_test_port();
} }
+1
View File
@@ -12,6 +12,7 @@ server:
ede: no # It is not needed for dns-error-reporting; only for clients to receive EDEs ede: no # It is not needed for dns-error-reporting; only for clients to receive EDEs
dns-error-reporting: yes dns-error-reporting: yes
do-ip6: no do-ip6: no
do-not-query-localhost: no
stub-zone: stub-zone:
name: domain name: domain
+9 -8
View File
@@ -9,20 +9,21 @@ PRE="../.."
# do the test # do the test
# Query plain request over DNSCrypt channel get closed # Query plain request over DNSCrypt.
# We use TCP to avoid hanging on waiting for UDP. # This used to close the channel; now it returns SERVFAIL.
# We expect `outfile` to contain no DNS payload # Old: We use TCP to avoid hanging on waiting for UDP.
echo "> dig TCP www.example.com. DNSCrypt port" # We expect `outfile` to contain no DNS payload
dig +tcp @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile echo "> dig www.example.com. DNSCrypt port"
dig @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile
echo "> cat logfiles" echo "> cat logfiles"
cat fwd.log cat fwd.log
cat unbound.log cat unbound.log
echo "> check answer" echo "> check answer"
if grep "QUESTION SECTION" outfile; then if grep "SERVFAIL" outfile; then
echo "OK"
else
echo "NOK" echo "NOK"
exit 1 exit 1
else
echo "OK"
fi fi
@@ -9,20 +9,21 @@ PRE="../.."
# do the test # do the test
# Query plain request over DNSCrypt channel get closed # Query plain request over DNSCrypt.
# We use TCP to avoid hanging on waiting for UDP. # This used to close the channel; now it returns SERVFAIL.
# We expect `outfile` to contain no DNS payload # Old: We use TCP to avoid hanging on waiting for UDP.
echo "> dig TCP www.example.com. DNSCrypt port" # We expect `outfile` to contain no DNS payload
dig +tcp @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile echo "> dig www.example.com. DNSCrypt port"
dig @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile
echo "> cat logfiles" echo "> cat logfiles"
cat fwd.log cat fwd.log
cat unbound.log cat unbound.log
echo "> check answer" echo "> check answer"
if grep "QUESTION SECTION" outfile; then if grep "SERVFAIL" outfile; then
echo "OK"
else
echo "NOK" echo "NOK"
exit 1 exit 1
else
echo "OK"
fi fi
+4 -4
View File
@@ -319,7 +319,7 @@ example.com. 360 IN NS ns.example.com.
SECTION ADDITIONAL SECTION ADDITIONAL
; this is picked up from the parent (because this simulation has the ; this is picked up from the parent (because this simulation has the
; parent respond with servfail, not actually timeout) ; parent respond with servfail, not actually timeout)
ns.example.com. 3600 IN A 1.2.3.4 ns.example.com. 360 IN A 1.2.3.4
ENTRY_END ENTRY_END
; another query to see if there is another lookup towards the authority ; another query to see if there is another lookup towards the authority
@@ -342,7 +342,7 @@ www.example.com. 360 IN A 10.20.30.40
SECTION AUTHORITY SECTION AUTHORITY
example.com. 360 IN NS ns.example.com. example.com. 360 IN NS ns.example.com.
SECTION ADDITIONAL SECTION ADDITIONAL
ns.example.com. 3600 IN A 1.2.3.4 ns.example.com. 360 IN A 1.2.3.4
ENTRY_END ENTRY_END
; some time later another query, and now it is fine to bother the authority ; some time later another query, and now it is fine to bother the authority
@@ -367,7 +367,7 @@ www.example.com. 330 IN A 10.20.30.40
SECTION AUTHORITY SECTION AUTHORITY
example.com. 330 IN NS ns.example.com. example.com. 330 IN NS ns.example.com.
SECTION ADDITIONAL SECTION ADDITIONAL
ns.example.com. 3570 IN A 1.2.3.4 ns.example.com. 330 IN A 1.2.3.4
ENTRY_END ENTRY_END
; now the just-looked-up entry ; now the just-looked-up entry
STEP 190 QUERY STEP 190 QUERY
@@ -388,7 +388,7 @@ www.example.com. 3600 IN A 10.20.30.40
SECTION AUTHORITY SECTION AUTHORITY
example.com. 3600 IN NS ns.example.com. example.com. 3600 IN NS ns.example.com.
SECTION ADDITIONAL SECTION ADDITIONAL
ns.example.com. 3570 IN A 1.2.3.4 ns.example.com. 3600 IN A 1.2.3.4
ENTRY_END ENTRY_END
+6 -3
View File
@@ -687,6 +687,9 @@ calc_size(sldns_buffer* pkt, uint16_t type, struct rr_parse* rr)
} }
rdf++; rdf++;
} }
/* rdata ended before all _dname_count names were seen */
if(count != 0)
return 0; /* the rdata is too short. */
} }
/* remaining rdata */ /* remaining rdata */
rr->size += pkt_len; rr->size += pkt_len;
@@ -1071,13 +1074,13 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
* purposes. It will be overwritten if (re)creation * purposes. It will be overwritten if (re)creation
* is needed. * is needed.
*/ */
if(repinfo->remote_addr.ss_family == AF_INET) { if(repinfo->client_addr.ss_family == AF_INET) {
memcpy(server_cookie + 16, memcpy(server_cookie + 16,
&((struct sockaddr_in*)&repinfo->remote_addr)->sin_addr, 4); &((struct sockaddr_in*)&repinfo->client_addr)->sin_addr, 4);
} else { } else {
cookie_is_v4 = 0; cookie_is_v4 = 0;
memcpy(server_cookie + 16, memcpy(server_cookie + 16,
&((struct sockaddr_in6*)&repinfo->remote_addr)->sin6_addr, 16); &((struct sockaddr_in6*)&repinfo->client_addr)->sin6_addr, 16);
} }
if(cfg->cookie_secret_file && if(cfg->cookie_secret_file &&
+1
View File
@@ -198,6 +198,7 @@ get_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname,
{ {
struct packed_rrset_data* d; struct packed_rrset_data* d;
size_t len; size_t len;
if(!rrset) return;
if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME && if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME &&
ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME) ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME)
return; return;
+1
View File
@@ -610,6 +610,7 @@ int
fptr_whitelist_alloc_cleanup(void (*fptr)(void*)) fptr_whitelist_alloc_cleanup(void (*fptr)(void*))
{ {
if(fptr == &worker_alloc_cleanup) return 1; if(fptr == &worker_alloc_cleanup) return 1;
else if(fptr == &libworker_alloc_cleanup) return 1;
return 0; return 0;
} }
+6
View File
@@ -730,6 +730,12 @@ struct module_qstate {
/** whether the reply should be dropped */ /** whether the reply should be dropped */
int is_drop; int is_drop;
/** the global quota that was reached, by one of the modules.
* So that continued counting can go on from that point. */
int global_quota_reached;
/** the global quota that a query started with, it is a subquery,
* so that calling mesh states can see the increase. */
int global_quota_started;
}; };
/** /**
+19 -25
View File
@@ -1835,7 +1835,6 @@ doq_send_retry(struct comm_point* c, struct doq_pkt_addr* paddr,
char host[256], port[32]; char host[256], port[32];
struct ngtcp2_cid scid; struct ngtcp2_cid scid;
uint8_t token[NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN]; uint8_t token[NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN];
ngtcp2_tstamp ts;
ngtcp2_ssize tokenlen, ret; ngtcp2_ssize tokenlen, ret;
if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host, if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host,
@@ -1849,12 +1848,10 @@ doq_send_retry(struct comm_point* c, struct doq_pkt_addr* paddr,
scid.datalen = c->doq_socket->sv_scidlen; scid.datalen = c->doq_socket->sv_scidlen;
doq_cid_randfill(&scid, scid.datalen, c->doq_socket->rnd); doq_cid_randfill(&scid, scid.datalen, c->doq_socket->rnd);
ts = doq_get_timestamp_nanosec();
tokenlen = ngtcp2_crypto_generate_retry_token(token, tokenlen = ngtcp2_crypto_generate_retry_token(token,
c->doq_socket->static_secret, c->doq_socket->static_secret_len, c->doq_socket->static_secret, c->doq_socket->static_secret_len,
hd->version, (void*)&paddr->addr, paddr->addrlen, &scid, hd->version, (void*)&paddr->addr, paddr->addrlen, &scid,
&hd->dcid, ts); &hd->dcid, doq_get_timestamp_nanosec());
if(tokenlen < 0) { if(tokenlen < 0) {
log_err("ngtcp2_crypto_generate_retry_token failed: %s", log_err("ngtcp2_crypto_generate_retry_token failed: %s",
ngtcp2_strerror(tokenlen)); ngtcp2_strerror(tokenlen));
@@ -1903,13 +1900,11 @@ doq_verify_retry_token(struct comm_point* c, struct doq_pkt_addr* paddr,
struct ngtcp2_cid* ocid, struct ngtcp2_pkt_hd* hd) struct ngtcp2_cid* ocid, struct ngtcp2_pkt_hd* hd)
{ {
char host[256], port[32]; char host[256], port[32];
ngtcp2_tstamp ts;
if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host, if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host,
sizeof(host), port, sizeof(port))) { sizeof(host), port, sizeof(port))) {
log_err("doq_verify_retry_token failed"); log_err("doq_verify_retry_token failed");
return 0; return 0;
} }
ts = doq_get_timestamp_nanosec();
verbose(VERB_ALGO, "doq: verifying retry token from %s %s", host, verbose(VERB_ALGO, "doq: verifying retry token from %s %s", host,
port); port);
if(ngtcp2_crypto_verify_retry_token(ocid, if(ngtcp2_crypto_verify_retry_token(ocid,
@@ -1921,7 +1916,7 @@ doq_verify_retry_token(struct comm_point* c, struct doq_pkt_addr* paddr,
c->doq_socket->static_secret, c->doq_socket->static_secret,
c->doq_socket->static_secret_len, hd->version, c->doq_socket->static_secret_len, hd->version,
(void*)&paddr->addr, paddr->addrlen, &hd->dcid, (void*)&paddr->addr, paddr->addrlen, &hd->dcid,
10*NGTCP2_SECONDS, ts) != 0) { 10*NGTCP2_SECONDS, doq_get_timestamp_nanosec()) != 0) {
verbose(VERB_ALGO, "doq: could not verify retry token " verbose(VERB_ALGO, "doq: could not verify retry token "
"from %s %s", host, port); "from %s %s", host, port);
return 0; return 0;
@@ -1936,13 +1931,11 @@ doq_verify_token(struct comm_point* c, struct doq_pkt_addr* paddr,
struct ngtcp2_pkt_hd* hd) struct ngtcp2_pkt_hd* hd)
{ {
char host[256], port[32]; char host[256], port[32];
ngtcp2_tstamp ts;
if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host, if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host,
sizeof(host), port, sizeof(port))) { sizeof(host), port, sizeof(port))) {
log_err("doq_verify_token failed"); log_err("doq_verify_token failed");
return 0; return 0;
} }
ts = doq_get_timestamp_nanosec();
verbose(VERB_ALGO, "doq: verifying token from %s %s", host, port); verbose(VERB_ALGO, "doq: verifying token from %s %s", host, port);
if(ngtcp2_crypto_verify_regular_token( if(ngtcp2_crypto_verify_regular_token(
#ifdef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN #ifdef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN
@@ -1952,7 +1945,7 @@ doq_verify_token(struct comm_point* c, struct doq_pkt_addr* paddr,
#endif #endif
c->doq_socket->static_secret, c->doq_socket->static_secret_len, c->doq_socket->static_secret, c->doq_socket->static_secret_len,
(void*)&paddr->addr, paddr->addrlen, 3600*NGTCP2_SECONDS, (void*)&paddr->addr, paddr->addrlen, 3600*NGTCP2_SECONDS,
ts) != 0) { doq_get_timestamp_nanosec()) != 0) {
verbose(VERB_ALGO, "doq: could not verify token from %s %s", verbose(VERB_ALGO, "doq: could not verify token from %s %s",
host, port); host, port);
return 0; return 0;
@@ -2179,6 +2172,7 @@ doq_pickup_timer(struct comm_point* c)
{ {
struct doq_timer* t; struct doq_timer* t;
struct timeval tv; struct timeval tv;
ngtcp2_tstamp ts = 0;
int have_time = 0; int have_time = 0;
memset(&tv, 0, sizeof(tv)); memset(&tv, 0, sizeof(tv));
@@ -2188,27 +2182,24 @@ doq_pickup_timer(struct comm_point* c)
t->worker_doq_socket == c->doq_socket) { t->worker_doq_socket == c->doq_socket) {
/* pick up this element */ /* pick up this element */
t->worker_doq_socket = c->doq_socket; t->worker_doq_socket = c->doq_socket;
memcpy(&tv, &t->time_real, sizeof(tv));
ts = t->time_mono;
have_time = 1; have_time = 1;
memcpy(&tv, &t->time, sizeof(tv));
break; break;
} }
} }
lock_rw_unlock(&c->doq_socket->table->lock); lock_rw_unlock(&c->doq_socket->table->lock);
c->doq_socket->marked_time = ts;
if(have_time) { if(have_time) {
struct timeval rel; struct timeval rel;
timeval_subtract(&rel, &tv, c->doq_socket->now_tv); timeval_subtract(&rel, &tv, c->doq_socket->now_tv);
comm_timer_set(c->doq_socket->timer, &rel); comm_timer_set(c->doq_socket->timer, &rel);
memcpy(&c->doq_socket->marked_time, &tv,
sizeof(c->doq_socket->marked_time));
verbose(VERB_ALGO, "doq pickup timer at %d.%6.6d in %d.%6.6d", verbose(VERB_ALGO, "doq pickup timer at %d.%6.6d in %d.%6.6d",
(int)tv.tv_sec, (int)tv.tv_usec, (int)rel.tv_sec, (int)tv.tv_sec, (int)tv.tv_usec, (int)rel.tv_sec,
(int)rel.tv_usec); (int)rel.tv_usec);
} else { } else {
if(comm_timer_is_set(c->doq_socket->timer)) if(comm_timer_is_set(c->doq_socket->timer))
comm_timer_disable(c->doq_socket->timer); comm_timer_disable(c->doq_socket->timer);
memset(&c->doq_socket->marked_time, 0,
sizeof(c->doq_socket->marked_time));
verbose(VERB_ALGO, "doq timer disabled"); verbose(VERB_ALGO, "doq timer disabled");
} }
} }
@@ -2221,13 +2212,14 @@ doq_done_setup_timer_and_write(struct comm_point* c, struct doq_conn* conn)
uint8_t cid[NGTCP2_MAX_CIDLEN]; uint8_t cid[NGTCP2_MAX_CIDLEN];
rbnode_type* node; rbnode_type* node;
struct timeval new_tv; struct timeval new_tv;
ngtcp2_tstamp new_ts;
int write_change = 0, timer_change = 0; int write_change = 0, timer_change = 0;
/* No longer in callbacks, so the pointer to doq_socket is back /* No longer in callbacks, so the pointer to doq_socket is back
* to NULL. */ * to NULL. */
conn->doq_socket = NULL; conn->doq_socket = NULL;
if(doq_conn_check_timer(conn, &new_tv)) if(doq_conn_check_timer(conn, &new_tv, &new_ts))
timer_change = 1; timer_change = 1;
if( (conn->write_interest && !conn->on_write_list) || if( (conn->write_interest && !conn->on_write_list) ||
(!conn->write_interest && conn->on_write_list)) (!conn->write_interest && conn->on_write_list))
@@ -2273,7 +2265,7 @@ doq_done_setup_timer_and_write(struct comm_point* c, struct doq_conn* conn)
} }
if(timer_change) { if(timer_change) {
doq_timer_set(c->doq_socket->table, &conn->timer, doq_timer_set(c->doq_socket->table, &conn->timer,
c->doq_socket, &new_tv); c->doq_socket, &new_tv, new_ts);
} }
lock_rw_unlock(&c->doq_socket->table->lock); lock_rw_unlock(&c->doq_socket->table->lock);
lock_basic_unlock(&conn->lock); lock_basic_unlock(&conn->lock);
@@ -2437,7 +2429,7 @@ doq_write_blocked_pkt(struct comm_point* c)
return 1; return 1;
} }
/** doq find a timer that timeouted and return the conn, locked. */ /** doq find a timer that timed out and return the conn, locked. */
static struct doq_conn* static struct doq_conn*
doq_timer_timeout_conn(struct doq_server_socket* doq_socket) doq_timer_timeout_conn(struct doq_server_socket* doq_socket)
{ {
@@ -2450,7 +2442,7 @@ doq_timer_timeout_conn(struct doq_server_socket* doq_socket)
conn = t->conn; conn = t->conn;
/* If now < timer then no further timeouts in tree. */ /* If now < timer then no further timeouts in tree. */
if(timeval_smaller(doq_socket->now_tv, &t->time)) { if(timeval_smaller(doq_socket->now_tv, &t->time_real)) {
lock_rw_unlock(&doq_socket->table->lock); lock_rw_unlock(&doq_socket->table->lock);
return NULL; return NULL;
} }
@@ -2473,11 +2465,11 @@ doq_timer_erase_marker(struct doq_server_socket* doq_socket)
{ {
struct doq_timer* t; struct doq_timer* t;
lock_rw_wrlock(&doq_socket->table->lock); lock_rw_wrlock(&doq_socket->table->lock);
t = doq_timer_find_time(doq_socket->table, &doq_socket->marked_time); t = doq_timer_find_time(doq_socket->table, doq_socket->marked_time);
if(t && t->worker_doq_socket == doq_socket) if(t && t->worker_doq_socket == doq_socket)
t->worker_doq_socket = NULL; t->worker_doq_socket = NULL;
lock_rw_unlock(&doq_socket->table->lock); lock_rw_unlock(&doq_socket->table->lock);
memset(&doq_socket->marked_time, 0, sizeof(doq_socket->marked_time)); doq_socket->marked_time = 0;
} }
void void
@@ -2784,7 +2776,7 @@ doq_server_socket_create(struct doq_table* table, struct ub_randstate* rnd,
free(doq_socket); free(doq_socket);
return NULL; return NULL;
} }
memset(&doq_socket->marked_time, 0, sizeof(doq_socket->marked_time)); doq_socket->marked_time = 0;
comm_base_timept(base, &doq_socket->now_tt, &doq_socket->now_tv); comm_base_timept(base, &doq_socket->now_tt, &doq_socket->now_tv);
doq_socket->cfg = cfg; doq_socket->cfg = cfg;
return doq_socket; return doq_socket;
@@ -3241,7 +3233,7 @@ static void http2_stream_delete(struct http2_session* h2_session,
{ {
if(h2_stream->mesh_state) { if(h2_stream->mesh_state) {
mesh_state_remove_reply(h2_stream->mesh, h2_stream->mesh_state, mesh_state_remove_reply(h2_stream->mesh, h2_stream->mesh_state,
h2_session->c, h2_stream); h2_session->c, h2_stream, NULL);
h2_stream->mesh_state = NULL; h2_stream->mesh_state = NULL;
} }
http2_req_stream_clear(h2_stream); http2_req_stream_clear(h2_stream);
@@ -6784,7 +6776,9 @@ comm_point_send_reply(struct comm_reply *repinfo)
log_assert(repinfo && repinfo->c); log_assert(repinfo && repinfo->c);
#ifdef USE_DNSCRYPT #ifdef USE_DNSCRYPT
buffer = repinfo->c->dnscrypt_buffer; buffer = repinfo->c->dnscrypt_buffer;
if(!dnsc_handle_uncurved_request(repinfo)) { if(!dnsc_handle_uncurved_request(repinfo,
repinfo->c->tcp_req_info?
repinfo->c->tcp_req_info->spool_buffer:repinfo->c->buffer)) {
return; return;
} }
#else #else
+5 -1
View File
@@ -189,6 +189,8 @@ struct comm_reply {
/** port number for doq */ /** port number for doq */
int doq_srcport; int doq_srcport;
#endif /* HAVE_NGTCP2 */ #endif /* HAVE_NGTCP2 */
/** The doq stream to register mesh states to. */
struct doq_stream* doq_stream;
}; };
/** /**
@@ -1095,8 +1097,10 @@ struct doq_server_socket {
struct doq_pkt_addr* blocked_paddr; struct doq_pkt_addr* blocked_paddr;
/** timer for this worker on this comm_point to wait on. */ /** timer for this worker on this comm_point to wait on. */
struct comm_timer* timer; struct comm_timer* timer;
#ifdef HAVE_NGTCP2
/** the timer that is marked by the doq_socket as waited on. */ /** the timer that is marked by the doq_socket as waited on. */
struct timeval marked_time; ngtcp2_tstamp marked_time;
#endif
/** the current time for use by time functions, time_t. */ /** the current time for use by time functions, time_t. */
time_t* now_tt; time_t* now_tt;
/** the current time for use by time functions, timeval. */ /** the current time for use by time functions, timeval. */
+14 -4
View File
@@ -1107,6 +1107,7 @@ canonicalize_rdata(sldns_buffer* buf, struct ub_packed_rrset_key* rrset,
{ {
uint8_t* datstart = sldns_buffer_current(buf)-len+2; uint8_t* datstart = sldns_buffer_current(buf)-len+2;
uint8_t* datend = sldns_buffer_current(buf); uint8_t* datend = sldns_buffer_current(buf);
size_t firstlen;
switch(ntohs(rrset->rk.type)) { switch(ntohs(rrset->rk.type)) {
case LDNS_RR_TYPE_NXT: case LDNS_RR_TYPE_NXT:
case LDNS_RR_TYPE_NS: case LDNS_RR_TYPE_NS:
@@ -1126,8 +1127,9 @@ canonicalize_rdata(sldns_buffer* buf, struct ub_packed_rrset_key* rrset,
case LDNS_RR_TYPE_SOA: case LDNS_RR_TYPE_SOA:
/* two names after another */ /* two names after another */
canon_dname_tolower(datstart, datend); canon_dname_tolower(datstart, datend);
canon_dname_tolower(datstart + firstlen = dname_valid(datstart, len-2);
dname_valid(datstart, len-2), datend); if(firstlen && firstlen < len-2)
canon_dname_tolower(datstart + firstlen, datend);
return; return;
case LDNS_RR_TYPE_RT: case LDNS_RR_TYPE_RT:
case LDNS_RR_TYPE_AFSDB: case LDNS_RR_TYPE_AFSDB:
@@ -1154,8 +1156,9 @@ canonicalize_rdata(sldns_buffer* buf, struct ub_packed_rrset_key* rrset,
return; return;
datstart += 2; datstart += 2;
canon_dname_tolower(datstart, datend); canon_dname_tolower(datstart, datend);
canon_dname_tolower(datstart + firstlen = dname_valid(datstart, len-2-2);
dname_valid(datstart, len-2-2), datend); if(firstlen && firstlen < len-2-2)
canon_dname_tolower(datstart + firstlen, datend);
return; return;
case LDNS_RR_TYPE_NAPTR: case LDNS_RR_TYPE_NAPTR:
if(len < 2+4) if(len < 2+4)
@@ -1681,6 +1684,13 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS; *reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus; return sec_status_bogus;
} }
if((int)sig[2+3] < dname_signame_label_count(signer)) {
verbose(VERB_QUERY, "verify: RRSIG label count too low for signer");
*reason = "signature labelcount lower than signature signer";
if(reason_bogus)
*reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
return sec_status_bogus;
}
/* original ttl, always ok */ /* original ttl, always ok */
+13 -4
View File
@@ -157,7 +157,7 @@ val_classify_response(uint16_t query_flags, struct query_info* origqinf,
} }
/** Get signer name from RRSIG */ /** Get signer name from RRSIG */
static void void
rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname, size_t* slen) rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname, size_t* slen)
{ {
/* RRSIG rdata is not allowed to be compressed, it is stored /* RRSIG rdata is not allowed to be compressed, it is stored
@@ -439,10 +439,15 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
* only improves security status * only improves security status
* and bogus is set only once, even if we rechecked the status */ * and bogus is set only once, even if we rechecked the status */
if(sec > d->security) { if(sec > d->security) {
int wc_expanded = 0;
d->security = sec; d->security = sec;
if(sec == sec_status_secure) if(sec == sec_status_secure) {
uint8_t* wc = NULL;
size_t wclen = 0;
d->trust = rrset_trust_validated; d->trust = rrset_trust_validated;
else if(sec == sec_status_bogus) { if(val_rrset_wildcard(rrset, &wc, &wclen) && wc)
wc_expanded = 1;
} else if(sec == sec_status_bogus) {
size_t i; size_t i;
/* update ttl for rrset to fixed value. */ /* update ttl for rrset to fixed value. */
d->ttl = ve->bogus_ttl; d->ttl = ve->bogus_ttl;
@@ -455,7 +460,11 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
lock_basic_unlock(&ve->bogus_lock); lock_basic_unlock(&ve->bogus_lock);
} }
/* if status updated - store in cache for reuse */ /* if status updated - store in cache for reuse */
rrset_update_sec_status(env->rrset_cache, rrset, *env->now); /* For a wildcard rrset, that is secure, do not store this
* into the cache, because it changes proofs around the
* item. */
if(!wc_expanded)
rrset_update_sec_status(env->rrset_cache, rrset, *env->now);
} }
return sec; return sec;
+4
View File
@@ -448,4 +448,8 @@ struct dns_msg* val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen,
int derive_cname_from_dname(struct ub_packed_rrset_key* cname, int derive_cname_from_dname(struct ub_packed_rrset_key* cname,
struct ub_packed_rrset_key* dname, uint8_t* out, size_t outlen); struct ub_packed_rrset_key* dname, uint8_t* out, size_t outlen);
/** Get signer name from RRSIG, sname is NULL if malformed. */
void rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname,
size_t* slen);
#endif /* VALIDATOR_VAL_UTILS_H */ #endif /* VALIDATOR_VAL_UTILS_H */
+56 -3
View File
@@ -520,6 +520,14 @@ generate_request(struct module_qstate* qstate, int id, uint8_t* name,
/* add our blacklist to the query blacklist */ /* add our blacklist to the query blacklist */
sock_list_merge(&(*newq)->blacklist, (*newq)->region, sock_list_merge(&(*newq)->blacklist, (*newq)->region,
vq->chain_blacklist); vq->chain_blacklist);
/* start its global quota counter where this one is. */
if(qstate->global_quota_reached >
(*newq)->global_quota_reached) {
(*newq)->global_quota_started =
qstate->global_quota_reached;
(*newq)->global_quota_reached =
qstate->global_quota_reached;
}
} }
qstate->ext_state[id] = module_wait_subquery; qstate->ext_state[id] = module_wait_subquery;
return 1; return 1;
@@ -1069,7 +1077,14 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
uint8_t* wc = NULL; uint8_t* wc = NULL;
size_t wl; size_t wl;
int wc_cached = 0; int wc_cached = 0;
int wc_to_cache = 0;
uint8_t* cache_wc = NULL;
size_t cache_wl = 0;
struct ub_packed_rrset_key* cache_s = NULL;
int wc_NSEC_ok = 0; int wc_NSEC_ok = 0;
/* This is used to update the RRset cache, with the combination
* of the dname expansion and this wildcard, for security status. */
struct ub_packed_rrset_key* wc_rrset = NULL;
int nsec3s_seen = 0; int nsec3s_seen = 0;
size_t i; size_t i;
struct ub_packed_rrset_key* s; struct ub_packed_rrset_key* s;
@@ -1088,14 +1103,20 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
ntohs(s->rk.type), ntohs(s->rk.rrset_class)); ntohs(s->rk.type), ntohs(s->rk.rrset_class));
chase_reply->security = sec_status_bogus; chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
if(wc_rrset)
((struct packed_rrset_data*)wc_rrset->
entry.data)->security = sec_status_bogus;
return; return;
} }
if(wc && !wc_cached && env->cfg->aggressive_nsec) { if(wc && !wc_cached && env->cfg->aggressive_nsec) {
rrset_cache_update_wildcard(env->rrset_cache, s, wc, wl, /* Postpone cache adjust until proof has succeeded. */
env->alloc, *env->now); wc_to_cache = 1;
cache_wc = wc;
cache_wl = wl;
cache_s = s;
wc_cached = 1; wc_cached = 1;
} }
if(wc) wc_rrset = s;
} }
/* validate the AUTHORITY section as well - this will generally be /* validate the AUTHORITY section as well - this will generally be
@@ -1152,8 +1173,15 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
"did not exist"); "did not exist");
chase_reply->security = sec_status_bogus; chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
if(wc_rrset)
((struct packed_rrset_data*)wc_rrset->
entry.data)->security = sec_status_bogus;
return; return;
} }
if(wc_to_cache) {
rrset_cache_update_wildcard(env->rrset_cache, cache_s,
cache_wc, cache_wl, env->alloc, *env->now);
}
verbose(VERB_ALGO, "Successfully validated positive response"); verbose(VERB_ALGO, "Successfully validated positive response");
chase_reply->security = sec_status_secure; chase_reply->security = sec_status_secure;
@@ -1553,6 +1581,16 @@ validate_any_response(struct module_env* env, struct val_env* ve,
"did not exist"); "did not exist");
chase_reply->security = sec_status_bogus; chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
/* Make the expanded name and wildcard RRSIG rrsets bogus */
for(i=0; i<chase_reply->an_numrrsets; i++) {
uint8_t* cwc = NULL;
size_t cwl = 0;
s = chase_reply->rrsets[i];
if(val_rrset_wildcard(s, &cwc, &cwl) && cwc) {
((struct packed_rrset_data*)s->
entry.data)->security = sec_status_bogus;
}
}
return; return;
} }
@@ -1590,6 +1628,9 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
uint8_t* wc = NULL; uint8_t* wc = NULL;
size_t wl; size_t wl;
int wc_NSEC_ok = 0; int wc_NSEC_ok = 0;
/* This is used to update the RRset cache, with the combination
* of the dname expansion and this wildcard, for security status. */
struct ub_packed_rrset_key* wc_rrset = NULL;
int nsec3s_seen = 0; int nsec3s_seen = 0;
size_t i; size_t i;
struct ub_packed_rrset_key* s; struct ub_packed_rrset_key* s;
@@ -1610,6 +1651,7 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
return; return;
} }
if(wc) wc_rrset = s;
/* Refuse wildcarded DNAMEs rfc 4597. /* Refuse wildcarded DNAMEs rfc 4597.
* Do not follow a wildcarded DNAME because * Do not follow a wildcarded DNAME because
@@ -1621,6 +1663,9 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
ntohs(s->rk.type), ntohs(s->rk.rrset_class)); ntohs(s->rk.type), ntohs(s->rk.rrset_class));
chase_reply->security = sec_status_bogus; chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
if(wc_rrset)
((struct packed_rrset_data*)wc_rrset->
entry.data)->security = sec_status_bogus;
return; return;
} }
@@ -1685,6 +1730,9 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
"did not exist"); "did not exist");
chase_reply->security = sec_status_bogus; chase_reply->security = sec_status_bogus;
update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
if(wc_rrset)
((struct packed_rrset_data*)wc_rrset->
entry.data)->security = sec_status_bogus;
return; return;
} }
@@ -3565,6 +3613,11 @@ val_inform_super(struct module_qstate* qstate, int id,
verbose(VERB_ALGO, "super: has no validator state"); verbose(VERB_ALGO, "super: has no validator state");
return; return;
} }
/* Pick up the global quota limit from the subquery. */
if(qstate->global_quota_reached > qstate->global_quota_started) {
super->global_quota_reached += qstate->global_quota_reached -
qstate->global_quota_started;
}
if(vq->wait_prime_ta) { if(vq->wait_prime_ta) {
vq->wait_prime_ta = 0; vq->wait_prime_ta = 0;
process_prime_response(super, vq, id, qstate->return_rcode, process_prime_response(super, vq, id, qstate->return_rcode,