From b04432bfc35915c7378aa1ab7f59ea2a3e8c6012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20=C5=A0pa=C4=8Dek?= <petr.spacek@nic.cz> Date: Thu, 25 Jan 2018 12:26:50 +0100 Subject: [PATCH] policy: add explanatory TXT record to zones blocked by default --- modules/policy/README.rst | 1 + modules/policy/policy.lua | 49 ++++++++++++++++++++++++++++----------- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/modules/policy/README.rst b/modules/policy/README.rst index 499d15f15..934604ee4 100644 --- a/modules/policy/README.rst +++ b/modules/policy/README.rst @@ -26,6 +26,7 @@ There are several actions available in the ``policy.`` table: * ``PASS`` - let the query pass through; it's useful to make exceptions before wider rules * ``DENY`` - reply NXDOMAIN authoritatively +* ``DENY_MSG(msg)`` - reply NXDOMAIN authoritatively and add explanatory message to additional section * ``DROP`` - terminate query resolution and return SERVFAIL to the requestor * ``TC`` - set TC=1 if the request came through UDP, forcing client to retry with TCP * ``FORWARD(ip)`` - resolve a query via forwarding to an IP while validating and caching locally; diff --git a/modules/policy/policy.lua b/modules/policy/policy.lua index cd32181d2..552731ed0 100644 --- a/modules/policy/policy.lua +++ b/modules/policy/policy.lua @@ -464,15 +464,28 @@ function policy.rpz(action, path) end end -function policy.DENY(_, req) - -- Write authority information - local answer = req.answer - ffi.C.kr_pkt_make_auth_header(answer) - answer:rcode(kres.rcode.NXDOMAIN) - answer:begin(kres.section.AUTHORITY) - mkauth_soa(answer, '\7blocked\0') - return kres.DONE +function policy.DENY_MSG(msg) + if msg and (type(msg) ~= 'string' or #msg >= 255) then + error('DENY_MSG: optional msg must be string shorter than 256 characters') + end + + return function (_, req) + -- Write authority information + local answer = req.answer + ffi.C.kr_pkt_make_auth_header(answer) + answer:rcode(kres.rcode.NXDOMAIN) + answer:begin(kres.section.AUTHORITY) + mkauth_soa(answer, '\7blocked\0') + if msg then + answer:begin(kres.section.ADDITIONAL) + answer:put('\11explanation\7invalid', 900, answer:qclass(), kres.type.TXT, + string.char(#msg) .. msg) + + end + return kres.DONE + end end +policy.DENY = policy.DENY_MSG() -- compatibility with < 2.0 function policy.DROP(_, _) return kres.FAIL @@ -603,7 +616,7 @@ local private_zones = { '100.51.198.in-addr.arpa.', '113.0.203.in-addr.arpa.', '255.255.255.255.in-addr.arpa.', - -- RFC7796 + -- RFC7793 '64.100.in-addr.arpa.', '65.100.in-addr.arpa.', '66.100.in-addr.arpa.', @@ -686,14 +699,22 @@ policy.rules = {} policy.postrules = {} policy.special_names = { { - cb=policy.suffix_common(policy.DENY, private_zones, todname('arpa.')), + cb=policy.suffix_common(policy.DENY_MSG( + 'Blocking is mandated by standards, see references on ' + .. 'https://www.iana.org/assignments/' + .. 'locally-served-dns-zones/locally-served-dns-zones.xhtml'), + private_zones, todname('arpa.')), count=0 }, { - cb=policy.suffix(policy.DENY, { - todname('test.'), - todname('invalid.'), - todname('onion.'), -- RFC7686, 2.4 + cb=policy.suffix(policy.DENY_MSG( + 'Blocking is mandated by standards, see references on ' + .. 'https://www.iana.org/assignments/' + .. 'special-use-domain-names/special-use-domain-names.xhtml'), + { + todname('test.'), + todname('onion.'), + todname('invalid.'), }), count=0 }, -- GitLab