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  }