mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
net/netns, net/dns/resolver, etc: make netmon required in most places
The goal is to move more network state accessors to netmon.Monitor where they can be cheaper/cached. But first (this change and others) we need to make sure the one netmon.Monitor is plumbed everywhere. Some notable bits: * tsdial.NewDialer is added, taking a now-required netmon * because a tsdial.Dialer always has a netmon, anything taking both a Dialer and a NetMon is now redundant; take only the Dialer and get the NetMon from that if/when needed. * netmon.NewStatic is added, primarily for tests Updates tailscale/corp#10910 Updates tailscale/corp#18960 Updates #7967 Updates #3299 Change-Id: I877f9cb87618c4eb037cee098241d18da9c01691 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
4f73a26ea5
commit
3672f29a4e
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
"tailscale.com/derp"
|
"tailscale.com/derp"
|
||||||
"tailscale.com/derp/derphttp"
|
"tailscale.com/derp/derphttp"
|
||||||
|
"tailscale.com/net/netmon"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
)
|
)
|
||||||
@ -36,7 +37,8 @@ func startMesh(s *derp.Server) error {
|
|||||||
|
|
||||||
func startMeshWithHost(s *derp.Server, host string) error {
|
func startMeshWithHost(s *derp.Server, host string) error {
|
||||||
logf := logger.WithPrefix(log.Printf, fmt.Sprintf("mesh(%q): ", host))
|
logf := logger.WithPrefix(log.Printf, fmt.Sprintf("mesh(%q): ", host))
|
||||||
c, err := derphttp.NewClient(s.PrivateKey(), "https://"+host+"/derp", logf)
|
netMon := netmon.NewStatic() // good enough for cmd/derper; no need for netns fanciness
|
||||||
|
c, err := derphttp.NewClient(s.PrivateKey(), "https://"+host+"/derp", logf, netMon)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -393,8 +393,8 @@ func run() (err error) {
|
|||||||
// Always clean up, even if we're going to run the server. This covers cases
|
// Always clean up, even if we're going to run the server. This covers cases
|
||||||
// such as when a system was rebooted without shutting down, or tailscaled
|
// such as when a system was rebooted without shutting down, or tailscaled
|
||||||
// crashed, and would for example restore system DNS configuration.
|
// crashed, and would for example restore system DNS configuration.
|
||||||
dns.CleanUp(logf, args.tunname)
|
dns.CleanUp(logf, netMon, args.tunname)
|
||||||
router.CleanUp(logf, args.tunname)
|
router.CleanUp(logf, netMon, args.tunname)
|
||||||
// If the cleanUp flag was passed, then exit.
|
// If the cleanUp flag was passed, then exit.
|
||||||
if args.cleanUp {
|
if args.cleanUp {
|
||||||
return nil
|
return nil
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
"tailscale.com/util/singleflight"
|
"tailscale.com/util/singleflight"
|
||||||
"tailscale.com/util/syspolicy"
|
"tailscale.com/util/syspolicy"
|
||||||
"tailscale.com/util/systemd"
|
"tailscale.com/util/systemd"
|
||||||
|
"tailscale.com/util/testenv"
|
||||||
"tailscale.com/util/zstdframe"
|
"tailscale.com/util/zstdframe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -68,7 +69,7 @@ type Direct struct {
|
|||||||
serverURL string // URL of the tailcontrol server
|
serverURL string // URL of the tailcontrol server
|
||||||
clock tstime.Clock
|
clock tstime.Clock
|
||||||
logf logger.Logf
|
logf logger.Logf
|
||||||
netMon *netmon.Monitor // or nil
|
netMon *netmon.Monitor // non-nil
|
||||||
health *health.Tracker
|
health *health.Tracker
|
||||||
discoPubKey key.DiscoPublic
|
discoPubKey key.DiscoPublic
|
||||||
getMachinePrivKey func() (key.MachinePrivate, error)
|
getMachinePrivKey func() (key.MachinePrivate, error)
|
||||||
@ -120,10 +121,9 @@ type Options struct {
|
|||||||
Hostinfo *tailcfg.Hostinfo // non-nil passes ownership, nil means to use default using os.Hostname, etc
|
Hostinfo *tailcfg.Hostinfo // non-nil passes ownership, nil means to use default using os.Hostname, etc
|
||||||
DiscoPublicKey key.DiscoPublic
|
DiscoPublicKey key.DiscoPublic
|
||||||
Logf logger.Logf
|
Logf logger.Logf
|
||||||
HTTPTestClient *http.Client // optional HTTP client to use (for tests only)
|
HTTPTestClient *http.Client // optional HTTP client to use (for tests only)
|
||||||
NoiseTestClient *http.Client // optional HTTP client to use for noise RPCs (tests only)
|
NoiseTestClient *http.Client // optional HTTP client to use for noise RPCs (tests only)
|
||||||
DebugFlags []string // debug settings to send to control
|
DebugFlags []string // debug settings to send to control
|
||||||
NetMon *netmon.Monitor // optional network monitor
|
|
||||||
HealthTracker *health.Tracker
|
HealthTracker *health.Tracker
|
||||||
PopBrowserURL func(url string) // optional func to open browser
|
PopBrowserURL func(url string) // optional func to open browser
|
||||||
OnClientVersion func(*tailcfg.ClientVersion) // optional func to inform GUI of client version status
|
OnClientVersion func(*tailcfg.ClientVersion) // optional func to inform GUI of client version status
|
||||||
@ -213,6 +213,19 @@ func NewDirect(opts Options) (*Direct, error) {
|
|||||||
if opts.GetMachinePrivateKey == nil {
|
if opts.GetMachinePrivateKey == nil {
|
||||||
return nil, errors.New("controlclient.New: no GetMachinePrivateKey specified")
|
return nil, errors.New("controlclient.New: no GetMachinePrivateKey specified")
|
||||||
}
|
}
|
||||||
|
if opts.Dialer == nil {
|
||||||
|
if testenv.InTest() {
|
||||||
|
panic("no Dialer")
|
||||||
|
}
|
||||||
|
return nil, errors.New("controlclient.New: no Dialer specified")
|
||||||
|
}
|
||||||
|
netMon := opts.Dialer.NetMon()
|
||||||
|
if netMon == nil {
|
||||||
|
if testenv.InTest() {
|
||||||
|
panic("no NetMon in Dialer")
|
||||||
|
}
|
||||||
|
return nil, errors.New("controlclient.New: Dialer has nil NetMon")
|
||||||
|
}
|
||||||
if opts.ControlKnobs == nil {
|
if opts.ControlKnobs == nil {
|
||||||
opts.ControlKnobs = &controlknobs.Knobs{}
|
opts.ControlKnobs = &controlknobs.Knobs{}
|
||||||
}
|
}
|
||||||
@ -233,9 +246,8 @@ func NewDirect(opts Options) (*Direct, error) {
|
|||||||
dnsCache := &dnscache.Resolver{
|
dnsCache := &dnscache.Resolver{
|
||||||
Forward: dnscache.Get().Forward, // use default cache's forwarder
|
Forward: dnscache.Get().Forward, // use default cache's forwarder
|
||||||
UseLastGood: true,
|
UseLastGood: true,
|
||||||
LookupIPFallback: dnsfallback.MakeLookupFunc(opts.Logf, opts.NetMon),
|
LookupIPFallback: dnsfallback.MakeLookupFunc(opts.Logf, netMon),
|
||||||
Logf: opts.Logf,
|
Logf: opts.Logf,
|
||||||
NetMon: opts.NetMon,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
httpc := opts.HTTPTestClient
|
httpc := opts.HTTPTestClient
|
||||||
@ -272,7 +284,7 @@ func NewDirect(opts Options) (*Direct, error) {
|
|||||||
authKey: opts.AuthKey,
|
authKey: opts.AuthKey,
|
||||||
discoPubKey: opts.DiscoPublicKey,
|
discoPubKey: opts.DiscoPublicKey,
|
||||||
debugFlags: opts.DebugFlags,
|
debugFlags: opts.DebugFlags,
|
||||||
netMon: opts.NetMon,
|
netMon: netMon,
|
||||||
health: opts.HealthTracker,
|
health: opts.HealthTracker,
|
||||||
skipIPForwardingCheck: opts.SkipIPForwardingCheck,
|
skipIPForwardingCheck: opts.SkipIPForwardingCheck,
|
||||||
pinger: opts.Pinger,
|
pinger: opts.Pinger,
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
"tailscale.com/hostinfo"
|
"tailscale.com/hostinfo"
|
||||||
"tailscale.com/ipn/ipnstate"
|
"tailscale.com/ipn/ipnstate"
|
||||||
|
"tailscale.com/net/netmon"
|
||||||
"tailscale.com/net/tsdial"
|
"tailscale.com/net/tsdial"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
@ -31,7 +32,7 @@ func TestNewDirect(t *testing.T) {
|
|||||||
GetMachinePrivateKey: func() (key.MachinePrivate, error) {
|
GetMachinePrivateKey: func() (key.MachinePrivate, error) {
|
||||||
return k, nil
|
return k, nil
|
||||||
},
|
},
|
||||||
Dialer: new(tsdial.Dialer),
|
Dialer: tsdial.NewDialer(netmon.NewStatic()),
|
||||||
}
|
}
|
||||||
c, err := NewDirect(opts)
|
c, err := NewDirect(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -107,7 +108,7 @@ func TestTsmpPing(t *testing.T) {
|
|||||||
GetMachinePrivateKey: func() (key.MachinePrivate, error) {
|
GetMachinePrivateKey: func() (key.MachinePrivate, error) {
|
||||||
return k, nil
|
return k, nil
|
||||||
},
|
},
|
||||||
Dialer: new(tsdial.Dialer),
|
Dialer: tsdial.NewDialer(netmon.NewStatic()),
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := NewDirect(opts)
|
c, err := NewDirect(opts)
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
"tailscale.com/control/controlhttp"
|
"tailscale.com/control/controlhttp"
|
||||||
|
"tailscale.com/net/netmon"
|
||||||
"tailscale.com/net/tsdial"
|
"tailscale.com/net/tsdial"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
@ -73,7 +74,7 @@ func (tt noiseClientTest) run(t *testing.T) {
|
|||||||
})
|
})
|
||||||
defer hs.Close()
|
defer hs.Close()
|
||||||
|
|
||||||
dialer := new(tsdial.Dialer)
|
dialer := tsdial.NewDialer(netmon.NewStatic())
|
||||||
nc, err := NewNoiseClient(NoiseOpts{
|
nc, err := NewNoiseClient(NoiseOpts{
|
||||||
PrivKey: clientPrivate,
|
PrivKey: clientPrivate,
|
||||||
ServerPubKey: serverPrivate.Public(),
|
ServerPubKey: serverPrivate.Public(),
|
||||||
|
@ -393,7 +393,6 @@ func (a *Dialer) resolver() *dnscache.Resolver {
|
|||||||
LookupIPFallback: dnsfallback.MakeLookupFunc(a.logf, a.NetMon),
|
LookupIPFallback: dnsfallback.MakeLookupFunc(a.logf, a.NetMon),
|
||||||
UseLastGood: true,
|
UseLastGood: true,
|
||||||
Logf: a.Logf, // not a.logf method; we want to propagate nil-ness
|
Logf: a.Logf, // not a.logf method; we want to propagate nil-ness
|
||||||
NetMon: a.NetMon,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,7 +411,6 @@ func (a *Dialer) tryURLUpgrade(ctx context.Context, u *url.URL, addr netip.Addr,
|
|||||||
SingleHostStaticResult: []netip.Addr{addr},
|
SingleHostStaticResult: []netip.Addr{addr},
|
||||||
SingleHost: u.Hostname(),
|
SingleHost: u.Hostname(),
|
||||||
Logf: a.Logf, // not a.logf method; we want to propagate nil-ness
|
Logf: a.Logf, // not a.logf method; we want to propagate nil-ness
|
||||||
NetMon: a.NetMon,
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dns = a.resolver()
|
dns = a.resolver()
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
"tailscale.com/control/controlbase"
|
"tailscale.com/control/controlbase"
|
||||||
"tailscale.com/net/dnscache"
|
"tailscale.com/net/dnscache"
|
||||||
|
"tailscale.com/net/netmon"
|
||||||
"tailscale.com/net/socks5"
|
"tailscale.com/net/socks5"
|
||||||
"tailscale.com/net/tsdial"
|
"tailscale.com/net/tsdial"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
@ -199,14 +200,17 @@ func testControlHTTP(t *testing.T, param httpTestParam) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netMon := netmon.NewStatic()
|
||||||
|
dialer := tsdial.NewDialer(netMon)
|
||||||
a := &Dialer{
|
a := &Dialer{
|
||||||
Hostname: "localhost",
|
Hostname: "localhost",
|
||||||
HTTPPort: strconv.Itoa(httpLn.Addr().(*net.TCPAddr).Port),
|
HTTPPort: strconv.Itoa(httpLn.Addr().(*net.TCPAddr).Port),
|
||||||
HTTPSPort: strconv.Itoa(httpsLn.Addr().(*net.TCPAddr).Port),
|
HTTPSPort: strconv.Itoa(httpsLn.Addr().(*net.TCPAddr).Port),
|
||||||
MachineKey: client,
|
MachineKey: client,
|
||||||
ControlKey: server.Public(),
|
ControlKey: server.Public(),
|
||||||
|
NetMon: netMon,
|
||||||
ProtocolVersion: testProtocolVersion,
|
ProtocolVersion: testProtocolVersion,
|
||||||
Dialer: new(tsdial.Dialer).SystemDial,
|
Dialer: dialer.SystemDial,
|
||||||
Logf: t.Logf,
|
Logf: t.Logf,
|
||||||
omitCertErrorLogging: true,
|
omitCertErrorLogging: true,
|
||||||
testFallbackDelay: fallbackDelay,
|
testFallbackDelay: fallbackDelay,
|
||||||
@ -643,7 +647,7 @@ func TestDialPlan(t *testing.T) {
|
|||||||
|
|
||||||
dialer := closeTrackDialer{
|
dialer := closeTrackDialer{
|
||||||
t: t,
|
t: t,
|
||||||
inner: new(tsdial.Dialer).SystemDial,
|
inner: tsdial.NewDialer(netmon.NewStatic()).SystemDial,
|
||||||
conns: make(map[*closeTrackConn]bool),
|
conns: make(map[*closeTrackConn]bool),
|
||||||
}
|
}
|
||||||
defer dialer.Done()
|
defer dialer.Done()
|
||||||
|
@ -71,7 +71,7 @@ type Client struct {
|
|||||||
|
|
||||||
privateKey key.NodePrivate
|
privateKey key.NodePrivate
|
||||||
logf logger.Logf
|
logf logger.Logf
|
||||||
netMon *netmon.Monitor // optional; nil means interfaces will be looked up on-demand
|
netMon *netmon.Monitor // always non-nil
|
||||||
dialer func(ctx context.Context, network, addr string) (net.Conn, error)
|
dialer func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||||
|
|
||||||
// Either url or getRegion is non-nil:
|
// Either url or getRegion is non-nil:
|
||||||
@ -116,9 +116,11 @@ func (c *Client) String() string {
|
|||||||
|
|
||||||
// NewRegionClient returns a new DERP-over-HTTP client. It connects lazily.
|
// NewRegionClient returns a new DERP-over-HTTP client. It connects lazily.
|
||||||
// To trigger a connection, use Connect.
|
// To trigger a connection, use Connect.
|
||||||
// The netMon parameter is optional; if non-nil it's used to do faster interface lookups.
|
|
||||||
// The healthTracker parameter is also optional.
|
// The healthTracker parameter is also optional.
|
||||||
func NewRegionClient(privateKey key.NodePrivate, logf logger.Logf, netMon *netmon.Monitor, getRegion func() *tailcfg.DERPRegion) *Client {
|
func NewRegionClient(privateKey key.NodePrivate, logf logger.Logf, netMon *netmon.Monitor, getRegion func() *tailcfg.DERPRegion) *Client {
|
||||||
|
if netMon == nil {
|
||||||
|
panic("nil netMon")
|
||||||
|
}
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
c := &Client{
|
c := &Client{
|
||||||
privateKey: privateKey,
|
privateKey: privateKey,
|
||||||
@ -140,7 +142,10 @@ func NewNetcheckClient(logf logger.Logf) *Client {
|
|||||||
|
|
||||||
// NewClient returns a new DERP-over-HTTP client. It connects lazily.
|
// NewClient returns a new DERP-over-HTTP client. It connects lazily.
|
||||||
// To trigger a connection, use Connect.
|
// To trigger a connection, use Connect.
|
||||||
func NewClient(privateKey key.NodePrivate, serverURL string, logf logger.Logf) (*Client, error) {
|
func NewClient(privateKey key.NodePrivate, serverURL string, logf logger.Logf, netMon *netmon.Monitor) (*Client, error) {
|
||||||
|
if netMon == nil {
|
||||||
|
panic("nil netMon")
|
||||||
|
}
|
||||||
u, err := url.Parse(serverURL)
|
u, err := url.Parse(serverURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("derphttp.NewClient: %v", err)
|
return nil, fmt.Errorf("derphttp.NewClient: %v", err)
|
||||||
@ -157,6 +162,7 @@ func NewClient(privateKey key.NodePrivate, serverURL string, logf logger.Logf) (
|
|||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancelCtx: cancel,
|
cancelCtx: cancel,
|
||||||
clock: tstime.StdClock{},
|
clock: tstime.StdClock{},
|
||||||
|
netMon: netMon,
|
||||||
}
|
}
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,15 @@
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tailscale.com/derp"
|
"tailscale.com/derp"
|
||||||
|
"tailscale.com/net/netmon"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSendRecv(t *testing.T) {
|
func TestSendRecv(t *testing.T) {
|
||||||
serverPrivateKey := key.NewNode()
|
serverPrivateKey := key.NewNode()
|
||||||
|
|
||||||
|
netMon := netmon.NewStatic()
|
||||||
|
|
||||||
const numClients = 3
|
const numClients = 3
|
||||||
var clientPrivateKeys []key.NodePrivate
|
var clientPrivateKeys []key.NodePrivate
|
||||||
var clientKeys []key.NodePublic
|
var clientKeys []key.NodePublic
|
||||||
@ -68,7 +71,7 @@ func TestSendRecv(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
for i := range numClients {
|
for i := range numClients {
|
||||||
key := clientPrivateKeys[i]
|
key := clientPrivateKeys[i]
|
||||||
c, err := NewClient(key, serverURL, t.Logf)
|
c, err := NewClient(key, serverURL, t.Logf, netMon)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("client %d: %v", i, err)
|
t.Fatalf("client %d: %v", i, err)
|
||||||
}
|
}
|
||||||
@ -183,7 +186,7 @@ func TestPing(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
c, err := NewClient(key.NewNode(), serverURL, t.Logf)
|
c, err := NewClient(key.NewNode(), serverURL, t.Logf, netmon.NewStatic())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClient: %v", err)
|
t.Fatalf("NewClient: %v", err)
|
||||||
}
|
}
|
||||||
@ -236,7 +239,7 @@ func newTestServer(t *testing.T, k key.NodePrivate) (serverURL string, s *derp.S
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newWatcherClient(t *testing.T, watcherPrivateKey key.NodePrivate, serverToWatchURL string) (c *Client) {
|
func newWatcherClient(t *testing.T, watcherPrivateKey key.NodePrivate, serverToWatchURL string) (c *Client) {
|
||||||
c, err := NewClient(watcherPrivateKey, serverToWatchURL, t.Logf)
|
c, err := NewClient(watcherPrivateKey, serverToWatchURL, t.Logf, netmon.NewStatic())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -353,6 +353,12 @@ func NewLocalBackend(logf logger.Logf, logID logid.PublicID, sys *tsd.System, lo
|
|||||||
e := sys.Engine.Get()
|
e := sys.Engine.Get()
|
||||||
store := sys.StateStore.Get()
|
store := sys.StateStore.Get()
|
||||||
dialer := sys.Dialer.Get()
|
dialer := sys.Dialer.Get()
|
||||||
|
if dialer == nil {
|
||||||
|
return nil, errors.New("dialer to NewLocalBackend must be set")
|
||||||
|
}
|
||||||
|
if dialer.NetMon() == nil {
|
||||||
|
return nil, errors.New("dialer to NewLocalBackend must have a NetMon")
|
||||||
|
}
|
||||||
_ = sys.MagicSock.Get() // or panic
|
_ = sys.MagicSock.Get() // or panic
|
||||||
|
|
||||||
goos := envknob.GOOS()
|
goos := envknob.GOOS()
|
||||||
@ -1762,7 +1768,6 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
|
|||||||
HTTPTestClient: httpTestClient,
|
HTTPTestClient: httpTestClient,
|
||||||
DiscoPublicKey: discoPublic,
|
DiscoPublicKey: discoPublic,
|
||||||
DebugFlags: debugFlags,
|
DebugFlags: debugFlags,
|
||||||
NetMon: b.sys.NetMon.Get(),
|
|
||||||
HealthTracker: b.health,
|
HealthTracker: b.health,
|
||||||
Pinger: b,
|
Pinger: b,
|
||||||
PopBrowserURL: b.tellClientToBrowseToURL,
|
PopBrowserURL: b.tellClientToBrowseToURL,
|
||||||
|
@ -2273,7 +2273,6 @@ func TestOnTailnetDefaultAutoUpdate(t *testing.T) {
|
|||||||
t.Skip("test broken on macOS; see https://github.com/tailscale/tailscale/issues/11894")
|
t.Skip("test broken on macOS; see https://github.com/tailscale/tailscale/issues/11894")
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
desc string
|
|
||||||
before, after opt.Bool
|
before, after opt.Bool
|
||||||
tailnetDefault bool
|
tailnetDefault bool
|
||||||
}{
|
}{
|
||||||
@ -2309,7 +2308,7 @@ func TestOnTailnetDefaultAutoUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(fmt.Sprintf("before=%s after=%s", tt.before, tt.after), func(t *testing.T) {
|
t.Run(fmt.Sprintf("before=%s,after=%s", tt.before, tt.after), func(t *testing.T) {
|
||||||
b := newTestBackend(t)
|
b := newTestBackend(t)
|
||||||
p := ipn.NewPrefs()
|
p := ipn.NewPrefs()
|
||||||
p.AutoUpdate.Apply = tt.before
|
p.AutoUpdate.Apply = tt.before
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
"tailscale.com/hostinfo"
|
"tailscale.com/hostinfo"
|
||||||
"tailscale.com/ipn"
|
"tailscale.com/ipn"
|
||||||
"tailscale.com/ipn/store/mem"
|
"tailscale.com/ipn/store/mem"
|
||||||
|
"tailscale.com/net/netmon"
|
||||||
|
"tailscale.com/net/tsdial"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/tka"
|
"tailscale.com/tka"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
@ -50,6 +52,7 @@ func fakeControlClient(t *testing.T, c *http.Client) *controlclient.Auto {
|
|||||||
HTTPTestClient: c,
|
HTTPTestClient: c,
|
||||||
NoiseTestClient: c,
|
NoiseTestClient: c,
|
||||||
Observer: observerFunc(func(controlclient.Status) {}),
|
Observer: observerFunc(func(controlclient.Status) {}),
|
||||||
|
Dialer: tsdial.NewDialer(netmon.NewStatic()),
|
||||||
}
|
}
|
||||||
|
|
||||||
cc, err := controlclient.NewNoStart(opts)
|
cc, err := controlclient.NewNoStart(opts)
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"tailscale.com/ipn/store/mem"
|
"tailscale.com/ipn/store/mem"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/tsd"
|
"tailscale.com/tsd"
|
||||||
|
"tailscale.com/types/logger"
|
||||||
"tailscale.com/types/logid"
|
"tailscale.com/types/logid"
|
||||||
"tailscale.com/types/netmap"
|
"tailscale.com/types/netmap"
|
||||||
"tailscale.com/util/mak"
|
"tailscale.com/util/mak"
|
||||||
@ -663,14 +664,21 @@ func mustCreateURL(t *testing.T, u string) url.URL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newTestBackend(t *testing.T) *LocalBackend {
|
func newTestBackend(t *testing.T) *LocalBackend {
|
||||||
|
var logf logger.Logf = logger.Discard
|
||||||
|
const debug = true
|
||||||
|
if debug {
|
||||||
|
logf = logger.WithPrefix(t.Logf, "... ")
|
||||||
|
}
|
||||||
|
|
||||||
sys := &tsd.System{}
|
sys := &tsd.System{}
|
||||||
e, err := wgengine.NewUserspaceEngine(t.Logf, wgengine.Config{SetSubsystem: sys.Set})
|
e, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{SetSubsystem: sys.Set})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
sys.Set(e)
|
sys.Set(e)
|
||||||
sys.Set(new(mem.Store))
|
sys.Set(new(mem.Store))
|
||||||
b, err := NewLocalBackend(t.Logf, logid.PublicID{}, sys, 0)
|
|
||||||
|
b, err := NewLocalBackend(logf, logid.PublicID{}, sys, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -678,7 +686,7 @@ func newTestBackend(t *testing.T) *LocalBackend {
|
|||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
b.SetVarRoot(dir)
|
b.SetVarRoot(dir)
|
||||||
|
|
||||||
pm := must.Get(newProfileManager(new(mem.Store), t.Logf))
|
pm := must.Get(newProfileManager(new(mem.Store), logf))
|
||||||
pm.currentProfile = &ipn.LoginProfile{ID: "id0"}
|
pm.currentProfile = &ipn.LoginProfile{ID: "id0"}
|
||||||
b.pm = pm
|
b.pm = pm
|
||||||
|
|
||||||
|
@ -93,11 +93,16 @@ func SockstatLogID(logID logid.PublicID) logid.PrivateID {
|
|||||||
// On platforms that do not support sockstat logging, a nil Logger will be returned.
|
// On platforms that do not support sockstat logging, a nil Logger will be returned.
|
||||||
// The returned Logger is not yet enabled, and must be shut down with Shutdown when it is no longer needed.
|
// 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.
|
// 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.
|
//
|
||||||
|
// The netMon parameter is optional. It should be specified in environments where
|
||||||
|
// Tailscaled is manipulating the routing table.
|
||||||
func NewLogger(logdir string, logf logger.Logf, logID logid.PublicID, netMon *netmon.Monitor, health *health.Tracker) (*Logger, error) {
|
func NewLogger(logdir string, logf logger.Logf, logID logid.PublicID, netMon *netmon.Monitor, health *health.Tracker) (*Logger, error) {
|
||||||
if !sockstats.IsAvailable {
|
if !sockstats.IsAvailable {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
if netMon == nil {
|
||||||
|
netMon = netmon.NewStatic()
|
||||||
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(logdir, 0755); err != nil && !os.IsExist(err) {
|
if err := os.MkdirAll(logdir, 0755); err != nil && !os.IsExist(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -447,8 +447,8 @@ func tryFixLogStateLocation(dir, cmdname string, logf logger.Logf) {
|
|||||||
// New returns a new log policy (a logger and its instance ID) for a given
|
// New returns a new log policy (a logger and its instance ID) for a given
|
||||||
// collection name.
|
// collection name.
|
||||||
//
|
//
|
||||||
// The netMon parameter is optional; if non-nil it's used to do faster
|
// The netMon parameter is optional. It should be specified in environments where
|
||||||
// interface lookups.
|
// Tailscaled is manipulating the routing table.
|
||||||
//
|
//
|
||||||
// The logf parameter is optional; if non-nil, information logs (e.g. when
|
// 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
|
// migrating state) are sent to that logger, and global changes to the log
|
||||||
@ -459,6 +459,9 @@ func New(collection string, netMon *netmon.Monitor, health *health.Tracker, logf
|
|||||||
|
|
||||||
// NewWithConfigPath is identical to New, but uses the specified directory and
|
// NewWithConfigPath is identical to New, but uses the specified directory and
|
||||||
// command name. If either is empty, it derives them automatically.
|
// command name. If either is empty, it derives them automatically.
|
||||||
|
//
|
||||||
|
// The netMon parameter is optional. It should be specified in environments where
|
||||||
|
// Tailscaled is manipulating the routing table.
|
||||||
func NewWithConfigPath(collection, dir, cmdName string, netMon *netmon.Monitor, health *health.Tracker, logf logger.Logf) *Policy {
|
func NewWithConfigPath(collection, dir, cmdName string, netMon *netmon.Monitor, health *health.Tracker, logf logger.Logf) *Policy {
|
||||||
var lflags int
|
var lflags int
|
||||||
if term.IsTerminal(2) || runtime.GOOS == "windows" {
|
if term.IsTerminal(2) || runtime.GOOS == "windows" {
|
||||||
@ -681,8 +684,12 @@ func (p *Policy) Shutdown(ctx context.Context) error {
|
|||||||
// - If TLS connection fails, try again using LetsEncrypt's built-in root certificate,
|
// - If TLS connection fails, try again using LetsEncrypt's built-in root certificate,
|
||||||
// for the benefit of older OS platforms which might not include it.
|
// for the benefit of older OS platforms which might not include it.
|
||||||
//
|
//
|
||||||
// The netMon parameter is optional; if non-nil it's used to do faster interface lookups.
|
// The netMon parameter is optional. It should be specified in environments where
|
||||||
|
// Tailscaled is manipulating the routing table.
|
||||||
func MakeDialFunc(netMon *netmon.Monitor, logf logger.Logf) func(ctx context.Context, netw, addr string) (net.Conn, error) {
|
func MakeDialFunc(netMon *netmon.Monitor, logf logger.Logf) func(ctx context.Context, netw, addr string) (net.Conn, error) {
|
||||||
|
if netMon == nil {
|
||||||
|
netMon = netmon.NewStatic()
|
||||||
|
}
|
||||||
return func(ctx context.Context, netw, addr string) (net.Conn, error) {
|
return func(ctx context.Context, netw, addr string) (net.Conn, error) {
|
||||||
return dialContext(ctx, netw, addr, netMon, logf)
|
return dialContext(ctx, netw, addr, netMon, logf)
|
||||||
}
|
}
|
||||||
@ -725,7 +732,6 @@ func dialContext(ctx context.Context, netw, addr string, netMon *netmon.Monitor,
|
|||||||
Forward: dnscache.Get().Forward, // use default cache's forwarder
|
Forward: dnscache.Get().Forward, // use default cache's forwarder
|
||||||
UseLastGood: true,
|
UseLastGood: true,
|
||||||
LookupIPFallback: dnsfallback.MakeLookupFunc(logf, netMon),
|
LookupIPFallback: dnsfallback.MakeLookupFunc(logf, netMon),
|
||||||
NetMon: netMon,
|
|
||||||
}
|
}
|
||||||
dialer := dnscache.Dialer(nd.DialContext, dnsCache)
|
dialer := dnscache.Dialer(nd.DialContext, dnsCache)
|
||||||
c, err = dialer(ctx, netw, addr)
|
c, err = dialer(ctx, netw, addr)
|
||||||
@ -738,7 +744,8 @@ func dialContext(ctx context.Context, netw, addr string, netMon *netmon.Monitor,
|
|||||||
// NewLogtailTransport returns an HTTP Transport particularly suited to uploading
|
// NewLogtailTransport returns an HTTP Transport particularly suited to uploading
|
||||||
// logs to the given host name. See DialContext for details on how it works.
|
// logs to the given host name. See DialContext for details on how it works.
|
||||||
//
|
//
|
||||||
// The netMon parameter is optional; if non-nil it's used to do faster interface lookups.
|
// The netMon parameter is optional. It should be specified in environments where
|
||||||
|
// Tailscaled is manipulating the routing table.
|
||||||
//
|
//
|
||||||
// The logf parameter is optional; if non-nil, logs are printed using the
|
// The logf parameter is optional; if non-nil, logs are printed using the
|
||||||
// provided function; if nil, log.Printf will be used instead.
|
// provided function; if nil, log.Printf will be used instead.
|
||||||
@ -746,6 +753,9 @@ func NewLogtailTransport(host string, netMon *netmon.Monitor, health *health.Tra
|
|||||||
if testenv.InTest() {
|
if testenv.InTest() {
|
||||||
return noopPretendSuccessTransport{}
|
return noopPretendSuccessTransport{}
|
||||||
}
|
}
|
||||||
|
if netMon == nil {
|
||||||
|
netMon = netmon.NewStatic()
|
||||||
|
}
|
||||||
// Start with a copy of http.DefaultTransport and tweak it a bit.
|
// Start with a copy of http.DefaultTransport and tweak it a bit.
|
||||||
tr := http.DefaultTransport.(*http.Transport).Clone()
|
tr := http.DefaultTransport.(*http.Transport).Clone()
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ func (l *Logger) SetVerbosityLevel(level int) {
|
|||||||
atomic.StoreInt64(&l.stderrLevel, int64(level))
|
atomic.StoreInt64(&l.stderrLevel, int64(level))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNetMon sets the optional the network monitor.
|
// SetNetMon sets the network monitor.
|
||||||
//
|
//
|
||||||
// It should not be changed concurrently with log writes and should
|
// It should not be changed concurrently with log writes and should
|
||||||
// only be set once.
|
// only be set once.
|
||||||
|
@ -55,15 +55,17 @@ type Manager struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewManagers created a new manager from the given config.
|
// 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, health *health.Tracker, 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 {
|
if dialer == nil {
|
||||||
panic("nil Dialer")
|
panic("nil Dialer")
|
||||||
}
|
}
|
||||||
|
if dialer.NetMon() == nil {
|
||||||
|
panic("Dialer has nil NetMon")
|
||||||
|
}
|
||||||
logf = logger.WithPrefix(logf, "dns: ")
|
logf = logger.WithPrefix(logf, "dns: ")
|
||||||
m := &Manager{
|
m := &Manager{
|
||||||
logf: logf,
|
logf: logf,
|
||||||
resolver: resolver.New(logf, netMon, linkSel, dialer, knobs),
|
resolver: resolver.New(logf, linkSel, dialer, knobs),
|
||||||
os: oscfg,
|
os: oscfg,
|
||||||
health: health,
|
health: health,
|
||||||
}
|
}
|
||||||
@ -454,13 +456,15 @@ func (m *Manager) FlushCaches() error {
|
|||||||
// CleanUp restores the system DNS configuration to its original state
|
// CleanUp restores the system DNS configuration to its original state
|
||||||
// in case the Tailscale daemon terminated without closing the router.
|
// in case the Tailscale daemon terminated without closing the router.
|
||||||
// No other state needs to be instantiated before this runs.
|
// No other state needs to be instantiated before this runs.
|
||||||
func CleanUp(logf logger.Logf, interfaceName string) {
|
func CleanUp(logf logger.Logf, netMon *netmon.Monitor, interfaceName string) {
|
||||||
oscfg, err := NewOSConfigurator(logf, nil, interfaceName)
|
oscfg, err := NewOSConfigurator(logf, nil, interfaceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logf("creating dns cleanup: %v", err)
|
logf("creating dns cleanup: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dns := NewManager(logf, oscfg, nil, nil, &tsdial.Dialer{Logf: logf}, nil, nil)
|
d := &tsdial.Dialer{Logf: logf}
|
||||||
|
d.SetNetMon(netMon)
|
||||||
|
dns := NewManager(logf, oscfg, nil, d, nil, nil)
|
||||||
if err := dns.Down(); err != nil {
|
if err := dns.Down(); err != nil {
|
||||||
logf("dns down: %v", err)
|
logf("dns down: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
dns "golang.org/x/net/dns/dnsmessage"
|
dns "golang.org/x/net/dns/dnsmessage"
|
||||||
|
"tailscale.com/net/netmon"
|
||||||
"tailscale.com/net/tsdial"
|
"tailscale.com/net/tsdial"
|
||||||
"tailscale.com/tstest"
|
"tailscale.com/tstest"
|
||||||
"tailscale.com/util/dnsname"
|
"tailscale.com/util/dnsname"
|
||||||
@ -87,7 +88,7 @@ func TestDNSOverTCP(t *testing.T) {
|
|||||||
SearchDomains: fqdns("coffee.shop"),
|
SearchDomains: fqdns("coffee.shop"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
m := NewManager(t.Logf, &f, nil, nil, new(tsdial.Dialer), nil, nil)
|
m := NewManager(t.Logf, &f, nil, tsdial.NewDialer(netmon.NewStatic()), nil, nil)
|
||||||
m.resolver.TestOnlySetHook(f.SetResolver)
|
m.resolver.TestOnlySetHook(f.SetResolver)
|
||||||
m.Set(Config{
|
m.Set(Config{
|
||||||
Hosts: hosts(
|
Hosts: hosts(
|
||||||
@ -172,7 +173,7 @@ func TestDNSOverTCP_TooLarge(t *testing.T) {
|
|||||||
SearchDomains: fqdns("coffee.shop"),
|
SearchDomains: fqdns("coffee.shop"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
m := NewManager(log, &f, nil, nil, new(tsdial.Dialer), nil, nil)
|
m := NewManager(log, &f, nil, tsdial.NewDialer(netmon.NewStatic()), nil, nil)
|
||||||
m.resolver.TestOnlySetHook(f.SetResolver)
|
m.resolver.TestOnlySetHook(f.SetResolver)
|
||||||
m.Set(Config{
|
m.Set(Config{
|
||||||
Hosts: hosts("andrew.ts.com.", "1.2.3.4"),
|
Hosts: hosts("andrew.ts.com.", "1.2.3.4"),
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/google/go-cmp/cmp/cmpopts"
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
"tailscale.com/net/dns/resolver"
|
"tailscale.com/net/dns/resolver"
|
||||||
|
"tailscale.com/net/netmon"
|
||||||
"tailscale.com/net/tsdial"
|
"tailscale.com/net/tsdial"
|
||||||
"tailscale.com/types/dnstype"
|
"tailscale.com/types/dnstype"
|
||||||
"tailscale.com/util/dnsname"
|
"tailscale.com/util/dnsname"
|
||||||
@ -613,7 +614,7 @@ func TestManager(t *testing.T) {
|
|||||||
SplitDNS: test.split,
|
SplitDNS: test.split,
|
||||||
BaseConfig: test.bs,
|
BaseConfig: test.bs,
|
||||||
}
|
}
|
||||||
m := NewManager(t.Logf, &f, nil, nil, new(tsdial.Dialer), nil, nil)
|
m := NewManager(t.Logf, &f, nil, tsdial.NewDialer(netmon.NewStatic()), nil, nil)
|
||||||
m.resolver.TestOnlySetHook(f.SetResolver)
|
m.resolver.TestOnlySetHook(f.SetResolver)
|
||||||
|
|
||||||
if err := m.Set(test.in); err != nil {
|
if err := m.Set(test.in); err != nil {
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
@ -186,7 +185,7 @@ type resolverAndDelay struct {
|
|||||||
// forwarder forwards DNS packets to a number of upstream nameservers.
|
// forwarder forwards DNS packets to a number of upstream nameservers.
|
||||||
type forwarder struct {
|
type forwarder struct {
|
||||||
logf logger.Logf
|
logf logger.Logf
|
||||||
netMon *netmon.Monitor
|
netMon *netmon.Monitor // always non-nil
|
||||||
linkSel ForwardLinkSelector // TODO(bradfitz): remove this when tsdial.Dialer absorbs it
|
linkSel ForwardLinkSelector // TODO(bradfitz): remove this when tsdial.Dialer absorbs it
|
||||||
dialer *tsdial.Dialer
|
dialer *tsdial.Dialer
|
||||||
|
|
||||||
@ -214,11 +213,10 @@ type forwarder struct {
|
|||||||
cloudHostFallback []resolverAndDelay
|
cloudHostFallback []resolverAndDelay
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
}
|
|
||||||
|
|
||||||
func newForwarder(logf logger.Logf, netMon *netmon.Monitor, linkSel ForwardLinkSelector, dialer *tsdial.Dialer, knobs *controlknobs.Knobs) *forwarder {
|
func newForwarder(logf logger.Logf, netMon *netmon.Monitor, linkSel ForwardLinkSelector, dialer *tsdial.Dialer, knobs *controlknobs.Knobs) *forwarder {
|
||||||
|
if netMon == nil {
|
||||||
|
panic("nil netMon")
|
||||||
|
}
|
||||||
f := &forwarder{
|
f := &forwarder{
|
||||||
logf: logger.WithPrefix(logf, "forward: "),
|
logf: logger.WithPrefix(logf, "forward: "),
|
||||||
netMon: netMon,
|
netMon: netMon,
|
||||||
@ -410,7 +408,6 @@ func (f *forwarder) getKnownDoHClientForProvider(urlBase string) (c *http.Client
|
|||||||
SingleHost: dohURL.Hostname(),
|
SingleHost: dohURL.Hostname(),
|
||||||
SingleHostStaticResult: allIPs,
|
SingleHostStaticResult: allIPs,
|
||||||
Logf: f.logf,
|
Logf: f.logf,
|
||||||
NetMon: f.netMon,
|
|
||||||
})
|
})
|
||||||
c = &http.Client{
|
c = &http.Client{
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
@ -584,7 +581,7 @@ func (f *forwarder) send(ctx context.Context, fq *forwardQuery, rr resolverAndDe
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Kick off the race between the UDP and TCP queries.
|
// Kick off the race between the UDP and TCP queries.
|
||||||
rh := race.New[[]byte](timeout, firstUDP, thenTCP)
|
rh := race.New(timeout, firstUDP, thenTCP)
|
||||||
resp, err := rh.Start(ctx)
|
resp, err := rh.Start(ctx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
@ -181,7 +181,7 @@ func WriteRoutes(w *bufio.Writer, routes map[dnsname.FQDN][]*dnstype.Resolver) {
|
|||||||
// it delegates to upstream nameservers if any are set.
|
// it delegates to upstream nameservers if any are set.
|
||||||
type Resolver struct {
|
type Resolver struct {
|
||||||
logf logger.Logf
|
logf logger.Logf
|
||||||
netMon *netmon.Monitor // or nil
|
netMon *netmon.Monitor // non-nil
|
||||||
dialer *tsdial.Dialer // non-nil
|
dialer *tsdial.Dialer // non-nil
|
||||||
saveConfigForTests func(cfg Config) // used in tests to capture resolver config
|
saveConfigForTests func(cfg Config) // used in tests to capture resolver config
|
||||||
// forwarder forwards requests to upstream nameservers.
|
// forwarder forwards requests to upstream nameservers.
|
||||||
@ -205,11 +205,14 @@ type ForwardLinkSelector interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new resolver.
|
// New returns a new resolver.
|
||||||
// netMon optionally specifies a network monitor to use for socket rebinding.
|
func New(logf logger.Logf, linkSel ForwardLinkSelector, dialer *tsdial.Dialer, knobs *controlknobs.Knobs) *Resolver {
|
||||||
func New(logf logger.Logf, netMon *netmon.Monitor, linkSel ForwardLinkSelector, dialer *tsdial.Dialer, knobs *controlknobs.Knobs) *Resolver {
|
|
||||||
if dialer == nil {
|
if dialer == nil {
|
||||||
panic("nil Dialer")
|
panic("nil Dialer")
|
||||||
}
|
}
|
||||||
|
netMon := dialer.NetMon()
|
||||||
|
if netMon == nil {
|
||||||
|
logf("nil netMon")
|
||||||
|
}
|
||||||
r := &Resolver{
|
r := &Resolver{
|
||||||
logf: logger.WithPrefix(logf, "resolver: "),
|
logf: logger.WithPrefix(logf, "resolver: "),
|
||||||
netMon: netMon,
|
netMon: netMon,
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"tailscale.com/net/tsdial"
|
"tailscale.com/net/tsdial"
|
||||||
"tailscale.com/tstest"
|
"tailscale.com/tstest"
|
||||||
"tailscale.com/types/dnstype"
|
"tailscale.com/types/dnstype"
|
||||||
|
"tailscale.com/types/logger"
|
||||||
"tailscale.com/util/dnsname"
|
"tailscale.com/util/dnsname"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -313,7 +314,11 @@ func TestRDNSNameToIPv6(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newResolver(t testing.TB) *Resolver {
|
func newResolver(t testing.TB) *Resolver {
|
||||||
return New(t.Logf, nil /* no network monitor */, nil /* no link selector */, new(tsdial.Dialer), nil /* no control knobs */)
|
return New(t.Logf,
|
||||||
|
nil, // no link selector
|
||||||
|
tsdial.NewDialer(netmon.NewStatic()),
|
||||||
|
nil, // no control knobs
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResolveLocal(t *testing.T) {
|
func TestResolveLocal(t *testing.T) {
|
||||||
@ -1009,7 +1014,13 @@ func TestForwardLinkSelection(t *testing.T) {
|
|||||||
// routes differently.
|
// routes differently.
|
||||||
specialIP := netaddr.IPv4(1, 2, 3, 4)
|
specialIP := netaddr.IPv4(1, 2, 3, 4)
|
||||||
|
|
||||||
fwd := newForwarder(t.Logf, nil, linkSelFunc(func(ip netip.Addr) string {
|
netMon, err := netmon.New(logger.WithPrefix(t.Logf, ".... netmon: "))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Cleanup(func() { netMon.Close() })
|
||||||
|
|
||||||
|
fwd := newForwarder(t.Logf, netMon, linkSelFunc(func(ip netip.Addr) string {
|
||||||
if ip == netaddr.IPv4(1, 2, 3, 4) {
|
if ip == netaddr.IPv4(1, 2, 3, 4) {
|
||||||
return "special"
|
return "special"
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tailscale.com/envknob"
|
"tailscale.com/envknob"
|
||||||
"tailscale.com/net/netmon"
|
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
"tailscale.com/util/cloudenv"
|
"tailscale.com/util/cloudenv"
|
||||||
"tailscale.com/util/singleflight"
|
"tailscale.com/util/singleflight"
|
||||||
@ -90,11 +89,6 @@ type Resolver struct {
|
|||||||
// be added to all log messages printed with this logger.
|
// be added to all log messages printed with this logger.
|
||||||
Logf logger.Logf
|
Logf logger.Logf
|
||||||
|
|
||||||
// NetMon optionally provides a netmon.Monitor to use to get the current
|
|
||||||
// (cached) network interface.
|
|
||||||
// If nil, the interface will be looked up dynamically.
|
|
||||||
NetMon *netmon.Monitor
|
|
||||||
|
|
||||||
sf singleflight.Group[string, ipRes]
|
sf singleflight.Group[string, ipRes]
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
@ -1657,7 +1657,6 @@ func (c *Client) nodeAddr(ctx context.Context, n *tailcfg.DERPNode, proto probeP
|
|||||||
Forward: net.DefaultResolver,
|
Forward: net.DefaultResolver,
|
||||||
UseLastGood: true,
|
UseLastGood: true,
|
||||||
Logf: c.logf,
|
Logf: c.logf,
|
||||||
NetMon: c.NetMon,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolver := c.resolver
|
resolver := c.resolver
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
"tailscale.com/net/stun/stuntest"
|
"tailscale.com/net/stun/stuntest"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/tstest"
|
"tailscale.com/tstest"
|
||||||
"tailscale.com/types/logger"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHairpinSTUN(t *testing.T) {
|
func TestHairpinSTUN(t *testing.T) {
|
||||||
@ -157,14 +156,8 @@ func TestHairpinWait(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newTestClient(t testing.TB) *Client {
|
func newTestClient(t testing.TB) *Client {
|
||||||
netMon, err := netmon.New(logger.WithPrefix(t.Logf, "... netmon: "))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("netmon.New: %v", err)
|
|
||||||
}
|
|
||||||
t.Cleanup(func() { netMon.Close() })
|
|
||||||
|
|
||||||
c := &Client{
|
c := &Client{
|
||||||
NetMon: netMon,
|
NetMon: netmon.NewStatic(),
|
||||||
Logf: t.Logf,
|
Logf: t.Logf,
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
|
@ -24,12 +24,15 @@
|
|||||||
// to bind, errors will be returned, if one or both protocols can bind no error
|
// to bind, errors will be returned, if one or both protocols can bind no error
|
||||||
// is returned.
|
// is returned.
|
||||||
func (c *Client) Standalone(ctx context.Context, bindAddr string) error {
|
func (c *Client) Standalone(ctx context.Context, bindAddr string) error {
|
||||||
|
if c.NetMon == nil {
|
||||||
|
panic("netcheck.Client.NetMon must be set")
|
||||||
|
}
|
||||||
if bindAddr == "" {
|
if bindAddr == "" {
|
||||||
bindAddr = ":0"
|
bindAddr = ":0"
|
||||||
}
|
}
|
||||||
var errs []error
|
var errs []error
|
||||||
|
|
||||||
u4, err := nettype.MakePacketListenerWithNetIP(netns.Listener(c.logf, nil)).ListenPacket(ctx, "udp4", bindAddr)
|
u4, err := nettype.MakePacketListenerWithNetIP(netns.Listener(c.logf, c.NetMon)).ListenPacket(ctx, "udp4", bindAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logf("udp4: %v", err)
|
c.logf("udp4: %v", err)
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
@ -37,7 +40,7 @@ func (c *Client) Standalone(ctx context.Context, bindAddr string) error {
|
|||||||
go readPackets(ctx, c.logf, u4, c.ReceiveSTUNPacket)
|
go readPackets(ctx, c.logf, u4, c.ReceiveSTUNPacket)
|
||||||
}
|
}
|
||||||
|
|
||||||
u6, err := nettype.MakePacketListenerWithNetIP(netns.Listener(c.logf, nil)).ListenPacket(ctx, "udp6", bindAddr)
|
u6, err := nettype.MakePacketListenerWithNetIP(netns.Listener(c.logf, c.NetMon)).ListenPacket(ctx, "udp6", bindAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logf("udp6: %v", err)
|
c.logf("udp6: %v", err)
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
|
@ -55,6 +55,7 @@ type Monitor struct {
|
|||||||
om osMon // nil means not supported on this platform
|
om osMon // nil means not supported on this platform
|
||||||
change chan bool // send false to wake poller, true to also force ChangeDeltas be sent
|
change chan bool // send false to wake poller, true to also force ChangeDeltas be sent
|
||||||
stop chan struct{} // closed on Stop
|
stop chan struct{} // closed on Stop
|
||||||
|
static bool // static Monitor that doesn't actually monitor
|
||||||
|
|
||||||
// Things that must be set early, before use,
|
// Things that must be set early, before use,
|
||||||
// and not change at runtime.
|
// and not change at runtime.
|
||||||
@ -139,6 +140,17 @@ func New(logf logger.Logf) (*Monitor, error) {
|
|||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewStatic returns a Monitor that's a one-time snapshot of the network state
|
||||||
|
// but doesn't actually monitor for changes. It should only be used in tests
|
||||||
|
// and situations like cleanups or short-lived CLI programs.
|
||||||
|
func NewStatic() *Monitor {
|
||||||
|
m := &Monitor{static: true}
|
||||||
|
if st, err := m.interfaceStateUncached(); err == nil {
|
||||||
|
m.ifState = st
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
// InterfaceState returns the latest snapshot of the machine's network
|
// InterfaceState returns the latest snapshot of the machine's network
|
||||||
// interfaces.
|
// interfaces.
|
||||||
//
|
//
|
||||||
@ -168,6 +180,10 @@ func (m *Monitor) SetTailscaleInterfaceName(ifName string) {
|
|||||||
// It's the same as interfaces.LikelyHomeRouterIP, but it caches the
|
// It's the same as interfaces.LikelyHomeRouterIP, but it caches the
|
||||||
// result until the monitor detects a network change.
|
// result until the monitor detects a network change.
|
||||||
func (m *Monitor) GatewayAndSelfIP() (gw, myIP netip.Addr, ok bool) {
|
func (m *Monitor) GatewayAndSelfIP() (gw, myIP netip.Addr, ok bool) {
|
||||||
|
if m.static {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
if m.gwValid {
|
if m.gwValid {
|
||||||
@ -190,6 +206,9 @@ func (m *Monitor) GatewayAndSelfIP() (gw, myIP netip.Addr, ok bool) {
|
|||||||
// notified (in their own goroutine) when the network state changes.
|
// notified (in their own goroutine) when the network state changes.
|
||||||
// To remove this callback, call unregister (or close the monitor).
|
// To remove this callback, call unregister (or close the monitor).
|
||||||
func (m *Monitor) RegisterChangeCallback(callback ChangeFunc) (unregister func()) {
|
func (m *Monitor) RegisterChangeCallback(callback ChangeFunc) (unregister func()) {
|
||||||
|
if m.static {
|
||||||
|
return func() {}
|
||||||
|
}
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
handle := m.cbs.Add(callback)
|
handle := m.cbs.Add(callback)
|
||||||
@ -210,6 +229,9 @@ func (m *Monitor) RegisterChangeCallback(callback ChangeFunc) (unregister func()
|
|||||||
// notified (in their own goroutine) when a Linux ip rule is deleted.
|
// notified (in their own goroutine) when a Linux ip rule is deleted.
|
||||||
// To remove this callback, call unregister (or close the monitor).
|
// To remove this callback, call unregister (or close the monitor).
|
||||||
func (m *Monitor) RegisterRuleDeleteCallback(callback RuleDeleteCallback) (unregister func()) {
|
func (m *Monitor) RegisterRuleDeleteCallback(callback RuleDeleteCallback) (unregister func()) {
|
||||||
|
if m.static {
|
||||||
|
return func() {}
|
||||||
|
}
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
handle := m.ruleDelCB.Add(callback)
|
handle := m.ruleDelCB.Add(callback)
|
||||||
@ -223,6 +245,9 @@ func (m *Monitor) RegisterRuleDeleteCallback(callback RuleDeleteCallback) (unreg
|
|||||||
// Start starts the monitor.
|
// Start starts the monitor.
|
||||||
// A monitor can only be started & closed once.
|
// A monitor can only be started & closed once.
|
||||||
func (m *Monitor) Start() {
|
func (m *Monitor) Start() {
|
||||||
|
if m.static {
|
||||||
|
return
|
||||||
|
}
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
if m.started || m.closed {
|
if m.started || m.closed {
|
||||||
@ -244,6 +269,9 @@ func (m *Monitor) Start() {
|
|||||||
|
|
||||||
// Close closes the monitor.
|
// Close closes the monitor.
|
||||||
func (m *Monitor) Close() error {
|
func (m *Monitor) Close() error {
|
||||||
|
if m.static {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
if m.closed {
|
if m.closed {
|
||||||
m.mu.Unlock()
|
m.mu.Unlock()
|
||||||
@ -275,6 +303,9 @@ func (m *Monitor) Close() error {
|
|||||||
// ChangeFunc callbacks will be called within the event coalescing
|
// ChangeFunc callbacks will be called within the event coalescing
|
||||||
// period (under a fraction of a second).
|
// period (under a fraction of a second).
|
||||||
func (m *Monitor) InjectEvent() {
|
func (m *Monitor) InjectEvent() {
|
||||||
|
if m.static {
|
||||||
|
return
|
||||||
|
}
|
||||||
select {
|
select {
|
||||||
case m.change <- true:
|
case m.change <- true:
|
||||||
default:
|
default:
|
||||||
@ -290,6 +321,9 @@ func (m *Monitor) InjectEvent() {
|
|||||||
// This is like InjectEvent but only fires ChangeFunc callbacks
|
// This is like InjectEvent but only fires ChangeFunc callbacks
|
||||||
// if the network state differed at all.
|
// if the network state differed at all.
|
||||||
func (m *Monitor) Poll() {
|
func (m *Monitor) Poll() {
|
||||||
|
if m.static {
|
||||||
|
return
|
||||||
|
}
|
||||||
select {
|
select {
|
||||||
case m.change <- false:
|
case m.change <- false:
|
||||||
default:
|
default:
|
||||||
|
@ -56,8 +56,10 @@ func SetDisableBindConnToInterface(v bool) {
|
|||||||
// Listener returns a new net.Listener with its Control hook func
|
// Listener returns a new net.Listener with its Control hook func
|
||||||
// initialized as necessary to run in logical network namespace that
|
// initialized as necessary to run in logical network namespace that
|
||||||
// doesn't route back into Tailscale.
|
// doesn't route back into Tailscale.
|
||||||
// The netMon parameter is optional; if non-nil it's used to do faster interface lookups.
|
|
||||||
func Listener(logf logger.Logf, netMon *netmon.Monitor) *net.ListenConfig {
|
func Listener(logf logger.Logf, netMon *netmon.Monitor) *net.ListenConfig {
|
||||||
|
if netMon == nil {
|
||||||
|
panic("netns.Listener called with nil netMon")
|
||||||
|
}
|
||||||
if disabled.Load() {
|
if disabled.Load() {
|
||||||
return new(net.ListenConfig)
|
return new(net.ListenConfig)
|
||||||
}
|
}
|
||||||
@ -68,8 +70,10 @@ func Listener(logf logger.Logf, netMon *netmon.Monitor) *net.ListenConfig {
|
|||||||
// hook func initialized as necessary to run in a logical network
|
// hook func initialized as necessary to run in a logical network
|
||||||
// namespace that doesn't route back into Tailscale. It also handles
|
// namespace that doesn't route back into Tailscale. It also handles
|
||||||
// using a SOCKS if configured in the environment with ALL_PROXY.
|
// using a SOCKS if configured in the environment with ALL_PROXY.
|
||||||
// The netMon parameter is optional; if non-nil it's used to do faster interface lookups.
|
|
||||||
func NewDialer(logf logger.Logf, netMon *netmon.Monitor) Dialer {
|
func NewDialer(logf logger.Logf, netMon *netmon.Monitor) Dialer {
|
||||||
|
if netMon == nil {
|
||||||
|
panic("netns.NewDialer called with nil netMon")
|
||||||
|
}
|
||||||
return FromDialer(logf, netMon, &net.Dialer{
|
return FromDialer(logf, netMon, &net.Dialer{
|
||||||
KeepAlive: netknob.PlatformTCPKeepAlive(),
|
KeepAlive: netknob.PlatformTCPKeepAlive(),
|
||||||
})
|
})
|
||||||
@ -79,8 +83,10 @@ func NewDialer(logf logger.Logf, netMon *netmon.Monitor) Dialer {
|
|||||||
// network namespace that doesn't route back into Tailscale. It also
|
// network namespace that doesn't route back into Tailscale. It also
|
||||||
// handles using a SOCKS if configured in the environment with
|
// handles using a SOCKS if configured in the environment with
|
||||||
// ALL_PROXY.
|
// ALL_PROXY.
|
||||||
// The netMon parameter is optional; if non-nil it's used to do faster interface lookups.
|
|
||||||
func FromDialer(logf logger.Logf, netMon *netmon.Monitor, d *net.Dialer) Dialer {
|
func FromDialer(logf logger.Logf, netMon *netmon.Monitor, d *net.Dialer) Dialer {
|
||||||
|
if netMon == nil {
|
||||||
|
panic("netns.FromDialer called with nil netMon")
|
||||||
|
}
|
||||||
if disabled.Load() {
|
if disabled.Load() {
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
"tailscale.com/control/controlknobs"
|
"tailscale.com/control/controlknobs"
|
||||||
"tailscale.com/net/netaddr"
|
"tailscale.com/net/netaddr"
|
||||||
|
"tailscale.com/net/netmon"
|
||||||
"tailscale.com/syncs"
|
"tailscale.com/syncs"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
)
|
)
|
||||||
@ -259,12 +260,13 @@ func (d *TestIGD) handlePCPQuery(pkt []byte, src netip.AddrPort) {
|
|||||||
|
|
||||||
func newTestClient(t *testing.T, igd *TestIGD) *Client {
|
func newTestClient(t *testing.T, igd *TestIGD) *Client {
|
||||||
var c *Client
|
var c *Client
|
||||||
c = NewClient(t.Logf, nil, nil, new(controlknobs.Knobs), func() {
|
c = NewClient(t.Logf, netmon.NewStatic(), nil, new(controlknobs.Knobs), func() {
|
||||||
t.Logf("port map changed")
|
t.Logf("port map changed")
|
||||||
t.Logf("have mapping: %v", c.HaveMapping())
|
t.Logf("have mapping: %v", c.HaveMapping())
|
||||||
})
|
})
|
||||||
c.testPxPPort = igd.TestPxPPort()
|
c.testPxPPort = igd.TestPxPPort()
|
||||||
c.testUPnPPort = igd.TestUPnPPort()
|
c.testUPnPPort = igd.TestUPnPPort()
|
||||||
|
c.netMon = netmon.NewStatic()
|
||||||
c.SetGatewayLookupFunc(testIPAndGateway)
|
c.SetGatewayLookupFunc(testIPAndGateway)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
@ -198,8 +198,7 @@ func (m *pmpMapping) Release(ctx context.Context) {
|
|||||||
|
|
||||||
// NewClient returns a new portmapping client.
|
// NewClient returns a new portmapping client.
|
||||||
//
|
//
|
||||||
// The netMon parameter is optional; if non-nil it's used to do faster interface
|
// The netMon parameter is required.
|
||||||
// lookups.
|
|
||||||
//
|
//
|
||||||
// The debug argument allows configuring the behaviour of the portmapper for
|
// The debug argument allows configuring the behaviour of the portmapper for
|
||||||
// debugging; if nil, a sensible set of defaults will be used.
|
// debugging; if nil, a sensible set of defaults will be used.
|
||||||
@ -211,10 +210,13 @@ func (m *pmpMapping) Release(ctx context.Context) {
|
|||||||
// whenever the port mapping status has changed. If nil, it doesn't make a
|
// whenever the port mapping status has changed. If nil, it doesn't make a
|
||||||
// callback.
|
// callback.
|
||||||
func NewClient(logf logger.Logf, netMon *netmon.Monitor, debug *DebugKnobs, controlKnobs *controlknobs.Knobs, onChange func()) *Client {
|
func NewClient(logf logger.Logf, netMon *netmon.Monitor, debug *DebugKnobs, controlKnobs *controlknobs.Knobs, onChange func()) *Client {
|
||||||
|
if netMon == nil {
|
||||||
|
panic("nil netMon")
|
||||||
|
}
|
||||||
ret := &Client{
|
ret := &Client{
|
||||||
logf: logf,
|
logf: logf,
|
||||||
netMon: netMon,
|
netMon: netMon,
|
||||||
ipAndGateway: interfaces.LikelyHomeRouterIP,
|
ipAndGateway: interfaces.LikelyHomeRouterIP, // TODO(bradfitz): move this to netMon
|
||||||
onChange: onChange,
|
onChange: onChange,
|
||||||
controlKnobs: controlKnobs,
|
controlKnobs: controlKnobs,
|
||||||
}
|
}
|
||||||
|
@ -26,13 +26,27 @@
|
|||||||
"tailscale.com/types/netmap"
|
"tailscale.com/types/netmap"
|
||||||
"tailscale.com/util/clientmetric"
|
"tailscale.com/util/clientmetric"
|
||||||
"tailscale.com/util/mak"
|
"tailscale.com/util/mak"
|
||||||
|
"tailscale.com/util/testenv"
|
||||||
"tailscale.com/version"
|
"tailscale.com/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NewDialer returns a new Dialer that can dial out of tailscaled.
|
||||||
|
// Its exported fields should be set before use, if any.
|
||||||
|
func NewDialer(netMon *netmon.Monitor) *Dialer {
|
||||||
|
if netMon == nil {
|
||||||
|
panic("NewDialer: netMon is nil")
|
||||||
|
}
|
||||||
|
d := &Dialer{}
|
||||||
|
d.SetNetMon(netMon)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
// Dialer dials out of tailscaled, while taking care of details while
|
// Dialer dials out of tailscaled, while taking care of details while
|
||||||
// handling the dozens of edge cases depending on the server mode
|
// handling the dozens of edge cases depending on the server mode
|
||||||
// (TUN, netstack), the OS network sandboxing style (macOS/iOS
|
// (TUN, netstack), the OS network sandboxing style (macOS/iOS
|
||||||
// Extension, none), user-selected route acceptance prefs, etc.
|
// Extension, none), user-selected route acceptance prefs, etc.
|
||||||
|
//
|
||||||
|
// Before use, SetNetMon should be called with a netmon.Monitor.
|
||||||
type Dialer struct {
|
type Dialer struct {
|
||||||
Logf logger.Logf
|
Logf logger.Logf
|
||||||
// UseNetstackForIP if non-nil is whether NetstackDialTCP (if
|
// UseNetstackForIP if non-nil is whether NetstackDialTCP (if
|
||||||
@ -130,9 +144,14 @@ func (d *Dialer) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetNetMon sets d's network monitor to netMon.
|
||||||
|
// It is a no-op to call SetNetMon with the same netMon as the current one.
|
||||||
func (d *Dialer) SetNetMon(netMon *netmon.Monitor) {
|
func (d *Dialer) SetNetMon(netMon *netmon.Monitor) {
|
||||||
d.mu.Lock()
|
d.mu.Lock()
|
||||||
defer d.mu.Unlock()
|
defer d.mu.Unlock()
|
||||||
|
if d.netMon == netMon {
|
||||||
|
return
|
||||||
|
}
|
||||||
if d.netMonUnregister != nil {
|
if d.netMonUnregister != nil {
|
||||||
go d.netMonUnregister()
|
go d.netMonUnregister()
|
||||||
d.netMonUnregister = nil
|
d.netMonUnregister = nil
|
||||||
@ -141,6 +160,14 @@ func (d *Dialer) SetNetMon(netMon *netmon.Monitor) {
|
|||||||
d.netMonUnregister = d.netMon.RegisterChangeCallback(d.linkChanged)
|
d.netMonUnregister = d.netMon.RegisterChangeCallback(d.linkChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NetMon returns the Dialer's network monitor.
|
||||||
|
// It returns nil if SetNetMon has not been called.
|
||||||
|
func (d *Dialer) NetMon() *netmon.Monitor {
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
return d.netMon
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
metricLinkChangeConnClosed = clientmetric.NewCounter("tsdial_linkchange_closes")
|
metricLinkChangeConnClosed = clientmetric.NewCounter("tsdial_linkchange_closes")
|
||||||
metricChangeDeltaNoDefaultRoute = clientmetric.NewCounter("tsdial_changedelta_no_default_route")
|
metricChangeDeltaNoDefaultRoute = clientmetric.NewCounter("tsdial_changedelta_no_default_route")
|
||||||
@ -314,6 +341,13 @@ func (d *Dialer) logf(format string, args ...any) {
|
|||||||
// Control and (in the future, as of 2022-04-27) DERPs..
|
// Control and (in the future, as of 2022-04-27) DERPs..
|
||||||
func (d *Dialer) SystemDial(ctx context.Context, network, addr string) (net.Conn, error) {
|
func (d *Dialer) SystemDial(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
d.mu.Lock()
|
d.mu.Lock()
|
||||||
|
if d.netMon == nil {
|
||||||
|
d.mu.Unlock()
|
||||||
|
if testenv.InTest() {
|
||||||
|
panic("SystemDial requires a netmon.Monitor; call SetNetMon first")
|
||||||
|
}
|
||||||
|
return nil, errors.New("SystemDial requires a netmon.Monitor; call SetNetMon first")
|
||||||
|
}
|
||||||
closed := d.closed
|
closed := d.closed
|
||||||
d.mu.Unlock()
|
d.mu.Unlock()
|
||||||
if closed {
|
if closed {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
"tailscale.com/derp"
|
"tailscale.com/derp"
|
||||||
"tailscale.com/derp/derphttp"
|
"tailscale.com/derp/derphttp"
|
||||||
|
"tailscale.com/net/netmon"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
)
|
)
|
||||||
@ -140,7 +141,7 @@ func TestRunDerpProbeNodePair(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
newClient := func() *derphttp.Client {
|
newClient := func() *derphttp.Client {
|
||||||
c, err := derphttp.NewClient(key.NewNode(), serverURL, t.Logf)
|
c, err := derphttp.NewClient(key.NewNode(), serverURL, t.Logf, netmon.NewStatic())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClient: %v", err)
|
t.Fatalf("NewClient: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ func New(logf logger.Logf, tundev tun.Device, netMon *netmon.Monitor, health *he
|
|||||||
// CleanUp restores the system network configuration to its original state
|
// CleanUp restores the system network configuration to its original state
|
||||||
// in case the Tailscale daemon terminated without closing the router.
|
// in case the Tailscale daemon terminated without closing the router.
|
||||||
// No other state needs to be instantiated before this runs.
|
// No other state needs to be instantiated before this runs.
|
||||||
func CleanUp(logf logger.Logf, interfaceName string) {
|
func CleanUp(logf logger.Logf, netMon *netmon.Monitor, interfaceName string) {
|
||||||
cleanUp(logf, interfaceName)
|
cleanUp(logf, interfaceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ type Config struct {
|
|||||||
HealthTracker *health.Tracker
|
HealthTracker *health.Tracker
|
||||||
|
|
||||||
// Dialer is the dialer to use for outbound connections.
|
// Dialer is the dialer to use for outbound connections.
|
||||||
// If nil, a new Dialer is created
|
// If nil, a new Dialer is created.
|
||||||
Dialer *tsdial.Dialer
|
Dialer *tsdial.Dialer
|
||||||
|
|
||||||
// ControlKnobs is the set of control plane-provied knobs
|
// ControlKnobs is the set of control plane-provied knobs
|
||||||
@ -341,7 +341,7 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
|
|||||||
tunName, _ := conf.Tun.Name()
|
tunName, _ := conf.Tun.Name()
|
||||||
conf.Dialer.SetTUNName(tunName)
|
conf.Dialer.SetTUNName(tunName)
|
||||||
conf.Dialer.SetNetMon(e.netMon)
|
conf.Dialer.SetNetMon(e.netMon)
|
||||||
e.dns = dns.NewManager(logf, conf.DNS, e.netMon, e.health, conf.Dialer, fwdDNSLinkSelector{e, tunName}, conf.ControlKnobs)
|
e.dns = dns.NewManager(logf, conf.DNS, e.health, conf.Dialer, fwdDNSLinkSelector{e, tunName}, conf.ControlKnobs)
|
||||||
|
|
||||||
// TODO: there's probably a better place for this
|
// TODO: there's probably a better place for this
|
||||||
sockstats.SetNetMon(e.netMon)
|
sockstats.SetNetMon(e.netMon)
|
||||||
|
Loading…
Reference in New Issue
Block a user