|
@@ -11,6 +11,7 @@ import (
|
|
|
"github.com/slackhq/nebula/test"
|
|
"github.com/slackhq/nebula/test"
|
|
|
"github.com/slackhq/nebula/udp"
|
|
"github.com/slackhq/nebula/udp"
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
+ "github.com/stretchr/testify/require"
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
func Test_NewHandshakeManagerVpnIp(t *testing.T) {
|
|
func Test_NewHandshakeManagerVpnIp(t *testing.T) {
|
|
@@ -42,8 +43,6 @@ func Test_NewHandshakeManagerVpnIp(t *testing.T) {
|
|
|
i2 := blah.StartHandshake(ip, nil)
|
|
i2 := blah.StartHandshake(ip, nil)
|
|
|
assert.Same(t, i, i2)
|
|
assert.Same(t, i, i2)
|
|
|
|
|
|
|
|
- i.remotes = NewRemoteList([]netip.Addr{}, nil)
|
|
|
|
|
-
|
|
|
|
|
// Adding something to pending should not affect the main hostmap
|
|
// Adding something to pending should not affect the main hostmap
|
|
|
assert.Empty(t, mainHM.Hosts)
|
|
assert.Empty(t, mainHM.Hosts)
|
|
|
|
|
|
|
@@ -235,3 +234,70 @@ func TestHandleIncomingDispatch(t *testing.T) {
|
|
|
assert.Empty(t, hm.indexes, "orphan stage-2 must not create state")
|
|
assert.Empty(t, hm.indexes, "orphan stage-2 must not create state")
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+// Test_PendingHandshakeHasRemotes covers create-tunnel -address: a pending hostinfo must already
|
|
|
|
|
+// carry its RemoteList when StartHandshake runs its callback, so SetRemote there, before the
|
|
|
|
|
+// handshake loop has run, is safe and the address becomes one the handshake is sent to.
|
|
|
|
|
+func Test_PendingHandshakeHasRemotes(t *testing.T) {
|
|
|
|
|
+ l := test.NewLogger()
|
|
|
|
|
+ mainHM := newHostMap(l)
|
|
|
|
|
+ preferredRanges := []netip.Prefix{}
|
|
|
|
|
+ mainHM.preferredRanges.Store(&preferredRanges)
|
|
|
|
|
+
|
|
|
|
|
+ hm := NewHandshakeManager(l, mainHM, newTestLighthouse(), &udp.NoopConn{}, defaultHandshakeConfig)
|
|
|
|
|
+
|
|
|
|
|
+ vpnIp := netip.MustParseAddr("172.1.1.2")
|
|
|
|
|
+ remote := netip.MustParseAddrPort("192.168.1.9:4242")
|
|
|
|
|
+
|
|
|
|
|
+ hi := hm.StartHandshake(vpnIp, func(hh *HandshakeHostInfo) {
|
|
|
|
|
+ require.NotNil(t, hh.hostinfo.remotes, "a pending handshake must never be without its RemoteList")
|
|
|
|
|
+ hh.hostinfo.SetRemote(remote)
|
|
|
|
|
+ })
|
|
|
|
|
+ assert.Contains(t, hi.remotes.CopyAddrs(preferredRanges), remote, "the handshake must be sent to the supplied remote")
|
|
|
|
|
+ assert.Equal(t, remote, hi.GetRemote())
|
|
|
|
|
+
|
|
|
|
|
+ // A RemoteList keeps one learned address per host, so a second remote replaces the
|
|
|
|
|
+ // first — the same behaviour change-remote has on an established tunnel.
|
|
|
|
|
+ other := netip.MustParseAddrPort("192.168.1.10:4242")
|
|
|
|
|
+ hi.SetRemote(other)
|
|
|
|
|
+ assert.Equal(t, []netip.AddrPort{other}, hi.remotes.CopyAddrs(preferredRanges))
|
|
|
|
|
+ assert.Equal(t, other, hi.GetRemote())
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// newRemotesRaceFixture builds a handshake manager with an established tunnel to vpnAddr whose
|
|
|
|
|
+// RemoteList is the lighthouse's cached list, the state every teardown-during-handshake race starts from.
|
|
|
|
|
+func newRemotesRaceFixture(t *testing.T, vpnAddr netip.Addr) (*HandshakeManager, *Interface, *HostInfo) {
|
|
|
|
|
+ t.Helper()
|
|
|
|
|
+ l := test.NewLogger()
|
|
|
|
|
+ mainHM := newHostMap(l)
|
|
|
|
|
+ preferredRanges := []netip.Prefix{}
|
|
|
|
|
+ mainHM.preferredRanges.Store(&preferredRanges)
|
|
|
|
|
+
|
|
|
|
|
+ lh := newTestLighthouse()
|
|
|
|
|
+ hm := NewHandshakeManager(l, mainHM, lh, &udp.NoopConn{}, defaultHandshakeConfig)
|
|
|
|
|
+ f := &Interface{hostMap: mainHM, lightHouse: lh, handshakeManager: hm, l: l}
|
|
|
|
|
+ hm.f = f
|
|
|
|
|
+
|
|
|
|
|
+ established := &HostInfo{
|
|
|
|
|
+ vpnAddrs: []netip.Addr{vpnAddr},
|
|
|
|
|
+ localIndexId: 1,
|
|
|
|
|
+ remoteIndexId: 101,
|
|
|
|
|
+ remotes: lh.QueryCache([]netip.Addr{vpnAddr}),
|
|
|
|
|
+ HandshakePacket: map[uint8][]byte{},
|
|
|
|
|
+ }
|
|
|
|
|
+ mainHM.Lock()
|
|
|
|
|
+ mainHM.unlockedAddHostInfo(established, f)
|
|
|
|
|
+ mainHM.Unlock()
|
|
|
|
|
+
|
|
|
|
|
+ return hm, f, established
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// With no handshake pending, tearing down the last tunnel still evicts the list.
|
|
|
|
|
+func Test_CloseTunnelEvictsWithoutPendingHandshake(t *testing.T) {
|
|
|
|
|
+ vpnAddr := netip.MustParseAddr("172.1.1.2")
|
|
|
|
|
+ _, f, established := newRemotesRaceFixture(t, vpnAddr)
|
|
|
|
|
+
|
|
|
|
|
+ f.closeTunnel(established)
|
|
|
|
|
+ assert.NotContains(t, f.hostMap.Hosts, vpnAddr)
|
|
|
|
|
+ assert.NotContains(t, f.lightHouse.addrMap, vpnAddr)
|
|
|
|
|
+}
|