test: fix TestDERPVerifyEndpoint

- `tailscale debug derp` use random node private key
This commit is contained in:
seiuneko 2024-12-03 18:54:09 +08:00
parent 103b069f1f
commit d604663121
No known key found for this signature in database
GPG Key ID: A5A75952899A0179
3 changed files with 86 additions and 32 deletions

View File

@ -1,11 +1,10 @@
package integration package integration
import ( import (
"encoding/json" "context"
"fmt" "fmt"
"net" "net"
"strconv" "strconv"
"strings"
"testing" "testing"
"github.com/juanfont/headscale/hscontrol/util" "github.com/juanfont/headscale/hscontrol/util"
@ -13,7 +12,11 @@ import (
"github.com/juanfont/headscale/integration/hsic" "github.com/juanfont/headscale/integration/hsic"
"github.com/juanfont/headscale/integration/integrationutil" "github.com/juanfont/headscale/integration/integrationutil"
"github.com/juanfont/headscale/integration/tsic" "github.com/juanfont/headscale/integration/tsic"
"tailscale.com/derp"
"tailscale.com/derp/derphttp"
"tailscale.com/net/netmon"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/key"
) )
func TestDERPVerifyEndpoint(t *testing.T) { func TestDERPVerifyEndpoint(t *testing.T) {
@ -45,23 +48,24 @@ func TestDERPVerifyEndpoint(t *testing.T) {
) )
assertNoErr(t, err) assertNoErr(t, err)
derpRegion := tailcfg.DERPRegion{
RegionCode: "test-derpverify",
RegionName: "TestDerpVerify",
Nodes: []*tailcfg.DERPNode{
{
Name: "TestDerpVerify",
RegionID: 900,
HostName: derper.GetHostname(),
STUNPort: derper.GetSTUNPort(),
STUNOnly: false,
DERPPort: derper.GetDERPPort(),
InsecureForTests: true,
},
},
}
derpMap := tailcfg.DERPMap{ derpMap := tailcfg.DERPMap{
Regions: map[int]*tailcfg.DERPRegion{ Regions: map[int]*tailcfg.DERPRegion{
900: { 900: &derpRegion,
RegionID: 900,
RegionCode: "test-derpverify",
RegionName: "TestDerpVerify",
Nodes: []*tailcfg.DERPNode{
{
Name: "TestDerpVerify",
RegionID: 900,
HostName: derper.GetHostname(),
STUNPort: derper.GetSTUNPort(),
STUNOnly: false,
DERPPort: derper.GetDERPPort(),
},
},
},
}, },
} }
@ -76,21 +80,40 @@ func TestDERPVerifyEndpoint(t *testing.T) {
allClients, err := scenario.ListTailscaleClients() allClients, err := scenario.ListTailscaleClients()
assertNoErrListClients(t, err) assertNoErrListClients(t, err)
for _, client := range allClients { fakeKey := key.NewNode()
report, err := client.DebugDERPRegion("test-derpverify") DERPVerify(t, fakeKey, derpRegion, false)
assertNoErr(t, err)
successful := false
for _, line := range report.Info {
if strings.Contains(line, "Successfully established a DERP connection with node") {
successful = true
break for _, client := range allClients {
} nodeKey, err := client.GetNodePrivateKey()
} assertNoErr(t, err)
if !successful { DERPVerify(t, *nodeKey, derpRegion, true)
stJSON, err := json.Marshal(report) }
assertNoErr(t, err) }
t.Errorf("Client %s could not establish a DERP connection: %s", client.Hostname(), string(stJSON))
} func DERPVerify(
t *testing.T,
nodeKey key.NodePrivate,
region tailcfg.DERPRegion,
expectSuccess bool,
) {
IntegrationSkip(t)
c := derphttp.NewRegionClient(nodeKey, t.Logf, netmon.NewStatic(), func() *tailcfg.DERPRegion {
return &region
})
var result error
if err := c.Connect(context.Background()); err != nil {
result = fmt.Errorf("client Connect: %w", err)
}
if m, err := c.Recv(); err != nil {
result = fmt.Errorf("client first Recv: %w", err)
} else if v, ok := m.(derp.ServerInfoMessage); !ok {
result = fmt.Errorf("client first Recv was unexpected type %T", v)
}
if expectSuccess && result != nil {
t.Fatalf("DERP verify failed unexpectedly for client %s. Expected success but got error: %v", nodeKey.Public(), result)
} else if !expectSuccess && result == nil {
t.Fatalf("DERP verify succeeded unexpectedly for client %s. Expected failure but it succeeded.", nodeKey.Public())
} }
} }

View File

@ -9,6 +9,7 @@ import (
"github.com/juanfont/headscale/integration/tsic" "github.com/juanfont/headscale/integration/tsic"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/net/netcheck" "tailscale.com/net/netcheck"
"tailscale.com/types/key"
"tailscale.com/types/netmap" "tailscale.com/types/netmap"
) )
@ -31,6 +32,7 @@ type TailscaleClient interface {
Status(...bool) (*ipnstate.Status, error) Status(...bool) (*ipnstate.Status, error)
Netmap() (*netmap.NetworkMap, error) Netmap() (*netmap.NetworkMap, error)
DebugDERPRegion(region string) (*ipnstate.DebugDERPRegionReport, error) DebugDERPRegion(region string) (*ipnstate.DebugDERPRegionReport, error)
GetNodePrivateKey() (*key.NodePrivate, error)
Netcheck() (*netcheck.Report, error) Netcheck() (*netcheck.Report, error)
WaitForNeedsLogin() error WaitForNeedsLogin() error
WaitForRunning() error WaitForRunning() error

View File

@ -24,7 +24,10 @@ import (
"github.com/ory/dockertest/v3/docker" "github.com/ory/dockertest/v3/docker"
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/ipn/store/mem"
"tailscale.com/net/netcheck" "tailscale.com/net/netcheck"
"tailscale.com/paths"
"tailscale.com/types/key"
"tailscale.com/types/netmap" "tailscale.com/types/netmap"
) )
@ -1149,3 +1152,29 @@ func (t *TailscaleInContainer) ReadFile(path string) ([]byte, error) {
return out.Bytes(), nil return out.Bytes(), nil
} }
func (t *TailscaleInContainer) GetNodePrivateKey() (*key.NodePrivate, error) {
state, err := t.ReadFile(paths.DefaultTailscaledStateFile())
if err != nil {
return nil, fmt.Errorf("failed to read state file: %w", err)
}
store := &mem.Store{}
if err = store.LoadFromJSON(state); err != nil {
return nil, fmt.Errorf("failed to unmarshal state file: %w", err)
}
currentProfileKey, err := store.ReadState(ipn.CurrentProfileStateKey)
if err != nil {
return nil, fmt.Errorf("failed to read current profile state key: %w", err)
}
currentProfile, err := store.ReadState(ipn.StateKey(currentProfileKey))
if err != nil {
return nil, fmt.Errorf("failed to read current profile state: %w", err)
}
p := &ipn.Prefs{}
if err = json.Unmarshal(currentProfile, &p); err != nil {
return nil, fmt.Errorf("failed to unmarshal current profile state: %w", err)
}
return &p.Persist.PrivateNodeKey, nil
}