mirror of
https://github.com/libp2p/go-libp2p.git
synced 2025-09-26 20:21:26 +08:00
swarm: move AddCertHashes to swarm (#3330)
This commit is contained in:
@@ -12,11 +12,8 @@ import (
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/event"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/transport"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/basic/internal/backoff"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
|
||||
libp2pwebrtc "github.com/libp2p/go-libp2p/p2p/transport/webrtc"
|
||||
libp2pwebtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport"
|
||||
"github.com/libp2p/go-netroute"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
@@ -44,7 +41,7 @@ type addrsManager struct {
|
||||
natManager NATManager
|
||||
addrsFactory AddrsFactory
|
||||
listenAddrs func() []ma.Multiaddr
|
||||
transportForListening func(ma.Multiaddr) transport.Transport
|
||||
addCertHashes func([]ma.Multiaddr) []ma.Multiaddr
|
||||
observedAddrsManager observedAddrsManager
|
||||
interfaceAddrs *interfaceAddrsCache
|
||||
addrsReachabilityTracker *addrsReachabilityTracker
|
||||
@@ -74,7 +71,7 @@ func newAddrsManager(
|
||||
natmgr NATManager,
|
||||
addrsFactory AddrsFactory,
|
||||
listenAddrs func() []ma.Multiaddr,
|
||||
transportForListening func(ma.Multiaddr) transport.Transport,
|
||||
addCertHashes func([]ma.Multiaddr) []ma.Multiaddr,
|
||||
observedAddrsManager observedAddrsManager,
|
||||
addrsUpdatedChan chan struct{},
|
||||
client autonatv2Client,
|
||||
@@ -85,7 +82,7 @@ func newAddrsManager(
|
||||
as := &addrsManager{
|
||||
bus: bus,
|
||||
listenAddrs: listenAddrs,
|
||||
transportForListening: transportForListening,
|
||||
addCertHashes: addCertHashes,
|
||||
observedAddrsManager: observedAddrsManager,
|
||||
natManager: natmgr,
|
||||
addrsFactory: addrsFactory,
|
||||
@@ -514,51 +511,6 @@ func (a *addrsManager) appendObservedAddrs(dst []ma.Multiaddr, listenAddr ma.Mul
|
||||
return dst
|
||||
}
|
||||
|
||||
func (a *addrsManager) addCertHashes(addrs []ma.Multiaddr) []ma.Multiaddr {
|
||||
if a.transportForListening == nil {
|
||||
return addrs
|
||||
}
|
||||
|
||||
// TODO(sukunrt): Move this to swarm.
|
||||
// There are two parts to determining our external address
|
||||
// 1. From the NAT device, or identify, or other such STUN like mechanism.
|
||||
// All that matters here is (internal_ip, internal_port, tcp) => (external_ip, external_port, tcp)
|
||||
// The rest of the address should be cut and appended to the external one.
|
||||
// 2. The user provides us with the address (/ip4/1.2.3.4/udp/1/webrtc-direct) and we add the certhash.
|
||||
// This API should be where the transports are, i.e. swarm.
|
||||
//
|
||||
// It would have been nice to remove this completely and just work with
|
||||
// mapping the interface thinwaist addresses (tcp, 192.168.18.18:4000 => 1.2.3.4:4577)
|
||||
// but that is only convenient if we're using the same port for listening on
|
||||
// all transports which share the same thinwaist protocol. If you listen
|
||||
// on 4001 for tcp, and 4002 for websocket, then it's a terrible API.
|
||||
type addCertHasher interface {
|
||||
AddCertHashes(m ma.Multiaddr) (ma.Multiaddr, bool)
|
||||
}
|
||||
|
||||
for i, addr := range addrs {
|
||||
wtOK, wtN := libp2pwebtransport.IsWebtransportMultiaddr(addr)
|
||||
webrtcOK, webrtcN := libp2pwebrtc.IsWebRTCDirectMultiaddr(addr)
|
||||
if (wtOK && wtN == 0) || (webrtcOK && webrtcN == 0) {
|
||||
t := a.transportForListening(addr)
|
||||
if t == nil {
|
||||
continue
|
||||
}
|
||||
tpt, ok := t.(addCertHasher)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
addrWithCerthash, added := tpt.AddCertHashes(addr)
|
||||
if !added {
|
||||
log.Warnf("Couldn't add certhashes to multiaddr: %s", addr)
|
||||
continue
|
||||
}
|
||||
addrs[i] = addrWithCerthash
|
||||
}
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
|
||||
func areAddrsDifferent(prev, current []ma.Multiaddr) bool {
|
||||
// TODO: make the sorted nature of ma.Unique a guarantee in multiaddrs
|
||||
prev = ma.Unique(prev)
|
||||
|
@@ -177,6 +177,7 @@ type addrsManagerArgs struct {
|
||||
AddrsFactory AddrsFactory
|
||||
ObservedAddrsManager observedAddrsManager
|
||||
ListenAddrs func() []ma.Multiaddr
|
||||
AddCertHashes func([]ma.Multiaddr) []ma.Multiaddr
|
||||
AutoNATClient autonatv2Client
|
||||
Bus event.Bus
|
||||
}
|
||||
@@ -196,8 +197,15 @@ func newAddrsManagerTestCase(t *testing.T, args addrsManagerArgs) addrsManagerTe
|
||||
args.AddrsFactory = func(addrs []ma.Multiaddr) []ma.Multiaddr { return addrs }
|
||||
}
|
||||
addrsUpdatedChan := make(chan struct{}, 1)
|
||||
|
||||
addCertHashes := func(addrs []ma.Multiaddr) []ma.Multiaddr {
|
||||
return addrs
|
||||
}
|
||||
if args.AddCertHashes != nil {
|
||||
addCertHashes = args.AddCertHashes
|
||||
}
|
||||
am, err := newAddrsManager(
|
||||
eb, args.NATManager, args.AddrsFactory, args.ListenAddrs, nil, args.ObservedAddrsManager, addrsUpdatedChan, args.AutoNATClient, true, prometheus.DefaultRegisterer,
|
||||
eb, args.NATManager, args.AddrsFactory, args.ListenAddrs, addCertHashes, args.ObservedAddrsManager, addrsUpdatedChan, args.AutoNATClient, true, prometheus.DefaultRegisterer,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@@ -18,7 +18,6 @@ import (
|
||||
"github.com/libp2p/go-libp2p/core/peerstore"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
"github.com/libp2p/go-libp2p/core/record"
|
||||
"github.com/libp2p/go-libp2p/core/transport"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/autonat"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/pstoremanager"
|
||||
@@ -232,12 +231,6 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) {
|
||||
if opts.NATManager != nil {
|
||||
natmgr = opts.NATManager(h.Network())
|
||||
}
|
||||
var tfl func(ma.Multiaddr) transport.Transport
|
||||
if s, ok := h.Network().(interface {
|
||||
TransportForListening(ma.Multiaddr) transport.Transport
|
||||
}); ok {
|
||||
tfl = s.TransportForListening
|
||||
}
|
||||
|
||||
if opts.AutoNATv2 != nil {
|
||||
h.autonatv2 = opts.AutoNATv2
|
||||
@@ -247,12 +240,23 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) {
|
||||
if h.autonatv2 != nil {
|
||||
autonatv2Client = h.autonatv2
|
||||
}
|
||||
|
||||
// Create addCertHashes function with interface assertion for swarm
|
||||
addCertHashesFunc := func(addrs []ma.Multiaddr) []ma.Multiaddr {
|
||||
return addrs
|
||||
}
|
||||
if swarm, ok := h.Network().(interface {
|
||||
AddCertHashes(addrs []ma.Multiaddr) []ma.Multiaddr
|
||||
}); ok {
|
||||
addCertHashesFunc = swarm.AddCertHashes
|
||||
}
|
||||
|
||||
h.addressManager, err = newAddrsManager(
|
||||
h.eventbus,
|
||||
natmgr,
|
||||
addrFactory,
|
||||
h.Network().ListenAddresses,
|
||||
tfl,
|
||||
addCertHashesFunc,
|
||||
h.ids,
|
||||
h.addrsUpdatedChan,
|
||||
autonatv2Client,
|
||||
|
@@ -961,3 +961,31 @@ func (r ResolverFromMaDNS) ResolveDNSComponent(ctx context.Context, maddr ma.Mul
|
||||
}
|
||||
return addrs, nil
|
||||
}
|
||||
|
||||
// AddCertHashes adds certificate hashes to relevant transport addresses, if there
|
||||
// are no certhashes already present on the method. It mutates `listenAddrs`.
|
||||
// This method is useful for adding certhashes to public addresses discovered
|
||||
// via identify, nat mapping, or provided by the user.
|
||||
func (s *Swarm) AddCertHashes(listenAddrs []ma.Multiaddr) []ma.Multiaddr {
|
||||
type addCertHasher interface {
|
||||
AddCertHashes(m ma.Multiaddr) (ma.Multiaddr, bool)
|
||||
}
|
||||
|
||||
for i, addr := range listenAddrs {
|
||||
t := s.TransportForListening(addr)
|
||||
if t == nil {
|
||||
continue
|
||||
}
|
||||
tpt, ok := t.(addCertHasher)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
addrWithCerthash, added := tpt.AddCertHashes(addr)
|
||||
if !added {
|
||||
log.Warnf("Couldn't add certhashes to multiaddr: %s", addr)
|
||||
continue
|
||||
}
|
||||
listenAddrs[i] = addrWithCerthash
|
||||
}
|
||||
return listenAddrs
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -567,3 +568,61 @@ func TestListenCloseCount(t *testing.T) {
|
||||
_, err := remainingAddrs[0].ValueForProtocol(ma.P_TCP)
|
||||
require.NoError(t, err, "expected the TCP address to still be present")
|
||||
}
|
||||
|
||||
func TestAddCertHashes(t *testing.T) {
|
||||
s := GenSwarm(t)
|
||||
|
||||
listenAddrs := s.ListenAddresses()
|
||||
splitCertHashes := func(a ma.Multiaddr) (prefix, certhashes ma.Multiaddr, ok bool) {
|
||||
for i, c := range a {
|
||||
if c.Protocol().Code == ma.P_CERTHASH {
|
||||
return prefix, a[i:], true
|
||||
}
|
||||
prefix = append(prefix, c)
|
||||
}
|
||||
return prefix, certhashes, false
|
||||
}
|
||||
addrWithNewIPPort := func(addr ma.Multiaddr, newIPPort ma.Multiaddr) ma.Multiaddr {
|
||||
a := slices.Clone(addr)
|
||||
a[0] = newIPPort[0]
|
||||
a[1] = newIPPort[1]
|
||||
return a
|
||||
}
|
||||
publicIPPort := []ma.Multiaddr{
|
||||
ma.StringCast("/ip4/1.1.1.1/udp/1"),
|
||||
ma.StringCast("/ip4/1.2.3.4/udp/1"),
|
||||
ma.StringCast("/ip6/2005::/udp/1"),
|
||||
}
|
||||
|
||||
certHashComponent := ma.StringCast("/certhash/uEgNmb28")
|
||||
for _, a := range listenAddrs {
|
||||
prefix, certhashes, ok := splitCertHashes(a)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
var publicAddrs []ma.Multiaddr
|
||||
for _, tc := range publicIPPort {
|
||||
publicAddrs = append(publicAddrs, addrWithNewIPPort(prefix, tc))
|
||||
}
|
||||
finalAddrs := s.AddCertHashes(publicAddrs)
|
||||
for _, a := range finalAddrs {
|
||||
_, certhash2, ok := splitCertHashes(a)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, certhashes, certhash2)
|
||||
}
|
||||
|
||||
// if the addr has a certhash already, check it isn't modified
|
||||
publicAddrs = nil
|
||||
for _, tc := range publicIPPort {
|
||||
a := addrWithNewIPPort(prefix, tc)
|
||||
a = append(a, certHashComponent...)
|
||||
publicAddrs = append(publicAddrs, a)
|
||||
}
|
||||
finalAddrs = s.AddCertHashes(publicAddrs)
|
||||
for _, a := range finalAddrs {
|
||||
_, certhash2, ok := splitCertHashes(a)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, certHashComponent, certhash2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user