In addition to the -bind thing there is also a complication with the port: if -bind=10.0.0.1:20000 -bind=[5566::1]:30000 has been used, then GetListenPort(), currently used by mapport.cpp, is not the right thing to do because it would return 20000.
To resolve both, we could get the listening addresses + the correct ports from:
AddLocal() / mapLocalHost, is called after bind (good), but also from other places and after the bind it is called only if fDiscover is true (bad).
CConnman::vhListenSocket, has sockets that used BF_DONT_ADVERTISE during bind. Those should be omitted.
-bind arguments, could get it from init.cpp / connOptions. Need to duplicate some of the logic of CConnman::InitBinds().
- introduce a new global list of
addr:port, similar but not identical to mapLocalHost, seems imperfect because the list is almost the same as mapLocalHost, ideally those addresses should be in one place with proper flags to distinguish them (or maybe not?).
Here is a crude implementation of 4:
<details>
<summary>[patch] do 4.</summary>
diff --git a/src/mapport.cpp b/src/mapport.cpp
index a1d584dae9..56d21e792b 100644
--- a/src/mapport.cpp
+++ b/src/mapport.cpp
@@ -48,13 +48,13 @@ static bool ProcessPCP()
// The same nonce is used for all mappings, this is allowed by the spec, and simplifies keeping track of them.
PCPMappingNonce pcp_nonce;
GetRandBytes(pcp_nonce);
bool ret = false;
bool no_resources = false;
- const uint16_t private_port = GetListenPort();
+ const uint16_t private_port = GetListenPort(); // XXX could be the wrong port if -bind is used
// Multiply the reannounce period by two, as we'll try to renew approximately halfway.
const uint32_t requested_lifetime = std::chrono::seconds(PORT_MAPPING_REANNOUNCE_PERIOD * 2).count();
uint32_t actual_lifetime = 0;
std::chrono::milliseconds sleep_time;
// Local functor to handle result from PCP/NATPMP mapping.
@@ -101,14 +101,18 @@ static bool ProcessPCP()
if (!gateway6) {
LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "portmap: Could not determine IPv6 default gateway\n");
} else {
LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "portmap: gateway [IPv6]: %s\n", gateway6->ToStringAddr());
// Try to open pinholes for all routable local IPv6 addresses.
- for (const auto &addr: GetLocalAddresses()) {
- if (!addr.IsRoutable() || !addr.IsIPv6()) continue;
+ const auto addresses =
+ WITH_LOCK(g_addresses_for_port_map.mutex, return g_addresses_for_port_map.addresses);
+ for (const auto& addr : addresses) {
+ if (!addr.IsIPv6()) {
+ continue;
+ }
auto res = PCPRequestPortMap(pcp_nonce, *gateway6, addr, private_port, requested_lifetime);
handle_mapping(res);
}
}
// Log message if we got NO_RESOURCES.
diff --git a/src/net.cpp b/src/net.cpp
index 7c6babc389..b621e76696 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -112,12 +112,15 @@ static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL; // SHA256
// Global state variables
//
bool fDiscover = true;
bool fListen = true;
GlobalMutex g_maplocalhost_mutex;
std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(g_maplocalhost_mutex);
+
+AddressesForPortMap g_addresses_for_port_map;
+
std::string strSubVersion;
size_t CSerializedNetMsg::GetMemoryUsage() const noexcept
{
// Don't count the dynamic memory used for the m_type string, by assuming it fits in the
// "small string" optimization area (which stores data inside the object itself, up to some
@@ -3151,14 +3154,17 @@ bool CConnman::Bind(const CService& addr_, unsigned int flags, NetPermissionFlag
if ((flags & BF_REPORT_ERROR) && m_client_interface) {
m_client_interface->ThreadSafeMessageBox(strError, "", CClientUIInterface::MSG_ERROR);
}
return false;
}
- if (addr.IsRoutable() && fDiscover && !(flags & BF_DONT_ADVERTISE) && !NetPermissions::HasFlag(permissions, NetPermissionFlags::NoBan)) {
- AddLocal(addr, LOCAL_BIND);
+ if (addr.IsRoutable() && !(flags & BF_DONT_ADVERTISE) && !NetPermissions::HasFlag(permissions, NetPermissionFlags::NoBan)) {
+ if (fDiscover) {
+ AddLocal(addr, LOCAL_BIND);
+ }
+ WITH_LOCK(g_addresses_for_port_map.mutex, g_addresses_for_port_map.addresses.push_back(addr));
}
return true;
}
bool CConnman::InitBinds(const Options& options)
diff --git a/src/net.h b/src/net.h
index 11cb01a95d..ae08603e64 100644
--- a/src/net.h
+++ b/src/net.h
@@ -175,12 +175,17 @@ struct LocalServiceInfo {
uint16_t nPort;
};
extern GlobalMutex g_maplocalhost_mutex;
extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(g_maplocalhost_mutex);
+extern struct AddressesForPortMap {
+ Mutex mutex;
+ std::vector<CService> addresses GUARDED_BY(mutex);
+} g_addresses_for_port_map;
+
extern const std::string NET_MESSAGE_TYPE_OTHER;
using mapMsgTypeSize = std::map</* message type */ std::string, /* total bytes */ uint64_t>;
class CNodeStats
{
public:
</details>