From 530ed8df76eabd181413260239716fe470eaa3e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Vavru=C5=A1a?= <marek.vavrusa@nic.cz> Date: Wed, 28 Oct 2015 16:38:24 +0100 Subject: [PATCH] modules/policy+view: new policy.FORWARD(dst) and policy.all matching rule this is Unbound's 'forward-zone' on steroids --- modules/policy/README.rst | 22 ++++++++++++++++++---- modules/policy/policy.lua | 23 ++++++++++++++++++++++- modules/view/README.rst | 2 ++ 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/modules/policy/README.rst b/modules/policy/README.rst index 40edc49c1..a0af187ba 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 eeed4c5f8..f67f5526c 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 0aebb6825..ffa264ebf 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 ^^^^^^^^^^ -- GitLab