pdns icon indicating copy to clipboard operation
pdns copied to clipboard

dnsdist: `additional_addresses` for Do53 frontends are bound to TCP only

Open edmonds opened this issue 7 months ago • 2 comments

Description

The BindConfiguration's additional_addresses setting is described as:

Sequence of String ("") - List of additional addresses (with port) to listen on. Using this option instead of creating a new frontend for each address avoids the creation of new thread and Frontend objects, reducing the memory usage. The drawback is that there will be a single set of metrics for all addresses

I tried to use this setting by defining a dnsdist.yml config with:

binds:
  - listen_address: "192.0.2.1:53"
    additional_addresses:
      - "203.0.113.1:53"
      - "198.51.100.1:53"
    reuseport: true
    threads: 1

  - listen_address: "192.0.2.2:53"
    additional_addresses:
      - "203.0.113.2:53"
      - "198.51.100.2:53"
    reuseport: true
    threads: 1

  - listen_address: "192.0.2.3:53"
    additional_addresses:
      - "203.0.113.3:53"
      - "198.51.100.3:53"
    reuseport: true
    threads: 1

I have all these addresses assigned as loopbacks:

$ ip a s dev lo | grepcidr 0.0.0.0/0 | sort -V
    inet 127.0.0.1/8 scope host lo
    inet 192.0.2.1/32 scope global lo
    inet 192.0.2.2/32 scope global lo
    inet 192.0.2.3/32 scope global lo
    inet 198.51.100.1/32 scope global lo
    inet 198.51.100.2/32 scope global lo
    inet 198.51.100.3/32 scope global lo
    inet 203.0.113.1/32 scope global lo
    inet 203.0.113.2/32 scope global lo
    inet 203.0.113.3/32 scope global lo

When I start dnsdist with this config I see the following output:

Loading configuration from YAML file /etc/dnsdist/dnsdist2.yml
Listening on 192.0.2.1:53
Listening on 203.0.113.1:53
Listening on 198.51.100.1:53
Raised send buffer to 212992 for local address '192.0.2.1:53'
Raised receive buffer to 212992 for local address '192.0.2.1:53'
Listening on 192.0.2.2:53
Listening on 203.0.113.2:53
Listening on 198.51.100.2:53
Raised send buffer to 212992 for local address '192.0.2.2:53'
Raised receive buffer to 212992 for local address '192.0.2.2:53'
Listening on 192.0.2.3:53
Listening on 203.0.113.3:53
Listening on 198.51.100.3:53
Raised send buffer to 212992 for local address '192.0.2.3:53'
Raised receive buffer to 212992 for local address '192.0.2.3:53'
ACL allowing queries from: 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.168.0.0/16, ::1/128, fc00::/7, fe80::/10
Console ACL allowing connections from: 127.0.0.0/8, ::1/128
Adding TCP Client thread
Adding TCP Client thread
Adding TCP Client thread
Adding TCP Client thread
Adding TCP Client thread
Adding TCP Client thread
Adding TCP Client thread
Adding TCP Client thread
Adding TCP Client thread
Adding TCP Client thread
No downstream servers defined: all packets will get dropped
Warning, this configuration can use more than 10046 file descriptors, web server and console connections not included, and the current limit is 1024.
You can increase this value by using ulimit.

However, it seems the additional_addresses were bound as TCP listeners only:

# lsof -Pni | grep ^dnsdist | grep UDP
dnsdist   163696            root   10u  IPv4 1168398      0t0  UDP 192.0.2.1:53
dnsdist   163696            root   14u  IPv4 1168402      0t0  UDP 192.0.2.2:53
dnsdist   163696            root   18u  IPv4 1168406      0t0  UDP 192.0.2.3:53
# lsof -Pni | grep ^dnsdist | grep TCP
dnsdist   163696            root    7u  IPv4 1168395      0t0  TCP 192.0.2.1:53 (LISTEN)
dnsdist   163696            root    8u  IPv4 1168396      0t0  TCP 203.0.113.1:53 (LISTEN)
dnsdist   163696            root    9u  IPv4 1168397      0t0  TCP 198.51.100.1:53 (LISTEN)
dnsdist   163696            root   11u  IPv4 1168399      0t0  TCP 192.0.2.2:53 (LISTEN)
dnsdist   163696            root   12u  IPv4 1168400      0t0  TCP 203.0.113.2:53 (LISTEN)
dnsdist   163696            root   13u  IPv4 1168401      0t0  TCP 198.51.100.2:53 (LISTEN)
dnsdist   163696            root   15u  IPv4 1168403      0t0  TCP 192.0.2.3:53 (LISTEN)
dnsdist   163696            root   16u  IPv4 1168404      0t0  TCP 203.0.113.3:53 (LISTEN)
dnsdist   163696            root   17u  IPv4 1168405      0t0  TCP 198.51.100.3:53 (LISTEN)

The UDP listeners above are the listen_address setting for each frontend.

Environment

  • Operating system: Ubuntu 24.04.2 LTS (Noble Numbat)
  • Software version: The master branch, commit 7b79eac90703b7102fbf25a7148906e6f6da09df
  • Software source: https://github.com/PowerDNS/pdns/tree/7b79eac90703b7102fbf25a7148906e6f6da09df

Steps to reproduce

See description above.

Expected behaviour

For Do53 protocol frontends, the addresses specified in listen_address and additional_addresses should be bound to both UDP and TCP.

Actual behaviour

For Do53 protocol frontends, only the address specified in listen_address was bound to UDP and the additional_addresses were ignored.

edmonds avatar May 02 '25 22:05 edmonds

I was wondering how the Lua configuration code handled this, because the frontend code that is called later does not seem to expect additional addresses to exist for UDP at all. It turns out that the "additional addresses" concept was initially designed for DoT/DoH only (57845fd81ff516df3c376989ef72e45c4b180471 mentions that) and the Lua configuration only allows it for addTLSLocal and addDOHLocal, which makes sense. So we have two options:

  • implement the same limitation in the YAML configuration, and document it clearly
  • support it for UDP/DoQ/DoH3 as well

Right now I'd be inclined to prefer the second option, because it seems useful to support it there as well, but I have not looked at all the implications.

rgacogne avatar May 05 '25 10:05 rgacogne

I also prefer the second option :-)

My use case is running dnsdist in front of authoritative nameservers, and this can be 8 addresses per nameserver "group" (four nameserver names, IPv4 + IPv6), with multiple "groups" of nameservers. So if there's an efficiency benefit (e.g. "avoids the creation of new thread and Frontend objects, reducing the memory usage") that would be nice, rather than defining a BindConfiguration for every IP address. If there's no real efficiency benefit for Do53 UDP (maybe the documented efficiency benefits are just for the TCP-based protocols?) then I'm happy to just generate all the BindConfigurations needed for each IP address, though.

Thanks!

edmonds avatar May 05 '25 16:05 edmonds

I finally had the time to look into this, and I don't think there would be much to gain for UDP-based protocols (including DoQ and DoH3), but I think it would still be nice to be able to bind on several addresses without duplicating the BindConfiguration. Let's see if I can make it work without adding too much complexity.

rgacogne avatar Jun 23 '25 09:06 rgacogne

I have working code for DoQ and DoH3, which is already a bit too complex to my liking to be included in 2.0.x, and looking at the UDP code it will require some refactoring. I already intended to refactor that area for 2.1.x, to make the AF_XDP code faster, so I'm going to postpone this to 2.1.x. In the meantime I'll make it an error to use additional addresses for UDP/DoQ/DoH3 and document it.

rgacogne avatar Jun 26 '25 09:06 rgacogne