lanes_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. package nebula
  2. import (
  3. "net/netip"
  4. "testing"
  5. "time"
  6. "github.com/gaissmai/bart"
  7. "github.com/slackhq/nebula/cert"
  8. "github.com/slackhq/nebula/config"
  9. "github.com/slackhq/nebula/header"
  10. "github.com/slackhq/nebula/overlay/batch"
  11. "github.com/slackhq/nebula/overlay/overlaytest"
  12. "github.com/slackhq/nebula/overlay/tio"
  13. "github.com/slackhq/nebula/test"
  14. "github.com/slackhq/nebula/udp"
  15. "github.com/stretchr/testify/assert"
  16. "github.com/stretchr/testify/require"
  17. )
  18. func newTestBaseHostInfo(vpnIp netip.Addr, localIdx, remoteIdx uint32, laneCount int) *HostInfo {
  19. base := &HostInfo{
  20. vpnAddrs: []netip.Addr{vpnIp},
  21. localIndexId: localIdx,
  22. remoteIndexId: remoteIdx,
  23. remotes: NewRemoteList([]netip.Addr{vpnIp}, nil),
  24. HandshakePacket: map[uint8][]byte{},
  25. }
  26. base.SetRemote(netip.MustParseAddrPort("192.0.2.1:4242"))
  27. base.lanes = newLaneState(laneCount, uint16(laneCount), 4242)
  28. return base
  29. }
  30. func newTestLaneHostInfo(base *HostInfo, laneIndex uint16, localIdx, remoteIdx uint32, owned bool) *HostInfo {
  31. lane := &HostInfo{
  32. vpnAddrs: base.vpnAddrs,
  33. localIndexId: localIdx,
  34. remoteIndexId: remoteIdx,
  35. remotes: NewRemoteList(base.vpnAddrs, nil),
  36. HandshakePacket: map[uint8][]byte{},
  37. sockIdx: int(laneIndex),
  38. laneIndex: laneIndex,
  39. laneOwned: owned,
  40. parent: base,
  41. }
  42. lane.SetRemote(netip.MustParseAddrPort("192.0.2.1:4243"))
  43. return lane
  44. }
  45. func TestLaneHostmapLifecycle(t *testing.T) {
  46. l := test.NewLogger()
  47. hostMap := newHostMap(l)
  48. ifce := &Interface{l: l} // connectionManager nil is tolerated by unlockedAddLane
  49. vpnIp := netip.MustParseAddr("172.1.1.2")
  50. base := newTestBaseHostInfo(vpnIp, 100, 200, 4)
  51. hostMap.Lock()
  52. hostMap.unlockedAddHostInfo(base, ifce)
  53. hostMap.Unlock()
  54. lane := newTestLaneHostInfo(base, 1, 101, 201, true)
  55. hostMap.Lock()
  56. hostMap.unlockedAddLane(lane, ifce)
  57. hostMap.Unlock()
  58. base.lanes.txLanes[1].Store(lane)
  59. // The lane is reachable by index (RX demux, recv_error) but never a Hosts primary.
  60. assert.Equal(t, lane, hostMap.QueryIndex(101))
  61. assert.Equal(t, lane, hostMap.QueryReverseIndex(201))
  62. assert.Equal(t, base, hostMap.Hosts[vpnIp])
  63. // A lane can never be promoted to primary.
  64. hostMap.Lock()
  65. assert.False(t, hostMap.unlockedMakePrimary(lane))
  66. hostMap.Unlock()
  67. assert.Equal(t, base, hostMap.Hosts[vpnIp])
  68. // Deleting the lane clears only its slot, applies backoff, and never
  69. // reports "no more tunnels to peer" (final).
  70. final := hostMap.DeleteHostInfo(lane)
  71. assert.False(t, final)
  72. assert.Nil(t, hostMap.QueryIndex(101))
  73. assert.Equal(t, base, hostMap.Hosts[vpnIp])
  74. assert.Nil(t, base.lanes.txLanes[1].Load())
  75. base.lanes.Lock()
  76. assert.Equal(t, uint8(1), base.lanes.txFails[1])
  77. assert.False(t, base.lanes.txPending[1])
  78. assert.True(t, base.lanes.txRetryAt[1].After(time.Now()))
  79. base.lanes.Unlock()
  80. // Idempotent: deleting again must not bump the backoff further.
  81. hostMap.DeleteHostInfo(lane)
  82. base.lanes.Lock()
  83. assert.Equal(t, uint8(2), base.lanes.txFails[1]) // noteLaneFailure still runs, but slot CAS is a no-op
  84. base.lanes.Unlock()
  85. }
  86. func TestLaneHostmapCascadeDelete(t *testing.T) {
  87. l := test.NewLogger()
  88. hostMap := newHostMap(l)
  89. ifce := &Interface{l: l}
  90. vpnIp := netip.MustParseAddr("172.1.1.3")
  91. base := newTestBaseHostInfo(vpnIp, 300, 400, 4)
  92. hostMap.Lock()
  93. hostMap.unlockedAddHostInfo(base, ifce)
  94. hostMap.Unlock()
  95. owned := newTestLaneHostInfo(base, 1, 301, 401, true)
  96. peer := newTestLaneHostInfo(base, 2, 302, 402, false)
  97. hostMap.Lock()
  98. hostMap.unlockedAddLane(owned, ifce)
  99. hostMap.unlockedAddLane(peer, ifce)
  100. hostMap.Unlock()
  101. base.lanes.txLanes[1].Store(owned)
  102. base.lanes.Lock()
  103. base.lanes.peerLanes = append(base.lanes.peerLanes, peer)
  104. base.lanes.Unlock()
  105. // Deleting the base takes the whole lane family with it.
  106. final := hostMap.DeleteHostInfo(base)
  107. assert.True(t, final)
  108. assert.Nil(t, hostMap.QueryIndex(300))
  109. assert.Nil(t, hostMap.QueryIndex(301))
  110. assert.Nil(t, hostMap.QueryIndex(302))
  111. assert.Nil(t, hostMap.Hosts[vpnIp])
  112. }
  113. // Regression: deleting a hostinfo whose pending entry is NOT the one recorded
  114. // in vpnIps (e.g. a lane, whose vpnAddrs alias the base's) must not evict a
  115. // concurrently pending base handshake for the same address.
  116. func TestHandshakeManagerVpnIpsIdentityDelete(t *testing.T) {
  117. l := test.NewLogger()
  118. hostMap := newHostMap(l)
  119. lh := newTestLighthouse()
  120. hm := NewHandshakeManager(l, hostMap, lh, &udp.NoopConn{}, defaultHandshakeConfig)
  121. vpnIp := netip.MustParseAddr("172.1.1.4")
  122. pendingBase := hm.StartHandshake(vpnIp, nil)
  123. require.NotNil(t, pendingBase)
  124. other := &HostInfo{vpnAddrs: []netip.Addr{vpnIp}, localIndexId: 999}
  125. hm.DeleteHostInfo(other)
  126. // The pending base handshake must still be tracked.
  127. assert.Equal(t, pendingBase, hm.QueryVpnAddr(vpnIp))
  128. // And deleting the actual owner still works.
  129. hm.DeleteHostInfo(pendingBase)
  130. assert.Nil(t, hm.QueryVpnAddr(vpnIp))
  131. }
  132. func newLaneTestConnectionManager(hostMap *HostMap) (*connectionManager, *Interface) {
  133. l := test.NewLogger()
  134. lh := newTestLighthouse()
  135. cs := &CertState{
  136. initiatingVersion: cert.Version1,
  137. privateKey: []byte{},
  138. v1Cert: &dummyCert{version: cert.Version1},
  139. v1Credential: nil,
  140. }
  141. ifce := &Interface{
  142. hostMap: hostMap,
  143. inside: &overlaytest.NoopTun{},
  144. outside: &udp.NoopConn{},
  145. firewall: &Firewall{},
  146. lightHouse: lh,
  147. pki: &PKI{},
  148. handshakeManager: NewHandshakeManager(l, hostMap, lh, &udp.NoopConn{}, defaultHandshakeConfig),
  149. myVpnNetworksTable: new(bart.Lite),
  150. l: l,
  151. }
  152. ifce.pki.cs.Store(cs)
  153. conf := config.NewC(test.NewLogger())
  154. punchy := NewPunchyFromConfig(test.NewLogger(), conf, nil)
  155. cm := newConnectionManagerFromConfig(test.NewLogger(), conf, hostMap, punchy)
  156. cm.intf = ifce
  157. ifce.connectionManager = cm
  158. ifce.handshakeManager.f = ifce
  159. return cm, ifce
  160. }
  161. func TestLaneTrafficDecision(t *testing.T) {
  162. hostMap := newHostMap(test.NewLogger())
  163. cm, ifce := newLaneTestConnectionManager(hostMap)
  164. vpnIp := netip.MustParseAddr("172.1.1.5")
  165. base := newTestBaseHostInfo(vpnIp, 500, 600, 4)
  166. base.ConnectionState = &ConnectionState{}
  167. hostMap.Lock()
  168. hostMap.unlockedAddHostInfo(base, ifce)
  169. hostMap.Unlock()
  170. lane := newTestLaneHostInfo(base, 1, 501, 601, true)
  171. lane.ConnectionState = &ConnectionState{}
  172. hostMap.Lock()
  173. hostMap.unlockedAddLane(lane, ifce)
  174. hostMap.Unlock()
  175. base.lanes.txLanes[1].Store(lane)
  176. now := time.Now()
  177. // A lane with inbound traffic is alive and never swaps primary or
  178. // migrates relays.
  179. lane.markIn()
  180. decision, resolved, _ := cm.makeTrafficDecision(lane.localIndexId, now)
  181. assert.Equal(t, doNothing, decision)
  182. assert.Equal(t, lane, resolved)
  183. assert.False(t, lane.isPendingDeletion())
  184. // An idle lane gets an active keepalive test...
  185. decision, _, _ = cm.makeTrafficDecision(lane.localIndexId, now)
  186. assert.Equal(t, sendTestPacket, decision)
  187. assert.True(t, lane.isPendingDeletion())
  188. // ...and is declared dead when the test goes unanswered.
  189. decision, _, _ = cm.makeTrafficDecision(lane.localIndexId, now)
  190. assert.Equal(t, deleteTunnel, decision)
  191. }
  192. func TestBaseInactiveConsidersLanes(t *testing.T) {
  193. hostMap := newHostMap(test.NewLogger())
  194. cm, _ := newLaneTestConnectionManager(hostMap)
  195. cm.dropInactive.Store(true)
  196. cm.inactivityTimeout.Store(int64(10 * time.Minute))
  197. now := time.Now()
  198. vpnIp := netip.MustParseAddr("172.1.1.6")
  199. base := newTestBaseHostInfo(vpnIp, 700, 800, 4)
  200. base.lastUsed = now.Add(-time.Hour)
  201. // Base alone: inactive.
  202. _, inactive := cm.isInactive(base, now)
  203. assert.True(t, inactive)
  204. // A recently used lane keeps the base alive.
  205. lane := newTestLaneHostInfo(base, 1, 701, 801, true)
  206. lane.lastUsed = now.Add(-time.Minute)
  207. base.lanes.txLanes[1].Store(lane)
  208. _, inactive = cm.isInactive(base, now)
  209. assert.False(t, inactive)
  210. // Peer-owned lanes count too.
  211. base.lanes.txLanes[1].Store(nil)
  212. base.lanes.Lock()
  213. base.lanes.peerLanes = append(base.lanes.peerLanes, lane)
  214. base.lanes.Unlock()
  215. _, inactive = cm.isInactive(base, now)
  216. assert.False(t, inactive)
  217. }
  218. // recordingBatchWriter satisfies batch's writer interface and records what
  219. // was flushed to it.
  220. type recordingBatchWriter struct {
  221. bufs [][]byte
  222. dsts []netip.AddrPort
  223. }
  224. func (w *recordingBatchWriter) WriteBatch(bufs [][]byte, addrs []netip.AddrPort) (int, error) {
  225. for i := range bufs {
  226. w.bufs = append(w.bufs, append([]byte(nil), bufs[i]...))
  227. w.dsts = append(w.dsts, addrs[i])
  228. }
  229. return len(bufs), nil
  230. }
  231. func TestSendInsideMessageLaneSwap(t *testing.T) {
  232. hostMap := newHostMap(test.NewLogger())
  233. cm, ifce := newLaneTestConnectionManager(hostMap)
  234. _ = cm
  235. vpnIp := netip.MustParseAddr("172.1.1.7")
  236. base := newTestBaseHostInfo(vpnIp, 900, 1000, 4)
  237. lane := newTestLaneHostInfo(base, 1, 901, 1001, true)
  238. // Real cipher states from a real handshake so encryption works.
  239. baseInit, _ := runTestHandshake(t)
  240. laneInit, _ := runTestHandshake(t)
  241. var err error
  242. base.ConnectionState, err = newConnectionStateFromResult(baseInit)
  243. require.NoError(t, err)
  244. lane.ConnectionState, err = newConnectionStateFromResult(laneInit)
  245. require.NoError(t, err)
  246. baseWriter := &recordingBatchWriter{}
  247. laneWriter := &recordingBatchWriter{}
  248. tx := &txQueue{
  249. base: batch.NewSendBatch(baseWriter, batch.SendBatchCap, 1<<16),
  250. lane: batch.NewSendBatch(laneWriter, batch.SendBatchCap, 1<<16),
  251. }
  252. pkt := tio.Packet{Bytes: []byte{0x45, 0, 0, 4, 1, 2, 3, 4}}
  253. nb := make([]byte, 12)
  254. // With the lane published, routine 1's traffic uses the lane session and
  255. // the lane batch.
  256. base.lanes.txLanes[1].Store(lane)
  257. ifce.sendInsideMessage(base, pkt, nb, tx, 1)
  258. tx.flush(ifce, 1)
  259. require.Len(t, laneWriter.bufs, 1)
  260. require.Empty(t, baseWriter.bufs)
  261. assert.Equal(t, lane.GetRemote(), laneWriter.dsts[0])
  262. h := &header.H{}
  263. require.NoError(t, h.Parse(laneWriter.bufs[0]))
  264. assert.Equal(t, lane.remoteIndexId, h.RemoteIndex)
  265. // Routine 2 has no lane: base tunnel, base batch.
  266. ifce.sendInsideMessage(base, pkt, nb, tx, 2)
  267. tx.flush(ifce, 1)
  268. require.Len(t, baseWriter.bufs, 1)
  269. assert.Equal(t, base.GetRemote(), baseWriter.dsts[0])
  270. require.NoError(t, h.Parse(baseWriter.bufs[0]))
  271. assert.Equal(t, base.remoteIndexId, h.RemoteIndex)
  272. // Lane death: slot cleared, instant fallback to base.
  273. base.lanes.txLanes[1].Store(nil)
  274. ifce.sendInsideMessage(base, pkt, nb, tx, 1)
  275. tx.flush(ifce, 1)
  276. require.Len(t, baseWriter.bufs, 2)
  277. require.Len(t, laneWriter.bufs, 1)
  278. }
  279. func TestCompleteLaneResponder(t *testing.T) {
  280. hostMap := newHostMap(test.NewLogger())
  281. _, ifce := newLaneTestConnectionManager(hostMap)
  282. ifce.writers = []udp.Conn{&udp.NoopConn{}, &udp.NoopConn{}, &udp.NoopConn{}, &udp.NoopConn{}}
  283. ifce.messageMetrics = newMessageMetricsOnlyRecvError()
  284. hm := ifce.handshakeManager
  285. hm.config.laneCount = 4
  286. hm.config.lanePortCount = 4
  287. hm.config.laneBasePort = 4242
  288. // A real handshake supplies usable keys and a peer cert.
  289. _, respR := runTestHandshake(t)
  290. respR.PeerLaneIndex = 2
  291. respR.PeerPortCount = 4
  292. respR.PeerBasePort = 5353
  293. via := ViaSender{UdpAddr: netip.MustParseAddrPort("192.0.2.9:5355"), SockIdx: 2}
  294. packet := make([]byte, header.Len+8)
  295. copy(packet[header.Len:], []byte("stage0!!"))
  296. vpnAddrs := []netip.Addr{netip.MustParseAddr("172.1.1.9")}
  297. // No base tunnel: the lane handshake is dropped, nothing registered.
  298. hm.completeLaneResponder(via, packet, []byte("resp"), respR, vpnAddrs)
  299. assert.Nil(t, hostMap.QueryIndex(respR.LocalIndex))
  300. // With a live base the lane attaches to it.
  301. base := newTestBaseHostInfo(vpnAddrs[0], 1300, 1400, 4)
  302. base.ConnectionState = &ConnectionState{}
  303. hostMap.Lock()
  304. hostMap.unlockedAddHostInfo(base, ifce)
  305. hostMap.Unlock()
  306. hm.completeLaneResponder(via, packet, []byte("resp"), respR, vpnAddrs)
  307. lane := hostMap.QueryIndex(respR.LocalIndex)
  308. require.NotNil(t, lane)
  309. assert.True(t, lane.isLane())
  310. assert.False(t, lane.laneOwned)
  311. assert.Equal(t, uint16(2), lane.laneIndex)
  312. assert.Equal(t, 2, lane.sockIdx)
  313. assert.Equal(t, via.UdpAddr, lane.GetRemote())
  314. assert.Equal(t, base, hostMap.Hosts[vpnAddrs[0]], "lane must not displace the base as primary")
  315. base.lanes.Lock()
  316. assert.Len(t, base.lanes.peerLanes, 1)
  317. base.lanes.Unlock()
  318. // A byte-identical stage-0 retransmit resends the cached response and
  319. // must not register a second lane.
  320. hm.completeLaneResponder(via, packet, []byte("resp"), respR, vpnAddrs)
  321. base.lanes.Lock()
  322. assert.Len(t, base.lanes.peerLanes, 1)
  323. base.lanes.Unlock()
  324. // An out-of-range lane index is refused.
  325. respR2 := *respR
  326. respR2.PeerLaneIndex = 9
  327. respR2.LocalIndex = respR.LocalIndex + 1
  328. hm.completeLaneResponder(via, packet, []byte("resp"), &respR2, vpnAddrs)
  329. assert.Nil(t, hostMap.QueryIndex(respR2.LocalIndex))
  330. }
  331. func TestEnsureLanesBackoffOnStage0Failure(t *testing.T) {
  332. hostMap := newHostMap(test.NewLogger())
  333. _, ifce := newLaneTestConnectionManager(hostMap)
  334. // laneCount enables multiport in the manager; the dummy CertState has no
  335. // credential, so stage-0 construction must fail and release the slot with
  336. // backoff rather than leaving it claimed forever.
  337. hm := ifce.handshakeManager
  338. hm.config.laneCount = 4
  339. hm.config.lanePortCount = 4
  340. hm.config.laneBasePort = 4242
  341. vpnIp := netip.MustParseAddr("172.1.1.8")
  342. base := newTestBaseHostInfo(vpnIp, 1100, 1200, 4)
  343. hm.EnsureLanes(base)
  344. base.lanes.Lock()
  345. defer base.lanes.Unlock()
  346. for i := 1; i < 4; i++ {
  347. assert.False(t, base.lanes.txPending[i], "slot %d still pending", i)
  348. assert.Equal(t, uint8(1), base.lanes.txFails[i], "slot %d fails", i)
  349. assert.True(t, base.lanes.txRetryAt[i].After(time.Now()), "slot %d retryAt", i)
  350. }
  351. }