mirror of
https://github.com/libp2p/go-libp2p.git
synced 2025-10-04 07:46:43 +08:00

Providing unknown addresses to the user, helps them infer whether autonatv2 has any more addresses it might confirm. There's no upside to not sending this information. This also changes host.ConfirmedAddrs to return all the three categories, Reachable, Unreachable, and Unknown addrs.
548 lines
19 KiB
Go
548 lines
19 KiB
Go
package basichost
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"slices"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/libp2p/go-libp2p/core/event"
|
|
"github.com/libp2p/go-libp2p/core/network"
|
|
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
|
|
"github.com/libp2p/go-libp2p/p2p/protocol/autonatv2"
|
|
ma "github.com/multiformats/go-multiaddr"
|
|
manet "github.com/multiformats/go-multiaddr/net"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestAppendNATAddrs(t *testing.T) {
|
|
if1, if2 := ma.StringCast("/ip4/192.168.0.100"), ma.StringCast("/ip4/1.1.1.1")
|
|
ifaceAddrs := []ma.Multiaddr{if1, if2}
|
|
tcpListenAddr, udpListenAddr := ma.StringCast("/ip4/0.0.0.0/tcp/1"), ma.StringCast("/ip4/0.0.0.0/udp/2/quic-v1")
|
|
cases := []struct {
|
|
Name string
|
|
Listen ma.Multiaddr
|
|
Nat ma.Multiaddr
|
|
ObsAddrFunc func(ma.Multiaddr) []ma.Multiaddr
|
|
Expected []ma.Multiaddr
|
|
}{
|
|
{
|
|
Name: "nat map success",
|
|
// nat mapping success, obsaddress ignored
|
|
Listen: ma.StringCast("/ip4/0.0.0.0/udp/1/quic-v1"),
|
|
Nat: ma.StringCast("/ip4/1.1.1.1/udp/10/quic-v1"),
|
|
ObsAddrFunc: func(_ ma.Multiaddr) []ma.Multiaddr {
|
|
return []ma.Multiaddr{ma.StringCast("/ip4/2.2.2.2/udp/100/quic-v1")}
|
|
},
|
|
Expected: []ma.Multiaddr{ma.StringCast("/ip4/1.1.1.1/udp/10/quic-v1")},
|
|
},
|
|
{
|
|
Name: "nat map failure",
|
|
// nat mapping fails, obs addresses added
|
|
Listen: ma.StringCast("/ip4/0.0.0.0/tcp/1"),
|
|
Nat: nil,
|
|
ObsAddrFunc: func(a ma.Multiaddr) []ma.Multiaddr {
|
|
ipC, _ := ma.SplitFirst(a)
|
|
ip := ipC.Multiaddr()
|
|
switch {
|
|
case ip.Equal(if1):
|
|
return []ma.Multiaddr{ma.StringCast("/ip4/2.2.2.2/tcp/100")}
|
|
case ip.Equal(if2):
|
|
return []ma.Multiaddr{ma.StringCast("/ip4/3.3.3.3/tcp/100")}
|
|
default:
|
|
return []ma.Multiaddr{}
|
|
}
|
|
},
|
|
Expected: []ma.Multiaddr{ma.StringCast("/ip4/2.2.2.2/tcp/100"), ma.StringCast("/ip4/3.3.3.3/tcp/100")},
|
|
},
|
|
{
|
|
Name: "if addrs ignored if not listening on unspecified",
|
|
// nat mapping fails, obs addresses added
|
|
Listen: ma.StringCast("/ip4/192.168.1.1/tcp/1"),
|
|
Nat: nil,
|
|
ObsAddrFunc: func(a ma.Multiaddr) []ma.Multiaddr {
|
|
ipC, _ := ma.SplitFirst(a)
|
|
ip := ipC.Multiaddr()
|
|
switch {
|
|
case ip.Equal(if1):
|
|
return []ma.Multiaddr{ma.StringCast("/ip4/2.2.2.2/tcp/100")}
|
|
case ip.Equal(if2):
|
|
return []ma.Multiaddr{ma.StringCast("/ip4/3.3.3.3/tcp/100")}
|
|
case ip.Equal(ma.StringCast("/ip4/192.168.1.1")):
|
|
return []ma.Multiaddr{ma.StringCast("/ip4/4.4.4.4/tcp/100")}
|
|
default:
|
|
return []ma.Multiaddr{}
|
|
}
|
|
},
|
|
Expected: []ma.Multiaddr{ma.StringCast("/ip4/4.4.4.4/tcp/100")},
|
|
},
|
|
{
|
|
Name: "nat map success but CGNAT",
|
|
// nat addr added, obs address added with nat provided port
|
|
Listen: tcpListenAddr,
|
|
Nat: ma.StringCast("/ip4/100.100.1.1/tcp/100"),
|
|
ObsAddrFunc: func(a ma.Multiaddr) []ma.Multiaddr {
|
|
ipC, _ := ma.SplitFirst(a)
|
|
ip := ipC.Multiaddr()
|
|
if ip.Equal(if1) {
|
|
return []ma.Multiaddr{ma.StringCast("/ip4/2.2.2.2/tcp/20")}
|
|
}
|
|
return []ma.Multiaddr{ma.StringCast("/ip4/3.3.3.3/tcp/30")}
|
|
},
|
|
Expected: []ma.Multiaddr{
|
|
ma.StringCast("/ip4/100.100.1.1/tcp/100"),
|
|
ma.StringCast("/ip4/2.2.2.2/tcp/20"),
|
|
ma.StringCast("/ip4/3.3.3.3/tcp/30"),
|
|
},
|
|
},
|
|
{
|
|
Name: "uses unspecified address for obs address",
|
|
// observed address manager should be queries with both specified and unspecified addresses
|
|
// udp observed addresses are mapped to unspecified addresses
|
|
Listen: udpListenAddr,
|
|
Nat: nil,
|
|
ObsAddrFunc: func(a ma.Multiaddr) []ma.Multiaddr {
|
|
if manet.IsIPUnspecified(a) {
|
|
return []ma.Multiaddr{ma.StringCast("/ip4/3.3.3.3/udp/20/quic-v1")}
|
|
}
|
|
return []ma.Multiaddr{ma.StringCast("/ip4/2.2.2.2/udp/20/quic-v1")}
|
|
},
|
|
Expected: []ma.Multiaddr{
|
|
ma.StringCast("/ip4/2.2.2.2/udp/20/quic-v1"),
|
|
ma.StringCast("/ip4/3.3.3.3/udp/20/quic-v1"),
|
|
},
|
|
},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.Name, func(t *testing.T) {
|
|
as := &addrsManager{
|
|
natManager: &mockNatManager{
|
|
GetMappingFunc: func(_ ma.Multiaddr) ma.Multiaddr {
|
|
return tc.Nat
|
|
},
|
|
},
|
|
observedAddrsManager: &mockObservedAddrs{
|
|
ObservedAddrsForFunc: tc.ObsAddrFunc,
|
|
},
|
|
}
|
|
res := as.appendNATAddrs(nil, []ma.Multiaddr{tc.Listen}, ifaceAddrs)
|
|
res = ma.Unique(res)
|
|
require.ElementsMatch(t, tc.Expected, res, "%s\n%s", tc.Expected, res)
|
|
})
|
|
}
|
|
}
|
|
|
|
type mockNatManager struct {
|
|
GetMappingFunc func(addr ma.Multiaddr) ma.Multiaddr
|
|
}
|
|
|
|
func (*mockNatManager) Close() error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockNatManager) GetMapping(addr ma.Multiaddr) ma.Multiaddr {
|
|
if m.GetMappingFunc == nil {
|
|
return nil
|
|
}
|
|
return m.GetMappingFunc(addr)
|
|
}
|
|
|
|
func (*mockNatManager) HasDiscoveredNAT() bool {
|
|
return true
|
|
}
|
|
|
|
var _ NATManager = &mockNatManager{}
|
|
|
|
type mockObservedAddrs struct {
|
|
OwnObservedAddrsFunc func() []ma.Multiaddr
|
|
ObservedAddrsForFunc func(ma.Multiaddr) []ma.Multiaddr
|
|
}
|
|
|
|
func (m *mockObservedAddrs) OwnObservedAddrs() []ma.Multiaddr {
|
|
return m.OwnObservedAddrsFunc()
|
|
}
|
|
|
|
func (m *mockObservedAddrs) ObservedAddrsFor(local ma.Multiaddr) []ma.Multiaddr {
|
|
return m.ObservedAddrsForFunc(local)
|
|
}
|
|
|
|
type addrsManagerArgs struct {
|
|
NATManager NATManager
|
|
AddrsFactory AddrsFactory
|
|
ObservedAddrsManager observedAddrsManager
|
|
ListenAddrs func() []ma.Multiaddr
|
|
AutoNATClient autonatv2Client
|
|
Bus event.Bus
|
|
}
|
|
|
|
type addrsManagerTestCase struct {
|
|
*addrsManager
|
|
PushRelay func(relayAddrs []ma.Multiaddr)
|
|
PushReachability func(rch network.Reachability)
|
|
}
|
|
|
|
func newAddrsManagerTestCase(t *testing.T, args addrsManagerArgs) addrsManagerTestCase {
|
|
eb := args.Bus
|
|
if eb == nil {
|
|
eb = eventbus.NewBus()
|
|
}
|
|
if args.AddrsFactory == nil {
|
|
args.AddrsFactory = func(addrs []ma.Multiaddr) []ma.Multiaddr { return addrs }
|
|
}
|
|
addrsUpdatedChan := make(chan struct{}, 1)
|
|
am, err := newAddrsManager(
|
|
eb, args.NATManager, args.AddrsFactory, args.ListenAddrs, nil, args.ObservedAddrsManager, addrsUpdatedChan, args.AutoNATClient,
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, am.Start())
|
|
raEm, err := eb.Emitter(new(event.EvtAutoRelayAddrsUpdated), eventbus.Stateful)
|
|
require.NoError(t, err)
|
|
|
|
rchEm, err := eb.Emitter(new(event.EvtLocalReachabilityChanged), eventbus.Stateful)
|
|
require.NoError(t, err)
|
|
|
|
t.Cleanup(am.Close)
|
|
return addrsManagerTestCase{
|
|
addrsManager: am,
|
|
PushRelay: func(relayAddrs []ma.Multiaddr) {
|
|
err := raEm.Emit(event.EvtAutoRelayAddrsUpdated{RelayAddrs: relayAddrs})
|
|
require.NoError(t, err)
|
|
},
|
|
PushReachability: func(rch network.Reachability) {
|
|
err := rchEm.Emit(event.EvtLocalReachabilityChanged{Reachability: rch})
|
|
require.NoError(t, err)
|
|
},
|
|
}
|
|
}
|
|
|
|
func TestAddrsManager(t *testing.T) {
|
|
lhquic := ma.StringCast("/ip4/127.0.0.1/udp/1/quic-v1")
|
|
lhtcp := ma.StringCast("/ip4/127.0.0.1/tcp/1")
|
|
|
|
publicQUIC := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1")
|
|
publicTCP := ma.StringCast("/ip4/1.2.3.4/tcp/1")
|
|
|
|
t.Run("only nat", func(t *testing.T) {
|
|
am := newAddrsManagerTestCase(t, addrsManagerArgs{
|
|
NATManager: &mockNatManager{
|
|
GetMappingFunc: func(addr ma.Multiaddr) ma.Multiaddr {
|
|
if _, err := addr.ValueForProtocol(ma.P_UDP); err == nil {
|
|
return publicQUIC
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
ListenAddrs: func() []ma.Multiaddr { return []ma.Multiaddr{lhquic, lhtcp} },
|
|
})
|
|
am.triggerAddrsUpdate()
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
expected := []ma.Multiaddr{publicQUIC, lhquic, lhtcp}
|
|
assert.ElementsMatch(collect, am.Addrs(), expected, "%s\n%s", am.Addrs(), expected)
|
|
}, 5*time.Second, 50*time.Millisecond)
|
|
})
|
|
|
|
t.Run("nat and observed addrs", func(t *testing.T) {
|
|
// nat mapping for udp, observed addrs for tcp
|
|
am := newAddrsManagerTestCase(t, addrsManagerArgs{
|
|
NATManager: &mockNatManager{
|
|
GetMappingFunc: func(addr ma.Multiaddr) ma.Multiaddr {
|
|
if _, err := addr.ValueForProtocol(ma.P_UDP); err == nil {
|
|
return publicQUIC
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
ObservedAddrsManager: &mockObservedAddrs{
|
|
ObservedAddrsForFunc: func(addr ma.Multiaddr) []ma.Multiaddr {
|
|
if _, err := addr.ValueForProtocol(ma.P_TCP); err == nil {
|
|
return []ma.Multiaddr{publicTCP}
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
ListenAddrs: func() []ma.Multiaddr { return []ma.Multiaddr{lhquic, lhtcp} },
|
|
})
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
expected := []ma.Multiaddr{lhquic, lhtcp, publicQUIC, publicTCP}
|
|
assert.ElementsMatch(collect, am.Addrs(), expected, "%s\n%s", am.Addrs(), expected)
|
|
}, 5*time.Second, 50*time.Millisecond)
|
|
})
|
|
t.Run("nat returns unspecified addr", func(t *testing.T) {
|
|
quicPort1 := ma.StringCast("/ip4/3.3.3.3/udp/1/quic-v1")
|
|
quicPort2 := ma.StringCast("/ip4/3.3.3.3/udp/2/quic-v1")
|
|
// port from nat, IP from observed addr
|
|
am := newAddrsManagerTestCase(t, addrsManagerArgs{
|
|
NATManager: &mockNatManager{
|
|
GetMappingFunc: func(addr ma.Multiaddr) ma.Multiaddr {
|
|
if addr.Equal(lhquic) {
|
|
return ma.StringCast("/ip4/0.0.0.0/udp/2/quic-v1")
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
ObservedAddrsManager: &mockObservedAddrs{
|
|
ObservedAddrsForFunc: func(addr ma.Multiaddr) []ma.Multiaddr {
|
|
if addr.Equal(lhquic) {
|
|
return []ma.Multiaddr{quicPort1}
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
ListenAddrs: func() []ma.Multiaddr { return []ma.Multiaddr{lhquic} },
|
|
})
|
|
expected := []ma.Multiaddr{lhquic, quicPort2}
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
assert.ElementsMatch(collect, am.Addrs(), expected, "%s\n%s", am.Addrs(), expected)
|
|
}, 5*time.Second, 50*time.Millisecond)
|
|
})
|
|
t.Run("only observed addrs", func(t *testing.T) {
|
|
am := newAddrsManagerTestCase(t, addrsManagerArgs{
|
|
ObservedAddrsManager: &mockObservedAddrs{
|
|
ObservedAddrsForFunc: func(addr ma.Multiaddr) []ma.Multiaddr {
|
|
if addr.Equal(lhtcp) {
|
|
return []ma.Multiaddr{publicTCP}
|
|
}
|
|
if addr.Equal(lhquic) {
|
|
return []ma.Multiaddr{publicQUIC}
|
|
}
|
|
return nil
|
|
},
|
|
},
|
|
ListenAddrs: func() []ma.Multiaddr { return []ma.Multiaddr{lhquic, lhtcp} },
|
|
})
|
|
am.triggerAddrsUpdate()
|
|
expected := []ma.Multiaddr{lhquic, lhtcp, publicTCP, publicQUIC}
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
assert.ElementsMatch(collect, am.Addrs(), expected, "%s\n%s", am.Addrs(), expected)
|
|
}, 5*time.Second, 50*time.Millisecond)
|
|
})
|
|
|
|
t.Run("observed addrs limit", func(t *testing.T) {
|
|
quicAddrs := []ma.Multiaddr{
|
|
ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1"),
|
|
ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1"),
|
|
ma.StringCast("/ip4/1.2.3.4/udp/3/quic-v1"),
|
|
ma.StringCast("/ip4/1.2.3.4/udp/4/quic-v1"),
|
|
ma.StringCast("/ip4/1.2.3.4/udp/5/quic-v1"),
|
|
ma.StringCast("/ip4/1.2.3.4/udp/6/quic-v1"),
|
|
ma.StringCast("/ip4/1.2.3.4/udp/7/quic-v1"),
|
|
ma.StringCast("/ip4/1.2.3.4/udp/8/quic-v1"),
|
|
ma.StringCast("/ip4/1.2.3.4/udp/9/quic-v1"),
|
|
ma.StringCast("/ip4/1.2.3.4/udp/10/quic-v1"),
|
|
}
|
|
am := newAddrsManagerTestCase(t, addrsManagerArgs{
|
|
ObservedAddrsManager: &mockObservedAddrs{
|
|
ObservedAddrsForFunc: func(_ ma.Multiaddr) []ma.Multiaddr {
|
|
return quicAddrs
|
|
},
|
|
},
|
|
ListenAddrs: func() []ma.Multiaddr { return []ma.Multiaddr{lhquic} },
|
|
})
|
|
am.triggerAddrsUpdate()
|
|
expected := []ma.Multiaddr{lhquic}
|
|
expected = append(expected, quicAddrs[:maxObservedAddrsPerListenAddr]...)
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
assert.ElementsMatch(collect, am.Addrs(), expected, "%s\n%s", am.Addrs(), expected)
|
|
}, 5*time.Second, 50*time.Millisecond)
|
|
})
|
|
t.Run("public addrs removed when private", func(t *testing.T) {
|
|
am := newAddrsManagerTestCase(t, addrsManagerArgs{
|
|
ObservedAddrsManager: &mockObservedAddrs{
|
|
ObservedAddrsForFunc: func(_ ma.Multiaddr) []ma.Multiaddr {
|
|
return []ma.Multiaddr{publicQUIC}
|
|
},
|
|
},
|
|
ListenAddrs: func() []ma.Multiaddr { return []ma.Multiaddr{lhquic, lhtcp} },
|
|
})
|
|
|
|
// remove public addrs
|
|
am.PushReachability(network.ReachabilityPrivate)
|
|
relayAddr := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1/p2p/QmdXGaeGiVA745XorV1jr11RHxB9z4fqykm6xCUPX1aTJo/p2p-circuit")
|
|
am.PushRelay([]ma.Multiaddr{relayAddr})
|
|
|
|
expectedAddrs := []ma.Multiaddr{relayAddr, lhquic, lhtcp}
|
|
expectedAllAddrs := []ma.Multiaddr{publicQUIC, lhquic, lhtcp}
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
assert.ElementsMatch(collect, am.Addrs(), expectedAddrs, "%s\n%s", am.Addrs(), expectedAddrs)
|
|
assert.ElementsMatch(collect, am.DirectAddrs(), expectedAllAddrs, "%s\n%s", am.DirectAddrs(), expectedAllAddrs)
|
|
}, 5*time.Second, 50*time.Millisecond)
|
|
|
|
// add public addrs
|
|
am.PushReachability(network.ReachabilityPublic)
|
|
|
|
expectedAddrs = expectedAllAddrs
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
assert.ElementsMatch(collect, am.Addrs(), expectedAddrs, "%s\n%s", am.Addrs(), expectedAddrs)
|
|
assert.ElementsMatch(collect, am.DirectAddrs(), expectedAllAddrs, "%s\n%s", am.DirectAddrs(), expectedAllAddrs)
|
|
}, 5*time.Second, 50*time.Millisecond)
|
|
})
|
|
|
|
t.Run("addrs factory gets relay addrs", func(t *testing.T) {
|
|
relayAddr := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1/p2p/QmdXGaeGiVA745XorV1jr11RHxB9z4fqykm6xCUPX1aTJo/p2p-circuit")
|
|
publicQUIC2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1")
|
|
am := newAddrsManagerTestCase(t, addrsManagerArgs{
|
|
AddrsFactory: func(addrs []ma.Multiaddr) []ma.Multiaddr {
|
|
for _, a := range addrs {
|
|
if a.Equal(relayAddr) {
|
|
return []ma.Multiaddr{publicQUIC2}
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
ObservedAddrsManager: &mockObservedAddrs{
|
|
ObservedAddrsForFunc: func(_ ma.Multiaddr) []ma.Multiaddr {
|
|
return []ma.Multiaddr{publicQUIC}
|
|
},
|
|
},
|
|
ListenAddrs: func() []ma.Multiaddr { return []ma.Multiaddr{lhquic, lhtcp} },
|
|
})
|
|
am.PushReachability(network.ReachabilityPrivate)
|
|
am.PushRelay([]ma.Multiaddr{relayAddr})
|
|
|
|
expectedAddrs := []ma.Multiaddr{publicQUIC2}
|
|
expectedAllAddrs := []ma.Multiaddr{publicQUIC, lhquic, lhtcp}
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
assert.ElementsMatch(collect, am.Addrs(), expectedAddrs, "%s\n%s", am.Addrs(), expectedAddrs)
|
|
assert.ElementsMatch(collect, am.DirectAddrs(), expectedAllAddrs, "%s\n%s", am.DirectAddrs(), expectedAllAddrs)
|
|
}, 5*time.Second, 50*time.Millisecond)
|
|
})
|
|
|
|
t.Run("updates addresses on signaling", func(t *testing.T) {
|
|
updateChan := make(chan struct{})
|
|
am := newAddrsManagerTestCase(t, addrsManagerArgs{
|
|
AddrsFactory: func(_ []ma.Multiaddr) []ma.Multiaddr {
|
|
select {
|
|
case <-updateChan:
|
|
return []ma.Multiaddr{publicQUIC}
|
|
default:
|
|
return []ma.Multiaddr{publicTCP}
|
|
}
|
|
},
|
|
ListenAddrs: func() []ma.Multiaddr { return []ma.Multiaddr{lhquic, lhtcp} },
|
|
})
|
|
require.Contains(t, am.Addrs(), publicTCP)
|
|
require.NotContains(t, am.Addrs(), publicQUIC)
|
|
close(updateChan)
|
|
am.triggerAddrsUpdate()
|
|
require.EventuallyWithT(t, func(collect *assert.CollectT) {
|
|
assert.Contains(collect, am.Addrs(), publicQUIC)
|
|
assert.NotContains(collect, am.Addrs(), publicTCP)
|
|
}, 1*time.Second, 50*time.Millisecond)
|
|
})
|
|
}
|
|
|
|
func TestAddrsManagerReachabilityEvent(t *testing.T) {
|
|
publicQUIC, _ := ma.NewMultiaddr("/ip4/1.2.3.4/udp/1234/quic-v1")
|
|
publicQUIC2, _ := ma.NewMultiaddr("/ip4/1.2.3.4/udp/1235/quic-v1")
|
|
publicTCP, _ := ma.NewMultiaddr("/ip4/1.2.3.4/tcp/1234")
|
|
|
|
bus := eventbus.NewBus()
|
|
|
|
sub, err := bus.Subscribe(new(event.EvtHostReachableAddrsChanged))
|
|
require.NoError(t, err)
|
|
defer sub.Close()
|
|
|
|
am := newAddrsManagerTestCase(t, addrsManagerArgs{
|
|
Bus: bus,
|
|
// currently they aren't being passed to the reachability tracker
|
|
ListenAddrs: func() []ma.Multiaddr { return []ma.Multiaddr{publicQUIC, publicQUIC2, publicTCP} },
|
|
AutoNATClient: mockAutoNATClient{
|
|
F: func(_ context.Context, reqs []autonatv2.Request) (autonatv2.Result, error) {
|
|
if reqs[0].Addr.Equal(publicQUIC) {
|
|
return autonatv2.Result{Addr: reqs[0].Addr, Idx: 0, Reachability: network.ReachabilityPublic}, nil
|
|
} else if reqs[0].Addr.Equal(publicTCP) || reqs[0].Addr.Equal(publicQUIC2) {
|
|
return autonatv2.Result{Addr: reqs[0].Addr, Idx: 0, Reachability: network.ReachabilityPrivate}, nil
|
|
}
|
|
return autonatv2.Result{}, errors.New("invalid")
|
|
},
|
|
},
|
|
})
|
|
|
|
initialUnknownAddrs := []ma.Multiaddr{publicQUIC, publicTCP, publicQUIC2}
|
|
|
|
// First event: all addresses are initially unknown
|
|
select {
|
|
case e := <-sub.Out():
|
|
evt := e.(event.EvtHostReachableAddrsChanged)
|
|
require.Empty(t, evt.Reachable)
|
|
require.Empty(t, evt.Unreachable)
|
|
require.ElementsMatch(t, initialUnknownAddrs, evt.Unknown)
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("expected initial event for reachability change")
|
|
}
|
|
|
|
// Wait for probes to complete and addresses to be classified
|
|
reachableAddrs := []ma.Multiaddr{publicQUIC}
|
|
unreachableAddrs := []ma.Multiaddr{publicTCP, publicQUIC2}
|
|
select {
|
|
case e := <-sub.Out():
|
|
evt := e.(event.EvtHostReachableAddrsChanged)
|
|
require.ElementsMatch(t, reachableAddrs, evt.Reachable)
|
|
require.ElementsMatch(t, unreachableAddrs, evt.Unreachable)
|
|
require.Empty(t, evt.Unknown)
|
|
reachable, unreachable, unknown := am.ConfirmedAddrs()
|
|
require.ElementsMatch(t, reachable, reachableAddrs)
|
|
require.ElementsMatch(t, unreachable, unreachableAddrs)
|
|
require.Empty(t, unknown)
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("expected final event for reachability change after probing")
|
|
}
|
|
}
|
|
|
|
func TestRemoveIfNotInSource(t *testing.T) {
|
|
var addrs []ma.Multiaddr
|
|
for i := 0; i < 10; i++ {
|
|
addrs = append(addrs, ma.StringCast(fmt.Sprintf("/ip4/1.2.3.4/tcp/%d", i)))
|
|
}
|
|
slices.SortFunc(addrs, func(a, b ma.Multiaddr) int { return a.Compare(b) })
|
|
cases := []struct {
|
|
addrs []ma.Multiaddr
|
|
source []ma.Multiaddr
|
|
expected []ma.Multiaddr
|
|
}{
|
|
{},
|
|
{addrs: slices.Clone(addrs[:5]), source: nil, expected: nil},
|
|
{addrs: nil, source: addrs, expected: nil},
|
|
{addrs: []ma.Multiaddr{addrs[0]}, source: []ma.Multiaddr{addrs[0]}, expected: []ma.Multiaddr{addrs[0]}},
|
|
{addrs: slices.Clone(addrs), source: []ma.Multiaddr{addrs[0]}, expected: []ma.Multiaddr{addrs[0]}},
|
|
{addrs: slices.Clone(addrs), source: slices.Clone(addrs[5:]), expected: slices.Clone(addrs[5:])},
|
|
{addrs: slices.Clone(addrs[:5]), source: []ma.Multiaddr{addrs[0], addrs[2], addrs[8]}, expected: []ma.Multiaddr{addrs[0], addrs[2]}},
|
|
}
|
|
for i, tc := range cases {
|
|
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
|
addrs := removeNotInSource(tc.addrs, tc.source)
|
|
require.ElementsMatch(t, tc.expected, addrs, "%s\n%s", tc.expected, tc.addrs)
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkAreAddrsDifferent(b *testing.B) {
|
|
var addrs [10]ma.Multiaddr
|
|
for i := 0; i < len(addrs); i++ {
|
|
addrs[i] = ma.StringCast(fmt.Sprintf("/ip4/1.1.1.%d/tcp/1", i))
|
|
}
|
|
b.Run("areAddrsDifferent", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
areAddrsDifferent(addrs[:], addrs[:])
|
|
}
|
|
})
|
|
}
|
|
|
|
func BenchmarkRemoveIfNotInSource(b *testing.B) {
|
|
var addrs [10]ma.Multiaddr
|
|
for i := 0; i < len(addrs); i++ {
|
|
addrs[i] = ma.StringCast(fmt.Sprintf("/ip4/1.1.1.%d/tcp/1", i))
|
|
}
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
removeNotInSource(slices.Clone(addrs[:5]), addrs[:])
|
|
}
|
|
}
|