From: TCY16 Date: Fri, 19 Nov 2021 10:27:13 +0000 (+0100) Subject: change do_ede to be local-zone specific and add places for more EDE codes X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0572870592e8fbaa9a9fc6ba000cf86440f14ff9;p=thirdparty%2Funbound.git change do_ede to be local-zone specific and add places for more EDE codes --- diff --git a/services/localzone.c b/services/localzone.c index d74191f9a..cf6411cc8 100644 --- a/services/localzone.c +++ b/services/localzone.c @@ -156,6 +156,7 @@ local_zone_create(uint8_t* nm, size_t len, int labs, z->name = nm; z->namelen = len; z->namelabs = labs; + z->do_ede = 0; lock_rw_init(&z->lock); z->region = regional_create_nochunk(sizeof(struct regional)); if(!z->region) { @@ -657,6 +658,53 @@ lz_enter_zone_tag(struct local_zones* zones, char* zname, uint8_t* list, return r; } +/** enter do-ede option into zone */ +static int +lz_enter_ede_respond(struct local_zones* zones, char* zname, char* option) +{ + uint8_t dname[LDNS_MAX_DOMAINLEN+1]; + size_t dname_len = sizeof(dname); + uint8_t ede_option = 0; + int dname_label_count; + struct local_zone* z; + + /* parse zone name */ + if(sldns_str2wire_dname_buf(zname, dname, &dname_len) != 0) { + log_err("cannot parse zone name in local-zone-do-ede: %s", + zname); + return 0; + } + dname_label_count = dname_count_labels(dname); + + /* parse option */ + if(strcmp(option, "yes") == 0) + ede_option = 1; + else if(strcmp(option, "no") == 0) + return 1; /* no need to change the default value */ + + /* find localzone entry */ + lock_rw_rdlock(&zones->lock); + z = local_zones_find(zones, dname, + dname_len, dname_label_count, LDNS_RR_CLASS_IN); + if(!z) { + lock_rw_unlock(&zones->lock); + log_err("no local-zone for local-zone-do-ede %s", zname); + return 0; + } + lock_rw_wrlock(&z->lock); + lock_rw_unlock(&zones->lock); + + if (z->do_ede) { + lock_rw_unlock(&z->lock); + log_err("duplicate local-zone-do-ede %s", zname); + return 1; + } + + z->do_ede = 1; /* respond with EDEs in this local-zone */ + lock_rw_unlock(&z->lock); + return 1; +} + /** enter override into zone */ static int lz_enter_override(struct local_zones* zones, char* zname, char* netblock, @@ -943,6 +991,18 @@ lz_enter_overrides(struct local_zones* zones, struct config_file* cfg) return 1; } +/** parse local-zone-do-ede: statements */ +static int +lz_enter_ede_respond_zones(struct local_zones* zones, struct config_file* cfg) +{ + struct config_str2list* p; + for(p = cfg->local_zone_do_ede; p; p = p->next) { + if(!lz_enter_ede_respond(zones, p->str, p->str2)) + return 0; + } + return 1; +} + /** setup parent pointers, so that a lookup can be done for closest match */ static void init_parents(struct local_zones* zones) @@ -1124,6 +1184,11 @@ local_zones_apply_cfg(struct local_zones* zones, struct config_file* cfg) if(!lz_enter_overrides(zones, cfg)) { return 0; } + /* enter EDE (RFC8914) response option for local zones */ + if(!lz_enter_ede_respond_zones(zones, cfg)) { + return 0; + } + /* create implicit transparent zone from data. */ if(!lz_setup_implicit(zones, cfg)) { return 0; @@ -1288,10 +1353,11 @@ local_encode(struct query_info* qinfo, struct module_env* env, /** encode answer consisting of 1 rrset (with EDE code) */ static int -local_encode_ede(struct query_info* qinfo, struct module_env* env, - struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf, - struct regional* temp, struct ub_packed_rrset_key* rrset, int ansec, - int rcode, sldns_ede_code ede_code, const char* ede_txt) +local_encode_ede(struct local_zone* zone, struct query_info* qinfo, + struct module_env* env, struct edns_data* edns, + struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp, + struct ub_packed_rrset_key* rrset, int ansec, int rcode, + sldns_ede_code ede_code, const char* ede_txt) { struct reply_info rep; uint16_t udpsize; @@ -1315,7 +1381,9 @@ local_encode_ede(struct query_info* qinfo, struct module_env* env, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), edns); } else { - edns_opt_list_append_ede(&edns->opt_list_out, temp, ede_code, ede_txt); + if(ede_code >= 0 && zone->do_ede) + edns_opt_list_append_ede(&edns->opt_list_out, + temp, ede_code, ede_txt); if(!reply_info_answer_encode(qinfo, &rep, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), @@ -1330,10 +1398,10 @@ local_encode_ede(struct query_info* qinfo, struct module_env* env, /** encode local error answer */ static void -local_error_encode(struct query_info* qinfo, struct module_env* env, - struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf, - struct regional* temp, int rcode, int r, sldns_ede_code ede_code, - const char* ede_txt) +local_error_encode(struct local_zone* zone, struct query_info* qinfo, + struct module_env* env, struct edns_data* edns, + struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp, + int rcode, int r, sldns_ede_code ede_code, const char* ede_txt) { edns->edns_version = EDNS_ADVERTISED_VERSION; edns->udp_size = EDNS_ADVERTISED_SIZE; @@ -1343,7 +1411,7 @@ local_error_encode(struct query_info* qinfo, struct module_env* env, if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL, rcode, edns, repinfo, temp, env->now_tv)) edns->opt_list_inplace_cb_out = NULL; - if(ede_code >= 0 && env->cfg->local_data_do_ede) + if(ede_code >= 0 && zone->do_ede) edns_opt_list_append_ede(&edns->opt_list_out, temp, ede_code, ede_txt); error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), edns); @@ -1540,7 +1608,7 @@ local_data_answer(struct local_zone* z, struct module_env* env, if(newtargetlen > LDNS_MAX_DOMAINLEN) { qinfo->local_alias = NULL; - local_error_encode(qinfo, env, edns,repinfo, + local_error_encode(z, qinfo, env, edns,repinfo, buf, temp, LDNS_RCODE_YXDOMAIN, (LDNS_RCODE_YXDOMAIN|BIT_AA), LDNS_EDE_OTHER, @@ -1647,7 +1715,7 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env, return 1; } else if(lz_type == local_zone_refuse || lz_type == local_zone_always_refuse) { - local_error_encode(qinfo, env, edns, repinfo, buf, temp, + local_error_encode(z, qinfo, env, edns, repinfo, buf, temp, LDNS_RCODE_REFUSED, (LDNS_RCODE_REFUSED|BIT_AA), LDNS_EDE_BLOCKED, ""); return 1; @@ -1674,7 +1742,7 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env, if(z != NULL && z->soa && z->soa_negative) return local_encode(qinfo, env, edns, repinfo, buf, temp, z->soa_negative, 0, rcode); - local_error_encode(qinfo, env, edns, repinfo, buf, temp, + local_error_encode(z, qinfo, env, edns, repinfo, buf, temp, rcode, (rcode|BIT_AA), LDNS_EDE_BLOCKED, ""); return 1; } else if(lz_type == local_zone_typetransparent @@ -1713,11 +1781,11 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env, d.rr_len = &rr_len; d.rr_data = &rr_datas; d.rr_ttl = &rr_ttl; - return local_encode_ede(qinfo, env, edns, repinfo, buf, temp, + return local_encode_ede(z, qinfo, env, edns, repinfo, buf, temp, &lrr, 1, LDNS_RCODE_NOERROR, LDNS_EDE_FORGED_ANSWER, ""); } else { /* NODATA: No EDE needed */ - local_error_encode(qinfo, env, edns, repinfo, buf, + local_error_encode(z, qinfo, env, edns, repinfo, buf, temp, LDNS_RCODE_NOERROR, (LDNS_RCODE_NOERROR|BIT_AA), -1, NULL); } @@ -1733,7 +1801,7 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env, return local_encode(qinfo, env, edns, repinfo, buf, temp, z->soa_negative, 0, rcode); /* NODATA: No EDE needed */ - local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode, + local_error_encode(z, qinfo, env, edns, repinfo, buf, temp, rcode, (rcode|BIT_AA), -1, NULL); return 1; } diff --git a/services/localzone.h b/services/localzone.h index 9a06a7f84..3a45ca166 100644 --- a/services/localzone.h +++ b/services/localzone.h @@ -164,6 +164,8 @@ struct local_zone { * artificial negative SOA rrset (TTL is the minimum of the TTL and the * SOA.MINIMUM). */ struct ub_packed_rrset_key* soa_negative; + /** should local_data result in EDE (RFC8914) code inclusion? */ + int do_ede; }; /** diff --git a/util/config_file.c b/util/config_file.c index 0d992528b..8b7ed5618 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -373,7 +373,7 @@ config_create(void) cfg->ipset_name_v4 = NULL; cfg->ipset_name_v6 = NULL; #endif - cfg->local_data_do_ede = 0; + cfg->local_zone_do_ede = NULL; return cfg; error_exit: config_delete(cfg); @@ -791,7 +791,7 @@ int config_set_option(struct config_file* cfg, const char* opt, } oi[cfg->num_out_ifs++] = d; cfg->out_ifs = oi; - } else S_YNO("local-data-do-ede:", local_data_do_ede) + } // else S_YNO("local-zone-do-ede:", local_zone_do_ede) else { /* unknown or unsupported (from the set_option interface): * interface, outgoing-interface, access-control, @@ -1241,6 +1241,7 @@ config_get_option(struct config_file* cfg, const char* opt, #ifdef USE_IPSET else O_STR(opt, "name-v4", ipset_name_v4) else O_STR(opt, "name-v6", ipset_name_v6) + else O_LS3(opt, "local-zone-do-ede", local_zone_do_ede) #endif /* not here: * outgoing-permit, outgoing-avoid - have list of ports diff --git a/util/config_file.h b/util/config_file.h index e9e43e43f..18b47007d 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -670,8 +670,8 @@ struct config_file { char* ipset_name_v6; #endif - /** should local_data result in EDE (RFC8914) code inclusion? */ - int local_data_do_ede; + /** should a local_zone results inlude an EDE (RFC8914) code? */ + struct config_str2list* local_zone_do_ede; }; /** from cfg username, after daemonize setup performed */ diff --git a/util/configlexer.lex b/util/configlexer.lex index 27809911a..c934c42d0 100644 --- a/util/configlexer.lex +++ b/util/configlexer.lex @@ -549,7 +549,7 @@ tcp-connection-limit{COLON} { YDVAR(2, VAR_TCP_CONNECTION_LIMIT) } edns-client-string{COLON} { YDVAR(2, VAR_EDNS_CLIENT_STRING) } edns-client-string-opcode{COLON} { YDVAR(1, VAR_EDNS_CLIENT_STRING_OPCODE) } nsid{COLON} { YDVAR(1, VAR_NSID ) } -local-data-do-ede{COLON} { YDVAR(1, VAR_LOCAL_DATA_DO_EDE) } +local-zone-do-ede{COLON} { YDVAR(2, VAR_LOCAL_DATA_DO_EDE) } {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 d0d103af7..4d9ec393c 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -310,7 +310,7 @@ content_server: server_num_threads | server_verbosity | server_port | server_edns_client_string_opcode | server_nsid | server_zonemd_permissive_mode | server_max_reuse_tcp_queries | server_tcp_reuse_timeout | server_tcp_auth_query_timeout | - server_local_data_do_ede + server_local_zone_do_ede ; stubstart: VAR_STUB_ZONE @@ -2208,14 +2208,15 @@ server_local_data_ptr: VAR_LOCAL_DATA_PTR STRING_ARG } } ; -server_local_data_do_ede: VAR_LOCAL_DATA_DO_EDE STRING_ARG +server_local_zone_do_ede: VAR_LOCAL_DATA_DO_EDE STRING_ARG STRING_ARG { - OUTYY(("P(server_local_data_do_ede:%s)\n", $2)); - if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + OUTYY(("P(server_local_zone_do_ede:%s %s)\n", $2, $3)); + if(strcmp($3, "yes") != 0 && strcmp($3, "no") != 0) yyerror("expected yes or no."); - else cfg_parser->cfg->local_data_do_ede = - (strcmp($2, "yes")==0); - free($2); + if(!cfg_str2list_insert(&cfg_parser->cfg->local_zone_do_ede, + $2, $3)) { + yyerror("out of memory adding local-zone-do-ede"); + } } ; server_minimal_responses: VAR_MINIMAL_RESPONSES STRING_ARG @@ -3016,14 +3017,6 @@ view_local_data_ptr: VAR_LOCAL_DATA_PTR STRING_ARG } } ; -// view_local_data_do_ede: VAR_LOCAL_DATA_DO_EDE STRING_ARG -// { -// OUTYY(("P(view_local_data_do_ede:%s)\n", $2)); -// if(!cfg_strlist_insert(&cfg_parser->cfg->views->local_data_do_ede, $2)) { -// fatal_exit("out of memory adding local-data"); -// } -// } -// ; view_first: VAR_VIEW_FIRST STRING_ARG { OUTYY(("P(view-first:%s)\n", $2)); diff --git a/validator/validator.c b/validator/validator.c index c5e351e83..5f5804264 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -1637,6 +1637,9 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq, return 1; } else if(key_entry_isbad(vq->key_entry)) { /* key is bad, chain is bad, reply is bogus */ + + // @TODO ADD Error Code 6 - DNSSEC Bogus + text chain of trust? + errinf_dname(qstate, "key for validation", vq->key_entry->name); errinf(qstate, "is marked as invalid"); if(key_entry_get_reason(vq->key_entry)) { @@ -1854,6 +1857,9 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, LDNS_RR_TYPE_DNSKEY, vq->key_entry->key_class); vq->chase_reply->security = sec_status_bogus; errinf(qstate, "while building chain of trust"); + + // @TODO ADD Error Code 6 - DNSSEC Bogus + text chain of trust? + if(vq->restart_count >= ve->max_restart) key_cache_insert(ve->kcache, vq->key_entry, qstate); return 1;