diff --git a/cmd/tailscale/cli/serve_v2.go b/cmd/tailscale/cli/serve_v2.go index 0e0c37d84..e040c9de8 100644 --- a/cmd/tailscale/cli/serve_v2.go +++ b/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] [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 { diff --git a/cmd/tailscale/cli/serve_v2_test.go b/cmd/tailscale/cli/serve_v2_test.go index e795ff286..8634d5b83 100644 --- a/cmd/tailscale/cli/serve_v2_test.go +++ b/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 diff --git a/cmd/tailscale/cli/up.go b/cmd/tailscale/cli/up.go index 67d6a3483..955e3ccc0 100644 --- a/cmd/tailscale/cli/up.go +++ b/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. diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index b5ac27975..379af4fe3 100644 --- a/cmd/tailscaled/depaware.txt +++ b/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 diff --git a/cmd/testwrapper/args.go b/cmd/testwrapper/args.go index 20c64e0e3..95157bc34 100644 --- a/cmd/testwrapper/args.go +++ b/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. diff --git a/cmd/tsconnect/build.go b/cmd/tsconnect/build.go index e3384b664..364ebf536 100644 --- a/cmd/tsconnect/build.go +++ b/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{ diff --git a/control/controlbase/conn_test.go b/control/controlbase/conn_test.go index 079c57c6e..504d1dbf5 100644 --- a/control/controlbase/conn_test.go +++ b/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 diff --git a/control/controlbase/noiseexplorer_test.go b/control/controlbase/noiseexplorer_test.go index 7407ae533..76b6f79be 100644 --- a/control/controlbase/noiseexplorer_test.go +++ b/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() {} diff --git a/control/controlclient/auto.go b/control/controlclient/auto.go index 1dc903376..86b03efa5 100644 --- a/control/controlclient/auto.go +++ b/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 { diff --git a/control/controlclient/map.go b/control/controlclient/map.go index 90bf83213..8797ed0bb 100644 --- a/control/controlclient/map.go +++ b/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 - } -} diff --git a/derp/derp_server.go b/derp/derp_server.go index cf42acdf7..2479ff5a5 100644 --- a/derp/derp_server.go +++ b/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 { diff --git a/docs/webhooks/example.go b/docs/webhooks/example.go index 6811a95e6..712028362 100644 --- a/docs/webhooks/example.go +++ b/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" diff --git a/doctor/permissions/permissions.go b/doctor/permissions/permissions.go index f9c0de950..77fe52626 100644 --- a/doctor/permissions/permissions.go +++ b/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 { diff --git a/ipn/ipnauth/ipnauth.go b/ipn/ipnauth/ipnauth.go index 5dc2e2768..7ae9ff3e4 100644 --- a/ipn/ipnauth/ipnauth.go +++ b/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 -} diff --git a/ipn/ipnauth/ipnauth_windows.go b/ipn/ipnauth/ipnauth_windows.go index c38b6db0f..d3421a5dc 100644 --- a/ipn/ipnauth/ipnauth_windows.go +++ b/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) diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 4f72a305e..fe17198c5 100644 --- a/ipn/ipnlocal/local.go +++ b/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() diff --git a/ipn/ipnlocal/peerapi.go b/ipn/ipnlocal/peerapi.go index d1d511462..6e45ea7df 100644 --- a/ipn/ipnlocal/peerapi.go +++ b/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 diff --git a/ipn/ipnlocal/peerapi_test.go b/ipn/ipnlocal/peerapi_test.go index 74e1f4e25..074d11482 100644 --- a/ipn/ipnlocal/peerapi_test.go +++ b/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 diff --git a/ipn/ipnlocal/ssh.go b/ipn/ipnlocal/ssh.go index 19a23c030..7a6000a56 100644 --- a/ipn/ipnlocal/ssh.go +++ b/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() +} diff --git a/net/art/stride_table.go b/net/art/stride_table.go index f18f76515..5ff0455fe 100644 --- a/net/art/stride_table.go +++ b/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) { diff --git a/net/art/stride_table_test.go b/net/art/stride_table_test.go index 82a7c915d..40700b175 100644 --- a/net/art/stride_table_test.go +++ b/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 { diff --git a/net/art/table_test.go b/net/art/table_test.go index 9166c00e5..39b76e0af 100644 --- a/net/art/table_test.go +++ b/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) -} diff --git a/net/dns/direct.go b/net/dns/direct.go index e9279d13a..501d42e85 100644 --- a/net/dns/direct.go +++ b/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" && diff --git a/net/dns/direct_linux.go b/net/dns/direct_linux.go index 4a388c47b..ad5a2163a 100644 --- a/net/dns/direct_linux.go +++ b/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() diff --git a/net/dns/manager.go b/net/dns/manager.go index ab94743db..69185909c 100644 --- a/net/dns/manager.go +++ b/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 diff --git a/net/dns/manager_linux.go b/net/dns/manager_linux.go index 75662d672..b5d3d841c 100644 --- a/net/dns/manager_linux.go +++ b/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) { diff --git a/net/dns/manager_test.go b/net/dns/manager_test.go index e88b61322..65b86bab4 100644 --- a/net/dns/manager_test.go +++ b/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{} diff --git a/net/dns/nm.go b/net/dns/nm.go index 4d9fbca66..adb33cdb7 100644 --- a/net/dns/nm.go +++ b/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 diff --git a/net/dns/recursive/recursive.go b/net/dns/recursive/recursive.go index d0fb5d5c7..eb23004d8 100644 --- a/net/dns/recursive/recursive.go +++ b/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 diff --git a/net/dns/resolved.go b/net/dns/resolved.go index d524d2e80..2917ab5b3 100644 --- a/net/dns/resolved.go +++ b/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 diff --git a/net/dns/resolver/tsdns.go b/net/dns/resolver/tsdns.go index 97b8434cc..a73add0c9 100644 --- a/net/dns/resolver/tsdns.go +++ b/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 diff --git a/net/dns/resolver/tsdns_test.go b/net/dns/resolver/tsdns_test.go index 882462012..cbef27588 100644 --- a/net/dns/resolver/tsdns_test.go +++ b/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{ diff --git a/net/dnscache/dnscache.go b/net/dnscache/dnscache.go index e0d6af4c1..fc3191b34 100644 --- a/net/dnscache/dnscache.go +++ b/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. diff --git a/net/netmon/netmon.go b/net/netmon/netmon.go index 94a5de72f..b0872034a 100644 --- a/net/netmon/netmon.go +++ b/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() { diff --git a/net/netmon/netmon_windows.go b/net/netmon/netmon_windows.go index a45452390..ddf13a2e4 100644 --- a/net/netmon/netmon_windows.go +++ b/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 +} diff --git a/net/netutil/netutil.go b/net/netutil/netutil.go index 2a4e0d60e..bc64e8fdc 100644 --- a/net/netutil/netutil.go +++ b/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) } diff --git a/net/routetable/routetable.go b/net/routetable/routetable.go index a065de436..2884706f1 100644 --- a/net/routetable/routetable.go +++ b/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)} diff --git a/net/tstun/wrap.go b/net/tstun/wrap.go index c459c367f..ac5442536 100644 --- a/net/tstun/wrap.go +++ b/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 diff --git a/portlist/netstat.go b/portlist/netstat.go index c7801ccdc..5fdef675d 100644 --- a/portlist/netstat.go +++ b/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. diff --git a/safesocket/pipe_windows.go b/safesocket/pipe_windows.go index dd6d521b6..eb78b2bc1 100644 --- a/safesocket/pipe_windows.go +++ b/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. diff --git a/staticcheck.conf b/staticcheck.conf index 1e51c7d56..876998489 100644 --- a/staticcheck.conf +++ b/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 ] diff --git a/tstest/integration/vms/opensuse_leap_15_1_test.go b/tstest/integration/vms/opensuse_leap_15_1_test.go index be8690c45..7d3ac579e 100644 --- a/tstest/integration/vms/opensuse_leap_15_1_test.go +++ b/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 ( diff --git a/util/linuxfw/helpers.go b/util/linuxfw/helpers.go index 7526d68ed..5d76adac6 100644 --- a/util/linuxfw/helpers.go +++ b/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 ( diff --git a/util/linuxfw/linuxfw_unsupported.go b/util/linuxfw/linuxfw_unsupported.go index 003d4bdff..7bfb4fd01 100644 --- a/util/linuxfw/linuxfw_unsupported.go +++ b/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 diff --git a/util/winutil/restartmgr_windows.go b/util/winutil/restartmgr_windows.go index 254b736b2..9fface9ca 100644 --- a/util/winutil/restartmgr_windows.go +++ b/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 diff --git a/util/winutil/subprocess_windows_test.go b/util/winutil/subprocess_windows_test.go index 4c6bb5977..f7c205d61 100644 --- a/util/winutil/subprocess_windows_test.go +++ b/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 diff --git a/util/winutil/winutil_windows.go b/util/winutil/winutil_windows.go index 53f368343..5a8df5bb9 100644 --- a/util/winutil/winutil_windows.go +++ b/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) { diff --git a/wgengine/magicsock/debugknobs.go b/wgengine/magicsock/debugknobs.go index 824c677f6..a8bbc61ff 100644 --- a/wgengine/magicsock/debugknobs.go +++ b/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. diff --git a/wgengine/magicsock/magicsock.go b/wgengine/magicsock/magicsock.go index ea4ebb05f..0d1a15a22 100644 --- a/wgengine/magicsock/magicsock.go +++ b/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. diff --git a/wgengine/magicsock/peermtu_stubs.go b/wgengine/magicsock/peermtu_stubs.go index 6981f28c3..4675e2501 100644 --- a/wgengine/magicsock/peermtu_stubs.go +++ b/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 } diff --git a/wgengine/router/ifconfig_windows.go b/wgengine/router/ifconfig_windows.go index ef098e542..414a8b708 100644 --- a/wgengine/router/ifconfig_windows.go +++ b/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) diff --git a/wgengine/router/router_test.go b/wgengine/router/router_test.go index 9c02a1bb4..0b20f8807 100644 --- a/wgengine/router/router_test.go +++ b/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 {