mirror of
https://github.com/juanfont/headscale.git
synced 2026-11-01 03:04:07 +09:00
Bounds the DERP HTTP client's error body read. DERP region IDs are now
tailcfg.DERPRegionID.
(cherry picked from commit 3aece6501, adapted)
135 lines
3.9 KiB
Go
135 lines
3.9 KiB
Go
package integration
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/juanfont/headscale/hscontrol/util"
|
|
"github.com/juanfont/headscale/integration/dsic"
|
|
"github.com/juanfont/headscale/integration/hsic"
|
|
"github.com/juanfont/headscale/integration/integrationutil"
|
|
"github.com/juanfont/headscale/integration/tsic"
|
|
"github.com/stretchr/testify/require"
|
|
"tailscale.com/derp"
|
|
"tailscale.com/derp/derphttp"
|
|
"tailscale.com/net/netmon"
|
|
"tailscale.com/tailcfg"
|
|
"tailscale.com/types/key"
|
|
)
|
|
|
|
func TestDERPVerifyEndpoint(t *testing.T) {
|
|
IntegrationSkip(t)
|
|
|
|
// Generate random hostname for the headscale instance
|
|
hash, err := util.GenerateRandomStringDNSSafe(6)
|
|
require.NoError(t, err)
|
|
|
|
testName := "derpverify"
|
|
hostname := fmt.Sprintf("hs-%s-%s", testName, hash)
|
|
|
|
headscalePort := 8080
|
|
|
|
// Create cert for headscale
|
|
caHeadscale, certHeadscale, keyHeadscale, err := integrationutil.CreateCertificate(hostname)
|
|
require.NoError(t, err)
|
|
|
|
spec := ScenarioSpec{
|
|
NodesPerUser: len(MustTestVersions),
|
|
Users: []string{"user1"},
|
|
}
|
|
|
|
scenario, err := NewScenario(spec)
|
|
|
|
require.NoError(t, err)
|
|
defer scenario.ShutdownAssertNoPanics(t)
|
|
|
|
derper, err := scenario.CreateDERPServer("head",
|
|
dsic.WithCACert(caHeadscale),
|
|
dsic.WithVerifyClientURL(fmt.Sprintf("https://%s/verify", net.JoinHostPort(hostname, strconv.Itoa(headscalePort)))),
|
|
)
|
|
require.NoError(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{
|
|
Regions: map[tailcfg.DERPRegionID]*tailcfg.DERPRegion{
|
|
900: &derpRegion,
|
|
},
|
|
}
|
|
|
|
// [hsic.WithHostname] is used instead of [hsic.WithTestName] because the hostname
|
|
// must match the pre-generated TLS certificate created above.
|
|
// The test name "derpverify" is embedded in the hostname variable.
|
|
//
|
|
// [tsic.WithCACert] passes the external DERP server's certificate so
|
|
// tailscale clients trust it. [hsic.WithCustomTLS] and [hsic.WithDERPConfig]
|
|
// configure headscale to use the external DERP server created
|
|
// above instead of the default embedded one.
|
|
err = scenario.CreateHeadscaleEnv([]tsic.Option{tsic.WithCACert(derper.GetCert())},
|
|
hsic.WithHostname(hostname),
|
|
hsic.WithPort(headscalePort),
|
|
hsic.WithCustomTLS(caHeadscale, certHeadscale, keyHeadscale),
|
|
hsic.WithDERPConfig(derpMap))
|
|
requireNoErrHeadscaleEnv(t, err)
|
|
|
|
allClients, err := scenario.ListTailscaleClients()
|
|
requireNoErrListClients(t, err)
|
|
|
|
fakeKey := key.NewNode()
|
|
DERPVerify(t, fakeKey, derpRegion, false)
|
|
|
|
for _, client := range allClients {
|
|
nodeKey, err := client.GetNodePrivateKey()
|
|
require.NoError(t, err)
|
|
DERPVerify(t, *nodeKey, derpRegion, true)
|
|
}
|
|
}
|
|
|
|
func DERPVerify(
|
|
t *testing.T,
|
|
nodeKey key.NodePrivate,
|
|
region tailcfg.DERPRegion,
|
|
expectSuccess bool,
|
|
) {
|
|
t.Helper()
|
|
|
|
c := derphttp.NewRegionClient(nodeKey, t.Logf, netmon.NewStatic(), func() *tailcfg.DERPRegion {
|
|
return ®ion
|
|
})
|
|
defer c.Close()
|
|
|
|
var result error
|
|
|
|
err := c.Connect(t.Context())
|
|
if err != nil {
|
|
result = fmt.Errorf("client Connect: %w", err)
|
|
}
|
|
|
|
if m, err := c.Recv(); err != nil { //nolint:noinlineerr
|
|
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) //nolint:err113
|
|
}
|
|
|
|
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())
|
|
}
|
|
}
|