mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-01 09:32:08 +00:00
tsd: add package with System type to unify subsystem init, discovery
This is part of an effort to clean up tailscaled initialization between tailscaled, tailscaled Windows service, tsnet, and the mac GUI. Updates #8036 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
0d7303b798
commit
6e967446e4
@@ -16,6 +16,7 @@ import (
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/net/tsdial"
|
||||
"tailscale.com/net/tstun"
|
||||
"tailscale.com/tsd"
|
||||
"tailscale.com/tstest"
|
||||
"tailscale.com/types/ipproto"
|
||||
"tailscale.com/types/logid"
|
||||
@@ -33,29 +34,26 @@ func TestInjectInboundLeak(t *testing.T) {
|
||||
t.Logf(format, args...)
|
||||
}
|
||||
}
|
||||
sys := new(tsd.System)
|
||||
eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{
|
||||
Tun: tunDev,
|
||||
Dialer: dialer,
|
||||
Tun: tunDev,
|
||||
Dialer: dialer,
|
||||
SetSubsystem: sys.Set,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer eng.Close()
|
||||
ig, ok := eng.(wgengine.InternalsGetter)
|
||||
if !ok {
|
||||
t.Fatal("not an InternalsGetter")
|
||||
}
|
||||
tunWrap, magicSock, dns, ok := ig.GetInternals()
|
||||
if !ok {
|
||||
t.Fatal("failed to get internals")
|
||||
}
|
||||
sys.Set(eng)
|
||||
sys.Set(new(mem.Store))
|
||||
|
||||
lb, err := ipnlocal.NewLocalBackend(logf, logid.PublicID{}, new(mem.Store), dialer, eng, 0)
|
||||
tunWrap := sys.Tun.Get()
|
||||
lb, err := ipnlocal.NewLocalBackend(logf, logid.PublicID{}, sys, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ns, err := Create(logf, tunWrap, eng, magicSock, dialer, dns)
|
||||
ns, err := Create(logf, tunWrap, eng, sys.MagicSock.Get(), dialer, sys.DNSManager.Get())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -89,32 +87,28 @@ func getMemStats() (ms runtime.MemStats) {
|
||||
|
||||
func makeNetstack(t *testing.T, config func(*Impl)) *Impl {
|
||||
tunDev := tstun.NewFake()
|
||||
sys := &tsd.System{}
|
||||
sys.Set(new(mem.Store))
|
||||
dialer := new(tsdial.Dialer)
|
||||
logf := tstest.WhileTestRunningLogger(t)
|
||||
eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{
|
||||
Tun: tunDev,
|
||||
Dialer: dialer,
|
||||
Tun: tunDev,
|
||||
Dialer: dialer,
|
||||
SetSubsystem: sys.Set,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { eng.Close() })
|
||||
ig, ok := eng.(wgengine.InternalsGetter)
|
||||
if !ok {
|
||||
t.Fatal("not an InternalsGetter")
|
||||
}
|
||||
tunWrap, magicSock, dns, ok := ig.GetInternals()
|
||||
if !ok {
|
||||
t.Fatal("failed to get internals")
|
||||
}
|
||||
sys.Set(eng)
|
||||
|
||||
ns, err := Create(logf, tunWrap, eng, magicSock, dialer, dns)
|
||||
ns, err := Create(logf, sys.Tun.Get(), eng, sys.MagicSock.Get(), dialer, sys.DNSManager.Get())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { ns.Close() })
|
||||
|
||||
lb, err := ipnlocal.NewLocalBackend(logf, logid.PublicID{}, new(mem.Store), dialer, eng, 0)
|
||||
lb, err := ipnlocal.NewLocalBackend(logf, logid.PublicID{}, sys, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("NewLocalBackend: %v", err)
|
||||
}
|
||||
|
||||
@@ -4,16 +4,9 @@
|
||||
package netstack
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"tailscale.com/wgengine"
|
||||
"tailscale.com/wgengine/router"
|
||||
)
|
||||
|
||||
func init() {
|
||||
wgengine.NetstackRouterType = reflect.TypeOf(&subnetRouter{})
|
||||
}
|
||||
|
||||
type subnetRouter struct {
|
||||
router.Router
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -25,7 +25,6 @@ import (
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
"tailscale.com/net/dns"
|
||||
"tailscale.com/net/dns/resolver"
|
||||
"tailscale.com/net/flowtrack"
|
||||
"tailscale.com/net/interfaces"
|
||||
"tailscale.com/net/netmon"
|
||||
@@ -150,29 +149,6 @@ type userspaceEngine struct {
|
||||
// Lock ordering: magicsock.Conn.mu, wgLock, then mu.
|
||||
}
|
||||
|
||||
// InternalsGetter is implemented by Engines that can export their internals.
|
||||
type InternalsGetter interface {
|
||||
GetInternals() (_ *tstun.Wrapper, _ *magicsock.Conn, _ *dns.Manager, ok bool)
|
||||
}
|
||||
|
||||
func (e *userspaceEngine) GetInternals() (_ *tstun.Wrapper, _ *magicsock.Conn, _ *dns.Manager, ok bool) {
|
||||
return e.tundev, e.magicConn, e.dns, true
|
||||
}
|
||||
|
||||
// ResolvingEngine is implemented by Engines that have DNS resolvers.
|
||||
type ResolvingEngine interface {
|
||||
GetResolver() (_ *resolver.Resolver, ok bool)
|
||||
}
|
||||
|
||||
var (
|
||||
_ ResolvingEngine = (*userspaceEngine)(nil)
|
||||
_ ResolvingEngine = (*watchdogEngine)(nil)
|
||||
)
|
||||
|
||||
func (e *userspaceEngine) GetResolver() (r *resolver.Resolver, ok bool) {
|
||||
return e.dns.Resolver(), true
|
||||
}
|
||||
|
||||
// BIRDClient handles communication with the BIRD Internet Routing Daemon.
|
||||
type BIRDClient interface {
|
||||
EnableProtocol(proto string) error
|
||||
@@ -219,47 +195,37 @@ type Config struct {
|
||||
// BIRDClient, if non-nil, will be used to configure BIRD whenever
|
||||
// this node is a primary subnet router.
|
||||
BIRDClient BIRDClient
|
||||
|
||||
// SetSubsystem, if non-nil, is called for each new subsystem created, just before a successful return.
|
||||
SetSubsystem func(any)
|
||||
}
|
||||
|
||||
func NewFakeUserspaceEngine(logf logger.Logf, listenPort uint16) (Engine, error) {
|
||||
logf("Starting userspace WireGuard engine (with fake TUN device)")
|
||||
return NewUserspaceEngine(logf, Config{
|
||||
ListenPort: listenPort,
|
||||
// NewFakeUserspaceEngine returns a new userspace engine for testing.
|
||||
//
|
||||
// The opts may contain the following types:
|
||||
//
|
||||
// - int or uint16: to set the ListenPort.
|
||||
func NewFakeUserspaceEngine(logf logger.Logf, opts ...any) (Engine, error) {
|
||||
conf := Config{
|
||||
RespondToPing: true,
|
||||
})
|
||||
}
|
||||
|
||||
// NetstackRouterType is a gross cross-package init-time registration
|
||||
// from netstack to here, informing this package of netstack's router
|
||||
// type.
|
||||
var NetstackRouterType reflect.Type
|
||||
|
||||
// IsNetstackRouter reports whether e is either fully netstack based
|
||||
// (without TUN) or is at least using netstack for routing.
|
||||
func IsNetstackRouter(e Engine) bool {
|
||||
switch e := e.(type) {
|
||||
case *userspaceEngine:
|
||||
if reflect.TypeOf(e.router) == NetstackRouterType {
|
||||
return true
|
||||
}
|
||||
for _, o := range opts {
|
||||
switch v := o.(type) {
|
||||
case uint16:
|
||||
conf.ListenPort = v
|
||||
case int:
|
||||
if v < 0 || v > math.MaxUint16 {
|
||||
return nil, fmt.Errorf("invalid ListenPort: %d", v)
|
||||
}
|
||||
conf.ListenPort = uint16(v)
|
||||
case func(any):
|
||||
conf.SetSubsystem = v
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown option type %T", v)
|
||||
}
|
||||
case *watchdogEngine:
|
||||
return IsNetstackRouter(e.wrap)
|
||||
}
|
||||
return IsNetstack(e)
|
||||
}
|
||||
|
||||
// IsNetstack reports whether e is a netstack-based TUN-free engine.
|
||||
func IsNetstack(e Engine) bool {
|
||||
ig, ok := e.(InternalsGetter)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
tw, _, _, ok := ig.GetInternals()
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
name, err := tw.Name()
|
||||
return err == nil && name == "FakeTUN"
|
||||
logf("Starting userspace WireGuard engine (with fake TUN device)")
|
||||
return NewUserspaceEngine(logf, conf)
|
||||
}
|
||||
|
||||
// NewUserspaceEngine creates the named tun device and returns a
|
||||
@@ -458,6 +424,15 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
|
||||
e.logf("Starting network monitor...")
|
||||
e.netMon.Start()
|
||||
|
||||
if conf.SetSubsystem != nil {
|
||||
conf.SetSubsystem(e.tundev)
|
||||
conf.SetSubsystem(e.magicConn)
|
||||
conf.SetSubsystem(e.dns)
|
||||
conf.SetSubsystem(conf.Router)
|
||||
conf.SetSubsystem(conf.Dialer)
|
||||
conf.SetSubsystem(e.netMon)
|
||||
}
|
||||
|
||||
e.logf("Engine created.")
|
||||
return e, nil
|
||||
}
|
||||
@@ -1119,10 +1094,6 @@ func (e *userspaceEngine) Wait() {
|
||||
<-e.waitCh
|
||||
}
|
||||
|
||||
func (e *userspaceEngine) GetNetMon() *netmon.Monitor {
|
||||
return e.netMon
|
||||
}
|
||||
|
||||
// LinkChange signals a network change event. It's currently
|
||||
// (2021-03-03) only called on Android. On other platforms, netMon
|
||||
// generates link change events for us.
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"tailscale.com/net/tstun"
|
||||
"tailscale.com/tsd"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/wgengine"
|
||||
"tailscale.com/wgengine/netstack"
|
||||
@@ -15,21 +16,23 @@ import (
|
||||
)
|
||||
|
||||
func TestIsNetstack(t *testing.T) {
|
||||
e, err := wgengine.NewUserspaceEngine(t.Logf, wgengine.Config{})
|
||||
sys := new(tsd.System)
|
||||
e, err := wgengine.NewUserspaceEngine(t.Logf, wgengine.Config{SetSubsystem: sys.Set})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer e.Close()
|
||||
if !wgengine.IsNetstack(e) {
|
||||
if !sys.IsNetstack() {
|
||||
t.Errorf("IsNetstack = false; want true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsNetstackRouter(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
conf wgengine.Config
|
||||
want bool
|
||||
name string
|
||||
conf wgengine.Config
|
||||
setNetstackRouter bool
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "no_netstack",
|
||||
@@ -50,23 +53,26 @@ func TestIsNetstackRouter(t *testing.T) {
|
||||
Tun: newFakeOSTUN(),
|
||||
Router: netstack.NewSubnetRouterWrapper(newFakeOSRouter()),
|
||||
},
|
||||
want: true,
|
||||
setNetstackRouter: true,
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
e, err := wgengine.NewUserspaceEngine(logger.Discard, tt.conf)
|
||||
sys := &tsd.System{}
|
||||
if tt.setNetstackRouter {
|
||||
sys.NetstackRouter.Set(true)
|
||||
}
|
||||
conf := tt.conf
|
||||
conf.SetSubsystem = sys.Set
|
||||
e, err := wgengine.NewUserspaceEngine(logger.Discard, conf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer e.Close()
|
||||
if got := wgengine.IsNetstackRouter(e); got != tt.want {
|
||||
if got := sys.IsNetstackRouter(); got != tt.want {
|
||||
t.Errorf("IsNetstackRouter = %v; want %v", got, tt.want)
|
||||
}
|
||||
|
||||
if got := wgengine.IsNetstackRouter(wgengine.NewWatchdog(e)); got != tt.want {
|
||||
t.Errorf("IsNetstackRouter(watchdog-wrapped) = %v; want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,15 +17,11 @@ import (
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
"tailscale.com/net/dns"
|
||||
"tailscale.com/net/dns/resolver"
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/net/tstun"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/netmap"
|
||||
"tailscale.com/wgengine/capture"
|
||||
"tailscale.com/wgengine/filter"
|
||||
"tailscale.com/wgengine/magicsock"
|
||||
"tailscale.com/wgengine/router"
|
||||
"tailscale.com/wgengine/wgcfg"
|
||||
)
|
||||
@@ -126,9 +122,6 @@ func (e *watchdogEngine) watchdog(name string, fn func()) {
|
||||
func (e *watchdogEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config, dnsCfg *dns.Config, debug *tailcfg.Debug) error {
|
||||
return e.watchdogErr("Reconfig", func() error { return e.wrap.Reconfig(cfg, routerCfg, dnsCfg, debug) })
|
||||
}
|
||||
func (e *watchdogEngine) GetNetMon() *netmon.Monitor {
|
||||
return e.wrap.GetNetMon()
|
||||
}
|
||||
func (e *watchdogEngine) GetFilter() *filter.Filter {
|
||||
return e.wrap.GetFilter()
|
||||
}
|
||||
@@ -181,18 +174,6 @@ func (e *watchdogEngine) WhoIsIPPort(ipp netip.AddrPort) (tsIP netip.Addr, ok bo
|
||||
func (e *watchdogEngine) Close() {
|
||||
e.watchdog("Close", e.wrap.Close)
|
||||
}
|
||||
func (e *watchdogEngine) GetInternals() (tw *tstun.Wrapper, c *magicsock.Conn, d *dns.Manager, ok bool) {
|
||||
if ig, ok := e.wrap.(InternalsGetter); ok {
|
||||
return ig.GetInternals()
|
||||
}
|
||||
return
|
||||
}
|
||||
func (e *watchdogEngine) GetResolver() (r *resolver.Resolver, ok bool) {
|
||||
if re, ok := e.wrap.(ResolvingEngine); ok {
|
||||
return re.GetResolver()
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
func (e *watchdogEngine) PeerForIP(ip netip.Addr) (ret PeerForIP, ok bool) {
|
||||
e.watchdog("PeerForIP", func() { ret, ok = e.wrap.PeerForIP(ip) })
|
||||
return ret, ok
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
"tailscale.com/net/dns"
|
||||
"tailscale.com/net/netmon"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/netmap"
|
||||
@@ -92,9 +91,6 @@ type Engine interface {
|
||||
// WireGuard status changes.
|
||||
SetStatusCallback(StatusCallback)
|
||||
|
||||
// GetNetMon returns the network monitor.
|
||||
GetNetMon() *netmon.Monitor
|
||||
|
||||
// RequestStatus requests a WireGuard status update right
|
||||
// away, sent to the callback registered via SetStatusCallback.
|
||||
RequestStatus()
|
||||
|
||||
Reference in New Issue
Block a user