Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ The Dash Core repo's [root README](/README.md) contains relevant information on
- [I2P Support](i2p.md)
- [Init Scripts (systemd/upstart/openrc)](init.md)
- [Managing Wallets](managing-wallets.md)
- [P2P bad ports definition and list](p2p-bad-ports.md)
- [PSBT support](psbt.md)
- [Reduce Memory](reduce-memory.md)
- [Reduce Traffic](reduce-traffic.md)
Expand Down
114 changes: 114 additions & 0 deletions doc/p2p-bad-ports.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
When Dash Core automatically opens outgoing P2P connections, it chooses
a peer (address and port) from its list of potential peers. This list is
populated with unchecked data gossiped over the P2P network by other peers.

A malicious actor may gossip an address:port where no Dash node is listening,
or one where a service is listening that is not related to the Dash network.
As a result, this service may occasionally get connection attempts from Dash
nodes.

"Bad" ports are ones used by services which are usually not open to the public
and usually require authentication. A connection attempt (by Dash Core,
trying to connect because it thinks there is a Dash node on that
address:port) to such service may be considered a malicious action by an
ultra-paranoid administrator. An example for such a port is 22 (ssh). On the
other hand, connection attempts to public services that usually do not require
authentication are unlikely to be considered a malicious action,
e.g. port 80 (http).

Below is a list of "bad" ports which Dash Core avoids when choosing a peer to
connect to. If a node is listening on such a port, it will likely receive fewer
incoming connections.

1: tcpmux
7: echo
9: discard
11: systat
13: daytime
15: netstat
17: qotd
19: chargen
20: ftp data
21: ftp access
22: ssh
23: telnet
25: smtp
37: time
42: name
43: nicname
53: domain
69: tftp
77: priv-rjs
79: finger
87: ttylink
95: supdup
101: hostname
102: iso-tsap
103: gppitnp
104: acr-nema
109: pop2
110: pop3
111: sunrpc
113: auth
115: sftp
117: uucp-path
119: nntp
123: NTP
135: loc-srv /epmap
137: netbios
139: netbios
143: imap2
161: snmp
179: BGP
389: ldap
427: SLP (Also used by Apple Filing Protocol)
465: smtp+ssl
512: print / exec
513: login
514: shell
515: printer
526: tempo
530: courier
531: chat
532: netnews
540: uucp
548: AFP (Apple Filing Protocol)
554: rtsp
556: remotefs
563: nntp+ssl
587: smtp (rfc6409)
601: syslog-conn (rfc3195)
636: ldap+ssl
989: ftps-data
990: ftps
993: ldap+ssl
995: pop3+ssl
1719: h323gatestat
1720: h323hostcall
1723: pptp
2049: nfs
3659: apple-sasl / PasswordServer
4045: lockd
5060: sip
5061: sips
6000: X11
6566: sane-port
6665: Alternate IRC
6666: Alternate IRC
6667: Standard IRC
6668: Alternate IRC
6669: Alternate IRC
6697: IRC + TLS
10080: Amanda

For further information see:

[pull/23306](https://github.com/bitcoin/bitcoin/pull/23306#issuecomment-947516736)

[pull/23542](https://github.com/bitcoin/bitcoin/pull/23542)

[fetch.spec.whatwg.org](https://fetch.spec.whatwg.org/#port-blocking)

[chromium.googlesource.com](https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/net/base/port_util.cc)

[hg.mozilla.org](https://hg.mozilla.org/mozilla-central/file/tip/netwerk/base/nsIOService.cpp)
10 changes: 5 additions & 5 deletions src/bitcoin-cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,8 +433,8 @@ class NetinfoRequestHandler : public BaseRequestHandler
bool is_addr_relay_enabled;
bool is_bip152_hb_from;
bool is_bip152_hb_to;
bool is_block_relay;
bool is_outbound;
bool is_tx_relay;
bool operator<(const Peer& rhs) const { return std::tie(is_outbound, min_ping) < std::tie(rhs.is_outbound, rhs.min_ping); }
};
std::vector<Peer> m_peers;
Expand Down Expand Up @@ -498,13 +498,13 @@ class NetinfoRequestHandler : public BaseRequestHandler
const int8_t network_id{NetworkStringToId(network)};
if (network_id == UNKNOWN_NETWORK) continue;
const bool is_outbound{!peer["inbound"].get_bool()};
const bool is_block_relay{peer["relaytxes"].isNull() ? false : !peer["relaytxes"].get_bool()};
const bool is_tx_relay{peer["relaytxes"].isNull() ? true : peer["relaytxes"].get_bool()};
const std::string conn_type{peer["connection_type"].get_str()};
++m_counts.at(is_outbound).at(network_id); // in/out by network
++m_counts.at(is_outbound).at(NETWORKS.size()); // in/out overall
++m_counts.at(2).at(network_id); // total by network
++m_counts.at(2).at(NETWORKS.size()); // total overall
if (is_block_relay) ++m_block_relay_peers_count;
if (conn_type == "block-relay-only") ++m_block_relay_peers_count;
if (conn_type == "manual") ++m_manual_peers_count;
if (DetailsRequested()) {
// Push data for this peer to the peers vector.
Expand All @@ -527,7 +527,7 @@ class NetinfoRequestHandler : public BaseRequestHandler
const bool is_addr_relay_enabled{peer["addr_relay_enabled"].isNull() ? false : peer["addr_relay_enabled"].get_bool()};
const bool is_bip152_hb_from{peer["bip152_hb_from"].get_bool()};
const bool is_bip152_hb_to{peer["bip152_hb_to"].get_bool()};
m_peers.push_back({addr, sub_version, conn_type, NETWORK_SHORT_NAMES[network_id], age, transport, min_ping, ping, addr_processed, addr_rate_limited, last_blck, last_recv, last_send, last_trxn, peer_id, mapped_as, version, is_addr_relay_enabled, is_bip152_hb_from, is_bip152_hb_to, is_block_relay, is_outbound});
m_peers.push_back({addr, sub_version, conn_type, NETWORK_SHORT_NAMES[network_id], age, transport, min_ping, ping, addr_processed, addr_rate_limited, last_blck, last_recv, last_send, last_trxn, peer_id, mapped_as, version, is_addr_relay_enabled, is_bip152_hb_from, is_bip152_hb_to, is_outbound, is_tx_relay});
m_max_addr_length = std::max(addr.length() + 1, m_max_addr_length);
m_max_addr_processed_length = std::max(ToString(addr_processed).length(), m_max_addr_processed_length);
m_max_addr_rate_limited_length = std::max(ToString(addr_rate_limited).length(), m_max_addr_rate_limited_length);
Expand Down Expand Up @@ -561,7 +561,7 @@ class NetinfoRequestHandler : public BaseRequestHandler
PingTimeToString(peer.ping),
peer.last_send ? ToString(time_now - peer.last_send) : "",
peer.last_recv ? ToString(time_now - peer.last_recv) : "",
peer.last_trxn ? ToString((time_now - peer.last_trxn) / 60) : peer.is_block_relay ? "*" : "",
peer.last_trxn ? ToString((time_now - peer.last_trxn) / 60) : peer.is_tx_relay ? "" : "*",
peer.last_blck ? ToString((time_now - peer.last_blck) / 60) : "",
strprintf("%s%s", peer.is_bip152_hb_to ? "." : " ", peer.is_bip152_hb_from ? "*" : " "),
m_max_addr_processed_length, // variable spacing
Expand Down
8 changes: 0 additions & 8 deletions src/compat/compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,6 @@ typedef char* sockopt_arg_type;
#define USE_KQUEUE
#endif

bool static inline IsSelectableSocket(const SOCKET& s) {
#if defined(USE_POLL) || defined(WIN32)
return true;
#else
return (s < FD_SETSIZE);
#endif
}

// MSG_NOSIGNAL is not available on some platforms, if it doesn't exist define it as 0
#if !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
Expand Down
22 changes: 22 additions & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,8 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-txreconciliation", strprintf("Enable transaction reconciliations per BIP 330 (default: %d)", DEFAULT_TXRECONCILIATION_ENABLE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION);
argsman.AddArg("-peertimeout=<n>", strprintf("Specify a p2p connection timeout delay in seconds. After connecting to a peer, wait this amount of time before considering disconnection based on inactivity (minimum: 1, default: %d)", DEFAULT_PEER_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
// TODO: remove the sentence "Nodes not using ... incoming connections." once the changes from
// https://github.com/bitcoin/bitcoin/pull/23542 have become widespread.
argsman.AddArg("-port=<port>", strprintf("Listen for connections on <port>. Nodes not using the default ports (default: %u, testnet: %u, regtest: %u) are unlikely to get incoming connections. Not relevant for I2P (see doc/i2p.md).", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
argsman.AddArg("-proxy=<ip:port>", "Connect through SOCKS5 proxy, set -noproxy to disable (default: disabled)", ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_ELISION, OptionsCategory::CONNECTION);
argsman.AddArg("-proxyrandomize", strprintf("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)", DEFAULT_PROXYRANDOMIZE), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
Expand Down Expand Up @@ -2270,13 +2272,24 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
const uint16_t default_bind_port =
static_cast<uint16_t>(args.GetArg("-port", Params().GetDefaultPort()));

const auto BadPortWarning = [](const char* prefix, uint16_t port) {
return strprintf(_("%s request to listen on port %u. This port is considered \"bad\" and "
"thus it is unlikely that any Dash Core peers connect to it. See "
"doc/p2p-bad-ports.md for details and a full list."),
prefix,
port);
};

for (const std::string& bind_arg : args.GetArgs("-bind")) {
std::optional<CService> bind_addr;
const size_t index = bind_arg.rfind('=');
if (index == std::string::npos) {
bind_addr = Lookup(bind_arg, default_bind_port, /*fAllowLookup=*/false);
if (bind_addr.has_value()) {
connOptions.vBinds.push_back(bind_addr.value());
if (IsBadPort(bind_addr.value().GetPort())) {
InitWarning(BadPortWarning("-bind", bind_addr.value().GetPort()));
}
continue;
}
} else {
Expand Down Expand Up @@ -2304,6 +2317,15 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// on any address - 0.0.0.0 (IPv4) and :: (IPv6).
connOptions.bind_on_any = args.GetArgs("-bind").empty() && args.GetArgs("-whitebind").empty();

// Emit a warning if a bad port is given to -port= but only if -bind and -whitebind are not
// given, because if they are, then -port= is ignored.
if (connOptions.bind_on_any && args.IsArgSet("-port")) {
const uint16_t port_arg = args.GetArg("-port", 0);
if (IsBadPort(port_arg)) {
InitWarning(BadPortWarning("-port", port_arg));
}
}

CService onion_service_target;
if (!connOptions.onion_binds.empty()) {
onion_service_target = connOptions.onion_binds.front();
Expand Down
2 changes: 1 addition & 1 deletion src/masternode/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ void CActiveMasternodeManager::InitInternal(const CBlockIndex* pindex)
LogPrintf("CActiveMasternodeManager::Init -- ERROR: %s\n", m_error);
return;
}
bool fConnected = ConnectSocketDirectly(m_info.service, *sock, nConnectTimeout, true) && IsSelectableSocket(sock->Get());
bool fConnected = ConnectSocketDirectly(m_info.service, *sock, nConnectTimeout, true) && sock->IsSelectable();
sock->Reset();

if (!fConnected && Params().RequireRoutableExternalIP()) {
Expand Down
64 changes: 44 additions & 20 deletions src/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2020,8 +2020,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
return;
}

if (!IsSelectableSocket(sock->Get()))
{
if (!sock->IsSelectable()) {
LogPrintf("%s: non-selectable socket\n", strDropped);
return;
}
Expand Down Expand Up @@ -2306,10 +2305,11 @@ void CConnman::NotifyNumConnectionsChanged(CMasternodeSync& mn_sync)
mn_sync.Reset();
}

if(nodes_size != nPrevNodeCount) {
if (nodes_size != nPrevNodeCount) {
nPrevNodeCount = nodes_size;
if(clientInterface)
clientInterface->NotifyNumConnectionsChanged(nodes_size);
if (m_client_interface) {
m_client_interface->NotifyNumConnectionsChanged(nodes_size);
}

CalculateNumConnectionsChangedStats();
}
Expand Down Expand Up @@ -3140,6 +3140,12 @@ void CConnman::SetTryNewOutboundPeer(bool flag)
LogPrint(BCLog::NET, "net: setting try another outbound peer=%s\n", flag ? "true" : "false");
}

void CConnman::StartExtraBlockRelayPeers()
{
LogPrint(BCLog::NET, "net: enabling extra block-relay-only peers\n");
m_start_extra_block_relay_peers = true;
}

// Return the number of peers we have over our outbound connection limit
// Exclude peers that are marked for disconnect, or are going to be
// disconnected soon (eg ADDR_FETCH and FEELER)
Expand Down Expand Up @@ -3299,7 +3305,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, CDe
// Therefore, we do not add them to addrman in the first place.
// In case previously unreachable networks become reachable
// (e.g. in case of -onlynet changes by the user), fixed seeds will
// be loaded only for networks for which we have no addressses.
// be loaded only for networks for which we have no addresses.
seed_addrs.erase(std::remove_if(seed_addrs.begin(), seed_addrs.end(),
[&fixed_seed_networks](const CAddress& addr) { return fixed_seed_networks.count(addr.GetNetwork()) == 0; }),
seed_addrs.end());
Expand Down Expand Up @@ -3542,12 +3548,26 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, CDe
continue;
}

// Do not allow non-default ports, unless after 50 invalid
// addresses selected already. This is to prevent malicious peers
// from advertising themselves as a service on another host and
// port, causing a DoS attack as nodes around the network attempt
// to connect to it fruitlessly.
if ((!isMasternode || !Params().AllowMultiplePorts()) && addr.GetPort() != Params().GetDefaultPort(addr.GetNetwork()) && addr.GetPort() != GetListenPort() && nTries < 50) {
// Port validation in Dash has additional rules. Some networks are prohibited
// from using a non-default port while others allow any arbitary port so long
// it isn't a bad port (and in the case of masternodes, it matches its listen
// port)
const bool is_prohibited_port = [this, &addr, &isMasternode](){
if (!Params().AllowMultiplePorts()) {
const uint16_t default_port{Params().GetDefaultPort(addr.GetNetwork())};
assert(!IsBadPort(default_port)); // Make sure we never set the default port to a bad port
return addr.GetPort() != default_port;
}
const bool is_bad_port{IsBadPort(addr.GetPort())};
if (isMasternode) {
return addr.GetPort() != GetListenPort() || is_bad_port;
} else {
return is_bad_port;
}
}();

// Do not connect to prohibited ports, unless 50 invalid addresses have been selected already.
if (nTries < 50 && is_prohibited_port) {
continue;
}

Expand Down Expand Up @@ -4196,7 +4216,9 @@ void CConnman::SetNetworkActive(bool active, CMasternodeSync* const mn_sync)
mn_sync->Reset();
}

uiInterface.NotifyNetworkActiveChanged(fNetworkActive);
if (m_client_interface) {
m_client_interface->NotifyNetworkActiveChanged(fNetworkActive);
}
}

CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In, AddrMan& addrman_in,
Expand Down Expand Up @@ -4225,8 +4247,8 @@ bool CConnman::Bind(const CService& addr_, unsigned int flags, NetPermissionFlag

bilingual_str strError;
if (!BindListenPort(addr, strError, permissions)) {
if ((flags & BF_REPORT_ERROR) && clientInterface) {
clientInterface->ThreadSafeMessageBox(strError, "", CClientUIInterface::MSG_ERROR);
if ((flags & BF_REPORT_ERROR) && m_client_interface) {
m_client_interface->ThreadSafeMessageBox(strError, "", CClientUIInterface::MSG_ERROR);
}
return false;
}
Expand Down Expand Up @@ -4276,8 +4298,8 @@ bool CConnman::Start(CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_met
}

if (fListen && !InitBinds(connOptions)) {
if (clientInterface) {
clientInterface->ThreadSafeMessageBox(
if (m_client_interface) {
m_client_interface->ThreadSafeMessageBox(
_("Failed to listen on any port. Use -listen=0 if you want this."),
"", CClientUIInterface::MSG_ERROR);
}
Expand All @@ -4303,7 +4325,9 @@ bool CConnman::Start(CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_met
LogPrintf("%i block-relay-only anchors will be tried for connections.\n", m_anchors.size());
}

uiInterface.InitMessage(_("Starting network threads…").translated);
if (m_client_interface) {
m_client_interface->InitMessage(_("Starting network threads…").translated);
}

fAddressesInitialized = true;

Expand Down Expand Up @@ -4350,8 +4374,8 @@ bool CConnman::Start(CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_met
threadOpenAddedConnections = std::thread(&util::TraceThread, "addcon", [this] { ThreadOpenAddedConnections(); });

if (connOptions.m_use_addrman_outgoing && !connOptions.m_specified_outgoing.empty()) {
if (clientInterface) {
clientInterface->ThreadSafeMessageBox(
if (m_client_interface) {
m_client_interface->ThreadSafeMessageBox(
_("Cannot provide specific connections and have addrman find outgoing connections at the same time."),
"", CClientUIInterface::MSG_ERROR);
}
Expand Down
Loading
Loading