From 0f78bea4a3b6a65a628342b69a5a36ad62ee3d6e Mon Sep 17 00:00:00 2001 From: "W.C.A. Wijngaards" Date: Tue, 17 Oct 2023 16:47:04 +0200 Subject: [PATCH] - Fix #954: Inconsistent RPZ handling for A record returned along with CNAME. --- doc/Changelog | 4 ++ iterator/iterator.c | 33 +++++++++ services/rpz.c | 4 ++ testdata/rpz_cached_cname.rpl | 122 ++++++++++++++++++++++++++++++++++ 4 files changed, 163 insertions(+) create mode 100644 testdata/rpz_cached_cname.rpl diff --git a/doc/Changelog b/doc/Changelog index ff12a6b46..bdd8ea2f1 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,7 @@ +17 October 2023: Wouter + - Fix #954: Inconsistent RPZ handling for A record returned along with + CNAME. + 16 October 2023: George - Expose the script filename in the Python module environment 'mod_env' instead of the config_file structure which includes the linked list diff --git a/iterator/iterator.c b/iterator/iterator.c index 053c0faec..6ff811a27 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -1449,6 +1449,39 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, } iq->qchase.qname = sname; iq->qchase.qname_len = slen; + if(qstate->env->auth_zones) { + /* apply rpz qname triggers after cname */ + struct dns_msg* forged_response = + rpz_callback_from_iterator_cname(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, &slen)) { + errinf(qstate, "malloc failure, CNAME info"); + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } + iq->qchase.qname = sname; + iq->qchase.qname_len = slen; + forged_response = + rpz_callback_from_iterator_cname(qstate, iq); + } + if(forged_response != NULL) { + qstate->ext_state[id] = module_finished; + qstate->return_rcode = LDNS_RCODE_NOERROR; + qstate->return_msg = forged_response; + iq->response = forged_response; + next_state(iq, FINISHED_STATE); + if(!iter_prepend(iq, qstate->return_msg, qstate->region)) { + log_err("rpz: after cached cname, prepend rrsets: out of memory"); + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } + qstate->return_msg->qinfo = qstate->qinfo; + return 0; + } + } /* This *is* a query restart, even if it is a cheap * one. */ iq->dp = NULL; diff --git a/services/rpz.c b/services/rpz.c index 7f7a2fa9b..18d76c07b 100644 --- a/services/rpz.c +++ b/services/rpz.c @@ -2448,6 +2448,10 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms, rpz_action_to_string(localzone_type_to_rpz_action(lzt))); ret = NULL; } + if(r->log) + log_rpz_apply("qname", (z?z->name:NULL), NULL, + localzone_type_to_rpz_action(lzt), + &is->qchase, NULL, ms, r->log_name); lock_rw_unlock(&z->lock); lock_rw_unlock(&a->lock); return ret; diff --git a/testdata/rpz_cached_cname.rpl b/testdata/rpz_cached_cname.rpl new file mode 100644 index 000000000..198b94631 --- /dev/null +++ b/testdata/rpz_cached_cname.rpl @@ -0,0 +1,122 @@ +; config options +server: + module-config: "respip validator iterator" + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: no + rrset-roundrobin: no + access-control: 192.0.0.0/8 allow + +rpz: + name: "rpz.example.com" + rpz-log: yes + rpz-log-name: "rpz.example.com" + zonefile: +TEMPFILE_NAME rpz.example.com +TEMPFILE_CONTENTS rpz.example.com +rpz.example.com. 3600 IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 1 3600 900 86400 3600 +rpz.example.com. 3600 IN NS ns.rpz.example.net. +a.foo.rpz.example.com. 120 IN A 10.99.99.99 +TEMPFILE_END + +stub-zone: + name: "." + stub-addr: 10.20.30.40 + +CONFIG_END + +SCENARIO_BEGIN Test RPZ with cached CNAME to A record + +RANGE_BEGIN 0 100 + ADDRESS 10.20.30.40 + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR NOERROR AA +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS ns. +SECTION ADDITIONAL +ns. IN NS 10.20.30.40 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR NOERROR AA +SECTION QUESTION +b.foo. IN A +SECTION ANSWER +b.foo. 30 CNAME a.foo. +a.foo. 30 A 1.2.3.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR NOERROR AA +SECTION QUESTION +a.foo. IN A +SECTION ANSWER +a.foo. A 1.2.3.4 +ENTRY_END + +RANGE_END + +STEP 10 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +a.foo. IN A +ENTRY_END + +STEP 20 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +a.foo. IN A +SECTION ANSWER +a.foo. 120 A 10.99.99.99 +ENTRY_END + +STEP 30 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +b.foo. IN A +ENTRY_END + +STEP 40 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +b.foo. IN A +SECTION ANSWER +b.foo. 30 CNAME a.foo. +a.foo. 120 A 10.99.99.99 +ENTRY_END + +STEP 50 TIME_PASSES ELAPSE 3 + +STEP 60 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +b.foo. IN A +ENTRY_END + +STEP 70 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +b.foo. IN A +SECTION ANSWER +b.foo. 30 CNAME a.foo. +a.foo. 120 A 10.99.99.99 +ENTRY_END + +SCENARIO_END -- 2.47.3