distribute can send out responses tsig signed

This commit is contained in:
Willem Toorop 2025-11-01 14:32:09 +01:00
parent c86c267b8b
commit 7977ef28f5
8 changed files with 89 additions and 16 deletions

View file

@ -2440,7 +2440,8 @@ worker_init(struct worker* worker, struct config_file *cfg,
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->dist, cfg->num_dist);
cfg->tcp_auth_query_timeout, (const char**)cfg->dist,
(const char**)cfg->dist_tsig, cfg->num_dist);
if(!worker->back) {
log_err("could not create outgoing sockets");
worker_delete(worker);

View file

@ -229,7 +229,9 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
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->dist, cfg->num_dist);
cfg->tcp_auth_query_timeout, (const char**)cfg->dist,
(const char**)cfg->dist_tsig,
cfg->num_dist);
w->env->outnet = w->back;
if(!w->is_bg || w->is_bg_thread) {
lock_basic_unlock(&ctx->cfglock);

View file

@ -59,6 +59,7 @@
#include "util/alloc.h"
#include "util/config_file.h"
#include "util/edns.h"
#include "sldns/parseutil.h"
#include "sldns/sbuffer.h"
#include "sldns/wire2str.h"
#include "services/localzone.h"
@ -66,6 +67,8 @@
#include "respip/respip.h"
#include "services/listen_dnsport.h"
#include "util/timeval_func.h"
#include "util/allow_response_list.h"
#include "util/tsig.h"
#ifdef CLIENT_SUBNET
#include "edns-subnet/subnetmod.h"
@ -1748,14 +1751,56 @@ void mesh_query_done(struct mesh_state* mstate)
1 /* cached */, mstate->s.env->scratch,
sizeof(data) /* udpsize */, NULL /* edns */,
1 /* dnssec */, 0 /* secure */);
log_err("Answer to be send to other unbounds, size: %d",
log_err("Answer to be send to %d other unbounds, size: %d",
mstate->s.env->outnet->num_dist,
(int)sldns_buffer_limit(&dest));
for(i = 0; i < mstate->s.env->outnet->num_dist; i++) {
if(mstate->s.env->outnet->dist[i] != -1)
struct tsig_key* key;
int r;
uint8_t data_signed[8192];
struct sldns_buffer dest_signed;
if(mstate->s.env->outnet->dist[i] == -1
|| mstate->s.env->outnet->dist_tsig[i] == NULL)
continue;
if(mstate->s.env->outnet->dist_tsig[i] == TSIG_NOKEY) {
send(mstate->s.env->outnet->dist[i],
data, sldns_buffer_limit(&dest), 0);
continue;
}
lock_rw_rdlock(&mstate->s.env->tsig_key_table->lock);
key = tsig_key_table_search_fromstr(
mstate->s.env->tsig_key_table,
mstate->s.env->outnet->dist_tsig[i]);
if(!key) {
lock_rw_unlock(
&mstate->s.env->tsig_key_table->lock);
log_err("tsig key \"%s\" not found when "
"distributing responses",
mstate->s.env->outnet->dist_tsig[i]);
continue;
}
sldns_buffer_init_frm_data(&dest_signed,
data_signed, sizeof(data_signed));
sldns_buffer_write(&dest_signed,
data, sldns_buffer_limit(&dest));
if((r = tsig_sign_shared(&dest_signed, key->name,
key->algo->wireformat_name,
key->data, key->data_len,
*mstate->s.env->now))) {
lock_rw_unlock(
&mstate->s.env->tsig_key_table->lock);
log_err("tsig key \"%s\" failed to sign"
"distributing response: %s",
key->name_str,
sldns_lookup_by_id(sldns_tsig_errors, r)?
sldns_lookup_by_id(sldns_tsig_errors, r)->name:"??");
continue;
}
lock_rw_unlock(&mstate->s.env->tsig_key_table->lock);
send(mstate->s.env->outnet->dist[i], data_signed,
sldns_buffer_position(&dest_signed), 0);
}
}
for(r = mstate->reply_list; r; r = r->next) {

View file

@ -59,6 +59,7 @@
#include "util/random.h"
#include "util/fptr_wlist.h"
#include "util/edns.h"
#include "util/allow_response_list.h"
#include "sldns/sbuffer.h"
#include "dnstap/dnstap.h"
#ifdef HAVE_OPENSSL_SSL_H
@ -1678,7 +1679,8 @@ outside_network_create(struct comm_base *base, size_t bufsize,
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, char** dist, int num_dist)
int tcp_auth_query_timeout, const char** dist, const char** dist_tsig,
int num_dist)
{
struct outside_network* outnet = (struct outside_network*)
calloc(1, sizeof(struct outside_network));
@ -1821,7 +1823,8 @@ outside_network_create(struct comm_base *base, size_t bufsize,
}
if (!(outnet->num_dist = num_dist))
outnet->dist = NULL;
else if ((outnet->dist = calloc(num_dist, sizeof(int)))) {
else if ((outnet->dist = calloc(num_dist, sizeof(int))) &&
(outnet->dist_tsig = calloc(num_dist, sizeof(const char*)))) {
int i;
for(i = 0; i < num_dist; i++) {
@ -1838,6 +1841,10 @@ outside_network_create(struct comm_base *base, size_t bufsize,
s = -1;
}
outnet->dist[i] = s;
outnet->dist_tsig[i] = dist_tsig[i] == NULL ? NULL
: strcmp(dist_tsig[i], TSIG_NOKEY)
? strdup(dist_tsig[i])
: TSIG_NOKEY;
}
}
return outnet;
@ -1970,6 +1977,8 @@ outside_network_delete(struct outside_network* outnet)
p = np;
}
}
if(outnet->num_dist > 0 && outnet->dist != NULL)
free(outnet->dist);
free(outnet);
}

View file

@ -194,6 +194,8 @@ struct outside_network {
int num_dist;
/** udp sockets to the addresses to send to be cached responses to */
int* dist;
/** names of TSIG keys with which to sign the outgoing responses */
const char** dist_tsig;
};
/**
@ -574,7 +576,8 @@ struct outside_network* outside_network_create(struct comm_base* base,
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, char** dist, int num_dist);
int tcp_auth_query_timeout, const char** dist, const char** dist_tsig,
int num_dist);
/**
* Delete outside_network structure.

View file

@ -251,6 +251,8 @@ struct config_file {
int num_dist;
/** distribute description strings (IP addresses) */
char **dist;
/** distribute description strings (IP addresses) */
char **dist_tsig;
/** list of allowed responses, linked list */
struct config_str2list* allow_response_list;

View file

@ -276,7 +276,7 @@ use-systemd{COLON} { YDVAR(1, VAR_USE_SYSTEMD) }
do-daemonize{COLON} { YDVAR(1, VAR_DO_DAEMONIZE) }
interface{COLON} { YDVAR(1, VAR_INTERFACE) }
ip-address{COLON} { YDVAR(1, VAR_INTERFACE) }
distribute{COLON} { YDVAR(1, VAR_DISTRIBUTE ) }
distribute{COLON} { YDVAR(2, VAR_DISTRIBUTE ) }
allow-response{COLON} { YDVAR(2, VAR_ALLOW_RESPONSE) }
outgoing-interface{COLON} { YDVAR(1, VAR_OUTGOING_INTERFACE) }
interface-automatic{COLON} { YDVAR(1, VAR_INTERFACE_AUTOMATIC) }

View file

@ -822,17 +822,28 @@ server_interface: VAR_INTERFACE STRING_ARG
cfg_parser->cfg->ifs[cfg_parser->cfg->num_ifs++] = $2;
}
;
server_distribute: VAR_DISTRIBUTE STRING_ARG
server_distribute: VAR_DISTRIBUTE STRING_ARG STRING_ARG
{
OUTYY(("P(server_distribute:%s)\n", $2));
if(cfg_parser->cfg->num_dist == 0)
OUTYY(("P(server_distribute: %s %s)\n", $2, $3));
if(cfg_parser->cfg->num_dist == 0) {
cfg_parser->cfg->dist = calloc(1, sizeof(char*));
else cfg_parser->cfg->dist = realloc(cfg_parser->cfg->dist,
cfg_parser->cfg->dist_tsig = calloc(1, sizeof(char*));
}
else {
cfg_parser->cfg->dist = realloc(cfg_parser->cfg->dist,
(cfg_parser->cfg->num_dist+1)*sizeof(char*));
if(!cfg_parser->cfg->dist)
cfg_parser->cfg->dist_tsig = realloc(
cfg_parser->cfg->dist_tsig,
(cfg_parser->cfg->num_dist+1)*sizeof(char*));
}
if(!cfg_parser->cfg->dist || !cfg_parser->cfg->dist_tsig)
yyerror("out of memory");
else
cfg_parser->cfg->dist[cfg_parser->cfg->num_dist++] = $2;
else {
cfg_parser->cfg->dist[cfg_parser->cfg->num_dist] = $2;
cfg_parser->cfg->dist_tsig[cfg_parser->cfg->num_dist]
= $3;
cfg_parser->cfg->num_dist += 1;
}
}
;
server_allow_response: VAR_ALLOW_RESPONSE STRING_ARG STRING_ARG