From 97d2fa2f5691b2d41384a356a6fcd53bd538b80a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 26 Apr 2021 15:14:41 -0700 Subject: [PATCH] net/dns: work around WSL DNS implementation flaws. Fixes tailscale/corp#1662 Signed-off-by: David Anderson --- net/dns/manager.go | 26 ++++++++++++++++++++++++-- net/dns/manager_test.go | 5 +++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/net/dns/manager.go b/net/dns/manager.go index e5385c484..e59842548 100644 --- a/net/dns/manager.go +++ b/net/dns/manager.go @@ -5,6 +5,7 @@ package dns import ( + "runtime" "strings" "time" @@ -118,7 +119,27 @@ func (m *Manager) compileConfig(cfg Config) (resolver.Config, OSConfig, error) { var rcfg resolver.Config var ocfg OSConfig - if !cfg.hasHosts() && cfg.singleResolverSet() != nil && m.os.SupportsSplitDNS() { + // Workaround for + // https://github.com/tailscale/corp/issues/1662. Even though + // Windows natively supports split DNS, it only configures linux + // containers using whatever the primary is, and doesn't apply + // NRPT rules to DNS traffic coming from WSL. + // + // In order to make WSL work okay when the host Windows is using + // Tailscale, we need to set up quad-100 as a "full proxy" + // resolver, regardless of whether Windows itself can do split + // DNS. We still make Windows do split DNS itself when it can, but + // quad-100 will still have the full split configuration as well, + // and so can service WSL requests correctly. + // + // This bool is used in a couple of places below to implement this + // workaround. + isWindows := runtime.GOOS == "windows" + + // The windows check is for + // . See also below + // for further routing workarounds there. + if !cfg.hasHosts() && cfg.singleResolverSet() != nil && m.os.SupportsSplitDNS() && !isWindows { // Split DNS configuration requested, where all split domains // go to the same resolvers. We can let the OS do it. return resolver.Config{}, OSConfig{ @@ -148,7 +169,8 @@ func (m *Manager) compileConfig(cfg Config) (resolver.Config, OSConfig, error) { // resolver config and blend it into our config. if m.os.SupportsSplitDNS() { ocfg.MatchDomains = cfg.matchDomains() - } else { + } + if !m.os.SupportsSplitDNS() || isWindows { bcfg, err := m.os.GetBaseConfig() if err != nil { // Temporary hack to make OSes where split-DNS isn't fully diff --git a/net/dns/manager_test.go b/net/dns/manager_test.go index 8610dd0d0..0d49ea344 100644 --- a/net/dns/manager_test.go +++ b/net/dns/manager_test.go @@ -5,6 +5,7 @@ package dns import ( + "runtime" "testing" "github.com/google/go-cmp/cmp" @@ -45,6 +46,10 @@ func (c *fakeOSConfigurator) GetBaseConfig() (OSConfig, error) { func (c *fakeOSConfigurator) Close() error { return nil } func TestManager(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skipf("test's assumptions break because of https://github.com/tailscale/corp/issues/1662") + } + // Note: these tests assume that it's safe to switch the // OSConfigurator's split-dns support on and off between Set // calls. Empirically this is currently true, because we reprobe