dnsdist: `additional_addresses` for Do53 frontends are bound to TCP only
-
[X] This is not a support question, I have read about opensource and will send support questions to the IRC channel, GitHub Discussions or the mailing list.
-
[X] I have read and understood the 'out in the open' support policy
-
Program: dnsdist
-
Issue type: Bug report
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.
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.
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!
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.
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.