From 9635aa40baadef401d2138f745416e5b3afb4fa0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Vladim=C3=ADr=20=C4=8Cun=C3=A1t?= Date: Wed, 2 Aug 2017 11:31:12 +0200 Subject: [PATCH] policy docs: rework it all - greatly reduce duplication - mainly actions and filters that were described on two separate places - try to improve readability etc. --- modules/policy/README.rst | 133 ++++++++++++-------------------------- 1 file changed, 43 insertions(+), 90 deletions(-) diff --git a/modules/policy/README.rst b/modules/policy/README.rst index a0dca4323..b5a527d10 100644 --- a/modules/policy/README.rst +++ b/modules/policy/README.rst @@ -4,41 +4,47 @@ Query policies -------------- This module can block, rewrite, or alter inbound queries based on user-defined policies. -By default, it blocks queries to reverse lookups in private subnets as per :rfc:`1918`, :rfc:`5735` and :rfc:`5737`. -You can however extend it to deflect `Slow drip DNS attacks `_ for example, or gray-list resolution of misbehaving zones. +By default, if no rule applies to a query, rules for special-use domain names are applied, as required by :rfc:`6761`. -There are several policies implemented: +You can however extend it e.g. to deflect `Slow drip DNS attacks `_ or gray-list resolution of misbehaving zones. -* ``pattern`` - - applies action if QNAME matches `regular expression `_ -* ``suffix`` - - applies action if QNAME suffix matches given list of suffixes (useful for "is domain in zone" rules), +There are several policy filters available in the ``policy.`` table: + +* ``all(action)`` + - always applies the action +* ``pattern(action, pattern)`` + - applies the action if QNAME matches a `regular expression `_ +* ``suffix(action, table)`` + - applies the action if QNAME suffix matches one of suffixes in the table (useful for "is domain in zone" rules), uses `Aho-Corasick`_ string matching algorithm implemented by `@jgrahamc`_ (CloudFlare, Inc.) (BSD 3-clause) +* :any:`policy.suffix_common` * ``rpz`` - - implementes a subset of the RPZ_ format. Currently it can be used with a zonefile, a binary database support is on the way. Binary database can be updated by an external process on the fly. + - implements a subset of RPZ_ in zonefile format. See below for details: :any:`policy.rpz`. * custom filter function -There are several defined actions: +There are several actions available in the ``policy.`` table: -* ``PASS`` - let the query pass through -* ``DENY`` - return NXDOMAIN answer -* ``DROP`` - terminate query resolution, returns SERVFAIL to requestor +* ``PASS`` - let the query pass through; it's useful to make exceptions before wider rules +* ``DENY`` - reply NXDOMAIN authoritatively +* ``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)`` - solve a query via forwarding to an IP while validating and caching locally; the parameter can be a single IP (string) or a lua list of up to four IPs. * ``STUB(ip)`` - similar to ``FORWARD(ip)`` but *without* attempting DNSSEC validation. Each request may be either answered from cache or simply sent to one of the IPs with proxying back the answer. -* ``MIRROR(ip)`` - mirror query to given IP and continue solving it (useful for partial snooping) +* ``MIRROR(ip)`` - mirror query to given IP and continue solving it (useful for partial snooping); it's a chain action * ``REROUTE({{subnet,target}, ...})`` - reroute addresses in response matching given subnet to given target, e.g. ``{'192.0.2.0/24', '127.0.0.0'}`` will rewrite '192.0.2.55' to '127.0.0.55', see :ref:`renumber module ` for more information. -* ``QTRACE`` - pretty-print DNS response packets into the log (useful for debugging weird DNS servers). -* ``FLAGS(set, clear)`` - set and/or clear some flags for the query. There can be multiple flags to set/clear, combined by ``bit.bor`` from ``kres.query.*`` values. +* ``QTRACE`` - pretty-print DNS response packets into the log for the query and its sub-queries. It's useful for debugging weird DNS servers. It's a chain action. +* ``FLAGS(set, clear)`` - set and/or clear some flags for the query. There can be multiple flags to set/clear, combined by ``bit.bor`` from ``kres.query.*`` values. It's a chain action. + +Most actions stop the policy matching on the query, but "chain actions" allow to keep trying to match other rules, until a non-chain action is triggered. .. warning:: The policy module currently only looks at whole DNS requests. The rules won't be re-applied e.g. when following CNAMEs. .. note:: The module (and ``kres``) expects domain names in wire format, not textual representation. So each label in name is prefixed with its length, e.g. "example.com" equals to ``"\7example\3com"``. You can use convenience function ``todname('example.com')`` for automatic conversion. -Example configuration -^^^^^^^^^^^^^^^^^^^^^ +Examples +^^^^^^^^ .. code-block:: lua @@ -66,101 +72,48 @@ Example configuration policy.add(policy.suffix(policy.FORWARD('192.168.1.1'), {todname('company.se')})) -- 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'))) + -- Forward all queries (to public resolvers https://www.nic.cz/odvr) + policy.add(policy.all(policy.FORWARD({'2001:678:1::206', '193.29.206.206'}))) -- Print all responses with matching suffix policy.add(policy.suffix(policy.QTRACE, {todname('rhybar.cz.')})) -- Print all responses policy.add(policy.all(policy.QTRACE)) - -- Mirror all queries and retrieve information - local rule = policy.add(policy.all(policy.MIRROR('127.0.0.2'))) - -- Print information about the rule - print(string.format('id: %d, matched queries: %d', rule.id, rule.count) - -- Reroute all addresses found in answer from 192.0.2.0/24 to 127.0.0.x - -- this policy is enforced on answers, therefore 'postrule' - local rule = policy.add(policy.REROUTE({'192.0.2.0/24', '127.0.0.0'}), true) - -- Delete rule that we just created - policy.del(rule.id) - -Properties -^^^^^^^^^^ - -.. envvar:: policy.PASS - - Pass-through all queries matching the rule. - -.. envvar:: policy.DENY - - Respond with NXDOMAIN to all queries matching the rule. - -.. envvar:: policy.DROP - - Drop all queries matching the rule. - -.. envvar:: policy.TC - - Respond with empty answer with TC bit set (if the query came through UDP). - -.. envvar:: policy.FORWARD (address) - - Forward query to given IP address. - -.. envvar:: policy.MIRROR (address) - - Forward query to given IP address. - -.. envvar:: policy.REROUTE({{subnet,target}, ...}) - - Reroute addresses in response matching given subnet to given target, e.g. ``{'192.0.2.0/24', '127.0.0.0'}`` will rewrite '192.0.2.55' to '127.0.0.55'. - -.. envvar:: policy.QTRACE + -- Mirror all queries and retrieve information + local rule = policy.add(policy.all(policy.MIRROR('127.0.0.2'))) + -- Print information about the rule + print(string.format('id: %d, matched queries: %d', rule.id, rule.count) + -- Reroute all addresses found in answer from 192.0.2.0/24 to 127.0.0.x + -- this policy is enforced on answers, therefore 'postrule' + local rule = policy.add(policy.REROUTE({'192.0.2.0/24', '127.0.0.0'}), true) + -- Delete rule that we just created + policy.del(rule.id) + +Additional properties +^^^^^^^^^^^^^^^^^^^^^ - Print pretty-formate (dig-like) DNS answers for current query and - all its subqueries that Knot Resolver receive from upstream - (authoritative) DNS servers. Very useful when dealing with - non-compliant DNS servers that violate DNS protocol. +Most properties (actions, filters) are described above. .. function:: policy.add(rule, postrule) :param rule: added rule, i.e. ``policy.pattern(policy.DENY, '[0-9]+\2cz')`` :param postrule: boolean, if true the rule will be evaluated on answer instead of query :return: rule description - + Add a new policy rule that is executed either or queries or answers, depending on the ``postrule`` parameter. You can then use the returned rule description to get information and unique identifier for the rule, as well as match count. .. function:: policy.del(id) :param id: identifier of a given rule :return: boolean - - Remove a rule from policy list. -.. 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 - :param pattern: regular expression - - Policy to block queries based on the QNAME regex matching. - -.. function:: policy.suffix(action, suffix_table) - - :param action: action if the pattern matches QNAME - :param suffix_table: table of valid suffixes - - Policy to block queries based on the QNAME suffix match. + Remove a rule from policy list. .. function:: policy.suffix_common(action, suffix_table[, common_suffix]) :param action: action if the pattern matches QNAME :param suffix_table: table of valid suffixes :param common_suffix: common suffix of entries in suffix_table - + Like suffix match, but you can also provide a common suffix of all matches for faster processing (nil otherwise). This function is faster for small suffix tables (in the order of "hundreds"). @@ -168,7 +121,7 @@ Properties :param action: the default action for match in the zone (e.g. RH-value `.`) :param path: path to zone file | database - + Enforce RPZ_ rules. This can be used in conjunction with published blocklist feeds. The RPZ_ operation is well described in this `Jan-Piet Mens's post`_, or the `Pro DNS and BIND`_ book. Here's compatibility table: @@ -195,7 +148,7 @@ Properties .. function:: policy.todnames({name, ...}) :param: names table of domain names in textual format - + Returns table of domain names in wire format converted from strings. .. code-block:: lua -- 2.47.3