Update dependencies

This commit is contained in:
bluepython508
2025-04-09 01:00:12 +01:00
parent f0641ffd6e
commit 5a9cfc022c
882 changed files with 68930 additions and 24201 deletions

View File

@@ -6,21 +6,25 @@ package dns
import (
"bytes"
"context"
"fmt"
"github.com/illarion/gonotify/v2"
"github.com/illarion/gonotify/v3"
"tailscale.com/health"
)
func (m *directManager) runFileWatcher() {
ctx, cancel := context.WithCancel(m.ctx)
defer cancel()
in, err := gonotify.NewInotify(ctx)
if err != nil {
// Oh well, we tried. This is all best effort for now, to
// surface warnings to users.
m.logf("dns: inotify new: %v", err)
return
if err := watchFile(m.ctx, "/etc/", resolvConf, m.checkForFileTrample); err != nil {
// This is all best effort for now, so surface warnings to users.
m.logf("dns: inotify: %s", err)
}
}
// watchFile sets up an inotify watch for a given directory and
// calls the callback function every time a particular file is changed.
// The filename should be located in the provided directory.
func watchFile(ctx context.Context, dir, filename string, cb func()) error {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
const events = gonotify.IN_ATTRIB |
gonotify.IN_CLOSE_WRITE |
@@ -29,30 +33,20 @@ func (m *directManager) runFileWatcher() {
gonotify.IN_MODIFY |
gonotify.IN_MOVE
if err := in.AddWatch("/etc/", events); err != nil {
m.logf("dns: inotify addwatch: %v", err)
return
watcher, err := gonotify.NewDirWatcher(ctx, events, dir)
if err != nil {
return fmt.Errorf("NewDirWatcher: %w", err)
}
for {
events, err := in.Read()
if ctx.Err() != nil {
return
}
if err != nil {
m.logf("dns: inotify read: %v", err)
return
}
var match bool
for _, ev := range events {
if ev.Name == resolvConf {
match = true
break
select {
case event := <-watcher.C:
if event.Name == filename {
cb()
}
case <-ctx.Done():
return ctx.Err()
}
if !match {
continue
}
m.checkForFileTrample()
}
}

View File

@@ -8,6 +8,7 @@ import (
"context"
"encoding/binary"
"errors"
"fmt"
"io"
"net"
"net/netip"
@@ -18,7 +19,6 @@ import (
"sync/atomic"
"time"
xmaps "golang.org/x/exp/maps"
"tailscale.com/control/controlknobs"
"tailscale.com/health"
"tailscale.com/net/dns/resolver"
@@ -30,10 +30,14 @@ import (
"tailscale.com/types/logger"
"tailscale.com/util/clientmetric"
"tailscale.com/util/dnsname"
"tailscale.com/util/slicesx"
)
var (
errFullQueue = errors.New("request queue full")
// ErrNoDNSConfig is returned by RecompileDNSConfig when the Manager
// has no existing DNS configuration.
ErrNoDNSConfig = errors.New("no DNS configuration")
)
// maxActiveQueries returns the maximal number of DNS requests that can
@@ -90,21 +94,18 @@ func NewManager(logf logger.Logf, oscfg OSConfigurator, health *health.Tracker,
}
// Rate limit our attempts to correct our DNS configuration.
// This is done on incoming queries, we don't want to spam it.
limiter := rate.NewLimiter(1.0/5.0, 1)
// This will recompile the DNS config, which in turn will requery the system
// DNS settings. The recovery func should triggered only when we are missing
// upstream nameservers and require them to forward a query.
m.resolver.SetMissingUpstreamRecovery(func() {
m.mu.Lock()
defer m.mu.Unlock()
if m.config == nil {
return
}
if limiter.Allow() {
m.logf("DNS resolution failed due to missing upstream nameservers. Recompiling DNS configuration.")
m.setLocked(*m.config)
m.logf("resolution failed due to missing upstream nameservers. Recompiling DNS configuration.")
if err := m.RecompileDNSConfig(); err != nil {
m.logf("config recompilation failed: %v", err)
}
}
})
@@ -116,6 +117,26 @@ func NewManager(logf logger.Logf, oscfg OSConfigurator, health *health.Tracker,
// Resolver returns the Manager's DNS Resolver.
func (m *Manager) Resolver() *resolver.Resolver { return m.resolver }
// RecompileDNSConfig sets the DNS config to the current value, which has
// the side effect of re-querying the OS's interface nameservers. This should be used
// on platforms where the interface nameservers can change. Darwin, for example,
// where the nameservers aren't always available when we process a major interface
// change event, or platforms where the nameservers may change while tunnel is up.
//
// This should be called if it is determined that [OSConfigurator.GetBaseConfig] may
// give a better or different result than when [Manager.Set] was last called. The
// logic for making that determination is up to the caller.
//
// It returns [ErrNoDNSConfig] if the [Manager] has no existing DNS configuration.
func (m *Manager) RecompileDNSConfig() error {
m.mu.Lock()
defer m.mu.Unlock()
if m.config == nil {
return ErrNoDNSConfig
}
return m.setLocked(*m.config)
}
func (m *Manager) Set(cfg Config) error {
m.mu.Lock()
defer m.mu.Unlock()
@@ -156,11 +177,11 @@ func (m *Manager) setLocked(cfg Config) error {
return err
}
if err := m.os.SetDNS(ocfg); err != nil {
m.health.SetDNSOSHealth(err)
m.health.SetUnhealthy(osConfigurationSetWarnable, health.Args{health.ArgError: err.Error()})
return err
}
m.health.SetDNSOSHealth(nil)
m.health.SetHealthy(osConfigurationSetWarnable)
m.config = &cfg
return nil
@@ -203,7 +224,7 @@ func compileHostEntries(cfg Config) (hosts []*HostEntry) {
if len(hostsMap) == 0 {
return nil
}
hosts = xmaps.Values(hostsMap)
hosts = slicesx.MapValues(hostsMap)
slices.SortFunc(hosts, func(a, b *HostEntry) int {
if len(a.Hosts) == 0 && len(b.Hosts) == 0 {
return 0
@@ -217,6 +238,26 @@ func compileHostEntries(cfg Config) (hosts []*HostEntry) {
return hosts
}
var osConfigurationReadWarnable = health.Register(&health.Warnable{
Code: "dns-read-os-config-failed",
Title: "Failed to read system DNS configuration",
Text: func(args health.Args) string {
return fmt.Sprintf("Tailscale failed to fetch the DNS configuration of your device: %v", args[health.ArgError])
},
Severity: health.SeverityLow,
DependsOn: []*health.Warnable{health.NetworkStatusWarnable},
})
var osConfigurationSetWarnable = health.Register(&health.Warnable{
Code: "dns-set-os-config-failed",
Title: "Failed to set system DNS configuration",
Text: func(args health.Args) string {
return fmt.Sprintf("Tailscale failed to set the DNS configuration of your device: %v", args[health.ArgError])
},
Severity: health.SeverityMedium,
DependsOn: []*health.Warnable{health.NetworkStatusWarnable},
})
// compileConfig converts cfg into a quad-100 resolver configuration
// and an OS-level configuration.
func (m *Manager) compileConfig(cfg Config) (rcfg resolver.Config, ocfg OSConfig, err error) {
@@ -225,8 +266,10 @@ func (m *Manager) compileConfig(cfg Config) (rcfg resolver.Config, ocfg OSConfig
// the OS.
rcfg.Hosts = cfg.Hosts
routes := map[dnsname.FQDN][]*dnstype.Resolver{} // assigned conditionally to rcfg.Routes below.
var propagateHostsToOS bool
for suffix, resolvers := range cfg.Routes {
if len(resolvers) == 0 {
propagateHostsToOS = true
rcfg.LocalDomains = append(rcfg.LocalDomains, suffix)
} else {
routes[suffix] = resolvers
@@ -235,7 +278,7 @@ func (m *Manager) compileConfig(cfg Config) (rcfg resolver.Config, ocfg OSConfig
// Similarly, the OS always gets search paths.
ocfg.SearchDomains = cfg.SearchDomains
if m.goos == "windows" {
if propagateHostsToOS && m.goos == "windows" {
ocfg.Hosts = compileHostEntries(cfg)
}
@@ -320,9 +363,10 @@ func (m *Manager) compileConfig(cfg Config) (rcfg resolver.Config, ocfg OSConfig
// This is currently (2022-10-13) expected on certain iOS and macOS
// builds.
} else {
m.health.SetDNSOSHealth(err)
m.health.SetUnhealthy(osConfigurationReadWarnable, health.Args{health.ArgError: err.Error()})
return resolver.Config{}, OSConfig{}, err
}
m.health.SetHealthy(osConfigurationReadWarnable)
}
if baseCfg == nil {

View File

@@ -1,7 +1,7 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
//go:build !linux && !freebsd && !openbsd && !windows && !darwin
//go:build !linux && !freebsd && !openbsd && !windows && !darwin && !illumos && !solaris
package dns

14
vendor/tailscale.com/net/dns/manager_solaris.go generated vendored Normal file
View File

@@ -0,0 +1,14 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package dns
import (
"tailscale.com/control/controlknobs"
"tailscale.com/health"
"tailscale.com/types/logger"
)
func NewOSConfigurator(logf logger.Logf, health *health.Tracker, _ *controlknobs.Knobs, iface string) (OSConfigurator, error) {
return newDirectManager(logf, health), nil
}

View File

@@ -8,10 +8,12 @@ import (
"bytes"
"errors"
"fmt"
"maps"
"net/netip"
"os"
"os/exec"
"path/filepath"
"slices"
"sort"
"strings"
"sync"
@@ -140,9 +142,8 @@ func (m *windowsManager) setSplitDNS(resolvers []netip.Addr, domains []dnsname.F
return m.nrptDB.WriteSplitDNSConfig(servers, domains)
}
func setTailscaleHosts(prevHostsFile []byte, hosts []*HostEntry) ([]byte, error) {
b := bytes.ReplaceAll(prevHostsFile, []byte("\r\n"), []byte("\n"))
sc := bufio.NewScanner(bytes.NewReader(b))
func setTailscaleHosts(logf logger.Logf, prevHostsFile []byte, hosts []*HostEntry) ([]byte, error) {
sc := bufio.NewScanner(bytes.NewReader(prevHostsFile))
const (
header = "# TailscaleHostsSectionStart"
footer = "# TailscaleHostsSectionEnd"
@@ -151,6 +152,32 @@ func setTailscaleHosts(prevHostsFile []byte, hosts []*HostEntry) ([]byte, error)
"# This section contains MagicDNS entries for Tailscale.",
"# Do not edit this section manually.",
}
prevEntries := make(map[netip.Addr][]string)
addPrevEntry := func(line string) {
if line == "" || line[0] == '#' {
return
}
parts := strings.Split(line, " ")
if len(parts) < 1 {
return
}
addr, err := netip.ParseAddr(parts[0])
if err != nil {
logf("Parsing address from hosts: %v", err)
return
}
prevEntries[addr] = parts[1:]
}
nextEntries := make(map[netip.Addr][]string, len(hosts))
for _, he := range hosts {
nextEntries[he.Addr] = he.Hosts
}
var out bytes.Buffer
var inSection bool
for sc.Scan() {
@@ -164,26 +191,34 @@ func setTailscaleHosts(prevHostsFile []byte, hosts []*HostEntry) ([]byte, error)
continue
}
if inSection {
addPrevEntry(line)
continue
}
fmt.Fprintln(&out, line)
fmt.Fprintf(&out, "%s\r\n", line)
}
if err := sc.Err(); err != nil {
return nil, err
}
if len(hosts) > 0 {
fmt.Fprintln(&out, header)
for _, c := range comments {
fmt.Fprintln(&out, c)
}
fmt.Fprintln(&out)
for _, he := range hosts {
fmt.Fprintf(&out, "%s %s\n", he.Addr, strings.Join(he.Hosts, " "))
}
fmt.Fprintln(&out)
fmt.Fprintln(&out, footer)
unchanged := maps.EqualFunc(prevEntries, nextEntries, func(a, b []string) bool {
return slices.Equal(a, b)
})
if unchanged {
return nil, nil
}
return bytes.ReplaceAll(out.Bytes(), []byte("\n"), []byte("\r\n")), nil
if len(hosts) > 0 {
fmt.Fprintf(&out, "%s\r\n", header)
for _, c := range comments {
fmt.Fprintf(&out, "%s\r\n", c)
}
fmt.Fprintf(&out, "\r\n")
for _, he := range hosts {
fmt.Fprintf(&out, "%s %s\r\n", he.Addr, strings.Join(he.Hosts, " "))
}
fmt.Fprintf(&out, "\r\n%s\r\n", footer)
}
return out.Bytes(), nil
}
// setHosts sets the hosts file to contain the given host entries.
@@ -197,10 +232,15 @@ func (m *windowsManager) setHosts(hosts []*HostEntry) error {
if err != nil {
return err
}
outB, err := setTailscaleHosts(b, hosts)
outB, err := setTailscaleHosts(m.logf, b, hosts)
if err != nil {
return err
}
if outB == nil {
// No change to hosts file, therefore no write necessary.
return nil
}
const fileMode = 0 // ignored on windows.
// This can fail spuriously with an access denied error, so retry it a

4
vendor/tailscale.com/net/dns/nm.go generated vendored
View File

@@ -7,6 +7,7 @@ package dns
import (
"context"
"encoding/binary"
"fmt"
"net"
"net/netip"
@@ -14,7 +15,6 @@ import (
"time"
"github.com/godbus/dbus/v5"
"github.com/josharian/native"
"tailscale.com/net/tsaddr"
"tailscale.com/util/dnsname"
)
@@ -137,7 +137,7 @@ func (m *nmManager) trySet(ctx context.Context, config OSConfig) error {
for _, ip := range config.Nameservers {
b := ip.As16()
if ip.Is4() {
dnsv4 = append(dnsv4, native.Endian.Uint32(b[12:]))
dnsv4 = append(dnsv4, binary.NativeEndian.Uint32(b[12:]))
} else {
dnsv6 = append(dnsv6, b[:])
}

View File

@@ -57,6 +57,7 @@ func (m *resolvdManager) SetDNS(config OSConfig) error {
if len(newSearch) > 1 {
newResolvConf = append(newResolvConf, []byte(strings.Join(newSearch, " "))...)
newResolvConf = append(newResolvConf, '\n')
}
err = m.fs.WriteFile(resolvConf, newResolvConf, 0644)
@@ -123,6 +124,6 @@ func (m resolvdManager) readResolvConf() (config OSConfig, err error) {
}
func removeSearchLines(orig []byte) []byte {
re := regexp.MustCompile(`(?m)^search\s+.+$`)
re := regexp.MustCompile(`(?ms)^search\s+.+$`)
return re.ReplaceAll(orig, []byte(""))
}

View File

@@ -163,9 +163,9 @@ func (m *resolvedManager) run(ctx context.Context) {
}
conn.Signal(signals)
// Reset backoff and SetNSOSHealth after successful on reconnect.
// Reset backoff and set osConfigurationSetWarnable to healthy after a successful reconnect.
bo.BackOff(ctx, nil)
m.health.SetDNSOSHealth(nil)
m.health.SetHealthy(osConfigurationSetWarnable)
return nil
}
@@ -243,9 +243,12 @@ func (m *resolvedManager) run(ctx context.Context) {
// Set health while holding the lock, because this will
// graciously serialize the resync's health outcome with a
// concurrent SetDNS call.
m.health.SetDNSOSHealth(err)
if err != nil {
m.logf("failed to configure systemd-resolved: %v", err)
m.health.SetUnhealthy(osConfigurationSetWarnable, health.Args{health.ArgError: err.Error()})
} else {
m.health.SetHealthy(osConfigurationSetWarnable)
}
}
}

View File

@@ -384,7 +384,7 @@ func (r *Resolver) HandlePeerDNSQuery(ctx context.Context, q []byte, from netip.
// but for now that's probably good enough. Later we'll
// want to blend in everything from scutil --dns.
fallthrough
case "linux", "freebsd", "openbsd", "illumos", "ios":
case "linux", "freebsd", "openbsd", "illumos", "solaris", "ios":
nameserver, err := stubResolverForOS()
if err != nil {
r.logf("stubResolverForOS: %v", err)