Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions core/commands/swarm_addrs_autonat.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
"github.com/ipfs/kubo/core/node/libp2p"
"github.com/libp2p/go-libp2p/core/network"
basichost "github.com/libp2p/go-libp2p/p2p/host/basic"
ma "github.com/multiformats/go-multiaddr"
)

Expand All @@ -21,6 +22,13 @@ type confirmedAddrsHost interface {
ConfirmedAddrs() (reachable, unreachable, unknown []ma.Multiaddr)
}

// Compile-time check: BasicHost must satisfy confirmedAddrsHost.
// ConfirmedAddrs is not part of the core host.Host interface and is marked
// experimental in go-libp2p. If BasicHost ever drops or changes this method,
// this assertion fails at build time instead of the command silently
// reporting nothing.
var _ confirmedAddrsHost = (*basichost.BasicHost)(nil)

// autoNATResult represents the AutoNAT reachability information.
type autoNATResult struct {
Reachability string `json:"reachability"`
Expand Down
78 changes: 42 additions & 36 deletions core/node/libp2p/routingopt.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import (
host "github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
routing "github.com/libp2p/go-libp2p/core/routing"
basichost "github.com/libp2p/go-libp2p/p2p/host/basic"
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
)

type RoutingOptionArgs struct {
Expand Down Expand Up @@ -320,58 +320,64 @@ var (
NilRouterOption = constructNilRouting
)

// confirmedAddrsHost matches libp2p hosts that support AutoNAT V2 address confirmation.
type confirmedAddrsHost interface {
ConfirmedAddrs() (reachable, unreachable, unknown []ma.Multiaddr)
}

// Compile-time check: BasicHost must satisfy confirmedAddrsHost.
// ConfirmedAddrs is not part of the core host.Host interface and is marked
// experimental in go-libp2p. If BasicHost ever drops or changes this method,
// this assertion will fail at build time. In that case, update
// httpRouterAddrFunc (this file) and the swarm autonat command
// (core/commands/swarm_addrs_autonat.go) which both type-assert to this
// interface.
var _ confirmedAddrsHost = (*basichost.BasicHost)(nil)

// httpRouterAddrFunc returns a function that resolves provider addresses for
// HTTP routers at provide-time.
//
// Resolution logic:
// - If Announce is set, use it as a static override (no dynamic resolution).
// - Otherwise, prefer AutoNAT V2 confirmed reachable addresses when available,
// falling back to host.Addrs() which resolves 0.0.0.0/:: Swarm binds to
// concrete interface addresses and applies the libp2p AddrsFactory
// (Addresses.NoAnnounce CIDR filters and Swarm.AddrFilters).
// - AppendAnnounce addresses are always appended.
// - Otherwise announce host.Addrs(), the same set identify sends to peers:
// 0.0.0.0/:: Swarm binds resolved to concrete interface addresses, the
// libp2p AddrsFactory applied (Addresses.NoAnnounce, and the AutoTLS
// /tls/ws address, which only exists here), and certhashes attached.
// - Narrowed to globally routable addresses when the node has any, matching
// the DHT provide path (selfAddrsFunc in core/node/provider.go). A node
// with no public address keeps announcing what it has, so LAN-only setups
// pointing at a local router still publish something dialable.
// - AppendAnnounce addresses are always appended, exactly once, and are
// exempt from both NoAnnounce and the public-address narrowing: an
// explicit operator entry wins.
//
// Do not narrow this to AutoNAT V2 confirmed reachable addresses. AutoNAT only
// ever sees listen addresses, so an address the AddrsFactory synthesizes (the
// AutoTLS /tls/ws one) can never be confirmed, and browser clients that reach
// us through a delegated router are left with nothing they can dial.
// See https://github.com/ipfs/kubo/issues/11369.
func httpRouterAddrFunc(h host.Host, cfgAddrs config.Addresses) func() []ma.Multiaddr {
appendAddrs := parseMultiaddrs(cfgAddrs.AppendAnnounce)

// If Announce is explicitly set, use it as a static override.
if len(cfgAddrs.Announce) > 0 {
staticAddrs := slices.Concat(parseMultiaddrs(cfgAddrs.Announce), appendAddrs)
announceAddrs := parseMultiaddrs(cfgAddrs.Announce)
// Skip AppendAnnounce entries already listed in Announce,
// mirroring makeAddrsFactory (addrs.go).
extra := ma.FilterAddrs(appendAddrs, func(a ma.Multiaddr) bool {
return !ma.Contains(announceAddrs, a)
})
staticAddrs := slices.Concat(announceAddrs, extra)
return func() []ma.Multiaddr { return staticAddrs }
}

ch, hasConfirmed := h.(confirmedAddrsHost)
return func() []ma.Multiaddr {
if hasConfirmed {
reachable, _, _ := ch.ConfirmedAddrs()
if len(reachable) > 0 {
if len(appendAddrs) == 0 {
return reachable
}
return slices.Concat(reachable, appendAddrs)
}
addrs := h.Addrs()
if len(appendAddrs) > 0 {
// The AddrsFactory (makeAddrsFactory in addrs.go) already injects
// AppendAnnounce into h.Addrs(). Take those out so the re-append
// below emits them exactly once, and so a public AppendAnnounce
// entry cannot trip the public-addr guard on a node whose own
// addresses are all private.
addrs = ma.FilterAddrs(addrs, func(a ma.Multiaddr) bool {
return !ma.Contains(appendAddrs, a)
})
}
// Delegated routers are public indexes, so keep loopback and LAN
// addresses out of the record whenever we have a routable one.
if public := ma.FilterAddrs(addrs, manet.IsPublicAddr); len(public) > 0 {
addrs = public
}
// Fallback: host.Addrs() resolves wildcard binds (0.0.0.0, ::) to
// concrete interface addresses and applies the libp2p AddrsFactory,
// which is where Addresses.NoAnnounce CIDR filtering happens.
hostAddrs := h.Addrs()
if len(appendAddrs) == 0 {
return hostAddrs
return addrs
}
return slices.Concat(hostAddrs, appendAddrs)
return slices.Concat(addrs, appendAddrs)
}
}

Expand Down
120 changes: 87 additions & 33 deletions core/node/libp2p/routingopt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,14 +206,19 @@ func TestEndpointCapabilitiesReadWriteLogic(t *testing.T) {
}

// stubHost is a minimal host.Host stub for testing httpRouterAddrFunc.
// reachable mocks ConfirmedAddrs (AutoNAT V2 result); hostAddrs mocks
// Addrs(), which in a real host returns wildcard-resolved interface
// addresses after the AddrsFactory filters (NoAnnounce/AddrFilters).
// hostAddrs mocks Addrs(), which in a real host returns wildcard-resolved
// interface addresses after the AddrsFactory ran (NoAnnounce filtering, the
// AutoTLS /tls/ws address, certhashes).
type stubHost struct {
reachable []ma.Multiaddr
hostAddrs []ma.Multiaddr
reachable []ma.Multiaddr
}

// ConfirmedAddrs mocks the AutoNAT V2 confirmed set. httpRouterAddrFunc must
// not consult it: AutoNAT only sees listen addresses, so the AddrsFactory-
// synthesized AutoTLS /tls/ws address can never appear in it, and a record
// narrowed to this set carries nothing a browser can dial.
// See https://github.com/ipfs/kubo/issues/11369.
func (h *stubHost) ConfirmedAddrs() (reachable, unreachable, unknown []ma.Multiaddr) {
return h.reachable, nil, nil
}
Expand All @@ -237,77 +242,126 @@ func (h *stubHost) ConnManager() connmgr.ConnManager { panic("unused") }
func (h *stubHost) EventBus() event.Bus { panic("unused") }

func TestHttpRouterAddrFunc(t *testing.T) {
// hostAddrs simulates what host.Addrs() returns in a running daemon:
// wildcard Swarm binds resolved to concrete interfaces, with the
// libp2p AddrsFactory (NoAnnounce/AddrFilters) already applied.
resolvedAddrs := []string{
"/ip4/192.168.1.10/tcp/4001",
"/ip4/192.168.1.10/udp/4001/quic-v1",
}
// A publicly reachable node with every transport kubo can announce.
// This is what host.Addrs() returns in a running daemon: wildcard Swarm
// binds resolved to concrete interfaces (so the LAN address shows up
// next to the public one), AddrsFactory applied, certhashes attached.
const (
autoTLSWS = "/dns4/1-2-3-4.k51qzi5uqu5dlwbcbb2u3ptbnhs5lpj4nc3xbhrgqrkgo3l0h5xgv9k1nn9k1.libp2p.direct/tcp/4001/tls/ws"
webRTCDirect = "/ip4/1.2.3.4/udp/4001/webrtc-direct/certhash/uEiDDq4_xKlbjmeSaEwB7UUcH_TS1z2WLwkGuOHZgKZgUSw"
webTransport = "/ip4/1.2.3.4/udp/4001/quic-v1/webtransport/certhash/uEiDDq4_xKlbjmeSaEwB7UUcH_TS1z2WLwkGuOHZgKZgUSw"
publicTCP = "/ip4/1.2.3.4/tcp/4001"
publicQUIC = "/ip4/1.2.3.4/udp/4001/quic-v1"
lanTCP = "/ip4/192.168.1.10/tcp/4001"
lanQUIC = "/ip4/192.168.1.10/udp/4001/quic-v1"
loopbackTCP = "/ip4/127.0.0.1/tcp/4001"
)
publicNodeAddrs := []string{autoTLSWS, webRTCDirect, webTransport, publicTCP, publicQUIC, lanTCP, loopbackTCP}
lanOnlyAddrs := []string{lanTCP, lanQUIC}

tests := []struct {
name string
reachable []string // autonat confirmed addrs (nil = none)
hostAddrs []string // host.Addrs() output (nil = none)
reachable []string // AutoNAT V2 confirmed set; must NOT influence the result
cfg config.Addresses
want []string
}{
{
name: "prefers autonat confirmed reachable addrs over host.Addrs fallback",
reachable: []string{"/ip4/1.2.3.4/tcp/4001", "/ip4/1.2.3.4/udp/4001/quic-v1"},
hostAddrs: resolvedAddrs,
// Regression test for https://github.com/ipfs/kubo/issues/11369:
// the record must be built from host.Addrs(), never from
// ConfirmedAddrs. reachable carries the narrowed set AutoNAT
// reports on such a node (no AutoTLS, no webrtc-direct); the
// browser-dialable addrs from hostAddrs must win.
name: "browser-dialable transports reach the record on a public node",
hostAddrs: publicNodeAddrs,
reachable: []string{publicTCP, publicQUIC, webTransport},
cfg: config.Addresses{Swarm: []string{"/ip4/0.0.0.0/tcp/4001", "/ip4/0.0.0.0/udp/4001/quic-v1"}},
want: []string{"/ip4/1.2.3.4/tcp/4001", "/ip4/1.2.3.4/udp/4001/quic-v1"},
want: []string{autoTLSWS, webRTCDirect, webTransport, publicTCP, publicQUIC},
},
{
name: "falls back to host.Addrs when autonat has no confirmed addrs",
hostAddrs: resolvedAddrs,
name: "LAN-only node announces what it has",
hostAddrs: lanOnlyAddrs,
cfg: config.Addresses{Swarm: []string{"/ip4/0.0.0.0/tcp/4001", "/ip4/0.0.0.0/udp/4001/quic-v1"}},
want: resolvedAddrs,
want: lanOnlyAddrs,
},
{
name: "empty host.Addrs announces nothing",
hostAddrs: nil,
cfg: config.Addresses{Swarm: []string{"/ip4/0.0.0.0/tcp/4001"}},
want: nil,
},
{
name: "Announce overrides autonat and host.Addrs",
reachable: []string{"/ip4/1.2.3.4/tcp/4001"},
hostAddrs: resolvedAddrs,
name: "empty host.Addrs with AppendAnnounce announces AppendAnnounce",
hostAddrs: nil,
cfg: config.Addresses{Swarm: []string{"/ip4/0.0.0.0/tcp/4001"}, AppendAnnounce: []string{"/ip4/10.0.0.1/tcp/4001"}},
want: []string{"/ip4/10.0.0.1/tcp/4001"},
},
{
name: "Announce overrides host.Addrs",
hostAddrs: publicNodeAddrs,
cfg: config.Addresses{Swarm: []string{"/ip4/0.0.0.0/tcp/4001"}, Announce: []string{"/ip4/5.6.7.8/tcp/4001"}},
want: []string{"/ip4/5.6.7.8/tcp/4001"},
},
{
name: "AppendAnnounce added to autonat addrs",
reachable: []string{"/ip4/1.2.3.4/tcp/4001"},
hostAddrs: resolvedAddrs,
// AppendAnnounce is an explicit operator override, so it survives
// the public-address filter even when it is a LAN address.
name: "AppendAnnounce added to host.Addrs",
hostAddrs: []string{publicTCP, lanTCP},
cfg: config.Addresses{Swarm: []string{"/ip4/0.0.0.0/tcp/4001"}, AppendAnnounce: []string{"/ip4/10.0.0.1/tcp/4001"}},
want: []string{"/ip4/1.2.3.4/tcp/4001", "/ip4/10.0.0.1/tcp/4001"},
want: []string{publicTCP, "/ip4/10.0.0.1/tcp/4001"},
},
{
name: "AppendAnnounce added to host.Addrs fallback",
hostAddrs: resolvedAddrs,
name: "AppendAnnounce added to LAN-only fallback",
hostAddrs: lanOnlyAddrs,
cfg: config.Addresses{Swarm: []string{"/ip4/0.0.0.0/tcp/4001"}, AppendAnnounce: []string{"/ip4/10.0.0.1/tcp/4001"}},
want: append(append([]string{}, resolvedAddrs...), "/ip4/10.0.0.1/tcp/4001"),
want: append(append([]string{}, lanOnlyAddrs...), "/ip4/10.0.0.1/tcp/4001"),
},
{
// The AddrsFactory injects AppendAnnounce into h.Addrs(), so the
// same addr arrives twice: once inside hostAddrs and once via the
// explicit re-append. The record must carry it exactly once.
name: "AppendAnnounce present in host.Addrs is not duplicated",
hostAddrs: []string{publicTCP, "/ip4/5.6.7.8/tcp/4001"},
cfg: config.Addresses{Swarm: []string{"/ip4/0.0.0.0/tcp/4001"}, AppendAnnounce: []string{"/ip4/5.6.7.8/tcp/4001"}},
want: []string{publicTCP, "/ip4/5.6.7.8/tcp/4001"},
},
{
// A public AppendAnnounce echoed back through h.Addrs() must not
// count as "the node has a public address" and evict the real
// LAN addresses of an otherwise private node.
name: "public AppendAnnounce does not evict LAN-only fallback addrs",
hostAddrs: append([]string{"/ip4/5.6.7.8/tcp/4001"}, lanOnlyAddrs...),
cfg: config.Addresses{Swarm: []string{"/ip4/0.0.0.0/tcp/4001"}, AppendAnnounce: []string{"/ip4/5.6.7.8/tcp/4001"}},
want: append(append([]string{}, lanOnlyAddrs...), "/ip4/5.6.7.8/tcp/4001"),
},
{
// NoAnnounce (including server profile CIDR ranges) is applied by the
// libp2p AddrsFactory before host.Addrs() returns, so httpRouterAddrFunc
// itself performs no filtering on the fallback.
// never sees the filtered addresses.
name: "NoAnnounce filtering happens upstream in host.Addrs",
hostAddrs: []string{"/ip4/192.168.1.10/tcp/4001"}, // already filtered by addrFactory
hostAddrs: []string{lanTCP}, // already filtered by addrFactory
cfg: config.Addresses{
Swarm: []string{"/ip4/0.0.0.0/tcp/4001"},
NoAnnounce: []string{"/ip4/127.0.0.0/ipcidr/8"},
},
want: []string{"/ip4/192.168.1.10/tcp/4001"},
want: []string{lanTCP},
},
{
name: "AppendAnnounce added to Announce",
cfg: config.Addresses{Swarm: []string{"/ip4/0.0.0.0/tcp/4001"}, Announce: []string{"/ip4/5.6.7.8/tcp/4001"}, AppendAnnounce: []string{"/ip4/10.0.0.1/tcp/4001"}},
want: []string{"/ip4/5.6.7.8/tcp/4001", "/ip4/10.0.0.1/tcp/4001"},
},
{
name: "AppendAnnounce overlapping Announce is not duplicated",
cfg: config.Addresses{Swarm: []string{"/ip4/0.0.0.0/tcp/4001"}, Announce: []string{"/ip4/5.6.7.8/tcp/4001"}, AppendAnnounce: []string{"/ip4/5.6.7.8/tcp/4001", "/ip4/10.0.0.1/tcp/4001"}},
want: []string{"/ip4/5.6.7.8/tcp/4001", "/ip4/10.0.0.1/tcp/4001"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
h := &stubHost{
reachable: parseMultiaddrs(tt.reachable),
hostAddrs: parseMultiaddrs(tt.hostAddrs),
reachable: parseMultiaddrs(tt.reachable),
}
fn := httpRouterAddrFunc(h, tt.cfg)
assert.Equal(t, parseMultiaddrs(tt.want), fn())
Expand Down
29 changes: 29 additions & 0 deletions docs/changelogs/vTBD.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Kubo changelog vTBD

<a href="https://ipshipyard.com/"><img align="right" src="https://github.com/user-attachments/assets/39ed3504-bb71-47f6-9bf8-cb9a1698f272" /></a>

This release was brought to you by the [Shipyard](https://ipshipyard.com/) team.

- [vTBD](#vtbd)

## vTBD

- [Overview](#overview)
- [🔦 Highlights](#-highlights)
- [🌐 Browsers can dial you again through delegated routers](#-browsers-can-dial-you-again-through-delegated-routers)
- [📝 Changelog](#-changelog)
- [👨‍👩‍👧‍👦 Contributors](#-contributors)

### Overview

### 🔦 Highlights

#### 🌐 Browsers can dial you again through delegated routers

A publicly reachable node with [AutoTLS](https://github.com/ipfs/kubo/blob/master/docs/config.md#autotls) or `webrtc-direct` enabled was leaving those addresses out of the provider records it sent to HTTP routers. The record carried only `tcp`, `quic-v1`, and `webtransport`, none of which a browser can dial, so browser and [Helia](https://helia.io/) clients that found the node through a delegated router had no way to connect to it, even though the node was listening and `ipfs id` showed the addresses.

Provider records sent to HTTP routers now carry the same addresses the node announces everywhere else, including the AutoTLS `/tls/ws` and `webrtc-direct` ones, matching what the DHT already published. Loopback and LAN addresses stay out of the record when the node has a public address. See [#11369](https://github.com/ipfs/kubo/issues/11369).

### 📝 Changelog

### 👨‍👩‍👧‍👦 Contributors
2 changes: 1 addition & 1 deletion docs/examples/kubo-as-a-library/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ replace github.com/ipfs/kubo => ./../../..
require (
github.com/ipfs/boxo v0.41.1-0.20260707130650-177b35c8ef09
github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
github.com/libp2p/go-libp2p v0.48.1-0.20260708062241-95be6665b014
github.com/libp2p/go-libp2p v0.48.1-0.20260715204039-42aa212c5646
github.com/multiformats/go-multiaddr v0.16.1
)

Expand Down
4 changes: 2 additions & 2 deletions docs/examples/kubo-as-a-library/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -411,8 +411,8 @@ github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZ
github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
github.com/libp2p/go-flow-metrics v0.3.0 h1:q31zcHUvHnwDO0SHaukewPYgwOBSxtt830uJtUx6784=
github.com/libp2p/go-flow-metrics v0.3.0/go.mod h1:nuhlreIwEguM1IvHAew3ij7A8BMlyHQJ279ao24eZZo=
github.com/libp2p/go-libp2p v0.48.1-0.20260708062241-95be6665b014 h1:RYkdiaWH3aPT7m98atoCw+MD2YJOHfUi16ZaXaP3yGg=
github.com/libp2p/go-libp2p v0.48.1-0.20260708062241-95be6665b014/go.mod h1:+zGTonNiePk+PlraDn51k+8grAbHh9df7IIAVOMwqZo=
github.com/libp2p/go-libp2p v0.48.1-0.20260715204039-42aa212c5646 h1:B7ql/sbL+R6vpJuQeophg8juH1tGshyTx4xKokpeSRE=
github.com/libp2p/go-libp2p v0.48.1-0.20260715204039-42aa212c5646/go.mod h1:+zGTonNiePk+PlraDn51k+8grAbHh9df7IIAVOMwqZo=
github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=
github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ require (
github.com/jbenet/go-temp-err-catcher v0.1.0
github.com/julienschmidt/httprouter v1.3.0
github.com/libp2p/go-doh-resolver v0.5.0
github.com/libp2p/go-libp2p v0.48.1-0.20260708062241-95be6665b014 // TODO: switch to a tagged release once one ships past v0.48.0
github.com/libp2p/go-libp2p v0.48.1-0.20260715204039-42aa212c5646 // TODO: switch to a tagged release once one ships past v0.48.0
github.com/libp2p/go-libp2p-http v0.5.0
github.com/libp2p/go-libp2p-kad-dht v0.41.0
github.com/libp2p/go-libp2p-kbucket v0.8.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -494,8 +494,8 @@ github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZ
github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
github.com/libp2p/go-flow-metrics v0.3.0 h1:q31zcHUvHnwDO0SHaukewPYgwOBSxtt830uJtUx6784=
github.com/libp2p/go-flow-metrics v0.3.0/go.mod h1:nuhlreIwEguM1IvHAew3ij7A8BMlyHQJ279ao24eZZo=
github.com/libp2p/go-libp2p v0.48.1-0.20260708062241-95be6665b014 h1:RYkdiaWH3aPT7m98atoCw+MD2YJOHfUi16ZaXaP3yGg=
github.com/libp2p/go-libp2p v0.48.1-0.20260708062241-95be6665b014/go.mod h1:+zGTonNiePk+PlraDn51k+8grAbHh9df7IIAVOMwqZo=
github.com/libp2p/go-libp2p v0.48.1-0.20260715204039-42aa212c5646 h1:B7ql/sbL+R6vpJuQeophg8juH1tGshyTx4xKokpeSRE=
github.com/libp2p/go-libp2p v0.48.1-0.20260715204039-42aa212c5646/go.mod h1:+zGTonNiePk+PlraDn51k+8grAbHh9df7IIAVOMwqZo=
github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=
github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=
Expand Down
Loading
Loading