mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-18 02:48:40 +00:00
net/dns: support split DNS in systemd-resolved.
Signed-off-by: David Anderson <danderson@tailscale.com>
This commit is contained in:
parent
00d641d9fc
commit
a7340c2015
@ -8,13 +8,10 @@ import "tailscale.com/types/logger"
|
||||
|
||||
func NewOSConfigurator(logf logger.Logf, interfaceName string) OSConfigurator {
|
||||
switch {
|
||||
case isResolvedActive():
|
||||
return newResolvedManager()
|
||||
case isNMActive():
|
||||
return newNMManager(interfaceName)
|
||||
// TODO: rework NetworkManager and resolved support.
|
||||
// case isResolvedActive():
|
||||
// return newResolvedManager()
|
||||
// case isNMActive():
|
||||
// return newNMManager(interfaceName)
|
||||
case isResolvconfActive():
|
||||
return newResolvconfManager(logf)
|
||||
default:
|
||||
|
@ -12,12 +12,12 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
|
||||
"github.com/godbus/dbus/v5"
|
||||
"golang.org/x/sys/unix"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/net/interfaces"
|
||||
"tailscale.com/util/dnsname"
|
||||
)
|
||||
|
||||
// resolvedListenAddr is the listen address of the resolved stub resolver.
|
||||
@ -51,15 +51,20 @@ type resolvedLinkDomain struct {
|
||||
|
||||
// isResolvedActive determines if resolved is currently managing system DNS settings.
|
||||
func isResolvedActive() bool {
|
||||
// systemd-resolved is never installed without systemd.
|
||||
_, err := exec.LookPath("systemctl")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), reconfigTimeout)
|
||||
defer cancel()
|
||||
|
||||
conn, err := dbus.SystemBus()
|
||||
if err != nil {
|
||||
// Probably no DBus on the system, or we're not allowed to use
|
||||
// it. Cannot control resolved.
|
||||
return false
|
||||
}
|
||||
|
||||
// is-active exits with code 3 if the service is not active.
|
||||
err = exec.Command("systemctl", "is-active", "systemd-resolved").Run()
|
||||
if err != nil {
|
||||
rd := conn.Object("org.freedesktop.resolve1", dbus.ObjectPath("/org/freedesktop/resolve1"))
|
||||
call := rd.CallWithContext(ctx, "org.freedesktop.DBus.Peer.Ping", 0)
|
||||
if call.Err != nil {
|
||||
// Can't talk to resolved.
|
||||
return false
|
||||
}
|
||||
|
||||
@ -134,12 +139,37 @@ func (m resolvedManager) SetDNS(config OSConfig) error {
|
||||
return fmt.Errorf("setLinkDNS: %w", err)
|
||||
}
|
||||
|
||||
var linkDomains = make([]resolvedLinkDomain, len(config.SearchDomains))
|
||||
for i, domain := range config.SearchDomains {
|
||||
linkDomains[i] = resolvedLinkDomain{
|
||||
Domain: domain.WithoutTrailingDot(),
|
||||
RoutingOnly: false,
|
||||
linkDomains := make([]resolvedLinkDomain, 0, len(config.SearchDomains)+len(config.MatchDomains))
|
||||
seenDomains := map[dnsname.FQDN]bool{}
|
||||
for _, domain := range config.SearchDomains {
|
||||
if seenDomains[domain] {
|
||||
continue
|
||||
}
|
||||
seenDomains[domain] = true
|
||||
linkDomains = append(linkDomains, resolvedLinkDomain{
|
||||
Domain: domain.WithTrailingDot(),
|
||||
RoutingOnly: false,
|
||||
})
|
||||
}
|
||||
for _, domain := range config.MatchDomains {
|
||||
if seenDomains[domain] {
|
||||
// Search domains act as both search and match in
|
||||
// resolved, so it's correct to skip.
|
||||
continue
|
||||
}
|
||||
seenDomains[domain] = true
|
||||
linkDomains = append(linkDomains, resolvedLinkDomain{
|
||||
Domain: domain.WithTrailingDot(),
|
||||
RoutingOnly: true,
|
||||
})
|
||||
}
|
||||
if len(config.MatchDomains) == 0 {
|
||||
// Caller requested full DNS interception, install a
|
||||
// routing-only root domain.
|
||||
linkDomains = append(linkDomains, resolvedLinkDomain{
|
||||
Domain: ".",
|
||||
RoutingOnly: true,
|
||||
})
|
||||
}
|
||||
|
||||
err = resolved.CallWithContext(
|
||||
@ -150,11 +180,41 @@ func (m resolvedManager) SetDNS(config OSConfig) error {
|
||||
return fmt.Errorf("setLinkDomains: %w", err)
|
||||
}
|
||||
|
||||
// Some best-effort setting of things, but resolved should do the
|
||||
// right thing if these fail (e.g. a really old resolved version
|
||||
// or something).
|
||||
|
||||
// Disable LLMNR, we don't do multicast.
|
||||
if call := resolved.CallWithContext(ctx, "org.freedesktop.resolve1.Manager.SetLinkLLMNR", 0, iface.Index, "no"); call.Err != nil {
|
||||
// TODO: log
|
||||
}
|
||||
|
||||
// Disable mdns.
|
||||
if call := resolved.CallWithContext(ctx, "org.freedesktop.resolve1.Manager.SetLinkMulticastDNS", 0, iface.Index, "no"); call.Err != nil {
|
||||
// TODO: log
|
||||
}
|
||||
|
||||
// We don't support dnssec consistently right now, force it off to
|
||||
// avoid partial failures when we split DNS internally.
|
||||
if call := resolved.CallWithContext(ctx, "org.freedesktop.resolve1.Manager.SetLinkDNSSEC", 0, iface.Index, "no"); call.Err != nil {
|
||||
// TODO: log
|
||||
}
|
||||
|
||||
if call := resolved.CallWithContext(ctx, "org.freedesktop.resolve1.Manager.SetLinkDNSOverTLS", 0, iface.Index, "no"); call.Err != nil {
|
||||
// TODO: log
|
||||
}
|
||||
|
||||
err = resolved.CallWithContext(
|
||||
ctx, "org.freedesktop.resolve1.Manager.FlushCaches", 0).Store()
|
||||
if err != nil {
|
||||
// TODO: log
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m resolvedManager) SupportsSplitDNS() bool {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
func (m resolvedManager) GetBaseConfig() (OSConfig, error) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user