That does not mean that the memory is completely allocated up-front, the final memory usage depending mostly on the size of cached responses and therefore varying during the cache's lifetime.
Assuming an average response size of 512 bytes, a cache size of 10000000 entries on a 64-bit host with 8GB of dedicated RAM would be a safe choice.
+The equivalent ``yaml`` configuration would be:
+
+.. code-block:: yaml
+
+ packet-caches:
+ - name: "pc"
+ size: 1000
+ max-ttl: 86400
+ min-ttl: 0
+ temporary-failure-ttl: 60
+ state-ttl: 60
+ dont-age: false
+ pools:
+ - name: ""
+ packet-cache: "pc"
+
The :func:`setStaleCacheEntriesTTL` directive can be used to allow dnsdist to use expired entries from the cache when no backend is available.
Only entries that have expired for less than n seconds will be used, and the returned TTL can be set when creating a new cache with :func:`newPacketCache`.
Where ``ourname`` can be used to override your hostname, and ``30`` is the reporting interval in seconds. ``dnsdist`` and ``main`` are used as namespace and instance variables. For querycount statistics these two variables are currently ignored. The last four arguments can be omitted.
The latest version of `PowerDNS Metronome <https://github.com/ahupowerdns/metronome>`_ comes with attractive graphs for dnsdist by default.
+The equivalent ``yaml`` configuration:
+
+.. code-block:: yaml
+
+ metrics:
+ carbon:
+ - address: "ip-address-of-carbon-server"
+ name: "ourname"
+ interval: "30"
+ namespace: "dnsdist"
+ instance: "main"
+
+
Query counters
--------------
controlSocket('192.0.2.53:5199')
+Or in ``yaml``:
+
+.. code-block:: yaml
+
+ console:
+ listen-address: "192.0.2.53:5199"
+
+
Enabling the console without encryption enabled is not recommended. Note that encryption requires building dnsdist with either libsodium or libcrypto support enabled.
Once you have a console-enabled dnsdist, the first step to enable encryption is to generate a key with :func:`makeKey`::
controlSocket('192.0.2.53:5199') -- Listen on this IP and port for client connections
setKey("ENCODED KEY") -- Shared secret for the console
+.. code-block:: yaml
+
+ console:
+ listen-address: "192.0.2.53:5199"
+ key: "ENCODED KEY"
+
Now you can run ``dnsdist -c`` to connect to the console.
This makes dnsdist read its configuration file and use the :func:`controlSocket` and :func:`setKey` statements to set up its connection to the server.
controlSocket('192.0.2.53:5199')
setConsoleACL('192.0.2.0/24')
+.. code-block:: yaml
+
+ console:
+ listen-address: "192.0.2.53:5199"
+ key: "ENCODED KEY"
+ acl:
+ - "192.0.2.0/24"
+
+
The default value is '127.0.0.1', restricting the use of the console to local users. Please make sure that encryption is enabled
before using :func:`addConsoleACL` or :func:`setConsoleACL` to allow connection from remote clients. Even if the console is
restricted to local users, the use of encryption is still strongly advised to prevent unauthorized local users from connecting to
addDOH3Local('2001:db8:1:f00::1', '/etc/ssl/certs/example.com.pem', '/etc/ssl/private/example.com.key', {congestionControlAlgo="bbr"})
+.. code-block:: yaml
+
+ binds:
+ - listen-address: "2001:db8:1:f00::1"
+ protocol: "DoH3"
+ tls:
+ certificates:
+ - certificate: "/etc/ssl/certs/example.com.pem"
+ key: "/etc/ssl/private/example.com.key"
+ quic:
+ congestion-control-algorithm: "bbr"
+
+
A particular attention should be taken to the permissions of the certificate and key files. Many ACME clients used to get and renew certificates, like CertBot, set permissions assuming that services are started as root, which is no longer true for dnsdist as of 1.5.0. For that particular case, making a copy of the necessary files in the /etc/dnsdist directory is advised, using for example CertBot's ``--deploy-hook`` feature to copy the files with the right permissions after a renewal.
More information about sessions management can also be found in :doc:`../advanced/tls-sessions-management`.
addDOHLocal('2001:db8:1:f00::1', '/etc/ssl/certs/example.com.pem', '/etc/ssl/private/example.com.key', "/", {customResponseHeaders={["link"]="<https://example.com/policy.html> rel=\\"service-meta\\"; type=\\"text/html\\""}})
+Or in ``yaml``:
+
+.. code-block:: yaml
+
+ - listen-address: "2001:db8:1:f00::1"
+ protocol: "DoH"
+ tls:
+ certificates:
+ - certificate: "/etc/ssl/certs/example.com.pem"
+ key: "/etc/ssl/private/example.com.key"
+ doh:
+ provider: "nghttp2"
+ paths:
+ - "/"
+ custom-response-headers:
+ - key: "link"
+ value: "<https://example.com/policy.html> rel=\\"service-meta\\"; type=\\"text/html\\""
+
+
A particular attention should be taken to the permissions of the certificate and key files. Many ACME clients used to get and renew certificates, like CertBot, set permissions assuming that services are started as root, which is no longer true for dnsdist as of 1.5.0. For that particular case, making a copy of the necessary files in the /etc/dnsdist directory is advised, using for example CertBot's ``--deploy-hook`` feature to copy the files with the right permissions after a renewal.
More information about sessions management can also be found in :doc:`../advanced/tls-sessions-management`.
newServer({address="[2001:DB8::1]:443", tls="openssl", subjectName="doh.powerdns.com", dohPath="/dns-query", validateCertificates=true})
+.. code-block:: yaml
+
+ backends:
+ - address: "127.0.0.1:%d"
+ protocol: "DoH"
+ tls:
+ provider: "openssl"
+ validate-certificate: true
+ subject-name: "doh.powerdns.com"
+ doh:
+ path: "/dns-query"
+
Internal design
^^^^^^^^^^^^^^^
addDOQLocal('2001:db8:1:f00::1', '/etc/ssl/certs/example.com.pem', '/etc/ssl/private/example.com.key', {congestionControlAlgo="bbr"})
+.. code-block:: yaml
+
+ binds:
+ - listen-address: "2001:db8:1:f00::1"
+ protocol: "DoQ"
+ tls:
+ certificates:
+ - certificate: "/etc/ssl/certs/example.com.pem"
+ key: "/etc/ssl/private/example.com.key"
+ quic:
+ congestion-control-algorithm: "bbr"
+
+
A particular attention should be taken to the permissions of the certificate and key files. Many ACME clients used to get and renew certificates, like CertBot, set permissions assuming that services are started as root, which is no longer true for dnsdist as of 1.5.0. For that particular case, making a copy of the necessary files in the /etc/dnsdist directory is advised, using for example CertBot's ``--deploy-hook`` feature to copy the files with the right permissions after a renewal.
More information about sessions management can also be found in :doc:`../advanced/tls-sessions-management`.
addTLSLocal('192.0.2.55', {'/etc/ssl/certs/example.com.rsa.pem', '/etc/ssl/certs/example.com.ecdsa.pem'}, {'/etc/ssl/private/example.com.rsa.key', '/etc/ssl/private/example.com.ecdsa.key'})
+.. code-block:: yaml
+
+ binds:
+ - listen-address: "192.0.2.55"
+ protocol: "DoT"
+ tls:
+ certificates:
+ - certificate: "/etc/ssl/certs/example.com.rsa.pem"
+ key: "/etc/ssl/private/example.com.rsa.key"
+ - certificate: "/etc/ssl/certs/example.com.ecdsa.pem"
+ key: "/etc/ssl/private/example.com.ecdsa.key"
+
The certificate chain presented by the server to an incoming client will then be selected based on the algorithms this client advertised support for.
A particular attention should be taken to the permissions of the certificate and key files. Many ACME clients used to get and renew certificates, like CertBot, set permissions assuming that services are started as root, which is no longer true for dnsdist as of 1.5.0. For that particular case, making a copy of the necessary files in the /etc/dnsdist directory is advised, using for example CertBot's ``--deploy-hook`` feature to copy the files with the right permissions after a renewal.
* :func:`showTCPStats` will display a lot of information about current and passed connections
* :func:`showTLSErrorCounters` some metrics about why TLS sessions failed to establish
-
addDNSCryptBind("127.0.0.1:8443", "2.providername", "/path/to/resolver.cert", "/path/to/resolver.key")
+
+And in ``yaml``:
+
+.. code-block:: yaml
+
+ binds:
+ - listen-address: "127.0.0.1:8443"
+ protocol: "DNSCrypt"
+ dnscrypt:
+ provider-name: "2.providername"
+ certificates:
+ - certificate: "/path/to/resolver.cert"
+ key: "/path/to/resolver.key"
+
+
To generate the provider and resolver certificates and keys, you can simply do::
> generateDNSCryptProviderKeys("/path/to/providerPublic.key", "/path/to/providerPrivate.key")
newServer({address="192.0.2.1", checkType="AAAA", checkClass=DNSClass.CHAOS, checkName="a.root-servers.net.", mustResolve=true})
+In ``yaml``:
+
+.. code-block:: yaml
+
+ backends:
+ - address: "192.0.2.1"
+ protocol: "Do53"
+ health-checks:
+ qname: "a.root-servers.net."
+ qtype: "AAAA"
+ qclass: "CHAOS"
+ must-resolve: true
+
+
You can turn on logging of health check errors using the :func:`setVerboseHealthChecks` function.
Lazy health-checking
newServer({address="192.0.2.1", healthCheckMode='lazy', checkInterval=1, lazyHealthCheckFailedInterval=30, rise=2, maxCheckFailures=3, lazyHealthCheckThreshold=30, lazyHealthCheckSampleSize=100, lazyHealthCheckMinSampleCount=10, lazyHealthCheckMode='TimeoutOnly'})
+.. code-block:: yaml
+
+ backends:
+ - address: "192.0.2.1"
+ protocol: "Do53"
+ health-checks:
+ mode: "lazy"
+ rise: 2
+ max-failures: 3
+ check-interval: 1
+ lazy:
+ mode: "TimeoutOnly"
+ interval: 30
+ threshold: 30
+ sample-size: 100
+ min-sample-count: 10
+
The 'lazy' mode also supports using an exponential back-off time between health-check queries, once a backend has been moved to the 'down' state. This can be enabled by setting the ``lazyHealthCheckUseExponentialBackOff`` parameter to 'true'. Once the backend has been marked as 'down', the first query will be sent after ``lazyHealthCheckFailedInterval`` seconds, the second one after 2 times ``lazyHealthCheckFailedInterval`` seconds, the third after 4 times ``lazyHealthCheckFailedInterval`` seconds, and so on and so forth, until ``lazyHealthCheckMaxBackOff`` has been reached. Then probes will be sent every ``lazyHealthCheckMaxBackOff`` seconds (default is 3600 so one hour) until the backend comes 'up' again.
Source address selection
newServer({address="192.0.2.1", source="eth1"})
newServer({address="192.0.2.1", source="192.0.2.127@eth1"})
+.. code-block:: yaml
+
+ backends:
+ - address: "192.0.2.1"
+ protocol: "Do53"
+ source: "192.0.2.127@eth1"
+
The supported values for source are:
- an IPv4 or IPv6 address, which must exist on the system
------------
dnsdist has the concept to "server pools", any number of servers can belong to a group.
-A default pool, identified by the empty string ``''`` is always present, and `newServer` without a pool argument will assign the new server to that pool.
+A default pool, identified by the empty string ``''`` is always present, and :func:`newServer` without a pool argument will assign the new server to that pool.
Let's say we know we're getting a whole bunch of traffic for a domain used in DoS attacks, for example 'example.com'.
We can do two things with this kind of traffic.
getServer(4):addPool("abuse")
getServer(4):rmPool("abuse")
-
setWebserverConfig({password="supersecretpassword", apiKey="supersecretAPIkey", acl="192.0.2.0/24, !192.0.2.1"})
+The equivalent ``yaml`` configuration would be:
+
+.. code-block:: yaml
+
+ webserver:
+ listen-address: "127.0.0.1:8083"
+ password: "supersecretpassword"
+ api-key: "supersecretAPIkey"
+ acl:
+ - "192.0.2.0/24"
+ - "!192.0.2.1"
+
Security of the Webserver
-------------------------
dnsdist Overview
================
-dnsdist is a highly DNS-, DoS- and abuse-aware loadbalancer.
+:program:`dnsdist` is a highly DNS-, DoS- and abuse-aware loadbalancer.
Its goal in life is to route traffic to the best server, delivering top performance to legitimate users while shunting or blocking abusive traffic.
-dnsdist is dynamic, its configuration language is `Lua <http://lua.org>`_ and it can be changed at runtime, and its statistics can be queried from a console-like interface or an HTTP API.
+:program:`dnsdist` is dynamic, its configuration can be changed at runtime via a :doc:`console-like interface <guides/console>`.
+It exposes :doc:`metrics <statistics>` that can be exported via Carbon, Prometheus, an HTTP API and the console.
+
+Until 2.0.0 the configuration was written in `Lua <http://lua.org>`_, but it is now possible to write the configuration in :doc:`yaml <reference/yaml-settings>` as well.
A configuration to balance DNS queries to several backend servers:
.. code-block:: lua
- newServer({address="2620:fe::fe", qps=1})
- newServer({address="2620:fe::9", qps=1})
- newServer({address="9.9.9.9", qps=1})
- newServer({address="2001:db8::1", qps=10})
- newServer({address="[2001:db8::2]:5300", name="dns1", qps=10})
+ newServer({address="2620:fe::fe"})
+ newServer({address="2620:fe::9"})
+ newServer({address="9.9.9.9"})
+ newServer({address="2001:db8::1"})
+ newServer({address="[2001:db8::2]:5300", name="dns1"})
newServer("192.0.2.1")
- setServerPolicy(firstAvailable) -- first server within its QPS limit
+
+Or in ``yaml``:
+
+.. code-block:: yaml
+
+ backends:
+ - address: "2620:fe::fe"
+ protocol: Do53
+ - address: "2620:fe::9"
+ protocol: Do53
+ - address: "9.9.9.9"
+ protocol: Do53
+ - address: "2001:db8::1"
+ protocol: Do53
+ - address: "[2001:db8::1]:5300"
+ name: "dns1"
+ protocol: Do53
+ - address: "192.0.2.1"
+ protocol: Do53
+
Running dnsdist
---------------
Installing from Packages
------------------------
-If dnsdist is available in your operating system's software repositories, install it from there.
+If dnsdist is available in your operating system's software repositories, you can install it from there.
However, the version of dnsdist in the repositories might be an older version that might not have a feature that was added in a later version.
Or you might want to be brave and try a development snapshot from the master branch.
PowerDNS provides software repositories for the most popular distributions.
* `Lua <http://www.lua.org/>`_ 5.1+ or `LuaJit <http://luajit.org/>`_
* `Editline (libedit) <http://thrysoee.dk/editline/>`_
* `libfstrm <https://github.com/farsightsec/fstrm>`_ (optional, dnstap support)
-* `GnuTLS <https://www.gnutls.org/>`_ (optional, DoT and outgoing DoH support)
+* `GnuTLS <https://www.gnutls.org/>`_ (optional, DoT and DoH support)
* `libbpf <https://github.com/libbpf/libbpf>`_ and `libxdp <https://github.com/xdp-project/xdp-tools>`_ (optional, `XSK`/`AF_XDP` support)
* `libcap <https://sites.google.com/site/fullycapable/>`_ (optional, capabilities support)
* `libh2o <https://github.com/h2o/h2o>`_ (optional, incoming DoH support, deprecated in 1.9.0 in favor of ``nghttp2``)
-* `libsodium <https://download.libsodium.org/doc/>`_ (optional, DNSCrypt and console encryption support)
+* `libsodium <https://download.libsodium.org/doc/>`_ (optional, DNSCrypt support)
* `LMDB <http://www.lmdb.tech/doc/>`_ (optional, LMDB support)
* `net-snmp <http://www.net-snmp.org/>`_ (optional, SNMP support)
-* `nghttp2 <https://nghttp2.org/>`_ (optional, outgoing DoH support)
+* `nghttp2 <https://nghttp2.org/>`_ (optional, DoH support)
* `OpenSSL <https://www.openssl.org/>`_ (optional, DoT and DoH support)
-* `protobuf <https://developers.google.com/protocol-buffers/>`_ (optional, not needed as of 1.6.0)
-* `quiche <https://github.com/cloudflare/quiche>`_ (optional, incoming DoQ support)
+* `Quiche <https://github.com/cloudflare/quiche>`_ (optional, incoming DoQ and DoH3 support)
* `re2 <https://github.com/google/re2>`_ (optional)
* `TinyCDB <https://www.corpit.ru/mjt/tinycdb.html>`_ (optional, CDB support)
+Since 2.0.0, the optional ``yaml`` configuration requires a Rust compiler and a Python 3 interpreter.
+
Should :program:`dnsdist` be run on a system with systemd, it is highly recommended to have
the systemd header files (``libsystemd-dev`` on Debian and ``systemd-devel`` on CentOS)
installed to have :program:`dnsdist` support ``systemd-notify``.
Here is more complete configuration, save it to ``dnsdist.conf``::
+.. code-block:: lua
+
newServer({address="2001:db8::1", qps=1})
newServer({address="2001:db8::2", qps=1})
newServer({address="[2001:db8::3]:5300", qps=10})
The :func:`newServer` function is used to add a backend server to the configuration.
+The ``yaml`` equivalent, from 2.0+ onwards, would be:
+
+.. code-block:: yaml
+
+ backends:
+ - address: "2001:db8::1"
+ protocol: Do53
+ qps: 1
+ - address: "2001:db8::2"
+ protocol: Do53
+ qps: 1
+ - address: "[2001:db8::3]:5300"
+ protocol: Do53
+ qps: 10
+ - address: "[2001:db8::4]"
+ name: "dns1"
+ protocol: Do53
+ qps: 10
+ - address: "192.0.2.1"
+ protocol: Do53
+ load-balancing-policies:
+ default-policy: "firstAvailable"
+
Now run dnsdist again, reading this configuration::
$ dnsdist -C dnsdist.conf --local=0.0.0.0:5300
setACL({'192.0.2.0/28', '2001:db8:1::/56'}) -- Set the ACL to only allow these subnets
addACL('2001:db8:2::/56') -- Add this subnet to the existing ACL
+And in ``yaml`` format:
+
+.. code-block:: yaml
+acl:
+ - "192.0.2.0/28"
+ - "2001:db8:1::/56"
+ - "2001:db8:2::/56"
+binds:
+ - listen-address: "192.0.2.53"
+ protocol: Do53
+ - listen-address: "[::1]:5300"
+ protocol: Do53
+
+
Securing the path to the backend
--------------------------------
============
:doc:`selectors` need to be combined with an action for them to actually do something with the matched packets.
+This page describes the ``Lua`` versions of these actions, for the ``YAML`` version please see :doc:`yaml-actions` and :doc:`yaml-response-actions`.
+
Some actions allow further processing of rules, this is noted in their description. Most of these start with 'Set' with a few exceptions, mostly for logging actions. These exceptions are:
- :func:`ClearRecordTypesResponseAction`
* A list of :class:`DNSName`\ s
* A (compounded) ``Rule``
+This page describes the ``Lua`` versions of these selectors, for the ``YAML`` version please see :doc:`yaml-selectors`.
+
Selectors can be combined via :func:`AndRule`, :func:`OrRule` and :func:`NotRule`.
.. function:: AllRule()
It receives packets on one or several addresses it listens on, and determines whether it will process this packet based on the :doc:`advanced/acl`. Should the packet be processed, :program:`dnsdist` attempts to match any of the configured rules in order and when one matches, the associated action is performed.
-These rule and action combinations are considered policies. The complete list of selectors (rules) can be found in :doc:`reference/selectors`, and the list of actions in :doc:`reference/actions`.
+These rule and action combinations are considered policies. The complete list of selectors (rules) can be found in :doc:`reference/selectors` (:doc:`reference/yaml-selectors`), and the list of actions in :doc:`reference/actions` (:doc:`reference/yaml-actions` and :doc:`reference/yaml-response-actions`).
Packet Actions
--------------
1.9.x to 2.0.0
--------------
+:program:`dnsdist` supports a new, optional ``yaml`` :doc:`configuration format <reference/yaml-settings>`. This new format requires a Rust compiler and a Python 3 interpreter.
+
:func:`showTLSContexts` has been renamed to :func:`showTLSFrontends`.
:func:`getTLSContext` and the associated :class:`TLSContext` have been removed, please use :func:`getTLSFrontend` and the associated :class:`TLSFrontend` instead.