Packet Policies

DNSdist packet flows

dnsdist works in essence like any other loadbalancer:

It receives packets on one or several addresses it listens on, and determines whether it will process this packet based on the Access Control. Should the packet be processed, 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 Rule selectors, and the list of actions in Rule Actions.

Packet Actions

Each packet can be:

  • Dropped
  • Turned into an answer directly
  • Forwarded to a downstream server
  • Modified and forwarded to a downstream and be modified back
  • Be delayed

This decision can be taken at different times during the forwarding process. All packets not handled by an explicit action are forwarded to a downstream server in the default pool.


Rules for traffic exceeding QPS limits

Traffic that exceeds a QPS limit, in total or per IP (subnet) can be matched by a rule.

For example:

addAction(MaxQPSIPRule(5, 32, 48), DelayAction(100))

This measures traffic per IPv4 address and per /48 of IPv6, and if traffic for such an address (range) exceeds 5 qps, it gets delayed by 100ms. (Please note: DelayAction() can only delay UDP traffic).

As another example:

addAction(MaxQPSIPRule(5), SetNoRecurseAction())

This strips the Recursion Desired (RD) bit from any traffic per IPv4 or IPv6 /64 that exceeds 5 qps. This means any those traffic bins is allowed to make a recursor do ‘work’ for only 5 qps.

If this is not enough, try:

addAction(MaxQPSIPRule(5), DropAction())


addAction(AndRule{MaxQPSIPRule(5), TCPRule(false)}, TCAction())

This will respectively drop traffic exceeding that 5 QPS limit per IP or range, or return it with TC=1, forcing clients to fall back to TCP.

In that last one, note the use of TCPRule(). Without it, clients would get TC=1 even if they correctly fell back to TCP.

To turn this per IP or range limit into a global limit, use NotRule(MaxQPSRule(5000)) instead of MaxQPSIPRule().

Regular Expressions

RegexRule() matches a regular expression on the query name, and it works like this:

addAction(RegexRule("[0-9]{5,}"), DelayAction(750)) -- milliseconds
addAction(RegexRule("[0-9]{4,}\\.example$"), DropAction())

This delays any query for a domain name with 5 or more consecutive digits in it. The second rule drops anything with more than 4 consecutive digits within a .example domain.

Note that the query name is presented without a trailing dot to the regex. The regex is applied case insensitively.

Alternatively, if compiled in, RE2Rule() provides similar functionality, but against libre2.

Note that to check if a name is in a list of domains, QNameSuffixRule() is preferred over complex regular expressions or multiple instances of RegexRule().

Managing Rules

Active Rules can be shown with showRules() and removed with rmRule():

> addAction("", QPSAction(10))
> addAction({"", ""} , QPSAction(20))
> addAction({"nl.", "be."}, QPSAction(1))
> showRules()
#     Matches Rule                                               Action
0           0                                   qps limit to 10
1           0,                      qps limit to 20
2           0 nl., be.                                           qps limit to 1

See Rules management for more information.