diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -862,6 +862,15 @@ #else hidden_args.emplace_back("-upnp"); #endif +#ifdef USE_NATPMP + argsman.AddArg( + "-natpmp", + strprintf("Use NAT-PMP to map the listening port (default: %s)", + DEFAULT_NATPMP ? "1 when listening and no -proxy" : "0"), + ArgsManager::ALLOW_BOOL, OptionsCategory::CONNECTION); +#else + hidden_args.emplace_back("-natpmp"); +#endif // USE_NATPMP argsman.AddArg( "-whitebind=<[permissions@]addr>", "Bind to the given address and add permission flags to the peers " @@ -1565,14 +1574,19 @@ "%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__); } - // to protect privacy, do not use UPNP when a proxy is set. The user may - // still specify -listen=1 to listen locally, so don't rely on this + // to protect privacy, do not map ports when a proxy is set. The user + // may still specify -listen=1 to listen locally, so don't rely on this // happening through -listen below. if (args.SoftSetBoolArg("-upnp", false)) { LogPrintf( "%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__); } + if (args.SoftSetBoolArg("-natpmp", false)) { + LogPrintf( + "%s: parameter interaction: -proxy set -> setting -natpmp=0\n", + __func__); + } // to protect privacy, do not discover addresses by default if (args.SoftSetBoolArg("-discover", false)) { LogPrintf("%s: parameter interaction: -proxy set -> setting " @@ -1589,6 +1603,11 @@ "%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__); } + if (args.SoftSetBoolArg("-natpmp", false)) { + LogPrintf( + "%s: parameter interaction: -listen=0 -> setting -natpmp=0\n", + __func__); + } if (args.SoftSetBoolArg("-discover", false)) { LogPrintf( "%s: parameter interaction: -listen=0 -> setting -discover=0\n", @@ -2997,8 +3016,9 @@ Discover(); - // Map ports with UPnP - StartMapPort(args.GetBoolArg("-upnp", DEFAULT_UPNP)); + // Map ports with UPnP or NAT-PMP. + StartMapPort(args.GetBoolArg("-upnp", DEFAULT_UPNP), + gArgs.GetBoolArg("-natpmp", DEFAULT_NATPMP)); CConnman::Options connOptions; connOptions.nLocalServices = nLocalServices; diff --git a/src/interfaces/node.h b/src/interfaces/node.h --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -84,7 +84,7 @@ virtual bool shutdownRequested() = 0; //! Map port. - virtual void mapPort(bool use_upnp) = 0; + virtual void mapPort(bool use_upnp, bool use_natpmp) = 0; //! Get proxy. virtual bool getProxy(Network net, proxyType &proxy_info) = 0; diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -86,7 +86,9 @@ } } bool shutdownRequested() override { return ShutdownRequested(); } - void mapPort(bool use_upnp) override { StartMapPort(use_upnp); } + void mapPort(bool use_upnp, bool use_natpmp) override { + StartMapPort(use_upnp, use_natpmp); + } bool getProxy(Network net, proxyType &proxy_info) override { return GetProxy(net, proxy_info); } diff --git a/src/mapport.h b/src/mapport.h --- a/src/mapport.h +++ b/src/mapport.h @@ -5,12 +5,17 @@ #ifndef BITCOIN_MAPPORT_H #define BITCOIN_MAPPORT_H -/** -upnp default */ #ifdef USE_UPNP -static const bool DEFAULT_UPNP = USE_UPNP; +static constexpr bool DEFAULT_UPNP = USE_UPNP; #else -static const bool DEFAULT_UPNP = false; -#endif +static constexpr bool DEFAULT_UPNP = false; +#endif // USE_UPNP + +#ifdef USE_NATPMP +static constexpr bool DEFAULT_NATPMP = USE_NATPMP; +#else +static constexpr bool DEFAULT_NATPMP = false; +#endif // USE_NATPMP enum MapPortProtoFlag : unsigned int { NONE = 0x00, @@ -18,7 +23,7 @@ NAT_PMP = 0x02, }; -void StartMapPort(bool use_upnp); +void StartMapPort(bool use_upnp, bool use_natpmp); void InterruptMapPort(); void StopMapPort(); diff --git a/src/mapport.cpp b/src/mapport.cpp --- a/src/mapport.cpp +++ b/src/mapport.cpp @@ -334,8 +334,9 @@ } } -void StartMapPort(bool use_upnp) { +void StartMapPort(bool use_upnp, bool use_natpmp) { MapPortProtoSetEnabled(MapPortProtoFlag::UPNP, use_upnp); + MapPortProtoSetEnabled(MapPortProtoFlag::NAT_PMP, use_natpmp); DispatchMapPort(); } @@ -354,7 +355,7 @@ } #else // #if defined(USE_NATPMP) || defined(USE_UPNP) -void StartMapPort(bool use_upnp) { +void StartMapPort(bool use_upnp, bool use_natpmp) { // Intentionally left blank. } void InterruptMapPort() { diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -50,7 +50,8 @@ #endif connect(this, &QDialog::accepted, [this]() { QSettings settings; - model->node().mapPort(settings.value("fUseUPnP").toBool()); + model->node().mapPort(settings.value("fUseUPnP").toBool(), + settings.value("fUseNatpmp").toBool()); }); ui->proxyIp->setEnabled(false); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -58,6 +58,7 @@ HideTrayIcon, // bool MinimizeToTray, // bool MapPortUPnP, // bool + MapPortNatpmp, // bool MinimizeOnClose, // bool ProxyUse, // bool ProxyIP, // QString diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -148,6 +148,14 @@ addOverriddenOption("-upnp"); } + if (!settings.contains("fUseNatpmp")) { + settings.setValue("fUseNatpmp", DEFAULT_NATPMP); + } + if (!gArgs.SoftSetBoolArg("-natpmp", + settings.value("fUseNatpmp").toBool())) { + addOverriddenOption("-natpmp"); + } + if (!settings.contains("fListen")) { settings.setValue("fListen", DEFAULT_LISTEN); } @@ -323,7 +331,13 @@ return settings.value("fUseUPnP"); #else return false; -#endif +#endif // USE_UPNP + case MapPortNatpmp: +#ifdef USE_NATPMP + return settings.value("fUseNatpmp"); +#else + return false; +#endif // USE_NATPMP case MinimizeOnClose: return fMinimizeOnClose; @@ -394,6 +408,9 @@ case MapPortUPnP: // core option - can be changed on-the-fly settings.setValue("fUseUPnP", value.toBool()); break; + case MapPortNatpmp: // core option - can be changed on-the-fly + settings.setValue("fUseNatpmp", value.toBool()); + break; case MinimizeOnClose: fMinimizeOnClose = value.toBool(); settings.setValue("fMinimizeOnClose", fMinimizeOnClose); diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -430,6 +430,7 @@ f.write("listenonion=0\n") f.write("printtoconsole=0\n") f.write("upnp=0\n") + f.write("natpmp=0\n") f.write("usecashaddr=1\n") # Increase peertimeout to avoid disconnects while using mocktime. # peertimeout is measured in mock time, so setting it large enough to