2020-02-05 22:16:58 +00:00
|
|
|
// Copyright (c) 2020 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
|
|
|
// The tailscaled program is the Tailscale client daemon. It's configured
|
|
|
|
// and controlled via the tailscale CLI program.
|
|
|
|
//
|
|
|
|
// It primarily supports Linux, though other systems will likely be
|
|
|
|
// supported in the future.
|
|
|
|
package main // import "tailscale.com/cmd/tailscaled"
|
2020-02-05 22:16:58 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-03-12 21:04:47 +00:00
|
|
|
"errors"
|
2020-09-25 20:10:53 +00:00
|
|
|
"flag"
|
2020-10-27 04:23:58 +00:00
|
|
|
"fmt"
|
2020-02-05 22:16:58 +00:00
|
|
|
"log"
|
2021-03-01 18:08:53 +00:00
|
|
|
"net"
|
2020-02-05 22:16:58 +00:00
|
|
|
"net/http"
|
|
|
|
"net/http/pprof"
|
2020-05-20 15:40:34 +00:00
|
|
|
"os"
|
2020-07-13 10:17:58 +00:00
|
|
|
"os/signal"
|
2020-04-30 20:20:09 +00:00
|
|
|
"runtime"
|
2020-05-20 15:40:34 +00:00
|
|
|
"runtime/debug"
|
2020-10-19 14:56:23 +00:00
|
|
|
"strconv"
|
2021-03-12 21:04:47 +00:00
|
|
|
"strings"
|
2020-07-13 10:17:58 +00:00
|
|
|
"syscall"
|
2020-05-15 20:13:44 +00:00
|
|
|
"time"
|
2020-02-05 22:16:58 +00:00
|
|
|
|
2021-03-12 21:04:47 +00:00
|
|
|
"github.com/go-multierror/multierror"
|
2021-07-19 21:14:24 +00:00
|
|
|
"tailscale.com/ipn"
|
2020-02-05 22:16:58 +00:00
|
|
|
"tailscale.com/ipn/ipnserver"
|
|
|
|
"tailscale.com/logpolicy"
|
2021-04-02 05:35:26 +00:00
|
|
|
"tailscale.com/net/dns"
|
2021-06-28 18:29:25 +00:00
|
|
|
"tailscale.com/net/socks5/tssocks"
|
2021-03-27 05:14:08 +00:00
|
|
|
"tailscale.com/net/tstun"
|
2020-03-03 17:33:09 +00:00
|
|
|
"tailscale.com/paths"
|
2020-09-25 20:10:53 +00:00
|
|
|
"tailscale.com/types/flagtype"
|
2020-05-08 19:21:36 +00:00
|
|
|
"tailscale.com/types/logger"
|
2021-04-22 07:25:00 +00:00
|
|
|
"tailscale.com/util/osshare"
|
2020-10-27 04:23:58 +00:00
|
|
|
"tailscale.com/version"
|
2021-03-12 21:04:47 +00:00
|
|
|
"tailscale.com/version/distro"
|
2020-02-05 22:16:58 +00:00
|
|
|
"tailscale.com/wgengine"
|
2021-03-02 06:09:43 +00:00
|
|
|
"tailscale.com/wgengine/monitor"
|
2020-09-03 22:45:41 +00:00
|
|
|
"tailscale.com/wgengine/netstack"
|
2020-07-13 10:17:58 +00:00
|
|
|
"tailscale.com/wgengine/router"
|
2020-02-05 22:16:58 +00:00
|
|
|
)
|
|
|
|
|
2020-07-13 16:23:44 +00:00
|
|
|
// defaultTunName returns the default tun device name for the platform.
|
|
|
|
func defaultTunName() string {
|
|
|
|
switch runtime.GOOS {
|
|
|
|
case "openbsd":
|
|
|
|
return "tun"
|
|
|
|
case "windows":
|
|
|
|
return "Tailscale"
|
2021-02-12 04:10:07 +00:00
|
|
|
case "darwin":
|
|
|
|
// "utun" is recognized by wireguard-go/tun/tun_darwin.go
|
|
|
|
// as a magic value that uses/creates any free number.
|
|
|
|
return "utun"
|
2021-03-12 21:04:47 +00:00
|
|
|
case "linux":
|
|
|
|
if distro.Get() == distro.Synology {
|
|
|
|
// Try TUN, but fall back to userspace networking if needed.
|
|
|
|
// See https://github.com/tailscale/tailscale-synology/issues/35
|
|
|
|
return "tailscale0,userspace-networking"
|
|
|
|
}
|
2020-07-13 16:23:44 +00:00
|
|
|
}
|
|
|
|
return "tailscale0"
|
|
|
|
}
|
|
|
|
|
2020-07-23 18:58:28 +00:00
|
|
|
var args struct {
|
|
|
|
cleanup bool
|
|
|
|
debug string
|
2021-03-12 21:04:47 +00:00
|
|
|
tunname string // tun name, "userspace-networking", or comma-separated list thereof
|
2020-07-23 18:58:28 +00:00
|
|
|
port uint16
|
|
|
|
statepath string
|
|
|
|
socketpath string
|
2020-12-21 18:53:18 +00:00
|
|
|
verbose int
|
2021-03-01 18:08:53 +00:00
|
|
|
socksAddr string // listen address for SOCKS5 server
|
2020-07-23 18:58:28 +00:00
|
|
|
}
|
|
|
|
|
2021-02-15 05:11:06 +00:00
|
|
|
var (
|
|
|
|
installSystemDaemon func([]string) error // non-nil on some platforms
|
|
|
|
uninstallSystemDaemon func([]string) error // non-nil on some platforms
|
|
|
|
)
|
|
|
|
|
|
|
|
var subCommands = map[string]*func([]string) error{
|
|
|
|
"install-system-daemon": &installSystemDaemon,
|
|
|
|
"uninstall-system-daemon": &uninstallSystemDaemon,
|
|
|
|
"debug": &debugModeFunc,
|
|
|
|
}
|
2021-02-13 20:57:49 +00:00
|
|
|
|
2021-03-25 15:59:00 +00:00
|
|
|
func main() {
|
2020-05-20 15:40:34 +00:00
|
|
|
// We aren't very performance sensitive, and the parts that are
|
|
|
|
// performance sensitive (wireguard) try hard not to do any memory
|
|
|
|
// allocations. So let's be aggressive about garbage collection,
|
|
|
|
// unless the user specifically overrides it in the usual way.
|
|
|
|
if _, ok := os.LookupEnv("GOGC"); !ok {
|
|
|
|
debug.SetGCPercent(10)
|
|
|
|
}
|
|
|
|
|
2020-10-27 04:23:58 +00:00
|
|
|
printVersion := false
|
2020-12-21 18:53:18 +00:00
|
|
|
flag.IntVar(&args.verbose, "verbose", 0, "log verbosity level; 0 is default, 1 or higher are increasingly verbose")
|
2020-09-25 20:10:53 +00:00
|
|
|
flag.BoolVar(&args.cleanup, "cleanup", false, "clean up system state and exit")
|
|
|
|
flag.StringVar(&args.debug, "debug", "", "listen address ([ip]:port) of optional debug server")
|
2021-03-01 18:08:53 +00:00
|
|
|
flag.StringVar(&args.socksAddr, "socks5-server", "", `optional [ip]:port to run a SOCK5 server (e.g. "localhost:1080")`)
|
|
|
|
flag.StringVar(&args.tunname, "tun", defaultTunName(), `tunnel interface name; use "userspace-networking" (beta) to not use TUN`)
|
2021-04-27 20:20:58 +00:00
|
|
|
flag.Var(flagtype.PortValue(&args.port, 0), "port", "UDP port to listen on for WireGuard and peer-to-peer traffic; 0 means automatically select")
|
2020-09-25 20:10:53 +00:00
|
|
|
flag.StringVar(&args.statepath, "state", paths.DefaultTailscaledStateFile(), "path of state file")
|
|
|
|
flag.StringVar(&args.socketpath, "socket", paths.DefaultTailscaledSocket(), "path of the service unix socket")
|
2020-10-27 04:23:58 +00:00
|
|
|
flag.BoolVar(&printVersion, "version", false, "print version information and exit")
|
2020-02-05 22:16:58 +00:00
|
|
|
|
2021-02-13 20:57:49 +00:00
|
|
|
if len(os.Args) > 1 {
|
2021-02-15 05:11:06 +00:00
|
|
|
sub := os.Args[1]
|
|
|
|
if fp, ok := subCommands[sub]; ok {
|
|
|
|
if *fp == nil {
|
2021-02-13 20:57:49 +00:00
|
|
|
log.SetFlags(0)
|
2021-02-15 05:11:06 +00:00
|
|
|
log.Fatalf("%s not available on %v", sub, runtime.GOOS)
|
|
|
|
}
|
|
|
|
if err := (*fp)(os.Args[2:]); err != nil {
|
2021-02-13 20:57:49 +00:00
|
|
|
log.SetFlags(0)
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
return
|
2021-02-04 20:20:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-05 17:53:54 +00:00
|
|
|
if beWindowsSubprocess() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-09-25 20:10:53 +00:00
|
|
|
flag.Parse()
|
|
|
|
if flag.NArg() > 0 {
|
|
|
|
log.Fatalf("tailscaled does not take non-flag arguments: %q", flag.Args())
|
2020-02-05 22:16:58 +00:00
|
|
|
}
|
|
|
|
|
2020-10-27 04:23:58 +00:00
|
|
|
if printVersion {
|
|
|
|
fmt.Println(version.String())
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
2021-03-12 21:04:47 +00:00
|
|
|
if runtime.GOOS == "darwin" && os.Getuid() != 0 && !strings.Contains(args.tunname, "userspace-networking") {
|
2021-02-17 23:45:50 +00:00
|
|
|
log.SetFlags(0)
|
2021-03-02 16:36:25 +00:00
|
|
|
log.Fatalf("tailscaled requires root; use sudo tailscaled (or use --tun=userspace-networking)")
|
2021-02-17 23:45:50 +00:00
|
|
|
}
|
|
|
|
|
2020-07-23 18:58:28 +00:00
|
|
|
if args.socketpath == "" && runtime.GOOS != "windows" {
|
2021-02-17 23:45:50 +00:00
|
|
|
log.SetFlags(0)
|
2020-02-18 20:33:28 +00:00
|
|
|
log.Fatalf("--socket is required")
|
|
|
|
}
|
|
|
|
|
2021-04-22 07:25:00 +00:00
|
|
|
err := run()
|
|
|
|
|
|
|
|
// Remove file sharing from Windows shell (noop in non-windows)
|
|
|
|
osshare.SetFileSharingEnabled(false, logger.Discard)
|
|
|
|
|
|
|
|
if err != nil {
|
2020-07-23 18:58:28 +00:00
|
|
|
// No need to log; the func already did
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-19 22:01:41 +00:00
|
|
|
func ipnServerOpts() (o ipnserver.Options) {
|
|
|
|
// Allow changing the OS-specific IPN behavior for tests
|
|
|
|
// so we can e.g. test Windows-specific behaviors on Linux.
|
|
|
|
goos := os.Getenv("TS_DEBUG_TAILSCALED_IPN_GOOS")
|
|
|
|
if goos == "" {
|
|
|
|
goos = runtime.GOOS
|
|
|
|
}
|
|
|
|
|
|
|
|
o.Port = 41112
|
|
|
|
o.StatePath = args.statepath
|
|
|
|
o.SocketPath = args.socketpath // even for goos=="windows", for tests
|
|
|
|
|
|
|
|
switch goos {
|
|
|
|
default:
|
|
|
|
o.SurviveDisconnects = true
|
|
|
|
o.AutostartStateKey = ipn.GlobalDaemonStateKey
|
|
|
|
case "windows":
|
|
|
|
// Not those.
|
|
|
|
}
|
|
|
|
return o
|
|
|
|
}
|
|
|
|
|
2020-07-23 18:58:28 +00:00
|
|
|
func run() error {
|
|
|
|
var err error
|
|
|
|
|
|
|
|
pol := logpolicy.New("tailnode.log.tailscale.io")
|
2020-12-21 18:53:18 +00:00
|
|
|
pol.SetVerbosityLevel(args.verbose)
|
2020-07-23 18:58:28 +00:00
|
|
|
defer func() {
|
|
|
|
// Finish uploading logs after closing everything else.
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
|
|
|
defer cancel()
|
|
|
|
pol.Shutdown(ctx)
|
|
|
|
}()
|
|
|
|
|
2021-02-05 16:46:12 +00:00
|
|
|
if isWindowsService() {
|
|
|
|
// Run the IPN server from the Windows service manager.
|
|
|
|
log.Printf("Running service...")
|
|
|
|
if err := runWindowsService(pol); err != nil {
|
|
|
|
log.Printf("runservice: %v", err)
|
|
|
|
}
|
|
|
|
log.Printf("Service ended.")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-10-19 14:56:23 +00:00
|
|
|
var logf logger.Logf = log.Printf
|
|
|
|
if v, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_MEMORY")); v {
|
|
|
|
logf = logger.RusagePrefixLog(logf)
|
|
|
|
}
|
2020-07-23 18:58:28 +00:00
|
|
|
logf = logger.RateLimitedFn(logf, 5*time.Second, 5, 100)
|
|
|
|
|
|
|
|
if args.cleanup {
|
2021-04-02 05:35:26 +00:00
|
|
|
dns.Cleanup(logf, args.tunname)
|
2020-07-23 18:58:28 +00:00
|
|
|
router.Cleanup(logf, args.tunname)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-01-22 19:35:22 +00:00
|
|
|
if args.statepath == "" {
|
|
|
|
log.Fatalf("--state is required")
|
|
|
|
}
|
|
|
|
|
2020-03-26 05:57:46 +00:00
|
|
|
var debugMux *http.ServeMux
|
2020-07-23 18:58:28 +00:00
|
|
|
if args.debug != "" {
|
2020-03-26 05:57:46 +00:00
|
|
|
debugMux = newDebugMux()
|
2020-07-23 18:58:28 +00:00
|
|
|
go runDebugServer(debugMux, args.debug)
|
2020-02-05 22:16:58 +00:00
|
|
|
}
|
|
|
|
|
2021-03-02 06:09:43 +00:00
|
|
|
linkMon, err := monitor.New(logf)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("creating link monitor: %v", err)
|
|
|
|
}
|
|
|
|
pol.Logtail.SetLinkMonitor(linkMon)
|
|
|
|
|
2021-03-01 18:08:53 +00:00
|
|
|
var socksListener net.Listener
|
|
|
|
if args.socksAddr != "" {
|
|
|
|
var err error
|
|
|
|
socksListener, err = net.Listen("tcp", args.socksAddr)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("SOCKS5 listener: %v", err)
|
2020-09-03 22:45:41 +00:00
|
|
|
}
|
2021-06-28 15:32:12 +00:00
|
|
|
if strings.HasSuffix(args.socksAddr, ":0") {
|
|
|
|
// Log kernel-selected port number so integration tests
|
|
|
|
// can find it portably.
|
|
|
|
log.Printf("SOCKS5 listening on %v", socksListener.Addr())
|
|
|
|
}
|
2021-03-01 18:08:53 +00:00
|
|
|
}
|
|
|
|
|
2021-03-12 21:04:47 +00:00
|
|
|
e, useNetstack, err := createEngine(logf, linkMon)
|
2020-02-05 22:16:58 +00:00
|
|
|
if err != nil {
|
2020-07-23 18:58:28 +00:00
|
|
|
logf("wgengine.New: %v", err)
|
|
|
|
return err
|
2020-02-05 22:16:58 +00:00
|
|
|
}
|
2021-03-01 18:08:53 +00:00
|
|
|
|
|
|
|
var ns *netstack.Impl
|
2021-04-01 16:35:41 +00:00
|
|
|
if useNetstack || wrapNetstack {
|
|
|
|
onlySubnets := wrapNetstack && !useNetstack
|
2021-04-14 17:13:10 +00:00
|
|
|
ns = mustStartNetstack(logf, e, onlySubnets)
|
2021-03-01 18:08:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if socksListener != nil {
|
2021-06-28 18:29:25 +00:00
|
|
|
srv := tssocks.NewServer(logger.WithPrefix(logf, "socks5: "), e, ns)
|
2021-03-01 18:08:53 +00:00
|
|
|
go func() {
|
|
|
|
log.Fatalf("SOCKS5 server exited: %v", srv.Serve(socksListener))
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2020-02-05 22:16:58 +00:00
|
|
|
e = wgengine.NewWatchdog(e)
|
|
|
|
|
2020-07-13 10:17:58 +00:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
// Exit gracefully by cancelling the ipnserver context in most common cases:
|
2020-08-01 02:07:14 +00:00
|
|
|
// interrupted from the TTY or killed by a service manager.
|
2020-08-01 02:12:07 +00:00
|
|
|
interrupt := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
// SIGPIPE sometimes gets generated when CLIs disconnect from
|
|
|
|
// tailscaled. The default action is to terminate the process, we
|
|
|
|
// want to keep running.
|
|
|
|
signal.Ignore(syscall.SIGPIPE)
|
2020-07-13 10:17:58 +00:00
|
|
|
go func() {
|
|
|
|
select {
|
2020-07-30 15:49:17 +00:00
|
|
|
case s := <-interrupt:
|
|
|
|
logf("tailscaled got signal %v; shutting down", s)
|
2020-07-13 10:17:58 +00:00
|
|
|
cancel()
|
|
|
|
case <-ctx.Done():
|
|
|
|
// continue
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2021-07-19 22:01:41 +00:00
|
|
|
opts := ipnServerOpts()
|
|
|
|
opts.DebugMux = debugMux
|
2020-07-29 20:38:09 +00:00
|
|
|
err = ipnserver.Run(ctx, logf, pol.PublicID.String(), ipnserver.FixedEngine(e), opts)
|
2020-07-23 18:58:28 +00:00
|
|
|
// Cancelation is not an error: it is the only way to stop ipnserver.
|
|
|
|
if err != nil && err != context.Canceled {
|
|
|
|
logf("ipnserver.Run: %v", err)
|
|
|
|
return err
|
2020-02-05 22:16:58 +00:00
|
|
|
}
|
|
|
|
|
2020-07-23 18:58:28 +00:00
|
|
|
return nil
|
2020-02-05 22:16:58 +00:00
|
|
|
}
|
|
|
|
|
2021-04-01 15:07:54 +00:00
|
|
|
func createEngine(logf logger.Logf, linkMon *monitor.Mon) (e wgengine.Engine, useNetstack bool, err error) {
|
2021-03-12 21:04:47 +00:00
|
|
|
if args.tunname == "" {
|
|
|
|
return nil, false, errors.New("no --tun value specified")
|
|
|
|
}
|
|
|
|
var errs []error
|
|
|
|
for _, name := range strings.Split(args.tunname, ",") {
|
|
|
|
logf("wgengine.NewUserspaceEngine(tun %q) ...", name)
|
2021-04-01 15:07:54 +00:00
|
|
|
e, useNetstack, err = tryEngine(logf, linkMon, name)
|
2021-03-12 21:04:47 +00:00
|
|
|
if err == nil {
|
2021-04-01 15:07:54 +00:00
|
|
|
return e, useNetstack, nil
|
2021-03-12 21:04:47 +00:00
|
|
|
}
|
|
|
|
logf("wgengine.NewUserspaceEngine(tun %q) error: %v", name, err)
|
|
|
|
errs = append(errs, err)
|
|
|
|
}
|
|
|
|
return nil, false, multierror.New(errs)
|
|
|
|
}
|
|
|
|
|
2021-04-01 16:35:41 +00:00
|
|
|
var wrapNetstack = shouldWrapNetstack()
|
|
|
|
|
|
|
|
func shouldWrapNetstack() bool {
|
|
|
|
if e := os.Getenv("TS_DEBUG_WRAP_NETSTACK"); e != "" {
|
|
|
|
v, err := strconv.ParseBool(e)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("invalid TS_DEBUG_WRAP_NETSTACK value: %v", err)
|
|
|
|
}
|
|
|
|
return v
|
|
|
|
}
|
2021-04-10 01:42:21 +00:00
|
|
|
if distro.Get() == distro.Synology {
|
|
|
|
return true
|
|
|
|
}
|
2021-04-01 16:35:41 +00:00
|
|
|
switch runtime.GOOS {
|
|
|
|
case "windows", "darwin":
|
|
|
|
// Enable on Windows and tailscaled-on-macOS (this doesn't
|
|
|
|
// affect the GUI clients).
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-04-01 15:07:54 +00:00
|
|
|
func tryEngine(logf logger.Logf, linkMon *monitor.Mon, name string) (e wgengine.Engine, useNetstack bool, err error) {
|
2021-03-27 04:03:21 +00:00
|
|
|
conf := wgengine.Config{
|
|
|
|
ListenPort: args.port,
|
|
|
|
LinkMonitor: linkMon,
|
|
|
|
}
|
2021-04-01 15:07:54 +00:00
|
|
|
useNetstack = name == "userspace-networking"
|
|
|
|
if !useNetstack {
|
2021-04-06 04:45:56 +00:00
|
|
|
dev, devName, err := tstun.New(logf, name)
|
2021-03-27 04:03:21 +00:00
|
|
|
if err != nil {
|
2021-03-27 05:14:08 +00:00
|
|
|
tstun.Diagnose(logf, name)
|
2021-03-27 04:03:21 +00:00
|
|
|
return nil, false, err
|
|
|
|
}
|
2021-03-29 02:25:01 +00:00
|
|
|
conf.Tun = dev
|
2021-03-29 01:59:33 +00:00
|
|
|
r, err := router.New(logf, dev)
|
|
|
|
if err != nil {
|
|
|
|
dev.Close()
|
|
|
|
return nil, false, err
|
|
|
|
}
|
2021-04-12 22:51:37 +00:00
|
|
|
d, err := dns.NewOSConfigurator(logf, devName)
|
|
|
|
if err != nil {
|
|
|
|
return nil, false, err
|
|
|
|
}
|
|
|
|
conf.DNS = d
|
2021-04-01 16:35:41 +00:00
|
|
|
conf.Router = r
|
|
|
|
if wrapNetstack {
|
|
|
|
conf.Router = netstack.NewSubnetRouterWrapper(conf.Router)
|
|
|
|
}
|
2021-03-27 04:03:21 +00:00
|
|
|
}
|
2021-03-29 02:25:01 +00:00
|
|
|
e, err = wgengine.NewUserspaceEngine(logf, conf)
|
2021-03-27 04:03:21 +00:00
|
|
|
if err != nil {
|
2021-04-01 15:07:54 +00:00
|
|
|
return nil, useNetstack, err
|
2021-03-27 04:03:21 +00:00
|
|
|
}
|
2021-04-01 15:07:54 +00:00
|
|
|
return e, useNetstack, nil
|
2021-03-27 04:03:21 +00:00
|
|
|
}
|
|
|
|
|
2020-03-26 05:57:46 +00:00
|
|
|
func newDebugMux() *http.ServeMux {
|
2020-02-05 22:16:58 +00:00
|
|
|
mux := http.NewServeMux()
|
|
|
|
mux.HandleFunc("/debug/pprof/", pprof.Index)
|
|
|
|
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
|
|
|
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
|
|
|
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
|
|
|
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
2020-03-26 05:57:46 +00:00
|
|
|
return mux
|
|
|
|
}
|
|
|
|
|
|
|
|
func runDebugServer(mux *http.ServeMux, addr string) {
|
|
|
|
srv := &http.Server{
|
2020-02-05 22:16:58 +00:00
|
|
|
Addr: addr,
|
|
|
|
Handler: mux,
|
|
|
|
}
|
|
|
|
if err := srv.ListenAndServe(); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
2021-04-01 16:35:41 +00:00
|
|
|
|
2021-04-14 17:13:10 +00:00
|
|
|
func mustStartNetstack(logf logger.Logf, e wgengine.Engine, onlySubnets bool) *netstack.Impl {
|
2021-04-01 16:35:41 +00:00
|
|
|
tunDev, magicConn, ok := e.(wgengine.InternalsGetter).GetInternals()
|
|
|
|
if !ok {
|
|
|
|
log.Fatalf("%T is not a wgengine.InternalsGetter", e)
|
|
|
|
}
|
|
|
|
ns, err := netstack.Create(logf, tunDev, e, magicConn, onlySubnets)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("netstack.Create: %v", err)
|
|
|
|
}
|
|
|
|
if err := ns.Start(); err != nil {
|
|
|
|
log.Fatalf("failed to start netstack: %v", err)
|
|
|
|
}
|
2021-04-14 17:13:10 +00:00
|
|
|
return ns
|
2021-04-01 16:35:41 +00:00
|
|
|
}
|