unbound icon indicating copy to clipboard operation
unbound copied to clipboard

forward-first: ssl handshake failed on root nameservers.

Open planetf1 opened this issue 8 months ago • 9 comments

Describe the bug With 'forward-first' active, unbound attempts to connect to root nameservers using SSL

<29>1 2025-03-04T08:40:44+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="36"] [1838:3] notice: ssl handshake failed 192.33.4.12 port 53
<27>1 2025-03-04T08:41:03+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="37"] [1838:2] error: ssl handshake failed: channel closed
<29>1 2025-03-04T08:41:03+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="38"] [1838:2] notice: ssl handshake failed 192.112.36.4 port 53
<27>1 2025-03-04T08:41:03+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="39"] [1838:2] error: ssl handshake failed: channel closed
<29>1 2025-03-04T08:41:03+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="40"] [1838:2] notice: ssl handshake failed 2801:1b8:10::b port 53
<27>1 2025-03-04T08:41:04+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="41"] [1838:2] error: ssl handshake failed: channel closed
<29>1 2025-03-04T08:41:04+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="42"] [1838:2] notice: ssl handshake failed 2801:1b8:10::b port 53
<27>1 2025-03-04T08:41:14+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="43"] [1838:3] error: ssl handshake failed: channel closed
<29>1 2025-03-04T08:41:14+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="44"] [1838:3] notice: ssl handshake failed 2001:500:12::d0d port 53
<27>1 2025-03-04T08:41:34+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="45"] [1838:2] error: ssl handshake failed: channel closed
<29>1 2025-03-04T08:41:34+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="46"] [1838:2] notice: ssl handshake failed 2001:dc3::35 port 53
<27>1 2025-03-04T08:41:37+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="47"] [1838:1] error: ssl handshake failed: channel closed
<29>1 2025-03-04T08:41:37+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="48"] [1838:1] notice: ssl handshake failed 198.97.190.53 port 53
<27>1 2025-03-04T08:41:44+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="49"] [1838:3] error: ssl handshake failed: channel closed
<29>1 2025-03-04T08:41:44+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="50"] [1838:3] notice: ssl handshake failed 2001:500:12::d0d port 53
<27>1 2025-03-04T08:41:52+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="51"] [1838:1] error: ssl handshake failed: channel closed
<29>1 2025-03-04T08:41:52+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="52"] [1838:1] notice: ssl handshake failed 198.97.190.53 port 53
<27>1 2025-03-04T08:41:53+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="53"] [1838:1] error: ssl handshake failed: channel closed
<29>1 2025-03-04T08:41:53+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="54"] [1838:1] notice: ssl handshake failed 170.247.170.2 port 53
<27>1 2025-03-04T08:41:53+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="55"] [1838:1] error: ssl handshake failed: channel closed
<29>1 2025-03-04T08:41:53+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="56"] [1838:1] notice: ssl handshake failed 170.247.170.2 port 53
<27>1 2025-03-04T08:42:04+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="57"] [1838:2] error: ssl handshake failed: channel closed
<29>1 2025-03-04T08:42:04+00:00 OPNsense.cherrybyte.me.uk unbound 1838 - [meta sequenceId="58"] [1838:2] notice: ssl handshake failed 2001:dc3::35 port 53

To reproduce Steps to reproduce the behavior:

  • Configure unbound to use quad9 as the primary resolver for all domains
  • Use forward-first to cause unbound to fallback to recursive resolution if quad9 fails

For example using this fragment

# Forward zones

# Forward zones over TLS
server:
  tls-cert-bundle: /usr/local/etc/ssl/cert.pem

forward-zone:
  name: "."
  forward-tls-upstream: yes
  forward-addr: 2620:fe::9@853#dns.quad9.net
  forward-addr: 149.112.112.112@853#dns.quad9.net
  forward-addr: 9.9.9.9@853#dns.quad9.net
  forward-addr: 2620:fe::fe@853#dns.quad9.net
  forward-first: yes

Unbound appears to be trying to connect to root nameservers using TLS, which they do not support

Expected behavior unbound connects to root nameservers using a non-SSL connection to act as backup (whether when needed, or ahead of time)

System:

  • Unbound version: 1.22
  • OS: FreeBSD 14.2-RELEASE-p2 stable/25.1-n269670-fd3d1a7d1e1 SMP amd64
  • unbound -V output:
Version 1.22.0

Configure line: --with-libexpat=/usr/local --with-libnghttp2 --with-ssl=/usr/local --enable-dnscrypt --disable-dnstap --with-dynlibmodule --enable-ecdsa --disable-event-api --enable-gost --with-libevent --with-pythonmodule=yes --with-pyunbound=yes ac_cv_path_SWIG=/usr/local/bin/swig LDFLAGS=-L/usr/local/lib --disable-subnet --disable-tfo-client --disable-tfo-server --with-pthreads --prefix=/usr/local --localstatedir=/var --mandir=/usr/local/share/man --infodir=/usr/local/share/info/ --build=amd64-portbld-freebsd14.2
Linked libs: libevent 2.1.12-stable (it uses kqueue), OpenSSL 3.0.16 11 Feb 2025
Linked modules: dns64 python dynlib respip validator iterator
DNSCrypt feature available

BSD licensed, see LICENSE in source package for details.
Report bugs to [email protected] or https://github.com/NLnetLabs/unbound/issues

Additional information

This may relate to forward-tls-upstream - but the primary forward addresses require TLS, it's just the 'forward-first' directive which gets it to use recursive that may be causing an issue

The current impact is that forward-first will not work when TLS is being used for the primary servers for a domain.

planetf1 avatar Mar 04 '25 09:03 planetf1

Note - I do not have either directive specified in the general server block, only in this server zone configuration

planetf1 avatar Mar 04 '25 09:03 planetf1

Also possibly related:

  • https://github.com/NLnetLabs/unbound/issues/1097

planetf1 avatar Mar 04 '25 09:03 planetf1

The root name servers do not support DNS over TLS and a forward zone is there so that Unbound sends the DNS requests you make to another upstream server via DNS over TLS e.g. to quad9 as you specified, so you have to add more settings that you need here is an example of options: https://github.com/NLnetLabs/unbound/blob/master/doc/example.conf.in https://unbound.docs.nlnetlabs.nl/en/latest/

Aura67 avatar Mar 05 '25 15:03 Aura67

Thanks @aura67 - I took a look at the annotated configuration file, but I couldn't see how I might configure

  • primarily lookup using TLS
  • fallback to root nameservers & recursion

The forward-first seems to be intended to do this, generally, but it retains the use of TLS - which as you say, and I know, is not supported by the root ns.

So I guess I'm wondering if there's a way to have a fallback (not round robin etc.. only to be used in error cases) to recursion without tls.

It seems not?

planetf1 avatar Mar 07 '25 17:03 planetf1

no, you can either only talk to the root server with unbound or you configure unbound so that it uses a forward zone with dns over tls with other upstream servers and the option :-> forward-first I would leave on default = no so that unbound can cache the answers that come from the upstream server so that unbound doesn't have to ask every time with quad9 for example that happens if you set forward-first to yes so that it asks every time so just leave it on standard you have to decide for yourself whether you want to talk to a different server or rather to the root servers where the domain is held but if you talk to the root server you can't encrypt anything you can only do that with a forward zone and the configuration of the forward zone never comes at the beginning of an unbound configuration but rather at the end of the config you should add options for this I have linked the examples

Aura67 avatar Mar 07 '25 18:03 Aura67

Thanks

  • I understand the root name servers don't support DNS over TLS
  • I understand the forward zone in my case is configured to use TLS as I have forward-tls-upstream (this is intended to protect DNS requests in most cases, plus Quad9 is the primary as it has filtering for the worst malicious sites). I do have 2 ipv4 and 2 ipv6 addresses listed which provides some redundancy, but doesn't handle the case (which has happened) where a provider messes up badly...
  • don't see in the example configs (there are many) have an option to configure a DoT forwarder with a fallback to non-TLS recursion. They cover one or the other
  • I can leave forward-first off, but in this case I don't have fallback beyond the quad9 servers

I do have a few options I can go with, though none really address what was my hope with forward-first

  • Having more servers as part of the forward zone, adding in other DNS providers such as cloudflare -- this will work in general in terms of name resolution, but would be less good from a threat protection perspective (quad9 >> cloudflare) - since I understand the providers aren't in any kind of priority setup (correct?).
  • I could have multiple dns servers sent to clients over DHCP - but that hits a similar issue to above since they too don't typically have a priority, but more often will do random, or prioritize on response
  • I could use a different DNS server which has this capability (tbh unbound is very good, so this isn't overly appealing!, I do know of some simpler dns forwarders that do allow this though, I suppose I could put them in front of unbound)
  • If anyone would want to share a few hints on how this might be possible I'd be happy to look at the code in more depth and see if a PR proposal might be possible.
  • or is there something I'm missing in the config that does mean the original scenario is possible?

Many thanks

planetf1 avatar Mar 09 '25 11:03 planetf1

Same issue here. I'm using OpenWRT 24.10.

  • in my understanding the configuration to do a tls-protected dns-request via sticks to that forwarding zone, where it is configured.
  • there is no reason to keep TLS protection in case fallback to open recursion kicks in.
  • in my case - as above - root servers are contacted via TLS on port 53: daemon.notice unbound: [30600:0] notice: ssl handshake failed 2001:500:2::c port 53

immanuelsch avatar Apr 03 '25 21:04 immanuelsch

same Problem here.

The Documentation is very misleading here

If a forwarded query is met with a SERVFAIL error, and this op- tion is enabled, Unbound will fall back to normal recursive res- olution for this query as if no query forwarding had been speci- fied. The default is "no".

at the moment this option just creates a non working setup, when used with a DOT Forwarder

loomy avatar Jun 20 '25 05:06 loomy

I checked the Logs and the sources. I managed to get a working recursive fallback resolving with this change in iterator.c

diff --git a/iterator/iterator.c b/iterator/iterator.c
index 0bf5523c5..266083caf 100644
--- a/iterator/iterator.c
+++ b/iterator/iterator.c
@@ -2141,6 +2141,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
        int query_count = 0;
        verbose(VERB_ALGO, "No more query targets, attempting last resort");
        log_assert(iq->dp);
+       iq->dp->ssl_upstream = 0;
 
        if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen,
                iq->qchase.qclass, NULL, NULL, NULL)) {

for my use case this last resort is only called if forwarding fails and forward-first is yes.

if the DoT forwarder is available again, it switches back to forwarding and ssl.

As I am not used to the code, maybe someone else could check this and can tell me, what I am destroying with this change?

loomy avatar Jun 20 '25 11:06 loomy

Hi @loomy,

As I am not used to the code, maybe someone else could check this and can tell me, what I am destroying with this change?

In your very specific example nothing but generally you hardcode a value that may conflict with the one configured in a possible equal stub-zone that may be configured next to the forward-zone, or the global tls-upstream configuration.

But thanks for looking and pointing to the correct location in the code :)

If you want to test it locally you can grab the referenced commits (you can skip the one about testing).

gthess avatar Jun 25 '25 12:06 gthess

If you want to test it locally you can grab the referenced commits (you can skip the one about testing).

tested and works as expected. thx for the information and the fix

loomy avatar Jun 27 '25 10:06 loomy

Just noticed the update! Thanks for fixing this!

planetf1 avatar Aug 18 '25 16:08 planetf1