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"
2021-03-01 18:08:53 +00:00
"sync"
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"
2020-02-05 22:16:58 +00:00
"tailscale.com/ipn/ipnserver"
"tailscale.com/logpolicy"
2021-03-01 18:08:53 +00:00
"tailscale.com/net/socks5"
2021-03-27 04:03:21 +00:00
"tailscale.com/net/tun"
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-03-01 18:08:53 +00:00
"tailscale.com/types/netmap"
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"
2020-02-12 07:09:24 +00:00
"tailscale.com/wgengine/magicsock"
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"
2021-03-01 18:08:53 +00:00
"tailscale.com/wgengine/tstun"
2020-02-05 22:16:58 +00:00
)
2020-02-16 02:14:50 +00:00
// globalStateKey is the ipn.StateKey that tailscaled loads on
// startup.
//
// We have to support multiple state keys for other OSes (Windows in
// particular), but right now Unix daemons run with a single
// node-global state. To keep open the option of having per-user state
// later, the global state key doesn't look like a username.
const globalStateKey = "_daemon"
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 ` )
2020-09-25 20:10:53 +00:00
flag . Var ( flagtype . PortValue ( & args . port , magicsock . DefaultPort ) , "port" , "UDP port to listen on for WireGuard and peer-to-peer traffic; 0 means automatically select" )
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" )
}
2020-07-23 18:58:28 +00:00
if err := run ( ) ; err != nil {
// No need to log; the func already did
os . Exit ( 1 )
}
}
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 {
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-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-03-12 21:04:47 +00:00
if useNetstack {
2021-03-01 18:08:53 +00:00
tunDev , magicConn := e . ( wgengine . InternalsGetter ) . GetInternals ( )
ns , err = netstack . Create ( logf , tunDev , e , magicConn )
if err != nil {
log . Fatalf ( "netstack.Create: %v" , err )
}
if err := ns . Start ( ) ; err != nil {
log . Fatalf ( "failed to start netstack: %v" , err )
}
}
if socksListener != nil {
srv := & socks5 . Server {
Logf : logger . WithPrefix ( logf , "socks5: " ) ,
}
2021-03-12 21:04:47 +00:00
if useNetstack {
2021-03-01 18:08:53 +00:00
srv . Dialer = func ( ctx context . Context , network , addr string ) ( net . Conn , error ) {
return ns . DialContextTCP ( ctx , addr )
}
} else {
var mu sync . Mutex
var dns netstack . DNSMap
e . AddNetworkMapCallback ( func ( nm * netmap . NetworkMap ) {
mu . Lock ( )
defer mu . Unlock ( )
dns = netstack . DNSMapFromNetworkMap ( nm )
} )
srv . Dialer = func ( ctx context . Context , network , addr string ) ( net . Conn , error ) {
ipp , err := dns . Resolve ( ctx , addr )
if err != nil {
return nil , err
}
var d net . Dialer
return d . DialContext ( ctx , network , ipp . String ( ) )
}
}
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
}
} ( )
2020-02-05 22:16:58 +00:00
opts := ipnserver . Options {
2020-07-23 18:58:28 +00:00
SocketPath : args . socketpath ,
2020-03-12 01:00:25 +00:00
Port : 41112 ,
2020-07-23 18:58:28 +00:00
StatePath : args . statepath ,
2020-02-16 02:14:50 +00:00
AutostartStateKey : globalStateKey ,
2020-07-13 15:59:01 +00:00
LegacyConfigPath : paths . LegacyConfigPath ( ) ,
2020-02-05 22:16:58 +00:00
SurviveDisconnects : true ,
2020-03-26 05:57:46 +00:00
DebugMux : debugMux ,
2020-02-05 22:16:58 +00:00
}
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-03-12 21:04:47 +00:00
func createEngine ( logf logger . Logf , linkMon * monitor . Mon ) ( e wgengine . Engine , isUserspace bool , err error ) {
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-03-27 04:03:21 +00:00
e , isUserspace , err = tryEngine ( logf , linkMon , name )
2021-03-12 21:04:47 +00:00
if err == nil {
return e , isUserspace , nil
}
logf ( "wgengine.NewUserspaceEngine(tun %q) error: %v" , name , err )
errs = append ( errs , err )
}
return nil , false , multierror . New ( errs )
}
2021-03-27 04:03:21 +00:00
func tryEngine ( logf logger . Logf , linkMon * monitor . Mon , name string ) ( e wgengine . Engine , isUserspace bool , err error ) {
conf := wgengine . Config {
ListenPort : args . port ,
LinkMonitor : linkMon ,
}
isUserspace = name == "userspace-networking"
if isUserspace {
conf . TUN = tstun . NewFakeTUN ( )
conf . RouterGen = router . NewFake
} else {
dev , err := tun . New ( logf , name )
if err != nil {
return nil , false , err
}
conf . TUN = dev
}
e , err = wgengine . NewUserspaceEngine ( logf , conf )
if err != nil {
return nil , isUserspace , err
}
return e , isUserspace , nil
}
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 )
}
}