lanes_test.go 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035
  1. package nebula
  2. import (
  3. "log/slog"
  4. "net/netip"
  5. "testing"
  6. "time"
  7. "github.com/gaissmai/bart"
  8. "github.com/slackhq/nebula/cert"
  9. "github.com/slackhq/nebula/config"
  10. "github.com/slackhq/nebula/firewall"
  11. "github.com/slackhq/nebula/handshake"
  12. "github.com/slackhq/nebula/header"
  13. "github.com/slackhq/nebula/overlay/overlaytest"
  14. "github.com/slackhq/nebula/overlay/tio"
  15. "github.com/slackhq/nebula/test"
  16. "github.com/slackhq/nebula/udp"
  17. "github.com/stretchr/testify/assert"
  18. "github.com/stretchr/testify/require"
  19. )
  20. var (
  21. testMyAddr = netip.MustParseAddr("10.0.0.1")
  22. testPeerAddr = netip.MustParseAddr("10.0.0.2")
  23. )
  24. // newTestLaneSet builds a lane set from a real handshake result so the sessions
  25. // it derives hold usable keys.
  26. func newTestLaneSet(t *testing.T, r *handshake.Result, myLanes int, peerPorts, peerBase, peerTxLanes uint32) *laneSet {
  27. t.Helper()
  28. r.PeerPortCount = peerPorts
  29. r.PeerBasePort = peerBase
  30. r.PeerTxLanes = peerTxLanes
  31. return newLaneSet(r, myLanes, testMyAddr, testPeerAddr)
  32. }
  33. // laneSessionFor derives lane s's session and installs it, standing in for the
  34. // data-plane call that would normally be the first to need it.
  35. func laneSessionFor(t *testing.T, ls *laneSet, s int) *ConnectionState {
  36. t.Helper()
  37. cs, err := ls.session(s)
  38. require.NoError(t, err)
  39. require.NotNil(t, cs)
  40. return cs
  41. }
  42. func newTestLaneHostInfo(t *testing.T, r *handshake.Result, ls *laneSet) *HostInfo {
  43. t.Helper()
  44. cs, err := newConnectionStateFromResult(r)
  45. require.NoError(t, err)
  46. hi := &HostInfo{
  47. vpnAddrs: []netip.Addr{testPeerAddr},
  48. localIndexId: 100,
  49. remoteIndexId: 200,
  50. remotes: NewRemoteList([]netip.Addr{testPeerAddr}, nil),
  51. HandshakePacket: map[uint8][]byte{},
  52. ConnectionState: cs,
  53. lanes: ls,
  54. }
  55. hi.SetRemote(netip.MustParseAddrPort("192.0.2.1:4242"))
  56. return hi
  57. }
  58. func TestLanePortOffset(t *testing.T) {
  59. a := netip.MustParseAddr("10.0.0.1")
  60. b := netip.MustParseAddr("10.0.0.2")
  61. // Deterministic and in range.
  62. for _, count := range []uint16{1, 2, 3, 4, 16, 256} {
  63. o := lanePortOffset(a, b, count)
  64. assert.Equal(t, o, lanePortOffset(a, b, count), "count %d not deterministic", count)
  65. assert.Less(t, o, count, "count %d out of range", count)
  66. }
  67. assert.Equal(t, uint16(0), lanePortOffset(a, b, 0), "zero port count")
  68. // The two sides' rotations cancel when port counts match, preserving the
  69. // lane-i-reverses-lane-j conntrack pairing.
  70. for _, count := range []uint16{2, 3, 4, 7, 16} {
  71. for i := range 32 {
  72. peer := netip.AddrFrom4([4]byte{192, 0, 2, byte(i)})
  73. oA := lanePortOffset(a, peer, count)
  74. oB := lanePortOffset(peer, a, count)
  75. assert.Equal(t, uint16(0), (oA+oB)%count,
  76. "offsets don't cancel for peer %s count %d", peer, count)
  77. }
  78. }
  79. // Distinct small peers land on distinct rotations of a big peer's range,
  80. // not all on the same first ports.
  81. const bigPeerPorts = 16
  82. distinct := map[uint16]struct{}{}
  83. for i := range 64 {
  84. client := netip.AddrFrom4([4]byte{192, 0, 2, byte(i)})
  85. distinct[lanePortOffset(client, a, bigPeerPorts)] = struct{}{}
  86. }
  87. assert.GreaterOrEqual(t, len(distinct), 8, "64 clients only produced %d distinct offsets", len(distinct))
  88. }
  89. func TestLaneTargetPort(t *testing.T) {
  90. ls := &laneSet{peerBasePort: 4242, peerPortCount: 4}
  91. // No rotation: lane i targets base+i, wrapping past the peer's range.
  92. for i, want := range map[int]uint16{1: 4243, 2: 4244, 3: 4245, 5: 4243} {
  93. assert.Equal(t, want, ls.laneTargetPortLocked(i), "lane %d", i)
  94. }
  95. // Rotation shifts the whole mapping; the wrapped lane lands on the base
  96. // port itself, which is a valid distinct 4-tuple (our source port differs).
  97. ls.portOffset = 3
  98. for i, want := range map[int]uint16{1: 4242, 2: 4243, 3: 4244} {
  99. assert.Equal(t, want, ls.laneTargetPortLocked(i), "rotated lane %d", i)
  100. }
  101. // Fewer peer ports than local lanes: rotation still spreads across all of
  102. // the peer's ports.
  103. ls = &laneSet{peerBasePort: 4242, peerPortCount: 2, portOffset: 1}
  104. assert.Equal(t, uint16(4242), ls.laneTargetPortLocked(1))
  105. assert.Equal(t, uint16(4243), ls.laneTargetPortLocked(2))
  106. }
  107. // A lane's keys are derived, not negotiated, so the whole design rests on the
  108. // two sides landing on the same pair without exchanging anything.
  109. func TestLaneKeyDerivationSymmetry(t *testing.T) {
  110. initR, respR := runTestHandshake(t)
  111. initLS := newTestLaneSet(t, initR, 4, 4, 4242, 4)
  112. respLS := newTestLaneSet(t, respR, 4, 4, 4242, 4)
  113. require.Len(t, initLS.sessions, 4)
  114. assert.Nil(t, initLS.sessions[0].Load(), "lane 0 is the base session, not a derived one")
  115. nb := make([]byte, 12)
  116. for s := 1; s < 4; s++ {
  117. out := header.EncodeLane(make([]byte, 0, mtu), header.Version, header.Message, 0, 200, 1, uint8(s))
  118. ct, err := laneSessionFor(t, initLS, s).eKey.EncryptDanger(out, out, []byte("lane payload"), 1, nb)
  119. require.NoError(t, err)
  120. pt, err := laneSessionFor(t, respLS, s).Decrypt(test.NewLogger(), 1, ct, nb)
  121. require.NoError(t, err, "lane %d keys did not match", s)
  122. assert.Equal(t, []byte("lane payload"), pt)
  123. }
  124. // Distinct lanes get distinct keys: lane 2's session must not open lane 1's
  125. // ciphertext, or the header's lane index would be forgeable in effect.
  126. out := header.EncodeLane(make([]byte, 0, mtu), header.Version, header.Message, 0, 200, 7, 1)
  127. ct, err := laneSessionFor(t, initLS, 1).eKey.EncryptDanger(out, out, []byte("lane payload"), 7, nb)
  128. require.NoError(t, err)
  129. _, err = laneSessionFor(t, respLS, 2).Decrypt(test.NewLogger(), 7, ct, nb)
  130. assert.Error(t, err)
  131. }
  132. func TestNewLaneSetSizing(t *testing.T) {
  133. initR, _ := runTestHandshake(t)
  134. // A peer with no multiport advert gets no lanes at all.
  135. assert.Nil(t, newLaneSet(&handshake.Result{}, 4, testMyAddr, testPeerAddr))
  136. // One lane means only the base tunnel, which is not a lane set.
  137. assert.Nil(t, newLaneSet(&handshake.Result{PeerPortCount: 4, PeerTxLanes: 1}, 1, testMyAddr, testPeerAddr))
  138. // Sessions cover both directions: enough for everything the peer may send,
  139. // even though we may only send on a few.
  140. ls := newTestLaneSet(t, initR, 2, 8, 4242, 6)
  141. assert.Len(t, ls.sessions, 6, "sessions must cover the peer's tx lanes")
  142. assert.Equal(t, 2, ls.txLanes, "we may only send on our own lanes")
  143. // The peer's advert sizes the session table but nothing else. Its lane count
  144. // is its own choice, so it must not be able to make us allocate per-lane tx
  145. // state we will never use.
  146. assert.Len(t, ls.txAddr, 2)
  147. assert.Len(t, ls.demand, 2)
  148. assert.Len(t, ls.probe, 2)
  149. // Nothing is derived up front, for the same reason.
  150. for s := range ls.sessions {
  151. assert.Nil(t, ls.sessions[s].Load(), "lane %d derived before anything needed it", s)
  152. }
  153. // Every lane starts demanded so the first traffic tick probes them all: a
  154. // lane that only comes up after its flows do is a lane the flows never move
  155. // onto, because the kernel has pinned them to the queue they started on.
  156. ls = newTestLaneSet(t, initR, 4, 4, 4242, 4)
  157. for s := 1; s < ls.txLanes; s++ {
  158. assert.True(t, ls.demand[s].Load(), "lane %d not demanded at creation", s)
  159. }
  160. // Our tx lanes are clamped to the ports the peer actually bound: a lane
  161. // aimed past the peer's range would land on some unrelated socket.
  162. ls = newTestLaneSet(t, initR, 8, 3, 4242, 8)
  163. assert.Equal(t, 3, ls.txLanes)
  164. assert.Len(t, ls.sessions, 8)
  165. }
  166. // The handshake log lines carry the negotiated lanes, so an operator can tell a
  167. // peer that got none from one that was never asked.
  168. func TestLaneLogAttr(t *testing.T) {
  169. initR, _ := runTestHandshake(t)
  170. // Not running multiport: an empty attr, which slog drops entirely.
  171. assert.Equal(t, slog.Attr{}, laneLogAttr(0, nil))
  172. // Running multiport against a peer that isn't: zeros, not silence.
  173. assert.Equal(t, m{"tx": 0, "sessions": 0}, laneLogAttr(4, nil).Value.Any())
  174. ls := newTestLaneSet(t, initR, 2, 8, 4242, 6)
  175. attr := laneLogAttr(2, ls)
  176. assert.Equal(t, "lanes", attr.Key)
  177. assert.Equal(t, m{
  178. "tx": 2,
  179. "sessions": 6,
  180. "peerBasePort": uint16(4242),
  181. "peerPorts": uint16(8),
  182. "portOffset": ls.portOffset,
  183. }, attr.Value.Any())
  184. }
  185. // The RX path must not cache a session for a lane until a packet on it has
  186. // actually decrypted, or a spoofer naming lanes at random could make us hold a
  187. // replay window and two cipher states per lane without authenticating anything.
  188. func TestLaneSessionRxDerivation(t *testing.T) {
  189. initR, respR := runTestHandshake(t)
  190. respLS := newTestLaneSet(t, respR, 4, 4, 4242, 4)
  191. hi := newTestLaneHostInfo(t, respR, respLS)
  192. ci, cached, err := hi.laneSession(2)
  193. require.NoError(t, err)
  194. require.NotNil(t, ci)
  195. assert.False(t, cached, "the first packet on a lane derives, it does not hit")
  196. assert.Nil(t, respLS.sessions[2].Load(), "an unauthenticated packet must not install a session")
  197. // The lane the peer really is using decrypts, and that is what installs it.
  198. nb := make([]byte, 12)
  199. out := header.EncodeLane(make([]byte, 0, mtu), header.Version, header.Message, 0, 200, 1, 2)
  200. ct, err := laneSessionFor(t, newTestLaneSet(t, initR, 4, 4, 4242, 4), 2).
  201. eKey.EncryptDanger(out, out, []byte("real lane traffic"), 1, nb)
  202. require.NoError(t, err)
  203. pt, err := ci.Decrypt(test.NewLogger(), 1, ct, nb)
  204. require.NoError(t, err)
  205. assert.Equal(t, []byte("real lane traffic"), pt)
  206. respLS.installSession(test.NewLogger(), 2, ci, 1)
  207. assert.Same(t, ci, respLS.sessions[2].Load())
  208. // Now it is a hit, and the replay window the decrypt above advanced is the
  209. // one the next packet sees.
  210. got, cached, err := hi.laneSession(2)
  211. require.NoError(t, err)
  212. assert.True(t, cached)
  213. assert.Same(t, ci, got)
  214. // A racing install loses rather than swapping the session out, which would
  215. // throw away the replay window the live one has been accumulating. The loser's
  216. // packet still has to be marked seen on the winner, or dropping its session
  217. // would make that one counter replayable.
  218. other, err := newLaneConnectionState(&respLS.material, 2)
  219. require.NoError(t, err)
  220. require.True(t, ci.window.Check(test.NewLogger(), 7), "counter 7 seen before the race")
  221. respLS.installSession(test.NewLogger(), 2, other, 7)
  222. assert.Same(t, ci, respLS.sessions[2].Load())
  223. assert.False(t, ci.window.Check(test.NewLogger(), 7),
  224. "the loser's counter was not carried to the surviving window")
  225. }
  226. func TestLaneTxGate(t *testing.T) {
  227. initR, _ := runTestHandshake(t)
  228. ls := newTestLaneSet(t, initR, 4, 4, 4242, 4)
  229. for s := range ls.demand {
  230. // Creation seeds demand on every lane; start from cold so this test can
  231. // tell what the TX path itself raises.
  232. ls.demand[s].Store(false)
  233. }
  234. // A down lane hands back nothing and raises demand, which is what gets it
  235. // re-probed after a demotion.
  236. ci, addr := ls.txLane(1)
  237. assert.Nil(t, ci)
  238. assert.False(t, addr.IsValid())
  239. assert.True(t, ls.demand[1].Load())
  240. assert.False(t, ls.demand[2].Load(), "demand raised on an untouched lane")
  241. // An up lane with no session derived yet cannot happen — the probe that
  242. // promoted it derived one — but it must fall back rather than send in the
  243. // clear if it ever does.
  244. want := netip.MustParseAddrPort("192.0.2.1:4243")
  245. ls.txAddr[1].Store(&want)
  246. ci, _ = ls.txLane(1)
  247. assert.Nil(t, ci)
  248. // Promotion publishes the session and destination together.
  249. sess := laneSessionFor(t, ls, 1)
  250. ls.demand[1].Store(false)
  251. ci, addr = ls.txLane(1)
  252. assert.Same(t, sess, ci)
  253. assert.Equal(t, want, addr)
  254. assert.False(t, ls.demand[1].Load(), "a hit must not raise demand")
  255. // Lane 0 is the base tunnel and lanes at or above txLanes are receive-only.
  256. ci, _ = ls.txLane(0)
  257. assert.Nil(t, ci)
  258. ci, _ = ls.txLane(4)
  259. assert.Nil(t, ci)
  260. }
  261. func TestLaneSessionLookup(t *testing.T) {
  262. initR, _ := runTestHandshake(t)
  263. ls := newTestLaneSet(t, initR, 3, 4, 4242, 3)
  264. hi := newTestLaneHostInfo(t, initR, ls)
  265. assertNoLane := func(s uint8, msg string) {
  266. t.Helper()
  267. ci, cached, err := hi.laneSession(s)
  268. require.NoError(t, err)
  269. assert.Nil(t, ci, msg)
  270. assert.False(t, cached, msg)
  271. }
  272. assertNoLane(0, "lane 0 is the base session")
  273. assertNoLane(3, "a lane beyond what this tunnel covers")
  274. assertNoLane(255, "a lane beyond what this tunnel covers")
  275. // An already-derived lane is returned as a hit.
  276. sess := laneSessionFor(t, ls, 2)
  277. ci, cached, err := hi.laneSession(2)
  278. require.NoError(t, err)
  279. assert.Same(t, sess, ci)
  280. assert.True(t, cached)
  281. // A peer without lanes answers nil for every lane rather than panicking.
  282. bare := &HostInfo{}
  283. ci, _, err = bare.laneSession(1)
  284. require.NoError(t, err)
  285. assert.Nil(t, ci)
  286. }
  287. func TestMaxMessageCounter(t *testing.T) {
  288. initR, _ := runTestHandshake(t)
  289. ls := newTestLaneSet(t, initR, 3, 4, 4242, 3)
  290. hi := newTestLaneHostInfo(t, initR, ls)
  291. hi.ConnectionState.messageCounter.Store(5)
  292. assert.Equal(t, uint64(5), hi.maxMessageCounter())
  293. // A lane past the base is what the rehandshake threshold has to notice: the
  294. // base counter would sit still while the lane burns through its nonces.
  295. laneSessionFor(t, ls, 2).messageCounter.Store(9000)
  296. assert.Equal(t, uint64(9000), hi.maxMessageCounter())
  297. assert.Equal(t, uint64(0), (&HostInfo{}).maxMessageCounter())
  298. }
  299. func TestLaneRetryDelay(t *testing.T) {
  300. assert.Equal(t, laneRetryBase, laneRetryDelay(0))
  301. assert.Equal(t, 2*laneRetryBase, laneRetryDelay(1))
  302. assert.Equal(t, laneRetryMax, laneRetryDelay(laneMaxFails), "backoff must saturate")
  303. }
  304. func newLaneTestInterface(hostMap *HostMap) *Interface {
  305. l := test.NewLogger()
  306. lh := newTestLighthouse()
  307. cs := &CertState{
  308. initiatingVersion: cert.Version1,
  309. privateKey: []byte{},
  310. v1Cert: &dummyCert{version: cert.Version1},
  311. v1Credential: nil,
  312. }
  313. ifce := &Interface{
  314. hostMap: hostMap,
  315. inside: &overlaytest.NoopTun{},
  316. outside: &udp.NoopConn{},
  317. firewall: &Firewall{},
  318. lightHouse: lh,
  319. pki: &PKI{},
  320. handshakeManager: NewHandshakeManager(l, hostMap, lh, &udp.NoopConn{}, defaultHandshakeConfig),
  321. myVpnNetworksTable: new(bart.Lite),
  322. messageMetrics: newMessageMetricsOnlyRecvError(),
  323. writers: []udp.Conn{&udp.NoopConn{}, &udp.NoopConn{}, &udp.NoopConn{}, &udp.NoopConn{}},
  324. // One socket per port keeps writers indexed by lane, which is what most of
  325. // these tests want; the tests that care about the group layout set their own.
  326. routinesPerPort: 1,
  327. l: l,
  328. }
  329. ifce.pki.cs.Store(cs)
  330. conf := config.NewC(l)
  331. punchy := NewPunchyFromConfig(l, conf, nil)
  332. cm := newConnectionManagerFromConfig(l, conf, hostMap, punchy)
  333. cm.intf = ifce
  334. ifce.connectionManager = cm
  335. ifce.handshakeManager.f = ifce
  336. return ifce
  337. }
  338. // The full TX lifecycle of a lane: demand -> probe -> ack -> up, then an
  339. // unanswered keepalive -> demoted.
  340. func TestLaneProbeLifecycle(t *testing.T) {
  341. hostMap := newHostMap(test.NewLogger())
  342. ifce := newLaneTestInterface(hostMap)
  343. initR, _ := runTestHandshake(t)
  344. ls := newTestLaneSet(t, initR, 4, 4, 5353, 4)
  345. hi := newTestLaneHostInfo(t, initR, ls)
  346. nb := make([]byte, 12)
  347. out := make([]byte, mtu)
  348. now := time.Now()
  349. // No demand: nothing is probed, so a peer we barely talk to costs nothing
  350. // beyond its base tunnel. (Creation seeds demand on every lane, so clear it
  351. // to get at the no-demand case.)
  352. for s := range ls.demand {
  353. ls.demand[s].Store(false)
  354. }
  355. ifce.probeLanes(hi, now, nb, out)
  356. ls.mu.Lock()
  357. for s := 1; s < 4; s++ {
  358. assert.True(t, ls.probe[s].sentAt.IsZero(), "lane %d probed without demand", s)
  359. }
  360. ls.mu.Unlock()
  361. // Demand on lane 1 alone probes lane 1 alone, aimed at the peer's port for
  362. // that lane.
  363. ls.demand[1].Store(true)
  364. ifce.probeLanes(hi, now, nb, out)
  365. ls.mu.Lock()
  366. require.False(t, ls.probe[1].sentAt.IsZero(), "demand did not produce a probe")
  367. assert.True(t, ls.probe[2].sentAt.IsZero())
  368. wantPort := ls.laneTargetPortLocked(1)
  369. assert.Equal(t, netip.AddrPortFrom(netip.MustParseAddr("192.0.2.1"), wantPort), ls.probe[1].target)
  370. gen := ls.probe[1].gen
  371. assert.False(t, ls.demand[1].Load(), "the probe did not consume the demand")
  372. ls.mu.Unlock()
  373. // The lane stays down until the ack lands, and a stale generation cannot
  374. // bring it up.
  375. assert.Nil(t, ls.txAddr[1].Load())
  376. _, promoted := ls.noteAck(1, gen+1, now)
  377. assert.False(t, promoted, "an ack for a superseded probe promoted the lane")
  378. assert.Nil(t, ls.txAddr[1].Load())
  379. // The matching ack promotes it, and the destination is the probed target.
  380. ackTarget, promoted := ls.noteAck(1, gen, now)
  381. assert.True(t, promoted)
  382. assert.Equal(t, netip.AddrPortFrom(netip.MustParseAddr("192.0.2.1"), wantPort), ackTarget)
  383. addr := ls.txAddr[1].Load()
  384. require.NotNil(t, addr)
  385. assert.Equal(t, netip.AddrPortFrom(netip.MustParseAddr("192.0.2.1"), wantPort), *addr)
  386. // A second ack is a keepalive, not a promotion.
  387. ls.mu.Lock()
  388. ls.probe[1].sentAt = now
  389. ls.mu.Unlock()
  390. _, promoted = ls.noteAck(1, gen, now)
  391. assert.False(t, promoted)
  392. assert.NotNil(t, ls.txAddr[1].Load())
  393. // An up lane is left alone until the keepalive comes due.
  394. ifce.probeLanes(hi, now, nb, out)
  395. ls.mu.Lock()
  396. assert.True(t, ls.probe[1].sentAt.IsZero(), "an up lane was re-probed early")
  397. ls.mu.Unlock()
  398. // Past the keepalive it re-proves its path...
  399. now = now.Add(laneKeepalive + time.Second)
  400. ifce.probeLanes(hi, now, nb, out)
  401. ls.mu.Lock()
  402. require.False(t, ls.probe[1].sentAt.IsZero(), "keepalive did not probe")
  403. ls.mu.Unlock()
  404. assert.NotNil(t, ls.txAddr[1].Load(), "lane demoted before its probe aged out")
  405. // ...and an unanswered keepalive demotes it with backoff, so the routine
  406. // falls back to the base tunnel.
  407. now = now.Add(laneProbeTimeout + time.Second)
  408. ifce.probeLanes(hi, now, nb, out)
  409. assert.Nil(t, ls.txAddr[1].Load(), "unanswered keepalive did not demote the lane")
  410. ls.mu.Lock()
  411. assert.Equal(t, uint8(1), ls.probe[1].fails)
  412. assert.True(t, ls.probe[1].retryAt.After(now))
  413. ls.mu.Unlock()
  414. // The backoff holds even with fresh demand.
  415. ls.demand[1].Store(true)
  416. ifce.probeLanes(hi, now, nb, out)
  417. ls.mu.Lock()
  418. assert.True(t, ls.probe[1].sentAt.IsZero(), "backoff was ignored")
  419. ls.mu.Unlock()
  420. }
  421. // A lane aims at its own peer port and nothing else. There is no fallback to the
  422. // peer's base port: sharing that destination would cost the peer the receive
  423. // spread lanes exist to create, so an unreachable lane port just means this lane
  424. // stays down and its flows ride the base tunnel.
  425. func TestLaneProbeAlwaysTargetsItsOwnPort(t *testing.T) {
  426. hostMap := newHostMap(test.NewLogger())
  427. ifce := newLaneTestInterface(hostMap)
  428. initR, _ := runTestHandshake(t)
  429. ls := newTestLaneSet(t, initR, 4, 4, 5353, 4)
  430. hi := newTestLaneHostInfo(t, initR, ls)
  431. nb := make([]byte, 12)
  432. out := make([]byte, mtu)
  433. now := time.Now()
  434. ls.mu.Lock()
  435. lanePort := ls.laneTargetPortLocked(1)
  436. ls.mu.Unlock()
  437. require.NotEqual(t, ls.peerBasePort, lanePort, "this test needs a lane that isn't aimed at the base port")
  438. // Repeated failures never move the target off the lane's own port.
  439. for i := 0; i < 4; i++ {
  440. ls.demand[1].Store(true)
  441. ifce.probeLanes(hi, now, nb, out)
  442. ls.mu.Lock()
  443. require.False(t, ls.probe[1].sentAt.IsZero(), "the lane was not probed")
  444. assert.Equal(t, lanePort, ls.probe[1].target.Port(), "probe %d left the lane port", i)
  445. gen := ls.probe[1].gen
  446. ls.mu.Unlock()
  447. // Age the probe out, then wait out the backoff for the next attempt.
  448. now = now.Add(laneProbeTimeout + time.Second)
  449. ifce.probeLanes(hi, now, nb, out)
  450. require.Nil(t, ls.txAddr[1].Load())
  451. assert.False(t, promotedByAck(ls, 1, gen, now), "an aged-out probe was still promotable")
  452. now = now.Add(laneRetryMax + time.Second)
  453. }
  454. // It comes up on that port, and the keepalive re-proves the same one.
  455. ls.demand[1].Store(true)
  456. ifce.probeLanes(hi, now, nb, out)
  457. ls.mu.Lock()
  458. gen := ls.probe[1].gen
  459. ls.mu.Unlock()
  460. target, promoted := ls.noteAck(1, gen, now)
  461. require.True(t, promoted)
  462. assert.Equal(t, lanePort, target.Port())
  463. now = now.Add(laneKeepalive + time.Second)
  464. ifce.probeLanes(hi, now, nb, out)
  465. ls.mu.Lock()
  466. require.False(t, ls.probe[1].sentAt.IsZero(), "the keepalive did not probe")
  467. assert.Equal(t, lanePort, ls.probe[1].target.Port(), "the keepalive left the lane port")
  468. ls.mu.Unlock()
  469. // And a demotion returns to probing that same port.
  470. now = now.Add(laneProbeTimeout + time.Second)
  471. ifce.probeLanes(hi, now, nb, out)
  472. require.Nil(t, ls.txAddr[1].Load(), "the unanswered keepalive did not demote the lane")
  473. now = now.Add(laneRetryMax + time.Second)
  474. ls.demand[1].Store(true)
  475. ifce.probeLanes(hi, now, nb, out)
  476. ls.mu.Lock()
  477. require.False(t, ls.probe[1].sentAt.IsZero(), "the lane was not retried")
  478. assert.Equal(t, lanePort, ls.probe[1].target.Port())
  479. ls.mu.Unlock()
  480. }
  481. // promotedByAck is noteAck's boolean alone, for assertions that only care whether
  482. // an ack could bring the lane up.
  483. func promotedByAck(ls *laneSet, s int, gen uint8, now time.Time) bool {
  484. _, promoted := ls.noteAck(s, gen, now)
  485. return promoted
  486. }
  487. // A roam is a new path with no derivable relationship to the old lane ports, so
  488. // every lane has to be rebuilt rather than moved.
  489. func TestLaneProbeRoamResets(t *testing.T) {
  490. hostMap := newHostMap(test.NewLogger())
  491. ifce := newLaneTestInterface(hostMap)
  492. initR, _ := runTestHandshake(t)
  493. ls := newTestLaneSet(t, initR, 4, 4, 5353, 4)
  494. hi := newTestLaneHostInfo(t, initR, ls)
  495. now := time.Now()
  496. nb := make([]byte, 12)
  497. out := make([]byte, mtu)
  498. ls.demand[1].Store(true)
  499. ifce.probeLanes(hi, now, nb, out)
  500. ls.mu.Lock()
  501. gen := ls.probe[1].gen
  502. ls.mu.Unlock()
  503. _, promoted := ls.noteAck(1, gen, now)
  504. require.True(t, promoted)
  505. require.NotNil(t, ls.txAddr[1].Load())
  506. // New remote address: the lane is taken down, not retargeted.
  507. hi.SetRemote(netip.MustParseAddrPort("198.51.100.7:4242"))
  508. ifce.probeLanes(hi, now, nb, out)
  509. assert.Nil(t, ls.txAddr[1].Load(), "lane survived a roam")
  510. ls.mu.Lock()
  511. assert.Zero(t, ls.probe[1].fails, "a roam is not a lane failure")
  512. assert.Equal(t, netip.MustParseAddr("198.51.100.7"), ls.peerAddr)
  513. ls.mu.Unlock()
  514. // Relayed (no direct remote) means no lanes at all.
  515. ls.demand[1].Store(true)
  516. ifce.probeLanes(hi, now, nb, out)
  517. ls.mu.Lock()
  518. gen = ls.probe[1].gen
  519. ls.mu.Unlock()
  520. _, promoted = ls.noteAck(1, gen, now)
  521. require.True(t, promoted)
  522. hi.SetRemote(netip.AddrPort{})
  523. ifce.probeLanes(hi, now, nb, out)
  524. assert.Nil(t, ls.txAddr[1].Load(), "lane survived losing the direct path")
  525. }
  526. // A lane probe is answered on the base tunnel, echoing the header's lane, so a
  527. // peer cannot get us to vouch for a lane it never probed.
  528. func TestHandleLaneProbe(t *testing.T) {
  529. hostMap := newHostMap(test.NewLogger())
  530. ifce := newLaneTestInterface(hostMap)
  531. initR, respR := runTestHandshake(t)
  532. ls := newTestLaneSet(t, respR, 4, 4, 4242, 4)
  533. hi := newTestLaneHostInfo(t, respR, ls)
  534. rxc := &rxContext{nb: make([]byte, 12), scratch: make([]byte, mtu)}
  535. sent := &recordingUdpConn{}
  536. ifce.writers = []udp.Conn{sent, &udp.NoopConn{}, &udp.NoopConn{}, &udp.NoopConn{}}
  537. // The payload's lane is ignored in favour of the header's.
  538. ifce.handleLaneProbe(hi, 2, []byte{3, 42}, rxc)
  539. require.Len(t, sent.bufs, 1, "the ack must ride the base tunnel's socket")
  540. h := &header.H{}
  541. require.NoError(t, h.Parse(sent.bufs[0]))
  542. assert.Equal(t, header.Test, h.Type)
  543. assert.Equal(t, header.LaneProbeAck, h.Subtype)
  544. assert.Equal(t, uint8(0), h.Lane(), "the ack is base-tunnel traffic")
  545. pt, err := laneSessionFor(t, newTestLaneSet(t, initR, 4, 4, 4242, 4), 1).dKey.DecryptDanger(
  546. nil, sent.bufs[0][:header.Len], sent.bufs[0][header.Len:], h.MessageCounter, make([]byte, 12))
  547. _ = pt
  548. assert.Error(t, err, "the ack must not be readable with a lane key")
  549. // A probe claiming lane 0 or with a truncated payload is answered with
  550. // nothing at all.
  551. sent.bufs = nil
  552. ifce.handleLaneProbe(hi, 0, []byte{1, 2}, rxc)
  553. ifce.handleLaneProbe(hi, 1, []byte{1}, rxc)
  554. assert.Empty(t, sent.bufs)
  555. }
  556. func TestHandleLaneProbeAck(t *testing.T) {
  557. hostMap := newHostMap(test.NewLogger())
  558. ifce := newLaneTestInterface(hostMap)
  559. initR, _ := runTestHandshake(t)
  560. ls := newTestLaneSet(t, initR, 4, 4, 5353, 4)
  561. hi := newTestLaneHostInfo(t, initR, ls)
  562. now := time.Now()
  563. ls.demand[1].Store(true)
  564. ifce.probeLanes(hi, now, make([]byte, 12), make([]byte, mtu))
  565. ls.mu.Lock()
  566. gen := ls.probe[1].gen
  567. ls.mu.Unlock()
  568. // A short or out-of-range ack is ignored, and a peer without lanes does not
  569. // panic the handler.
  570. ifce.handleLaneProbeAck(hi, []byte{1})
  571. ifce.handleLaneProbeAck(hi, []byte{99, gen})
  572. ifce.handleLaneProbeAck(&HostInfo{}, []byte{1, gen})
  573. assert.Nil(t, ls.txAddr[1].Load())
  574. ifce.handleLaneProbeAck(hi, []byte{1, gen})
  575. assert.NotNil(t, ls.txAddr[1].Load())
  576. }
  577. // recordingUdpConn records what was written to it, one datagram per write.
  578. type recordingUdpConn struct {
  579. udp.NoopConn
  580. bufs [][]byte
  581. dsts []netip.AddrPort
  582. }
  583. func (c *recordingUdpConn) WriteTo(b []byte, addr netip.AddrPort) error {
  584. c.bufs = append(c.bufs, append([]byte(nil), b...))
  585. c.dsts = append(c.dsts, addr)
  586. return nil
  587. }
  588. // recordingBatchConn is a udp.Conn that records the batches flushed to it, so a
  589. // test can see which socket a packet left on.
  590. type recordingBatchConn struct {
  591. udp.NoopConn
  592. bufs [][]byte
  593. dsts []netip.AddrPort
  594. }
  595. func (c *recordingBatchConn) WriteBatch(bufs [][]byte, addrs []netip.AddrPort) (int, error) {
  596. for i := range bufs {
  597. c.bufs = append(c.bufs, append([]byte(nil), bufs[i]...))
  598. c.dsts = append(c.dsts, addrs[i])
  599. }
  600. return len(bufs), nil
  601. }
  602. // laneOfFlow is what the TX path computes to pick a lane, without needing a
  603. // promoted lane to observe it.
  604. func laneOfFlow(ls *laneSet, p *firewall.Packet) int {
  605. return int((laneFlowHash(p) + uint32(ls.laneBias)) % uint32(ls.txLanes))
  606. }
  607. func testFlow(port uint16) *firewall.Packet {
  608. return &firewall.Packet{
  609. LocalAddr: testMyAddr,
  610. RemoteAddr: testPeerAddr,
  611. LocalPort: port,
  612. RemotePort: 443,
  613. Protocol: 6,
  614. }
  615. }
  616. // flowForLane finds a flow that hashes onto lane s, so a test can aim traffic at
  617. // a specific lane.
  618. func flowForLane(t *testing.T, ls *laneSet, s int) *firewall.Packet {
  619. t.Helper()
  620. for port := uint16(1024); port < 4096; port++ {
  621. p := testFlow(port)
  622. if laneOfFlow(ls, p) == s {
  623. return p
  624. }
  625. }
  626. t.Fatalf("no flow hashes onto lane %d", s)
  627. return nil
  628. }
  629. func TestSendInsideMessageLaneSwap(t *testing.T) {
  630. hostMap := newHostMap(test.NewLogger())
  631. ifce := newLaneTestInterface(hostMap)
  632. ifce.multiport = true
  633. ifce.laneCount = 4
  634. conns := []*recordingBatchConn{{}, {}, {}, {}}
  635. ifce.writers = []udp.Conn{conns[0], conns[1], conns[2], conns[3]}
  636. initR, respR := runTestHandshake(t)
  637. ls := newTestLaneSet(t, initR, 4, 4, 5353, 4)
  638. hi := newTestLaneHostInfo(t, initR, ls)
  639. peerLS := newTestLaneSet(t, respR, 4, 4, 4242, 4)
  640. tx := ifce.newTxQueue(1)
  641. pkt := tio.Packet{Bytes: []byte{0x45, 0, 0, 4, 1, 2, 3, 4}}
  642. nb := make([]byte, 12)
  643. flow1 := flowForLane(t, ls, 1)
  644. for s := range ls.demand {
  645. ls.demand[s].Store(false)
  646. }
  647. // A down lane rides the base tunnel and asks for a probe.
  648. ifce.sendInsideMessage(hi, pkt, flow1, nb, tx)
  649. tx.flush(ifce)
  650. require.Len(t, conns[0].bufs, 1)
  651. assert.Empty(t, conns[1].bufs)
  652. assert.True(t, ls.demand[1].Load(), "a miss did not raise demand")
  653. assert.False(t, ls.demand[2].Load(), "demand raised on a lane nothing hashed onto")
  654. h := &header.H{}
  655. require.NoError(t, h.Parse(conns[0].bufs[0]))
  656. assert.Equal(t, uint8(0), h.Lane())
  657. // Once the lane is up, a flow hashing onto it rides the lane session, the
  658. // lane socket and the lane's destination, tagged with the lane index.
  659. // Promotion normally happens on the ack of a probe, which is also what
  660. // derived the session, so stand both up here.
  661. laneRemote := netip.MustParseAddrPort("192.0.2.1:5354")
  662. laneSessionFor(t, ls, 1)
  663. ls.txAddr[1].Store(&laneRemote)
  664. ls.demand[1].Store(false)
  665. ifce.sendInsideMessage(hi, pkt, flow1, nb, tx)
  666. tx.flush(ifce)
  667. require.Len(t, conns[1].bufs, 1)
  668. assert.Equal(t, laneRemote, conns[1].dsts[0])
  669. assert.False(t, ls.demand[1].Load(), "a hit raised demand")
  670. require.NoError(t, h.Parse(conns[1].bufs[0]))
  671. assert.Equal(t, uint8(1), h.Lane())
  672. assert.Equal(t, hi.remoteIndexId, h.RemoteIndex)
  673. // And the peer's derived lane-1 session is what opens it.
  674. pt, err := laneSessionFor(t, peerLS, 1).Decrypt(test.NewLogger(), h.MessageCounter, conns[1].bufs[0], nb)
  675. require.NoError(t, err)
  676. assert.Equal(t, pkt.Bytes, pt)
  677. // Another routine sending the same flow rides the same lane socket and
  678. // session: the lane follows the flow, not the routine.
  679. tx2 := ifce.newTxQueue(2)
  680. ifce.sendInsideMessage(hi, pkt, flow1, nb, tx2)
  681. tx2.flush(ifce)
  682. require.Len(t, conns[1].bufs, 2)
  683. require.NoError(t, h.Parse(conns[1].bufs[1]))
  684. assert.Equal(t, uint8(1), h.Lane())
  685. // A flow that hashes onto lane 0 stays on the base tunnel even with lane 1
  686. // up: a full share of flows belongs there.
  687. ifce.sendInsideMessage(hi, pkt, flowForLane(t, ls, 0), nb, tx)
  688. tx.flush(ifce)
  689. require.Len(t, conns[0].bufs, 2)
  690. assert.Equal(t, hi.GetRemote(), conns[0].dsts[1])
  691. require.NoError(t, h.Parse(conns[0].bufs[1]))
  692. assert.Equal(t, uint8(0), h.Lane())
  693. // Demotion falls back to the base tunnel on the very next packet.
  694. ls.txAddr[1].Store(nil)
  695. ifce.sendInsideMessage(hi, pkt, flow1, nb, tx)
  696. tx.flush(ifce)
  697. require.Len(t, conns[0].bufs, 3)
  698. require.Len(t, conns[1].bufs, 2)
  699. }
  700. // Without multiport nothing about the send path changes: every socket shares one
  701. // port under SO_REUSEPORT, so a routine keeps writing to its own, and there are
  702. // no lane batches at all. A peer that negotiated no lanes is the same story on a
  703. // node that does run multiport, except that base traffic owes its 4-tuple to
  704. // socket 0.
  705. func TestTxQueueWithoutLanes(t *testing.T) {
  706. hostMap := newHostMap(test.NewLogger())
  707. ifce := newLaneTestInterface(hostMap)
  708. conns := []*recordingBatchConn{{}, {}, {}, {}}
  709. ifce.writers = []udp.Conn{conns[0], conns[1], conns[2], conns[3]}
  710. initR, _ := runTestHandshake(t)
  711. hi := newTestLaneHostInfo(t, initR, nil)
  712. pkt := tio.Packet{Bytes: []byte{0x45, 0, 0, 4, 1, 2, 3, 4}}
  713. nb := make([]byte, 12)
  714. flow := testFlow(1234)
  715. tx := ifce.newTxQueue(2)
  716. assert.Empty(t, tx.lane, "a queue with no lanes must not hold lane batches")
  717. require.Len(t, tx.live, 1)
  718. ifce.sendInsideMessage(hi, pkt, flow, nb, tx)
  719. tx.flush(ifce)
  720. assert.Len(t, conns[2].bufs, 1, "routine 2 did not send on its own socket")
  721. assert.Empty(t, conns[0].bufs)
  722. // Multiport on, but this peer has no lanes: socket 0, lane 0, one batch.
  723. ifce.multiport = true
  724. ifce.laneCount = 4
  725. tx = ifce.newTxQueue(2)
  726. require.Len(t, tx.live, 1)
  727. ifce.sendInsideMessage(hi, pkt, flow, nb, tx)
  728. tx.flush(ifce)
  729. require.Len(t, conns[0].bufs, 1, "base traffic left a socket other than 0")
  730. assert.Len(t, conns[2].bufs, 1)
  731. h := &header.H{}
  732. require.NoError(t, h.Parse(conns[0].bufs[0]))
  733. assert.Equal(t, uint8(0), h.Lane())
  734. assert.Len(t, tx.live, 1, "a lane batch was built for a peer with no lanes")
  735. }
  736. // `routines` is per port, so a port's sockets are a group sharing it through
  737. // SO_REUSEPORT and every routine has a sibling of its own on every port. Pin the
  738. // arithmetic that turns (queue, lane) into one of them.
  739. func TestLaneSockGroupLayout(t *testing.T) {
  740. hostMap := newHostMap(test.NewLogger())
  741. ifce := newLaneTestInterface(hostMap)
  742. // Two routines per port over three ports: writers[s*2+r] is the r'th socket
  743. // on port listen.port+s.
  744. ifce.routinesPerPort = 2
  745. ifce.routines = 6
  746. ifce.laneCount = 3
  747. // Off, every socket is on the one port, so a routine keeps writing to its own
  748. // and any of them can carry any lane.
  749. for q := 0; q < ifce.routines; q++ {
  750. assert.Equal(t, q, ifce.egressSock(q))
  751. for s := 0; s < ifce.laneCount; s++ {
  752. assert.Equal(t, q, ifce.laneSock(q, s))
  753. }
  754. }
  755. ifce.multiport = true
  756. for q := 0; q < ifce.routines; q++ {
  757. // Base traffic is lane 0's port, and each routine has its own socket
  758. // there rather than sharing one with the other five.
  759. assert.Equal(t, q%2, ifce.egressSock(q), "queue %d", q)
  760. for s := 0; s < ifce.laneCount; s++ {
  761. assert.Equal(t, s*2+q%2, ifce.laneSock(q, s), "queue %d lane %d", q, s)
  762. }
  763. }
  764. // Sibling routines land on different sockets of the same port, so a lane's
  765. // port is served by its whole group and not by one socket.
  766. assert.NotEqual(t, ifce.laneSock(0, 2), ifce.laneSock(1, 2))
  767. assert.Equal(t, ifce.laneSock(0, 2), ifce.laneSock(2, 2), "queues 0 and 2 share a group position")
  768. }
  769. // The lane batches a routine builds must flush to that routine's own sockets, not
  770. // to whatever socket happens to be indexed by the lane.
  771. func TestTxQueueLaneBatchesFollowTheGroup(t *testing.T) {
  772. hostMap := newHostMap(test.NewLogger())
  773. ifce := newLaneTestInterface(hostMap)
  774. ifce.multiport = true
  775. ifce.routinesPerPort = 2
  776. ifce.routines = 4
  777. ifce.laneCount = 2
  778. conns := []*recordingBatchConn{{}, {}, {}, {}}
  779. ifce.writers = []udp.Conn{conns[0], conns[1], conns[2], conns[3]}
  780. initR, _ := runTestHandshake(t)
  781. ls := newTestLaneSet(t, initR, 2, 2, 5353, 2)
  782. hi := newTestLaneHostInfo(t, initR, ls)
  783. laneSessionFor(t, ls, 1)
  784. laneRemote := netip.MustParseAddrPort("192.0.2.1:5354")
  785. ls.txAddr[1].Store(&laneRemote)
  786. pkt := tio.Packet{Bytes: []byte{0x45, 0, 0, 4, 1, 2, 3, 4}}
  787. nb := make([]byte, 12)
  788. flow1 := flowForLane(t, ls, 1)
  789. // Routine 1 is the second socket in each group, so its lane 1 traffic leaves
  790. // writers[1*2+1].
  791. tx := ifce.newTxQueue(1)
  792. ifce.sendInsideMessage(hi, pkt, flow1, nb, tx)
  793. tx.flush(ifce)
  794. require.Len(t, conns[3].bufs, 1, "lane 1 did not leave routine 1's socket on the lane port")
  795. assert.Equal(t, laneRemote, conns[3].dsts[0])
  796. assert.Empty(t, conns[2].bufs)
  797. // Routine 0 sends the same flow out the other socket on that same port.
  798. tx0 := ifce.newTxQueue(0)
  799. ifce.sendInsideMessage(hi, pkt, flow1, nb, tx0)
  800. tx0.flush(ifce)
  801. require.Len(t, conns[2].bufs, 1, "sibling routine shared a socket instead of its own")
  802. assert.Len(t, conns[3].bufs, 1)
  803. }
  804. // One routine has to be able to reach every lane, since the kernel decides which
  805. // routine sees a flow and it may well hand one routine everything.
  806. func TestTxLaneForFlowSpread(t *testing.T) {
  807. initR, _ := runTestHandshake(t)
  808. ls := newTestLaneSet(t, initR, 4, 4, 5353, 4)
  809. seen := map[int]int{}
  810. for port := uint16(1024); port < 1224; port++ {
  811. s := laneOfFlow(ls, testFlow(port))
  812. require.Less(t, s, ls.txLanes)
  813. seen[s]++
  814. }
  815. assert.Len(t, seen, 4, "200 flows did not reach all four lanes: %v", seen)
  816. for s, n := range seen {
  817. assert.Greater(t, n, 10, "lane %d got a negligible share of flows", s)
  818. }
  819. // A flow's lane is a function of its 5-tuple alone, so it never moves
  820. // mid-flow.
  821. p := testFlow(1234)
  822. assert.Equal(t, laneOfFlow(ls, p), laneOfFlow(ls, p))
  823. // A tunnel with nothing but the base lane always answers lane 0.
  824. one := newTestLaneSet(t, initR, 1, 1, 5353, 4)
  825. s, ci, addr := one.txLaneForFlow(p)
  826. assert.Zero(t, s)
  827. assert.Nil(t, ci)
  828. assert.False(t, addr.IsValid())
  829. s, ci, _ = (*laneSet)(nil).txLaneForFlow(p)
  830. assert.Zero(t, s)
  831. assert.Nil(t, ci)
  832. }
  833. // The two ends of a flow have to pick partner lanes, or the flow's two
  834. // directions use unrelated 4-tuples instead of exact reverses and neither side's
  835. // traffic arrives through the conntrack entry the other's probe opened.
  836. func TestLaneFlowSymmetry(t *testing.T) {
  837. initR, respR := runTestHandshake(t)
  838. // Our side is the low address; the peer builds the same pair reversed.
  839. const ourBase, peerBase = 4242, 5353
  840. ourLS := newTestLaneSet(t, initR, 4, 4, peerBase, 4)
  841. respR.PeerPortCount, respR.PeerBasePort, respR.PeerTxLanes = 4, ourBase, 4
  842. peerLS := newLaneSet(respR, 4, testPeerAddr, testMyAddr)
  843. require.NotNil(t, peerLS)
  844. require.Equal(t, uint16(0), ourLS.laneBias, "the low address hashes straight")
  845. partnered := 0
  846. for port := uint16(1024); port < 1124; port++ {
  847. p := testFlow(port)
  848. reverse := &firewall.Packet{
  849. LocalAddr: p.RemoteAddr, RemoteAddr: p.LocalAddr,
  850. LocalPort: p.RemotePort, RemotePort: p.LocalPort,
  851. Protocol: p.Protocol,
  852. }
  853. ours := laneOfFlow(ourLS, p)
  854. theirs := laneOfFlow(peerLS, reverse)
  855. require.Equal(t, (ours+int(ourLS.portOffset))%4, theirs,
  856. "flow on port %d: our lane %d is not partnered with their lane %d", port, ours, theirs)
  857. if ours == 0 || theirs == 0 {
  858. // The lane that lands on the other side's base port has no partner
  859. // lane; that flow rides one side's base tunnel. See lanePortOffset.
  860. continue
  861. }
  862. partnered++
  863. // Our source and destination ports are the reverse of theirs.
  864. ourLS.mu.Lock()
  865. peerLS.mu.Lock()
  866. assert.Equal(t, uint16(peerBase+theirs), ourLS.laneTargetPortLocked(ours), "flow on port %d", port)
  867. assert.Equal(t, uint16(ourBase+ours), peerLS.laneTargetPortLocked(theirs), "flow on port %d", port)
  868. peerLS.mu.Unlock()
  869. ourLS.mu.Unlock()
  870. }
  871. assert.Greater(t, partnered, 0, "no flow landed on a partnered lane")
  872. }
  873. // Regression: deleting a hostinfo whose pending entry is NOT the one recorded
  874. // in vpnIps must not evict a concurrently pending handshake for that address.
  875. func TestHandshakeManagerVpnIpsIdentityDelete(t *testing.T) {
  876. l := test.NewLogger()
  877. hostMap := newHostMap(l)
  878. lh := newTestLighthouse()
  879. hm := NewHandshakeManager(l, hostMap, lh, &udp.NoopConn{}, defaultHandshakeConfig)
  880. vpnIp := netip.MustParseAddr("172.1.1.4")
  881. pendingBase := hm.StartHandshake(vpnIp, nil)
  882. require.NotNil(t, pendingBase)
  883. other := &HostInfo{vpnAddrs: []netip.Addr{vpnIp}, localIndexId: 999}
  884. hm.DeleteHostInfo(other)
  885. // The pending base handshake must still be tracked.
  886. assert.Equal(t, pendingBase, hm.QueryVpnAddr(vpnIp))
  887. // And deleting the actual owner still works.
  888. hm.DeleteHostInfo(pendingBase)
  889. assert.Nil(t, hm.QueryVpnAddr(vpnIp))
  890. }