diff --git a/config/config.go b/config/config.go index 2791ce4309..8e2214e4da 100644 --- a/config/config.go +++ b/config/config.go @@ -146,7 +146,8 @@ type Config struct { DisableIdentifyAddressDiscovery bool - EnableAutoNATv2 bool + EnableAutoNATv2 bool + AutoNATv2AllowPrivateAddrs bool UDPBlackHoleSuccessCounter *swarm.BlackHoleSuccessCounter CustomUDPBlackHoleSuccessCounter bool @@ -572,7 +573,11 @@ func (cfg *Config) NewNode() (host.Host, error) { if !cfg.DisableMetrics { mt = autonatv2.NewMetricsTracer(cfg.PrometheusRegisterer) } - autoNATv2, err := autonatv2.New(ah, autonatv2.WithMetricsTracer(mt)) + autonatv2Opts := []autonatv2.AutoNATOption{autonatv2.WithMetricsTracer(mt)} + if cfg.AutoNATv2AllowPrivateAddrs { + autonatv2Opts = append(autonatv2Opts, autonatv2.AllowPrivateAddrs) + } + autoNATv2, err := autonatv2.New(ah, autonatv2Opts...) if err != nil { return nil, fmt.Errorf("failed to create autonatv2: %w", err) } diff --git a/libp2p_test.go b/libp2p_test.go index d9ca422c2c..d9b4bdcb58 100644 --- a/libp2p_test.go +++ b/libp2p_test.go @@ -423,6 +423,12 @@ func TestAutoNATv2Service(t *testing.T) { h.Close() } +func TestAutoNATv2AllowPrivateAddrs(t *testing.T) { + h, err := New(EnableAutoNATv2(), AutoNATv2AllowPrivateAddrs()) + require.NoError(t, err) + h.Close() +} + func TestDisableIdentifyAddressDiscovery(t *testing.T) { h, err := New(DisableIdentifyAddressDiscovery()) require.NoError(t, err) diff --git a/options.go b/options.go index 8a45773718..194139bbd0 100644 --- a/options.go +++ b/options.go @@ -632,6 +632,17 @@ func EnableAutoNATv2() Option { } } +// AutoNATv2AllowPrivateAddrs allows the AutoNATv2 service to use private and +// loopback addresses when verifying reachability. This is only useful for +// testing (e.g. interop tests on a local network) and should not be enabled +// in production. +func AutoNATv2AllowPrivateAddrs() Option { + return func(cfg *Config) error { + cfg.AutoNATv2AllowPrivateAddrs = true + return nil + } +} + // UDPBlackHoleSuccessCounter configures libp2p to use f as the black hole filter for UDP addrs func UDPBlackHoleSuccessCounter(f *swarm.BlackHoleSuccessCounter) Option { return func(cfg *Config) error { diff --git a/p2p/protocol/autonatv2/autonat.go b/p2p/protocol/autonatv2/autonat.go index 95f78c9329..8c45f1b9ec 100644 --- a/p2p/protocol/autonatv2/autonat.go +++ b/p2p/protocol/autonatv2/autonat.go @@ -87,9 +87,9 @@ type AutoNAT struct { // throttlePeerDuration is the duration to wait before making another dial request to the // same server. throttlePeerDuration time.Duration - // allowPrivateAddrs enables using private and localhost addresses for reachability checks. + // AllowPrivateAddrs enables using private and localhost addresses for reachability checks. // This is only useful for testing. - allowPrivateAddrs bool + AllowPrivateAddrs bool } // New returns a new AutoNAT instance. @@ -109,7 +109,7 @@ func New(dialerHost host.Host, opts ...AutoNATOption) (*AutoNAT, error) { cancel: cancel, srv: newServer(dialerHost, s), cli: newClient(s), - allowPrivateAddrs: s.allowPrivateAddrs, + AllowPrivateAddrs: s.AllowPrivateAddrs, peers: newPeersMap(), throttlePeer: make(map[peer.ID]time.Time), throttlePeerDuration: s.throttlePeerDuration, @@ -180,7 +180,7 @@ func (an *AutoNAT) Close() { // GetReachability makes a single dial request for checking reachability for requested addresses func (an *AutoNAT) GetReachability(ctx context.Context, reqs []Request) (Result, error) { var filteredReqs []Request - if !an.allowPrivateAddrs { + if !an.AllowPrivateAddrs { filteredReqs = make([]Request, 0, len(reqs)) for _, r := range reqs { if manet.IsPublicAddr(r.Addr) { diff --git a/p2p/protocol/autonatv2/autonat_test.go b/p2p/protocol/autonatv2/autonat_test.go index a0d8e7814c..dca55d2140 100644 --- a/p2p/protocol/autonatv2/autonat_test.go +++ b/p2p/protocol/autonatv2/autonat_test.go @@ -98,7 +98,7 @@ func TestAutoNATPrivateAddr(t *testing.T) { } func TestClientRequest(t *testing.T) { - an := newAutoNAT(t, nil, allowPrivateAddrs) + an := newAutoNAT(t, nil, AllowPrivateAddrs) defer an.Close() defer an.host.Close() @@ -133,7 +133,7 @@ func TestClientRequest(t *testing.T) { } func TestClientServerError(t *testing.T) { - an := newAutoNAT(t, nil, allowPrivateAddrs) + an := newAutoNAT(t, nil, AllowPrivateAddrs) defer an.Close() defer an.host.Close() @@ -177,7 +177,7 @@ func TestClientServerError(t *testing.T) { } func TestClientDataRequest(t *testing.T) { - an := newAutoNAT(t, nil, allowPrivateAddrs) + an := newAutoNAT(t, nil, AllowPrivateAddrs) defer an.Close() defer an.host.Close() @@ -335,7 +335,7 @@ func TestAutoNATPrivateAndPublicAddrs(t *testing.T) { } func TestClientDialBacks(t *testing.T) { - an := newAutoNAT(t, nil, allowPrivateAddrs) + an := newAutoNAT(t, nil, AllowPrivateAddrs) defer an.Close() defer an.host.Close() @@ -695,7 +695,7 @@ func TestPeerMap(t *testing.T) { } func FuzzClient(f *testing.F) { - a := newAutoNAT(f, nil, allowPrivateAddrs, WithServerRateLimit(math.MaxInt32, math.MaxInt32, math.MaxInt32, 2)) + a := newAutoNAT(f, nil, AllowPrivateAddrs, WithServerRateLimit(math.MaxInt32, math.MaxInt32, math.MaxInt32, 2)) c := newAutoNAT(f, nil) idAndWait(f, c, a) diff --git a/p2p/protocol/autonatv2/options.go b/p2p/protocol/autonatv2/options.go index f7cf4b7178..f5d0cbe16a 100644 --- a/p2p/protocol/autonatv2/options.go +++ b/p2p/protocol/autonatv2/options.go @@ -4,7 +4,7 @@ import "time" // autoNATSettings is used to configure AutoNAT type autoNATSettings struct { - allowPrivateAddrs bool + AllowPrivateAddrs bool serverRPM int serverPerPeerRPM int serverDialDataRPM int @@ -18,7 +18,7 @@ type autoNATSettings struct { func defaultSettings() *autoNATSettings { return &autoNATSettings{ - allowPrivateAddrs: false, + AllowPrivateAddrs: false, serverRPM: 60, // 1 every second serverPerPeerRPM: 12, // 1 every 5 seconds serverDialDataRPM: 12, // 1 every 5 seconds @@ -56,8 +56,8 @@ func withDataRequestPolicy(drp dataRequestPolicyFunc) AutoNATOption { } } -func allowPrivateAddrs(s *autoNATSettings) error { - s.allowPrivateAddrs = true +func AllowPrivateAddrs(s *autoNATSettings) error { + s.AllowPrivateAddrs = true return nil } diff --git a/p2p/protocol/autonatv2/server.go b/p2p/protocol/autonatv2/server.go index e3392399a9..9b54a6c284 100644 --- a/p2p/protocol/autonatv2/server.go +++ b/p2p/protocol/autonatv2/server.go @@ -56,7 +56,7 @@ type server struct { // for tests now func() time.Time - allowPrivateAddrs bool + AllowPrivateAddrs bool } func newServer(dialer host.Host, s *autoNATSettings) *server { @@ -64,7 +64,7 @@ func newServer(dialer host.Host, s *autoNATSettings) *server { dialerHost: dialer, dialDataRequestPolicy: s.dataRequestPolicy, amplificatonAttackPreventionDialWait: s.amplificatonAttackPreventionDialWait, - allowPrivateAddrs: s.allowPrivateAddrs, + AllowPrivateAddrs: s.AllowPrivateAddrs, limiter: &rateLimiter{ RPM: s.serverRPM, PerPeerRPM: s.serverPerPeerRPM, @@ -196,7 +196,7 @@ func (as *server) serveDialRequest(s network.Stream) EventDialRequestCompleted { if err != nil { continue } - if !as.allowPrivateAddrs && !manet.IsPublicAddr(a) { + if !as.AllowPrivateAddrs && !manet.IsPublicAddr(a) { continue } if !as.dialerHost.Network().CanDial(p, a) { diff --git a/p2p/protocol/autonatv2/server_test.go b/p2p/protocol/autonatv2/server_test.go index a524b84a77..af16432fe0 100644 --- a/p2p/protocol/autonatv2/server_test.go +++ b/p2p/protocol/autonatv2/server_test.go @@ -34,13 +34,13 @@ func newTestRequests(addrs []ma.Multiaddr, sendDialData bool) (reqs []Request) { } func TestServerInvalidAddrsRejected(t *testing.T) { - c := newAutoNAT(t, nil, allowPrivateAddrs, withAmplificationAttackPreventionDialWait(0)) + c := newAutoNAT(t, nil, AllowPrivateAddrs, withAmplificationAttackPreventionDialWait(0)) defer c.Close() defer c.host.Close() t.Run("no transport", func(t *testing.T) { dialer := bhost.NewBlankHost(swarmt.GenSwarm(t, swarmt.OptDisableQUIC, swarmt.OptDisableTCP)) - an := newAutoNAT(t, dialer, allowPrivateAddrs) + an := newAutoNAT(t, dialer, AllowPrivateAddrs) defer an.Close() defer an.host.Close() @@ -101,7 +101,7 @@ func TestServerInvalidAddrsRejected(t *testing.T) { t.Run("too many address", func(t *testing.T) { dialer := bhost.NewBlankHost(swarmt.GenSwarm(t, swarmt.OptDisableTCP)) - an := newAutoNAT(t, dialer, allowPrivateAddrs) + an := newAutoNAT(t, dialer, AllowPrivateAddrs) defer an.Close() defer an.host.Close() @@ -120,7 +120,7 @@ func TestServerInvalidAddrsRejected(t *testing.T) { t.Run("msg too large", func(t *testing.T) { dialer := bhost.NewBlankHost(swarmt.GenSwarm(t, swarmt.OptDisableTCP)) - an := newAutoNAT(t, dialer, allowPrivateAddrs) + an := newAutoNAT(t, dialer, AllowPrivateAddrs) defer an.Close() defer an.host.Close() @@ -142,7 +142,7 @@ func TestServerDataRequest(t *testing.T) { // server will skip all tcp addresses dialer := bhost.NewBlankHost(swarmt.GenSwarm(t, swarmt.OptDisableTCP)) // ask for dial data for quic address - an := newAutoNAT(t, dialer, allowPrivateAddrs, withDataRequestPolicy( + an := newAutoNAT(t, dialer, AllowPrivateAddrs, withDataRequestPolicy( func(_, dialAddr ma.Multiaddr) bool { if _, err := dialAddr.ValueForProtocol(ma.P_QUIC_V1); err == nil { return true @@ -155,7 +155,7 @@ func TestServerDataRequest(t *testing.T) { defer an.Close() defer an.host.Close() - c := newAutoNAT(t, nil, allowPrivateAddrs) + c := newAutoNAT(t, nil, AllowPrivateAddrs) defer c.Close() defer c.host.Close() @@ -192,7 +192,7 @@ func TestServerMaxConcurrentRequestsPerPeer(t *testing.T) { const concurrentRequests = 5 stallChan := make(chan struct{}) - an := newAutoNAT(t, nil, allowPrivateAddrs, withDataRequestPolicy( + an := newAutoNAT(t, nil, AllowPrivateAddrs, withDataRequestPolicy( // stall all allowed requests func(_, _ ma.Multiaddr) bool { <-stallChan @@ -206,7 +206,7 @@ func TestServerMaxConcurrentRequestsPerPeer(t *testing.T) { // server will skip all tcp addresses dialer := bhost.NewBlankHost(swarmt.GenSwarm(t, swarmt.OptDisableTCP)) - c := newAutoNAT(t, dialer, allowPrivateAddrs) + c := newAutoNAT(t, dialer, AllowPrivateAddrs) defer c.Close() defer c.host.Close() @@ -256,7 +256,7 @@ func TestServerDataRequestJitter(t *testing.T) { // server will skip all tcp addresses dialer := bhost.NewBlankHost(swarmt.GenSwarm(t, swarmt.OptDisableTCP)) // ask for dial data for quic address - an := newAutoNAT(t, dialer, allowPrivateAddrs, withDataRequestPolicy( + an := newAutoNAT(t, dialer, AllowPrivateAddrs, withDataRequestPolicy( func(_, dialAddr ma.Multiaddr) bool { if _, err := dialAddr.ValueForProtocol(ma.P_QUIC_V1); err == nil { return true @@ -269,7 +269,7 @@ func TestServerDataRequestJitter(t *testing.T) { defer an.Close() defer an.host.Close() - c := newAutoNAT(t, nil, allowPrivateAddrs) + c := newAutoNAT(t, nil, AllowPrivateAddrs) defer c.Close() defer c.host.Close() @@ -303,11 +303,11 @@ func TestServerDataRequestJitter(t *testing.T) { } func TestServerDial(t *testing.T) { - an := newAutoNAT(t, nil, WithServerRateLimit(10, 10, 10, 2), allowPrivateAddrs) + an := newAutoNAT(t, nil, WithServerRateLimit(10, 10, 10, 2), AllowPrivateAddrs) defer an.Close() defer an.host.Close() - c := newAutoNAT(t, nil, allowPrivateAddrs) + c := newAutoNAT(t, nil, AllowPrivateAddrs) defer c.Close() defer c.host.Close() @@ -521,14 +521,14 @@ func TestServerDataRequestWithAmplificationAttackPrevention(t *testing.T) { // server will skip all tcp addresses dialer := bhost.NewBlankHost(swarmt.GenSwarm(t, swarmt.OptDisableTCP)) // ask for dial data for quic address - an := newAutoNAT(t, dialer, allowPrivateAddrs, + an := newAutoNAT(t, dialer, AllowPrivateAddrs, WithServerRateLimit(10, 10, 10, 2), withAmplificationAttackPreventionDialWait(0), ) defer an.Close() defer an.host.Close() - c := newAutoNAT(t, nil, allowPrivateAddrs) + c := newAutoNAT(t, nil, AllowPrivateAddrs) defer c.Close() defer c.host.Close() @@ -596,7 +596,7 @@ func TestDefaultAmplificationAttackPrevention(t *testing.T) { } func FuzzServerDialRequest(f *testing.F) { - a := newAutoNAT(f, nil, allowPrivateAddrs, WithServerRateLimit(math.MaxInt32, math.MaxInt32, math.MaxInt32, 2)) + a := newAutoNAT(f, nil, AllowPrivateAddrs, WithServerRateLimit(math.MaxInt32, math.MaxInt32, math.MaxInt32, 2)) c := newAutoNAT(f, nil) idAndWait(f, c, a) // reduce the streamTimeout before running this. TODO: fix this