From: W.C.A. Wijngaards Date: Tue, 19 Mar 2024 08:32:53 +0000 (+0100) Subject: - Fix rpz so that rpz CNAME can apply after rpz CNAME. And fix that X-Git-Tag: release-1.20.0rc1~57 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fef974ca5c713639f3cc7080cfecb323c5eb9b3e;p=thirdparty%2Funbound.git - Fix rpz so that rpz CNAME can apply after rpz CNAME. And fix that clientip and nsip can give a CNAME. --- diff --git a/doc/Changelog b/doc/Changelog index 421d79a96..48106ac46 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,7 @@ +19 March 2024: Wouter + - Fix rpz so that rpz CNAME can apply after rpz CNAME. And fix that + clientip and nsip can give a CNAME. + 18 March 2024: Wouter - Fix that rpz CNAME content is limited to the max number of cnames. - Fix rpz, it follows iterator CNAMEs for nsip and nsdname and sets diff --git a/iterator/iterator.c b/iterator/iterator.c index b6d0b67d4..6ec8af401 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -1389,7 +1389,59 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, /* This either results in a query restart (CNAME cache response), a * terminating response (ANSWER), or a cache miss (null). */ - + + /* Check RPZ for override */ + if(qstate->env->auth_zones) { + /* apply rpz qname triggers, like after cname */ + struct dns_msg* forged_response = + rpz_callback_from_iterator_cname(qstate, iq); + if(forged_response) { + uint8_t* sname = 0; + size_t slen = 0; + int count = 0; + 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) && + iq->qchase.qtype != LDNS_RR_TYPE_CNAME && + count++ < ie->max_query_restarts) { + /* 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; + } + /* Follow the CNAME response */ + iq->dp = NULL; + iq->refetch_glue = 0; + iq->query_restart_count++; + iq->sent_count = 0; + iq->dp_target_count = 0; + sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region); + if(qstate->env->cfg->qname_minimisation) + iq->minimisation_state = INIT_MINIMISE_STATE; + return next_state(iq, INIT_REQUEST_STATE); + } + } + if (iter_stub_fwd_no_cache(qstate, &iq->qchase, &dpname, &dpnamelen)) { /* Asked to not query cache. */ verbose(VERB_ALGO, "no-cache set, going to the network"); @@ -1449,42 +1501,6 @@ 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); - int count = 0; - 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) && - iq->qchase.qtype != LDNS_RR_TYPE_CNAME && - count++ < ie->max_query_restarts) { - /* 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; @@ -1497,7 +1513,6 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, iq->minimisation_state = INIT_MINIMISE_STATE; return next_state(iq, INIT_REQUEST_STATE); } - /* if from cache, NULL, else insert 'cache IP' len=0 */ if(qstate->reply_origin) sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region); diff --git a/services/rpz.c b/services/rpz.c index 0637e3262..0bbb886f9 100644 --- a/services/rpz.c +++ b/services/rpz.c @@ -1244,16 +1244,20 @@ rpz_find_zone(struct local_zones* zones, uint8_t* qname, size_t qname_len, uint1 /** Find entry for RR type in the list of rrsets for the clientip. */ static struct local_rrset* rpz_find_synthesized_rrset(uint16_t qtype, - struct clientip_synthesized_rr* data) + struct clientip_synthesized_rr* data, int alias_ok) { - struct local_rrset* cursor = data->data; + struct local_rrset* cursor = data->data, *cname = NULL; while( cursor != NULL) { struct packed_rrset_key* packed_rrset = &cursor->rrset->rk; if(htons(qtype) == packed_rrset->type) { return cursor; } + if(ntohs(packed_rrset->type) == LDNS_RR_TYPE_CNAME && alias_ok) + cname = cursor; cursor = cursor->next; } + if(alias_ok) + return cname; return NULL; } @@ -1439,7 +1443,7 @@ static int rpz_remove_clientip_rr(struct clientip_synthesized_rr* node, struct local_rrset* rrset; struct packed_rrset_data* d; size_t index; - rrset = rpz_find_synthesized_rrset(rr_type, node); + rrset = rpz_find_synthesized_rrset(rr_type, node, 0); if(rrset == NULL) return 0; /* type not found, ignore */ d = (struct packed_rrset_data*)rrset->rrset->entry.data; @@ -1842,7 +1846,7 @@ rpz_apply_clientip_localdata_action(struct clientip_synthesized_rr* raddr, } /* check query type / rr type */ - rrset = rpz_find_synthesized_rrset(qinfo->qtype, raddr); + rrset = rpz_find_synthesized_rrset(qinfo->qtype, raddr, 1); if(rrset == NULL) { verbose(VERB_ALGO, "rpz: unable to find local-data for query"); rrset_count = 0; @@ -2056,7 +2060,7 @@ rpz_synthesize_nsip_localdata(struct rpz* r, struct module_qstate* ms, { struct local_rrset* rrset; - rrset = rpz_find_synthesized_rrset(qi->qtype, data); + rrset = rpz_find_synthesized_rrset(qi->qtype, data, 1); if(rrset == NULL) { verbose(VERB_ALGO, "rpz: nsip: no matching local data found"); return NULL; @@ -2128,12 +2132,12 @@ rpz_synthesize_qname_localdata_msg(struct rpz* r, struct module_qstate* ms, key.namelabs = dname_count_labels(qinfo->qname); ld = (struct local_data*)rbtree_search(&z->data, &key.node); if(ld == NULL) { - verbose(VERB_ALGO, "rpz: qname after cname: name not found"); + verbose(VERB_ALGO, "rpz: qname: name not found"); return NULL; } rrset = local_data_find_type(ld, qinfo->qtype, 1); if(rrset == NULL) { - verbose(VERB_ALGO, "rpz: qname after cname: type not found"); + verbose(VERB_ALGO, "rpz: qname: type not found"); return NULL; } return rpz_synthesize_localdata_from_rrset(r, ms, qinfo, rrset, az); @@ -2539,10 +2543,10 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms, dname_str(is->qchase.qname, nm); dname_str(z->name, zn); if(strcmp(zn, nm) != 0) - verbose(VERB_ALGO, "rpz: qname trigger after cname %s on %s, with action=%s", + verbose(VERB_ALGO, "rpz: qname trigger %s on %s, with action=%s", zn, nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt))); else - verbose(VERB_ALGO, "rpz: qname trigger after cname %s, with action=%s", + verbose(VERB_ALGO, "rpz: qname trigger %s, with action=%s", nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt))); } switch(localzone_type_to_rpz_action(lzt)) { @@ -2571,7 +2575,7 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms, ms->rpz_passthru = 1; break; default: - verbose(VERB_ALGO, "rpz: qname trigger after cname: bug: unhandled or invalid action: '%s'", + verbose(VERB_ALGO, "rpz: qname trigger: bug: unhandled or invalid action: '%s'", rpz_action_to_string(localzone_type_to_rpz_action(lzt))); ret = NULL; } diff --git a/testdata/rpz_cname_handle.rpl b/testdata/rpz_cname_handle.rpl new file mode 100644 index 000000000..38dddf12c --- /dev/null +++ b/testdata/rpz_cname_handle.rpl @@ -0,0 +1,779 @@ +; 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" + 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. +www.gotham.a A 1.2.3.61 +www.gotham2.a CNAME g2.target.a. +g2.target.a A 1.2.3.62 +www.gotham3.a CNAME g3.target.a. +g3.target.a CNAME g3b.target.a. +g3b.target.a A 1.2.3.63 +www.gotham4.a CNAME g4.target.a. +g4.target.a CNAME g4b.target.a. +g4b.target.a CNAME g4c.target.a. +g4c.target.a A 1.2.3.64 +w2.gotham5.a A 1.2.3.65 +w2.gotham6.a CNAME g6.target.a. +g6.target.a A 1.2.3.66 +w2.gotham7.a CNAME g7.target.a. +g7.target.a CNAME g7b.target.a. +g7b.target.a A 1.2.3.66 +; ns1.gotham8.a +32.48.30.20.10.rpz-nsip A 1.2.3.68 +; ns1.gotham9.a +32.49.30.20.10.rpz-nsip CNAME g9.target.a. +g9.target.a A 1.2.3.69 +; ns1.gotham10.a +32.50.30.20.10.rpz-nsip CNAME g10.target.a. +g10.target.a CNAME g10b.target.a. +g10b.target.a A 1.2.3.70 +www.gotham11.a CNAME g11.target.a. +www.gotham12.a CNAME g12.target.a. +g12.target.a CNAME g12b.target.a. +www.gotham13.a CNAME g13.target.a. +g13.target.a CNAME g13b.target.a. +g13b.target.a CNAME g13c.target.a. +w2.gotham14.a CNAME g14.target.a. +w2.gotham15.a CNAME g15.target.a. +g15.target.a CNAME g15b.target.a. +; ns1.gotham16.a +32.56.30.20.10.rpz-nsip CNAME g16.target.a. +; ns1.gotham17.a +32.57.30.20.10.rpz-nsip CNAME g17.target.a. +g17.target.a CNAME g17b.target.a. +TEMPFILE_END + +stub-zone: + name: "a." + stub-addr: 10.20.30.40 +CONFIG_END + +SCENARIO_BEGIN Test RPZ handling of CNAMEs. + +; a. +RANGE_BEGIN 0 1000 + ADDRESS 10.20.30.40 +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +gotham5.a. IN NS +SECTION AUTHORITY +gotham5.a. NS ns1.gotham5.a. +SECTION ADDITIONAL +ns1.gotham5.a. A 10.20.30.45 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +gotham6.a. IN NS +SECTION AUTHORITY +gotham6.a. NS ns1.gotham6.a. +SECTION ADDITIONAL +ns1.gotham6.a. A 10.20.30.46 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +gotham7.a. IN NS +SECTION AUTHORITY +gotham7.a. NS ns1.gotham7.a. +SECTION ADDITIONAL +ns1.gotham7.a. A 10.20.30.47 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +gotham8.a. IN NS +SECTION AUTHORITY +gotham8.a. NS ns1.gotham8.a. +SECTION ADDITIONAL +ns1.gotham8.a. A 10.20.30.48 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +gotham9.a. IN NS +SECTION AUTHORITY +gotham9.a. NS ns1.gotham9.a. +SECTION ADDITIONAL +ns1.gotham9.a. A 10.20.30.49 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +gotham10.a. IN NS +SECTION AUTHORITY +gotham10.a. NS ns1.gotham10.a. +SECTION ADDITIONAL +ns1.gotham10.a. A 10.20.30.50 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +gotham14.a. IN NS +SECTION AUTHORITY +gotham14.a. NS ns1.gotham14.a. +SECTION ADDITIONAL +ns1.gotham14.a. A 10.20.30.54 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +gotham15.a. IN NS +SECTION AUTHORITY +gotham15.a. NS ns1.gotham15.a. +SECTION ADDITIONAL +ns1.gotham15.a. A 10.20.30.55 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +gotham16.a. IN NS +SECTION AUTHORITY +gotham16.a. NS ns1.gotham16.a. +SECTION ADDITIONAL +ns1.gotham16.a. A 10.20.30.56 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +gotham17.a. IN NS +SECTION AUTHORITY +gotham17.a. NS ns1.gotham17.a. +SECTION ADDITIONAL +ns1.gotham17.a. A 10.20.30.57 +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 + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +g11.target.a. IN A +SECTION ANSWER +g11.target.a. IN A 1.2.3.11 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +g12b.target.a. IN A +SECTION ANSWER +g12b.target.a. A 1.2.3.12 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +g13c.target.a. IN A +SECTION ANSWER +g13c.target.a. A 1.2.3.13 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +g14.target.a. IN A +SECTION ANSWER +g14.target.a. A 1.2.3.14 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +g15b.target.a. IN A +SECTION ANSWER +g15b.target.a. A 1.2.3.15 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +g16.target.a. IN A +SECTION ANSWER +g16.target.a. A 1.2.3.16 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +g17b.target.a. IN A +SECTION ANSWER +g17b.target.a. A 1.2.3.17 +ENTRY_END +RANGE_END + +; gotham5.a. +RANGE_BEGIN 0 1000 + ADDRESS 10.20.30.45 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.gotham5.a. IN A +SECTION ANSWER +www.gotham5.a. CNAME w2.gotham5.a. +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. CNAME w2.gotham6.a. +ENTRY_END +RANGE_END + +; gotham7.a. +RANGE_BEGIN 0 1000 + ADDRESS 10.20.30.47 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.gotham7.a. IN A +SECTION ANSWER +www.gotham7.a. CNAME w2.gotham7.a. +ENTRY_END +RANGE_END + +; gotham14.a. +RANGE_BEGIN 0 1000 + ADDRESS 10.20.30.54 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.gotham14.a. IN A +SECTION ANSWER +www.gotham14.a. CNAME w2.gotham14.a. +ENTRY_END +RANGE_END + +; gotham15.a. +RANGE_BEGIN 0 1000 + ADDRESS 10.20.30.55 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +www.gotham15.a. IN A +SECTION ANSWER +www.gotham15.a. CNAME w2.gotham15.a. +ENTRY_END +RANGE_END + +; Test with zero rpz CNAMEs, rpz answer. +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 NOERROR +SECTION QUESTION +www.gotham.a. IN A +SECTION ANSWER +www.gotham.a. A 1.2.3.61 +ENTRY_END + +; Test with one rpz CNAME, rpz answer. +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 +www.gotham2.a. CNAME g2.target.a. +g2.target.a. A 1.2.3.62 +ENTRY_END + +; Test with two rpz CNAMEs, rpz answer. +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 AA NOERROR +SECTION QUESTION +www.gotham3.a. IN A +SECTION ANSWER +www.gotham3.a. CNAME g3.target.a. +g3.target.a. CNAME g3b.target.a. +g3b.target.a. A 1.2.3.63 +ENTRY_END + +; Test with three rpz CNAMEs, rpz answer. +STEP 40 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham4.a. IN A +ENTRY_END + +STEP 41 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +www.gotham4.a. IN A +SECTION ANSWER +www.gotham4.a. CNAME g4.target.a. +g4.target.a. CNAME g4b.target.a. +g4b.target.a. CNAME g4c.target.a. +g4c.target.a. A 1.2.3.64 +ENTRY_END + +; Test with a CNAME from upstream, zero rpz CNAMEs, rpz answer. +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 AA NOERROR +SECTION QUESTION +www.gotham5.a. IN A +SECTION ANSWER +www.gotham5.a. CNAME w2.gotham5.a. +w2.gotham5.a. A 1.2.3.65 +ENTRY_END + +; Test with a CNAME from upstream, one rpz CNAME, rpz answer. +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 AA NOERROR +SECTION QUESTION +www.gotham6.a. IN A +SECTION ANSWER +www.gotham6.a. CNAME w2.gotham6.a. +w2.gotham6.a. CNAME g6.target.a. +g6.target.a. A 1.2.3.66 +ENTRY_END + +; Test with a CNAME from upstream, two rpz CNAMEs, rpz answer. +STEP 70 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham7.a. IN A +ENTRY_END + +STEP 71 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +www.gotham7.a. IN A +SECTION ANSWER +www.gotham7.a. CNAME w2.gotham7.a. +w2.gotham7.a. CNAME g7.target.a. +g7.target.a. CNAME g7b.target.a. +g7b.target.a. A 1.2.3.66 +ENTRY_END + +; Test with a CNAME from cache, zero rpz CNAMEs, rpz answer. +STEP 80 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham5.a. IN A +ENTRY_END + +STEP 81 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +www.gotham5.a. IN A +SECTION ANSWER +www.gotham5.a. CNAME w2.gotham5.a. +w2.gotham5.a. A 1.2.3.65 +ENTRY_END + +; Test with a CNAME from cache, one rpz CNAME, rpz answer. +STEP 90 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham6.a. IN A +ENTRY_END + +STEP 91 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +www.gotham6.a. IN A +SECTION ANSWER +www.gotham6.a. CNAME w2.gotham6.a. +w2.gotham6.a. CNAME g6.target.a. +g6.target.a. A 1.2.3.66 +ENTRY_END + +; Test with a CNAME from cache, two rpz CNAMEs, rpz answer. +STEP 100 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham7.a. IN A +ENTRY_END + +STEP 101 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +www.gotham7.a. IN A +SECTION ANSWER +www.gotham7.a. CNAME w2.gotham7.a. +w2.gotham7.a. CNAME g7.target.a. +g7.target.a. CNAME g7b.target.a. +g7b.target.a. A 1.2.3.66 +ENTRY_END + +; Test with lookup from nameserver, zero rpz CNAMEs, rpz nsip answer. +STEP 110 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham8.a. IN A +ENTRY_END + +STEP 111 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +www.gotham8.a. IN A +SECTION ANSWER +www.gotham8.a. A 1.2.3.68 +ENTRY_END + +; Test with lookup from nameserver, one rpz CNAME, rpz nsip answer. +STEP 120 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham9.a. IN A +ENTRY_END + +STEP 121 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +www.gotham9.a. IN A +SECTION ANSWER +www.gotham9.a. CNAME g9.target.a. +g9.target.a. A 1.2.3.69 +ENTRY_END + +; Test with lookup from nameserver, two rpz CNAMEs, rpz nsip answer. +STEP 130 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham10.a. IN A +ENTRY_END + +STEP 131 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +www.gotham10.a. IN A +SECTION ANSWER +www.gotham10.a. CNAME g10.target.a. +g10.target.a. CNAME g10b.target.a. +g10b.target.a. A 1.2.3.70 +ENTRY_END + +; Test with one rpz CNAME, upstream answer. +STEP 140 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham11.a. IN A +ENTRY_END + +STEP 141 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +www.gotham11.a. IN A +SECTION ANSWER +www.gotham11.a. CNAME g11.target.a. +g11.target.a. A 1.2.3.11 +ENTRY_END + +; Test with two rpz CNAMEs, upstream answer. +STEP 150 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham12.a. IN A +ENTRY_END + +STEP 151 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +www.gotham12.a. IN A +SECTION ANSWER +www.gotham12.a. CNAME g12.target.a. +g12.target.a. CNAME g12b.target.a. +g12b.target.a. A 1.2.3.12 +ENTRY_END + +; Test with three rpz CNAMEs, upstream answer. +STEP 160 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham13.a. IN A +ENTRY_END + +STEP 161 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +www.gotham13.a. IN A +SECTION ANSWER +www.gotham13.a. CNAME g13.target.a. +g13.target.a. CNAME g13b.target.a. +g13b.target.a. CNAME g13c.target.a. +g13c.target.a. A 1.2.3.13 +ENTRY_END + +; Test with a CNAME from upstream, one rpz CNAME, upstream answer. +STEP 170 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham14.a. IN A +ENTRY_END + +STEP 171 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +www.gotham14.a. IN A +SECTION ANSWER +www.gotham14.a. CNAME w2.gotham14.a. +w2.gotham14.a. CNAME g14.target.a. +g14.target.a. A 1.2.3.14 +ENTRY_END + +; Test with a CNAME from upstream, two rpz CNAMEs, upstream answer. +STEP 180 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham15.a. IN A +ENTRY_END + +STEP 181 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +www.gotham15.a. IN A +SECTION ANSWER +www.gotham15.a. CNAME w2.gotham15.a. +w2.gotham15.a. CNAME g15.target.a. +g15.target.a. CNAME g15b.target.a. +g15b.target.a. A 1.2.3.15 +ENTRY_END + +; Test with a CNAME from cache, one rpz CNAME, upstream answer. +STEP 190 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham14.a. IN A +ENTRY_END + +STEP 191 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +www.gotham14.a. IN A +SECTION ANSWER +www.gotham14.a. CNAME w2.gotham14.a. +w2.gotham14.a. CNAME g14.target.a. +g14.target.a. A 1.2.3.14 +ENTRY_END + +; Test with a CNAME from cache, two rpz CNAMEs, upstream answer. +STEP 200 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham15.a. IN A +ENTRY_END + +STEP 201 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +www.gotham15.a. IN A +SECTION ANSWER +www.gotham15.a. CNAME w2.gotham15.a. +w2.gotham15.a. CNAME g15.target.a. +g15.target.a. CNAME g15b.target.a. +g15b.target.a. A 1.2.3.15 +ENTRY_END + +; Test with lookup from nameserver, one rpz nsip CNAME, upstream answer. +STEP 210 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham16.a. IN A +ENTRY_END + +STEP 211 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +www.gotham16.a. IN A +SECTION ANSWER +www.gotham16.a. CNAME g16.target.a. +g16.target.a. A 1.2.3.16 +ENTRY_END + +; Test with lookup from nameserver, two rpz nsip CNAMEs, upstream answer. +STEP 220 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.gotham17.a. IN A +ENTRY_END + +STEP 221 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +www.gotham17.a. IN A +SECTION ANSWER +www.gotham17.a. CNAME g17.target.a. +g17.target.a. CNAME g17b.target.a. +g17b.target.a. A 1.2.3.17 +ENTRY_END + +SCENARIO_END