Compare commits
6 Commits
d08e972dc0
...
3e64dc69e3
Author | SHA1 | Date |
---|---|---|
Irbe Krumina | 3e64dc69e3 | |
Jonathan Nobels | 71e9258ad9 | |
Brad Fitzpatrick | 745931415c | |
Brad Fitzpatrick | a4a282cd49 | |
Brad Fitzpatrick | 6d69fc137f | |
Irbe Krumina | 2fa7d1d836 |
|
@ -138,6 +138,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
|
|||
tailscale.com/types/structs from tailscale.com/ipn+
|
||||
tailscale.com/types/tkatype from tailscale.com/client/tailscale+
|
||||
tailscale.com/types/views from tailscale.com/ipn+
|
||||
tailscale.com/util/cibuild from tailscale.com/health
|
||||
tailscale.com/util/clientmetric from tailscale.com/net/netmon+
|
||||
tailscale.com/util/cloudenv from tailscale.com/hostinfo+
|
||||
W tailscale.com/util/cmpver from tailscale.com/net/tshttpproxy
|
||||
|
|
|
@ -14,10 +14,8 @@ spec:
|
|||
- name: sysctler
|
||||
securityContext:
|
||||
privileged: true
|
||||
command: ["/bin/sh"]
|
||||
args:
|
||||
- -c
|
||||
- sysctl -w net.ipv4.ip_forward=1 net.ipv6.conf.all.forwarding=1
|
||||
command: ["/bin/sh", "-c"]
|
||||
args: [sysctl -w net.ipv4.ip_forward=1; if sysctl net.ipv6.conf.all.forwarding; then sysctl -w net.ipv6.conf.all.forwarding=1; fi]
|
||||
resources:
|
||||
requests:
|
||||
cpu: 1m
|
||||
|
|
|
@ -189,8 +189,8 @@ func expectedSTS(t *testing.T, cl client.Client, opts configOpts) *appsv1.Statef
|
|||
{
|
||||
Name: "sysctler",
|
||||
Image: "tailscale/tailscale",
|
||||
Command: []string{"/bin/sh"},
|
||||
Args: []string{"-c", "sysctl -w net.ipv4.ip_forward=1 net.ipv6.conf.all.forwarding=1"},
|
||||
Command: []string{"/bin/sh", "-c"},
|
||||
Args: []string{"sysctl -w net.ipv4.ip_forward=1; if sysctl net.ipv6.conf.all.forwarding; then sysctl -w net.ipv6.conf.all.forwarding=1; fi"},
|
||||
SecurityContext: &corev1.SecurityContext{
|
||||
Privileged: ptr.To(true),
|
||||
},
|
||||
|
|
|
@ -142,6 +142,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
|||
tailscale.com/types/structs from tailscale.com/ipn+
|
||||
tailscale.com/types/tkatype from tailscale.com/types/key+
|
||||
tailscale.com/types/views from tailscale.com/tailcfg+
|
||||
tailscale.com/util/cibuild from tailscale.com/health
|
||||
tailscale.com/util/clientmetric from tailscale.com/net/netcheck+
|
||||
tailscale.com/util/cloudenv from tailscale.com/net/dnscache+
|
||||
tailscale.com/util/cmpver from tailscale.com/net/tshttpproxy+
|
||||
|
|
|
@ -358,6 +358,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||
tailscale.com/types/structs from tailscale.com/control/controlclient+
|
||||
tailscale.com/types/tkatype from tailscale.com/tka+
|
||||
tailscale.com/types/views from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/util/cibuild from tailscale.com/health
|
||||
tailscale.com/util/clientmetric from tailscale.com/control/controlclient+
|
||||
tailscale.com/util/cloudenv from tailscale.com/net/dns/resolver+
|
||||
tailscale.com/util/cmpver from tailscale.com/net/dns+
|
||||
|
|
|
@ -358,7 +358,7 @@ func run() (err error) {
|
|||
sys.Set(netMon)
|
||||
}
|
||||
|
||||
pol := logpolicy.New(logtail.CollectionNode, netMon, nil /* use log.Printf */)
|
||||
pol := logpolicy.New(logtail.CollectionNode, netMon, sys.HealthTracker(), nil /* use log.Printf */)
|
||||
pol.SetVerbosityLevel(args.verbose)
|
||||
logPol = pol
|
||||
defer func() {
|
||||
|
@ -651,6 +651,7 @@ func tryEngine(logf logger.Logf, sys *tsd.System, name string) (onlyNetstack boo
|
|||
conf := wgengine.Config{
|
||||
ListenPort: args.port,
|
||||
NetMon: sys.NetMon.Get(),
|
||||
HealthTracker: sys.HealthTracker(),
|
||||
Dialer: sys.Dialer.Get(),
|
||||
SetSubsystem: sys.Set,
|
||||
ControlKnobs: sys.ControlKnobs(),
|
||||
|
@ -676,7 +677,7 @@ func tryEngine(logf logger.Logf, sys *tsd.System, name string) (onlyNetstack boo
|
|||
// configuration being unavailable (from the noop
|
||||
// manager). More in Issue 4017.
|
||||
// TODO(bradfitz): add a Synology-specific DNS manager.
|
||||
conf.DNS, err = dns.NewOSConfigurator(logf, "") // empty interface name
|
||||
conf.DNS, err = dns.NewOSConfigurator(logf, sys.HealthTracker(), "") // empty interface name
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("dns.NewOSConfigurator: %w", err)
|
||||
}
|
||||
|
@ -698,13 +699,13 @@ func tryEngine(logf logger.Logf, sys *tsd.System, name string) (onlyNetstack boo
|
|||
return false, err
|
||||
}
|
||||
|
||||
r, err := router.New(logf, dev, sys.NetMon.Get())
|
||||
r, err := router.New(logf, dev, sys.NetMon.Get(), sys.HealthTracker())
|
||||
if err != nil {
|
||||
dev.Close()
|
||||
return false, fmt.Errorf("creating router: %w", err)
|
||||
}
|
||||
|
||||
d, err := dns.NewOSConfigurator(logf, devName)
|
||||
d, err := dns.NewOSConfigurator(logf, sys.HealthTracker(), devName)
|
||||
if err != nil {
|
||||
dev.Close()
|
||||
r.Close()
|
||||
|
|
|
@ -104,9 +104,10 @@ func newIPN(jsConfig js.Value) map[string]any {
|
|||
sys.Set(store)
|
||||
dialer := &tsdial.Dialer{Logf: logf}
|
||||
eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{
|
||||
Dialer: dialer,
|
||||
SetSubsystem: sys.Set,
|
||||
ControlKnobs: sys.ControlKnobs(),
|
||||
Dialer: dialer,
|
||||
SetSubsystem: sys.Set,
|
||||
ControlKnobs: sys.ControlKnobs(),
|
||||
HealthTracker: sys.HealthTracker(),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/logtail/backoff"
|
||||
"tailscale.com/net/sockstats"
|
||||
"tailscale.com/tailcfg"
|
||||
|
@ -195,7 +194,7 @@ func NewNoStart(opts Options) (_ *Auto, err error) {
|
|||
c.mapCtx, c.mapCancel = context.WithCancel(context.Background())
|
||||
c.mapCtx = sockstats.WithSockStats(c.mapCtx, sockstats.LabelControlClientAuto, opts.Logf)
|
||||
|
||||
c.unregisterHealthWatch = health.Global.RegisterWatcher(direct.ReportHealthChange)
|
||||
c.unregisterHealthWatch = opts.HealthTracker.RegisterWatcher(direct.ReportHealthChange)
|
||||
return c, nil
|
||||
|
||||
}
|
||||
|
@ -316,7 +315,7 @@ func (c *Auto) authRoutine() {
|
|||
}
|
||||
|
||||
if goal == nil {
|
||||
health.Global.SetAuthRoutineInError(nil)
|
||||
c.direct.health.SetAuthRoutineInError(nil)
|
||||
// Wait for user to Login or Logout.
|
||||
<-ctx.Done()
|
||||
c.logf("[v1] authRoutine: context done.")
|
||||
|
@ -343,7 +342,7 @@ func (c *Auto) authRoutine() {
|
|||
f = "TryLogin"
|
||||
}
|
||||
if err != nil {
|
||||
health.Global.SetAuthRoutineInError(err)
|
||||
c.direct.health.SetAuthRoutineInError(err)
|
||||
report(err, f)
|
||||
bo.BackOff(ctx, err)
|
||||
continue
|
||||
|
@ -373,7 +372,7 @@ func (c *Auto) authRoutine() {
|
|||
}
|
||||
|
||||
// success
|
||||
health.Global.SetAuthRoutineInError(nil)
|
||||
c.direct.health.SetAuthRoutineInError(nil)
|
||||
c.mu.Lock()
|
||||
c.urlToVisit = ""
|
||||
c.loggedIn = true
|
||||
|
@ -503,11 +502,11 @@ func (c *Auto) mapRoutine() {
|
|||
c.logf("[v1] mapRoutine: context done.")
|
||||
continue
|
||||
}
|
||||
health.Global.SetOutOfPollNetMap()
|
||||
c.direct.health.SetOutOfPollNetMap()
|
||||
|
||||
err := c.direct.PollNetMap(ctx, mrs)
|
||||
|
||||
health.Global.SetOutOfPollNetMap()
|
||||
c.direct.health.SetOutOfPollNetMap()
|
||||
c.mu.Lock()
|
||||
c.inMapPoll = false
|
||||
if c.state == StateSynchronized {
|
||||
|
|
|
@ -69,6 +69,7 @@ type Direct struct {
|
|||
clock tstime.Clock
|
||||
logf logger.Logf
|
||||
netMon *netmon.Monitor // or nil
|
||||
health *health.Tracker
|
||||
discoPubKey key.DiscoPublic
|
||||
getMachinePrivKey func() (key.MachinePrivate, error)
|
||||
debugFlags []string
|
||||
|
@ -119,10 +120,11 @@ type Options struct {
|
|||
Hostinfo *tailcfg.Hostinfo // non-nil passes ownership, nil means to use default using os.Hostname, etc
|
||||
DiscoPublicKey key.DiscoPublic
|
||||
Logf logger.Logf
|
||||
HTTPTestClient *http.Client // optional HTTP client to use (for tests only)
|
||||
NoiseTestClient *http.Client // optional HTTP client to use for noise RPCs (tests only)
|
||||
DebugFlags []string // debug settings to send to control
|
||||
NetMon *netmon.Monitor // optional network monitor
|
||||
HTTPTestClient *http.Client // optional HTTP client to use (for tests only)
|
||||
NoiseTestClient *http.Client // optional HTTP client to use for noise RPCs (tests only)
|
||||
DebugFlags []string // debug settings to send to control
|
||||
NetMon *netmon.Monitor // optional network monitor
|
||||
HealthTracker *health.Tracker
|
||||
PopBrowserURL func(url string) // optional func to open browser
|
||||
OnClientVersion func(*tailcfg.ClientVersion) // optional func to inform GUI of client version status
|
||||
OnControlTime func(time.Time) // optional func to notify callers of new time from control
|
||||
|
@ -248,7 +250,7 @@ func NewDirect(opts Options) (*Direct, error) {
|
|||
tr := http.DefaultTransport.(*http.Transport).Clone()
|
||||
tr.Proxy = tshttpproxy.ProxyFromEnvironment
|
||||
tshttpproxy.SetTransportGetProxyConnectHeader(tr)
|
||||
tr.TLSClientConfig = tlsdial.Config(serverURL.Hostname(), health.Global, tr.TLSClientConfig)
|
||||
tr.TLSClientConfig = tlsdial.Config(serverURL.Hostname(), opts.HealthTracker, tr.TLSClientConfig)
|
||||
tr.DialContext = dnscache.Dialer(opts.Dialer.SystemDial, dnsCache)
|
||||
tr.DialTLSContext = dnscache.TLSDialer(opts.Dialer.SystemDial, dnsCache, tr.TLSClientConfig)
|
||||
tr.ForceAttemptHTTP2 = true
|
||||
|
@ -271,6 +273,7 @@ func NewDirect(opts Options) (*Direct, error) {
|
|||
discoPubKey: opts.DiscoPublicKey,
|
||||
debugFlags: opts.DebugFlags,
|
||||
netMon: opts.NetMon,
|
||||
health: opts.HealthTracker,
|
||||
skipIPForwardingCheck: opts.SkipIPForwardingCheck,
|
||||
pinger: opts.Pinger,
|
||||
popBrowser: opts.PopBrowserURL,
|
||||
|
@ -894,10 +897,10 @@ func (c *Direct) sendMapRequest(ctx context.Context, isStreaming bool, nu Netmap
|
|||
ipForwardingBroken(hi.RoutableIPs, c.netMon.InterfaceState()) {
|
||||
extraDebugFlags = append(extraDebugFlags, "warn-ip-forwarding-off")
|
||||
}
|
||||
if health.Global.RouterHealth() != nil {
|
||||
if c.health.RouterHealth() != nil {
|
||||
extraDebugFlags = append(extraDebugFlags, "warn-router-unhealthy")
|
||||
}
|
||||
extraDebugFlags = health.Global.AppendWarnableDebugFlags(extraDebugFlags)
|
||||
extraDebugFlags = c.health.AppendWarnableDebugFlags(extraDebugFlags)
|
||||
if hostinfo.DisabledEtcAptSource() {
|
||||
extraDebugFlags = append(extraDebugFlags, "warn-etc-apt-source-disabled")
|
||||
}
|
||||
|
@ -970,7 +973,7 @@ func (c *Direct) sendMapRequest(ctx context.Context, isStreaming bool, nu Netmap
|
|||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
health.Global.NoteMapRequestHeard(request)
|
||||
c.health.NoteMapRequestHeard(request)
|
||||
watchdogTimer.Reset(watchdogTimeout)
|
||||
|
||||
if nu == nil {
|
||||
|
@ -1041,7 +1044,7 @@ func (c *Direct) sendMapRequest(ctx context.Context, isStreaming bool, nu Netmap
|
|||
metricMapResponseMessages.Add(1)
|
||||
|
||||
if isStreaming {
|
||||
health.Global.GotStreamedMapResponse()
|
||||
c.health.GotStreamedMapResponse()
|
||||
}
|
||||
|
||||
if pr := resp.PingRequest; pr != nil && c.isUniquePingRequest(pr) {
|
||||
|
@ -1450,14 +1453,15 @@ func (c *Direct) getNoiseClient() (*NoiseClient, error) {
|
|||
}
|
||||
c.logf("[v1] creating new noise client")
|
||||
nc, err := NewNoiseClient(NoiseOpts{
|
||||
PrivKey: k,
|
||||
ServerPubKey: serverNoiseKey,
|
||||
ServerURL: c.serverURL,
|
||||
Dialer: c.dialer,
|
||||
DNSCache: c.dnsCache,
|
||||
Logf: c.logf,
|
||||
NetMon: c.netMon,
|
||||
DialPlan: dp,
|
||||
PrivKey: k,
|
||||
ServerPubKey: serverNoiseKey,
|
||||
ServerURL: c.serverURL,
|
||||
Dialer: c.dialer,
|
||||
DNSCache: c.dnsCache,
|
||||
Logf: c.logf,
|
||||
NetMon: c.netMon,
|
||||
HealthTracker: c.health,
|
||||
DialPlan: dp,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"golang.org/x/net/http2"
|
||||
"tailscale.com/control/controlbase"
|
||||
"tailscale.com/control/controlhttp"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/net/dnscache"
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/net/tsdial"
|
||||
|
@ -174,6 +175,7 @@ type NoiseClient struct {
|
|||
|
||||
logf logger.Logf
|
||||
netMon *netmon.Monitor
|
||||
health *health.Tracker
|
||||
|
||||
// mu only protects the following variables.
|
||||
mu sync.Mutex
|
||||
|
@ -204,6 +206,8 @@ type NoiseOpts struct {
|
|||
// network interface state. This field can be nil; if so, the current
|
||||
// state will be looked up dynamically.
|
||||
NetMon *netmon.Monitor
|
||||
// HealthTracker, if non-nil, is the health tracker to use.
|
||||
HealthTracker *health.Tracker
|
||||
// DialPlan, if set, is a function that should return an explicit plan
|
||||
// on how to connect to the server.
|
||||
DialPlan func() *tailcfg.ControlDialPlan
|
||||
|
@ -247,6 +251,7 @@ func NewNoiseClient(opts NoiseOpts) (*NoiseClient, error) {
|
|||
dialPlan: opts.DialPlan,
|
||||
logf: opts.Logf,
|
||||
netMon: opts.NetMon,
|
||||
health: opts.HealthTracker,
|
||||
}
|
||||
|
||||
// Create the HTTP/2 Transport using a net/http.Transport
|
||||
|
@ -453,6 +458,7 @@ func (nc *NoiseClient) dial(ctx context.Context) (*noiseConn, error) {
|
|||
DialPlan: dialPlan,
|
||||
Logf: nc.logf,
|
||||
NetMon: nc.netMon,
|
||||
HealthTracker: nc.health,
|
||||
Clock: tstime.StdClock{},
|
||||
}).Dial(ctx)
|
||||
if err != nil {
|
||||
|
|
|
@ -38,7 +38,6 @@ import (
|
|||
|
||||
"tailscale.com/control/controlbase"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/net/dnscache"
|
||||
"tailscale.com/net/dnsfallback"
|
||||
"tailscale.com/net/netutil"
|
||||
|
@ -434,7 +433,7 @@ func (a *Dialer) tryURLUpgrade(ctx context.Context, u *url.URL, addr netip.Addr,
|
|||
// Disable HTTP2, since h2 can't do protocol switching.
|
||||
tr.TLSClientConfig.NextProtos = []string{}
|
||||
tr.TLSNextProto = map[string]func(string, *tls.Conn) http.RoundTripper{}
|
||||
tr.TLSClientConfig = tlsdial.Config(a.Hostname, health.Global, tr.TLSClientConfig)
|
||||
tr.TLSClientConfig = tlsdial.Config(a.Hostname, a.HealthTracker, tr.TLSClientConfig)
|
||||
if !tr.TLSClientConfig.InsecureSkipVerify {
|
||||
panic("unexpected") // should be set by tlsdial.Config
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"net/url"
|
||||
"time"
|
||||
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/net/dnscache"
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/tailcfg"
|
||||
|
@ -79,6 +80,9 @@ type Dialer struct {
|
|||
|
||||
NetMon *netmon.Monitor
|
||||
|
||||
// HealthTracker, if non-nil, is the health tracker to use.
|
||||
HealthTracker *health.Tracker
|
||||
|
||||
// DialPlan, if set, contains instructions from the control server on
|
||||
// how to connect to it. If present, we will try the methods in this
|
||||
// plan before falling back to DNS.
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
"sync"
|
||||
|
@ -18,6 +19,7 @@ import (
|
|||
"tailscale.com/envknob"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/opt"
|
||||
"tailscale.com/util/cibuild"
|
||||
"tailscale.com/util/mak"
|
||||
"tailscale.com/util/multierr"
|
||||
"tailscale.com/util/set"
|
||||
|
@ -28,15 +30,9 @@ var (
|
|||
debugHandler map[string]http.Handler
|
||||
)
|
||||
|
||||
// Global is a global health tracker for the process.
|
||||
//
|
||||
// TODO(bradfitz): finish moving all reference to this plumb it (ultimately out
|
||||
// from tsd.System) so a process can have multiple tsnet/etc instances with
|
||||
// their own health trackers. But for now (2024-04-25), the tsd.System value
|
||||
// given out is just this one, until that's the only remaining Global reference
|
||||
// remaining.
|
||||
var Global = new(Tracker)
|
||||
|
||||
// Tracker tracks the health of various Tailscale subsystems,
|
||||
// comparing each subsystems' state with each other to make sure
|
||||
// they're consistent based on the user's intended state.
|
||||
type Tracker struct {
|
||||
// mu guards everything in this var block.
|
||||
mu sync.Mutex
|
||||
|
@ -152,6 +148,11 @@ func (t *Tracker) nil() bool {
|
|||
if t != nil {
|
||||
return false
|
||||
}
|
||||
if cibuild.On() {
|
||||
stack := make([]byte, 1<<10)
|
||||
stack = stack[:runtime.Stack(stack, false)]
|
||||
fmt.Fprintf(os.Stderr, "## WARNING: (non-fatal) nil health.Tracker (being strict in CI):\n%s\n", stack)
|
||||
}
|
||||
// TODO(bradfitz): open source our "unexpected" package
|
||||
// and use it here to capture samples of stacks where
|
||||
// t is nil.
|
||||
|
|
|
@ -327,6 +327,16 @@ type LocalBackend struct {
|
|||
outgoingFiles map[string]*ipn.OutgoingFile
|
||||
}
|
||||
|
||||
// HealthTracker returns the health tracker for the backend.
|
||||
func (b *LocalBackend) HealthTracker() *health.Tracker {
|
||||
return b.health
|
||||
}
|
||||
|
||||
// NetMon returns the network monitor for the backend.
|
||||
func (b *LocalBackend) NetMon() *netmon.Monitor {
|
||||
return b.sys.NetMon.Get()
|
||||
}
|
||||
|
||||
type updateStatus struct {
|
||||
started bool
|
||||
}
|
||||
|
@ -405,7 +415,7 @@ func NewLocalBackend(logf logger.Logf, logID logid.PublicID, sys *tsd.System, lo
|
|||
}
|
||||
|
||||
netMon := sys.NetMon.Get()
|
||||
b.sockstatLogger, err = sockstatlog.NewLogger(logpolicy.LogsDir(logf), logf, logID, netMon)
|
||||
b.sockstatLogger, err = sockstatlog.NewLogger(logpolicy.LogsDir(logf), logf, logID, netMon, sys.HealthTracker())
|
||||
if err != nil {
|
||||
log.Printf("error setting up sockstat logger: %v", err)
|
||||
}
|
||||
|
@ -1753,6 +1763,7 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
|
|||
DiscoPublicKey: discoPublic,
|
||||
DebugFlags: debugFlags,
|
||||
NetMon: b.sys.NetMon.Get(),
|
||||
HealthTracker: b.health,
|
||||
Pinger: b,
|
||||
PopBrowserURL: b.tellClientToBrowseToURL,
|
||||
OnClientVersion: b.onClientVersion,
|
||||
|
@ -6242,6 +6253,7 @@ func mayDeref[T any](p *T) (v T) {
|
|||
}
|
||||
|
||||
var ErrNoPreferredDERP = errors.New("no preferred DERP, try again later")
|
||||
var ErrCannotSuggestExitNode = errors.New("unable to suggest an exit node, try again later")
|
||||
|
||||
// SuggestExitNode computes a suggestion based on the current netmap and last netcheck report. If
|
||||
// there are multiple equally good options, one is selected at random, so the result is not stable. To be
|
||||
|
@ -6255,6 +6267,9 @@ func (b *LocalBackend) SuggestExitNode() (response apitype.ExitNodeSuggestionRes
|
|||
lastReport := b.MagicConn().GetLastNetcheckReport(b.ctx)
|
||||
netMap := b.netMap
|
||||
b.mu.Unlock()
|
||||
if lastReport == nil || netMap == nil {
|
||||
return response, ErrCannotSuggestExitNode
|
||||
}
|
||||
seed := time.Now().UnixNano()
|
||||
r := rand.New(rand.NewSource(seed))
|
||||
return suggestExitNode(lastReport, netMap, r)
|
||||
|
|
|
@ -20,7 +20,6 @@ import (
|
|||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/health/healthmsg"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
|
@ -59,11 +58,11 @@ type tkaState struct {
|
|||
// b.mu must be held.
|
||||
func (b *LocalBackend) tkaFilterNetmapLocked(nm *netmap.NetworkMap) {
|
||||
if b.tka == nil && !b.capTailnetLock {
|
||||
health.Global.SetTKAHealth(nil)
|
||||
b.health.SetTKAHealth(nil)
|
||||
return
|
||||
}
|
||||
if b.tka == nil {
|
||||
health.Global.SetTKAHealth(nil)
|
||||
b.health.SetTKAHealth(nil)
|
||||
return // TKA not enabled.
|
||||
}
|
||||
|
||||
|
@ -117,9 +116,9 @@ func (b *LocalBackend) tkaFilterNetmapLocked(nm *netmap.NetworkMap) {
|
|||
|
||||
// Check that we ourselves are not locked out, report a health issue if so.
|
||||
if nm.SelfNode.Valid() && b.tka.authority.NodeKeyAuthorized(nm.SelfNode.Key(), nm.SelfNode.KeySignature().AsSlice()) != nil {
|
||||
health.Global.SetTKAHealth(errors.New(healthmsg.LockedOut))
|
||||
b.health.SetTKAHealth(errors.New(healthmsg.LockedOut))
|
||||
} else {
|
||||
health.Global.SetTKAHealth(nil)
|
||||
b.health.SetTKAHealth(nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,7 +187,7 @@ func (b *LocalBackend) tkaSyncIfNeeded(nm *netmap.NetworkMap, prefs ipn.PrefsVie
|
|||
b.logf("Disablement failed, leaving TKA enabled. Error: %v", err)
|
||||
} else {
|
||||
isEnabled = false
|
||||
health.Global.SetTKAHealth(nil)
|
||||
b.health.SetTKAHealth(nil)
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("[bug] unreachable invariant of wantEnabled w/ isEnabled")
|
||||
|
|
|
@ -199,7 +199,7 @@ func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
defer onDone()
|
||||
|
||||
if strings.HasPrefix(r.URL.Path, "/localapi/") {
|
||||
lah := localapi.NewHandler(lb, s.logf, s.netMon, s.backendLogID)
|
||||
lah := localapi.NewHandler(lb, s.logf, s.backendLogID)
|
||||
lah.PermitRead, lah.PermitWrite = s.localAPIPermissions(ci)
|
||||
lah.PermitCert = s.connCanFetchCerts(ci)
|
||||
lah.ConnIdentity = ci
|
||||
|
|
|
@ -140,7 +140,7 @@ func (h *Handler) serveDebugDERPRegion(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
checkSTUN4 := func(derpNode *tailcfg.DERPNode) {
|
||||
u4, err := nettype.MakePacketListenerWithNetIP(netns.Listener(h.logf, h.netMon)).ListenPacket(ctx, "udp4", ":0")
|
||||
u4, err := nettype.MakePacketListenerWithNetIP(netns.Listener(h.logf, h.b.NetMon())).ListenPacket(ctx, "udp4", ":0")
|
||||
if err != nil {
|
||||
st.Errors = append(st.Errors, fmt.Sprintf("Error creating IPv4 STUN listener: %v", err))
|
||||
return
|
||||
|
@ -249,7 +249,7 @@ func (h *Handler) serveDebugDERPRegion(w http.ResponseWriter, r *http.Request) {
|
|||
serverPubKeys := make(map[key.NodePublic]bool)
|
||||
for i := range 5 {
|
||||
func() {
|
||||
rc := derphttp.NewRegionClient(fakePrivKey, h.logf, h.netMon, func() *tailcfg.DERPRegion {
|
||||
rc := derphttp.NewRegionClient(fakePrivKey, h.logf, h.b.NetMon(), func() *tailcfg.DERPRegion {
|
||||
return &tailcfg.DERPRegion{
|
||||
RegionID: reg.RegionID,
|
||||
RegionCode: reg.RegionCode,
|
||||
|
|
|
@ -36,7 +36,6 @@ import (
|
|||
"tailscale.com/clientupdate"
|
||||
"tailscale.com/drive"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/hostinfo"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/ipn/ipnauth"
|
||||
|
@ -156,8 +155,8 @@ var (
|
|||
|
||||
// NewHandler creates a new LocalAPI HTTP handler. All parameters except netMon
|
||||
// are required (if non-nil it's used to do faster interface lookups).
|
||||
func NewHandler(b *ipnlocal.LocalBackend, logf logger.Logf, netMon *netmon.Monitor, logID logid.PublicID) *Handler {
|
||||
return &Handler{b: b, logf: logf, netMon: netMon, backendLogID: logID, clock: tstime.StdClock{}}
|
||||
func NewHandler(b *ipnlocal.LocalBackend, logf logger.Logf, logID logid.PublicID) *Handler {
|
||||
return &Handler{b: b, logf: logf, backendLogID: logID, clock: tstime.StdClock{}}
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
|
@ -188,7 +187,6 @@ type Handler struct {
|
|||
|
||||
b *ipnlocal.LocalBackend
|
||||
logf logger.Logf
|
||||
netMon *netmon.Monitor // optional; nil means interfaces will be looked up on-demand
|
||||
backendLogID logid.PublicID
|
||||
clock tstime.Clock
|
||||
}
|
||||
|
@ -358,7 +356,7 @@ func (h *Handler) serveBugReport(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
hi, _ := json.Marshal(hostinfo.New())
|
||||
h.logf("user bugreport hostinfo: %s", hi)
|
||||
if err := health.Global.OverallError(); err != nil {
|
||||
if err := h.b.HealthTracker().OverallError(); err != nil {
|
||||
h.logf("user bugreport health: %s", err.Error())
|
||||
} else {
|
||||
h.logf("user bugreport health: ok")
|
||||
|
@ -748,7 +746,7 @@ func (h *Handler) serveDebugPortmap(w http.ResponseWriter, r *http.Request) {
|
|||
done := make(chan bool, 1)
|
||||
|
||||
var c *portmapper.Client
|
||||
c = portmapper.NewClient(logger.WithPrefix(logf, "portmapper: "), h.netMon, debugKnobs, h.b.ControlKnobs(), func() {
|
||||
c = portmapper.NewClient(logger.WithPrefix(logf, "portmapper: "), h.b.NetMon(), debugKnobs, h.b.ControlKnobs(), func() {
|
||||
logf("portmapping changed.")
|
||||
logf("have mapping: %v", c.HaveMapping())
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/logpolicy"
|
||||
"tailscale.com/logtail"
|
||||
"tailscale.com/logtail/filch"
|
||||
|
@ -93,7 +94,7 @@ func SockstatLogID(logID logid.PublicID) logid.PrivateID {
|
|||
// The returned Logger is not yet enabled, and must be shut down with Shutdown when it is no longer needed.
|
||||
// Logs will be uploaded to the log server using a new log ID derived from the provided backend logID.
|
||||
// The netMon parameter is optional; if non-nil it's used to do faster interface lookups.
|
||||
func NewLogger(logdir string, logf logger.Logf, logID logid.PublicID, netMon *netmon.Monitor) (*Logger, error) {
|
||||
func NewLogger(logdir string, logf logger.Logf, logID logid.PublicID, netMon *netmon.Monitor, health *health.Tracker) (*Logger, error) {
|
||||
if !sockstats.IsAvailable {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -113,7 +114,7 @@ func NewLogger(logdir string, logf logger.Logf, logID logid.PublicID, netMon *ne
|
|||
logger := &Logger{
|
||||
logf: logf,
|
||||
filch: filch,
|
||||
tr: logpolicy.NewLogtailTransport(logtail.DefaultHost, netMon, logf),
|
||||
tr: logpolicy.NewLogtailTransport(logtail.DefaultHost, netMon, health, logf),
|
||||
}
|
||||
logger.logger = logtail.NewLogger(logtail.Config{
|
||||
BaseURL: logpolicy.LogURL(),
|
||||
|
|
|
@ -23,7 +23,7 @@ func TestResourceCleanup(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
lg, err := NewLogger(td, logger.Discard, id.Public(), nil)
|
||||
lg, err := NewLogger(td, logger.Discard, id.Public(), nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -453,13 +453,13 @@ func tryFixLogStateLocation(dir, cmdname string, logf logger.Logf) {
|
|||
// The logf parameter is optional; if non-nil, information logs (e.g. when
|
||||
// migrating state) are sent to that logger, and global changes to the log
|
||||
// package are avoided. If nil, logs will be printed using log.Printf.
|
||||
func New(collection string, netMon *netmon.Monitor, logf logger.Logf) *Policy {
|
||||
return NewWithConfigPath(collection, "", "", netMon, logf)
|
||||
func New(collection string, netMon *netmon.Monitor, health *health.Tracker, logf logger.Logf) *Policy {
|
||||
return NewWithConfigPath(collection, "", "", netMon, health, logf)
|
||||
}
|
||||
|
||||
// NewWithConfigPath is identical to New, but uses the specified directory and
|
||||
// command name. If either is empty, it derives them automatically.
|
||||
func NewWithConfigPath(collection, dir, cmdName string, netMon *netmon.Monitor, logf logger.Logf) *Policy {
|
||||
func NewWithConfigPath(collection, dir, cmdName string, netMon *netmon.Monitor, health *health.Tracker, logf logger.Logf) *Policy {
|
||||
var lflags int
|
||||
if term.IsTerminal(2) || runtime.GOOS == "windows" {
|
||||
lflags = 0
|
||||
|
@ -555,7 +555,7 @@ func NewWithConfigPath(collection, dir, cmdName string, netMon *netmon.Monitor,
|
|||
PrivateID: newc.PrivateID,
|
||||
Stderr: logWriter{console},
|
||||
CompressLogs: true,
|
||||
HTTPC: &http.Client{Transport: NewLogtailTransport(logtail.DefaultHost, netMon, logf)},
|
||||
HTTPC: &http.Client{Transport: NewLogtailTransport(logtail.DefaultHost, netMon, health, logf)},
|
||||
}
|
||||
if collection == logtail.CollectionNode {
|
||||
conf.MetricsDelta = clientmetric.EncodeLogTailMetricsDelta
|
||||
|
@ -570,7 +570,7 @@ func NewWithConfigPath(collection, dir, cmdName string, netMon *netmon.Monitor,
|
|||
logf("You have enabled a non-default log target. Doing without being told to by Tailscale staff or your network administrator will make getting support difficult.")
|
||||
conf.BaseURL = val
|
||||
u, _ := url.Parse(val)
|
||||
conf.HTTPC = &http.Client{Transport: NewLogtailTransport(u.Host, netMon, logf)}
|
||||
conf.HTTPC = &http.Client{Transport: NewLogtailTransport(u.Host, netMon, health, logf)}
|
||||
}
|
||||
|
||||
filchOptions := filch.Options{
|
||||
|
@ -742,7 +742,7 @@ func dialContext(ctx context.Context, netw, addr string, netMon *netmon.Monitor,
|
|||
//
|
||||
// The logf parameter is optional; if non-nil, logs are printed using the
|
||||
// provided function; if nil, log.Printf will be used instead.
|
||||
func NewLogtailTransport(host string, netMon *netmon.Monitor, logf logger.Logf) http.RoundTripper {
|
||||
func NewLogtailTransport(host string, netMon *netmon.Monitor, health *health.Tracker, logf logger.Logf) http.RoundTripper {
|
||||
if testenv.InTest() {
|
||||
return noopPretendSuccessTransport{}
|
||||
}
|
||||
|
@ -783,7 +783,7 @@ func NewLogtailTransport(host string, netMon *netmon.Monitor, logf logger.Logf)
|
|||
tr.TLSNextProto = map[string]func(authority string, c *tls.Conn) http.RoundTripper{}
|
||||
}
|
||||
|
||||
tr.TLSClientConfig = tlsdial.Config(host, health.Global, tr.TLSClientConfig)
|
||||
tr.TLSClientConfig = tlsdial.Config(host, health, tr.TLSClientConfig)
|
||||
|
||||
return tr
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/net/dns/resolvconffile"
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/types/logger"
|
||||
|
@ -116,8 +117,9 @@ func restartResolved() error {
|
|||
// The caller must call Down before program shutdown
|
||||
// or as cleanup if the program terminates unexpectedly.
|
||||
type directManager struct {
|
||||
logf logger.Logf
|
||||
fs wholeFileFS
|
||||
logf logger.Logf
|
||||
health *health.Tracker
|
||||
fs wholeFileFS
|
||||
// renameBroken is set if fs.Rename to or from /etc/resolv.conf
|
||||
// fails. This can happen in some container runtimes, where
|
||||
// /etc/resolv.conf is bind-mounted from outside the container,
|
||||
|
@ -140,14 +142,15 @@ type directManager struct {
|
|||
}
|
||||
|
||||
//lint:ignore U1000 used in manager_{freebsd,openbsd}.go
|
||||
func newDirectManager(logf logger.Logf) *directManager {
|
||||
return newDirectManagerOnFS(logf, directFS{})
|
||||
func newDirectManager(logf logger.Logf, health *health.Tracker) *directManager {
|
||||
return newDirectManagerOnFS(logf, health, directFS{})
|
||||
}
|
||||
|
||||
func newDirectManagerOnFS(logf logger.Logf, fs wholeFileFS) *directManager {
|
||||
func newDirectManagerOnFS(logf logger.Logf, health *health.Tracker, fs wholeFileFS) *directManager {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
m := &directManager{
|
||||
logf: logf,
|
||||
health: health,
|
||||
fs: fs,
|
||||
ctx: ctx,
|
||||
ctxClose: cancel,
|
||||
|
|
|
@ -78,7 +78,7 @@ func (m *directManager) checkForFileTrample() {
|
|||
return
|
||||
}
|
||||
if bytes.Equal(cur, want) {
|
||||
health.Global.SetWarnable(warnTrample, nil)
|
||||
m.health.SetWarnable(warnTrample, nil)
|
||||
if lastWarn != nil {
|
||||
m.mu.Lock()
|
||||
m.lastWarnContents = nil
|
||||
|
@ -101,7 +101,7 @@ func (m *directManager) checkForFileTrample() {
|
|||
show = show[:1024]
|
||||
}
|
||||
m.logf("trample: resolv.conf changed from what we expected. did some other program interfere? current contents: %q", show)
|
||||
health.Global.SetWarnable(warnTrample, errors.New("Linux DNS config not ideal. /etc/resolv.conf overwritten. See https://tailscale.com/s/dns-fight"))
|
||||
m.health.SetWarnable(warnTrample, errors.New("Linux DNS config not ideal. /etc/resolv.conf overwritten. See https://tailscale.com/s/dns-fight"))
|
||||
}
|
||||
|
||||
func (m *directManager) closeInotifyOnDone(ctx context.Context, in *gonotify.Inotify) {
|
||||
|
|
|
@ -42,7 +42,8 @@ const maxActiveQueries = 256
|
|||
|
||||
// Manager manages system DNS settings.
|
||||
type Manager struct {
|
||||
logf logger.Logf
|
||||
logf logger.Logf
|
||||
health *health.Tracker
|
||||
|
||||
activeQueriesAtomic int32
|
||||
|
||||
|
@ -55,7 +56,7 @@ type Manager struct {
|
|||
|
||||
// NewManagers created a new manager from the given config.
|
||||
// The netMon parameter is optional; if non-nil it's used to do faster interface lookups.
|
||||
func NewManager(logf logger.Logf, oscfg OSConfigurator, netMon *netmon.Monitor, dialer *tsdial.Dialer, linkSel resolver.ForwardLinkSelector, knobs *controlknobs.Knobs) *Manager {
|
||||
func NewManager(logf logger.Logf, oscfg OSConfigurator, netMon *netmon.Monitor, health *health.Tracker, dialer *tsdial.Dialer, linkSel resolver.ForwardLinkSelector, knobs *controlknobs.Knobs) *Manager {
|
||||
if dialer == nil {
|
||||
panic("nil Dialer")
|
||||
}
|
||||
|
@ -64,6 +65,7 @@ func NewManager(logf logger.Logf, oscfg OSConfigurator, netMon *netmon.Monitor,
|
|||
logf: logf,
|
||||
resolver: resolver.New(logf, netMon, linkSel, dialer, knobs),
|
||||
os: oscfg,
|
||||
health: health,
|
||||
}
|
||||
m.ctx, m.ctxCancel = context.WithCancel(context.Background())
|
||||
m.logf("using %T", m.os)
|
||||
|
@ -94,10 +96,10 @@ func (m *Manager) Set(cfg Config) error {
|
|||
return err
|
||||
}
|
||||
if err := m.os.SetDNS(ocfg); err != nil {
|
||||
health.Global.SetDNSOSHealth(err)
|
||||
m.health.SetDNSOSHealth(err)
|
||||
return err
|
||||
}
|
||||
health.Global.SetDNSOSHealth(nil)
|
||||
m.health.SetDNSOSHealth(nil)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -248,7 +250,7 @@ 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 {
|
||||
health.Global.SetDNSOSHealth(err)
|
||||
m.health.SetDNSOSHealth(err)
|
||||
return resolver.Config{}, OSConfig{}, err
|
||||
}
|
||||
}
|
||||
|
@ -453,12 +455,12 @@ func (m *Manager) FlushCaches() error {
|
|||
// in case the Tailscale daemon terminated without closing the router.
|
||||
// No other state needs to be instantiated before this runs.
|
||||
func CleanUp(logf logger.Logf, interfaceName string) {
|
||||
oscfg, err := NewOSConfigurator(logf, interfaceName)
|
||||
oscfg, err := NewOSConfigurator(logf, nil, interfaceName)
|
||||
if err != nil {
|
||||
logf("creating dns cleanup: %v", err)
|
||||
return
|
||||
}
|
||||
dns := NewManager(logf, oscfg, nil, &tsdial.Dialer{Logf: logf}, nil, nil)
|
||||
dns := NewManager(logf, oscfg, nil, nil, &tsdial.Dialer{Logf: logf}, nil, nil)
|
||||
if err := dns.Down(); err != nil {
|
||||
logf("dns down: %v", err)
|
||||
}
|
||||
|
|
|
@ -8,11 +8,12 @@ import (
|
|||
"os"
|
||||
|
||||
"go4.org/mem"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/util/mak"
|
||||
)
|
||||
|
||||
func NewOSConfigurator(logf logger.Logf, ifName string) (OSConfigurator, error) {
|
||||
func NewOSConfigurator(logf logger.Logf, health *health.Tracker, ifName string) (OSConfigurator, error) {
|
||||
return &darwinConfigurator{logf: logf, ifName: ifName}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
|
||||
package dns
|
||||
|
||||
import "tailscale.com/types/logger"
|
||||
import (
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
||||
func NewOSConfigurator(logger.Logf, string) (OSConfigurator, error) {
|
||||
// TODO(dmytro): on darwin, we should use a macOS-specific method such as scutil.
|
||||
// This is currently not implemented. Editing /etc/resolv.conf does not work,
|
||||
// as most applications use the system resolver, which disregards it.
|
||||
func NewOSConfigurator(logger.Logf, *health.Tracker, string) (OSConfigurator, error) {
|
||||
return NewNoopManager()
|
||||
}
|
||||
|
|
|
@ -7,13 +7,14 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
||||
func NewOSConfigurator(logf logger.Logf, _ string) (OSConfigurator, error) {
|
||||
func NewOSConfigurator(logf logger.Logf, health *health.Tracker, _ string) (OSConfigurator, error) {
|
||||
bs, err := os.ReadFile("/etc/resolv.conf")
|
||||
if os.IsNotExist(err) {
|
||||
return newDirectManager(logf), nil
|
||||
return newDirectManager(logf, health), nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading /etc/resolv.conf: %w", err)
|
||||
|
@ -23,16 +24,16 @@ func NewOSConfigurator(logf logger.Logf, _ string) (OSConfigurator, error) {
|
|||
case "resolvconf":
|
||||
switch resolvconfStyle() {
|
||||
case "":
|
||||
return newDirectManager(logf), nil
|
||||
return newDirectManager(logf, health), nil
|
||||
case "debian":
|
||||
return newDebianResolvconfManager(logf)
|
||||
case "openresolv":
|
||||
return newOpenresolvManager(logf)
|
||||
default:
|
||||
logf("[unexpected] got unknown flavor of resolvconf %q, falling back to direct manager", resolvconfStyle())
|
||||
return newDirectManager(logf), nil
|
||||
return newDirectManager(logf, health), nil
|
||||
}
|
||||
default:
|
||||
return newDirectManager(logf), nil
|
||||
return newDirectManager(logf, health), nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ func (kv kv) String() string {
|
|||
|
||||
var publishOnce sync.Once
|
||||
|
||||
func NewOSConfigurator(logf logger.Logf, interfaceName string) (ret OSConfigurator, err error) {
|
||||
func NewOSConfigurator(logf logger.Logf, health *health.Tracker, interfaceName string) (ret OSConfigurator, err error) {
|
||||
env := newOSConfigEnv{
|
||||
fs: directFS{},
|
||||
dbusPing: dbusPing,
|
||||
|
@ -40,7 +40,7 @@ func NewOSConfigurator(logf logger.Logf, interfaceName string) (ret OSConfigurat
|
|||
nmVersionBetween: nmVersionBetween,
|
||||
resolvconfStyle: resolvconfStyle,
|
||||
}
|
||||
mode, err := dnsMode(logf, env)
|
||||
mode, err := dnsMode(logf, health, env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -52,9 +52,9 @@ func NewOSConfigurator(logf logger.Logf, interfaceName string) (ret OSConfigurat
|
|||
logf("dns: using %q mode", mode)
|
||||
switch mode {
|
||||
case "direct":
|
||||
return newDirectManagerOnFS(logf, env.fs), nil
|
||||
return newDirectManagerOnFS(logf, health, env.fs), nil
|
||||
case "systemd-resolved":
|
||||
return newResolvedManager(logf, interfaceName)
|
||||
return newResolvedManager(logf, health, interfaceName)
|
||||
case "network-manager":
|
||||
return newNMManager(interfaceName)
|
||||
case "debian-resolvconf":
|
||||
|
@ -63,7 +63,7 @@ func NewOSConfigurator(logf logger.Logf, interfaceName string) (ret OSConfigurat
|
|||
return newOpenresolvManager(logf)
|
||||
default:
|
||||
logf("[unexpected] detected unknown DNS mode %q, using direct manager as last resort", mode)
|
||||
return newDirectManagerOnFS(logf, env.fs), nil
|
||||
return newDirectManagerOnFS(logf, health, env.fs), nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ type newOSConfigEnv struct {
|
|||
resolvconfStyle func() string
|
||||
}
|
||||
|
||||
func dnsMode(logf logger.Logf, env newOSConfigEnv) (ret string, err error) {
|
||||
func dnsMode(logf logger.Logf, health *health.Tracker, env newOSConfigEnv) (ret string, err error) {
|
||||
var debug []kv
|
||||
dbg := func(k, v string) {
|
||||
debug = append(debug, kv{k, v})
|
||||
|
@ -271,7 +271,7 @@ func dnsMode(logf logger.Logf, env newOSConfigEnv) (ret string, err error) {
|
|||
return "direct", nil
|
||||
}
|
||||
|
||||
health.Global.SetDNSManagerHealth(errors.New("systemd-resolved and NetworkManager are wired together incorrectly; MagicDNS will probably not work. For more info, see https://tailscale.com/s/resolved-nm"))
|
||||
health.SetDNSManagerHealth(errors.New("systemd-resolved and NetworkManager are wired together incorrectly; MagicDNS will probably not work. For more info, see https://tailscale.com/s/resolved-nm"))
|
||||
dbg("nm-safe", "no")
|
||||
return "systemd-resolved", nil
|
||||
default:
|
||||
|
|
|
@ -286,7 +286,7 @@ func TestLinuxDNSMode(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var logBuf tstest.MemLogger
|
||||
got, err := dnsMode(logBuf.Logf, tt.env)
|
||||
got, err := dnsMode(logBuf.Logf, nil, tt.env)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
||||
|
@ -19,8 +20,8 @@ func (kv kv) String() string {
|
|||
return fmt.Sprintf("%s=%s", kv.k, kv.v)
|
||||
}
|
||||
|
||||
func NewOSConfigurator(logf logger.Logf, interfaceName string) (OSConfigurator, error) {
|
||||
return newOSConfigurator(logf, interfaceName,
|
||||
func NewOSConfigurator(logf logger.Logf, health *health.Tracker, interfaceName string) (OSConfigurator, error) {
|
||||
return newOSConfigurator(logf, health, interfaceName,
|
||||
newOSConfigEnv{
|
||||
rcIsResolvd: rcIsResolvd,
|
||||
fs: directFS{},
|
||||
|
@ -33,7 +34,7 @@ type newOSConfigEnv struct {
|
|||
rcIsResolvd func(resolvConfContents []byte) bool
|
||||
}
|
||||
|
||||
func newOSConfigurator(logf logger.Logf, interfaceName string, env newOSConfigEnv) (ret OSConfigurator, err error) {
|
||||
func newOSConfigurator(logf logger.Logf, health *health.Tracker, interfaceName string, env newOSConfigEnv) (ret OSConfigurator, err error) {
|
||||
var debug []kv
|
||||
dbg := func(k, v string) {
|
||||
debug = append(debug, kv{k, v})
|
||||
|
@ -48,7 +49,7 @@ func newOSConfigurator(logf logger.Logf, interfaceName string, env newOSConfigEn
|
|||
bs, err := env.fs.ReadFile(resolvConf)
|
||||
if os.IsNotExist(err) {
|
||||
dbg("rc", "missing")
|
||||
return newDirectManager(logf), nil
|
||||
return newDirectManager(logf, health), nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading /etc/resolv.conf: %w", err)
|
||||
|
@ -60,7 +61,7 @@ func newOSConfigurator(logf logger.Logf, interfaceName string, env newOSConfigEn
|
|||
}
|
||||
|
||||
dbg("resolvd", "missing")
|
||||
return newDirectManager(logf), nil
|
||||
return newDirectManager(logf, health), nil
|
||||
}
|
||||
|
||||
func rcIsResolvd(resolvConfContents []byte) bool {
|
||||
|
|
|
@ -87,7 +87,7 @@ func TestDNSOverTCP(t *testing.T) {
|
|||
SearchDomains: fqdns("coffee.shop"),
|
||||
},
|
||||
}
|
||||
m := NewManager(t.Logf, &f, nil, new(tsdial.Dialer), nil, nil)
|
||||
m := NewManager(t.Logf, &f, nil, nil, new(tsdial.Dialer), nil, nil)
|
||||
m.resolver.TestOnlySetHook(f.SetResolver)
|
||||
m.Set(Config{
|
||||
Hosts: hosts(
|
||||
|
@ -172,7 +172,7 @@ func TestDNSOverTCP_TooLarge(t *testing.T) {
|
|||
SearchDomains: fqdns("coffee.shop"),
|
||||
},
|
||||
}
|
||||
m := NewManager(log, &f, nil, new(tsdial.Dialer), nil, nil)
|
||||
m := NewManager(log, &f, nil, nil, new(tsdial.Dialer), nil, nil)
|
||||
m.resolver.TestOnlySetHook(f.SetResolver)
|
||||
m.Set(Config{
|
||||
Hosts: hosts("andrew.ts.com.", "1.2.3.4"),
|
||||
|
|
|
@ -613,7 +613,7 @@ func TestManager(t *testing.T) {
|
|||
SplitDNS: test.split,
|
||||
BaseConfig: test.bs,
|
||||
}
|
||||
m := NewManager(t.Logf, &f, nil, new(tsdial.Dialer), nil, nil)
|
||||
m := NewManager(t.Logf, &f, nil, nil, new(tsdial.Dialer), nil, nil)
|
||||
m.resolver.TestOnlySetHook(f.SetResolver)
|
||||
|
||||
if err := m.Set(test.in); err != nil {
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||
"tailscale.com/atomicfile"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/util/dnsname"
|
||||
"tailscale.com/util/winutil"
|
||||
|
@ -44,11 +45,11 @@ type windowsManager struct {
|
|||
closing bool
|
||||
}
|
||||
|
||||
func NewOSConfigurator(logf logger.Logf, interfaceName string) (OSConfigurator, error) {
|
||||
func NewOSConfigurator(logf logger.Logf, health *health.Tracker, interfaceName string) (OSConfigurator, error) {
|
||||
ret := &windowsManager{
|
||||
logf: logf,
|
||||
guid: interfaceName,
|
||||
wslManager: newWSLManager(logf),
|
||||
wslManager: newWSLManager(logf, health),
|
||||
}
|
||||
|
||||
if isWindows10OrBetter() {
|
||||
|
|
|
@ -84,7 +84,7 @@ func TestManagerWindowsGPCopy(t *testing.T) {
|
|||
}
|
||||
defer delIfKey()
|
||||
|
||||
cfg, err := NewOSConfigurator(logf, fakeInterface.String())
|
||||
cfg, err := NewOSConfigurator(logf, nil, fakeInterface.String())
|
||||
if err != nil {
|
||||
t.Fatalf("NewOSConfigurator: %v\n", err)
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ func runTest(t *testing.T, isLocal bool) {
|
|||
}
|
||||
defer delIfKey()
|
||||
|
||||
cfg, err := NewOSConfigurator(logf, fakeInterface.String())
|
||||
cfg, err := NewOSConfigurator(logf, nil, fakeInterface.String())
|
||||
if err != nil {
|
||||
t.Fatalf("NewOSConfigurator: %v\n", err)
|
||||
}
|
||||
|
|
|
@ -63,13 +63,14 @@ type resolvedManager struct {
|
|||
ctx context.Context
|
||||
cancel func() // terminate the context, for close
|
||||
|
||||
logf logger.Logf
|
||||
ifidx int
|
||||
logf logger.Logf
|
||||
health *health.Tracker
|
||||
ifidx int
|
||||
|
||||
configCR chan changeRequest // tracks OSConfigs changes and error responses
|
||||
}
|
||||
|
||||
func newResolvedManager(logf logger.Logf, interfaceName string) (*resolvedManager, error) {
|
||||
func newResolvedManager(logf logger.Logf, health *health.Tracker, interfaceName string) (*resolvedManager, error) {
|
||||
iface, err := net.InterfaceByName(interfaceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -82,8 +83,9 @@ func newResolvedManager(logf logger.Logf, interfaceName string) (*resolvedManage
|
|||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
|
||||
logf: logf,
|
||||
ifidx: iface.Index,
|
||||
logf: logf,
|
||||
health: health,
|
||||
ifidx: iface.Index,
|
||||
|
||||
configCR: make(chan changeRequest),
|
||||
}
|
||||
|
@ -163,7 +165,7 @@ func (m *resolvedManager) run(ctx context.Context) {
|
|||
|
||||
// Reset backoff and SetNSOSHealth after successful on reconnect.
|
||||
bo.BackOff(ctx, nil)
|
||||
health.Global.SetDNSOSHealth(nil)
|
||||
m.health.SetDNSOSHealth(nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -241,7 +243,7 @@ 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.
|
||||
health.Global.SetDNSOSHealth(err)
|
||||
m.health.SetDNSOSHealth(err)
|
||||
if err != nil {
|
||||
m.logf("failed to configure systemd-resolved: %v", err)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"time"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/util/winutil"
|
||||
)
|
||||
|
@ -54,12 +55,14 @@ func wslDistros() ([]string, error) {
|
|||
// wslManager is a DNS manager for WSL2 linux distributions.
|
||||
// It configures /etc/wsl.conf and /etc/resolv.conf.
|
||||
type wslManager struct {
|
||||
logf logger.Logf
|
||||
logf logger.Logf
|
||||
health *health.Tracker
|
||||
}
|
||||
|
||||
func newWSLManager(logf logger.Logf) *wslManager {
|
||||
func newWSLManager(logf logger.Logf, health *health.Tracker) *wslManager {
|
||||
m := &wslManager{
|
||||
logf: logf,
|
||||
logf: logf,
|
||||
health: health,
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
@ -73,7 +76,7 @@ func (wm *wslManager) SetDNS(cfg OSConfig) error {
|
|||
}
|
||||
managers := make(map[string]*directManager)
|
||||
for _, distro := range distros {
|
||||
managers[distro] = newDirectManagerOnFS(wm.logf, wslFS{
|
||||
managers[distro] = newDirectManagerOnFS(wm.logf, wm.health, wslFS{
|
||||
user: "root",
|
||||
distro: distro,
|
||||
})
|
||||
|
|
|
@ -139,14 +139,6 @@ func (s *System) ProxyMapper() *proxymap.Mapper {
|
|||
|
||||
// HealthTracker returns the system health tracker.
|
||||
func (s *System) HealthTracker() *health.Tracker {
|
||||
// TODO(bradfitz): plumb the tsd.System.HealthTracker() value
|
||||
// everywhere and then then remove this use of the global
|
||||
// and remove health.Global entirely. But for now we keep
|
||||
// the two in sync during plumbing.
|
||||
const stillPlumbing = true
|
||||
if stillPlumbing {
|
||||
return health.Global
|
||||
}
|
||||
return &s.healthTracker
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import (
|
|||
"tailscale.com/client/tailscale"
|
||||
"tailscale.com/control/controlclient"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/hostinfo"
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/ipn/ipnlocal"
|
||||
|
@ -233,7 +234,7 @@ func (s *Server) Loopback() (addr string, proxyCred, localAPICred string, err er
|
|||
// out the CONNECT code from tailscaled/proxy.go that uses
|
||||
// httputil.ReverseProxy and adding auth support.
|
||||
go func() {
|
||||
lah := localapi.NewHandler(s.lb, s.logf, s.netMon, s.logid)
|
||||
lah := localapi.NewHandler(s.lb, s.logf, s.logid)
|
||||
lah.PermitWrite = true
|
||||
lah.PermitRead = true
|
||||
lah.RequiredPassword = s.localAPICred
|
||||
|
@ -504,7 +505,8 @@ func (s *Server) start() (reterr error) {
|
|||
return fmt.Errorf("%v is not a directory", s.rootPath)
|
||||
}
|
||||
|
||||
if err := s.startLogger(&closePool); err != nil {
|
||||
sys := new(tsd.System)
|
||||
if err := s.startLogger(&closePool, sys.HealthTracker()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -514,14 +516,14 @@ func (s *Server) start() (reterr error) {
|
|||
}
|
||||
closePool.add(s.netMon)
|
||||
|
||||
sys := new(tsd.System)
|
||||
s.dialer = &tsdial.Dialer{Logf: logf} // mutated below (before used)
|
||||
eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{
|
||||
ListenPort: s.Port,
|
||||
NetMon: s.netMon,
|
||||
Dialer: s.dialer,
|
||||
SetSubsystem: sys.Set,
|
||||
ControlKnobs: sys.ControlKnobs(),
|
||||
ListenPort: s.Port,
|
||||
NetMon: s.netMon,
|
||||
Dialer: s.dialer,
|
||||
SetSubsystem: sys.Set,
|
||||
ControlKnobs: sys.ControlKnobs(),
|
||||
HealthTracker: sys.HealthTracker(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -606,7 +608,7 @@ func (s *Server) start() (reterr error) {
|
|||
go s.printAuthURLLoop()
|
||||
|
||||
// Run the localapi handler, to allow fetching LetsEncrypt certs.
|
||||
lah := localapi.NewHandler(lb, logf, s.netMon, s.logid)
|
||||
lah := localapi.NewHandler(lb, logf, s.logid)
|
||||
lah.PermitWrite = true
|
||||
lah.PermitRead = true
|
||||
|
||||
|
@ -626,7 +628,7 @@ func (s *Server) start() (reterr error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) startLogger(closePool *closeOnErrorPool) error {
|
||||
func (s *Server) startLogger(closePool *closeOnErrorPool, health *health.Tracker) error {
|
||||
if testenv.InTest() {
|
||||
return nil
|
||||
}
|
||||
|
@ -657,7 +659,7 @@ func (s *Server) startLogger(closePool *closeOnErrorPool) error {
|
|||
Stderr: io.Discard, // log everything to Buffer
|
||||
Buffer: s.logbuffer,
|
||||
CompressLogs: true,
|
||||
HTTPC: &http.Client{Transport: logpolicy.NewLogtailTransport(logtail.DefaultHost, s.netMon, s.logf)},
|
||||
HTTPC: &http.Client{Transport: logpolicy.NewLogtailTransport(logtail.DefaultHost, s.netMon, health, s.logf)},
|
||||
MetricsDelta: clientmetric.EncodeLogTailMetricsDelta,
|
||||
}
|
||||
s.logtail = logtail.NewLogger(c, s.logf)
|
||||
|
|
|
@ -165,7 +165,7 @@ func (c *Conn) maybeSetNearestDERP(report *netcheck.Report) (preferredDERP int)
|
|||
if testenv.InTest() && !checkControlHealthDuringNearestDERPInTests {
|
||||
connectedToControl = true
|
||||
} else {
|
||||
connectedToControl = health.Global.GetInPollNetMap()
|
||||
connectedToControl = c.health.GetInPollNetMap()
|
||||
}
|
||||
if !connectedToControl {
|
||||
c.mu.Lock()
|
||||
|
@ -201,12 +201,12 @@ func (c *Conn) setNearestDERP(derpNum int) (wantDERP bool) {
|
|||
defer c.mu.Unlock()
|
||||
if !c.wantDerpLocked() {
|
||||
c.myDerp = 0
|
||||
health.Global.SetMagicSockDERPHome(0, c.homeless)
|
||||
c.health.SetMagicSockDERPHome(0, c.homeless)
|
||||
return false
|
||||
}
|
||||
if c.homeless {
|
||||
c.myDerp = 0
|
||||
health.Global.SetMagicSockDERPHome(0, c.homeless)
|
||||
c.health.SetMagicSockDERPHome(0, c.homeless)
|
||||
return false
|
||||
}
|
||||
if derpNum == c.myDerp {
|
||||
|
@ -217,7 +217,7 @@ func (c *Conn) setNearestDERP(derpNum int) (wantDERP bool) {
|
|||
metricDERPHomeChange.Add(1)
|
||||
}
|
||||
c.myDerp = derpNum
|
||||
health.Global.SetMagicSockDERPHome(derpNum, c.homeless)
|
||||
c.health.SetMagicSockDERPHome(derpNum, c.homeless)
|
||||
|
||||
if c.privateKey.IsZero() {
|
||||
// No private key yet, so DERP connections won't come up anyway.
|
||||
|
@ -400,7 +400,7 @@ func (c *Conn) derpWriteChanOfAddr(addr netip.AddrPort, peer key.NodePublic) cha
|
|||
}
|
||||
return derpMap.Regions[regionID]
|
||||
})
|
||||
dc.HealthTracker = health.Global
|
||||
dc.HealthTracker = c.health
|
||||
|
||||
dc.SetCanAckPings(true)
|
||||
dc.NotePreferred(c.myDerp == regionID)
|
||||
|
@ -526,8 +526,8 @@ func (c *Conn) runDerpReader(ctx context.Context, derpFakeAddr netip.AddrPort, d
|
|||
return n
|
||||
}
|
||||
|
||||
defer health.Global.SetDERPRegionConnectedState(regionID, false)
|
||||
defer health.Global.SetDERPRegionHealth(regionID, "")
|
||||
defer c.health.SetDERPRegionConnectedState(regionID, false)
|
||||
defer c.health.SetDERPRegionHealth(regionID, "")
|
||||
|
||||
// peerPresent is the set of senders we know are present on this
|
||||
// connection, based on messages we've received from the server.
|
||||
|
@ -539,7 +539,7 @@ func (c *Conn) runDerpReader(ctx context.Context, derpFakeAddr netip.AddrPort, d
|
|||
for {
|
||||
msg, connGen, err := dc.RecvDetail()
|
||||
if err != nil {
|
||||
health.Global.SetDERPRegionConnectedState(regionID, false)
|
||||
c.health.SetDERPRegionConnectedState(regionID, false)
|
||||
// Forget that all these peers have routes.
|
||||
for peer := range peerPresent {
|
||||
delete(peerPresent, peer)
|
||||
|
@ -577,14 +577,14 @@ func (c *Conn) runDerpReader(ctx context.Context, derpFakeAddr netip.AddrPort, d
|
|||
|
||||
now := time.Now()
|
||||
if lastPacketTime.IsZero() || now.Sub(lastPacketTime) > frameReceiveRecordRate {
|
||||
health.Global.NoteDERPRegionReceivedFrame(regionID)
|
||||
c.health.NoteDERPRegionReceivedFrame(regionID)
|
||||
lastPacketTime = now
|
||||
}
|
||||
|
||||
switch m := msg.(type) {
|
||||
case derp.ServerInfoMessage:
|
||||
health.Global.SetDERPRegionConnectedState(regionID, true)
|
||||
health.Global.SetDERPRegionHealth(regionID, "") // until declared otherwise
|
||||
c.health.SetDERPRegionConnectedState(regionID, true)
|
||||
c.health.SetDERPRegionHealth(regionID, "") // until declared otherwise
|
||||
c.logf("magicsock: derp-%d connected; connGen=%v", regionID, connGen)
|
||||
continue
|
||||
case derp.ReceivedPacket:
|
||||
|
@ -624,7 +624,7 @@ func (c *Conn) runDerpReader(ctx context.Context, derpFakeAddr netip.AddrPort, d
|
|||
}()
|
||||
continue
|
||||
case derp.HealthMessage:
|
||||
health.Global.SetDERPRegionHealth(regionID, m.Problem)
|
||||
c.health.SetDERPRegionHealth(regionID, m.Problem)
|
||||
continue
|
||||
case derp.PeerGoneMessage:
|
||||
switch m.Reason {
|
||||
|
|
|
@ -91,6 +91,7 @@ type Conn struct {
|
|||
testOnlyPacketListener nettype.PacketListener
|
||||
noteRecvActivity func(key.NodePublic) // or nil, see Options.NoteRecvActivity
|
||||
netMon *netmon.Monitor // or nil
|
||||
health *health.Tracker // or nil
|
||||
controlKnobs *controlknobs.Knobs // or nil
|
||||
|
||||
// ================================================================
|
||||
|
@ -369,9 +370,13 @@ type Options struct {
|
|||
NoteRecvActivity func(key.NodePublic)
|
||||
|
||||
// NetMon is the network monitor to use.
|
||||
// With one, the portmapper won't be used.
|
||||
// If nil, the portmapper won't be used.
|
||||
NetMon *netmon.Monitor
|
||||
|
||||
// HealthTracker optionally specifies the health tracker to
|
||||
// report errors and warnings to.
|
||||
HealthTracker *health.Tracker
|
||||
|
||||
// ControlKnobs are the set of control knobs to use.
|
||||
// If nil, they're ignored and not updated.
|
||||
ControlKnobs *controlknobs.Knobs
|
||||
|
@ -463,6 +468,7 @@ func NewConn(opts Options) (*Conn, error) {
|
|||
c.portMapper.SetGatewayLookupFunc(opts.NetMon.GatewayAndSelfIP)
|
||||
}
|
||||
c.netMon = opts.NetMon
|
||||
c.health = opts.HealthTracker
|
||||
c.onPortUpdate = opts.OnPortUpdate
|
||||
c.getPeerByKey = opts.PeerByKeyFunc
|
||||
|
||||
|
@ -666,7 +672,7 @@ func (c *Conn) updateNetInfo(ctx context.Context) (*netcheck.Report, error) {
|
|||
// NOTE(andrew-d): I don't love that we're depending on the
|
||||
// health package here, but I'd rather do that and not store
|
||||
// the exact same state in two different places.
|
||||
GetLastDERPActivity: health.Global.GetDERPRegionReceivedTime,
|
||||
GetLastDERPActivity: c.health.GetDERPRegionReceivedTime,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -2471,7 +2477,7 @@ func (c *Conn) bindSocket(ruc *RebindingUDPConn, network string, curPortFate cur
|
|||
}
|
||||
ruc.setConnLocked(pconn, network, c.bind.BatchSize())
|
||||
if network == "udp4" {
|
||||
health.Global.SetUDP4Unbound(false)
|
||||
c.health.SetUDP4Unbound(false)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -2482,7 +2488,7 @@ func (c *Conn) bindSocket(ruc *RebindingUDPConn, network string, curPortFate cur
|
|||
// we get a link change and we can try binding again.
|
||||
ruc.setConnLocked(newBlockForeverConn(), "", c.bind.BatchSize())
|
||||
if network == "udp4" {
|
||||
health.Global.SetUDP4Unbound(true)
|
||||
c.health.SetUDP4Unbound(true)
|
||||
}
|
||||
return fmt.Errorf("failed to bind any ports (tried %v)", ports)
|
||||
}
|
||||
|
|
|
@ -3113,21 +3113,23 @@ func TestMaybeSetNearestDERP(t *testing.T) {
|
|||
}
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ht := new(health.Tracker)
|
||||
c := newConn()
|
||||
c.logf = t.Logf
|
||||
c.myDerp = tt.old
|
||||
c.derpMap = derpMap
|
||||
c.health = ht
|
||||
|
||||
report := &netcheck.Report{PreferredDERP: tt.reportDERP}
|
||||
|
||||
oldConnected := health.Global.GetInPollNetMap()
|
||||
oldConnected := ht.GetInPollNetMap()
|
||||
if tt.connectedToControl != oldConnected {
|
||||
if tt.connectedToControl {
|
||||
health.Global.GotStreamedMapResponse()
|
||||
t.Cleanup(health.Global.SetOutOfPollNetMap)
|
||||
ht.GotStreamedMapResponse()
|
||||
t.Cleanup(ht.SetOutOfPollNetMap)
|
||||
} else {
|
||||
health.Global.SetOutOfPollNetMap()
|
||||
t.Cleanup(health.Global.GotStreamedMapResponse)
|
||||
ht.SetOutOfPollNetMap()
|
||||
t.Cleanup(ht.GotStreamedMapResponse)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/logpolicy"
|
||||
"tailscale.com/logtail"
|
||||
"tailscale.com/net/connstats"
|
||||
|
@ -92,7 +93,7 @@ var testClient *http.Client
|
|||
// The IP protocol and source port are always zero.
|
||||
// The sock is used to populated the PhysicalTraffic field in Message.
|
||||
// The netMon parameter is optional; if non-nil it's used to do faster interface lookups.
|
||||
func (nl *Logger) Startup(nodeID tailcfg.StableNodeID, nodeLogID, domainLogID logid.PrivateID, tun, sock Device, netMon *netmon.Monitor) error {
|
||||
func (nl *Logger) Startup(nodeID tailcfg.StableNodeID, nodeLogID, domainLogID logid.PrivateID, tun, sock Device, netMon *netmon.Monitor, health *health.Tracker) error {
|
||||
nl.mu.Lock()
|
||||
defer nl.mu.Unlock()
|
||||
if nl.logger != nil {
|
||||
|
@ -101,7 +102,7 @@ func (nl *Logger) Startup(nodeID tailcfg.StableNodeID, nodeLogID, domainLogID lo
|
|||
|
||||
// Startup a log stream to Tailscale's logging service.
|
||||
logf := log.Printf
|
||||
httpc := &http.Client{Transport: logpolicy.NewLogtailTransport(logtail.DefaultHost, netMon, logf)}
|
||||
httpc := &http.Client{Transport: logpolicy.NewLogtailTransport(logtail.DefaultHost, netMon, health, logf)}
|
||||
if testClient != nil {
|
||||
httpc = testClient
|
||||
}
|
||||
|
|
|
@ -237,7 +237,7 @@ func interfaceFromLUID(luid winipcfg.LUID, flags winipcfg.GAAFlags) (*winipcfg.I
|
|||
|
||||
var networkCategoryWarning = health.NewWarnable(health.WithMapDebugFlag("warn-network-category-unhealthy"))
|
||||
|
||||
func configureInterface(cfg *Config, tun *tun.NativeTun) (retErr error) {
|
||||
func configureInterface(cfg *Config, tun *tun.NativeTun, health *health.Tracker) (retErr error) {
|
||||
var mtu = tstun.DefaultTUNMTU()
|
||||
luid := winipcfg.LUID(tun.LUID())
|
||||
iface, err := interfaceFromLUID(luid,
|
||||
|
@ -268,10 +268,10 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) (retErr error) {
|
|||
for i := range tries {
|
||||
found, err := setPrivateNetwork(luid)
|
||||
if err != nil {
|
||||
health.Global.SetWarnable(networkCategoryWarning, fmt.Errorf("set-network-category: %w", err))
|
||||
health.SetWarnable(networkCategoryWarning, fmt.Errorf("set-network-category: %w", err))
|
||||
log.Printf("setPrivateNetwork(try=%d): %v", i, err)
|
||||
} else {
|
||||
health.Global.SetWarnable(networkCategoryWarning, nil)
|
||||
health.SetWarnable(networkCategoryWarning, nil)
|
||||
if found {
|
||||
if i > 0 {
|
||||
log.Printf("setPrivateNetwork(try=%d): success", i)
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"reflect"
|
||||
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/preftype"
|
||||
|
@ -44,9 +45,9 @@ type Router interface {
|
|||
//
|
||||
// If netMon is nil, it's not used. It's currently (2021-07-20) only
|
||||
// used on Linux in some situations.
|
||||
func New(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor) (Router, error) {
|
||||
func New(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor, health *health.Tracker) (Router, error) {
|
||||
logf = logger.WithPrefix(logf, "router: ")
|
||||
return newUserspaceRouter(logf, tundev, netMon)
|
||||
return newUserspaceRouter(logf, tundev, netMon, health)
|
||||
}
|
||||
|
||||
// CleanUp restores the system network configuration to its original state
|
||||
|
|
|
@ -5,12 +5,13 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
||||
func newUserspaceRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor) (Router, error) {
|
||||
return newUserspaceBSDRouter(logf, tundev, netMon)
|
||||
func newUserspaceRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor, health *health.Tracker) (Router, error) {
|
||||
return newUserspaceBSDRouter(logf, tundev, netMon, health)
|
||||
}
|
||||
|
||||
func cleanUp(logger.Logf, string) {
|
||||
|
|
|
@ -10,11 +10,12 @@ import (
|
|||
"runtime"
|
||||
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
||||
func newUserspaceRouter(logf logger.Logf, tunDev tun.Device, netMon *netmon.Monitor) (Router, error) {
|
||||
func newUserspaceRouter(logf logger.Logf, tunDev tun.Device, netMon *netmon.Monitor, health *health.Tracker) (Router, error) {
|
||||
return nil, fmt.Errorf("unsupported OS %q", runtime.GOOS)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/types/logger"
|
||||
)
|
||||
|
@ -14,8 +15,8 @@ import (
|
|||
// Work is currently underway for an in-kernel FreeBSD implementation of wireguard
|
||||
// https://svnweb.freebsd.org/base?view=revision&revision=357986
|
||||
|
||||
func newUserspaceRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor) (Router, error) {
|
||||
return newUserspaceBSDRouter(logf, tundev, netMon)
|
||||
func newUserspaceRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor, health *health.Tracker) (Router, error) {
|
||||
return newUserspaceBSDRouter(logf, tundev, netMon, health)
|
||||
}
|
||||
|
||||
func cleanUp(logf logger.Logf, interfaceName string) {
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"golang.org/x/sys/unix"
|
||||
"golang.org/x/time/rate"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/preftype"
|
||||
|
@ -69,7 +70,7 @@ type linuxRouter struct {
|
|||
magicsockPortV6 uint16
|
||||
}
|
||||
|
||||
func newUserspaceRouter(logf logger.Logf, tunDev tun.Device, netMon *netmon.Monitor) (Router, error) {
|
||||
func newUserspaceRouter(logf logger.Logf, tunDev tun.Device, netMon *netmon.Monitor, health *health.Tracker) (Router, error) {
|
||||
tunname, err := tunDev.Name()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -886,7 +886,7 @@ func newLinuxRootTest(t *testing.T) *linuxTest {
|
|||
mon.Start()
|
||||
lt.mon = mon
|
||||
|
||||
r, err := newUserspaceRouter(logf, lt.tun, mon)
|
||||
r, err := newUserspaceRouter(logf, lt.tun, mon, nil)
|
||||
if err != nil {
|
||||
lt.Close()
|
||||
t.Fatal(err)
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"go4.org/netipx"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/util/set"
|
||||
|
@ -30,7 +31,7 @@ type openbsdRouter struct {
|
|||
routes set.Set[netip.Prefix]
|
||||
}
|
||||
|
||||
func newUserspaceRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor) (Router, error) {
|
||||
func newUserspaceRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor, health *health.Tracker) (Router, error) {
|
||||
tunname, err := tundev.Name()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"go4.org/netipx"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/types/logger"
|
||||
|
@ -23,12 +24,13 @@ import (
|
|||
type userspaceBSDRouter struct {
|
||||
logf logger.Logf
|
||||
netMon *netmon.Monitor
|
||||
health *health.Tracker
|
||||
tunname string
|
||||
local []netip.Prefix
|
||||
routes map[netip.Prefix]bool
|
||||
}
|
||||
|
||||
func newUserspaceBSDRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor) (Router, error) {
|
||||
func newUserspaceBSDRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor, health *health.Tracker) (Router, error) {
|
||||
tunname, err := tundev.Name()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -37,6 +39,7 @@ func newUserspaceBSDRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.M
|
|||
return &userspaceBSDRouter{
|
||||
logf: logf,
|
||||
netMon: netMon,
|
||||
health: health,
|
||||
tunname: tunname,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/tailscale/wireguard-go/tun"
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/logtail/backoff"
|
||||
"tailscale.com/net/dns"
|
||||
"tailscale.com/net/netmon"
|
||||
|
@ -31,12 +32,13 @@ import (
|
|||
type winRouter struct {
|
||||
logf func(fmt string, args ...any)
|
||||
netMon *netmon.Monitor // may be nil
|
||||
health *health.Tracker
|
||||
nativeTun *tun.NativeTun
|
||||
routeChangeCallback *winipcfg.RouteChangeCallback
|
||||
firewall *firewallTweaker
|
||||
}
|
||||
|
||||
func newUserspaceRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor) (Router, error) {
|
||||
func newUserspaceRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor, health *health.Tracker) (Router, error) {
|
||||
nativeTun := tundev.(*tun.NativeTun)
|
||||
luid := winipcfg.LUID(nativeTun.LUID())
|
||||
guid, err := luid.GUID()
|
||||
|
@ -47,6 +49,7 @@ func newUserspaceRouter(logf logger.Logf, tundev tun.Device, netMon *netmon.Moni
|
|||
return &winRouter{
|
||||
logf: logf,
|
||||
netMon: netMon,
|
||||
health: health,
|
||||
nativeTun: nativeTun,
|
||||
firewall: &firewallTweaker{
|
||||
logf: logger.WithPrefix(logf, "firewall: "),
|
||||
|
@ -80,7 +83,7 @@ func (r *winRouter) Set(cfg *Config) error {
|
|||
}
|
||||
r.firewall.set(localAddrs, cfg.Routes, cfg.LocalRoutes)
|
||||
|
||||
err := configureInterface(cfg, r.nativeTun)
|
||||
err := configureInterface(cfg, r.nativeTun, r.health)
|
||||
if err != nil {
|
||||
r.logf("ConfigureInterface: %v", err)
|
||||
return err
|
||||
|
|
|
@ -98,6 +98,7 @@ type userspaceEngine struct {
|
|||
dns *dns.Manager
|
||||
magicConn *magicsock.Conn
|
||||
netMon *netmon.Monitor
|
||||
health *health.Tracker
|
||||
netMonOwned bool // whether we created netMon (and thus need to close it)
|
||||
netMonUnregister func() // unsubscribes from changes; used regardless of netMonOwned
|
||||
birdClient BIRDClient // or nil
|
||||
|
@ -188,6 +189,9 @@ type Config struct {
|
|||
// If nil, a new network monitor is created.
|
||||
NetMon *netmon.Monitor
|
||||
|
||||
// HealthTracker, if non-nil, is the health tracker to use.
|
||||
HealthTracker *health.Tracker
|
||||
|
||||
// Dialer is the dialer to use for outbound connections.
|
||||
// If nil, a new Dialer is created
|
||||
Dialer *tsdial.Dialer
|
||||
|
@ -310,6 +314,7 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
|
|||
birdClient: conf.BIRDClient,
|
||||
controlKnobs: conf.ControlKnobs,
|
||||
reconfigureVPN: conf.ReconfigureVPN,
|
||||
health: conf.HealthTracker,
|
||||
}
|
||||
|
||||
if e.birdClient != nil {
|
||||
|
@ -336,7 +341,7 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
|
|||
tunName, _ := conf.Tun.Name()
|
||||
conf.Dialer.SetTUNName(tunName)
|
||||
conf.Dialer.SetNetMon(e.netMon)
|
||||
e.dns = dns.NewManager(logf, conf.DNS, e.netMon, conf.Dialer, fwdDNSLinkSelector{e, tunName}, conf.ControlKnobs)
|
||||
e.dns = dns.NewManager(logf, conf.DNS, e.netMon, e.health, conf.Dialer, fwdDNSLinkSelector{e, tunName}, conf.ControlKnobs)
|
||||
|
||||
// TODO: there's probably a better place for this
|
||||
sockstats.SetNetMon(e.netMon)
|
||||
|
@ -372,6 +377,7 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
|
|||
IdleFunc: e.tundev.IdleDuration,
|
||||
NoteRecvActivity: e.noteRecvActivity,
|
||||
NetMon: e.netMon,
|
||||
HealthTracker: e.health,
|
||||
ControlKnobs: conf.ControlKnobs,
|
||||
OnPortUpdate: onPortUpdate,
|
||||
PeerByKeyFunc: e.PeerByKey,
|
||||
|
@ -960,7 +966,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
|
|||
nid := cfg.NetworkLogging.NodeID
|
||||
tid := cfg.NetworkLogging.DomainID
|
||||
e.logf("wgengine: Reconfig: starting up network logger (node:%s tailnet:%s)", nid.Public(), tid.Public())
|
||||
if err := e.networkLogger.Startup(cfg.NodeID, nid, tid, e.tundev, e.magicConn, e.netMon); err != nil {
|
||||
if err := e.networkLogger.Startup(cfg.NodeID, nid, tid, e.tundev, e.magicConn, e.netMon, e.health); err != nil {
|
||||
e.logf("wgengine: Reconfig: error starting up network logger: %v", err)
|
||||
}
|
||||
e.networkLogger.ReconfigRoutes(routerCfg)
|
||||
|
@ -970,7 +976,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
|
|||
e.logf("wgengine: Reconfig: configuring router")
|
||||
e.networkLogger.ReconfigRoutes(routerCfg)
|
||||
err := e.router.Set(routerCfg)
|
||||
health.Global.SetRouterHealth(err)
|
||||
e.health.SetRouterHealth(err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -979,7 +985,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
|
|||
// assigned address.
|
||||
e.logf("wgengine: Reconfig: configuring DNS")
|
||||
err = e.dns.Set(*dnsCfg)
|
||||
health.Global.SetDNSHealth(err)
|
||||
e.health.SetDNSHealth(err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1183,7 +1189,7 @@ func (e *userspaceEngine) linkChange(delta *netmon.ChangeDelta) {
|
|||
e.logf("[v1] LinkChange: minor")
|
||||
}
|
||||
|
||||
health.Global.SetAnyInterfaceUp(up)
|
||||
e.health.SetAnyInterfaceUp(up)
|
||||
e.magicConn.SetNetworkUp(up)
|
||||
if !up || changed {
|
||||
if err := e.dns.FlushCaches(); err != nil {
|
||||
|
|
Loading…
Reference in New Issue