mirror of https://github.com/tailscale/tailscale/
net/dns: add tailscaled-on-macOS DNS OSConfigurator
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>pull/4513/head
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