2021-02-05 16:46:12 +00:00
|
|
|
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2021-03-25 15:59:00 +00:00
|
|
|
package main // import "tailscale.com/cmd/tailscaled"
|
2021-02-05 16:46:12 +00:00
|
|
|
|
2021-02-05 17:53:54 +00:00
|
|
|
// TODO: check if administrator, like tswin does.
|
|
|
|
//
|
|
|
|
// TODO: try to load wintun.dll early at startup, before wireguard/tun
|
|
|
|
// does (which panics) and if we'd fail (e.g. due to access
|
|
|
|
// denied, even if administrator), use 'tasklist /m wintun.dll'
|
|
|
|
// to see if something else is currently using it and tell user.
|
|
|
|
//
|
|
|
|
// TODO: check if Tailscale service is already running, and fail early
|
|
|
|
// like tswin does.
|
|
|
|
//
|
|
|
|
// TODO: on failure, check if on a UNC drive and recommend copying it
|
|
|
|
// to C:\ to run it, like tswin does.
|
|
|
|
|
2021-02-05 16:46:12 +00:00
|
|
|
import (
|
|
|
|
"context"
|
2021-06-16 15:53:08 +00:00
|
|
|
"encoding/json"
|
2021-02-05 17:53:54 +00:00
|
|
|
"fmt"
|
2021-02-05 16:46:12 +00:00
|
|
|
"log"
|
2021-02-05 17:53:54 +00:00
|
|
|
"os"
|
|
|
|
"time"
|
2021-02-05 16:46:12 +00:00
|
|
|
|
|
|
|
"golang.org/x/sys/windows"
|
|
|
|
"golang.org/x/sys/windows/svc"
|
2021-03-02 00:24:26 +00:00
|
|
|
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
2021-06-16 15:53:08 +00:00
|
|
|
"inet.af/netaddr"
|
2021-02-05 16:46:12 +00:00
|
|
|
"tailscale.com/ipn/ipnserver"
|
|
|
|
"tailscale.com/logpolicy"
|
2021-04-06 04:45:56 +00:00
|
|
|
"tailscale.com/net/dns"
|
2021-03-27 05:07:19 +00:00
|
|
|
"tailscale.com/net/tstun"
|
2021-02-05 17:53:54 +00:00
|
|
|
"tailscale.com/types/logger"
|
2021-09-28 22:33:08 +00:00
|
|
|
"tailscale.com/util/winutil"
|
2021-02-05 17:53:54 +00:00
|
|
|
"tailscale.com/version"
|
2021-05-10 16:56:15 +00:00
|
|
|
"tailscale.com/wf"
|
2021-02-05 17:53:54 +00:00
|
|
|
"tailscale.com/wgengine"
|
2021-04-01 16:35:41 +00:00
|
|
|
"tailscale.com/wgengine/netstack"
|
2021-03-29 01:59:33 +00:00
|
|
|
"tailscale.com/wgengine/router"
|
2021-02-05 16:46:12 +00:00
|
|
|
)
|
|
|
|
|
2021-02-05 19:13:34 +00:00
|
|
|
const serviceName = "Tailscale"
|
2021-02-05 16:46:12 +00:00
|
|
|
|
2021-09-28 22:33:08 +00:00
|
|
|
var flushDNSOnSessionUnlock bool
|
|
|
|
|
2021-02-05 16:46:12 +00:00
|
|
|
func isWindowsService() bool {
|
|
|
|
v, err := svc.IsWindowsService()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("svc.IsWindowsService failed: %v", err)
|
|
|
|
}
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
func runWindowsService(pol *logpolicy.Policy) error {
|
|
|
|
return svc.Run(serviceName, &ipnService{Policy: pol})
|
|
|
|
}
|
|
|
|
|
|
|
|
type ipnService struct {
|
|
|
|
Policy *logpolicy.Policy
|
|
|
|
}
|
|
|
|
|
|
|
|
// Called by Windows to execute the windows service.
|
|
|
|
func (service *ipnService) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (bool, uint32) {
|
|
|
|
changes <- svc.Status{State: svc.StartPending}
|
|
|
|
|
2021-09-28 22:33:08 +00:00
|
|
|
flushDNSOnSessionUnlock = winutil.GetRegInteger("FlushDNSOnSessionUnlock", 0) != 0
|
2021-02-05 16:46:12 +00:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
doneCh := make(chan struct{})
|
|
|
|
go func() {
|
|
|
|
defer close(doneCh)
|
|
|
|
args := []string{"/subproc", service.Policy.PublicID.String()}
|
|
|
|
ipnserver.BabysitProc(ctx, args, log.Printf)
|
|
|
|
}()
|
|
|
|
|
|
|
|
changes <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop}
|
|
|
|
|
|
|
|
for ctx.Err() == nil {
|
|
|
|
select {
|
|
|
|
case <-doneCh:
|
|
|
|
case cmd := <-r:
|
|
|
|
switch cmd.Cmd {
|
|
|
|
case svc.Stop:
|
|
|
|
cancel()
|
|
|
|
case svc.Interrogate:
|
|
|
|
changes <- cmd.CurrentStatus
|
2021-09-28 22:33:08 +00:00
|
|
|
case svc.SessionChange:
|
|
|
|
handleSessionChange(cmd)
|
|
|
|
changes <- cmd.CurrentStatus
|
2021-02-05 16:46:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
changes <- svc.Status{State: svc.StopPending}
|
|
|
|
return false, windows.NO_ERROR
|
|
|
|
}
|
2021-02-05 17:53:54 +00:00
|
|
|
|
|
|
|
func beWindowsSubprocess() bool {
|
2021-03-02 00:24:26 +00:00
|
|
|
if beFirewallKillswitch() {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2021-02-05 17:53:54 +00:00
|
|
|
if len(os.Args) != 3 || os.Args[1] != "/subproc" {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
logid := os.Args[2]
|
|
|
|
|
|
|
|
log.Printf("Program starting: v%v: %#v", version.Long, os.Args)
|
|
|
|
log.Printf("subproc mode: logid=%v", logid)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
b := make([]byte, 16)
|
|
|
|
for {
|
|
|
|
_, err := os.Stdin.Read(b)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("stdin err (parent process died): %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
err := startIPNServer(context.Background(), logid)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("ipnserver: %v", err)
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2021-03-02 00:24:26 +00:00
|
|
|
func beFirewallKillswitch() bool {
|
|
|
|
if len(os.Args) != 3 || os.Args[1] != "/firewall" {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
log.SetFlags(0)
|
|
|
|
log.Printf("killswitch subprocess starting, tailscale GUID is %s", os.Args[2])
|
|
|
|
|
|
|
|
guid, err := windows.GUIDFromString(os.Args[2])
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("invalid GUID %q: %v", os.Args[2], err)
|
|
|
|
}
|
|
|
|
|
|
|
|
luid, err := winipcfg.LUIDFromGUID(&guid)
|
|
|
|
if err != nil {
|
2021-05-10 16:56:15 +00:00
|
|
|
log.Fatalf("no interface with GUID %q: %v", guid, err)
|
2021-03-02 00:24:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
start := time.Now()
|
2021-06-16 15:53:08 +00:00
|
|
|
fw, err := wf.New(uint64(luid))
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("failed to enable firewall: %v", err)
|
2021-05-10 16:56:15 +00:00
|
|
|
}
|
2021-03-02 00:24:26 +00:00
|
|
|
log.Printf("killswitch enabled, took %s", time.Since(start))
|
|
|
|
|
2021-06-16 15:53:08 +00:00
|
|
|
// Note(maisem): when local lan access toggled, tailscaled needs to
|
|
|
|
// inform the firewall to let local routes through. The set of routes
|
|
|
|
// is passed in via stdin encoded in json.
|
|
|
|
dcd := json.NewDecoder(os.Stdin)
|
|
|
|
for {
|
|
|
|
var routes []netaddr.IPPrefix
|
|
|
|
if err := dcd.Decode(&routes); err != nil {
|
|
|
|
log.Fatalf("parent process died or requested exit, exiting (%v)", err)
|
|
|
|
}
|
|
|
|
if err := fw.UpdatePermittedRoutes(routes); err != nil {
|
|
|
|
log.Fatalf("failed to update routes (%v)", err)
|
|
|
|
}
|
|
|
|
}
|
2021-03-02 00:24:26 +00:00
|
|
|
}
|
|
|
|
|
2021-02-05 17:53:54 +00:00
|
|
|
func startIPNServer(ctx context.Context, logid string) error {
|
|
|
|
var logf logger.Logf = log.Printf
|
|
|
|
|
cmd/tailscaled: don't block ipnserver startup behind engine init on Windows
With this change, the ipnserver's safesocket.Listen (the localhost
tcp.Listen) happens right away, before any synchronous
TUN/DNS/Engine/etc setup work, which might be slow, especially on
early boot on Windows.
Because the safesocket.Listen starts up early, that means localhost
TCP dials (the safesocket.Connect from the GUI) complete successfully
and thus the GUI avoids the MessageBox error. (I verified that
pacifies it, even without a Listener.Accept; I'd feared that Windows
localhost was maybe special and avoided the normal listener backlog).
Once the GUI can then connect immediately without errors, the various
timeouts then matter less, because the backend is no longer trying to
race against the GUI's timeout. So keep retrying on errors for a
minute, or 10 minutes if the system just booted in the past 10
minutes.
This should fix the problem with Windows 10 desktops auto-logging in
and starting the Tailscale frontend which was then showing a
MessageBox error about failing to connect to tailscaled, which was
slow coming up because the Windows networking stack wasn't up
yet. Fingers crossed.
Fixes #1313 (previously #1187, etc)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2021-04-19 20:45:55 +00:00
|
|
|
getEngineRaw := func() (wgengine.Engine, error) {
|
2021-04-06 04:45:56 +00:00
|
|
|
dev, devName, err := tstun.New(logf, "Tailscale")
|
2021-03-27 04:03:21 +00:00
|
|
|
if err != nil {
|
cmd/tailscaled: don't block ipnserver startup behind engine init on Windows
With this change, the ipnserver's safesocket.Listen (the localhost
tcp.Listen) happens right away, before any synchronous
TUN/DNS/Engine/etc setup work, which might be slow, especially on
early boot on Windows.
Because the safesocket.Listen starts up early, that means localhost
TCP dials (the safesocket.Connect from the GUI) complete successfully
and thus the GUI avoids the MessageBox error. (I verified that
pacifies it, even without a Listener.Accept; I'd feared that Windows
localhost was maybe special and avoided the normal listener backlog).
Once the GUI can then connect immediately without errors, the various
timeouts then matter less, because the backend is no longer trying to
race against the GUI's timeout. So keep retrying on errors for a
minute, or 10 minutes if the system just booted in the past 10
minutes.
This should fix the problem with Windows 10 desktops auto-logging in
and starting the Tailscale frontend which was then showing a
MessageBox error about failing to connect to tailscaled, which was
slow coming up because the Windows networking stack wasn't up
yet. Fingers crossed.
Fixes #1313 (previously #1187, etc)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2021-04-19 20:45:55 +00:00
|
|
|
return nil, fmt.Errorf("TUN: %w", err)
|
2021-03-27 04:03:21 +00:00
|
|
|
}
|
2021-07-20 20:28:06 +00:00
|
|
|
r, err := router.New(logf, dev, nil)
|
2021-03-29 01:59:33 +00:00
|
|
|
if err != nil {
|
|
|
|
dev.Close()
|
2021-05-03 20:00:32 +00:00
|
|
|
return nil, fmt.Errorf("router: %w", err)
|
2021-03-29 01:59:33 +00:00
|
|
|
}
|
2021-04-01 16:35:41 +00:00
|
|
|
if wrapNetstack {
|
|
|
|
r = netstack.NewSubnetRouterWrapper(r)
|
|
|
|
}
|
2021-04-12 22:51:37 +00:00
|
|
|
d, err := dns.NewOSConfigurator(logf, devName)
|
|
|
|
if err != nil {
|
|
|
|
r.Close()
|
|
|
|
dev.Close()
|
cmd/tailscaled: don't block ipnserver startup behind engine init on Windows
With this change, the ipnserver's safesocket.Listen (the localhost
tcp.Listen) happens right away, before any synchronous
TUN/DNS/Engine/etc setup work, which might be slow, especially on
early boot on Windows.
Because the safesocket.Listen starts up early, that means localhost
TCP dials (the safesocket.Connect from the GUI) complete successfully
and thus the GUI avoids the MessageBox error. (I verified that
pacifies it, even without a Listener.Accept; I'd feared that Windows
localhost was maybe special and avoided the normal listener backlog).
Once the GUI can then connect immediately without errors, the various
timeouts then matter less, because the backend is no longer trying to
race against the GUI's timeout. So keep retrying on errors for a
minute, or 10 minutes if the system just booted in the past 10
minutes.
This should fix the problem with Windows 10 desktops auto-logging in
and starting the Tailscale frontend which was then showing a
MessageBox error about failing to connect to tailscaled, which was
slow coming up because the Windows networking stack wasn't up
yet. Fingers crossed.
Fixes #1313 (previously #1187, etc)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2021-04-19 20:45:55 +00:00
|
|
|
return nil, fmt.Errorf("DNS: %w", err)
|
2021-04-12 22:51:37 +00:00
|
|
|
}
|
2021-03-29 02:25:01 +00:00
|
|
|
eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{
|
|
|
|
Tun: dev,
|
2021-03-29 01:59:33 +00:00
|
|
|
Router: r,
|
2021-04-12 22:51:37 +00:00
|
|
|
DNS: d,
|
2021-02-28 05:42:34 +00:00
|
|
|
ListenPort: 41641,
|
|
|
|
})
|
2021-02-05 17:53:54 +00:00
|
|
|
if err != nil {
|
2021-03-29 01:59:33 +00:00
|
|
|
r.Close()
|
2021-03-27 04:03:21 +00:00
|
|
|
dev.Close()
|
2021-05-03 20:00:32 +00:00
|
|
|
return nil, fmt.Errorf("engine: %w", err)
|
2021-02-05 17:53:54 +00:00
|
|
|
}
|
2021-04-01 16:35:41 +00:00
|
|
|
onlySubnets := true
|
|
|
|
if wrapNetstack {
|
|
|
|
mustStartNetstack(logf, eng, onlySubnets)
|
|
|
|
}
|
2021-02-05 17:53:54 +00:00
|
|
|
return wgengine.NewWatchdog(eng), nil
|
|
|
|
}
|
|
|
|
|
cmd/tailscaled: don't block ipnserver startup behind engine init on Windows
With this change, the ipnserver's safesocket.Listen (the localhost
tcp.Listen) happens right away, before any synchronous
TUN/DNS/Engine/etc setup work, which might be slow, especially on
early boot on Windows.
Because the safesocket.Listen starts up early, that means localhost
TCP dials (the safesocket.Connect from the GUI) complete successfully
and thus the GUI avoids the MessageBox error. (I verified that
pacifies it, even without a Listener.Accept; I'd feared that Windows
localhost was maybe special and avoided the normal listener backlog).
Once the GUI can then connect immediately without errors, the various
timeouts then matter less, because the backend is no longer trying to
race against the GUI's timeout. So keep retrying on errors for a
minute, or 10 minutes if the system just booted in the past 10
minutes.
This should fix the problem with Windows 10 desktops auto-logging in
and starting the Tailscale frontend which was then showing a
MessageBox error about failing to connect to tailscaled, which was
slow coming up because the Windows networking stack wasn't up
yet. Fingers crossed.
Fixes #1313 (previously #1187, etc)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2021-04-19 20:45:55 +00:00
|
|
|
type engineOrError struct {
|
|
|
|
Engine wgengine.Engine
|
|
|
|
Err error
|
|
|
|
}
|
|
|
|
engErrc := make(chan engineOrError)
|
|
|
|
t0 := time.Now()
|
|
|
|
go func() {
|
|
|
|
const ms = time.Millisecond
|
|
|
|
for try := 1; ; try++ {
|
|
|
|
logf("tailscaled: getting engine... (try %v)", try)
|
|
|
|
t1 := time.Now()
|
|
|
|
eng, err := getEngineRaw()
|
|
|
|
d, dt := time.Since(t1).Round(ms), time.Since(t1).Round(ms)
|
2021-02-05 17:53:54 +00:00
|
|
|
if err != nil {
|
cmd/tailscaled: don't block ipnserver startup behind engine init on Windows
With this change, the ipnserver's safesocket.Listen (the localhost
tcp.Listen) happens right away, before any synchronous
TUN/DNS/Engine/etc setup work, which might be slow, especially on
early boot on Windows.
Because the safesocket.Listen starts up early, that means localhost
TCP dials (the safesocket.Connect from the GUI) complete successfully
and thus the GUI avoids the MessageBox error. (I verified that
pacifies it, even without a Listener.Accept; I'd feared that Windows
localhost was maybe special and avoided the normal listener backlog).
Once the GUI can then connect immediately without errors, the various
timeouts then matter less, because the backend is no longer trying to
race against the GUI's timeout. So keep retrying on errors for a
minute, or 10 minutes if the system just booted in the past 10
minutes.
This should fix the problem with Windows 10 desktops auto-logging in
and starting the Tailscale frontend which was then showing a
MessageBox error about failing to connect to tailscaled, which was
slow coming up because the Windows networking stack wasn't up
yet. Fingers crossed.
Fixes #1313 (previously #1187, etc)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2021-04-19 20:45:55 +00:00
|
|
|
logf("tailscaled: engine fetch error (try %v) in %v (total %v, sysUptime %v): %v",
|
|
|
|
try, d, dt, windowsUptime().Round(time.Second), err)
|
|
|
|
} else {
|
|
|
|
if try > 1 {
|
|
|
|
logf("tailscaled: got engine on try %v in %v (total %v)", try, d, dt)
|
|
|
|
} else {
|
|
|
|
logf("tailscaled: got engine in %v", d)
|
|
|
|
}
|
2021-02-05 17:53:54 +00:00
|
|
|
}
|
cmd/tailscaled: don't block ipnserver startup behind engine init on Windows
With this change, the ipnserver's safesocket.Listen (the localhost
tcp.Listen) happens right away, before any synchronous
TUN/DNS/Engine/etc setup work, which might be slow, especially on
early boot on Windows.
Because the safesocket.Listen starts up early, that means localhost
TCP dials (the safesocket.Connect from the GUI) complete successfully
and thus the GUI avoids the MessageBox error. (I verified that
pacifies it, even without a Listener.Accept; I'd feared that Windows
localhost was maybe special and avoided the normal listener backlog).
Once the GUI can then connect immediately without errors, the various
timeouts then matter less, because the backend is no longer trying to
race against the GUI's timeout. So keep retrying on errors for a
minute, or 10 minutes if the system just booted in the past 10
minutes.
This should fix the problem with Windows 10 desktops auto-logging in
and starting the Tailscale frontend which was then showing a
MessageBox error about failing to connect to tailscaled, which was
slow coming up because the Windows networking stack wasn't up
yet. Fingers crossed.
Fixes #1313 (previously #1187, etc)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2021-04-19 20:45:55 +00:00
|
|
|
timer := time.NewTimer(5 * time.Second)
|
|
|
|
engErrc <- engineOrError{eng, err}
|
|
|
|
if err == nil {
|
|
|
|
timer.Stop()
|
|
|
|
return
|
2021-02-05 17:53:54 +00:00
|
|
|
}
|
cmd/tailscaled: don't block ipnserver startup behind engine init on Windows
With this change, the ipnserver's safesocket.Listen (the localhost
tcp.Listen) happens right away, before any synchronous
TUN/DNS/Engine/etc setup work, which might be slow, especially on
early boot on Windows.
Because the safesocket.Listen starts up early, that means localhost
TCP dials (the safesocket.Connect from the GUI) complete successfully
and thus the GUI avoids the MessageBox error. (I verified that
pacifies it, even without a Listener.Accept; I'd feared that Windows
localhost was maybe special and avoided the normal listener backlog).
Once the GUI can then connect immediately without errors, the various
timeouts then matter less, because the backend is no longer trying to
race against the GUI's timeout. So keep retrying on errors for a
minute, or 10 minutes if the system just booted in the past 10
minutes.
This should fix the problem with Windows 10 desktops auto-logging in
and starting the Tailscale frontend which was then showing a
MessageBox error about failing to connect to tailscaled, which was
slow coming up because the Windows networking stack wasn't up
yet. Fingers crossed.
Fixes #1313 (previously #1187, etc)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2021-04-19 20:45:55 +00:00
|
|
|
<-timer.C
|
2021-02-05 17:53:54 +00:00
|
|
|
}
|
cmd/tailscaled: don't block ipnserver startup behind engine init on Windows
With this change, the ipnserver's safesocket.Listen (the localhost
tcp.Listen) happens right away, before any synchronous
TUN/DNS/Engine/etc setup work, which might be slow, especially on
early boot on Windows.
Because the safesocket.Listen starts up early, that means localhost
TCP dials (the safesocket.Connect from the GUI) complete successfully
and thus the GUI avoids the MessageBox error. (I verified that
pacifies it, even without a Listener.Accept; I'd feared that Windows
localhost was maybe special and avoided the normal listener backlog).
Once the GUI can then connect immediately without errors, the various
timeouts then matter less, because the backend is no longer trying to
race against the GUI's timeout. So keep retrying on errors for a
minute, or 10 minutes if the system just booted in the past 10
minutes.
This should fix the problem with Windows 10 desktops auto-logging in
and starting the Tailscale frontend which was then showing a
MessageBox error about failing to connect to tailscaled, which was
slow coming up because the Windows networking stack wasn't up
yet. Fingers crossed.
Fixes #1313 (previously #1187, etc)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2021-04-19 20:45:55 +00:00
|
|
|
}()
|
|
|
|
|
|
|
|
// getEngine is called by ipnserver to get the engine. It's
|
|
|
|
// not called concurrently and is not called again once it
|
|
|
|
// successfully returns an engine.
|
|
|
|
getEngine := func() (wgengine.Engine, error) {
|
|
|
|
if msg := os.Getenv("TS_DEBUG_WIN_FAIL"); msg != "" {
|
|
|
|
return nil, fmt.Errorf("pretending to be a service failure: %v", msg)
|
|
|
|
}
|
|
|
|
for {
|
|
|
|
res := <-engErrc
|
|
|
|
if res.Engine != nil {
|
|
|
|
return res.Engine, nil
|
2021-02-05 17:53:54 +00:00
|
|
|
}
|
cmd/tailscaled: don't block ipnserver startup behind engine init on Windows
With this change, the ipnserver's safesocket.Listen (the localhost
tcp.Listen) happens right away, before any synchronous
TUN/DNS/Engine/etc setup work, which might be slow, especially on
early boot on Windows.
Because the safesocket.Listen starts up early, that means localhost
TCP dials (the safesocket.Connect from the GUI) complete successfully
and thus the GUI avoids the MessageBox error. (I verified that
pacifies it, even without a Listener.Accept; I'd feared that Windows
localhost was maybe special and avoided the normal listener backlog).
Once the GUI can then connect immediately without errors, the various
timeouts then matter less, because the backend is no longer trying to
race against the GUI's timeout. So keep retrying on errors for a
minute, or 10 minutes if the system just booted in the past 10
minutes.
This should fix the problem with Windows 10 desktops auto-logging in
and starting the Tailscale frontend which was then showing a
MessageBox error about failing to connect to tailscaled, which was
slow coming up because the Windows networking stack wasn't up
yet. Fingers crossed.
Fixes #1313 (previously #1187, etc)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2021-04-19 20:45:55 +00:00
|
|
|
if time.Since(t0) < time.Minute || windowsUptime() < 10*time.Minute {
|
|
|
|
// Ignore errors during early boot. Windows 10 auto logs in the GUI
|
|
|
|
// way sooner than the networking stack components start up.
|
|
|
|
// So the network will fail for a bit (and require a few tries) while
|
|
|
|
// the GUI is still fine.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
// Return nicer errors to users, annotated with logids, which helps
|
|
|
|
// when they file bugs.
|
|
|
|
return nil, fmt.Errorf("%w\n\nlogid: %v", res.Err, logid)
|
2021-02-05 17:53:54 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-19 22:01:41 +00:00
|
|
|
err := ipnserver.Run(ctx, logf, logid, getEngine, ipnServerOpts())
|
2021-02-05 17:53:54 +00:00
|
|
|
if err != nil {
|
|
|
|
logf("ipnserver.Run: %v", err)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
cmd/tailscaled: don't block ipnserver startup behind engine init on Windows
With this change, the ipnserver's safesocket.Listen (the localhost
tcp.Listen) happens right away, before any synchronous
TUN/DNS/Engine/etc setup work, which might be slow, especially on
early boot on Windows.
Because the safesocket.Listen starts up early, that means localhost
TCP dials (the safesocket.Connect from the GUI) complete successfully
and thus the GUI avoids the MessageBox error. (I verified that
pacifies it, even without a Listener.Accept; I'd feared that Windows
localhost was maybe special and avoided the normal listener backlog).
Once the GUI can then connect immediately without errors, the various
timeouts then matter less, because the backend is no longer trying to
race against the GUI's timeout. So keep retrying on errors for a
minute, or 10 minutes if the system just booted in the past 10
minutes.
This should fix the problem with Windows 10 desktops auto-logging in
and starting the Tailscale frontend which was then showing a
MessageBox error about failing to connect to tailscaled, which was
slow coming up because the Windows networking stack wasn't up
yet. Fingers crossed.
Fixes #1313 (previously #1187, etc)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2021-04-19 20:45:55 +00:00
|
|
|
|
2021-09-28 22:33:08 +00:00
|
|
|
func handleSessionChange(chgRequest svc.ChangeRequest) {
|
|
|
|
if chgRequest.Cmd != svc.SessionChange || chgRequest.EventType != windows.WTS_SESSION_UNLOCK ||
|
|
|
|
!flushDNSOnSessionUnlock {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("Received WTS_SESSION_UNLOCK event, initiating DNS flush.")
|
|
|
|
go func() {
|
|
|
|
err := dns.Flush()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error flushing DNS on session unlock: %v", err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
cmd/tailscaled: don't block ipnserver startup behind engine init on Windows
With this change, the ipnserver's safesocket.Listen (the localhost
tcp.Listen) happens right away, before any synchronous
TUN/DNS/Engine/etc setup work, which might be slow, especially on
early boot on Windows.
Because the safesocket.Listen starts up early, that means localhost
TCP dials (the safesocket.Connect from the GUI) complete successfully
and thus the GUI avoids the MessageBox error. (I verified that
pacifies it, even without a Listener.Accept; I'd feared that Windows
localhost was maybe special and avoided the normal listener backlog).
Once the GUI can then connect immediately without errors, the various
timeouts then matter less, because the backend is no longer trying to
race against the GUI's timeout. So keep retrying on errors for a
minute, or 10 minutes if the system just booted in the past 10
minutes.
This should fix the problem with Windows 10 desktops auto-logging in
and starting the Tailscale frontend which was then showing a
MessageBox error about failing to connect to tailscaled, which was
slow coming up because the Windows networking stack wasn't up
yet. Fingers crossed.
Fixes #1313 (previously #1187, etc)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2021-04-19 20:45:55 +00:00
|
|
|
var (
|
|
|
|
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
|
|
|
getTickCount64Proc = kernel32.NewProc("GetTickCount64")
|
|
|
|
)
|
|
|
|
|
|
|
|
func windowsUptime() time.Duration {
|
|
|
|
r, _, _ := getTickCount64Proc.Call()
|
|
|
|
return time.Duration(int64(r)) * time.Millisecond
|
|
|
|
}
|