mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-26 08:35:17 +00:00
437 lines
12 KiB
Go
437 lines
12 KiB
Go
package identify_test
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"testing"
|
|
"time"
|
|
|
|
ic "github.com/libp2p/go-libp2p/core/crypto"
|
|
"github.com/libp2p/go-libp2p/core/event"
|
|
"github.com/libp2p/go-libp2p/core/host"
|
|
"github.com/libp2p/go-libp2p/core/network"
|
|
"github.com/libp2p/go-libp2p/core/peer"
|
|
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
|
|
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
|
|
"github.com/libp2p/go-libp2p/p2p/protocol/identify"
|
|
|
|
ma "github.com/multiformats/go-multiaddr"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type harness struct {
|
|
t *testing.T
|
|
|
|
mocknet mocknet.Mocknet
|
|
host host.Host
|
|
|
|
oas *identify.ObservedAddrManager
|
|
}
|
|
|
|
func (h *harness) add(observer ma.Multiaddr) peer.ID {
|
|
// create a new fake peer.
|
|
sk, _, err := ic.GenerateECDSAKeyPair(rand.Reader)
|
|
if err != nil {
|
|
h.t.Fatal(err)
|
|
}
|
|
h2, err := h.mocknet.AddPeer(sk, observer)
|
|
if err != nil {
|
|
h.t.Fatal(err)
|
|
}
|
|
_, err = h.mocknet.LinkPeers(h.host.ID(), h2.ID())
|
|
if err != nil {
|
|
h.t.Fatal(err)
|
|
}
|
|
return h2.ID()
|
|
}
|
|
|
|
func (h *harness) conn(observer peer.ID) network.Conn {
|
|
c, err := h.mocknet.ConnectPeers(h.host.ID(), observer)
|
|
if err != nil {
|
|
h.t.Fatal(err)
|
|
}
|
|
if c.Stat().Direction != network.DirOutbound {
|
|
h.t.Fatal("expected conn direction to be outbound")
|
|
}
|
|
return c
|
|
}
|
|
|
|
func (h *harness) connInbound(observer peer.ID) network.Conn {
|
|
c, err := h.mocknet.ConnectPeers(observer, h.host.ID())
|
|
if err != nil {
|
|
h.t.Fatal(err)
|
|
}
|
|
|
|
c = mocknet.ConnComplement(c)
|
|
if c.Stat().Direction != network.DirInbound {
|
|
h.t.Fatal("expected conn direction to be inbound")
|
|
}
|
|
return c
|
|
}
|
|
|
|
func (h *harness) observe(observed ma.Multiaddr, observer peer.ID) network.Conn {
|
|
c := h.conn(observer)
|
|
h.oas.Record(c, observed)
|
|
time.Sleep(200 * time.Millisecond) // let the worker run
|
|
return c
|
|
}
|
|
|
|
func (h *harness) observeInbound(observed ma.Multiaddr, observer peer.ID) network.Conn {
|
|
c := h.connInbound(observer)
|
|
h.oas.Record(c, observed)
|
|
time.Sleep(200 * time.Millisecond) // let the worker run
|
|
return c
|
|
}
|
|
|
|
func newHarness(t *testing.T) harness {
|
|
return newHarnessWithMa(t, ma.StringCast("/ip4/127.0.0.1/tcp/10086"))
|
|
}
|
|
|
|
func newHarnessWithMa(t *testing.T, listenAddr ma.Multiaddr) harness {
|
|
mn := mocknet.New()
|
|
sk, _, err := ic.GenerateECDSAKeyPair(rand.Reader)
|
|
require.NoError(t, err)
|
|
h, err := mn.AddPeer(sk, listenAddr)
|
|
require.NoError(t, err)
|
|
oas, err := identify.NewObservedAddrManager(h)
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() {
|
|
mn.Close()
|
|
oas.Close()
|
|
})
|
|
return harness{
|
|
oas: oas,
|
|
mocknet: mn,
|
|
host: h,
|
|
t: t,
|
|
}
|
|
}
|
|
|
|
// TestObsAddrSet
|
|
func TestObsAddrSet(t *testing.T) {
|
|
addrsMatch := func(a, b []ma.Multiaddr) bool {
|
|
if len(a) != len(b) {
|
|
return false
|
|
}
|
|
for _, aa := range a {
|
|
if !ma.Contains(b, aa) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
a1 := ma.StringCast("/ip4/1.2.3.4/tcp/1231")
|
|
a2 := ma.StringCast("/ip4/1.2.3.4/tcp/1232")
|
|
a3 := ma.StringCast("/ip4/1.2.3.4/tcp/1233")
|
|
a4 := ma.StringCast("/ip4/1.2.3.4/tcp/1234")
|
|
a5 := ma.StringCast("/ip4/1.2.3.4/tcp/1235")
|
|
|
|
b1 := ma.StringCast("/ip4/1.2.3.6/tcp/1236")
|
|
b2 := ma.StringCast("/ip4/1.2.3.7/tcp/1237")
|
|
b3 := ma.StringCast("/ip4/1.2.3.8/tcp/1237")
|
|
b4 := ma.StringCast("/ip4/1.2.3.9/tcp/1237")
|
|
b5 := ma.StringCast("/ip4/1.2.3.10/tcp/1237")
|
|
|
|
harness := newHarness(t)
|
|
if !addrsMatch(harness.oas.Addrs(), nil) {
|
|
t.Error("addrs should be empty")
|
|
}
|
|
|
|
pa4 := harness.add(a4)
|
|
pa5 := harness.add(a5)
|
|
|
|
pb1 := harness.add(b1)
|
|
pb2 := harness.add(b2)
|
|
pb3 := harness.add(b3)
|
|
pb4 := harness.add(b4)
|
|
pb5 := harness.add(b5)
|
|
|
|
harness.observe(a1, pa4)
|
|
harness.observe(a2, pa4)
|
|
harness.observe(a3, pa4)
|
|
|
|
// these are all different so we should not yet get them.
|
|
if !addrsMatch(harness.oas.Addrs(), nil) {
|
|
t.Error("addrs should _still_ be empty (once)")
|
|
}
|
|
|
|
// same observer, so should not yet get them.
|
|
harness.observe(a1, pa4)
|
|
harness.observe(a2, pa4)
|
|
harness.observe(a3, pa4)
|
|
if !addrsMatch(harness.oas.Addrs(), nil) {
|
|
t.Error("addrs should _still_ be empty (same obs)")
|
|
}
|
|
|
|
// different observer, but same observer group.
|
|
harness.observe(a1, pa5)
|
|
harness.observe(a2, pa5)
|
|
harness.observe(a3, pa5)
|
|
if !addrsMatch(harness.oas.Addrs(), nil) {
|
|
t.Error("addrs should _still_ be empty (same obs group)")
|
|
}
|
|
|
|
harness.observe(a1, pb1)
|
|
harness.observe(a1, pb2)
|
|
harness.observe(a1, pb3)
|
|
if !addrsMatch(harness.oas.Addrs(), []ma.Multiaddr{a1}) {
|
|
t.Error("addrs should only have a1")
|
|
}
|
|
|
|
harness.observe(a2, pa5)
|
|
harness.observe(a1, pa5)
|
|
harness.observe(a1, pa5)
|
|
harness.observe(a2, pb1)
|
|
harness.observe(a1, pb1)
|
|
harness.observe(a1, pb1)
|
|
harness.observe(a2, pb2)
|
|
harness.observe(a1, pb2)
|
|
harness.observe(a1, pb2)
|
|
harness.observe(a2, pb4)
|
|
harness.observe(a2, pb5)
|
|
if !addrsMatch(harness.oas.Addrs(), []ma.Multiaddr{a1, a2}) {
|
|
t.Error("addrs should only have a1, a2")
|
|
}
|
|
|
|
// force a refresh.
|
|
harness.oas.SetTTL(time.Millisecond * 200)
|
|
require.Eventuallyf(t,
|
|
func() bool { return addrsMatch(harness.oas.Addrs(), []ma.Multiaddr{a1, a2}) },
|
|
time.Second,
|
|
50*time.Millisecond,
|
|
"addrs should only have %s, %s; have %s", a1, a2, harness.oas.Addrs(),
|
|
)
|
|
|
|
// disconnect from all but b5.
|
|
for _, p := range harness.host.Network().Peers() {
|
|
if p == pb5 {
|
|
continue
|
|
}
|
|
harness.host.Network().ClosePeer(p)
|
|
}
|
|
|
|
// Wait for all other addresses to time out.
|
|
// After that, we hould still have a2.
|
|
require.Eventuallyf(t,
|
|
func() bool { return addrsMatch(harness.oas.Addrs(), []ma.Multiaddr{a2}) },
|
|
time.Second,
|
|
50*time.Millisecond,
|
|
"should only have a2 (%s), have: %v", a2, harness.oas.Addrs(),
|
|
)
|
|
harness.host.Network().ClosePeer(pb5)
|
|
|
|
// wait for all addresses to timeout
|
|
require.Eventually(t,
|
|
func() bool { return len(harness.oas.Addrs()) == 0 },
|
|
400*time.Millisecond,
|
|
20*time.Millisecond,
|
|
"addrs should have timed out",
|
|
)
|
|
}
|
|
|
|
func TestObservedAddrFiltering(t *testing.T) {
|
|
harness := newHarness(t)
|
|
require.Empty(t, harness.oas.Addrs())
|
|
|
|
// IP4/TCP
|
|
it1 := ma.StringCast("/ip4/1.2.3.4/tcp/1231")
|
|
it2 := ma.StringCast("/ip4/1.2.3.4/tcp/1232")
|
|
it3 := ma.StringCast("/ip4/1.2.3.4/tcp/1233")
|
|
it4 := ma.StringCast("/ip4/1.2.3.4/tcp/1234")
|
|
it5 := ma.StringCast("/ip4/1.2.3.4/tcp/1235")
|
|
it6 := ma.StringCast("/ip4/1.2.3.4/tcp/1236")
|
|
it7 := ma.StringCast("/ip4/1.2.3.4/tcp/1237")
|
|
|
|
// observers
|
|
b1 := ma.StringCast("/ip4/1.2.3.6/tcp/1236")
|
|
b2 := ma.StringCast("/ip4/1.2.3.7/tcp/1237")
|
|
b3 := ma.StringCast("/ip4/1.2.3.8/tcp/1237")
|
|
b4 := ma.StringCast("/ip4/1.2.3.9/tcp/1237")
|
|
b5 := ma.StringCast("/ip4/1.2.3.10/tcp/1237")
|
|
|
|
b6 := ma.StringCast("/ip4/1.2.3.11/tcp/1237")
|
|
b7 := ma.StringCast("/ip4/1.2.3.12/tcp/1237")
|
|
|
|
// These are all observers in the same group.
|
|
b8 := ma.StringCast("/ip4/1.2.3.13/tcp/1237")
|
|
b9 := ma.StringCast("/ip4/1.2.3.13/tcp/1238")
|
|
b10 := ma.StringCast("/ip4/1.2.3.13/tcp/1239")
|
|
|
|
peers := []peer.ID{
|
|
harness.add(b1),
|
|
harness.add(b2),
|
|
harness.add(b3),
|
|
harness.add(b4),
|
|
harness.add(b5),
|
|
|
|
harness.add(b6),
|
|
harness.add(b7),
|
|
|
|
harness.add(b8),
|
|
harness.add(b9),
|
|
harness.add(b10),
|
|
}
|
|
for i := 0; i < 4; i++ {
|
|
harness.observe(it1, peers[i])
|
|
harness.observe(it2, peers[i])
|
|
harness.observe(it3, peers[i])
|
|
harness.observe(it4, peers[i])
|
|
harness.observe(it5, peers[i])
|
|
harness.observe(it6, peers[i])
|
|
harness.observe(it7, peers[i])
|
|
}
|
|
|
|
harness.observe(it1, peers[4])
|
|
harness.observe(it7, peers[4])
|
|
|
|
addrs := harness.oas.Addrs()
|
|
require.Len(t, addrs, 2)
|
|
require.Contains(t, addrs, it1)
|
|
require.Contains(t, addrs, it7)
|
|
|
|
// Bump the number of observations so 1 & 7 have 7 observations.
|
|
harness.observe(it1, peers[5])
|
|
harness.observe(it1, peers[6])
|
|
harness.observe(it7, peers[5])
|
|
harness.observe(it7, peers[6])
|
|
|
|
// Add an observation from IP 1.2.3.13
|
|
// 2 & 3 now have 5 observations
|
|
harness.observe(it2, peers[7])
|
|
harness.observe(it3, peers[7])
|
|
|
|
addrs = harness.oas.Addrs()
|
|
require.Len(t, addrs, 2)
|
|
require.Contains(t, addrs, it1)
|
|
require.Contains(t, addrs, it7)
|
|
|
|
// Add an inbound observation from IP 1.2.3.13, it should override the
|
|
// existing observation and it should make these addresses win even
|
|
// though we have fewer observations.
|
|
//
|
|
// 2 & 3 now have 6 observations.
|
|
harness.observeInbound(it2, peers[8])
|
|
harness.observeInbound(it3, peers[8])
|
|
addrs = harness.oas.Addrs()
|
|
require.Len(t, addrs, 2)
|
|
require.Contains(t, addrs, it2)
|
|
require.Contains(t, addrs, it3)
|
|
|
|
// Adding an outbound observation shouldn't "downgrade" it.
|
|
//
|
|
// 2 & 3 now have 7 observations.
|
|
harness.observe(it2, peers[9])
|
|
harness.observe(it3, peers[9])
|
|
addrs = harness.oas.Addrs()
|
|
require.Len(t, addrs, 2)
|
|
require.Contains(t, addrs, it2)
|
|
require.Contains(t, addrs, it3)
|
|
}
|
|
|
|
func TestEmitNATDeviceTypeSymmetric(t *testing.T) {
|
|
harness := newHarness(t)
|
|
require.Empty(t, harness.oas.Addrs())
|
|
emitter, err := harness.host.EventBus().Emitter(new(event.EvtLocalReachabilityChanged), eventbus.Stateful)
|
|
require.NoError(t, err)
|
|
require.NoError(t, emitter.Emit(event.EvtLocalReachabilityChanged{Reachability: network.ReachabilityPrivate}))
|
|
|
|
// TCP
|
|
it1 := ma.StringCast("/ip4/1.2.3.4/tcp/1231")
|
|
it2 := ma.StringCast("/ip4/1.2.3.4/tcp/1232")
|
|
it3 := ma.StringCast("/ip4/1.2.3.4/tcp/1233")
|
|
it4 := ma.StringCast("/ip4/1.2.3.4/tcp/1234")
|
|
|
|
// observers
|
|
b1 := ma.StringCast("/ip4/1.2.3.6/tcp/1236")
|
|
b2 := ma.StringCast("/ip4/1.2.3.7/tcp/1237")
|
|
b3 := ma.StringCast("/ip4/1.2.3.8/tcp/1237")
|
|
b4 := ma.StringCast("/ip4/1.2.3.9/tcp/1237")
|
|
|
|
peers := []peer.ID{
|
|
harness.add(b1),
|
|
harness.add(b2),
|
|
harness.add(b3),
|
|
harness.add(b4),
|
|
}
|
|
|
|
harness.observe(it1, peers[0])
|
|
harness.observe(it2, peers[1])
|
|
harness.observe(it3, peers[2])
|
|
harness.observe(it4, peers[3])
|
|
|
|
sub, err := harness.host.EventBus().Subscribe(new(event.EvtNATDeviceTypeChanged))
|
|
require.NoError(t, err)
|
|
select {
|
|
case ev := <-sub.Out():
|
|
evt := ev.(event.EvtNATDeviceTypeChanged)
|
|
require.Equal(t, network.NATDeviceTypeSymmetric, evt.NatDeviceType)
|
|
require.Equal(t, network.NATTransportTCP, evt.TransportProtocol)
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("did not get Symmetric NAT event")
|
|
}
|
|
|
|
}
|
|
|
|
func TestEmitNATDeviceTypeCone(t *testing.T) {
|
|
harness := newHarness(t)
|
|
require.Empty(t, harness.oas.Addrs())
|
|
emitter, err := harness.host.EventBus().Emitter(new(event.EvtLocalReachabilityChanged), eventbus.Stateful)
|
|
require.NoError(t, err)
|
|
require.NoError(t, emitter.Emit(event.EvtLocalReachabilityChanged{Reachability: network.ReachabilityPrivate}))
|
|
|
|
it1 := ma.StringCast("/ip4/1.2.3.4/tcp/1231")
|
|
it2 := ma.StringCast("/ip4/1.2.3.4/tcp/1231")
|
|
it3 := ma.StringCast("/ip4/1.2.3.4/tcp/1231")
|
|
it4 := ma.StringCast("/ip4/1.2.3.4/tcp/1231")
|
|
|
|
// observers
|
|
b1 := ma.StringCast("/ip4/1.2.3.6/tcp/1236")
|
|
b2 := ma.StringCast("/ip4/1.2.3.7/tcp/1237")
|
|
b3 := ma.StringCast("/ip4/1.2.3.8/tcp/1237")
|
|
b4 := ma.StringCast("/ip4/1.2.3.9/tcp/1237")
|
|
|
|
peers := []peer.ID{
|
|
harness.add(b1),
|
|
harness.add(b2),
|
|
harness.add(b3),
|
|
harness.add(b4),
|
|
}
|
|
|
|
harness.observe(it1, peers[0])
|
|
harness.observe(it2, peers[1])
|
|
harness.observe(it3, peers[2])
|
|
harness.observe(it4, peers[3])
|
|
|
|
sub, err := harness.host.EventBus().Subscribe(new(event.EvtNATDeviceTypeChanged))
|
|
require.NoError(t, err)
|
|
select {
|
|
case ev := <-sub.Out():
|
|
evt := ev.(event.EvtNATDeviceTypeChanged)
|
|
require.Equal(t, network.NATDeviceTypeCone, evt.NatDeviceType)
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("did not get Cone NAT event")
|
|
}
|
|
}
|
|
|
|
func TestObserveWebtransport(t *testing.T) {
|
|
listenAddr := ma.StringCast("/ip4/1.2.3.4/udp/9999/quic-v1/webtransport/certhash/uEgNmb28")
|
|
observedAddr := ma.StringCast("/ip4/1.2.3.4/udp/1231/quic-v1/webtransport")
|
|
|
|
harness := newHarnessWithMa(t, listenAddr)
|
|
|
|
pb1 := harness.add(ma.StringCast("/ip4/1.2.3.6/udp/1236/quic-v1/webtransport"))
|
|
pb2 := harness.add(ma.StringCast("/ip4/1.2.3.7/udp/1237/quic-v1/webtransport"))
|
|
pb3 := harness.add(ma.StringCast("/ip4/1.2.3.8/udp/1237/quic-v1/webtransport"))
|
|
pb4 := harness.add(ma.StringCast("/ip4/1.2.3.9/udp/1237/quic-v1/webtransport"))
|
|
pb5 := harness.add(ma.StringCast("/ip4/1.2.3.10/udp/1237/quic-v1/webtransport"))
|
|
|
|
harness.observe(observedAddr, pb1)
|
|
harness.observe(observedAddr, pb2)
|
|
harness.observe(observedAddr, pb3)
|
|
harness.observe(observedAddr, pb4)
|
|
harness.observe(observedAddr, pb5)
|
|
|
|
require.Equal(t, 1, len(harness.oas.Addrs()))
|
|
require.Equal(t, "/ip4/1.2.3.4/udp/1231/quic-v1/webtransport", harness.oas.Addrs()[0].String())
|
|
}
|