1
0

lighthouse_test.go 24 KB

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