From 687c7d4a5d6849fe2fcf6e16ac3ae81b095c28dd Mon Sep 17 00:00:00 2001
From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com>
Date: Sat, 26 Feb 2022 17:49:13 +0530
Subject: [PATCH 1/4] merge bitcoin#18077: Add NAT-PMP port forwarding support
---
configure.ac | 47 ++++
depends/Makefile | 6 +-
depends/README.md | 2 +
depends/config.site.in | 4 +
depends/packages/libnatpmp.mk | 19 ++
depends/packages/packages.mk | 1 +
doc/build-osx.md | 2 +-
doc/productivity.md | 1 +
doc/tor.md | 2 +-
src/Makefile.am | 8 +-
src/Makefile.bench.include | 2 +-
src/Makefile.qt.include | 2 +-
src/Makefile.qttest.include | 2 +-
src/Makefile.test.include | 2 +-
src/init.cpp | 20 +-
src/interfaces/node.cpp | 11 +-
src/interfaces/node.h | 2 +-
src/mapport.cpp | 336 +++++++++++++++++++++++++
src/mapport.h | 30 +++
src/net.cpp | 123 ---------
src/net.h | 11 +-
src/qt/forms/optionsdialog.ui | 10 +
src/qt/optionsdialog.cpp | 8 +
src/qt/optionsmodel.cpp | 24 +-
src/qt/optionsmodel.h | 1 +
test/functional/test_framework/util.py | 1 +
26 files changed, 514 insertions(+), 163 deletions(-)
create mode 100644 depends/packages/libnatpmp.mk
create mode 100644 src/mapport.cpp
create mode 100644 src/mapport.h
diff --git a/configure.ac b/configure.ac
index 38fb7c99d36d..6438aef332b1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -134,6 +134,18 @@ AC_ARG_ENABLE([upnp-default],
[use_upnp_default=$enableval],
[use_upnp_default=no])
+AC_ARG_WITH([natpmp],
+ [AS_HELP_STRING([--with-natpmp],
+ [enable NAT-PMP (default is yes if libnatpmp is found)])],
+ [use_natpmp=$withval],
+ [use_natpmp=auto])
+
+AC_ARG_ENABLE([natpmp-default],
+ [AS_HELP_STRING([--enable-natpmp-default],
+ [if NAT-PMP is enabled, turn it on at startup (default is no)])],
+ [use_natpmp_default=$enableval],
+ [use_natpmp_default=no])
+
AC_ARG_ENABLE(tests,
AS_HELP_STRING([--disable-tests],[do not compile tests (default is to compile)]),
[use_tests=$enableval],
@@ -1182,6 +1194,7 @@ if test "x$enable_fuzz" = "xyes"; then
use_bench=no
use_openssl=no
use_upnp=no
+ use_natpmp=no
use_zmq=no
else
BITCOIN_QT_INIT
@@ -1235,6 +1248,13 @@ if test x$have_miniupnpc != xno; then
fi
fi
+dnl Check for libnatpmp (optional).
+if test "x$use_natpmp" != xno; then
+ AC_CHECK_HEADERS([natpmp.h],
+ [AC_CHECK_LIB([natpmp], [initnatpmp], [NATPMP_LIBS=-lnatpmp], [have_natpmp=no])],
+ [have_natpmp=no])
+fi
+
if test x$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononononono; then
use_boost=no
else
@@ -1597,6 +1617,31 @@ else
fi
fi
+dnl Enable NAT-PMP support.
+AC_MSG_CHECKING([whether to build with support for NAT-PMP])
+if test "x$have_natpmp" = xno; then
+ if test "x$use_natpmp" = xyes; then
+ AC_MSG_ERROR([NAT-PMP requested but cannot be built. Use --without-natpmp])
+ fi
+ AC_MSG_RESULT([no])
+ use_natpmp=no
+else
+ if test "x$use_natpmp" != xno; then
+ AC_MSG_RESULT([yes])
+ AC_MSG_CHECKING([whether to build with NAT-PMP enabled by default])
+ use_natpmp=yes
+ natpmp_setting=0
+ if test "x$use_natpmp_default" != xno; then
+ use_natpmp_default=yes
+ natpmp_setting=1
+ fi
+ AC_MSG_RESULT($use_natpmp_default)
+ AC_DEFINE_UNQUOTED([USE_NATPMP], [$natpmp_setting], [NAT-PMP support not compiled if undefined, otherwise value (0 or 1) determines default state])
+ else
+ AC_MSG_RESULT([no])
+ fi
+fi
+
dnl these are only used when qt is enabled
BUILD_TEST_QT=""
if test x$bitcoin_enable_qt != xno; then
@@ -1773,6 +1818,7 @@ AC_SUBST(MINIUPNPC_LIBS)
AC_SUBST(CRYPTO_LIBS)
AC_SUBST(SSL_LIBS)
AC_SUBST(GMP_LIBS)
+AC_SUBST(NATPMP_LIBS)
AC_SUBST(EVENT_LIBS)
AC_SUBST(EVENT_PTHREADS_LIBS)
AC_SUBST(ZMQ_LIBS)
@@ -1851,6 +1897,7 @@ if test x$use_tests != xno; then
echo " with fuzz = $enable_fuzz"
fi
echo " with upnp = $use_upnp"
+echo " with natpmp = $use_natpmp"
echo " use asm = $use_asm"
echo " sanitizers = $use_sanitizers"
echo " debug enabled = $enable_debug"
diff --git a/depends/Makefile b/depends/Makefile
index cae17a2eda1b..df4491e71a3a 100644
--- a/depends/Makefile
+++ b/depends/Makefile
@@ -38,6 +38,7 @@ NO_OPENSSL ?=
NO_WALLET ?=
NO_ZMQ ?=
NO_UPNP ?=
+NO_NATPMP ?=
FALLBACK_DOWNLOAD_PATH ?= https://bitcoincore.org/depends-sources
BUILD = $(shell ./config.guess)
@@ -134,12 +135,14 @@ endif
qt_packages_$(NO_QT) = $(qt_packages) $(qt_$(host_os)_packages) $(qt_$(host_arch)_$(host_os)_packages)
wallet_packages_$(NO_WALLET) = $(wallet_packages)
upnp_packages_$(NO_UPNP) = $(upnp_packages)
+natpmp_packages_$(NO_NATPMP) = $(natpmp_packages)
+
zmq_packages_$(NO_ZMQ) = $(zmq_packages)
protobuf_packages_$(NO_PROTOBUF) = $(protobuf_packages)
openssl_packages_$(NO_OPENSSL) = $(openssl_packages)
-packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_)
+packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_) $(natpmp_packages_)
native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages)
ifneq ($(protobuf_packages_),)
@@ -218,6 +221,7 @@ $(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_
-e 's|@disable_bip70@|$(NO_PROTOBUF)|' \
-e 's|@no_wallet@|$(NO_WALLET)|' \
-e 's|@no_upnp@|$(NO_UPNP)|' \
+ -e 's|@no_natpmp@|$(NO_NATPMP)|' \
-e 's|@debug@|$(DEBUG)|' \
$< > $@
$(AT)touch $@
diff --git a/depends/README.md b/depends/README.md
index 138d18d05ffe..2725e56b82af 100644
--- a/depends/README.md
+++ b/depends/README.md
@@ -89,6 +89,8 @@ The following can be set when running make: `make FOO=bar`
Don't download/build/cache libs needed to enable the wallet
NO_UPNP
Don't download/build/cache packages needed for enabling upnp
+NO_NATPMP
+Don't download/build/cache packages needed for enabling NAT-PMP
DEBUG
disable some optimizations and enable more runtime checking
PROTOBUF
diff --git a/depends/config.site.in b/depends/config.site.in
index ff50f6e48d0f..a36eb406090f 100644
--- a/depends/config.site.in
+++ b/depends/config.site.in
@@ -39,6 +39,10 @@ if test -z $with_miniupnpc && test -n "@no_upnp@"; then
with_miniupnpc=no
fi
+if test -z $with_natpmp && test -n "@no_natpmp@"; then
+ with_natpmp=no
+fi
+
if test -z $with_gui && test -n "@no_qt@"; then
with_gui=no
fi
diff --git a/depends/packages/libnatpmp.mk b/depends/packages/libnatpmp.mk
new file mode 100644
index 000000000000..a24f201859a0
--- /dev/null
+++ b/depends/packages/libnatpmp.mk
@@ -0,0 +1,19 @@
+package=libnatpmp
+$(package)_version=20150609
+$(package)_download_path=https://miniupnp.tuxfamily.org/files/
+$(package)_file_name=$(package)-$($(package)_version).tar.gz
+$(package)_sha256_hash=e1aa9c4c4219bc06943d6b2130f664daee213fb262fcb94dd355815b8f4536b0
+
+define $(package)_set_vars
+ $(package)_build_opts=CC="$($(package)_cc)"
+endef
+
+define $(package)_build_cmds
+ $(MAKE) libnatpmp.a $($(package)_build_opts)
+endef
+
+define $(package)_stage_cmds
+ mkdir -p $($(package)_staging_prefix_dir)/include $($(package)_staging_prefix_dir)/lib &&\
+ install *.h $($(package)_staging_prefix_dir)/include &&\
+ install libnatpmp.a $($(package)_staging_prefix_dir)/lib
+endef
diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk
index af672ed18666..bbff61e598ca 100644
--- a/depends/packages/packages.mk
+++ b/depends/packages/packages.mk
@@ -18,6 +18,7 @@ wallet_packages=bdb
zmq_packages=zeromq
upnp_packages=miniupnpc
+natpmp_packages=libnatpmp
darwin_native_packages = native_biplist native_ds_store native_mac_alias
diff --git a/doc/build-osx.md b/doc/build-osx.md
index 7ce4c07e4a77..df5afa9e25e3 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -17,7 +17,7 @@ Base build dependencies
-----------------------
```bash
-brew install automake libtool pkg-config
+brew install automake libtool pkg-config libnatpmp
```
If you want to build the disk image with `make deploy` (.dmg / optional), you need RSVG:
diff --git a/doc/productivity.md b/doc/productivity.md
index 39f3cdf194ac..c0eb98faf8e0 100644
--- a/doc/productivity.md
+++ b/doc/productivity.md
@@ -51,6 +51,7 @@ After running `./autogen.sh`, which generates the `./configure` file, use `./con
```sh
--without-miniupnpc
+--without-natpmp
--disable-bench
--disable-wallet
--without-gui
diff --git a/doc/tor.md b/doc/tor.md
index 17cb85ace8ca..8e6d6be52555 100644
--- a/doc/tor.md
+++ b/doc/tor.md
@@ -92,7 +92,7 @@ as well, use `discover` instead:
./dashd ... -discover
-and open port 9999 on your firewall (or use -upnp).
+and open port 9999 on your firewall (or use port mapping, i.e., `-upnp` or `-natpmp`).
If you only want to use Tor to reach .onion addresses, but not use it as a proxy
for normal IPv4/IPv6 communication, use:
diff --git a/src/Makefile.am b/src/Makefile.am
index 8da39387e0dc..6eb9b551d76d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -219,6 +219,7 @@ BITCOIN_CORE_H = \
llmq/params.h \
logging.h \
logging/timer.h \
+ mapport.h \
masternode/node.h \
masternode/meta.h \
masternode/payments.h \
@@ -354,6 +355,7 @@ libdash_server_a_SOURCES = \
coinjoin/options.cpp \
coinjoin/server.cpp \
consensus/tx_verify.cpp \
+ dbwrapper.cpp \
dsnotificationinterface.cpp \
evo/cbtx.cpp \
evo/deterministicmns.cpp \
@@ -373,7 +375,6 @@ libdash_server_a_SOURCES = \
interfaces/chain.cpp \
interfaces/node.cpp \
init.cpp \
- dbwrapper.cpp \
governance/governance.cpp \
governance/classes.cpp \
governance/object.cpp \
@@ -393,6 +394,7 @@ libdash_server_a_SOURCES = \
llmq/signing.cpp \
llmq/signing_shares.cpp \
llmq/utils.cpp \
+ mapport.cpp \
masternode/node.cpp \
masternode/meta.cpp \
masternode/payments.cpp \
@@ -734,7 +736,7 @@ dashd_LDADD = \
$(LIBMEMENV) \
$(LIBSECP256K1)
-dashd_LDADD += $(BACKTRACE_LIB) $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(BLS_LIBS) $(GMP_LIBS)
+dashd_LDADD += $(BACKTRACE_LIB) $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(BLS_LIBS) $(GMP_LIBS)
# dash-cli binary #
dash_cli_SOURCES = dash-cli.cpp
@@ -803,7 +805,7 @@ dash_wallet_LDADD = \
$(LIBSECP256K1) \
$(LIBUNIVALUE)
-dash_wallet_LDADD += $(BACKTRACE_LIB) $(BOOST_LIBS) $(BDB_LIBS) $(CRYPTO_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(ZMQ_LIBS) $(BLS_LIBS) $(GMP_LIBS)
+dash_wallet_LDADD += $(BACKTRACE_LIB) $(BOOST_LIBS) $(BDB_LIBS) $(CRYPTO_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(ZMQ_LIBS) $(BLS_LIBS) $(GMP_LIBS)
#
# dashconsensus library #
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 653da08f3980..8728f5e5e2d7 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -78,7 +78,7 @@ bench_bench_dash_SOURCES += bench/coin_selection.cpp
bench_bench_dash_SOURCES += bench/wallet_balance.cpp
endif
-bench_bench_dash_LDADD += $(BACKTRACE_LIB) $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(BLS_LIBS) $(GMP_LIBS)
+bench_bench_dash_LDADD += $(BACKTRACE_LIB) $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(BLS_LIBS) $(GMP_LIBS)
bench_bench_dash_LDFLAGS = $(LDFLAGS_WRAP_EXCEPTIONS) $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES)
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 270ea35fb503..de08c77b768d 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -407,7 +407,7 @@ if ENABLE_ZMQ
qt_dash_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
qt_dash_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
- $(BACKTRACE_LIB) $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
+ $(BACKTRACE_LIB) $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(BLS_LIBS) $(GMP_LIBS)
if ENABLE_BIP70
qt_dash_qt_LDADD += $(SSL_LIBS)
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index f28967128861..f10fa55466b7 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -76,7 +76,7 @@ qt_test_test_dash_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
qt_test_test_dash_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \
$(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BACKTRACE_LIB) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
- $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
+ $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(BLS_LIBS) $(GMP_LIBS)
qt_test_test_dash_qt_LDFLAGS = $(LDFLAGS_WRAP_EXCEPTIONS) $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
qt_test_test_dash_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 0e0db4a1478a..9bba515794bb 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -227,7 +227,7 @@ test_test_dash_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMM
$(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BACKTRACE_LIB) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
test_test_dash_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
-test_test_dash_LDADD += $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(BLS_LIBS) $(GMP_LIBS)
+test_test_dash_LDADD += $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(BLS_LIBS) $(GMP_LIBS)
test_test_dash_LDFLAGS = $(LDFLAGS_WRAP_EXCEPTIONS) $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static
if ENABLE_ZMQ
diff --git a/src/init.cpp b/src/init.cpp
index 030cf8fc4e23..95094dfb1d01 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -28,7 +28,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -57,6 +57,7 @@
#include
#include
#include
+#include
#include
#include
@@ -559,6 +560,11 @@ void SetupServerArgs()
#else
hidden_args.emplace_back("-upnp");
#endif
+#ifdef USE_NATPMP
+ gArgs.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
gArgs.AddArg("-whitebind=<[permissions@]addr>", "Bind to given address and whitelist peers connecting to it. "
"Use [host]:port notation for IPv6. Allowed permissions are bloomfilter (allow requesting BIP37 filtered blocks and transactions), "
"noban (do not ban for misbehavior), "
@@ -1084,10 +1090,12 @@ void InitParameterInteraction()
// to protect privacy, do not listen by default if a default proxy server is specified
if (gArgs.SoftSetBoolArg("-listen", false))
LogPrintf("%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 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 (gArgs.SoftSetBoolArg("-upnp", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__);
+ if (gArgs.SoftSetBoolArg("-natpmp", false))
+ LogPrintf("%s: parameter interaction: -proxy set -> setting -natpmp=0\n", __func__);
// to protect privacy, do not discover addresses by default
if (gArgs.SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -discover=0\n", __func__);
@@ -1097,6 +1105,8 @@ void InitParameterInteraction()
// do not map ports or try to retrieve public IP when not listening (pointless)
if (gArgs.SoftSetBoolArg("-upnp", false))
LogPrintf("%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__);
+ if (gArgs.SoftSetBoolArg("-natpmp", false))
+ LogPrintf("%s: parameter interaction: -listen=0 -> setting -natpmp=0\n", __func__);
if (gArgs.SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -listen=0 -> setting -discover=0\n", __func__);
if (gArgs.SoftSetBoolArg("-listenonion", false))
@@ -2411,10 +2421,8 @@ bool AppInitMain(InitInterfaces& interfaces)
Discover();
- // Map ports with UPnP
- if (gArgs.GetBoolArg("-upnp", DEFAULT_UPNP)) {
- StartMapPort();
- }
+ // Map ports with UPnP or NAT-PMP.
+ StartMapPort(gArgs.GetBoolArg("-upnp", DEFAULT_UPNP), gArgs.GetBoolArg("-natpmp", DEFAULT_NATPMP));
CConnman::Options connOptions;
connOptions.nLocalServices = nLocalServices;
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index 30257ca10564..dcf31d72dd87 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -16,6 +16,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -208,15 +209,7 @@ class NodeImpl : public Node
}
void startShutdown() override { StartShutdown(); }
bool shutdownRequested() override { return ShutdownRequested(); }
- void mapPort(bool use_upnp) override
- {
- if (use_upnp) {
- StartMapPort();
- } else {
- InterruptMapPort();
- StopMapPort();
- }
- }
+ void mapPort(bool use_upnp, bool use_natpmp) override { StartMapPort(use_upnp, use_natpmp); }
void setupServerArgs() override { return SetupServerArgs(); }
bool getProxy(Network net, proxyType& proxy_info) override { return GetProxy(net, proxy_info); }
size_t getNodeCount(CConnman::NumConnections flags) override
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index c75c6959ff26..81558175f3de 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -160,7 +160,7 @@ class Node
virtual void setupServerArgs() = 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/mapport.cpp b/src/mapport.cpp
new file mode 100644
index 000000000000..661687382b45
--- /dev/null
+++ b/src/mapport.cpp
@@ -0,0 +1,336 @@
+// Copyright (c) 2011-2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#if defined(HAVE_CONFIG_H)
+#include
+#endif
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef USE_NATPMP
+#include
+#include
+#endif // USE_NATPMP
+
+#ifdef USE_UPNP
+#include
+#include
+#include
+// The minimum supported miniUPnPc API version is set to 10. This keeps compatibility
+// with Ubuntu 16.04 LTS and Debian 8 libminiupnpc-dev packages.
+static_assert(MINIUPNPC_API_VERSION >= 10, "miniUPnPc API version >= 10 assumed");
+#endif // USE_UPNP
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if defined(USE_NATPMP) || defined(USE_UPNP)
+static CThreadInterrupt g_mapport_interrupt;
+static std::thread g_mapport_thread;
+static std::atomic_uint g_mapport_enabled_protos{MapPortProtoFlag::NONE};
+static std::atomic g_mapport_current_proto{MapPortProtoFlag::NONE};
+
+using namespace std::chrono_literals;
+static constexpr auto PORT_MAPPING_REANNOUNCE_PERIOD{20min};
+static constexpr auto PORT_MAPPING_RETRY_PERIOD{5min};
+
+#ifdef USE_NATPMP
+static uint16_t g_mapport_external_port = 0;
+static bool NatpmpInit(natpmp_t* natpmp)
+{
+ const int r_init = initnatpmp(natpmp, /* detect gateway automatically */ 0, /* forced gateway - NOT APPLIED*/ 0);
+ if (r_init == 0) return true;
+ LogPrintf("natpmp: initnatpmp() failed with %d error.\n", r_init);
+ return false;
+}
+
+static bool NatpmpDiscover(natpmp_t* natpmp, struct in_addr& external_ipv4_addr)
+{
+ const int r_send = sendpublicaddressrequest(natpmp);
+ if (r_send == 2 /* OK */) {
+ int r_read;
+ natpmpresp_t response;
+ do {
+ r_read = readnatpmpresponseorretry(natpmp, &response);
+ } while (r_read == NATPMP_TRYAGAIN);
+
+ if (r_read == 0) {
+ external_ipv4_addr = response.pnu.publicaddress.addr;
+ return true;
+ } else if (r_read == NATPMP_ERR_NOGATEWAYSUPPORT) {
+ LogPrintf("natpmp: The gateway does not support NAT-PMP.\n");
+ } else {
+ LogPrintf("natpmp: readnatpmpresponseorretry() for public address failed with %d error.\n", r_read);
+ }
+ } else {
+ LogPrintf("natpmp: sendpublicaddressrequest() failed with %d error.\n", r_send);
+ }
+
+ return false;
+}
+
+static bool NatpmpMapping(natpmp_t* natpmp, const struct in_addr& external_ipv4_addr, uint16_t private_port, bool& external_ip_discovered)
+{
+ const uint16_t suggested_external_port = g_mapport_external_port ? g_mapport_external_port : private_port;
+ const int r_send = sendnewportmappingrequest(natpmp, NATPMP_PROTOCOL_TCP, private_port, suggested_external_port, 3600 /*seconds*/);
+ if (r_send == 12 /* OK */) {
+ int r_read;
+ natpmpresp_t response;
+ do {
+ r_read = readnatpmpresponseorretry(natpmp, &response);
+ } while (r_read == NATPMP_TRYAGAIN);
+
+ if (r_read == 0) {
+ auto pm = response.pnu.newportmapping;
+ if (private_port == pm.privateport && pm.lifetime > 0) {
+ g_mapport_external_port = pm.mappedpublicport;
+ const CService external{external_ipv4_addr, pm.mappedpublicport};
+ if (!external_ip_discovered && fDiscover) {
+ AddLocal(external, LOCAL_MAPPED);
+ external_ip_discovered = true;
+ }
+ LogPrintf("natpmp: Port mapping successful. External address = %s\n", external.ToString());
+ return true;
+ } else {
+ LogPrintf("natpmp: Port mapping failed.\n");
+ }
+ } else if (r_read == NATPMP_ERR_NOGATEWAYSUPPORT) {
+ LogPrintf("natpmp: The gateway does not support NAT-PMP.\n");
+ } else {
+ LogPrintf("natpmp: readnatpmpresponseorretry() for port mapping failed with %d error.\n", r_read);
+ }
+ } else {
+ LogPrintf("natpmp: sendnewportmappingrequest() failed with %d error.\n", r_send);
+ }
+
+ return false;
+}
+
+static bool ProcessNatpmp()
+{
+ bool ret = false;
+ natpmp_t natpmp;
+ struct in_addr external_ipv4_addr;
+ if (NatpmpInit(&natpmp) && NatpmpDiscover(&natpmp, external_ipv4_addr)) {
+ bool external_ip_discovered = false;
+ const uint16_t private_port = GetListenPort();
+ do {
+ ret = NatpmpMapping(&natpmp, external_ipv4_addr, private_port, external_ip_discovered);
+ } while (ret && g_mapport_interrupt.sleep_for(PORT_MAPPING_REANNOUNCE_PERIOD));
+ g_mapport_interrupt.reset();
+
+ const int r_send = sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_TCP, private_port, g_mapport_external_port, /* remove a port mapping */ 0);
+ g_mapport_external_port = 0;
+ if (r_send == 12 /* OK */) {
+ LogPrintf("natpmp: Port mapping removed successfully.\n");
+ } else {
+ LogPrintf("natpmp: sendnewportmappingrequest(0) failed with %d error.\n", r_send);
+ }
+ }
+
+ closenatpmp(&natpmp);
+ return ret;
+}
+#endif // USE_NATPMP
+
+#ifdef USE_UPNP
+static bool ProcessUpnp()
+{
+ bool ret = false;
+ std::string port = strprintf("%u", GetListenPort());
+ const char * multicastif = nullptr;
+ const char * minissdpdpath = nullptr;
+ struct UPNPDev * devlist = nullptr;
+ char lanaddr[64];
+
+ int error = 0;
+#if MINIUPNPC_API_VERSION < 14
+ devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);
+#else
+ devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error);
+#endif
+
+ struct UPNPUrls urls;
+ struct IGDdatas data;
+ int r;
+
+ r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
+ if (r == 1)
+ {
+ if (fDiscover) {
+ char externalIPAddress[40];
+ r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
+ if (r != UPNPCOMMAND_SUCCESS) {
+ LogPrintf("UPnP: GetExternalIPAddress() returned %d\n", r);
+ } else {
+ if (externalIPAddress[0]) {
+ CNetAddr resolved;
+ if (LookupHost(externalIPAddress, resolved, false)) {
+ LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved.ToString().c_str());
+ AddLocal(resolved, LOCAL_MAPPED);
+ }
+ } else {
+ LogPrintf("UPnP: GetExternalIPAddress failed.\n");
+ }
+ }
+ }
+
+ std::string strDesc = PACKAGE_NAME " " + FormatFullVersion();
+
+ do {
+ r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0");
+
+ if (r != UPNPCOMMAND_SUCCESS) {
+ ret = false;
+ LogPrintf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", port, port, lanaddr, r, strupnperror(r));
+ break;
+ } else {
+ ret = true;
+ LogPrintf("UPnP Port Mapping successful.\n");
+ }
+ } while (g_mapport_interrupt.sleep_for(PORT_MAPPING_REANNOUNCE_PERIOD));
+ g_mapport_interrupt.reset();
+
+ r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0);
+ LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r);
+ freeUPNPDevlist(devlist); devlist = nullptr;
+ FreeUPNPUrls(&urls);
+ } else {
+ LogPrintf("No valid UPnP IGDs found\n");
+ freeUPNPDevlist(devlist); devlist = nullptr;
+ if (r != 0)
+ FreeUPNPUrls(&urls);
+ }
+
+ return ret;
+}
+#endif // USE_UPNP
+
+static void ThreadMapPort()
+{
+ bool ok;
+ do {
+ ok = false;
+
+#ifdef USE_UPNP
+ // High priority protocol.
+ if (g_mapport_enabled_protos & MapPortProtoFlag::UPNP) {
+ g_mapport_current_proto = MapPortProtoFlag::UPNP;
+ ok = ProcessUpnp();
+ if (ok) continue;
+ }
+#endif // USE_UPNP
+
+#ifdef USE_NATPMP
+ // Low priority protocol.
+ if (g_mapport_enabled_protos & MapPortProtoFlag::NAT_PMP) {
+ g_mapport_current_proto = MapPortProtoFlag::NAT_PMP;
+ ok = ProcessNatpmp();
+ if (ok) continue;
+ }
+#endif // USE_NATPMP
+
+ g_mapport_current_proto = MapPortProtoFlag::NONE;
+ if (g_mapport_enabled_protos == MapPortProtoFlag::NONE) {
+ return;
+ }
+
+ } while (ok || g_mapport_interrupt.sleep_for(PORT_MAPPING_RETRY_PERIOD));
+}
+
+void StartThreadMapPort()
+{
+ if (!g_mapport_thread.joinable()) {
+ assert(!g_mapport_interrupt);
+ g_mapport_thread = std::thread(std::bind(&TraceThread, "mapport", &ThreadMapPort));
+ }
+}
+
+static void DispatchMapPort()
+{
+ if (g_mapport_current_proto == MapPortProtoFlag::NONE && g_mapport_enabled_protos == MapPortProtoFlag::NONE) {
+ return;
+ }
+
+ if (g_mapport_current_proto == MapPortProtoFlag::NONE && g_mapport_enabled_protos != MapPortProtoFlag::NONE) {
+ StartThreadMapPort();
+ return;
+ }
+
+ if (g_mapport_current_proto != MapPortProtoFlag::NONE && g_mapport_enabled_protos == MapPortProtoFlag::NONE) {
+ InterruptMapPort();
+ StopMapPort();
+ return;
+ }
+
+ if (g_mapport_enabled_protos & g_mapport_current_proto) {
+ // Enabling another protocol does not cause switching from the currently used one.
+ return;
+ }
+
+ assert(g_mapport_thread.joinable());
+ assert(!g_mapport_interrupt);
+ // Interrupt a protocol-specific loop in the ThreadUpnp() or in the ThreadNatpmp()
+ // to force trying the next protocol in the ThreadMapPort() loop.
+ g_mapport_interrupt();
+}
+
+static void MapPortProtoSetEnabled(MapPortProtoFlag proto, bool enabled)
+{
+ if (enabled) {
+ g_mapport_enabled_protos |= proto;
+ } else {
+ g_mapport_enabled_protos &= ~proto;
+ }
+}
+
+void StartMapPort(bool use_upnp, bool use_natpmp)
+{
+ MapPortProtoSetEnabled(MapPortProtoFlag::UPNP, use_upnp);
+ MapPortProtoSetEnabled(MapPortProtoFlag::NAT_PMP, use_natpmp);
+ DispatchMapPort();
+}
+
+void InterruptMapPort()
+{
+ g_mapport_enabled_protos = MapPortProtoFlag::NONE;
+ if (g_mapport_thread.joinable()) {
+ g_mapport_interrupt();
+ }
+}
+
+void StopMapPort()
+{
+ if (g_mapport_thread.joinable()) {
+ g_mapport_thread.join();
+ g_mapport_interrupt.reset();
+ }
+}
+
+#else // #if defined(USE_NATPMP) || defined(USE_UPNP)
+void StartMapPort(bool use_upnp, bool use_natpmp)
+{
+ // Intentionally left blank.
+}
+void InterruptMapPort()
+{
+ // Intentionally left blank.
+}
+void StopMapPort()
+{
+ // Intentionally left blank.
+}
+#endif // #if defined(USE_NATPMP) || defined(USE_UPNP)
diff --git a/src/mapport.h b/src/mapport.h
new file mode 100644
index 000000000000..279d65167f50
--- /dev/null
+++ b/src/mapport.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2011-2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_MAPPORT_H
+#define BITCOIN_MAPPORT_H
+
+#ifdef USE_UPNP
+static constexpr bool DEFAULT_UPNP = USE_UPNP;
+#else
+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,
+ UPNP = 0x01,
+ NAT_PMP = 0x02,
+};
+
+void StartMapPort(bool use_upnp, bool use_natpmp);
+void InterruptMapPort();
+void StopMapPort();
+
+#endif // BITCOIN_MAPPORT_H
diff --git a/src/net.cpp b/src/net.cpp
index 16a513443d1c..59f21346b546 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -48,15 +48,6 @@
#include
#endif
-#ifdef USE_UPNP
-#include
-#include
-#include
-// The minimum supported miniUPnPc API version is set to 10. This keeps compatibility
-// with Ubuntu 16.04 LTS and Debian 8 libminiupnpc-dev packages.
-static_assert(MINIUPNPC_API_VERSION >= 10, "miniUPnPc API version >= 10 assumed");
-#endif
-
#include
#include
@@ -1940,120 +1931,6 @@ void CConnman::WakeSelect()
wakeupSelectNeeded = false;
}
-
-
-
-
-#ifdef USE_UPNP
-static CThreadInterrupt g_upnp_interrupt;
-static std::thread g_upnp_thread;
-static void ThreadMapPort()
-{
- std::string port = strprintf("%u", GetListenPort());
- const char * multicastif = nullptr;
- const char * minissdpdpath = nullptr;
- struct UPNPDev * devlist = nullptr;
- char lanaddr[64];
-
- int error = 0;
-#if MINIUPNPC_API_VERSION < 14
- devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);
-#else
- devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error);
-#endif
-
- struct UPNPUrls urls;
- struct IGDdatas data;
- int r;
-
- r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
- if (r == 1)
- {
- if (fDiscover) {
- char externalIPAddress[40];
- r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
- if (r != UPNPCOMMAND_SUCCESS) {
- LogPrintf("UPnP: GetExternalIPAddress() returned %d\n", r);
- } else {
- if (externalIPAddress[0]) {
- CNetAddr resolved;
- if (LookupHost(externalIPAddress, resolved, false)) {
- LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved.ToString().c_str());
- AddLocal(resolved, LOCAL_UPNP);
- }
- } else {
- LogPrintf("UPnP: GetExternalIPAddress failed.\n");
- }
- }
- }
-
- std::string strDesc = PACKAGE_NAME " " + FormatFullVersion();
-
- do {
- r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0");
-
- if (r != UPNPCOMMAND_SUCCESS) {
- LogPrintf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", port, port, lanaddr, r, strupnperror(r));
- } else {
- LogPrintf("UPnP Port Mapping successful.\n");
- }
- } while (g_upnp_interrupt.sleep_for(std::chrono::minutes(20)));
-
- r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0);
- LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r);
- freeUPNPDevlist(devlist); devlist = nullptr;
- FreeUPNPUrls(&urls);
- } else {
- LogPrintf("No valid UPnP IGDs found\n");
- freeUPNPDevlist(devlist); devlist = nullptr;
- if (r != 0)
- FreeUPNPUrls(&urls);
- }
-}
-
-void StartMapPort()
-{
- if (!g_upnp_thread.joinable()) {
- assert(!g_upnp_interrupt);
- g_upnp_thread = std::thread((std::bind(&TraceThread, "upnp", &ThreadMapPort)));
- }
-}
-
-void InterruptMapPort()
-{
- if(g_upnp_thread.joinable()) {
- g_upnp_interrupt();
- }
-}
-
-void StopMapPort()
-{
- if(g_upnp_thread.joinable()) {
- g_upnp_thread.join();
- g_upnp_interrupt.reset();
- }
-}
-
-#else
-void StartMapPort()
-{
- // Intentionally left blank.
-}
-void InterruptMapPort()
-{
- // Intentionally left blank.
-}
-void StopMapPort()
-{
- // Intentionally left blank.
-}
-#endif
-
-
-
-
-
-
void CConnman::ThreadDNSAddressSeed()
{
FastRandomContext rng;
diff --git a/src/net.h b/src/net.h
index 7c2e81986570..1e95b61ef122 100644
--- a/src/net.h
+++ b/src/net.h
@@ -76,12 +76,6 @@ static const int MAX_ADDNODE_CONNECTIONS = 8;
static const int INBOUND_EVICTION_PROTECTION_TIME = 1;
/** -listen default */
static const bool DEFAULT_LISTEN = true;
-/** -upnp default */
-#ifdef USE_UPNP
-static const bool DEFAULT_UPNP = USE_UPNP;
-#else
-static const bool DEFAULT_UPNP = false;
-#endif
/** The maximum number of peer connections to maintain.
* Masternodes are forced to accept at least this many connections
*/
@@ -668,9 +662,6 @@ friend class CNode;
extern std::unique_ptr g_connman;
extern std::unique_ptr g_banman;
void Discover();
-void StartMapPort();
-void InterruptMapPort();
-void StopMapPort();
unsigned short GetListenPort();
struct CombinerAll
@@ -712,7 +703,7 @@ enum
LOCAL_NONE, // unknown
LOCAL_IF, // address a local interface listens on
LOCAL_BIND, // address explicit bound to
- LOCAL_UPNP, // address reported by UPnP
+ LOCAL_MAPPED, // address reported by UPnP or NAT-PMP
LOCAL_MANUAL, // address explicitly specified (-externalip=)
LOCAL_MAX
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 8779266381b3..a96e4662f11f 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -513,6 +513,16 @@
+ -
+
+
+ Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.
+
+
+ Map port using NA&T-PMP
+
+
+
-
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index ad8cca2fd5a5..84f9906dfd5d 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -72,6 +72,13 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
#ifndef USE_UPNP
ui->mapPortUpnp->setEnabled(false);
#endif
+#ifndef USE_NATPMP
+ ui->mapPortNatpmp->setEnabled(false);
+#endif
+ connect(this, &QDialog::accepted, [this](){
+ QSettings settings;
+ model->node().mapPort(settings.value("fUseUPnP").toBool(), settings.value("fUseNatpmp").toBool());
+ });
ui->proxyIp->setEnabled(false);
ui->proxyPort->setEnabled(false);
@@ -313,6 +320,7 @@ void OptionsDialog::setMapper()
/* Network */
mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP);
+ mapper->addMapping(ui->mapPortNatpmp, OptionsModel::MapPortNatpmp);
mapper->addMapping(ui->allowIncoming, OptionsModel::Listen);
mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse);
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 84fd7c8d8c56..5eafe40f019d 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -14,10 +14,11 @@
#include
#include
-#include // For DEFAULT_SCRIPTCHECK_THREADS
+#include
#include
#include
-#include // for -dbcache defaults
+#include // for -dbcache defaults
+#include // For DEFAULT_SCRIPTCHECK_THREADS
#ifdef ENABLE_WALLET
#include
@@ -249,6 +250,13 @@ void OptionsModel::Init(bool resetSettings)
if (!m_node.softSetBoolArg("-upnp", settings.value("fUseUPnP").toBool()))
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);
if (!m_node.softSetBoolArg("-listen", settings.value("fListen").toBool()))
@@ -383,7 +391,13 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
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;
@@ -499,7 +513,9 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
break;
case MapPortUPnP: // core option - can be changed on-the-fly
settings.setValue("fUseUPnP", value.toBool());
- m_node.mapPort(value.toBool());
+ break;
+ case MapPortNatpmp: // core option - can be changed on-the-fly
+ settings.setValue("fUseNatpmp", value.toBool());
break;
case MinimizeOnClose:
fMinimizeOnClose = value.toBool();
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index 12e5f33982fc..496db4e26e2d 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -38,6 +38,7 @@ class OptionsModel : public QAbstractListModel
HideTrayIcon, // bool
MinimizeToTray, // bool
MapPortUPnP, // bool
+ MapPortNatpmp, // bool
MinimizeOnClose, // bool
ProxyUse, // bool
ProxyIP, // QString
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index d781d5481153..f1206b3e588a 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -346,6 +346,7 @@ def initialize_datadir(dirname, n, chain):
f.write("listenonion=0\n")
f.write("printtoconsole=0\n")
f.write("upnp=0\n")
+ f.write("natpmp=0\n")
f.write("shrinkdebugfile=0\n")
os.makedirs(os.path.join(datadir, 'stderr'), exist_ok=True)
os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)
From d23a3c8af88cf8c0af7132de019a88fb23e41b8b Mon Sep 17 00:00:00 2001
From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com>
Date: Mon, 1 Mar 2021 14:00:36 +0800
Subject: [PATCH 2/4] merge bitcoin#21320: fix libnatpmp macos cross compile
---
depends/packages/libnatpmp.mk | 1 +
1 file changed, 1 insertion(+)
diff --git a/depends/packages/libnatpmp.mk b/depends/packages/libnatpmp.mk
index a24f201859a0..391b9337b725 100644
--- a/depends/packages/libnatpmp.mk
+++ b/depends/packages/libnatpmp.mk
@@ -6,6 +6,7 @@ $(package)_sha256_hash=e1aa9c4c4219bc06943d6b2130f664daee213fb262fcb94dd355815b8
define $(package)_set_vars
$(package)_build_opts=CC="$($(package)_cc)"
+ $(package)_build_env+=CFLAGS="$($(package)_cflags) $($(package)_cppflags)" AR="$($(package)_ar)"
endef
define $(package)_build_cmds
From c382730033cb2b115870a0a4608e209ff7659d24 Mon Sep 17 00:00:00 2001
From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com>
Date: Wed, 17 Feb 2021 15:06:30 +0800
Subject: [PATCH 3/4] merge bitcoin#21209: use newer source for libnatpmp
---
configure.ac | 4 ++++
depends/packages/libnatpmp.mk | 10 ++++++----
src/Makefile.am | 2 +-
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/configure.ac b/configure.ac
index 6438aef332b1..f7c531b86d77 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1637,6 +1637,9 @@ else
fi
AC_MSG_RESULT($use_natpmp_default)
AC_DEFINE_UNQUOTED([USE_NATPMP], [$natpmp_setting], [NAT-PMP support not compiled if undefined, otherwise value (0 or 1) determines default state])
+ if test x$TARGET_OS = xwindows; then
+ NATPMP_CPPFLAGS="-DSTATICLIB -DNATPMP_STATICLIB"
+ fi
else
AC_MSG_RESULT([no])
fi
@@ -1818,6 +1821,7 @@ AC_SUBST(MINIUPNPC_LIBS)
AC_SUBST(CRYPTO_LIBS)
AC_SUBST(SSL_LIBS)
AC_SUBST(GMP_LIBS)
+AC_SUBST(NATPMP_CPPFLAGS)
AC_SUBST(NATPMP_LIBS)
AC_SUBST(EVENT_LIBS)
AC_SUBST(EVENT_PTHREADS_LIBS)
diff --git a/depends/packages/libnatpmp.mk b/depends/packages/libnatpmp.mk
index 391b9337b725..cdcf8c0bf2c1 100644
--- a/depends/packages/libnatpmp.mk
+++ b/depends/packages/libnatpmp.mk
@@ -1,11 +1,13 @@
package=libnatpmp
-$(package)_version=20150609
-$(package)_download_path=https://miniupnp.tuxfamily.org/files/
-$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=e1aa9c4c4219bc06943d6b2130f664daee213fb262fcb94dd355815b8f4536b0
+$(package)_version=4536032ae32268a45c073a4d5e91bbab4534773a
+$(package)_download_path=https://github.com/miniupnp/libnatpmp/archive
+$(package)_file_name=$($(package)_version).tar.gz
+$(package)_sha256_hash=543b460aab26acf91e11d15e17d8798f845304199eea2d76c2f444ec749c5383
define $(package)_set_vars
$(package)_build_opts=CC="$($(package)_cc)"
+ $(package)_build_opts_mingw32=CPPFLAGS=-DNATPMP_STATICLIB
+ $(package)_build_opts_darwin=LIBTOOL="$($(package)_libtool)"
$(package)_build_env+=CFLAGS="$($(package)_cflags) $($(package)_cppflags)" AR="$($(package)_ar)"
endef
diff --git a/src/Makefile.am b/src/Makefile.am
index 6eb9b551d76d..28c713330127 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -341,7 +341,7 @@ libdash_util_a-clientversion.$(OBJEXT): obj/build.h
# Contains code accessing mempool and chain state that is meant to be separated
# from wallet and gui code (see node/README.md). Shared code should go in
# libdash_common or libdash_util libraries, instead.
-libdash_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
+libdash_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libdash_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libdash_server_a_SOURCES = \
addrdb.cpp \
From 4e9fe85700baee307b4c59452d8e6ca00244de3f Mon Sep 17 00:00:00 2001
From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com>
Date: Sat, 3 Jul 2021 15:29:11 +0300
Subject: [PATCH 4/4] merge bitcoin#22397: Fix macOS Apple Silicon build with
miniupnpc and libnatpmp
---
configure.ac | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/configure.ac b/configure.ac
index f7c531b86d77..971e82454946 100644
--- a/configure.ac
+++ b/configure.ac
@@ -690,6 +690,33 @@ case $host in
PKG_CONFIG_PATH="$qt5_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
export PKG_CONFIG_PATH
fi
+
+ case $host in
+ *aarch64*)
+ dnl The preferred Homebrew prefix for Apple Silicon is /opt/homebrew.
+ dnl Therefore, as we do not use pkg-config to detect miniupnpc and libnatpmp
+ dnl packages, we should set the CPPFLAGS and LDFLAGS variables for them
+ dnl explicitly.
+ if test "x$use_upnp" != xno && $BREW list --versions miniupnpc >/dev/null; then
+ miniupnpc_prefix=$($BREW --prefix miniupnpc 2>/dev/null)
+ if test "x$suppress_external_warnings" != xno; then
+ CPPFLAGS="$CPPFLAGS -isystem $miniupnpc_prefix/include"
+ else
+ CPPFLAGS="$CPPFLAGS -I$miniupnpc_prefix/include"
+ fi
+ LDFLAGS="$LDFLAGS -L$miniupnpc_prefix/lib"
+ fi
+ if test "x$use_natpmp" != xno && $BREW list --versions libnatpmp >/dev/null; then
+ libnatpmp_prefix=$($BREW --prefix libnatpmp 2>/dev/null)
+ if test "x$suppress_external_warnings" != xno; then
+ CPPFLAGS="$CPPFLAGS -isystem $libnatpmp_prefix/include"
+ else
+ CPPFLAGS="$CPPFLAGS -I$libnatpmp_prefix/include"
+ fi
+ LDFLAGS="$LDFLAGS -L$libnatpmp_prefix/lib"
+ fi
+ ;;
+ esac
fi
else
case $build_os in