envknob: support changing envknobs post-init

Updates #5114

Change-Id: Ia423fc7486e1b3f3180a26308278be0086fae49b
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/5654/head
Brad Fitzpatrick 2 years ago committed by Brad Fitzpatrick
parent 33ee2c058e
commit 74674b110d

@ -132,6 +132,7 @@ var subCommands = map[string]*func([]string) error{
var beCLI func() // non-nil if CLI is linked in
func main() {
envknob.PanicIfAnyEnvCheckedInInit()
printVersion := false
flag.IntVar(&args.verbose, "verbose", 0, "log verbosity level; 0 is default, 1 or higher are increasingly verbose")
flag.BoolVar(&args.cleanup, "cleanup", false, "clean up system state and exit")
@ -376,7 +377,7 @@ func run() error {
return fmt.Errorf("newNetstack: %w", err)
}
ns.ProcessLocalIPs = useNetstack
ns.ProcessSubnets = useNetstack || wrapNetstack
ns.ProcessSubnets = useNetstack || shouldWrapNetstack()
if useNetstack {
dialer.UseNetstackForIP = func(ip netip.Addr) bool {
@ -477,8 +478,6 @@ func createEngine(logf logger.Logf, linkMon *monitor.Mon, dialer *tsdial.Dialer)
return nil, false, multierr.New(errs...)
}
var wrapNetstack = shouldWrapNetstack()
func shouldWrapNetstack() bool {
if v, ok := envknob.LookupBool("TS_DEBUG_WRAP_NETSTACK"); ok {
return v
@ -549,7 +548,7 @@ func tryEngine(logf logger.Logf, linkMon *monitor.Mon, dialer *tsdial.Dialer, na
}
conf.DNS = d
conf.Router = r
if wrapNetstack {
if shouldWrapNetstack() {
conf.Router = netstack.NewSubnetRouterWrapper(conf.Router)
}
}

@ -274,7 +274,7 @@ func startIPNServer(ctx context.Context, logid string) error {
dev.Close()
return nil, nil, fmt.Errorf("router: %w", err)
}
if wrapNetstack {
if shouldWrapNetstack() {
r = netstack.NewSubnetRouterWrapper(r)
}
d, err := dns.NewOSConfigurator(logf, devName)
@ -301,7 +301,7 @@ func startIPNServer(ctx context.Context, logid string) error {
return nil, nil, fmt.Errorf("newNetstack: %w", err)
}
ns.ProcessLocalIPs = false
ns.ProcessSubnets = wrapNetstack
ns.ProcessSubnets = shouldWrapNetstack()
if err := ns.Start(); err != nil {
return nil, nil, fmt.Errorf("failed to start netstack: %w", err)
}

@ -490,7 +490,7 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new
c.logf("RegisterReq sign error: %v", err)
}
}
if debugRegister {
if debugRegister() {
j, _ := json.MarshalIndent(request, "", "\t")
c.logf("RegisterRequest: %s", j)
}
@ -533,7 +533,7 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new
c.logf("error decoding RegisterResponse with server key %s and machine key %s: %v", serverKey, machinePrivKey.Public(), err)
return regen, opt.URL, fmt.Errorf("register request: %v", err)
}
if debugRegister {
if debugRegister() {
j, _ := json.MarshalIndent(resp, "", "\t")
c.logf("RegisterResponse: %s", j)
}
@ -715,7 +715,7 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, readOnly bool
c.logf("[v1] PollNetMap: stream=%v ep=%v", allowStream, epStrs)
vlogf := logger.Discard
if DevKnob.DumpNetMaps {
if DevKnob.DumpNetMaps() {
// TODO(bradfitz): update this to use "[v2]" prefix perhaps? but we don't
// want to upload it always.
vlogf = c.logf
@ -963,12 +963,12 @@ func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, readOnly bool
controlTrimWGConfig.Store(d.TrimWGConfig)
}
if DevKnob.StripEndpoints {
if DevKnob.StripEndpoints() {
for _, p := range resp.Peers {
p.Endpoints = nil
}
}
if DevKnob.StripCaps {
if DevKnob.StripCaps() {
nm.SelfNode.Capabilities = nil
}
@ -1012,8 +1012,8 @@ func decode(res *http.Response, v any, serverKey, serverNoiseKey key.MachinePubl
}
var (
debugMap = envknob.Bool("TS_DEBUG_MAP")
debugRegister = envknob.Bool("TS_DEBUG_REGISTER")
debugMap = envknob.RegisterBool("TS_DEBUG_MAP")
debugRegister = envknob.RegisterBool("TS_DEBUG_REGISTER")
)
var jsonEscapedZero = []byte(`\u0000`)
@ -1051,7 +1051,7 @@ func (c *Direct) decodeMsg(msg []byte, v any, mkey key.MachinePrivate) error {
return err
}
}
if debugMap {
if debugMap() {
var buf bytes.Buffer
json.Indent(&buf, b, "", " ")
log.Printf("MapResponse: %s", buf.Bytes())
@ -1088,7 +1088,7 @@ func encode(v any, serverKey, serverNoiseKey key.MachinePublic, mkey key.Machine
if err != nil {
return nil, err
}
if debugMap {
if debugMap() {
if _, ok := v.(*tailcfg.MapRequest); ok {
log.Printf("MapRequest: %s", b)
}
@ -1139,18 +1139,18 @@ func loadServerPubKeys(ctx context.Context, httpc *http.Client, serverURL string
var DevKnob = initDevKnob()
type devKnobs struct {
DumpNetMaps bool
ForceProxyDNS bool
StripEndpoints bool // strip endpoints from control (only use disco messages)
StripCaps bool // strip all local node's control-provided capabilities
DumpNetMaps func() bool
ForceProxyDNS func() bool
StripEndpoints func() bool // strip endpoints from control (only use disco messages)
StripCaps func() bool // strip all local node's control-provided capabilities
}
func initDevKnob() devKnobs {
return devKnobs{
DumpNetMaps: envknob.Bool("TS_DEBUG_NETMAP"),
ForceProxyDNS: envknob.Bool("TS_DEBUG_PROXY_DNS"),
StripEndpoints: envknob.Bool("TS_DEBUG_STRIP_ENDPOINTS"),
StripCaps: envknob.Bool("TS_DEBUG_STRIP_CAPS"),
DumpNetMaps: envknob.RegisterBool("TS_DEBUG_NETMAP"),
ForceProxyDNS: envknob.RegisterBool("TS_DEBUG_PROXY_DNS"),
StripEndpoints: envknob.RegisterBool("TS_DEBUG_STRIP_ENDPOINTS"),
StripCaps: envknob.RegisterBool("TS_DEBUG_STRIP_CAPS"),
}
}

@ -190,7 +190,7 @@ func (ms *mapSession) netmapForResponse(resp *tailcfg.MapResponse) *netmap.Netwo
}
ms.addUserProfile(peer.User)
}
if DevKnob.ForceProxyDNS {
if DevKnob.ForceProxyDNS() {
nm.DNS.Proxied = true
}
ms.netMapBuilding = nil
@ -356,13 +356,13 @@ func cloneNodes(v1 []*tailcfg.Node) []*tailcfg.Node {
return v2
}
var debugSelfIPv6Only = envknob.Bool("TS_DEBUG_SELF_V6_ONLY")
var debugSelfIPv6Only = envknob.RegisterBool("TS_DEBUG_SELF_V6_ONLY")
func filterSelfAddresses(in []netip.Prefix) (ret []netip.Prefix) {
switch {
default:
return in
case debugSelfIPv6Only:
case debugSelfIPv6Only():
for _, a := range in {
if a.Addr().Is6() {
ret = append(ret, a)

@ -13,20 +13,18 @@ import (
)
// disableUPnP indicates whether to attempt UPnP mapping.
var disableUPnP atomic.Bool
var disableUPnPControl atomic.Bool
func init() {
SetDisableUPnP(envknob.Bool("TS_DISABLE_UPNP"))
}
var disableUPnpEnv = envknob.RegisterBool("TS_DISABLE_UPNP")
// DisableUPnP reports the last reported value from control
// whether UPnP portmapping should be disabled.
func DisableUPnP() bool {
return disableUPnP.Load()
return disableUPnPControl.Load() || disableUPnpEnv()
}
// SetDisableUPnP sets whether control says that UPnP should be
// disabled.
func SetDisableUPnP(v bool) {
disableUPnP.Store(v)
disableUPnPControl.Store(v)
}

@ -47,8 +47,6 @@ import (
"tailscale.com/version"
)
var debug = envknob.Bool("DERP_DEBUG_LOGS")
// verboseDropKeys is the set of destination public keys that should
// verbosely log whenever DERP drops a packet.
var verboseDropKeys = map[key.NodePublic]bool{}
@ -106,6 +104,7 @@ type Server struct {
limitedLogf logger.Logf
metaCert []byte // the encoded x509 cert to send after LetsEncrypt cert+intermediate
dupPolicy dupPolicy
debug bool
// Counters:
packetsSent, bytesSent expvar.Int
@ -299,6 +298,7 @@ func NewServer(privateKey key.NodePrivate, logf logger.Logf) *Server {
runtime.ReadMemStats(&ms)
s := &Server{
debug: envknob.Bool("DERP_DEBUG_LOGS"),
privateKey: privateKey,
publicKey: privateKey.Public(),
logf: logf,
@ -980,7 +980,7 @@ func (s *Server) recordDrop(packetBytes []byte, srcKey, dstKey key.NodePublic, r
msg := fmt.Sprintf("drop (%s) %s -> %s", srcKey.ShortString(), reason, dstKey.ShortString())
s.limitedLogf(msg)
}
if debug {
if s.debug {
s.logf("dropping packet reason=%s dst=%s disco=%v", reason, dstKey, disco.LooksLikeDiscoWrapper(packetBytes))
}
}

@ -19,28 +19,36 @@ package envknob
import (
"log"
"os"
"runtime"
"sort"
"strconv"
"strings"
"sync"
"sync/atomic"
"tailscale.com/types/opt"
)
var (
mu sync.Mutex
set = map[string]string{}
list []string
mu sync.Mutex
set = map[string]string{}
regStr = map[string]*string{}
regBool = map[string]*bool{}
regOptBool = map[string]*opt.Bool{}
)
func noteEnv(k, v string) {
if v == "" {
return
}
mu.Lock()
defer mu.Unlock()
if _, ok := set[k]; !ok {
list = append(list, k)
noteEnvLocked(k, v)
}
func noteEnvLocked(k, v string) {
if v != "" {
set[k] = v
} else {
delete(set, k)
}
set[k] = v
}
// logf is logger.Logf, but logger depends on envknob, so for circular
@ -52,11 +60,39 @@ type logf = func(format string, args ...any)
func LogCurrent(logf logf) {
mu.Lock()
defer mu.Unlock()
list := make([]string, 0, len(set))
for k := range set {
list = append(list, k)
}
sort.Strings(list)
for _, k := range list {
logf("envknob: %s=%q", k, set[k])
}
}
// Setenv changes an environment variable.
//
// It is not safe for concurrent reading of environment variables via the
// Register functions. All Setenv calls are meant to happen early in main before
// any goroutines are started.
func Setenv(envVar, val string) {
mu.Lock()
defer mu.Unlock()
os.Setenv(envVar, val)
noteEnvLocked(envVar, val)
if p := regStr[envVar]; p != nil {
*p = val
}
if p := regBool[envVar]; p != nil {
setBoolLocked(p, envVar, val)
}
if p := regOptBool[envVar]; p != nil {
setOptBoolLocked(p, envVar, val)
}
}
// String returns the named environment variable, using os.Getenv.
//
// If the variable is non-empty, it's also tracked & logged as being
@ -67,6 +103,82 @@ func String(envVar string) string {
return v
}
// RegisterString returns a func that gets the named environment variable,
// without a map lookup per call. It assumes that mutations happen via
// envknob.Setenv.
func RegisterString(envVar string) func() string {
mu.Lock()
defer mu.Unlock()
p, ok := regStr[envVar]
if !ok {
val := os.Getenv(envVar)
if val != "" {
noteEnvLocked(envVar, val)
}
p = &val
regStr[envVar] = p
}
return func() string { return *p }
}
// RegisterBool returns a func that gets the named environment variable,
// without a map lookup per call. It assumes that mutations happen via
// envknob.Setenv.
func RegisterBool(envVar string) func() bool {
mu.Lock()
defer mu.Unlock()
p, ok := regBool[envVar]
if !ok {
var b bool
p = &b
setBoolLocked(p, envVar, os.Getenv(envVar))
regBool[envVar] = p
}
return func() bool { return *p }
}
// RegisterOptBool returns a func that gets the named environment variable,
// without a map lookup per call. It assumes that mutations happen via
// envknob.Setenv.
func RegisterOptBool(envVar string) func() opt.Bool {
mu.Lock()
defer mu.Unlock()
p, ok := regOptBool[envVar]
if !ok {
var b opt.Bool
p = &b
setOptBoolLocked(p, envVar, os.Getenv(envVar))
regOptBool[envVar] = p
}
return func() opt.Bool { return *p }
}
func setBoolLocked(p *bool, envVar, val string) {
noteEnvLocked(envVar, val)
if val == "" {
*p = false
return
}
var err error
*p, err = strconv.ParseBool(val)
if err != nil {
log.Fatalf("invalid boolean environment variable %s value %q", envVar, val)
}
}
func setOptBoolLocked(p *opt.Bool, envVar, val string) {
noteEnvLocked(envVar, val)
if val == "" {
*p = ""
return
}
b, err := strconv.ParseBool(val)
if err != nil {
log.Fatalf("invalid boolean environment variable %s value %q", envVar, val)
}
p.Set(b)
}
// Bool returns the boolean value of the named environment variable.
// If the variable is not set, it returns false.
// An invalid value exits the binary with a failure.
@ -81,6 +193,7 @@ func BoolDefaultTrue(envVar string) bool {
}
func boolOr(envVar string, implicitValue bool) bool {
assertNotInInit()
val := os.Getenv(envVar)
if val == "" {
return implicitValue
@ -98,6 +211,7 @@ func boolOr(envVar string, implicitValue bool) bool {
// The ok result is whether a value was set.
// If the value isn't a valid int, it exits the program with a failure.
func LookupBool(envVar string) (v bool, ok bool) {
assertNotInInit()
val := os.Getenv(envVar)
if val == "" {
return false, false
@ -113,6 +227,7 @@ func LookupBool(envVar string) (v bool, ok bool) {
// OptBool is like Bool, but returns an opt.Bool, so the caller can
// distinguish between implicitly and explicitly false.
func OptBool(envVar string) opt.Bool {
assertNotInInit()
b, ok := LookupBool(envVar)
if !ok {
return ""
@ -126,6 +241,7 @@ func OptBool(envVar string) opt.Bool {
// The ok result is whether a value was set.
// If the value isn't a valid int, it exits the program with a failure.
func LookupInt(envVar string) (v int, ok bool) {
assertNotInInit()
val := os.Getenv(envVar)
if val == "" {
return 0, false
@ -164,5 +280,44 @@ func NoLogsNoSupport() bool {
// SetNoLogsNoSupport enables no-logs-no-support mode.
func SetNoLogsNoSupport() {
os.Setenv("TS_NO_LOGS_NO_SUPPORT", "true")
Setenv("TS_NO_LOGS_NO_SUPPORT", "true")
}
// notInInit is set true the first time we've seen a non-init stack trace.
var notInInit atomic.Bool
func assertNotInInit() {
if notInInit.Load() {
return
}
skip := 0
for {
pc, _, _, ok := runtime.Caller(skip)
if !ok {
notInInit.Store(true)
return
}
fu := runtime.FuncForPC(pc)
if fu == nil {
return
}
name := fu.Name()
name = strings.TrimRightFunc(name, func(r rune) bool { return r >= '0' && r <= '9' })
if strings.HasSuffix(name, ".init") || strings.HasSuffix(name, ".init.") {
stack := make([]byte, 1<<10)
stack = stack[:runtime.Stack(stack, false)]
envCheckedInInitStack = stack
}
skip++
}
}
var envCheckedInInitStack []byte
// PanicIfAnyEnvCheckedInInit panics if environment variables were read during
// init.
func PanicIfAnyEnvCheckedInInit() {
if envCheckedInInitStack != nil {
panic("envknob check of called from init function: " + string(envCheckedInInitStack))
}
}

@ -325,7 +325,7 @@ func OverallError() error {
return overallErrorLocked()
}
var fakeErrForTesting = envknob.String("TS_DEBUG_FAKE_HEALTH_ERROR")
var fakeErrForTesting = envknob.RegisterString("TS_DEBUG_FAKE_HEALTH_ERROR")
func overallErrorLocked() error {
if !anyInterfaceUp {
@ -383,7 +383,7 @@ func overallErrorLocked() error {
for _, s := range controlHealth {
errs = append(errs, errors.New(s))
}
if e := fakeErrForTesting; len(errs) == 0 && e != "" {
if e := fakeErrForTesting(); len(errs) == 0 && e != "" {
return errors.New(e)
}
sort.Slice(errs, func(i, j int) bool {

@ -68,7 +68,6 @@ import (
)
var controlDebugFlags = getControlDebugFlags()
var canSSH = envknob.CanSSHD()
func getControlDebugFlags() []string {
if e := envknob.String("TS_DEBUG_CONTROL_FLAGS"); e != "" {
@ -1510,12 +1509,12 @@ func (b *LocalBackend) tellClientToBrowseToURL(url string) {
}
// For testing lazy machine key generation.
var panicOnMachineKeyGeneration = envknob.Bool("TS_DEBUG_PANIC_MACHINE_KEY")
var panicOnMachineKeyGeneration = envknob.RegisterBool("TS_DEBUG_PANIC_MACHINE_KEY")
func (b *LocalBackend) createGetMachinePrivateKeyFunc() func() (key.MachinePrivate, error) {
var cache syncs.AtomicValue[key.MachinePrivate]
return func() (key.MachinePrivate, error) {
if panicOnMachineKeyGeneration {
if panicOnMachineKeyGeneration() {
panic("machine key generated")
}
if v, ok := cache.LoadOk(); ok {
@ -1752,7 +1751,7 @@ func (b *LocalBackend) loadStateLocked(key ipn.StateKey, prefs *ipn.Prefs) (err
// setAtomicValuesFromPrefs populates sshAtomicBool and containsViaIPFuncAtomic
// from the prefs p, which may be nil.
func (b *LocalBackend) setAtomicValuesFromPrefs(p *ipn.Prefs) {
b.sshAtomicBool.Store(p != nil && p.RunSSH && canSSH)
b.sshAtomicBool.Store(p != nil && p.RunSSH && envknob.CanSSHD())
if p == nil {
b.containsViaIPFuncAtomic.Store(tsaddr.NewContainsIPFunc(nil))
@ -1967,7 +1966,7 @@ func (b *LocalBackend) checkSSHPrefsLocked(p *ipn.Prefs) error {
default:
return errors.New("The Tailscale SSH server is not supported on " + runtime.GOOS)
}
if !canSSH {
if !envknob.CanSSHD() {
return errors.New("The Tailscale SSH server has been administratively disabled.")
}
if envknob.SSHIgnoreTailnetPolicy() || envknob.SSHPolicyFile() != "" {
@ -2032,7 +2031,7 @@ func (b *LocalBackend) EditPrefs(mp *ipn.MaskedPrefs) (*ipn.Prefs, error) {
b.logf("EditPrefs check error: %v", err)
return nil, err
}
if p1.RunSSH && !canSSH {
if p1.RunSSH && !envknob.CanSSHD() {
b.mu.Unlock()
b.logf("EditPrefs requests SSH, but disabled by envknob; returning error")
return nil, errors.New("Tailscale SSH server administratively disabled.")
@ -2854,7 +2853,7 @@ func (b *LocalBackend) applyPrefsToHostinfo(hi *tailcfg.Hostinfo, prefs *ipn.Pre
hi.ShieldsUp = prefs.ShieldsUp
var sshHostKeys []string
if prefs.RunSSH && canSSH {
if prefs.RunSSH && envknob.CanSSHD() {
// TODO(bradfitz): this is called with b.mu held. Not ideal.
// If the filesystem gets wedged or something we could block for
// a long time. But probably fine.
@ -3073,7 +3072,7 @@ func (b *LocalBackend) ResetForClientDisconnect() {
b.setAtomicValuesFromPrefs(nil)
}
func (b *LocalBackend) ShouldRunSSH() bool { return b.sshAtomicBool.Load() && canSSH }
func (b *LocalBackend) ShouldRunSSH() bool { return b.sshAtomicBool.Load() && envknob.CanSSHD() }
// ShouldHandleViaIP reports whether whether ip is an IPv6 address in the
// Tailscale ULA's v6 "via" range embedding an IPv4 address to be forwarded to

@ -478,8 +478,8 @@ func (panicOnUseTransport) RoundTrip(*http.Request) (*http.Response, error) {
// Issue 1573: don't generate a machine key if we don't want to be running.
func TestLazyMachineKeyGeneration(t *testing.T) {
defer func(old bool) { panicOnMachineKeyGeneration = old }(panicOnMachineKeyGeneration)
panicOnMachineKeyGeneration = true
defer func(old func() bool) { panicOnMachineKeyGeneration = old }(panicOnMachineKeyGeneration)
panicOnMachineKeyGeneration = func() bool { return true }
var logf logger.Logf = logger.Discard
store := new(mem.Store)

@ -24,7 +24,7 @@ import (
"tailscale.com/types/tkatype"
)
var networkLockAvailable = envknob.Bool("TS_EXPERIMENTAL_NETWORK_LOCK")
var networkLockAvailable = envknob.RegisterBool("TS_EXPERIMENTAL_NETWORK_LOCK")
type tkaState struct {
authority *tka.Authority
@ -82,7 +82,7 @@ func (b *LocalBackend) NetworkLockInit(keys []tka.Key) error {
if b.tka != nil {
return errors.New("network-lock is already initialized")
}
if !networkLockAvailable {
if !networkLockAvailable() {
return errors.New("this is an experimental feature in your version of tailscale - Please upgrade to the latest to use this.")
}
if !b.CanSupportNetworkLock() {

@ -73,7 +73,7 @@ func (h *Handler) certDir() (string, error) {
return full, nil
}
var acmeDebug = envknob.Bool("TS_DEBUG_ACME")
var acmeDebug = envknob.RegisterBool("TS_DEBUG_ACME")
func (h *Handler) serveCert(w http.ResponseWriter, r *http.Request) {
if !h.PermitWrite && !h.PermitCert {
@ -96,7 +96,7 @@ func (h *Handler) serveCert(w http.ResponseWriter, r *http.Request) {
now := time.Now()
logf := logger.WithPrefix(h.logf, fmt.Sprintf("cert(%q): ", domain))
traceACME := func(v any) {
if !acmeDebug {
if !acmeDebug() {
return
}
j, _ := json.MarshalIndent(v, "", "\t")

@ -32,7 +32,7 @@ const (
versionKey = `SOFTWARE\Microsoft\Windows NT\CurrentVersion`
)
var configureWSL = envknob.Bool("TS_DEBUG_CONFIGURE_WSL")
var configureWSL = envknob.RegisterBool("TS_DEBUG_CONFIGURE_WSL")
type windowsManager struct {
logf logger.Logf
@ -359,7 +359,7 @@ func (m windowsManager) SetDNS(cfg OSConfig) error {
// On initial setup of WSL, the restart caused by --shutdown is slow,
// so we do it out-of-line.
if configureWSL {
if configureWSL() {
go func() {
if err := m.wslManager.SetDNS(cfg); err != nil {
m.logf("WSL SetDNS: %v", err) // continue

@ -484,13 +484,13 @@ func (f *forwarder) sendDoH(ctx context.Context, urlBase string, c *http.Client,
return res, err
}
var verboseDNSForward = envknob.Bool("TS_DEBUG_DNS_FORWARD_SEND")
var verboseDNSForward = envknob.RegisterBool("TS_DEBUG_DNS_FORWARD_SEND")
// send sends packet to dst. It is best effort.
//
// send expects the reply to have the same txid as txidOut.
func (f *forwarder) send(ctx context.Context, fq *forwardQuery, rr resolverAndDelay) (ret []byte, err error) {
if verboseDNSForward {
if verboseDNSForward() {
f.logf("forwarder.send(%q) ...", rr.name.Addr)
defer func() {
f.logf("forwarder.send(%q) = %v, %v", rr.name.Addr, len(ret), err)

@ -141,7 +141,7 @@ func (r *Resolver) ttl() time.Duration {
return 10 * time.Minute
}
var debug = envknob.Bool("TS_DEBUG_DNS_CACHE")
var debug = envknob.RegisterBool("TS_DEBUG_DNS_CACHE")
// LookupIP returns the host's primary IP address (either IPv4 or
// IPv6, but preferring IPv4) and optionally its IPv6 address, if
@ -167,14 +167,14 @@ func (r *Resolver) LookupIP(ctx context.Context, host string) (ip, v6 netip.Addr
}
if ip, err := netip.ParseAddr(host); err == nil {
ip = ip.Unmap()
if debug {
if debug() {
log.Printf("dnscache: %q is an IP", host)
}
return ip, zaddr, []netip.Addr{ip}, nil
}
if ip, ip6, allIPs, ok := r.lookupIPCache(host); ok {
if debug {
if debug() {
log.Printf("dnscache: %q = %v (cached)", host, ip)
}
return ip, ip6, allIPs, nil
@ -192,13 +192,13 @@ func (r *Resolver) LookupIP(ctx context.Context, host string) (ip, v6 netip.Addr
if res.Err != nil {
if r.UseLastGood {
if ip, ip6, allIPs, ok := r.lookupIPCacheExpired(host); ok {
if debug {
if debug() {
log.Printf("dnscache: %q using %v after error", host, ip)
}
return ip, ip6, allIPs, nil
}
}
if debug {
if debug() {
log.Printf("dnscache: error resolving %q: %v", host, res.Err)
}
return zaddr, zaddr, nil, res.Err
@ -206,7 +206,7 @@ func (r *Resolver) LookupIP(ctx context.Context, host string) (ip, v6 netip.Addr
r := res.Val
return r.ip, r.ip6, r.allIPs, nil
case <-ctx.Done():
if debug {
if debug() {
log.Printf("dnscache: context done while resolving %q: %v", host, ctx.Err())
}
return zaddr, zaddr, nil, ctx.Err()
@ -250,7 +250,7 @@ func (r *Resolver) lookupTimeoutForHost(host string) time.Duration {
func (r *Resolver) lookupIP(host string) (ip, ip6 netip.Addr, allIPs []netip.Addr, err error) {
if ip, ip6, allIPs, ok := r.lookupIPCache(host); ok {
if debug {
if debug() {
log.Printf("dnscache: %q found in cache as %v", host, ip)
}
return ip, ip6, allIPs, nil
@ -300,13 +300,13 @@ func (r *Resolver) addIPCache(host string, ip, ip6 netip.Addr, allIPs []netip.Ad
if ip.IsPrivate() {
// Don't cache obviously wrong entries from captive portals.
// TODO: use DoH or DoT for the forwarding resolver?
if debug {
if debug() {
log.Printf("dnscache: %q resolved to private IP %v; using but not caching", host, ip)
}
return
}
if debug {
if debug() {
log.Printf("dnscache: %q resolved to IP %v; caching", host, ip)
}
@ -382,7 +382,7 @@ func (d *dialer) DialContext(ctx context.Context, network, address string) (retC
}
i4s := v4addrs(allIPs)
if len(i4s) < 2 {
if debug {
if debug() {
log.Printf("dnscache: dialing %s, %s for %s", network, ip, address)
}
c, err := dc.dialOne(ctx, ip.Unmap())
@ -406,7 +406,7 @@ func (d *dialer) shouldTryBootstrap(ctx context.Context, err error, dc *dialCall
// Can't try bootstrap DNS if we don't have a fallback function
if d.dnsCache.LookupIPFallback == nil {
if debug {
if debug() {
log.Printf("dnscache: not using bootstrap DNS: no fallback")
}
return false
@ -415,7 +415,7 @@ func (d *dialer) shouldTryBootstrap(ctx context.Context, err error, dc *dialCall
// We can't retry if the context is canceled, since any further
// operations with this context will fail.
if ctxErr := ctx.Err(); ctxErr != nil {
if debug {
if debug() {
log.Printf("dnscache: not using bootstrap DNS: context error: %v", ctxErr)
}
return false
@ -423,7 +423,7 @@ func (d *dialer) shouldTryBootstrap(ctx context.Context, err error, dc *dialCall
wasTrustworthy := dc.dnsWasTrustworthy()
if wasTrustworthy {
if debug {
if debug() {
log.Printf("dnscache: not using bootstrap DNS: DNS was trustworthy")
}
return false

@ -167,10 +167,8 @@ func TestInterleaveSlices(t *testing.T) {
func TestShouldTryBootstrap(t *testing.T) {
oldDebug := debug
t.Cleanup(func() {
debug = oldDebug
})
debug = true
t.Cleanup(func() { debug = oldDebug })
debug = func() bool { return true }
type step struct {
ip netip.Addr // IP we pretended to dial

@ -43,7 +43,7 @@ import (
// Debugging and experimentation tweakables.
var (
debugNetcheck = envknob.Bool("TS_DEBUG_NETCHECK")
debugNetcheck = envknob.RegisterBool("TS_DEBUG_NETCHECK")
)
// The various default timeouts for things.
@ -210,7 +210,7 @@ func (c *Client) logf(format string, a ...any) {
}
func (c *Client) vlogf(format string, a ...any) {
if c.Verbose || debugNetcheck {
if c.Verbose || debugNetcheck() {
c.logf(format, a...)
}
}

@ -63,12 +63,12 @@ func socketMarkWorks() bool {
return true
}
var forceBindToDevice = envknob.Bool("TS_FORCE_LINUX_BIND_TO_DEVICE")
var forceBindToDevice = envknob.RegisterBool("TS_FORCE_LINUX_BIND_TO_DEVICE")
// UseSocketMark reports whether SO_MARK is in use.
// If it doesn't, we have to use SO_BINDTODEVICE on our sockets instead.
func UseSocketMark() bool {
if forceBindToDevice {
if forceBindToDevice() {
return false
}
socketMarkWorksOnce.Do(func() {

@ -32,7 +32,7 @@ var counterFallbackOK int32 // atomic
// See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format
var sslKeyLogFile = os.Getenv("SSLKEYLOGFILE")
var debug = envknob.Bool("TS_DEBUG_TLS_DIAL")
var debug = envknob.RegisterBool("TS_DEBUG_TLS_DIAL")
// Config returns a tls.Config for connecting to a server.
// If base is non-nil, it's cloned as the base config before
@ -77,7 +77,7 @@ func Config(host string, base *tls.Config) *tls.Config {
opts.Intermediates.AddCert(cert)
}
_, errSys := cs.PeerCertificates[0].Verify(opts)
if debug {
if debug() {
log.Printf("tlsdial(sys %q): %v", host, errSys)
}
if errSys == nil {
@ -88,7 +88,7 @@ func Config(host string, base *tls.Config) *tls.Config {
// or broken, fall back to trying LetsEncrypt at least.
opts.Roots = bakedInRoots()
_, err := cs.PeerCertificates[0].Verify(opts)
if debug {
if debug() {
log.Printf("tlsdial(bake %q): %v", host, err)
}
if err == nil {
@ -142,7 +142,7 @@ func SetConfigExpectedCert(c *tls.Config, certDNSName string) {
opts.Intermediates.AddCert(cert)
}
_, errSys := certs[0].Verify(opts)
if debug {
if debug() {
log.Printf("tlsdial(sys %q/%q): %v", c.ServerName, certDNSName, errSys)
}
if errSys == nil {
@ -150,7 +150,7 @@ func SetConfigExpectedCert(c *tls.Config, certDNSName string) {
}
opts.Roots = bakedInRoots()
_, err := certs[0].Verify(opts)
if debug {
if debug() {
log.Printf("tlsdial(bake %q/%q): %v", c.ServerName, certDNSName, err)
}
if err == nil {

@ -20,14 +20,6 @@ import (
"tailscale.com/types/logger"
)
var tunMTU = DefaultMTU
func init() {
if mtu, ok := envknob.LookupInt("TS_DEBUG_MTU"); ok {
tunMTU = mtu
}
}
// createTAP is non-nil on Linux.
var createTAP func(tapName, bridgeName string) (tun.Device, error)
@ -52,6 +44,10 @@ func New(logf logger.Logf, tunName string) (tun.Device, string, error) {
}
dev, err = createTAP(tapName, bridgeName)
} else {
tunMTU := DefaultMTU
if mtu, ok := envknob.LookupInt("TS_DEBUG_MTU"); ok {
tunMTU = mtu
}
dev, err = tun.CreateTUN(tunName, tunMTU)
}
if err != nil {

@ -74,10 +74,10 @@ func (pl List) String() string {
return strings.TrimRight(sb.String(), "\n")
}
var debugDisablePortlist = envknob.Bool("TS_DEBUG_DISABLE_PORTLIST")
var debugDisablePortlist = envknob.RegisterBool("TS_DEBUG_DISABLE_PORTLIST")
func GetList(prev List) (List, error) {
if debugDisablePortlist {
if debugDisablePortlist() {
return nil, nil
}
pl, err := listPorts()

@ -46,9 +46,7 @@ import (
)
var (
debugPolicyFile = envknob.SSHPolicyFile()
debugIgnoreTailnetSSHPolicy = envknob.SSHIgnoreTailnetPolicy()
sshVerboseLogging = envknob.Bool("TS_DEBUG_SSH_VLOG")
sshVerboseLogging = envknob.RegisterBool("TS_DEBUG_SSH_VLOG")
)
type server struct {
@ -384,9 +382,10 @@ func (c *conn) sshPolicy() (_ *tailcfg.SSHPolicy, ok bool) {
if nm == nil {
return nil, false
}
if pol := nm.SSHPolicy; pol != nil && !debugIgnoreTailnetSSHPolicy {
if pol := nm.SSHPolicy; pol != nil && !envknob.SSHIgnoreTailnetPolicy() {
return pol, true
}
debugPolicyFile := envknob.SSHPolicyFile()
if debugPolicyFile != "" {
c.logf("reading debug SSH policy file: %v", debugPolicyFile)
f, err := os.ReadFile(debugPolicyFile)
@ -769,7 +768,7 @@ type sshSession struct {
}
func (ss *sshSession) vlogf(format string, args ...interface{}) {
if sshVerboseLogging {
if sshVerboseLogging() {
ss.logf(format, args...)
}
}
@ -952,7 +951,7 @@ func (ss *sshSession) handleSSHAgentForwarding(s ssh.Session, lu *user.User) err
// functionality and support off-node streaming.
//
// TODO(bradfitz,maisem): move this to SSHPolicy.
var recordSSH = envknob.Bool("TS_DEBUG_LOG_SSH")
var recordSSH = envknob.RegisterBool("TS_DEBUG_LOG_SSH")
// run is the entrypoint for a newly accepted SSH session.
//
@ -1092,7 +1091,7 @@ func (ss *sshSession) shouldRecord() bool {
// TODO(bradfitz,maisem): make configurable on SSHPolicy and
// support recording non-pty stuff too.
_, _, isPtyReq := ss.Pty()
return recordSSH && isPtyReq
return recordSSH() && isPtyReq
}
type sshConnInfo struct {

@ -129,8 +129,6 @@ type limitData struct {
ele *list.Element // list element used to access this string in the cache
}
var disableRateLimit = envknob.String("TS_DEBUG_LOG_RATE") == "all"
// rateFree are format string substrings that are exempt from rate limiting.
// Things should not be added to this unless they're already limited otherwise
// or are critical for generating important stats from the logs.
@ -156,7 +154,7 @@ func RateLimitedFn(logf Logf, f time.Duration, burst int, maxCache int) Logf {
// timeNow is a function that returns the current time, used for calculating
// rate limits.
func RateLimitedFnWithClock(logf Logf, f time.Duration, burst int, maxCache int, timeNow func() time.Time) Logf {
if disableRateLimit {
if envknob.String("TS_DEBUG_LOG_RATE") == "all" {
return logf
}
var (

@ -11,28 +11,30 @@ import (
"tailscale.com/envknob"
)
const linkDebug = true
// Various debugging and experimental tweakables, set by environment
// variable.
var (
// debugDisco prints verbose logs of active discovery events as
// they happen.
debugDisco = envknob.Bool("TS_DEBUG_DISCO")
debugDisco = envknob.RegisterBool("TS_DEBUG_DISCO")
// debugOmitLocalAddresses removes all local interface addresses
// from magicsock's discovered local endpoints. Used in some tests.
debugOmitLocalAddresses = envknob.Bool("TS_DEBUG_OMIT_LOCAL_ADDRS")
debugOmitLocalAddresses = envknob.RegisterBool("TS_DEBUG_OMIT_LOCAL_ADDRS")
// debugUseDerpRoute temporarily (2020-03-22) controls whether DERP
// reverse routing is enabled (Issue 150).
debugUseDerpRoute = envknob.OptBool("TS_DEBUG_ENABLE_DERP_ROUTE")
debugUseDerpRoute = envknob.RegisterOptBool("TS_DEBUG_ENABLE_DERP_ROUTE")
// logDerpVerbose logs all received DERP packets, including their
// full payload.
logDerpVerbose = envknob.Bool("TS_DEBUG_DERP")
logDerpVerbose = envknob.RegisterBool("TS_DEBUG_DERP")
// debugReSTUNStopOnIdle unconditionally enables the "shut down
// STUN if magicsock is idle" behavior that normally only triggers
// on mobile devices, lowers the shutdown interval, and logs more
// verbosely about idle measurements.
debugReSTUNStopOnIdle = envknob.Bool("TS_DEBUG_RESTUN_STOP_ON_IDLE")
debugReSTUNStopOnIdle = envknob.RegisterBool("TS_DEBUG_RESTUN_STOP_ON_IDLE")
// debugAlwaysDERP disables the use of UDP, forcing all peer communication over DERP.
debugAlwaysDERP = envknob.Bool("TS_DEBUG_ALWAYS_USE_DERP")
debugAlwaysDERP = envknob.RegisterBool("TS_DEBUG_ALWAYS_USE_DERP")
)
// inTest reports whether the running program is a test that set the

@ -10,15 +10,15 @@ package magicsock
import "tailscale.com/types/opt"
// All knobs are disabled on iOS and Wasm.
// Further, they're const, so the toolchain can produce smaller binaries.
const (
debugDisco = false
debugOmitLocalAddresses = false
debugUseDerpRouteEnv = ""
debugUseDerpRoute opt.Bool = ""
logDerpVerbose = false
debugReSTUNStopOnIdle = false
debugAlwaysDERP = false
)
//
// They're inlinable and the linker can deadcode that's guarded by them to make
// smaller binaries.
func debugDisco() bool { return false }
func debugOmitLocalAddresses() bool { return false }
func logDerpVerbose() bool { return false }
func debugReSTUNStopOnIdle() bool { return false }
func debugAlwaysDERP() bool { return false }
func debugUseDerpRouteEnv() string { return "" }
func debugUseDerpRoute() opt.Bool { return "" }
func inTest() bool { return false }

@ -74,7 +74,7 @@ const (
// useDerpRoute reports whether magicsock should enable the DERP
// return path optimization (Issue 150).
func useDerpRoute() bool {
if b, ok := debugUseDerpRoute.Get(); ok {
if b, ok := debugUseDerpRoute().Get(); ok {
return b
}
ob := controlclient.DERPRouteFlag()
@ -638,18 +638,18 @@ func (c *Conn) updateEndpoints(why string) {
// etc)
d := tstime.RandomDurationBetween(20*time.Second, 26*time.Second)
if t := c.periodicReSTUNTimer; t != nil {
if debugReSTUNStopOnIdle {
if debugReSTUNStopOnIdle() {
c.logf("resetting existing periodicSTUN to run in %v", d)
}
t.Reset(d)
} else {
if debugReSTUNStopOnIdle {
if debugReSTUNStopOnIdle() {
c.logf("scheduling periodicSTUN to run in %v", d)
}
c.periodicReSTUNTimer = time.AfterFunc(d, c.doPeriodicSTUN)
}
} else {
if debugReSTUNStopOnIdle {
if debugReSTUNStopOnIdle() {
c.logf("periodic STUN idle")
}
c.stopPeriodicReSTUNTimerLocked()
@ -1074,7 +1074,7 @@ func (c *Conn) determineEndpoints(ctx context.Context) ([]tailcfg.Endpoint, erro
return
}
addAddr := func(ipp netip.AddrPort, et tailcfg.EndpointType) {
if !ipp.IsValid() || (debugOmitLocalAddresses && et == tailcfg.EndpointLocal) {
if !ipp.IsValid() || (debugOmitLocalAddresses() && et == tailcfg.EndpointLocal) {
return
}
if _, ok := already[ipp]; !ok {
@ -1575,7 +1575,7 @@ func (c *Conn) runDerpReader(ctx context.Context, derpFakeAddr netip.AddrPort, d
pkt = m
res.n = len(m.Data)
res.src = m.Source
if logDerpVerbose {
if logDerpVerbose() {
c.logf("magicsock: got derp-%v packet: %q", regionID, m.Data)
}
// If this is a new sender we hadn't seen before, remember it and
@ -1826,7 +1826,7 @@ func (c *Conn) sendDiscoMessage(dst netip.AddrPort, dstKey key.NodePublic, dstDi
pkt = append(pkt, box...)
sent, err = c.sendAddr(dst, dstKey, pkt)
if sent {
if logLevel == discoLog || (logLevel == discoVerboseLog && debugDisco) {
if logLevel == discoLog || (logLevel == discoVerboseLog && debugDisco()) {
node := "?"
if !dstKey.IsZero() {
node = dstKey.ShortString()
@ -1890,7 +1890,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netip.AddrPort, derpNodeSrc ke
if c.closed {
return
}
if debugDisco {
if debugDisco() {
c.logf("magicsock: disco: got disco-looking frame from %v", sender.ShortString())
}
if c.privateKey.IsZero() {
@ -1899,7 +1899,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netip.AddrPort, derpNodeSrc ke
return
}
if c.discoPrivate.IsZero() {
if debugDisco {
if debugDisco() {
c.logf("magicsock: disco: ignoring disco-looking frame, no local key")
}
return
@ -1907,7 +1907,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netip.AddrPort, derpNodeSrc ke
if !c.peerMap.anyEndpointForDiscoKey(sender) {
metricRecvDiscoBadPeer.Add(1)
if debugDisco {
if debugDisco() {
c.logf("magicsock: disco: ignoring disco-looking frame, don't know endpoint for %v", sender.ShortString())
}
return
@ -1931,7 +1931,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netip.AddrPort, derpNodeSrc ke
// Don't log in normal case. Pass on to wireguard, in case
// it's actually a wireguard packet (super unlikely,
// but).
if debugDisco {
if debugDisco() {
c.logf("magicsock: disco: failed to open naclbox from %v (wrong rcpt?)", sender)
}
metricRecvDiscoBadKey.Add(1)
@ -1939,7 +1939,7 @@ func (c *Conn) handleDiscoMessage(msg []byte, src netip.AddrPort, derpNodeSrc ke
}
dm, err := disco.Parse(payload)
if debugDisco {
if debugDisco() {
c.logf("magicsock: disco: disco.Parse = %T, %v", dm, err)
}
if err != nil {
@ -2094,7 +2094,7 @@ func (c *Conn) handlePingLocked(dm *disco.Ping, src netip.AddrPort, di *discoInf
return
}
if !likelyHeartBeat || debugDisco {
if !likelyHeartBeat || debugDisco() {
pingNodeSrcStr := dstKey.ShortString()
if numNodes > 1 {
pingNodeSrcStr = "[one-of-multi]"
@ -2381,7 +2381,7 @@ func (c *Conn) SetNetworkMap(nm *netmap.NetworkMap) {
}
ep.wgEndpoint = n.Key.UntypedHexString()
ep.initFakeUDPAddr()
if debugDisco { // rather than making a new knob
if debugDisco() { // rather than making a new knob
c.logf("magicsock: created endpoint key=%s: disco=%s; %v", n.Key.ShortString(), n.DiscoKey.ShortString(), logger.ArgWriter(func(w *bufio.Writer) {
const derpPrefix = "127.3.3.40:"
if strings.HasPrefix(n.DERP, derpPrefix) {
@ -2736,7 +2736,7 @@ func (c *Conn) goroutinesRunningLocked() bool {
}
func maxIdleBeforeSTUNShutdown() time.Duration {
if debugReSTUNStopOnIdle {
if debugReSTUNStopOnIdle() {
return 45 * time.Second
}
return sessionActiveTimeout
@ -2753,7 +2753,7 @@ func (c *Conn) shouldDoPeriodicReSTUNLocked() bool {
}
if f := c.idleFunc; f != nil {
idleFor := f()
if debugReSTUNStopOnIdle {
if debugReSTUNStopOnIdle() {
c.logf("magicsock: periodicReSTUN: idle for %v", idleFor.Round(time.Second))
}
if idleFor > maxIdleBeforeSTUNShutdown() {
@ -2834,7 +2834,7 @@ func (c *Conn) bindSocket(ruc *RebindingUDPConn, network string, curPortFate cur
return nil
}
if debugAlwaysDERP {
if debugAlwaysDERP() {
c.logf("disabled %v per TS_DEBUG_ALWAYS_USE_DERP", network)
ruc.setConnLocked(newBlockForeverConn())
return nil
@ -3626,7 +3626,7 @@ func (de *endpoint) pingTimeout(txid stun.TxID) {
if !ok {
return
}
if debugDisco || !de.bestAddr.IsValid() || mono.Now().After(de.trustBestAddrUntil) {
if debugDisco() || !de.bestAddr.IsValid() || mono.Now().After(de.trustBestAddrUntil) {
de.c.logf("[v1] magicsock: disco: timeout waiting for pong %x from %v (%v, %v)", txid[:6], sp.to, de.publicKey.ShortString(), de.discoShort)
}
de.removeSentPingLocked(txid, sp)

@ -28,7 +28,7 @@ const (
)
// Enable/disable using raw sockets to receive disco traffic.
var debugDisableRawDisco = envknob.Bool("TS_DEBUG_DISABLE_RAW_DISCO")
var debugDisableRawDisco = envknob.RegisterBool("TS_DEBUG_DISABLE_RAW_DISCO")
// These are our BPF filters that we use for testing packets.
var (
@ -125,7 +125,7 @@ var (
// and BPF filter.
// https://github.com/tailscale/tailscale/issues/3824
func (c *Conn) listenRawDisco(family string) (io.Closer, error) {
if debugDisableRawDisco {
if debugDisableRawDisco() {
return nil, errors.New("raw disco listening disabled by debug flag")
}

@ -20,7 +20,7 @@ import (
"tailscale.com/types/logger"
)
var debugNetlinkMessages = envknob.Bool("TS_DEBUG_NETLINK")
var debugNetlinkMessages = envknob.RegisterBool("TS_DEBUG_NETLINK")
// unspecifiedMessage is a minimal message implementation that should not
// be ignored. In general, OS-specific implementations should use better
@ -96,7 +96,7 @@ func (c *nlConn) Receive() (message, error) {
nip := netaddrIP(rmsg.Attributes.Address)
if debugNetlinkMessages {
if debugNetlinkMessages() {
typ := "RTM_NEWADDR"
if msg.Header.Type == unix.RTM_DELADDR {
typ = "RTM_DELADDR"
@ -125,7 +125,7 @@ func (c *nlConn) Receive() (message, error) {
}
if addrs[nip] {
if debugNetlinkMessages {
if debugNetlinkMessages() {
c.logf("ignored duplicate RTM_NEWADDR for %s", nip)
}
return ignoreMessage{}, nil
@ -147,7 +147,7 @@ func (c *nlConn) Receive() (message, error) {
Addr: nip,
Delete: msg.Header.Type == unix.RTM_DELADDR,
}
if debugNetlinkMessages {
if debugNetlinkMessages() {
c.logf("%+v", nam)
}
return nam, nil
@ -169,7 +169,7 @@ func (c *nlConn) Receive() (message, error) {
(rmsg.Attributes.Table == 255 || rmsg.Attributes.Table == 254) &&
(dst.Addr().IsMulticast() || dst.Addr().IsLinkLocalUnicast()) {
if debugNetlinkMessages {
if debugNetlinkMessages() {
c.logf("%s ignored", typeStr)
}
@ -202,7 +202,7 @@ func (c *nlConn) Receive() (message, error) {
Dst: dst,
Gateway: gw,
}
if debugNetlinkMessages {
if debugNetlinkMessages() {
c.logf("%+v", nrm)
}
return nrm, nil
@ -225,7 +225,7 @@ func (c *nlConn) Receive() (message, error) {
table: rmsg.Table,
priority: rmsg.Attributes.Priority,
}
if debugNetlinkMessages {
if debugNetlinkMessages() {
c.logf("%+v", rdm)
}
return rdm, nil

@ -55,7 +55,7 @@ import (
const debugPackets = false
var debugNetstack = envknob.Bool("TS_DEBUG_NETSTACK")
var debugNetstack = envknob.RegisterBool("TS_DEBUG_NETSTACK")
var (
magicDNSIP = tsaddr.TailscaleServiceIP()
@ -638,7 +638,7 @@ func (ns *Impl) userPing(dstIP netip.Addr, pingResPkt []byte) {
}
return
}
if debugNetstack {
if debugNetstack() {
ns.logf("exec pinged %v in %v", dstIP, time.Since(t0))
}
if err := ns.tundev.InjectOutbound(pingResPkt); err != nil {
@ -718,7 +718,7 @@ func netaddrIPFromNetstackIP(s tcpip.Address) netip.Addr {
func (ns *Impl) acceptTCP(r *tcp.ForwarderRequest) {
reqDetails := r.ID()
if debugNetstack {
if debugNetstack() {
ns.logf("[v2] TCP ForwarderRequest: %s", stringifyTEI(reqDetails))
}
clientRemoteIP := netaddrIPFromNetstackIP(reqDetails.RemoteAddress)
@ -849,7 +849,7 @@ func (ns *Impl) acceptTCP(r *tcp.ForwarderRequest) {
func (ns *Impl) forwardTCP(getClient func() *gonet.TCPConn, clientRemoteIP netip.Addr, wq *waiter.Queue, dialAddr netip.AddrPort) (handled bool) {
dialAddrStr := dialAddr.String()
if debugNetstack {
if debugNetstack() {
ns.logf("[v2] netstack: forwarding incoming connection to %s", dialAddrStr)
}
@ -866,7 +866,7 @@ func (ns *Impl) forwardTCP(getClient func() *gonet.TCPConn, clientRemoteIP netip
go func() {
select {
case <-notifyCh:
if debugNetstack {
if debugNetstack() {
ns.logf("[v2] netstack: forwardTCP notifyCh fired; canceling context for %s", dialAddrStr)
}
case <-done:
@ -919,7 +919,7 @@ func (ns *Impl) forwardTCP(getClient func() *gonet.TCPConn, clientRemoteIP netip
func (ns *Impl) acceptUDP(r *udp.ForwarderRequest) {
sess := r.ID()
if debugNetstack {
if debugNetstack() {
ns.logf("[v2] UDP ForwarderRequest: %v", stringifyTEI(sess))
}
var wq waiter.Queue
@ -995,7 +995,7 @@ func (ns *Impl) handleMagicDNSUDP(srcAddr netip.AddrPort, c *gonet.UDPConn) {
// proxy to it directly.
func (ns *Impl) forwardUDP(client *gonet.UDPConn, wq *waiter.Queue, clientAddr, dstAddr netip.AddrPort) {
port, srcPort := dstAddr.Port(), clientAddr.Port()
if debugNetstack {
if debugNetstack() {
ns.logf("[v2] netstack: forwarding incoming UDP connection on port %v", port)
}
@ -1071,7 +1071,7 @@ func (ns *Impl) forwardUDP(client *gonet.UDPConn, wq *waiter.Queue, clientAddr,
}
func startPacketCopy(ctx context.Context, cancel context.CancelFunc, dst net.PacketConn, dstAddr net.Addr, src net.PacketConn, logf logger.Logf, extend func()) {
if debugNetstack {
if debugNetstack() {
logf("[v2] netstack: startPacketCopy to %v (%T) from %T", dstAddr, dst, src)
}
go func() {
@ -1096,7 +1096,7 @@ func startPacketCopy(ctx context.Context, cancel context.CancelFunc, dst net.Pac
}
return
}
if debugNetstack {
if debugNetstack() {
logf("[v2] wrote UDP packet %s -> %s", srcAddr, dstAddr)
}
extend()

@ -316,7 +316,7 @@ func useAmbientCaps() bool {
return distro.DSMVersion() >= 7
}
var forceIPCommand = envknob.Bool("TS_DEBUG_USE_IP_COMMAND")
var forceIPCommand = envknob.RegisterBool("TS_DEBUG_USE_IP_COMMAND")
// useIPCommand reports whether r should use the "ip" command (or its
// fake commandRunner for tests) instead of netlink.
@ -324,7 +324,7 @@ func (r *linuxRouter) useIPCommand() bool {
if r.cmd == nil {
panic("invalid init")
}
if forceIPCommand {
if forceIPCommand() {
return true
}
// In the future we might need to fall back to using the "ip"

@ -534,7 +534,7 @@ func (e *userspaceEngine) pollResolver() {
}
}
var debugTrimWireguard = envknob.OptBool("TS_DEBUG_TRIM_WIREGUARD")
var debugTrimWireguard = envknob.RegisterOptBool("TS_DEBUG_TRIM_WIREGUARD")
// forceFullWireguardConfig reports whether we should give wireguard our full
// network map, even for inactive peers.
@ -550,7 +550,7 @@ var debugTrimWireguard = envknob.OptBool("TS_DEBUG_TRIM_WIREGUARD")
// with these knobs in place.
func forceFullWireguardConfig(numPeers int) bool {
// Did the user explicitly enable trimmming via the environment variable knob?
if b, ok := debugTrimWireguard.Get(); ok {
if b, ok := debugTrimWireguard().Get(); ok {
return !b
}
if opt := controlclient.TrimWGConfig(); opt != "" {

Loading…
Cancel
Save