diff --git a/p2p/host/autorelay/addrsplosion.go b/p2p/host/autorelay/addrsplosion.go deleted file mode 100644 index 13e6274b71..0000000000 --- a/p2p/host/autorelay/addrsplosion.go +++ /dev/null @@ -1,158 +0,0 @@ -package autorelay - -import ( - "encoding/binary" - - ma "github.com/multiformats/go-multiaddr" - manet "github.com/multiformats/go-multiaddr/net" -) - -// This function cleans up a relay's address set to remove private addresses and curtail -// addrsplosion. -// TODO: Remove this, we don't need this. The current method tries to select the -// best address for the relay. Instead we should rely on the addresses provided by the -// relay in response to the reservation request. -func cleanupAddressSet(addrs []ma.Multiaddr) []ma.Multiaddr { - var public, private []ma.Multiaddr - - for _, a := range addrs { - if isRelayAddr(a) { - continue - } - - if manet.IsPublicAddr(a) { - public = append(public, a) - continue - } - - // discard unroutable addrs - if manet.IsPrivateAddr(a) { - private = append(private, a) - } - } - - if !hasAddrsplosion(public) { - return public - } - - return sanitizeAddrsplodedSet(public, private) -} - -func isRelayAddr(a ma.Multiaddr) bool { - isRelay := false - - ma.ForEach(a, func(c ma.Component) bool { - switch c.Protocol().Code { - case ma.P_CIRCUIT: - isRelay = true - return false - default: - return true - } - }) - - return isRelay -} - -// we have addrsplosion if for some protocol we advertise multiple ports on -// the same base address. -func hasAddrsplosion(addrs []ma.Multiaddr) bool { - aset := make(map[string]int) - - for _, a := range addrs { - key, port := addrKeyAndPort(a) - xport, ok := aset[key] - if ok && port != xport { - return true - } - aset[key] = port - } - - return false -} - -func addrKeyAndPort(a ma.Multiaddr) (string, int) { - var ( - key string - port int - ) - - ma.ForEach(a, func(c ma.Component) bool { - switch c.Protocol().Code { - case ma.P_TCP, ma.P_UDP: - port = int(binary.BigEndian.Uint16(c.RawValue())) - key += "/" + c.Protocol().Name - default: - val := c.Value() - if val == "" { - val = c.Protocol().Name - } - key += "/" + val - } - return true - }) - - return key, port -} - -// clean up addrsplosion -// the following heuristic is used: -// - for each base address/protocol combination, if there are multiple ports advertised then -// only accept the default port if present. -// - If the default port is not present, we check for non-standard ports by tracking -// private port bindings if present. -// - If there is no default or private port binding, then we can't infer the correct -// port and give up and return all addrs (for that base address) -func sanitizeAddrsplodedSet(public, private []ma.Multiaddr) []ma.Multiaddr { - type portAndAddr struct { - addr ma.Multiaddr - port int - } - - privports := make(map[int]struct{}) - pubaddrs := make(map[string][]portAndAddr) - - for _, a := range private { - _, port := addrKeyAndPort(a) - privports[port] = struct{}{} - } - - for _, a := range public { - key, port := addrKeyAndPort(a) - pubaddrs[key] = append(pubaddrs[key], portAndAddr{addr: a, port: port}) - } - - var result []ma.Multiaddr - for _, pas := range pubaddrs { - if len(pas) == 1 { - // it's not addrsploded - result = append(result, pas[0].addr) - continue - } - - haveAddr := false - for _, pa := range pas { - if _, ok := privports[pa.port]; ok { - // it matches a privately bound port, use it - result = append(result, pa.addr) - haveAddr = true - continue - } - - if pa.port == 4001 || pa.port == 4002 { - // it's a default port, use it - result = append(result, pa.addr) - haveAddr = true - } - } - - if !haveAddr { - // we weren't able to select a port; bite the bullet and use them all - for _, pa := range pas { - result = append(result, pa.addr) - } - } - } - - return result -} diff --git a/p2p/host/autorelay/addrsplosion_test.go b/p2p/host/autorelay/addrsplosion_test.go deleted file mode 100644 index 19425c555e..0000000000 --- a/p2p/host/autorelay/addrsplosion_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package autorelay - -import ( - "testing" - - ma "github.com/multiformats/go-multiaddr" - matest "github.com/multiformats/go-multiaddr/matest" -) - -func TestCleanupAddrs(t *testing.T) { - t.Run("with no addrplosion", func(t *testing.T) { - addrs := makeAddrList( - "/ip4/127.0.0.1/tcp/4001", - "/ip4/127.0.0.1/udp/4002/quic-v1", - "/ip4/1.2.3.4/tcp/4001", - "/ip4/1.2.3.4/udp/4002/quic-v1", - "/dnsaddr/somedomain.com/tcp/4002/ws", - ) - clean := makeAddrList( - "/ip4/1.2.3.4/tcp/4001", - "/ip4/1.2.3.4/udp/4002/quic-v1", - "/dnsaddr/somedomain.com/tcp/4002/ws", - ) - matest.AssertMultiaddrsMatch(t, clean, cleanupAddressSet(addrs)) - }) - - t.Run("with default port", func(t *testing.T) { - // test with default port addrspolosion - addrs := makeAddrList( - "/ip4/127.0.0.1/tcp/4001", - "/ip4/1.2.3.4/tcp/4001", - "/ip4/1.2.3.4/tcp/33333", - "/ip4/1.2.3.4/tcp/33334", - "/ip4/1.2.3.4/tcp/33335", - "/ip4/1.2.3.4/udp/4002/quic-v1", - ) - clean := makeAddrList( - "/ip4/1.2.3.4/tcp/4001", - "/ip4/1.2.3.4/udp/4002/quic-v1", - ) - matest.AssertMultiaddrsMatch(t, clean, cleanupAddressSet(addrs)) - }) - - t.Run("with default port, but no private addrs", func(t *testing.T) { - // test with default port addrsplosion but no private addrs - addrs := makeAddrList( - "/ip4/1.2.3.4/tcp/4001", - "/ip4/1.2.3.4/tcp/33333", - "/ip4/1.2.3.4/tcp/33334", - "/ip4/1.2.3.4/tcp/33335", - "/ip4/1.2.3.4/udp/4002/quic-v1", - ) - clean := makeAddrList( - "/ip4/1.2.3.4/tcp/4001", - "/ip4/1.2.3.4/udp/4002/quic-v1", - ) - matest.AssertMultiaddrsMatch(t, clean, cleanupAddressSet(addrs)) - }) - - t.Run("with non-standard port", func(t *testing.T) { - addrs := makeAddrList( - "/ip4/127.0.0.1/tcp/12345", - "/ip4/1.2.3.4/tcp/12345", - "/ip4/1.2.3.4/tcp/33333", - "/ip4/1.2.3.4/tcp/33334", - "/ip4/1.2.3.4/tcp/33335", - ) - clean := makeAddrList( - "/ip4/1.2.3.4/tcp/12345", - ) - if !matest.AssertEqualMultiaddrs(t, clean, cleanupAddressSet(addrs)) { - t.Log("cleaned up set doesn't match expected") - } - }) - - t.Run("with a clean address set", func(t *testing.T) { - // test with a squeaky clean address set - addrs := makeAddrList( - "/ip4/1.2.3.4/tcp/4001", - "/ip4/1.2.3.4/udp/4001/quic-v1", - ) - matest.AssertMultiaddrsMatch(t, addrs, cleanupAddressSet(addrs)) - }) -} - -func makeAddrList(strs ...string) []ma.Multiaddr { - result := make([]ma.Multiaddr, 0, len(strs)) - for _, s := range strs { - result = append(result, ma.StringCast(s)) - } - return result -} diff --git a/p2p/host/autorelay/relay_finder.go b/p2p/host/autorelay/relay_finder.go index 35ac928b7a..17baf207c8 100644 --- a/p2p/host/autorelay/relay_finder.go +++ b/p2p/host/autorelay/relay_finder.go @@ -255,8 +255,8 @@ func (rf *relayFinder) getCircuitAddrs() []ma.Multiaddr { defer rf.relayMx.Unlock() raddrs := make([]ma.Multiaddr, 0, 4*len(rf.relays)+4) - for p := range rf.relays { - addrs := cleanupAddressSet(rf.host.Peerstore().Addrs(p)) + for p, rsvp := range rf.relays { + addrs := rsvp.Addrs circuit := ma.StringCast(fmt.Sprintf("/p2p/%s/p2p-circuit", p)) for _, addr := range addrs { pub := addr.Encapsulate(circuit) @@ -837,3 +837,20 @@ func areSortedAddrsDifferent(a, b []ma.Multiaddr) bool { } return false } + +// isRelayAddr returns true if the multiaddr contains the /p2p-circuit component. +func isRelayAddr(a ma.Multiaddr) bool { + isRelay := false + + ma.ForEach(a, func(c ma.Component) bool { + switch c.Protocol().Code { + case ma.P_CIRCUIT: + isRelay = true + return false + default: + return true + } + }) + + return isRelay +}