Is there a recommended way to set custom DNS (over TLS / HTTPS) servers globally *that will not break captive portal logins?*

Currently I use the ‘drop in’ method for systemd-resolved, but it breaks captive portal logins, and is tedious to undo and redo each time I need to login at a cafe or something.

edit: or if there is no straightforward way to do this globally, is there another approach that would make sense?

I think you cannot completely trust any captive portal as it can be compromised or just be a honeypot that looks like the real thing but actively tampers your traffic.

They may block DoH and DoT clients running in opportunistic mode to make them degrade to plain DNS and then utilize DNS hijacking.

A possible workaround is using a script to temporarily disable encrypted DNS or switch it to opportunistic mode, then revert the changes after a few seconds and flush the DNS cache:

resolvectl dnsovertls NET_IFACE opportunistic
sleep 20
resolvectl revert NET_IFACE
resolvectl flush-caches

You can try to invoke it automatically with NetworkManager dispatcher:
NetworkManager-dispatcher: NetworkManager Reference Manual

Also consider asking the NetworkManager developers directly:
Issues · NetworkManager / NetworkManager · GitLab


I don’t think this is task for the Network Manager. NM detects captive portal, its presence should be visible in nmcli general command.

What is failing is systemd-resolved missing support for captive portal scenario. dnssec-trigger package has some support for captive portals, but that lacks any support for DNS over TLS unfortunately. I doubt we have any decent support for it in any package at the moment. Found issue for systemd: Captive portals dont work · Issue #27485 · systemd/systemd · GitHub.

What is needed is some reaction to NM states and appropriate action from local DNS cache. I think encrypted DNS should be configured only after global connectivity pass. If we knew local name used for captive portal, we could use redirection only for that name on cache level. Unbound or dnsmasq would be able to do that. But I think NM does not export name, which is caught by HTTP redirection in connectivity check.

1 Like

This may work for opportunistic encryption mode, but it is not acceptable for mandatory mode since it creates the possibility of DNS leaks and DNS hijacking that can be exploited by an attacker with access to the captive portal.
In mandatory mode, this kind of security regression must be explicitly approved by the user, or it requires a different approach using split DNS with different trust levels for reserved domains.


Agreed. Split DNS should be able to obtain names required to pass captive portal. It may forward only those to unencrypted local resolvers offered by the network. If passing captive portal does not require additional domain names resolved, which I think would be true typically, it may pass portal without switching completely from DoT.

1 Like

I could not find anything about this. I think launching an instance of gnome’s/kde’s own webengines would be best.

Instead of breaking a secure default, it should only allow a single process to bypass it, just like on android which works perfectly.

Plasma 6 has a Gui captive portal detection implemented but I suppose this does not use split DNS yet.

Can someone give the command how to launch for example firefox with DOT and DNSSEC temporarily disabled, as well as no DNS servers stated?

And afterwards close that thing up again. Run the process in bubblejail, or as a flatpak, so many possibilities. Maybe tighten it up to allow no filesystem access at all.

(Sitting in a train with no wifi currently, sucks XD)