feat(host): recursively resolve addresses
We currently only resolve /dnsaddr addresses once. This patch resolves up to 32 dnsaddr addresses per dial. fixes https://github.com/libp2p/go-libp2p/issues/744
This commit is contained in:
parent
3304e01bbb
commit
e5d28696f5
3
go.sum
3
go.sum
|
@ -132,6 +132,7 @@ github.com/libp2p/go-eventbus v0.1.0 h1:mlawomSAjjkk97QnYiEmHsLu7E136+2oCWSHRUvM
|
|||
github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4=
|
||||
github.com/libp2p/go-flow-metrics v0.0.1 h1:0gxuFd2GuK7IIP5pKljLwps6TvcuYgvG7Atqi3INF5s=
|
||||
github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8=
|
||||
github.com/libp2p/go-flow-metrics v0.0.2 h1:U5TvqfoyR6GVRM+bC15Ux1ltar1kbj6Zw6xOVR02CZs=
|
||||
github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
|
||||
github.com/libp2p/go-libp2p-autonat v0.1.1 h1:WLBZcIRsjZlWdAZj9CiBSvU2wQXoUOiS1Zk1tM7DTJI=
|
||||
github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE=
|
||||
|
@ -151,8 +152,6 @@ github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV
|
|||
github.com/libp2p/go-libp2p-core v0.2.5 h1:iP1PIiIrlRrGbE1fYq2918yBc5NlCH3pFuIPSWU9hds=
|
||||
github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA=
|
||||
github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI=
|
||||
github.com/libp2p/go-libp2p-discovery v0.1.0 h1:j+R6cokKcGbnZLf4kcNwpx6mDEUPF3N6SrqMymQhmvs=
|
||||
github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g=
|
||||
github.com/libp2p/go-libp2p-discovery v0.2.0 h1:1p3YSOq7VsgaL+xVHPi8XAmtGyas6D2J6rWBEfz/aiY=
|
||||
github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg=
|
||||
github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8=
|
||||
|
|
|
@ -31,6 +31,10 @@ import (
|
|||
msmux "github.com/multiformats/go-multistream"
|
||||
)
|
||||
|
||||
// The maximum number of address resolution steps we'll perform for a single
|
||||
// peer (for all addresses).
|
||||
const maxAddressResolution = 32
|
||||
|
||||
var log = logging.Logger("basichost")
|
||||
|
||||
var (
|
||||
|
@ -522,28 +526,59 @@ func (h *BasicHost) resolveAddrs(ctx context.Context, pi peer.AddrInfo) ([]ma.Mu
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var addrs []ma.Multiaddr
|
||||
for _, addr := range pi.Addrs {
|
||||
addrs = append(addrs, addr)
|
||||
resolveSteps := 0
|
||||
|
||||
// Recursively resolve all addrs.
|
||||
//
|
||||
// While the toResolve list is non-empty:
|
||||
// * Pop an address off.
|
||||
// * If the address is fully resolved, add it to the resolved list.
|
||||
// * Otherwise, resolve it and add the results to the "to resolve" list.
|
||||
toResolve := append(([]ma.Multiaddr)(nil), pi.Addrs...)
|
||||
resolved := make([]ma.Multiaddr, 0, len(pi.Addrs))
|
||||
for len(toResolve) > 0 {
|
||||
// pop the last addr off.
|
||||
addr := toResolve[len(toResolve)-1]
|
||||
toResolve = toResolve[:len(toResolve)-1]
|
||||
|
||||
// if it's resolved, add it to the resolved list.
|
||||
if !madns.Matches(addr) {
|
||||
resolved = append(resolved, addr)
|
||||
continue
|
||||
}
|
||||
|
||||
resolveSteps++
|
||||
|
||||
// We've resolved too many addresses. We can keep all the fully
|
||||
// resolved addresses but we'll need to skip the rest.
|
||||
if resolveSteps >= maxAddressResolution {
|
||||
log.Warningf(
|
||||
"peer %s asked us to resolve too many addresses: %s/%s",
|
||||
pi.ID,
|
||||
resolveSteps,
|
||||
maxAddressResolution,
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
// otherwise, resolve it
|
||||
reqaddr := addr.Encapsulate(p2paddr)
|
||||
resaddrs, err := h.maResolver.Resolve(ctx, reqaddr)
|
||||
if err != nil {
|
||||
log.Infof("error resolving %s: %s", reqaddr, err)
|
||||
}
|
||||
|
||||
// add the results to the toResolve list.
|
||||
for _, res := range resaddrs {
|
||||
pi, err := peer.AddrInfoFromP2pAddr(res)
|
||||
if err != nil {
|
||||
log.Infof("error parsing %s: %s", res, err)
|
||||
}
|
||||
addrs = append(addrs, pi.Addrs...)
|
||||
toResolve = append(toResolve, pi.Addrs...)
|
||||
}
|
||||
}
|
||||
|
||||
return addrs, nil
|
||||
return resolved, nil
|
||||
}
|
||||
|
||||
// dialPeer opens a connection to peer, and makes sure to identify
|
||||
|
|
|
@ -407,9 +407,9 @@ func TestAddrResolution(t *testing.T) {
|
|||
}
|
||||
addr1 := ma.StringCast("/dnsaddr/example.com")
|
||||
addr2 := ma.StringCast("/ip4/192.0.2.1/tcp/123")
|
||||
p2paddr1 := ma.StringCast("/dnsaddr/example.com/ipfs/" + p1.Pretty())
|
||||
p2paddr2 := ma.StringCast("/ip4/192.0.2.1/tcp/123/ipfs/" + p1.Pretty())
|
||||
p2paddr3 := ma.StringCast("/ip4/192.0.2.1/tcp/123/ipfs/" + p2.Pretty())
|
||||
p2paddr1 := ma.StringCast("/dnsaddr/example.com/p2p/" + p1.Pretty())
|
||||
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.MockBackend{
|
||||
TXT: map[string][]string{"_dnsaddr.example.com": []string{
|
||||
|
@ -438,6 +438,75 @@ func TestAddrResolution(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
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.MockBackend{
|
||||
TXT: map[string][]string{
|
||||
"_dnsaddr.example.com": []string{
|
||||
"dnsaddr=" + p2paddr1i.String(),
|
||||
"dnsaddr=" + p2paddr2i.String(),
|
||||
},
|
||||
"_dnsaddr.foo.example.com": []string{
|
||||
"dnsaddr=" + p2paddr1f.String(),
|
||||
},
|
||||
"_dnsaddr.bar.example.com": []string{
|
||||
"dnsaddr=" + p2paddr2i.String(),
|
||||
},
|
||||
},
|
||||
}
|
||||
resolver := &madns.Resolver{Backend: backend}
|
||||
|
||||
h := New(swarmt.GenSwarm(t, ctx), resolver)
|
||||
defer h.Close()
|
||||
|
||||
pi1, err := peer.AddrInfoFromP2pAddr(p2paddr1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
tctx, cancel := context.WithTimeout(ctx, time.Millisecond*100)
|
||||
defer cancel()
|
||||
_ = h.Connect(tctx, *pi1)
|
||||
|
||||
addrs1 := h.Peerstore().Addrs(pi1.ID)
|
||||
sort.Sort(sortedMultiaddrs(addrs1))
|
||||
|
||||
if len(addrs1) != 2 || !addrs1[0].Equal(addr1) || !addrs1[1].Equal(addr2) {
|
||||
t.Fatalf("expected [%s %s], got %+v", addr1, addr2, addrs1)
|
||||
}
|
||||
|
||||
pi2, err := peer.AddrInfoFromP2pAddr(p2paddr2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_ = h.Connect(tctx, *pi2)
|
||||
|
||||
addrs2 := h.Peerstore().Addrs(pi2.ID)
|
||||
sort.Sort(sortedMultiaddrs(addrs2))
|
||||
|
||||
if len(addrs2) != 1 || !addrs2[0].Equal(addr1) {
|
||||
t.Fatalf("expected [%s], got %+v", addr1, addrs2)
|
||||
}
|
||||
}
|
||||
|
||||
type sortedMultiaddrs []ma.Multiaddr
|
||||
|
||||
func (sma sortedMultiaddrs) Len() int { return len(sma) }
|
||||
|
|
Loading…
Reference in New Issue