mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
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:
parent
c9836b454d
commit
2716250ee8
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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{
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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() {}
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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"
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
|
@ -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" &&
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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{}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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{
|
||||||
|
@ -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.
|
||||||
|
@ -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() {
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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) }
|
||||||
|
@ -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)}
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
]
|
]
|
||||||
|
@ -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 (
|
||||||
|
@ -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 (
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user