Skip to content

WIP: Implement Linux DNS support via systemd-resolved#2575

Open
jmariondev wants to merge 2 commits intozerotier:devfrom
jmariondev:systemd-resolved-dns
Open

WIP: Implement Linux DNS support via systemd-resolved#2575
jmariondev wants to merge 2 commits intozerotier:devfrom
jmariondev:systemd-resolved-dns

Conversation

@jmariondev
Copy link
Copy Markdown

Implements LinuxEthernetTap::setDns. The allowDNS network flag now works on Linux, matching existing Windows and macOS behavior.

This partially addresses #2492 , though has only been tested on Fedora 43. The polkit approach may need to be fixed for Debian/Ubuntu.

Approach

  • New LinuxDNSHelper class following the same pattern as WinDNSHelper and MacDNSHelper
  • Calls resolvectl dns <iface> <servers> and resolvectl domain <iface> ~<domain> to configure per-interface DNS routing via systemd-resolved, the recommended approach for VPN-like services
  • The ~ domain prefix configures a route-only domain (not a search domain), so queries matching that suffix are routed to the ZT DNS servers without polluting global resolution
  • Cleanup via resolvectl revert <iface> in the destructor and when allowDNS is toggled off
  • Subprocess spawning uses fork/exec matching the existing _routeCmd pattern in ManagedRoute.cpp

Non-systemd systems

Checks for /run/systemd/resolve/stub-resolv.conf before attempting any resolvectl calls. If systemd-resolved is not active, setDNS logs a warning pointing to #2492 and returns.

polkit rule

(This was developed for Fedora, I'm not sure of the Debian/Ubuntu situation here)

ZeroTier drops root privileges to the zerotier-one user at startup (retaining CAP_NET_ADMIN/CAP_NET_RAW). However, systemd-resolved checks polkit identity — not capabilities — for DNS changes. A polkit rule is included and installed by the RPM spec to grant the zerotier-one user access to org.freedesktop.resolve1.{set-dns-servers,set-domains,revert}.

Interface name vs network ID

Unlike Windows/macOS helpers which take a network ID, LinuxDNSHelper takes an interface name because resolvectl operates on interfaces.


This PR was created with help from Claude.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 5, 2026

CLA assistant check
All committers have signed the CLA.

Drop capabilities, close inherited file descriptors, and sanitize the
environment before execing resolvectl. The ZeroTier daemon retains
CAP_NET_ADMIN/CAP_NET_RAW as ambient capabilities after dropping root,
which were being inherited by child processes unnecessarily. resolvectl
only needs D-Bus access to systemd-resolved.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jmariondev
Copy link
Copy Markdown
Author

I've added a second commit that focuses on subprocess security.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants