lighthouse_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. package nebula
  2. import (
  3. "fmt"
  4. "net"
  5. "testing"
  6. "github.com/golang/protobuf/proto"
  7. "github.com/slackhq/nebula/header"
  8. "github.com/slackhq/nebula/iputil"
  9. "github.com/slackhq/nebula/udp"
  10. "github.com/slackhq/nebula/util"
  11. "github.com/stretchr/testify/assert"
  12. )
  13. //TODO: Add a test to ensure udpAddr is copied and not reused
  14. func TestOldIPv4Only(t *testing.T) {
  15. // This test ensures our new ipv6 enabled LH protobuf IpAndPorts works with the old style to enable backwards compatibility
  16. b := []byte{8, 129, 130, 132, 80, 16, 10}
  17. var m Ip4AndPort
  18. err := proto.Unmarshal(b, &m)
  19. assert.NoError(t, err)
  20. assert.Equal(t, "10.1.1.1", iputil.VpnIp(m.GetIp()).String())
  21. }
  22. func TestNewLhQuery(t *testing.T) {
  23. myIp := net.ParseIP("192.1.1.1")
  24. myIpint := iputil.Ip2VpnIp(myIp)
  25. // Generating a new lh query should work
  26. a := NewLhQueryByInt(myIpint)
  27. // The result should be a nebulameta protobuf
  28. assert.IsType(t, &NebulaMeta{}, a)
  29. // It should also Marshal fine
  30. b, err := proto.Marshal(a)
  31. assert.Nil(t, err)
  32. // and then Unmarshal fine
  33. n := &NebulaMeta{}
  34. err = proto.Unmarshal(b, n)
  35. assert.Nil(t, err)
  36. }
  37. func Test_lhStaticMapping(t *testing.T) {
  38. l := util.NewTestLogger()
  39. lh1 := "10.128.0.2"
  40. lh1IP := net.ParseIP(lh1)
  41. udpServer, _ := udp.NewListener(l, "0.0.0.0", 0, true, 2)
  42. meh := NewLightHouse(l, true, &net.IPNet{IP: net.IP{0, 0, 0, 1}, Mask: net.IPMask{255, 255, 255, 255}}, []iputil.VpnIp{iputil.Ip2VpnIp(lh1IP)}, 10, 10003, udpServer, false, 1, false)
  43. meh.AddStaticRemote(iputil.Ip2VpnIp(lh1IP), udp.NewAddr(lh1IP, uint16(4242)))
  44. err := meh.ValidateLHStaticEntries()
  45. assert.Nil(t, err)
  46. lh2 := "10.128.0.3"
  47. lh2IP := net.ParseIP(lh2)
  48. meh = NewLightHouse(l, true, &net.IPNet{IP: net.IP{0, 0, 0, 1}, Mask: net.IPMask{255, 255, 255, 255}}, []iputil.VpnIp{iputil.Ip2VpnIp(lh1IP), iputil.Ip2VpnIp(lh2IP)}, 10, 10003, udpServer, false, 1, false)
  49. meh.AddStaticRemote(iputil.Ip2VpnIp(lh1IP), udp.NewAddr(lh1IP, uint16(4242)))
  50. err = meh.ValidateLHStaticEntries()
  51. assert.EqualError(t, err, "Lighthouse 10.128.0.3 does not have a static_host_map entry")
  52. }
  53. func BenchmarkLighthouseHandleRequest(b *testing.B) {
  54. l := util.NewTestLogger()
  55. lh1 := "10.128.0.2"
  56. lh1IP := net.ParseIP(lh1)
  57. udpServer, _ := udp.NewListener(l, "0.0.0.0", 0, true, 2)
  58. lh := NewLightHouse(l, true, &net.IPNet{IP: net.IP{0, 0, 0, 1}, Mask: net.IPMask{0, 0, 0, 0}}, []iputil.VpnIp{iputil.Ip2VpnIp(lh1IP)}, 10, 10003, udpServer, false, 1, false)
  59. hAddr := udp.NewAddrFromString("4.5.6.7:12345")
  60. hAddr2 := udp.NewAddrFromString("4.5.6.7:12346")
  61. lh.addrMap[3] = NewRemoteList()
  62. lh.addrMap[3].unlockedSetV4(
  63. 3,
  64. 3,
  65. []*Ip4AndPort{
  66. NewIp4AndPort(hAddr.IP, uint32(hAddr.Port)),
  67. NewIp4AndPort(hAddr2.IP, uint32(hAddr2.Port)),
  68. },
  69. func(iputil.VpnIp, *Ip4AndPort) bool { return true },
  70. )
  71. rAddr := udp.NewAddrFromString("1.2.2.3:12345")
  72. rAddr2 := udp.NewAddrFromString("1.2.2.3:12346")
  73. lh.addrMap[2] = NewRemoteList()
  74. lh.addrMap[2].unlockedSetV4(
  75. 3,
  76. 3,
  77. []*Ip4AndPort{
  78. NewIp4AndPort(rAddr.IP, uint32(rAddr.Port)),
  79. NewIp4AndPort(rAddr2.IP, uint32(rAddr2.Port)),
  80. },
  81. func(iputil.VpnIp, *Ip4AndPort) bool { return true },
  82. )
  83. mw := &mockEncWriter{}
  84. b.Run("notfound", func(b *testing.B) {
  85. lhh := lh.NewRequestHandler()
  86. req := &NebulaMeta{
  87. Type: NebulaMeta_HostQuery,
  88. Details: &NebulaMetaDetails{
  89. VpnIp: 4,
  90. Ip4AndPorts: nil,
  91. },
  92. }
  93. p, err := proto.Marshal(req)
  94. assert.NoError(b, err)
  95. for n := 0; n < b.N; n++ {
  96. lhh.HandleRequest(rAddr, 2, p, mw)
  97. }
  98. })
  99. b.Run("found", func(b *testing.B) {
  100. lhh := lh.NewRequestHandler()
  101. req := &NebulaMeta{
  102. Type: NebulaMeta_HostQuery,
  103. Details: &NebulaMetaDetails{
  104. VpnIp: 3,
  105. Ip4AndPorts: nil,
  106. },
  107. }
  108. p, err := proto.Marshal(req)
  109. assert.NoError(b, err)
  110. for n := 0; n < b.N; n++ {
  111. lhh.HandleRequest(rAddr, 2, p, mw)
  112. }
  113. })
  114. }
  115. func TestLighthouse_Memory(t *testing.T) {
  116. l := util.NewTestLogger()
  117. myUdpAddr0 := &udp.Addr{IP: net.ParseIP("10.0.0.2"), Port: 4242}
  118. myUdpAddr1 := &udp.Addr{IP: net.ParseIP("192.168.0.2"), Port: 4242}
  119. myUdpAddr2 := &udp.Addr{IP: net.ParseIP("172.16.0.2"), Port: 4242}
  120. myUdpAddr3 := &udp.Addr{IP: net.ParseIP("100.152.0.2"), Port: 4242}
  121. myUdpAddr4 := &udp.Addr{IP: net.ParseIP("24.15.0.2"), Port: 4242}
  122. myUdpAddr5 := &udp.Addr{IP: net.ParseIP("192.168.0.2"), Port: 4243}
  123. myUdpAddr6 := &udp.Addr{IP: net.ParseIP("192.168.0.2"), Port: 4244}
  124. myUdpAddr7 := &udp.Addr{IP: net.ParseIP("192.168.0.2"), Port: 4245}
  125. myUdpAddr8 := &udp.Addr{IP: net.ParseIP("192.168.0.2"), Port: 4246}
  126. myUdpAddr9 := &udp.Addr{IP: net.ParseIP("192.168.0.2"), Port: 4247}
  127. myUdpAddr10 := &udp.Addr{IP: net.ParseIP("192.168.0.2"), Port: 4248}
  128. myUdpAddr11 := &udp.Addr{IP: net.ParseIP("192.168.0.2"), Port: 4249}
  129. myVpnIp := iputil.Ip2VpnIp(net.ParseIP("10.128.0.2"))
  130. theirUdpAddr0 := &udp.Addr{IP: net.ParseIP("10.0.0.3"), Port: 4242}
  131. theirUdpAddr1 := &udp.Addr{IP: net.ParseIP("192.168.0.3"), Port: 4242}
  132. theirUdpAddr2 := &udp.Addr{IP: net.ParseIP("172.16.0.3"), Port: 4242}
  133. theirUdpAddr3 := &udp.Addr{IP: net.ParseIP("100.152.0.3"), Port: 4242}
  134. theirUdpAddr4 := &udp.Addr{IP: net.ParseIP("24.15.0.3"), Port: 4242}
  135. theirVpnIp := iputil.Ip2VpnIp(net.ParseIP("10.128.0.3"))
  136. udpServer, _ := udp.NewListener(l, "0.0.0.0", 0, true, 2)
  137. lh := NewLightHouse(l, true, &net.IPNet{IP: net.IP{10, 128, 0, 1}, Mask: net.IPMask{255, 255, 255, 0}}, []iputil.VpnIp{}, 10, 10003, udpServer, false, 1, false)
  138. lhh := lh.NewRequestHandler()
  139. // Test that my first update responds with just that
  140. newLHHostUpdate(myUdpAddr0, myVpnIp, []*udp.Addr{myUdpAddr1, myUdpAddr2}, lhh)
  141. r := newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  142. assertIp4InArray(t, r.msg.Details.Ip4AndPorts, myUdpAddr1, myUdpAddr2)
  143. // Ensure we don't accumulate addresses
  144. newLHHostUpdate(myUdpAddr0, myVpnIp, []*udp.Addr{myUdpAddr3}, lhh)
  145. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  146. assertIp4InArray(t, r.msg.Details.Ip4AndPorts, myUdpAddr3)
  147. // Grow it back to 2
  148. newLHHostUpdate(myUdpAddr0, myVpnIp, []*udp.Addr{myUdpAddr1, myUdpAddr4}, lhh)
  149. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  150. assertIp4InArray(t, r.msg.Details.Ip4AndPorts, myUdpAddr1, myUdpAddr4)
  151. // Update a different host
  152. newLHHostUpdate(theirUdpAddr0, theirVpnIp, []*udp.Addr{theirUdpAddr1, theirUdpAddr2, theirUdpAddr3, theirUdpAddr4}, lhh)
  153. r = newLHHostRequest(theirUdpAddr0, theirVpnIp, myVpnIp, lhh)
  154. assertIp4InArray(t, r.msg.Details.Ip4AndPorts, theirUdpAddr1, theirUdpAddr2, theirUdpAddr3, theirUdpAddr4)
  155. // Make sure we didn't get changed
  156. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  157. assertIp4InArray(t, r.msg.Details.Ip4AndPorts, myUdpAddr1, myUdpAddr4)
  158. // Ensure proper ordering and limiting
  159. // Send 12 addrs, get 10 back, the last 2 removed, allowing the duplicate to remain (clients dedupe)
  160. newLHHostUpdate(
  161. myUdpAddr0,
  162. myVpnIp,
  163. []*udp.Addr{
  164. myUdpAddr1,
  165. myUdpAddr2,
  166. myUdpAddr3,
  167. myUdpAddr4,
  168. myUdpAddr5,
  169. myUdpAddr5, //Duplicated on purpose
  170. myUdpAddr6,
  171. myUdpAddr7,
  172. myUdpAddr8,
  173. myUdpAddr9,
  174. myUdpAddr10,
  175. myUdpAddr11, // This should get cut
  176. }, lhh)
  177. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  178. assertIp4InArray(
  179. t,
  180. r.msg.Details.Ip4AndPorts,
  181. myUdpAddr1, myUdpAddr2, myUdpAddr3, myUdpAddr4, myUdpAddr5, myUdpAddr5, myUdpAddr6, myUdpAddr7, myUdpAddr8, myUdpAddr9,
  182. )
  183. // Make sure we won't add ips in our vpn network
  184. bad1 := &udp.Addr{IP: net.ParseIP("10.128.0.99"), Port: 4242}
  185. bad2 := &udp.Addr{IP: net.ParseIP("10.128.0.100"), Port: 4242}
  186. good := &udp.Addr{IP: net.ParseIP("1.128.0.99"), Port: 4242}
  187. newLHHostUpdate(myUdpAddr0, myVpnIp, []*udp.Addr{bad1, bad2, good}, lhh)
  188. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  189. assertIp4InArray(t, r.msg.Details.Ip4AndPorts, good)
  190. }
  191. func newLHHostRequest(fromAddr *udp.Addr, myVpnIp, queryVpnIp iputil.VpnIp, lhh *LightHouseHandler) testLhReply {
  192. req := &NebulaMeta{
  193. Type: NebulaMeta_HostQuery,
  194. Details: &NebulaMetaDetails{
  195. VpnIp: uint32(queryVpnIp),
  196. },
  197. }
  198. b, err := req.Marshal()
  199. if err != nil {
  200. panic(err)
  201. }
  202. w := &testEncWriter{}
  203. lhh.HandleRequest(fromAddr, myVpnIp, b, w)
  204. return w.lastReply
  205. }
  206. func newLHHostUpdate(fromAddr *udp.Addr, vpnIp iputil.VpnIp, addrs []*udp.Addr, lhh *LightHouseHandler) {
  207. req := &NebulaMeta{
  208. Type: NebulaMeta_HostUpdateNotification,
  209. Details: &NebulaMetaDetails{
  210. VpnIp: uint32(vpnIp),
  211. Ip4AndPorts: make([]*Ip4AndPort, len(addrs)),
  212. },
  213. }
  214. for k, v := range addrs {
  215. req.Details.Ip4AndPorts[k] = &Ip4AndPort{Ip: uint32(iputil.Ip2VpnIp(v.IP)), Port: uint32(v.Port)}
  216. }
  217. b, err := req.Marshal()
  218. if err != nil {
  219. panic(err)
  220. }
  221. w := &testEncWriter{}
  222. lhh.HandleRequest(fromAddr, vpnIp, b, w)
  223. }
  224. //TODO: this is a RemoteList test
  225. //func Test_lhRemoteAllowList(t *testing.T) {
  226. // l := NewTestLogger()
  227. // c := NewConfig(l)
  228. // c.Settings["remoteallowlist"] = map[interface{}]interface{}{
  229. // "10.20.0.0/12": false,
  230. // }
  231. // allowList, err := c.GetAllowList("remoteallowlist", false)
  232. // assert.Nil(t, err)
  233. //
  234. // lh1 := "10.128.0.2"
  235. // lh1IP := net.ParseIP(lh1)
  236. //
  237. // udpServer, _ := NewListener(l, "0.0.0.0", 0, true)
  238. //
  239. // 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)
  240. // lh.SetRemoteAllowList(allowList)
  241. //
  242. // // A disallowed ip should not enter the cache but we should end up with an empty entry in the addrMap
  243. // remote1IP := net.ParseIP("10.20.0.3")
  244. // remotes := lh.unlockedGetRemoteList(ip2int(remote1IP))
  245. // remotes.unlockedPrependV4(ip2int(remote1IP), NewIp4AndPort(remote1IP, 4242))
  246. // assert.NotNil(t, lh.addrMap[ip2int(remote1IP)])
  247. // assert.Empty(t, lh.addrMap[ip2int(remote1IP)].CopyAddrs([]*net.IPNet{}))
  248. //
  249. // // Make sure a good ip enters the cache and addrMap
  250. // remote2IP := net.ParseIP("10.128.0.3")
  251. // remote2UDPAddr := NewUDPAddr(remote2IP, uint16(4242))
  252. // lh.addRemoteV4(ip2int(remote2IP), ip2int(remote2IP), NewIp4AndPort(remote2UDPAddr.IP, uint32(remote2UDPAddr.Port)), false, false)
  253. // assertUdpAddrInArray(t, lh.addrMap[ip2int(remote2IP)].CopyAddrs([]*net.IPNet{}), remote2UDPAddr)
  254. //
  255. // // Another good ip gets into the cache, ordering is inverted
  256. // remote3IP := net.ParseIP("10.128.0.4")
  257. // remote3UDPAddr := NewUDPAddr(remote3IP, uint16(4243))
  258. // lh.addRemoteV4(ip2int(remote2IP), ip2int(remote2IP), NewIp4AndPort(remote3UDPAddr.IP, uint32(remote3UDPAddr.Port)), false, false)
  259. // assertUdpAddrInArray(t, lh.addrMap[ip2int(remote2IP)].CopyAddrs([]*net.IPNet{}), remote2UDPAddr, remote3UDPAddr)
  260. //
  261. // // If we exceed the length limit we should only have the most recent addresses
  262. // addedAddrs := []*udpAddr{}
  263. // for i := 0; i < 11; i++ {
  264. // remoteUDPAddr := NewUDPAddr(net.IP{10, 128, 0, 4}, uint16(4243+i))
  265. // lh.addRemoteV4(ip2int(remote2IP), ip2int(remote2IP), NewIp4AndPort(remoteUDPAddr.IP, uint32(remoteUDPAddr.Port)), false, false)
  266. // // The first entry here is a duplicate, don't add it to the assert list
  267. // if i != 0 {
  268. // addedAddrs = append(addedAddrs, remoteUDPAddr)
  269. // }
  270. // }
  271. //
  272. // // We should only have the last 10 of what we tried to add
  273. // assert.True(t, len(addedAddrs) >= 10, "We should have tried to add at least 10 addresses")
  274. // assertUdpAddrInArray(
  275. // t,
  276. // lh.addrMap[ip2int(remote2IP)].CopyAddrs([]*net.IPNet{}),
  277. // addedAddrs[0],
  278. // addedAddrs[1],
  279. // addedAddrs[2],
  280. // addedAddrs[3],
  281. // addedAddrs[4],
  282. // addedAddrs[5],
  283. // addedAddrs[6],
  284. // addedAddrs[7],
  285. // addedAddrs[8],
  286. // addedAddrs[9],
  287. // )
  288. //}
  289. func Test_ipMaskContains(t *testing.T) {
  290. assert.True(t, ipMaskContains(iputil.Ip2VpnIp(net.ParseIP("10.0.0.1")), 32-24, iputil.Ip2VpnIp(net.ParseIP("10.0.0.255"))))
  291. assert.False(t, ipMaskContains(iputil.Ip2VpnIp(net.ParseIP("10.0.0.1")), 32-24, iputil.Ip2VpnIp(net.ParseIP("10.0.1.1"))))
  292. assert.True(t, ipMaskContains(iputil.Ip2VpnIp(net.ParseIP("10.0.0.1")), 32, iputil.Ip2VpnIp(net.ParseIP("10.0.1.1"))))
  293. }
  294. type testLhReply struct {
  295. nebType header.MessageType
  296. nebSubType header.MessageSubType
  297. vpnIp iputil.VpnIp
  298. msg *NebulaMeta
  299. }
  300. type testEncWriter struct {
  301. lastReply testLhReply
  302. }
  303. func (tw *testEncWriter) SendMessageToVpnIp(t header.MessageType, st header.MessageSubType, vpnIp iputil.VpnIp, p, _, _ []byte) {
  304. tw.lastReply = testLhReply{
  305. nebType: t,
  306. nebSubType: st,
  307. vpnIp: vpnIp,
  308. msg: &NebulaMeta{},
  309. }
  310. err := proto.Unmarshal(p, tw.lastReply.msg)
  311. if err != nil {
  312. panic(err)
  313. }
  314. }
  315. // assertIp4InArray asserts every address in want is at the same position in have and that the lengths match
  316. func assertIp4InArray(t *testing.T, have []*Ip4AndPort, want ...*udp.Addr) {
  317. assert.Len(t, have, len(want))
  318. for k, w := range want {
  319. if !(have[k].Ip == uint32(iputil.Ip2VpnIp(w.IP)) && have[k].Port == uint32(w.Port)) {
  320. assert.Fail(t, fmt.Sprintf("Response did not contain: %v:%v at %v; %v", w.IP, w.Port, k, translateV4toUdpAddr(have)))
  321. }
  322. }
  323. }
  324. // assertUdpAddrInArray asserts every address in want is at the same position in have and that the lengths match
  325. func assertUdpAddrInArray(t *testing.T, have []*udp.Addr, want ...*udp.Addr) {
  326. assert.Len(t, have, len(want))
  327. for k, w := range want {
  328. if !(have[k].IP.Equal(w.IP) && have[k].Port == w.Port) {
  329. assert.Fail(t, fmt.Sprintf("Response did not contain: %v at %v; %v", w, k, have))
  330. }
  331. }
  332. }
  333. func translateV4toUdpAddr(ips []*Ip4AndPort) []*udp.Addr {
  334. addrs := make([]*udp.Addr, len(ips))
  335. for k, v := range ips {
  336. addrs[k] = NewUDPAddrFromLH4(v)
  337. }
  338. return addrs
  339. }