lighthouse_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. package nebula
  2. import (
  3. "context"
  4. "encoding/binary"
  5. "fmt"
  6. "net/netip"
  7. "testing"
  8. "github.com/gaissmai/bart"
  9. "github.com/slackhq/nebula/cert"
  10. "github.com/slackhq/nebula/config"
  11. "github.com/slackhq/nebula/header"
  12. "github.com/slackhq/nebula/test"
  13. "github.com/stretchr/testify/assert"
  14. "gopkg.in/yaml.v2"
  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. assert.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.Table[struct{}])
  30. nt.Insert(myVpnNet, struct{}{})
  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[interface{}]interface{}{"hosts": []interface{}{lh1}}
  38. c.Settings["static_host_map"] = map[interface{}]interface{}{lh1: []interface{}{"1.1.1.1:4242"}}
  39. _, err := NewLightHouseFromConfig(context.Background(), l, c, cs, nil, nil)
  40. assert.Nil(t, err)
  41. lh2 := "10.128.0.3"
  42. c = config.NewC(l)
  43. c.Settings["lighthouse"] = map[interface{}]interface{}{"hosts": []interface{}{lh1, lh2}}
  44. c.Settings["static_host_map"] = map[interface{}]interface{}{lh1: []interface{}{"100.1.1.1:4242"}}
  45. _, err = NewLightHouseFromConfig(context.Background(), l, c, cs, nil, nil)
  46. assert.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.Table[struct{}])
  52. nt.Insert(myVpnNet, struct{}{})
  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[interface{}]interface{}{
  60. "hosts": []interface{}{lh1},
  61. "interval": "1s",
  62. }
  63. c.Settings["static_host_map"] = map[interface{}]interface{}{lh1: []interface{}{"1.1.1.1:4242"}}
  64. lh, err := NewLightHouseFromConfig(context.Background(), l, c, cs, nil, nil)
  65. assert.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. assert.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. assert.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. assert.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.Table[struct{}])
  81. nt.Insert(myVpnNet, struct{}{})
  82. cs := &CertState{
  83. myVpnNetworks: []netip.Prefix{myVpnNet},
  84. myVpnNetworksTable: nt,
  85. }
  86. c := config.NewC(l)
  87. lh, err := NewLightHouseFromConfig(context.Background(), l, c, cs, nil, nil)
  88. if !assert.NoError(b, err) {
  89. b.Fatal()
  90. }
  91. hAddr := netip.MustParseAddrPort("4.5.6.7:12345")
  92. hAddr2 := netip.MustParseAddrPort("4.5.6.7:12346")
  93. vpnIp3 := netip.MustParseAddr("0.0.0.3")
  94. lh.addrMap[vpnIp3] = NewRemoteList([]netip.Addr{vpnIp3}, nil)
  95. lh.addrMap[vpnIp3].unlockedSetV4(
  96. vpnIp3,
  97. vpnIp3,
  98. []*V4AddrPort{
  99. netAddrToProtoV4AddrPort(hAddr.Addr(), hAddr.Port()),
  100. netAddrToProtoV4AddrPort(hAddr2.Addr(), hAddr2.Port()),
  101. },
  102. func(netip.Addr, *V4AddrPort) bool { return true },
  103. )
  104. rAddr := netip.MustParseAddrPort("1.2.2.3:12345")
  105. rAddr2 := netip.MustParseAddrPort("1.2.2.3:12346")
  106. vpnIp2 := netip.MustParseAddr("0.0.0.3")
  107. lh.addrMap[vpnIp2] = NewRemoteList([]netip.Addr{vpnIp2}, nil)
  108. lh.addrMap[vpnIp2].unlockedSetV4(
  109. vpnIp3,
  110. vpnIp3,
  111. []*V4AddrPort{
  112. netAddrToProtoV4AddrPort(rAddr.Addr(), rAddr.Port()),
  113. netAddrToProtoV4AddrPort(rAddr2.Addr(), rAddr2.Port()),
  114. },
  115. func(netip.Addr, *V4AddrPort) bool { return true },
  116. )
  117. mw := &mockEncWriter{}
  118. hi := []netip.Addr{vpnIp2}
  119. b.Run("notfound", func(b *testing.B) {
  120. lhh := lh.NewRequestHandler()
  121. req := &NebulaMeta{
  122. Type: NebulaMeta_HostQuery,
  123. Details: &NebulaMetaDetails{
  124. OldVpnAddr: 4,
  125. V4AddrPorts: nil,
  126. },
  127. }
  128. p, err := req.Marshal()
  129. assert.NoError(b, err)
  130. for n := 0; n < b.N; n++ {
  131. lhh.HandleRequest(rAddr, hi, p, mw)
  132. }
  133. })
  134. b.Run("found", func(b *testing.B) {
  135. lhh := lh.NewRequestHandler()
  136. req := &NebulaMeta{
  137. Type: NebulaMeta_HostQuery,
  138. Details: &NebulaMetaDetails{
  139. OldVpnAddr: 3,
  140. V4AddrPorts: nil,
  141. },
  142. }
  143. p, err := req.Marshal()
  144. assert.NoError(b, err)
  145. for n := 0; n < b.N; n++ {
  146. lhh.HandleRequest(rAddr, hi, p, mw)
  147. }
  148. })
  149. }
  150. func TestLighthouse_Memory(t *testing.T) {
  151. l := test.NewLogger()
  152. myUdpAddr0 := netip.MustParseAddrPort("10.0.0.2:4242")
  153. myUdpAddr1 := netip.MustParseAddrPort("192.168.0.2:4242")
  154. myUdpAddr2 := netip.MustParseAddrPort("172.16.0.2:4242")
  155. myUdpAddr3 := netip.MustParseAddrPort("100.152.0.2:4242")
  156. myUdpAddr4 := netip.MustParseAddrPort("24.15.0.2:4242")
  157. myUdpAddr5 := netip.MustParseAddrPort("192.168.0.2:4243")
  158. myUdpAddr6 := netip.MustParseAddrPort("192.168.0.2:4244")
  159. myUdpAddr7 := netip.MustParseAddrPort("192.168.0.2:4245")
  160. myUdpAddr8 := netip.MustParseAddrPort("192.168.0.2:4246")
  161. myUdpAddr9 := netip.MustParseAddrPort("192.168.0.2:4247")
  162. myUdpAddr10 := netip.MustParseAddrPort("192.168.0.2:4248")
  163. myUdpAddr11 := netip.MustParseAddrPort("192.168.0.2:4249")
  164. myVpnIp := netip.MustParseAddr("10.128.0.2")
  165. theirUdpAddr0 := netip.MustParseAddrPort("10.0.0.3:4242")
  166. theirUdpAddr1 := netip.MustParseAddrPort("192.168.0.3:4242")
  167. theirUdpAddr2 := netip.MustParseAddrPort("172.16.0.3:4242")
  168. theirUdpAddr3 := netip.MustParseAddrPort("100.152.0.3:4242")
  169. theirUdpAddr4 := netip.MustParseAddrPort("24.15.0.3:4242")
  170. theirVpnIp := netip.MustParseAddr("10.128.0.3")
  171. c := config.NewC(l)
  172. c.Settings["lighthouse"] = map[interface{}]interface{}{"am_lighthouse": true}
  173. c.Settings["listen"] = map[interface{}]interface{}{"port": 4242}
  174. myVpnNet := netip.MustParsePrefix("10.128.0.1/24")
  175. nt := new(bart.Table[struct{}])
  176. nt.Insert(myVpnNet, struct{}{})
  177. cs := &CertState{
  178. myVpnNetworks: []netip.Prefix{myVpnNet},
  179. myVpnNetworksTable: nt,
  180. }
  181. lh, err := NewLightHouseFromConfig(context.Background(), l, c, cs, nil, nil)
  182. lh.ifce = &mockEncWriter{}
  183. assert.NoError(t, err)
  184. lhh := lh.NewRequestHandler()
  185. // Test that my first update responds with just that
  186. newLHHostUpdate(myUdpAddr0, myVpnIp, []netip.AddrPort{myUdpAddr1, myUdpAddr2}, lhh)
  187. r := newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  188. assertIp4InArray(t, r.msg.Details.V4AddrPorts, myUdpAddr1, myUdpAddr2)
  189. // Ensure we don't accumulate addresses
  190. newLHHostUpdate(myUdpAddr0, myVpnIp, []netip.AddrPort{myUdpAddr3}, lhh)
  191. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  192. assertIp4InArray(t, r.msg.Details.V4AddrPorts, myUdpAddr3)
  193. // Grow it back to 2
  194. newLHHostUpdate(myUdpAddr0, myVpnIp, []netip.AddrPort{myUdpAddr1, myUdpAddr4}, lhh)
  195. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  196. assertIp4InArray(t, r.msg.Details.V4AddrPorts, myUdpAddr1, myUdpAddr4)
  197. // Update a different host and ask about it
  198. newLHHostUpdate(theirUdpAddr0, theirVpnIp, []netip.AddrPort{theirUdpAddr1, theirUdpAddr2, theirUdpAddr3, theirUdpAddr4}, lhh)
  199. r = newLHHostRequest(theirUdpAddr0, theirVpnIp, theirVpnIp, lhh)
  200. assertIp4InArray(t, r.msg.Details.V4AddrPorts, theirUdpAddr1, theirUdpAddr2, theirUdpAddr3, theirUdpAddr4)
  201. // Have both hosts ask about the other
  202. r = newLHHostRequest(theirUdpAddr0, theirVpnIp, myVpnIp, lhh)
  203. assertIp4InArray(t, r.msg.Details.V4AddrPorts, myUdpAddr1, myUdpAddr4)
  204. r = newLHHostRequest(myUdpAddr0, myVpnIp, theirVpnIp, lhh)
  205. assertIp4InArray(t, r.msg.Details.V4AddrPorts, theirUdpAddr1, theirUdpAddr2, theirUdpAddr3, theirUdpAddr4)
  206. // Make sure we didn't get changed
  207. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  208. assertIp4InArray(t, r.msg.Details.V4AddrPorts, myUdpAddr1, myUdpAddr4)
  209. // Ensure proper ordering and limiting
  210. // Send 12 addrs, get 10 back, the last 2 removed, allowing the duplicate to remain (clients dedupe)
  211. newLHHostUpdate(
  212. myUdpAddr0,
  213. myVpnIp,
  214. []netip.AddrPort{
  215. myUdpAddr1,
  216. myUdpAddr2,
  217. myUdpAddr3,
  218. myUdpAddr4,
  219. myUdpAddr5,
  220. myUdpAddr5, //Duplicated on purpose
  221. myUdpAddr6,
  222. myUdpAddr7,
  223. myUdpAddr8,
  224. myUdpAddr9,
  225. myUdpAddr10,
  226. myUdpAddr11, // This should get cut
  227. }, lhh)
  228. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  229. assertIp4InArray(
  230. t,
  231. r.msg.Details.V4AddrPorts,
  232. myUdpAddr1, myUdpAddr2, myUdpAddr3, myUdpAddr4, myUdpAddr5, myUdpAddr5, myUdpAddr6, myUdpAddr7, myUdpAddr8, myUdpAddr9,
  233. )
  234. // Make sure we won't add ips in our vpn network
  235. bad1 := netip.MustParseAddrPort("10.128.0.99:4242")
  236. bad2 := netip.MustParseAddrPort("10.128.0.100:4242")
  237. good := netip.MustParseAddrPort("1.128.0.99:4242")
  238. newLHHostUpdate(myUdpAddr0, myVpnIp, []netip.AddrPort{bad1, bad2, good}, lhh)
  239. r = newLHHostRequest(myUdpAddr0, myVpnIp, myVpnIp, lhh)
  240. assertIp4InArray(t, r.msg.Details.V4AddrPorts, good)
  241. }
  242. func TestLighthouse_reload(t *testing.T) {
  243. l := test.NewLogger()
  244. c := config.NewC(l)
  245. c.Settings["lighthouse"] = map[interface{}]interface{}{"am_lighthouse": true}
  246. c.Settings["listen"] = map[interface{}]interface{}{"port": 4242}
  247. myVpnNet := netip.MustParsePrefix("10.128.0.1/24")
  248. nt := new(bart.Table[struct{}])
  249. nt.Insert(myVpnNet, struct{}{})
  250. cs := &CertState{
  251. myVpnNetworks: []netip.Prefix{myVpnNet},
  252. myVpnNetworksTable: nt,
  253. }
  254. lh, err := NewLightHouseFromConfig(context.Background(), l, c, cs, nil, nil)
  255. assert.NoError(t, err)
  256. nc := map[interface{}]interface{}{
  257. "static_host_map": map[interface{}]interface{}{
  258. "10.128.0.2": []interface{}{"1.1.1.1:4242"},
  259. },
  260. }
  261. rc, err := yaml.Marshal(nc)
  262. assert.NoError(t, err)
  263. c.ReloadConfigString(string(rc))
  264. err = lh.reload(c, false)
  265. assert.NoError(t, err)
  266. }
  267. func newLHHostRequest(fromAddr netip.AddrPort, myVpnIp, queryVpnIp netip.Addr, lhh *LightHouseHandler) testLhReply {
  268. req := &NebulaMeta{
  269. Type: NebulaMeta_HostQuery,
  270. Details: &NebulaMetaDetails{},
  271. }
  272. if queryVpnIp.Is4() {
  273. bip := queryVpnIp.As4()
  274. req.Details.OldVpnAddr = binary.BigEndian.Uint32(bip[:])
  275. } else {
  276. req.Details.VpnAddr = netAddrToProtoAddr(queryVpnIp)
  277. }
  278. b, err := req.Marshal()
  279. if err != nil {
  280. panic(err)
  281. }
  282. filter := NebulaMeta_HostQueryReply
  283. w := &testEncWriter{
  284. metaFilter: &filter,
  285. }
  286. lhh.HandleRequest(fromAddr, []netip.Addr{myVpnIp}, b, w)
  287. return w.lastReply
  288. }
  289. func newLHHostUpdate(fromAddr netip.AddrPort, vpnIp netip.Addr, addrs []netip.AddrPort, lhh *LightHouseHandler) {
  290. req := &NebulaMeta{
  291. Type: NebulaMeta_HostUpdateNotification,
  292. Details: &NebulaMetaDetails{},
  293. }
  294. if vpnIp.Is4() {
  295. bip := vpnIp.As4()
  296. req.Details.OldVpnAddr = binary.BigEndian.Uint32(bip[:])
  297. } else {
  298. req.Details.VpnAddr = netAddrToProtoAddr(vpnIp)
  299. }
  300. for _, v := range addrs {
  301. if v.Addr().Is4() {
  302. req.Details.V4AddrPorts = append(req.Details.V4AddrPorts, netAddrToProtoV4AddrPort(v.Addr(), v.Port()))
  303. } else {
  304. req.Details.V6AddrPorts = append(req.Details.V6AddrPorts, netAddrToProtoV6AddrPort(v.Addr(), v.Port()))
  305. }
  306. }
  307. b, err := req.Marshal()
  308. if err != nil {
  309. panic(err)
  310. }
  311. w := &testEncWriter{}
  312. lhh.HandleRequest(fromAddr, []netip.Addr{vpnIp}, b, w)
  313. }
  314. type testLhReply struct {
  315. nebType header.MessageType
  316. nebSubType header.MessageSubType
  317. vpnIp netip.Addr
  318. msg *NebulaMeta
  319. }
  320. type testEncWriter struct {
  321. lastReply testLhReply
  322. metaFilter *NebulaMeta_MessageType
  323. protocolVersion cert.Version
  324. }
  325. func (tw *testEncWriter) SendVia(via *HostInfo, relay *Relay, ad, nb, out []byte, nocopy bool) {
  326. }
  327. func (tw *testEncWriter) Handshake(vpnIp netip.Addr) {
  328. }
  329. func (tw *testEncWriter) SendMessageToHostInfo(t header.MessageType, st header.MessageSubType, hostinfo *HostInfo, p, _, _ []byte) {
  330. msg := &NebulaMeta{}
  331. err := msg.Unmarshal(p)
  332. if tw.metaFilter == nil || msg.Type == *tw.metaFilter {
  333. tw.lastReply = testLhReply{
  334. nebType: t,
  335. nebSubType: st,
  336. vpnIp: hostinfo.vpnAddrs[0],
  337. msg: msg,
  338. }
  339. }
  340. if err != nil {
  341. panic(err)
  342. }
  343. }
  344. func (tw *testEncWriter) SendMessageToVpnAddr(t header.MessageType, st header.MessageSubType, vpnIp netip.Addr, p, _, _ []byte) {
  345. msg := &NebulaMeta{}
  346. err := msg.Unmarshal(p)
  347. if tw.metaFilter == nil || msg.Type == *tw.metaFilter {
  348. tw.lastReply = testLhReply{
  349. nebType: t,
  350. nebSubType: st,
  351. vpnIp: vpnIp,
  352. msg: msg,
  353. }
  354. }
  355. if err != nil {
  356. panic(err)
  357. }
  358. }
  359. func (tw *testEncWriter) GetHostInfo(vpnIp netip.Addr) *HostInfo {
  360. return nil
  361. }
  362. func (tw *testEncWriter) GetCertState() *CertState {
  363. return &CertState{defaultVersion: tw.protocolVersion}
  364. }
  365. // assertIp4InArray asserts every address in want is at the same position in have and that the lengths match
  366. func assertIp4InArray(t *testing.T, have []*V4AddrPort, want ...netip.AddrPort) {
  367. if !assert.Len(t, have, len(want)) {
  368. return
  369. }
  370. for k, w := range want {
  371. h := protoV4AddrPortToNetAddrPort(have[k])
  372. if !(h == w) {
  373. assert.Fail(t, fmt.Sprintf("Response did not contain: %v at %v, found %v", w, k, h))
  374. }
  375. }
  376. }
  377. func Test_findNetworkUnion(t *testing.T) {
  378. var out netip.Addr
  379. var ok bool
  380. tenDot := netip.MustParsePrefix("10.0.0.0/8")
  381. oneSevenTwo := netip.MustParsePrefix("172.16.0.0/16")
  382. fe80 := netip.MustParsePrefix("fe80::/8")
  383. fc00 := netip.MustParsePrefix("fc00::/7")
  384. a1 := netip.MustParseAddr("10.0.0.1")
  385. afe81 := netip.MustParseAddr("fe80::1")
  386. //simple
  387. out, ok = findNetworkUnion([]netip.Prefix{tenDot}, []netip.Addr{a1})
  388. assert.True(t, ok)
  389. assert.Equal(t, out, a1)
  390. //mixed lengths
  391. out, ok = findNetworkUnion([]netip.Prefix{tenDot}, []netip.Addr{a1, afe81})
  392. assert.True(t, ok)
  393. assert.Equal(t, out, a1)
  394. out, ok = findNetworkUnion([]netip.Prefix{tenDot, oneSevenTwo}, []netip.Addr{a1})
  395. assert.True(t, ok)
  396. assert.Equal(t, out, a1)
  397. //mixed family
  398. out, ok = findNetworkUnion([]netip.Prefix{tenDot, oneSevenTwo, fe80}, []netip.Addr{a1})
  399. assert.True(t, ok)
  400. assert.Equal(t, out, a1)
  401. out, ok = findNetworkUnion([]netip.Prefix{tenDot, oneSevenTwo, fe80}, []netip.Addr{a1, afe81})
  402. assert.True(t, ok)
  403. assert.Equal(t, out, a1)
  404. //ordering
  405. out, ok = findNetworkUnion([]netip.Prefix{tenDot, oneSevenTwo, fe80}, []netip.Addr{afe81, a1})
  406. assert.True(t, ok)
  407. assert.Equal(t, out, a1)
  408. out, ok = findNetworkUnion([]netip.Prefix{fe80, tenDot, oneSevenTwo}, []netip.Addr{afe81, a1})
  409. assert.True(t, ok)
  410. assert.Equal(t, out, afe81)
  411. //some mismatches
  412. out, ok = findNetworkUnion([]netip.Prefix{tenDot, oneSevenTwo, fe80}, []netip.Addr{afe81})
  413. assert.True(t, ok)
  414. assert.Equal(t, out, afe81)
  415. out, ok = findNetworkUnion([]netip.Prefix{oneSevenTwo, fe80}, []netip.Addr{a1, afe81})
  416. assert.True(t, ok)
  417. assert.Equal(t, out, afe81)
  418. //falsey cases
  419. out, ok = findNetworkUnion([]netip.Prefix{oneSevenTwo, fe80}, []netip.Addr{a1})
  420. assert.False(t, ok)
  421. out, ok = findNetworkUnion([]netip.Prefix{fc00, fe80}, []netip.Addr{a1})
  422. assert.False(t, ok)
  423. out, ok = findNetworkUnion([]netip.Prefix{oneSevenTwo, fc00}, []netip.Addr{a1, afe81})
  424. assert.False(t, ok)
  425. out, ok = findNetworkUnion([]netip.Prefix{fc00}, []netip.Addr{a1, afe81})
  426. assert.False(t, ok)
  427. }