From: W.C.A. Wijngaards Date: Thu, 31 Jul 2025 15:02:55 +0000 (+0200) Subject: - xfr-tsig, check that tsig keys exist at startup and in unbound-checkconf. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fxfr-tsig;p=thirdparty%2Funbound.git - xfr-tsig, check that tsig keys exist at startup and in unbound-checkconf. --- diff --git a/Makefile.in b/Makefile.in index 417e8c4ef..60c15f460 100644 --- a/Makefile.in +++ b/Makefile.in @@ -961,7 +961,7 @@ authzone.lo authzone.o: $(srcdir)/services/authzone.c config.h $(srcdir)/service $(srcdir)/services/rpz.h $(srcdir)/services/localzone.h $(srcdir)/util/storage/dnstree.h \ $(srcdir)/services/view.h $(srcdir)/sldns/sbuffer.h $(srcdir)/util/config_file.h $(srcdir)/daemon/stats.h \ $(srcdir)/util/timehist.h $(srcdir)/libunbound/unbound.h $(srcdir)/respip/respip.h $(srcdir)/util/data/dname.h \ - $(srcdir)/util/data/msgencode.h $(srcdir)/util/regional.h $(srcdir)/util/net_help.h $(srcdir)/util/random.h \ + $(srcdir)/util/data/msgencode.h $(srcdir)/util/regional.h $(srcdir)/util/net_help.h $(srcdir)/util/random.h $(srcdir)/util/tsig.h \ $(srcdir)/services/cache/dns.h $(srcdir)/services/outside_network.h \ $(srcdir)/services/listen_dnsport.h $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/wire2str.h \ $(srcdir)/sldns/parseutil.h $(srcdir)/sldns/keyraw.h $(srcdir)/validator/val_nsec3.h \ @@ -1483,7 +1483,7 @@ memstats.lo memstats.o: $(srcdir)/testcode/memstats.c config.h $(srcdir)/util/lo unbound-checkconf.lo unbound-checkconf.o: $(srcdir)/smallapp/unbound-checkconf.c config.h $(srcdir)/util/log.h \ $(srcdir)/util/config_file.h $(srcdir)/util/module.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h \ $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h \ - $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/net_help.h $(srcdir)/util/regional.h \ + $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/net_help.h $(srcdir)/util/regional.h $(srcdir)/util/tsig.h \ $(srcdir)/iterator/iterator.h $(srcdir)/services/outbound_list.h $(srcdir)/iterator/iter_fwd.h \ $(srcdir)/util/rbtree.h $(srcdir)/iterator/iter_hints.h $(srcdir)/util/storage/dnstree.h \ $(srcdir)/validator/validator.h $(srcdir)/validator/val_utils.h $(srcdir)/services/localzone.h \ diff --git a/daemon/daemon.c b/daemon/daemon.c index 92d0d031b..11d81d048 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -792,7 +792,8 @@ daemon_fork(struct daemon* daemon) /* read auth zonefiles */ if(!auth_zones_apply_cfg(daemon->env->auth_zones, daemon->cfg, 1, - &daemon->use_rpz, daemon->env, &daemon->mods)) + &daemon->use_rpz, daemon->env, &daemon->mods, + daemon->env->tsig_key_table)) fatal_exit("auth_zones could not be setup"); /* Set-up EDNS strings */ diff --git a/daemon/remote.c b/daemon/remote.c index 22475c468..386854061 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5159,7 +5159,8 @@ fr_construct_from_config(struct fast_reload_thread* fr, return 0; } if(!auth_zones_apply_cfg(ct->auth_zones, newcfg, 1, &ct->use_rpz, - fr->worker->daemon->env, &fr->worker->daemon->mods)) { + fr->worker->daemon->env, &fr->worker->daemon->mods, + fr->worker->daemon->env->tsig_key_table)) { fr_construct_clear(ct); return 0; } diff --git a/libunbound/context.c b/libunbound/context.c index 38b5dbf00..02c279bc5 100644 --- a/libunbound/context.c +++ b/libunbound/context.c @@ -90,7 +90,7 @@ context_finalize(struct ub_ctx* ctx) if(!local_zones_apply_cfg(ctx->local_zones, cfg)) return UB_INITFAIL; if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz, - ctx->env, &ctx->mods)) + ctx->env, &ctx->mods, ctx->env->tsig_key_table)) return UB_INITFAIL; if(!(ctx->env->fwds = forwards_create()) || !forwards_apply_cfg(ctx->env->fwds, cfg)) diff --git a/services/authzone.c b/services/authzone.c index e59d384f2..c014c5643 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -55,6 +55,7 @@ #include "util/log.h" #include "util/module.h" #include "util/random.h" +#include "util/tsig.h" #include "services/cache/dns.h" #include "services/outside_network.h" #include "services/listen_dnsport.h" @@ -2091,7 +2092,8 @@ auth_zones_setup_zones(struct auth_zones* az) /** set config items and create zones */ static int -auth_zones_cfg(struct auth_zones* az, struct config_auth* c) +auth_zones_cfg(struct auth_zones* az, struct config_auth* c, + struct tsig_key_table* tsig_key_table) { struct auth_zone* z; struct auth_xfer* x = NULL; @@ -2171,12 +2173,14 @@ auth_zones_cfg(struct auth_zones* az, struct config_auth* c) if(x) { z->zone_is_slave = 1; /* set options on xfer zone */ - if(!xfer_set_masters(&x->task_probe->masters, c, 0)) { + if(!xfer_set_masters(&x->task_probe->masters, c, 0, + tsig_key_table)) { lock_basic_unlock(&x->lock); lock_rw_unlock(&z->lock); return 0; } - if(!xfer_set_masters(&x->task_transfer->masters, c, 1)) { + if(!xfer_set_masters(&x->task_transfer->masters, c, 1, + tsig_key_table)) { lock_basic_unlock(&x->lock); lock_rw_unlock(&z->lock); return 0; @@ -2244,7 +2248,7 @@ az_delete_deleted_zones(struct auth_zones* az) int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg, int setup, int* is_rpz, struct module_env* env, - struct module_stack* mods) + struct module_stack* mods, struct tsig_key_table* tsig_key_table) { struct config_auth* p; az_setall_deleted(az); @@ -2254,7 +2258,7 @@ int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg, continue; } *is_rpz = (*is_rpz || p->isrpz); - if(!auth_zones_cfg(az, p)) { + if(!auth_zones_cfg(az, p, tsig_key_table)) { log_err("cannot config auth zone %s", p->name); return 0; } @@ -7284,9 +7288,30 @@ parse_url(char* url, char** host, char** file, int* port, int* ssl) return 1; } +/** Check the tsig key exists */ +static int +check_tsig_key_exists(struct tsig_key_table* tsig_key_table, + const char* optname, char* str, char* str2) +{ + struct tsig_key* key; + if(!tsig_key_table) + return 1; + + lock_rw_rdlock(&tsig_key_table->lock); + key = tsig_key_table_search_fromstr(tsig_key_table, str2); + lock_rw_unlock(&tsig_key_table->lock); + + if(!key) { + log_err("could not find tsig-key for %s: %s %s", + optname, str, str2); + return 0; + } + return 1; +} + int xfer_set_masters(struct auth_master** list, struct config_auth* c, - int with_http) + int with_http, struct tsig_key_table* tsig_key_table) { struct auth_master* m; struct config_strlist* p; @@ -7322,6 +7347,9 @@ xfer_set_masters(struct auth_master** list, struct config_auth* c, log_err("malloc failure"); return 0; } + if(!check_tsig_key_exists(tsig_key_table, "primary-tsig", + p2->str, p2->str2)) + return 0; m->tsig_key_name = strdup(p2->str2); if(!m->tsig_key_name) { log_err("malloc failure"); @@ -7347,6 +7375,9 @@ xfer_set_masters(struct auth_master** list, struct config_auth* c, log_err("malloc failure"); return 0; } + if(!check_tsig_key_exists(tsig_key_table, "allow-notify-tsig", + p2->str, p2->str2)) + return 0; m->tsig_key_name = strdup(p2->str2); if(!m->tsig_key_name) { log_err("malloc failure"); diff --git a/services/authzone.h b/services/authzone.h index 00e6343f2..7ca0a9963 100644 --- a/services/authzone.h +++ b/services/authzone.h @@ -55,6 +55,7 @@ struct query_info; struct dns_msg; struct edns_data; struct module_env; +struct tsig_key_table; struct worker; struct comm_point; struct comm_timer; @@ -488,11 +489,13 @@ struct auth_zones* auth_zones_create(void); * @param is_rpz: set to 1 if at least one RPZ zone is configured. * @param env: environment for offline verification. * @param mods: modules in environment. + * @param tsig_key_table: tsig key table to check if tsig keys exist. + * If NULL, no check is performed. * @return false on failure. */ int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg, int setup, int* is_rpz, struct module_env* env, - struct module_stack* mods); + struct module_stack* mods, struct tsig_key_table* tsig_key_table); /** initial pick up of worker timeouts, ties events to worker event loop * @param az: auth zones structure @@ -669,10 +672,12 @@ struct auth_xfer* auth_xfer_create(struct auth_zones* az, struct auth_zone* z); * @param list: pointer to start of list. The malloced list is returned here. * @param c: the config items to copy over. * @param with_http: if true, http urls are also included, before the masters. + * @param tsig_key_table: if nonNULL, used to check that tsig keys exist in + * the key table. * @return false on failure. */ int xfer_set_masters(struct auth_master** list, struct config_auth* c, - int with_http); + int with_http, struct tsig_key_table* tsig_key_table); /** xfer nextprobe timeout callback, this is part of task_nextprobe */ void auth_xfer_timer(void* arg); diff --git a/smallapp/unbound-checkconf.c b/smallapp/unbound-checkconf.c index 2ca69e9e6..66f53bd4d 100644 --- a/smallapp/unbound-checkconf.c +++ b/smallapp/unbound-checkconf.c @@ -49,6 +49,7 @@ #include "util/module.h" #include "util/net_help.h" #include "util/regional.h" +#include "util/tsig.h" #include "iterator/iterator.h" #include "iterator/iter_fwd.h" #include "iterator/iter_hints.h" @@ -1003,13 +1004,23 @@ static void check_auth(struct config_file* cfg) { int is_rpz = 0; + struct tsig_key_table* tsig_key_table; struct auth_zones* az = auth_zones_create(); - if(!az || !auth_zones_apply_cfg(az, cfg, 0, &is_rpz, NULL, NULL)) { + + /* construct tsig key table for tsig key name checks, and it + * also checks the TSIG key name and algorithm and base64 syntax. */ + tsig_key_table = tsig_key_table_create(); + if(!tsig_key_table || !tsig_key_table_apply_cfg(tsig_key_table, cfg)) + fatal_exit("Could not set up TSIG keys"); + + if(!az || !auth_zones_apply_cfg(az, cfg, 0, &is_rpz, NULL, NULL, + tsig_key_table)) { fatal_exit("Could not setup authority zones"); } if(is_rpz && !strstr(cfg->module_conf, "respip")) fatal_exit("RPZ requires the respip module"); auth_zones_delete(az); + tsig_key_table_delete(tsig_key_table); } /** check config file */ diff --git a/util/tsig.c b/util/tsig.c index 23075c536..187c6a3ca 100644 --- a/util/tsig.c +++ b/util/tsig.c @@ -252,6 +252,18 @@ tsig_key_table_search(struct tsig_key_table* key_table, uint8_t* name, return (struct tsig_key*)node->key; } +struct tsig_key* +tsig_key_table_search_fromstr(struct tsig_key_table* key_table, char* name) +{ + uint8_t buf[LDNS_MAX_DOMAINLEN+1]; + size_t len = sizeof(buf); + if(sldns_str2wire_dname_buf(name, buf, &len) != 0) { + log_err("could not parse '%s'", name); + return NULL; + } + return tsig_key_table_search(key_table, buf, len); +} + void tsig_key_delete(struct tsig_key* key) { if(!key) diff --git a/util/tsig.h b/util/tsig.h index 06a63f5bb..448637a2d 100644 --- a/util/tsig.h +++ b/util/tsig.h @@ -217,6 +217,16 @@ int tsig_key_table_apply_cfg(struct tsig_key_table* key_table, struct tsig_key* tsig_key_table_search(struct tsig_key_table* key_table, uint8_t* name, size_t namelen); +/** + * Find key in key table. Caller must hold lock on the table. + * @param key_table: the tsig key table. + * @param name: the name in string format, it is parsed to wireformat. + * @return the found key or NULL if not found or NULL on parse error of the + * key name as a domain name. The item is locked by the key_table lock. + */ +struct tsig_key* tsig_key_table_search_fromstr( + struct tsig_key_table* key_table, char* name); + /** * Delete TSIG key. * @param key: to delete