lighthouse_test.go 12 KB

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