diff --git a/client.go b/client.go index 9d8dfe4..cde6f57 100644 --- a/client.go +++ b/client.go @@ -186,9 +186,19 @@ func createHost(_ context.Context, hostOpts []libp2p.Option, config Config, rela fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", config.Port), fmt.Sprintf("/ip6/::/tcp/%d", config.Port), ), - libp2p.NATPortMap(), - libp2p.EnableNATService(), - libp2p.EnableHolePunching(), + ) + + // Only enable NAT traversal features if not disabled + // NAT features can cause data races in tests due to libp2p's NAT manager using non-thread-safe global state + if !config.DisableNAT { + hostOpts = append(hostOpts, + libp2p.NATPortMap(), + libp2p.EnableNATService(), + libp2p.EnableHolePunching(), + ) + } + + hostOpts = append(hostOpts, libp2p.EnableRelay(), libp2p.EnableAutoRelayWithStaticRelays(relayPeers), ) diff --git a/config.go b/config.go index ffa338c..8aaef71 100644 --- a/config.go +++ b/config.go @@ -97,4 +97,10 @@ type Config struct { // Recommended: 6-24 hours for production to reduce CPU overhead. // The cleanup frequency trades off between memory usage (stale records) and CPU usage. DHTCleanupInterval time.Duration + + // DisableNAT disables NAT traversal features (UPnP/NAT-PMP port mapping, NAT service, hole punching). + // Set to true in test environments where NAT traversal is not needed and can cause data races + // due to libp2p's NAT manager using non-thread-safe global state. + // Default: false (NAT features enabled) + DisableNAT bool }