From 41fd4eab5c13b12dbafc16a4496af63f20432d03 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 24 Jan 2022 10:52:57 -0800 Subject: [PATCH] envknob: add new package for all the strconv.ParseBool(os.Getenv(..)) A new package can also later record/report which knobs are checked and set. It also makes the code cleaner & easier to grep for env knobs. Change-Id: Id8a123ab7539f1fadbd27e0cbeac79c2e4f09751 Signed-off-by: Brad Fitzpatrick --- cmd/tailscale/cli/file.go | 4 +- cmd/tailscale/cli/netcheck.go | 4 +- cmd/tailscale/depaware.txt | 1 + cmd/tailscaled/debug.go | 3 +- cmd/tailscaled/depaware.txt | 1 + cmd/tailscaled/tailscaled.go | 14 +-- cmd/tailscaled/tailscaled_windows.go | 3 +- control/controlclient/direct.go | 28 ++--- control/controlclient/map.go | 5 +- control/controlknobs/controlknobs.go | 7 +- derp/derp_server.go | 6 +- derp/derphttp/derphttp_client.go | 6 +- envknob/envknob.go | 102 ++++++++++++++++++ health/health.go | 4 +- ipn/ipnlocal/local.go | 5 +- ipn/localapi/cert.go | 4 +- logpolicy/logpolicy.go | 8 +- net/dns/manager_windows.go | 5 +- net/dnscache/dnscache.go | 5 +- net/netcheck/netcheck.go | 5 +- net/tlsdial/tlsdial.go | 5 +- net/tstun/tun.go | 5 +- portlist/portlist.go | 6 +- scripts/check_license_headers.sh | 2 +- .../tailscaled_deps_test_darwin.go | 1 + .../tailscaled_deps_test_freebsd.go | 1 + .../integration/tailscaled_deps_test_linux.go | 1 + .../tailscaled_deps_test_openbsd.go | 1 + .../tailscaled_deps_test_windows.go | 1 + tsweb/tsweb.go | 5 +- types/logger/logger.go | 5 +- wgengine/filter/filter.go | 4 +- wgengine/magicsock/debugknobs.go | 24 ++--- wgengine/magicsock/magicsock.go | 4 +- wgengine/netstack/netstack.go | 3 +- wgengine/pendopen.go | 13 --- wgengine/router/router_linux.go | 3 +- wgengine/userspace.go | 14 +-- wgengine/watchdog.go | 5 +- 39 files changed, 195 insertions(+), 128 deletions(-) create mode 100644 envknob/envknob.go diff --git a/cmd/tailscale/cli/file.go b/cmd/tailscale/cli/file.go index 775c44933..64bde3134 100644 --- a/cmd/tailscale/cli/file.go +++ b/cmd/tailscale/cli/file.go @@ -16,7 +16,6 @@ import ( "net/http" "os" "path/filepath" - "strconv" "strings" "time" "unicode/utf8" @@ -26,6 +25,7 @@ import ( "inet.af/netaddr" "tailscale.com/client/tailscale" "tailscale.com/client/tailscale/apitype" + "tailscale.com/envknob" "tailscale.com/ipn" "tailscale.com/net/tsaddr" "tailscale.com/tailcfg" @@ -148,7 +148,7 @@ func runCp(ctx context.Context, args []string) error { name = filepath.Base(fileArg) } - if slow, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_SLOW_PUSH")); slow { + if envknob.Bool("TS_DEBUG_SLOW_PUSH") { fileContents = &slowReader{r: fileContents} } } diff --git a/cmd/tailscale/cli/netcheck.go b/cmd/tailscale/cli/netcheck.go index 59e8bc256..30f7a58bf 100644 --- a/cmd/tailscale/cli/netcheck.go +++ b/cmd/tailscale/cli/netcheck.go @@ -13,13 +13,13 @@ import ( "io/ioutil" "log" "net/http" - "os" "sort" "strings" "time" "github.com/peterbourgon/ff/v3/ffcli" "tailscale.com/client/tailscale" + "tailscale.com/envknob" "tailscale.com/ipn" "tailscale.com/net/netcheck" "tailscale.com/net/portmapper" @@ -49,7 +49,7 @@ var netcheckArgs struct { func runNetcheck(ctx context.Context, args []string) error { c := &netcheck.Client{ - UDPBindAddr: os.Getenv("TS_DEBUG_NETCHECK_UDP_BIND"), + UDPBindAddr: envknob.String("TS_DEBUG_NETCHECK_UDP_BIND"), PortMapper: portmapper.NewClient(logger.WithPrefix(log.Printf, "portmap: "), nil), } if netcheckArgs.verbose { diff --git a/cmd/tailscale/depaware.txt b/cmd/tailscale/depaware.txt index 0f303b086..cbc65aa61 100644 --- a/cmd/tailscale/depaware.txt +++ b/cmd/tailscale/depaware.txt @@ -38,6 +38,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep tailscale.com/derp/derphttp from tailscale.com/net/netcheck L tailscale.com/derp/wsconn from tailscale.com/derp/derphttp tailscale.com/disco from tailscale.com/derp + tailscale.com/envknob from tailscale.com/cmd/tailscale/cli+ tailscale.com/hostinfo from tailscale.com/net/interfaces tailscale.com/ipn from tailscale.com/cmd/tailscale/cli+ tailscale.com/ipn/ipnstate from tailscale.com/cmd/tailscale/cli+ diff --git a/cmd/tailscaled/debug.go b/cmd/tailscaled/debug.go index 596b00b11..e51111c90 100644 --- a/cmd/tailscaled/debug.go +++ b/cmd/tailscaled/debug.go @@ -24,6 +24,7 @@ import ( "inet.af/netaddr" "tailscale.com/derp/derphttp" + "tailscale.com/envknob" "tailscale.com/ipn" "tailscale.com/net/interfaces" "tailscale.com/net/portmapper" @@ -224,7 +225,7 @@ func debugPortmap(ctx context.Context) error { defer cancel() portmapper.VerboseLogs = true - switch os.Getenv("TS_DEBUG_PORTMAP_TYPE") { + switch envknob.String("TS_DEBUG_PORTMAP_TYPE") { case "": case "pmp": portmapper.DisablePCP = true diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index 823d161e1..1107d3bcc 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -171,6 +171,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/derp/derphttp from tailscale.com/cmd/tailscaled+ L tailscale.com/derp/wsconn from tailscale.com/derp/derphttp tailscale.com/disco from tailscale.com/derp+ + tailscale.com/envknob from tailscale.com/cmd/tailscaled+ tailscale.com/health from tailscale.com/control/controlclient+ tailscale.com/hostinfo from tailscale.com/control/controlclient+ tailscale.com/ipn from tailscale.com/client/tailscale+ diff --git a/cmd/tailscaled/tailscaled.go b/cmd/tailscaled/tailscaled.go index bcd5501d5..1fc47bf69 100644 --- a/cmd/tailscaled/tailscaled.go +++ b/cmd/tailscaled/tailscaled.go @@ -23,12 +23,12 @@ import ( "path/filepath" "runtime" "runtime/debug" - "strconv" "strings" "syscall" "time" "inet.af/netaddr" + "tailscale.com/envknob" "tailscale.com/ipn" "tailscale.com/ipn/ipnserver" "tailscale.com/logpolicy" @@ -224,7 +224,7 @@ func statePathOrDefault() string { 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") + goos := envknob.String("TS_DEBUG_TAILSCALED_IPN_GOOS") if goos == "" { goos = runtime.GOOS } @@ -272,13 +272,13 @@ func run() error { } var logf logger.Logf = log.Printf - if v, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_MEMORY")); v { + if envknob.Bool("TS_DEBUG_MEMORY") { logf = logger.RusagePrefixLog(logf) } logf = logger.RateLimitedFn(logf, 5*time.Second, 5, 100) if args.cleanup { - if os.Getenv("TS_PLEASE_PANIC") != "" { + if envknob.Bool("TS_PLEASE_PANIC") { panic("TS_PLEASE_PANIC asked us to panic") } dns.Cleanup(logf, args.tunname) @@ -431,11 +431,7 @@ func createEngine(logf logger.Logf, linkMon *monitor.Mon, dialer *tsdial.Dialer) 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) - } + if v, ok := envknob.LookupBool("TS_DEBUG_WRAP_NETSTACK"); ok { return v } if distro.Get() == distro.Synology { diff --git a/cmd/tailscaled/tailscaled_windows.go b/cmd/tailscaled/tailscaled_windows.go index 3f41f9560..b886343c3 100644 --- a/cmd/tailscaled/tailscaled_windows.go +++ b/cmd/tailscaled/tailscaled_windows.go @@ -29,6 +29,7 @@ import ( "golang.org/x/sys/windows/svc" "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" "inet.af/netaddr" + "tailscale.com/envknob" "tailscale.com/ipn/ipnserver" "tailscale.com/logpolicy" "tailscale.com/net/dns" @@ -314,7 +315,7 @@ func startIPNServer(ctx context.Context, logid string) error { // not called concurrently and is not called again once it // successfully returns an engine. getEngine := func() (wgengine.Engine, error) { - if msg := os.Getenv("TS_DEBUG_WIN_FAIL"); msg != "" { + if msg := envknob.String("TS_DEBUG_WIN_FAIL"); msg != "" { return nil, fmt.Errorf("pretending to be a service failure: %v", msg) } for { diff --git a/control/controlclient/direct.go b/control/controlclient/direct.go index 82b0f8229..78077137a 100644 --- a/control/controlclient/direct.go +++ b/control/controlclient/direct.go @@ -21,7 +21,6 @@ import ( "os/exec" "reflect" "runtime" - "strconv" "strings" "sync" "sync/atomic" @@ -30,6 +29,7 @@ import ( "go4.org/mem" "inet.af/netaddr" "tailscale.com/control/controlknobs" + "tailscale.com/envknob" "tailscale.com/health" "tailscale.com/hostinfo" "tailscale.com/ipn/ipnstate" @@ -874,8 +874,8 @@ func decode(res *http.Response, v interface{}, serverKey key.MachinePublic, mkey } var ( - debugMap, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_MAP")) - debugRegister, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_REGISTER")) + debugMap = envknob.Bool("TS_DEBUG_MAP") + debugRegister = envknob.Bool("TS_DEBUG_REGISTER") ) var jsonEscapedZero = []byte(`\u0000`) @@ -985,26 +985,14 @@ type debug struct { func initDebug() debug { return debug{ - NetMap: envBool("TS_DEBUG_NETMAP"), - ProxyDNS: envBool("TS_DEBUG_PROXY_DNS"), - StripEndpoints: envBool("TS_DEBUG_STRIP_ENDPOINTS"), - StripCaps: envBool("TS_DEBUG_STRIP_CAPS"), - Disco: os.Getenv("TS_DEBUG_USE_DISCO") == "" || envBool("TS_DEBUG_USE_DISCO"), + NetMap: envknob.Bool("TS_DEBUG_NETMAP"), + ProxyDNS: envknob.Bool("TS_DEBUG_PROXY_DNS"), + StripEndpoints: envknob.Bool("TS_DEBUG_STRIP_ENDPOINTS"), + StripCaps: envknob.Bool("TS_DEBUG_STRIP_CAPS"), + Disco: envknob.BoolDefaultTrue("TS_DEBUG_USE_DISCO"), } } -func envBool(k string) bool { - e := os.Getenv(k) - if e == "" { - return false - } - v, err := strconv.ParseBool(e) - if err != nil { - panic(fmt.Sprintf("invalid non-bool %q for env var %q", e, k)) - } - return v -} - var clockNow = time.Now // opt.Bool configs from control. diff --git a/control/controlclient/map.go b/control/controlclient/map.go index 80db55259..b7ba87957 100644 --- a/control/controlclient/map.go +++ b/control/controlclient/map.go @@ -6,11 +6,10 @@ package controlclient import ( "log" - "os" "sort" - "strconv" "inet.af/netaddr" + "tailscale.com/envknob" "tailscale.com/tailcfg" "tailscale.com/types/key" "tailscale.com/types/logger" @@ -289,7 +288,7 @@ func cloneNodes(v1 []*tailcfg.Node) []*tailcfg.Node { return v2 } -var debugSelfIPv6Only, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_SELF_V6_ONLY")) +var debugSelfIPv6Only = envknob.Bool("TS_DEBUG_SELF_V6_ONLY") func filterSelfAddresses(in []netaddr.IPPrefix) (ret []netaddr.IPPrefix) { switch { diff --git a/control/controlknobs/controlknobs.go b/control/controlknobs/controlknobs.go index 84d71fdf2..5c3c3865c 100644 --- a/control/controlknobs/controlknobs.go +++ b/control/controlknobs/controlknobs.go @@ -7,9 +7,7 @@ package controlknobs import ( - "os" - "strconv" - + "tailscale.com/envknob" "tailscale.com/syncs" ) @@ -17,8 +15,7 @@ import ( var disableUPnP syncs.AtomicBool func init() { - v, _ := strconv.ParseBool(os.Getenv("TS_DISABLE_UPNP")) - SetDisableUPnP(v) + SetDisableUPnP(envknob.Bool("TS_DISABLE_UPNP")) } // DisableUPnP reports the last reported value from control diff --git a/derp/derp_server.go b/derp/derp_server.go index 6b92619aa..9d522ece9 100644 --- a/derp/derp_server.go +++ b/derp/derp_server.go @@ -25,7 +25,6 @@ import ( "math/rand" "net" "net/http" - "os" "os/exec" "runtime" "strconv" @@ -40,6 +39,7 @@ import ( "inet.af/netaddr" "tailscale.com/client/tailscale" "tailscale.com/disco" + "tailscale.com/envknob" "tailscale.com/metrics" "tailscale.com/syncs" "tailscale.com/types/key" @@ -48,14 +48,14 @@ import ( "tailscale.com/version" ) -var debug, _ = strconv.ParseBool(os.Getenv("DERP_DEBUG_LOGS")) +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{} func init() { - keys := os.Getenv("TS_DEBUG_VERBOSE_DROPS") + keys := envknob.String("TS_DEBUG_VERBOSE_DROPS") if keys == "" { return } diff --git a/derp/derphttp/derphttp_client.go b/derp/derphttp/derphttp_client.go index 6d1e84ac4..1e47e1e13 100644 --- a/derp/derphttp/derphttp_client.go +++ b/derp/derphttp/derphttp_client.go @@ -23,9 +23,7 @@ import ( "net" "net/http" "net/url" - "os" "runtime" - "strconv" "strings" "sync" "time" @@ -33,6 +31,7 @@ import ( "go4.org/mem" "inet.af/netaddr" "tailscale.com/derp" + "tailscale.com/envknob" "tailscale.com/net/dnscache" "tailscale.com/net/netns" "tailscale.com/net/tlsdial" @@ -190,8 +189,7 @@ func useWebsockets() bool { return true } if dialWebsocketFunc != nil { - v, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_DERP_WS_CLIENT")) - return v + return envknob.Bool("TS_DEBUG_DERP_WS_CLIENT") } return false } diff --git a/envknob/envknob.go b/envknob/envknob.go new file mode 100644 index 000000000..850ca6b0d --- /dev/null +++ b/envknob/envknob.go @@ -0,0 +1,102 @@ +// Copyright (c) 2022 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. + +// Package envknob provides access to environment-variable tweakable +// debug settings. +// +// These are primarily knobs used by Tailscale developers during +// development or by users when instructed to by Tailscale developers +// when debugging something. They are not a stable interface and may +// be removed or any time. +// +// A related package, control/controlknobs, are knobs that can be +// changed at runtime by the control plane. Sometimes both are used: +// an envknob for the default/explicit value, else falling back +// to the controlknob value. +package envknob + +import ( + "log" + "os" + "strconv" + + "tailscale.com/types/opt" +) + +// String returns the named environment variable, using os.Getenv. +// +// In the future it will also track usage for reporting on debug pages. +func String(envVar string) string { + return os.Getenv(envVar) +} + +// 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. +func Bool(envVar string) bool { + return boolOr(envVar, false) +} + +// BoolDefaultTrue is like Bool, but returns true by default if the +// environment variable isn't present. +func BoolDefaultTrue(envVar string) bool { + return boolOr(envVar, true) +} + +func boolOr(envVar string, implicitValue bool) bool { + val := os.Getenv(envVar) + if val == "" { + return implicitValue + } + b, err := strconv.ParseBool(val) + if err == nil { + return b + } + log.Fatalf("invalid environment variable %s value %q: %v", envVar, val, err) + panic("unreachable") +} + +// LookupBool returns the boolean value of the named environment value. +// 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) { + val := os.Getenv(envVar) + if val == "" { + return false, false + } + b, err := strconv.ParseBool(val) + if err == nil { + return b, true + } + log.Fatalf("invalid environment variable %s value %q: %v", envVar, val, err) + panic("unreachable") +} + +// 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 { + b, ok := LookupBool(envVar) + if !ok { + return "" + } + var ret opt.Bool + ret.Set(b) + return ret +} + +// LookupInt returns the integer value of the named environment value. +// 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) { + val := os.Getenv(envVar) + if val == "" { + return 0, false + } + v, err := strconv.Atoi(val) + if err == nil { + return v, true + } + log.Fatalf("invalid environment variable %s value %q: %v", envVar, val, err) + panic("unreachable") +} diff --git a/health/health.go b/health/health.go index eab7477ea..18464d0f7 100644 --- a/health/health.go +++ b/health/health.go @@ -10,13 +10,13 @@ import ( "errors" "fmt" "net/http" - "os" "runtime" "sort" "sync" "sync/atomic" "time" + "tailscale.com/envknob" "tailscale.com/tailcfg" "tailscale.com/util/multierr" ) @@ -308,7 +308,7 @@ func OverallError() error { return overallErrorLocked() } -var fakeErrForTesting = os.Getenv("TS_DEBUG_FAKE_HEALTH_ERROR") +var fakeErrForTesting = envknob.String("TS_DEBUG_FAKE_HEALTH_ERROR") func overallErrorLocked() error { if !anyInterfaceUp { diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 7c9db799a..a48949c86 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -27,6 +27,7 @@ import ( "inet.af/netaddr" "tailscale.com/client/tailscale/apitype" "tailscale.com/control/controlclient" + "tailscale.com/envknob" "tailscale.com/health" "tailscale.com/hostinfo" "tailscale.com/ipn" @@ -64,7 +65,7 @@ import ( var controlDebugFlags = getControlDebugFlags() func getControlDebugFlags() []string { - if e := os.Getenv("TS_DEBUG_CONTROL_FLAGS"); e != "" { + if e := envknob.String("TS_DEBUG_CONTROL_FLAGS"); e != "" { return strings.Split(e, ",") } return nil @@ -1349,7 +1350,7 @@ func (b *LocalBackend) popBrowserAuthNow() { } // For testing lazy machine key generation. -var panicOnMachineKeyGeneration, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_PANIC_MACHINE_KEY")) +var panicOnMachineKeyGeneration = envknob.Bool("TS_DEBUG_PANIC_MACHINE_KEY") func (b *LocalBackend) createGetMachinePrivateKeyFunc() func() (key.MachinePrivate, error) { var cache atomic.Value diff --git a/ipn/localapi/cert.go b/ipn/localapi/cert.go index 26fec06df..c0c54ae04 100644 --- a/ipn/localapi/cert.go +++ b/ipn/localapi/cert.go @@ -29,12 +29,12 @@ import ( "net/http" "os" "path/filepath" - "strconv" "strings" "sync" "time" "golang.org/x/crypto/acme" + "tailscale.com/envknob" "tailscale.com/ipn/ipnstate" "tailscale.com/types/logger" ) @@ -63,7 +63,7 @@ func (h *Handler) certDir() (string, error) { return full, nil } -var acmeDebug, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_ACME")) +var acmeDebug = envknob.Bool("TS_DEBUG_ACME") func (h *Handler) serveCert(w http.ResponseWriter, r *http.Request) { if !h.PermitWrite { diff --git a/logpolicy/logpolicy.go b/logpolicy/logpolicy.go index 8bc0675f5..513fec776 100644 --- a/logpolicy/logpolicy.go +++ b/logpolicy/logpolicy.go @@ -25,13 +25,13 @@ import ( "os/exec" "path/filepath" "runtime" - "strconv" "strings" "sync" "time" "golang.org/x/term" "tailscale.com/atomicfile" + "tailscale.com/envknob" "tailscale.com/log/filelogger" "tailscale.com/logtail" "tailscale.com/logtail/filch" @@ -227,7 +227,7 @@ func runningUnderSystemd() bool { } func redirectStderrToLogPanics() bool { - return runningUnderSystemd() || os.Getenv("TS_PLEASE_PANIC") != "" + return runningUnderSystemd() || envknob.Bool("TS_PLEASE_PANIC") } // winProgramDataAccessible reports whether the directory (assumed to @@ -405,7 +405,7 @@ func New(collection string) *Policy { } else { lflags = log.LstdFlags } - if v, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_LOG_TIME")); v { + if envknob.Bool("TS_DEBUG_LOG_TIME") { lflags = log.LstdFlags | log.Lmicroseconds } if runningUnderSystemd() { @@ -670,7 +670,7 @@ func NewLogtailTransport(host string) *http.Transport { // TODO(bradfitz): remove this debug knob once we've decided // to upload via HTTP/1 or HTTP/2 (probably HTTP/1). Or we might just enforce // it server-side. - if h1, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_FORCE_H1_LOGS")); h1 { + if envknob.Bool("TS_DEBUG_FORCE_H1_LOGS") { tr.TLSClientConfig = nil // DefaultTransport's was already initialized w/ h2 tr.ForceAttemptHTTP2 = false tr.TLSNextProto = map[string]func(authority string, c *tls.Conn) http.RoundTripper{} diff --git a/net/dns/manager_windows.go b/net/dns/manager_windows.go index 83a54602d..7b60e6771 100644 --- a/net/dns/manager_windows.go +++ b/net/dns/manager_windows.go @@ -7,10 +7,8 @@ package dns import ( "errors" "fmt" - "os" "os/exec" "sort" - "strconv" "strings" "syscall" "time" @@ -19,6 +17,7 @@ import ( "golang.org/x/sys/windows/registry" "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" "inet.af/netaddr" + "tailscale.com/envknob" "tailscale.com/types/logger" "tailscale.com/util/dnsname" ) @@ -36,7 +35,7 @@ const ( versionKey = `SOFTWARE\Microsoft\Windows NT\CurrentVersion` ) -var configureWSL, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_CONFIGURE_WSL")) +var configureWSL = envknob.Bool("TS_DEBUG_CONFIGURE_WSL") type windowsManager struct { logf logger.Logf diff --git a/net/dnscache/dnscache.go b/net/dnscache/dnscache.go index 2f96aab24..508769753 100644 --- a/net/dnscache/dnscache.go +++ b/net/dnscache/dnscache.go @@ -15,14 +15,13 @@ import ( "fmt" "log" "net" - "os" "runtime" - "strconv" "sync" "time" "golang.org/x/sync/singleflight" "inet.af/netaddr" + "tailscale.com/envknob" ) var single = &Resolver{ @@ -100,7 +99,7 @@ func (r *Resolver) ttl() time.Duration { return 10 * time.Minute } -var debug, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_DNS_CACHE")) +var debug = envknob.Bool("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 diff --git a/net/netcheck/netcheck.go b/net/netcheck/netcheck.go index 72896dde0..4aa007d30 100644 --- a/net/netcheck/netcheck.go +++ b/net/netcheck/netcheck.go @@ -16,16 +16,15 @@ import ( "log" "net" "net/http" - "os" "runtime" "sort" - "strconv" "sync" "time" "github.com/tcnksm/go-httpstat" "inet.af/netaddr" "tailscale.com/derp/derphttp" + "tailscale.com/envknob" "tailscale.com/net/interfaces" "tailscale.com/net/neterror" "tailscale.com/net/netns" @@ -40,7 +39,7 @@ import ( // Debugging and experimentation tweakables. var ( - debugNetcheck, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_NETCHECK")) + debugNetcheck = envknob.Bool("TS_DEBUG_NETCHECK") ) // The various default timeouts for things. diff --git a/net/tlsdial/tlsdial.go b/net/tlsdial/tlsdial.go index 3efb846e4..103e00f4d 100644 --- a/net/tlsdial/tlsdial.go +++ b/net/tlsdial/tlsdial.go @@ -17,10 +17,11 @@ import ( "errors" "log" "os" - "strconv" "sync" "sync/atomic" "time" + + "tailscale.com/envknob" ) var counterFallbackOK int32 // atomic @@ -31,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, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_TLS_DIAL")) +var debug = envknob.Bool("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 diff --git a/net/tstun/tun.go b/net/tstun/tun.go index d04725fcd..09386bd51 100644 --- a/net/tstun/tun.go +++ b/net/tstun/tun.go @@ -11,13 +11,12 @@ package tstun import ( "errors" - "os" "runtime" - "strconv" "strings" "time" "golang.zx2c4.com/wireguard/tun" + "tailscale.com/envknob" "tailscale.com/types/logger" ) @@ -32,7 +31,7 @@ import ( var tunMTU = 1280 func init() { - if mtu, _ := strconv.Atoi(os.Getenv("TS_DEBUG_MTU")); mtu != 0 { + if mtu, ok := envknob.LookupInt("TS_DEBUG_MTU"); ok { tunMTU = mtu } } diff --git a/portlist/portlist.go b/portlist/portlist.go index 977b51efe..9eb35ebfc 100644 --- a/portlist/portlist.go +++ b/portlist/portlist.go @@ -6,10 +6,10 @@ package portlist import ( "fmt" - "os" "sort" - "strconv" "strings" + + "tailscale.com/envknob" ) // Port is a listening port on the machine. @@ -74,7 +74,7 @@ func (pl List) String() string { return strings.TrimRight(sb.String(), "\n") } -var debugDisablePortlist, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_DISABLE_PORTLIST")) +var debugDisablePortlist = envknob.Bool("TS_DEBUG_DISABLE_PORTLIST") func GetList(prev List) (List, error) { if debugDisablePortlist { diff --git a/scripts/check_license_headers.sh b/scripts/check_license_headers.sh index 3d6eb20e1..253515f5d 100755 --- a/scripts/check_license_headers.sh +++ b/scripts/check_license_headers.sh @@ -10,7 +10,7 @@ check_file() { got=$1 - for year in `seq 2019 2021`; do + for year in `seq 2019 2022`; do want=$(cat <= 7 } -var forceIPCommand, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_USE_IP_COMMAND")) +var forceIPCommand = envknob.Bool("TS_DEBUG_USE_IP_COMMAND") // useIPCommand reports whether r should use the "ip" command (or its // fake commandRunner for tests) instead of netlink. diff --git a/wgengine/userspace.go b/wgengine/userspace.go index 6e7f5286a..6583804ec 100644 --- a/wgengine/userspace.go +++ b/wgengine/userspace.go @@ -11,10 +11,8 @@ import ( "errors" "fmt" "io" - "os" "reflect" "runtime" - "strconv" "strings" "sync" "sync/atomic" @@ -25,6 +23,7 @@ import ( "golang.zx2c4.com/wireguard/tun" "inet.af/netaddr" "tailscale.com/control/controlclient" + "tailscale.com/envknob" "tailscale.com/health" "tailscale.com/ipn/ipnstate" "tailscale.com/net/dns" @@ -366,7 +365,7 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error) } e.tundev.PreFilterOut = e.handleLocalPackets - if debugConnectFailures() { + if envknob.BoolDefaultTrue("TS_DEBUG_CONNECT_FAILURES") { if e.tundev.PreFilterIn != nil { return nil, errors.New("unexpected PreFilterIn already set") } @@ -550,10 +549,7 @@ func (e *userspaceEngine) pollResolver() { } } -var ( - debugTrimWireguardEnv = os.Getenv("TS_DEBUG_TRIM_WIREGUARD") - debugTrimWireguard, _ = strconv.ParseBool(debugTrimWireguardEnv) -) +var debugTrimWireguard = envknob.OptBool("TS_DEBUG_TRIM_WIREGUARD") // forceFullWireguardConfig reports whether we should give wireguard // our full network map, even for inactive peers @@ -563,8 +559,8 @@ var ( // and we haven't got enough time testing it. func forceFullWireguardConfig(numPeers int) bool { // Did the user explicitly enable trimmming via the environment variable knob? - if debugTrimWireguardEnv != "" { - return !debugTrimWireguard + if b, ok := debugTrimWireguard.Get(); ok { + return !b } if opt := controlclient.TrimWGConfig(); opt != "" { return !opt.EqualBool(true) diff --git a/wgengine/watchdog.go b/wgengine/watchdog.go index baa84ca95..1353a1589 100644 --- a/wgengine/watchdog.go +++ b/wgengine/watchdog.go @@ -6,13 +6,12 @@ package wgengine import ( "log" - "os" "runtime/pprof" - "strconv" "strings" "time" "inet.af/netaddr" + "tailscale.com/envknob" "tailscale.com/ipn/ipnstate" "tailscale.com/net/dns" "tailscale.com/net/dns/resolver" @@ -32,7 +31,7 @@ import ( // // If they do not, the watchdog crashes the process. func NewWatchdog(e Engine) Engine { - if v, _ := strconv.ParseBool(os.Getenv("TS_DEBUG_DISABLE_WATCHDOG")); v { + if envknob.Bool("TS_DEBUG_DISABLE_WATCHDOG") { return e } return &watchdogEngine{