pointsize
polarssl
policyactions
+policyevent
policykinds
policyname
pollmplexer
Frequently, Response Policy Zones get to be very large and change quickly, so it is customary to update them over IXFR.
It allows the use of third-party feeds, and near real-time policy updates.
+Evaluation order
+----------------
+
If multiple RPZs are loaded, they get consulted in the order they were
defined in. It is however possible from Lua to make queries skip specific
Response Policy Zones.
+The evaluation order of RPZ policies is not always straightforward. Before 4.4.0, the recursor first checked whether the source address of the client matched a "Client IP Address" filter
+in any RPZ zones, then if the qname matched a "QNAME" trigger. It would then start the regular resolution process and check whether any "NSDNAME" or "NSIP" rule was triggered, then after the resolution process was done check whether any of the final records matched a "Response IP Address" rule.
+It would stop as soon as a match was found and apply the requested decision immediately, unless the decision was a "passthru". In that last case it would resume the normal processing but would only evaluate the rules coming from a policy with a higher order than the one that matched.
+
+Since 4.4.0 the behaviour is a bit different, to better follow the RPZ specifications. The source address of the client is still checked first. Then the normal resolution process starts and the initial qname as well as any CNAME part of the chain starting from the qname is checked against "QNAME" rules. "NSDNAME" and "NSIP" rules are still checked during the remaining part of the process, and "Response IP Address" rules are applied to the final records in the end.
+This matches the precedence rules from the RPZ specifications that specify that "A policy rule match which occurs at an earlier stage of resolution is preferred to a policy rule match which occurs at a later stage".
+For compatibility reasons, 4.4.0 still evaluates policy rules of higher order after a "passthru", even though the section 5.1 of the RPZ specifications seems to deny that behaviour: "Recall that only one policy rule, from among all those matched at all stages of resolving a CNAME or DNAME chain, can affect the final response; this is true even if the selected rule has a PASSTHRU action".
+
+Note that "RPZ rules do not apply to synthetic data generated by using RPZ rules. For example, if RPZ supplies a CNAME pointing to a walled garden, RPZ policies will not be used while following that CNAME. If RPZ supplies local data giving a particular A record, RPZ policies will not apply to that response IP address", as stated in section 6.1 of the RPZ specifications.
+
Configuring RPZ
---------------
An RPZ can be loaded from file or slaved from a master. To load from file, use for example:
Intercepting queries with Lua
=============================
+
To get a quick start, we have supplied a sample script that showcases all functionality described below.
Please find it `here <https://github.com/PowerDNS/pdns/blob/master/pdns/recursordist/contrib/powerdns-example-script.lua>`_.
- after the resolving process failed to find a correct answer for a domain (:func:`nodata`, :func:`nxdomain`)
- after the whole process is done and an answer is ready for the client (:func:`postresolve`)
- before an outgoing query is made to an authoritative server (:func:`preoutquery`)
+- after a filtering policy hit has occurred (:func:`policyEventFilter`)
Writing Lua PowerDNS Recursor scripts
-------------------------------------
:param DNSQuestion dq: The DNS question to handle
+.. function:: policyEventFilter(event)
+
+ .. versionadded:: 4.4.0
+
+ This hook is called when a filtering policy has been hit, before the decision has been applied, making it possible to change a policy decision by altering its content or to skip it entirely.
+ Using the :meth:`event:discardPolicy() <PolicyEvent:discardPolicy>` function, it is also possible to selectively disable one or more filtering policy, for example RPZ zones.
+ The return value indicates whether the policy hit should be completely ignored (true) or applied (false), possibly after editing the action to take in that latter case (see :ref:`modifyingpolicydecisions` below). when true is returned, the resolution process will resume as if the policy hit never took place.
+
+ As an example, to ignore the result of a policy hit for the example.com domain:
+
+ .. code-block:: Lua
+
+ function policyEventFilter(event)
+ if event.qname:equal("example.com") then
+ -- ignore that policy hit
+ return true
+ end
+ return false
+ end
+
+ To alter the decision of the policy hit instead:
+
+ .. code-block:: Lua
+
+ function policyEventFilter(event)
+ if event.qname:equal("example.com") then
+ -- replace the decision with a custom CNAME
+ event.appliedPolicy.policyKind = pdns.policykinds.Custom
+ event.appliedPolicy.policyCustom = "example.net"
+ -- returning false so that the hit is not ignored
+ return false
+ end
+ return false
+ end
+
+ :param :class:`PolicyEvent` event: The event to handle
+
Semantics
^^^^^^^^^
The functions must return ``true`` if they have taken over the query and wish that the nameserver should not proceed with its regular query-processing.
The :func:`ipfilter` and :func:`preoutquery` hooks are different, in that :func:`ipfilter` can only return a true of false value, and that :func:`preoutquery` can also set rcode -3 to signify that the whole query should be terminated.
+The func:`policyEventFilter` has a different meaning as well, where returning true means that the policy hit should be ignored and normal processing should be resumed.
+
A minimal sample script:
.. code-block:: Lua
Starting with version 4.0.1 of the recursor, it is possible to alter this decision inside the Lua hooks.
If the decision is modified in a Lua hook, ``false`` should be returned, as the query is not actually handled by Lua so the decision is picked up by the Recursor.
-The result of the policy decision is checked after :func:`preresolve` and :func:`postresolve`.
+The result of the policy decision is checked after :func:`preresolve` and :func:`postresolve` before 4.4.0. Beginning with version 4.4.0, the policy decision is checked after :func:`preresolve` and any :func:`policyEventFilter` call instead.
For example, if a decision is set to ``pdns.policykinds.NODATA`` by the policy engine and is unchanged in :func:`preresolve`, the query is replied to with a NODATA response immediately after :func:`preresolve`.
dnsrecord
comboaddress
netmask
+ policyevent
statistics
logging
hooks
--- /dev/null
+.. _scripting-policyevent:
+
+Policy Events
+=============
+
+Since 4.4.0, the Lua hook :func:`policyEventFilter` is called along with a :class:`PolicyEvent` object whenever a filtering policy matches.
+
+PolicyEvent class
+------------------
+
+.. class:: PolicyEvent
+
+ Represents an event related to a filtering policy.
+
+ .. method:: PolicyEvent:addPolicyTag(tag)
+
+ Add policyTag ``tag`` to the list of policyTags.
+
+ :param str tag: The tag to add
+
+ .. method:: PolicyEvent:getPolicyTags() -> {str}
+
+ Get the current policy tags as a table of strings.
+
+ .. method:: PolicyEvent:setPolicyTags(tags)
+
+ Set the policy tags to ``tags``, overwriting any existing policy tags.
+
+ :param {str} tags: The policy tags
+
+ .. method:: PolicyEvent:discardPolicy(policyname)
+
+ Skip the filtering policy (for example RPZ) named ``policyname`` for this query.
+
+ :param str policyname: The name of the policy to ignore.
+
+ .. attribute:: PolicyEvent.appliedPolicy
+
+ The decision that was made by the policy engine, see :ref:`modifyingpolicydecisions`.
+
+ .. attribute:: PolicyEvent.appliedPolicy.policyName
+
+ A string with the name of the policy.
+ Set by :ref:`policyName <rpz-policyName>` in the :func:`rpzFile` and :func:`rpzMaster` configuration items.
+ It is advised to overwrite this when modifying the :attr:`PolicyEvent.appliedPolicy.policyKind`
+
+ .. attribute:: PolicyEvent.appliedPolicy.policyAction
+
+ The action taken by the engine
+
+ .. attribute:: PolicyEvent.appliedPolicy.policyCustom
+
+ The CNAME content for the ``pdns.policyactions.Custom`` response, a string
+
+ .. attribute:: PolicyEvent.appliedPolicy.policyKind
+
+ The kind of policy response, there are several policy kinds:
+
+ - ``pdns.policykinds.Custom`` will return a NoError, CNAME answer with the value specified in :attr:`PolicyEvent.appliedPolicy.policyCustom`
+ - ``pdns.policykinds.Drop`` will simply cause the query to be dropped
+ - ``pdns.policykinds.NoAction`` will continue normal processing of the query
+ - ``pdns.policykinds.NODATA`` will return a NoError response with no value in the answer section
+ - ``pdns.policykinds.NXDOMAIN`` will return a response with a NXDomain rcode
+ - ``pdns.policykinds.Truncate`` will return a NoError, no answer, truncated response over UDP. Normal processing will continue over TCP
+
+ .. attribute:: PolicyEvent.appliedPolicy.policyTTL
+
+ The TTL in seconds for the ``pdns.policyactions.Custom`` response
+
+ .. attribute:: PolicyEvent.qname
+
+ :class:`DNSName` of the name the query is for.
+
+ .. attribute:: PolicyEvent.qtype
+
+ Type the query is for as an integer, can be compared against ``pdns.A``, ``pdns.AAAA``.
+
+ .. attribute:: PolicyEvent.isTcp
+
+ Whether the query was received over TCP.
+
+ .. attribute:: PolicyEvent.remote
+
+ :class:`ComboAddress` of the requestor.
+