Browse Source

all: cleanup unused code, part 2 (#10670)

And enable U1000 check in staticcheck.

Updates #cleanup

Signed-off-by: Andrew Lytvynov <[email protected]>
Andrew Lytvynov 2 years ago
parent
commit
2716250ee8
52 changed files with 115 additions and 578 deletions
  1. 0 8
      cmd/tailscale/cli/serve_v2.go
  2. 0 9
      cmd/tailscale/cli/serve_v2_test.go
  3. 0 12
      cmd/tailscale/cli/up.go
  4. 1 1
      cmd/tailscaled/depaware.txt
  5. 0 16
      cmd/testwrapper/args.go
  6. 0 20
      cmd/tsconnect/build.go
  7. 0 27
      control/controlbase/conn_test.go
  8. 0 32
      control/controlbase/noiseexplorer_test.go
  9. 0 16
      control/controlclient/auto.go
  10. 0 42
      control/controlclient/map.go
  11. 0 6
      derp/derp_server.go
  12. 2 2
      docs/webhooks/example.go
  13. 3 0
      doctor/permissions/permissions.go
  14. 0 11
      ipn/ipnauth/ipnauth.go
  15. 1 1
      ipn/ipnauth/ipnauth_windows.go
  16. 0 9
      ipn/ipnlocal/local.go
  17. 0 4
      ipn/ipnlocal/peerapi.go
  18. 0 1
      ipn/ipnlocal/peerapi_test.go
  19. 9 0
      ipn/ipnlocal/ssh.go
  20. 0 9
      net/art/stride_table.go
  21. 0 6
      net/art/stride_table_test.go
  22. 0 37
      net/art/table_test.go
  23. 6 49
      net/dns/direct.go
  24. 49 0
      net/dns/direct_linux.go
  25. 0 12
      net/dns/manager.go
  26. 6 7
      net/dns/manager_linux.go
  27. 0 27
      net/dns/manager_test.go
  28. 7 0
      net/dns/nm.go
  29. 0 7
      net/dns/recursive/recursive.go
  30. 0 23
      net/dns/resolved.go
  31. 4 5
      net/dns/resolver/tsdns.go
  32. 0 2
      net/dns/resolver/tsdns_test.go
  33. 0 2
      net/dnscache/dnscache.go
  34. 0 7
      net/netmon/netmon.go
  35. 7 0
      net/netmon/netmon_windows.go
  36. 0 6
      net/netutil/netutil.go
  37. 1 0
      net/routetable/routetable.go
  38. 3 2
      net/tstun/wrap.go
  39. 0 2
      portlist/netstat.go
  40. 0 8
      safesocket/pipe_windows.go
  41. 1 0
      staticcheck.conf
  42. 2 0
      tstest/integration/vms/opensuse_leap_15_1_test.go
  43. 2 0
      util/linuxfw/helpers.go
  44. 1 1
      util/linuxfw/linuxfw_unsupported.go
  45. 1 0
      util/winutil/restartmgr_windows.go
  46. 0 86
      util/winutil/subprocess_windows_test.go
  47. 0 20
      util/winutil/winutil_windows.go
  48. 4 0
      wgengine/magicsock/debugknobs.go
  49. 4 0
      wgengine/magicsock/magicsock.go
  50. 0 25
      wgengine/magicsock/peermtu_stubs.go
  51. 0 18
      wgengine/router/ifconfig_windows.go
  52. 1 0
      wgengine/router/router_test.go

+ 0 - 8
cmd/tailscale/cli/serve_v2.go

@@ -93,14 +93,6 @@ var infoMap = map[serveMode]commandInfo{
 	},
 }
 
-func buildShortUsage(subcmd string) string {
-	return strings.Join([]string{
-		subcmd + " [flags] <target> [off]",
-		subcmd + " status [--json]",
-		subcmd + " reset",
-	}, "\n  ")
-}
-
 // errHelpFunc is standard error text that prompts users to
 // run `$subcmd --help` for information on how to use serve.
 var errHelpFunc = func(m serveMode) error {

+ 0 - 9
cmd/tailscale/cli/serve_v2_test.go

@@ -27,7 +27,6 @@ func TestServeDevConfigMutations(t *testing.T) {
 		command []string                       // serve args; nil means no command to run (only reset)
 		want    *ipn.ServeConfig               // non-nil means we want a save of this value
 		wantErr func(error) (badErrMsg string) // nil means no error is wanted
-		before  func(t *testing.T)
 	}
 
 	// group is a group of steps that share the same
@@ -1224,14 +1223,6 @@ func TestMessageForPort(t *testing.T) {
 	}
 }
 
-func unindent(s string) string {
-	lines := strings.Split(s, "\n")
-	for i, line := range lines {
-		lines[i] = strings.TrimSpace(line)
-	}
-	return strings.Join(lines, "\n")
-}
-
 func TestIsLegacyInvocation(t *testing.T) {
 	tests := []struct {
 		subcmd      serveMode

+ 0 - 12
cmd/tailscale/cli/up.go

@@ -1044,18 +1044,6 @@ func exitNodeIP(p *ipn.Prefs, st *ipnstate.Status) (ip netip.Addr) {
 	return
 }
 
-func anyPeerAdvertisingRoutes(st *ipnstate.Status) bool {
-	for _, ps := range st.Peer {
-		if ps.PrimaryRoutes == nil {
-			continue
-		}
-		if ps.PrimaryRoutes.Len() > 0 {
-			return true
-		}
-	}
-	return false
-}
-
 func init() {
 	// Required to use our client API. We're fine with the instability since the
 	// client lives in the same repo as this code.

+ 1 - 1
cmd/tailscaled/depaware.txt

@@ -283,7 +283,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
         tailscale.com/net/netknob                                    from tailscale.com/net/netns+
         tailscale.com/net/netmon                                     from tailscale.com/cmd/tailscaled+
         tailscale.com/net/netns                                      from tailscale.com/derp/derphttp+
-     💣 tailscale.com/net/netstat                                    from tailscale.com/ipn/ipnauth+
+   W 💣 tailscale.com/net/netstat                                    from tailscale.com/portlist
         tailscale.com/net/netutil                                    from tailscale.com/ipn/ipnlocal+
         tailscale.com/net/packet                                     from tailscale.com/net/tstun+
         tailscale.com/net/packet/checksum                            from tailscale.com/net/tstun

+ 0 - 16
cmd/testwrapper/args.go

@@ -12,22 +12,6 @@ import (
 	"testing"
 )
 
-// defaultTestArgs contains the default values for all flags in the testing
-// package. It is used to reset the flag values in testwrapper tests to allow
-// parsing the flags again.
-var defaultTestArgs map[string]string
-
-// initDefaultTestArgs initializes defaultTestArgs.
-func initDefaultTestArgs() {
-	if defaultTestArgs != nil {
-		return
-	}
-	defaultTestArgs = make(map[string]string)
-	flag.CommandLine.VisitAll(func(f *flag.Flag) {
-		defaultTestArgs[f.Name] = f.DefValue
-	})
-}
-
 // registerTestFlags registers all flags from the testing package with the
 // provided flag set. It does so by calling testing.Init() and then iterating
 // over all flags registered on flag.CommandLine.

+ 0 - 20
cmd/tsconnect/build.go

@@ -83,26 +83,6 @@ func fixEsbuildMetadataPaths(metadataStr string) ([]byte, error) {
 	return json.Marshal(metadata)
 }
 
-func cleanDist() error {
-	log.Printf("Cleaning %s...\n", *distDir)
-	files, err := os.ReadDir(*distDir)
-	if err != nil {
-		if os.IsNotExist(err) {
-			return os.MkdirAll(*distDir, 0755)
-		}
-		return err
-	}
-
-	for _, file := range files {
-		if file.Name() != "placeholder" {
-			if err := os.Remove(filepath.Join(*distDir, file.Name())); err != nil {
-				return err
-			}
-		}
-	}
-	return nil
-}
-
 func precompressDist(fastCompression bool) error {
 	log.Printf("Pre-compressing files in %s/...\n", *distDir)
 	return precompress.PrecompressDir(*distDir, precompress.Options{

+ 0 - 27
control/controlbase/conn_test.go

@@ -7,7 +7,6 @@ import (
 	"bufio"
 	"bytes"
 	"context"
-	"crypto/rand"
 	"encoding/binary"
 	"fmt"
 	"io"
@@ -302,32 +301,6 @@ func TestConnMemoryOverhead(t *testing.T) {
 	}
 }
 
-// mkConns creates synthetic Noise Conns wrapping the given net.Conns.
-// This function is for testing just the Conn transport logic without
-// having to muck about with Noise handshakes.
-func mkConns(s1, s2 net.Conn) (*Conn, *Conn) {
-	var k1, k2 [chp.KeySize]byte
-	if _, err := rand.Read(k1[:]); err != nil {
-		panic(err)
-	}
-	if _, err := rand.Read(k2[:]); err != nil {
-		panic(err)
-	}
-
-	ret1 := &Conn{
-		conn: s1,
-		tx:   txState{cipher: newCHP(k1)},
-		rx:   rxState{cipher: newCHP(k2)},
-	}
-	ret2 := &Conn{
-		conn: s2,
-		tx:   txState{cipher: newCHP(k2)},
-		rx:   rxState{cipher: newCHP(k1)},
-	}
-
-	return ret1, ret2
-}
-
 type readSink struct {
 	r io.Reader
 

+ 0 - 32
control/controlbase/noiseexplorer_test.go

@@ -32,7 +32,6 @@ import (
 	"encoding/binary"
 	"hash"
 	"io"
-	"math"
 
 	"golang.org/x/crypto/blake2s"
 	"golang.org/x/crypto/chacha20poly1305"
@@ -105,10 +104,6 @@ var minNonce = uint32(0)
  * UTILITY FUNCTIONS                                                *
  * ---------------------------------------------------------------- */
 
-func getPublicKey(kp *keypair) [32]byte {
-	return kp.public_key
-}
-
 func isEmptyKey(k [32]byte) bool {
 	return subtle.ConstantTimeCompare(k[:], emptyKey[:]) == 1
 }
@@ -162,12 +157,6 @@ func generateKeypair() keypair {
 	return generateKeypair()
 }
 
-func generatePublicKey(private_key [32]byte) [32]byte {
-	var public_key [32]byte
-	curve25519.ScalarBaseMult(&public_key, &private_key)
-	return public_key
-}
-
 func encrypt(k [32]byte, n uint32, ad []byte, plaintext []byte) []byte {
 	var nonce [12]byte
 	var ciphertext []byte
@@ -246,12 +235,6 @@ func decryptWithAd(cs *cipherstate, ad []byte, ciphertext []byte) (*cipherstate,
 	return cs, plaintext, valid
 }
 
-func reKey(cs *cipherstate) *cipherstate {
-	e := encrypt(cs.k, math.MaxUint32, []byte{}, emptyKey[:])
-	copy(cs.k[:], e)
-	return cs
-}
-
 /* SymmetricState */
 
 func initializeSymmetric(protocolName []byte) symmetricstate {
@@ -273,19 +256,6 @@ func mixHash(ss *symmetricstate, data []byte) *symmetricstate {
 	return ss
 }
 
-func mixKeyAndHash(ss *symmetricstate, ikm [32]byte) *symmetricstate {
-	var tempH [32]byte
-	var tempK [32]byte
-	ss.ck, tempH, tempK = getHkdf(ss.ck, ikm[:])
-	ss = mixHash(ss, tempH[:])
-	ss.cs = initializeKey(tempK)
-	return ss
-}
-
-func getHandshakeHash(ss *symmetricstate) [32]byte {
-	return ss.h
-}
-
 func encryptAndHash(ss *symmetricstate, plaintext []byte) (*symmetricstate, []byte) {
 	var ciphertext []byte
 	if hasKey(&ss.cs) {
@@ -471,5 +441,3 @@ func RecvMessage(session *noisesession, message *messagebuffer) (*noisesession,
 	session.mc = session.mc + 1
 	return session, plaintext, valid
 }
-
-func main() {}

+ 0 - 16
control/controlclient/auto.go

@@ -252,14 +252,6 @@ func (c *Auto) updateControl() {
 	}
 }
 
-// cancelAuthCtx cancels the existing auth goroutine's context
-// & creates a new one, causing it to restart.
-func (c *Auto) cancelAuthCtx() {
-	c.mu.Lock()
-	defer c.mu.Unlock()
-	c.cancelAuthCtxLocked()
-}
-
 // cancelAuthCtxLocked is like cancelAuthCtx, but assumes the caller holds c.mu.
 func (c *Auto) cancelAuthCtxLocked() {
 	if c.authCancel != nil {
@@ -271,14 +263,6 @@ func (c *Auto) cancelAuthCtxLocked() {
 	}
 }
 
-// cancelMapCtx cancels the context for the existing mapPoll and liteUpdates
-// goroutines and creates a new one, causing them to restart.
-func (c *Auto) cancelMapCtx() {
-	c.mu.Lock()
-	defer c.mu.Unlock()
-	c.cancelMapCtxLocked()
-}
-
 // cancelMapCtxLocked is like cancelMapCtx, but assumes the caller holds c.mu.
 func (c *Auto) cancelMapCtxLocked() {
 	if c.mapCancel != nil {

+ 0 - 42
control/controlclient/map.go

@@ -8,7 +8,6 @@ import (
 	"encoding/json"
 	"fmt"
 	"net"
-	"net/netip"
 	"reflect"
 	"slices"
 	"sort"
@@ -86,7 +85,6 @@ type mapSession struct {
 	lastDomainAuditLogID   string
 	lastHealth             []string
 	lastPopBrowserURL      string
-	stickyDebug            tailcfg.Debug // accumulated opt.Bool values
 	lastTKAInfo            *tailcfg.TKAInfo
 	lastNetmapSummary      string // from NetworkMap.VeryConcise
 }
@@ -790,43 +788,3 @@ func (ms *mapSession) netmap() *netmap.NetworkMap {
 	}
 	return nm
 }
-
-func nodesSorted(v []*tailcfg.Node) bool {
-	for i, n := range v {
-		if i > 0 && n.ID <= v[i-1].ID {
-			return false
-		}
-	}
-	return true
-}
-
-func sortNodes(v []*tailcfg.Node) {
-	sort.Slice(v, func(i, j int) bool { return v[i].ID < v[j].ID })
-}
-
-func cloneNodes(v1 []*tailcfg.Node) []*tailcfg.Node {
-	if v1 == nil {
-		return nil
-	}
-	v2 := make([]*tailcfg.Node, len(v1))
-	for i, n := range v1 {
-		v2[i] = n.Clone()
-	}
-	return v2
-}
-
-var debugSelfIPv6Only = envknob.RegisterBool("TS_DEBUG_SELF_V6_ONLY")
-
-func filterSelfAddresses(in []netip.Prefix) (ret []netip.Prefix) {
-	switch {
-	default:
-		return in
-	case debugSelfIPv6Only():
-		for _, a := range in {
-			if a.Addr().Is6() {
-				ret = append(ret, a)
-			}
-		}
-		return ret
-	}
-}

+ 0 - 6
derp/derp_server.go

@@ -753,12 +753,6 @@ func (s *Server) debugLogf(format string, v ...any) {
 	}
 }
 
-// for testing
-var (
-	timeSleep = time.Sleep
-	timeNow   = time.Now
-)
-
 // run serves the client until there's an error.
 // If the client hangs up or the server is closed, run returns nil, otherwise run returns an error.
 func (c *sclient) run(ctx context.Context) error {

+ 2 - 2
docs/webhooks/example.go

@@ -1,9 +1,9 @@
 // Copyright (c) Tailscale Inc & AUTHORS
 // SPDX-License-Identifier: BSD-3-Clause
 
-// Package webhooks provides example consumer code for Tailscale
+// Command webhooks provides example consumer code for Tailscale
 // webhooks.
-package webhooks
+package main
 
 import (
 	"crypto/hmac"

+ 3 - 0
doctor/permissions/permissions.go

@@ -26,6 +26,7 @@ func (Check) Run(_ context.Context, logf logger.Logf) error {
 	return permissionsImpl(logf)
 }
 
+//lint:ignore U1000 used in non-windows implementations.
 func formatUserID[T constraints.Integer](id T) string {
 	idStr := fmt.Sprint(id)
 	if uu, err := user.LookupId(idStr); err != nil {
@@ -35,6 +36,7 @@ func formatUserID[T constraints.Integer](id T) string {
 	}
 }
 
+//lint:ignore U1000 used in non-windows implementations.
 func formatGroupID[T constraints.Integer](id T) string {
 	idStr := fmt.Sprint(id)
 	if g, err := user.LookupGroupId(idStr); err != nil {
@@ -44,6 +46,7 @@ func formatGroupID[T constraints.Integer](id T) string {
 	}
 }
 
+//lint:ignore U1000 used in non-windows implementations.
 func formatGroups[T constraints.Integer](groups []T) string {
 	var buf strings.Builder
 	for i, group := range groups {

+ 0 - 11
ipn/ipnauth/ipnauth.go

@@ -9,7 +9,6 @@ import (
 	"fmt"
 	"io"
 	"net"
-	"net/netip"
 	"os"
 	"os/user"
 	"runtime"
@@ -18,7 +17,6 @@ import (
 	"inet.af/peercred"
 	"tailscale.com/envknob"
 	"tailscale.com/ipn"
-	"tailscale.com/net/netstat"
 	"tailscale.com/safesocket"
 	"tailscale.com/types/logger"
 	"tailscale.com/util/clientmetric"
@@ -207,12 +205,3 @@ func isLocalAdmin(uid string) (bool, error) {
 	}
 	return groupmember.IsMemberOfGroup(adminGroup, u.Username)
 }
-
-func peerPid(entries []netstat.Entry, la, ra netip.AddrPort) int {
-	for _, e := range entries {
-		if e.Local == ra && e.Remote == la {
-			return e.Pid
-		}
-	}
-	return 0
-}

+ 1 - 1
ipn/ipnauth/ipnauth_windows.go

@@ -20,7 +20,7 @@ import (
 // based on the user who owns the other end of the connection.
 // If c is not backed by a named pipe, an error is returned.
 func GetConnIdentity(logf logger.Logf, c net.Conn) (ci *ConnIdentity, err error) {
-	ci = &ConnIdentity{conn: c}
+	ci = &ConnIdentity{conn: c, notWindows: false}
 	wcc, ok := c.(*safesocket.WindowsClientConn)
 	if !ok {
 		return nil, fmt.Errorf("not a WindowsClientConn: %T", c)

+ 0 - 9
ipn/ipnlocal/local.go

@@ -5324,15 +5324,6 @@ func (b *LocalBackend) DoNoiseRequest(req *http.Request) (*http.Response, error)
 	return cc.DoNoiseRequest(req)
 }
 
-// tailscaleSSHEnabled reports whether Tailscale SSH is currently enabled based
-// on prefs. It returns false if there are no prefs set.
-func (b *LocalBackend) tailscaleSSHEnabled() bool {
-	b.mu.Lock()
-	defer b.mu.Unlock()
-	p := b.pm.CurrentPrefs()
-	return p.Valid() && p.RunSSH()
-}
-
 func (b *LocalBackend) sshServerOrInit() (_ SSHServer, err error) {
 	b.mu.Lock()
 	defer b.mu.Unlock()

+ 0 - 4
ipn/ipnlocal/peerapi.go

@@ -62,10 +62,6 @@ type peerAPIServer struct {
 	taildrop *taildrop.Manager
 }
 
-var (
-	errNilPeerAPIServer = errors.New("peerapi unavailable; not listening")
-)
-
 func (s *peerAPIServer) listen(ip netip.Addr, ifState *interfaces.State) (ln net.Listener, err error) {
 	// Android for whatever reason often has problems creating the peerapi listener.
 	// But since we started intercepting it with netstack, it's not even important that

+ 0 - 1
ipn/ipnlocal/peerapi_test.go

@@ -114,7 +114,6 @@ func hexAll(v string) string {
 }
 
 func TestHandlePeerAPI(t *testing.T) {
-	const nodeFQDN = "self-node.tail-scale.ts.net."
 	tests := []struct {
 		name       string
 		isSelf     bool // the peer sending the request is owned by us

+ 9 - 0
ipn/ipnlocal/ssh.go

@@ -217,3 +217,12 @@ func (b *LocalBackend) getSSHHostKeyPublicStrings() (ret []string) {
 	}
 	return ret
 }
+
+// tailscaleSSHEnabled reports whether Tailscale SSH is currently enabled based
+// on prefs. It returns false if there are no prefs set.
+func (b *LocalBackend) tailscaleSSHEnabled() bool {
+	b.mu.Lock()
+	defer b.mu.Unlock()
+	p := b.pm.CurrentPrefs()
+	return p.Valid() && p.RunSSH()
+}

+ 0 - 9
net/art/stride_table.go

@@ -240,15 +240,6 @@ func (t *strideTable[T]) tableDebugString() string {
 	return ret.String()
 }
 
-// treeDebugString returns the contents of t, formatted as a sparse tree. Each
-// line is one entry, indented such that it is contained by all its parents, and
-// non-overlapping with any of its siblings.
-func (t *strideTable[T]) treeDebugString() string {
-	var ret bytes.Buffer
-	t.treeDebugStringRec(&ret, 1, 0) // index of 0/0, and 0 indent
-	return ret.String()
-}
-
 func (t *strideTable[T]) treeDebugStringRec(w io.Writer, idx, indent int) {
 	addr, len := inversePrefixIndex(idx)
 	if t.hasPrefixRootedAt(idx) {

+ 0 - 6
net/art/stride_table_test.go

@@ -348,12 +348,6 @@ func (t *slowTable[T]) String() string {
 	return ret.String()
 }
 
-func (t *slowTable[T]) insert(addr uint8, prefixLen int, val T) {
-	t.delete(addr, prefixLen) // no-op if prefix doesn't exist
-
-	t.prefixes = append(t.prefixes, slowEntry[T]{addr, prefixLen, val})
-}
-
 func (t *slowTable[T]) delete(addr uint8, prefixLen int) {
 	pfx := make([]slowEntry[T], 0, len(t.prefixes))
 	for _, e := range t.prefixes {

+ 0 - 37
net/art/table_test.go

@@ -968,8 +968,6 @@ func BenchmarkTableDelete(b *testing.B) {
 	})
 }
 
-var addrSink netip.Addr
-
 func BenchmarkTableGet(b *testing.B) {
 	forFamilyAndCount(b, func(b *testing.B, routes []slowPrefixEntry[int]) {
 		genAddr := randomAddr4
@@ -1106,18 +1104,6 @@ type slowPrefixEntry[T any] struct {
 	val T
 }
 
-func (t *slowPrefixTable[T]) delete(pfx netip.Prefix) {
-	pfx = pfx.Masked()
-	ret := make([]slowPrefixEntry[T], 0, len(t.prefixes))
-	for _, ent := range t.prefixes {
-		if ent.pfx == pfx {
-			continue
-		}
-		ret = append(ret, ent)
-	}
-	t.prefixes = ret
-}
-
 func (t *slowPrefixTable[T]) insert(pfx netip.Prefix, val T) {
 	pfx = pfx.Masked()
 	for i, ent := range t.prefixes {
@@ -1230,26 +1216,3 @@ func roundFloat64(f float64) float64 {
 	}
 	return ret
 }
-
-func minimize(pfxs []slowPrefixEntry[int], f func(skip map[netip.Prefix]bool) error) (map[netip.Prefix]bool, error) {
-	if f(nil) == nil {
-		return nil, nil
-	}
-
-	remove := map[netip.Prefix]bool{}
-	for lastLen := -1; len(remove) != lastLen; lastLen = len(remove) {
-		fmt.Println("len is ", len(remove))
-		for i, pfx := range pfxs {
-			if remove[pfx.pfx] {
-				continue
-			}
-			remove[pfx.pfx] = true
-			fmt.Printf("%d %d: trying without %s\n", i, len(remove), pfx.pfx)
-			if f(remove) == nil {
-				delete(remove, pfx.pfx)
-			}
-		}
-	}
-
-	return remove, f(remove)
-}

+ 6 - 49
net/dns/direct.go

@@ -20,7 +20,6 @@ import (
 	"sync"
 	"time"
 
-	"tailscale.com/health"
 	"tailscale.com/net/dns/resolvconffile"
 	"tailscale.com/types/logger"
 	"tailscale.com/util/dnsname"
@@ -50,6 +49,8 @@ func readResolv(r io.Reader) (OSConfig, error) {
 // resolvOwner returns the apparent owner of the resolv.conf
 // configuration in bs - one of "resolvconf", "systemd-resolved" or
 // "NetworkManager", or "" if no known owner was found.
+//
+//lint:ignore U1000 used in linux and freebsd code
 func resolvOwner(bs []byte) string {
 	likely := ""
 	b := bytes.NewBuffer(bs)
@@ -130,11 +131,13 @@ type directManager struct {
 	ctx      context.Context    // valid until Close
 	ctxClose context.CancelFunc // closes ctx
 
-	mu               sync.Mutex
-	wantResolvConf   []byte // if non-nil, what we expect /etc/resolv.conf to contain
+	mu             sync.Mutex
+	wantResolvConf []byte // if non-nil, what we expect /etc/resolv.conf to contain
+	//lint:ignore U1000 used in direct_linux.go
 	lastWarnContents []byte // last resolv.conf contents that we warned about
 }
 
+//lint:ignore U1000 used in manager_{freebsd,openbsd}.go
 func newDirectManager(logf logger.Logf) *directManager {
 	return newDirectManagerOnFS(logf, directFS{})
 }
@@ -288,52 +291,6 @@ func (m *directManager) setWant(want []byte) {
 	m.wantResolvConf = want
 }
 
-var warnTrample = health.NewWarnable()
-
-// checkForFileTrample checks whether /etc/resolv.conf has been trampled
-// by another program on the system. (e.g. a DHCP client)
-func (m *directManager) checkForFileTrample() {
-	m.mu.Lock()
-	want := m.wantResolvConf
-	lastWarn := m.lastWarnContents
-	m.mu.Unlock()
-
-	if want == nil {
-		return
-	}
-
-	cur, err := m.fs.ReadFile(resolvConf)
-	if err != nil {
-		m.logf("trample: read error: %v", err)
-		return
-	}
-	if bytes.Equal(cur, want) {
-		warnTrample.Set(nil)
-		if lastWarn != nil {
-			m.mu.Lock()
-			m.lastWarnContents = nil
-			m.mu.Unlock()
-			m.logf("trample: resolv.conf again matches expected content")
-		}
-		return
-	}
-	if bytes.Equal(cur, lastWarn) {
-		// We already logged about this, so not worth doing it again.
-		return
-	}
-
-	m.mu.Lock()
-	m.lastWarnContents = cur
-	m.mu.Unlock()
-
-	show := cur
-	if len(show) > 1024 {
-		show = show[:1024]
-	}
-	m.logf("trample: resolv.conf changed from what we expected. did some other program interfere? current contents: %q", show)
-	warnTrample.Set(errors.New("Linux DNS config not ideal. /etc/resolv.conf overwritten. See https://tailscale.com/s/dns-fight"))
-}
-
 func (m *directManager) SetDNS(config OSConfig) (err error) {
 	defer func() {
 		if err != nil && errors.Is(err, fs.ErrPermission) && runtime.GOOS == "linux" &&

+ 49 - 0
net/dns/direct_linux.go

@@ -4,9 +4,12 @@
 package dns
 
 import (
+	"bytes"
 	"context"
+	"errors"
 
 	"github.com/illarion/gonotify"
+	"tailscale.com/health"
 )
 
 func (m *directManager) runFileWatcher() {
@@ -55,6 +58,52 @@ func (m *directManager) runFileWatcher() {
 	}
 }
 
+var warnTrample = health.NewWarnable()
+
+// checkForFileTrample checks whether /etc/resolv.conf has been trampled
+// by another program on the system. (e.g. a DHCP client)
+func (m *directManager) checkForFileTrample() {
+	m.mu.Lock()
+	want := m.wantResolvConf
+	lastWarn := m.lastWarnContents
+	m.mu.Unlock()
+
+	if want == nil {
+		return
+	}
+
+	cur, err := m.fs.ReadFile(resolvConf)
+	if err != nil {
+		m.logf("trample: read error: %v", err)
+		return
+	}
+	if bytes.Equal(cur, want) {
+		warnTrample.Set(nil)
+		if lastWarn != nil {
+			m.mu.Lock()
+			m.lastWarnContents = nil
+			m.mu.Unlock()
+			m.logf("trample: resolv.conf again matches expected content")
+		}
+		return
+	}
+	if bytes.Equal(cur, lastWarn) {
+		// We already logged about this, so not worth doing it again.
+		return
+	}
+
+	m.mu.Lock()
+	m.lastWarnContents = cur
+	m.mu.Unlock()
+
+	show := cur
+	if len(show) > 1024 {
+		show = show[:1024]
+	}
+	m.logf("trample: resolv.conf changed from what we expected. did some other program interfere? current contents: %q", show)
+	warnTrample.Set(errors.New("Linux DNS config not ideal. /etc/resolv.conf overwritten. See https://tailscale.com/s/dns-fight"))
+}
+
 func (m *directManager) closeInotifyOnDone(ctx context.Context, in *gonotify.Inotify) {
 	<-ctx.Done()
 	in.Close()

+ 0 - 12
net/dns/manager.go

@@ -40,18 +40,6 @@ const maxActiveQueries = 256
 // the lint exception is necessary and on others it is not,
 // and plain ignore complains if the exception is unnecessary.
 
-// reconfigTimeout is the time interval within which Manager.{Up,Down} should complete.
-//
-// This is particularly useful because certain conditions can cause indefinite hangs
-// (such as improper dbus auth followed by contextless dbus.Object.Call).
-// Such operations should be wrapped in a timeout context.
-const reconfigTimeout = time.Second
-
-type response struct {
-	pkt []byte
-	to  netip.AddrPort // response destination (request source)
-}
-
 // Manager manages system DNS settings.
 type Manager struct {
 	logf logger.Logf

+ 6 - 7
net/dns/manager_linux.go

@@ -69,13 +69,12 @@ func NewOSConfigurator(logf logger.Logf, interfaceName string) (ret OSConfigurat
 
 // newOSConfigEnv are the funcs newOSConfigurator needs, pulled out for testing.
 type newOSConfigEnv struct {
-	fs                        wholeFileFS
-	dbusPing                  func(string, string) error
-	dbusReadString            func(string, string, string, string) (string, error)
-	nmIsUsingResolved         func() error
-	nmVersionBetween          func(v1, v2 string) (safe bool, err error)
-	resolvconfStyle           func() string
-	isResolvconfDebianVersion func() bool
+	fs                wholeFileFS
+	dbusPing          func(string, string) error
+	dbusReadString    func(string, string, string, string) (string, error)
+	nmIsUsingResolved func() error
+	nmVersionBetween  func(v1, v2 string) (safe bool, err error)
+	resolvconfStyle   func() string
 }
 
 func dnsMode(logf logger.Logf, env newOSConfigEnv) (ret string, err error) {

+ 0 - 27
net/dns/manager_test.go

@@ -636,13 +636,6 @@ func mustIPs(strs ...string) (ret []netip.Addr) {
 	return ret
 }
 
-func mustIPPs(strs ...string) (ret []netip.AddrPort) {
-	for _, s := range strs {
-		ret = append(ret, netip.MustParseAddrPort(s))
-	}
-	return ret
-}
-
 func mustRes(strs ...string) (ret []*dnstype.Resolver) {
 	for _, s := range strs {
 		ret = append(ret, &dnstype.Resolver{Addr: s})
@@ -681,26 +674,6 @@ func hosts(strs ...string) (ret map[dnsname.FQDN][]netip.Addr) {
 	return ret
 }
 
-func hostsR(strs ...string) (ret map[dnsname.FQDN][]dnstype.Resolver) {
-	var key dnsname.FQDN
-	ret = map[dnsname.FQDN][]dnstype.Resolver{}
-	for _, s := range strs {
-		if ip, err := netip.ParseAddr(s); err == nil {
-			if key == "" {
-				panic("IP provided before name")
-			}
-			ret[key] = append(ret[key], dnstype.Resolver{Addr: ip.String()})
-		} else {
-			fqdn, err := dnsname.ToFQDN(s)
-			if err != nil {
-				panic(err)
-			}
-			key = fqdn
-		}
-	}
-	return ret
-}
-
 func upstreams(strs ...string) (ret map[dnsname.FQDN][]*dnstype.Resolver) {
 	var key dnsname.FQDN
 	ret = map[dnsname.FQDN][]*dnstype.Resolver{}

+ 7 - 0
net/dns/nm.go

@@ -25,6 +25,13 @@ const (
 	lowerPriority   = int32(200) // lower than all builtin auto priorities
 )
 
+// reconfigTimeout is the time interval within which Manager.{Up,Down} should complete.
+//
+// This is particularly useful because certain conditions can cause indefinite hangs
+// (such as improper dbus auth followed by contextless dbus.Object.Call).
+// Such operations should be wrapped in a timeout context.
+const reconfigTimeout = time.Second
+
 // nmManager uses the NetworkManager DBus API.
 type nmManager struct {
 	interfaceName string

+ 0 - 7
net/dns/recursive/recursive.go

@@ -163,13 +163,6 @@ func (r *Resolver) logf(format string, args ...any) {
 	r.Logf(format, args...)
 }
 
-func (r *Resolver) dlogf(format string, args ...any) {
-	if r.Logf == nil || !debug() {
-		return
-	}
-	r.Logf(format, args...)
-}
-
 func (r *Resolver) depthlogf(depth int, format string, args ...any) {
 	if r.Logf == nil || !debug() {
 		return

+ 0 - 23
net/dns/resolved.go

@@ -7,7 +7,6 @@ package dns
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"net"
 	"strings"
@@ -17,32 +16,10 @@ import (
 	"golang.org/x/sys/unix"
 	"tailscale.com/health"
 	"tailscale.com/logtail/backoff"
-	"tailscale.com/net/netaddr"
 	"tailscale.com/types/logger"
 	"tailscale.com/util/dnsname"
 )
 
-// resolvedListenAddr is the listen address of the resolved stub resolver.
-//
-// We only consider resolved to be the system resolver if the stub resolver is;
-// that is, if this address is the sole nameserver in /etc/resolved.conf.
-// In other cases, resolved may be managing the system DNS configuration directly.
-// Then the nameserver list will be a concatenation of those for all
-// the interfaces that register their interest in being a default resolver with
-//
-//	SetLinkDomains([]{{"~.", true}, ...})
-//
-// which includes at least the interface with the default route, i.e. not us.
-// This does not work for us: there is a possibility of getting NXDOMAIN
-// from the other nameservers before we are asked or get a chance to respond.
-// We consider this case as lacking resolved support and fall through to dnsDirect.
-//
-// While it may seem that we need to read a config option to get at this,
-// this address is, in fact, hard-coded into resolved.
-var resolvedListenAddr = netaddr.IPv4(127, 0, 0, 53)
-
-var errNotReady = errors.New("interface not ready")
-
 // DBus entities we talk to.
 //
 // DBus is an RPC bus. In particular, the bus we're talking to is the

+ 4 - 5
net/dns/resolver/tsdns.go

@@ -189,8 +189,6 @@ type Resolver struct {
 
 	// closed signals all goroutines to stop.
 	closed chan struct{}
-	// wg signals when all goroutines have stopped.
-	wg sync.WaitGroup
 
 	// mu guards the following fields from being updated while used.
 	mu           sync.Mutex
@@ -609,6 +607,7 @@ func (r *Resolver) resolveLocal(domain dnsname.FQDN, typ dns.Type) (netip.Addr,
 			}
 		}
 		// Not authoritative, signal that forwarding is advisable.
+		metricDNSResolveLocalErrorRefused.Add(1)
 		return netip.Addr{}, dns.RCodeRefused
 	}
 
@@ -1248,6 +1247,7 @@ func (r *Resolver) respond(query []byte) ([]byte, error) {
 	resp := parser.response()
 	resp.Header.RCode = rcode
 	resp.IP = ip
+	metricDNSMagicDNSSuccessName.Add(1)
 	return marshalResponse(resp)
 }
 
@@ -1305,9 +1305,8 @@ var (
 	metricDNSFwdErrorContext         = clientmetric.NewCounter("dns_query_fwd_error_context")
 	metricDNSFwdErrorContextGotError = clientmetric.NewCounter("dns_query_fwd_error_context_got_error")
 
-	metricDNSFwdErrorType      = clientmetric.NewCounter("dns_query_fwd_error_type")
-	metricDNSFwdErrorParseAddr = clientmetric.NewCounter("dns_query_fwd_error_parse_addr")
-	metricDNSFwdTruncated      = clientmetric.NewCounter("dns_query_fwd_truncated")
+	metricDNSFwdErrorType = clientmetric.NewCounter("dns_query_fwd_error_type")
+	metricDNSFwdTruncated = clientmetric.NewCounter("dns_query_fwd_truncated")
 
 	metricDNSFwdUDP            = clientmetric.NewCounter("dns_query_fwd_udp")       // on entry
 	metricDNSFwdUDPWrote       = clientmetric.NewCounter("dns_query_fwd_udp_wrote") // sent UDP packet

+ 0 - 2
net/dns/resolver/tsdns_test.go

@@ -37,8 +37,6 @@ var (
 
 	testipv4Arpa = dnsname.FQDN("4.3.2.1.in-addr.arpa.")
 	testipv6Arpa = dnsname.FQDN("f.0.e.0.d.0.c.0.b.0.a.0.9.0.8.0.7.0.6.0.5.0.4.0.3.0.2.0.1.0.0.0.ip6.arpa.")
-
-	magicDNSv4Port = netip.MustParseAddrPort("100.100.100.100:53")
 )
 
 var dnsCfg = Config{

+ 0 - 2
net/dnscache/dnscache.go

@@ -656,8 +656,6 @@ func v6addrs(aa []netip.Addr) (ret []netip.Addr) {
 	return ret
 }
 
-var errTLSHandshakeTimeout = errors.New("timeout doing TLS handshake")
-
 // TLSDialer is like Dialer but returns a func suitable for using with net/http.Transport.DialTLSContext.
 // It returns a *tls.Conn type on success.
 // On TLS cert validation failure, it can invoke a backup DNS resolution strategy.

+ 0 - 7
net/netmon/netmon.go

@@ -220,13 +220,6 @@ func (m *Monitor) RegisterRuleDeleteCallback(callback RuleDeleteCallback) (unreg
 	}
 }
 
-// isActive reports whether this monitor has been started and not yet closed.
-func (m *Monitor) isActive() bool {
-	m.mu.Lock()
-	defer m.mu.Unlock()
-	return m.started && !m.closed
-}
-
 // Start starts the monitor.
 // A monitor can only be started & closed once.
 func (m *Monitor) Start() {

+ 7 - 0
net/netmon/netmon_windows.go

@@ -181,3 +181,10 @@ func (m *winMon) somethingChanged(evt string) {
 		return
 	}
 }
+
+// isActive reports whether this monitor has been started and not yet closed.
+func (m *Monitor) isActive() bool {
+	m.mu.Lock()
+	defer m.mu.Unlock()
+	return m.started && !m.closed
+}

+ 0 - 6
net/netutil/netutil.go

@@ -53,12 +53,6 @@ func (ln *oneConnListener) Close() error {
 	return nil
 }
 
-type dummyListener struct{}
-
-func (dummyListener) Close() error                    { return nil }
-func (dummyListener) Addr() net.Addr                  { return dummyAddr("unused-address") }
-func (dummyListener) Accept() (c net.Conn, err error) { return nil, io.EOF }
-
 type dummyAddr string
 
 func (a dummyAddr) Network() string { return string(a) }

+ 1 - 0
net/routetable/routetable.go

@@ -15,6 +15,7 @@ import (
 )
 
 var (
+	//lint:ignore U1000 used in routetable_linux_test.go and routetable_bsd_test.go
 	defaultRouteIPv4 = RouteDestination{Prefix: netip.PrefixFrom(netip.IPv4Unspecified(), 0)}
 	//lint:ignore U1000 used in routetable_bsd_test.go
 	defaultRouteIPv6 = RouteDestination{Prefix: netip.PrefixFrom(netip.IPv6Unspecified(), 0)}

+ 3 - 2
net/tstun/wrap.go

@@ -99,8 +99,9 @@ type Wrapper struct {
 	lastActivityAtomic mono.Time // time of last send or receive
 
 	destIPActivity syncs.AtomicValue[map[netip.Addr]func()]
-	destMACAtomic  syncs.AtomicValue[[6]byte]
-	discoKey       syncs.AtomicValue[key.DiscoPublic]
+	//lint:ignore U1000 used in tap_linux.go
+	destMACAtomic syncs.AtomicValue[[6]byte]
+	discoKey      syncs.AtomicValue[key.DiscoPublic]
 
 	// timeNow, if non-nil, will be used to obtain the current time.
 	timeNow func() time.Time

+ 0 - 2
portlist/netstat.go

@@ -55,8 +55,6 @@ func isLoopbackAddr(s mem.RO) bool {
 		mem.HasPrefix(s, mem.S("::1."))
 }
 
-type nothing struct{}
-
 // appendParsePortsNetstat appends to base listening ports
 // from "netstat" output, read from br. See TestParsePortsNetstat
 // for example input lines.

+ 0 - 8
safesocket/pipe_windows.go

@@ -10,7 +10,6 @@ import (
 	"fmt"
 	"net"
 	"runtime"
-	"syscall"
 	"time"
 
 	"github.com/tailscale/go-winio"
@@ -26,13 +25,6 @@ func connect(path string) (net.Conn, error) {
 	return winio.DialPipeAccessImpLevel(ctx, path, windows.GENERIC_READ|windows.GENERIC_WRITE, winio.PipeImpLevelIdentification)
 }
 
-func setFlags(network, address string, c syscall.RawConn) error {
-	return c.Control(func(fd uintptr) {
-		syscall.SetsockoptInt(syscall.Handle(fd), syscall.SOL_SOCKET,
-			syscall.SO_REUSEADDR, 1)
-	})
-}
-
 // windowsSDDL is the Security Descriptor set on the namedpipe.
 // It provides read/write access to all users and the local system.
 // It is a var for testing, do not change this value.

+ 1 - 0
staticcheck.conf

@@ -14,4 +14,5 @@ checks = [
 
 	"QF1004", # Use `strings.ReplaceAll` instead of `strings.Replace` with `n == 1`
 	"QF1006", # Lift if+break into loop condition
+	"U1000", # catch unused code
 ]

+ 2 - 0
tstest/integration/vms/opensuse_leap_15_1_test.go

@@ -1,6 +1,8 @@
 // Copyright (c) Tailscale Inc & AUTHORS
 // SPDX-License-Identifier: BSD-3-Clause
 
+//go:build !windows && !plan9
+
 package vms
 
 import (

+ 2 - 0
util/linuxfw/helpers.go

@@ -1,6 +1,8 @@
 // Copyright (c) Tailscale Inc & AUTHORS
 // SPDX-License-Identifier: BSD-3-Clause
 
+//go:build linux
+
 package linuxfw
 
 import (

+ 1 - 1
util/linuxfw/linuxfw_unsupported.go

@@ -5,7 +5,7 @@
 // support in upstream dependencies.
 
 // TODO(#8502): add support for more architectures
-//go:build !linux || (linux && !(arm64 || amd64))
+//go:build linux && !(arm64 || amd64)
 
 package linuxfw
 

+ 1 - 0
util/winutil/restartmgr_windows.go

@@ -112,6 +112,7 @@ const (
 type _RM_APP_STATUS uint32
 
 const (
+	//lint:ignore U1000 maps to a win32 API
 	_RmStatusUnknown        _RM_APP_STATUS = 0x0
 	_RmStatusRunning        _RM_APP_STATUS = 0x1
 	_RmStatusStopped        _RM_APP_STATUS = 0x2

+ 0 - 86
util/winutil/subprocess_windows_test.go

@@ -12,11 +12,9 @@ import (
 	"os/exec"
 	"path/filepath"
 	"runtime"
-	"strconv"
 	"strings"
 	"sync"
 	"testing"
-	"time"
 )
 
 // The code in this file is adapted from internal/testenv in the Go source tree
@@ -52,15 +50,6 @@ func pathToTestProg(t *testing.T, binary string) string {
 	return exe
 }
 
-func runTestProg(t *testing.T, binary, name string, env ...string) string {
-	exe, err := buildTestProg(t, binary, "-buildvcs=false")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	return runBuiltTestProg(t, exe, name, env...)
-}
-
 func startTestProg(t *testing.T, binary, name string, env ...string) {
 	exe, err := buildTestProg(t, binary, "-buildvcs=false")
 	if err != nil {
@@ -70,16 +59,6 @@ func startTestProg(t *testing.T, binary, name string, env ...string) {
 	startBuiltTestProg(t, exe, name, env...)
 }
 
-func runBuiltTestProg(t *testing.T, exe, name string, env ...string) string {
-	cmd := exec.Command(exe, name)
-	cmd.Env = append(cmd.Env, env...)
-	if testing.Short() {
-		cmd.Env = append(cmd.Env, "RUNTIME_TEST_SHORT=1")
-	}
-	out, _ := runWithTimeout(t, cmd)
-	return string(out)
-}
-
 func startBuiltTestProg(t *testing.T, exe, name string, env ...string) {
 	cmd := exec.Command(exe, name)
 	cmd.Env = append(cmd.Env, env...)
@@ -276,20 +255,6 @@ func mustHaveGoBuild(t testing.TB) {
 	}
 }
 
-// hasGoRun reports whether the current system can run programs with “go run.”
-func hasGoRun() bool {
-	// For now, having go run and having go build are the same.
-	return hasGoBuild()
-}
-
-// mustHaveGoRun checks that the current system can run programs with “go run.”
-// If not, mustHaveGoRun calls t.Skip with an explanation.
-func mustHaveGoRun(t testing.TB) {
-	if !hasGoRun() {
-		t.Skipf("skipping test: 'go run' not available on %s/%s", runtime.GOOS, runtime.GOARCH)
-	}
-}
-
 var (
 	gorootOnce sync.Once
 	gorootPath string
@@ -366,57 +331,6 @@ func findGOROOT() (string, error) {
 	return gorootPath, gorootErr
 }
 
-// runWithTimeout runs cmd and returns its combined output. If the
-// subprocess exits with a non-zero status, it will log that status
-// and return a non-nil error, but this is not considered fatal.
-func runWithTimeout(t testing.TB, cmd *exec.Cmd) ([]byte, error) {
-	args := cmd.Args
-	if args == nil {
-		args = []string{cmd.Path}
-	}
-
-	var b bytes.Buffer
-	cmd.Stdout = &b
-	cmd.Stderr = &b
-	if err := cmd.Start(); err != nil {
-		t.Fatalf("starting %s: %v", args, err)
-	}
-
-	// If the process doesn't complete within 1 minute,
-	// assume it is hanging and kill it to get a stack trace.
-	p := cmd.Process
-	done := make(chan bool)
-	go func() {
-		scale := 2
-		if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
-			if sc, err := strconv.Atoi(s); err == nil {
-				scale = sc
-			}
-		}
-
-		select {
-		case <-done:
-		case <-time.After(time.Duration(scale) * time.Minute):
-			p.Signal(os.Kill)
-			// If SIGQUIT doesn't do it after a little
-			// while, kill the process.
-			select {
-			case <-done:
-			case <-time.After(time.Duration(scale) * 30 * time.Second):
-				p.Signal(os.Kill)
-			}
-		}
-	}()
-
-	err := cmd.Wait()
-	if err != nil {
-		t.Logf("%s exit status: %v", args, err)
-	}
-	close(done)
-
-	return b.Bytes(), err
-}
-
 // start runs cmd asynchronously and returns immediately.
 func start(t testing.TB, cmd *exec.Cmd) {
 	args := cmd.Args

+ 0 - 20
util/winutil/winutil_windows.go

@@ -382,26 +382,6 @@ func CreateAppMutex(name string) (windows.Handle, error) {
 	return windows.CreateMutex(nil, false, windows.StringToUTF16Ptr(name))
 }
 
-// getTokenInfoVariableLen obtains variable-length token information. Use
-// this function for information classes that output variable-length data.
-func getTokenInfoVariableLen[T any](token windows.Token, infoClass uint32) (*T, error) {
-	var buf []byte
-	var desiredLen uint32
-
-	err := windows.GetTokenInformation(token, infoClass, nil, 0, &desiredLen)
-
-	for err == windows.ERROR_INSUFFICIENT_BUFFER {
-		buf = make([]byte, desiredLen)
-		err = windows.GetTokenInformation(token, infoClass, unsafe.SliceData(buf), desiredLen, &desiredLen)
-	}
-
-	if err != nil {
-		return nil, err
-	}
-
-	return (*T)(unsafe.Pointer(unsafe.SliceData(buf))), nil
-}
-
 // getTokenInfoFixedLen obtains known fixed-length token information. Use this
 // function for information classes that output enumerations, BOOLs, integers etc.
 func getTokenInfoFixedLen[T any](token windows.Token, infoClass uint32) (result T, err error) {

+ 4 - 0
wgengine/magicsock/debugknobs.go

@@ -53,8 +53,12 @@ var (
 	// discovery on UDP connections between peers. Currently (2023-09-05)
 	// this only turns on the don't fragment bit for the magicsock UDP
 	// sockets.
+	//
+	//lint:ignore U1000 used on Linux/Darwin only
 	debugEnablePMTUD = envknob.RegisterOptBool("TS_DEBUG_ENABLE_PMTUD")
 	// debugPMTUD prints extra debugging about peer MTU path discovery.
+	//
+	//lint:ignore U1000 used on Linux/Darwin only
 	debugPMTUD = envknob.RegisterBool("TS_DEBUG_PMTUD")
 	// Hey you! Adding a new debugknob? Make sure to stub it out in the
 	// debugknobs_stubs.go file too.

+ 4 - 0
wgengine/magicsock/magicsock.go

@@ -169,6 +169,8 @@ type Conn struct {
 	port atomic.Uint32
 
 	// peerMTUEnabled is whether path MTU discovery to peers is enabled.
+	//
+	//lint:ignore U1000 used on Linux/Darwin only
 	peerMTUEnabled atomic.Bool
 
 	// stats maintains per-connection counters.
@@ -2933,7 +2935,9 @@ var (
 	metricDERPHomeChange = clientmetric.NewCounter("derp_home_change")
 
 	// Disco packets received bpf read path
+	//lint:ignore U1000 used on Linux only
 	metricRecvDiscoPacketIPv4 = clientmetric.NewCounter("magicsock_disco_recv_bpf_ipv4")
+	//lint:ignore U1000 used on Linux only
 	metricRecvDiscoPacketIPv6 = clientmetric.NewCounter("magicsock_disco_recv_bpf_ipv6")
 
 	// metricMaxPeerMTUProbed is the largest peer path MTU we successfully probed.

+ 0 - 25
wgengine/magicsock/peermtu_stubs.go

@@ -5,31 +5,6 @@
 
 package magicsock
 
-import (
-	"errors"
-)
-
-// setDontFragment sets the don't fragment sockopt on the underlying connection
-// specified by network, which must be "udp4" or "udp6". See
-// https://datatracker.ietf.org/doc/html/rfc3542#section-11.2 for details on
-// IPv6 fragmentation.
-//
-// Return values:
-// - an error if peer MTU is not supported on this OS
-// - errNoActiveUDP if the underlying connection is not UDP
-// - otherwise, the result of setting the don't fragment bit
-func (c *Conn) setDontFragment(network string, enable bool) error {
-	return errors.New("peer path MTU discovery not supported on this OS")
-}
-
-// getDontFragment gets the don't fragment setting on the underlying connection
-// specified by network, which must be "udp4" or "udp6". Returns true if the
-// underlying connection is UDP and the don't fragment bit is set, otherwise
-// false.
-func (c *Conn) getDontFragment(network string) (bool, error) {
-	return false, nil
-}
-
 func (c *Conn) DontFragSetting() (bool, error) {
 	return false, nil
 }

+ 0 - 18
wgengine/router/ifconfig_windows.go

@@ -9,7 +9,6 @@ import (
 	"errors"
 	"fmt"
 	"log"
-	"net"
 	"net/netip"
 	"slices"
 	"sort"
@@ -28,8 +27,6 @@ import (
 	"tailscale.com/wgengine/winnet"
 )
 
-var wintunLinkLocal = netip.MustParseAddr("fe80::99d0:ec2d:b2e7:536b")
-
 // monitorDefaultRoutes subscribes to route change events and updates
 // the Tailscale tunnel interface's MTU to match that of the
 // underlying default route.
@@ -470,21 +467,6 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) (retErr error) {
 	return errAcc
 }
 
-// unwrapIP returns the shortest version of ip.
-func unwrapIP(ip net.IP) net.IP {
-	if ip4 := ip.To4(); ip4 != nil {
-		return ip4
-	}
-	return ip
-}
-
-func v4Mask(m net.IPMask) net.IPMask {
-	if len(m) == 16 {
-		return m[12:]
-	}
-	return m
-}
-
 func netCompare(a, b netip.Prefix) int {
 	aip, bip := a.Addr().Unmap(), b.Addr().Unmap()
 	v := aip.Compare(bip)

+ 1 - 0
wgengine/router/router_test.go

@@ -11,6 +11,7 @@ import (
 	"tailscale.com/types/preftype"
 )
 
+//lint:ignore U1000 used in Windows/Linux tests only
 func mustCIDRs(ss ...string) []netip.Prefix {
 	var ret []netip.Prefix
 	for _, s := range ss {