.. SPDX-License-Identifier: GPL-3.0-or-later

.. _config-local-data:

Local Data and RPZ
==================

Local overrides for DNS data may be defined in the :option:`local-data <local-data:>` configuration tree.
It provides various input formats described in following subsections.

.. code-block:: yaml

   # Some typical use cases:
   local-data:
     addresses:
       a1.example.com: 2001:db8::1
       a2.example.org: [ 192.0.2.2, 192.0.2.3, 2001:db8::4 ]
     addresses-files:
       - /etc/hosts
     records: |
       www.google.com.  CNAME  forcesafesearch.google.com.
     rpz:
       - file: /tmp/blocklist.rpz


.. option:: local-data:

   .. option:: ttl: <time ms|s|m|h|d>

      Optional, this allows to write the new TTL value for records generated by the local-data.

   .. option:: nodata: true|false

      :default: true

      Enabling NODATA synthesis, false if disabling.
      If set to true (the default), an empty answer will be synthesised for matching name but mismatching type (e.g. AAAA query when only A hint exists).
      This setting also applies to normal records defined in RPZ files.

   Records
   -------

   The typical use case is to define some name-address pairs, which also generate corresponding
   `reverse PTR records <https://en.wikipedia.org/wiki/Reverse_DNS_lookup>`_.


   .. option:: addresses: <dict[hostname, address]>

      Optional, direct addition of hostname and IP address pairs.

   .. option:: addresses-files: <list of paths>

      Optional, direct addition of hostname and IP address pairs from files in ``/etc/hosts`` like format.

      .. code-block:: yaml

        local-data:
          addresses:
            a1.example.com: 2001:db8::1
            a2.example.com: 2001:db8::2
          addresses-files:
            - /etc/hosts
          # some options
          ttl: 5m
          nodata: false # don't force empty answer for missing record types on mentioned names

   .. option:: records: <zonefile format string>

      Optional, direct addition of records in DNS zonefile format.
      The zonefile syntax is more flexible, e.g. it can define any type of records.

      .. code-block:: yaml

        local-data:
          records: |
            www.google.com.  CNAME  forcesafesearch.google.com.
            example.com  TXT  "an example text record"
            34.example.com  AAAA  2001:db8::3
            34.example.com  AAAA  2001:db8::4

      If you want records from an actual file, e.g. because you have too many,
      we suggest using :ref:`config-local-data-rpz` just below,
      even if you do not need any additional behavior defined by RPZ.
      Same syntax of normal record definitions in RPZs will cause the same result.

   .. warning::

      While you can insert all kinds of records and rules into ``local-data:``,
      they won't work exactly as in real zones on authoritative servers.
      For example, wildcards won't get expanded and DNAMEs won't cause occlusion.

   .. _config-local-data-rpz:

   Response Policy Zones (RPZ)
   ---------------------------

   `RPZ <https://dnsrpz.info>`_ files are another way of adding rules.

   .. option:: rpz: <list>

      .. option:: file: <path>

         Path to a RPZ zonefile.

      .. option:: tags: <list of tags>

         Optional, restrict when this RPZ applies.  See :ref:`config-policy-new-tags`.

      .. option:: watchdog: auto | true | false 

         This option controls whether the RPZ file is automatically reloaded whenever it changes.

         That feature needs ``python-watchdog`` package to be present.

         - ``auto``: this is the default, watch the file if possible
         - ``true``: watch the file and fail config validation if dependency is missing
         - ``false``: don't watch the file

      .. option:: log: <list, subset of [ name, ip ]>

         Optional, indicate that each application of a rule should log the domain name
         triggering it and/or the requestor's IP.
         Logging is then done at the *notice* level.

         .. code-block::

            [rules ] => local data applied, user: ::1, name: foo.bar.93.100.in-addr.arpa.

      .. hide this for now
         .. option:: dry-run: <boolean, false by default>

            Do not apply these rules.  You want to combine this with ``log``.

   .. code-block:: yaml

      local-data:
        rpz:
          - file: /tmp/adult.rpz
            tags: [ adult ]
          # security blocklist applied for everyone
          - file: /tmp/security.rpz

   .. hide this for now
          # log these but do not block them
          - file: /tmp/suspicious.rpz
            dry-run: true
            log: [ name, ip ]

   So far, RPZ support is limited to the most common features:

   * just files which are *not* automatically reloaded when changed
   * rules with ``rpz-*`` labels are ignored, e.g. ``.rpz-client-ip``
   .. * ``CNAME *.some.thing`` does not expand the wildcard
   * wildcard support is limited to left-hand side of CNAME:
     ``*.some.name. CNAME .`` or ``*.some.name. CNAME *.`` or ``*.some.name. CNAME block.page.``

   Advanced rules
   --------------

   .. option:: rules: <list>

      This allows defining more complex sets of rules for records and subtrees.
      For example, it allows blocking whole subtrees.

      .. option:: name: <domain name or list>

         Optional, hostname(s)/subtree(s) to which the rule applies.

      .. option:: address: <address or list>

         Optional, IP address(es) to pair with hostname(s).

         .. code-block:: yaml

            local-data:
              rules:
                # hostname and IP address pair
                - name: a3.example.com
                  address: 2001:db8::3
                  tags: [example]
                  ttl: 10m

      .. option:: subtree: empty|nxdomain|redirect

         Optional, type of this subtree:

          - ``empty`` is an empty zone with just SOA and NS at the top
          - ``nxdomain`` replies ``NXDOMAIN`` everywhere, though in some cases that looks slightly weird
          - ``redirect`` answers with local-data records from the top of the zone, inside the whole virtual subtree

         .. code-block:: yaml

            local-data:
              rules:
                - name: [ evil.example.org, malware.example.net ]
                  subtree: empty
                  tags: [ malware ]
                - name: a5.example
                  subtree: redirect
                  address: 2001:db8::5

      .. option:: file: <path or list>

         Optional, direct addition of hostname and IP address pairs from files in ``/etc/hosts`` like format.

         .. code-block:: yaml

            local-data:
              rules:
                - file: custom.hosts
                  tags: [ malware ]
                  ttl: 20m
                  nodata: false

      .. option:: records: <zonefile format string>

         Optional, direct addition of records in DNS zonefile format.
         The zonefile syntax is more flexible, e.g. it can define any type of records.

         .. code-block:: yaml

            local-data:
              rules:
                - records: |
                    www.google.com.  CNAME  forcesafesearch.google.com.
                  tags: [ adult ]

         If you want records from an actual file, e.g. because you have too many,
         we suggest using :ref:`config-local-data-rpz`,
         even if you do not need any additional behavior defined by RPZ.
         Same syntax of normal record definitions in RPZs will cause the same result.

      .. option:: tags: <list of tags>

         Optional, restrict when this rule applies.  See :ref:`config-policy-new-tags`.

      .. option:: ttl: <time s|m|h|d>

         Optional, TTL of answers from this rule.  Uses ``/local-data/ttl`` if unspecified.

      .. option:: nodata: true|false

         Optional, enabling NODATA synthesis, false if disabling. Uses ``/local-data/nodata`` if unspecified.
         If set to true, an empty answer will be synthesised for matching name but mismatching type (e.g. AAAA query when only A hint exists).

   .. future
      .. option:: addresses: <list of addresses>

         Optional, subtree addresses.

      One of, :option:`roots <roots: <list of hostnames>>`, :option:`roots-file <roots-file: <path>>` or :option:`roots-url <roots-url: <url>>` must be configured.

      .. option:: roots: <list of hostnames>

         Subtree roots.

      .. option:: roots-file: <path>

         Subtree roots from given file.

      .. option:: roots-url: <url>

         Subtree roots from given URL.

      .. option:: refresh: <time ms|s|m|h|d>

         Refresh time to update data from :option:`roots-file <roots-file: <path>>` or :option:`roots-url <roots-url: <url>>`.
