diff --git a/modules/policy/README.rst b/modules/policy/README.rst index 40edc49c1ab5f686c2b65490933d21466d6e0590..a0af187ba667f18b17e5686598bf5c7fec4fac80 100644 --- a/modules/policy/README.rst +++ b/modules/policy/README.rst @@ -24,6 +24,7 @@ There are several defined actions: * ``DENY`` - return NXDOMAIN answer * ``DROP`` - terminate query resolution, returns SERVFAIL to requestor * ``TC`` - set TC=1 if the request came through UDP, forcing client to retry with TCP +* ``FORWARD(ip)`` - forward query to given IP and proxy back response (stub mode) .. note:: The module (and ``kres``) treats domain names as wire, not textual representation. So each label in name is prefixed with its length, e.g. "example.com" equals to ``"\7example\3com"``. @@ -52,14 +53,21 @@ Example configuration end) -- Enforce local RPZ policy:add(policy.rpz(policy.DENY, 'blacklist.rpz')) + -- Forward all queries below 'company.se' to given resolver + policy:add(policy.suffix(policy.FORWARD('192.168.1.1'), {'\7company\2se'})) + -- Forward all queries matching pattern + policy:add(policy.pattern(policy.FORWARD('2001:DB8::1'), '\4bad[0-9]\2cz')) + -- Forward all queries (complete stub mode) + policy:add(policy.all(policy.FORWARD('2001:DB8::1'))) Properties ^^^^^^^^^^ -.. envvar:: policy.PASS (number) -.. envvar:: policy.DENY (number) -.. envvar:: policy.DROP (number) -.. envvar:: policy.TC (number) +.. envvar:: policy.PASS (number) +.. envvar:: policy.DENY (number) +.. envvar:: policy.DROP (number) +.. envvar:: policy.TC (number) +.. envvar:: policy.FORWARD (function) .. function:: policy:add(rule) @@ -68,6 +76,12 @@ Properties Policy to block queries based on the QNAME regex matching. +.. function:: policy.all(action) + + :param action: executed action for all queries + + Perform action for all queries (no filtering). + .. function:: policy.pattern(action, pattern) :param action: action if the pattern matches QNAME diff --git a/modules/policy/policy.lua b/modules/policy/policy.lua index eeed4c5f83bfa05239e724857e84044f4584d06b..f67f5526cc6b5dd2f40e4c7f02c3e343f73fac72 100644 --- a/modules/policy/policy.lua +++ b/modules/policy/policy.lua @@ -1,11 +1,30 @@ local kres = require('kres') + +-- Forward request, and solve as stub query +local function forward(target) + local dst_ip = kres.str2ip(target) + if dst_ip == nil then error("FORWARD target '"..target..'" is not a valid IP address') end + return function(state, req) + req = kres.request_t(req) + local qry = req:current() + qry.flags = qry.flags + kres.query.STUB + qry:nslist(dst_ip) + return state + end +end + local policy = { -- Policies - PASS = 1, DENY = 2, DROP = 3, TC = 4, + PASS = 1, DENY = 2, DROP = 3, TC = 4, FORWARD = forward, -- Special values ANY = 0, } +-- All requests +function policy.all(action) + return function(req, query) return action end +end + -- Requests which QNAME matches given zone list (i.e. suffix match) function policy.suffix(action, zone_list) local AC = require('aho-corasick') @@ -127,6 +146,8 @@ function policy.enforce(state, req, action) answer:tc(1) -- ^ Only UDP queries return kres.DONE end + elseif type(action) == 'function' then + return action(state, req) end return state end diff --git a/modules/view/README.rst b/modules/view/README.rst index 0aebb6825b9df09e46910d4c2d826914d49affd0..ffa264ebf23fcde6b7da36ff7719f933bc9a12f2 100644 --- a/modules/view/README.rst +++ b/modules/view/README.rst @@ -38,6 +38,8 @@ Example configuration view:addr('10.0.0.0/8', policy.suffix(policy.DROP, {'\3xxx'})) -- RPZ for subset of clients view:addr('192.168.1.0/24', policy.rpz(policy.PASS, 'whitelist.rpz')) + -- Forward all queries from given subnet to proxy + view:addr('10.0.0.0/8', policy.all(policy.FORWARD('2001:DB8::1'))) Properties ^^^^^^^^^^