]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
distribute can send out responses tsig signed
authorWillem Toorop <willem@nlnetlabs.nl>
Sat, 1 Nov 2025 13:32:09 +0000 (14:32 +0100)
committerWillem Toorop <willem@nlnetlabs.nl>
Sat, 1 Nov 2025 13:32:09 +0000 (14:32 +0100)
daemon/worker.c
libunbound/libworker.c
services/mesh.c
services/outside_network.c
services/outside_network.h
util/config_file.h
util/configlexer.lex
util/configparser.y

index ab7ae899aaf186bd2f2461f15bae81e51b2c447b..3151f10a4a5c898bd4686148dbe0676117874f31 100644 (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);
index affa6185b2225c92ca7445beb675c6ca23bd6261..58cc895e4b740df30b091ea7465348995c299ce1 100644 (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);
index d3cac3204e58128ff86418134a4e942b6dfffbee..fcf882859b995d55b73d0555205f589b2195c1a7 100644 (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) {
index b34d7e7ea223985e234b074211d9a732c1f976b2..c36199e84b8d02506ebdc038c915ccedff268327 100644 (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);
 }
 
index 881c2ef790b3377ae825dfa41a6b1a304fee7ce8..7af9f75d6e91d4ea9d42ed65f12e27fe23401829 100644 (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.
index 6c64266621f41871f10a6ac80895ac5884579085..a4d2561399d98ce670cec9305cc1d2b8275dfeaf 100644 (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;
index f01b4f59a4505262696937c4a5b1987bec7118f4..d10d0f08a3be25ec78b489334ded2da4b4fd3944 100644 (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) }
index 54601fd0bc9118ff5763c45677cbaba07ef924e6..46844fad7e9c3d2772a5812cbd92e9be5fd33b7e 100644 (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