From: Willem Toorop Date: Sat, 1 Nov 2025 13:32:09 +0000 (+0100) Subject: distribute can send out responses tsig signed X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7977ef28f5218cbf9a9c2cfeeaeeb076ff35aa12;p=thirdparty%2Funbound.git distribute can send out responses tsig signed --- diff --git a/daemon/worker.c b/daemon/worker.c index ab7ae899a..3151f10a4 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -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); diff --git a/libunbound/libworker.c b/libunbound/libworker.c index affa6185b..58cc895e4 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -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); diff --git a/services/mesh.c b/services/mesh.c index d3cac3204..fcf882859 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -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) { diff --git a/services/outside_network.c b/services/outside_network.c index b34d7e7ea..c36199e84 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -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); } diff --git a/services/outside_network.h b/services/outside_network.h index 881c2ef79..7af9f75d6 100644 --- a/services/outside_network.h +++ b/services/outside_network.h @@ -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. diff --git a/util/config_file.h b/util/config_file.h index 6c6426662..a4d256139 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -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; diff --git a/util/configlexer.lex b/util/configlexer.lex index f01b4f59a..d10d0f08a 100644 --- a/util/configlexer.lex +++ b/util/configlexer.lex @@ -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) } diff --git a/util/configparser.y b/util/configparser.y index 54601fd0b..46844fad7 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -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