lanes_test.go 38 KB

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