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-09-09 22:20:08 +00:00
"tailscale.com/net/netns"
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 {
2021-07-23 16:45:04 +00:00
// tunname is a /dev/net/tun tunnel name ("tailscale0"), the
// string "userspace-networking", "tap:TAPNAME[:BRIDGENAME]"
// or comma-separated list thereof.
tunname string
2021-08-30 16:45:55 +00:00
cleanup bool
debug string
port uint16
statepath string
socketpath string
birdSocketPath string
verbose int
socksAddr string // listen address for SOCKS5 server
2021-09-28 17:16:05 +00:00
httpProxyAddr string // listen address for HTTP proxy server
2020-07-23 18:58:28 +00:00
}
2021-02-15 05:11:06 +00:00
var (
2021-08-30 16:45:55 +00:00
installSystemDaemon func ( [ ] string ) error // non-nil on some platforms
uninstallSystemDaemon func ( [ ] string ) error // non-nil on some platforms
createBIRDClient func ( string ) ( wgengine . BIRDClient , error ) // non-nil on some platforms
2021-02-15 05:11:06 +00:00
)
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") ` )
2021-09-29 18:23:05 +00:00
flag . StringVar ( & args . httpProxyAddr , "outbound-http-proxy-listen" , "" , ` optional [ip]:port to run an outbound HTTP proxy (e.g. "localhost:8080") ` )
2021-03-01 18:08:53 +00:00
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" )
2021-10-12 16:51:52 +00:00
flag . StringVar ( & args . statepath , "state" , paths . DefaultTailscaledStateFile ( ) , "path of state file; use 'kube:<secret-name>' to use Kubernetes secrets or 'arn:aws:ssm:...' to store in AWS SSM" )
2020-09-25 20:10:53 +00:00
flag . StringVar ( & args . socketpath , "socket" , paths . DefaultTailscaledSocket ( ) , "path of the service unix socket" )
2021-08-30 16:45:55 +00:00
flag . StringVar ( & args . birdSocketPath , "bird-socket" , "" , "path of the bird 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-08-05 22:38:38 +00:00
if runtime . GOOS == "darwin" && os . Getuid ( ) != 0 && ! strings . Contains ( args . tunname , "userspace-networking" ) && ! args . cleanup {
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-08-30 16:45:55 +00:00
if args . birdSocketPath != "" && createBIRDClient == nil {
log . SetFlags ( 0 )
log . Fatalf ( "--bird-socket is not supported on %s" , runtime . GOOS )
}
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-08-18 20:34:31 +00:00
func trySynologyMigration ( p string ) error {
if runtime . GOOS != "linux" || distro . Get ( ) != distro . Synology {
return nil
}
fi , err := os . Stat ( p )
if err == nil && fi . Size ( ) > 0 || ! os . IsNotExist ( err ) {
return err
}
// File is empty or doesn't exist, try reading from the old path.
const oldPath = "/var/packages/Tailscale/etc/tailscaled.state"
if _ , err := os . Stat ( oldPath ) ; err != nil {
if os . IsNotExist ( err ) {
return nil
}
return err
}
if err := os . Chown ( oldPath , os . Getuid ( ) , os . Getgid ( ) ) ; err != nil {
return err
}
if err := os . Rename ( oldPath , p ) ; err != nil {
return err
}
return nil
}
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-07-28 22:17:31 +00:00
if os . Getenv ( "TS_PLEASE_PANIC" ) != "" {
panic ( "TS_PLEASE_PANIC asked us to panic" )
}
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" )
}
2021-08-18 20:34:31 +00:00
if err := trySynologyMigration ( args . statepath ) ; err != nil {
log . Printf ( "error in synology migration: %v" , err )
}
2021-01-22 19:35:22 +00:00
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-09-28 17:16:05 +00:00
socksListener := mustStartTCPListener ( "SOCKS5" , args . socksAddr )
httpProxyListener := mustStartTCPListener ( "HTTP proxy" , args . httpProxyAddr )
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
}
2021-09-28 17:16:05 +00:00
if socksListener != nil || httpProxyListener != nil {
2021-06-28 18:29:25 +00:00
srv := tssocks . NewServer ( logger . WithPrefix ( logf , "socks5: " ) , e , ns )
2021-09-28 17:16:05 +00:00
if httpProxyListener != nil {
hs := & http . Server { Handler : httpProxyHandler ( srv . Dialer ) }
go func ( ) {
log . Fatalf ( "HTTP proxy exited: %v" , hs . Serve ( httpProxyListener ) )
} ( )
}
if socksListener != nil {
go func ( ) {
log . Fatalf ( "SOCKS5 server exited: %v" , srv . Serve ( socksListener ) )
} ( )
}
2021-03-01 18:08:53 +00:00
}
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 {
2021-08-15 01:38:26 +00:00
case "windows" , "darwin" , "freebsd" :
2021-04-01 16:35:41 +00:00
// Enable on Windows and tailscaled-on-macOS (this doesn't
2021-08-15 01:38:26 +00:00
// affect the GUI clients), and on FreeBSD.
2021-04-01 16:35:41 +00:00
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-09-11 05:24:30 +00:00
useNetstack = name == "userspace-networking"
netns . SetEnabled ( ! useNetstack )
2021-08-30 16:45:55 +00:00
if args . birdSocketPath != "" && createBIRDClient != nil {
log . Printf ( "Connecting to BIRD at %s ..." , args . birdSocketPath )
conf . BIRDClient , err = createBIRDClient ( args . birdSocketPath )
if err != nil {
return nil , false , err
}
}
2021-04-01 15:07:54 +00:00
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-07-23 16:45:04 +00:00
if strings . HasPrefix ( name , "tap:" ) {
conf . IsTAP = true
e , err := wgengine . NewUserspaceEngine ( logf , conf )
return e , false , err
}
2021-07-20 20:28:06 +00:00
r , err := router . New ( logf , dev , linkMon )
2021-03-29 01:59:33 +00:00
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
}
2021-09-28 17:16:05 +00:00
func mustStartTCPListener ( name , addr string ) net . Listener {
if addr == "" {
return nil
}
ln , err := net . Listen ( "tcp" , addr )
if err != nil {
log . Fatalf ( "%v listener: %v" , name , err )
}
if strings . HasSuffix ( addr , ":0" ) {
// Log kernel-selected port number so integration tests
// can find it portably.
log . Printf ( "%v listening on %v" , name , ln . Addr ( ) )
}
return ln
}