From: W.C.A. Wijngaards Date: Wed, 13 Mar 2024 16:14:14 +0000 (+0100) Subject: - Fix rpz for cname override action after nsdname and nsip triggers. X-Git-Tag: release-1.20.0rc1~66 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4b54d8e15ece6c0a7ec4bc9b423e7d534b6756d3;p=thirdparty%2Funbound.git - Fix rpz for cname override action after nsdname and nsip triggers. --- diff --git a/doc/Changelog b/doc/Changelog index 6651612d8..a2229a42e 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -6,6 +6,7 @@ clientip localdata action is logged. Fix rpz override action cname for the clientip trigger. - Fix to unify codepath for local alias for rpz cname action override. + - Fix rpz for cname override action after nsdname and nsip triggers. 12 March 2024: Yorgos - Merge #1028: Clearer documentation for tcp-idle-timeout and diff --git a/iterator/iterator.c b/iterator/iterator.c index 3c5d31781..e35d8e34a 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -2746,8 +2746,48 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, delegpt_add_unused_targets(iq->dp); if(qstate->env->auth_zones) { + uint8_t* sname = NULL; + size_t snamelen = 0; /* apply rpz triggers at query time */ + struct dns_msg* forged_response_after_cname; struct dns_msg* forged_response = rpz_callback_from_iterator_module(qstate, iq); + while(forged_response && reply_find_rrset_section_an( + forged_response->rep, iq->qchase.qname, + iq->qchase.qname_len, LDNS_RR_TYPE_CNAME, + iq->qchase.qclass)) { + /* another cname to follow */ + if(!handle_cname_response(qstate, iq, forged_response, + &sname, &snamelen)) { + errinf(qstate, "malloc failure, CNAME info"); + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } + iq->qchase.qname = sname; + iq->qchase.qname_len = snamelen; + forged_response_after_cname = + rpz_callback_from_iterator_cname(qstate, iq); + if(forged_response_after_cname) { + forged_response = forged_response_after_cname; + } else { + /* Follow the CNAME with a query restart */ + iq->deleg_msg = NULL; + iq->dp = NULL; + iq->dsns_point = NULL; + iq->auth_zone_response = 0; + iq->refetch_glue = 0; + iq->query_restart_count++; + iq->sent_count = 0; + iq->dp_target_count = 0; + if(qstate->env->cfg->qname_minimisation) + iq->minimisation_state = INIT_MINIMISE_STATE; + outbound_list_clear(&iq->outlist); + iq->num_current_queries = 0; + fptr_ok(fptr_whitelist_modenv_detach_subs( + qstate->env->detach_subs)); + (*qstate->env->detach_subs)(qstate); + iq->num_target_queries = 0; + return next_state(iq, INIT_REQUEST_STATE); + } + } if(forged_response != NULL) { qstate->ext_state[id] = module_finished; qstate->return_rcode = LDNS_RCODE_NOERROR; diff --git a/services/rpz.c b/services/rpz.c index fb9814335..a753f307b 100644 --- a/services/rpz.c +++ b/services/rpz.c @@ -2139,6 +2139,58 @@ rpz_synthesize_qname_localdata_msg(struct rpz* r, struct module_qstate* ms, return rpz_synthesize_localdata_from_rrset(r, ms, qinfo, rrset, az); } +/** Synthesize a CNAME message for RPZ action override */ +static struct dns_msg* +rpz_synthesize_cname_override_msg(struct rpz* r, struct module_qstate* ms, + struct query_info* qinfo) +{ + struct dns_msg* msg = NULL; + struct reply_info* new_reply_info; + struct ub_packed_rrset_key* rp; + + msg = rpz_dns_msg_new(ms->region); + if(msg == NULL) { return NULL; } + + new_reply_info = construct_reply_info_base(ms->region, + LDNS_RCODE_NOERROR | BIT_QR | BIT_AA | BIT_RA, + 1, /* qd */ + 0, /* ttl */ + 0, /* prettl */ + 0, /* expttl */ + 1, /* an */ + 0, /* ns */ + 0, /* ar */ + 1, /* total */ + sec_status_insecure, + LDNS_EDE_NONE); + if(new_reply_info == NULL) { + log_err("out of memory"); + return NULL; + } + new_reply_info->authoritative = 1; + + rp = respip_copy_rrset(r->cname_override, ms->region); + if(rp == NULL) { + log_err("out of memory"); + return NULL; + } + rp->rk.dname = qinfo->qname; + rp->rk.dname_len = qinfo->qname_len; + /* this rrset is from the rpz data, or synthesized. + * It is not actually from the network, so we flag it with this + * flags as a fake RRset. If later the cache is used to look up + * rrsets, then the fake ones are not returned (if you look without + * the flag). For like CNAME lookups from the iterator or A, AAAA + * lookups for nameserver targets, it would use the without flag + * actual data. So that the actual network data and fake data + * are kept track of separately. */ + rp->rk.flags |= PACKED_RRSET_RPZ; + new_reply_info->rrsets[0] = rp; + + msg->rep = new_reply_info; + return msg; +} + static int rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r, struct local_zone* z, enum localzone_type lzt, struct query_info* qinfo, @@ -2244,6 +2296,9 @@ rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r, ret = NULL; ms->rpz_passthru = 1; break; + case RPZ_CNAME_OVERRIDE_ACTION: + ret = rpz_synthesize_cname_override_msg(r, ms, &ms->qinfo); + break; default: verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'", rpz_action_to_string(action)); @@ -2299,8 +2354,11 @@ rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r, ret = NULL; ms->rpz_passthru = 1; break; + case RPZ_CNAME_OVERRIDE_ACTION: + ret = rpz_synthesize_cname_override_msg(r, ms, &ms->qinfo); + break; default: - verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'", + verbose(VERB_ALGO, "rpz: nsdname: bug: unhandled or invalid action: '%s'", rpz_action_to_string(action)); ret = NULL; } diff --git a/testdata/rpz_nsdname_override.rpl b/testdata/rpz_nsdname_override.rpl new file mode 100644 index 000000000..d662e55c7 --- /dev/null +++ b/testdata/rpz_nsdname_override.rpl @@ -0,0 +1,325 @@ +; config options +server: + module-config: "respip validator iterator" + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: no + access-control: 192.0.0.0/8 allow + +rpz: + name: "rpz.example.com." + rpz-log: yes + rpz-log-name: "rpz.example.com" + rpz-action-override: "nxdomain" + zonefile: +TEMPFILE_NAME rpz.example.com +TEMPFILE_CONTENTS rpz.example.com +$ORIGIN example.com. +rpz 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. ( + 1379078166 28800 7200 604800 7200 ) + 3600 IN NS ns1.rpz.example.com. + 3600 IN NS ns2.rpz.example.com. +$ORIGIN rpz.example.com. +ns1.gotham.a.rpz-nsdname A 1.2.3.5 +TEMPFILE_END + +rpz: + name: "rpz2.example.com." + rpz-log: yes + rpz-log-name: "rpz2.example.com" + rpz-action-override: "nodata" + zonefile: +TEMPFILE_NAME rpz2.example.com +TEMPFILE_CONTENTS rpz2.example.com +$ORIGIN example.com. +rpz2 3600 IN SOA ns1.rpz2.example.com. hostmaster.rpz2.example.com. ( + 1379078166 28800 7200 604800 7200 ) + 3600 IN NS ns1.rpz2.example.com. + 3600 IN NS ns2.rpz2.example.com. +$ORIGIN rpz2.example.com. +ns1.gotham2.a.rpz-nsdname A 1.2.3.5 +TEMPFILE_END + +rpz: + name: "rpz3.example.com." + rpz-log: yes + rpz-log-name: "rpz3.example.com" + rpz-action-override: "passthru" + zonefile: +TEMPFILE_NAME rpz3.example.com +TEMPFILE_CONTENTS rpz3.example.com +$ORIGIN example.com. +rpz3 3600 IN SOA ns1.rpz3.example.com. hostmaster.rpz3.example.com. ( + 1379078166 28800 7200 604800 7200 ) + 3600 IN NS ns1.rpz3.example.com. + 3600 IN NS ns2.rpz3.example.com. +$ORIGIN rpz3.example.com. +ns1.gotham3.a.rpz-nsdname A 1.2.3.5 +TEMPFILE_END + +rpz: + name: "rpz4.example.com." + rpz-log: yes + rpz-log-name: "rpz4.example.com" + rpz-action-override: "drop" + zonefile: +TEMPFILE_NAME rpz4.example.com +TEMPFILE_CONTENTS rpz4.example.com +$ORIGIN example.com. +rpz4 3600 IN SOA ns1.rpz4.example.com. hostmaster.rpz4.example.com. ( + 1379078166 28800 7200 604800 7200 ) + 3600 IN NS ns1.rpz4.example.com. + 3600 IN NS ns2.rpz4.example.com. +$ORIGIN rpz4.example.com. +ns1.gotham3.a.rpz-nsdname A 1.2.3.5 +ns1.gotham4.a.rpz-nsdname A 1.2.3.5 +TEMPFILE_END + +rpz: + name: "rpz5.example.com." + rpz-log: yes + rpz-log-name: "rpz5.example.com" + rpz-action-override: "cname" + rpz-cname-override: "target.a" + zonefile: +TEMPFILE_NAME rpz5.example.com +TEMPFILE_CONTENTS rpz5.example.com +$ORIGIN example.com. +rpz5 3600 IN SOA ns1.rpz5.example.com. hostmaster.rpz5.example.com. ( + 1379078166 28800 7200 604800 7200 ) + 3600 IN NS ns1.rpz5.example.com. + 3600 IN NS ns2.rpz5.example.com. +$ORIGIN rpz5.example.com. +ns1.gotham5.a.rpz-nsdname A 1.2.3.5 +TEMPFILE_END + +rpz: + name: "rpz6.example.com." + rpz-log: yes + rpz-log-name: "rpz6.example.com" + rpz-action-override: "disabled" + zonefile: +TEMPFILE_NAME rpz6.example.com +TEMPFILE_CONTENTS rpz6.example.com +$ORIGIN example.com. +rpz6 3600 IN SOA ns1.rpz6.example.com. hostmaster.rpz6.example.com. ( + 1379078166 28800 7200 604800 7200 ) + 3600 IN NS ns1.rpz6.example.com. + 3600 IN NS ns2.rpz6.example.com. +$ORIGIN rpz6.example.com. +ns1.gotham6.a.rpz-nsdname A 1.2.3.5 +TEMPFILE_END + +stub-zone: + name: "a." + stub-addr: 10.20.30.40 +CONFIG_END + +SCENARIO_BEGIN Test RPZ action override with trigger from nsdname. + +; a. +RANGE_BEGIN 0 1000 + ADDRESS 10.20.30.40 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.gotham.a. IN A +SECTION AUTHORITY +gotham.a. NS ns1.gotham.a. +SECTION ADDITIONAL +ns1.gotham.a. A 10.20.30.41 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.gotham2.a. IN A +SECTION AUTHORITY +gotham2.a. NS ns1.gotham2.a. +SECTION ADDITIONAL +ns1.gotham2.a. A 10.20.30.42 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.gotham3.a. IN A +SECTION AUTHORITY +gotham3.a. NS ns1.gotham3.a. +SECTION ADDITIONAL +ns1.gotham3.a. A 10.20.30.43 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.gotham4.a. IN A +SECTION AUTHORITY +gotham4.a. NS ns1.gotham4.a. +SECTION ADDITIONAL +ns1.gotham4.a. A 10.20.30.44 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.gotham5.a. IN A +SECTION AUTHORITY +gotham5.a. NS ns1.gotham5.a. +SECTION ADDITIONAL +ns1.gotham5.a. A 10.20.30.45 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.gotham6.a. IN A +SECTION AUTHORITY +gotham6.a. NS ns1.gotham6.a. +SECTION ADDITIONAL +ns1.gotham6.a. A 10.20.30.46 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +target.a. IN A +SECTION ANSWER +target.a. IN A 1.2.3.6 +ENTRY_END +RANGE_END + +; gotham3.a. +RANGE_BEGIN 0 1000 + ADDRESS 10.20.30.43 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.gotham3.a. IN A +SECTION ANSWER +www.gotham3.a. A 1.2.3.4 +ENTRY_END +RANGE_END + +; gotham6.a. +RANGE_BEGIN 0 1000 + ADDRESS 10.20.30.46 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.gotham6.a. IN A +SECTION ANSWER +www.gotham6.a. A 1.2.3.4 +ENTRY_END +RANGE_END + +STEP 10 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham.a. IN A +ENTRY_END + +STEP 11 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NXDOMAIN +SECTION QUESTION +www.gotham.a. IN A +SECTION ANSWER +ENTRY_END + +STEP 20 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham2.a. IN A +ENTRY_END + +STEP 21 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +www.gotham2.a. IN A +SECTION ANSWER +ENTRY_END + +STEP 30 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham3.a. IN A +ENTRY_END + +STEP 31 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +www.gotham3.a. IN A +SECTION ANSWER +www.gotham3.a. A 1.2.3.4 +ENTRY_END + +STEP 40 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham4.a. IN A +ENTRY_END +;dropped + +STEP 50 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham5.a. IN A +ENTRY_END + +STEP 51 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +www.gotham5.a. IN A +SECTION ANSWER +www.gotham5.a. CNAME target.a +target.a A 1.2.3.6 +ENTRY_END + +STEP 60 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham6.a. IN A +ENTRY_END + +STEP 61 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +www.gotham6.a. IN A +SECTION ANSWER +www.gotham6.a. A 1.2.3.4 +ENTRY_END + +SCENARIO_END