From: W.C.A. Wijngaards Date: Fri, 13 Jun 2025 10:12:49 +0000 (+0200) Subject: - xfr-tsig, tsig-key, with name, algorithm and secret options. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8811bd48443992d0392f1688b0017a14b978ef79;p=thirdparty%2Funbound.git - xfr-tsig, tsig-key, with name, algorithm and secret options. --- diff --git a/Makefile.in b/Makefile.in index f2efa5d2c..095717e16 100644 --- a/Makefile.in +++ b/Makefile.in @@ -937,8 +937,8 @@ config_file.lo config_file.o: $(srcdir)/util/config_file.c config.h $(srcdir)/ut configlexer.lo configlexer.o: util/configlexer.c config.h $(srcdir)/util/configyyrename.h \ $(srcdir)/util/config_file.h util/configparser.h configparser.lo configparser.o: util/configparser.c config.h $(srcdir)/util/configyyrename.h \ - $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h $(srcdir)/util/log.h $(srcdir)/sldns/str2wire.h \ - $(srcdir)/sldns/rrdef.h + $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h $(srcdir)/util/log.h $(srcdir)/util/tsig.h $(srcdir)/sldns/str2wire.h \ + $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/parseutil.h shm_main.lo shm_main.o: $(srcdir)/util/shm_side/shm_main.c config.h $(srcdir)/util/shm_side/shm_main.h \ $(srcdir)/libunbound/unbound.h $(srcdir)/daemon/daemon.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \ $(srcdir)/util/alloc.h $(srcdir)/services/modstack.h \ @@ -1299,7 +1299,7 @@ daemon.lo daemon.o: $(srcdir)/daemon/daemon.c config.h $(srcdir)/daemon/daemon.h $(srcdir)/util/edns.h $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/rrset.h \ $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/services/localzone.h \ $(srcdir)/services/authzone.h $(srcdir)/services/mesh.h $(srcdir)/services/rpz.h $(srcdir)/respip/respip.h \ - $(srcdir)/util/random.h $(srcdir)/util/tube.h $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h \ + $(srcdir)/util/random.h $(srcdir)/util/tube.h $(srcdir)/util/net_help.h $(srcdir)/util/tsig.h $(srcdir)/sldns/keyraw.h \ $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h remote.lo remote.o: $(srcdir)/daemon/remote.c config.h $(srcdir)/daemon/remote.h $(srcdir)/daemon/worker.h \ $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h $(srcdir)/util/data/packed_rrset.h \ @@ -1509,7 +1509,7 @@ context.lo context.o: $(srcdir)/libunbound/context.c config.h $(srcdir)/libunbou $(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h \ $(srcdir)/util/netevent.h $(srcdir)/dnscrypt/dnscrypt.h \ $(srcdir)/services/authzone.h $(srcdir)/services/mesh.h $(srcdir)/services/rpz.h $(srcdir)/daemon/stats.h \ - $(srcdir)/util/timehist.h $(srcdir)/respip/respip.h $(srcdir)/util/edns.h \ + $(srcdir)/util/timehist.h $(srcdir)/respip/respip.h $(srcdir)/util/edns.h $(srcdir)/util/tsig.h \ $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h libunbound.lo libunbound.o: $(srcdir)/libunbound/libunbound.c $(srcdir)/libunbound/unbound.h \ $(srcdir)/libunbound/unbound-event.h config.h $(srcdir)/libunbound/context.h $(srcdir)/util/locks.h \ @@ -1517,7 +1517,7 @@ libunbound.lo libunbound.o: $(srcdir)/libunbound/libunbound.c $(srcdir)/libunbou $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/libunbound/libworker.h \ $(srcdir)/util/config_file.h $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h \ $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/regional.h \ - $(srcdir)/util/random.h $(srcdir)/util/net_help.h $(srcdir)/util/tube.h $(srcdir)/util/ub_event.h $(srcdir)/util/edns.h \ + $(srcdir)/util/random.h $(srcdir)/util/net_help.h $(srcdir)/util/tube.h $(srcdir)/util/ub_event.h $(srcdir)/util/edns.h $(srcdir)/util/tsig.h \ $(srcdir)/util/storage/dnstree.h $(srcdir)/services/localzone.h $(srcdir)/services/view.h \ $(srcdir)/sldns/sbuffer.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/util/netevent.h \ $(srcdir)/dnscrypt/dnscrypt.h $(srcdir)/services/cache/rrset.h \ diff --git a/daemon/daemon.c b/daemon/daemon.c index f882bb9ad..92d0d031b 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -89,6 +89,7 @@ #include "util/random.h" #include "util/tube.h" #include "util/net_help.h" +#include "util/tsig.h" #include "sldns/keyraw.h" #include "respip/respip.h" #include "iterator/iter_fwd.h" @@ -320,6 +321,17 @@ daemon_init(void) free(daemon); return NULL; } + if(!(daemon->env->tsig_key_table = tsig_key_table_create())) { + auth_zones_delete(daemon->env->auth_zones); + acl_list_delete(daemon->acl_interface); + acl_list_delete(daemon->acl); + tcl_list_delete(daemon->tcl); + edns_known_options_delete(daemon->env); + edns_strings_delete(daemon->env->edns_strings); + free(daemon->env); + free(daemon); + return NULL; + } return daemon; } @@ -771,6 +783,10 @@ daemon_fork(struct daemon* daemon) daemon->use_response_ip = !respip_set_is_empty( daemon->env->respip_set) || have_view_respip_cfg; + /* setup tsig keys */ + if(!tsig_key_table_apply_cfg(daemon->env->tsig_key_table, daemon->cfg)) + fatal_exit("Could not set up TSIG keys"); + /* setup modules */ daemon_setup_modules(daemon); @@ -944,6 +960,7 @@ daemon_delete(struct daemon* daemon) edns_known_options_delete(daemon->env); edns_strings_delete(daemon->env->edns_strings); auth_zones_delete(daemon->env->auth_zones); + tsig_key_table_delete(daemon->env->tsig_key_table); } ub_randfree(daemon->rand); alloc_clear(&daemon->superalloc); diff --git a/libunbound/context.c b/libunbound/context.c index a1a4adf98..38b5dbf00 100644 --- a/libunbound/context.c +++ b/libunbound/context.c @@ -52,6 +52,7 @@ #include "util/data/msgreply.h" #include "util/storage/slabhash.h" #include "util/edns.h" +#include "util/tsig.h" #include "sldns/sbuffer.h" #include "iterator/iter_fwd.h" #include "iterator/iter_hints.h" @@ -81,6 +82,8 @@ context_finalize(struct ub_ctx* ctx) return UB_INITFAIL; listen_setup_locks(); log_edns_known_options(VERB_ALGO, ctx->env); + if(!tsig_key_table_apply_cfg(ctx->env->tsig_key_table, cfg)) + return UB_INITFAIL; ctx->local_zones = local_zones_create(); if(!ctx->local_zones) return UB_NOMEM; diff --git a/libunbound/libunbound.c b/libunbound/libunbound.c index 9c6a3e309..e5b340013 100644 --- a/libunbound/libunbound.c +++ b/libunbound/libunbound.c @@ -59,6 +59,7 @@ #include "util/tube.h" #include "util/ub_event.h" #include "util/edns.h" +#include "util/tsig.h" #include "services/modstack.h" #include "services/localzone.h" #include "services/cache/infra.h" @@ -168,6 +169,18 @@ static struct ub_ctx* ub_ctx_create_nopipe(void) errno = ENOMEM; return NULL; } + ctx->env->tsig_key_table = tsig_key_table_create(); + if(!ctx->env->tsig_key_table) { + auth_zones_delete(ctx->env->auth_zones); + edns_known_options_delete(ctx->env); + edns_strings_delete(ctx->env->edns_strings); + config_delete(ctx->env->cfg); + free(ctx->env); + ub_randfree(ctx->seed_rnd); + free(ctx); + errno = ENOMEM; + return NULL; + } ctx->env->alloc = &ctx->superalloc; ctx->env->worker = NULL; @@ -388,6 +401,7 @@ ub_ctx_delete(struct ub_ctx* ctx) config_delete(ctx->env->cfg); edns_known_options_delete(ctx->env); edns_strings_delete(ctx->env->edns_strings); + tsig_key_table_delete(ctx->env->tsig_key_table); forwards_delete(ctx->env->fwds); hints_delete(ctx->env->hints); auth_zones_delete(ctx->env->auth_zones); diff --git a/util/config_file.c b/util/config_file.c index b1e767b3b..89e8760ce 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -222,6 +222,7 @@ config_create(void) cfg->stubs = NULL; cfg->forwards = NULL; cfg->auths = NULL; + cfg->tsig_keys = NULL; #ifdef CLIENT_SUBNET cfg->client_subnet = NULL; cfg->client_subnet_zone = NULL; @@ -928,7 +929,7 @@ int config_set_option(struct config_file* cfg, const char* opt, * max-client-subnet-ipv4, max-client-subnet-ipv6, * min-client-subnet-ipv4, min-client-subnet-ipv6, * max-ecs-tree-size-ipv4, max-ecs-tree-size-ipv6, ipsecmod_hook, - * ipsecmod_whitelist. */ + * ipsecmod_whitelist, tsig-key. */ return 0; } return 1; @@ -1433,6 +1434,7 @@ config_get_option(struct config_file* cfg, const char* opt, * local-data-ptr - converted to local-data entries * stub-zone, name, stub-addr, stub-host, stub-prime * forward-zone, name, forward-addr, forward-host + * tsig-key */ else return 0; return 1; @@ -1704,6 +1706,27 @@ config_delviews(struct config_view* p) } } +void +config_deltsig_key(struct config_tsig_key* p) +{ + if(!p) return; + free(p->name); + free(p->algorithm); + free(p->secret); + free(p); +} + +void +config_deltsig_keys(struct config_tsig_key* p) +{ + struct config_tsig_key* np; + while(p) { + np = p->next; + config_deltsig_key(p); + p = np; + } +} + void config_del_strarray(char** array, int num) { @@ -1758,6 +1781,7 @@ config_delete(struct config_file* cfg) config_delstubs(cfg->forwards); config_delauths(cfg->auths); config_delviews(cfg->views); + config_deltsig_keys(cfg->tsig_keys); config_delstrlist(cfg->donotqueryaddrs); config_delstrlist(cfg->root_hints); #ifdef CLIENT_SUBNET diff --git a/util/config_file.h b/util/config_file.h index 44ac036b8..9e6314561 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -45,6 +45,7 @@ struct config_stub; struct config_auth; struct config_view; +struct config_tsig_key; struct config_strlist; struct config_str2list; struct config_str3list; @@ -260,6 +261,8 @@ struct config_file { struct config_auth* auths; /** the views definitions, linked list */ struct config_view* views; + /** the tsig-key definitions, linked list */ + struct config_tsig_key* tsig_keys; /** list of donotquery addresses, linked list */ struct config_strlist* donotqueryaddrs; #ifdef CLIENT_SUBNET @@ -904,6 +907,20 @@ struct config_view { struct config_str2list* respip_data; }; +/** + * Tsig-key config options + */ +struct config_tsig_key { + /** next in list */ + struct config_tsig_key* next; + /** name of the tsig key */ + char* name; + /** algorithm */ + char* algorithm; + /** secret date, in base64 */ + char* secret; +}; + /** * List of strings for config options */ @@ -1216,6 +1233,18 @@ void config_delview(struct config_view* p); */ void config_delviews(struct config_view* list); +/** + * Delete a tsig_key item + * @param p: tsig_key item + */ +void config_deltsig_key(struct config_tsig_key* p); + +/** + * Delete items in config tsig_key list. + * @param list: list. + */ +void config_deltsig_keys(struct config_tsig_key* list); + /** check if config for remote control turns on IP-address interface * with certificates or a named pipe without certificates. */ int options_remote_is_address(struct config_file* cfg); diff --git a/util/configlexer.lex b/util/configlexer.lex index bc258673d..d415e7a04 100644 --- a/util/configlexer.lex +++ b/util/configlexer.lex @@ -606,6 +606,9 @@ proxy-protocol-port{COLON} { YDVAR(1, VAR_PROXY_PROTOCOL_PORT) } iter-scrub-ns{COLON} { YDVAR(1, VAR_ITER_SCRUB_NS) } iter-scrub-cname{COLON} { YDVAR(1, VAR_ITER_SCRUB_CNAME) } max-global-quota{COLON} { YDVAR(1, VAR_MAX_GLOBAL_QUOTA) } +tsig-key{COLON} { YDVAR(0, VAR_TSIG_KEY) } +algorithm{COLON} { YDVAR(1, VAR_ALGORITHM) } +secret{COLON} { YDVAR(1, VAR_SECRET) } {NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; } /* Quoted strings. Strip leading and ending quotes */ diff --git a/util/configparser.y b/util/configparser.y index ebb23f41c..9638740c9 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -47,7 +47,9 @@ #include "util/configyyrename.h" #include "util/config_file.h" #include "util/net_help.h" +#include "util/tsig.h" #include "sldns/str2wire.h" +#include "sldns/parseutil.h" int ub_c_lex(void); void ub_c_error(const char *message); @@ -215,6 +217,7 @@ extern struct config_parser_state* cfg_parser; %token VAR_LOG_DESTADDR VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED %token VAR_COOKIE_SECRET_FILE VAR_ITER_SCRUB_NS VAR_ITER_SCRUB_CNAME %token VAR_MAX_GLOBAL_QUOTA VAR_HARDEN_UNVERIFIED_GLUE VAR_LOG_TIME_ISO +%token VAR_TSIG_KEY VAR_ALGORITHM VAR_SECRET %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -223,7 +226,7 @@ toplevelvar: serverstart contents_server | stub_clause | rcstart contents_rc | dtstart contents_dt | view_clause | dnscstart contents_dnsc | cachedbstart contents_cachedb | ipsetstart contents_ipset | authstart contents_auth | - rpzstart contents_rpz | dynlibstart contents_dl | + rpzstart contents_rpz | dynlibstart contents_dl | tsig_key_clause | force_toplevel ; force_toplevel: VAR_FORCE_TOPLEVEL @@ -3732,6 +3735,82 @@ dl_file: VAR_DYNLIB_FILE STRING_ARG yyerror("out of memory"); } ; +tsig_key_clause: tsig_key_start contents_tsig_key + { + /* tsig-key end */ + if(cfg_parser->cfg->tsig_keys) { + if(!cfg_parser->cfg->tsig_keys->name) + yyerror("tsig-key without name"); + else if(!cfg_parser->cfg->tsig_keys->algorithm) + ub_c_error_msg("tsig-key %s has no algorithm", + cfg_parser->cfg->tsig_keys->name); + else if(!cfg_parser->cfg->tsig_keys->secret) + ub_c_error_msg("tsig-key %s has no secret blob", + cfg_parser->cfg->tsig_keys->name); + } + } + ; +tsig_key_start: VAR_TSIG_KEY + { + struct config_tsig_key* s; + OUTYY(("\nP(tsig-key:)\n")); + cfg_parser->started_toplevel = 1; + s = (struct config_tsig_key*)calloc(1, + sizeof(struct config_tsig_key)); + if(s) { + s->next = cfg_parser->cfg->tsig_keys; + cfg_parser->cfg->tsig_keys = s; + } else { + yyerror("out of memory"); + } + } + ; +contents_tsig_key: contents_tsig_key content_tsig_key + | ; +content_tsig_key: tsig_key_name | tsig_key_algorithm | tsig_key_secret + ; +tsig_key_name: VAR_NAME STRING_ARG + { + uint8_t buf[LDNS_MAX_DOMAINLEN+1]; + size_t len = sizeof(buf); + int r; + + OUTYY(("P(name:%s)\n", $2)); + free(cfg_parser->cfg->tsig_keys->name); + cfg_parser->cfg->tsig_keys->name = $2; + + if((r=sldns_str2wire_dname_buf($2, buf, &len))!=0) + ub_c_error_msg("could not parse tsig key name" + " '%s':%d: %s", $2, LDNS_WIREPARSE_OFFSET(r), + sldns_get_errorstr_parse(r)); + } +tsig_key_algorithm: VAR_ALGORITHM STRING_ARG + { + OUTYY(("P(algorithm:%s)\n", $2)); + free(cfg_parser->cfg->tsig_keys->algorithm); + cfg_parser->cfg->tsig_keys->algorithm = $2; + if(!tsig_algo_check_name($2)) + ub_c_error_msg("could not parse tsig key algorithm '%s'", + $2); + } +tsig_key_secret: VAR_SECRET STRING_ARG + { + uint8_t data[16384]; + int size; + + OUTYY(("P(secret:%s)\n", $2)); + free(cfg_parser->cfg->tsig_keys->secret); + cfg_parser->cfg->tsig_keys->secret = $2; + + size = sldns_b64_pton($2, data, sizeof(data)); + if(size == -1) { + ub_c_error_msg("cannot base64 decode tsig secret %s", + cfg_parser->cfg->tsig_keys->name? + cfg_parser->cfg->tsig_keys->name:""); + } else if(size != 0) { + explicit_bzero(data, size); + } + } server_disable_dnssec_lame_check: VAR_DISABLE_DNSSEC_LAME_CHECK STRING_ARG { OUTYY(("P(disable_dnssec_lame_check:%s)\n", $2)); diff --git a/util/module.h b/util/module.h index edce4a523..aa7508ac2 100644 --- a/util/module.h +++ b/util/module.h @@ -181,6 +181,7 @@ struct views; struct respip_set; struct respip_client_info; struct respip_addr_info; +struct tsig_key_table; struct module_stack; /** Maximum number of modules in operation */ @@ -529,6 +530,8 @@ struct module_env { struct views* views; /** response-ip set with associated actions and tags. */ struct respip_set* respip_set; + /** the TSIG keys */ + struct tsig_key_table* tsig_key_table; /** module specific data. indexed by module id. */ void* modinfo[MAX_MODULE]; diff --git a/util/tsig.c b/util/tsig.c index 81309699d..79438adc0 100644 --- a/util/tsig.c +++ b/util/tsig.c @@ -41,10 +41,13 @@ #include "config.h" #include "util/tsig.h" +#include "util/config_file.h" #include "util/log.h" +#include "sldns/parseutil.h" #include "sldns/pkthdr.h" #include "sldns/rrdef.h" #include "sldns/sbuffer.h" +#include "sldns/str2wire.h" #include "util/data/msgparse.h" #include "util/data/dname.h" #include @@ -114,6 +117,95 @@ tsig_key_table_delete(struct tsig_key_table* key_table) free(key_table); } +/** Create a tsig_key */ +static struct tsig_key* +tsig_key_create(const char* name, const char* algorithm, const char* secret) +{ + struct tsig_key* key = (struct tsig_key*)calloc(1, sizeof(*key)); + int ret; + if(!key) { + log_err("out of memory"); + return NULL; + } + key->node.key = key; + key->name_str = strdup(name); + if(!key->name_str) { + log_err("out of memory"); + tsig_key_delete(key); + return NULL; + } + key->algo = tsig_algo_find_name(algorithm); + if(!key->algo) { + log_err("tsig key %s could not parse algorithm '%s'", + name, algorithm); + tsig_key_delete(key); + return NULL; + } + key->name = sldns_str2wire_dname(name, &key->name_len); + if(!key->name) { + log_err("tsig key %s could not parse name into wireformat", + name); + tsig_key_delete(key); + return NULL; + } + + key->data_len = sldns_b64_pton_calculate_size(strlen(secret)); + if(key->data_len == 0) + key->data = NULL; + else key->data = malloc(key->data_len); + if(!key->data) { + log_err("out of memory"); + tsig_key_delete(key); + return NULL; + } + ret = sldns_b64_pton(secret, key->data, key->data_len); + if(ret == -1 || ret > (int)key->data_len) { + log_err("tsig key %s could not base64 decode secret blob", + name); + tsig_key_delete(key); + return NULL; + } + key->data_len = ret; + + return key; +} + +/** Add a key to the TSIG key table. */ +static int +tsig_key_table_add_key(struct tsig_key_table* key_table, + struct config_tsig_key* s) +{ + struct tsig_key* key; + key = tsig_key_create(s->name, s->algorithm, s->secret); + if(!key) + return 0; + /* Wipe the secret from config, it is in the key_table. */ + if(s->secret[0] != 0) + explicit_bzero(s->secret, strlen(s->secret)); + + lock_rw_wrlock(&key_table->lock); + if(!rbtree_insert(key_table->tree, &key->node)) { + log_warn("duplicate tsig-key: %s", key->name_str); + lock_rw_unlock(&key_table->lock); + tsig_key_delete(key); + return 0; + } + lock_rw_unlock(&key_table->lock); + return 1; +} + +int +tsig_key_table_apply_cfg(struct tsig_key_table* key_table, + struct config_file* cfg) +{ + struct config_tsig_key* s; + for(s = cfg->tsig_keys; s; s = s->next) { + if(!tsig_key_table_add_key(key_table, s)) + return 0; + } + return 1; +} + void tsig_key_delete(struct tsig_key* key) { if(!key) @@ -122,7 +214,8 @@ void tsig_key_delete(struct tsig_key* key) free(key->name); if(key->data) { /* The secret data is removed. */ - explicit_bzero(key->data, key->data_len); + if(key->data_len > 0) + explicit_bzero(key->data, key->data_len); free(key->data); } free(key); diff --git a/util/tsig.h b/util/tsig.h index eb4391d75..b6ac605dd 100644 --- a/util/tsig.h +++ b/util/tsig.h @@ -44,6 +44,7 @@ #include "util/locks.h" #include "util/rbtree.h" struct sldns_buffer; +struct config_file; /** * TSIG record, the RR that is in the packet. @@ -146,6 +147,15 @@ struct tsig_key_table* tsig_key_table_create(void); */ void tsig_key_table_delete(struct tsig_key_table* key_table); +/** + * Apply config to the tsig key table. + * @param key_table: the tsig key table. + * @param cfg: the config to read. + * @return false on failure. + */ +int tsig_key_table_apply_cfg(struct tsig_key_table* key_table, + struct config_file* cfg); + /** * Delete TSIG key. * @param key: to delete