|
|
|
|
@ -44,6 +44,7 @@ import ( |
|
|
|
|
"tailscale.com/types/opt" |
|
|
|
|
"tailscale.com/types/ptr" |
|
|
|
|
"tailscale.com/util/must" |
|
|
|
|
"tailscale.com/util/set" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func TestMain(m *testing.M) { |
|
|
|
|
@ -1530,3 +1531,105 @@ func TestEncryptStateMigration(t *testing.T) { |
|
|
|
|
runNode(t, wantPlaintextStateKeys) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TestPeerRelayPing creates three nodes with one acting as a peer relay.
|
|
|
|
|
// The test succeeds when "tailscale ping" flows through the peer
|
|
|
|
|
// relay between all 3 nodes.
|
|
|
|
|
func TestPeerRelayPing(t *testing.T) { |
|
|
|
|
tstest.Shard(t) |
|
|
|
|
tstest.Parallel(t) |
|
|
|
|
|
|
|
|
|
env := NewTestEnv(t, ConfigureControl(func(server *testcontrol.Server) { |
|
|
|
|
server.PeerRelayGrants = true |
|
|
|
|
})) |
|
|
|
|
env.neverDirectUDP = true |
|
|
|
|
env.relayServerUseLoopback = true |
|
|
|
|
|
|
|
|
|
n1 := NewTestNode(t, env) |
|
|
|
|
n2 := NewTestNode(t, env) |
|
|
|
|
peerRelay := NewTestNode(t, env) |
|
|
|
|
|
|
|
|
|
allNodes := []*TestNode{n1, n2, peerRelay} |
|
|
|
|
wantPeerRelayServers := make(set.Set[string]) |
|
|
|
|
for _, n := range allNodes { |
|
|
|
|
n.StartDaemon() |
|
|
|
|
n.AwaitResponding() |
|
|
|
|
n.MustUp() |
|
|
|
|
wantPeerRelayServers.Add(n.AwaitIP4().String()) |
|
|
|
|
n.AwaitRunning() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err := peerRelay.Tailscale("set", "--relay-server-port=0").Run(); err != nil { |
|
|
|
|
t.Fatal(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
errCh := make(chan error) |
|
|
|
|
for _, a := range allNodes { |
|
|
|
|
go func() { |
|
|
|
|
err := tstest.WaitFor(time.Second*5, func() error { |
|
|
|
|
out, err := a.Tailscale("debug", "peer-relay-servers").CombinedOutput() |
|
|
|
|
if err != nil { |
|
|
|
|
return fmt.Errorf("debug peer-relay-servers failed: %v", err) |
|
|
|
|
} |
|
|
|
|
servers := make([]string, 0) |
|
|
|
|
err = json.Unmarshal(out, &servers) |
|
|
|
|
if err != nil { |
|
|
|
|
return fmt.Errorf("failed to unmarshal debug peer-relay-servers: %v", err) |
|
|
|
|
} |
|
|
|
|
gotPeerRelayServers := make(set.Set[string]) |
|
|
|
|
for _, server := range servers { |
|
|
|
|
gotPeerRelayServers.Add(server) |
|
|
|
|
} |
|
|
|
|
if !gotPeerRelayServers.Equal(wantPeerRelayServers) { |
|
|
|
|
return fmt.Errorf("got peer relay servers: %v want: %v", gotPeerRelayServers, wantPeerRelayServers) |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
}) |
|
|
|
|
errCh <- err |
|
|
|
|
}() |
|
|
|
|
} |
|
|
|
|
for range allNodes { |
|
|
|
|
err := <-errCh |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatal(err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pingPairs := make([][2]*TestNode, 0) |
|
|
|
|
for _, a := range allNodes { |
|
|
|
|
for _, z := range allNodes { |
|
|
|
|
if a == z { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
pingPairs = append(pingPairs, [2]*TestNode{a, z}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
for _, pair := range pingPairs { |
|
|
|
|
go func() { |
|
|
|
|
a := pair[0] |
|
|
|
|
z := pair[1] |
|
|
|
|
err := tstest.WaitFor(time.Second*10, func() error { |
|
|
|
|
remoteKey := z.MustStatus().Self.PublicKey |
|
|
|
|
if err := a.Tailscale("ping", "--until-direct=false", "--c=1", "--timeout=1s", z.AwaitIP4().String()).Run(); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
remotePeer, ok := a.MustStatus().Peer[remoteKey] |
|
|
|
|
if !ok { |
|
|
|
|
return fmt.Errorf("%v->%v remote peer not found", a.MustStatus().Self.ID, z.MustStatus().Self.ID) |
|
|
|
|
} |
|
|
|
|
if len(remotePeer.PeerRelay) == 0 { |
|
|
|
|
return fmt.Errorf("%v->%v not using peer relay, curAddr=%v relay=%v", a.MustStatus().Self.ID, z.MustStatus().Self.ID, remotePeer.CurAddr, remotePeer.Relay) |
|
|
|
|
} |
|
|
|
|
t.Logf("%v->%v using peer relay addr: %v", a.MustStatus().Self.ID, z.MustStatus().Self.ID, remotePeer.PeerRelay) |
|
|
|
|
return nil |
|
|
|
|
}) |
|
|
|
|
errCh <- err |
|
|
|
|
}() |
|
|
|
|
} |
|
|
|
|
for range pingPairs { |
|
|
|
|
err := <-errCh |
|
|
|
|
if err != nil { |
|
|
|
|
t.Fatal(err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|