-******
+.. _daemon:
+
Daemon
-******
+======
The server is in the `daemon` directory, it works out of the box without any configuration.
Configuration
-=============
+-------------
.. contents::
:depth: 2
There are several choices on how you can configure the daemon, a RPC interface, a CLI, and a configuration file.
Fortunately all share common syntax and are transparent to each other.
-Configuration example
----------------------
-.. code-block:: lua
-
- -- interfaces
- net = { '127.0.0.1', '::1' }
- -- load some modules
- modules = { 'policy' }
- -- 10MB cache
- cache.size = 10*MB
-
-.. tip:: There are more configuration examples in `etc/` directory for personal, ISP, company internal and resolver cluster use cases.
-
-Configuration syntax
---------------------
-
-The configuration is kept in the ``config`` file in the daemon working directory, and it's going to get loaded automatically.
-If there isn't one, the daemon is going to start with sane defaults, listening on `localhost`.
-The syntax for options is like follows: ``group.option = value`` or ``group.action(parameters)``.
-You can also comment using a ``--`` prefix.
-
-A simple example would be to load static hints.
-
-.. code-block:: lua
-
- modules = {
- 'hints' -- no configuration
- }
-
-If the module accepts configuration, you can call the ``module.config({...})`` or provide options table.
-The syntax for table is ``{ key1 = value, key2 = value }``, and it represents the unpacked `JSON-encoded`_ string, that
-the modules use as the :ref:`input configuration <mod-properties>`.
-
-.. code-block:: lua
-
- modules = {
- hints = '/etc/hosts'
- }
-
-.. warning:: Modules specified including their configuration may not load exactly in the same order as specified.
-
-Modules are inherently ordered by their declaration. Some modules are built-in, so it would be normally impossible to place for example *hints* before *cache*. You can enforce specific order by precedence operators **>** and **<**.
-
-.. code-block:: lua
-
- modules = {
- 'hints > iterate', -- Hints AFTER iterate
- 'policy > hints', -- Policy AFTER hints
- 'view < cache' -- View BEFORE cache
- }
- modules.list() -- Check module call order
-
-This is useful if you're writing a module with a layer, that evaluates an answer before writing it into cache for example.
-
-.. tip:: The configuration and CLI syntax is Lua language, with which you may already be familiar with.
- If not, you can read the `Learn Lua in 15 minutes`_ for a syntax overview. Spending just a few minutes
- will allow you to break from static configuration, write more efficient configuration with iteration, and
- leverage events and hooks. Lua is heavily used for scripting in applications ranging from embedded to game engines,
- but in DNS world notably in `PowerDNS Recursor`_. Knot Resolver does not simply use Lua modules, but it is
- the heart of the daemon for everything from configuration, internal events and user interaction.
-
-Dynamic configuration
-^^^^^^^^^^^^^^^^^^^^^
-
-Knowing that the the configuration is a Lua in disguise enables you to write dynamic rules. It also helps you to avoid repetitive templating that is unavoidable with static configuration.
-
-.. code-block:: lua
-
- if hostname() == 'hidden' then
- net.listen(net.eth0, 5353)
- else
- net = { '127.0.0.1', net.eth1.addr[1] }
- end
-
-Another example would show how it is possible to bind to all interfaces, using iteration.
-
-.. code-block:: lua
-
- for name, addr_list in pairs(net.interfaces()) do
- net.listen(addr_list)
- end
-
-.. tip:: Some users observed a considerable, close to 100%, performance gain in Docker containers when they bound the daemon to a single interface:ip address pair. One may expand the aforementioned example with browsing available addresses as:
-
- .. code-block:: lua
-
- addrpref = env.EXPECTED_ADDR_PREFIX
- for k, v in pairs(addr_list["addr"]) do
- if string.sub(v,1,string.len(addrpref)) == addrpref then
- net.listen(v)
- ...
-
-You can also use third-party packages (available for example through LuaRocks_) as on this example
-to download cache from parent, to avoid cold-cache start.
-
-.. code-block:: lua
-
- local http = require('socket.http')
- local ltn12 = require('ltn12')
-
- local cache_size = 100*MB
- local cache_path = '/var/cache/knot-resolver'
- cache.open(cache_size, 'lmdb://' .. cache_path)
- if cache.count() == 0 then
- cache.close()
- -- download cache from parent
- http.request {
- url = 'http://parent/data.mdb',
- sink = ltn12.sink.file(io.open(cache_path .. '/data.mdb', 'w'))
- }
- -- reopen cache with 100M limit
- cache.open(cache_size, 'lmdb://' .. cache_path)
- end
-
-.. _async-events:
-
-Asynchronous events
-^^^^^^^^^^^^^^^^^^^
-
-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 that 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
-
- 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
-
- -- monitor every minute
- local monitor_id = event.recurrent(1 * minute, speed_monitor())
-
-Another type of actionable event is activity on a file descriptor. This allows you to embed other
-event loops or monitor open files and then fire a callback when an activity is detected.
-This allows you to build persistent services like HTTP servers or monitoring probes that cooperate
-well with the daemon internal operations. See :func:`event.socket()`
-
-
-File watchers are possible with :func:`worker.coroutine()` and cqueues_, see the cqueues documentation for more information.
-
-.. code-block:: lua
-
- local notify = require('cqueues.notify')
- local watcher = notify.opendir('/etc')
- watcher:add('hosts')
-
- -- Watch changes to /etc/hosts
- worker.coroutine(function ()
- for flags, name in watcher:changes() do
- for flag in notify.flags(flags) do
- print(name, notify[flag])
- end
- end
- end)
-
-.. _closures: https://www.lua.org/pil/6.1.html
Configuration reference
-----------------------
2.1.1
-.. include:: ../daemon/bindings/net.rst
-
-
-.. _dnssec-config:
-
-Trust anchors and DNSSEC
-^^^^^^^^^^^^^^^^^^^^^^^^
-
-Since version 4.0, **DNSSEC validation is enabled by default**.
-This is secure default and should not be changed unless absolutely necessary.
-
-**Options in this section are intended only for expert users and normally
-should not be needed.**
-
-If you really need to turn DNSSEC off and are okay with lowering security of your
-system by doing so, add the following snippet to your configuration file.
-
-.. code-block:: lua
-
- -- turns off DNSSEC validation
- trust_anchors.remove('.')
-
-The resolver supports DNSSEC including :rfc:`5011` automated DNSSEC TA updates
-and :rfc:`7646` negative trust anchors. Depending on your distribution, DNSSEC
-trust anchors should be either maintained in accordance with the distro-wide
-policy, or automatically maintained by the resolver itself.
-
-In practice this means that you can forget about it and your favorite Linux
-distribution will take care of it for you.
-
-
-.. function:: trust_anchors.add_file(keyfile[, readonly = false])
-
- :param string keyfile: path to the file.
- :param readonly: if true, do not attempt to update the file.
-
- The format is standard zone file, though additional information may be persisted in comments.
- Either DS or DNSKEY records can be used for TAs.
- If the file does not exist, bootstrapping of *root* TA will be attempted.
- If you want to use bootstrapping, install `lua-http`_ library.
-
- Each file can only contain records for a single domain.
- The TAs will be updated according to :rfc:`5011` and persisted in the file (if allowed).
-
- Example output:
-
- .. code-block:: lua
-
- > trust_anchors.add_file('root.key')
- [ ta ] new state of trust anchors for a domain:
- . 165488 DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
- nil
-
- [ ta ] key: 19036 state: Valid
-
-.. function:: trust_anchors.remove(zonename)
-
- Remove specified trust anchor from trusted key set. Removing trust anchor for the root zone effectivelly disables DNSSEC validation (unless you configured another trust anchor).
-
- .. code-block:: lua
-
- > trust_anchors.remove('.')
- true
-
- If you want to disable DNSSEC validation for a particular domain but keep it enabled for the rest of DNS tree, use :func:`trust_anchors.set_insecure`.
-
-.. envvar:: trust_anchors.hold_down_time = 30 * day
-
- :return: int (default: 30 * day)
-
- Modify RFC5011 hold-down timer to given value. Intended only for testing purposes. Example: ``30 * sec``
-
-.. envvar:: trust_anchors.refresh_time = nil
-
- :return: int (default: nil)
-
- Modify RFC5011 refresh timer to given value (not set by default), this will force trust anchors
- to be updated every N seconds periodically instead of relying on RFC5011 logic and TTLs.
- Intended only for testing purposes.
- Example: ``10 * sec``
-
-.. envvar:: trust_anchors.keep_removed = 0
-
- :return: int (default: 0)
-
- How many ``Removed`` keys should be held in history (and key file) before being purged.
- Note: all ``Removed`` keys will be purged from key file after restarting the process.
-
-
-.. function:: trust_anchors.set_insecure(nta_set)
-
- :param table nta_list: List of domain names (text format) representing NTAs.
-
- When you use a domain name as an *negative trust anchor* (NTA), DNSSEC validation will be turned off at/below these names.
- Each function call replaces the previous NTA set. You can find the current active set in ``trust_anchors.insecure`` variable.
- If you want to disable DNSSEC validation completely use :func:`trust_anchors.remove` function instead.
-
- Example output:
-
- .. code-block:: lua
-
- > trust_anchors.set_insecure({ 'bad.boy', 'example.com' })
- > trust_anchors.insecure
- [1] => bad.boy
- [2] => example.com
-
- .. warning:: If you set NTA on a name that is not a zone cut,
- it may not always affect names not separated from the NTA by a zone cut.
-
-.. function:: trust_anchors.add(rr_string)
-
- :param string rr_string: DS/DNSKEY records in presentation format (e.g. ``. 3600 IN DS 19036 8 2 49AAC11...``)
-
- Inserts DS/DNSKEY record(s) into current keyset. These will not be managed or updated, use it only for testing
- or if you have a specific use case for not using a keyfile.
-
- .. note:: Static keys are very error-prone and should not be used in production. Use :func:`trust_anchors.add_file` instead.
-
- Example output:
-
- .. code-block:: lua
-
- > trust_anchors.add('. 3600 IN DS 19036 8 2 49AAC11...')
-
-.. function:: trust_anchors.summary()
-
- Return string with summary of configured DNSSEC trust anchors, including negative TAs.
-
-
.. include:: ../daemon/bindings/modules.rst
-.. include:: ../daemon/bindings/cache.rst
-.. include:: ../daemon/bindings/event.rst
-.. include:: ../daemon/bindings/worker.rst
CLI interface
=============
$ nohup ./daemon/kresd -a 127.0.0.1 -f 1 -v &
-
-Control sockets
-===============
-
-Unless ran manually, knot-resolver is typically started in non-interactive mode.
-The mode gets triggered by using the ``-f`` command-line parameter or by passing sockets from systemd.
-
-You can attach to the the consoles for each process; by default they are in ``rundir/tty/$PID``.
-When running kresd with systemd, you can find the location of the socket(s) using
-``systemctl status kresd-control@*.socket``. Typically, these are in ``/run/knot-resolver/control@*``.
-
-Connection to the socket can be made by ``netcat`` or ``socat`` through command line.
-
-.. code-block:: bash
-
- $ nc -U rundir/tty/3008 # or socat - UNIX-CONNECT:/run/knot-resolver/control@1
- > cache.count()
- 83
-
-When successfully connected to a socket, the command line should change to something like ``>``.
-Then you can interact with kresd to see configuration or set a new one.
-There are some basic commands to start with.
-
-.. code-block:: lua
-
- > help() -- shows help
- > net.interfaces() -- lists available interfaces
- > net.list() -- lists running network services
-
-
-The *direct output* of the CLI command is captured and sent over the socket, while also printed to the daemon standard outputs (for accountability). This gives you an immediate response on the outcome of your command.
-Error or debug logs aren't captured, but you can find them in the daemon standard outputs.
-
-This is also a way to enumerate and test running instances, the list of files in ``tty`` corresponds to the list
-of running processes, and you can test the process for liveliness by connecting to the UNIX socket.
-
-
-Cache Garbage Collector
-=======================
-
-kresd daemon uses the available cache until it's full. When more space is
-required, the entire cache is dropped. To avoid starting over with an empty
-cache, a separate garbage collector daemon is available to periodically trim
-the cache instead.
-
-The cache garbage collector daemon (``kres-cache-gc``) monitors the cache usage
-and attempts to free up space when a threshold is reached. A garbage collector
-systemd service, ``kres-cache-gc.service`` is turned on in our upstream packages.
-
-To spawn the daemon manually and configure it to run every second, use:
-
-.. code-block:: bash
-
- $ kres-cache-gc -c /var/cache/knot-resolver -d 1000
-
.. _`JSON-encoded`: http://json.org/example
.. _`Learn Lua in 15 minutes`: http://tylerneylon.com/a/learn-lua/
.. _`PowerDNS Recursor`: https://doc.powerdns.com/md/recursor/scripting/
-.. _LuaRocks: https://luarocks.org/
.. _libuv: https://github.com/libuv/libuv
.. _Lua: https://www.lua.org/about.html
.. _LuaJIT: http://luajit.org/luajit.html
-.. _cqueues: https://25thandclement.com/~william/projects/cqueues.html
.. _`real process managers`: http://blog.crocodoc.com/post/48703468992/process-managers-the-good-the-bad-and-the-ugly
.. _`socket activation`: http://0pointer.de/blog/projects/socket-activation.html
.. _`dnsproxy module`: https://www.knot-dns.cz/docs/2.7/html/modules.html#dnsproxy-tiny-dns-proxy
-
Cache configuration
-^^^^^^^^^^^^^^^^^^^
+===================
+
+The default cache in Knot Resolver is persistent on disk, which means that the daemon doesn't lose
+the cached data on restart or crash, and thus performace does not suffer from cold-starts.
-The default cache in Knot Resolver is persistent with LMDB backend, this means that the daemon doesn't lose
-the cached data on restart or crash to avoid cold-starts. The cache may be reused between cache
+The cache may be reused between cache
daemons or manipulated from other processes, making for example synchronized load-balanced recursors possible.
.. function:: cache.open(max_size[, config_uri])
[subtree] => example.com.
.. [#] This is a consequence of DNSSEC negative cache which relies on proofs of non-existence on various owner nodes. It is impossible to efficiently flush part of DNS zones signed with NSEC3.
+
+.. include:: ../utils/cache_gc/README.rst
-Timers and events
-^^^^^^^^^^^^^^^^^
+Timers and events reference
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The timer represents exactly the thing described in the examples - it allows you to execute closures
+The timer represents exactly the thing described in the examples - it allows you to execute closures_
after specified time, or event recurrent events. Time is always described in milliseconds,
but there are convenient variables that you can use - ``sec, minute, hour``.
For example, ``5 * hour`` represents five hours, or 5*60*60*100 milliseconds.
Pause execution of current function (asynchronously if running inside a worker coroutine).
-When daemon is running in forked mode, each process acts independently. This is good because it reduces software complexity and allows for runtime scaling, but not ideal because of additional operational burden.
-For example, when you want to add a new policy, you'd need to add it to either put it in the configuration, or execute command on each process independently. The daemon simplifies this by promoting process group leader which is able to execute commands synchronously over forks.
+Example:
- Example:
+.. code-block:: lua
- .. code-block:: lua
+ function async_print(testname, sleep)
+ log(testname .. ': system time before sleep' .. tostring(os.time())
+ worker.sleep(sleep) -- other corroutines continue execution now
+ log(testname .. ': system time AFTER sleep' .. tostring(os.time())
+ end
+
+ worker.coroutine(function() async_print('call #1', 5) end)
+ worker.coroutine(function() async_print('call #2', 3) end)
+
+Output from this example demonstrates that both calls to function ``async_print`` were executed asynchronously:
+
+
+.. code-block:: none
- worker.sleep(1)
+ call #2: system time before sleep 1578065073
+ call #1: system time before sleep 1578065073
+ call #2: system time AFTER sleep 1578065076
+ call #1: system time AFTER sleep 1578065078
.. _network-configuration:
Network configuration
-^^^^^^^^^^^^^^^^^^^^^
+=====================
Modern Linux distributions use so-called *Systemd socket activation*, which
effectively means that IP addresses and ports to listen on are configured
.. _tls-server-config:
TLS server configuration
-^^^^^^^^^^^^^^^^^^^^^^^^
+========================
DNS-over-TLS server (:rfc:`7858`) is enabled by default on loopback interface port 853.
Information how to configure listening on specific IP addresses is in previous sections
:ref:`network-configuration`.
--- /dev/null
+.. _dnssec-config:
+
+Trust anchors and DNSSEC
+========================
+
+Since version 4.0, **DNSSEC validation is enabled by default**.
+This is secure default and should not be changed unless absolutely necessary.
+
+**Options in this section are intended only for expert users and normally
+should not be needed.**
+
+If you really need to turn DNSSEC off and are okay with lowering security of your
+system by doing so, add the following snippet to your configuration file.
+
+.. code-block:: lua
+
+ -- turns off DNSSEC validation
+ trust_anchors.remove('.')
+
+The resolver supports DNSSEC including :rfc:`5011` automated DNSSEC TA updates
+and :rfc:`7646` negative trust anchors. Depending on your distribution, DNSSEC
+trust anchors should be either maintained in accordance with the distro-wide
+policy, or automatically maintained by the resolver itself.
+
+In practice this means that you can forget about it and your favorite Linux
+distribution will take care of it for you.
+
+
+.. function:: trust_anchors.add_file(keyfile[, readonly = false])
+
+ :param string keyfile: path to the file.
+ :param readonly: if true, do not attempt to update the file.
+
+ The format is standard zone file, though additional information may be persisted in comments.
+ Either DS or DNSKEY records can be used for TAs.
+ If the file does not exist, bootstrapping of *root* TA will be attempted.
+ If you want to use bootstrapping, install `lua-http`_ library.
+
+ Each file can only contain records for a single domain.
+ The TAs will be updated according to :rfc:`5011` and persisted in the file (if allowed).
+
+ Example output:
+
+ .. code-block:: lua
+
+ > trust_anchors.add_file('root.key')
+ [ ta ] new state of trust anchors for a domain:
+ . 165488 DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
+ nil
+
+ [ ta ] key: 19036 state: Valid
+
+.. function:: trust_anchors.remove(zonename)
+
+ Remove specified trust anchor from trusted key set. Removing trust anchor for the root zone effectivelly disables DNSSEC validation (unless you configured another trust anchor).
+
+ .. code-block:: lua
+
+ > trust_anchors.remove('.')
+ true
+
+ If you want to disable DNSSEC validation for a particular domain but keep it enabled for the rest of DNS tree, use :func:`trust_anchors.set_insecure`.
+
+.. envvar:: trust_anchors.hold_down_time = 30 * day
+
+ :return: int (default: 30 * day)
+
+ Modify RFC5011 hold-down timer to given value. Intended only for testing purposes. Example: ``30 * sec``
+
+.. envvar:: trust_anchors.refresh_time = nil
+
+ :return: int (default: nil)
+
+ Modify RFC5011 refresh timer to given value (not set by default), this will force trust anchors
+ to be updated every N seconds periodically instead of relying on RFC5011 logic and TTLs.
+ Intended only for testing purposes.
+ Example: ``10 * sec``
+
+.. envvar:: trust_anchors.keep_removed = 0
+
+ :return: int (default: 0)
+
+ How many ``Removed`` keys should be held in history (and key file) before being purged.
+ Note: all ``Removed`` keys will be purged from key file after restarting the process.
+
+
+.. function:: trust_anchors.set_insecure(nta_set)
+
+ :param table nta_list: List of domain names (text format) representing NTAs.
+
+ When you use a domain name as an *negative trust anchor* (NTA), DNSSEC validation will be turned off at/below these names.
+ Each function call replaces the previous NTA set. You can find the current active set in ``trust_anchors.insecure`` variable.
+ If you want to disable DNSSEC validation completely use :func:`trust_anchors.remove` function instead.
+
+ Example output:
+
+ .. code-block:: lua
+
+ > trust_anchors.set_insecure({ 'bad.boy', 'example.com' })
+ > trust_anchors.insecure
+ [1] => bad.boy
+ [2] => example.com
+
+ .. warning:: If you set NTA on a name that is not a zone cut,
+ it may not always affect names not separated from the NTA by a zone cut.
+
+.. function:: trust_anchors.add(rr_string)
+
+ :param string rr_string: DS/DNSKEY records in presentation format (e.g. ``. 3600 IN DS 19036 8 2 49AAC11...``)
+
+ Inserts DS/DNSKEY record(s) into current keyset. These will not be managed or updated, use it only for testing
+ or if you have a specific use case for not using a keyfile.
+
+ .. note:: Static keys are very error-prone and should not be used in production. Use :func:`trust_anchors.add_file` instead.
+
+ Example output:
+
+ .. code-block:: lua
+
+ > trust_anchors.add('. 3600 IN DS 19036 8 2 49AAC11...')
+
+.. function:: trust_anchors.summary()
+
+ Return string with summary of configured DNSSEC trust anchors, including negative TAs.
--- /dev/null
+Run-time reconfiguration
+========================
+
+Knot Resolver offers several ways to modify its configuration at run-time:
+
+ - Using control socket driven by an external system
+ - Using Lua script embeded in Resolver's configuration file
+
+Control sockets
+---------------
+Control socket acts like "an interactive configuration file" so all actions available in configuration file can be executed interactively using the control socket. One possible use-case is reconfiguring Resolver instances from another program, e.g. your maintenance script.
+
+.. note::
+
+ Each instance of Knot Resolver exposes its own control socket. Take that into account when scripting deployments with `Multiple instances`_.
+
+When Knot Resolver is started using Systemd (see section :ref:`startup`) it creates a control socket in path ``/run/knot-resolver/control@$INSTANCENAME``. Connection to the socket can be made from command line using e.g. ``netcat`` or ``socat``:
+
+.. code-block:: bash
+
+ $ nc -U /run/knot-resolver/control@1
+ or
+ $ socat - UNIX-CONNECT:/run/knot-resolver/control@1
+
+When successfully connected to a socket, the command line should change to something like ``>``.
+Then you can interact with kresd to see configuration or set a new one.
+There are some basic commands to start with.
+
+.. code-block:: lua
+
+ > help() -- shows help
+ > net.interfaces() -- lists available interfaces
+ > net.list() -- lists running network services
+
+
+The *direct output* of the CLI command is captured and sent over the socket, while also printed to the daemon standard outputs (for accountability). This gives you an immediate response on the outcome of your command.
+Error or debug logs aren't captured, but you can find them in the daemon standard outputs.
+
+Control sockets are also a way to enumerate and test running instances, the list of sockets corresponds to the list
+of processes, and you can test the process for liveliness by connecting to the UNIX socket.
+
+Lua scripts
+-----------
+
+As it was mentioned in section :ref:`config-syntax`, Resolver's configuration file contains program in Lua programming language. This allows you to write dynamic rules and helps you to avoid repetitive templating that is unavoidable with static configuration. For example parts of configuration can depend on hostname of the machine:
+
+.. code-block:: lua
+
+ if hostname() == 'hidden' then
+ net.listen(net.eth0, 5353)
+ else
+ net.listen('127.0.0.1')
+ net.listen(net.eth1.addr[1])
+ end
+
+Another example would show how it is possible to bind to all interfaces, using iteration.
+
+.. code-block:: lua
+
+ for name, addr_list in pairs(net.interfaces()) do
+ net.listen(addr_list)
+ end
+
+.. tip:: Some users observed a considerable, close to 100%, performance gain in Docker containers when they bound the daemon to a single interface:ip address pair. One may expand the aforementioned example with browsing available addresses as:
+
+ .. code-block:: lua
+
+ addrpref = env.EXPECTED_ADDR_PREFIX
+ for k, v in pairs(addr_list["addr"]) do
+ if string.sub(v,1,string.len(addrpref)) == addrpref then
+ net.listen(v)
+ ...
+
+You can also use third-party Lua libraries (available for example through
+LuaRocks_) as on this example to download cache from parent,
+to avoid cold-cache start.
+
+.. code-block:: lua
+
+ local http = require('socket.http')
+ local ltn12 = require('ltn12')
+
+ local cache_size = 100*MB
+ local cache_path = '/var/cache/knot-resolver'
+ cache.open(cache_size, 'lmdb://' .. cache_path)
+ if cache.count() == 0 then
+ cache.close()
+ -- download cache from parent
+ http.request {
+ url = 'http://parent/data.mdb',
+ sink = ltn12.sink.file(io.open(cache_path .. '/data.mdb', 'w'))
+ }
+ -- reopen cache with 100M limit
+ cache.open(cache_size, 'lmdb://' .. cache_path)
+ end
+
+.. _async-events:
+
+Asynchronous events
+-------------------
+
+Lua language used in configuration file allows you to script actions upon
+various events, for example publish statistics each minute. Following example uses built-in function :func:`event.recurrent()` which calls user-supplied anonymous function:
+
+.. code-block:: lua
+
+ 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)
+
+
+Note that 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.
+
+To persist state between two invocations of a fuction Lua uses concept called closures_. In the following example function ``speed_monitor()`` is a closure function, which provides 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
+
+ -- monitor every minute
+ local monitor_id = event.recurrent(1 * minute, speed_monitor())
+
+Another type of actionable event is activity on a file descriptor. This allows you to embed other event loops or monitor open files and then fire a callback when an activity is detected.
+This allows you to build persistent services like monitoring probes that cooperate well with the daemon internal operations. See :func:`event.socket()`.
+
+
+Filesystem watchers are possible with :func:`worker.coroutine()` and cqueues_, see the cqueues documentation for more information. Here is an simple example:
+
+.. code-block:: lua
+
+ local notify = require('cqueues.notify')
+ local watcher = notify.opendir('/etc')
+ watcher:add('hosts')
+
+ -- Watch changes to /etc/hosts
+ worker.coroutine(function ()
+ for flags, name in watcher:changes() do
+ for flag in notify.flags(flags) do
+ -- print information about the modified file
+ print(name, notify[flag])
+ end
+ end
+ end)
+
+.. include:: ../daemon/bindings/event.rst
+
+.. _closures: https://www.lua.org/pil/6.1.html
+.. _cqueues: https://25thandclement.com/~william/projects/cqueues.html
+.. _LuaRocks: https://luarocks.org/
+.. _config-syntax:
+
+Files and syntax
+================
+
+Configuration file is named ``/etc/knot-resolver/kresd.conf`` and is read when you execute Knot Resolver using systemd commands described in section :ref:`startup`. [#]_
+
+
+The syntax for options is like follows: ``group.option = value`` or ``group.action(parameter1, parameter2)``. You can also comment using a ``--`` prefix.
+
+Following example sets cache size and starts listening for unencrypted and also encrypted DNS queries on IP address 192.0.2.1.
+
+.. code-block:: lua
+
+ cache.size = 10 * MB
+ -- this is a comment: listen for unencrypted queries
+ net.listen('192.0.2.1')
+ -- another comment: listen for queries encrypted using TLS on port 853
+ net.listen('192.0.2.1', 853, { kind = 'tls' })
+
+.. tip:: The configuration and CLI syntax is Lua language which allows great
+ flexibility. Luckily you do not need to learn Lua, copy&pasting examples
+ from this manual is sufficient for normal use-cases. Just pay close
+ attention to brackets.
+
+ If you want to use full power of configuration language see article
+ `Learn Lua in 15 minutes`_ for a syntax overview.
+
+
+.. [#] If you decide to run binary ``/usr/sbin/kresd`` manually (instead of using systemd) do not forget to specify ``-c`` option with path to configuration file, otherwise ``kresd`` will read file named ``config`` from its current working directory.
+
+.. include:: ../daemon/bindings/net.rst
+.. include:: ../daemon/bindings/cache.rst
+.. include:: ../daemon/lua/trust_anchors.rst
+
+.. include:: ../daemon/README.rst
+.. include:: ../daemon/scripting.rst
+
Multiple instances
==================
+++ /dev/null
-.. _daemon:
-
-.. include:: ../daemon/README.rst
\ No newline at end of file
:maxdepth: 2
config
- daemon
modules
Add the `OBS <https://en.opensuse.org/Portal:Build_Service>`_ 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.
+.. _startup:
+
*******
Startup
*******
.. note::
Copy&pasting examples from this manual is sufficient for normal use-cases.
- Please pay close attention to brackets, especially
- in more complex configurations like :func:`policy.add` and :func:`view:addr`.
+ Please pay close attention to brackets.
If you want to use full power of configuration language, see article
`Learn Lua in 15 minutes`_ for a syntax overview.
--- /dev/null
+Garbage Collector
+-----------------
+
+Knot Resolver employs a separate garbage collector daemon (process ``kres-cache-gc``) which periodically trims the cache to keep its size below a configured size limit.
+
+Systemd service ``kres-cache-gc.service`` is enabled by default and does not need any manual intervention.
+
+If you decide to experiment with garbage collector configuration you can execute the daemon manually and configure it to run every second:
+
+.. code-block:: bash
+
+ $ kres-cache-gc -c /var/cache/knot-resolver -d 1000
+