From ccb576f95e6cd4c10c04d4aa74f2d320d3dec872 Mon Sep 17 00:00:00 2001 From: Ralph Dolmans Date: Fri, 23 Aug 2019 12:15:37 +0200 Subject: [PATCH] - add always_deny action, use this one for RPZ - use localzone's memory layout when removing rr from rrset --- respip/respip.c | 11 +- services/localzone.c | 29 ++- services/localzone.h | 13 ++ services/rpz.c | 18 +- services/rpz.h | 1 + testdata/rpz_ixfr.rpl | 378 +++++++++++++++++++++++++++++++ testdata/rpz_qname_override.rpl | 19 ++ testdata/rpz_respip_override.rpl | 30 +++ 8 files changed, 483 insertions(+), 16 deletions(-) create mode 100644 testdata/rpz_ixfr.rpl diff --git a/respip/respip.c b/respip/respip.c index 57abed683..5da60ad0e 100644 --- a/respip/respip.c +++ b/respip/respip.c @@ -195,6 +195,8 @@ respip_action_cfg(struct respip_set* set, const char* ipstr, action = respip_always_nxdomain; else if(strcmp(actnstr, "always_nodata") == 0) action = respip_always_nodata; + else if(strcmp(actnstr, "always_deny") == 0) + action = respip_always_deny; else { log_err("unknown response-ip action %s", actnstr); return 0; @@ -962,6 +964,7 @@ respip_rewrite_reply(const struct query_info* qinfo, && action != respip_always_transparent && action != respip_always_nxdomain && action != respip_always_nodata + && action != respip_always_deny && (result = respip_data_answer(action, (data) ? data : raddr->data, qinfo->qtype, rep, rrset_id, new_repp, tag, tag_datas, tag_datas_size, @@ -1080,9 +1083,11 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id, } else { qstate->respip_action_info = NULL; } - if (new_rep == qstate->return_msg->rep && + if (actinfo.action == respip_always_deny || + (new_rep == qstate->return_msg->rep && (actinfo.action == respip_deny || - actinfo.action == respip_inform_deny)) { + actinfo.action == respip_deny || + actinfo.action == respip_inform_deny))) { /* for deny-variant actions (unless response-ip * data is applied), mark the query state so * the response will be dropped for all @@ -1283,7 +1288,7 @@ respip_inform_print(struct respip_action_info* respip_actinfo, uint8_t* qname, txtlen += snprintf(txt+txtlen, sizeof(txt)-txtlen, "[%s] ", respip_actinfo->log_name); } - txtlen += snprintf(txt+txtlen, sizeof(txt)-txtlen, + snprintf(txt+txtlen, sizeof(txt)-txtlen, "%s/%d %s %s@%u", respip, respip_addr->net, (actionstr) ? actionstr : "inform", srcip, port); if(actionstr) diff --git a/services/localzone.c b/services/localzone.c index 5034de149..33062ea69 100644 --- a/services/localzone.c +++ b/services/localzone.c @@ -394,6 +394,27 @@ rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd, return 1; } +/** Delete RR from local-zone RRset, wastes memory as the deleted RRs cannot be + * free'd (regionally alloc'd) */ +int +local_rrset_remove_rr(struct packed_rrset_data* pd, size_t index) +{ + if(index >= pd->count) { + log_warn("Trying to remove RR with out of bound index"); + return 0; + } + if(index - 1 < pd->count) { + /* not removing last element */ + size_t nexti = index + 1; + size_t num = pd->count - nexti; + memcpy(pd->rr_len+index, pd->rr_len+nexti, sizeof(*pd->rr_len)*num); + memcpy(pd->rr_ttl+index, pd->rr_ttl+nexti, sizeof(*pd->rr_ttl)*num); + memcpy(pd->rr_data+index, pd->rr_data+nexti, sizeof(*pd->rr_data)*num); + } + pd->count--; + return 1; +} + struct local_data* local_zone_find_data(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs) { @@ -1447,7 +1468,9 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env, struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp, struct local_data* ld, enum localzone_type lz_type) { - if(lz_type == local_zone_deny || lz_type == local_zone_inform_deny) { + if(lz_type == local_zone_deny || + lz_type == local_zone_always_deny || + lz_type == local_zone_inform_deny) { /** no reply at all, signal caller by clearing buffer. */ sldns_buffer_clear(buf); sldns_buffer_flip(buf); @@ -1655,6 +1678,7 @@ local_zones_answer(struct local_zones* zones, struct module_env* env, && lzt != local_zone_always_transparent && lzt != local_zone_always_nxdomain && lzt != local_zone_always_nodata + && lzt != local_zone_always_deny && local_data_answer(z, env, qinfo, edns, repinfo, buf, temp, labs, &ld, lzt, tag, tag_datas, tag_datas_size, tagname, num_tags)) { lock_rw_unlock(&z->lock); @@ -1685,6 +1709,7 @@ const char* local_zone_type2str(enum localzone_type t) case local_zone_always_refuse: return "always_refuse"; case local_zone_always_nxdomain: return "always_nxdomain"; case local_zone_always_nodata: return "always_nodata"; + case local_zone_always_deny: return "always_deny"; case local_zone_noview: return "noview"; case local_zone_invalid: return "invalid"; } @@ -1719,6 +1744,8 @@ int local_zone_str2type(const char* type, enum localzone_type* t) *t = local_zone_always_nxdomain; else if(strcmp(type, "always_nodata") == 0) *t = local_zone_always_nodata; + else if(strcmp(type, "always_deny") == 0) + *t = local_zone_always_deny; else if(strcmp(type, "noview") == 0) *t = local_zone_noview; else if(strcmp(type, "nodefault") == 0) diff --git a/services/localzone.h b/services/localzone.h index a476f36c9..10bfab82e 100644 --- a/services/localzone.h +++ b/services/localzone.h @@ -94,6 +94,8 @@ enum localzone_type { local_zone_always_nxdomain, /** answer with noerror/nodata, even when there is local data */ local_zone_always_nodata, + /** drop query, even when there is local data */ + local_zone_always_deny, /** answer not from the view, but global or no-answer */ local_zone_noview, /** Invalid type, cannot be used to generate answer */ @@ -513,6 +515,15 @@ int rrstr_get_rr_content(const char* str, uint8_t** nm, uint16_t* type, int rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd, uint8_t* rdata, size_t rdata_len, time_t ttl, const char* rrstr); +/** + * Remove RR from rrset that is created using localzone's rrset_insert_rr. + * @param pd: the RRset containing the RR to remove + * @param index: index of RR to remove + * @return: 1 on success; 0 otherwise. + */ +int +local_rrset_remove_rr(struct packed_rrset_data* pd, size_t index); + /** * Valid response ip actions for the IP-response-driven-action feature; * defined here instead of in the respip module to enable sharing of enum @@ -543,6 +554,8 @@ enum respip_action { respip_always_nxdomain = local_zone_always_nxdomain, /** answer with nodata response */ respip_always_nodata = local_zone_always_nodata, + /** answer with nodata response */ + respip_always_deny = local_zone_always_deny, /* The rest of the values are only possible as * access-control-tag-action */ diff --git a/services/rpz.c b/services/rpz.c index a7605d8f6..8653a30f0 100644 --- a/services/rpz.c +++ b/services/rpz.c @@ -197,7 +197,7 @@ rpz_action_to_localzone_type(enum rpz_action a) switch(a) { case RPZ_NXDOMAIN_ACTION: return local_zone_always_nxdomain; case RPZ_NODATA_ACTION: return local_zone_always_nodata; - case RPZ_DROP_ACTION: return local_zone_deny; + case RPZ_DROP_ACTION: return local_zone_always_deny; case RPZ_PASSTHRU_ACTION: return local_zone_always_transparent; case RPZ_LOCAL_DATA_ACTION: case RPZ_CNAME_OVERRIDE_ACTION: @@ -215,7 +215,7 @@ rpz_action_to_respip_action(enum rpz_action a) switch(a) { case RPZ_NXDOMAIN_ACTION: return respip_always_nxdomain; case RPZ_NODATA_ACTION: return respip_always_nodata; - case RPZ_DROP_ACTION: return respip_deny; + case RPZ_DROP_ACTION: return respip_always_deny; case RPZ_PASSTHRU_ACTION: return respip_always_transparent; case RPZ_LOCAL_DATA_ACTION: case RPZ_CNAME_OVERRIDE_ACTION: @@ -233,7 +233,7 @@ localzone_type_to_rpz_action(enum localzone_type lzt) switch(lzt) { case local_zone_always_nxdomain: return RPZ_NXDOMAIN_ACTION; case local_zone_always_nodata: return RPZ_NODATA_ACTION; - case local_zone_deny: return RPZ_DROP_ACTION; + case local_zone_always_deny: return RPZ_DROP_ACTION; case local_zone_always_transparent: return RPZ_PASSTHRU_ACTION; case local_zone_redirect: return RPZ_LOCAL_DATA_ACTION; case local_zone_invalid: @@ -248,7 +248,7 @@ respip_action_to_rpz_action(enum respip_action a) switch(a) { case respip_always_nxdomain: return RPZ_NXDOMAIN_ACTION; case respip_always_nodata: return RPZ_NODATA_ACTION; - case respip_deny: return RPZ_DROP_ACTION; + case respip_always_deny: return RPZ_DROP_ACTION; case respip_always_transparent: return RPZ_PASSTHRU_ACTION; case respip_redirect: return RPZ_LOCAL_DATA_ACTION; case respip_invalid: @@ -689,11 +689,8 @@ rpz_data_delete_rr(struct local_zone* z, uint8_t* policydname, } if(d->count > 1) { - struct packed_rrset_data* new; - new = packed_rrset_remove_rr(d, index, z->region); - if(!new) + if(!local_rrset_remove_rr(d, index)) return 0; - p->rrset->entry.data = new; } } } @@ -731,11 +728,8 @@ rpz_rrset_delete_rr(struct resp_addr* raddr, uint16_t rr_type, uint8_t* rdata, return 1; } if(d->count > 1) { - struct packed_rrset_data* new; - new = packed_rrset_remove_rr(d, index, region); - if(!new) + if(!local_rrset_remove_rr(d, index)) return 0; - raddr->data->entry.data = new; } } return 0; diff --git a/services/rpz.h b/services/rpz.h index 042773f33..80edad822 100644 --- a/services/rpz.h +++ b/services/rpz.h @@ -44,6 +44,7 @@ #include "services/localzone.h" #include "util/locks.h" +#include "util/log.h" #include "util/config_file.h" #include "services/authzone.h" #include "sldns/sbuffer.h" diff --git a/testdata/rpz_ixfr.rpl b/testdata/rpz_ixfr.rpl new file mode 100644 index 000000000..3f7cb3d35 --- /dev/null +++ b/testdata/rpz_ixfr.rpl @@ -0,0 +1,378 @@ +; config options +server: + module-config: "respip validator iterator" + target-fetch-policy: "0 0 0 0 0" + qname-minimisation: no + +rpz: + name: "rpz.example.com." + master: 10.20.30.40 + 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.rpz.example.com. IN CNAME *. +c.rpz.example.com. IN TXT "hello from initial RPZ" +c.rpz.example.com. IN TXT "another hello from initial RPZ" +c.rpz.example.com. IN TXT "yet another hello from initial RPZ" +d.rpz.example.com. IN CNAME . +32.1.123.0.10.rpz-ip.rpz.example.com. CNAME *. +32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.3 +32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.4 +32.4.123.0.10.rpz-ip.rpz.example.com. CNAME . +TEMPFILE_END + +stub-zone: + name: "." + stub-addr: 10.20.30.40 + +CONFIG_END + +SCENARIO_BEGIN Test RPZ QNAME trigger, loaded using IXFR + +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. IN TXT +SECTION ANSWER +b. TXT "hello from upstream" +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR NOERROR AA +SECTION QUESTION +d. IN TXT +SECTION ANSWER +d. TXT "hello from upstream" +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR NOERROR AA +SECTION QUESTION +a.rpz-ip. IN A +SECTION ANSWER +a.rpz-ip. IN A 10.0.123.1 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR NOERROR AA +SECTION QUESTION +c.rpz-ip. IN A +SECTION ANSWER +c.rpz-ip. IN A 10.0.123.3 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR NOERROR AA +SECTION QUESTION +d.rpz-ip. IN A +SECTION ANSWER +d.rpz-ip. IN A 10.0.123.4 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +rpz.example.com. IN SOA +SECTION ANSWER +rpz.example.com. IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 2 3600 900 86400 3600 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qname qtype +ADJUST copy_id +REPLY QR AA NOERROR +SECTION QUESTION +rpz.example.com. IN IXFR +SECTION ANSWER +rpz.example.com. IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 2 3600 900 86400 3600 +rpz.example.com. IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 1 3600 900 86400 3600 +a.rpz.example.com. IN CNAME *. +c.rpz.example.com. IN TXT "hello from initial RPZ" +c.rpz.example.com. IN TXT "another hello from initial RPZ" +d.rpz.example.com. IN CNAME . +32.1.123.0.10.rpz-ip.rpz.example.com. CNAME *. +32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.3 +32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.4 +32.4.123.0.10.rpz-ip.rpz.example.com. CNAME . +rpz.example.com. IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 2 3600 900 86400 3600 +b.rpz.example.com. TXT "hello from RPZ" +c.rpz.example.com. TXT "hello from RPZ" +a.rpz.example.com. CNAME . +32.1.123.0.10.rpz-ip.rpz.example.com. CNAME . +32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.5 +32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.6 +rpz.example.com. IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 2 3600 900 86400 3600 +ENTRY_END + +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +b. IN TXT +ENTRY_END + +STEP 2 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +b. IN TXT +SECTION ANSWER +b. IN TXT "hello from upstream" +ENTRY_END + +STEP 3 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +a. IN TXT +ENTRY_END + +STEP 4 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +a. IN TXT +SECTION ANSWER +ENTRY_END + +STEP 5 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +a.rpz-ip. IN A +ENTRY_END + +STEP 6 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +a.rpz-ip. IN A +SECTION ANSWER +ENTRY_END + +STEP 7 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +c. IN TXT +ENTRY_END + +STEP 8 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +c. IN TXT +SECTION ANSWER +c. IN TXT "yet another hello from initial RPZ" +c. IN TXT "another hello from initial RPZ" +c. IN TXT "hello from initial RPZ" +ENTRY_END + +STEP 9 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +c.rpz-ip. IN A +ENTRY_END + +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +c.rpz-ip. IN A +SECTION ANSWER +c.rpz-ip. IN A 10.66.0.4 +c.rpz-ip. IN A 10.66.0.3 +ENTRY_END + +STEP 11 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +d. IN TXT +ENTRY_END + +STEP 12 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NXDOMAIN +SECTION QUESTION +d. IN TXT +ENTRY_END + +STEP 13 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +d.rpz-ip. IN A +ENTRY_END + + +STEP 15 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NXDOMAIN +SECTION QUESTION +d.rpz-ip. IN A +ENTRY_END + +STEP 16 TIME_PASSES ELAPSE 1 +STEP 30 TIME_PASSES ELAPSE 3600 +STEP 40 TRAFFIC + +STEP 50 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +b. IN TXT +ENTRY_END + +STEP 51 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +b. IN TXT +SECTION ANSWER +b. IN TXT "hello from RPZ" +ENTRY_END + +STEP 52 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +a. IN TXT +ENTRY_END + +STEP 53 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NXDOMAIN +SECTION QUESTION +a. IN TXT +SECTION ANSWER +ENTRY_END + +STEP 54 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +a.rpz-ip. IN A +ENTRY_END + +STEP 55 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NXDOMAIN +SECTION QUESTION +a.rpz-ip. IN A +SECTION ANSWER +ENTRY_END + +STEP 56 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +c. IN TXT +ENTRY_END + +STEP 57 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AA NOERROR +SECTION QUESTION +c. IN TXT +SECTION ANSWER +c. IN TXT "hello from RPZ" +c. IN TXT "yet another hello from initial RPZ" +ENTRY_END + +STEP 58 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +c.rpz-ip. IN A +ENTRY_END + +STEP 59 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +c.rpz-ip. IN A +SECTION ANSWER +c.rpz-ip. IN A 10.66.0.6 +c.rpz-ip. IN A 10.66.0.5 +ENTRY_END + +STEP 60 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +d. IN TXT +ENTRY_END + +STEP 61 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +d. IN TXT +SECTION ANSWER +d. IN TXT "hello from upstream" +ENTRY_END + +STEP 62 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +d.rpz-ip. IN A +ENTRY_END + +STEP 63 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +d.rpz-ip. IN A +SECTION ANSWER +d.rpz-ip. IN A 10.0.123.4 +ENTRY_END + +SCENARIO_END diff --git a/testdata/rpz_qname_override.rpl b/testdata/rpz_qname_override.rpl index d75049306..b2608e251 100644 --- a/testdata/rpz_qname_override.rpl +++ b/testdata/rpz_qname_override.rpl @@ -64,6 +64,16 @@ $ORIGIN rpz6.example.com. e TXT "should be override by cname" TEMPFILE_END +rpz: + name: "rpz7.example.com." + rpz-action-override: drop + zonefile: +TEMPFILE_NAME rpz7.example.com +TEMPFILE_CONTENTS rpz7.example.com +$ORIGIN rpz7.example.com. +f TXT "should be override by drop policy" +TEMPFILE_END + stub-zone: name: "d." stub-addr: 10.20.30.40 @@ -175,4 +185,13 @@ e. IN CNAME d. d. IN TXT "answer from upstream ns" ENTRY_END +; check drop override, would be localdata without override +STEP 60 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +f. IN TXT +ENTRY_END +; no answer is checked at exit of testbound. + SCENARIO_END diff --git a/testdata/rpz_respip_override.rpl b/testdata/rpz_respip_override.rpl index f5672d621..16d91378a 100644 --- a/testdata/rpz_respip_override.rpl +++ b/testdata/rpz_respip_override.rpl @@ -64,6 +64,16 @@ $ORIGIN rpz6.example.com. 32.6.113.0.203.rpz-ip A 192.0.2.6 TEMPFILE_END +rpz: + name: "rpz7.example.com." + rpz-action-override: drop + zonefile: +TEMPFILE_NAME rpz7.example.com +TEMPFILE_CONTENTS rpz7.example.com +$ORIGIN rpz7.example.com. +32.7.113.0.203.rpz-ip A 192.0.2.7 +TEMPFILE_END + stub-zone: name: "." stub-addr: 10.20.30.40 @@ -146,6 +156,16 @@ SECTION ANSWER e. IN A 203.0.113.6 ENTRY_END +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +f. IN A +SECTION ANSWER +f. IN A 203.0.113.7 +ENTRY_END + RANGE_END STEP 1 QUERY @@ -232,4 +252,14 @@ e. IN CNAME ns. ns. IN A 10.20.30.40 ENTRY_END +STEP 11 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +f. IN A +ENTRY_END +; no answer is checked at exit of testbound. + +STEP 12 TIME_PASSES ELAPSE 10 + SCENARIO_END -- 2.47.2