lanes_test.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  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/handshake"
  10. "github.com/slackhq/nebula/header"
  11. "github.com/slackhq/nebula/overlay/batch"
  12. "github.com/slackhq/nebula/overlay/overlaytest"
  13. "github.com/slackhq/nebula/overlay/tio"
  14. "github.com/slackhq/nebula/test"
  15. "github.com/slackhq/nebula/udp"
  16. "github.com/stretchr/testify/assert"
  17. "github.com/stretchr/testify/require"
  18. )
  19. var (
  20. testMyAddr = netip.MustParseAddr("10.0.0.1")
  21. testPeerAddr = netip.MustParseAddr("10.0.0.2")
  22. )
  23. // newTestLaneSet builds a lane set from a real handshake result so the sessions
  24. // it derives hold usable keys.
  25. func newTestLaneSet(t *testing.T, r *handshake.Result, myLanes int, peerPorts, peerBase, peerTxLanes uint32) *laneSet {
  26. t.Helper()
  27. r.PeerPortCount = peerPorts
  28. r.PeerBasePort = peerBase
  29. r.PeerTxLanes = peerTxLanes
  30. return newLaneSet(r, myLanes, testMyAddr, testPeerAddr)
  31. }
  32. // laneSessionFor derives lane s's session and installs it, standing in for the
  33. // data-plane call that would normally be the first to need it.
  34. func laneSessionFor(t *testing.T, ls *laneSet, s int) *ConnectionState {
  35. t.Helper()
  36. cs, err := ls.session(s)
  37. require.NoError(t, err)
  38. require.NotNil(t, cs)
  39. return cs
  40. }
  41. func newTestLaneHostInfo(t *testing.T, r *handshake.Result, ls *laneSet) *HostInfo {
  42. t.Helper()
  43. cs, err := newConnectionStateFromResult(r)
  44. require.NoError(t, err)
  45. hi := &HostInfo{
  46. vpnAddrs: []netip.Addr{testPeerAddr},
  47. localIndexId: 100,
  48. remoteIndexId: 200,
  49. remotes: NewRemoteList([]netip.Addr{testPeerAddr}, nil),
  50. HandshakePacket: map[uint8][]byte{},
  51. ConnectionState: cs,
  52. lanes: ls,
  53. }
  54. hi.SetRemote(netip.MustParseAddrPort("192.0.2.1:4242"))
  55. return hi
  56. }
  57. func TestLanePortOffset(t *testing.T) {
  58. a := netip.MustParseAddr("10.0.0.1")
  59. b := netip.MustParseAddr("10.0.0.2")
  60. // Deterministic and in range.
  61. for _, count := range []uint16{1, 2, 3, 4, 16, 256} {
  62. o := lanePortOffset(a, b, count)
  63. assert.Equal(t, o, lanePortOffset(a, b, count), "count %d not deterministic", count)
  64. assert.Less(t, o, count, "count %d out of range", count)
  65. }
  66. assert.Equal(t, uint16(0), lanePortOffset(a, b, 0), "zero port count")
  67. // The two sides' rotations cancel when port counts match, preserving the
  68. // lane-i-reverses-lane-j conntrack pairing.
  69. for _, count := range []uint16{2, 3, 4, 7, 16} {
  70. for i := range 32 {
  71. peer := netip.AddrFrom4([4]byte{192, 0, 2, byte(i)})
  72. oA := lanePortOffset(a, peer, count)
  73. oB := lanePortOffset(peer, a, count)
  74. assert.Equal(t, uint16(0), (oA+oB)%count,
  75. "offsets don't cancel for peer %s count %d", peer, count)
  76. }
  77. }
  78. // Distinct small peers land on distinct rotations of a big peer's range,
  79. // not all on the same first ports.
  80. const bigPeerPorts = 16
  81. distinct := map[uint16]struct{}{}
  82. for i := range 64 {
  83. client := netip.AddrFrom4([4]byte{192, 0, 2, byte(i)})
  84. distinct[lanePortOffset(client, a, bigPeerPorts)] = struct{}{}
  85. }
  86. assert.GreaterOrEqual(t, len(distinct), 8, "64 clients only produced %d distinct offsets", len(distinct))
  87. }
  88. func TestLaneTargetPort(t *testing.T) {
  89. ls := &laneSet{peerBasePort: 4242, peerPortCount: 4}
  90. // No rotation: lane i targets base+i, wrapping past the peer's range.
  91. for i, want := range map[int]uint16{1: 4243, 2: 4244, 3: 4245, 5: 4243} {
  92. assert.Equal(t, want, ls.laneTargetPortLocked(i), "lane %d", i)
  93. }
  94. // Rotation shifts the whole mapping; the wrapped lane lands on the base
  95. // port itself, which is a valid distinct 4-tuple (our source port differs).
  96. ls.portOffset = 3
  97. for i, want := range map[int]uint16{1: 4242, 2: 4243, 3: 4244} {
  98. assert.Equal(t, want, ls.laneTargetPortLocked(i), "rotated lane %d", i)
  99. }
  100. // Fewer peer ports than local lanes: rotation still spreads across all of
  101. // the peer's ports.
  102. ls = &laneSet{peerBasePort: 4242, peerPortCount: 2, portOffset: 1}
  103. assert.Equal(t, uint16(4242), ls.laneTargetPortLocked(1))
  104. assert.Equal(t, uint16(4243), ls.laneTargetPortLocked(2))
  105. }
  106. // A lane's keys are derived, not negotiated, so the whole design rests on the
  107. // two sides landing on the same pair without exchanging anything.
  108. func TestLaneKeyDerivationSymmetry(t *testing.T) {
  109. initR, respR := runTestHandshake(t)
  110. initLS := newTestLaneSet(t, initR, 4, 4, 4242, 4)
  111. respLS := newTestLaneSet(t, respR, 4, 4, 4242, 4)
  112. require.Len(t, initLS.sessions, 4)
  113. assert.Nil(t, initLS.sessions[0].Load(), "lane 0 is the base session, not a derived one")
  114. nb := make([]byte, 12)
  115. for s := 1; s < 4; s++ {
  116. out := header.EncodeLane(make([]byte, 0, mtu), header.Version, header.Message, 0, 200, 1, uint8(s))
  117. ct, err := laneSessionFor(t, initLS, s).eKey.EncryptDanger(out, out, []byte("lane payload"), 1, nb)
  118. require.NoError(t, err)
  119. pt, err := laneSessionFor(t, respLS, s).Decrypt(test.NewLogger(), 1, ct, nb)
  120. require.NoError(t, err, "lane %d keys did not match", s)
  121. assert.Equal(t, []byte("lane payload"), pt)
  122. }
  123. // Distinct lanes get distinct keys: lane 2's session must not open lane 1's
  124. // ciphertext, or the header's lane index would be forgeable in effect.
  125. out := header.EncodeLane(make([]byte, 0, mtu), header.Version, header.Message, 0, 200, 7, 1)
  126. ct, err := laneSessionFor(t, initLS, 1).eKey.EncryptDanger(out, out, []byte("lane payload"), 7, nb)
  127. require.NoError(t, err)
  128. _, err = laneSessionFor(t, respLS, 2).Decrypt(test.NewLogger(), 7, ct, nb)
  129. assert.Error(t, err)
  130. }
  131. func TestNewLaneSetSizing(t *testing.T) {
  132. initR, _ := runTestHandshake(t)
  133. // A peer with no multiport advert gets no lanes at all.
  134. assert.Nil(t, newLaneSet(&handshake.Result{}, 4, testMyAddr, testPeerAddr))
  135. // One lane means only the base tunnel, which is not a lane set.
  136. assert.Nil(t, newLaneSet(&handshake.Result{PeerPortCount: 4, PeerTxLanes: 1}, 1, testMyAddr, testPeerAddr))
  137. // Sessions cover both directions: enough for everything the peer may send,
  138. // even though we may only send on a few.
  139. ls := newTestLaneSet(t, initR, 2, 8, 4242, 6)
  140. assert.Len(t, ls.sessions, 6, "sessions must cover the peer's tx lanes")
  141. assert.Equal(t, 2, ls.txLanes, "we may only send on our own lanes")
  142. // The peer's advert sizes the session table but nothing else. Its lane count
  143. // is its own choice, so it must not be able to make us allocate per-lane tx
  144. // state we will never use.
  145. assert.Len(t, ls.txAddr, 2)
  146. assert.Len(t, ls.demand, 2)
  147. assert.Len(t, ls.probe, 2)
  148. // Nothing is derived up front, for the same reason.
  149. for s := range ls.sessions {
  150. assert.Nil(t, ls.sessions[s].Load(), "lane %d derived before anything needed it", s)
  151. }
  152. // Our tx lanes are clamped to the ports the peer actually bound: a lane
  153. // aimed past the peer's range would land on some unrelated socket.
  154. ls = newTestLaneSet(t, initR, 8, 3, 4242, 8)
  155. assert.Equal(t, 3, ls.txLanes)
  156. assert.Len(t, ls.sessions, 8)
  157. }
  158. // The RX path must not cache a session for a lane until a packet on it has
  159. // actually decrypted, or a spoofer naming lanes at random could make us hold a
  160. // replay window and two cipher states per lane without authenticating anything.
  161. func TestLaneSessionRxDerivation(t *testing.T) {
  162. initR, respR := runTestHandshake(t)
  163. respLS := newTestLaneSet(t, respR, 4, 4, 4242, 4)
  164. hi := newTestLaneHostInfo(t, respR, respLS)
  165. ci, cached, err := hi.laneSession(2)
  166. require.NoError(t, err)
  167. require.NotNil(t, ci)
  168. assert.False(t, cached, "the first packet on a lane derives, it does not hit")
  169. assert.Nil(t, respLS.sessions[2].Load(), "an unauthenticated packet must not install a session")
  170. // The lane the peer really is using decrypts, and that is what installs it.
  171. nb := make([]byte, 12)
  172. out := header.EncodeLane(make([]byte, 0, mtu), header.Version, header.Message, 0, 200, 1, 2)
  173. ct, err := laneSessionFor(t, newTestLaneSet(t, initR, 4, 4, 4242, 4), 2).
  174. eKey.EncryptDanger(out, out, []byte("real lane traffic"), 1, nb)
  175. require.NoError(t, err)
  176. pt, err := ci.Decrypt(test.NewLogger(), 1, ct, nb)
  177. require.NoError(t, err)
  178. assert.Equal(t, []byte("real lane traffic"), pt)
  179. respLS.installSession(test.NewLogger(), 2, ci, 1)
  180. assert.Same(t, ci, respLS.sessions[2].Load())
  181. // Now it is a hit, and the replay window the decrypt above advanced is the
  182. // one the next packet sees.
  183. got, cached, err := hi.laneSession(2)
  184. require.NoError(t, err)
  185. assert.True(t, cached)
  186. assert.Same(t, ci, got)
  187. // A racing install loses rather than swapping the session out, which would
  188. // throw away the replay window the live one has been accumulating. The loser's
  189. // packet still has to be marked seen on the winner, or dropping its session
  190. // would make that one counter replayable.
  191. other, err := newLaneConnectionState(&respLS.material, 2)
  192. require.NoError(t, err)
  193. require.True(t, ci.window.Check(test.NewLogger(), 7), "counter 7 seen before the race")
  194. respLS.installSession(test.NewLogger(), 2, other, 7)
  195. assert.Same(t, ci, respLS.sessions[2].Load())
  196. assert.False(t, ci.window.Check(test.NewLogger(), 7),
  197. "the loser's counter was not carried to the surviving window")
  198. }
  199. func TestLaneTxGate(t *testing.T) {
  200. initR, _ := runTestHandshake(t)
  201. ls := newTestLaneSet(t, initR, 4, 4, 4242, 4)
  202. // A down lane hands back nothing and raises demand, which is what gets it
  203. // probed.
  204. ci, addr := ls.txLane(1)
  205. assert.Nil(t, ci)
  206. assert.False(t, addr.IsValid())
  207. assert.True(t, ls.demand[1].Load())
  208. assert.False(t, ls.demand[2].Load(), "demand raised on an untouched lane")
  209. // An up lane with no session derived yet cannot happen — the probe that
  210. // promoted it derived one — but it must fall back rather than send in the
  211. // clear if it ever does.
  212. want := netip.MustParseAddrPort("192.0.2.1:4243")
  213. ls.txAddr[1].Store(&want)
  214. ci, _ = ls.txLane(1)
  215. assert.Nil(t, ci)
  216. // Promotion publishes the session and destination together.
  217. sess := laneSessionFor(t, ls, 1)
  218. ls.demand[1].Store(false)
  219. ci, addr = ls.txLane(1)
  220. assert.Same(t, sess, ci)
  221. assert.Equal(t, want, addr)
  222. assert.False(t, ls.demand[1].Load(), "a hit must not raise demand")
  223. // Lane 0 is the base tunnel and lanes at or above txLanes are receive-only.
  224. ci, _ = ls.txLane(0)
  225. assert.Nil(t, ci)
  226. ci, _ = ls.txLane(4)
  227. assert.Nil(t, ci)
  228. }
  229. func TestLaneSessionLookup(t *testing.T) {
  230. initR, _ := runTestHandshake(t)
  231. ls := newTestLaneSet(t, initR, 3, 4, 4242, 3)
  232. hi := newTestLaneHostInfo(t, initR, ls)
  233. assertNoLane := func(s uint8, msg string) {
  234. t.Helper()
  235. ci, cached, err := hi.laneSession(s)
  236. require.NoError(t, err)
  237. assert.Nil(t, ci, msg)
  238. assert.False(t, cached, msg)
  239. }
  240. assertNoLane(0, "lane 0 is the base session")
  241. assertNoLane(3, "a lane beyond what this tunnel covers")
  242. assertNoLane(255, "a lane beyond what this tunnel covers")
  243. // An already-derived lane is returned as a hit.
  244. sess := laneSessionFor(t, ls, 2)
  245. ci, cached, err := hi.laneSession(2)
  246. require.NoError(t, err)
  247. assert.Same(t, sess, ci)
  248. assert.True(t, cached)
  249. // A peer without lanes answers nil for every lane rather than panicking.
  250. bare := &HostInfo{}
  251. ci, _, err = bare.laneSession(1)
  252. require.NoError(t, err)
  253. assert.Nil(t, ci)
  254. }
  255. func TestMaxMessageCounter(t *testing.T) {
  256. initR, _ := runTestHandshake(t)
  257. ls := newTestLaneSet(t, initR, 3, 4, 4242, 3)
  258. hi := newTestLaneHostInfo(t, initR, ls)
  259. hi.ConnectionState.messageCounter.Store(5)
  260. assert.Equal(t, uint64(5), hi.maxMessageCounter())
  261. // A lane past the base is what the rehandshake threshold has to notice: the
  262. // base counter would sit still while the lane burns through its nonces.
  263. laneSessionFor(t, ls, 2).messageCounter.Store(9000)
  264. assert.Equal(t, uint64(9000), hi.maxMessageCounter())
  265. assert.Equal(t, uint64(0), (&HostInfo{}).maxMessageCounter())
  266. }
  267. func TestLaneRetryDelay(t *testing.T) {
  268. assert.Equal(t, laneRetryBase, laneRetryDelay(0))
  269. assert.Equal(t, 2*laneRetryBase, laneRetryDelay(1))
  270. assert.Equal(t, laneRetryMax, laneRetryDelay(laneMaxFails), "backoff must saturate")
  271. }
  272. func newLaneTestInterface(hostMap *HostMap) *Interface {
  273. l := test.NewLogger()
  274. lh := newTestLighthouse()
  275. cs := &CertState{
  276. initiatingVersion: cert.Version1,
  277. privateKey: []byte{},
  278. v1Cert: &dummyCert{version: cert.Version1},
  279. v1Credential: nil,
  280. }
  281. ifce := &Interface{
  282. hostMap: hostMap,
  283. inside: &overlaytest.NoopTun{},
  284. outside: &udp.NoopConn{},
  285. firewall: &Firewall{},
  286. lightHouse: lh,
  287. pki: &PKI{},
  288. handshakeManager: NewHandshakeManager(l, hostMap, lh, &udp.NoopConn{}, defaultHandshakeConfig),
  289. myVpnNetworksTable: new(bart.Lite),
  290. messageMetrics: newMessageMetricsOnlyRecvError(),
  291. writers: []udp.Conn{&udp.NoopConn{}, &udp.NoopConn{}, &udp.NoopConn{}, &udp.NoopConn{}},
  292. l: l,
  293. }
  294. ifce.pki.cs.Store(cs)
  295. conf := config.NewC(l)
  296. punchy := NewPunchyFromConfig(l, conf, nil)
  297. cm := newConnectionManagerFromConfig(l, conf, hostMap, punchy)
  298. cm.intf = ifce
  299. ifce.connectionManager = cm
  300. ifce.handshakeManager.f = ifce
  301. return ifce
  302. }
  303. // The full TX lifecycle of a lane: demand -> probe -> ack -> up, then an
  304. // unanswered keepalive -> demoted.
  305. func TestLaneProbeLifecycle(t *testing.T) {
  306. hostMap := newHostMap(test.NewLogger())
  307. ifce := newLaneTestInterface(hostMap)
  308. initR, _ := runTestHandshake(t)
  309. ls := newTestLaneSet(t, initR, 4, 4, 5353, 4)
  310. hi := newTestLaneHostInfo(t, initR, ls)
  311. nb := make([]byte, 12)
  312. out := make([]byte, mtu)
  313. now := time.Now()
  314. // No demand: nothing is probed, so a peer we barely talk to costs nothing
  315. // beyond its base tunnel.
  316. ifce.probeLanes(hi, now, nb, out)
  317. ls.mu.Lock()
  318. for s := 1; s < 4; s++ {
  319. assert.True(t, ls.probe[s].sentAt.IsZero(), "lane %d probed without demand", s)
  320. }
  321. ls.mu.Unlock()
  322. // Demand on lane 1 alone probes lane 1 alone, aimed at the peer's port for
  323. // that lane.
  324. ls.demand[1].Store(true)
  325. ifce.probeLanes(hi, now, nb, out)
  326. ls.mu.Lock()
  327. require.False(t, ls.probe[1].sentAt.IsZero(), "demand did not produce a probe")
  328. assert.True(t, ls.probe[2].sentAt.IsZero())
  329. wantPort := ls.laneTargetPortLocked(1)
  330. assert.Equal(t, netip.AddrPortFrom(netip.MustParseAddr("192.0.2.1"), wantPort), ls.probe[1].target)
  331. gen := ls.probe[1].gen
  332. assert.False(t, ls.demand[1].Load(), "the probe did not consume the demand")
  333. ls.mu.Unlock()
  334. // The lane stays down until the ack lands, and a stale generation cannot
  335. // bring it up.
  336. assert.Nil(t, ls.txAddr[1].Load())
  337. assert.False(t, ls.noteAck(1, gen+1, now), "an ack for a superseded probe promoted the lane")
  338. assert.Nil(t, ls.txAddr[1].Load())
  339. // The matching ack promotes it, and the destination is the probed target.
  340. assert.True(t, ls.noteAck(1, gen, now))
  341. addr := ls.txAddr[1].Load()
  342. require.NotNil(t, addr)
  343. assert.Equal(t, netip.AddrPortFrom(netip.MustParseAddr("192.0.2.1"), wantPort), *addr)
  344. // A second ack is a keepalive, not a promotion.
  345. ls.mu.Lock()
  346. ls.probe[1].sentAt = now
  347. ls.mu.Unlock()
  348. assert.False(t, ls.noteAck(1, gen, now))
  349. assert.NotNil(t, ls.txAddr[1].Load())
  350. // An up lane is left alone until the keepalive comes due.
  351. ifce.probeLanes(hi, now, nb, out)
  352. ls.mu.Lock()
  353. assert.True(t, ls.probe[1].sentAt.IsZero(), "an up lane was re-probed early")
  354. ls.mu.Unlock()
  355. // Past the keepalive it re-proves its path...
  356. now = now.Add(laneKeepalive + time.Second)
  357. ifce.probeLanes(hi, now, nb, out)
  358. ls.mu.Lock()
  359. require.False(t, ls.probe[1].sentAt.IsZero(), "keepalive did not probe")
  360. ls.mu.Unlock()
  361. assert.NotNil(t, ls.txAddr[1].Load(), "lane demoted before its probe aged out")
  362. // ...and an unanswered keepalive demotes it with backoff, so the routine
  363. // falls back to the base tunnel.
  364. now = now.Add(laneProbeTimeout + time.Second)
  365. ifce.probeLanes(hi, now, nb, out)
  366. assert.Nil(t, ls.txAddr[1].Load(), "unanswered keepalive did not demote the lane")
  367. ls.mu.Lock()
  368. assert.Equal(t, uint8(1), ls.probe[1].fails)
  369. assert.True(t, ls.probe[1].retryAt.After(now))
  370. ls.mu.Unlock()
  371. // The backoff holds even with fresh demand.
  372. ls.demand[1].Store(true)
  373. ifce.probeLanes(hi, now, nb, out)
  374. ls.mu.Lock()
  375. assert.True(t, ls.probe[1].sentAt.IsZero(), "backoff was ignored")
  376. ls.mu.Unlock()
  377. }
  378. // A roam is a new path with no derivable relationship to the old lane ports, so
  379. // every lane has to be rebuilt rather than moved.
  380. func TestLaneProbeRoamResets(t *testing.T) {
  381. hostMap := newHostMap(test.NewLogger())
  382. ifce := newLaneTestInterface(hostMap)
  383. initR, _ := runTestHandshake(t)
  384. ls := newTestLaneSet(t, initR, 4, 4, 5353, 4)
  385. hi := newTestLaneHostInfo(t, initR, ls)
  386. now := time.Now()
  387. nb := make([]byte, 12)
  388. out := make([]byte, mtu)
  389. ls.demand[1].Store(true)
  390. ifce.probeLanes(hi, now, nb, out)
  391. ls.mu.Lock()
  392. gen := ls.probe[1].gen
  393. ls.mu.Unlock()
  394. require.True(t, ls.noteAck(1, gen, now))
  395. require.NotNil(t, ls.txAddr[1].Load())
  396. // New remote address: the lane is taken down, not retargeted.
  397. hi.SetRemote(netip.MustParseAddrPort("198.51.100.7:4242"))
  398. ifce.probeLanes(hi, now, nb, out)
  399. assert.Nil(t, ls.txAddr[1].Load(), "lane survived a roam")
  400. ls.mu.Lock()
  401. assert.Zero(t, ls.probe[1].fails, "a roam is not a lane failure")
  402. assert.Equal(t, netip.MustParseAddr("198.51.100.7"), ls.peerAddr)
  403. ls.mu.Unlock()
  404. // Relayed (no direct remote) means no lanes at all.
  405. ls.demand[1].Store(true)
  406. ifce.probeLanes(hi, now, nb, out)
  407. ls.mu.Lock()
  408. gen = ls.probe[1].gen
  409. ls.mu.Unlock()
  410. require.True(t, ls.noteAck(1, gen, now))
  411. hi.SetRemote(netip.AddrPort{})
  412. ifce.probeLanes(hi, now, nb, out)
  413. assert.Nil(t, ls.txAddr[1].Load(), "lane survived losing the direct path")
  414. }
  415. // A lane probe is answered on the base tunnel, echoing the header's lane, so a
  416. // peer cannot get us to vouch for a lane it never probed.
  417. func TestHandleLaneProbe(t *testing.T) {
  418. hostMap := newHostMap(test.NewLogger())
  419. ifce := newLaneTestInterface(hostMap)
  420. initR, respR := runTestHandshake(t)
  421. ls := newTestLaneSet(t, respR, 4, 4, 4242, 4)
  422. hi := newTestLaneHostInfo(t, respR, ls)
  423. rxc := &rxContext{nb: make([]byte, 12), scratch: make([]byte, mtu)}
  424. sent := &recordingUdpConn{}
  425. ifce.writers = []udp.Conn{sent, &udp.NoopConn{}, &udp.NoopConn{}, &udp.NoopConn{}}
  426. // The payload's lane is ignored in favour of the header's.
  427. ifce.handleLaneProbe(hi, 2, []byte{3, 42}, rxc)
  428. require.Len(t, sent.bufs, 1, "the ack must ride the base tunnel's socket")
  429. h := &header.H{}
  430. require.NoError(t, h.Parse(sent.bufs[0]))
  431. assert.Equal(t, header.Test, h.Type)
  432. assert.Equal(t, header.LaneProbeAck, h.Subtype)
  433. assert.Equal(t, uint8(0), h.Lane(), "the ack is base-tunnel traffic")
  434. pt, err := laneSessionFor(t, newTestLaneSet(t, initR, 4, 4, 4242, 4), 1).dKey.DecryptDanger(
  435. nil, sent.bufs[0][:header.Len], sent.bufs[0][header.Len:], h.MessageCounter, make([]byte, 12))
  436. _ = pt
  437. assert.Error(t, err, "the ack must not be readable with a lane key")
  438. // A probe claiming lane 0 or with a truncated payload is answered with
  439. // nothing at all.
  440. sent.bufs = nil
  441. ifce.handleLaneProbe(hi, 0, []byte{1, 2}, rxc)
  442. ifce.handleLaneProbe(hi, 1, []byte{1}, rxc)
  443. assert.Empty(t, sent.bufs)
  444. }
  445. func TestHandleLaneProbeAck(t *testing.T) {
  446. hostMap := newHostMap(test.NewLogger())
  447. ifce := newLaneTestInterface(hostMap)
  448. initR, _ := runTestHandshake(t)
  449. ls := newTestLaneSet(t, initR, 4, 4, 5353, 4)
  450. hi := newTestLaneHostInfo(t, initR, ls)
  451. now := time.Now()
  452. ls.demand[1].Store(true)
  453. ifce.probeLanes(hi, now, make([]byte, 12), make([]byte, mtu))
  454. ls.mu.Lock()
  455. gen := ls.probe[1].gen
  456. ls.mu.Unlock()
  457. // A short or out-of-range ack is ignored, and a peer without lanes does not
  458. // panic the handler.
  459. ifce.handleLaneProbeAck(hi, []byte{1})
  460. ifce.handleLaneProbeAck(hi, []byte{99, gen})
  461. ifce.handleLaneProbeAck(&HostInfo{}, []byte{1, gen})
  462. assert.Nil(t, ls.txAddr[1].Load())
  463. ifce.handleLaneProbeAck(hi, []byte{1, gen})
  464. assert.NotNil(t, ls.txAddr[1].Load())
  465. }
  466. // recordingUdpConn records what was written to it, one datagram per write.
  467. type recordingUdpConn struct {
  468. udp.NoopConn
  469. bufs [][]byte
  470. dsts []netip.AddrPort
  471. }
  472. func (c *recordingUdpConn) WriteTo(b []byte, addr netip.AddrPort) error {
  473. c.bufs = append(c.bufs, append([]byte(nil), b...))
  474. c.dsts = append(c.dsts, addr)
  475. return nil
  476. }
  477. // recordingBatchWriter satisfies batch's writer interface and records what
  478. // was flushed to it.
  479. type recordingBatchWriter struct {
  480. bufs [][]byte
  481. dsts []netip.AddrPort
  482. }
  483. func (w *recordingBatchWriter) WriteBatch(bufs [][]byte, addrs []netip.AddrPort) (int, error) {
  484. for i := range bufs {
  485. w.bufs = append(w.bufs, append([]byte(nil), bufs[i]...))
  486. w.dsts = append(w.dsts, addrs[i])
  487. }
  488. return len(bufs), nil
  489. }
  490. func TestSendInsideMessageLaneSwap(t *testing.T) {
  491. hostMap := newHostMap(test.NewLogger())
  492. ifce := newLaneTestInterface(hostMap)
  493. initR, respR := runTestHandshake(t)
  494. ls := newTestLaneSet(t, initR, 4, 4, 5353, 4)
  495. hi := newTestLaneHostInfo(t, initR, ls)
  496. peerLS := newTestLaneSet(t, respR, 4, 4, 4242, 4)
  497. baseWriter := &recordingBatchWriter{}
  498. laneWriter := &recordingBatchWriter{}
  499. newTx := func(laneSlot int) *txQueue {
  500. return &txQueue{
  501. laneSlot: laneSlot,
  502. base: batch.NewSendBatch(baseWriter, batch.SendBatchCap, 1<<16),
  503. lane: batch.NewSendBatch(laneWriter, batch.SendBatchCap, 1<<16),
  504. }
  505. }
  506. tx1 := newTx(1)
  507. tx2 := newTx(2)
  508. pkt := tio.Packet{Bytes: []byte{0x45, 0, 0, 4, 1, 2, 3, 4}}
  509. nb := make([]byte, 12)
  510. // A down lane rides the base tunnel and asks for a probe.
  511. ifce.sendInsideMessage(hi, pkt, nb, tx1)
  512. tx1.flush(ifce)
  513. require.Len(t, baseWriter.bufs, 1)
  514. assert.Empty(t, laneWriter.bufs)
  515. assert.True(t, ls.demand[1].Load(), "a miss did not raise demand")
  516. assert.False(t, ls.demand[2].Load(), "demand raised on an untouched lane")
  517. h := &header.H{}
  518. require.NoError(t, h.Parse(baseWriter.bufs[0]))
  519. assert.Equal(t, uint8(0), h.Lane())
  520. // Once the lane is up, slot-1 traffic rides the lane session, the lane
  521. // socket and the lane's destination, tagged with the lane index. Promotion
  522. // normally happens on the ack of a probe, which is also what derived the
  523. // session, so stand both up here.
  524. laneRemote := netip.MustParseAddrPort("192.0.2.1:5354")
  525. laneSessionFor(t, ls, 1)
  526. ls.txAddr[1].Store(&laneRemote)
  527. ls.demand[1].Store(false)
  528. ifce.sendInsideMessage(hi, pkt, nb, tx1)
  529. tx1.flush(ifce)
  530. require.Len(t, laneWriter.bufs, 1)
  531. assert.Equal(t, laneRemote, laneWriter.dsts[0])
  532. assert.False(t, ls.demand[1].Load(), "a hit raised demand")
  533. require.NoError(t, h.Parse(laneWriter.bufs[0]))
  534. assert.Equal(t, uint8(1), h.Lane())
  535. assert.Equal(t, hi.remoteIndexId, h.RemoteIndex)
  536. // And the peer's derived lane-1 session is what opens it.
  537. pt, err := laneSessionFor(t, peerLS, 1).Decrypt(test.NewLogger(), h.MessageCounter, laneWriter.bufs[0], nb)
  538. require.NoError(t, err)
  539. assert.Equal(t, pkt.Bytes, pt)
  540. // An overflow routine sharing slot 1 (multiport.lanes < routines) rides the
  541. // same lane session.
  542. tx1b := newTx(1)
  543. ifce.sendInsideMessage(hi, pkt, nb, tx1b)
  544. tx1b.flush(ifce)
  545. require.Len(t, laneWriter.bufs, 2)
  546. require.NoError(t, h.Parse(laneWriter.bufs[1]))
  547. assert.Equal(t, uint8(1), h.Lane())
  548. // Slot 2's lane is still down: base tunnel, base batch, lane 0.
  549. ifce.sendInsideMessage(hi, pkt, nb, tx2)
  550. tx2.flush(ifce)
  551. require.Len(t, baseWriter.bufs, 2)
  552. assert.Equal(t, hi.GetRemote(), baseWriter.dsts[1])
  553. require.NoError(t, h.Parse(baseWriter.bufs[1]))
  554. assert.Equal(t, uint8(0), h.Lane())
  555. // Demotion falls back to the base tunnel on the very next packet.
  556. ls.txAddr[1].Store(nil)
  557. ifce.sendInsideMessage(hi, pkt, nb, tx1)
  558. tx1.flush(ifce)
  559. require.Len(t, baseWriter.bufs, 3)
  560. require.Len(t, laneWriter.bufs, 2)
  561. }
  562. func TestLaneSlotFor(t *testing.T) {
  563. // Overflow routines wrap onto the configured lanes round-robin.
  564. f := &Interface{multiport: true, laneCount: 2}
  565. for i, want := range []int{0, 1, 0, 1, 0, 1} {
  566. assert.Equal(t, want, f.laneSlotFor(i), "routine %d", i)
  567. }
  568. // Full lane count: identity mapping, one lane per routine.
  569. f = &Interface{multiport: true, laneCount: 4}
  570. for i := range 4 {
  571. assert.Equal(t, i, f.laneSlotFor(i), "routine %d", i)
  572. }
  573. // Multiport off: identity, each routine keeps its own writer.
  574. f = &Interface{multiport: false, laneCount: 0}
  575. for i := range 4 {
  576. assert.Equal(t, i, f.laneSlotFor(i), "routine %d", i)
  577. }
  578. }
  579. // Regression: deleting a hostinfo whose pending entry is NOT the one recorded
  580. // in vpnIps must not evict a concurrently pending handshake for that address.
  581. func TestHandshakeManagerVpnIpsIdentityDelete(t *testing.T) {
  582. l := test.NewLogger()
  583. hostMap := newHostMap(l)
  584. lh := newTestLighthouse()
  585. hm := NewHandshakeManager(l, hostMap, lh, &udp.NoopConn{}, defaultHandshakeConfig)
  586. vpnIp := netip.MustParseAddr("172.1.1.4")
  587. pendingBase := hm.StartHandshake(vpnIp, nil)
  588. require.NotNil(t, pendingBase)
  589. other := &HostInfo{vpnAddrs: []netip.Addr{vpnIp}, localIndexId: 999}
  590. hm.DeleteHostInfo(other)
  591. // The pending base handshake must still be tracked.
  592. assert.Equal(t, pendingBase, hm.QueryVpnAddr(vpnIp))
  593. // And deleting the actual owner still works.
  594. hm.DeleteHostInfo(pendingBase)
  595. assert.Nil(t, hm.QueryVpnAddr(vpnIp))
  596. }