ipn/ipnserver, cmd/tailscaled: fix peerapi on Windows

We weren't wiring up netstack.Impl to the LocalBackend in some cases
on Windows. This fixes Windows 7 when run as a service.

Updates #4750 (fixes after pull in to corp repo)

Change-Id: I9ce51b797710f2bedfa90545776b7628c7528e99
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/4784/head
Brad Fitzpatrick 3 years ago committed by Brad Fitzpatrick
parent 43f9c25fd2
commit a9b4bf1535

@ -282,7 +282,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/wgengine/filter from tailscale.com/control/controlclient+ tailscale.com/wgengine/filter from tailscale.com/control/controlclient+
tailscale.com/wgengine/magicsock from tailscale.com/ipn/ipnlocal+ tailscale.com/wgengine/magicsock from tailscale.com/ipn/ipnlocal+
tailscale.com/wgengine/monitor from tailscale.com/control/controlclient+ tailscale.com/wgengine/monitor from tailscale.com/control/controlclient+
tailscale.com/wgengine/netstack from tailscale.com/cmd/tailscaled tailscale.com/wgengine/netstack from tailscale.com/cmd/tailscaled+
tailscale.com/wgengine/router from tailscale.com/ipn/ipnlocal+ tailscale.com/wgengine/router from tailscale.com/ipn/ipnlocal+
tailscale.com/wgengine/wgcfg from tailscale.com/ipn/ipnlocal+ tailscale.com/wgengine/wgcfg from tailscale.com/ipn/ipnlocal+
tailscale.com/wgengine/wgcfg/nmcfg from tailscale.com/ipn/ipnlocal tailscale.com/wgengine/wgcfg/nmcfg from tailscale.com/ipn/ipnlocal

@ -264,15 +264,15 @@ func startIPNServer(ctx context.Context, logid string) error {
} }
dialer := new(tsdial.Dialer) dialer := new(tsdial.Dialer)
getEngineRaw := func() (wgengine.Engine, error) { getEngineRaw := func() (wgengine.Engine, *netstack.Impl, error) {
dev, devName, err := tstun.New(logf, "Tailscale") dev, devName, err := tstun.New(logf, "Tailscale")
if err != nil { if err != nil {
return nil, fmt.Errorf("TUN: %w", err) return nil, nil, fmt.Errorf("TUN: %w", err)
} }
r, err := router.New(logf, dev, nil) r, err := router.New(logf, dev, nil)
if err != nil { if err != nil {
dev.Close() dev.Close()
return nil, fmt.Errorf("router: %w", err) return nil, nil, fmt.Errorf("router: %w", err)
} }
if wrapNetstack { if wrapNetstack {
r = netstack.NewSubnetRouterWrapper(r) r = netstack.NewSubnetRouterWrapper(r)
@ -281,7 +281,7 @@ func startIPNServer(ctx context.Context, logid string) error {
if err != nil { if err != nil {
r.Close() r.Close()
dev.Close() dev.Close()
return nil, fmt.Errorf("DNS: %w", err) return nil, nil, fmt.Errorf("DNS: %w", err)
} }
eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{ eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{
Tun: dev, Tun: dev,
@ -294,23 +294,24 @@ func startIPNServer(ctx context.Context, logid string) error {
if err != nil { if err != nil {
r.Close() r.Close()
dev.Close() dev.Close()
return nil, fmt.Errorf("engine: %w", err) return nil, nil, fmt.Errorf("engine: %w", err)
} }
ns, err := newNetstack(logf, dialer, eng) ns, err := newNetstack(logf, dialer, eng)
if err != nil { if err != nil {
return nil, fmt.Errorf("newNetstack: %w", err) return nil, nil, fmt.Errorf("newNetstack: %w", err)
} }
ns.ProcessLocalIPs = false ns.ProcessLocalIPs = false
ns.ProcessSubnets = wrapNetstack ns.ProcessSubnets = wrapNetstack
if err := ns.Start(); err != nil { if err := ns.Start(); err != nil {
return nil, fmt.Errorf("failed to start netstack: %w", err) return nil, nil, fmt.Errorf("failed to start netstack: %w", err)
} }
return wgengine.NewWatchdog(eng), nil return wgengine.NewWatchdog(eng), ns, nil
} }
type engineOrError struct { type engineOrError struct {
Engine wgengine.Engine Engine wgengine.Engine
Err error Netstack *netstack.Impl
Err error
} }
engErrc := make(chan engineOrError) engErrc := make(chan engineOrError)
t0 := time.Now() t0 := time.Now()
@ -319,7 +320,7 @@ func startIPNServer(ctx context.Context, logid string) error {
for try := 1; ; try++ { for try := 1; ; try++ {
logf("tailscaled: getting engine... (try %v)", try) logf("tailscaled: getting engine... (try %v)", try)
t1 := time.Now() t1 := time.Now()
eng, err := getEngineRaw() eng, ns, err := getEngineRaw()
d, dt := time.Since(t1).Round(ms), time.Since(t1).Round(ms) d, dt := time.Since(t1).Round(ms), time.Since(t1).Round(ms)
if err != nil { if err != nil {
logf("tailscaled: engine fetch error (try %v) in %v (total %v, sysUptime %v): %v", logf("tailscaled: engine fetch error (try %v) in %v (total %v, sysUptime %v): %v",
@ -332,7 +333,7 @@ func startIPNServer(ctx context.Context, logid string) error {
} }
} }
timer := time.NewTimer(5 * time.Second) timer := time.NewTimer(5 * time.Second)
engErrc <- engineOrError{eng, err} engErrc <- engineOrError{eng, ns, err}
if err == nil { if err == nil {
timer.Stop() timer.Stop()
return return
@ -344,14 +345,14 @@ func startIPNServer(ctx context.Context, logid string) error {
// getEngine is called by ipnserver to get the engine. It's // getEngine is called by ipnserver to get the engine. It's
// not called concurrently and is not called again once it // not called concurrently and is not called again once it
// successfully returns an engine. // successfully returns an engine.
getEngine := func() (wgengine.Engine, error) { getEngine := func() (wgengine.Engine, *netstack.Impl, error) {
if msg := envknob.String("TS_DEBUG_WIN_FAIL"); msg != "" { if msg := envknob.String("TS_DEBUG_WIN_FAIL"); msg != "" {
return nil, fmt.Errorf("pretending to be a service failure: %v", msg) return nil, nil, fmt.Errorf("pretending to be a service failure: %v", msg)
} }
for { for {
res := <-engErrc res := <-engErrc
if res.Engine != nil { if res.Engine != nil {
return res.Engine, nil return res.Engine, res.Netstack, nil
} }
if time.Since(t0) < time.Minute || windowsUptime() < 10*time.Minute { if time.Since(t0) < time.Minute || windowsUptime() < 10*time.Minute {
// Ignore errors during early boot. Windows 10 auto logs in the GUI // Ignore errors during early boot. Windows 10 auto logs in the GUI
@ -362,7 +363,7 @@ func startIPNServer(ctx context.Context, logid string) error {
} }
// Return nicer errors to users, annotated with logids, which helps // Return nicer errors to users, annotated with logids, which helps
// when they file bugs. // when they file bugs.
return nil, fmt.Errorf("%w\n\nlogid: %v", res.Err, logid) return nil, nil, fmt.Errorf("%w\n\nlogid: %v", res.Err, logid)
} }
} }
store, err := store.New(logf, statePathOrDefault()) store, err := store.New(logf, statePathOrDefault())

@ -51,6 +51,7 @@ import (
"tailscale.com/version/distro" "tailscale.com/version/distro"
"tailscale.com/wgengine" "tailscale.com/wgengine"
"tailscale.com/wgengine/monitor" "tailscale.com/wgengine/monitor"
"tailscale.com/wgengine/netstack"
) )
// Options is the configuration of the Tailscale node agent. // Options is the configuration of the Tailscale node agent.
@ -659,7 +660,7 @@ func (s *Server) writeToClients(n ipn.Notify) {
// The getEngine func is called repeatedly, once per connection, until it returns an engine successfully. // The getEngine func is called repeatedly, once per connection, until it returns an engine successfully.
// //
// Deprecated: use New and Server.Run instead. // Deprecated: use New and Server.Run instead.
func Run(ctx context.Context, logf logger.Logf, ln net.Listener, store ipn.StateStore, linkMon *monitor.Mon, dialer *tsdial.Dialer, logid string, getEngine func() (wgengine.Engine, error), opts Options) error { func Run(ctx context.Context, logf logger.Logf, ln net.Listener, store ipn.StateStore, linkMon *monitor.Mon, dialer *tsdial.Dialer, logid string, getEngine func() (wgengine.Engine, *netstack.Impl, error), opts Options) error {
getEngine = getEngineUntilItWorksWrapper(getEngine) getEngine = getEngineUntilItWorksWrapper(getEngine)
runDone := make(chan struct{}) runDone := make(chan struct{})
defer close(runDone) defer close(runDone)
@ -706,7 +707,7 @@ func Run(ctx context.Context, logf logger.Logf, ln net.Listener, store ipn.State
bo := backoff.NewBackoff("ipnserver", logf, 30*time.Second) bo := backoff.NewBackoff("ipnserver", logf, 30*time.Second)
var unservedConn net.Conn // if non-nil, accepted, but hasn't served yet var unservedConn net.Conn // if non-nil, accepted, but hasn't served yet
eng, err := getEngine() eng, ns, err := getEngine()
if err != nil { if err != nil {
logf("ipnserver: initial getEngine call: %v", err) logf("ipnserver: initial getEngine call: %v", err)
for i := 1; ctx.Err() == nil; i++ { for i := 1; ctx.Err() == nil; i++ {
@ -717,7 +718,7 @@ func Run(ctx context.Context, logf logger.Logf, ln net.Listener, store ipn.State
continue continue
} }
logf("ipnserver: try%d: trying getEngine again...", i) logf("ipnserver: try%d: trying getEngine again...", i)
eng, err = getEngine() eng, ns, err = getEngine()
if err == nil { if err == nil {
logf("%d: GetEngine worked; exiting failure loop", i) logf("%d: GetEngine worked; exiting failure loop", i)
unservedConn = c unservedConn = c
@ -747,6 +748,9 @@ func Run(ctx context.Context, logf logger.Logf, ln net.Listener, store ipn.State
if err != nil { if err != nil {
return err return err
} }
if ns != nil {
ns.SetLocalBackend(server.LocalBackend())
}
serverMu.Lock() serverMu.Lock()
serverOrNil = server serverOrNil = server
serverMu.Unlock() serverMu.Unlock()
@ -996,29 +1000,26 @@ func BabysitProc(ctx context.Context, args []string, logf logger.Logf) {
} }
} }
// FixedEngine returns a func that returns eng and a nil error.
func FixedEngine(eng wgengine.Engine) func() (wgengine.Engine, error) {
return func() (wgengine.Engine, error) { return eng, nil }
}
// getEngineUntilItWorksWrapper returns a getEngine wrapper that does // getEngineUntilItWorksWrapper returns a getEngine wrapper that does
// not call getEngine concurrently and stops calling getEngine once // not call getEngine concurrently and stops calling getEngine once
// it's returned a working engine. // it's returned a working engine.
func getEngineUntilItWorksWrapper(getEngine func() (wgengine.Engine, error)) func() (wgengine.Engine, error) { func getEngineUntilItWorksWrapper(getEngine func() (wgengine.Engine, *netstack.Impl, error)) func() (wgengine.Engine, *netstack.Impl, error) {
var mu sync.Mutex var mu sync.Mutex
var engGood wgengine.Engine var engGood wgengine.Engine
return func() (wgengine.Engine, error) { var nsGood *netstack.Impl
return func() (wgengine.Engine, *netstack.Impl, error) {
mu.Lock() mu.Lock()
defer mu.Unlock() defer mu.Unlock()
if engGood != nil { if engGood != nil {
return engGood, nil return engGood, nsGood, nil
} }
e, err := getEngine() e, ns, err := getEngine()
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
engGood = e engGood = e
return e, nil nsGood = ns
return e, ns, nil
} }
} }

@ -17,6 +17,7 @@ import (
"tailscale.com/net/tsdial" "tailscale.com/net/tsdial"
"tailscale.com/safesocket" "tailscale.com/safesocket"
"tailscale.com/wgengine" "tailscale.com/wgengine"
"tailscale.com/wgengine/netstack"
) )
func TestRunMultipleAccepts(t *testing.T) { func TestRunMultipleAccepts(t *testing.T) {
@ -75,6 +76,11 @@ func TestRunMultipleAccepts(t *testing.T) {
} }
defer ln.Close() defer ln.Close()
err = ipnserver.Run(ctx, logTriggerTestf, ln, store, nil /* mon */, new(tsdial.Dialer), "dummy_logid", ipnserver.FixedEngine(eng), opts) err = ipnserver.Run(ctx, logTriggerTestf, ln, store, nil /* mon */, new(tsdial.Dialer), "dummy_logid", FixedEngine(eng), opts)
t.Logf("ipnserver.Run = %v", err) t.Logf("ipnserver.Run = %v", err)
} }
// FixedEngine returns a func that returns eng and a nil error.
func FixedEngine(eng wgengine.Engine) func() (wgengine.Engine, *netstack.Impl, error) {
return func() (wgengine.Engine, *netstack.Impl, error) { return eng, nil, nil }
}

Loading…
Cancel
Save