lighthouse_test.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. package nebula
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "net/netip"
  6. "testing"
  7. "github.com/gaissmai/bart"
  8. "github.com/slackhq/nebula/cert"
  9. "github.com/slackhq/nebula/config"
  10. "github.com/slackhq/nebula/header"
  11. "github.com/slackhq/nebula/test"
  12. "github.com/stretchr/testify/assert"
  13. "github.com/stretchr/testify/require"
  14. "go.yaml.in/yaml/v3"
  15. )
  16. func TestOldIPv4Only(t *testing.T) {
  17. // This test ensures our new ipv6 enabled LH protobuf IpAndPorts works with the old style to enable backwards compatibility
  18. b := []byte{8, 129, 130, 132, 80, 16, 10}
  19. var m V4AddrPort
  20. err := m.Unmarshal(b)
  21. require.NoError(t, err)
  22. ip := netip.MustParseAddr("10.1.1.1")
  23. bp := ip.As4()
  24. assert.Equal(t, binary.BigEndian.Uint32(bp[:]), m.GetAddr())
  25. }
  26. func testCertState(networks ...netip.Prefix) *CertState {
  27. cs := &CertState{
  28. myVpnNetworks: networks,
  29. myVpnNetworksTable: new(bart.Lite),
  30. myVpnAddrs: make([]netip.Addr, 0, len(networks)),
  31. myVpnAddrsTable: new(bart.Lite),
  32. }
  33. for _, n := range networks {
  34. cs.myVpnNetworksTable.Insert(n)
  35. cs.myVpnAddrs = append(cs.myVpnAddrs, n.Addr())
  36. cs.myVpnAddrsTable.Insert(netip.PrefixFrom(n.Addr(), n.Addr().BitLen()))
  37. }
  38. return cs
  39. }
  40. func Test_lhStaticMapping(t *testing.T) {
  41. l := test.NewLogger()
  42. myVpnNet := netip.MustParsePrefix("10.128.0.1/16")
  43. cs := testCertState(myVpnNet)
  44. lh1 := "10.128.0.2"
  45. c := config.NewC(l)
  46. c.Settings["lighthouse"] = map[string]any{"hosts": []any{lh1}}
  47. c.Settings["static_host_map"] = map[string]any{lh1: []any{"1.1.1.1:4242"}}
  48. _, err := NewLightHouseFromConfig(t.Context(), l, c, cs, nil, nil)
  49. require.NoError(t, err)
  50. lh2 := "10.128.0.3"
  51. c = config.NewC(l)
  52. c.Settings["lighthouse"] = map[string]any{"hosts": []any{lh1, lh2}}
  53. c.Settings["static_host_map"] = map[string]any{lh1: []any{"100.1.1.1:4242"}}
  54. _, err = NewLightHouseFromConfig(t.Context(), l, c, cs, nil, nil)
  55. require.EqualError(t, err, "lighthouse 10.128.0.3 does not have a static_host_map entry")
  56. }
  57. func TestReloadLighthouseInterval(t *testing.T) {
  58. l := test.NewLogger()
  59. myVpnNet := netip.MustParsePrefix("10.128.0.1/16")
  60. cs := testCertState(myVpnNet)
  61. lh1 := "10.128.0.2"
  62. c := config.NewC(l)
  63. c.Settings["lighthouse"] = map[string]any{
  64. "hosts": []any{lh1},
  65. "interval": "1s",
  66. }
  67. c.Settings["static_host_map"] = map[string]any{lh1: []any{"1.1.1.1:4242"}}
  68. lh, err := NewLightHouseFromConfig(t.Context(), l, c, cs, nil, nil)
  69. require.NoError(t, err)
  70. lh.ifce = &mockEncWriter{}
  71. // The first one routine is kicked off by main.go currently, lets make sure that one dies
  72. require.NoError(t, c.ReloadConfigString("lighthouse:\n interval: 5"))
  73. assert.Equal(t, int64(5), lh.interval.Load())
  74. // Subsequent calls are killed off by the LightHouse.Reload function
  75. require.NoError(t, c.ReloadConfigString("lighthouse:\n interval: 10"))
  76. assert.Equal(t, int64(10), lh.interval.Load())
  77. // If this completes then nothing is stealing our reload routine
  78. require.NoError(t, c.ReloadConfigString("lighthouse:\n interval: 11"))
  79. assert.Equal(t, int64(11), lh.interval.Load())
  80. }
  81. func BenchmarkLighthouseHandleRequest(b *testing.B) {
  82. l := test.NewLogger()
  83. myVpnNet := netip.MustParsePrefix("10.128.0.1/0")
  84. cs := testCertState(myVpnNet)
  85. c := config.NewC(l)
  86. lh, err := NewLightHouseFromConfig(b.Context(), l, c, cs, nil, nil)
  87. require.NoError(b, err)
  88. hAddr := netip.MustParseAddrPort("4.5.6.7:12345")
  89. hAddr2 := netip.MustParseAddrPort("4.5.6.7:12346")
  90. vpnIp3 := netip.MustParseAddr("0.0.0.3")
  91. lh.addrMap[vpnIp3] = NewRemoteList([]netip.Addr{vpnIp3}, nil)
  92. lh.addrMap[vpnIp3].unlockedSetV4(
  93. vpnIp3,
  94. vpnIp3,
  95. []*V4AddrPort{
  96. netAddrToProtoV4AddrPort(hAddr.Addr(), hAddr.Port()),
  97. netAddrToProtoV4AddrPort(hAddr2.Addr(), hAddr2.Port()),
  98. },
  99. func(netip.Addr, *V4AddrPort) bool { return true },
  100. )
  101. rAddr := netip.MustParseAddrPort("1.2.2.3:12345")
  102. rAddr2 := netip.MustParseAddrPort("1.2.2.3:12346")
  103. vpnIp2 := netip.MustParseAddr("0.0.0.3")
  104. lh.addrMap[vpnIp2] = NewRemoteList([]netip.Addr{vpnIp2}, nil)
  105. lh.addrMap[vpnIp2].unlockedSetV4(
  106. vpnIp3,
  107. vpnIp3,
  108. []*V4AddrPort{
  109. netAddrToProtoV4AddrPort(rAddr.Addr(), rAddr.Port()),
  110. netAddrToProtoV4AddrPort(rAddr2.Addr(), rAddr2.Port()),
  111. },
  112. func(netip.Addr, *V4AddrPort) bool { return true },
  113. )
  114. mw := &mockEncWriter{}
  115. hi := []netip.Addr{vpnIp2}
  116. b.Run("notfound", func(b *testing.B) {
  117. lhh := lh.NewRequestHandler()
  118. req := &NebulaMeta{
  119. Type: NebulaMeta_HostQuery,
  120. Details: &NebulaMetaDetails{
  121. OldVpnAddr: 4,
  122. V4AddrPorts: nil,
  123. },
  124. }
  125. p, err := req.Marshal()
  126. require.NoError(b, err)
  127. for n := 0; n < b.N; n++ {
  128. lhh.HandleRequest(rAddr, hi, p, mw)
  129. }
  130. })
  131. b.Run("found", func(b *testing.B) {
  132. lhh := lh.NewRequestHandler()
  133. req := &NebulaMeta{
  134. Type: NebulaMeta_HostQuery,
  135. Details: &NebulaMetaDetails{
  136. OldVpnAddr: 3,
  137. V4AddrPorts: nil,
  138. },
  139. }
  140. p, err := req.Marshal()
  141. require.NoError(b, err)
  142. for n := 0; n < b.N; n++ {
  143. lhh.HandleRequest(rAddr, hi, p, mw)
  144. }
  145. })
  146. }
  147. func TestLighthouse_Memory(t *testing.T) {
  148. l := test.NewLogger()
  149. myUdpAddr0 := netip.MustParseAddrPort("10.0.0.2:4242")
  150. myUdpAddr1 := netip.MustParseAddrPort("192.168.0.2:4242")
  151. myUdpAddr2 := netip.MustParseAddrPort("172.16.0.2:4242")
  152. myUdpAddr3 := netip.MustParseAddrPort("100.152.0.2:4242")
  153. myUdpAddr4 := netip.MustParseAddrPort("24.15.0.2:4242")
  154. myUdpAddr5 := netip.MustParseAddrPort("192.168.0.2:4243")
  155. myUdpAddr6 := netip.MustParseAddrPort("192.168.0.2:4244")
  156. myUdpAddr7 := netip.MustParseAddrPort("192.168.0.2:4245")
  157. myUdpAddr8 := netip.MustParseAddrPort("192.168.0.2:4246")
  158. myUdpAddr9 := netip.MustParseAddrPort("192.168.0.2:4247")
  159. myUdpAddr10 := netip.MustParseAddrPort("192.168.0.2:4248")
  160. myUdpAddr11 := netip.MustParseAddrPort("192.168.0.2:4249")
  161. myVpnIp := netip.MustParseAddr("10.128.0.2")
  162. theirUdpAddr0 := netip.MustParseAddrPort("10.0.0.3:4242")
  163. theirUdpAddr1 := netip.MustParseAddrPort("192.168.0.3:4242")
  164. theirUdpAddr2 := netip.MustParseAddrPort("172.16.0.3:4242")
  165. theirUdpAddr3 := netip.MustParseAddrPort("100.152.0.3:4242")
  166. theirUdpAddr4 := netip.MustParseAddrPort("24.15.0.3:4242")
  167. theirVpnIp := netip.MustParseAddr("10.128.0.3")
  168. c := config.NewC(l)
  169. c.Settings["lighthouse"] = map[string]any{"am_lighthouse": true}
  170. c.Settings["listen"] = map[string]any{"port": 4242}
  171. myVpnNet := netip.MustParsePrefix("10.128.0.1/24")
  172. cs := testCertState(myVpnNet)
  173. lh, err := NewLightHouseFromConfig(t.Context(), l, c, cs, nil, nil)
  174. lh.ifce = &mockEncWriter{}
  175. require.NoError(t, err)
  176. lhh := lh.NewRequestHandler()
  177. // Test that my first update responds with just that
  178. newLHHostUpdate(myUdpAddr0, myVpnIp, []netip.AddrPort{myUdpAddr1, myUdpAddr2}, lhh)
  179. r := newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  180. assertIp4InArray(t, r.msg.Details.V4AddrPorts, myUdpAddr1, myUdpAddr2)
  181. // Ensure we don't accumulate addresses
  182. newLHHostUpdate(myUdpAddr0, myVpnIp, []netip.AddrPort{myUdpAddr3}, lhh)
  183. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  184. assertIp4InArray(t, r.msg.Details.V4AddrPorts, myUdpAddr3)
  185. // Grow it back to 2
  186. newLHHostUpdate(myUdpAddr0, myVpnIp, []netip.AddrPort{myUdpAddr1, myUdpAddr4}, lhh)
  187. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  188. assertIp4InArray(t, r.msg.Details.V4AddrPorts, myUdpAddr1, myUdpAddr4)
  189. // Update a different host and ask about it
  190. newLHHostUpdate(theirUdpAddr0, theirVpnIp, []netip.AddrPort{theirUdpAddr1, theirUdpAddr2, theirUdpAddr3, theirUdpAddr4}, lhh)
  191. r = newLHHostRequest(theirUdpAddr0, theirVpnIp, theirVpnIp, lhh)
  192. assertIp4InArray(t, r.msg.Details.V4AddrPorts, theirUdpAddr1, theirUdpAddr2, theirUdpAddr3, theirUdpAddr4)
  193. // Have both hosts ask about the other
  194. r = newLHHostRequest(theirUdpAddr0, theirVpnIp, myVpnIp, lhh)
  195. assertIp4InArray(t, r.msg.Details.V4AddrPorts, myUdpAddr1, myUdpAddr4)
  196. r = newLHHostRequest(myUdpAddr0, myVpnIp, theirVpnIp, lhh)
  197. assertIp4InArray(t, r.msg.Details.V4AddrPorts, theirUdpAddr1, theirUdpAddr2, theirUdpAddr3, theirUdpAddr4)
  198. // Make sure we didn't get changed
  199. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  200. assertIp4InArray(t, r.msg.Details.V4AddrPorts, myUdpAddr1, myUdpAddr4)
  201. // Ensure proper ordering and limiting
  202. // Send 12 addrs, get 10 back, the last 2 removed, allowing the duplicate to remain (clients dedupe)
  203. newLHHostUpdate(
  204. myUdpAddr0,
  205. myVpnIp,
  206. []netip.AddrPort{
  207. myUdpAddr1,
  208. myUdpAddr2,
  209. myUdpAddr3,
  210. myUdpAddr4,
  211. myUdpAddr5,
  212. myUdpAddr5, //Duplicated on purpose
  213. myUdpAddr6,
  214. myUdpAddr7,
  215. myUdpAddr8,
  216. myUdpAddr9,
  217. myUdpAddr10,
  218. myUdpAddr11, // This should get cut
  219. }, lhh)
  220. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  221. assertIp4InArray(
  222. t,
  223. r.msg.Details.V4AddrPorts,
  224. myUdpAddr1, myUdpAddr2, myUdpAddr3, myUdpAddr4, myUdpAddr5, myUdpAddr5, myUdpAddr6, myUdpAddr7, myUdpAddr8, myUdpAddr9,
  225. )
  226. // Make sure we won't add ips in our vpn network
  227. bad1 := netip.MustParseAddrPort("10.128.0.99:4242")
  228. bad2 := netip.MustParseAddrPort("10.128.0.100:4242")
  229. good := netip.MustParseAddrPort("1.128.0.99:4242")
  230. newLHHostUpdate(myUdpAddr0, myVpnIp, []netip.AddrPort{bad1, bad2, good}, lhh)
  231. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  232. assertIp4InArray(t, r.msg.Details.V4AddrPorts, good)
  233. }
  234. func TestLighthouse_reload(t *testing.T) {
  235. l := test.NewLogger()
  236. c := config.NewC(l)
  237. c.Settings["lighthouse"] = map[string]any{"am_lighthouse": true}
  238. c.Settings["listen"] = map[string]any{"port": 4242}
  239. myVpnNet := netip.MustParsePrefix("10.128.0.1/24")
  240. cs := testCertState(myVpnNet)
  241. lh, err := NewLightHouseFromConfig(t.Context(), l, c, cs, nil, nil)
  242. require.NoError(t, err)
  243. nc := map[string]any{
  244. "static_host_map": map[string]any{
  245. "10.128.0.2": []any{"1.1.1.1:4242"},
  246. },
  247. }
  248. rc, err := yaml.Marshal(nc)
  249. require.NoError(t, err)
  250. c.ReloadConfigString(string(rc))
  251. err = lh.reload(c, false)
  252. require.NoError(t, err)
  253. }
  254. // TestLighthouse_reloadStaticHostMap verifies that reloading static_host_map applies the new
  255. // config rather than appending to it. See issue #718.
  256. func TestLighthouse_reloadStaticHostMap(t *testing.T) {
  257. l := test.NewLogger()
  258. c := config.NewC(l)
  259. c.Settings["lighthouse"] = map[string]any{"am_lighthouse": true}
  260. c.Settings["listen"] = map[string]any{"port": 4242}
  261. c.Settings["static_host_map"] = map[string]any{
  262. "10.128.0.2": []any{"1.1.1.1:4242"},
  263. }
  264. myVpnNet := netip.MustParsePrefix("10.128.0.1/24")
  265. cs := testCertState(myVpnNet)
  266. lh, err := NewLightHouseFromConfig(t.Context(), l, c, cs, nil, nil)
  267. require.NoError(t, err)
  268. staticHost := netip.MustParseAddr("10.128.0.2")
  269. otherHost := netip.MustParseAddr("10.128.0.3")
  270. // Capture the RemoteList pointer up front; an in-flight handshake would hold the same one
  271. // on hostinfo.remotes, so it must reflect every reload below.
  272. pinned := lh.Query(staticHost)
  273. require.NotNil(t, pinned)
  274. assert.Equal(t, []netip.AddrPort{netip.MustParseAddrPort("1.1.1.1:4242")}, pinned.CopyAddrs([]netip.Prefix{}))
  275. // Replace the remote address. The new address should be the only entry.
  276. nc := map[string]any{
  277. "static_host_map": map[string]any{
  278. "10.128.0.2": []any{"2.2.2.2:4242"},
  279. },
  280. }
  281. rc, err := yaml.Marshal(nc)
  282. require.NoError(t, err)
  283. require.NoError(t, c.ReloadConfigString(string(rc)))
  284. rl := lh.Query(staticHost)
  285. require.NotNil(t, rl)
  286. assert.Same(t, pinned, rl, "RemoteList pointer must stay stable so in-flight handshakes pick up the change")
  287. assert.Equal(t, []netip.AddrPort{netip.MustParseAddrPort("2.2.2.2:4242")}, rl.CopyAddrs([]netip.Prefix{}))
  288. // Reload back to the original IP. Mirrors the round-trip in issue #718 step 6-8 where
  289. // the buggy reload produced [1.1.1.1, 2.2.2.2, 1.1.1.1] instead of [1.1.1.1].
  290. nc = map[string]any{
  291. "static_host_map": map[string]any{
  292. "10.128.0.2": []any{"1.1.1.1:4242"},
  293. },
  294. }
  295. rc, err = yaml.Marshal(nc)
  296. require.NoError(t, err)
  297. require.NoError(t, c.ReloadConfigString(string(rc)))
  298. rl = lh.Query(staticHost)
  299. require.NotNil(t, rl)
  300. assert.Same(t, pinned, rl)
  301. assert.Equal(t, []netip.AddrPort{netip.MustParseAddrPort("1.1.1.1:4242")}, rl.CopyAddrs([]netip.Prefix{}))
  302. // Reload with the same config. An unchanged entry must not duplicate.
  303. require.NoError(t, c.ReloadConfigString(string(rc)))
  304. rl = lh.Query(staticHost)
  305. require.NotNil(t, rl)
  306. assert.Same(t, pinned, rl)
  307. assert.Equal(t, []netip.AddrPort{netip.MustParseAddrPort("1.1.1.1:4242")}, rl.CopyAddrs([]netip.Prefix{}))
  308. // Switch back to 2.2.2.2 so the rest of the test continues against a known address.
  309. nc = map[string]any{
  310. "static_host_map": map[string]any{
  311. "10.128.0.2": []any{"2.2.2.2:4242"},
  312. },
  313. }
  314. rc, err = yaml.Marshal(nc)
  315. require.NoError(t, err)
  316. require.NoError(t, c.ReloadConfigString(string(rc)))
  317. // Add a second host alongside the first. Both should be present, neither duplicated.
  318. nc = map[string]any{
  319. "static_host_map": map[string]any{
  320. "10.128.0.2": []any{"2.2.2.2:4242"},
  321. "10.128.0.3": []any{"3.3.3.3:4242"},
  322. },
  323. }
  324. rc, err = yaml.Marshal(nc)
  325. require.NoError(t, err)
  326. require.NoError(t, c.ReloadConfigString(string(rc)))
  327. rl = lh.Query(staticHost)
  328. require.NotNil(t, rl)
  329. assert.Same(t, pinned, rl, "adding a sibling entry must not displace the existing RemoteList")
  330. assert.Equal(t, []netip.AddrPort{netip.MustParseAddrPort("2.2.2.2:4242")}, rl.CopyAddrs([]netip.Prefix{}))
  331. rl = lh.Query(otherHost)
  332. require.NotNil(t, rl)
  333. assert.Equal(t, []netip.AddrPort{netip.MustParseAddrPort("3.3.3.3:4242")}, rl.CopyAddrs([]netip.Prefix{}))
  334. // Drop the first host entirely. The vpnAddr is no longer marked static, our owner
  335. // contribution is cleared, but the addrMap entry stays in place so non-static cache
  336. // data (from lighthouse queries) on the same RemoteList isn't lost. In-flight handshakes
  337. // that already had the pointer see an empty address list rather than retrying stale ones.
  338. nc = map[string]any{
  339. "static_host_map": map[string]any{
  340. "10.128.0.3": []any{"3.3.3.3:4242"},
  341. },
  342. }
  343. rc, err = yaml.Marshal(nc)
  344. require.NoError(t, err)
  345. require.NoError(t, c.ReloadConfigString(string(rc)))
  346. _, isStatic := lh.GetStaticHostList()[staticHost]
  347. assert.False(t, isStatic)
  348. rl = lh.Query(staticHost)
  349. require.NotNil(t, rl)
  350. assert.Same(t, pinned, rl)
  351. assert.Empty(t, rl.CopyAddrs([]netip.Prefix{}))
  352. rl = lh.Query(otherHost)
  353. require.NotNil(t, rl)
  354. assert.Equal(t, []netip.AddrPort{netip.MustParseAddrPort("3.3.3.3:4242")}, rl.CopyAddrs([]netip.Prefix{}))
  355. }
  356. // sendLHHostRequest delivers a HostQuery to lhh and hands back the writer that
  357. // captured what it emitted. Pass a nil filter to see every message.
  358. func sendLHHostRequest(fromAddr netip.AddrPort, myVpnIp, queryVpnIp netip.Addr, lhh *LightHouseHandler, filter *NebulaMeta_MessageType) *testEncWriter {
  359. req := &NebulaMeta{
  360. Type: NebulaMeta_HostQuery,
  361. Details: &NebulaMetaDetails{},
  362. }
  363. if queryVpnIp.Is4() {
  364. bip := queryVpnIp.As4()
  365. req.Details.OldVpnAddr = binary.BigEndian.Uint32(bip[:])
  366. } else {
  367. req.Details.VpnAddr = netAddrToProtoAddr(queryVpnIp)
  368. }
  369. b, err := req.Marshal()
  370. if err != nil {
  371. panic(err)
  372. }
  373. w := &testEncWriter{metaFilter: filter}
  374. lhh.HandleRequest(fromAddr, []netip.Addr{myVpnIp}, b, w)
  375. return w
  376. }
  377. func newLHHostRequest(fromAddr netip.AddrPort, myVpnIp, queryVpnIp netip.Addr, lhh *LightHouseHandler) testLhReply {
  378. filter := NebulaMeta_HostQueryReply
  379. return sendLHHostRequest(fromAddr, myVpnIp, queryVpnIp, lhh, &filter).lastReply
  380. }
  381. func TestLighthouse_IgnoresHostQueryForItself(t *testing.T) {
  382. // Validate that we don't answer host queries for our own address.
  383. l := test.NewLogger()
  384. myVpnNet := netip.MustParsePrefix("10.128.0.1/24")
  385. myVpnIp := myVpnNet.Addr()
  386. c := config.NewC(l)
  387. c.Settings["lighthouse"] = map[string]any{"am_lighthouse": true}
  388. c.Settings["listen"] = map[string]any{"port": 4242}
  389. // Add a static_host_map entry for ourselves, so our address
  390. // is in the addrMap.
  391. c.Settings["static_host_map"] = map[string]any{
  392. myVpnIp.String(): []any{"192.168.100.1:4242"},
  393. }
  394. lh, err := NewLightHouseFromConfig(t.Context(), l, c, testCertState(myVpnNet), nil, nil)
  395. require.NoError(t, err)
  396. lh.ifce = &mockEncWriter{}
  397. lhh := lh.NewRequestHandler()
  398. peerVpnIp := netip.MustParseAddr("10.128.0.2")
  399. peerUdpAddr := netip.MustParseAddrPort("10.0.0.2:4242")
  400. otherVpnIp := netip.MustParseAddr("10.128.0.3")
  401. otherUdpAddr := netip.MustParseAddrPort("10.0.0.3:4242")
  402. newLHHostUpdate(peerUdpAddr, peerVpnIp, []netip.AddrPort{peerUdpAddr}, lhh)
  403. newLHHostUpdate(otherUdpAddr, otherVpnIp, []netip.AddrPort{otherUdpAddr}, lhh)
  404. // Control: a query about a real peer is still answered, and still ends with
  405. // the punch notification aimed at the host that was asked about.
  406. w := sendLHHostRequest(peerUdpAddr, peerVpnIp, otherVpnIp, lhh, nil)
  407. require.NotNil(t, w.lastReply.msg)
  408. assert.Equal(t, NebulaMeta_HostPunchNotification, w.lastReply.msg.Type)
  409. assert.Equal(t, otherVpnIp, w.lastReply.vpnIp)
  410. // Now validate that we don't send to ourselves.
  411. found, _, err := lh.queryAndPrepMessage(myVpnIp, func(*cache) (int, error) { return 0, nil })
  412. require.NoError(t, err)
  413. require.True(t, found, "the lighthouse should hold a cache entry for its own address")
  414. w = sendLHHostRequest(peerUdpAddr, peerVpnIp, myVpnIp, lhh, nil)
  415. assert.Nil(t, w.lastReply.msg, "a query about our own address must produce no reply and no punch notification")
  416. }
  417. func newLHHostUpdate(fromAddr netip.AddrPort, vpnIp netip.Addr, addrs []netip.AddrPort, lhh *LightHouseHandler) {
  418. req := &NebulaMeta{
  419. Type: NebulaMeta_HostUpdateNotification,
  420. Details: &NebulaMetaDetails{},
  421. }
  422. if vpnIp.Is4() {
  423. bip := vpnIp.As4()
  424. req.Details.OldVpnAddr = binary.BigEndian.Uint32(bip[:])
  425. } else {
  426. req.Details.VpnAddr = netAddrToProtoAddr(vpnIp)
  427. }
  428. for _, v := range addrs {
  429. if v.Addr().Is4() {
  430. req.Details.V4AddrPorts = append(req.Details.V4AddrPorts, netAddrToProtoV4AddrPort(v.Addr(), v.Port()))
  431. } else {
  432. req.Details.V6AddrPorts = append(req.Details.V6AddrPorts, netAddrToProtoV6AddrPort(v.Addr(), v.Port()))
  433. }
  434. }
  435. b, err := req.Marshal()
  436. if err != nil {
  437. panic(err)
  438. }
  439. w := &testEncWriter{}
  440. lhh.HandleRequest(fromAddr, []netip.Addr{vpnIp}, b, w)
  441. }
  442. type testLhReply struct {
  443. nebType header.MessageType
  444. nebSubType header.MessageSubType
  445. vpnIp netip.Addr
  446. msg *NebulaMeta
  447. }
  448. type testEncWriter struct {
  449. lastReply testLhReply
  450. metaFilter *NebulaMeta_MessageType
  451. protocolVersion cert.Version
  452. }
  453. func (tw *testEncWriter) SendVia(via *HostInfo, relay *Relay, ad, nb, out []byte, nocopy bool, q int) {
  454. }
  455. func (tw *testEncWriter) Handshake(vpnIp netip.Addr) {
  456. }
  457. func (tw *testEncWriter) SendMessageToHostInfo(t header.MessageType, st header.MessageSubType, hostinfo *HostInfo, p, _, _ []byte) {
  458. msg := &NebulaMeta{}
  459. err := msg.Unmarshal(p)
  460. if tw.metaFilter == nil || msg.Type == *tw.metaFilter {
  461. tw.lastReply = testLhReply{
  462. nebType: t,
  463. nebSubType: st,
  464. vpnIp: hostinfo.vpnAddrs[0],
  465. msg: msg,
  466. }
  467. }
  468. if err != nil {
  469. panic(err)
  470. }
  471. }
  472. func (tw *testEncWriter) SendMessageToVpnAddr(t header.MessageType, st header.MessageSubType, vpnIp netip.Addr, p, _, _ []byte) {
  473. msg := &NebulaMeta{}
  474. err := msg.Unmarshal(p)
  475. if tw.metaFilter == nil || msg.Type == *tw.metaFilter {
  476. tw.lastReply = testLhReply{
  477. nebType: t,
  478. nebSubType: st,
  479. vpnIp: vpnIp,
  480. msg: msg,
  481. }
  482. }
  483. if err != nil {
  484. panic(err)
  485. }
  486. }
  487. func (tw *testEncWriter) GetHostInfo(vpnIp netip.Addr) *HostInfo {
  488. return nil
  489. }
  490. func (tw *testEncWriter) GetCertState() *CertState {
  491. return &CertState{initiatingVersion: tw.protocolVersion}
  492. }
  493. // assertIp4InArray asserts every address in want is at the same position in have and that the lengths match
  494. func assertIp4InArray(t *testing.T, have []*V4AddrPort, want ...netip.AddrPort) {
  495. if !assert.Len(t, have, len(want)) {
  496. return
  497. }
  498. for k, w := range want {
  499. h := protoV4AddrPortToNetAddrPort(have[k])
  500. if !(h == w) {
  501. assert.Fail(t, fmt.Sprintf("Response did not contain: %v at %v, found %v", w, k, h))
  502. }
  503. }
  504. }
  505. func Test_findNetworkUnion(t *testing.T) {
  506. var out netip.Addr
  507. var ok bool
  508. tenDot := netip.MustParsePrefix("10.0.0.0/8")
  509. oneSevenTwo := netip.MustParsePrefix("172.16.0.0/16")
  510. fe80 := netip.MustParsePrefix("fe80::/8")
  511. fc00 := netip.MustParsePrefix("fc00::/7")
  512. a1 := netip.MustParseAddr("10.0.0.1")
  513. afe81 := netip.MustParseAddr("fe80::1")
  514. //simple
  515. out, ok = findNetworkUnion([]netip.Prefix{tenDot}, []netip.Addr{a1})
  516. assert.True(t, ok)
  517. assert.Equal(t, out, a1)
  518. //mixed lengths
  519. out, ok = findNetworkUnion([]netip.Prefix{tenDot}, []netip.Addr{a1, afe81})
  520. assert.True(t, ok)
  521. assert.Equal(t, out, a1)
  522. out, ok = findNetworkUnion([]netip.Prefix{tenDot, oneSevenTwo}, []netip.Addr{a1})
  523. assert.True(t, ok)
  524. assert.Equal(t, out, a1)
  525. //mixed family
  526. out, ok = findNetworkUnion([]netip.Prefix{tenDot, oneSevenTwo, fe80}, []netip.Addr{a1})
  527. assert.True(t, ok)
  528. assert.Equal(t, out, a1)
  529. out, ok = findNetworkUnion([]netip.Prefix{tenDot, oneSevenTwo, fe80}, []netip.Addr{a1, afe81})
  530. assert.True(t, ok)
  531. assert.Equal(t, out, a1)
  532. //ordering
  533. out, ok = findNetworkUnion([]netip.Prefix{tenDot, oneSevenTwo, fe80}, []netip.Addr{afe81, a1})
  534. assert.True(t, ok)
  535. assert.Equal(t, out, a1)
  536. out, ok = findNetworkUnion([]netip.Prefix{fe80, tenDot, oneSevenTwo}, []netip.Addr{afe81, a1})
  537. assert.True(t, ok)
  538. assert.Equal(t, out, afe81)
  539. //some mismatches
  540. out, ok = findNetworkUnion([]netip.Prefix{tenDot, oneSevenTwo, fe80}, []netip.Addr{afe81})
  541. assert.True(t, ok)
  542. assert.Equal(t, out, afe81)
  543. out, ok = findNetworkUnion([]netip.Prefix{oneSevenTwo, fe80}, []netip.Addr{a1, afe81})
  544. assert.True(t, ok)
  545. assert.Equal(t, out, afe81)
  546. //falsey cases
  547. out, ok = findNetworkUnion([]netip.Prefix{oneSevenTwo, fe80}, []netip.Addr{a1})
  548. assert.False(t, ok)
  549. out, ok = findNetworkUnion([]netip.Prefix{fc00, fe80}, []netip.Addr{a1})
  550. assert.False(t, ok)
  551. out, ok = findNetworkUnion([]netip.Prefix{oneSevenTwo, fc00}, []netip.Addr{a1, afe81})
  552. assert.False(t, ok)
  553. out, ok = findNetworkUnion([]netip.Prefix{fc00}, []netip.Addr{a1, afe81})
  554. assert.False(t, ok)
  555. }
  556. func TestLighthouse_Dont_Delete_Static_Hosts(t *testing.T) {
  557. l := test.NewLogger()
  558. myUdpAddr2 := netip.MustParseAddrPort("1.2.3.4:4242")
  559. testSameHostNotStatic := netip.MustParseAddr("10.128.0.41")
  560. testStaticHost := netip.MustParseAddr("10.128.0.42")
  561. //myVpnIp := netip.MustParseAddr("10.128.0.2")
  562. c := config.NewC(l)
  563. lh1 := "10.128.0.2"
  564. c.Settings["lighthouse"] = map[string]any{
  565. "hosts": []any{lh1},
  566. "interval": "1s",
  567. }
  568. c.Settings["listen"] = map[string]any{"port": 4242}
  569. c.Settings["static_host_map"] = map[string]any{
  570. lh1: []any{"1.1.1.1:4242"},
  571. "10.128.0.42": []any{"1.2.3.4:4242"},
  572. }
  573. myVpnNet := netip.MustParsePrefix("10.128.0.1/24")
  574. cs := testCertState(myVpnNet)
  575. lh, err := NewLightHouseFromConfig(t.Context(), l, c, cs, nil, nil)
  576. require.NoError(t, err)
  577. lh.ifce = &mockEncWriter{}
  578. //test that we actually have the static entry:
  579. out := lh.Query(testStaticHost)
  580. assert.NotNil(t, out)
  581. assert.Equal(t, out.vpnAddrs[0], testStaticHost)
  582. out.Rebuild([]netip.Prefix{}) //why tho
  583. assert.Equal(t, out.addrs[0], myUdpAddr2)
  584. //bolt on a lower numbered primary IP
  585. am := lh.unlockedGetRemoteList([]netip.Addr{testStaticHost})
  586. am.vpnAddrs = []netip.Addr{testSameHostNotStatic, testStaticHost}
  587. lh.addrMap[testSameHostNotStatic] = am
  588. out.Rebuild([]netip.Prefix{}) //???
  589. //test that we actually have the static entry:
  590. out = lh.Query(testStaticHost)
  591. assert.NotNil(t, out)
  592. assert.Equal(t, out.vpnAddrs[0], testSameHostNotStatic)
  593. assert.Equal(t, out.vpnAddrs[1], testStaticHost)
  594. assert.Equal(t, out.addrs[0], myUdpAddr2)
  595. //test that we actually have the static entry for BOTH:
  596. out2 := lh.Query(testSameHostNotStatic)
  597. assert.Same(t, out2, out)
  598. //now do the delete
  599. lh.DeleteVpnAddrs([]netip.Addr{testSameHostNotStatic, testStaticHost})
  600. //verify
  601. out = lh.Query(testSameHostNotStatic)
  602. assert.NotNil(t, out)
  603. if out == nil {
  604. t.Fatal("expected non-nil query for the static host")
  605. }
  606. assert.Equal(t, out.vpnAddrs[0], testSameHostNotStatic)
  607. assert.Equal(t, out.vpnAddrs[1], testStaticHost)
  608. assert.Equal(t, out.addrs[0], myUdpAddr2)
  609. }
  610. func TestLighthouse_DeletesWork(t *testing.T) {
  611. l := test.NewLogger()
  612. myUdpAddr2 := netip.MustParseAddrPort("1.2.3.4:4242")
  613. testHost := netip.MustParseAddr("10.128.0.42")
  614. c := config.NewC(l)
  615. lh1 := "10.128.0.2"
  616. c.Settings["lighthouse"] = map[string]any{
  617. "hosts": []any{lh1},
  618. "interval": "1s",
  619. }
  620. c.Settings["listen"] = map[string]any{"port": 4242}
  621. c.Settings["static_host_map"] = map[string]any{
  622. lh1: []any{"1.1.1.1:4242"},
  623. }
  624. myVpnNet := netip.MustParsePrefix("10.128.0.1/24")
  625. cs := testCertState(myVpnNet)
  626. lh, err := NewLightHouseFromConfig(t.Context(), l, c, cs, nil, nil)
  627. require.NoError(t, err)
  628. lh.ifce = &mockEncWriter{}
  629. //insert the host
  630. am := lh.unlockedGetRemoteList([]netip.Addr{testHost})
  631. am.vpnAddrs = []netip.Addr{testHost}
  632. am.addrs = []netip.AddrPort{myUdpAddr2}
  633. lh.addrMap[testHost] = am
  634. am.Rebuild([]netip.Prefix{}) //???
  635. //test that we actually have the entry:
  636. out := lh.Query(testHost)
  637. assert.NotNil(t, out)
  638. assert.Equal(t, out.vpnAddrs[0], testHost)
  639. out.Rebuild([]netip.Prefix{}) //why tho
  640. assert.Equal(t, out.addrs[0], myUdpAddr2)
  641. //now do the delete
  642. lh.DeleteVpnAddrs([]netip.Addr{testHost})
  643. //verify
  644. out = lh.Query(testHost)
  645. assert.Nil(t, out)
  646. }