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