Skip to content

Commit 30308cc

Browse files
committed
Merge bitcoin#20196: net: fix GetListenPort() to derive the proper port
7d64ea4 net: only assume all local addresses if listening on any (Vasil Dimov) 0cfc0cd net: fix GetListenPort() to derive the proper port (Vasil Dimov) f98cdcb net: pass Span by value to CaptureMessage() (Vasil Dimov) 3cb9d9c net: make CaptureMessage() mockable (Vasil Dimov) 43868ba timedata: rename variables to match the coding style (Vasil Dimov) 60da1ea timedata: make it possible to reset the state (Vasil Dimov) Pull request description: `GetListenPort()` uses a simple logic: "if `-port=P` is given, then we must be listening on `P`, otherwise we must be listening on `8333`". This is however not true if `-bind=` has been provided with `:port` part or if `-whitebind=` has been provided. Thus, extend `GetListenPort()` to return the port from `-bind=` or `-whitebind=`, if any. Also, if `-bind=` is provided then we would bind only to a particular address and should not add all the other addresses of the machine to the list of local addresses. Fixes bitcoin#20184 ACKs for top commit: sipa: utACK 7d64ea4. I didn't review the tests in detail. jonatack: re-ACK 7d64ea4 per `git range-diff 08bcfa2 35ec977 7d64ea4`, changes are rebase-only, light re-review, re-ran the new tests locally Tree-SHA512: 45135ab9c0ec3cc8c83e3b3e58a1c1f77eaeaba00618d54f1010db1d23d6db7d9c0dc7807e72ebc34e8b2d0e91f1e0d0e9239d13b90f1bdce8be84459e7837f0
2 parents 08bcfa2 + 7d64ea4 commit 30308cc

12 files changed

+454
-27
lines changed

src/init.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,8 +1668,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
16681668
LogPrintf("nBestHeight = %d\n", chain_active_height);
16691669
if (node.peerman) node.peerman->SetBestHeight(chain_active_height);
16701670

1671-
Discover();
1672-
16731671
// Map ports with UPnP or NAT-PMP.
16741672
StartMapPort(args.GetBoolArg("-upnp", DEFAULT_UPNP), gArgs.GetBoolArg("-natpmp", DEFAULT_NATPMP));
16751673

@@ -1689,6 +1687,10 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
16891687
connOptions.nMaxOutboundLimit = *opt_max_upload;
16901688
connOptions.m_peer_connect_timeout = peer_connect_timeout;
16911689

1690+
// Port to bind to if `-bind=addr` is provided without a `:port` suffix.
1691+
const uint16_t default_bind_port =
1692+
static_cast<uint16_t>(args.GetIntArg("-port", Params().GetDefaultPort()));
1693+
16921694
const auto BadPortWarning = [](const char* prefix, uint16_t port) {
16931695
return strprintf(_("%s request to listen on port %u. This port is considered \"bad\" and "
16941696
"thus it is unlikely that any Bitcoin Core peers connect to it. See "
@@ -1701,7 +1703,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
17011703
CService bind_addr;
17021704
const size_t index = bind_arg.rfind('=');
17031705
if (index == std::string::npos) {
1704-
if (Lookup(bind_arg, bind_addr, GetListenPort(), false)) {
1706+
if (Lookup(bind_arg, bind_addr, default_bind_port, /*fAllowLookup=*/false)) {
17051707
connOptions.vBinds.push_back(bind_addr);
17061708
if (IsBadPort(bind_addr.GetPort())) {
17071709
InitWarning(BadPortWarning("-bind", bind_addr.GetPort()));
@@ -1758,6 +1760,12 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
17581760
StartTorControl(onion_service_target);
17591761
}
17601762

1763+
if (connOptions.bind_on_any) {
1764+
// Only add all IP addresses of the machine if we would be listening on
1765+
// any address - 0.0.0.0 (IPv4) and :: (IPv6).
1766+
Discover();
1767+
}
1768+
17611769
for (const auto& net : args.GetArgs("-whitelist")) {
17621770
NetWhitelistPermissions subnet;
17631771
bilingual_str error;

src/net.cpp

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,31 @@ void CConnman::AddAddrFetch(const std::string& strDest)
126126

127127
uint16_t GetListenPort()
128128
{
129+
// If -bind= is provided with ":port" part, use that (first one if multiple are provided).
130+
for (const std::string& bind_arg : gArgs.GetArgs("-bind")) {
131+
CService bind_addr;
132+
constexpr uint16_t dummy_port = 0;
133+
134+
if (Lookup(bind_arg, bind_addr, dummy_port, /*fAllowLookup=*/false)) {
135+
if (bind_addr.GetPort() != dummy_port) {
136+
return bind_addr.GetPort();
137+
}
138+
}
139+
}
140+
141+
// Otherwise, if -whitebind= without NetPermissionFlags::NoBan is provided, use that
142+
// (-whitebind= is required to have ":port").
143+
for (const std::string& whitebind_arg : gArgs.GetArgs("-whitebind")) {
144+
NetWhitebindPermissions whitebind;
145+
bilingual_str error;
146+
if (NetWhitebindPermissions::TryParse(whitebind_arg, whitebind, error)) {
147+
if (!NetPermissions::HasFlag(whitebind.m_flags, NetPermissionFlags::NoBan)) {
148+
return whitebind.m_service.GetPort();
149+
}
150+
}
151+
}
152+
153+
// Otherwise, if -port= is provided, use that. Otherwise use the default port.
129154
return static_cast<uint16_t>(gArgs.GetIntArg("-port", Params().GetDefaultPort()));
130155
}
131156

@@ -221,7 +246,17 @@ std::optional<CAddress> GetLocalAddrForPeer(CNode *pnode)
221246
if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||
222247
rng.randbits((GetnScore(addrLocal) > LOCAL_MANUAL) ? 3 : 1) == 0))
223248
{
224-
addrLocal.SetIP(pnode->GetAddrLocal());
249+
if (pnode->IsInboundConn()) {
250+
// For inbound connections, assume both the address and the port
251+
// as seen from the peer.
252+
addrLocal = CAddress{pnode->GetAddrLocal(), addrLocal.nServices};
253+
} else {
254+
// For outbound connections, assume just the address as seen from
255+
// the peer and leave the port in `addrLocal` as returned by
256+
// `GetLocalAddress()` above. The peer has no way to observe our
257+
// listening port when we have initiated the connection.
258+
addrLocal.SetIP(pnode->GetAddrLocal());
259+
}
225260
}
226261
if (addrLocal.IsRoutable() || gArgs.GetBoolArg("-addrmantest", false))
227262
{
@@ -3085,7 +3120,10 @@ uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) const
30853120
return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(vchNetGroup.data(), vchNetGroup.size()).Finalize();
30863121
}
30873122

3088-
void CaptureMessage(const CAddress& addr, const std::string& msg_type, const Span<const unsigned char>& data, bool is_incoming)
3123+
void CaptureMessageToFile(const CAddress& addr,
3124+
const std::string& msg_type,
3125+
Span<const unsigned char> data,
3126+
bool is_incoming)
30893127
{
30903128
// Note: This function captures the message at the time of processing,
30913129
// not at socket receive/send time.
@@ -3112,3 +3150,9 @@ void CaptureMessage(const CAddress& addr, const std::string& msg_type, const Spa
31123150
ser_writedata32(f, size);
31133151
f.write(AsBytes(data));
31143152
}
3153+
3154+
std::function<void(const CAddress& addr,
3155+
const std::string& msg_type,
3156+
Span<const unsigned char> data,
3157+
bool is_incoming)>
3158+
CaptureMessage = CaptureMessageToFile;

src/net.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <condition_variable>
3232
#include <cstdint>
3333
#include <deque>
34+
#include <functional>
3435
#include <map>
3536
#include <memory>
3637
#include <optional>
@@ -182,7 +183,15 @@ enum class ConnectionType {
182183

183184
/** Convert ConnectionType enum to a string value */
184185
std::string ConnectionTypeAsString(ConnectionType conn_type);
186+
187+
/**
188+
* Look up IP addresses from all interfaces on the machine and add them to the
189+
* list of local addresses to self-advertise.
190+
* The loopback interface is skipped and only the first address from each
191+
* interface is used.
192+
*/
185193
void Discover();
194+
186195
uint16_t GetListenPort();
187196

188197
enum
@@ -1272,7 +1281,17 @@ class CConnman
12721281
};
12731282

12741283
/** Dump binary message to file, with timestamp */
1275-
void CaptureMessage(const CAddress& addr, const std::string& msg_type, const Span<const unsigned char>& data, bool is_incoming);
1284+
void CaptureMessageToFile(const CAddress& addr,
1285+
const std::string& msg_type,
1286+
Span<const unsigned char> data,
1287+
bool is_incoming);
1288+
1289+
/** Defaults to `CaptureMessageToFile()`, but can be overridden by unit tests. */
1290+
extern std::function<void(const CAddress& addr,
1291+
const std::string& msg_type,
1292+
Span<const unsigned char> data,
1293+
bool is_incoming)>
1294+
CaptureMessage;
12761295

12771296
struct NodeEvictionCandidate
12781297
{

src/net_processing.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2711,6 +2711,10 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
27112711
LogPrint(BCLog::NET, "ProcessMessages: advertising address %s\n", addr.ToString());
27122712
PushAddress(*peer, addr, insecure_rand);
27132713
} else if (IsPeerAddrLocalGood(&pfrom)) {
2714+
// Override just the address with whatever the peer sees us as.
2715+
// Leave the port in addr as it was returned by GetLocalAddress()
2716+
// above, as this is an outbound connection and the peer cannot
2717+
// observe our listening port.
27142718
addr.SetIP(addrMe);
27152719
LogPrint(BCLog::NET, "ProcessMessages: advertising address %s\n", addr.ToString());
27162720
PushAddress(*peer, addr, insecure_rand);

0 commit comments

Comments
 (0)