local function rpz_parse(action, path)
local rules = {}
local new_actions = {}
- local origin = '.'
+ local origin = '\0'
local action_map = {
-- RPZ Policy Actions
['\0'] = action,
end
if not ok then break end
- local name = ffi.string(parser.r_owner, parser.r_owner_length)
+ local full_name = ffi.gc(ffi.C.knot_dname_copy(parser.r_owner, nil), ffi.C.free)
local rdata = ffi.string(parser.r_data, parser.r_data_length)
+ ffi.C.knot_dname_to_lower(full_name)
if (parser.r_type == kres.type.SOA) then
- -- parser return \0 if SOA use @ as owner
- origin = (name == '\0') and origin or name
+ origin = ffi.gc(ffi.C.knot_dname_copy(full_name, nil), ffi.C.free)
goto continue
end
- name = (name == origin) and name or name:gsub('%'..origin, '')
+ local prefix_labels = ffi.C.knot_dname_in_bailiwick(full_name, origin)
+ local name
+ if prefix_labels > 0 then
+ local bytes = 0
+ for _=1,prefix_labels do
+ bytes = bytes + 1 + full_name[bytes]
+ end
+ name = ffi.string(full_name, bytes)
+ name = name..'\0'
+ else
+ name = ffi.string(full_name, parser.r_owner_length)
+ end
if parser.r_type == kres.type.CNAME then
if action_map[rdata] then
rules[name] = action_map[rdata]
else
- log('[poli] RPZ %s:%d: CNAME in RPZ is not supported', path, tonumber(parser.line_counter))
+ log('[poli] RPZ %s:%d: CNAME with custom target in RPZ is not supported', path, tonumber(parser.line_counter))
end
else
-- Warn when NYI
::continue::
end
collectgarbage()
- for k, v in pairs(new_actions) do
- rules[k] = policy.ANSWER(v, true)
+ for qname, rrsets in pairs(new_actions) do
+ rules[qname] = policy.ANSWER(rrsets, true)
end
return rules
end
local function test_rpz()
check_answer('"CNAME ." return NXDOMAIN',
'nxdomain.', kres.type.A, kres.rcode.NXDOMAIN)
- check_answer('"CNAME *." return NXDOMAIN',
+ check_answer('"CNAME *." return NODATA',
'nodata.', kres.type.A, kres.rcode.NOERROR)
+ check_answer('"CNAME *. on wildcard" return NODATA',
+ 'nodata.nxdomain.', kres.type.A, kres.rcode.NOERROR)
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('"A 192.168.66.6" with suffixed zone name in owner return local A rrset',
- 'rra-zonename-suffix.', kres.type.A, kres.rcode.NOERROR, '192.168.66.6')
+ check_answer('"A 192.168.5.5" return local A rrset',
+ 'rra.', kres.type.A, kres.rcode.NOERROR, '192.168.5.5')
+ check_answer('"A 192.168.6.6" with suffixed zone name in owner return local A rrset',
+ 'rra-zonename-suffix.', kres.type.A, kres.rcode.NOERROR, '192.168.6.6')
+ check_answer('"A 192.168.7.7" with suffixed zone name in owner return local A rrset',
+ 'testdomain.rra.', kres.type.A, kres.rcode.NOERROR, '192.168.7.7')
check_answer('non existing AAAA on rra domain return NODATA',
'rra.', kres.type.AAAA, kres.rcode.NOERROR)
+ check_answer('"A 192.168.8.8" and domain with uppercase and lowercase letters',
+ 'case.sensitive.', kres.type.A, kres.rcode.NOERROR, '192.168.8.8')
+ check_answer('"A 192.168.8.8" and domain with uppercase and lowercase letters',
+ 'CASe.SENSItivE.', kres.type.A, kres.rcode.NOERROR, '192.168.8.8')
end
net.ipv4 = false