|
|
|
@ -136,13 +136,17 @@ type magicStack struct {
|
|
|
|
|
// friends. You need to call conn.SetNetworkMap and dev.Reconfig
|
|
|
|
|
// before anything interesting happens.
|
|
|
|
|
func newMagicStack(t testing.TB, logf logger.Logf, l nettype.PacketListener, derpMap *tailcfg.DERPMap) *magicStack {
|
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
|
|
privateKey, err := wgkey.NewPrivate()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("generating private key: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return newMagicStackWithKey(t, logf, l, derpMap, privateKey)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func newMagicStackWithKey(t testing.TB, logf logger.Logf, l nettype.PacketListener, derpMap *tailcfg.DERPMap, privateKey wgkey.Private) *magicStack {
|
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
|
|
epCh := make(chan []tailcfg.Endpoint, 100) // arbitrary
|
|
|
|
|
conn, err := NewConn(Options{
|
|
|
|
|
Logf: logf,
|
|
|
|
@ -647,6 +651,76 @@ func TestNoDiscoKey(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDiscokeyChange(t *testing.T) {
|
|
|
|
|
tstest.PanicOnLog()
|
|
|
|
|
tstest.ResourceCheck(t)
|
|
|
|
|
|
|
|
|
|
derpMap, cleanup := runDERPAndStun(t, t.Logf, localhostListener{}, netaddr.IPv4(127, 0, 0, 1))
|
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
|
|
m1Key, err := wgkey.NewPrivate()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("generating nodekey: %v", err)
|
|
|
|
|
}
|
|
|
|
|
m1 := newMagicStackWithKey(t, t.Logf, localhostListener{}, derpMap, m1Key)
|
|
|
|
|
defer m1.Close()
|
|
|
|
|
m2 := newMagicStack(t, t.Logf, localhostListener{}, derpMap)
|
|
|
|
|
defer m2.Close()
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
mu sync.Mutex
|
|
|
|
|
// Start with some random discoKey that isn't actually m1's key,
|
|
|
|
|
// to simulate m2 coming up with knowledge of an old, expired
|
|
|
|
|
// discokey. We'll switch to the correct one later in the test.
|
|
|
|
|
m1DiscoKey = tailcfg.DiscoKey(key.NewPrivate().Public())
|
|
|
|
|
)
|
|
|
|
|
setm1Key := func(idx int, nm *netmap.NetworkMap) {
|
|
|
|
|
if idx != 1 {
|
|
|
|
|
// only mutate m2's netmap
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if len(nm.Peers) != 1 {
|
|
|
|
|
// m1 not in netmap yet.
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
mu.Lock()
|
|
|
|
|
defer mu.Unlock()
|
|
|
|
|
nm.Peers[0].DiscoKey = m1DiscoKey
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cleanupMesh := meshStacks(t.Logf, setm1Key, m1, m2)
|
|
|
|
|
defer cleanupMesh()
|
|
|
|
|
|
|
|
|
|
// Wait for both peers to know about each other.
|
|
|
|
|
for {
|
|
|
|
|
if s1 := m1.Status(); len(s1.Peer) != 1 {
|
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if s2 := m2.Status(); len(s2.Peer) != 1 {
|
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mu.Lock()
|
|
|
|
|
m1DiscoKey = m1.conn.DiscoPublicKey()
|
|
|
|
|
mu.Unlock()
|
|
|
|
|
|
|
|
|
|
// Manually trigger an endpoint update to meshStacks, so it hands
|
|
|
|
|
// m2 a new netmap.
|
|
|
|
|
m1.conn.mu.Lock()
|
|
|
|
|
m1.epCh <- m1.conn.lastEndpoints
|
|
|
|
|
m1.conn.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
cleanup = newPinger(t, t.Logf, m1, m2)
|
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
|
|
mustDirect(t, t.Logf, m1, m2)
|
|
|
|
|
mustDirect(t, t.Logf, m2, m1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestActiveDiscovery(t *testing.T) {
|
|
|
|
|
t.Run("simple_internet", func(t *testing.T) {
|
|
|
|
|
t.Parallel()
|
|
|
|
@ -878,28 +952,27 @@ func testActiveDiscovery(t *testing.T, d *devices) {
|
|
|
|
|
// Everything is now up and running, active discovery should find
|
|
|
|
|
// a direct path between our peers. Wait for it to switch away
|
|
|
|
|
// from DERP.
|
|
|
|
|
mustDirect(t, logf, m1, m2)
|
|
|
|
|
mustDirect(t, logf, m2, m1)
|
|
|
|
|
|
|
|
|
|
mustDirect := func(m1, m2 *magicStack) {
|
|
|
|
|
lastLog := time.Now().Add(-time.Minute)
|
|
|
|
|
// See https://github.com/tailscale/tailscale/issues/654 for a discussion of this deadline.
|
|
|
|
|
for deadline := time.Now().Add(10 * time.Second); time.Now().Before(deadline); time.Sleep(10 * time.Millisecond) {
|
|
|
|
|
pst := m1.Status().Peer[m2.Public()]
|
|
|
|
|
if pst.CurAddr != "" {
|
|
|
|
|
logf("direct link %s->%s found with addr %s", m1, m2, pst.CurAddr)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if now := time.Now(); now.Sub(lastLog) > time.Second {
|
|
|
|
|
logf("no direct path %s->%s yet, addrs %v", m1, m2, pst.Addrs)
|
|
|
|
|
lastLog = now
|
|
|
|
|
}
|
|
|
|
|
logf("starting cleanup")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func mustDirect(t *testing.T, logf logger.Logf, m1, m2 *magicStack) {
|
|
|
|
|
lastLog := time.Now().Add(-time.Minute)
|
|
|
|
|
// See https://github.com/tailscale/tailscale/issues/654 for a discussion of this deadline.
|
|
|
|
|
for deadline := time.Now().Add(10 * time.Second); time.Now().Before(deadline); time.Sleep(10 * time.Millisecond) {
|
|
|
|
|
pst := m1.Status().Peer[m2.Public()]
|
|
|
|
|
if pst.CurAddr != "" {
|
|
|
|
|
logf("direct link %s->%s found with addr %s", m1, m2, pst.CurAddr)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if now := time.Now(); now.Sub(lastLog) > time.Second {
|
|
|
|
|
logf("no direct path %s->%s yet, addrs %v", m1, m2, pst.Addrs)
|
|
|
|
|
lastLog = now
|
|
|
|
|
}
|
|
|
|
|
t.Errorf("magicsock did not find a direct path from %s to %s", m1, m2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mustDirect(m1, m2)
|
|
|
|
|
mustDirect(m2, m1)
|
|
|
|
|
|
|
|
|
|
logf("starting cleanup")
|
|
|
|
|
t.Errorf("magicsock did not find a direct path from %s to %s", m1, m2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testTwoDevicePing(t *testing.T, d *devices) {
|
|
|
|
|