This populates DNS suffixes ("ts.net", etc) in /etc/resolver/* files
to point to 100.100.100.100 so MagicDNS works.
It also sets search domains.
Updates #4276
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
main
parent
bbca2c78cb
commit
e97209c6bf
@ -0,0 +1,127 @@ |
||||
// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns |
||||
|
||||
import ( |
||||
"bytes" |
||||
"errors" |
||||
"os" |
||||
|
||||
"go4.org/mem" |
||||
"tailscale.com/types/logger" |
||||
"tailscale.com/util/mak" |
||||
) |
||||
|
||||
func NewOSConfigurator(logf logger.Logf, ifName string) (OSConfigurator, error) { |
||||
return &darwinConfigurator{logf: logf, ifName: ifName}, nil |
||||
} |
||||
|
||||
// darwinConfigurator is the tailscaled-on-macOS DNS OS configurator that
|
||||
// maintains the Split DNS nameserver entries pointing MagicDNS DNS suffixes
|
||||
// to 100.100.100.100 using the macOS /etc/resolver/$SUFFIX files.
|
||||
type darwinConfigurator struct { |
||||
logf logger.Logf |
||||
ifName string |
||||
} |
||||
|
||||
func (c *darwinConfigurator) Close() error { |
||||
c.removeResolverFiles(func(domain string) bool { return true }) |
||||
return nil |
||||
} |
||||
|
||||
func (c *darwinConfigurator) SupportsSplitDNS() bool { |
||||
return true |
||||
} |
||||
|
||||
func (c *darwinConfigurator) SetDNS(cfg OSConfig) error { |
||||
var buf bytes.Buffer |
||||
buf.WriteString(macResolverFileHeader) |
||||
for i, ip := range cfg.Nameservers { |
||||
if i == 0 { |
||||
buf.WriteString("nameserver ") |
||||
} else { |
||||
buf.WriteString(" ") |
||||
} |
||||
buf.WriteString(ip.String()) |
||||
} |
||||
buf.WriteString("\n") |
||||
|
||||
if err := os.MkdirAll("/etc/resolver", 0755); err != nil { |
||||
return err |
||||
} |
||||
|
||||
var keep map[string]bool |
||||
|
||||
// Add a dummy file to /etc/resolver with a "search ..." directive if we have
|
||||
// search suffixes to add.
|
||||
if len(cfg.SearchDomains) > 0 { |
||||
const searchFile = "search.tailscale" // fake DNS suffix+TLD to put our search
|
||||
mak.Set(&keep, searchFile, true) |
||||
var sbuf bytes.Buffer |
||||
sbuf.WriteString(macResolverFileHeader) |
||||
sbuf.WriteString("search") |
||||
for _, d := range cfg.SearchDomains { |
||||
sbuf.WriteString(" ") |
||||
sbuf.WriteString(string(d.WithoutTrailingDot())) |
||||
} |
||||
sbuf.WriteString("\n") |
||||
if err := os.WriteFile("/etc/resolver/"+searchFile, sbuf.Bytes(), 0644); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
|
||||
for _, d := range cfg.MatchDomains { |
||||
fileBase := string(d.WithoutTrailingDot()) |
||||
mak.Set(&keep, fileBase, true) |
||||
fullPath := "/etc/resolver/" + fileBase |
||||
|
||||
if err := os.WriteFile(fullPath, buf.Bytes(), 0644); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
return c.removeResolverFiles(func(domain string) bool { return !keep[domain] }) |
||||
} |
||||
|
||||
func (c *darwinConfigurator) GetBaseConfig() (OSConfig, error) { |
||||
return OSConfig{}, errors.New("[unexpected] unreachable") |
||||
} |
||||
|
||||
const macResolverFileHeader = "# Added by tailscaled\n" |
||||
|
||||
// removeResolverFiles deletes all files in /etc/resolver for which the shouldDelete
|
||||
// func returns true.
|
||||
func (c *darwinConfigurator) removeResolverFiles(shouldDelete func(domain string) bool) error { |
||||
dents, err := os.ReadDir("/etc/resolver") |
||||
if os.IsNotExist(err) { |
||||
return nil |
||||
} |
||||
if err != nil { |
||||
return err |
||||
} |
||||
for _, de := range dents { |
||||
if !de.Type().IsRegular() { |
||||
continue |
||||
} |
||||
name := de.Name() |
||||
if !shouldDelete(name) { |
||||
continue |
||||
} |
||||
fullPath := "/etc/resolver/" + name |
||||
contents, err := os.ReadFile(fullPath) |
||||
if err != nil { |
||||
if os.IsNotExist(err) { // race?
|
||||
continue |
||||
} |
||||
return err |
||||
} |
||||
if !mem.HasPrefix(mem.B(contents), mem.S(macResolverFileHeader)) { |
||||
continue |
||||
} |
||||
if err := os.Remove(fullPath); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
Loading…
Reference in new issue