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>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
4453cc5f53
commit
bd2a2d53d3
@@ -698,7 +698,7 @@ func TestRateLogger(t *testing.T) {
|
|||||||
wasCalled = true
|
wasCalled = true
|
||||||
})
|
})
|
||||||
|
|
||||||
for i := 0; i < 3; i++ {
|
for range 3 {
|
||||||
clock.Advance(1 * time.Millisecond)
|
clock.Advance(1 * time.Millisecond)
|
||||||
rl.update(0)
|
rl.update(0)
|
||||||
if wasCalled {
|
if wasCalled {
|
||||||
@@ -720,7 +720,7 @@ func TestRateLogger(t *testing.T) {
|
|||||||
wasCalled = true
|
wasCalled = true
|
||||||
})
|
})
|
||||||
|
|
||||||
for i := 0; i < 3; i++ {
|
for range 3 {
|
||||||
clock.Advance(1 * time.Minute)
|
clock.Advance(1 * time.Minute)
|
||||||
rl.update(0)
|
rl.update(0)
|
||||||
if wasCalled {
|
if wasCalled {
|
||||||
|
|||||||
@@ -192,8 +192,8 @@ func (e *AccessDeniedError) Unwrap() error { return e.err }
|
|||||||
|
|
||||||
// IsAccessDeniedError reports whether err is or wraps an AccessDeniedError.
|
// IsAccessDeniedError reports whether err is or wraps an AccessDeniedError.
|
||||||
func IsAccessDeniedError(err error) bool {
|
func IsAccessDeniedError(err error) bool {
|
||||||
var ae *AccessDeniedError
|
_, ok := errors.AsType[*AccessDeniedError](err)
|
||||||
return errors.As(err, &ae)
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// PreconditionsFailedError is returned when the server responds
|
// 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.
|
// IsPreconditionsFailedError reports whether err is or wraps an PreconditionsFailedError.
|
||||||
func IsPreconditionsFailedError(err error) bool {
|
func IsPreconditionsFailedError(err error) bool {
|
||||||
var ae *PreconditionsFailedError
|
_, ok := errors.AsType[*PreconditionsFailedError](err)
|
||||||
return errors.As(err, &ae)
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// bestError returns either err, or if body contains a valid JSON
|
// bestError returns either err, or if body contains a valid JSON
|
||||||
@@ -1071,7 +1071,7 @@ func tailscaledConnectHint() string {
|
|||||||
// ActiveState=inactive
|
// ActiveState=inactive
|
||||||
// SubState=dead
|
// SubState=dead
|
||||||
st := map[string]string{}
|
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 {
|
if k, v, ok := strings.Cut(line, "="); ok {
|
||||||
st[k] = strings.TrimSpace(v)
|
st[k] = strings.TrimSpace(v)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -233,8 +233,8 @@ func (logo tsLogo) renderWithBorder(borderUnits int) *bytes.Buffer {
|
|||||||
dc.InvertMask()
|
dc.InvertMask()
|
||||||
}
|
}
|
||||||
|
|
||||||
for y := 0; y < 3; y++ {
|
for y := range 3 {
|
||||||
for x := 0; x < 3; x++ {
|
for x := range 3 {
|
||||||
px := (borderUnits + 1 + 3*x) * radius
|
px := (borderUnits + 1 + 3*x) * radius
|
||||||
py := (borderUnits + 1 + 3*y) * radius
|
py := (borderUnits + 1 + 3*y) * radius
|
||||||
col := fg
|
col := fg
|
||||||
|
|||||||
@@ -1292,6 +1292,6 @@ func requireRoot() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isExitError(err error) bool {
|
func isExitError(err error) bool {
|
||||||
var exitErr *exec.ExitError
|
_, ok := errors.AsType[*exec.ExitError](err)
|
||||||
return errors.As(err, &exitErr)
|
return ok
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -451,7 +451,7 @@ func TestSynoArch(t *testing.T) {
|
|||||||
synoinfoConfPath := filepath.Join(t.TempDir(), "synoinfo.conf")
|
synoinfoConfPath := filepath.Join(t.TempDir(), "synoinfo.conf")
|
||||||
if err := os.WriteFile(
|
if err := os.WriteFile(
|
||||||
synoinfoConfPath,
|
synoinfoConfPath,
|
||||||
[]byte(fmt.Sprintf("unique=%q\n", tt.synoinfoUnique)),
|
fmt.Appendf(nil, "unique=%q\n", tt.synoinfoUnique),
|
||||||
0600,
|
0600,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func ensureIPForwarding(root, clusterProxyTargetIP, tailnetTargetIP, tailnetTarg
|
|||||||
v4Forwarding = true
|
v4Forwarding = true
|
||||||
}
|
}
|
||||||
if routes != nil && *routes != "" {
|
if routes != nil && *routes != "" {
|
||||||
for _, route := range strings.Split(*routes, ",") {
|
for route := range strings.SplitSeq(*routes, ",") {
|
||||||
cidr, err := netip.ParsePrefix(route)
|
cidr, err := netip.ParsePrefix(route)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid subnet route: %v", err)
|
return fmt.Errorf("invalid subnet route: %v", err)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"maps"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
@@ -1249,7 +1250,7 @@ func (b *lockingBuffer) String() string {
|
|||||||
func waitLogLine(t *testing.T, timeout time.Duration, b *lockingBuffer, want string) {
|
func waitLogLine(t *testing.T, timeout time.Duration, b *lockingBuffer, want string) {
|
||||||
deadline := time.Now().Add(timeout)
|
deadline := time.Now().Add(timeout)
|
||||||
for time.Now().Before(deadline) {
|
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: ") {
|
if !strings.HasPrefix(line, "boot: ") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -1438,9 +1439,7 @@ func (k *kubeServer) Secret() map[string]string {
|
|||||||
k.Lock()
|
k.Lock()
|
||||||
defer k.Unlock()
|
defer k.Unlock()
|
||||||
ret := map[string]string{}
|
ret := map[string]string{}
|
||||||
for k, v := range k.secret {
|
maps.Copy(ret, k.secret)
|
||||||
ret[k] = v
|
|
||||||
}
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ func startMesh(s *derpserver.Server) error {
|
|||||||
if !s.HasMeshKey() {
|
if !s.HasMeshKey() {
|
||||||
return errors.New("--mesh-with requires --mesh-psk-file")
|
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 {
|
if err := startMeshWithHost(s, hostTuple); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"math/rand/v2"
|
"math/rand/v2"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/AlekSi/pointer"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
discoveryv1 "k8s.io/api/discovery/v1"
|
discoveryv1 "k8s.io/api/discovery/v1"
|
||||||
@@ -106,11 +105,11 @@ func TestTailscaleEgressEndpointSlices(t *testing.T) {
|
|||||||
expectReconciled(t, er, "operator-ns", "foo")
|
expectReconciled(t, er, "operator-ns", "foo")
|
||||||
eps.Endpoints = append(eps.Endpoints, discoveryv1.Endpoint{
|
eps.Endpoints = append(eps.Endpoints, discoveryv1.Endpoint{
|
||||||
Addresses: []string{"10.0.0.1"},
|
Addresses: []string{"10.0.0.1"},
|
||||||
Hostname: pointer.To("foo"),
|
Hostname: new("foo"),
|
||||||
Conditions: discoveryv1.EndpointConditions{
|
Conditions: discoveryv1.EndpointConditions{
|
||||||
Serving: pointer.ToBool(true),
|
Serving: new(true),
|
||||||
Ready: pointer.ToBool(true),
|
Ready: new(true),
|
||||||
Terminating: pointer.ToBool(false),
|
Terminating: new(false),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
expectEqual(t, fc, eps)
|
expectEqual(t, fc, eps)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/AlekSi/pointer"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
corev1 "k8s.io/api/core/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{
|
eps.Endpoints = append(eps.Endpoints, discoveryv1.Endpoint{
|
||||||
Addresses: []string{p.Status.PodIPs[0].IP},
|
Addresses: []string{p.Status.PodIPs[0].IP},
|
||||||
Conditions: discoveryv1.EndpointConditions{
|
Conditions: discoveryv1.EndpointConditions{
|
||||||
Ready: pointer.ToBool(true),
|
Ready: new(true),
|
||||||
Serving: pointer.ToBool(true),
|
Serving: new(true),
|
||||||
Terminating: pointer.ToBool(false),
|
Terminating: new(false),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ func portsForEndpointSlice(svc *corev1.Service) []discoveryv1.EndpointPort {
|
|||||||
ports = append(ports, discoveryv1.EndpointPort{
|
ports = append(ports, discoveryv1.EndpointPort{
|
||||||
Name: &p.Name,
|
Name: &p.Name,
|
||||||
Protocol: &p.Protocol,
|
Protocol: &p.Protocol,
|
||||||
Port: pointer.ToInt32(p.TargetPort.IntVal),
|
Port: new(p.TargetPort.IntVal),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return ports
|
return ports
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"math/rand/v2"
|
"math/rand/v2"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -914,9 +915,7 @@ func ownerAnnotations(operatorID string, svc *tailscale.VIPService) (map[string]
|
|||||||
}
|
}
|
||||||
|
|
||||||
newAnnots := make(map[string]string, len(svc.Annotations)+1)
|
newAnnots := make(map[string]string, len(svc.Annotations)+1)
|
||||||
for k, v := range svc.Annotations {
|
maps.Copy(newAnnots, svc.Annotations)
|
||||||
newAnnots[k] = v
|
|
||||||
}
|
|
||||||
newAnnots[ownerAnnotation] = string(json)
|
newAnnots[ownerAnnotation] = string(json)
|
||||||
return newAnnots, nil
|
return newAnnots, nil
|
||||||
}
|
}
|
||||||
@@ -1129,8 +1128,7 @@ func hasCerts(ctx context.Context, cl client.Client, lc localClient, ns string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isErrorTailscaleServiceNotFound(err error) bool {
|
func isErrorTailscaleServiceNotFound(err error) bool {
|
||||||
var errResp tailscale.ErrResponse
|
errResp, ok := errors.AsType[tailscale.ErrResponse](err)
|
||||||
ok := errors.As(err, &errResp)
|
|
||||||
return ok && errResp.Status == http.StatusNotFound
|
return ok && errResp.Status == http.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1144,7 +1142,7 @@ func tagViolations(obj client.Object) []string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tag := range strings.Split(tags, ",") {
|
for tag := range strings.SplitSeq(tags, ",") {
|
||||||
tag = strings.TrimSpace(tag)
|
tag = strings.TrimSpace(tag)
|
||||||
if err := tailcfg.CheckTag(tag); err != nil {
|
if err := tailcfg.CheckTag(tag); err != nil {
|
||||||
violations = append(violations, fmt.Sprintf("invalid tag %q: %v", tag, err))
|
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),
|
Labels: pgSecretLabels(pgName, kubetypes.LabelSecretTypeConfig),
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{
|
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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@@ -286,11 +287,7 @@ func isNamespacedProxyType(typ string) bool {
|
|||||||
|
|
||||||
func mergeMapKeys(a, b map[string]string) map[string]string {
|
func mergeMapKeys(a, b map[string]string) map[string]string {
|
||||||
m := make(map[string]string, len(a)+len(b))
|
m := make(map[string]string, len(a)+len(b))
|
||||||
for key, val := range b {
|
maps.Copy(m, b)
|
||||||
m[key] = val
|
maps.Copy(m, a)
|
||||||
}
|
|
||||||
for key, val := range a {
|
|
||||||
m[key] = val
|
|
||||||
}
|
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -308,8 +308,7 @@ func (r *ProxyGroupReconciler) maybeProvision(ctx context.Context, tailscaleClie
|
|||||||
var err error
|
var err error
|
||||||
svcToNodePorts, tailscaledPort, err = r.ensureNodePortServiceCreated(ctx, pg, proxyClass)
|
svcToNodePorts, tailscaledPort, err = r.ensureNodePortServiceCreated(ctx, pg, proxyClass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var allocatePortErr *allocatePortsErr
|
if _, ok := errors.AsType[*allocatePortsErr](err); ok {
|
||||||
if errors.As(err, &allocatePortErr) {
|
|
||||||
reason := reasonProxyGroupCreationFailed
|
reason := reasonProxyGroupCreationFailed
|
||||||
msg := fmt.Sprintf("error provisioning NodePort Services for static endpoints: %v", err)
|
msg := fmt.Sprintf("error provisioning NodePort Services for static endpoints: %v", err)
|
||||||
r.recorder.Event(pg, corev1.EventTypeWarning, reason, msg)
|
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)
|
staticEndpoints, err := r.ensureConfigSecretsCreated(ctx, tailscaleClient, pg, proxyClass, svcToNodePorts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var selectorErr *FindStaticEndpointErr
|
if _, ok := errors.AsType[*FindStaticEndpointErr](err); ok {
|
||||||
if errors.As(err, &selectorErr) {
|
|
||||||
reason := reasonProxyGroupCreationFailed
|
reason := reasonProxyGroupCreationFailed
|
||||||
msg := fmt.Sprintf("error provisioning config Secrets: %v", err)
|
msg := fmt.Sprintf("error provisioning config Secrets: %v", err)
|
||||||
r.recorder.Event(pg, corev1.EventTypeWarning, reason, msg)
|
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 {
|
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))
|
logger.Debugf("deleting device %s from control", string(id))
|
||||||
if err := tailscaleClient.DeleteDevice(ctx, string(id)); err != nil {
|
if err := tailscaleClient.DeleteDevice(ctx, string(id)); err != nil {
|
||||||
errResp := &tailscale.ErrResponse{}
|
if errResp, ok := errors.AsType[tailscale.ErrResponse](err); ok && errResp.Status == http.StatusNotFound {
|
||||||
if ok := errors.As(err, errResp); ok && errResp.Status == http.StatusNotFound {
|
|
||||||
logger.Debugf("device %s not found, likely because it has already been deleted from control", string(id))
|
logger.Debugf("device %s not found, likely because it has already been deleted from control", string(id))
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("error deleting device: %w", err)
|
return fmt.Errorf("error deleting device: %w", err)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -544,9 +545,7 @@ func pgSecretLabels(pgName, secretType string) map[string]string {
|
|||||||
|
|
||||||
func pgLabels(pgName string, customLabels map[string]string) map[string]string {
|
func pgLabels(pgName string, customLabels map[string]string) map[string]string {
|
||||||
labels := make(map[string]string, len(customLabels)+3)
|
labels := make(map[string]string, len(customLabels)+3)
|
||||||
for k, v := range customLabels {
|
maps.Copy(labels, customLabels)
|
||||||
labels[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
labels[kubetypes.LabelManaged] = "true"
|
labels[kubetypes.LabelManaged] = "true"
|
||||||
labels[LabelParentType] = "proxygroup"
|
labels[LabelParentType] = "proxygroup"
|
||||||
|
|||||||
@@ -1826,10 +1826,10 @@ func addNodeIDToStateSecrets(t *testing.T, fc client.WithWatch, pg *tsapi.ProxyG
|
|||||||
currentProfileKey: []byte(key),
|
currentProfileKey: []byte(key),
|
||||||
key: bytes,
|
key: bytes,
|
||||||
kubetypes.KeyDeviceIPs: []byte(`["1.2.3.4", "::1"]`),
|
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.
|
// TODO(tomhjp): We have two different mechanisms to retrieve device IDs.
|
||||||
// Consolidate on this one.
|
// Consolidate on this one.
|
||||||
kubetypes.KeyDeviceID: []byte(fmt.Sprintf("nodeid-%d", i)),
|
kubetypes.KeyDeviceID: fmt.Appendf(nil, "nodeid-%d", i),
|
||||||
kubetypes.KeyPodUID: []byte(podUID),
|
kubetypes.KeyPodUID: []byte(podUID),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
+6
-10
@@ -11,6 +11,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@@ -304,8 +305,7 @@ func (a *tailscaleSTSReconciler) Cleanup(ctx context.Context, tailnet string, lo
|
|||||||
if dev.id != "" {
|
if dev.id != "" {
|
||||||
logger.Debugf("deleting device %s from control", string(dev.id))
|
logger.Debugf("deleting device %s from control", string(dev.id))
|
||||||
if err = tailscaleClient.DeleteDevice(ctx, string(dev.id)); err != nil {
|
if err = tailscaleClient.DeleteDevice(ctx, string(dev.id)); err != nil {
|
||||||
errResp := &tailscale.ErrResponse{}
|
if errResp, ok := errors.AsType[tailscale.ErrResponse](err); ok && errResp.Status == http.StatusNotFound {
|
||||||
if ok := errors.As(err, errResp); ok && errResp.Status == http.StatusNotFound {
|
|
||||||
logger.Debugf("device %s not found, likely because it has already been deleted from control", string(dev.id))
|
logger.Debugf("device %s not found, likely because it has already been deleted from control", string(dev.id))
|
||||||
} else {
|
} else {
|
||||||
return false, fmt.Errorf("deleting device: %w", err)
|
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 != "" {
|
if dev != nil && dev.id != "" {
|
||||||
var errResp *tailscale.ErrResponse
|
|
||||||
|
|
||||||
err = tailscaleClient.DeleteDevice(ctx, string(dev.id))
|
err = tailscaleClient.DeleteDevice(ctx, string(dev.id))
|
||||||
switch {
|
if errResp, ok := errors.AsType[*tailscale.ErrResponse](err); ok && errResp.Status == http.StatusNotFound {
|
||||||
case errors.As(err, &errResp) && errResp.Status == http.StatusNotFound:
|
|
||||||
// This device has possibly already been deleted in the admin console. So we can ignore this
|
// This device has possibly already been deleted in the admin console. So we can ignore this
|
||||||
// and move on to removing the secret.
|
// and move on to removing the secret.
|
||||||
case err != nil:
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -677,9 +674,8 @@ func (a *tailscaleSTSReconciler) reconcileSTS(ctx context.Context, logger *zap.S
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
mak.Set(&pod.Labels, "app", sts.ParentResourceUID)
|
mak.Set(&pod.Labels, "app", sts.ParentResourceUID)
|
||||||
for key, val := range sts.ChildResourceLabels {
|
// sync StatefulSet labels to Pod to make it easier for users to select the Pod
|
||||||
pod.Labels[key] = val // 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 {
|
if sts.Replicas > 0 {
|
||||||
ss.Spec.Replicas = new(sts.Replicas)
|
ss.Spec.Replicas = new(sts.Replicas)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -408,7 +409,5 @@ func Test_mergeStatefulSetLabelsOrAnnots(t *testing.T) {
|
|||||||
|
|
||||||
// updateMap updates map a with the values from map b.
|
// updateMap updates map a with the values from map b.
|
||||||
func updateMap(a, b map[string]string) {
|
func updateMap(a, b map[string]string) {
|
||||||
for key, val := range b {
|
maps.Copy(a, b)
|
||||||
a[key] = val
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
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)
|
svc, err := tsClient.GetVIPService(ctx, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errResp := &tailscale.ErrResponse{}
|
errResp, ok := errors.AsType[tailscale.ErrResponse](err)
|
||||||
ok := errors.As(err, errResp)
|
|
||||||
if ok && errResp.Status == http.StatusNotFound {
|
if ok && errResp.Status == http.StatusNotFound {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -555,7 +556,7 @@ func expectedSecret(t *testing.T, cl client.Client, opts configOpts) *corev1.Sec
|
|||||||
if opts.isExitNode {
|
if opts.isExitNode {
|
||||||
r = "0.0.0.0/0,::/0," + r
|
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)
|
prefix, err := netip.ParsePrefix(rr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -822,12 +823,9 @@ func expectEvents(t *testing.T, rec *record.FakeRecorder, wantsEvents []string)
|
|||||||
select {
|
select {
|
||||||
case gotEvent := <-rec.Events:
|
case gotEvent := <-rec.Events:
|
||||||
found := false
|
found := false
|
||||||
for _, wantEvent := range wantsEvents {
|
if slices.Contains(wantsEvents, gotEvent) {
|
||||||
if wantEvent == gotEvent {
|
found = true
|
||||||
found = true
|
seenEvents = append(seenEvents, gotEvent)
|
||||||
seenEvents = append(seenEvents, gotEvent)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
t.Errorf("got unexpected event %q, expected events: %+#v", gotEvent, wantsEvents)
|
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 {
|
if ok {
|
||||||
var errResp *tailscale.ErrResponse
|
|
||||||
|
|
||||||
r.log.Debugf("deleting device %s", devicePrefs.Config.NodeID)
|
r.log.Debugf("deleting device %s", devicePrefs.Config.NodeID)
|
||||||
err = tailscaleClient.DeleteDevice(ctx, string(devicePrefs.Config.NodeID))
|
err = tailscaleClient.DeleteDevice(ctx, string(devicePrefs.Config.NodeID))
|
||||||
switch {
|
if errResp, ok := errors.AsType[*tailscale.ErrResponse](err); ok && errResp.Status == http.StatusNotFound {
|
||||||
case errors.As(err, &errResp) && errResp.Status == http.StatusNotFound:
|
|
||||||
// This device has possibly already been deleted in the admin console. So we can ignore this
|
// This device has possibly already been deleted in the admin console. So we can ignore this
|
||||||
// and move on to removing the secret.
|
// and move on to removing the secret.
|
||||||
case err != nil:
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -412,8 +409,7 @@ func (r *RecorderReconciler) maybeCleanup(ctx context.Context, tsr *tsapi.Record
|
|||||||
nodeID := string(devicePrefs.Config.NodeID)
|
nodeID := string(devicePrefs.Config.NodeID)
|
||||||
logger.Debugf("deleting device %s from control", nodeID)
|
logger.Debugf("deleting device %s from control", nodeID)
|
||||||
if err = tailscaleClient.DeleteDevice(ctx, nodeID); err != nil {
|
if err = tailscaleClient.DeleteDevice(ctx, nodeID); err != nil {
|
||||||
errResp := &tailscale.ErrResponse{}
|
if errResp, ok := errors.AsType[tailscale.ErrResponse](err); ok && errResp.Status == http.StatusNotFound {
|
||||||
if errors.As(err, errResp) && errResp.Status == http.StatusNotFound {
|
|
||||||
logger.Debugf("device %s not found, likely because it has already been deleted from control", nodeID)
|
logger.Debugf("device %s not found, likely because it has already been deleted from control", nodeID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
|
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
corev1 "k8s.io/api/core/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 {
|
func tsrLabels(app, instance string, customLabels map[string]string) map[string]string {
|
||||||
labels := make(map[string]string, len(customLabels)+3)
|
labels := make(map[string]string, len(customLabels)+3)
|
||||||
for k, v := range customLabels {
|
maps.Copy(labels, customLabels)
|
||||||
labels[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
|
// ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
|
||||||
labels["app.kubernetes.io/name"] = app
|
labels["app.kubernetes.io/name"] = app
|
||||||
|
|||||||
+2
-2
@@ -24,7 +24,7 @@ func parseFiles(s string, typ string) (files.Contents, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
var contents files.Contents
|
var contents files.Contents
|
||||||
for _, f := range strings.Split(s, ",") {
|
for f := range strings.SplitSeq(s, ",") {
|
||||||
fs := strings.Split(f, ":")
|
fs := strings.Split(f, ":")
|
||||||
if len(fs) != 2 {
|
if len(fs) != 2 {
|
||||||
return nil, fmt.Errorf("unparseable file field %q", f)
|
return nil, fmt.Errorf("unparseable file field %q", f)
|
||||||
@@ -41,7 +41,7 @@ func parseEmptyDirs(s string) files.Contents {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var contents files.Contents
|
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})
|
contents = append(contents, &files.Content{Type: files.TypeDir, Destination: d})
|
||||||
}
|
}
|
||||||
return contents
|
return contents
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func TestIPPoolExhaustion(t *testing.T) {
|
|||||||
|
|
||||||
from := tailcfg.NodeID(12345)
|
from := tailcfg.NodeID(12345)
|
||||||
|
|
||||||
for i := 0; i < 5; i++ {
|
for range 5 {
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
addr, err := pool.IPForDomain(from, domain)
|
addr, err := pool.IPForDomain(from, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+2
-3
@@ -149,7 +149,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var prefixes []netip.Prefix
|
var prefixes []netip.Prefix
|
||||||
for _, s := range strings.Split(*v4PfxStr, ",") {
|
for s := range strings.SplitSeq(*v4PfxStr, ",") {
|
||||||
p := netip.MustParsePrefix(strings.TrimSpace(s))
|
p := netip.MustParsePrefix(strings.TrimSpace(s))
|
||||||
if p.Masked() != p {
|
if p.Masked() != p {
|
||||||
log.Fatalf("v4 prefix %v is not a masked prefix", 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++
|
addrQCount++
|
||||||
if _, ok := resolves[q.Name.String()]; !ok {
|
if _, ok := resolves[q.Name.String()]; !ok {
|
||||||
addrs, err := c.resolver.LookupNetIP(ctx, "ip", q.Name.String())
|
addrs, err := c.resolver.LookupNetIP(ctx, "ip", q.Name.String())
|
||||||
var dnsErr *net.DNSError
|
if dnsErr, ok := errors.AsType[*net.DNSError](err); ok && dnsErr.IsNotFound {
|
||||||
if errors.As(err, &dnsErr) && dnsErr.IsNotFound {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ func (s *sniproxy) mergeConfigFromFlags(out *appctype.AppConnectorConfig, ports,
|
|||||||
Addrs: []netip.Addr{ip4, ip6},
|
Addrs: []netip.Addr{ip4, ip6},
|
||||||
}
|
}
|
||||||
if ports != "" {
|
if ports != "" {
|
||||||
for _, portStr := range strings.Split(ports, ",") {
|
for portStr := range strings.SplitSeq(ports, ",") {
|
||||||
port, err := strconv.ParseUint(portStr, 10, 16)
|
port, err := strconv.ParseUint(portStr, 10, 16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("invalid port: %s", portStr)
|
log.Fatalf("invalid port: %s", portStr)
|
||||||
@@ -238,7 +238,7 @@ func (s *sniproxy) mergeConfigFromFlags(out *appctype.AppConnectorConfig, ports,
|
|||||||
}
|
}
|
||||||
|
|
||||||
var forwardConfigFromFlags []appctype.DNATConfig
|
var forwardConfigFromFlags []appctype.DNATConfig
|
||||||
for _, forwStr := range strings.Split(forwards, ",") {
|
for forwStr := range strings.SplitSeq(forwards, ",") {
|
||||||
if forwStr == "" {
|
if forwStr == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,8 +72,7 @@ var speedtestArgs struct {
|
|||||||
func runSpeedtest(ctx context.Context, args []string) error {
|
func runSpeedtest(ctx context.Context, args []string) error {
|
||||||
|
|
||||||
if _, _, err := net.SplitHostPort(speedtestArgs.host); err != nil {
|
if _, _, err := net.SplitHostPort(speedtestArgs.host); err != nil {
|
||||||
var addrErr *net.AddrError
|
if addrErr, ok := errors.AsType[*net.AddrError](err); ok && addrErr.Err == "missing port in address" {
|
||||||
if errors.As(err, &addrErr) && addrErr.Err == "missing port in address" {
|
|
||||||
// if no port is provided, append the default port
|
// if no port is provided, append the default port
|
||||||
speedtestArgs.host = net.JoinHostPort(speedtestArgs.host, strconv.Itoa(speedtest.DefaultPort))
|
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)
|
reqCtx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
||||||
writeErr = client.write(reqCtx, ts)
|
writeErr = client.write(reqCtx, ts)
|
||||||
cancel()
|
cancel()
|
||||||
var re recoverableErr
|
_, recoverable := errors.AsType[recoverableErr](writeErr)
|
||||||
recoverable := errors.As(writeErr, &re)
|
|
||||||
if writeErr != nil {
|
if writeErr != nil {
|
||||||
log.Printf("remote write error(recoverable=%v): %v", recoverable, writeErr)
|
log.Printf("remote write error(recoverable=%v): %v", recoverable, writeErr)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,12 +102,12 @@ func getSummarizeLearnedOutput(ri *appctype.RouteInfo) string {
|
|||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
})
|
})
|
||||||
s := ""
|
var s strings.Builder
|
||||||
fmtString := fmt.Sprintf("%%-%ds %%d\n", maxDomainWidth) // eg "%-10s %d\n"
|
fmtString := fmt.Sprintf("%%-%ds %%d\n", maxDomainWidth) // eg "%-10s %d\n"
|
||||||
for _, dc := range x {
|
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 {
|
func runAppcRoutesInfo(ctx context.Context, args []string) error {
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ func Run(args []string) (err error) {
|
|||||||
if errors.Is(err, flag.ErrHelp) {
|
if errors.Is(err, flag.ErrHelp) {
|
||||||
return nil
|
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
|
// When the user enters an unknown subcommand, ffcli tries to run
|
||||||
// the closest valid parent subcommand with everything else as args,
|
// the closest valid parent subcommand with everything else as args,
|
||||||
// returning NoExecError if it doesn't have an Exec function.
|
// returning NoExecError if it doesn't have an Exec function.
|
||||||
|
|||||||
@@ -962,8 +962,8 @@ func TestPrefFlagMapping(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
prefType := reflect.TypeFor[ipn.Prefs]()
|
prefType := reflect.TypeFor[ipn.Prefs]()
|
||||||
for i := range prefType.NumField() {
|
for field := range prefType.Fields() {
|
||||||
prefName := prefType.Field(i).Name
|
prefName := field.Name
|
||||||
if prefHasFlag[prefName] {
|
if prefHasFlag[prefName] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/peterbourgon/ff/v3/ffcli"
|
"github.com/peterbourgon/ff/v3/ffcli"
|
||||||
@@ -85,11 +86,8 @@ func runConfigureSynologyCert(ctx context.Context, args []string) error {
|
|||||||
domain = st.CertDomains[0]
|
domain = st.CertDomains[0]
|
||||||
} else {
|
} else {
|
||||||
var found bool
|
var found bool
|
||||||
for _, d := range st.CertDomains {
|
if slices.Contains(st.CertDomains, domain) {
|
||||||
if d == domain {
|
found = true
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
return fmt.Errorf("Domain %q was not one of the valid domain options: %q.", domain, st.CertDomains)
|
return fmt.Errorf("Domain %q was not one of the valid domain options: %q.", domain, st.CertDomains)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -126,10 +127,8 @@ func runCp(ctx context.Context, args []string) error {
|
|||||||
if cpArgs.name != "" {
|
if cpArgs.name != "" {
|
||||||
return errors.New("can't use --name= with multiple files")
|
return errors.New("can't use --name= with multiple files")
|
||||||
}
|
}
|
||||||
for _, fileArg := range files {
|
if slices.Contains(files, "-") {
|
||||||
if fileArg == "-" {
|
return errors.New("can't use '-' as STDIN file when providing filename arguments")
|
||||||
return errors.New("can't use '-' as STDIN file when providing filename arguments")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"github.com/peterbourgon/ff/v3/ffcli"
|
"github.com/peterbourgon/ff/v3/ffcli"
|
||||||
"tailscale.com/ipn/ipnstate"
|
"tailscale.com/ipn/ipnstate"
|
||||||
@@ -114,17 +115,13 @@ func peerMatchingIP(st *ipnstate.Status, ipStr string) (ps *ipnstate.PeerStatus,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, ps = range st.Peer {
|
for _, ps = range st.Peer {
|
||||||
for _, pip := range ps.TailscaleIPs {
|
if slices.Contains(ps.TailscaleIPs, ip) {
|
||||||
if ip == pip {
|
return ps, true
|
||||||
return ps, true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ps := st.Self; ps != nil {
|
if ps := st.Self; ps != nil {
|
||||||
for _, pip := range ps.TailscaleIPs {
|
if slices.Contains(ps.TailscaleIPs, ip) {
|
||||||
if ip == pip {
|
return ps, true
|
||||||
return ps, true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, false
|
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
|
// isRiskAccepted reports whether riskType is in the comma-separated list of
|
||||||
// risks in acceptedRisks.
|
// risks in acceptedRisks.
|
||||||
func isRiskAccepted(riskType, acceptedRisks string) bool {
|
func isRiskAccepted(riskType, acceptedRisks string) bool {
|
||||||
for _, r := range strings.Split(acceptedRisks, ",") {
|
for r := range strings.SplitSeq(acceptedRisks, ",") {
|
||||||
if r == riskType || r == riskAll {
|
if r == riskType || r == riskAll {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,8 +114,8 @@ func (u *acceptAppCapsFlag) Set(s string) error {
|
|||||||
if s == "" {
|
if s == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
appCaps := strings.Split(s, ",")
|
appCaps := strings.SplitSeq(s, ",")
|
||||||
for _, appCap := range appCaps {
|
for appCap := range appCaps {
|
||||||
appCap = strings.TrimSpace(appCap)
|
appCap = strings.TrimSpace(appCap)
|
||||||
if !validAppCap.MatchString(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)
|
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.AutoExitNode = expr
|
||||||
maskedPrefs.AutoExitNodeSet = true
|
maskedPrefs.AutoExitNodeSet = true
|
||||||
} else if err := maskedPrefs.Prefs.SetExitNodeIP(setArgs.exitNodeIP, st); err != nil {
|
} else if err := maskedPrefs.Prefs.SetExitNodeIP(setArgs.exitNodeIP, st); err != nil {
|
||||||
var e ipn.ExitNodeLocalIPError
|
if _, ok := errors.AsType[ipn.ExitNodeLocalIPError](err); ok {
|
||||||
if errors.As(err, &e) {
|
|
||||||
return fmt.Errorf("%w; did you mean --advertise-exit-node?", err)
|
return fmt.Errorf("%w; did you mean --advertise-exit-node?", err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@@ -251,8 +250,8 @@ func runSet(ctx context.Context, args []string) (retErr error) {
|
|||||||
|
|
||||||
if setArgs.relayServerStaticEndpoints != "" {
|
if setArgs.relayServerStaticEndpoints != "" {
|
||||||
endpointsSet := make(set.Set[netip.AddrPort])
|
endpointsSet := make(set.Set[netip.AddrPort])
|
||||||
endpointsSplit := strings.Split(setArgs.relayServerStaticEndpoints, ",")
|
endpointsSplit := strings.SplitSeq(setArgs.relayServerStaticEndpoints, ",")
|
||||||
for _, s := range endpointsSplit {
|
for s := range endpointsSplit {
|
||||||
ap, err := netip.ParseAddrPort(s)
|
ap, err := netip.ParseAddrPort(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to set relay server static endpoints: %q is not a valid IP:port", s)
|
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"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/peterbourgon/ff/v3/ffcli"
|
"github.com/peterbourgon/ff/v3/ffcli"
|
||||||
@@ -202,10 +203,8 @@ func peerStatusFromArg(st *ipnstate.Status, arg string) (*ipnstate.PeerStatus, b
|
|||||||
argIP, _ := netip.ParseAddr(arg)
|
argIP, _ := netip.ParseAddr(arg)
|
||||||
for _, ps := range st.Peer {
|
for _, ps := range st.Peer {
|
||||||
if argIP.IsValid() {
|
if argIP.IsValid() {
|
||||||
for _, ip := range ps.TailscaleIPs {
|
if slices.Contains(ps.TailscaleIPs, argIP) {
|
||||||
if ip == argIP {
|
return ps, true
|
||||||
return ps, true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -230,10 +229,8 @@ func nodeDNSNameFromArg(st *ipnstate.Status, arg string) (dnsName string, ok boo
|
|||||||
for _, ps := range st.Peer {
|
for _, ps := range st.Peer {
|
||||||
dnsName = ps.DNSName
|
dnsName = ps.DNSName
|
||||||
if argIP.IsValid() {
|
if argIP.IsValid() {
|
||||||
for _, ip := range ps.TailscaleIPs {
|
if slices.Contains(ps.TailscaleIPs, argIP) {
|
||||||
if ip == argIP {
|
return dnsName, true
|
||||||
return dnsName, true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,9 +28,8 @@ func execSSH(ssh string, argv []string) error {
|
|||||||
cmd.Stdin = os.Stdin
|
cmd.Stdin = os.Stdin
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
var ee *exec.ExitError
|
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if errors.As(err, &ee) {
|
if ee, ok := errors.AsType[*exec.ExitError](err); ok {
|
||||||
os.Exit(ee.ExitCode())
|
os.Exit(ee.ExitCode())
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func init() {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
prefix := []byte("SSH_CLIENT=")
|
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) {
|
if bytes.HasPrefix(env, prefix) {
|
||||||
return string(env[len(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 {
|
if expr, useAutoExitNode := ipn.ParseAutoExitNodeString(upArgs.exitNodeIP); useAutoExitNode {
|
||||||
prefs.AutoExitNode = expr
|
prefs.AutoExitNode = expr
|
||||||
} else if err := prefs.SetExitNodeIP(upArgs.exitNodeIP, st); err != nil {
|
} else if err := prefs.SetExitNodeIP(upArgs.exitNodeIP, st); err != nil {
|
||||||
var e ipn.ExitNodeLocalIPError
|
if _, ok := errors.AsType[ipn.ExitNodeLocalIPError](err); ok {
|
||||||
if errors.As(err, &e) {
|
|
||||||
return nil, fmt.Errorf("%w; did you mean --advertise-exit-node?", err)
|
return nil, fmt.Errorf("%w; did you mean --advertise-exit-node?", err)
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -912,7 +911,7 @@ func addPrefFlagMapping(flagName string, prefNames ...string) {
|
|||||||
prefType := reflect.TypeFor[ipn.Prefs]()
|
prefType := reflect.TypeFor[ipn.Prefs]()
|
||||||
for _, pref := range prefNames {
|
for _, pref := range prefNames {
|
||||||
t := prefType
|
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.
|
// Crash at runtime if there's a typo in the prefName.
|
||||||
f, ok := t.FieldByName(name)
|
f, ok := t.FieldByName(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
@@ -352,8 +352,7 @@ func main() {
|
|||||||
// If there's nothing to retry and no non-retryable tests have
|
// If there's nothing to retry and no non-retryable tests have
|
||||||
// failed then we've probably hit a build error.
|
// failed then we've probably hit a build error.
|
||||||
if err := <-runErr; len(toRetry) == 0 && err != nil {
|
if err := <-runErr; len(toRetry) == 0 && err != nil {
|
||||||
var exit *exec.ExitError
|
if exit, ok := errors.AsType[*exec.ExitError](err); ok {
|
||||||
if errors.As(err, &exit) {
|
|
||||||
if code := exit.ExitCode(); code > -1 {
|
if code := exit.ExitCode(); code > -1 {
|
||||||
os.Exit(exit.ExitCode())
|
os.Exit(exit.ExitCode())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -273,8 +273,7 @@ func TestCached(t *testing.T) {}
|
|||||||
}
|
}
|
||||||
|
|
||||||
func errExitCode(err error) (int, bool) {
|
func errExitCode(err error) (int, bool) {
|
||||||
var exit *exec.ExitError
|
if exit, ok := errors.AsType[*exec.ExitError](err); ok {
|
||||||
if errors.As(err, &exit) {
|
|
||||||
return exit.ExitCode(), true
|
return exit.ExitCode(), true
|
||||||
}
|
}
|
||||||
return 0, false
|
return 0, false
|
||||||
|
|||||||
+1
-1
@@ -91,7 +91,7 @@ func main() {
|
|||||||
if distro.Get() == distro.Gokrazy {
|
if distro.Get() == distro.Gokrazy {
|
||||||
cmdLine, _ := os.ReadFile("/proc/cmdline")
|
cmdLine, _ := os.ReadFile("/proc/cmdline")
|
||||||
explicitNS := false
|
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 {
|
if ns, ok := strings.CutPrefix(s, "tta.nameserver="); ok {
|
||||||
err := atomicfile.WriteFile("/tmp/resolv.conf", []byte("nameserver "+ns+"\n"), 0644)
|
err := atomicfile.WriteFile("/tmp/resolv.conf", []byte("nameserver "+ns+"\n"), 0644)
|
||||||
log.Printf("Wrote /tmp/resolv.conf: %v", err)
|
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)
|
writeTemplateWithComment("unsupportedField", fname)
|
||||||
}
|
}
|
||||||
for i := range typ.NumMethods() {
|
for f := range typ.Methods() {
|
||||||
f := typ.Method(i)
|
|
||||||
if !f.Exported() {
|
if !f.Exported() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -720,7 +719,7 @@ func main() {
|
|||||||
fieldComments := getFieldComments(pkg.Syntax)
|
fieldComments := getFieldComments(pkg.Syntax)
|
||||||
|
|
||||||
cloneOnlyType := map[string]bool{}
|
cloneOnlyType := map[string]bool{}
|
||||||
for _, t := range strings.Split(*flagCloneOnlyTypes, ",") {
|
for t := range strings.SplitSeq(*flagCloneOnlyTypes, ",") {
|
||||||
cloneOnlyType[t] = true
|
cloneOnlyType[t] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func fieldsOf(t reflect.Type) (fields []string) {
|
func fieldsOf(t reflect.Type) (fields []string) {
|
||||||
for i := range t.NumField() {
|
for field := range t.Fields() {
|
||||||
if name := t.Field(i).Name; name != "_" {
|
if name := field.Name; name != "_" {
|
||||||
fields = append(fields, name)
|
fields = append(fields, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,12 +214,12 @@ func TestRetryableErrors(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type retryableForTest interface {
|
type retryableForTest interface {
|
||||||
|
error
|
||||||
Retryable() bool
|
Retryable() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func isRetryableErrorForTest(err error) bool {
|
func isRetryableErrorForTest(err error) bool {
|
||||||
var ae retryableForTest
|
if ae, ok := errors.AsType[retryableForTest](err); ok {
|
||||||
if errors.As(err, &ae) {
|
|
||||||
return ae.Retryable()
|
return ae.Retryable()
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -1484,7 +1484,7 @@ func (c *Direct) answerPing(pr *tailcfg.PingRequest) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, t := range strings.Split(pr.Types, ",") {
|
for t := range strings.SplitSeq(pr.Types, ",") {
|
||||||
switch pt := tailcfg.PingType(t); pt {
|
switch pt := tailcfg.PingType(t); pt {
|
||||||
case tailcfg.PingTSMP, tailcfg.PingDisco, tailcfg.PingICMP, tailcfg.PingPeerAPI:
|
case tailcfg.PingTSMP, tailcfg.PingDisco, tailcfg.PingICMP, tailcfg.PingPeerAPI:
|
||||||
go doPingerPing(c.logf, httpc, pr, c.pinger, pt)
|
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)
|
var nodeFields = sync.OnceValue(getNodeFields)
|
||||||
|
|
||||||
// getNodeFields returns the fails of tailcfg.Node.
|
// getNodeFields returns the fields of tailcfg.Node.
|
||||||
func getNodeFields() []string {
|
func getNodeFields() []string {
|
||||||
rt := reflect.TypeFor[tailcfg.Node]()
|
rt := reflect.TypeFor[tailcfg.Node]()
|
||||||
ret := make([]string, rt.NumField())
|
ret := make([]string, 0, rt.NumField())
|
||||||
for i := range rt.NumField() {
|
for f := range rt.Fields() {
|
||||||
ret[i] = rt.Field(i).Name
|
ret = append(ret, f.Name)
|
||||||
}
|
}
|
||||||
return ret
|
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
|
// split on "|" first to remove memnet pipe suffix
|
||||||
addrPart := raddrStr
|
addrPart := raddrStr
|
||||||
if idx := strings.Index(raddrStr, "|"); idx >= 0 {
|
if before, _, ok := strings.Cut(raddrStr, "|"); ok {
|
||||||
addrPart = raddrStr[:idx]
|
addrPart = before
|
||||||
}
|
}
|
||||||
|
|
||||||
host, _, err2 := net.SplitHostPort(addrPart)
|
host, _, err2 := net.SplitHostPort(addrPart)
|
||||||
|
|||||||
@@ -205,17 +205,15 @@ func (k *Knobs) AsDebugJSON() map[string]any {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
ret := map[string]any{}
|
ret := map[string]any{}
|
||||||
rt := reflect.TypeFor[Knobs]()
|
|
||||||
rv := reflect.ValueOf(k).Elem() // of *k
|
rv := reflect.ValueOf(k).Elem() // of *k
|
||||||
for i := 0; i < rt.NumField(); i++ {
|
for sf, fv := range rv.Fields() {
|
||||||
name := rt.Field(i).Name
|
switch v := fv.Addr().Interface().(type) {
|
||||||
switch v := rv.Field(i).Addr().Interface().(type) {
|
|
||||||
case *atomic.Bool:
|
case *atomic.Bool:
|
||||||
ret[name] = v.Load()
|
ret[sf.Name] = v.Load()
|
||||||
case *syncs.AtomicValue[opt.Bool]:
|
case *syncs.AtomicValue[opt.Bool]:
|
||||||
ret[name] = v.Load()
|
ret[sf.Name] = v.Load()
|
||||||
default:
|
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
|
return ret
|
||||||
|
|||||||
+4
-8
@@ -121,8 +121,7 @@ func TestSendRecv(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer cin.Close()
|
defer cin.Close()
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx := t.Context()
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
brwServer := bufio.NewReadWriter(bufio.NewReader(cin), bufio.NewWriter(cin))
|
brwServer := bufio.NewReadWriter(bufio.NewReader(cin), bufio.NewWriter(cin))
|
||||||
go s.Accept(ctx, cin, brwServer, fmt.Sprintf("[abc::def]:%v", i))
|
go s.Accept(ctx, cin, brwServer, fmt.Sprintf("[abc::def]:%v", i))
|
||||||
@@ -331,8 +330,7 @@ func TestSendFreeze(t *testing.T) {
|
|||||||
return c, c2
|
return c, c2
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, clientCtxCancel := context.WithCancel(context.Background())
|
ctx := t.Context()
|
||||||
defer clientCtxCancel()
|
|
||||||
|
|
||||||
aliceKey := key.NewNode()
|
aliceKey := key.NewNode()
|
||||||
aliceClient, aliceConn := newClient(ctx, "alice", aliceKey)
|
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
|
// TestWatch tests the connection watcher mechanism used by regional
|
||||||
// DERP nodes to mesh up with each other.
|
// DERP nodes to mesh up with each other.
|
||||||
func TestWatch(t *testing.T) {
|
func TestWatch(t *testing.T) {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx := t.Context()
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
ts := newTestServer(t, ctx)
|
ts := newTestServer(t, ctx)
|
||||||
defer ts.close(t)
|
defer ts.close(t)
|
||||||
@@ -764,8 +761,7 @@ func waitConnect(t testing.TB, c *Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestServerRepliesToPing(t *testing.T) {
|
func TestServerRepliesToPing(t *testing.T) {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx := t.Context()
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
ts := newTestServer(t, ctx)
|
ts := newTestServer(t, ctx)
|
||||||
defer ts.close(t)
|
defer ts.close(t)
|
||||||
|
|||||||
@@ -299,9 +299,7 @@ func TestBreakWatcherConnRecv(t *testing.T) {
|
|||||||
errChan := make(chan error, 1)
|
errChan := make(chan error, 1)
|
||||||
|
|
||||||
// Start the watcher thread (which connects to the watched server)
|
// 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
|
wg.Go(func() {
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
var peers int
|
var peers int
|
||||||
add := func(m derp.PeerPresentMessage) {
|
add := func(m derp.PeerPresentMessage) {
|
||||||
t.Logf("add: %v", m.Key.ShortString())
|
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)
|
watcher.RunWatchConnectionLoop(ctx, serverPrivateKey1.Public(), t.Logf, add, remove, notifyErr)
|
||||||
}()
|
})
|
||||||
|
|
||||||
synctest.Wait()
|
synctest.Wait()
|
||||||
|
|
||||||
@@ -381,9 +379,7 @@ func TestBreakWatcherConn(t *testing.T) {
|
|||||||
errorChan := make(chan error, 1)
|
errorChan := make(chan error, 1)
|
||||||
|
|
||||||
// Start the watcher thread (which connects to the watched server)
|
// 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
|
wg.Go(func() {
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
var peers int
|
var peers int
|
||||||
add := func(m derp.PeerPresentMessage) {
|
add := func(m derp.PeerPresentMessage) {
|
||||||
t.Logf("add: %v", m.Key.ShortString())
|
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)
|
watcher1.RunWatchConnectionLoop(ctx, serverPrivateKey1.Public(), t.Logf, add, remove, notifyError)
|
||||||
}()
|
})
|
||||||
|
|
||||||
synctest.Wait()
|
synctest.Wait()
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -71,7 +72,7 @@ func init() {
|
|||||||
if keys == "" {
|
if keys == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, keyStr := range strings.Split(keys, ",") {
|
for keyStr := range strings.SplitSeq(keys, ",") {
|
||||||
k, err := key.ParseNodePublicUntyped(mem.S(keyStr))
|
k, err := key.ParseNodePublicUntyped(mem.S(keyStr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("ignoring invalid debug key %q: %v", keyStr, err)
|
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) {
|
if disco.LooksLikeDiscoWrapper(p.bs) {
|
||||||
sendQueue = dst.discoSendQueue
|
sendQueue = dst.discoSendQueue
|
||||||
}
|
}
|
||||||
for attempt := 0; attempt < 3; attempt++ {
|
for attempt := range 3 {
|
||||||
select {
|
select {
|
||||||
case <-dst.done:
|
case <-dst.done:
|
||||||
s.recordDrop(p.bs, c.key, dstKey, dropReasonGoneDisconnected)
|
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
|
// If we saw this connection send previously, then consider
|
||||||
// the group fighting and disable them all.
|
// the group fighting and disable them all.
|
||||||
if s.dupPolicy == disableFighters {
|
if s.dupPolicy == disableFighters {
|
||||||
for _, prior := range dup.sendHistory {
|
if slices.Contains(dup.sendHistory, c) {
|
||||||
if prior == c {
|
cs.ForeachClient(func(c *sclient) {
|
||||||
cs.ForeachClient(func(c *sclient) {
|
c.isDisabled.Store(true)
|
||||||
c.isDisabled.Store(true)
|
if cs.activeClient.Load() == c {
|
||||||
if cs.activeClient.Load() == c {
|
cs.activeClient.Store(nil)
|
||||||
cs.activeClient.Store(nil)
|
}
|
||||||
}
|
})
|
||||||
})
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -627,22 +627,17 @@ func BenchmarkConcurrentStreams(b *testing.B) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
defer ln.Close()
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx := b.Context()
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
|
acceptDone := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
for ctx.Err() == nil {
|
defer close(acceptDone)
|
||||||
|
for {
|
||||||
connIn, err := ln.Accept()
|
connIn, err := ln.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if ctx.Err() != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b.Error(err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
brwServer := bufio.NewReadWriter(bufio.NewReader(connIn), bufio.NewWriter(connIn))
|
brwServer := bufio.NewReadWriter(bufio.NewReader(connIn), bufio.NewWriter(connIn))
|
||||||
go s.Accept(ctx, connIn, brwServer, "test-client")
|
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) {
|
func BenchmarkSendRecv(b *testing.B) {
|
||||||
@@ -769,7 +767,7 @@ func TestServeDebugTrafficUniqueSenders(t *testing.T) {
|
|||||||
senderCardinality: hyperloglog.New(),
|
senderCardinality: hyperloglog.New(),
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < 5; i++ {
|
for range 5 {
|
||||||
c.senderCardinality.Insert(key.NewNode().Public().AppendTo(nil))
|
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)
|
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))
|
c.senderCardinality.Insert(senders[i].AppendTo(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -869,7 +867,7 @@ func TestSenderCardinality100(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
numSenders := 100
|
numSenders := 100
|
||||||
for i := 0; i < numSenders; i++ {
|
for range numSenders {
|
||||||
c.senderCardinality.Insert(key.NewNode().Public().AppendTo(nil))
|
c.senderCardinality.Insert(key.NewNode().Public().AppendTo(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -945,7 +943,7 @@ func BenchmarkHyperLogLogInsertUnique(b *testing.B) {
|
|||||||
func BenchmarkHyperLogLogEstimate(b *testing.B) {
|
func BenchmarkHyperLogLogEstimate(b *testing.B) {
|
||||||
hll := hyperloglog.New()
|
hll := hyperloglog.New()
|
||||||
|
|
||||||
for i := 0; i < 100; i++ {
|
for range 100 {
|
||||||
hll.Insert(key.NewNode().Public().AppendTo(nil))
|
hll.Insert(key.NewNode().Public().AppendTo(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,8 +62,7 @@ func NewSTUNServer(config *STUNServerConfig, opts ...STUNServerOption) (*STUNSer
|
|||||||
objs := new(bpfObjects)
|
objs := new(bpfObjects)
|
||||||
err = loadBpfObjects(objs, nil)
|
err = loadBpfObjects(objs, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var ve *ebpf.VerifierError
|
if ve, ok := errors.AsType[*ebpf.VerifierError](err); config.FullVerifierErr && ok {
|
||||||
if config.FullVerifierErr && errors.As(err, &ve) {
|
|
||||||
err = fmt.Errorf("verifier error: %+v", ve)
|
err = fmt.Errorf("verifier error: %+v", ve)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("error loading XDP program: %w", err)
|
return nil, fmt.Errorf("error loading XDP program: %w", err)
|
||||||
|
|||||||
+4
-4
@@ -475,7 +475,7 @@ const allocateUDPRelayEndpointRequestLen = key.DiscoPublicRawLen*2 + // ClientDi
|
|||||||
|
|
||||||
func (m *AllocateUDPRelayEndpointRequest) AppendMarshal(b []byte) []byte {
|
func (m *AllocateUDPRelayEndpointRequest) AppendMarshal(b []byte) []byte {
|
||||||
ret, p := appendMsgHeader(b, TypeAllocateUDPRelayEndpointRequest, v0, allocateUDPRelayEndpointRequestLen)
|
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)
|
disco := m.ClientDisco[i].AppendTo(nil)
|
||||||
copy(p, disco)
|
copy(p, disco)
|
||||||
p = p[key.DiscoPublicRawLen:]
|
p = p[key.DiscoPublicRawLen:]
|
||||||
@@ -492,7 +492,7 @@ func parseAllocateUDPRelayEndpointRequest(ver uint8, p []byte) (m *AllocateUDPRe
|
|||||||
if len(p) < allocateUDPRelayEndpointRequestLen {
|
if len(p) < allocateUDPRelayEndpointRequestLen {
|
||||||
return m, errShort
|
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]))
|
m.ClientDisco[i] = key.DiscoPublicFromRaw32(mem.B(p[:key.DiscoPublicRawLen]))
|
||||||
p = p[key.DiscoPublicRawLen:]
|
p = p[key.DiscoPublicRawLen:]
|
||||||
}
|
}
|
||||||
@@ -565,7 +565,7 @@ func (m *UDPRelayEndpoint) encode(b []byte) {
|
|||||||
disco := m.ServerDisco.AppendTo(nil)
|
disco := m.ServerDisco.AppendTo(nil)
|
||||||
copy(b, disco)
|
copy(b, disco)
|
||||||
b = b[key.DiscoPublicRawLen:]
|
b = b[key.DiscoPublicRawLen:]
|
||||||
for i := 0; i < len(m.ClientDisco); i++ {
|
for i := range len(m.ClientDisco) {
|
||||||
disco = m.ClientDisco[i].AppendTo(nil)
|
disco = m.ClientDisco[i].AppendTo(nil)
|
||||||
copy(b, disco)
|
copy(b, disco)
|
||||||
b = b[key.DiscoPublicRawLen:]
|
b = b[key.DiscoPublicRawLen:]
|
||||||
@@ -594,7 +594,7 @@ func (m *UDPRelayEndpoint) decode(b []byte) error {
|
|||||||
}
|
}
|
||||||
m.ServerDisco = key.DiscoPublicFromRaw32(mem.B(b[:key.DiscoPublicRawLen]))
|
m.ServerDisco = key.DiscoPublicFromRaw32(mem.B(b[:key.DiscoPublicRawLen]))
|
||||||
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]))
|
m.ClientDisco[i] = key.DiscoPublicFromRaw32(mem.B(b[:key.DiscoPublicRawLen]))
|
||||||
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
|
return nil, err
|
||||||
}
|
}
|
||||||
mac := hmac.New(sha256.New, []byte(secret))
|
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([]byte("."))
|
||||||
mac.Write(b)
|
mac.Write(b)
|
||||||
want := hex.EncodeToString(mac.Sum(nil))
|
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)
|
signatures = make(map[string][]string)
|
||||||
pairs := strings.Split(header, ",")
|
pairs := strings.SplitSeq(header, ",")
|
||||||
for _, pair := range pairs {
|
for pair := range pairs {
|
||||||
parts := strings.Split(pair, "=")
|
parts := strings.Split(pair, "=")
|
||||||
if len(parts) != 2 {
|
if len(parts) != 2 {
|
||||||
return time.Time{}, nil, errNotSigned
|
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.
|
// Fixup paths to add the requested path as a prefix, escaped for inclusion in XML.
|
||||||
pp := shared.EscapeForXML(shared.Join(pathComponents[0:mpl]...))
|
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
|
return bw.status, b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"slices"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"go4.org/netipx"
|
"go4.org/netipx"
|
||||||
@@ -329,13 +330,7 @@ func configFromNodeView(n tailcfg.NodeView) (config, error) {
|
|||||||
selfRoutedDomains: set.Set[dnsname.FQDN]{},
|
selfRoutedDomains: set.Set[dnsname.FQDN]{},
|
||||||
}
|
}
|
||||||
for _, app := range apps {
|
for _, app := range apps {
|
||||||
selfMatchesTags := false
|
selfMatchesTags := slices.ContainsFunc(app.Connectors, selfTags.Contains)
|
||||||
for _, tag := range app.Connectors {
|
|
||||||
if selfTags.Contains(tag) {
|
|
||||||
selfMatchesTags = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, d := range app.Domains {
|
for _, d := range app.Domains {
|
||||||
fqdn, err := dnsname.ToFQDN(d)
|
fqdn, err := dnsname.ToFQDN(d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ func TestHandleConnectorTransitIPRequestMultipleTIP(t *testing.T) {
|
|||||||
t.Fatalf("n TransitIPs in response: %d, want 3", len(resp.TransitIPs))
|
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
|
got := resp.TransitIPs[i].Code
|
||||||
if got != TransitIPResponseCode(0) {
|
if got != TransitIPResponseCode(0) {
|
||||||
t.Fatalf("i=%d TransitIP Code: %d, want 0", i, got)
|
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))
|
}).Exchange(ctx, "", oauth2.SetAuthURLParam("client_id", clientID), oauth2.SetAuthURLParam("jwt", idToken))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Try to extract more detailed error message
|
// Try to extract more detailed error message
|
||||||
var retrieveErr *oauth2.RetrieveError
|
if retrieveErr, ok := errors.AsType[*oauth2.RetrieveError](err); ok {
|
||||||
if errors.As(err, &retrieveErr) {
|
|
||||||
return "", fmt.Errorf("token exchange failed with status %d: %s", retrieveErr.Response.StatusCode, string(retrieveErr.Body))
|
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)
|
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.
|
// Keep writing until we get a callback.
|
||||||
func() {
|
func() {
|
||||||
for i := range 10000 {
|
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)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ func (f fsFileOps) Rename(oldPath, newName string) (newPath string, err error) {
|
|||||||
wantSize := st.Size()
|
wantSize := st.Size()
|
||||||
|
|
||||||
const maxRetries = 10
|
const maxRetries = 10
|
||||||
for i := 0; i < maxRetries; i++ {
|
for range maxRetries {
|
||||||
renameMu.Lock()
|
renameMu.Lock()
|
||||||
fi, statErr := os.Stat(dst)
|
fi, statErr := os.Stat(dst)
|
||||||
// Atomically rename the partial file as the destination file if it doesn't exist.
|
// 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) {
|
func TestNilMethodsDontCrash(t *testing.T) {
|
||||||
var nilt *Tracker
|
var nilt *Tracker
|
||||||
rv := reflect.ValueOf(nilt)
|
rv := reflect.ValueOf(nilt)
|
||||||
for i := 0; i < rv.NumMethod(); i++ {
|
for mt, method := range rv.Methods() {
|
||||||
mt := rv.Type().Method(i)
|
|
||||||
t.Logf("calling Tracker.%s ...", mt.Name)
|
t.Logf("calling Tracker.%s ...", mt.Name)
|
||||||
var args []reflect.Value
|
var args []reflect.Value
|
||||||
for j := 0; j < mt.Type.NumIn(); j++ {
|
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)))
|
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 {
|
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 {
|
if suffix, ok := strings.CutPrefix(field, "QTSFW_"); ok {
|
||||||
return suffix
|
return suffix
|
||||||
}
|
}
|
||||||
@@ -110,11 +110,11 @@ func linuxVersionMeta() (meta versionMeta) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
eq := bytes.IndexByte(line, '=')
|
before, after, ok := bytes.Cut(line, []byte{'='})
|
||||||
if eq == -1 {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
k, v := string(line[:eq]), strings.Trim(string(line[eq+1:]), `"'`)
|
k, v := string(before), strings.Trim(string(after), `"'`)
|
||||||
m[k] = v
|
m[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,8 +69,11 @@ type Opts struct {
|
|||||||
// IsRetryableError returns true if the given error is retryable
|
// IsRetryableError returns true if the given error is retryable
|
||||||
// See [controlclient.apiResponseError]. Potentially retryable errors implement the Retryable() method.
|
// See [controlclient.apiResponseError]. Potentially retryable errors implement the Retryable() method.
|
||||||
func IsRetryableError(err error) bool {
|
func IsRetryableError(err error) bool {
|
||||||
var retryable interface{ Retryable() bool }
|
retryable, ok := errors.AsType[interface {
|
||||||
return errors.As(err, &retryable) && retryable.Retryable()
|
error
|
||||||
|
Retryable() bool
|
||||||
|
}](err)
|
||||||
|
return ok && retryable.Retryable()
|
||||||
}
|
}
|
||||||
|
|
||||||
type backoffOpts struct {
|
type backoffOpts struct {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ func init() {
|
|||||||
|
|
||||||
func breakTCPConnsLinux() error {
|
func breakTCPConnsLinux() error {
|
||||||
var matched int
|
var matched int
|
||||||
for fd := 0; fd < 1000; fd++ {
|
for fd := range 1000 {
|
||||||
_, err := unix.GetsockoptTCPInfo(fd, unix.IPPROTO_TCP, unix.TCP_INFO)
|
_, err := unix.GetsockoptTCPInfo(fd, unix.IPPROTO_TCP, unix.TCP_INFO)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
matched++
|
matched++
|
||||||
|
|||||||
@@ -36,9 +36,8 @@ func TestIsNotableNotify(t *testing.T) {
|
|||||||
// We use reflect to catch fields that might be added in the future without
|
// We use reflect to catch fields that might be added in the future without
|
||||||
// remembering to update the [isNotableNotify] function.
|
// remembering to update the [isNotableNotify] function.
|
||||||
rt := reflect.TypeFor[ipn.Notify]()
|
rt := reflect.TypeFor[ipn.Notify]()
|
||||||
for i := range rt.NumField() {
|
for sf := range rt.Fields() {
|
||||||
n := &ipn.Notify{}
|
n := &ipn.Notify{}
|
||||||
sf := rt.Field(i)
|
|
||||||
switch sf.Name {
|
switch sf.Name {
|
||||||
case "_", "NetMap", "Engine", "Version":
|
case "_", "NetMap", "Engine", "Version":
|
||||||
// Already covered above or not applicable.
|
// Already covered above or not applicable.
|
||||||
@@ -46,7 +45,7 @@ func TestIsNotableNotify(t *testing.T) {
|
|||||||
case "DriveShares":
|
case "DriveShares":
|
||||||
n.DriveShares = views.SliceOfViews[*drive.Share, drive.ShareView](make([]*drive.Share, 1))
|
n.DriveShares = views.SliceOfViews[*drive.Share, drive.ShareView](make([]*drive.Share, 1))
|
||||||
default:
|
default:
|
||||||
rf := reflect.ValueOf(n).Elem().Field(i)
|
rf := reflect.ValueOf(n).Elem().FieldByIndex(sf.Index)
|
||||||
switch rf.Kind() {
|
switch rf.Kind() {
|
||||||
case reflect.Pointer:
|
case reflect.Pointer:
|
||||||
rf.Set(reflect.New(rf.Type().Elem()))
|
rf.Set(reflect.New(rf.Type().Elem()))
|
||||||
@@ -64,7 +63,7 @@ func TestIsNotableNotify(t *testing.T) {
|
|||||||
notify *ipn.Notify
|
notify *ipn.Notify
|
||||||
want bool
|
want bool
|
||||||
}{
|
}{
|
||||||
name: "field-" + rt.Field(i).Name,
|
name: "field-" + sf.Name,
|
||||||
notify: n,
|
notify: n,
|
||||||
want: true,
|
want: true,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ func (h *ExtensionHost) FindMatchingExtension(target any) bool {
|
|||||||
|
|
||||||
val := reflect.ValueOf(target)
|
val := reflect.ValueOf(target)
|
||||||
typ := val.Type()
|
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")
|
panic("ipnext: target must be a non-nil pointer")
|
||||||
}
|
}
|
||||||
targetType := typ.Elem()
|
targetType := typ.Elem()
|
||||||
|
|||||||
@@ -1010,9 +1010,8 @@ func TestNilExtensionHostMethodCall(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
var h *ExtensionHost
|
var h *ExtensionHost
|
||||||
typ := reflect.TypeOf(h)
|
typ := reflect.TypeFor[*ExtensionHost]()
|
||||||
for i := range typ.NumMethod() {
|
for m := range typ.Methods() {
|
||||||
m := typ.Method(i)
|
|
||||||
if strings.HasSuffix(m.Name, "ForTest") {
|
if strings.HasSuffix(m.Name, "ForTest") {
|
||||||
// Skip methods that are only for testing.
|
// Skip methods that are only for testing.
|
||||||
continue
|
continue
|
||||||
|
|||||||
+3
-10
@@ -3687,12 +3687,7 @@ func generateInterceptTCPPortFunc(ports []uint16) func(uint16) bool {
|
|||||||
f = func(p uint16) bool { return m[p] }
|
f = func(p uint16) bool { return m[p] }
|
||||||
} else {
|
} else {
|
||||||
f = func(p uint16) bool {
|
f = func(p uint16) bool {
|
||||||
for _, x := range ports {
|
return slices.Contains(ports, p)
|
||||||
if p == x {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7387,10 +7382,8 @@ var (
|
|||||||
// allowedAutoRoute determines if the route being added via AdvertiseRoute (the app connector featuge) should be allowed.
|
// allowedAutoRoute determines if the route being added via AdvertiseRoute (the app connector featuge) should be allowed.
|
||||||
func allowedAutoRoute(ipp netip.Prefix) bool {
|
func allowedAutoRoute(ipp netip.Prefix) bool {
|
||||||
// Note: blocking the addrs for globals, not solely the prefixes.
|
// Note: blocking the addrs for globals, not solely the prefixes.
|
||||||
for _, addr := range disallowedAddrs {
|
if slices.Contains(disallowedAddrs, ipp.Addr()) {
|
||||||
if ipp.Addr() == addr {
|
return false
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for _, pfx := range disallowedRanges {
|
for _, pfx := range disallowedRanges {
|
||||||
if pfx.Overlaps(ipp) {
|
if pfx.Overlaps(ipp) {
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ var skippedMapFields = []string{
|
|||||||
func checkFieldCoverage(t *testing.T, nm *netmap.NetworkMap) {
|
func checkFieldCoverage(t *testing.T, nm *netmap.NetworkMap) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
mt := reflect.TypeOf(nm).Elem()
|
mt := reflect.TypeFor[netmap.NetworkMap]()
|
||||||
mv := reflect.ValueOf(nm).Elem()
|
mv := reflect.ValueOf(nm).Elem()
|
||||||
for i := 0; i < mt.NumField(); i++ {
|
for i := 0; i < mt.NumField(); i++ {
|
||||||
f := mt.Field(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.
|
// deterministic that people will bake this into clients.
|
||||||
// We try a few times just in case something's already
|
// We try a few times just in case something's already
|
||||||
// listening on that port (on all interfaces, probably).
|
// listening on that port (on all interfaces, probably).
|
||||||
for try := uint8(0); try < 5; try++ {
|
for try := range uint8(5) {
|
||||||
a16 := ip.As16()
|
a16 := ip.As16()
|
||||||
hashData := a16[len(a16)-3:]
|
hashData := a16[len(a16)-3:]
|
||||||
hashData[0] += try
|
hashData[0] += try
|
||||||
|
|||||||
@@ -835,8 +835,8 @@ func (b *LocalBackend) proxyHandlerForBackend(backend string) (http.Handler, err
|
|||||||
targetURL, insecure := expandProxyArg(backend)
|
targetURL, insecure := expandProxyArg(backend)
|
||||||
|
|
||||||
// Handle unix: scheme specially
|
// Handle unix: scheme specially
|
||||||
if strings.HasPrefix(targetURL, "unix:") {
|
if after, ok := strings.CutPrefix(targetURL, "unix:"); ok {
|
||||||
socketPath := strings.TrimPrefix(targetURL, "unix:")
|
socketPath := after
|
||||||
if socketPath == "" {
|
if socketPath == "" {
|
||||||
return nil, fmt.Errorf("empty unix socket path")
|
return nil, fmt.Errorf("empty unix socket path")
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -101,9 +101,9 @@ func (b *LocalBackend) getSSHUsernames(req *tailcfg.C2NSSHUsernamesRequest) (*ta
|
|||||||
mem.HasSuffix(mem.B(line), mem.S("/false")) {
|
mem.HasSuffix(mem.B(line), mem.S("/false")) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
colon := bytes.IndexByte(line, ':')
|
before, _, ok := bytes.Cut(line, []byte{':'})
|
||||||
if colon != -1 {
|
if ok {
|
||||||
add(string(line[:colon]))
|
add(string(before))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,14 +142,11 @@ func (h *Handler) serveDebugDialTypes(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
for _, dialer := range dialers {
|
for _, dialer := range dialers {
|
||||||
dialer := dialer // loop capture
|
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Go(func() {
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
conn, err := dialer.dial(ctx, network, addr)
|
conn, err := dialer.dial(ctx, network, addr)
|
||||||
results <- result{dialer.name, conn, err}
|
results <- result{dialer.name, conn, err}
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|||||||
+6
-14
@@ -439,12 +439,11 @@ func applyPrefsEdits(src, dst reflect.Value, mask map[string]reflect.Value) {
|
|||||||
|
|
||||||
func maskFields(v reflect.Value) map[string]reflect.Value {
|
func maskFields(v reflect.Value) map[string]reflect.Value {
|
||||||
mask := make(map[string]reflect.Value)
|
mask := make(map[string]reflect.Value)
|
||||||
for i := range v.NumField() {
|
for sf, fv := range v.Fields() {
|
||||||
f := v.Type().Field(i).Name
|
if !strings.HasSuffix(sf.Name, "Set") {
|
||||||
if !strings.HasSuffix(f, "Set") {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mask[strings.TrimSuffix(f, "Set")] = v.Field(i)
|
mask[strings.TrimSuffix(sf.Name, "Set")] = fv
|
||||||
}
|
}
|
||||||
return mask
|
return mask
|
||||||
}
|
}
|
||||||
@@ -845,22 +844,15 @@ func (p *Prefs) SetAdvertiseExitNode(runExit bool) {
|
|||||||
// Tailscale IP.
|
// Tailscale IP.
|
||||||
func peerWithTailscaleIP(st *ipnstate.Status, ip netip.Addr) (ps *ipnstate.PeerStatus, ok bool) {
|
func peerWithTailscaleIP(st *ipnstate.Status, ip netip.Addr) (ps *ipnstate.PeerStatus, ok bool) {
|
||||||
for _, ps := range st.Peer {
|
for _, ps := range st.Peer {
|
||||||
for _, ip2 := range ps.TailscaleIPs {
|
if slices.Contains(ps.TailscaleIPs, ip) {
|
||||||
if ip == ip2 {
|
return ps, true
|
||||||
return ps, true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func isRemoteIP(st *ipnstate.Status, ip netip.Addr) bool {
|
func isRemoteIP(st *ipnstate.Status, ip netip.Addr) bool {
|
||||||
for _, selfIP := range st.TailscaleIPs {
|
return !slices.Contains(st.TailscaleIPs, ip)
|
||||||
if ip == selfIP {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearExitNode sets the ExitNodeID and ExitNodeIP to their zero values.
|
// ClearExitNode sets the ExitNodeID and ExitNodeIP to their zero values.
|
||||||
|
|||||||
+2
-2
@@ -27,8 +27,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func fieldsOf(t reflect.Type) (fields []string) {
|
func fieldsOf(t reflect.Type) (fields []string) {
|
||||||
for i := range t.NumField() {
|
for field := range t.Fields() {
|
||||||
fields = append(fields, t.Field(i).Name)
|
fields = append(fields, field.Name)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -673,7 +673,7 @@ func CheckFunnelPort(wantedPort uint16, node *ipnstate.PeerStatus) error {
|
|||||||
return deny("")
|
return deny("")
|
||||||
}
|
}
|
||||||
wantedPortString := strconv.Itoa(int(wantedPort))
|
wantedPortString := strconv.Itoa(int(wantedPort))
|
||||||
for _, ps := range strings.Split(portsStr, ",") {
|
for ps := range strings.SplitSeq(portsStr, ",") {
|
||||||
if ps == "" {
|
if ps == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,8 +189,7 @@ func (s *awsStore) LoadState() error {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var pnf *ssmTypes.ParameterNotFound
|
if _, ok := errors.AsType[*ssmTypes.ParameterNotFound](err); ok {
|
||||||
if errors.As(err, &pnf) {
|
|
||||||
// Create the parameter as it does not exist yet
|
// Create the parameter as it does not exist yet
|
||||||
// and return directly as it is defacto empty
|
// and return directly as it is defacto empty
|
||||||
return s.persistState()
|
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)
|
return nil, fmt.Errorf("error determining num headers: %v", err)
|
||||||
}
|
}
|
||||||
h := make(http.Header, numHeaders)
|
h := make(http.Header, numHeaders)
|
||||||
for i := uint32(0); i < numHeaders; i++ {
|
for range numHeaders {
|
||||||
name, err := readLenBytes()
|
name, err := readLenBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -224,7 +224,7 @@ func parseHeaders(decompressor io.Reader, log *zap.SugaredLogger) (http.Header,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error reading header data: %w", err)
|
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))
|
h.Add(ns, string(v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -902,8 +902,8 @@ func parseAndRemoveLogLevel(buf []byte) (level int, cleanBuf []byte) {
|
|||||||
if bytes.Contains(buf, v2) {
|
if bytes.Contains(buf, v2) {
|
||||||
return 2, bytes.ReplaceAll(buf, v2, nil)
|
return 2, bytes.ReplaceAll(buf, v2, nil)
|
||||||
}
|
}
|
||||||
if i := bytes.Index(buf, vJSON); i != -1 {
|
if _, after, ok := bytes.Cut(buf, vJSON); ok {
|
||||||
rest := buf[i+len(vJSON):]
|
rest := after
|
||||||
if len(rest) >= 2 {
|
if len(rest) >= 2 {
|
||||||
v := rest[0]
|
v := rest[0]
|
||||||
if v >= '0' && v <= '9' {
|
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.
|
// 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++ {
|
for i := 0; i <= logLines; i++ {
|
||||||
body += string(<-ts.uploaded)
|
body.WriteString(string(<-ts.uploaded))
|
||||||
count := strings.Count(body, "log line")
|
count := strings.Count(body.String(), "log line")
|
||||||
if count == logLines {
|
if count == logLines {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,16 +63,16 @@ func LabelString(k any) string {
|
|||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
sb.WriteString("{")
|
sb.WriteString("{")
|
||||||
|
|
||||||
for i := range t.NumField() {
|
first := true
|
||||||
if i > 0 {
|
for ft, fv := range rv.Fields() {
|
||||||
|
if !first {
|
||||||
sb.WriteString(",")
|
sb.WriteString(",")
|
||||||
}
|
}
|
||||||
ft := t.Field(i)
|
first = false
|
||||||
label := ft.Tag.Get("prom")
|
label := ft.Tag.Get("prom")
|
||||||
if label == "" {
|
if label == "" {
|
||||||
label = strings.ToLower(ft.Name)
|
label = strings.ToLower(ft.Name)
|
||||||
}
|
}
|
||||||
fv := rv.Field(i)
|
|
||||||
switch fv.Kind() {
|
switch fv.Kind() {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
fmt.Fprintf(&sb, "%s=%q", label, fv.String())
|
fmt.Fprintf(&sb, "%s=%q", label, fv.String())
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import (
|
|||||||
func TestInversePrefix(t *testing.T) {
|
func TestInversePrefix(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
for i := range 256 {
|
for i := range 256 {
|
||||||
for len := 0; len < 9; len++ {
|
for len := range 9 {
|
||||||
addr := i & (0xFF << (8 - len))
|
addr := i & (0xFF << (8 - len))
|
||||||
idx := prefixIndex(uint8(addr), len)
|
idx := prefixIndex(uint8(addr), len)
|
||||||
addr2, len2 := inversePrefixIndex(idx)
|
addr2, len2 := inversePrefixIndex(idx)
|
||||||
|
|||||||
@@ -94,8 +94,7 @@ func TestCaptivePortalRequest(t *testing.T) {
|
|||||||
now := time.Now()
|
now := time.Now()
|
||||||
d.clock = func() time.Time { return now }
|
d.clock = func() time.Time { return now }
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx := t.Context()
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.Method != "GET" {
|
if r.Method != "GET" {
|
||||||
@@ -133,8 +132,7 @@ func TestCaptivePortalRequest(t *testing.T) {
|
|||||||
func TestAgainstDERPHandler(t *testing.T) {
|
func TestAgainstDERPHandler(t *testing.T) {
|
||||||
d := NewDetector(t.Logf)
|
d := NewDetector(t.Logf)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx := t.Context()
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
s := httptest.NewServer(http.HandlerFunc(derpserver.ServeNoContent))
|
s := httptest.NewServer(http.HandlerFunc(derpserver.ServeNoContent))
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|||||||
@@ -380,7 +380,7 @@ func isLibnssResolveUsed(env newOSConfigEnv) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reading /etc/resolv.conf: %w", err)
|
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)
|
fields := strings.Fields(line)
|
||||||
if len(fields) < 2 || fields[0] != "hosts:" {
|
if len(fields) < 2 || fields[0] != "hosts:" {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ func (m openresolvManager) GetBaseConfig() (OSConfig, error) {
|
|||||||
|
|
||||||
// Remove the "tailscale" snippet from the list.
|
// Remove the "tailscale" snippet from the list.
|
||||||
args := []string{"-l"}
|
args := []string{"-l"}
|
||||||
for _, f := range strings.Split(strings.TrimSpace(string(bs)), " ") {
|
for f := range strings.SplitSeq(strings.TrimSpace(string(bs)), " ") {
|
||||||
if f == "tailscale" {
|
if f == "tailscale" {
|
||||||
continue
|
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.
|
// If we got a truncated UDP response, return that instead of an error.
|
||||||
var trErr truncatedResponseError
|
if trErr, ok := errors.AsType[truncatedResponseError](err); ok {
|
||||||
if errors.As(err, &trErr) {
|
|
||||||
return trErr.res, nil
|
return trErr.res, nil
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ func runDNSServer(tb testing.TB, opts *testDNSServerOptions, response []byte, on
|
|||||||
udpLn *net.UDPConn
|
udpLn *net.UDPConn
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
for try := 0; try < tries; try++ {
|
for range tries {
|
||||||
if tcpLn != nil {
|
if tcpLn != nil {
|
||||||
tcpLn.Close()
|
tcpLn.Close()
|
||||||
tcpLn = nil
|
tcpLn = nil
|
||||||
@@ -392,9 +392,7 @@ func runDNSServer(tb testing.TB, opts *testDNSServerOptions, response []byte, on
|
|||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
if opts == nil || !opts.SkipTCP {
|
if opts == nil || !opts.SkipTCP {
|
||||||
wg.Add(1)
|
wg.Go(func() {
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
for {
|
for {
|
||||||
conn, err := tcpLn.Accept()
|
conn, err := tcpLn.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -402,7 +400,7 @@ func runDNSServer(tb testing.TB, opts *testDNSServerOptions, response []byte, on
|
|||||||
}
|
}
|
||||||
go handleConn(conn)
|
go handleConn(conn)
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUDP := func(addr netip.AddrPort, req []byte) {
|
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 {
|
if opts == nil || !opts.SkipUDP {
|
||||||
wg.Add(1)
|
wg.Go(func() {
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
for {
|
for {
|
||||||
buf := make([]byte, 65535)
|
buf := make([]byte, 65535)
|
||||||
n, addr, err := udpLn.ReadFromUDPAddrPort(buf)
|
n, addr, err := udpLn.ReadFromUDPAddrPort(buf)
|
||||||
@@ -425,7 +421,7 @@ func runDNSServer(tb testing.TB, opts *testDNSServerOptions, response []byte, on
|
|||||||
buf = buf[:n]
|
buf = buf[:n]
|
||||||
go handleUDP(addr, buf)
|
go handleUDP(addr, buf)
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
tb.Cleanup(func() {
|
tb.Cleanup(func() {
|
||||||
@@ -684,7 +680,7 @@ func makeResponseOfSize(tb testing.TB, domain string, targetSize int, includeOPT
|
|||||||
var response []byte
|
var response []byte
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
for attempt := 0; attempt < 10; attempt++ {
|
for range 10 {
|
||||||
testBuilder := dns.NewBuilder(nil, dns.Header{
|
testBuilder := dns.NewBuilder(nil, dns.Header{
|
||||||
Response: true,
|
Response: true,
|
||||||
Authoritative: true,
|
Authoritative: true,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -172,7 +172,7 @@ func WriteRoutes(w *bufio.Writer, routes map[dnsname.FQDN][]*dnstype.Resolver) {
|
|||||||
}
|
}
|
||||||
kk = append(kk, k)
|
kk = append(kk, k)
|
||||||
}
|
}
|
||||||
sort.Slice(kk, func(i, j int) bool { return kk[i] < kk[j] })
|
slices.Sort(kk)
|
||||||
w.WriteByte('{')
|
w.WriteByte('{')
|
||||||
for i, k := range kk {
|
for i, k := range kk {
|
||||||
if i > 0 {
|
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) {
|
func (fs wslFS) ReadFile(name string) ([]byte, error) {
|
||||||
b, err := wslCombinedOutput(fs.cmd("cat", "--", name))
|
b, err := wslCombinedOutput(fs.cmd("cat", "--", name))
|
||||||
var ee *exec.ExitError
|
if ee, ok := errors.AsType[*exec.ExitError](err); ok && ee.ExitCode() == 1 {
|
||||||
if errors.As(err, &ee) && ee.ExitCode() == 1 {
|
|
||||||
return nil, os.ErrNotExist
|
return nil, os.ErrNotExist
|
||||||
}
|
}
|
||||||
return b, err
|
return b, err
|
||||||
|
|||||||
@@ -545,7 +545,7 @@ func makeProbePlanInitial(dm *tailcfg.DERPMap, ifState *netmon.State) (plan prob
|
|||||||
|
|
||||||
var p4 []probe
|
var p4 []probe
|
||||||
var p6 []probe
|
var p6 []probe
|
||||||
for try := 0; try < 3; try++ {
|
for try := range 3 {
|
||||||
n := reg.Nodes[try%len(reg.Nodes)]
|
n := reg.Nodes[try%len(reg.Nodes)]
|
||||||
delay := time.Duration(try) * defaultInitialRetransmitTime
|
delay := time.Duration(try) * defaultInitialRetransmitTime
|
||||||
if n.IPv4 != "none" && ((ifState.HaveV4 && nodeMight4(n)) || n.IsTestNode()) {
|
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
|
// need to close the underlying Pinger after a timeout
|
||||||
// or when all ICMP probes are done, regardless of
|
// or when all ICMP probes are done, regardless of
|
||||||
// whether the HTTPS probes have finished.
|
// whether the HTTPS probes have finished.
|
||||||
wg.Add(1)
|
wg.Go(func() {
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
if err := c.measureAllICMPLatency(ctx, rs, need); err != nil {
|
if err := c.measureAllICMPLatency(ctx, rs, need); err != nil {
|
||||||
c.logf("[v1] measureAllICMPLatency: %v", err)
|
c.logf("[v1] measureAllICMPLatency: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
wg.Add(len(need))
|
wg.Add(len(need))
|
||||||
c.logf("netcheck: UDP is blocked, trying HTTPS")
|
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 {
|
if len(rg.Nodes) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
wg.Add(1)
|
wg.Go(func() {
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
node := rg.Nodes[0]
|
node := rg.Nodes[0]
|
||||||
req, _ := http.NewRequestWithContext(ctx, "HEAD", "https://"+node.HostName+"/derp/probe", nil)
|
req, _ := http.NewRequestWithContext(ctx, "HEAD", "https://"+node.HostName+"/derp/probe", nil)
|
||||||
// One warm-up one to get HTTP connection set
|
// 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)
|
d := c.timeNow().Sub(t0)
|
||||||
rs.addNodeLatency(node, netip.AddrPort{}, d)
|
rs.addNodeLatency(node, netip.AddrPort{}, d)
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -42,8 +42,7 @@ func TestBasic(t *testing.T) {
|
|||||||
|
|
||||||
c := newTestClient(t)
|
c := newTestClient(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx := t.Context()
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
if err := c.Standalone(ctx, "127.0.0.1:0"); err != nil {
|
if err := c.Standalone(ctx, "127.0.0.1:0"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -124,8 +123,7 @@ func TestWorksWhenUDPBlocked(t *testing.T) {
|
|||||||
|
|
||||||
c := newTestClient(t)
|
c := newTestClient(t)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx := t.Context()
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
r, err := c.GetReport(ctx, dm, nil)
|
r, err := c.GetReport(ctx, dm, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1038,8 +1036,7 @@ func TestNoUDPNilGetReportOpts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c := newTestClient(t)
|
c := newTestClient(t)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx := t.Context()
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
r, err := c.GetReport(ctx, dm, nil)
|
r, err := c.GetReport(ctx, dm, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
shouldDisableUDPGSO = func(err error) bool {
|
shouldDisableUDPGSO = func(err error) bool {
|
||||||
var serr *os.SyscallError
|
if serr, ok := errors.AsType[*os.SyscallError](err); ok {
|
||||||
if errors.As(err, &serr) {
|
|
||||||
// EIO is returned by udp_send_skb() if the device driver does not
|
// EIO is returned by udp_send_skb() if the device driver does not
|
||||||
// have tx checksumming enabled, which is a hard requirement of
|
// have tx checksumming enabled, which is a hard requirement of
|
||||||
// UDP_SEGMENT. See:
|
// UDP_SEGMENT. See:
|
||||||
|
|||||||
+2
-5
@@ -812,11 +812,8 @@ func (m *Monitor) HasCGNATInterface() (bool, error) {
|
|||||||
if hasCGNATInterface || !i.IsUp() || isTailscaleInterface(i.Name, pfxs) {
|
if hasCGNATInterface || !i.IsUp() || isTailscaleInterface(i.Name, pfxs) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, pfx := range pfxs {
|
if slices.ContainsFunc(pfxs, cgnatRange.Overlaps) {
|
||||||
if cgnatRange.Overlaps(pfx) {
|
hasCGNATInterface = true
|
||||||
hasCGNATInterface = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ func CalcAdvertiseRoutes(advertiseRoutes string, advertiseDefaultRoute bool) ([]
|
|||||||
routeMap := map[netip.Prefix]bool{}
|
routeMap := map[netip.Prefix]bool{}
|
||||||
if advertiseRoutes != "" {
|
if advertiseRoutes != "" {
|
||||||
var default4, default6 bool
|
var default4, default6 bool
|
||||||
advroutes := strings.Split(advertiseRoutes, ",")
|
advroutes := strings.SplitSeq(advertiseRoutes, ",")
|
||||||
for _, s := range advroutes {
|
for s := range advroutes {
|
||||||
ipp, err := netip.ParsePrefix(s)
|
ipp, err := netip.ParsePrefix(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%q is not a valid IP address or CIDR prefix", s)
|
return nil, fmt.Errorf("%q is not a valid IP address or CIDR prefix", s)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -488,10 +489,8 @@ func parseClientGreeting(r io.Reader, authMethod byte) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not read methods")
|
return fmt.Errorf("could not read methods")
|
||||||
}
|
}
|
||||||
for _, m := range methods {
|
if slices.Contains(methods, authMethod) {
|
||||||
if m == authMethod {
|
return nil
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return fmt.Errorf("no acceptable auth methods")
|
return fmt.Errorf("no acceptable auth methods")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,11 +180,11 @@ func TestUDP(t *testing.T) {
|
|||||||
|
|
||||||
const echoServerNumber = 3
|
const echoServerNumber = 3
|
||||||
echoServerListener := make([]net.PacketConn, echoServerNumber)
|
echoServerListener := make([]net.PacketConn, echoServerNumber)
|
||||||
for i := 0; i < echoServerNumber; i++ {
|
for i := range echoServerNumber {
|
||||||
echoServerListener[i] = newUDPEchoServer()
|
echoServerListener[i] = newUDPEchoServer()
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
for i := 0; i < echoServerNumber; i++ {
|
for i := range echoServerNumber {
|
||||||
_ = echoServerListener[i].Close()
|
_ = echoServerListener[i].Close()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -277,10 +277,10 @@ func TestUDP(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer socks5UDPConn.Close()
|
defer socks5UDPConn.Close()
|
||||||
|
|
||||||
for i := 0; i < echoServerNumber; i++ {
|
for i := range echoServerNumber {
|
||||||
port := echoServerListener[i].LocalAddr().(*net.UDPAddr).Port
|
port := echoServerListener[i].LocalAddr().(*net.UDPAddr).Port
|
||||||
addr := socksAddr{addrType: ipv4, addr: "127.0.0.1", port: uint16(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)
|
responseBody := sendUDPAndWaitResponse(socks5UDPConn, addr, requestBody)
|
||||||
if !bytes.Equal(requestBody, responseBody) {
|
if !bytes.Equal(requestBody, responseBody) {
|
||||||
t.Fatalf("got: %q want: %q", responseBody, requestBody)
|
t.Fatalf("got: %q want: %q", responseBody, requestBody)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user