]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
docs: quick start documentation first draft
authorAles Mrazek <ales.mrazek@nic.cz>
Wed, 11 Sep 2019 12:34:25 +0000 (14:34 +0200)
committerPetr Špaček <petr.spacek@nic.cz>
Mon, 23 Dec 2019 18:54:24 +0000 (19:54 +0100)
doc/daemon.rst
doc/index.rst
doc/modules_api.rst
doc/startguide.rst [new file with mode: 0644]
modules/policy/README.rst

index dbeecabfa9755cac060255c1d7fd96987becad72..6d20ee3ac51f613183dc2f17211f472260e5aa23 100644 (file)
@@ -1 +1,3 @@
+.. _daemon:
+
 .. include:: ../daemon/README.rst
\ No newline at end of file
index b8b56ccec25750e0f9763c00612669873672ac38..a5e2fee0842122d5c88ec6ba60a957dd24cce536 100644 (file)
@@ -6,6 +6,14 @@ Knot Resolver is a minimalistic implementation of a caching validating DNS resol
 Modular architecture keeps the core tiny and efficient,
 and it provides a state-machine like API for extensions.
 
+
+.. toctree::
+   :caption: Quick Start
+   :name: quickstart
+   :maxdepth: 2
+
+   startguide
+
 .. toctree::
    :caption: Users
    :name: users
index 2f0f14738561e3f68e426358975509320ed529a4..6e08c171b3c20d4276f5824695218c93e0d371d0 100644 (file)
@@ -1 +1,3 @@
+.. _modules:
+
 .. include:: ../modules/README.rst
\ No newline at end of file
diff --git a/doc/startguide.rst b/doc/startguide.rst
new file mode 100644 (file)
index 0000000..3059725
--- /dev/null
@@ -0,0 +1,580 @@
+.. _startguide:
+
+************
+Installation
+************
+
+- :ref:`build`
+- `All downloadable packages <https://secure.nic.cz/files/knot-resolver>`_
+
+
+.. Warning::
+
+    Packages available in distribution's repositories are often outdated,
+    especially in **Debian** and **Ubuntu** repositories.
+
+We recommend using these official upstream repositories with the **latest version** of Knot Resolver.
+
+**Debian/Ubuntu**
+
+.. code-block:: bash
+
+    ~$ wget https://secure.nic.cz/files/knot-resolver/knot-resolver-release.deb
+    ~$ dpkg -i knot-resolver-release.deb
+    ~$ apt update && apt install -y knot-resolver
+
+**CentOS**
+
+.. code-block:: bash
+
+    ~$ yum install -y https://secure.nic.cz/files/knot-resolver/knot-resolver-release.el.rpm
+    ~$ yum install -y knot-resolver
+
+**Fedora**
+
+.. code-block:: bash
+
+    ~$ dnf install -y https://secure.nic.cz/files/knot-resolver/knot-resolver-release.fedora.rpm
+    ~$ dnf install -y knot-resolver
+
+**OpenSUSE Leap / Tumbleweed**
+
+Add the *OBS* package repository `home:CZ-NIC:knot-resolver-latest <https://build.opensuse.org/package/show/home:CZ-NIC:knot-resolver-latest/knot-resolver>`_ to your system.
+
+**Arch Linux**
+
+`Knot-resolver <https://aur.archlinux.org/packages/knot-resolver/>`_
+package is maintained in **AUR**. It can be installed by using AUR helper,
+for instance, ``yay``
+
+.. code-block:: bash
+
+    ~$ yay -S knot-resolver
+
+
+*************
+Configuration
+*************
+
+.. contents::
+   :depth: 1
+   :local:
+
+**Detailed configuration of daemon and modules.**
+
+- :ref:`Daemon configuration <daemon>`
+- :ref:`Modules configuration <modules>`
+
+.. note::
+
+   The configuration syntax is **Lua** language.
+
+**Startup configuration**
+
+To set startup configuration, paste required configuration to ``/etc/knot-resolver/kresd.conf``
+configuration file or run Knot Resolver with ``-c`` parameter to set path to configuration file.
+
+**Interactive / Dynamic configuration**
+
+Every Knot Resolver instance has its own *unix domain socket*.
+
+For instance, you start Knot Resolver using systemd
+
+.. code-block:: bash
+
+    ~$ systemctl start kresd@1.service
+
+
+Then the related unix domain socket will be available on ``/run/knot-resolver/control@1``
+
+Connection to the socket can be made by ``socat`` or ``netcat`` through command line
+
+.. code-block:: bash
+
+    ~$ socat - /run/knot-resolver/control@1
+    ~$ nc -U /run/knot-resolver/control@1
+
+When successfully connected to a socket, the command line should change to something like ``>``.
+Then you can interact with Knot Resolver to list configuration or set a new one.
+
+There are some useful commands.
+
+.. code-block:: bash
+
+    > help()            # shows help
+    > net.interfaces()  # lists available interfaces
+    > net.list()        # lists running network services
+
+==================
+Bind to interfaces
+==================
+
+Knot Resolver can listen on multiple interfaces that are defined in configuration.
+
+.. code-block:: lua
+
+    net = {'192.168.1.1','fc00::1:1'}
+
+Default port is ``53``. Port can be specified by separating it by ``@`` from ip address. For example ``'127.0.0.1@5353'``.
+
+
+Available interfaces can be listed
+
+.. code-block:: bash
+
+   > net.interfaces()
+   [eth1] => {
+      [addr] => {
+         [1] => 192.168.1.1
+         [2] => fc00::1:1
+         [4] => fe80::1:1
+      }
+   }
+   [lo] => {
+      [addr] => {
+         [1] => 127.0.0.1
+         [2] => ::1
+      }
+   }
+
+``net.eth1.addr[1]`` refers to ``192.168.1.1`` and ``net.eth1.addr[2]`` refers to ``fc00::1:1``
+
+.. code-block:: lua
+
+    net = {net.eth1.addr[1],net.eth1.addr[2]}
+
+.. warning::
+
+    On machines with multiple IP addresses avoid listening on wildcards ``0.0.0.0`` or ``::``.
+    Knot Resolver could answer from different IP addresses if the network address ranges
+    overlap, and clients would probably refuse such a response.
+
+
+=================
+Internal Resolver
+=================
+
+How to configure Knot Resolver to resolve internal-only domain.
+
+Forward internal-only domain
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For instance, ``company.example`` is the internal-only domain which is not available from the public Internet.
+To resolve internal-only domain, e.g. ``company.exmaple`` a query policy to forward query has to be added.
+The followind example will add query policy that will trigger ``FORWARD`` action based on suffix of a domain.
+This configuration will forward everything below ``company.example`` domain to ``192.168.1.2`` IP address, port ``443``.
+
+.. code-block:: lua
+
+    -- policy module is required for query policy configuration
+    modules = { 'policy' }
+
+    -- forward all queries below 'company.example' to '192.168.1.2@443'
+    policy.add(policy.suffix(policy.FORWARD('192.168.1.2@443'), {todname('company.example')}))
+
+
+Example ``kresd.conf``
+^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: lua
+
+    -- bind to interfaces
+    net = {'192.168.1.1','fc00::1:1'}
+
+    -- load policy module
+    modules = { 'policy' }
+
+    -- forward all queries below suffix 'company.example' to '192.168.1.2@443'
+    policy.add(policy.suffix(policy.FORWARD('192.168.1.2@443'), {todname('company.example')}))
+
+
+.. _personalresolver:
+
+====================================
+Personal privacy-preserving Resolver
+====================================
+
+TLS server configuration
+^^^^^^^^^^^^^^^^^^^^^^^^
+.. Warning::
+
+    By default a self-signed certificate is generated.
+    For serious deployments it is strongly recommended to
+    configure your own TLS certificates signed by a trusted CA.
+    This can be done by using function ``net.tls()``.
+
+.. code-block:: lua
+
+    net.tls("/etc/knot-resolver/server-cert.pem", "/etc/knot-resolver/server-key.pem")
+
+Calling this function without parameters prints configured TLS paths.
+
+Forwarding over TLS protocol (DNS-over-TLS)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+More examples on :ref:`tls-examples`.
+
+CA+hostname authentication
+``````````````````````````
+Traditional PKI authentication requires server to present certificate
+with specified hostname, which is issued by one of trusted CAs.
+
+.. code-block:: lua
+
+    -- forward all queries over TLS to the specified server
+    policy.add(policy.all(
+       policy.TLS_FORWARD({
+          {'2001:DB8::d0c', hostname='res.example.com', ca_file='/etc/knot-resolver/tlsca.crt'}
+       })
+    ))
+
+Key-pinned authentication
+``````````````````````````
+Instead of CAs, you can specify hashes of accepted certificates in ``pin_sha256``.
+They are in the usual format -- base64 from sha256.
+You may still specify ``hostname`` if you want SNI_ to be sent.
+
+.. code-block:: lua
+
+    -- forward all queries over TLS to the specified server
+    policy.add(policy.all(
+       policy.TLS_FORWARD({
+          {'192.0.2.1', pin_sha256={'YQ=='}
+       })
+    ))
+
+Forwarding to multiple targets
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+With the use of :any:`policy.slice` function, it is possible to split the
+entire DNS namespace into distinct slices. When used in conjunction with
+``policy.TLS_FORWARD``, it's possible to forward different queries to different
+targets.
+
+.. code-block:: lua
+
+    policy.add(policy.slice(
+       policy.slice_randomize_psl(),
+       policy.TLS_FORWARD({{'192.0.2.1', hostname='res.example.com'}}),
+       -- multiple servers can be specified for a single slice
+       -- the one with lowest round-trip time will be used
+       policy.TLS_FORWARD({
+          {'193.17.47.1', hostname='odvr.nic.cz'},
+          {'185.43.135.1', hostname='odvr.nic.cz'},
+       })
+    ))
+
+Moving cache to tmpfs
+^^^^^^^^^^^^^^^^^^^^^
+Moving cache to temporary file storage.
+Data is stored in volatile memory instead of a persistent storage device.
+On reboot, everything stored in *tmpfs* will be lost.
+
+For example, in most of the Unix-like systems ``/tmp``, ``/var/lock`` and ``/var/run`` are commonly *tmpfs*.
+You can check file system type by ``df -T /tmp`` command.
+
+Move cache storage to ``/tmp/knot-resolver``
+
+.. code-block:: lua
+
+   cache.storage = 'lmdb:///tmp/knot-resolver'
+
+Check cache storage
+
+.. code-block:: bash
+
+   > cache.current_storage
+   lmdb:///tmp/knot-resolver
+
+Example ``kresd.conf``
+^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: lua
+
+   -- bind to interfaces
+   net = {'192.168.1.1','fc00::1:1'}
+
+   -- configure TLS server
+   net.tls(net.tls("/etc/knot-resolver/server-cert.pem", "/etc/knot-resolver/server-key.pem"))
+
+   -- Move cache to '/tmp/knot-resolver' tmpfs
+   cache.storage = 'lmdb:///tmp/knot-resolver'
+
+   -- load policy module
+   modules = { 'policy' }
+
+   -- forward over TLS
+   policy.add(policy.all(
+       policy.TLS_FORWARD({
+          {'2001:DB8::d0c', hostname='res.example.com', ca_file='/etc/knot-resolver/tlsca.crt'},
+          {'192.0.2.1', pin_sha256={'YQ=='}
+       })
+    ))
+
+   -- forwarding to multiple targets
+   policy.add(policy.slice(
+       policy.slice_randomize_psl(),
+       policy.TLS_FORWARD({{'192.0.2.1', hostname='res.example.com'}}),
+       -- multiple servers can be specified for a single slice
+       -- the one with lowest round-trip time will be used
+       policy.TLS_FORWARD({
+          {'193.17.47.1', hostname='odvr.nic.cz'},
+          {'185.43.135.1', hostname='odvr.nic.cz'},
+       })
+    ))
+
+.. _ispresolver:
+
+============
+ISP Resolver
+============
+
+Limiting client access
+^^^^^^^^^^^^^^^^^^^^^^
+More on :ref:`mod-view`
+
+The current implementation is best understood as three separate rule chains:
+vanilla :func:`policy.add()`, :func:`view:tsig()` and :func:`view:addr`.
+For each request the rules in these chains get tried one by one until a non-chain
+policy action gets executed.
+
+View module allows you to combine query source information with policy rules.
+
+.. code-block:: lua
+
+    modules = { 'view' }
+
+    -- Block local IPv4 clients (ACL like)
+    view:addr('127.0.0.1', policy.all(policy.DENY))
+
+    -- Drop queries with suffix match for remote client
+    view:addr('10.0.0.0/8', policy.suffix(policy.TC, policy.todnames({'example.com'})))
+
+    -- Whitelist queries identified by TSIG key
+    view:tsig('\5mykey', policy.all(policy.PASS))
+
+
+Mandatory domain blocking
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+RPZ
+```
+DNS Response Policy Zones Blacklist
+
+.. code-block:: lua
+
+   policy.add(policy.rpz(policy.DENY, 'blacklist.rpz'))
+
+
+Hand-made
+`````````
+Hand-made Blacklist
+
+.. code-block:: lua
+
+   --
+
+Max cache size
+^^^^^^^^^^^^^^
+Maximal cache size can be larger than available RAM,
+least frequently accessed records will be paged out.
+For large cache size we don't need to flush cache often.
+
+.. code-block:: lua
+
+   cache.size = 4 * GB
+
+
+Statistics
+^^^^^^^^^^
+
+Worker is a service over event loop that tracks and schedules outstanding queries,
+you can see the statistics or schedule new queries.
+
+.. code-block:: lua
+
+   -- return table of worker statistics
+   > worker.stats()
+
+   -- return table of low-level cache statistics
+   > cache.stats()
+
+
+``worker.stats() cache.stats()`` commands can be executed synchronously over all forks.
+Results are returned as a table ordered as forks.
+Expression inserted to ``map ''`` can be any valid expression in Lua.
+
+.. code-block:: lua
+
+    > map 'worker.stats()'
+
+
+:ref:`mod-stats` gathers various counters from the query resolution and server internals,
+and offers them as a key-value storage :func:`stats.list()`.
+
+.. code-block:: lua
+
+    -- Statistics collector is a module
+    > modules.load('stats')
+
+    -- Enumerate metrics
+    > stats.list()
+
+
+Monitoring/logging
+^^^^^^^^^^^^^^^^^^
+
+Lua supports a concept called `closures`_, this is extremely useful for scripting actions upon various events,
+say for example - publish statistics each minute and so on.
+Here's an example of an anonymous function with :func:`event.recurrent()`.
+
+.. note::
+
+    Each scheduled event is identified by a number valid for the duration of the event,
+    you may use it to cancel the event at any time.
+
+.. code-block:: lua
+
+    -- load module for statistics
+    modules.load('stats')
+
+    -- log statistics every second
+    local stat_id = event.recurrent(1 * second, function(evid)
+        log(table_print(stats.list()))
+    end)
+
+    -- stop printing statistics after first minute
+    event.after(1 * minute, function(evid)
+            event.cancel(stat_id)
+    end)
+
+If you need to persist state between events, encapsulate even handle in closure
+function which will provide persistent variable (called ``previous``):
+
+.. code-block:: lua
+
+    modules.load('stats')
+
+    -- make a closure, encapsulating counter
+    function speed_monitor()
+            local previous = stats.list()
+            -- monitoring function
+            return function(evid)
+                    local now = stats.list()
+                    local total_increment = now['answer.total'] - previous['answer.total']
+                    local slow_increment = now['answer.slow'] - previous['answer.slow']
+                    if slow_increment / total_increment > 0.05 then
+                            log('WARNING! More than 5 %% of queries was slow!')
+                    end
+                    previous = now  -- store current value in closure
+             end
+    end
+
+    -- speed monitor every minute
+    local monitor_id = event.recurrent(1 * minute, speed_monitor())
+
+
+Example ``kresd.conf``
+^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: lua
+
+    -- bind to interfaces
+    net = {'192.168.1.1','fc00::1:1'}
+
+    -- set max cache size
+    cache.size = 4 * GB
+
+    -- modules
+    modules = {
+        'view',
+        'stats'
+    }
+
+    -- log statistics every second
+    local stat_id = event.recurrent(1 * second, function(evid)
+        log(table_print(stats.list()))
+    end)
+
+    -- stop printing statistics after first minute
+    event.after(1 * minute, function(evid)
+            event.cancel(stat_id)
+    end)
+
+    -- make a closure, encapsulating counter
+    function speed_monitor()
+            local previous = stats.list()
+            -- monitoring function
+            return function(evid)
+                    local now = stats.list()
+                    local total_increment = now['answer.total'] - previous['answer.total']
+                    local slow_increment = now['answer.slow'] - previous['answer.slow']
+                    if slow_increment / total_increment > 0.05 then
+                            log('WARNING! More than 5 %% of queries was slow!')
+                    end
+                    previous = now  -- store current value in closure
+             end
+    end
+
+    -- speed monitor every minute
+    local monitor_id = event.recurrent(1 * minute, speed_monitor())
+
+    -- Apply RPZ for all clients, default rule is DENY
+    policy.add(policy.rpz(policy.DENY, 'blacklist.rpz'))
+
+    -- Block local IPv4 clients (ACL like)
+    view:addr('127.0.0.1', policy.all(policy.DENY))
+
+    -- Drop queries with suffix match for remote client
+    view:addr('10.0.0.0/8', policy.suffix(policy.TC, policy.todnames({'example.com'})))
+
+    -- Force all clients from 192.168.2.0/24 to TCP
+    view:addr('192.168.2.0/24', policy.all(policy.TC))
+
+    -- Whitelist queries identified by TSIG key
+    view:tsig('\5mykey', policy.all(policy.PASS))
+
+
+**********
+How to Run
+**********
+
+===============
+Single instance
+===============
+
+If you're using our packages, the simplest way to run **single instance** of Knot Resolver is to use provided Knot Resolver's ``systemd`` integration.
+
+For help run ``man kresd.systemd``
+
+.. code-block:: bash
+
+   ~$ systemctl start kresd@1.service
+
+See logs and status of running instance with ``systemctl status kresd@1.service`` command.
+
+.. Note:: The instance of Knot Resolver is single process incapable of multithreading.
+
+==================
+Multiple instances
+==================
+
+Knot Resolver can run in multiple independent processes, all sharing the same interface socket and cache.
+
+Because single running instance of Knot Resolver is incapable of multithreading, to use up of all resources, for instance, of 4 CPUs system, the best way is to run four instances at a time.
+
+.. code-block:: bash
+
+    ~$ systemctl start kresd@1.service
+    ~$ systemctl start kresd@2.service
+    ~$ systemctl start kresd@3.service
+    ~$ systemctl start kresd@4.service
+
+or simpler way
+
+.. code-block:: bash
+
+    ~$ systemctl start kresd@{1..4}.service
+
+
+.. _SNI: https://en.wikipedia.org/wiki/Server_Name_Indication
+.. _closures: https://www.lua.org/pil/6.1.html
\ No newline at end of file
index 77ce89700ba37a859af38f73772950c087403d56..36d7cf90bb53159640c3b53191bd181d0883bdf0 100644 (file)
@@ -113,6 +113,8 @@ Instead of CAs, you can specify hashes of accepted certificates in ``pin_sha256`
 They are in the usual format -- base64 from sha256.
 You may still specify ``hostname`` if you want SNI_ to be sent.
 
+.. _tls-examples:
+
 TLS Examples
 ~~~~~~~~~~~~