lighthouse_test.go 26 KB

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