mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-03-25 15:05:55 +01:00
net: Add libnatpmp support
This commit is contained in:
@@ -598,7 +598,7 @@ bitcoin_bin_ldadd = \
|
||||
$(LIBMEMENV) \
|
||||
$(LIBSECP256K1)
|
||||
|
||||
bitcoin_bin_ldadd += $(BOOST_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(SQLITE_LIBS)
|
||||
bitcoin_bin_ldadd += $(BOOST_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(SQLITE_LIBS)
|
||||
|
||||
bitcoind_SOURCES = $(bitcoin_daemon_sources)
|
||||
bitcoind_CPPFLAGS = $(bitcoin_bin_cppflags)
|
||||
|
||||
@@ -74,7 +74,7 @@ bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp
|
||||
bench_bench_bitcoin_SOURCES += bench/wallet_balance.cpp
|
||||
endif
|
||||
|
||||
bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(SQLITE_LIBS)
|
||||
bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS)
|
||||
bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
|
||||
|
||||
CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES)
|
||||
|
||||
@@ -320,7 +320,7 @@ if ENABLE_ZMQ
|
||||
bitcoin_qt_ldadd += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
|
||||
endif
|
||||
bitcoin_qt_ldadd += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
|
||||
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
|
||||
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \
|
||||
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(SQLITE_LIBS)
|
||||
bitcoin_qt_ldflags = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
|
||||
bitcoin_qt_libtoolflags = $(AM_LIBTOOLFLAGS) --tag CXX
|
||||
|
||||
@@ -55,7 +55,7 @@ qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
|
||||
endif
|
||||
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \
|
||||
$(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
|
||||
$(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
|
||||
$(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \
|
||||
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(SQLITE_LIBS)
|
||||
qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
|
||||
qt_test_test_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
|
||||
|
||||
@@ -167,7 +167,7 @@ test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_C
|
||||
$(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
|
||||
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
|
||||
test_test_bitcoin_LDADD += $(BDB_LIBS) $(MINIUPNPC_LIBS) $(SQLITE_LIBS)
|
||||
test_test_bitcoin_LDADD += $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS)
|
||||
test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) -static
|
||||
|
||||
if ENABLE_ZMQ
|
||||
|
||||
116
src/mapport.cpp
116
src/mapport.cpp
@@ -16,6 +16,11 @@
|
||||
#include <threadinterrupt.h>
|
||||
#include <util/system.h>
|
||||
|
||||
#ifdef USE_NATPMP
|
||||
#include <compat.h>
|
||||
#include <natpmp.h>
|
||||
#endif // USE_NATPMP
|
||||
|
||||
#ifdef USE_UPNP
|
||||
#include <miniupnpc/miniupnpc.h>
|
||||
#include <miniupnpc/upnpcommands.h>
|
||||
@@ -23,7 +28,7 @@
|
||||
// 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
|
||||
#endif // USE_UPNP
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
@@ -32,7 +37,7 @@ static_assert(MINIUPNPC_API_VERSION >= 10, "miniUPnPc API version >= 10 assumed"
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#ifdef USE_UPNP
|
||||
#if defined(USE_NATPMP) || defined(USE_UPNP)
|
||||
static CThreadInterrupt g_mapport_interrupt;
|
||||
static std::thread g_mapport_thread;
|
||||
static std::atomic_uint g_mapport_target_proto{MapPortProtoFlag::NONE};
|
||||
@@ -41,6 +46,106 @@ 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;
|
||||
@@ -111,6 +216,7 @@ static bool ProcessUpnp()
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif // USE_UPNP
|
||||
|
||||
static void ThreadMapPort()
|
||||
{
|
||||
@@ -123,7 +229,7 @@ void StartThreadMapPort()
|
||||
{
|
||||
if (!g_mapport_thread.joinable()) {
|
||||
assert(!g_mapport_interrupt);
|
||||
g_mapport_thread = std::thread((std::bind(&TraceThread<void (*)()>, "mapport", &ThreadMapPort)));
|
||||
g_mapport_thread = std::thread(std::bind(&TraceThread<void (*)()>, "mapport", &ThreadMapPort));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +273,7 @@ void StopMapPort()
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#else // #if defined(USE_NATPMP) || defined(USE_UPNP)
|
||||
void StartMapPort(bool use_upnp)
|
||||
{
|
||||
// Intentionally left blank.
|
||||
@@ -180,4 +286,4 @@ void StopMapPort()
|
||||
{
|
||||
// Intentionally left blank.
|
||||
}
|
||||
#endif
|
||||
#endif // #if defined(USE_NATPMP) || defined(USE_UPNP)
|
||||
|
||||
@@ -15,6 +15,7 @@ static const bool DEFAULT_UPNP = false;
|
||||
enum MapPortProtoFlag : unsigned int {
|
||||
NONE = 0x00,
|
||||
UPNP = 0x01,
|
||||
NAT_PMP = 0x02,
|
||||
};
|
||||
|
||||
void StartMapPort(bool use_upnp);
|
||||
|
||||
@@ -182,7 +182,7 @@ enum
|
||||
LOCAL_NONE, // unknown
|
||||
LOCAL_IF, // address a local interface listens on
|
||||
LOCAL_BIND, // address explicit bound to
|
||||
LOCAL_MAPPED, // address reported by UPnP
|
||||
LOCAL_MAPPED, // address reported by UPnP or NAT-PMP
|
||||
LOCAL_MANUAL, // address explicitly specified (-externalip=)
|
||||
|
||||
LOCAL_MAX
|
||||
|
||||
Reference in New Issue
Block a user