From: Lukáš Ježek Date: Thu, 2 Apr 2020 12:38:13 +0000 (+0200) Subject: modules/policy: Add RPZ test X-Git-Tag: v5.1.0~14^2~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2ad1a47b2c57035c2a5e3871846cf1a4f32963ea;p=thirdparty%2Fknot-resolver.git modules/policy: Add RPZ test --- diff --git a/modules/policy/meson.build b/modules/policy/meson.build index 2e16c4d14..8a4991349 100644 --- a/modules/policy/meson.build +++ b/modules/policy/meson.build @@ -8,6 +8,7 @@ lua_mod_src += [ config_tests += [ ['policy', files('policy.test.lua')], ['policy.slice', files('policy.slice.test.lua')], + ['policy.rpz', files('policy.rpz.test.lua')], ] integr_tests += [ diff --git a/modules/policy/policy.lua b/modules/policy/policy.lua index a75d5fdf1..53a0ce7b8 100644 --- a/modules/policy/policy.lua +++ b/modules/policy/policy.lua @@ -416,19 +416,24 @@ local function rpz_parse(action, path) if not ok then break end local name = ffi.string(parser.r_owner, parser.r_owner_length) - local name_action = ffi.string(parser.r_data, parser.r_data_length) - rules[name] = action_map[name_action] - -- Warn when NYI - if #name > 1 and not action_map[name_action] then + local rdata = ffi.string(parser.r_data, parser.r_data_length) - if parser.r_type == kres.type.CNAME then - log('[poli] RPZ %s:%d: CNAME in RPZ is not supported', path, tonumber(parser.line_counter)) - elseif unsupp_rrs(parser.r_type) then - log('[poli] RPZ %s:%d: RR type %s is not allowed in RPZ', path, tonumber(parser.line_counter), - kres.tostring.type[parser.r_type]) + if parser.r_type == kres.type.CNAME then + if action_map[rdata] then + rules[name] = action_map[rdata] else - if new_actions[name] == nil then new_actions[name] = {} end - new_actions[name][parser.r_type] = { ttl=parser.r_ttl, rdata=name_action } + log('[poli] RPZ %s:%d: CNAME in RPZ is not supported', path, tonumber(parser.line_counter)) + end + else + -- Warn when NYI + if #name then + if unsupp_rrs(parser.r_type) then + log('[poli] RPZ %s:%d: RR type %s is not allowed in RPZ', path, tonumber(parser.line_counter), + kres.tostring.type[parser.r_type]) + else + if new_actions[name] == nil then new_actions[name] = {} end + new_actions[name][parser.r_type] = { ttl=parser.r_ttl, rdata=rdata } + end end end end diff --git a/modules/policy/policy.rpz.test.lua b/modules/policy/policy.rpz.test.lua new file mode 100644 index 000000000..b63d850b1 --- /dev/null +++ b/modules/policy/policy.rpz.test.lua @@ -0,0 +1,69 @@ + +local function prepare_cache() + cache.open(100*MB) + cache.clear() + + local ffi = require('ffi') + local c = kres.context().cache + + local passthru_addr = '\127\0\0\9' + rr_passthru = kres.rrset(todname('rpzpassthru.'), kres.type.A, kres.class.IN, 3600999999) + assert(rr_passthru:add_rdata(passthru_addr, #passthru_addr)) + assert(c:insert(rr_passthru, nil, ffi.C.KR_RANK_SECURE + ffi.C.KR_RANK_AUTH)) + + c:commit() +end + +local function rrset_to_texts(rr) + local rr_text = {} + for w in rr:txt_dump():gmatch("%S+") do table.insert(rr_text, w) end + return rr_text +end + +local function check_answer(desc, qname, qtype, expected_rcode, expected_rdata) + qtype_str = kres.tostring.type[qtype] + callback = function(pkt) + same(pkt:rcode(), expected_rcode, + desc .. ': expecting answer for query ' .. qname .. ' ' .. qtype_str + .. ' with rcode ' .. kres.tostring.rcode[expected_rcode]) + + if expected_rdata then + rr_text = rrset_to_texts(pkt:rrsets(kres.section.ANSWER)[1]) + ok(rr_text[4] == expected_rdata, + desc ..': checking rdata of answer for ' .. qname .. ' ' .. qtype_str) + else + -- check empty section + ok(pkt:rrsets(kres.section.ANSWER)[1] == nil, + desc ..': checking empty answer section for ' .. qname .. ' ' .. qtype_str) + end + + end + + resolve(qname, qtype, kres.class.IN, {}, callback) +end + +local function test_rpz() + check_answer('"CNAME ." return NXDOMAIN', + 'nxdomain.', kres.type.A, kres.rcode.NXDOMAIN) + check_answer('"CNAME *." return NXDOMAIN', + 'nodata.', kres.type.A, kres.rcode.NXDOMAIN) + check_answer('"CNAME rpz-drop." be dropped', + 'rpzdrop.', kres.type.A, kres.rcode.SERVFAIL) + check_answer('"CNAME rpz-passthru" return A rrset', + 'rpzpassthru.', kres.type.A, kres.rcode.NOERROR, '127.0.0.9') + check_answer('"A 192.168.55.5" return local A rrset', + 'rra.', kres.type.A, kres.rcode.NOERROR, '192.168.55.5') + check_answer('non existing AAAA on rra domain return NODATA', + 'rra.', kres.type.AAAA, kres.rcode.NOERROR) +end + +net.ipv4 = false +net.ipv6 = false + +prepare_cache() + +policy.add(policy.rpz(policy.DENY, 'policy.test.rpz')) + +return { + test_rpz, +} diff --git a/modules/policy/policy.test.rpz b/modules/policy/policy.test.rpz new file mode 100644 index 000000000..9ebaa17e3 --- /dev/null +++ b/modules/policy/policy.test.rpz @@ -0,0 +1,9 @@ +$TTL 30 +@ SOA nonexistent.nodomain.none. dummy.nodomain.none. 1 12h 15m 3w 2h + NS nonexistant.nodomain.none. + +nxdomain. CNAME . +nodata. CNAME *. +rpzdrop. CNAME rpz-drop. +rpzpassthru. CNAME rpz-passthru. +rra. A 192.168.55.5