mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-10-11 22:19:52 +00:00
Merge branch 'branch-1.25.2'
This commit is contained in:
@@ -23021,6 +23021,29 @@ printf "%s\n" "no" >&6; }
|
||||
fi
|
||||
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
|
||||
|
||||
# set static linking for uninstalled libraries if requested
|
||||
|
||||
@@ -1747,6 +1747,22 @@ if test x_$withval = x_yes -o x_$withval != x_no; then
|
||||
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
|
||||
|
||||
# set static linking for uninstalled libraries if requested
|
||||
|
||||
+8
-4
@@ -79,6 +79,7 @@
|
||||
#include "util/tcp_conn_limit.h"
|
||||
#include "util/edns.h"
|
||||
#include "services/listen_dnsport.h"
|
||||
#include "services/outside_network.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "services/localzone.h"
|
||||
@@ -825,6 +826,10 @@ daemon_create_workers(struct daemon* daemon)
|
||||
fatal_exit("out of memory during daemon init");
|
||||
numport = daemon_get_shufport(daemon, shufport);
|
||||
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
|
||||
if (cfg_has_quic(daemon->cfg)) {
|
||||
@@ -855,10 +860,7 @@ daemon_create_workers(struct daemon* daemon)
|
||||
#endif
|
||||
}
|
||||
for(i=0; i<daemon->num; 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 */
|
||||
if(!(daemon->workers[i] = worker_create(daemon, i)))
|
||||
fatal_exit("could not create worker");
|
||||
}
|
||||
/* 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)
|
||||
daemon_clear_allocs(daemon);
|
||||
daemon->num = 0;
|
||||
shared_ports_delete(daemon->shared_ports);
|
||||
daemon->shared_ports = NULL;
|
||||
#ifdef USE_DNSTAP
|
||||
dt_delete(daemon->dtenv);
|
||||
daemon->dtenv = NULL;
|
||||
|
||||
@@ -62,6 +62,7 @@ struct doq_table;
|
||||
struct cookie_secrets;
|
||||
struct fast_reload_thread;
|
||||
struct fast_reload_printq;
|
||||
struct shared_ports;
|
||||
|
||||
#include "dnstap/dnstap_config.h"
|
||||
#ifdef USE_DNSTAP
|
||||
@@ -97,6 +98,8 @@ struct daemon {
|
||||
int rc_port;
|
||||
/** listening ports for remote control */
|
||||
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) */
|
||||
struct daemon_remote* rc;
|
||||
/** ssl context for listening to dnstcp over ssl */
|
||||
|
||||
@@ -1735,6 +1735,14 @@ do_view_data_add(RES* ssl, struct worker* worker, char* arg)
|
||||
ssl_printf(ssl,"error out of memory\n");
|
||||
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);
|
||||
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");
|
||||
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 */
|
||||
(void)snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s ", arg);
|
||||
|
||||
+17
-13
@@ -1555,6 +1555,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
return 0;
|
||||
}
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
|
||||
sldns_buffer_copy(c->dnscrypt_buffer, c->buffer);
|
||||
return 1;
|
||||
}
|
||||
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,
|
||||
qinfo.qname_len);
|
||||
worker->stats.num_query_dnscrypt_cleartext++;
|
||||
sldns_buffer_copy(c->dnscrypt_buffer, c->buffer);
|
||||
return 1;
|
||||
}
|
||||
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,
|
||||
qinfo.qclass, &edns, repinfo);
|
||||
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 */
|
||||
#endif
|
||||
if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
|
||||
&edns, repinfo, c->buffer)) {
|
||||
regional_free_all(worker->scratchpad);
|
||||
@@ -2121,7 +2129,7 @@ send_reply_rc:
|
||||
}
|
||||
}
|
||||
#ifdef USE_DNSCRYPT
|
||||
if(!dnsc_handle_uncurved_request(repinfo)) {
|
||||
if(!dnsc_handle_uncurved_request(repinfo, c->buffer)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -2234,23 +2242,16 @@ void worker_probe_timer_cb(void* arg)
|
||||
}
|
||||
|
||||
struct worker*
|
||||
worker_create(struct daemon* daemon, int id, int* ports, int n)
|
||||
worker_create(struct daemon* daemon, int id)
|
||||
{
|
||||
unsigned int seed;
|
||||
struct worker* worker = (struct worker*)calloc(1,
|
||||
sizeof(struct worker));
|
||||
if(!worker)
|
||||
return NULL;
|
||||
worker->numports = n;
|
||||
worker->ports = (int*)memdup(ports, sizeof(int)*n);
|
||||
if(!worker->ports) {
|
||||
free(worker);
|
||||
return NULL;
|
||||
}
|
||||
worker->daemon = daemon;
|
||||
worker->thread_num = id;
|
||||
if(!(worker->cmd = tube_create())) {
|
||||
free(worker->ports);
|
||||
free(worker);
|
||||
return NULL;
|
||||
}
|
||||
@@ -2258,7 +2259,6 @@ worker_create(struct daemon* daemon, int id, int* ports, int n)
|
||||
if(!(worker->rndstate = ub_initstate(daemon->rand))) {
|
||||
log_err("could not init random numbers.");
|
||||
tube_delete(worker->cmd);
|
||||
free(worker->ports);
|
||||
free(worker);
|
||||
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->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
|
||||
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,
|
||||
&worker_alloc_cleanup, worker,
|
||||
cfg->do_udp || cfg->udp_upstream_without_downstream,
|
||||
worker->daemon->connect_dot_sslctx, cfg->delay_close,
|
||||
cfg->tls_use_sni, dtenv, cfg->udp_connect,
|
||||
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) {
|
||||
log_err("could not create outgoing sockets");
|
||||
worker_delete(worker);
|
||||
@@ -2517,7 +2517,6 @@ worker_delete(struct worker* worker)
|
||||
tube_delete(worker->cmd);
|
||||
comm_timer_delete(worker->stat_timer);
|
||||
comm_timer_delete(worker->env.probe_timer);
|
||||
free(worker->ports);
|
||||
if(worker->thread_num == 0) {
|
||||
#ifdef UB_ON_WINDOWS
|
||||
wsvc_desetup_worker(worker);
|
||||
@@ -2653,6 +2652,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
|
||||
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))
|
||||
{
|
||||
log_assert(0);
|
||||
|
||||
+1
-7
@@ -104,10 +104,6 @@ struct worker {
|
||||
struct listen_dnsport* front;
|
||||
/** the backside outside network interface to the auth servers */
|
||||
struct outside_network* back;
|
||||
/** ports to be used by this worker. */
|
||||
int* ports;
|
||||
/** number of ports for this worker */
|
||||
int numports;
|
||||
/** the signal handler */
|
||||
struct comm_signal* comsig;
|
||||
/** commpoint to listen to commands. */
|
||||
@@ -146,11 +142,9 @@ struct worker {
|
||||
* with backpointers only. Use worker_init on it later.
|
||||
* @param daemon: the daemon that this worker thread is part of.
|
||||
* @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.
|
||||
*/
|
||||
struct worker* worker_create(struct daemon* daemon, int id, int* ports, int n);
|
||||
struct worker* worker_create(struct daemon* daemon, int id);
|
||||
|
||||
/**
|
||||
* Initialize worker.
|
||||
|
||||
+23
-3
@@ -474,10 +474,18 @@ dnscrypt_server_curve(const dnsccert *cert,
|
||||
uint8_t *const buf = sldns_buffer_begin(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 (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);
|
||||
@@ -520,6 +528,7 @@ dnscrypt_server_curve(const dnsccert *cert,
|
||||
DNSCRYPT_MAGIC_HEADER_LEN,
|
||||
nonce,
|
||||
crypto_box_NONCEBYTES);
|
||||
sldns_buffer_flip(buffer);
|
||||
sldns_buffer_set_limit(buffer, len + DNSCRYPT_REPLY_HEADER_SIZE);
|
||||
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);
|
||||
for (i = 0U; i < dnscenv->signed_certs_count; i++) {
|
||||
if(!certs[i].keypair)
|
||||
continue;
|
||||
if (memcmp(certs[i].magic_query, dnscrypt_header->magic_query,
|
||||
DNSCRYPT_MAGIC_HEADER_LEN) == 0) {
|
||||
return &certs[i];
|
||||
@@ -804,6 +815,7 @@ dnsc_parse_keys(struct dnsc_env *env, struct config_file *cfg)
|
||||
sizeof *env->keypairs);
|
||||
env->certs = sodium_allocarray(env->signed_certs_count,
|
||||
sizeof *env->certs);
|
||||
memset(env->certs, 0, env->signed_certs_count * sizeof(*env->certs));
|
||||
|
||||
cert_id = 0U;
|
||||
keypair_id = 0U;
|
||||
@@ -919,12 +931,13 @@ dnsc_handle_curved_request(struct dnsc_env* dnscenv,
|
||||
}
|
||||
|
||||
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) {
|
||||
return 1;
|
||||
}
|
||||
sldns_buffer_copy(repinfo->c->dnscrypt_buffer, repinfo->c->buffer);
|
||||
sldns_buffer_copy(repinfo->c->dnscrypt_buffer, buffer);
|
||||
if(!repinfo->is_dnscrypted) {
|
||||
return 1;
|
||||
}
|
||||
@@ -970,12 +983,19 @@ dnsc_create(void)
|
||||
int
|
||||
dnsc_apply_cfg(struct dnsc_env *env, struct config_file *cfg)
|
||||
{
|
||||
int nkeys;
|
||||
if(dnsc_parse_certs(env, cfg) <= 0) {
|
||||
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");
|
||||
}
|
||||
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);
|
||||
env->provider_name = cfg->dnscrypt_provider;
|
||||
|
||||
|
||||
+2
-1
@@ -128,7 +128,8 @@ int dnsc_handle_curved_request(struct dnsc_env* dnscenv,
|
||||
* \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.
|
||||
|
||||
@@ -1737,6 +1737,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
|
||||
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))
|
||||
{
|
||||
log_assert(0);
|
||||
|
||||
@@ -2055,6 +2055,13 @@ These options are part of the ``server:`` section.
|
||||
flushing away any poison.
|
||||
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)
|
||||
|
||||
|
||||
|
||||
@@ -132,6 +132,18 @@ donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg)
|
||||
if(cfg->do_ip6) {
|
||||
if(!donotq_str_cfg(dq, "::1"))
|
||||
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);
|
||||
|
||||
+47
-20
@@ -81,7 +81,8 @@ int BLACKLIST_PENALTY = (120000*4);
|
||||
/** Timeout when only a single probe query per IP is allowed. */
|
||||
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
|
||||
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)) &&
|
||||
(dpns->got6 == 2 || !ie->supports_ipv6)) {
|
||||
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) {
|
||||
@@ -734,7 +735,7 @@ is_caps_whitelisted(struct iter_env* ie, struct iter_qstate* iq)
|
||||
* created for the parent query.
|
||||
*/
|
||||
static void
|
||||
target_count_create(struct iter_qstate* iq)
|
||||
target_count_create(struct module_qstate* qstate, struct iter_qstate* iq)
|
||||
{
|
||||
if(!iq->target_count) {
|
||||
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) {
|
||||
iq->target_count[TARGET_COUNT_REF] = 1;
|
||||
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
|
||||
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)
|
||||
iq->target_count[TARGET_COUNT_QUERIES] += num;
|
||||
iq->dp_target_count++;
|
||||
}
|
||||
|
||||
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)
|
||||
iq->target_count[TARGET_COUNT_NX] += num;
|
||||
}
|
||||
|
||||
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)
|
||||
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];
|
||||
memset(subiq, 0, sizeof(*subiq));
|
||||
subiq->num_target_queries = 0;
|
||||
target_count_create(iq);
|
||||
target_count_create(qstate, iq);
|
||||
subiq->target_count = iq->target_count;
|
||||
if(iq->target_count) {
|
||||
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);
|
||||
}
|
||||
iq->num_target_queries += qs;
|
||||
target_count_increase(iq, qs);
|
||||
target_count_increase(qstate, iq, qs);
|
||||
if(qs != 0) {
|
||||
qstate->ext_state[id] = module_wait_subquery;
|
||||
return 0; /* and wait for them */
|
||||
@@ -2291,7 +2316,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* lookups at a time. */
|
||||
verbose(VERB_ALGO, "try parent-side glue lookup");
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
@@ -2311,7 +2336,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
if(query_count != 0) { /* suspend to await results */
|
||||
verbose(VERB_ALGO, "try parent-side glue lookup");
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
@@ -2795,7 +2820,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->num_target_queries += extra;
|
||||
target_count_increase(iq, extra);
|
||||
target_count_increase(qstate, iq, extra);
|
||||
if(iq->num_target_queries > 0) {
|
||||
/* wait to get all targets, we want to try em */
|
||||
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
|
||||
* this result, we do not have to reply with SERVFAIL */
|
||||
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. */
|
||||
@@ -2969,7 +2994,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
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
|
||||
* 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 */
|
||||
if(extra > 0) {
|
||||
iq->num_target_queries += extra;
|
||||
target_count_increase(iq, extra);
|
||||
target_count_increase(qstate, iq, extra);
|
||||
check_waiting_queries(iq, qstate, id);
|
||||
/* undo qname minimise step because we'll get back here
|
||||
* 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]
|
||||
> MAX_GLOBAL_QUOTA) {
|
||||
char s[LDNS_MAX_DOMAINLEN];
|
||||
@@ -3897,7 +3922,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
|
||||
/* no new addresses, increase the nxns counter, like
|
||||
* this could be a list of wildcards with no new
|
||||
* addresses */
|
||||
target_count_increase_nx(foriq, 1);
|
||||
target_count_increase_nx(qstate, foriq, 1);
|
||||
}
|
||||
verbose(VERB_ALGO, "added target response");
|
||||
delegpt_log(VERB_ALGO, foriq->dp);
|
||||
@@ -3909,7 +3934,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
|
||||
dpns->resolved = 1; /* fail the target */
|
||||
/* do not count cached answers */
|
||||
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,
|
||||
iq->deleg_msg?iq->deleg_msg->rep:
|
||||
(iq->response?iq->response->rep:NULL));
|
||||
target_count_store(qstate, iq);
|
||||
if(!iq->response) {
|
||||
verbose(VERB_ALGO, "No response is set, servfail");
|
||||
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];
|
||||
if(iq) {
|
||||
outbound_list_clear(&iq->outlist);
|
||||
target_count_store(qstate, iq);
|
||||
if(iq->target_count && --iq->target_count[TARGET_COUNT_REF] == 0) {
|
||||
free(iq->target_count);
|
||||
if(*iq->nxns_dp) free(*iq->nxns_dp);
|
||||
|
||||
+11
-2
@@ -105,6 +105,7 @@ libworker_delete_env(struct libworker* w)
|
||||
SSL_CTX_free(w->sslctx);
|
||||
#endif
|
||||
outside_network_delete(w->back);
|
||||
shared_ports_delete(w->shared_ports);
|
||||
}
|
||||
|
||||
/** delete libworker struct */
|
||||
@@ -219,17 +220,25 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
|
||||
libworker_delete(w);
|
||||
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,
|
||||
(size_t)cfg->outgoing_num_ports, cfg->out_ifs,
|
||||
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
|
||||
cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
|
||||
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->do_udp || cfg->udp_upstream_without_downstream, w->sslctx,
|
||||
cfg->delay_close, cfg->tls_use_sni, NULL, cfg->udp_connect,
|
||||
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;
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
|
||||
@@ -60,6 +60,7 @@ struct tube;
|
||||
struct sldns_buffer;
|
||||
struct ub_event_base;
|
||||
struct query_info;
|
||||
struct shared_ports;
|
||||
|
||||
/**
|
||||
* The library-worker status structure
|
||||
@@ -84,6 +85,8 @@ struct libworker {
|
||||
struct comm_base* base;
|
||||
/** the backside outside network interface to the auth servers */
|
||||
struct outside_network* back;
|
||||
/** shared ports structure */
|
||||
struct shared_ports* shared_ports;
|
||||
/** random() table for this worker. */
|
||||
struct ub_randstate* rndstate;
|
||||
/** sslcontext for SSL wrapped DNS over TCP queries */
|
||||
|
||||
+7
-1
@@ -1121,7 +1121,13 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
if((qstate->qinfo.qtype == LDNS_RR_TYPE_A ||
|
||||
qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA ||
|
||||
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 ub_packed_rrset_key* alias_rrset = NULL;
|
||||
struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
|
||||
|
||||
+22
-6
@@ -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 */
|
||||
void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
|
||||
enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus),
|
||||
int ATTR_UNUSED(was_ratelimited))
|
||||
enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited))
|
||||
{
|
||||
struct auth_xfer* xfr = (struct auth_xfer*)arg;
|
||||
struct module_env* env;
|
||||
@@ -5894,7 +5893,16 @@ void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
|
||||
}
|
||||
|
||||
/* 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;
|
||||
struct regional* temp = env->scratch;
|
||||
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 */
|
||||
void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
|
||||
enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus),
|
||||
int ATTR_UNUSED(was_ratelimited))
|
||||
enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited))
|
||||
{
|
||||
struct auth_xfer* xfr = (struct auth_xfer*)arg;
|
||||
struct module_env* env;
|
||||
@@ -7045,7 +7052,16 @@ void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
|
||||
}
|
||||
|
||||
/* 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;
|
||||
struct regional* temp = env->scratch;
|
||||
struct query_info rq;
|
||||
|
||||
Vendored
+3
-1
@@ -277,6 +277,8 @@ find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
|
||||
|
||||
/* snip off front label */
|
||||
lablen = *qname;
|
||||
if(lablen == 0)
|
||||
break;
|
||||
qname += lablen + 1;
|
||||
qnamelen -= lablen + 1;
|
||||
}
|
||||
@@ -1075,7 +1077,7 @@ dns_cache_lookup(struct module_env* env,
|
||||
if(env->cfg->harden_below_nxdomain) {
|
||||
while(!dname_is_root(k.qname)) {
|
||||
if(dpname && dpnamelen
|
||||
&& !dname_subdomain_c(k.qname, dpname))
|
||||
&& !dname_strict_subdomain_c(k.qname, dpname))
|
||||
break; /* no synth nxdomain above the stub */
|
||||
dname_remove_label(&k.qname, &k.qname_len);
|
||||
h = query_info_hash(&k, flags);
|
||||
|
||||
Vendored
+41
-3
@@ -50,6 +50,7 @@
|
||||
#include "util/regional.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/net_help.h"
|
||||
#include "validator/val_utils.h"
|
||||
|
||||
void
|
||||
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 */
|
||||
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* 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;
|
||||
/* ghost-domain: never let an NS overwrite extend lifetime
|
||||
* 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) {
|
||||
size_t i;
|
||||
if(a_aaaa) newd->trust=rrset_trust_add_noAA;
|
||||
newd->ttl = cached->ttl;
|
||||
for(i=0; i<(newd->count+newd->rrsig_count); i++)
|
||||
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.
|
||||
data, (struct packed_rrset_data*)e->data);
|
||||
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 */
|
||||
lock_rw_unlock(&e->lock);
|
||||
ub_packed_rrset_parsedelete(k, alloc);
|
||||
@@ -262,6 +269,29 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
|
||||
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,
|
||||
struct ub_packed_rrset_key* rrset, uint8_t* ce, size_t ce_len,
|
||||
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* new_dname;
|
||||
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);
|
||||
if(!rrset) {
|
||||
log_err("malloc failure in rrset_cache_update_wildcard");
|
||||
|
||||
+158
-75
@@ -42,7 +42,6 @@
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <limits.h>
|
||||
#ifdef USE_TCP_FASTOPEN
|
||||
#include <netinet/tcp.h>
|
||||
@@ -2168,7 +2167,7 @@ void tcp_req_info_clear(struct tcp_req_info* req)
|
||||
while(open) {
|
||||
nopen = open->next;
|
||||
mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp,
|
||||
NULL);
|
||||
NULL, NULL);
|
||||
free(open);
|
||||
open = nopen;
|
||||
}
|
||||
@@ -3400,14 +3399,13 @@ doq_table_delete(struct doq_table* table)
|
||||
}
|
||||
|
||||
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 rbnode_type* node;
|
||||
log_assert(table != NULL);
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.time.tv_sec = tv->tv_sec;
|
||||
key.time.tv_usec = tv->tv_usec;
|
||||
key.time_mono = ts;
|
||||
node = rbtree_search(table->timer_tree, &key);
|
||||
if(node)
|
||||
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)
|
||||
return;
|
||||
/* 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(timer->setlist_prev)
|
||||
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,
|
||||
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;
|
||||
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);
|
||||
}
|
||||
if(timer->timer_in_tree || timer->timer_in_list) {
|
||||
if(timer->time.tv_sec == tv->tv_sec &&
|
||||
timer->time.tv_usec == tv->tv_usec)
|
||||
if(timer->time_mono == ts)
|
||||
return; /* already set on that time */
|
||||
doq_timer_unset(table, timer);
|
||||
}
|
||||
timer->time.tv_sec = tv->tv_sec;
|
||||
timer->time.tv_usec = tv->tv_usec;
|
||||
rb_timer = doq_timer_find_time(table, tv);
|
||||
timer->time_real.tv_sec = tv->tv_sec;
|
||||
timer->time_real.tv_usec = tv->tv_usec;
|
||||
timer->time_mono = ts;
|
||||
rb_timer = doq_timer_find_time(table, ts);
|
||||
if(rb_timer) {
|
||||
/* There is a timeout already with this value. Timer is
|
||||
* added to the setlist. */
|
||||
@@ -3598,15 +3597,29 @@ doq_conn_create(struct comm_point* c, struct doq_pkt_addr* paddr,
|
||||
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 */
|
||||
static void
|
||||
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;
|
||||
if(!node)
|
||||
return;
|
||||
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)
|
||||
doq_table_quic_size_subtract(table, stream->inlen);
|
||||
if(stream->out)
|
||||
@@ -3629,7 +3642,11 @@ doq_conn_delete(struct doq_conn* conn, struct doq_table* table)
|
||||
if(conn->ssl)
|
||||
SSL_set_app_data(conn->ssl, NULL);
|
||||
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);
|
||||
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* f = (struct doq_timer*)key2;
|
||||
if(e->time.tv_sec < f->time.tv_sec)
|
||||
if(e->time_mono < f->time_mono)
|
||||
return -1;
|
||||
if(e->time.tv_sec > f->time.tv_sec)
|
||||
return 1;
|
||||
if(e->time.tv_usec < f->time.tv_usec)
|
||||
return -1;
|
||||
if(e->time.tv_usec > f->time.tv_usec)
|
||||
if(e->time_mono > f->time_mono)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -3942,6 +3955,11 @@ doq_stream_close(struct doq_conn* conn, struct doq_stream* stream,
|
||||
if(stream->is_closed)
|
||||
return 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);
|
||||
if(send_shutdown) {
|
||||
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 */
|
||||
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;
|
||||
if(stream->out) {
|
||||
@@ -3981,6 +4000,11 @@ doq_stream_pickup_answer(struct doq_stream* stream, struct sldns_buffer* buf)
|
||||
}
|
||||
stream->nwrite = 0;
|
||||
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 potential resends, until the remote end has acknowledged them.
|
||||
* 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)
|
||||
doq_table_quic_size_subtract(conn->doq_socket->table,
|
||||
stream->outlen);
|
||||
if(!doq_stream_pickup_answer(stream, buf))
|
||||
if(!doq_stream_pickup_answer(conn, stream, buf))
|
||||
return 0;
|
||||
doq_table_quic_size_add(conn->doq_socket->table, stream->outlen);
|
||||
doq_stream_on_write_list(conn, stream);
|
||||
doq_conn_write_enable(conn);
|
||||
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
|
||||
* allocation failure. */
|
||||
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) {
|
||||
log_err("doq stream in length too large %d",
|
||||
(int)stream->inlen);
|
||||
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);
|
||||
if(!stream->in) {
|
||||
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;
|
||||
}
|
||||
c->repinfo.doq_streamid = stream->stream_id;
|
||||
c->repinfo.doq_stream = stream;
|
||||
conn->doq_socket->current_conn = conn;
|
||||
fptr_ok(fptr_whitelist_comm_point(c->callback));
|
||||
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 */
|
||||
static int
|
||||
doq_stream_recv_data(struct doq_stream* stream, const uint8_t* data,
|
||||
size_t datalen, int* recv_done, struct doq_table* table)
|
||||
doq_stream_recv_data(struct doq_conn* conn, struct doq_stream* stream,
|
||||
const uint8_t* data, size_t datalen, int* recv_done,
|
||||
struct doq_table* table)
|
||||
{
|
||||
int got_data = 0;
|
||||
/* 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) {
|
||||
/* the initial length value is completed */
|
||||
stream->inlen = ntohs(tcplen);
|
||||
if(!doq_stream_datalen_complete(stream, table))
|
||||
if(!doq_stream_datalen_complete(conn, stream, table))
|
||||
return 0;
|
||||
} else {
|
||||
/* store for later */
|
||||
@@ -4256,12 +4314,11 @@ doq_submit_new_token(struct doq_conn* conn)
|
||||
ngtcp2_ssize tokenlen;
|
||||
int ret;
|
||||
const ngtcp2_path* path = ngtcp2_conn_get_path(conn->conn);
|
||||
ngtcp2_tstamp ts = doq_get_timestamp_nanosec();
|
||||
|
||||
tokenlen = ngtcp2_crypto_generate_regular_token(token,
|
||||
conn->doq_socket->static_secret,
|
||||
conn->doq_socket->static_secret_len, path->remote.addr,
|
||||
path->remote.addrlen, ts);
|
||||
path->remote.addrlen, doq_get_timestamp_nanosec());
|
||||
if(tokenlen < 0) {
|
||||
log_err("doq ngtcp2_crypto_generate_regular_token failed");
|
||||
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");
|
||||
return 0;
|
||||
}
|
||||
if(stream_id != 0 && stream_id != 4 && /* allow one stream on a new connection */
|
||||
!doq_table_quic_size_available(doq_conn->doq_socket->table,
|
||||
if(!doq_table_quic_size_available(doq_conn->doq_socket->table,
|
||||
doq_conn->doq_socket->cfg, sizeof(*stream)
|
||||
+ 100 /* estimated query in */
|
||||
+ 512 /* estimated response out */
|
||||
@@ -4383,8 +4439,8 @@ doq_recv_stream_data_cb(ngtcp2_conn* ATTR_UNUSED(conn), uint32_t flags,
|
||||
return 0;
|
||||
}
|
||||
if(datalen != 0) {
|
||||
if(!doq_stream_recv_data(stream, data, datalen, &recv_done,
|
||||
doq_conn->doq_socket->table))
|
||||
if(!doq_stream_recv_data(doq_conn, stream, data, datalen,
|
||||
&recv_done, doq_conn->doq_socket->table))
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/** 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 */
|
||||
static int
|
||||
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_close = doq_stream_close_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.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)
|
||||
{
|
||||
#ifdef CLOCK_REALTIME
|
||||
struct timespec tp;
|
||||
memset(&tp, 0, sizeof(tp));
|
||||
/* Get a nanosecond time, that can be compared with the event base. */
|
||||
if(clock_gettime(CLOCK_REALTIME, &tp) == -1) {
|
||||
log_err("clock_gettime failed: %s", strerror(errno));
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
if(clock_gettime(CLOCK_BOOTTIME, &tp) == -1) {
|
||||
#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) +
|
||||
((uint64_t)tp.tv_nsec);
|
||||
#else
|
||||
}
|
||||
|
||||
static struct timeval doq_get_timevalue(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
if(gettimeofday(&tv, NULL) < 0) {
|
||||
log_err("gettimeofday failed: %s", strerror(errno));
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
}
|
||||
return ((uint64_t)tv.tv_sec)*((uint64_t)1000000000) +
|
||||
((uint64_t)tv.tv_usec)*((uint64_t)1000);
|
||||
#endif /* CLOCK_REALTIME */
|
||||
return tv;
|
||||
}
|
||||
|
||||
/** 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 ret;
|
||||
ngtcp2_tstamp ts;
|
||||
struct ngtcp2_path path;
|
||||
memset(&path, 0, sizeof(path));
|
||||
path.remote.addr = (struct sockaddr*)&paddr->addr;
|
||||
path.remote.addrlen = paddr->addrlen;
|
||||
path.local.addr = (struct sockaddr*)&paddr->localaddr;
|
||||
path.local.addrlen = paddr->localaddrlen;
|
||||
ts = doq_get_timestamp_nanosec();
|
||||
|
||||
ret = ngtcp2_conn_read_pkt(conn->conn, &path, pi,
|
||||
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(err_retry)
|
||||
*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;
|
||||
ngtcp2_path_storage ps;
|
||||
ngtcp2_tstamp ts = doq_get_timestamp_nanosec();
|
||||
size_t num_packets = 0, max_packets = 65535;
|
||||
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,
|
||||
sldns_buffer_begin(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 == NGTCP2_ERR_WRITE_MORE) {
|
||||
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;
|
||||
} else if(ret == NGTCP2_ERR_STREAM_DATA_BLOCKED) {
|
||||
verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_DATA_BLOCKED");
|
||||
#ifdef HAVE_NGTCP2_CCERR_DEFAULT
|
||||
ngtcp2_ccerr_set_application_error(
|
||||
&conn->ccerr, -1, NULL, 0);
|
||||
#else
|
||||
ngtcp2_connection_close_error_set_application_error(&conn->last_error, -1, NULL, 0);
|
||||
#endif
|
||||
if(err_drop)
|
||||
*err_drop = 0;
|
||||
if(!doq_conn_close_error(c, conn)) {
|
||||
if(err_drop)
|
||||
*err_drop = 1;
|
||||
if(stream) {
|
||||
doq_stream_off_write_list(conn, stream);
|
||||
stream = stream->write_next;
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
} else if(ret == NGTCP2_ERR_STREAM_SHUT_WR) {
|
||||
verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_SHUT_WR");
|
||||
#ifdef HAVE_NGTCP2_CCERR_DEFAULT
|
||||
ngtcp2_ccerr_set_application_error(
|
||||
&conn->ccerr, -1, NULL, 0);
|
||||
&conn->ccerr, DOQ_APP_ERROR_CODE, NULL, 0);
|
||||
#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
|
||||
if(err_drop)
|
||||
*err_drop = 0;
|
||||
@@ -5467,7 +5547,8 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
|
||||
if(ret == 0) {
|
||||
/* congestion limited */
|
||||
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;
|
||||
}
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -5558,32 +5639,35 @@ doq_table_pop_first(struct doq_table* table)
|
||||
}
|
||||
|
||||
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 now = doq_get_timestamp_nanosec();
|
||||
ngtcp2_tstamp doq_expiry = ngtcp2_conn_get_expiry(conn->conn);
|
||||
ngtcp2_tstamp doq_now = doq_get_timestamp_nanosec();
|
||||
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.
|
||||
* This should call the callback straight away. Calling it
|
||||
* from the event callbacks is cleaner than calling it here,
|
||||
* because then it is always called with the same locks and
|
||||
* so on. This routine only has the conn.lock. */
|
||||
t = now;
|
||||
t = doq_now;
|
||||
memcpy(tv, &now, sizeof(*tv));
|
||||
} 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 */
|
||||
memset(tv, 0, sizeof(*tv));
|
||||
tv->tv_sec = t / NGTCP2_SECONDS;
|
||||
tv->tv_usec = (t / NGTCP2_MICROSECONDS)%1000000;
|
||||
*ts = t;
|
||||
|
||||
/* 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.time.tv_sec == tv->tv_sec &&
|
||||
conn->timer.time.tv_usec == tv->tv_usec)
|
||||
if(conn->timer.time_mono == *ts)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -5604,13 +5688,12 @@ doq_conn_log_line(struct doq_conn* conn, char* s)
|
||||
int
|
||||
doq_conn_handle_timeout(struct doq_conn* conn)
|
||||
{
|
||||
ngtcp2_tstamp now = doq_get_timestamp_nanosec();
|
||||
int rv;
|
||||
|
||||
if(verbosity >= VERB_ALGO)
|
||||
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) {
|
||||
verbose(VERB_ALGO, "ngtcp2_conn_handle_expiry failed: %s",
|
||||
ngtcp2_strerror(rv));
|
||||
|
||||
@@ -61,6 +61,8 @@ struct config_file;
|
||||
struct addrinfo;
|
||||
struct sldns_buffer;
|
||||
struct tcl_list;
|
||||
struct mesh_area;
|
||||
struct mesh_state;
|
||||
|
||||
/**
|
||||
* Listening for queries structure.
|
||||
@@ -538,8 +540,11 @@ void doq_table_delete(struct doq_table* table);
|
||||
struct doq_timer {
|
||||
/** The rbnode in the tree sorted by timeout value. Key this struct. */
|
||||
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. */
|
||||
struct timeval time;
|
||||
struct timeval time_real;
|
||||
/** If the timer is in the time tree, with the node. */
|
||||
int timer_in_tree;
|
||||
/** If there are more timers with the exact same timeout value,
|
||||
@@ -689,6 +694,11 @@ struct doq_stream {
|
||||
uint8_t* out;
|
||||
/** if the stream is on the 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 */
|
||||
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 */
|
||||
int doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream,
|
||||
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 */
|
||||
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.
|
||||
* @param conn: connection, caller must hold lock on it.
|
||||
* @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
|
||||
* 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 */
|
||||
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. */
|
||||
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 */
|
||||
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
|
||||
* deletion. */
|
||||
@@ -851,6 +873,9 @@ int doq_table_quic_size_available(struct doq_table* table,
|
||||
|
||||
/** doq get the quic size value */
|
||||
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 */
|
||||
|
||||
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 */
|
||||
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 */
|
||||
|
||||
@@ -573,7 +573,7 @@ enum respip_action {
|
||||
respip_always_nxdomain = local_zone_always_nxdomain,
|
||||
/** answer with nodata response */
|
||||
respip_always_nodata = local_zone_always_nodata,
|
||||
/** answer with nodata response */
|
||||
/** drop query */
|
||||
respip_always_deny = local_zone_always_deny,
|
||||
/** RPZ: truncate answer in order to force switch to tcp */
|
||||
respip_truncate = local_zone_truncate,
|
||||
|
||||
+54
-14
@@ -506,6 +506,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
"incoming query.");
|
||||
if(rep->c->use_h2)
|
||||
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);
|
||||
mesh->stats_dropped++;
|
||||
return;
|
||||
@@ -519,6 +521,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
"dropping incoming query.");
|
||||
if(rep->c->use_h2)
|
||||
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);
|
||||
mesh->num_queries_replyaddr_limit++;
|
||||
return;
|
||||
@@ -593,6 +597,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
added_tcp = 1;
|
||||
if(rep->c->use_h2) {
|
||||
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 */
|
||||
if(timeout && !mesh_serve_expired_init(s, timeout)) {
|
||||
@@ -648,6 +654,8 @@ servfail_mem:
|
||||
qinfo, qid, qflags, edns);
|
||||
if(rep->c->use_h2)
|
||||
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);
|
||||
if(added_reply_without_accounting) {
|
||||
mesh_remove_reply_without_accounting(s, repadded);
|
||||
@@ -979,8 +987,7 @@ cfg_region_strlist_copy(struct regional* region, struct config_strlist* list)
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Copy the client info to the query region. */
|
||||
static struct respip_client_info*
|
||||
struct respip_client_info*
|
||||
mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo)
|
||||
{
|
||||
size_t i;
|
||||
@@ -1025,6 +1032,11 @@ mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo)
|
||||
cinfo->view->name);
|
||||
if(!client_info->view_name)
|
||||
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;
|
||||
}
|
||||
@@ -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
|
||||
* connection gets cleanup before HTTP/2 stream close. */
|
||||
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 */
|
||||
/* 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,
|
||||
LDNS_EDNS_REPORT_CHANNEL);
|
||||
if(!opt) return;
|
||||
agent_domain_len = opt->opt_len;
|
||||
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
|
||||
* root; from RFC9567. */
|
||||
return;
|
||||
@@ -1827,6 +1843,8 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
mstate->reply_list = NULL;
|
||||
if(r->query_reply.c->use_h2)
|
||||
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);
|
||||
mstate->reply_list = reply_list;
|
||||
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;
|
||||
if(r->query_reply.c->use_h2) {
|
||||
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);
|
||||
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)
|
||||
r->h2_stream = rep->c->h2_stream;
|
||||
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
|
||||
* 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,
|
||||
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;
|
||||
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 */
|
||||
while(n) {
|
||||
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 */
|
||||
if(prev) prev->next = 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
|
||||
* don't point back. */
|
||||
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; */
|
||||
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
|
||||
* 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) &&
|
||||
*encode_repp == rep)
|
||||
*encode_repp == rep))
|
||||
*encode_repp = NULL;
|
||||
|
||||
return 1;
|
||||
@@ -2566,12 +2596,15 @@ mesh_serve_expired_callback(void* arg)
|
||||
qstate->client_info, &actinfo, msg->rep, &alias_rrset, &encode_rep,
|
||||
qstate->env->auth_zones)) {
|
||||
return;
|
||||
} else if(partial_rep &&
|
||||
!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep,
|
||||
} else if(partial_rep) {
|
||||
if(!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep,
|
||||
qstate->client_info, must_validate, &encode_rep, qstate->region,
|
||||
qstate->env->auth_zones, qstate->env->views,
|
||||
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) {
|
||||
@@ -2582,6 +2615,7 @@ mesh_serve_expired_callback(void* arg)
|
||||
partial_rep = encode_rep;
|
||||
}
|
||||
}
|
||||
msg->rep = encode_rep;
|
||||
/* We've found a partial reply ending with an
|
||||
* alias. Replace the lookup qinfo for the
|
||||
* 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);
|
||||
|
||||
for(r = mstate->reply_list; r; r = r->next) {
|
||||
struct timeval old;
|
||||
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
|
||||
if(mstate->s.env->cfg->discard_timeout != 0 &&
|
||||
if(mesh_is_udp(r)) {
|
||||
struct timeval old;
|
||||
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 >
|
||||
mstate->s.env->cfg->discard_timeout) {
|
||||
/* Drop the reply, it is too old */
|
||||
@@ -2626,10 +2661,15 @@ mesh_serve_expired_callback(void* arg)
|
||||
mstate->reply_list = NULL;
|
||||
if(r->query_reply.c->use_h2)
|
||||
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);
|
||||
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++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
+8
-1
@@ -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 h2_stream: if not NULL, it specifies the h2_stream to match
|
||||
* 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,
|
||||
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
|
||||
* 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,
|
||||
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 */
|
||||
|
||||
+321
-67
@@ -208,6 +208,7 @@ static void
|
||||
waiting_tcp_delete(struct waiting_tcp* w)
|
||||
{
|
||||
if(!w) return;
|
||||
free(w->tls_auth_name);
|
||||
if(w->timer)
|
||||
comm_timer_delete(w->timer);
|
||||
free(w);
|
||||
@@ -1480,7 +1481,7 @@ portcomm_loweruse(struct outside_network* outnet, struct port_comm* pc)
|
||||
pif = pc->pif;
|
||||
log_assert(pif->inuse > 0);
|
||||
#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
|
||||
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 */
|
||||
static int setup_if(struct port_if* pif, const char* addrstr,
|
||||
int* avail, int numavail, size_t numfd)
|
||||
static int setup_if(struct port_if* pif, const char* addrstr, 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) &&
|
||||
!netblockstrtoaddr(addrstr, UNBOUND_DNS_PORT,
|
||||
&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");
|
||||
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
|
||||
pif->maxout = (int)numfd;
|
||||
pif->inuse = 0;
|
||||
@@ -1726,12 +1727,12 @@ struct outside_network*
|
||||
outside_network_create(struct comm_base *base, 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,
|
||||
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
|
||||
int numavailports, size_t unwanted_threshold, int tcp_mss,
|
||||
struct ub_randstate* rnd, int use_caps_for_id,
|
||||
size_t unwanted_threshold, int tcp_mss,
|
||||
void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
|
||||
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 tcp_auth_query_timeout)
|
||||
int tcp_auth_query_timeout, struct shared_ports* shared_ports)
|
||||
{
|
||||
struct outside_network* outnet = (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->tcp_mss = tcp_mss;
|
||||
outnet->ip_dscp = dscp;
|
||||
outnet->shared_ports = shared_ports;
|
||||
#ifndef S_SPLINT_S
|
||||
if(delayclose) {
|
||||
outnet->delayclose = 1;
|
||||
@@ -1776,7 +1778,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
if(udp_connect) {
|
||||
outnet->udp_connect = 1;
|
||||
}
|
||||
if(numavailports == 0 || num_ports == 0) {
|
||||
if(num_ports == 0) {
|
||||
log_err("no outgoing ports available");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
@@ -1844,13 +1846,13 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
/* allocate interfaces */
|
||||
if(num_ifs == 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");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
}
|
||||
if(do_ip6 && !setup_if(&outnet->ip6_ifs[0], "::",
|
||||
availports, numavailports, num_ports)) {
|
||||
num_ports, outnet->shared_ports)) {
|
||||
log_err("malloc failed");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
@@ -1861,7 +1863,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
for(i=0; i<num_ifs; i++) {
|
||||
if(str_is_ip6(ifs[i]) && do_ip6) {
|
||||
if(!setup_if(&outnet->ip6_ifs[done_6], ifs[i],
|
||||
availports, numavailports, num_ports)){
|
||||
num_ports, outnet->shared_ports)){
|
||||
log_err("malloc failed");
|
||||
outside_network_delete(outnet);
|
||||
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(!setup_if(&outnet->ip4_ifs[done_4], ifs[i],
|
||||
availports, numavailports, num_ports)){
|
||||
num_ports, outnet->shared_ports)){
|
||||
log_err("malloc failed");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
@@ -1948,9 +1950,6 @@ outside_network_delete(struct outside_network* outnet)
|
||||
comm_point_delete(pc->cp);
|
||||
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);
|
||||
@@ -1964,9 +1963,6 @@ outside_network_delete(struct outside_network* outnet)
|
||||
comm_point_delete(pc->cp);
|
||||
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);
|
||||
@@ -2176,7 +2172,10 @@ static int
|
||||
select_ifport(struct outside_network* outnet, struct pending* pend,
|
||||
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;
|
||||
/* randomly select interface and port */
|
||||
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);
|
||||
pif = &ifs[my_if];
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
if(outnet->udp_connect) {
|
||||
/* if we connect() we cannot reuse fds for a port */
|
||||
if(pif->inuse >= pif->avail_total) {
|
||||
tries++;
|
||||
if(tries < MAX_PORT_RETRY)
|
||||
continue;
|
||||
log_err("failed to find an open port, drop msg");
|
||||
return 0;
|
||||
}
|
||||
my_port = pif->inuse + ub_random_max(outnet->rnd,
|
||||
pif->avail_total - pif->inuse);
|
||||
} else {
|
||||
my_port = ub_random_max(outnet->rnd, pif->avail_total);
|
||||
if(my_port < pif->inuse) {
|
||||
/* port already open */
|
||||
pend->pc = pif->out[my_port];
|
||||
verbose(VERB_ALGO, "using UDP if=%d port=%d",
|
||||
my_if, pend->pc->number);
|
||||
break;
|
||||
}
|
||||
if(!shared_ports_fetch_random(outnet->shared_ports,
|
||||
pif->shpif, outnet->rnd, outnet->udp_connect,
|
||||
pif->inuse, &portno, &reused)) {
|
||||
tries++;
|
||||
if(tries < MAX_PORT_RETRY)
|
||||
continue;
|
||||
log_err("failed to find an open port, drop msg");
|
||||
return 0;
|
||||
}
|
||||
if(reused) {
|
||||
/* port already open */
|
||||
log_assert(portno < pif->inuse);
|
||||
pend->pc = pif->out[portno];
|
||||
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
|
||||
my_port = portno = 0;
|
||||
portno = 0;
|
||||
#endif
|
||||
/* try to open new port, if fails, loop to try again */
|
||||
fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen,
|
||||
portno, &inuse, outnet->rnd, outnet->ip_dscp);
|
||||
if(fd == -1 && !inuse) {
|
||||
/* nonrecoverable error making socket */
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
shared_ports_return_port(outnet->shared_ports,
|
||||
pif->shpif, portno);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
if(fd != -1) {
|
||||
@@ -2237,6 +2234,11 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
|
||||
pend->addrlen);
|
||||
}
|
||||
sock_close(fd);
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
shared_ports_return_port(
|
||||
outnet->shared_ports,
|
||||
pif->shpif, portno);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -2254,14 +2256,14 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
|
||||
|
||||
/* grab port in interface */
|
||||
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++;
|
||||
break;
|
||||
}
|
||||
/* 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);
|
||||
tries++;
|
||||
if(tries == MAX_PORT_RETRY) {
|
||||
@@ -2553,7 +2555,16 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
|
||||
w->cb = callback;
|
||||
w->cb_arg = callback_arg;
|
||||
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->id_node.key = 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;
|
||||
socklen_t addrlen;
|
||||
int i, try, pnum, dscp;
|
||||
int i, try, dscp;
|
||||
struct port_if* pif;
|
||||
|
||||
/* create fd */
|
||||
dscp = outnet->ip_dscp;
|
||||
for(try = 0; try<1000; try++) {
|
||||
int port = 0;
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
int reused = 0;
|
||||
#endif
|
||||
int freebind = 0;
|
||||
int noproto = 0;
|
||||
int inuse = 0;
|
||||
@@ -3680,16 +3694,18 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
|
||||
addr = &pif->addr;
|
||||
addrlen = pif->addrlen;
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
pnum = ub_random_max(outnet->rnd, pif->avail_total);
|
||||
if(pnum < pif->inuse) {
|
||||
/* port already open */
|
||||
port = pif->out[pnum]->number;
|
||||
} else {
|
||||
/* unused ports in start part of array */
|
||||
port = pif->avail_ports[pnum - pif->inuse];
|
||||
if(!shared_ports_fetch_random(outnet->shared_ports,
|
||||
pif->shpif, outnet->rnd, 0, pif->inuse,
|
||||
&port, &reused)) {
|
||||
/* try again, perhaps another interface. */
|
||||
continue;
|
||||
}
|
||||
if(reused) {
|
||||
log_assert(port < pif->inuse);
|
||||
port = pif->out[port]->number;
|
||||
}
|
||||
#else
|
||||
pnum = port = 0;
|
||||
port = 0;
|
||||
#endif
|
||||
if(addr_is_ip6(to_addr, to_addrlen)) {
|
||||
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,
|
||||
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) {
|
||||
return fd;
|
||||
}
|
||||
@@ -3961,11 +3985,7 @@ if_get_mem(struct port_if* pif)
|
||||
{
|
||||
size_t s;
|
||||
int i;
|
||||
s = sizeof(*pif) +
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
sizeof(int)*pif->avail_total +
|
||||
#endif
|
||||
sizeof(struct port_comm*)*pif->maxout;
|
||||
s = sizeof(*pif) + sizeof(struct port_comm*)*pif->maxout;
|
||||
for(i=0; i<pif->inuse; i++)
|
||||
s += sizeof(*pif->out[i]) +
|
||||
comm_point_get_mem(pif->out[i]->cp);
|
||||
@@ -4053,3 +4073,237 @@ serviced_get_mem(struct serviced_query* sq)
|
||||
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
@@ -70,6 +70,8 @@ struct module_env;
|
||||
struct module_qstate;
|
||||
struct query_info;
|
||||
struct config_file;
|
||||
struct shared_ports;
|
||||
struct shared_ports_if;
|
||||
|
||||
/**
|
||||
* Send queries to outside servers and wait for answers from servers.
|
||||
@@ -119,6 +121,9 @@ struct outside_network {
|
||||
int udp_connect;
|
||||
/** number of udp packets sent. */
|
||||
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 */
|
||||
struct port_if* ip4_ifs;
|
||||
@@ -211,11 +216,8 @@ struct port_if {
|
||||
int pfxlen;
|
||||
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
/** 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 shared port numbers for this interface. */
|
||||
struct shared_ports_if* shpif;
|
||||
#endif
|
||||
|
||||
/** array of the commpoints currently in use.
|
||||
@@ -245,6 +247,42 @@ struct port_comm {
|
||||
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.
|
||||
*/
|
||||
@@ -419,7 +457,7 @@ struct waiting_tcp {
|
||||
void* cb_arg;
|
||||
/** if it uses 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;
|
||||
/** the packet was involved in an error, to stop looping errors */
|
||||
int error_count;
|
||||
@@ -551,8 +589,6 @@ struct serviced_query {
|
||||
* @param infra: pointer to infra cached used 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 availports: array of available ports.
|
||||
* @param numavailports: number of available ports in array.
|
||||
* @param unwanted_threshold: when to take defensive action.
|
||||
* @param unwanted_action: the action to take.
|
||||
* @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 tcp_reuse_timeout: timeout for REUSE entries in milliseconds.
|
||||
* @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.
|
||||
*/
|
||||
struct outside_network* outside_network_create(struct comm_base* base,
|
||||
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,
|
||||
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
|
||||
int numavailports, size_t unwanted_threshold, int tcp_mss,
|
||||
struct ub_randstate* rnd, int use_caps_for_id,
|
||||
size_t unwanted_threshold, int tcp_mss,
|
||||
void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
|
||||
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 tcp_auth_query_timeout);
|
||||
int tcp_auth_query_timeout, struct shared_ports* shared_ports);
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
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 */
|
||||
int outnet_udp_cb(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply *reply_info);
|
||||
|
||||
@@ -129,6 +129,12 @@ worker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void
|
||||
libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
struct outbound_entry* libworker_send_query(
|
||||
struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags),
|
||||
int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
|
||||
|
||||
@@ -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));
|
||||
#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
|
||||
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
|
||||
return 0;
|
||||
}
|
||||
@@ -2676,6 +2676,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
|
||||
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))
|
||||
{
|
||||
log_assert(0);
|
||||
|
||||
+27
-3
@@ -1126,15 +1126,16 @@ outside_network_create(struct comm_base* base, size_t bufsize,
|
||||
int ATTR_UNUSED(dscp),
|
||||
struct infra_cache* infra,
|
||||
struct ub_randstate* ATTR_UNUSED(rnd),
|
||||
int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports),
|
||||
int ATTR_UNUSED(numavailports), size_t ATTR_UNUSED(unwanted_threshold),
|
||||
int ATTR_UNUSED(use_caps_for_id),
|
||||
size_t ATTR_UNUSED(unwanted_threshold),
|
||||
int ATTR_UNUSED(outgoing_tcp_mss),
|
||||
void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param),
|
||||
int ATTR_UNUSED(do_udp), void* ATTR_UNUSED(sslctx),
|
||||
int ATTR_UNUSED(delayclose), int ATTR_UNUSED(tls_use_sni),
|
||||
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(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 outside_network* outnet = calloc(1,
|
||||
@@ -1981,6 +1982,20 @@ int outnet_tcp_connect(int ATTR_UNUSED(s), struct sockaddr_storage* ATTR_UNUSED(
|
||||
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),
|
||||
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* ATTR_UNUSED(arg))
|
||||
{
|
||||
|
||||
@@ -1282,6 +1282,61 @@ static void localzone_test(void)
|
||||
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)
|
||||
{
|
||||
printf("test %s:%s\n", file, func);
|
||||
@@ -1356,6 +1411,7 @@ main(int argc, char* argv[])
|
||||
msgparse_test();
|
||||
edns_ede_answer_encode_test();
|
||||
localzone_test();
|
||||
mesh_test();
|
||||
#ifdef CLIENT_SUBNET
|
||||
ecs_test();
|
||||
#endif /* CLIENT_SUBNET */
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "config.h"
|
||||
#include "testcode/unitmain.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/random.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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
unit_show_feature("tcp_reuse");
|
||||
@@ -486,4 +759,7 @@ void tcpreuse_test(void)
|
||||
tcp_reuse_tree_list_test();
|
||||
waiting_tcp_list_test();
|
||||
reuse_write_wait_test();
|
||||
unit_show_feature("shared_ports");
|
||||
shared_port_test_ifs();
|
||||
shared_port_test_port();
|
||||
}
|
||||
|
||||
Vendored
+1
@@ -12,6 +12,7 @@ server:
|
||||
ede: no # It is not needed for dns-error-reporting; only for clients to receive EDEs
|
||||
dns-error-reporting: yes
|
||||
do-ip6: no
|
||||
do-not-query-localhost: no
|
||||
|
||||
stub-zone:
|
||||
name: domain
|
||||
|
||||
+9
-8
@@ -9,20 +9,21 @@ PRE="../.."
|
||||
|
||||
# do the test
|
||||
|
||||
# Query plain request over DNSCrypt channel get closed
|
||||
# We use TCP to avoid hanging on waiting for UDP.
|
||||
# We expect `outfile` to contain no DNS payload
|
||||
echo "> dig TCP www.example.com. DNSCrypt port"
|
||||
dig +tcp @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile
|
||||
# Query plain request over DNSCrypt.
|
||||
# This used to close the channel; now it returns SERVFAIL.
|
||||
# Old: We use TCP to avoid hanging on waiting for UDP.
|
||||
# We expect `outfile` to contain no DNS payload
|
||||
echo "> dig www.example.com. DNSCrypt port"
|
||||
dig @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile
|
||||
echo "> cat logfiles"
|
||||
cat fwd.log
|
||||
cat unbound.log
|
||||
echo "> check answer"
|
||||
if grep "QUESTION SECTION" outfile; then
|
||||
if grep "SERVFAIL" outfile; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "NOK"
|
||||
exit 1
|
||||
else
|
||||
echo "OK"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
@@ -9,20 +9,21 @@ PRE="../.."
|
||||
|
||||
# do the test
|
||||
|
||||
# Query plain request over DNSCrypt channel get closed
|
||||
# We use TCP to avoid hanging on waiting for UDP.
|
||||
# We expect `outfile` to contain no DNS payload
|
||||
echo "> dig TCP www.example.com. DNSCrypt port"
|
||||
dig +tcp @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile
|
||||
# Query plain request over DNSCrypt.
|
||||
# This used to close the channel; now it returns SERVFAIL.
|
||||
# Old: We use TCP to avoid hanging on waiting for UDP.
|
||||
# We expect `outfile` to contain no DNS payload
|
||||
echo "> dig www.example.com. DNSCrypt port"
|
||||
dig @127.0.0.1 -p $DNSCRYPT_PORT www.example.com. A | tee outfile
|
||||
echo "> cat logfiles"
|
||||
cat fwd.log
|
||||
cat unbound.log
|
||||
echo "> check answer"
|
||||
if grep "QUESTION SECTION" outfile; then
|
||||
if grep "SERVFAIL" outfile; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "NOK"
|
||||
exit 1
|
||||
else
|
||||
echo "OK"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
Vendored
+4
-4
@@ -319,7 +319,7 @@ example.com. 360 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
; this is picked up from the parent (because this simulation has the
|
||||
; 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
|
||||
|
||||
; 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
|
||||
example.com. 360 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 3600 IN A 1.2.3.4
|
||||
ns.example.com. 360 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; 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
|
||||
example.com. 330 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 3570 IN A 1.2.3.4
|
||||
ns.example.com. 330 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
; now the just-looked-up entry
|
||||
STEP 190 QUERY
|
||||
@@ -388,7 +388,7 @@ www.example.com. 3600 IN A 10.20.30.40
|
||||
SECTION AUTHORITY
|
||||
example.com. 3600 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 3570 IN A 1.2.3.4
|
||||
ns.example.com. 3600 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
|
||||
|
||||
@@ -687,6 +687,9 @@ calc_size(sldns_buffer* pkt, uint16_t type, struct rr_parse* rr)
|
||||
}
|
||||
rdf++;
|
||||
}
|
||||
/* rdata ended before all _dname_count names were seen */
|
||||
if(count != 0)
|
||||
return 0; /* the rdata is too short. */
|
||||
}
|
||||
/* remaining rdata */
|
||||
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
|
||||
* is needed.
|
||||
*/
|
||||
if(repinfo->remote_addr.ss_family == AF_INET) {
|
||||
if(repinfo->client_addr.ss_family == AF_INET) {
|
||||
memcpy(server_cookie + 16,
|
||||
&((struct sockaddr_in*)&repinfo->remote_addr)->sin_addr, 4);
|
||||
&((struct sockaddr_in*)&repinfo->client_addr)->sin_addr, 4);
|
||||
} else {
|
||||
cookie_is_v4 = 0;
|
||||
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 &&
|
||||
|
||||
@@ -198,6 +198,7 @@ get_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname,
|
||||
{
|
||||
struct packed_rrset_data* d;
|
||||
size_t len;
|
||||
if(!rrset) return;
|
||||
if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME &&
|
||||
ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME)
|
||||
return;
|
||||
|
||||
@@ -610,6 +610,7 @@ int
|
||||
fptr_whitelist_alloc_cleanup(void (*fptr)(void*))
|
||||
{
|
||||
if(fptr == &worker_alloc_cleanup) return 1;
|
||||
else if(fptr == &libworker_alloc_cleanup) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -730,6 +730,12 @@ struct module_qstate {
|
||||
|
||||
/** whether the reply should be dropped */
|
||||
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
@@ -1835,7 +1835,6 @@ doq_send_retry(struct comm_point* c, struct doq_pkt_addr* paddr,
|
||||
char host[256], port[32];
|
||||
struct ngtcp2_cid scid;
|
||||
uint8_t token[NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN];
|
||||
ngtcp2_tstamp ts;
|
||||
ngtcp2_ssize tokenlen, ret;
|
||||
|
||||
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;
|
||||
doq_cid_randfill(&scid, scid.datalen, c->doq_socket->rnd);
|
||||
|
||||
ts = doq_get_timestamp_nanosec();
|
||||
|
||||
tokenlen = ngtcp2_crypto_generate_retry_token(token,
|
||||
c->doq_socket->static_secret, c->doq_socket->static_secret_len,
|
||||
hd->version, (void*)&paddr->addr, paddr->addrlen, &scid,
|
||||
&hd->dcid, ts);
|
||||
&hd->dcid, doq_get_timestamp_nanosec());
|
||||
if(tokenlen < 0) {
|
||||
log_err("ngtcp2_crypto_generate_retry_token failed: %s",
|
||||
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)
|
||||
{
|
||||
char host[256], port[32];
|
||||
ngtcp2_tstamp ts;
|
||||
if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host,
|
||||
sizeof(host), port, sizeof(port))) {
|
||||
log_err("doq_verify_retry_token failed");
|
||||
return 0;
|
||||
}
|
||||
ts = doq_get_timestamp_nanosec();
|
||||
verbose(VERB_ALGO, "doq: verifying retry token from %s %s", host,
|
||||
port);
|
||||
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_len, hd->version,
|
||||
(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 "
|
||||
"from %s %s", host, port);
|
||||
return 0;
|
||||
@@ -1936,13 +1931,11 @@ doq_verify_token(struct comm_point* c, struct doq_pkt_addr* paddr,
|
||||
struct ngtcp2_pkt_hd* hd)
|
||||
{
|
||||
char host[256], port[32];
|
||||
ngtcp2_tstamp ts;
|
||||
if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host,
|
||||
sizeof(host), port, sizeof(port))) {
|
||||
log_err("doq_verify_token failed");
|
||||
return 0;
|
||||
}
|
||||
ts = doq_get_timestamp_nanosec();
|
||||
verbose(VERB_ALGO, "doq: verifying token from %s %s", host, port);
|
||||
if(ngtcp2_crypto_verify_regular_token(
|
||||
#ifdef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN
|
||||
@@ -1952,7 +1945,7 @@ doq_verify_token(struct comm_point* c, struct doq_pkt_addr* paddr,
|
||||
#endif
|
||||
c->doq_socket->static_secret, c->doq_socket->static_secret_len,
|
||||
(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",
|
||||
host, port);
|
||||
return 0;
|
||||
@@ -2179,6 +2172,7 @@ doq_pickup_timer(struct comm_point* c)
|
||||
{
|
||||
struct doq_timer* t;
|
||||
struct timeval tv;
|
||||
ngtcp2_tstamp ts = 0;
|
||||
int have_time = 0;
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
|
||||
@@ -2188,27 +2182,24 @@ doq_pickup_timer(struct comm_point* c)
|
||||
t->worker_doq_socket == c->doq_socket) {
|
||||
/* pick up this element */
|
||||
t->worker_doq_socket = c->doq_socket;
|
||||
memcpy(&tv, &t->time_real, sizeof(tv));
|
||||
ts = t->time_mono;
|
||||
have_time = 1;
|
||||
memcpy(&tv, &t->time, sizeof(tv));
|
||||
break;
|
||||
}
|
||||
}
|
||||
lock_rw_unlock(&c->doq_socket->table->lock);
|
||||
|
||||
c->doq_socket->marked_time = ts;
|
||||
if(have_time) {
|
||||
struct timeval rel;
|
||||
timeval_subtract(&rel, &tv, c->doq_socket->now_tv);
|
||||
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",
|
||||
(int)tv.tv_sec, (int)tv.tv_usec, (int)rel.tv_sec,
|
||||
(int)rel.tv_usec);
|
||||
} else {
|
||||
if(comm_timer_is_set(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");
|
||||
}
|
||||
}
|
||||
@@ -2221,13 +2212,14 @@ doq_done_setup_timer_and_write(struct comm_point* c, struct doq_conn* conn)
|
||||
uint8_t cid[NGTCP2_MAX_CIDLEN];
|
||||
rbnode_type* node;
|
||||
struct timeval new_tv;
|
||||
ngtcp2_tstamp new_ts;
|
||||
int write_change = 0, timer_change = 0;
|
||||
|
||||
/* No longer in callbacks, so the pointer to doq_socket is back
|
||||
* to 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;
|
||||
if( (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) {
|
||||
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_basic_unlock(&conn->lock);
|
||||
@@ -2437,7 +2429,7 @@ doq_write_blocked_pkt(struct comm_point* c)
|
||||
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*
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
return NULL;
|
||||
}
|
||||
@@ -2473,11 +2465,11 @@ doq_timer_erase_marker(struct doq_server_socket* doq_socket)
|
||||
{
|
||||
struct doq_timer* t;
|
||||
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)
|
||||
t->worker_doq_socket = NULL;
|
||||
lock_rw_unlock(&doq_socket->table->lock);
|
||||
memset(&doq_socket->marked_time, 0, sizeof(doq_socket->marked_time));
|
||||
doq_socket->marked_time = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2784,7 +2776,7 @@ doq_server_socket_create(struct doq_table* table, struct ub_randstate* rnd,
|
||||
free(doq_socket);
|
||||
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);
|
||||
doq_socket->cfg = cfg;
|
||||
return doq_socket;
|
||||
@@ -3241,7 +3233,7 @@ static void http2_stream_delete(struct http2_session* h2_session,
|
||||
{
|
||||
if(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;
|
||||
}
|
||||
http2_req_stream_clear(h2_stream);
|
||||
@@ -6784,7 +6776,9 @@ comm_point_send_reply(struct comm_reply *repinfo)
|
||||
log_assert(repinfo && repinfo->c);
|
||||
#ifdef USE_DNSCRYPT
|
||||
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;
|
||||
}
|
||||
#else
|
||||
|
||||
+5
-1
@@ -189,6 +189,8 @@ struct comm_reply {
|
||||
/** port number for doq */
|
||||
int doq_srcport;
|
||||
#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;
|
||||
/** timer for this worker on this comm_point to wait on. */
|
||||
struct comm_timer* timer;
|
||||
#ifdef HAVE_NGTCP2
|
||||
/** 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. */
|
||||
time_t* now_tt;
|
||||
/** the current time for use by time functions, timeval. */
|
||||
|
||||
@@ -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* datend = sldns_buffer_current(buf);
|
||||
size_t firstlen;
|
||||
switch(ntohs(rrset->rk.type)) {
|
||||
case LDNS_RR_TYPE_NXT:
|
||||
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:
|
||||
/* two names after another */
|
||||
canon_dname_tolower(datstart, datend);
|
||||
canon_dname_tolower(datstart +
|
||||
dname_valid(datstart, len-2), datend);
|
||||
firstlen = dname_valid(datstart, len-2);
|
||||
if(firstlen && firstlen < len-2)
|
||||
canon_dname_tolower(datstart + firstlen, datend);
|
||||
return;
|
||||
case LDNS_RR_TYPE_RT:
|
||||
case LDNS_RR_TYPE_AFSDB:
|
||||
@@ -1154,8 +1156,9 @@ canonicalize_rdata(sldns_buffer* buf, struct ub_packed_rrset_key* rrset,
|
||||
return;
|
||||
datstart += 2;
|
||||
canon_dname_tolower(datstart, datend);
|
||||
canon_dname_tolower(datstart +
|
||||
dname_valid(datstart, len-2-2), datend);
|
||||
firstlen = dname_valid(datstart, len-2-2);
|
||||
if(firstlen && firstlen < len-2-2)
|
||||
canon_dname_tolower(datstart + firstlen, datend);
|
||||
return;
|
||||
case LDNS_RR_TYPE_NAPTR:
|
||||
if(len < 2+4)
|
||||
@@ -1681,6 +1684,13 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
|
||||
*reason_bogus = LDNS_EDE_DNSSEC_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 */
|
||||
|
||||
|
||||
+13
-4
@@ -157,7 +157,7 @@ val_classify_response(uint16_t query_flags, struct query_info* origqinf,
|
||||
}
|
||||
|
||||
/** Get signer name from RRSIG */
|
||||
static void
|
||||
void
|
||||
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
|
||||
@@ -439,10 +439,15 @@ val_verify_rrset(struct module_env* env, struct val_env* ve,
|
||||
* only improves security status
|
||||
* and bogus is set only once, even if we rechecked the status */
|
||||
if(sec > d->security) {
|
||||
int wc_expanded = 0;
|
||||
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;
|
||||
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;
|
||||
/* update ttl for rrset to fixed value. */
|
||||
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);
|
||||
}
|
||||
/* 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;
|
||||
|
||||
@@ -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,
|
||||
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 */
|
||||
|
||||
+56
-3
@@ -520,6 +520,14 @@ generate_request(struct module_qstate* qstate, int id, uint8_t* name,
|
||||
/* add our blacklist to the query blacklist */
|
||||
sock_list_merge(&(*newq)->blacklist, (*newq)->region,
|
||||
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;
|
||||
return 1;
|
||||
@@ -1069,7 +1077,14 @@ validate_positive_response(struct module_env* env, struct val_env* ve,
|
||||
uint8_t* wc = NULL;
|
||||
size_t wl;
|
||||
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;
|
||||
/* 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;
|
||||
size_t i;
|
||||
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));
|
||||
chase_reply->security = sec_status_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;
|
||||
}
|
||||
if(wc && !wc_cached && env->cfg->aggressive_nsec) {
|
||||
rrset_cache_update_wildcard(env->rrset_cache, s, wc, wl,
|
||||
env->alloc, *env->now);
|
||||
/* Postpone cache adjust until proof has succeeded. */
|
||||
wc_to_cache = 1;
|
||||
cache_wc = wc;
|
||||
cache_wl = wl;
|
||||
cache_s = s;
|
||||
wc_cached = 1;
|
||||
}
|
||||
|
||||
if(wc) wc_rrset = s;
|
||||
}
|
||||
|
||||
/* 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");
|
||||
chase_reply->security = sec_status_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;
|
||||
}
|
||||
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");
|
||||
chase_reply->security = sec_status_secure;
|
||||
@@ -1553,6 +1581,16 @@ validate_any_response(struct module_env* env, struct val_env* ve,
|
||||
"did not exist");
|
||||
chase_reply->security = sec_status_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;
|
||||
}
|
||||
|
||||
@@ -1590,6 +1628,9 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
|
||||
uint8_t* wc = NULL;
|
||||
size_t wl;
|
||||
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;
|
||||
size_t i;
|
||||
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);
|
||||
return;
|
||||
}
|
||||
if(wc) wc_rrset = s;
|
||||
|
||||
/* Refuse wildcarded DNAMEs rfc 4597.
|
||||
* 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));
|
||||
chase_reply->security = sec_status_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;
|
||||
}
|
||||
|
||||
@@ -1685,6 +1730,9 @@ validate_cname_response(struct module_env* env, struct val_env* ve,
|
||||
"did not exist");
|
||||
chase_reply->security = sec_status_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;
|
||||
}
|
||||
|
||||
@@ -3565,6 +3613,11 @@ val_inform_super(struct module_qstate* qstate, int id,
|
||||
verbose(VERB_ALGO, "super: has no validator state");
|
||||
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) {
|
||||
vq->wait_prime_ta = 0;
|
||||
process_prime_response(super, vq, id, qstate->return_rcode,
|
||||
|
||||
Reference in New Issue
Block a user