4
"context"
5
"fmt"
6
"os"
7
+ "slices"
8
"strings"
9
"time"
10
19
host "github.com/libp2p/go-libp2p/core/host"
20
"github.com/libp2p/go-libp2p/core/peer"
21
routing "github.com/libp2p/go-libp2p/core/routing"
22
+ basichost "github.com/libp2p/go-libp2p/p2p/host/basic"
23
+ ma "github.com/multiformats/go-multiaddr"
24
)
25
26
type RoutingOptionArgs struct {
108
return endpoints
109
}
110
108
-func constructDefaultHTTPRouters(cfg *config.Config) ([]*routinghelpers.ParallelRouter, error) {
111
+func constructDefaultHTTPRouters(cfg *config.Config, addrFunc func() []ma.Multiaddr) ([]*routinghelpers.ParallelRouter, error) {
112
var routers []*routinghelpers.ParallelRouter
113
httpRetrievalEnabled := cfg.HTTPRetrieval.Enabled.WithDefault(config.DefaultHTTPRetrievalEnabled)
114
133
// Create single HTTP router and composer per origin
134
for baseURL, capabilities := range originCapabilities {
135
// Construct HTTP router using base URL (without path)
133
- httpRouter, err := irouting.ConstructHTTPRouter(baseURL, cfg.Identity.PeerID, httpAddrsFromConfig(cfg.Addresses), cfg.Identity.PrivKey, httpRetrievalEnabled)
136
+ httpRouter, err := irouting.ConstructHTTPRouter(baseURL, cfg.Identity.PeerID, addrFunc, cfg.Identity.PrivKey, httpRetrievalEnabled)
137
if err != nil {
138
return nil, err
139
}
194
var routers []*routinghelpers.ParallelRouter
195
196
// Add HTTP delegated routers (includes both router and publisher capabilities)
194
- httpRouters, err := constructDefaultHTTPRouters(cfg)
197
+ addrFunc := httpRouterAddrFunc(args.Host, cfg.Addresses)
198
+ httpRouters, err := constructDefaultHTTPRouters(cfg, addrFunc)
199
if err != nil {
200
return nil, err
201
}
229
ExecuteAfter: 0,
230
})
231
228
- httpRouters, err := constructDefaultHTTPRouters(cfg)
232
+ addrFunc := httpRouterAddrFunc(args.Host, cfg.Addresses)
233
+ httpRouters, err := constructDefaultHTTPRouters(cfg, addrFunc)
234
if err != nil {
235
return nil, err
236
}
276
// ConstructDelegatedRouting is used when Routing.Type = "custom"
277
func ConstructDelegatedRouting(routers config.Routers, methods config.Methods, peerID string, addrs config.Addresses, privKey string, httpRetrieval bool) RoutingOption {
278
return func(args RoutingOptionArgs) (routing.Routing, error) {
279
+ addrFunc := httpRouterAddrFunc(args.Host, addrs)
280
return irouting.Parse(routers, methods,
281
&irouting.ExtraDHTParams{
282
BootstrapPeers: args.BootstrapPeers,
287
},
288
&irouting.ExtraHTTPParams{
289
PeerID: peerID,
284
- Addrs: httpAddrsFromConfig(addrs),
290
+ AddrFunc: addrFunc,
291
PrivKeyB64: privKey,
292
HTTPRetrieval: httpRetrieval,
293
},
306
NilRouterOption = constructNilRouting
307
)
308
303
-// httpAddrsFromConfig creates a list of addresses from the provided configuration to be used by HTTP delegated routers.
304
-func httpAddrsFromConfig(cfgAddrs config.Addresses) []string {
305
- // Swarm addrs are announced by default
306
- addrs := cfgAddrs.Swarm
307
- // if Announce addrs are specified - override Swarm
309
+// confirmedAddrsHost matches libp2p hosts that support AutoNAT V2 address confirmation.
310
+type confirmedAddrsHost interface {
311
+ ConfirmedAddrs() (reachable, unreachable, unknown []ma.Multiaddr)
312
+}
313
+
314
+// Compile-time check: BasicHost must satisfy confirmedAddrsHost.
315
+// ConfirmedAddrs is not part of the core host.Host interface and is marked
316
+// experimental in go-libp2p. If BasicHost ever drops or changes this method,
317
+// this assertion will fail at build time. In that case, update
318
+// httpRouterAddrFunc (this file) and the swarm autonat command
319
+// (core/commands/swarm_addrs_autonat.go) which both type-assert to this
320
+// interface.
321
+var _ confirmedAddrsHost = (*basichost.BasicHost)(nil)
322
+
323
+// httpRouterAddrFunc returns a function that resolves provider addresses for
324
+// HTTP routers at provide-time.
325
+//
326
+// Resolution logic:
327
+// - If Announce is set, use it as a static override (no dynamic resolution).
328
+// - Otherwise, prefer AutoNAT V2 confirmed reachable addresses when available,
329
+// falling back to static Swarm addresses (filtered by NoAnnounce).
330
+// - AppendAnnounce addresses are always appended.
331
+func httpRouterAddrFunc(h host.Host, cfgAddrs config.Addresses) func() []ma.Multiaddr {
332
+ appendAddrs := parseMultiaddrs(cfgAddrs.AppendAnnounce)
333
+
334
+ // If Announce is explicitly set, use it as a static override.
335
if len(cfgAddrs.Announce) > 0 {
309
- addrs = cfgAddrs.Announce
310
- } else if len(cfgAddrs.NoAnnounce) > 0 {
311
- // if Announce adds are not specified - filter Swarm addrs with NoAnnounce list
312
- maddrs := map[string]struct{}{}
313
- for _, addr := range addrs {
314
- maddrs[addr] = struct{}{}
336
+ staticAddrs := slices.Concat(parseMultiaddrs(cfgAddrs.Announce), appendAddrs)
337
+ return func() []ma.Multiaddr { return staticAddrs }
338
+ }
339
+
340
+ // Precompute fallback: Swarm minus NoAnnounce plus AppendAnnounce.
341
+ fallbackStrs := cfgAddrs.Swarm
342
+ if len(cfgAddrs.NoAnnounce) > 0 {
343
+ noAnnounce := map[string]struct{}{}
344
+ for _, a := range cfgAddrs.NoAnnounce {
345
+ noAnnounce[a] = struct{}{}
346
}
316
- for _, addr := range cfgAddrs.NoAnnounce {
317
- delete(maddrs, addr)
347
+ filtered := make([]string, 0, len(fallbackStrs))
348
+ for _, a := range fallbackStrs {
349
+ if _, skip := noAnnounce[a]; !skip {
350
+ filtered = append(filtered, a)
351
+ }
352
}
319
- addrs = make([]string, 0, len(maddrs))
320
- for k := range maddrs {
321
- addrs = append(addrs, k)
353
+ fallbackStrs = filtered
354
+ }
355
+ fallbackResult := slices.Concat(parseMultiaddrs(fallbackStrs), appendAddrs)
356
+
357
+ ch, hasConfirmed := h.(confirmedAddrsHost)
358
+ return func() []ma.Multiaddr {
359
+ if hasConfirmed {
360
+ reachable, _, _ := ch.ConfirmedAddrs()
361
+ if len(reachable) > 0 {
362
+ if len(appendAddrs) == 0 {
363
+ return reachable
364
+ }
365
+ return slices.Concat(reachable, appendAddrs)
366
+ }
367
}
368
+ return fallbackResult
369
}
324
- // append AppendAnnounce addrs to the result list
325
- if len(cfgAddrs.AppendAnnounce) > 0 {
326
- addrs = append(addrs, cfgAddrs.AppendAnnounce...)
370
+}
371
+
372
+func parseMultiaddrs(strs []string) []ma.Multiaddr {
373
+ addrs := make([]ma.Multiaddr, 0, len(strs))
374
+ for _, s := range strs {
375
+ a, err := ma.NewMultiaddr(s)
376
+ if err != nil {
377
+ log.Errorf("ignoring invalid multiaddr %q: %s", s, err)
378
+ continue
379
+ }
380
+ addrs = append(addrs, a)
381
}
382
return addrs
383
}