Skip to content

Commit 9720863

Browse files
committed
net: open p2p connections to nodes that listen on non-default ports
By default, for mainnet, the p2p listening port is 8333. Bitcoin Core has a strong preference for only connecting to nodes that listen on that port. Remove that preference because connections over clearnet that involve port 8333 make it easy to detect, analyze, block or divert Bitcoin p2p traffic before the connection is even established (at TCP SYN time). For further justification see the OP of: bitcoin/bitcoin#23306
1 parent bcecde6 commit 9720863

File tree

7 files changed

+258
-6
lines changed

7 files changed

+258
-6
lines changed

doc/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ The Bitcoin repo's [root README](/README.md) contains relevant information on th
7979
- [Init Scripts (systemd/upstart/openrc)](init.md)
8080
- [Managing Wallets](managing-wallets.md)
8181
- [Multisig Tutorial](multisig-tutorial.md)
82+
- [P2P bad ports definition and list](p2p-bad-ports.md)
8283
- [PSBT support](psbt.md)
8384
- [Reduce Memory](reduce-memory.md)
8485
- [Reduce Traffic](reduce-traffic.md)

doc/p2p-bad-ports.md

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
When Bitcoin Core automatically opens outgoing P2P connections it chooses
2+
a peer (address and port) from its list of potential peers. This list is
3+
populated with unchecked data, gossiped over the P2P network by other peers.
4+
5+
A malicious actor may gossip an address:port where no Bitcoin node is listening,
6+
or one where a service is listening that is not related to the Bitcoin network.
7+
As a result, this service may occasionally get connection attempts from Bitcoin
8+
nodes.
9+
10+
"Bad" ports are ones used by services which are usually not open to the public
11+
and usually require authentication. A connection attempt (by Bitcoin Core,
12+
trying to connect because it thinks there is a Bitcoin node on that
13+
address:port) to such service may be considered a malicious action by an
14+
ultra-paranoid administrator. An example for such a port is 22 (ssh). On the
15+
other hand, connection attempts to public services that usually do not require
16+
authentication are unlikely to be considered a malicious action,
17+
e.g. port 80 (http).
18+
19+
Below is a list of "bad" ports which Bitcoin Core avoids when choosing a peer to
20+
connect to. If a node is listening on such a port, it will likely receive less
21+
incoming connections.
22+
23+
1: tcpmux
24+
7: echo
25+
9: discard
26+
11: systat
27+
13: daytime
28+
15: netstat
29+
17: qotd
30+
19: chargen
31+
20: ftp data
32+
21: ftp access
33+
22: ssh
34+
23: telnet
35+
25: smtp
36+
37: time
37+
42: name
38+
43: nicname
39+
53: domain
40+
69: tftp
41+
77: priv-rjs
42+
79: finger
43+
87: ttylink
44+
95: supdup
45+
101: hostname
46+
102: iso-tsap
47+
103: gppitnp
48+
104: acr-nema
49+
109: pop2
50+
110: pop3
51+
111: sunrpc
52+
113: auth
53+
115: sftp
54+
117: uucp-path
55+
119: nntp
56+
123: NTP
57+
135: loc-srv /epmap
58+
137: netbios
59+
139: netbios
60+
143: imap2
61+
161: snmp
62+
179: BGP
63+
389: ldap
64+
427: SLP (Also used by Apple Filing Protocol)
65+
465: smtp+ssl
66+
512: print / exec
67+
513: login
68+
514: shell
69+
515: printer
70+
526: tempo
71+
530: courier
72+
531: chat
73+
532: netnews
74+
540: uucp
75+
548: AFP (Apple Filing Protocol)
76+
554: rtsp
77+
556: remotefs
78+
563: nntp+ssl
79+
587: smtp (rfc6409)
80+
601: syslog-conn (rfc3195)
81+
636: ldap+ssl
82+
989: ftps-data
83+
990: ftps
84+
993: ldap+ssl
85+
995: pop3+ssl
86+
1719: h323gatestat
87+
1720: h323hostcall
88+
1723: pptp
89+
2049: nfs
90+
3659: apple-sasl / PasswordServer
91+
4045: lockd
92+
5060: sip
93+
5061: sips
94+
6000: X11
95+
6566: sane-port
96+
6665: Alternate IRC
97+
6666: Alternate IRC
98+
6667: Standard IRC
99+
6668: Alternate IRC
100+
6669: Alternate IRC
101+
6697: IRC + TLS
102+
10080: Amanda
103+
104+
For further information see:
105+
106+
[pull/23306](https://github.com/bitcoin/bitcoin/pull/23306#issuecomment-947516736)
107+
108+
[pull/23542](https://github.com/bitcoin/bitcoin/pull/23542)
109+
110+
[fetch.spec.whatwg.org](https://fetch.spec.whatwg.org/#port-blocking)
111+
112+
[chromium.googlesource.com](https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/net/base/port_util.cc)
113+
114+
[hg.mozilla.org](https://hg.mozilla.org/mozilla-central/file/tip/netwerk/base/nsIOService.cpp)

src/init.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,8 @@ void SetupServerArgs(ArgsManager& argsman)
466466
argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
467467
argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
468468
argsman.AddArg("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
469+
// TODO: remove the sentence "Nodes not using ... incoming connections." once the changes from
470+
// https://github.com/bitcoin/bitcoin/pull/23542 have become widespread.
469471
argsman.AddArg("-port=<port>", strprintf("Listen for connections on <port>. Nodes not using the default ports (default: %u, testnet: %u, signet: %u, regtest: %u) are unlikely to get incoming connections. Not relevant for I2P (see doc/i2p.md).", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), signetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
470472
argsman.AddArg("-proxy=<ip:port>", "Connect through SOCKS5 proxy, set -noproxy to disable (default: disabled)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
471473
argsman.AddArg("-proxyrandomize", strprintf("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)", DEFAULT_PROXYRANDOMIZE), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
@@ -1698,12 +1700,23 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
16981700
connOptions.nMaxOutboundLimit = *opt_max_upload;
16991701
connOptions.m_peer_connect_timeout = peer_connect_timeout;
17001702

1703+
const auto BadPortWarning = [](const char* prefix, uint16_t port) {
1704+
return strprintf(_("%s request to listen on port %u. This port is considered \"bad\" and "
1705+
"thus it is unlikely that any Bitcoin Core peers connect to it. See "
1706+
"doc/p2p-bad-ports.md for details and a full list."),
1707+
prefix,
1708+
port);
1709+
};
1710+
17011711
for (const std::string& bind_arg : args.GetArgs("-bind")) {
17021712
CService bind_addr;
17031713
const size_t index = bind_arg.rfind('=');
17041714
if (index == std::string::npos) {
17051715
if (Lookup(bind_arg, bind_addr, GetListenPort(), false)) {
17061716
connOptions.vBinds.push_back(bind_addr);
1717+
if (IsBadPort(bind_addr.GetPort())) {
1718+
InitWarning(BadPortWarning("-bind", bind_addr.GetPort()));
1719+
}
17071720
continue;
17081721
}
17091722
} else {
@@ -1730,6 +1743,15 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
17301743
// on any address - 0.0.0.0 (IPv4) and :: (IPv6).
17311744
connOptions.bind_on_any = args.GetArgs("-bind").empty() && args.GetArgs("-whitebind").empty();
17321745

1746+
// Emit a warning if a bad port is given to -port= but only if -bind and -whitebind are not
1747+
// given, because if they are, then -port= is ignored.
1748+
if (connOptions.bind_on_any && args.IsArgSet("-port")) {
1749+
const uint16_t port_arg = args.GetIntArg("-port", 0);
1750+
if (IsBadPort(port_arg)) {
1751+
InitWarning(BadPortWarning("-port", port_arg));
1752+
}
1753+
}
1754+
17331755
CService onion_service_target;
17341756
if (!connOptions.onion_binds.empty()) {
17351757
onion_service_target = connOptions.onion_binds.front();

src/net.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2120,12 +2120,8 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
21202120
continue;
21212121
}
21222122

2123-
// Do not allow non-default ports, unless after 50 invalid
2124-
// addresses selected already. This is to prevent malicious peers
2125-
// from advertising themselves as a service on another host and
2126-
// port, causing a DoS attack as nodes around the network attempt
2127-
// to connect to it fruitlessly.
2128-
if (addr.GetPort() != Params().GetDefaultPort(addr.GetNetwork()) && nTries < 50) {
2123+
// Do not connect to bad ports, unless 50 invalid addresses have been selected already.
2124+
if (nTries < 50 && (addr.IsIPv4() || addr.IsIPv6()) && IsBadPort(addr.GetPort())) {
21292125
continue;
21302126
}
21312127

src/netbase.cpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,3 +749,93 @@ void InterruptSocks5(bool interrupt)
749749
{
750750
interruptSocks5Recv = interrupt;
751751
}
752+
753+
bool IsBadPort(uint16_t port)
754+
{
755+
/* Don't forget to update doc/p2p-bad-ports.md if you change this list. */
756+
757+
switch (port) {
758+
case 1: // tcpmux
759+
case 7: // echo
760+
case 9: // discard
761+
case 11: // systat
762+
case 13: // daytime
763+
case 15: // netstat
764+
case 17: // qotd
765+
case 19: // chargen
766+
case 20: // ftp data
767+
case 21: // ftp access
768+
case 22: // ssh
769+
case 23: // telnet
770+
case 25: // smtp
771+
case 37: // time
772+
case 42: // name
773+
case 43: // nicname
774+
case 53: // domain
775+
case 69: // tftp
776+
case 77: // priv-rjs
777+
case 79: // finger
778+
case 87: // ttylink
779+
case 95: // supdup
780+
case 101: // hostname
781+
case 102: // iso-tsap
782+
case 103: // gppitnp
783+
case 104: // acr-nema
784+
case 109: // pop2
785+
case 110: // pop3
786+
case 111: // sunrpc
787+
case 113: // auth
788+
case 115: // sftp
789+
case 117: // uucp-path
790+
case 119: // nntp
791+
case 123: // NTP
792+
case 135: // loc-srv /epmap
793+
case 137: // netbios
794+
case 139: // netbios
795+
case 143: // imap2
796+
case 161: // snmp
797+
case 179: // BGP
798+
case 389: // ldap
799+
case 427: // SLP (Also used by Apple Filing Protocol)
800+
case 465: // smtp+ssl
801+
case 512: // print / exec
802+
case 513: // login
803+
case 514: // shell
804+
case 515: // printer
805+
case 526: // tempo
806+
case 530: // courier
807+
case 531: // chat
808+
case 532: // netnews
809+
case 540: // uucp
810+
case 548: // AFP (Apple Filing Protocol)
811+
case 554: // rtsp
812+
case 556: // remotefs
813+
case 563: // nntp+ssl
814+
case 587: // smtp (rfc6409)
815+
case 601: // syslog-conn (rfc3195)
816+
case 636: // ldap+ssl
817+
case 989: // ftps-data
818+
case 990: // ftps
819+
case 993: // ldap+ssl
820+
case 995: // pop3+ssl
821+
case 1719: // h323gatestat
822+
case 1720: // h323hostcall
823+
case 1723: // pptp
824+
case 2049: // nfs
825+
case 3659: // apple-sasl / PasswordServer
826+
case 4045: // lockd
827+
case 5060: // sip
828+
case 5061: // sips
829+
case 6000: // X11
830+
case 6566: // sane-port
831+
case 6665: // Alternate IRC
832+
case 6666: // Alternate IRC
833+
case 6667: // Standard IRC
834+
case 6668: // Alternate IRC
835+
case 6669: // Alternate IRC
836+
case 6697: // IRC + TLS
837+
case 10080: // Amanda
838+
return true;
839+
}
840+
return false;
841+
}

src/netbase.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,4 +247,13 @@ void InterruptSocks5(bool interrupt);
247247
*/
248248
bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* auth, const Sock& socket);
249249

250+
/**
251+
* Determine if a port is "bad" from the perspective of attempting to connect
252+
* to a node on that port.
253+
* @see doc/p2p-bad-ports.md
254+
* @param[in] port Port to check.
255+
* @returns whether the port is bad
256+
*/
257+
bool IsBadPort(uint16_t port);
258+
250259
#endif // BITCOIN_NETBASE_H

src/test/netbase_tests.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,4 +576,24 @@ BOOST_AUTO_TEST_CASE(caddress_unserialize_v2)
576576
BOOST_CHECK(fixture_addresses == addresses_unserialized);
577577
}
578578

579+
BOOST_AUTO_TEST_CASE(isbadport)
580+
{
581+
BOOST_CHECK(IsBadPort(1));
582+
BOOST_CHECK(IsBadPort(22));
583+
BOOST_CHECK(IsBadPort(6000));
584+
585+
BOOST_CHECK(!IsBadPort(80));
586+
BOOST_CHECK(!IsBadPort(443));
587+
BOOST_CHECK(!IsBadPort(8333));
588+
589+
// Check all ports, there must be 80 bad ports in total.
590+
size_t total_bad_ports{0};
591+
for (uint16_t port = std::numeric_limits<uint16_t>::max(); port > 0; --port) {
592+
if (IsBadPort(port)) {
593+
++total_bad_ports;
594+
}
595+
}
596+
BOOST_CHECK_EQUAL(total_bad_ports, 80);
597+
}
598+
579599
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)