@ -20,7 +20,6 @@ import (
"net/netip"
"net/netip"
"net/url"
"net/url"
"os"
"os"
"os/exec"
"runtime"
"runtime"
"runtime/debug"
"runtime/debug"
"strconv"
"strconv"
@ -45,307 +44,302 @@ import (
"tailscale.com/types/key"
"tailscale.com/types/key"
"tailscale.com/types/logger"
"tailscale.com/types/logger"
"tailscale.com/util/must"
"tailscale.com/util/must"
"tailscale.com/wgengine/capture"
)
)
var debugCmd = & ffcli . Command {
var (
Name : "debug" ,
debugCaptureCmd func ( ) * ffcli . Command // or nil
Exec : runDebug ,
)
ShortUsage : "tailscale debug <debug-flags | subcommand>" ,
ShortHelp : "Debug commands" ,
func debugCmd ( ) * ffcli . Command {
LongHelp : hidden + ` "tailscale debug" contains misc debug facilities; it is not a stable interface. ` ,
return & ffcli . Command {
FlagSet : ( func ( ) * flag . FlagSet {
Name : "debug" ,
fs := newFlagSet ( "debug" )
Exec : runDebug ,
fs . StringVar ( & debugArgs . file , "file" , "" , "get, delete:NAME, or NAME" )
ShortUsage : "tailscale debug <debug-flags | subcommand>" ,
fs . StringVar ( & debugArgs . cpuFile , "cpu-profile" , "" , "if non-empty, grab a CPU profile for --profile-seconds seconds and write it to this file; - for stdout" )
ShortHelp : "Debug commands" ,
fs . StringVar ( & debugArgs . memFile , "mem-profile" , "" , "if non-empty, grab a memory profile and write it to this file; - for stdout" )
LongHelp : hidden + ` "tailscale debug" contains misc debug facilities; it is not a stable interface. ` ,
fs . IntVar ( & debugArgs . cpuSec , "profile-seconds" , 15 , "number of seconds to run a CPU profile for, when --cpu-profile is non-empty" )
FlagSet : ( func ( ) * flag . FlagSet {
return fs
fs := newFlagSet ( "debug" )
} ) ( ) ,
fs . StringVar ( & debugArgs . file , "file" , "" , "get, delete:NAME, or NAME" )
Subcommands : [ ] * ffcli . Command {
fs . StringVar ( & debugArgs . cpuFile , "cpu-profile" , "" , "if non-empty, grab a CPU profile for --profile-seconds seconds and write it to this file; - for stdout" )
{
fs . StringVar ( & debugArgs . memFile , "mem-profile" , "" , "if non-empty, grab a memory profile and write it to this file; - for stdout" )
Name : "derp-map" ,
fs . IntVar ( & debugArgs . cpuSec , "profile-seconds" , 15 , "number of seconds to run a CPU profile for, when --cpu-profile is non-empty" )
ShortUsage : "tailscale debug derp-map" ,
return fs
Exec : runDERPMap ,
} ) ( ) ,
ShortHelp : "Print DERP map" ,
Subcommands : nonNilCmds ( [ ] * ffcli . Command {
} ,
{
{
Name : "derp-map" ,
Name : "component-logs" ,
ShortUsage : "tailscale debug derp-map" ,
ShortUsage : "tailscale debug component-logs [" + strings . Join ( ipn . DebuggableComponents , "|" ) + "]" ,
Exec : runDERPMap ,
Exec : runDebugComponentLogs ,
ShortHelp : "Print DERP map" ,
ShortHelp : "Enable/disable debug logs for a component" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
{
fs := newFlagSet ( "component-logs" )
Name : "component-logs" ,
fs . DurationVar ( & debugComponentLogsArgs . forDur , "for" , time . Hour , "how long to enable debug logs for; zero or negative means to disable" )
ShortUsage : "tailscale debug component-logs [" + strings . Join ( ipn . DebuggableComponents , "|" ) + "]" ,
return fs
Exec : runDebugComponentLogs ,
} ) ( ) ,
ShortHelp : "Enable/disable debug logs for a component" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
{
fs := newFlagSet ( "component-logs" )
Name : "daemon-goroutines" ,
fs . DurationVar ( & debugComponentLogsArgs . forDur , "for" , time . Hour , "how long to enable debug logs for; zero or negative means to disable" )
ShortUsage : "tailscale debug daemon-goroutines" ,
return fs
Exec : runDaemonGoroutines ,
} ) ( ) ,
ShortHelp : "Print tailscaled's goroutines" ,
} ,
} ,
{
{
Name : "daemon-goroutines" ,
Name : "daemon-logs" ,
ShortUsage : "tailscale debug daemon-goroutines" ,
ShortUsage : "tailscale debug daemon-logs" ,
Exec : runDaemonGoroutines ,
Exec : runDaemonLogs ,
ShortHelp : "Print tailscaled's goroutines" ,
ShortHelp : "Watch tailscaled's server logs" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
{
fs := newFlagSet ( "daemon-logs" )
Name : "daemon-logs" ,
fs . IntVar ( & daemonLogsArgs . verbose , "verbose" , 0 , "verbosity level" )
ShortUsage : "tailscale debug daemon-logs" ,
fs . BoolVar ( & daemonLogsArgs . time , "time" , false , "include client time" )
Exec : runDaemonLogs ,
return fs
ShortHelp : "Watch tailscaled's server logs" ,
} ) ( ) ,
FlagSet : ( func ( ) * flag . FlagSet {
} ,
fs := newFlagSet ( "daemon-logs" )
{
fs . IntVar ( & daemonLogsArgs . verbose , "verbose" , 0 , "verbosity level" )
Name : "metrics" ,
fs . BoolVar ( & daemonLogsArgs . time , "time" , false , "include client time" )
ShortUsage : "tailscale debug metrics" ,
return fs
Exec : runDaemonMetrics ,
} ) ( ) ,
ShortHelp : "Print tailscaled's metrics" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
{
fs := newFlagSet ( "metrics" )
Name : "metrics" ,
fs . BoolVar ( & metricsArgs . watch , "watch" , false , "print JSON dump of delta values" )
ShortUsage : "tailscale debug metrics" ,
return fs
Exec : runDaemonMetrics ,
} ) ( ) ,
ShortHelp : "Print tailscaled's metrics" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
{
fs := newFlagSet ( "metrics" )
Name : "env" ,
fs . BoolVar ( & metricsArgs . watch , "watch" , false , "print JSON dump of delta values" )
ShortUsage : "tailscale debug env" ,
return fs
Exec : runEnv ,
} ) ( ) ,
ShortHelp : "Print cmd/tailscale environment" ,
} ,
} ,
{
{
Name : "env" ,
Name : "stat" ,
ShortUsage : "tailscale debug env" ,
ShortUsage : "tailscale debug stat <files...>" ,
Exec : runEnv ,
Exec : runStat ,
ShortHelp : "Print cmd/tailscale environment" ,
ShortHelp : "Stat a file" ,
} ,
} ,
{
{
Name : "stat" ,
Name : "hostinfo" ,
ShortUsage : "tailscale debug stat <files...>" ,
ShortUsage : "tailscale debug hostinfo" ,
Exec : runStat ,
Exec : runHostinfo ,
ShortHelp : "Stat a file" ,
ShortHelp : "Print hostinfo" ,
} ,
} ,
{
{
Name : "hostinfo" ,
Name : "local-creds" ,
ShortUsage : "tailscale debug hostinfo" ,
ShortUsage : "tailscale debug local-creds" ,
Exec : runHostinfo ,
Exec : runLocalCreds ,
ShortHelp : "Print hostinfo" ,
ShortHelp : "Print how to access Tailscale LocalAPI" ,
} ,
} ,
{
{
Name : "local-creds" ,
Name : "restun" ,
ShortUsage : "tailscale debug local-creds" ,
ShortUsage : "tailscale debug restun" ,
Exec : runLocalCreds ,
Exec : localAPIAction ( "restun" ) ,
ShortHelp : "Print how to access Tailscale LocalAPI" ,
ShortHelp : "Force a magicsock restun" ,
} ,
} ,
{
{
Name : "restun" ,
Name : "rebind" ,
ShortUsage : "tailscale debug restun" ,
ShortUsage : "tailscale debug rebind" ,
Exec : localAPIAction ( "restun" ) ,
Exec : localAPIAction ( "rebind" ) ,
ShortHelp : "Force a magicsock restun" ,
ShortHelp : "Force a magicsock rebind" ,
} ,
} ,
{
{
Name : "rebind" ,
Name : "derp-set-on-demand" ,
ShortUsage : "tailscale debug rebind" ,
ShortUsage : "tailscale debug derp-set-on-demand" ,
Exec : localAPIAction ( "rebind" ) ,
Exec : localAPIAction ( "derp-set-homeless" ) ,
ShortHelp : "Force a magicsock rebind" ,
ShortHelp : "Enable DERP on-demand mode (breaks reachability)" ,
} ,
} ,
{
{
Name : "derp-set-on-demand" ,
Name : "derp-unset-on-demand" ,
ShortUsage : "tailscale debug derp-set-on-demand" ,
ShortUsage : "tailscale debug derp-unset-on-demand" ,
Exec : localAPIAction ( "derp-set-homeless" ) ,
Exec : localAPIAction ( "derp-unset-homeless" ) ,
ShortHelp : "Enable DERP on-demand mode (breaks reachability)" ,
ShortHelp : "Disable DERP on-demand mode" ,
} ,
} ,
{
{
Name : "derp-unset-on-demand" ,
Name : "break-tcp-conns" ,
ShortUsage : "tailscale debug derp-unset-on-demand" ,
ShortUsage : "tailscale debug break-tcp-conns" ,
Exec : localAPIAction ( "derp-unset-homeless" ) ,
Exec : localAPIAction ( "break-tcp-conns" ) ,
ShortHelp : "Disable DERP on-demand mode" ,
ShortHelp : "Break any open TCP connections from the daemon" ,
} ,
} ,
{
{
Name : "break-tcp-conns" ,
Name : "break-derp-conns" ,
ShortUsage : "tailscale debug break-tcp-conns" ,
ShortUsage : "tailscale debug break-derp-conns" ,
Exec : localAPIAction ( "break-tcp-conns" ) ,
Exec : localAPIAction ( "break-derp-conns" ) ,
ShortHelp : "Break any open TCP connections from the daemon" ,
ShortHelp : "Break any open DERP connections from the daemon" ,
} ,
} ,
{
{
Name : "break-derp-conns" ,
Name : "pick-new-derp" ,
ShortUsage : "tailscale debug break-derp-conns" ,
ShortUsage : "tailscale debug pick-new-derp" ,
Exec : localAPIAction ( "break-derp-conns" ) ,
Exec : localAPIAction ( "pick-new-derp" ) ,
ShortHelp : "Break any open DERP connections from the daemon" ,
ShortHelp : "Switch to some other random DERP home region for a short time" ,
} ,
} ,
{
{
Name : "pick-new-derp" ,
Name : "force-prefer-derp" ,
ShortUsage : "tailscale debug pick-new-derp" ,
ShortUsage : "tailscale debug force-prefer-derp" ,
Exec : localAPIAction ( "pick-new-derp" ) ,
Exec : forcePreferDERP ,
ShortHelp : "Switch to some other random DERP home region for a short time" ,
ShortHelp : "Prefer the given region ID if reachable (until restart, or 0 to clear)" ,
} ,
} ,
{
{
Name : "force-prefer-derp" ,
Name : "force-netmap-update" ,
ShortUsage : "tailscale debug force-prefer-derp" ,
ShortUsage : "tailscale debug force-netmap-update" ,
Exec : forcePreferDERP ,
Exec : localAPIAction ( "force-netmap-update" ) ,
ShortHelp : "Prefer the given region ID if reachable (until restart, or 0 to clear)" ,
ShortHelp : "Force a full no-op netmap update (for load testing)" ,
} ,
} ,
{
{
Name : "force-netmap-update" ,
// TODO(bradfitz,maisem): eventually promote this out of debug
ShortUsage : "tailscale debug force-netmap-update" ,
Name : "reload-config" ,
Exec : localAPIAction ( "force-netmap-update" ) ,
ShortUsage : "tailscale debug reload-config" ,
ShortHelp : "Force a full no-op netmap update (for load testing)" ,
Exec : reloadConfig ,
} ,
ShortHelp : "Reload config" ,
{
} ,
// TODO(bradfitz,maisem): eventually promote this out of debug
{
Name : "reload-config" ,
Name : "control-knobs" ,
ShortUsage : "tailscale debug reload-config" ,
ShortUsage : "tailscale debug control-knobs" ,
Exec : reloadConfig ,
Exec : debugControlKnobs ,
ShortHelp : "Reload config" ,
ShortHelp : "See current control knobs" ,
} ,
} ,
{
{
Name : "control-knobs" ,
Name : "prefs" ,
ShortUsage : "tailscale debug control-knobs" ,
ShortUsage : "tailscale debug prefs" ,
Exec : debugControlKnobs ,
Exec : runPrefs ,
ShortHelp : "See current control knobs" ,
ShortHelp : "Print prefs" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
{
fs := newFlagSet ( "prefs" )
Name : "prefs" ,
fs . BoolVar ( & prefsArgs . pretty , "pretty" , false , "If true, pretty-print output" )
ShortUsage : "tailscale debug prefs" ,
return fs
Exec : runPrefs ,
} ) ( ) ,
ShortHelp : "Print prefs" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
{
fs := newFlagSet ( "prefs" )
Name : "watch-ipn" ,
fs . BoolVar ( & prefsArgs . pretty , "pretty" , false , "If true, pretty-print output" )
ShortUsage : "tailscale debug watch-ipn" ,
return fs
Exec : runWatchIPN ,
} ) ( ) ,
ShortHelp : "Subscribe to IPN message bus" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
{
fs := newFlagSet ( "watch-ipn" )
Name : "watch-ipn" ,
fs . BoolVar ( & watchIPNArgs . netmap , "netmap" , true , "include netmap in messages" )
ShortUsage : "tailscale debug watch-ipn" ,
fs . BoolVar ( & watchIPNArgs . initial , "initial" , false , "include initial status" )
Exec : runWatchIPN ,
fs . BoolVar ( & watchIPNArgs . rateLimit , "rate-limit" , true , "rate limit messags" )
ShortHelp : "Subscribe to IPN message bus" ,
fs . BoolVar ( & watchIPNArgs . showPrivateKey , "show-private-key" , false , "include node private key in printed netmap" )
FlagSet : ( func ( ) * flag . FlagSet {
fs . IntVar ( & watchIPNArgs . count , "count" , 0 , "exit after printing this many statuses, or 0 to keep going forever" )
fs := newFlagSet ( "watch-ipn" )
return fs
fs . BoolVar ( & watchIPNArgs . netmap , "netmap" , true , "include netmap in messages" )
} ) ( ) ,
fs . BoolVar ( & watchIPNArgs . initial , "initial" , false , "include initial status" )
} ,
fs . BoolVar ( & watchIPNArgs . rateLimit , "rate-limit" , true , "rate limit messags" )
{
fs . BoolVar ( & watchIPNArgs . showPrivateKey , "show-private-key" , false , "include node private key in printed netmap" )
Name : "netmap" ,
fs . IntVar ( & watchIPNArgs . count , "count" , 0 , "exit after printing this many statuses, or 0 to keep going forever" )
ShortUsage : "tailscale debug netmap" ,
return fs
Exec : runNetmap ,
} ) ( ) ,
ShortHelp : "Print the current network map" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
{
fs := newFlagSet ( "netmap" )
Name : "netmap" ,
fs . BoolVar ( & netmapArgs . showPrivateKey , "show-private-key" , false , "include node private key in printed netmap" )
ShortUsage : "tailscale debug netmap" ,
return fs
Exec : runNetmap ,
} ) ( ) ,
ShortHelp : "Print the current network map" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
{
fs := newFlagSet ( "netmap" )
Name : "via" ,
fs . BoolVar ( & netmapArgs . showPrivateKey , "show-private-key" , false , "include node private key in printed netmap" )
ShortUsage : "tailscale debug via <site-id> <v4-cidr>\n" +
return fs
"tailscale debug via <v6-route>" ,
} ) ( ) ,
Exec : runVia ,
} ,
ShortHelp : "Convert between site-specific IPv4 CIDRs and IPv6 'via' routes" ,
{
} ,
Name : "via" ,
{
ShortUsage : "tailscale debug via <site-id> <v4-cidr>\n" +
Name : "ts2021" ,
"tailscale debug via <v6-route>" ,
ShortUsage : "tailscale debug ts2021" ,
Exec : runVia ,
Exec : runTS2021 ,
ShortHelp : "Convert between site-specific IPv4 CIDRs and IPv6 'via' routes" ,
ShortHelp : "Debug ts2021 protocol connectivity" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
{
fs := newFlagSet ( "ts2021" )
Name : "ts2021" ,
fs . StringVar ( & ts2021Args . host , "host" , "controlplane.tailscale.com" , "hostname of control plane" )
ShortUsage : "tailscale debug ts2021" ,
fs . IntVar ( & ts2021Args . version , "version" , int ( tailcfg . CurrentCapabilityVersion ) , "protocol version" )
Exec : runTS2021 ,
fs . BoolVar ( & ts2021Args . verbose , "verbose" , false , "be extra verbose" )
ShortHelp : "Debug ts2021 protocol connectivity" ,
return fs
FlagSet : ( func ( ) * flag . FlagSet {
} ) ( ) ,
fs := newFlagSet ( "ts2021" )
} ,
fs . StringVar ( & ts2021Args . host , "host" , "controlplane.tailscale.com" , "hostname of control plane" )
{
fs . IntVar ( & ts2021Args . version , "version" , int ( tailcfg . CurrentCapabilityVersion ) , "protocol version" )
Name : "set-expire" ,
fs . BoolVar ( & ts2021Args . verbose , "verbose" , false , "be extra verbose" )
ShortUsage : "tailscale debug set-expire --in=1m" ,
return fs
Exec : runSetExpire ,
} ) ( ) ,
ShortHelp : "Manipulate node key expiry for testing" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
{
fs := newFlagSet ( "set-expire" )
Name : "set-expire" ,
fs . DurationVar ( & setExpireArgs . in , "in" , 0 , "if non-zero, set node key to expire this duration from now" )
ShortUsage : "tailscale debug set-expire --in=1m" ,
return fs
Exec : runSetExpire ,
} ) ( ) ,
ShortHelp : "Manipulate node key expiry for testing" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
{
fs := newFlagSet ( "set-expire" )
Name : "dev-store-set" ,
fs . DurationVar ( & setExpireArgs . in , "in" , 0 , "if non-zero, set node key to expire this duration from now" )
ShortUsage : "tailscale debug dev-store-set" ,
return fs
Exec : runDevStoreSet ,
} ) ( ) ,
ShortHelp : "Set a key/value pair during development" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
{
fs := newFlagSet ( "store-set" )
Name : "dev-store-set" ,
fs . BoolVar ( & devStoreSetArgs . danger , "danger" , false , "accept danger" )
ShortUsage : "tailscale debug dev-store-set" ,
return fs
Exec : runDevStoreSet ,
} ) ( ) ,
ShortHelp : "Set a key/value pair during development" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
{
fs := newFlagSet ( "store-set" )
Name : "derp" ,
fs . BoolVar ( & devStoreSetArgs . danger , "danger" , false , "accept danger" )
ShortUsage : "tailscale debug derp" ,
return fs
Exec : runDebugDERP ,
} ) ( ) ,
ShortHelp : "Test a DERP configuration" ,
} ,
} ,
{
{
Name : "derp" ,
Name : "capture" ,
ShortUsage : "tailscale debug derp" ,
ShortUsage : "tailscale debug capture" ,
Exec : runDebugDERP ,
Exec : runCapture ,
ShortHelp : "Test a DERP configuration" ,
ShortHelp : "Stream pcaps for debugging" ,
} ,
FlagSet : ( func ( ) * flag . FlagSet {
ccall ( debugCaptureCmd ) ,
fs := newFlagSet ( "capture" )
{
fs . StringVar ( & captureArgs . outFile , "o" , "" , "path to stream the pcap (or - for stdout), leave empty to start wireshark" )
Name : "portmap" ,
return fs
ShortUsage : "tailscale debug portmap" ,
} ) ( ) ,
Exec : debugPortmap ,
} ,
ShortHelp : "Run portmap debugging" ,
{
FlagSet : ( func ( ) * flag . FlagSet {
Name : "portmap" ,
fs := newFlagSet ( "portmap" )
ShortUsage : "tailscale debug portmap" ,
fs . DurationVar ( & debugPortmapArgs . duration , "duration" , 5 * time . Second , "timeout for port mapping" )
Exec : debugPortmap ,
fs . StringVar ( & debugPortmapArgs . ty , "type" , "" , ` portmap debug type (one of "", "pmp", "pcp", or "upnp") ` )
ShortHelp : "Run portmap debugging" ,
fs . StringVar ( & debugPortmapArgs . gatewayAddr , "gateway-addr" , "" , ` override gateway IP (must also pass --self-addr) ` )
FlagSet : ( func ( ) * flag . FlagSet {
fs . StringVar ( & debugPortmapArgs . selfAddr , "self-addr" , "" , ` override self IP (must also pass --gateway-addr) ` )
fs := newFlagSet ( "portmap" )
fs . BoolVar ( & debugPortmapArgs . logHTTP , "log-http" , false , ` print all HTTP requests and responses to the log ` )
fs . DurationVar ( & debugPortmapArgs . duration , "duration" , 5 * time . Second , "timeout for port mapping" )
return fs
fs . StringVar ( & debugPortmapArgs . ty , "type" , "" , ` portmap debug type (one of "", "pmp", "pcp", or "upnp") ` )
} ) ( ) ,
fs . StringVar ( & debugPortmapArgs . gatewayAddr , "gateway-addr" , "" , ` override gateway IP (must also pass --self-addr) ` )
} ,
fs . StringVar ( & debugPortmapArgs . selfAddr , "self-addr" , "" , ` override self IP (must also pass --gateway-addr) ` )
{
fs . BoolVar ( & debugPortmapArgs . logHTTP , "log-http" , false , ` print all HTTP requests and responses to the log ` )
Name : "peer-endpoint-changes" ,
return fs
ShortUsage : "tailscale debug peer-endpoint-changes <hostname-or-IP>" ,
} ) ( ) ,
Exec : runPeerEndpointChanges ,
} ,
ShortHelp : "Print debug information about a peer's endpoint changes" ,
{
} ,
Name : "peer-endpoint-changes" ,
{
ShortUsage : "tailscale debug peer-endpoint-changes <hostname-or-IP>" ,
Name : "dial-types" ,
Exec : runPeerEndpointChanges ,
ShortUsage : "tailscale debug dial-types <hostname-or-IP> <port>" ,
ShortHelp : "Print debug information about a peer's endpoint changes" ,
Exec : runDebugDialTypes ,
} ,
ShortHelp : "Print debug information about connecting to a given host or IP" ,
{
FlagSet : ( func ( ) * flag . FlagSet {
Name : "dial-types" ,
fs := newFlagSet ( "dial-types" )
ShortUsage : "tailscale debug dial-types <hostname-or-IP> <port>" ,
fs . StringVar ( & debugDialTypesArgs . network , "network" , "tcp" , ` network type to dial ("tcp", "udp", etc.) ` )
Exec : runDebugDialTypes ,
return fs
ShortHelp : "Print debug information about connecting to a given host or IP" ,
} ) ( ) ,
FlagSet : ( func ( ) * flag . FlagSet {
} ,
fs := newFlagSet ( "dial-types" )
{
fs . StringVar ( & debugDialTypesArgs . network , "network" , "tcp" , ` network type to dial ("tcp", "udp", etc.) ` )
Name : "resolve" ,
return fs
ShortUsage : "tailscale debug resolve <hostname>" ,
} ) ( ) ,
Exec : runDebugResolve ,
} ,
ShortHelp : "Does a DNS lookup" ,
{
FlagSet : ( func ( ) * flag . FlagSet {
Name : "resolve" ,
fs := newFlagSet ( "resolve" )
ShortUsage : "tailscale debug resolve <hostname>" ,
fs . StringVar ( & resolveArgs . net , "net" , "ip" , "network type to resolve (ip, ip4, ip6)" )
Exec : runDebugResolve ,
return fs
ShortHelp : "Does a DNS lookup" ,
} ) ( ) ,
FlagSet : ( func ( ) * flag . FlagSet {
} ,
fs := newFlagSet ( "resolve" )
{
fs . StringVar ( & resolveArgs . net , "net" , "ip" , "network type to resolve (ip, ip4, ip6)" )
Name : "go-buildinfo" ,
return fs
ShortUsage : "tailscale debug go-buildinfo" ,
} ) ( ) ,
ShortHelp : "Print Go's runtime/debug.BuildInfo" ,
} ,
Exec : runGoBuildInfo ,
{
} ,
Name : "go-buildinfo" ,
} ... ) ,
ShortUsage : "tailscale debug go-buildinfo" ,
}
ShortHelp : "Print Go's runtime/debug.BuildInfo" ,
Exec : runGoBuildInfo ,
} ,
} ,
}
}
func runGoBuildInfo ( ctx context . Context , args [ ] string ) error {
func runGoBuildInfo ( ctx context . Context , args [ ] string ) error {
@ -1036,50 +1030,6 @@ func runSetExpire(ctx context.Context, args []string) error {
return localClient . DebugSetExpireIn ( ctx , setExpireArgs . in )
return localClient . DebugSetExpireIn ( ctx , setExpireArgs . in )
}
}
var captureArgs struct {
outFile string
}
func runCapture ( ctx context . Context , args [ ] string ) error {
stream , err := localClient . StreamDebugCapture ( ctx )
if err != nil {
return err
}
defer stream . Close ( )
switch captureArgs . outFile {
case "-" :
fmt . Fprintln ( Stderr , "Press Ctrl-C to stop the capture." )
_ , err = io . Copy ( os . Stdout , stream )
return err
case "" :
lua , err := os . CreateTemp ( "" , "ts-dissector" )
if err != nil {
return err
}
defer os . Remove ( lua . Name ( ) )
lua . Write ( [ ] byte ( capture . DissectorLua ) )
if err := lua . Close ( ) ; err != nil {
return err
}
wireshark := exec . CommandContext ( ctx , "wireshark" , "-X" , "lua_script:" + lua . Name ( ) , "-k" , "-i" , "-" )
wireshark . Stdin = stream
wireshark . Stdout = os . Stdout
wireshark . Stderr = os . Stderr
return wireshark . Run ( )
}
f , err := os . OpenFile ( captureArgs . outFile , os . O_WRONLY | os . O_CREATE | os . O_TRUNC , 0644 )
if err != nil {
return err
}
defer f . Close ( )
fmt . Fprintln ( Stderr , "Press Ctrl-C to stop the capture." )
_ , err = io . Copy ( f , stream )
return err
}
var debugPortmapArgs struct {
var debugPortmapArgs struct {
duration time . Duration
duration time . Duration
gatewayAddr string
gatewayAddr string