all: use Go 1.26 things, run most gofix modernizers

I omitted a lot of the min/max modernizers because they didn't
result in more clear code.

Some of it's older "for x := range 123".

Also: errors.AsType, any, fmt.Appendf, etc.

Updates #18682

Change-Id: I83a451577f33877f962766a5b65ce86f7696471c
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
main
Brad Fitzpatrick 1 month ago committed by Brad Fitzpatrick
parent 4453cc5f53
commit bd2a2d53d3
  1. 4
      appc/appconnector_test.go
  2. 10
      client/local/local.go
  3. 4
      client/systray/logo.go
  4. 4
      clientupdate/clientupdate.go
  5. 2
      clientupdate/clientupdate_test.go
  6. 2
      cmd/containerboot/forwarding.go
  7. 7
      cmd/containerboot/main_test.go
  8. 2
      cmd/derper/mesh.go
  9. 9
      cmd/k8s-operator/egress-eps_test.go
  10. 7
      cmd/k8s-operator/egress-services-readiness_test.go
  11. 2
      cmd/k8s-operator/egress-services_test.go
  12. 10
      cmd/k8s-operator/ingress-for-pg.go
  13. 2
      cmd/k8s-operator/ingress-for-pg_test.go
  14. 9
      cmd/k8s-operator/metrics_resources.go
  15. 9
      cmd/k8s-operator/proxygroup.go
  16. 5
      cmd/k8s-operator/proxygroup_specs.go
  17. 4
      cmd/k8s-operator/proxygroup_test.go
  18. 16
      cmd/k8s-operator/sts.go
  19. 5
      cmd/k8s-operator/sts_test.go
  20. 3
      cmd/k8s-operator/svc-for-pg.go
  21. 12
      cmd/k8s-operator/testutils_test.go
  22. 10
      cmd/k8s-operator/tsrecorder.go
  23. 5
      cmd/k8s-operator/tsrecorder_specs.go
  24. 4
      cmd/mkpkg/main.go
  25. 2
      cmd/natc/ippool/ippool_test.go
  26. 5
      cmd/natc/natc.go
  27. 4
      cmd/sniproxy/sniproxy.go
  28. 3
      cmd/speedtest/speedtest.go
  29. 3
      cmd/stunstamp/stunstamp.go
  30. 6
      cmd/tailscale/cli/appcroutes.go
  31. 2
      cmd/tailscale/cli/cli.go
  32. 4
      cmd/tailscale/cli/cli_test.go
  33. 8
      cmd/tailscale/cli/configure-synology-cert.go
  34. 7
      cmd/tailscale/cli/file.go
  35. 13
      cmd/tailscale/cli/ip.go
  36. 2
      cmd/tailscale/cli/risks.go
  37. 4
      cmd/tailscale/cli/serve_v2.go
  38. 7
      cmd/tailscale/cli/set.go
  39. 13
      cmd/tailscale/cli/ssh.go
  40. 3
      cmd/tailscale/cli/ssh_exec_windows.go
  41. 2
      cmd/tailscale/cli/ssh_unix.go
  42. 5
      cmd/tailscale/cli/up.go
  43. 3
      cmd/testwrapper/testwrapper.go
  44. 3
      cmd/testwrapper/testwrapper_test.go
  45. 2
      cmd/tta/tta.go
  46. 5
      cmd/viewer/viewer.go
  47. 8
      control/controlclient/controlclient_test.go
  48. 2
      control/controlclient/direct.go
  49. 8
      control/controlclient/map.go
  50. 4
      control/controlhttp/http_test.go
  51. 12
      control/controlknobs/controlknobs.go
  52. 12
      derp/derp_test.go
  53. 12
      derp/derphttp/derphttp_test.go
  54. 22
      derp/derpserver/derpserver.go
  55. 24
      derp/derpserver/derpserver_test.go
  56. 3
      derp/xdp/xdp_linux.go
  57. 8
      disco/disco.go
  58. 6
      docs/webhooks/example.go
  59. 2
      drive/driveimpl/compositedav/rewriting.go
  60. 9
      feature/conn25/conn25.go
  61. 2
      feature/conn25/conn25_test.go
  62. 3
      feature/identityfederation/identityfederation.go
  63. 2
      feature/linuxdnsfight/linuxdnsfight_test.go
  64. 2
      feature/taildrop/fileops_fs.go
  65. 5
      health/health_test.go
  66. 8
      hostinfo/hostinfo_linux.go
  67. 7
      ipn/auditlog/auditlog.go
  68. 2
      ipn/ipnlocal/breaktcp_linux.go
  69. 7
      ipn/ipnlocal/bus_test.go
  70. 2
      ipn/ipnlocal/extension_host.go
  71. 5
      ipn/ipnlocal/extension_host_test.go
  72. 13
      ipn/ipnlocal/local.go
  73. 2
      ipn/ipnlocal/netmapcache/netmapcache_test.go
  74. 2
      ipn/ipnlocal/peerapi.go
  75. 4
      ipn/ipnlocal/serve.go
  76. 6
      ipn/ipnlocal/ssh.go
  77. 7
      ipn/localapi/debug.go
  78. 20
      ipn/prefs.go
  79. 4
      ipn/prefs_test.go
  80. 2
      ipn/serve.go
  81. 3
      ipn/store/awsstore/store_aws.go
  82. 4
      k8s-operator/sessionrecording/spdy/frame.go
  83. 4
      logtail/logtail.go
  84. 6
      logtail/logtail_test.go
  85. 8
      metrics/multilabelmap.go
  86. 2
      net/art/stride_table_test.go
  87. 6
      net/captivedetection/captivedetection_test.go
  88. 2
      net/dns/manager_linux.go
  89. 2
      net/dns/openresolv.go
  90. 3
      net/dns/resolver/forwarder.go
  91. 16
      net/dns/resolver/forwarder_test.go
  92. 4
      net/dns/resolver/tsdns.go
  93. 3
      net/dns/wsl_windows.go
  94. 14
      net/netcheck/netcheck.go
  95. 9
      net/netcheck/netcheck_test.go
  96. 3
      net/neterror/neterror_linux.go
  97. 7
      net/netmon/state.go
  98. 4
      net/netutil/routes.go
  99. 7
      net/socks5/socks5.go
  100. 8
      net/socks5/socks5_test.go
  101. Some files were not shown because too many files have changed in this diff Show More

@ -698,7 +698,7 @@ func TestRateLogger(t *testing.T) {
wasCalled = true
})
for i := 0; i < 3; i++ {
for range 3 {
clock.Advance(1 * time.Millisecond)
rl.update(0)
if wasCalled {
@ -720,7 +720,7 @@ func TestRateLogger(t *testing.T) {
wasCalled = true
})
for i := 0; i < 3; i++ {
for range 3 {
clock.Advance(1 * time.Minute)
rl.update(0)
if wasCalled {

@ -192,8 +192,8 @@ func (e *AccessDeniedError) Unwrap() error { return e.err }
// IsAccessDeniedError reports whether err is or wraps an AccessDeniedError.
func IsAccessDeniedError(err error) bool {
var ae *AccessDeniedError
return errors.As(err, &ae)
_, ok := errors.AsType[*AccessDeniedError](err)
return ok
}
// PreconditionsFailedError is returned when the server responds
@ -210,8 +210,8 @@ func (e *PreconditionsFailedError) Unwrap() error { return e.err }
// IsPreconditionsFailedError reports whether err is or wraps an PreconditionsFailedError.
func IsPreconditionsFailedError(err error) bool {
var ae *PreconditionsFailedError
return errors.As(err, &ae)
_, ok := errors.AsType[*PreconditionsFailedError](err)
return ok
}
// bestError returns either err, or if body contains a valid JSON
@ -1071,7 +1071,7 @@ func tailscaledConnectHint() string {
// ActiveState=inactive
// SubState=dead
st := map[string]string{}
for _, line := range strings.Split(string(out), "\n") {
for line := range strings.SplitSeq(string(out), "\n") {
if k, v, ok := strings.Cut(line, "="); ok {
st[k] = strings.TrimSpace(v)
}

@ -233,8 +233,8 @@ func (logo tsLogo) renderWithBorder(borderUnits int) *bytes.Buffer {
dc.InvertMask()
}
for y := 0; y < 3; y++ {
for x := 0; x < 3; x++ {
for y := range 3 {
for x := range 3 {
px := (borderUnits + 1 + 3*x) * radius
py := (borderUnits + 1 + 3*y) * radius
col := fg

@ -1292,6 +1292,6 @@ func requireRoot() error {
}
func isExitError(err error) bool {
var exitErr *exec.ExitError
return errors.As(err, &exitErr)
_, ok := errors.AsType[*exec.ExitError](err)
return ok
}

@ -451,7 +451,7 @@ func TestSynoArch(t *testing.T) {
synoinfoConfPath := filepath.Join(t.TempDir(), "synoinfo.conf")
if err := os.WriteFile(
synoinfoConfPath,
[]byte(fmt.Sprintf("unique=%q\n", tt.synoinfoUnique)),
fmt.Appendf(nil, "unique=%q\n", tt.synoinfoUnique),
0600,
); err != nil {
t.Fatal(err)

@ -51,7 +51,7 @@ func ensureIPForwarding(root, clusterProxyTargetIP, tailnetTargetIP, tailnetTarg
v4Forwarding = true
}
if routes != nil && *routes != "" {
for _, route := range strings.Split(*routes, ",") {
for route := range strings.SplitSeq(*routes, ",") {
cidr, err := netip.ParsePrefix(route)
if err != nil {
return fmt.Errorf("invalid subnet route: %v", err)

@ -15,6 +15,7 @@ import (
"fmt"
"io"
"io/fs"
"maps"
"net"
"net/http"
"net/http/httptest"
@ -1249,7 +1250,7 @@ func (b *lockingBuffer) String() string {
func waitLogLine(t *testing.T, timeout time.Duration, b *lockingBuffer, want string) {
deadline := time.Now().Add(timeout)
for time.Now().Before(deadline) {
for _, line := range strings.Split(b.String(), "\n") {
for line := range strings.SplitSeq(b.String(), "\n") {
if !strings.HasPrefix(line, "boot: ") {
continue
}
@ -1438,9 +1439,7 @@ func (k *kubeServer) Secret() map[string]string {
k.Lock()
defer k.Unlock()
ret := map[string]string{}
for k, v := range k.secret {
ret[k] = v
}
maps.Copy(ret, k.secret)
return ret
}

@ -25,7 +25,7 @@ func startMesh(s *derpserver.Server) error {
if !s.HasMeshKey() {
return errors.New("--mesh-with requires --mesh-psk-file")
}
for _, hostTuple := range strings.Split(*meshWith, ",") {
for hostTuple := range strings.SplitSeq(*meshWith, ",") {
if err := startMeshWithHost(s, hostTuple); err != nil {
return err
}

@ -11,7 +11,6 @@ import (
"math/rand/v2"
"testing"
"github.com/AlekSi/pointer"
"go.uber.org/zap"
corev1 "k8s.io/api/core/v1"
discoveryv1 "k8s.io/api/discovery/v1"
@ -106,11 +105,11 @@ func TestTailscaleEgressEndpointSlices(t *testing.T) {
expectReconciled(t, er, "operator-ns", "foo")
eps.Endpoints = append(eps.Endpoints, discoveryv1.Endpoint{
Addresses: []string{"10.0.0.1"},
Hostname: pointer.To("foo"),
Hostname: new("foo"),
Conditions: discoveryv1.EndpointConditions{
Serving: pointer.ToBool(true),
Ready: pointer.ToBool(true),
Terminating: pointer.ToBool(false),
Serving: new(true),
Ready: new(true),
Terminating: new(false),
},
})
expectEqual(t, fc, eps)

@ -9,7 +9,6 @@ import (
"fmt"
"testing"
"github.com/AlekSi/pointer"
"go.uber.org/zap"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
@ -145,9 +144,9 @@ func setEndpointForReplica(pg *tsapi.ProxyGroup, ordinal int32, eps *discoveryv1
eps.Endpoints = append(eps.Endpoints, discoveryv1.Endpoint{
Addresses: []string{p.Status.PodIPs[0].IP},
Conditions: discoveryv1.EndpointConditions{
Ready: pointer.ToBool(true),
Serving: pointer.ToBool(true),
Terminating: pointer.ToBool(false),
Ready: new(true),
Serving: new(true),
Terminating: new(false),
},
})
}

@ -243,7 +243,7 @@ func portsForEndpointSlice(svc *corev1.Service) []discoveryv1.EndpointPort {
ports = append(ports, discoveryv1.EndpointPort{
Name: &p.Name,
Protocol: &p.Protocol,
Port: pointer.ToInt32(p.TargetPort.IntVal),
Port: new(p.TargetPort.IntVal),
})
}
return ports

@ -10,6 +10,7 @@ import (
"encoding/json"
"errors"
"fmt"
"maps"
"math/rand/v2"
"net/http"
"reflect"
@ -914,9 +915,7 @@ func ownerAnnotations(operatorID string, svc *tailscale.VIPService) (map[string]
}
newAnnots := make(map[string]string, len(svc.Annotations)+1)
for k, v := range svc.Annotations {
newAnnots[k] = v
}
maps.Copy(newAnnots, svc.Annotations)
newAnnots[ownerAnnotation] = string(json)
return newAnnots, nil
}
@ -1129,8 +1128,7 @@ func hasCerts(ctx context.Context, cl client.Client, lc localClient, ns string,
}
func isErrorTailscaleServiceNotFound(err error) bool {
var errResp tailscale.ErrResponse
ok := errors.As(err, &errResp)
errResp, ok := errors.AsType[tailscale.ErrResponse](err)
return ok && errResp.Status == http.StatusNotFound
}
@ -1144,7 +1142,7 @@ func tagViolations(obj client.Object) []string {
return nil
}
for _, tag := range strings.Split(tags, ",") {
for tag := range strings.SplitSeq(tags, ",") {
tag = strings.TrimSpace(tag)
if err := tailcfg.CheckTag(tag); err != nil {
violations = append(violations, fmt.Sprintf("invalid tag %q: %v", tag, err))

@ -1102,7 +1102,7 @@ func verifyTailscaledConfig(t *testing.T, fc client.Client, pgName string, expec
Labels: pgSecretLabels(pgName, kubetypes.LabelSecretTypeConfig),
},
Data: map[string][]byte{
tsoperator.TailscaledConfigFileName(pgMinCapabilityVersion): []byte(fmt.Sprintf(`{"Version":""%s}`, expected)),
tsoperator.TailscaledConfigFileName(pgMinCapabilityVersion): fmt.Appendf(nil, `{"Version":""%s}`, expected),
},
})
}

@ -8,6 +8,7 @@ package main
import (
"context"
"fmt"
"maps"
"reflect"
"go.uber.org/zap"
@ -286,11 +287,7 @@ func isNamespacedProxyType(typ string) bool {
func mergeMapKeys(a, b map[string]string) map[string]string {
m := make(map[string]string, len(a)+len(b))
for key, val := range b {
m[key] = val
}
for key, val := range a {
m[key] = val
}
maps.Copy(m, b)
maps.Copy(m, a)
return m
}

@ -308,8 +308,7 @@ func (r *ProxyGroupReconciler) maybeProvision(ctx context.Context, tailscaleClie
var err error
svcToNodePorts, tailscaledPort, err = r.ensureNodePortServiceCreated(ctx, pg, proxyClass)
if err != nil {
var allocatePortErr *allocatePortsErr
if errors.As(err, &allocatePortErr) {
if _, ok := errors.AsType[*allocatePortsErr](err); ok {
reason := reasonProxyGroupCreationFailed
msg := fmt.Sprintf("error provisioning NodePort Services for static endpoints: %v", err)
r.recorder.Event(pg, corev1.EventTypeWarning, reason, msg)
@ -321,8 +320,7 @@ func (r *ProxyGroupReconciler) maybeProvision(ctx context.Context, tailscaleClie
staticEndpoints, err := r.ensureConfigSecretsCreated(ctx, tailscaleClient, pg, proxyClass, svcToNodePorts)
if err != nil {
var selectorErr *FindStaticEndpointErr
if errors.As(err, &selectorErr) {
if _, ok := errors.AsType[*FindStaticEndpointErr](err); ok {
reason := reasonProxyGroupCreationFailed
msg := fmt.Sprintf("error provisioning config Secrets: %v", err)
r.recorder.Event(pg, corev1.EventTypeWarning, reason, msg)
@ -718,8 +716,7 @@ func (r *ProxyGroupReconciler) maybeCleanup(ctx context.Context, tailscaleClient
func (r *ProxyGroupReconciler) deleteTailnetDevice(ctx context.Context, tailscaleClient tsClient, id tailcfg.StableNodeID, logger *zap.SugaredLogger) error {
logger.Debugf("deleting device %s from control", string(id))
if err := tailscaleClient.DeleteDevice(ctx, string(id)); err != nil {
errResp := &tailscale.ErrResponse{}
if ok := errors.As(err, errResp); ok && errResp.Status == http.StatusNotFound {
if errResp, ok := errors.AsType[tailscale.ErrResponse](err); ok && errResp.Status == http.StatusNotFound {
logger.Debugf("device %s not found, likely because it has already been deleted from control", string(id))
} else {
return fmt.Errorf("error deleting device: %w", err)

@ -7,6 +7,7 @@ package main
import (
"fmt"
"maps"
"slices"
"strconv"
"strings"
@ -544,9 +545,7 @@ func pgSecretLabels(pgName, secretType string) map[string]string {
func pgLabels(pgName string, customLabels map[string]string) map[string]string {
labels := make(map[string]string, len(customLabels)+3)
for k, v := range customLabels {
labels[k] = v
}
maps.Copy(labels, customLabels)
labels[kubetypes.LabelManaged] = "true"
labels[LabelParentType] = "proxygroup"

@ -1826,10 +1826,10 @@ func addNodeIDToStateSecrets(t *testing.T, fc client.WithWatch, pg *tsapi.ProxyG
currentProfileKey: []byte(key),
key: bytes,
kubetypes.KeyDeviceIPs: []byte(`["1.2.3.4", "::1"]`),
kubetypes.KeyDeviceFQDN: []byte(fmt.Sprintf("hostname-nodeid-%d.tails-scales.ts.net", i)),
kubetypes.KeyDeviceFQDN: fmt.Appendf(nil, "hostname-nodeid-%d.tails-scales.ts.net", i),
// TODO(tomhjp): We have two different mechanisms to retrieve device IDs.
// Consolidate on this one.
kubetypes.KeyDeviceID: []byte(fmt.Sprintf("nodeid-%d", i)),
kubetypes.KeyDeviceID: fmt.Appendf(nil, "nodeid-%d", i),
kubetypes.KeyPodUID: []byte(podUID),
}
})

@ -11,6 +11,7 @@ import (
"encoding/json"
"errors"
"fmt"
"maps"
"net/http"
"os"
"path"
@ -304,8 +305,7 @@ func (a *tailscaleSTSReconciler) Cleanup(ctx context.Context, tailnet string, lo
if dev.id != "" {
logger.Debugf("deleting device %s from control", string(dev.id))
if err = tailscaleClient.DeleteDevice(ctx, string(dev.id)); err != nil {
errResp := &tailscale.ErrResponse{}
if ok := errors.As(err, errResp); ok && errResp.Status == http.StatusNotFound {
if errResp, ok := errors.AsType[tailscale.ErrResponse](err); ok && errResp.Status == http.StatusNotFound {
logger.Debugf("device %s not found, likely because it has already been deleted from control", string(dev.id))
} else {
return false, fmt.Errorf("deleting device: %w", err)
@ -499,14 +499,11 @@ func (a *tailscaleSTSReconciler) provisionSecrets(ctx context.Context, tailscale
}
if dev != nil && dev.id != "" {
var errResp *tailscale.ErrResponse
err = tailscaleClient.DeleteDevice(ctx, string(dev.id))
switch {
case errors.As(err, &errResp) && errResp.Status == http.StatusNotFound:
if errResp, ok := errors.AsType[*tailscale.ErrResponse](err); ok && errResp.Status == http.StatusNotFound {
// This device has possibly already been deleted in the admin console. So we can ignore this
// and move on to removing the secret.
case err != nil:
} else if err != nil {
return nil, err
}
}
@ -677,9 +674,8 @@ func (a *tailscaleSTSReconciler) reconcileSTS(ctx context.Context, logger *zap.S
},
}
mak.Set(&pod.Labels, "app", sts.ParentResourceUID)
for key, val := range sts.ChildResourceLabels {
pod.Labels[key] = val // sync StatefulSet labels to Pod to make it easier for users to select the Pod
}
// sync StatefulSet labels to Pod to make it easier for users to select the Pod
maps.Copy(pod.Labels, sts.ChildResourceLabels)
if sts.Replicas > 0 {
ss.Spec.Replicas = new(sts.Replicas)

@ -8,6 +8,7 @@ package main
import (
_ "embed"
"fmt"
"maps"
"reflect"
"regexp"
"strings"
@ -408,7 +409,5 @@ func Test_mergeStatefulSetLabelsOrAnnots(t *testing.T) {
// updateMap updates map a with the values from map b.
func updateMap(a, b map[string]string) {
for key, val := range b {
a[key] = val
}
maps.Copy(a, b)
}

@ -526,8 +526,7 @@ func (r *HAServiceReconciler) tailnetCertDomain(ctx context.Context) (string, er
func cleanupTailscaleService(ctx context.Context, tsClient tsClient, name tailcfg.ServiceName, operatorID string, logger *zap.SugaredLogger) (updated bool, err error) {
svc, err := tsClient.GetVIPService(ctx, name)
if err != nil {
errResp := &tailscale.ErrResponse{}
ok := errors.As(err, errResp)
errResp, ok := errors.AsType[tailscale.ErrResponse](err)
if ok && errResp.Status == http.StatusNotFound {
return false, nil
}

@ -13,6 +13,7 @@ import (
"net/netip"
"path"
"reflect"
"slices"
"strings"
"sync"
"testing"
@ -555,7 +556,7 @@ func expectedSecret(t *testing.T, cl client.Client, opts configOpts) *corev1.Sec
if opts.isExitNode {
r = "0.0.0.0/0,::/0," + r
}
for _, rr := range strings.Split(r, ",") {
for rr := range strings.SplitSeq(r, ",") {
prefix, err := netip.ParsePrefix(rr)
if err != nil {
t.Fatal(err)
@ -822,12 +823,9 @@ func expectEvents(t *testing.T, rec *record.FakeRecorder, wantsEvents []string)
select {
case gotEvent := <-rec.Events:
found := false
for _, wantEvent := range wantsEvents {
if wantEvent == gotEvent {
found = true
seenEvents = append(seenEvents, gotEvent)
break
}
if slices.Contains(wantsEvents, gotEvent) {
found = true
seenEvents = append(seenEvents, gotEvent)
}
if !found {
t.Errorf("got unexpected event %q, expected events: %+#v", gotEvent, wantsEvents)

@ -363,15 +363,12 @@ func (r *RecorderReconciler) maybeCleanupSecrets(ctx context.Context, tailscaleC
}
if ok {
var errResp *tailscale.ErrResponse
r.log.Debugf("deleting device %s", devicePrefs.Config.NodeID)
err = tailscaleClient.DeleteDevice(ctx, string(devicePrefs.Config.NodeID))
switch {
case errors.As(err, &errResp) && errResp.Status == http.StatusNotFound:
if errResp, ok := errors.AsType[*tailscale.ErrResponse](err); ok && errResp.Status == http.StatusNotFound {
// This device has possibly already been deleted in the admin console. So we can ignore this
// and move on to removing the secret.
case err != nil:
} else if err != nil {
return err
}
}
@ -412,8 +409,7 @@ func (r *RecorderReconciler) maybeCleanup(ctx context.Context, tsr *tsapi.Record
nodeID := string(devicePrefs.Config.NodeID)
logger.Debugf("deleting device %s from control", nodeID)
if err = tailscaleClient.DeleteDevice(ctx, nodeID); err != nil {
errResp := &tailscale.ErrResponse{}
if errors.As(err, errResp) && errResp.Status == http.StatusNotFound {
if errResp, ok := errors.AsType[tailscale.ErrResponse](err); ok && errResp.Status == http.StatusNotFound {
logger.Debugf("device %s not found, likely because it has already been deleted from control", nodeID)
continue
}

@ -7,6 +7,7 @@ package main
import (
"fmt"
"maps"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
@ -312,9 +313,7 @@ func tsrEnv(tsr *tsapi.Recorder, loginServer string) []corev1.EnvVar {
func tsrLabels(app, instance string, customLabels map[string]string) map[string]string {
labels := make(map[string]string, len(customLabels)+3)
for k, v := range customLabels {
labels[k] = v
}
maps.Copy(labels, customLabels)
// ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
labels["app.kubernetes.io/name"] = app

@ -24,7 +24,7 @@ func parseFiles(s string, typ string) (files.Contents, error) {
return nil, nil
}
var contents files.Contents
for _, f := range strings.Split(s, ",") {
for f := range strings.SplitSeq(s, ",") {
fs := strings.Split(f, ":")
if len(fs) != 2 {
return nil, fmt.Errorf("unparseable file field %q", f)
@ -41,7 +41,7 @@ func parseEmptyDirs(s string) files.Contents {
return nil
}
var contents files.Contents
for _, d := range strings.Split(s, ",") {
for d := range strings.SplitSeq(s, ",") {
contents = append(contents, &files.Content{Type: files.TypeDir, Destination: d})
}
return contents

@ -30,7 +30,7 @@ func TestIPPoolExhaustion(t *testing.T) {
from := tailcfg.NodeID(12345)
for i := 0; i < 5; i++ {
for range 5 {
for _, domain := range domains {
addr, err := pool.IPForDomain(from, domain)
if err != nil {

@ -149,7 +149,7 @@ func main() {
}
var prefixes []netip.Prefix
for _, s := range strings.Split(*v4PfxStr, ",") {
for s := range strings.SplitSeq(*v4PfxStr, ",") {
p := netip.MustParsePrefix(strings.TrimSpace(s))
if p.Masked() != p {
log.Fatalf("v4 prefix %v is not a masked prefix", p)
@ -372,8 +372,7 @@ func (c *connector) handleDNS(pc net.PacketConn, buf []byte, remoteAddr *net.UDP
addrQCount++
if _, ok := resolves[q.Name.String()]; !ok {
addrs, err := c.resolver.LookupNetIP(ctx, "ip", q.Name.String())
var dnsErr *net.DNSError
if errors.As(err, &dnsErr) && dnsErr.IsNotFound {
if dnsErr, ok := errors.AsType[*net.DNSError](err); ok && dnsErr.IsNotFound {
continue
}
if err != nil {

@ -225,7 +225,7 @@ func (s *sniproxy) mergeConfigFromFlags(out *appctype.AppConnectorConfig, ports,
Addrs: []netip.Addr{ip4, ip6},
}
if ports != "" {
for _, portStr := range strings.Split(ports, ",") {
for portStr := range strings.SplitSeq(ports, ",") {
port, err := strconv.ParseUint(portStr, 10, 16)
if err != nil {
log.Fatalf("invalid port: %s", portStr)
@ -238,7 +238,7 @@ func (s *sniproxy) mergeConfigFromFlags(out *appctype.AppConnectorConfig, ports,
}
var forwardConfigFromFlags []appctype.DNATConfig
for _, forwStr := range strings.Split(forwards, ",") {
for forwStr := range strings.SplitSeq(forwards, ",") {
if forwStr == "" {
continue
}

@ -72,8 +72,7 @@ var speedtestArgs struct {
func runSpeedtest(ctx context.Context, args []string) error {
if _, _, err := net.SplitHostPort(speedtestArgs.host); err != nil {
var addrErr *net.AddrError
if errors.As(err, &addrErr) && addrErr.Err == "missing port in address" {
if addrErr, ok := errors.AsType[*net.AddrError](err); ok && addrErr.Err == "missing port in address" {
// if no port is provided, append the default port
speedtestArgs.host = net.JoinHostPort(speedtestArgs.host, strconv.Itoa(speedtest.DefaultPort))
}

@ -889,8 +889,7 @@ func remoteWriteTimeSeries(client *remoteWriteClient, tsCh chan []prompb.TimeSer
reqCtx, cancel := context.WithTimeout(context.Background(), time.Second*30)
writeErr = client.write(reqCtx, ts)
cancel()
var re recoverableErr
recoverable := errors.As(writeErr, &re)
_, recoverable := errors.AsType[recoverableErr](writeErr)
if writeErr != nil {
log.Printf("remote write error(recoverable=%v): %v", recoverable, writeErr)
}

@ -102,12 +102,12 @@ func getSummarizeLearnedOutput(ri *appctype.RouteInfo) string {
}
return 0
})
s := ""
var s strings.Builder
fmtString := fmt.Sprintf("%%-%ds %%d\n", maxDomainWidth) // eg "%-10s %d\n"
for _, dc := range x {
s += fmt.Sprintf(fmtString, dc.domain, dc.count)
s.WriteString(fmt.Sprintf(fmtString, dc.domain, dc.count))
}
return s
return s.String()
}
func runAppcRoutesInfo(ctx context.Context, args []string) error {

@ -124,7 +124,7 @@ func Run(args []string) (err error) {
if errors.Is(err, flag.ErrHelp) {
return nil
}
if noexec := (ffcli.NoExecError{}); errors.As(err, &noexec) {
if noexec, ok := errors.AsType[ffcli.NoExecError](err); ok {
// When the user enters an unknown subcommand, ffcli tries to run
// the closest valid parent subcommand with everything else as args,
// returning NoExecError if it doesn't have an Exec function.

@ -962,8 +962,8 @@ func TestPrefFlagMapping(t *testing.T) {
}
prefType := reflect.TypeFor[ipn.Prefs]()
for i := range prefType.NumField() {
prefName := prefType.Field(i).Name
for field := range prefType.Fields() {
prefName := field.Name
if prefHasFlag[prefName] {
continue
}

@ -16,6 +16,7 @@ import (
"os/exec"
"path"
"runtime"
"slices"
"strings"
"github.com/peterbourgon/ff/v3/ffcli"
@ -85,11 +86,8 @@ func runConfigureSynologyCert(ctx context.Context, args []string) error {
domain = st.CertDomains[0]
} else {
var found bool
for _, d := range st.CertDomains {
if d == domain {
found = true
break
}
if slices.Contains(st.CertDomains, domain) {
found = true
}
if !found {
return fmt.Errorf("Domain %q was not one of the valid domain options: %q.", domain, st.CertDomains)

@ -19,6 +19,7 @@ import (
"os"
"path"
"path/filepath"
"slices"
"strings"
"sync"
"sync/atomic"
@ -126,10 +127,8 @@ func runCp(ctx context.Context, args []string) error {
if cpArgs.name != "" {
return errors.New("can't use --name= with multiple files")
}
for _, fileArg := range files {
if fileArg == "-" {
return errors.New("can't use '-' as STDIN file when providing filename arguments")
}
if slices.Contains(files, "-") {
return errors.New("can't use '-' as STDIN file when providing filename arguments")
}
}

@ -9,6 +9,7 @@ import (
"flag"
"fmt"
"net/netip"
"slices"
"github.com/peterbourgon/ff/v3/ffcli"
"tailscale.com/ipn/ipnstate"
@ -114,17 +115,13 @@ func peerMatchingIP(st *ipnstate.Status, ipStr string) (ps *ipnstate.PeerStatus,
return
}
for _, ps = range st.Peer {
for _, pip := range ps.TailscaleIPs {
if ip == pip {
return ps, true
}
if slices.Contains(ps.TailscaleIPs, ip) {
return ps, true
}
}
if ps := st.Self; ps != nil {
for _, pip := range ps.TailscaleIPs {
if ip == pip {
return ps, true
}
if slices.Contains(ps.TailscaleIPs, ip) {
return ps, true
}
}
return nil, false

@ -39,7 +39,7 @@ func registerAcceptRiskFlag(f *flag.FlagSet, acceptedRisks *string) {
// isRiskAccepted reports whether riskType is in the comma-separated list of
// risks in acceptedRisks.
func isRiskAccepted(riskType, acceptedRisks string) bool {
for _, r := range strings.Split(acceptedRisks, ",") {
for r := range strings.SplitSeq(acceptedRisks, ",") {
if r == riskType || r == riskAll {
return true
}

@ -114,8 +114,8 @@ func (u *acceptAppCapsFlag) Set(s string) error {
if s == "" {
return nil
}
appCaps := strings.Split(s, ",")
for _, appCap := range appCaps {
appCaps := strings.SplitSeq(s, ",")
for appCap := range appCaps {
appCap = strings.TrimSpace(appCap)
if !validAppCap.MatchString(appCap) {
return fmt.Errorf("%q does not match the form {domain}/{name}, where domain must be a fully qualified domain name", appCap)

@ -183,8 +183,7 @@ func runSet(ctx context.Context, args []string) (retErr error) {
maskedPrefs.AutoExitNode = expr
maskedPrefs.AutoExitNodeSet = true
} else if err := maskedPrefs.Prefs.SetExitNodeIP(setArgs.exitNodeIP, st); err != nil {
var e ipn.ExitNodeLocalIPError
if errors.As(err, &e) {
if _, ok := errors.AsType[ipn.ExitNodeLocalIPError](err); ok {
return fmt.Errorf("%w; did you mean --advertise-exit-node?", err)
}
return err
@ -251,8 +250,8 @@ func runSet(ctx context.Context, args []string) (retErr error) {
if setArgs.relayServerStaticEndpoints != "" {
endpointsSet := make(set.Set[netip.AddrPort])
endpointsSplit := strings.Split(setArgs.relayServerStaticEndpoints, ",")
for _, s := range endpointsSplit {
endpointsSplit := strings.SplitSeq(setArgs.relayServerStaticEndpoints, ",")
for s := range endpointsSplit {
ap, err := netip.ParseAddrPort(s)
if err != nil {
return fmt.Errorf("failed to set relay server static endpoints: %q is not a valid IP:port", s)

@ -14,6 +14,7 @@ import (
"os/user"
"path/filepath"
"runtime"
"slices"
"strings"
"github.com/peterbourgon/ff/v3/ffcli"
@ -202,10 +203,8 @@ func peerStatusFromArg(st *ipnstate.Status, arg string) (*ipnstate.PeerStatus, b
argIP, _ := netip.ParseAddr(arg)
for _, ps := range st.Peer {
if argIP.IsValid() {
for _, ip := range ps.TailscaleIPs {
if ip == argIP {
return ps, true
}
if slices.Contains(ps.TailscaleIPs, argIP) {
return ps, true
}
continue
}
@ -230,10 +229,8 @@ func nodeDNSNameFromArg(st *ipnstate.Status, arg string) (dnsName string, ok boo
for _, ps := range st.Peer {
dnsName = ps.DNSName
if argIP.IsValid() {
for _, ip := range ps.TailscaleIPs {
if ip == argIP {
return dnsName, true
}
if slices.Contains(ps.TailscaleIPs, argIP) {
return dnsName, true
}
continue
}

@ -28,9 +28,8 @@ func execSSH(ssh string, argv []string) error {
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
var ee *exec.ExitError
err := cmd.Run()
if errors.As(err, &ee) {
if ee, ok := errors.AsType[*exec.ExitError](err); ok {
os.Exit(ee.ExitCode())
}
return err

@ -39,7 +39,7 @@ func init() {
return ""
}
prefix := []byte("SSH_CLIENT=")
for _, env := range bytes.Split(b, []byte{0}) {
for env := range bytes.SplitSeq(b, []byte{0}) {
if bytes.HasPrefix(env, prefix) {
return string(env[len(prefix):])
}

@ -334,8 +334,7 @@ func prefsFromUpArgs(upArgs upArgsT, warnf logger.Logf, st *ipnstate.Status, goo
if expr, useAutoExitNode := ipn.ParseAutoExitNodeString(upArgs.exitNodeIP); useAutoExitNode {
prefs.AutoExitNode = expr
} else if err := prefs.SetExitNodeIP(upArgs.exitNodeIP, st); err != nil {
var e ipn.ExitNodeLocalIPError
if errors.As(err, &e) {
if _, ok := errors.AsType[ipn.ExitNodeLocalIPError](err); ok {
return nil, fmt.Errorf("%w; did you mean --advertise-exit-node?", err)
}
return nil, err
@ -912,7 +911,7 @@ func addPrefFlagMapping(flagName string, prefNames ...string) {
prefType := reflect.TypeFor[ipn.Prefs]()
for _, pref := range prefNames {
t := prefType
for _, name := range strings.Split(pref, ".") {
for name := range strings.SplitSeq(pref, ".") {
// Crash at runtime if there's a typo in the prefName.
f, ok := t.FieldByName(name)
if !ok {

@ -352,8 +352,7 @@ func main() {
// If there's nothing to retry and no non-retryable tests have
// failed then we've probably hit a build error.
if err := <-runErr; len(toRetry) == 0 && err != nil {
var exit *exec.ExitError
if errors.As(err, &exit) {
if exit, ok := errors.AsType[*exec.ExitError](err); ok {
if code := exit.ExitCode(); code > -1 {
os.Exit(exit.ExitCode())
}

@ -273,8 +273,7 @@ func TestCached(t *testing.T) {}
}
func errExitCode(err error) (int, bool) {
var exit *exec.ExitError
if errors.As(err, &exit) {
if exit, ok := errors.AsType[*exec.ExitError](err); ok {
return exit.ExitCode(), true
}
return 0, false

@ -91,7 +91,7 @@ func main() {
if distro.Get() == distro.Gokrazy {
cmdLine, _ := os.ReadFile("/proc/cmdline")
explicitNS := false
for _, s := range strings.Fields(string(cmdLine)) {
for s := range strings.FieldsSeq(string(cmdLine)) {
if ns, ok := strings.CutPrefix(s, "tta.nameserver="); ok {
err := atomicfile.WriteFile("/tmp/resolv.conf", []byte("nameserver "+ns+"\n"), 0644)
log.Printf("Wrote /tmp/resolv.conf: %v", err)

@ -500,8 +500,7 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, fie
}
writeTemplateWithComment("unsupportedField", fname)
}
for i := range typ.NumMethods() {
f := typ.Method(i)
for f := range typ.Methods() {
if !f.Exported() {
continue
}
@ -720,7 +719,7 @@ func main() {
fieldComments := getFieldComments(pkg.Syntax)
cloneOnlyType := map[string]bool{}
for _, t := range strings.Split(*flagCloneOnlyTypes, ",") {
for t := range strings.SplitSeq(*flagCloneOnlyTypes, ",") {
cloneOnlyType[t] = true
}

@ -38,8 +38,8 @@ import (
)
func fieldsOf(t reflect.Type) (fields []string) {
for i := range t.NumField() {
if name := t.Field(i).Name; name != "_" {
for field := range t.Fields() {
if name := field.Name; name != "_" {
fields = append(fields, name)
}
}
@ -214,12 +214,12 @@ func TestRetryableErrors(t *testing.T) {
}
type retryableForTest interface {
error
Retryable() bool
}
func isRetryableErrorForTest(err error) bool {
var ae retryableForTest
if errors.As(err, &ae) {
if ae, ok := errors.AsType[retryableForTest](err); ok {
return ae.Retryable()
}
return false

@ -1484,7 +1484,7 @@ func (c *Direct) answerPing(pr *tailcfg.PingRequest) {
}
return
}
for _, t := range strings.Split(pr.Types, ",") {
for t := range strings.SplitSeq(pr.Types, ",") {
switch pt := tailcfg.PingType(t); pt {
case tailcfg.PingTSMP, tailcfg.PingDisco, tailcfg.PingICMP, tailcfg.PingPeerAPI:
go doPingerPing(c.logf, httpc, pr, c.pinger, pt)

@ -617,12 +617,12 @@ func (ms *mapSession) patchifyPeersChanged(resp *tailcfg.MapResponse) {
var nodeFields = sync.OnceValue(getNodeFields)
// getNodeFields returns the fails of tailcfg.Node.
// getNodeFields returns the fields of tailcfg.Node.
func getNodeFields() []string {
rt := reflect.TypeFor[tailcfg.Node]()
ret := make([]string, rt.NumField())
for i := range rt.NumField() {
ret[i] = rt.Field(i).Name
ret := make([]string, 0, rt.NumField())
for f := range rt.Fields() {
ret = append(ret, f.Name)
}
return ret
}

@ -814,8 +814,8 @@ func runDialPlanTest(t *testing.T, plan *tailcfg.ControlDialPlan, want []netip.A
// split on "|" first to remove memnet pipe suffix
addrPart := raddrStr
if idx := strings.Index(raddrStr, "|"); idx >= 0 {
addrPart = raddrStr[:idx]
if before, _, ok := strings.Cut(raddrStr, "|"); ok {
addrPart = before
}
host, _, err2 := net.SplitHostPort(addrPart)

@ -205,17 +205,15 @@ func (k *Knobs) AsDebugJSON() map[string]any {
return nil
}
ret := map[string]any{}
rt := reflect.TypeFor[Knobs]()
rv := reflect.ValueOf(k).Elem() // of *k
for i := 0; i < rt.NumField(); i++ {
name := rt.Field(i).Name
switch v := rv.Field(i).Addr().Interface().(type) {
for sf, fv := range rv.Fields() {
switch v := fv.Addr().Interface().(type) {
case *atomic.Bool:
ret[name] = v.Load()
ret[sf.Name] = v.Load()
case *syncs.AtomicValue[opt.Bool]:
ret[name] = v.Load()
ret[sf.Name] = v.Load()
default:
panic(fmt.Sprintf("unknown field type %T for %v", v, name))
panic(fmt.Sprintf("unknown field type %T for %v", v, sf.Name))
}
}
return ret

@ -121,8 +121,7 @@ func TestSendRecv(t *testing.T) {
}
defer cin.Close()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ctx := t.Context()
brwServer := bufio.NewReadWriter(bufio.NewReader(cin), bufio.NewWriter(cin))
go s.Accept(ctx, cin, brwServer, fmt.Sprintf("[abc::def]:%v", i))
@ -331,8 +330,7 @@ func TestSendFreeze(t *testing.T) {
return c, c2
}
ctx, clientCtxCancel := context.WithCancel(context.Background())
defer clientCtxCancel()
ctx := t.Context()
aliceKey := key.NewNode()
aliceClient, aliceConn := newClient(ctx, "alice", aliceKey)
@ -716,8 +714,7 @@ func (c *testClient) close(t *testing.T) {
// TestWatch tests the connection watcher mechanism used by regional
// DERP nodes to mesh up with each other.
func TestWatch(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ctx := t.Context()
ts := newTestServer(t, ctx)
defer ts.close(t)
@ -764,8 +761,7 @@ func waitConnect(t testing.TB, c *Client) {
}
func TestServerRepliesToPing(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ctx := t.Context()
ts := newTestServer(t, ctx)
defer ts.close(t)

@ -299,9 +299,7 @@ func TestBreakWatcherConnRecv(t *testing.T) {
errChan := make(chan error, 1)
// Start the watcher thread (which connects to the watched server)
wg.Add(1) // To avoid using t.Logf after the test ends. See https://golang.org/issue/40343
go func() {
defer wg.Done()
wg.Go(func() {
var peers int
add := func(m derp.PeerPresentMessage) {
t.Logf("add: %v", m.Key.ShortString())
@ -318,7 +316,7 @@ func TestBreakWatcherConnRecv(t *testing.T) {
}
watcher.RunWatchConnectionLoop(ctx, serverPrivateKey1.Public(), t.Logf, add, remove, notifyErr)
}()
})
synctest.Wait()
@ -381,9 +379,7 @@ func TestBreakWatcherConn(t *testing.T) {
errorChan := make(chan error, 1)
// Start the watcher thread (which connects to the watched server)
wg.Add(1) // To avoid using t.Logf after the test ends. See https://golang.org/issue/40343
go func() {
defer wg.Done()
wg.Go(func() {
var peers int
add := func(m derp.PeerPresentMessage) {
t.Logf("add: %v", m.Key.ShortString())
@ -403,7 +399,7 @@ func TestBreakWatcherConn(t *testing.T) {
}
watcher1.RunWatchConnectionLoop(ctx, serverPrivateKey1.Public(), t.Logf, add, remove, notifyError)
}()
})
synctest.Wait()

@ -30,6 +30,7 @@ import (
"os"
"os/exec"
"runtime"
"slices"
"strconv"
"strings"
"sync"
@ -71,7 +72,7 @@ func init() {
if keys == "" {
return
}
for _, keyStr := range strings.Split(keys, ",") {
for keyStr := range strings.SplitSeq(keys, ",") {
k, err := key.ParseNodePublicUntyped(mem.S(keyStr))
if err != nil {
log.Printf("ignoring invalid debug key %q: %v", keyStr, err)
@ -1287,7 +1288,7 @@ func (c *sclient) sendPkt(dst *sclient, p pkt) error {
if disco.LooksLikeDiscoWrapper(p.bs) {
sendQueue = dst.discoSendQueue
}
for attempt := 0; attempt < 3; attempt++ {
for attempt := range 3 {
select {
case <-dst.done:
s.recordDrop(p.bs, c.key, dstKey, dropReasonGoneDisconnected)
@ -1484,16 +1485,13 @@ func (s *Server) noteClientActivity(c *sclient) {
// If we saw this connection send previously, then consider
// the group fighting and disable them all.
if s.dupPolicy == disableFighters {
for _, prior := range dup.sendHistory {
if prior == c {
cs.ForeachClient(func(c *sclient) {
c.isDisabled.Store(true)
if cs.activeClient.Load() == c {
cs.activeClient.Store(nil)
}
})
break
}
if slices.Contains(dup.sendHistory, c) {
cs.ForeachClient(func(c *sclient) {
c.isDisabled.Store(true)
if cs.activeClient.Load() == c {
cs.activeClient.Store(nil)
}
})
}
}

@ -627,22 +627,17 @@ func BenchmarkConcurrentStreams(b *testing.B) {
if err != nil {
b.Fatal(err)
}
defer ln.Close()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ctx := b.Context()
acceptDone := make(chan struct{})
go func() {
for ctx.Err() == nil {
defer close(acceptDone)
for {
connIn, err := ln.Accept()
if err != nil {
if ctx.Err() != nil {
return
}
b.Error(err)
return
}
brwServer := bufio.NewReadWriter(bufio.NewReader(connIn), bufio.NewWriter(connIn))
go s.Accept(ctx, connIn, brwServer, "test-client")
}
@ -680,6 +675,9 @@ func BenchmarkConcurrentStreams(b *testing.B) {
}
}
})
ln.Close()
<-acceptDone
}
func BenchmarkSendRecv(b *testing.B) {
@ -769,7 +767,7 @@ func TestServeDebugTrafficUniqueSenders(t *testing.T) {
senderCardinality: hyperloglog.New(),
}
for i := 0; i < 5; i++ {
for range 5 {
c.senderCardinality.Insert(key.NewNode().Public().AppendTo(nil))
}
@ -845,7 +843,7 @@ func TestSenderCardinality(t *testing.T) {
t.Errorf("EstimatedUniqueSenders() = %d, want ~10 (8-12 range)", estimate)
}
for i := 0; i < 5; i++ {
for i := range 5 {
c.senderCardinality.Insert(senders[i].AppendTo(nil))
}
@ -869,7 +867,7 @@ func TestSenderCardinality100(t *testing.T) {
}
numSenders := 100
for i := 0; i < numSenders; i++ {
for range numSenders {
c.senderCardinality.Insert(key.NewNode().Public().AppendTo(nil))
}
@ -945,7 +943,7 @@ func BenchmarkHyperLogLogInsertUnique(b *testing.B) {
func BenchmarkHyperLogLogEstimate(b *testing.B) {
hll := hyperloglog.New()
for i := 0; i < 100; i++ {
for range 100 {
hll.Insert(key.NewNode().Public().AppendTo(nil))
}

@ -62,8 +62,7 @@ func NewSTUNServer(config *STUNServerConfig, opts ...STUNServerOption) (*STUNSer
objs := new(bpfObjects)
err = loadBpfObjects(objs, nil)
if err != nil {
var ve *ebpf.VerifierError
if config.FullVerifierErr && errors.As(err, &ve) {
if ve, ok := errors.AsType[*ebpf.VerifierError](err); config.FullVerifierErr && ok {
err = fmt.Errorf("verifier error: %+v", ve)
}
return nil, fmt.Errorf("error loading XDP program: %w", err)

@ -475,7 +475,7 @@ const allocateUDPRelayEndpointRequestLen = key.DiscoPublicRawLen*2 + // ClientDi
func (m *AllocateUDPRelayEndpointRequest) AppendMarshal(b []byte) []byte {
ret, p := appendMsgHeader(b, TypeAllocateUDPRelayEndpointRequest, v0, allocateUDPRelayEndpointRequestLen)
for i := 0; i < len(m.ClientDisco); i++ {
for i := range len(m.ClientDisco) {
disco := m.ClientDisco[i].AppendTo(nil)
copy(p, disco)
p = p[key.DiscoPublicRawLen:]
@ -492,7 +492,7 @@ func parseAllocateUDPRelayEndpointRequest(ver uint8, p []byte) (m *AllocateUDPRe
if len(p) < allocateUDPRelayEndpointRequestLen {
return m, errShort
}
for i := 0; i < len(m.ClientDisco); i++ {
for i := range len(m.ClientDisco) {
m.ClientDisco[i] = key.DiscoPublicFromRaw32(mem.B(p[:key.DiscoPublicRawLen]))
p = p[key.DiscoPublicRawLen:]
}
@ -565,7 +565,7 @@ func (m *UDPRelayEndpoint) encode(b []byte) {
disco := m.ServerDisco.AppendTo(nil)
copy(b, disco)
b = b[key.DiscoPublicRawLen:]
for i := 0; i < len(m.ClientDisco); i++ {
for i := range len(m.ClientDisco) {
disco = m.ClientDisco[i].AppendTo(nil)
copy(b, disco)
b = b[key.DiscoPublicRawLen:]
@ -594,7 +594,7 @@ func (m *UDPRelayEndpoint) decode(b []byte) error {
}
m.ServerDisco = key.DiscoPublicFromRaw32(mem.B(b[:key.DiscoPublicRawLen]))
b = b[key.DiscoPublicRawLen:]
for i := 0; i < len(m.ClientDisco); i++ {
for i := range len(m.ClientDisco) {
m.ClientDisco[i] = key.DiscoPublicFromRaw32(mem.B(b[:key.DiscoPublicRawLen]))
b = b[key.DiscoPublicRawLen:]
}

@ -87,7 +87,7 @@ func verifyWebhookSignature(req *http.Request, secret string) (events []event, e
return nil, err
}
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(fmt.Sprint(timestamp.Unix())))
mac.Write(fmt.Append(nil, timestamp.Unix()))
mac.Write([]byte("."))
mac.Write(b)
want := hex.EncodeToString(mac.Sum(nil))
@ -120,8 +120,8 @@ func parseSignatureHeader(header string) (timestamp time.Time, signatures map[st
}
signatures = make(map[string][]string)
pairs := strings.Split(header, ",")
for _, pair := range pairs {
pairs := strings.SplitSeq(header, ",")
for pair := range pairs {
parts := strings.Split(pair, "=")
if len(parts) != 2 {
return time.Time{}, nil, errNotSigned

@ -63,7 +63,7 @@ func (h *Handler) delegateRewriting(w http.ResponseWriter, r *http.Request, path
// Fixup paths to add the requested path as a prefix, escaped for inclusion in XML.
pp := shared.EscapeForXML(shared.Join(pathComponents[0:mpl]...))
b := responseHrefRegex.ReplaceAll(bw.buf.Bytes(), []byte(fmt.Sprintf("$1<D:href>%s/$3</D:href>", pp)))
b := responseHrefRegex.ReplaceAll(bw.buf.Bytes(), fmt.Appendf(nil, "$1<D:href>%s/$3</D:href>", pp))
return bw.status, b
}

@ -12,6 +12,7 @@ import (
"errors"
"net/http"
"net/netip"
"slices"
"sync"
"go4.org/netipx"
@ -329,13 +330,7 @@ func configFromNodeView(n tailcfg.NodeView) (config, error) {
selfRoutedDomains: set.Set[dnsname.FQDN]{},
}
for _, app := range apps {
selfMatchesTags := false
for _, tag := range app.Connectors {
if selfTags.Contains(tag) {
selfMatchesTags = true
break
}
}
selfMatchesTags := slices.ContainsFunc(app.Connectors, selfTags.Contains)
for _, d := range app.Domains {
fqdn, err := dnsname.ToFQDN(d)
if err != nil {

@ -115,7 +115,7 @@ func TestHandleConnectorTransitIPRequestMultipleTIP(t *testing.T) {
t.Fatalf("n TransitIPs in response: %d, want 3", len(resp.TransitIPs))
}
for i := 0; i < 3; i++ {
for i := range 3 {
got := resp.TransitIPs[i].Code
if got != TransitIPResponseCode(0) {
t.Fatalf("i=%d TransitIP Code: %d, want 0", i, got)

@ -128,8 +128,7 @@ func exchangeJWTForToken(ctx context.Context, baseURL, clientID, idToken string)
}).Exchange(ctx, "", oauth2.SetAuthURLParam("client_id", clientID), oauth2.SetAuthURLParam("jwt", idToken))
if err != nil {
// Try to extract more detailed error message
var retrieveErr *oauth2.RetrieveError
if errors.As(err, &retrieveErr) {
if retrieveErr, ok := errors.AsType[*oauth2.RetrieveError](err); ok {
return "", fmt.Errorf("token exchange failed with status %d: %s", retrieveErr.Response.StatusCode, string(retrieveErr.Body))
}
return "", fmt.Errorf("unexpected token exchange request error: %w", err)

@ -42,7 +42,7 @@ func TestWatchFile(t *testing.T) {
// Keep writing until we get a callback.
func() {
for i := range 10000 {
if err := os.WriteFile(filepath, []byte(fmt.Sprintf("write%d", i)), 0644); err != nil {
if err := os.WriteFile(filepath, fmt.Appendf(nil, "write%d", i), 0644); err != nil {
t.Fatal(err)
}
select {

@ -101,7 +101,7 @@ func (f fsFileOps) Rename(oldPath, newName string) (newPath string, err error) {
wantSize := st.Size()
const maxRetries = 10
for i := 0; i < maxRetries; i++ {
for range maxRetries {
renameMu.Lock()
fi, statErr := os.Stat(dst)
// Atomically rename the partial file as the destination file if it doesn't exist.

@ -82,8 +82,7 @@ func TestAppendWarnableDebugFlags(t *testing.T) {
func TestNilMethodsDontCrash(t *testing.T) {
var nilt *Tracker
rv := reflect.ValueOf(nilt)
for i := 0; i < rv.NumMethod(); i++ {
mt := rv.Type().Method(i)
for mt, method := range rv.Methods() {
t.Logf("calling Tracker.%s ...", mt.Name)
var args []reflect.Value
for j := 0; j < mt.Type.NumIn(); j++ {
@ -92,7 +91,7 @@ func TestNilMethodsDontCrash(t *testing.T) {
}
args = append(args, reflect.Zero(mt.Type.In(j)))
}
rv.Method(i).Call(args)
method.Call(args)
}
}

@ -68,7 +68,7 @@ func deviceModelLinux() string {
}
func getQnapQtsVersion(versionInfo string) string {
for _, field := range strings.Fields(versionInfo) {
for field := range strings.FieldsSeq(versionInfo) {
if suffix, ok := strings.CutPrefix(field, "QTSFW_"); ok {
return suffix
}
@ -110,11 +110,11 @@ func linuxVersionMeta() (meta versionMeta) {
if err != nil {
break
}
eq := bytes.IndexByte(line, '=')
if eq == -1 {
before, after, ok := bytes.Cut(line, []byte{'='})
if !ok {
continue
}
k, v := string(line[:eq]), strings.Trim(string(line[eq+1:]), `"'`)
k, v := string(before), strings.Trim(string(after), `"'`)
m[k] = v
}

@ -69,8 +69,11 @@ type Opts struct {
// IsRetryableError returns true if the given error is retryable
// See [controlclient.apiResponseError]. Potentially retryable errors implement the Retryable() method.
func IsRetryableError(err error) bool {
var retryable interface{ Retryable() bool }
return errors.As(err, &retryable) && retryable.Retryable()
retryable, ok := errors.AsType[interface {
error
Retryable() bool
}](err)
return ok && retryable.Retryable()
}
type backoffOpts struct {

@ -15,7 +15,7 @@ func init() {
func breakTCPConnsLinux() error {
var matched int
for fd := 0; fd < 1000; fd++ {
for fd := range 1000 {
_, err := unix.GetsockoptTCPInfo(fd, unix.IPPROTO_TCP, unix.TCP_INFO)
if err == nil {
matched++

@ -36,9 +36,8 @@ func TestIsNotableNotify(t *testing.T) {
// We use reflect to catch fields that might be added in the future without
// remembering to update the [isNotableNotify] function.
rt := reflect.TypeFor[ipn.Notify]()
for i := range rt.NumField() {
for sf := range rt.Fields() {
n := &ipn.Notify{}
sf := rt.Field(i)
switch sf.Name {
case "_", "NetMap", "Engine", "Version":
// Already covered above or not applicable.
@ -46,7 +45,7 @@ func TestIsNotableNotify(t *testing.T) {
case "DriveShares":
n.DriveShares = views.SliceOfViews[*drive.Share, drive.ShareView](make([]*drive.Share, 1))
default:
rf := reflect.ValueOf(n).Elem().Field(i)
rf := reflect.ValueOf(n).Elem().FieldByIndex(sf.Index)
switch rf.Kind() {
case reflect.Pointer:
rf.Set(reflect.New(rf.Type().Elem()))
@ -64,7 +63,7 @@ func TestIsNotableNotify(t *testing.T) {
notify *ipn.Notify
want bool
}{
name: "field-" + rt.Field(i).Name,
name: "field-" + sf.Name,
notify: n,
want: true,
})

@ -339,7 +339,7 @@ func (h *ExtensionHost) FindMatchingExtension(target any) bool {
val := reflect.ValueOf(target)
typ := val.Type()
if typ.Kind() != reflect.Ptr || val.IsNil() {
if typ.Kind() != reflect.Pointer || val.IsNil() {
panic("ipnext: target must be a non-nil pointer")
}
targetType := typ.Elem()

@ -1010,9 +1010,8 @@ func TestNilExtensionHostMethodCall(t *testing.T) {
t.Parallel()
var h *ExtensionHost
typ := reflect.TypeOf(h)
for i := range typ.NumMethod() {
m := typ.Method(i)
typ := reflect.TypeFor[*ExtensionHost]()
for m := range typ.Methods() {
if strings.HasSuffix(m.Name, "ForTest") {
// Skip methods that are only for testing.
continue

@ -3687,12 +3687,7 @@ func generateInterceptTCPPortFunc(ports []uint16) func(uint16) bool {
f = func(p uint16) bool { return m[p] }
} else {
f = func(p uint16) bool {
for _, x := range ports {
if p == x {
return true
}
}
return false
return slices.Contains(ports, p)
}
}
}
@ -7387,10 +7382,8 @@ var (
// allowedAutoRoute determines if the route being added via AdvertiseRoute (the app connector featuge) should be allowed.
func allowedAutoRoute(ipp netip.Prefix) bool {
// Note: blocking the addrs for globals, not solely the prefixes.
for _, addr := range disallowedAddrs {
if ipp.Addr() == addr {
return false
}
if slices.Contains(disallowedAddrs, ipp.Addr()) {
return false
}
for _, pfx := range disallowedRanges {
if pfx.Overlaps(ipp) {

@ -275,7 +275,7 @@ var skippedMapFields = []string{
func checkFieldCoverage(t *testing.T, nm *netmap.NetworkMap) {
t.Helper()
mt := reflect.TypeOf(nm).Elem()
mt := reflect.TypeFor[netmap.NetworkMap]()
mv := reflect.ValueOf(nm).Elem()
for i := 0; i < mt.NumField(); i++ {
f := mt.Field(i)

@ -103,7 +103,7 @@ func (s *peerAPIServer) listen(ip netip.Addr, tunIfIndex int) (ln net.Listener,
// deterministic that people will bake this into clients.
// We try a few times just in case something's already
// listening on that port (on all interfaces, probably).
for try := uint8(0); try < 5; try++ {
for try := range uint8(5) {
a16 := ip.As16()
hashData := a16[len(a16)-3:]
hashData[0] += try

@ -835,8 +835,8 @@ func (b *LocalBackend) proxyHandlerForBackend(backend string) (http.Handler, err
targetURL, insecure := expandProxyArg(backend)
// Handle unix: scheme specially
if strings.HasPrefix(targetURL, "unix:") {
socketPath := strings.TrimPrefix(targetURL, "unix:")
if after, ok := strings.CutPrefix(targetURL, "unix:"); ok {
socketPath := after
if socketPath == "" {
return nil, fmt.Errorf("empty unix socket path")
}

@ -101,9 +101,9 @@ func (b *LocalBackend) getSSHUsernames(req *tailcfg.C2NSSHUsernamesRequest) (*ta
mem.HasSuffix(mem.B(line), mem.S("/false")) {
continue
}
colon := bytes.IndexByte(line, ':')
if colon != -1 {
add(string(line[:colon]))
before, _, ok := bytes.Cut(line, []byte{':'})
if ok {
add(string(before))
}
}
}

@ -142,14 +142,11 @@ func (h *Handler) serveDebugDialTypes(w http.ResponseWriter, r *http.Request) {
var wg sync.WaitGroup
for _, dialer := range dialers {
dialer := dialer // loop capture
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
conn, err := dialer.dial(ctx, network, addr)
results <- result{dialer.name, conn, err}
}()
})
}
wg.Wait()

@ -439,12 +439,11 @@ func applyPrefsEdits(src, dst reflect.Value, mask map[string]reflect.Value) {
func maskFields(v reflect.Value) map[string]reflect.Value {
mask := make(map[string]reflect.Value)
for i := range v.NumField() {
f := v.Type().Field(i).Name
if !strings.HasSuffix(f, "Set") {
for sf, fv := range v.Fields() {
if !strings.HasSuffix(sf.Name, "Set") {
continue
}
mask[strings.TrimSuffix(f, "Set")] = v.Field(i)
mask[strings.TrimSuffix(sf.Name, "Set")] = fv
}
return mask
}
@ -845,22 +844,15 @@ func (p *Prefs) SetAdvertiseExitNode(runExit bool) {
// Tailscale IP.
func peerWithTailscaleIP(st *ipnstate.Status, ip netip.Addr) (ps *ipnstate.PeerStatus, ok bool) {
for _, ps := range st.Peer {
for _, ip2 := range ps.TailscaleIPs {
if ip == ip2 {
return ps, true
}
if slices.Contains(ps.TailscaleIPs, ip) {
return ps, true
}
}
return nil, false
}
func isRemoteIP(st *ipnstate.Status, ip netip.Addr) bool {
for _, selfIP := range st.TailscaleIPs {
if ip == selfIP {
return false
}
}
return true
return !slices.Contains(st.TailscaleIPs, ip)
}
// ClearExitNode sets the ExitNodeID and ExitNodeIP to their zero values.

@ -27,8 +27,8 @@ import (
)
func fieldsOf(t reflect.Type) (fields []string) {
for i := range t.NumField() {
fields = append(fields, t.Field(i).Name)
for field := range t.Fields() {
fields = append(fields, field.Name)
}
return
}

@ -673,7 +673,7 @@ func CheckFunnelPort(wantedPort uint16, node *ipnstate.PeerStatus) error {
return deny("")
}
wantedPortString := strconv.Itoa(int(wantedPort))
for _, ps := range strings.Split(portsStr, ",") {
for ps := range strings.SplitSeq(portsStr, ",") {
if ps == "" {
continue
}

@ -189,8 +189,7 @@ func (s *awsStore) LoadState() error {
)
if err != nil {
var pnf *ssmTypes.ParameterNotFound
if errors.As(err, &pnf) {
if _, ok := errors.AsType[*ssmTypes.ParameterNotFound](err); ok {
// Create the parameter as it does not exist yet
// and return directly as it is defacto empty
return s.persistState()

@ -211,7 +211,7 @@ func parseHeaders(decompressor io.Reader, log *zap.SugaredLogger) (http.Header,
return nil, fmt.Errorf("error determining num headers: %v", err)
}
h := make(http.Header, numHeaders)
for i := uint32(0); i < numHeaders; i++ {
for range numHeaders {
name, err := readLenBytes()
if err != nil {
return nil, err
@ -224,7 +224,7 @@ func parseHeaders(decompressor io.Reader, log *zap.SugaredLogger) (http.Header,
if err != nil {
return nil, fmt.Errorf("error reading header data: %w", err)
}
for _, v := range bytes.Split(val, headerSep) {
for v := range bytes.SplitSeq(val, headerSep) {
h.Add(ns, string(v))
}
}

@ -902,8 +902,8 @@ func parseAndRemoveLogLevel(buf []byte) (level int, cleanBuf []byte) {
if bytes.Contains(buf, v2) {
return 2, bytes.ReplaceAll(buf, v2, nil)
}
if i := bytes.Index(buf, vJSON); i != -1 {
rest := buf[i+len(vJSON):]
if _, after, ok := bytes.Cut(buf, vJSON); ok {
rest := after
if len(rest) >= 2 {
v := rest[0]
if v >= '0' && v <= '9' {

@ -86,10 +86,10 @@ func TestDrainPendingMessages(t *testing.T) {
}
// all of the "log line" messages usually arrive at once, but poll if needed.
body := ""
var body strings.Builder
for i := 0; i <= logLines; i++ {
body += string(<-ts.uploaded)
count := strings.Count(body, "log line")
body.WriteString(string(<-ts.uploaded))
count := strings.Count(body.String(), "log line")
if count == logLines {
break
}

@ -63,16 +63,16 @@ func LabelString(k any) string {
var sb strings.Builder
sb.WriteString("{")
for i := range t.NumField() {
if i > 0 {
first := true
for ft, fv := range rv.Fields() {
if !first {
sb.WriteString(",")
}
ft := t.Field(i)
first = false
label := ft.Tag.Get("prom")
if label == "" {
label = strings.ToLower(ft.Name)
}
fv := rv.Field(i)
switch fv.Kind() {
case reflect.String:
fmt.Fprintf(&sb, "%s=%q", label, fv.String())

@ -19,7 +19,7 @@ import (
func TestInversePrefix(t *testing.T) {
t.Parallel()
for i := range 256 {
for len := 0; len < 9; len++ {
for len := range 9 {
addr := i & (0xFF << (8 - len))
idx := prefixIndex(uint8(addr), len)
addr2, len2 := inversePrefixIndex(idx)

@ -94,8 +94,7 @@ func TestCaptivePortalRequest(t *testing.T) {
now := time.Now()
d.clock = func() time.Time { return now }
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ctx := t.Context()
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
@ -133,8 +132,7 @@ func TestCaptivePortalRequest(t *testing.T) {
func TestAgainstDERPHandler(t *testing.T) {
d := NewDetector(t.Logf)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ctx := t.Context()
s := httptest.NewServer(http.HandlerFunc(derpserver.ServeNoContent))
defer s.Close()

@ -380,7 +380,7 @@ func isLibnssResolveUsed(env newOSConfigEnv) error {
if err != nil {
return fmt.Errorf("reading /etc/resolv.conf: %w", err)
}
for _, line := range strings.Split(string(bs), "\n") {
for line := range strings.SplitSeq(string(bs), "\n") {
fields := strings.Fields(line)
if len(fields) < 2 || fields[0] != "hosts:" {
continue

@ -82,7 +82,7 @@ func (m openresolvManager) GetBaseConfig() (OSConfig, error) {
// Remove the "tailscale" snippet from the list.
args := []string{"-l"}
for _, f := range strings.Split(strings.TrimSpace(string(bs)), " ") {
for f := range strings.SplitSeq(strings.TrimSpace(string(bs)), " ") {
if f == "tailscale" {
continue
}

@ -727,8 +727,7 @@ func (f *forwarder) send(ctx context.Context, fq *forwardQuery, rr resolverAndDe
}
// If we got a truncated UDP response, return that instead of an error.
var trErr truncatedResponseError
if errors.As(err, &trErr) {
if trErr, ok := errors.AsType[truncatedResponseError](err); ok {
return trErr.res, nil
}
return nil, err

@ -328,7 +328,7 @@ func runDNSServer(tb testing.TB, opts *testDNSServerOptions, response []byte, on
udpLn *net.UDPConn
err error
)
for try := 0; try < tries; try++ {
for range tries {
if tcpLn != nil {
tcpLn.Close()
tcpLn = nil
@ -392,9 +392,7 @@ func runDNSServer(tb testing.TB, opts *testDNSServerOptions, response []byte, on
var wg sync.WaitGroup
if opts == nil || !opts.SkipTCP {
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
for {
conn, err := tcpLn.Accept()
if err != nil {
@ -402,7 +400,7 @@ func runDNSServer(tb testing.TB, opts *testDNSServerOptions, response []byte, on
}
go handleConn(conn)
}
}()
})
}
handleUDP := func(addr netip.AddrPort, req []byte) {
@ -413,9 +411,7 @@ func runDNSServer(tb testing.TB, opts *testDNSServerOptions, response []byte, on
}
if opts == nil || !opts.SkipUDP {
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
for {
buf := make([]byte, 65535)
n, addr, err := udpLn.ReadFromUDPAddrPort(buf)
@ -425,7 +421,7 @@ func runDNSServer(tb testing.TB, opts *testDNSServerOptions, response []byte, on
buf = buf[:n]
go handleUDP(addr, buf)
}
}()
})
}
tb.Cleanup(func() {
@ -684,7 +680,7 @@ func makeResponseOfSize(tb testing.TB, domain string, targetSize int, includeOPT
var response []byte
var err error
for attempt := 0; attempt < 10; attempt++ {
for range 10 {
testBuilder := dns.NewBuilder(nil, dns.Header{
Response: true,
Authoritative: true,

@ -16,7 +16,7 @@ import (
"net/netip"
"os"
"runtime"
"sort"
"slices"
"strconv"
"strings"
"sync"
@ -172,7 +172,7 @@ func WriteRoutes(w *bufio.Writer, routes map[dnsname.FQDN][]*dnstype.Resolver) {
}
kk = append(kk, k)
}
sort.Slice(kk, func(i, j int) bool { return kk[i] < kk[j] })
slices.Sort(kk)
w.WriteByte('{')
for i, k := range kk {
if i > 0 {

@ -172,8 +172,7 @@ func (fs wslFS) Truncate(name string) error { return fs.WriteFile(name, nil, 064
func (fs wslFS) ReadFile(name string) ([]byte, error) {
b, err := wslCombinedOutput(fs.cmd("cat", "--", name))
var ee *exec.ExitError
if errors.As(err, &ee) && ee.ExitCode() == 1 {
if ee, ok := errors.AsType[*exec.ExitError](err); ok && ee.ExitCode() == 1 {
return nil, os.ErrNotExist
}
return b, err

@ -545,7 +545,7 @@ func makeProbePlanInitial(dm *tailcfg.DERPMap, ifState *netmon.State) (plan prob
var p4 []probe
var p6 []probe
for try := 0; try < 3; try++ {
for try := range 3 {
n := reg.Nodes[try%len(reg.Nodes)]
delay := time.Duration(try) * defaultInitialRetransmitTime
if n.IPv4 != "none" && ((ifState.HaveV4 && nodeMight4(n)) || n.IsTestNode()) {
@ -975,13 +975,11 @@ func (c *Client) GetReport(ctx context.Context, dm *tailcfg.DERPMap, opts *GetRe
// need to close the underlying Pinger after a timeout
// or when all ICMP probes are done, regardless of
// whether the HTTPS probes have finished.
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
if err := c.measureAllICMPLatency(ctx, rs, need); err != nil {
c.logf("[v1] measureAllICMPLatency: %v", err)
}
}()
})
}
wg.Add(len(need))
c.logf("netcheck: UDP is blocked, trying HTTPS")
@ -1072,9 +1070,7 @@ func (c *Client) runHTTPOnlyChecks(ctx context.Context, last *Report, rs *report
if len(rg.Nodes) == 0 {
continue
}
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
node := rg.Nodes[0]
req, _ := http.NewRequestWithContext(ctx, "HEAD", "https://"+node.HostName+"/derp/probe", nil)
// One warm-up one to get HTTP connection set
@ -1099,7 +1095,7 @@ func (c *Client) runHTTPOnlyChecks(ctx context.Context, last *Report, rs *report
}
d := c.timeNow().Sub(t0)
rs.addNodeLatency(node, netip.AddrPort{}, d)
}()
})
}
wg.Wait()
return nil

@ -42,8 +42,7 @@ func TestBasic(t *testing.T) {
c := newTestClient(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ctx := t.Context()
if err := c.Standalone(ctx, "127.0.0.1:0"); err != nil {
t.Fatal(err)
@ -124,8 +123,7 @@ func TestWorksWhenUDPBlocked(t *testing.T) {
c := newTestClient(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ctx := t.Context()
r, err := c.GetReport(ctx, dm, nil)
if err != nil {
@ -1038,8 +1036,7 @@ func TestNoUDPNilGetReportOpts(t *testing.T) {
}
c := newTestClient(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
ctx := t.Context()
r, err := c.GetReport(ctx, dm, nil)
if err != nil {

@ -12,8 +12,7 @@ import (
func init() {
shouldDisableUDPGSO = func(err error) bool {
var serr *os.SyscallError
if errors.As(err, &serr) {
if serr, ok := errors.AsType[*os.SyscallError](err); ok {
// EIO is returned by udp_send_skb() if the device driver does not
// have tx checksumming enabled, which is a hard requirement of
// UDP_SEGMENT. See:

@ -812,11 +812,8 @@ func (m *Monitor) HasCGNATInterface() (bool, error) {
if hasCGNATInterface || !i.IsUp() || isTailscaleInterface(i.Name, pfxs) {
return
}
for _, pfx := range pfxs {
if cgnatRange.Overlaps(pfx) {
hasCGNATInterface = true
break
}
if slices.ContainsFunc(pfxs, cgnatRange.Overlaps) {
hasCGNATInterface = true
}
})
if err != nil {

@ -41,8 +41,8 @@ func CalcAdvertiseRoutes(advertiseRoutes string, advertiseDefaultRoute bool) ([]
routeMap := map[netip.Prefix]bool{}
if advertiseRoutes != "" {
var default4, default6 bool
advroutes := strings.Split(advertiseRoutes, ",")
for _, s := range advroutes {
advroutes := strings.SplitSeq(advertiseRoutes, ",")
for s := range advroutes {
ipp, err := netip.ParsePrefix(s)
if err != nil {
return nil, fmt.Errorf("%q is not a valid IP address or CIDR prefix", s)

@ -21,6 +21,7 @@ import (
"io"
"log"
"net"
"slices"
"strconv"
"time"
@ -488,10 +489,8 @@ func parseClientGreeting(r io.Reader, authMethod byte) error {
if err != nil {
return fmt.Errorf("could not read methods")
}
for _, m := range methods {
if m == authMethod {
return nil
}
if slices.Contains(methods, authMethod) {
return nil
}
return fmt.Errorf("no acceptable auth methods")
}

@ -180,11 +180,11 @@ func TestUDP(t *testing.T) {
const echoServerNumber = 3
echoServerListener := make([]net.PacketConn, echoServerNumber)
for i := 0; i < echoServerNumber; i++ {
for i := range echoServerNumber {
echoServerListener[i] = newUDPEchoServer()
}
defer func() {
for i := 0; i < echoServerNumber; i++ {
for i := range echoServerNumber {
_ = echoServerListener[i].Close()
}
}()
@ -277,10 +277,10 @@ func TestUDP(t *testing.T) {
}
defer socks5UDPConn.Close()
for i := 0; i < echoServerNumber; i++ {
for i := range echoServerNumber {
port := echoServerListener[i].LocalAddr().(*net.UDPAddr).Port
addr := socksAddr{addrType: ipv4, addr: "127.0.0.1", port: uint16(port)}
requestBody := []byte(fmt.Sprintf("Test %d", i))
requestBody := fmt.Appendf(nil, "Test %d", i)
responseBody := sendUDPAndWaitResponse(socks5UDPConn, addr, requestBody)
if !bytes.Equal(requestBody, responseBody) {
t.Fatalf("got: %q want: %q", responseBody, requestBody)

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save