3
0

lighthouse_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. package nebula
  2. import (
  3. "context"
  4. "encoding/binary"
  5. "fmt"
  6. "net/netip"
  7. "testing"
  8. "github.com/slackhq/nebula/config"
  9. "github.com/slackhq/nebula/header"
  10. "github.com/slackhq/nebula/test"
  11. "github.com/stretchr/testify/assert"
  12. "gopkg.in/yaml.v2"
  13. )
  14. //TODO: Add a test to ensure udpAddr is copied and not reused
  15. func TestOldIPv4Only(t *testing.T) {
  16. // This test ensures our new ipv6 enabled LH protobuf IpAndPorts works with the old style to enable backwards compatibility
  17. b := []byte{8, 129, 130, 132, 80, 16, 10}
  18. var m Ip4AndPort
  19. err := m.Unmarshal(b)
  20. assert.NoError(t, err)
  21. ip := netip.MustParseAddr("10.1.1.1")
  22. bp := ip.As4()
  23. assert.Equal(t, binary.BigEndian.Uint32(bp[:]), m.GetIp())
  24. }
  25. func TestNewLhQuery(t *testing.T) {
  26. myIp, err := netip.ParseAddr("192.1.1.1")
  27. assert.NoError(t, err)
  28. // Generating a new lh query should work
  29. a := NewLhQueryByInt(myIp)
  30. // The result should be a nebulameta protobuf
  31. assert.IsType(t, &NebulaMeta{}, a)
  32. // It should also Marshal fine
  33. b, err := a.Marshal()
  34. assert.Nil(t, err)
  35. // and then Unmarshal fine
  36. n := &NebulaMeta{}
  37. err = n.Unmarshal(b)
  38. assert.Nil(t, err)
  39. }
  40. func Test_lhStaticMapping(t *testing.T) {
  41. l := test.NewLogger()
  42. myVpnNet := netip.MustParsePrefix("10.128.0.1/16")
  43. lh1 := "10.128.0.2"
  44. c := config.NewC(l)
  45. c.Settings["lighthouse"] = map[interface{}]interface{}{"hosts": []interface{}{lh1}}
  46. c.Settings["static_host_map"] = map[interface{}]interface{}{lh1: []interface{}{"1.1.1.1:4242"}}
  47. _, err := NewLightHouseFromConfig(context.Background(), l, c, myVpnNet, nil, nil)
  48. assert.Nil(t, err)
  49. lh2 := "10.128.0.3"
  50. c = config.NewC(l)
  51. c.Settings["lighthouse"] = map[interface{}]interface{}{"hosts": []interface{}{lh1, lh2}}
  52. c.Settings["static_host_map"] = map[interface{}]interface{}{lh1: []interface{}{"100.1.1.1:4242"}}
  53. _, err = NewLightHouseFromConfig(context.Background(), l, c, myVpnNet, nil, nil)
  54. assert.EqualError(t, err, "lighthouse 10.128.0.3 does not have a static_host_map entry")
  55. }
  56. func TestReloadLighthouseInterval(t *testing.T) {
  57. l := test.NewLogger()
  58. myVpnNet := netip.MustParsePrefix("10.128.0.1/16")
  59. lh1 := "10.128.0.2"
  60. c := config.NewC(l)
  61. c.Settings["lighthouse"] = map[interface{}]interface{}{
  62. "hosts": []interface{}{lh1},
  63. "interval": "1s",
  64. }
  65. c.Settings["static_host_map"] = map[interface{}]interface{}{lh1: []interface{}{"1.1.1.1:4242"}}
  66. lh, err := NewLightHouseFromConfig(context.Background(), l, c, myVpnNet, nil, nil)
  67. assert.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. assert.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. assert.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. assert.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. c := config.NewC(l)
  83. lh, err := NewLightHouseFromConfig(context.Background(), l, c, myVpnNet, nil, nil)
  84. if !assert.NoError(b, err) {
  85. b.Fatal()
  86. }
  87. hAddr := netip.MustParseAddrPort("4.5.6.7:12345")
  88. hAddr2 := netip.MustParseAddrPort("4.5.6.7:12346")
  89. vpnIp3 := netip.MustParseAddr("0.0.0.3")
  90. lh.addrMap[vpnIp3] = NewRemoteList(nil)
  91. lh.addrMap[vpnIp3].unlockedSetV4(
  92. vpnIp3,
  93. vpnIp3,
  94. []*Ip4AndPort{
  95. NewIp4AndPortFromNetIP(hAddr.Addr(), hAddr.Port()),
  96. NewIp4AndPortFromNetIP(hAddr2.Addr(), hAddr2.Port()),
  97. },
  98. func(netip.Addr, *Ip4AndPort) bool { return true },
  99. )
  100. rAddr := netip.MustParseAddrPort("1.2.2.3:12345")
  101. rAddr2 := netip.MustParseAddrPort("1.2.2.3:12346")
  102. vpnIp2 := netip.MustParseAddr("0.0.0.3")
  103. lh.addrMap[vpnIp2] = NewRemoteList(nil)
  104. lh.addrMap[vpnIp2].unlockedSetV4(
  105. vpnIp3,
  106. vpnIp3,
  107. []*Ip4AndPort{
  108. NewIp4AndPortFromNetIP(rAddr.Addr(), rAddr.Port()),
  109. NewIp4AndPortFromNetIP(rAddr2.Addr(), rAddr2.Port()),
  110. },
  111. func(netip.Addr, *Ip4AndPort) bool { return true },
  112. )
  113. mw := &mockEncWriter{}
  114. b.Run("notfound", func(b *testing.B) {
  115. lhh := lh.NewRequestHandler()
  116. req := &NebulaMeta{
  117. Type: NebulaMeta_HostQuery,
  118. Details: &NebulaMetaDetails{
  119. VpnIp: 4,
  120. Ip4AndPorts: nil,
  121. },
  122. }
  123. p, err := req.Marshal()
  124. assert.NoError(b, err)
  125. for n := 0; n < b.N; n++ {
  126. lhh.HandleRequest(rAddr, vpnIp2, p, mw)
  127. }
  128. })
  129. b.Run("found", func(b *testing.B) {
  130. lhh := lh.NewRequestHandler()
  131. req := &NebulaMeta{
  132. Type: NebulaMeta_HostQuery,
  133. Details: &NebulaMetaDetails{
  134. VpnIp: 3,
  135. Ip4AndPorts: nil,
  136. },
  137. }
  138. p, err := req.Marshal()
  139. assert.NoError(b, err)
  140. for n := 0; n < b.N; n++ {
  141. lhh.HandleRequest(rAddr, vpnIp2, p, mw)
  142. }
  143. })
  144. }
  145. func TestLighthouse_Memory(t *testing.T) {
  146. l := test.NewLogger()
  147. myUdpAddr0 := netip.MustParseAddrPort("10.0.0.2:4242")
  148. myUdpAddr1 := netip.MustParseAddrPort("192.168.0.2:4242")
  149. myUdpAddr2 := netip.MustParseAddrPort("172.16.0.2:4242")
  150. myUdpAddr3 := netip.MustParseAddrPort("100.152.0.2:4242")
  151. myUdpAddr4 := netip.MustParseAddrPort("24.15.0.2:4242")
  152. myUdpAddr5 := netip.MustParseAddrPort("192.168.0.2:4243")
  153. myUdpAddr6 := netip.MustParseAddrPort("192.168.0.2:4244")
  154. myUdpAddr7 := netip.MustParseAddrPort("192.168.0.2:4245")
  155. myUdpAddr8 := netip.MustParseAddrPort("192.168.0.2:4246")
  156. myUdpAddr9 := netip.MustParseAddrPort("192.168.0.2:4247")
  157. myUdpAddr10 := netip.MustParseAddrPort("192.168.0.2:4248")
  158. myUdpAddr11 := netip.MustParseAddrPort("192.168.0.2:4249")
  159. myVpnIp := netip.MustParseAddr("10.128.0.2")
  160. theirUdpAddr0 := netip.MustParseAddrPort("10.0.0.3:4242")
  161. theirUdpAddr1 := netip.MustParseAddrPort("192.168.0.3:4242")
  162. theirUdpAddr2 := netip.MustParseAddrPort("172.16.0.3:4242")
  163. theirUdpAddr3 := netip.MustParseAddrPort("100.152.0.3:4242")
  164. theirUdpAddr4 := netip.MustParseAddrPort("24.15.0.3:4242")
  165. theirVpnIp := netip.MustParseAddr("10.128.0.3")
  166. c := config.NewC(l)
  167. c.Settings["lighthouse"] = map[interface{}]interface{}{"am_lighthouse": true}
  168. c.Settings["listen"] = map[interface{}]interface{}{"port": 4242}
  169. lh, err := NewLightHouseFromConfig(context.Background(), l, c, netip.MustParsePrefix("10.128.0.1/24"), nil, nil)
  170. assert.NoError(t, err)
  171. lhh := lh.NewRequestHandler()
  172. // Test that my first update responds with just that
  173. newLHHostUpdate(myUdpAddr0, myVpnIp, []netip.AddrPort{myUdpAddr1, myUdpAddr2}, lhh)
  174. r := newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  175. assertIp4InArray(t, r.msg.Details.Ip4AndPorts, myUdpAddr1, myUdpAddr2)
  176. // Ensure we don't accumulate addresses
  177. newLHHostUpdate(myUdpAddr0, myVpnIp, []netip.AddrPort{myUdpAddr3}, lhh)
  178. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  179. assertIp4InArray(t, r.msg.Details.Ip4AndPorts, myUdpAddr3)
  180. // Grow it back to 2
  181. newLHHostUpdate(myUdpAddr0, myVpnIp, []netip.AddrPort{myUdpAddr1, myUdpAddr4}, lhh)
  182. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  183. assertIp4InArray(t, r.msg.Details.Ip4AndPorts, myUdpAddr1, myUdpAddr4)
  184. // Update a different host and ask about it
  185. newLHHostUpdate(theirUdpAddr0, theirVpnIp, []netip.AddrPort{theirUdpAddr1, theirUdpAddr2, theirUdpAddr3, theirUdpAddr4}, lhh)
  186. r = newLHHostRequest(theirUdpAddr0, theirVpnIp, theirVpnIp, lhh)
  187. assertIp4InArray(t, r.msg.Details.Ip4AndPorts, theirUdpAddr1, theirUdpAddr2, theirUdpAddr3, theirUdpAddr4)
  188. // Have both hosts ask about the other
  189. r = newLHHostRequest(theirUdpAddr0, theirVpnIp, myVpnIp, lhh)
  190. assertIp4InArray(t, r.msg.Details.Ip4AndPorts, myUdpAddr1, myUdpAddr4)
  191. r = newLHHostRequest(myUdpAddr0, myVpnIp, theirVpnIp, lhh)
  192. assertIp4InArray(t, r.msg.Details.Ip4AndPorts, theirUdpAddr1, theirUdpAddr2, theirUdpAddr3, theirUdpAddr4)
  193. // Make sure we didn't get changed
  194. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  195. assertIp4InArray(t, r.msg.Details.Ip4AndPorts, myUdpAddr1, myUdpAddr4)
  196. // Ensure proper ordering and limiting
  197. // Send 12 addrs, get 10 back, the last 2 removed, allowing the duplicate to remain (clients dedupe)
  198. newLHHostUpdate(
  199. myUdpAddr0,
  200. myVpnIp,
  201. []netip.AddrPort{
  202. myUdpAddr1,
  203. myUdpAddr2,
  204. myUdpAddr3,
  205. myUdpAddr4,
  206. myUdpAddr5,
  207. myUdpAddr5, //Duplicated on purpose
  208. myUdpAddr6,
  209. myUdpAddr7,
  210. myUdpAddr8,
  211. myUdpAddr9,
  212. myUdpAddr10,
  213. myUdpAddr11, // This should get cut
  214. }, lhh)
  215. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  216. assertIp4InArray(
  217. t,
  218. r.msg.Details.Ip4AndPorts,
  219. myUdpAddr1, myUdpAddr2, myUdpAddr3, myUdpAddr4, myUdpAddr5, myUdpAddr5, myUdpAddr6, myUdpAddr7, myUdpAddr8, myUdpAddr9,
  220. )
  221. // Make sure we won't add ips in our vpn network
  222. bad1 := netip.MustParseAddrPort("10.128.0.99:4242")
  223. bad2 := netip.MustParseAddrPort("10.128.0.100:4242")
  224. good := netip.MustParseAddrPort("1.128.0.99:4242")
  225. newLHHostUpdate(myUdpAddr0, myVpnIp, []netip.AddrPort{bad1, bad2, good}, lhh)
  226. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  227. assertIp4InArray(t, r.msg.Details.Ip4AndPorts, good)
  228. }
  229. func TestLighthouse_reload(t *testing.T) {
  230. l := test.NewLogger()
  231. c := config.NewC(l)
  232. c.Settings["lighthouse"] = map[interface{}]interface{}{"am_lighthouse": true}
  233. c.Settings["listen"] = map[interface{}]interface{}{"port": 4242}
  234. lh, err := NewLightHouseFromConfig(context.Background(), l, c, netip.MustParsePrefix("10.128.0.1/24"), nil, nil)
  235. assert.NoError(t, err)
  236. nc := map[interface{}]interface{}{
  237. "static_host_map": map[interface{}]interface{}{
  238. "10.128.0.2": []interface{}{"1.1.1.1:4242"},
  239. },
  240. }
  241. rc, err := yaml.Marshal(nc)
  242. assert.NoError(t, err)
  243. c.ReloadConfigString(string(rc))
  244. err = lh.reload(c, false)
  245. assert.NoError(t, err)
  246. }
  247. func newLHHostRequest(fromAddr netip.AddrPort, myVpnIp, queryVpnIp netip.Addr, lhh *LightHouseHandler) testLhReply {
  248. //TODO: IPV6-WORK
  249. bip := queryVpnIp.As4()
  250. req := &NebulaMeta{
  251. Type: NebulaMeta_HostQuery,
  252. Details: &NebulaMetaDetails{
  253. VpnIp: binary.BigEndian.Uint32(bip[:]),
  254. },
  255. }
  256. b, err := req.Marshal()
  257. if err != nil {
  258. panic(err)
  259. }
  260. filter := NebulaMeta_HostQueryReply
  261. w := &testEncWriter{
  262. metaFilter: &filter,
  263. }
  264. lhh.HandleRequest(fromAddr, myVpnIp, b, w)
  265. return w.lastReply
  266. }
  267. func newLHHostUpdate(fromAddr netip.AddrPort, vpnIp netip.Addr, addrs []netip.AddrPort, lhh *LightHouseHandler) {
  268. //TODO: IPV6-WORK
  269. bip := vpnIp.As4()
  270. req := &NebulaMeta{
  271. Type: NebulaMeta_HostUpdateNotification,
  272. Details: &NebulaMetaDetails{
  273. VpnIp: binary.BigEndian.Uint32(bip[:]),
  274. Ip4AndPorts: make([]*Ip4AndPort, len(addrs)),
  275. },
  276. }
  277. for k, v := range addrs {
  278. req.Details.Ip4AndPorts[k] = NewIp4AndPortFromNetIP(v.Addr(), v.Port())
  279. }
  280. b, err := req.Marshal()
  281. if err != nil {
  282. panic(err)
  283. }
  284. w := &testEncWriter{}
  285. lhh.HandleRequest(fromAddr, vpnIp, b, w)
  286. }
  287. //TODO: this is a RemoteList test
  288. //func Test_lhRemoteAllowList(t *testing.T) {
  289. // l := NewLogger()
  290. // c := NewConfig(l)
  291. // c.Settings["remoteallowlist"] = map[interface{}]interface{}{
  292. // "10.20.0.0/12": false,
  293. // }
  294. // allowList, err := c.GetAllowList("remoteallowlist", false)
  295. // assert.Nil(t, err)
  296. //
  297. // lh1 := "10.128.0.2"
  298. // lh1IP := net.ParseIP(lh1)
  299. //
  300. // udpServer, _ := NewListener(l, "0.0.0.0", 0, true)
  301. //
  302. // lh := NewLightHouse(l, true, &net.IPNet{IP: net.IP{0, 0, 0, 1}, Mask: net.IPMask{255, 255, 255, 0}}, []uint32{ip2int(lh1IP)}, 10, 10003, udpServer, false, 1, false)
  303. // lh.SetRemoteAllowList(allowList)
  304. //
  305. // // A disallowed ip should not enter the cache but we should end up with an empty entry in the addrMap
  306. // remote1IP := net.ParseIP("10.20.0.3")
  307. // remotes := lh.unlockedGetRemoteList(ip2int(remote1IP))
  308. // remotes.unlockedPrependV4(ip2int(remote1IP), NewIp4AndPort(remote1IP, 4242))
  309. // assert.NotNil(t, lh.addrMap[ip2int(remote1IP)])
  310. // assert.Empty(t, lh.addrMap[ip2int(remote1IP)].CopyAddrs([]*net.IPNet{}))
  311. //
  312. // // Make sure a good ip enters the cache and addrMap
  313. // remote2IP := net.ParseIP("10.128.0.3")
  314. // remote2UDPAddr := NewUDPAddr(remote2IP, uint16(4242))
  315. // lh.addRemoteV4(ip2int(remote2IP), ip2int(remote2IP), NewIp4AndPort(remote2UDPAddr.IP, uint32(remote2UDPAddr.Port)), false, false)
  316. // assertUdpAddrInArray(t, lh.addrMap[ip2int(remote2IP)].CopyAddrs([]*net.IPNet{}), remote2UDPAddr)
  317. //
  318. // // Another good ip gets into the cache, ordering is inverted
  319. // remote3IP := net.ParseIP("10.128.0.4")
  320. // remote3UDPAddr := NewUDPAddr(remote3IP, uint16(4243))
  321. // lh.addRemoteV4(ip2int(remote2IP), ip2int(remote2IP), NewIp4AndPort(remote3UDPAddr.IP, uint32(remote3UDPAddr.Port)), false, false)
  322. // assertUdpAddrInArray(t, lh.addrMap[ip2int(remote2IP)].CopyAddrs([]*net.IPNet{}), remote2UDPAddr, remote3UDPAddr)
  323. //
  324. // // If we exceed the length limit we should only have the most recent addresses
  325. // addedAddrs := []*udpAddr{}
  326. // for i := 0; i < 11; i++ {
  327. // remoteUDPAddr := NewUDPAddr(net.IP{10, 128, 0, 4}, uint16(4243+i))
  328. // lh.addRemoteV4(ip2int(remote2IP), ip2int(remote2IP), NewIp4AndPort(remoteUDPAddr.IP, uint32(remoteUDPAddr.Port)), false, false)
  329. // // The first entry here is a duplicate, don't add it to the assert list
  330. // if i != 0 {
  331. // addedAddrs = append(addedAddrs, remoteUDPAddr)
  332. // }
  333. // }
  334. //
  335. // // We should only have the last 10 of what we tried to add
  336. // assert.True(t, len(addedAddrs) >= 10, "We should have tried to add at least 10 addresses")
  337. // assertUdpAddrInArray(
  338. // t,
  339. // lh.addrMap[ip2int(remote2IP)].CopyAddrs([]*net.IPNet{}),
  340. // addedAddrs[0],
  341. // addedAddrs[1],
  342. // addedAddrs[2],
  343. // addedAddrs[3],
  344. // addedAddrs[4],
  345. // addedAddrs[5],
  346. // addedAddrs[6],
  347. // addedAddrs[7],
  348. // addedAddrs[8],
  349. // addedAddrs[9],
  350. // )
  351. //}
  352. type testLhReply struct {
  353. nebType header.MessageType
  354. nebSubType header.MessageSubType
  355. vpnIp netip.Addr
  356. msg *NebulaMeta
  357. }
  358. type testEncWriter struct {
  359. lastReply testLhReply
  360. metaFilter *NebulaMeta_MessageType
  361. }
  362. func (tw *testEncWriter) SendVia(via *HostInfo, relay *Relay, ad, nb, out []byte, nocopy bool) {
  363. }
  364. func (tw *testEncWriter) Handshake(vpnIp netip.Addr) {
  365. }
  366. func (tw *testEncWriter) SendMessageToHostInfo(t header.MessageType, st header.MessageSubType, hostinfo *HostInfo, p, _, _ []byte) {
  367. msg := &NebulaMeta{}
  368. err := msg.Unmarshal(p)
  369. if tw.metaFilter == nil || msg.Type == *tw.metaFilter {
  370. tw.lastReply = testLhReply{
  371. nebType: t,
  372. nebSubType: st,
  373. vpnIp: hostinfo.vpnIp,
  374. msg: msg,
  375. }
  376. }
  377. if err != nil {
  378. panic(err)
  379. }
  380. }
  381. func (tw *testEncWriter) SendMessageToVpnIp(t header.MessageType, st header.MessageSubType, vpnIp netip.Addr, p, _, _ []byte) {
  382. msg := &NebulaMeta{}
  383. err := msg.Unmarshal(p)
  384. if tw.metaFilter == nil || msg.Type == *tw.metaFilter {
  385. tw.lastReply = testLhReply{
  386. nebType: t,
  387. nebSubType: st,
  388. vpnIp: vpnIp,
  389. msg: msg,
  390. }
  391. }
  392. if err != nil {
  393. panic(err)
  394. }
  395. }
  396. // assertIp4InArray asserts every address in want is at the same position in have and that the lengths match
  397. func assertIp4InArray(t *testing.T, have []*Ip4AndPort, want ...netip.AddrPort) {
  398. if !assert.Len(t, have, len(want)) {
  399. return
  400. }
  401. for k, w := range want {
  402. //TODO: IPV6-WORK
  403. h := AddrPortFromIp4AndPort(have[k])
  404. if !(h == w) {
  405. assert.Fail(t, fmt.Sprintf("Response did not contain: %v at %v, found %v", w, k, h))
  406. }
  407. }
  408. }