mirror of
				https://source.quilibrium.com/quilibrium/ceremonyclient.git
				synced 2025-11-04 13:27:27 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			376 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			376 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package swarm
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"context"
 | 
						|
	"crypto/rand"
 | 
						|
	"net"
 | 
						|
	"sort"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/libp2p/go-libp2p/core/crypto"
 | 
						|
	"github.com/libp2p/go-libp2p/core/network"
 | 
						|
	"github.com/libp2p/go-libp2p/core/peer"
 | 
						|
	"github.com/libp2p/go-libp2p/core/peerstore"
 | 
						|
	"github.com/libp2p/go-libp2p/core/test"
 | 
						|
	"github.com/libp2p/go-libp2p/p2p/host/eventbus"
 | 
						|
	"github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem"
 | 
						|
	libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic"
 | 
						|
	"github.com/libp2p/go-libp2p/p2p/transport/quicreuse"
 | 
						|
	"github.com/libp2p/go-libp2p/p2p/transport/tcp"
 | 
						|
	"github.com/libp2p/go-libp2p/p2p/transport/websocket"
 | 
						|
	libp2pwebtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport"
 | 
						|
	"github.com/quic-go/quic-go"
 | 
						|
 | 
						|
	ma "github.com/multiformats/go-multiaddr"
 | 
						|
	madns "github.com/multiformats/go-multiaddr-dns"
 | 
						|
	"github.com/stretchr/testify/require"
 | 
						|
)
 | 
						|
 | 
						|
func TestAddrsForDial(t *testing.T) {
 | 
						|
	mockResolver := madns.MockResolver{IP: make(map[string][]net.IPAddr)}
 | 
						|
	ipaddr, err := net.ResolveIPAddr("ip4", "1.2.3.4")
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
	mockResolver.IP["example.com"] = []net.IPAddr{*ipaddr}
 | 
						|
 | 
						|
	resolver, err := madns.NewResolver(madns.WithDomainResolver("example.com", &mockResolver))
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
 | 
						|
	priv, _, err := crypto.GenerateEd25519Key(rand.Reader)
 | 
						|
	require.NoError(t, err)
 | 
						|
	id, err := peer.IDFromPrivateKey(priv)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	ps, err := pstoremem.NewPeerstore()
 | 
						|
	require.NoError(t, err)
 | 
						|
	ps.AddPubKey(id, priv.GetPublic())
 | 
						|
	ps.AddPrivKey(id, priv)
 | 
						|
	t.Cleanup(func() { ps.Close() })
 | 
						|
 | 
						|
	tpt, err := websocket.New(nil, &network.NullResourceManager{})
 | 
						|
	require.NoError(t, err)
 | 
						|
	s, err := NewSwarm(id, ps, eventbus.NewBus(), WithMultiaddrResolver(resolver))
 | 
						|
	require.NoError(t, err)
 | 
						|
	defer s.Close()
 | 
						|
	err = s.AddTransport(tpt)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	otherPeer := test.RandPeerIDFatal(t)
 | 
						|
 | 
						|
	ps.AddAddr(otherPeer, ma.StringCast("/dns4/example.com/tcp/1234/wss"), time.Hour)
 | 
						|
 | 
						|
	ctx := context.Background()
 | 
						|
	mas, err := s.addrsForDial(ctx, otherPeer)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	require.NotZero(t, len(mas))
 | 
						|
}
 | 
						|
 | 
						|
func TestDedupAddrsForDial(t *testing.T) {
 | 
						|
	mockResolver := madns.MockResolver{IP: make(map[string][]net.IPAddr)}
 | 
						|
	ipaddr, err := net.ResolveIPAddr("ip4", "1.2.3.4")
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
	mockResolver.IP["example.com"] = []net.IPAddr{*ipaddr}
 | 
						|
 | 
						|
	resolver, err := madns.NewResolver(madns.WithDomainResolver("example.com", &mockResolver))
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
 | 
						|
	priv, _, err := crypto.GenerateEd25519Key(rand.Reader)
 | 
						|
	require.NoError(t, err)
 | 
						|
	id, err := peer.IDFromPrivateKey(priv)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	ps, err := pstoremem.NewPeerstore()
 | 
						|
	require.NoError(t, err)
 | 
						|
	ps.AddPubKey(id, priv.GetPublic())
 | 
						|
	ps.AddPrivKey(id, priv)
 | 
						|
	t.Cleanup(func() { ps.Close() })
 | 
						|
 | 
						|
	s, err := NewSwarm(id, ps, eventbus.NewBus(), WithMultiaddrResolver(resolver))
 | 
						|
	require.NoError(t, err)
 | 
						|
	defer s.Close()
 | 
						|
 | 
						|
	tpt, err := tcp.NewTCPTransport(nil, &network.NullResourceManager{})
 | 
						|
	require.NoError(t, err)
 | 
						|
	err = s.AddTransport(tpt)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	otherPeer := test.RandPeerIDFatal(t)
 | 
						|
 | 
						|
	ps.AddAddr(otherPeer, ma.StringCast("/dns4/example.com/tcp/1234"), time.Hour)
 | 
						|
	ps.AddAddr(otherPeer, ma.StringCast("/ip4/1.2.3.4/tcp/1234"), time.Hour)
 | 
						|
 | 
						|
	ctx := context.Background()
 | 
						|
	mas, err := s.addrsForDial(ctx, otherPeer)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	require.Equal(t, 1, len(mas))
 | 
						|
}
 | 
						|
 | 
						|
func newTestSwarmWithResolver(t *testing.T, resolver *madns.Resolver) *Swarm {
 | 
						|
	priv, _, err := crypto.GenerateEd25519Key(rand.Reader)
 | 
						|
	require.NoError(t, err)
 | 
						|
	id, err := peer.IDFromPrivateKey(priv)
 | 
						|
	require.NoError(t, err)
 | 
						|
	ps, err := pstoremem.NewPeerstore()
 | 
						|
	require.NoError(t, err)
 | 
						|
	ps.AddPubKey(id, priv.GetPublic())
 | 
						|
	ps.AddPrivKey(id, priv)
 | 
						|
	t.Cleanup(func() { ps.Close() })
 | 
						|
	s, err := NewSwarm(id, ps, eventbus.NewBus(), WithMultiaddrResolver(resolver))
 | 
						|
	require.NoError(t, err)
 | 
						|
	t.Cleanup(func() {
 | 
						|
		s.Close()
 | 
						|
	})
 | 
						|
 | 
						|
	// Add a tcp transport so that we know we can dial a tcp multiaddr and we don't filter it out.
 | 
						|
	tpt, err := tcp.NewTCPTransport(nil, &network.NullResourceManager{})
 | 
						|
	require.NoError(t, err)
 | 
						|
	err = s.AddTransport(tpt)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	connmgr, err := quicreuse.NewConnManager(quic.StatelessResetKey{})
 | 
						|
	require.NoError(t, err)
 | 
						|
	quicTpt, err := libp2pquic.NewTransport(priv, connmgr, nil, nil, &network.NullResourceManager{})
 | 
						|
	require.NoError(t, err)
 | 
						|
	err = s.AddTransport(quicTpt)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	wtTpt, err := libp2pwebtransport.New(priv, nil, connmgr, nil, &network.NullResourceManager{})
 | 
						|
	require.NoError(t, err)
 | 
						|
	err = s.AddTransport(wtTpt)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	wsTpt, err := websocket.New(nil, &network.NullResourceManager{})
 | 
						|
	require.NoError(t, err)
 | 
						|
	err = s.AddTransport(wsTpt)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	return s
 | 
						|
}
 | 
						|
 | 
						|
func TestAddrResolution(t *testing.T) {
 | 
						|
	ctx := context.Background()
 | 
						|
 | 
						|
	p1 := test.RandPeerIDFatal(t)
 | 
						|
	p2 := test.RandPeerIDFatal(t)
 | 
						|
	addr1 := ma.StringCast("/dnsaddr/example.com")
 | 
						|
	addr2 := ma.StringCast("/ip4/192.0.2.1/tcp/123")
 | 
						|
 | 
						|
	p2paddr2 := ma.StringCast("/ip4/192.0.2.1/tcp/123/p2p/" + p1.Pretty())
 | 
						|
	p2paddr3 := ma.StringCast("/ip4/192.0.2.1/tcp/123/p2p/" + p2.Pretty())
 | 
						|
 | 
						|
	backend := &madns.MockResolver{
 | 
						|
		TXT: map[string][]string{"_dnsaddr.example.com": {
 | 
						|
			"dnsaddr=" + p2paddr2.String(), "dnsaddr=" + p2paddr3.String(),
 | 
						|
		}},
 | 
						|
	}
 | 
						|
	resolver, err := madns.NewResolver(madns.WithDefaultResolver(backend))
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	s := newTestSwarmWithResolver(t, resolver)
 | 
						|
 | 
						|
	s.peers.AddAddr(p1, addr1, time.Hour)
 | 
						|
 | 
						|
	tctx, cancel := context.WithTimeout(ctx, time.Millisecond*100)
 | 
						|
	defer cancel()
 | 
						|
	mas, err := s.addrsForDial(tctx, p1)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	require.Len(t, mas, 1)
 | 
						|
	require.Contains(t, mas, addr2)
 | 
						|
 | 
						|
	addrs := s.peers.Addrs(p1)
 | 
						|
	require.Len(t, addrs, 2)
 | 
						|
	require.Contains(t, addrs, addr1)
 | 
						|
	require.Contains(t, addrs, addr2)
 | 
						|
}
 | 
						|
 | 
						|
func TestAddrResolutionRecursive(t *testing.T) {
 | 
						|
	ctx := context.Background()
 | 
						|
 | 
						|
	p1, err := test.RandPeerID()
 | 
						|
	if err != nil {
 | 
						|
		t.Error(err)
 | 
						|
	}
 | 
						|
	p2, err := test.RandPeerID()
 | 
						|
	if err != nil {
 | 
						|
		t.Error(err)
 | 
						|
	}
 | 
						|
	addr1 := ma.StringCast("/dnsaddr/example.com")
 | 
						|
	addr2 := ma.StringCast("/ip4/192.0.2.1/tcp/123")
 | 
						|
	p2paddr1 := ma.StringCast("/dnsaddr/example.com/p2p/" + p1.Pretty())
 | 
						|
	p2paddr2 := ma.StringCast("/dnsaddr/example.com/p2p/" + p2.Pretty())
 | 
						|
	p2paddr1i := ma.StringCast("/dnsaddr/foo.example.com/p2p/" + p1.Pretty())
 | 
						|
	p2paddr2i := ma.StringCast("/dnsaddr/bar.example.com/p2p/" + p2.Pretty())
 | 
						|
	p2paddr1f := ma.StringCast("/ip4/192.0.2.1/tcp/123/p2p/" + p1.Pretty())
 | 
						|
 | 
						|
	backend := &madns.MockResolver{
 | 
						|
		TXT: map[string][]string{
 | 
						|
			"_dnsaddr.example.com": {
 | 
						|
				"dnsaddr=" + p2paddr1i.String(),
 | 
						|
				"dnsaddr=" + p2paddr2i.String(),
 | 
						|
			},
 | 
						|
			"_dnsaddr.foo.example.com": {
 | 
						|
				"dnsaddr=" + p2paddr1f.String(),
 | 
						|
			},
 | 
						|
			"_dnsaddr.bar.example.com": {
 | 
						|
				"dnsaddr=" + p2paddr2i.String(),
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
	resolver, err := madns.NewResolver(madns.WithDefaultResolver(backend))
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
 | 
						|
	s := newTestSwarmWithResolver(t, resolver)
 | 
						|
 | 
						|
	pi1, err := peer.AddrInfoFromP2pAddr(p2paddr1)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	tctx, cancel := context.WithTimeout(ctx, time.Millisecond*100)
 | 
						|
	defer cancel()
 | 
						|
	s.Peerstore().AddAddrs(pi1.ID, pi1.Addrs, peerstore.TempAddrTTL)
 | 
						|
	_, err = s.addrsForDial(tctx, p1)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	addrs1 := s.Peerstore().Addrs(pi1.ID)
 | 
						|
	require.Len(t, addrs1, 2)
 | 
						|
	require.Contains(t, addrs1, addr1)
 | 
						|
	require.Contains(t, addrs1, addr2)
 | 
						|
 | 
						|
	pi2, err := peer.AddrInfoFromP2pAddr(p2paddr2)
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	s.Peerstore().AddAddrs(pi2.ID, pi2.Addrs, peerstore.TempAddrTTL)
 | 
						|
	_, err = s.addrsForDial(tctx, p2)
 | 
						|
	// This never resolves to a good address
 | 
						|
	require.Equal(t, ErrNoGoodAddresses, err)
 | 
						|
 | 
						|
	addrs2 := s.Peerstore().Addrs(pi2.ID)
 | 
						|
	require.Len(t, addrs2, 1)
 | 
						|
	require.Contains(t, addrs2, addr1)
 | 
						|
}
 | 
						|
 | 
						|
func TestAddrsForDialFiltering(t *testing.T) {
 | 
						|
	q1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic")
 | 
						|
	q1v1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1")
 | 
						|
	wt1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1/webtransport/")
 | 
						|
 | 
						|
	q2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic")
 | 
						|
	q2v1 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1")
 | 
						|
	wt2 := ma.StringCast("/ip4/1.2.3.4/udp/2/quic-v1/webtransport/")
 | 
						|
 | 
						|
	q3 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic")
 | 
						|
 | 
						|
	t1 := ma.StringCast("/ip4/1.2.3.4/tcp/1")
 | 
						|
	ws1 := ma.StringCast("/ip4/1.2.3.4/tcp/1/ws")
 | 
						|
 | 
						|
	resolver, err := madns.NewResolver(madns.WithDefaultResolver(&madns.MockResolver{}))
 | 
						|
	require.NoError(t, err)
 | 
						|
	s := newTestSwarmWithResolver(t, resolver)
 | 
						|
	ourAddrs := s.ListenAddresses()
 | 
						|
 | 
						|
	testCases := []struct {
 | 
						|
		name   string
 | 
						|
		input  []ma.Multiaddr
 | 
						|
		output []ma.Multiaddr
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name:   "quic-filtered",
 | 
						|
			input:  []ma.Multiaddr{q1, q1v1, q2, q2v1, q3},
 | 
						|
			output: []ma.Multiaddr{q1v1, q2v1, q3},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:   "webtransport-filtered",
 | 
						|
			input:  []ma.Multiaddr{q1, q1v1, wt1, wt2},
 | 
						|
			output: []ma.Multiaddr{q1v1, wt2},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:   "all",
 | 
						|
			input:  []ma.Multiaddr{q1, q1v1, wt1, q2, q2v1, wt2, t1, ws1},
 | 
						|
			output: []ma.Multiaddr{q1v1, q2v1, t1},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:   "our-addrs-filtered",
 | 
						|
			input:  append([]ma.Multiaddr{q1}, ourAddrs...),
 | 
						|
			output: []ma.Multiaddr{q1},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	ctx := context.Background()
 | 
						|
	p1 := test.RandPeerIDFatal(t)
 | 
						|
 | 
						|
	for _, tc := range testCases {
 | 
						|
		t.Run(tc.name, func(t *testing.T) {
 | 
						|
			s.Peerstore().ClearAddrs(p1)
 | 
						|
			s.Peerstore().AddAddrs(p1, tc.input, peerstore.PermanentAddrTTL)
 | 
						|
			result, err := s.addrsForDial(ctx, p1)
 | 
						|
			require.NoError(t, err)
 | 
						|
			sort.Slice(result, func(i, j int) bool { return bytes.Compare(result[i].Bytes(), result[j].Bytes()) < 0 })
 | 
						|
			sort.Slice(tc.output, func(i, j int) bool { return bytes.Compare(tc.output[i].Bytes(), tc.output[j].Bytes()) < 0 })
 | 
						|
			if len(result) != len(tc.output) {
 | 
						|
				t.Fatalf("output mismatch got: %s want: %s", result, tc.output)
 | 
						|
			}
 | 
						|
			for i := 0; i < len(result); i++ {
 | 
						|
				if !result[i].Equal(tc.output[i]) {
 | 
						|
					t.Fatalf("output mismatch got: %s want: %s", result, tc.output)
 | 
						|
				}
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestBlackHoledAddrBlocked(t *testing.T) {
 | 
						|
	resolver, err := madns.NewResolver()
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
	s := newTestSwarmWithResolver(t, resolver)
 | 
						|
	defer s.Close()
 | 
						|
 | 
						|
	n := 3
 | 
						|
	s.bhd.ipv6 = &blackHoleFilter{n: n, minSuccesses: 1, name: "IPv6"}
 | 
						|
 | 
						|
	// all dials to the address will fail. RFC6666 Discard Prefix
 | 
						|
	addr := ma.StringCast("/ip6/0100::1/tcp/54321/")
 | 
						|
 | 
						|
	p, err := test.RandPeerID()
 | 
						|
	if err != nil {
 | 
						|
		t.Error(err)
 | 
						|
	}
 | 
						|
	s.Peerstore().AddAddr(p, addr, peerstore.PermanentAddrTTL)
 | 
						|
 | 
						|
	// do 1 extra dial to ensure that the blackHoleDetector state is updated since it
 | 
						|
	// happens in a different goroutine
 | 
						|
	for i := 0; i < n+1; i++ {
 | 
						|
		s.backf.Clear(p)
 | 
						|
		ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
 | 
						|
		conn, err := s.DialPeer(ctx, p)
 | 
						|
		if err == nil || conn != nil {
 | 
						|
			t.Fatalf("expected dial to fail")
 | 
						|
		}
 | 
						|
		cancel()
 | 
						|
	}
 | 
						|
	s.backf.Clear(p)
 | 
						|
	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
 | 
						|
	defer cancel()
 | 
						|
	conn, err := s.DialPeer(ctx, p)
 | 
						|
	if conn != nil {
 | 
						|
		t.Fatalf("expected dial to be blocked")
 | 
						|
	}
 | 
						|
	if err != ErrNoGoodAddresses {
 | 
						|
		t.Fatalf("expected to receive an error of type *DialError, got %s of type %T", err, err)
 | 
						|
	}
 | 
						|
}
 |