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

And enable U1000 check in staticcheck.

Updates #cleanup

Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
This commit is contained in:
Andrew Lytvynov 2023-12-21 19:40:03 -06:00 committed by GitHub
parent c9836b454d
commit 2716250ee8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 115 additions and 578 deletions

View File

@ -93,14 +93,6 @@ type commandInfo struct {
}, },
} }
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 // errHelpFunc is standard error text that prompts users to
// run `$subcmd --help` for information on how to use serve. // run `$subcmd --help` for information on how to use serve.
var errHelpFunc = func(m serveMode) error { var errHelpFunc = func(m serveMode) error {

View File

@ -27,7 +27,6 @@ type step struct {
command []string // serve args; nil means no command to run (only reset) 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 want *ipn.ServeConfig // non-nil means we want a save of this value
wantErr func(error) (badErrMsg string) // nil means no error is wanted 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 // 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) { func TestIsLegacyInvocation(t *testing.T) {
tests := []struct { tests := []struct {
subcmd serveMode subcmd serveMode

View File

@ -1044,18 +1044,6 @@ func exitNodeIP(p *ipn.Prefs, st *ipnstate.Status) (ip netip.Addr) {
return 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() { func init() {
// Required to use our client API. We're fine with the instability since the // Required to use our client API. We're fine with the instability since the
// client lives in the same repo as this code. // client lives in the same repo as this code.

View File

@ -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/netknob from tailscale.com/net/netns+
tailscale.com/net/netmon from tailscale.com/cmd/tailscaled+ tailscale.com/net/netmon from tailscale.com/cmd/tailscaled+
tailscale.com/net/netns from tailscale.com/derp/derphttp+ 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/netutil from tailscale.com/ipn/ipnlocal+
tailscale.com/net/packet from tailscale.com/net/tstun+ tailscale.com/net/packet from tailscale.com/net/tstun+
tailscale.com/net/packet/checksum from tailscale.com/net/tstun tailscale.com/net/packet/checksum from tailscale.com/net/tstun

View File

@ -12,22 +12,6 @@
"testing" "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 // registerTestFlags registers all flags from the testing package with the
// provided flag set. It does so by calling testing.Init() and then iterating // provided flag set. It does so by calling testing.Init() and then iterating
// over all flags registered on flag.CommandLine. // over all flags registered on flag.CommandLine.

View File

@ -83,26 +83,6 @@ func fixEsbuildMetadataPaths(metadataStr string) ([]byte, error) {
return json.Marshal(metadata) 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 { func precompressDist(fastCompression bool) error {
log.Printf("Pre-compressing files in %s/...\n", *distDir) log.Printf("Pre-compressing files in %s/...\n", *distDir)
return precompress.PrecompressDir(*distDir, precompress.Options{ return precompress.PrecompressDir(*distDir, precompress.Options{

View File

@ -7,7 +7,6 @@
"bufio" "bufio"
"bytes" "bytes"
"context" "context"
"crypto/rand"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"io" "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 { type readSink struct {
r io.Reader r io.Reader

View File

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

View File

@ -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. // cancelAuthCtxLocked is like cancelAuthCtx, but assumes the caller holds c.mu.
func (c *Auto) cancelAuthCtxLocked() { func (c *Auto) cancelAuthCtxLocked() {
if c.authCancel != nil { 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. // cancelMapCtxLocked is like cancelMapCtx, but assumes the caller holds c.mu.
func (c *Auto) cancelMapCtxLocked() { func (c *Auto) cancelMapCtxLocked() {
if c.mapCancel != nil { if c.mapCancel != nil {

View File

@ -8,7 +8,6 @@
"encoding/json" "encoding/json"
"fmt" "fmt"
"net" "net"
"net/netip"
"reflect" "reflect"
"slices" "slices"
"sort" "sort"
@ -86,7 +85,6 @@ type mapSession struct {
lastDomainAuditLogID string lastDomainAuditLogID string
lastHealth []string lastHealth []string
lastPopBrowserURL string lastPopBrowserURL string
stickyDebug tailcfg.Debug // accumulated opt.Bool values
lastTKAInfo *tailcfg.TKAInfo lastTKAInfo *tailcfg.TKAInfo
lastNetmapSummary string // from NetworkMap.VeryConcise lastNetmapSummary string // from NetworkMap.VeryConcise
} }
@ -790,43 +788,3 @@ func (ms *mapSession) netmap() *netmap.NetworkMap {
} }
return nm 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
}
}

View File

@ -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. // 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. // 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 { func (c *sclient) run(ctx context.Context) error {

View File

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

View File

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

View File

@ -9,7 +9,6 @@
"fmt" "fmt"
"io" "io"
"net" "net"
"net/netip"
"os" "os"
"os/user" "os/user"
"runtime" "runtime"
@ -18,7 +17,6 @@
"inet.af/peercred" "inet.af/peercred"
"tailscale.com/envknob" "tailscale.com/envknob"
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/net/netstat"
"tailscale.com/safesocket" "tailscale.com/safesocket"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/util/clientmetric" "tailscale.com/util/clientmetric"
@ -207,12 +205,3 @@ func isLocalAdmin(uid string) (bool, error) {
} }
return groupmember.IsMemberOfGroup(adminGroup, u.Username) 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
}

View File

@ -20,7 +20,7 @@
// based on the user who owns the other end of the connection. // 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. // 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) { 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) wcc, ok := c.(*safesocket.WindowsClientConn)
if !ok { if !ok {
return nil, fmt.Errorf("not a WindowsClientConn: %T", c) return nil, fmt.Errorf("not a WindowsClientConn: %T", c)

View File

@ -5324,15 +5324,6 @@ func (b *LocalBackend) DoNoiseRequest(req *http.Request) (*http.Response, error)
return cc.DoNoiseRequest(req) 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) { func (b *LocalBackend) sshServerOrInit() (_ SSHServer, err error) {
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()

View File

@ -62,10 +62,6 @@ type peerAPIServer struct {
taildrop *taildrop.Manager 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) { 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. // 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 // But since we started intercepting it with netstack, it's not even important that

View File

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

View File

@ -217,3 +217,12 @@ func (b *LocalBackend) getSSHHostKeyPublicStrings() (ret []string) {
} }
return ret 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()
}

View File

@ -240,15 +240,6 @@ func (t *strideTable[T]) tableDebugString() string {
return ret.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) { func (t *strideTable[T]) treeDebugStringRec(w io.Writer, idx, indent int) {
addr, len := inversePrefixIndex(idx) addr, len := inversePrefixIndex(idx)
if t.hasPrefixRootedAt(idx) { if t.hasPrefixRootedAt(idx) {

View File

@ -348,12 +348,6 @@ func (t *slowTable[T]) String() string {
return ret.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) { func (t *slowTable[T]) delete(addr uint8, prefixLen int) {
pfx := make([]slowEntry[T], 0, len(t.prefixes)) pfx := make([]slowEntry[T], 0, len(t.prefixes))
for _, e := range t.prefixes { for _, e := range t.prefixes {

View File

@ -968,8 +968,6 @@ func BenchmarkTableDelete(b *testing.B) {
}) })
} }
var addrSink netip.Addr
func BenchmarkTableGet(b *testing.B) { func BenchmarkTableGet(b *testing.B) {
forFamilyAndCount(b, func(b *testing.B, routes []slowPrefixEntry[int]) { forFamilyAndCount(b, func(b *testing.B, routes []slowPrefixEntry[int]) {
genAddr := randomAddr4 genAddr := randomAddr4
@ -1106,18 +1104,6 @@ type slowPrefixEntry[T any] struct {
val T 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) { func (t *slowPrefixTable[T]) insert(pfx netip.Prefix, val T) {
pfx = pfx.Masked() pfx = pfx.Masked()
for i, ent := range t.prefixes { for i, ent := range t.prefixes {
@ -1230,26 +1216,3 @@ func roundFloat64(f float64) float64 {
} }
return ret 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)
}

View File

@ -20,7 +20,6 @@
"sync" "sync"
"time" "time"
"tailscale.com/health"
"tailscale.com/net/dns/resolvconffile" "tailscale.com/net/dns/resolvconffile"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
@ -50,6 +49,8 @@ func readResolv(r io.Reader) (OSConfig, error) {
// resolvOwner returns the apparent owner of the resolv.conf // resolvOwner returns the apparent owner of the resolv.conf
// configuration in bs - one of "resolvconf", "systemd-resolved" or // configuration in bs - one of "resolvconf", "systemd-resolved" or
// "NetworkManager", or "" if no known owner was found. // "NetworkManager", or "" if no known owner was found.
//
//lint:ignore U1000 used in linux and freebsd code
func resolvOwner(bs []byte) string { func resolvOwner(bs []byte) string {
likely := "" likely := ""
b := bytes.NewBuffer(bs) b := bytes.NewBuffer(bs)
@ -130,11 +131,13 @@ type directManager struct {
ctx context.Context // valid until Close ctx context.Context // valid until Close
ctxClose context.CancelFunc // closes ctx ctxClose context.CancelFunc // closes ctx
mu sync.Mutex mu sync.Mutex
wantResolvConf []byte // if non-nil, what we expect /etc/resolv.conf to contain 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 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 { func newDirectManager(logf logger.Logf) *directManager {
return newDirectManagerOnFS(logf, directFS{}) return newDirectManagerOnFS(logf, directFS{})
} }
@ -288,52 +291,6 @@ func (m *directManager) setWant(want []byte) {
m.wantResolvConf = want 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) { func (m *directManager) SetDNS(config OSConfig) (err error) {
defer func() { defer func() {
if err != nil && errors.Is(err, fs.ErrPermission) && runtime.GOOS == "linux" && if err != nil && errors.Is(err, fs.ErrPermission) && runtime.GOOS == "linux" &&

View File

@ -4,9 +4,12 @@
package dns package dns
import ( import (
"bytes"
"context" "context"
"errors"
"github.com/illarion/gonotify" "github.com/illarion/gonotify"
"tailscale.com/health"
) )
func (m *directManager) runFileWatcher() { 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) { func (m *directManager) closeInotifyOnDone(ctx context.Context, in *gonotify.Inotify) {
<-ctx.Done() <-ctx.Done()
in.Close() in.Close()

View File

@ -40,18 +40,6 @@
// the lint exception is necessary and on others it is not, // the lint exception is necessary and on others it is not,
// and plain ignore complains if the exception is unnecessary. // 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. // Manager manages system DNS settings.
type Manager struct { type Manager struct {
logf logger.Logf logf logger.Logf

View File

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

View File

@ -636,13 +636,6 @@ func mustIPs(strs ...string) (ret []netip.Addr) {
return ret 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) { func mustRes(strs ...string) (ret []*dnstype.Resolver) {
for _, s := range strs { for _, s := range strs {
ret = append(ret, &dnstype.Resolver{Addr: s}) ret = append(ret, &dnstype.Resolver{Addr: s})
@ -681,26 +674,6 @@ func hosts(strs ...string) (ret map[dnsname.FQDN][]netip.Addr) {
return ret 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) { func upstreams(strs ...string) (ret map[dnsname.FQDN][]*dnstype.Resolver) {
var key dnsname.FQDN var key dnsname.FQDN
ret = map[dnsname.FQDN][]*dnstype.Resolver{} ret = map[dnsname.FQDN][]*dnstype.Resolver{}

View File

@ -25,6 +25,13 @@
lowerPriority = int32(200) // lower than all builtin auto priorities 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. // nmManager uses the NetworkManager DBus API.
type nmManager struct { type nmManager struct {
interfaceName string interfaceName string

View File

@ -163,13 +163,6 @@ func (r *Resolver) logf(format string, args ...any) {
r.Logf(format, args...) 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) { func (r *Resolver) depthlogf(depth int, format string, args ...any) {
if r.Logf == nil || !debug() { if r.Logf == nil || !debug() {
return return

View File

@ -7,7 +7,6 @@
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"net" "net"
"strings" "strings"
@ -17,32 +16,10 @@
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"tailscale.com/health" "tailscale.com/health"
"tailscale.com/logtail/backoff" "tailscale.com/logtail/backoff"
"tailscale.com/net/netaddr"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/util/dnsname" "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 entities we talk to.
// //
// DBus is an RPC bus. In particular, the bus we're talking to is the // DBus is an RPC bus. In particular, the bus we're talking to is the

View File

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

View File

@ -37,8 +37,6 @@
testipv4Arpa = dnsname.FQDN("4.3.2.1.in-addr.arpa.") 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.") 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{ var dnsCfg = Config{

View File

@ -656,8 +656,6 @@ func v6addrs(aa []netip.Addr) (ret []netip.Addr) {
return ret 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. // TLSDialer is like Dialer but returns a func suitable for using with net/http.Transport.DialTLSContext.
// It returns a *tls.Conn type on success. // It returns a *tls.Conn type on success.
// On TLS cert validation failure, it can invoke a backup DNS resolution strategy. // On TLS cert validation failure, it can invoke a backup DNS resolution strategy.

View File

@ -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. // Start starts the monitor.
// A monitor can only be started & closed once. // A monitor can only be started & closed once.
func (m *Monitor) Start() { func (m *Monitor) Start() {

View File

@ -181,3 +181,10 @@ func (m *winMon) somethingChanged(evt string) {
return 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
}

View File

@ -53,12 +53,6 @@ func (ln *oneConnListener) Close() error {
return nil 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 type dummyAddr string
func (a dummyAddr) Network() string { return string(a) } func (a dummyAddr) Network() string { return string(a) }

View File

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

View File

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

View File

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

View File

@ -10,7 +10,6 @@
"fmt" "fmt"
"net" "net"
"runtime" "runtime"
"syscall"
"time" "time"
"github.com/tailscale/go-winio" "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) 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. // windowsSDDL is the Security Descriptor set on the namedpipe.
// It provides read/write access to all users and the local system. // It provides read/write access to all users and the local system.
// It is a var for testing, do not change this value. // It is a var for testing, do not change this value.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -12,11 +12,9 @@
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv"
"strings" "strings"
"sync" "sync"
"testing" "testing"
"time"
) )
// The code in this file is adapted from internal/testenv in the Go source tree // 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 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) { func startTestProg(t *testing.T, binary, name string, env ...string) {
exe, err := buildTestProg(t, binary, "-buildvcs=false") exe, err := buildTestProg(t, binary, "-buildvcs=false")
if err != nil { if err != nil {
@ -70,16 +59,6 @@ func startTestProg(t *testing.T, binary, name string, env ...string) {
startBuiltTestProg(t, exe, name, env...) 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) { func startBuiltTestProg(t *testing.T, exe, name string, env ...string) {
cmd := exec.Command(exe, name) cmd := exec.Command(exe, name)
cmd.Env = append(cmd.Env, env...) 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 ( var (
gorootOnce sync.Once gorootOnce sync.Once
gorootPath string gorootPath string
@ -366,57 +331,6 @@ func findGOROOT() (string, error) {
return gorootPath, gorootErr 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. // start runs cmd asynchronously and returns immediately.
func start(t testing.TB, cmd *exec.Cmd) { func start(t testing.TB, cmd *exec.Cmd) {
args := cmd.Args args := cmd.Args

View File

@ -382,26 +382,6 @@ func CreateAppMutex(name string) (windows.Handle, error) {
return windows.CreateMutex(nil, false, windows.StringToUTF16Ptr(name)) 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 // getTokenInfoFixedLen obtains known fixed-length token information. Use this
// function for information classes that output enumerations, BOOLs, integers etc. // function for information classes that output enumerations, BOOLs, integers etc.
func getTokenInfoFixedLen[T any](token windows.Token, infoClass uint32) (result T, err error) { func getTokenInfoFixedLen[T any](token windows.Token, infoClass uint32) (result T, err error) {

View File

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

View File

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

View File

@ -5,31 +5,6 @@
package magicsock 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) { func (c *Conn) DontFragSetting() (bool, error) {
return false, nil return false, nil
} }

View File

@ -9,7 +9,6 @@
"errors" "errors"
"fmt" "fmt"
"log" "log"
"net"
"net/netip" "net/netip"
"slices" "slices"
"sort" "sort"
@ -28,8 +27,6 @@
"tailscale.com/wgengine/winnet" "tailscale.com/wgengine/winnet"
) )
var wintunLinkLocal = netip.MustParseAddr("fe80::99d0:ec2d:b2e7:536b")
// monitorDefaultRoutes subscribes to route change events and updates // monitorDefaultRoutes subscribes to route change events and updates
// the Tailscale tunnel interface's MTU to match that of the // the Tailscale tunnel interface's MTU to match that of the
// underlying default route. // underlying default route.
@ -470,21 +467,6 @@ func configureInterface(cfg *Config, tun *tun.NativeTun) (retErr error) {
return errAcc 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 { func netCompare(a, b netip.Prefix) int {
aip, bip := a.Addr().Unmap(), b.Addr().Unmap() aip, bip := a.Addr().Unmap(), b.Addr().Unmap()
v := aip.Compare(bip) v := aip.Compare(bip)

View File

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