mirror of
https://github.com/tailscale/tailscale.git
synced 2025-05-04 14:41:01 +00:00
cmd/tailscaled: move more of the Windows server setup code into tailscaled
Updates #1232
This commit is contained in:
parent
6f7974b7f2
commit
a7562be5e1
@ -2,8 +2,6 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
|
|
||||||
W 💣 github.com/alexbrainman/sspi from github.com/alexbrainman/sspi/negotiate
|
W 💣 github.com/alexbrainman/sspi from github.com/alexbrainman/sspi/negotiate
|
||||||
W 💣 github.com/alexbrainman/sspi/negotiate from tailscale.com/net/tshttpproxy
|
W 💣 github.com/alexbrainman/sspi/negotiate from tailscale.com/net/tshttpproxy
|
||||||
github.com/apenwarr/fixconsole from tailscale.com/cmd/tailscaled
|
|
||||||
W 💣 github.com/apenwarr/w32 from github.com/apenwarr/fixconsole
|
|
||||||
L github.com/coreos/go-iptables/iptables from tailscale.com/wgengine/router
|
L github.com/coreos/go-iptables/iptables from tailscale.com/wgengine/router
|
||||||
LW github.com/go-multierror/multierror from tailscale.com/wgengine/router
|
LW github.com/go-multierror/multierror from tailscale.com/wgengine/router
|
||||||
W 💣 github.com/go-ole/go-ole from github.com/go-ole/go-ole/oleutil+
|
W 💣 github.com/go-ole/go-ole from github.com/go-ole/go-ole/oleutil+
|
||||||
@ -163,7 +161,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
|||||||
golang.org/x/sync/singleflight from tailscale.com/net/dnscache
|
golang.org/x/sync/singleflight from tailscale.com/net/dnscache
|
||||||
golang.org/x/sys/cpu from golang.org/x/crypto/blake2b+
|
golang.org/x/sys/cpu from golang.org/x/crypto/blake2b+
|
||||||
LD golang.org/x/sys/unix from github.com/jsimonetti/rtnetlink/internal/unix+
|
LD golang.org/x/sys/unix from github.com/jsimonetti/rtnetlink/internal/unix+
|
||||||
W golang.org/x/sys/windows from github.com/apenwarr/fixconsole+
|
W golang.org/x/sys/windows from github.com/tailscale/wireguard-go/conn+
|
||||||
W golang.org/x/sys/windows/registry from golang.zx2c4.com/wireguard/windows/tunnel/winipcfg+
|
W golang.org/x/sys/windows/registry from golang.zx2c4.com/wireguard/windows/tunnel/winipcfg+
|
||||||
W golang.org/x/sys/windows/svc from tailscale.com/cmd/tailscaled
|
W golang.org/x/sys/windows/svc from tailscale.com/cmd/tailscaled
|
||||||
golang.org/x/term from tailscale.com/logpolicy
|
golang.org/x/term from tailscale.com/logpolicy
|
||||||
|
@ -24,7 +24,6 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/apenwarr/fixconsole"
|
|
||||||
"tailscale.com/ipn/ipnserver"
|
"tailscale.com/ipn/ipnserver"
|
||||||
"tailscale.com/logpolicy"
|
"tailscale.com/logpolicy"
|
||||||
"tailscale.com/paths"
|
"tailscale.com/paths"
|
||||||
@ -88,11 +87,6 @@ func main() {
|
|||||||
flag.StringVar(&args.socketpath, "socket", paths.DefaultTailscaledSocket(), "path of the service unix socket")
|
flag.StringVar(&args.socketpath, "socket", paths.DefaultTailscaledSocket(), "path of the service unix socket")
|
||||||
flag.BoolVar(&printVersion, "version", false, "print version information and exit")
|
flag.BoolVar(&printVersion, "version", false, "print version information and exit")
|
||||||
|
|
||||||
err := fixconsole.FixConsoleIfNeeded()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("fixConsoleOutput: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(os.Args) > 1 && os.Args[1] == "debug" {
|
if len(os.Args) > 1 && os.Args[1] == "debug" {
|
||||||
if err := debugMode(os.Args[2:]); err != nil {
|
if err := debugMode(os.Args[2:]); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@ -100,6 +94,10 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if beWindowsSubprocess() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if flag.NArg() > 0 {
|
if flag.NArg() > 0 {
|
||||||
log.Fatalf("tailscaled does not take non-flag arguments: %q", flag.Args())
|
log.Fatalf("tailscaled does not take non-flag arguments: %q", flag.Args())
|
||||||
|
@ -11,3 +11,5 @@ import "tailscale.com/logpolicy"
|
|||||||
func isWindowsService() bool { return false }
|
func isWindowsService() bool { return false }
|
||||||
|
|
||||||
func runWindowsService(pol *logpolicy.Policy) error { panic("unreachable") }
|
func runWindowsService(pol *logpolicy.Policy) error { panic("unreachable") }
|
||||||
|
|
||||||
|
func beWindowsSubprocess() bool { return false }
|
||||||
|
@ -4,14 +4,33 @@
|
|||||||
|
|
||||||
package main // import "tailscale.com/cmd/tailscaled"
|
package main // import "tailscale.com/cmd/tailscaled"
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
"golang.org/x/sys/windows/svc"
|
"golang.org/x/sys/windows/svc"
|
||||||
"tailscale.com/ipn/ipnserver"
|
"tailscale.com/ipn/ipnserver"
|
||||||
"tailscale.com/logpolicy"
|
"tailscale.com/logpolicy"
|
||||||
|
"tailscale.com/types/logger"
|
||||||
|
"tailscale.com/version"
|
||||||
|
"tailscale.com/wgengine"
|
||||||
)
|
)
|
||||||
|
|
||||||
const serviceName = "Tailscale IPN"
|
const serviceName = "Tailscale IPN"
|
||||||
@ -62,3 +81,100 @@ func (service *ipnService) Execute(args []string, r <-chan svc.ChangeRequest, ch
|
|||||||
changes <- svc.Status{State: svc.StopPending}
|
changes <- svc.Status{State: svc.StopPending}
|
||||||
return false, windows.NO_ERROR
|
return false, windows.NO_ERROR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func beWindowsSubprocess() bool {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func startIPNServer(ctx context.Context, logid string) error {
|
||||||
|
var logf logger.Logf = log.Printf
|
||||||
|
var eng wgengine.Engine
|
||||||
|
var err error
|
||||||
|
|
||||||
|
getEngine := func() (wgengine.Engine, error) {
|
||||||
|
eng, err := wgengine.NewUserspaceEngine(logf, "Tailscale", 41641)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return wgengine.NewWatchdog(eng), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg := os.Getenv("TS_DEBUG_WIN_FAIL"); msg != "" {
|
||||||
|
err = fmt.Errorf("pretending to be a service failure: %v", msg)
|
||||||
|
} else {
|
||||||
|
// We have a bunch of bug reports of wgengine.NewUserspaceEngine returning a few different errors,
|
||||||
|
// all intermittently. A few times I (Brad) have also seen sporadic failures that simply
|
||||||
|
// restarting fixed. So try a few times.
|
||||||
|
for try := 1; try <= 5; try++ {
|
||||||
|
if try > 1 {
|
||||||
|
// Only sleep a bit. Don't do some massive backoff because
|
||||||
|
// the frontend GUI has a 30 second timeout on connecting to us,
|
||||||
|
// but even 5 seconds is too long for them to get any results.
|
||||||
|
// 5 tries * 1 second each seems fine.
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
eng, err = getEngine()
|
||||||
|
if err != nil {
|
||||||
|
logf("wgengine.NewUserspaceEngine: (try %v) %v", try, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if try > 1 {
|
||||||
|
logf("wgengine.NewUserspaceEngine: ended up working on try %v", try)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
// Log the error, but don't fatalf. We want to
|
||||||
|
// propagate the error message to the UI frontend. So
|
||||||
|
// we continue and tell the ipnserver to return that
|
||||||
|
// in a Notify message.
|
||||||
|
logf("wgengine.NewUserspaceEngine: %v", err)
|
||||||
|
}
|
||||||
|
opts := ipnserver.Options{
|
||||||
|
Port: 41112,
|
||||||
|
SurviveDisconnects: false,
|
||||||
|
StatePath: args.statepath,
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
// Return nicer errors to users, annotated with logids, which helps
|
||||||
|
// when they file bugs.
|
||||||
|
rawGetEngine := getEngine // raw == without verbose logid-containing error
|
||||||
|
getEngine = func() (wgengine.Engine, error) {
|
||||||
|
eng, err := rawGetEngine()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("wgengine.NewUserspaceEngine: %v\n\nlogid: %v", err, logid)
|
||||||
|
}
|
||||||
|
return eng, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
getEngine = ipnserver.FixedEngine(eng)
|
||||||
|
}
|
||||||
|
err = ipnserver.Run(ctx, logf, logid, getEngine, opts)
|
||||||
|
if err != nil {
|
||||||
|
logf("ipnserver.Run: %v", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
@ -8,6 +8,7 @@ package paths
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -42,5 +43,8 @@ func DefaultTailscaledStateFile() string {
|
|||||||
if f := stateFileFunc; f != nil {
|
if f := stateFileFunc; f != nil {
|
||||||
return f()
|
return f()
|
||||||
}
|
}
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
return filepath.Join(os.Getenv("LocalAppData"), "Tailscale", "server-state.conf")
|
||||||
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user