
Bitcoin Core 坏端口机制详解IsBadPort 黑名单如何保护网络与用户【免费下载链接】bitcoinBitcoin Core integration/staging tree项目地址: https://gitcode.com/GitHub_Trending/bi/bitcoin本篇围绕 Bitcoin Core 的坏端口bad ports机制展开讲清为什么节点自动建立的出站连接可能误触他人机器上的敏感服务、BadPort 黑名单的完整 85 项端口清单、以及它在连接选路src/net.cpp、启动参数校验src/init.cpp与单元测试src/test/netbase_tests.cpp中的具体实现。读完你能掌握该机制的完整端口列表、源码级调用链以及运行节点时监听端口选择的正确实践。一、问题背景P2P 地址列表是不可信数据当 Bitcoin Core 自动建立出站 P2P 连接时它从潜在对端地址列表addrman中挑选一个地址:端口进行连接。这个列表的数据来源于其他节点通过 P2P 网络广播gossip的未经校验的地址数据详见 doc/p2p-bad-ports.md。由于地址:端口数据本身不可信攻击者可以广播一个恶意构造的地址:端口它可能指向没有运行任何 Bitcoin 节点的主机运行着与 Bitcoin 网络无关服务的端口。结果是该服务会不定期地收到来自 Bitcoin 节点的连接尝试。二、什么是坏端口文档给出的核心定义坏端口通常被那些不向公众开放、且一般要求认证的服务所占用。Bitcoin Core 出于误以为该地址:端口上有一个 Bitcoin 节点而尝试连接这类服务时极偏执的运维人员ultra-paranoid administrator可能把这次连接尝试视为恶意行为例如扫描 22/ssh 端口的行为常触发入侵检测告警。与之相反连接尝试通常不需要认证的公开服务如 80/http 端口不太可能被认定为恶意行为。一个直接的运维含义是如果你的 Bitcoin 节点监听在某个坏端口上它收到的入站连接会明显减少——因为全网所有节点在自动选路时都会主动避开这个端口。三、完整的 BadPort 黑名单85 个端口以下是 Bitcoin Core 选择连接对端时主动避开的坏端口完整列表与文档保持一致并可直接与源码 src/netbase.cpp 中IsBadPort的switch分支逐一对应端口服务端口服务1tcpmux514shell7echo515printer9discard526tempo11systat530courier13daytime531chat15netstat532netnews17qotd540uucp19chargen548AFP (Apple Filing Protocol)20ftp data554rtsp21ftp access556remotefs22ssh563nntpssl23telnet587smtp (rfc6409)25smtp601syslog-conn (rfc3195)37time636ldapssl42name989ftps-data43nicname990ftps53domain993ldapssl文档原文如此69tftp995pop3ssl77priv-rjs1719h323gatestat79finger1720h323hostcall87ttylink1723pptp95supdup2049nfs101hostname3306MySQL102iso-tsap3389RDP / Windows Remote Desktop103gppitnp3659apple-sasl / PasswordServer104acr-nema4045lockd109pop25060sip110pop35061sips111sunrpc5432PostgreSQL113auth5900VNC115sftp6000X11117uucp-path6566sane-port119nntp6665Alternate IRC123NTP6666Alternate IRC135loc-srv / epmap6667Standard IRC137netbios6668Alternate IRC139netbios6669Alternate IRC143imap26697IRC TLS161snmp10080Amanda179BGP27017MongoDB389ldap427SLP亦用于 Apple Filing Protocol465smtpssl512print / exec513login合计 85 个端口。单元测试通过遍历全部 65535 个端口号强制约束了这个数量见下文第五节。四、源码实现IsBadPort 与它的三个调用点4.1 核心判定函数IsBadPort声明在 src/netbase.h实现在 src/netbase.cpp。它是一个纯粹的switch匹配函数命中上表任一端口的值即返回true其余返回falsebool IsBadPort(uint16_t port) { /* Dont forget to update doc/p2p-bad-ports.md if you change this list. */ switch (port) { case 1: // tcpmux case 7: // echo case 9: // discard // ...共 85 个 case见上文清单... case 10080: // Amanda case 27017: // MongoDB return true; } return false; }注意源码中显式的一条注释如果修改了这个列表别忘了更新 doc/p2p-bad-ports.md——也就是说文档中的端口清单与代码是人工保持同步的契约这正是本篇以该文档为主体的原因。4.2 出站连接选路中的过滤核心场景在CNode::ThreadOpenOutbound的自动出站连接选路循环中节点从 addrman 反复Select候选地址并逐一检查坏端口过滤就发生在其中src/net.cpp// Do not connect to bad ports, unless 50 invalid addresses have been selected already. if (nTries 50 (addr.IsIPv4() || addr.IsIPv6()) IsBadPort(addr.GetPort())) { continue; }从这段代码可以读出三条精确规则只针对 IPv4/IPv6Tor、I2P、CJDNS 等隐藏网络不受该过滤影响因为它们的端口不直接暴露到公网基础设施有逃生通道nTries 50意味着选路循环最多尝试 100 个候选地址nTries 100时退出本轮见 src/net.cpp如果在尝试 50 次后仍没找到其他可用地址坏端口也会被放行——避免在极端情况下节点因 addrman 中地址全部落在坏端口上而完全无法建立连接过滤发生在选路阶段与要求候选满足全部期望的 service flags避开已连接的网络分组等检查并列属于选路前置条件之一。这就是文档所说节点会避开坏端口来选择连接对端的具体实现位置。4.3 启动参数校验-bind 与 -port 的坏端口警告除了被动避开节点启动时若用户主动把监听端口配置成坏端口Bitcoin Core 会发出启动警告而非直接报错。逻辑在 src/init.cppconst 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 peer will connect to it. See doc/p2p-bad-ports.md for details and a full list.), prefix, port); };两处触发点解析-bindaddr:port时若端口命中坏端口记录InitWarning(BadPortWarning(-bind, ...))src/init.cpp当未指定-bind/-whitebind即bind_on_any且设置了-port时对该端口做同样检查src/init.cpp。警告文案直接指向doc/p2p-bad-ports.md提示不太可能有对端会连接到这个端口。注意这是警告而非错误节点仍会按该端口监听只是如文档所述收到的入站连接会少。五、测试保障85 个端口的穷举约束单元测试isbadportsrc/test/netbase_tests.cpp对这一机制做了双重验证BOOST_AUTO_TEST_CASE(isbadport) { BOOST_CHECK(IsBadPort(1)); BOOST_CHECK(IsBadPort(22)); BOOST_CHECK(IsBadPort(6000)); BOOST_CHECK(!IsBadPort(80)); BOOST_CHECK(!IsBadPort(443)); BOOST_CHECK(!IsBadPort(8333)); // Check all possible ports and ensure we only flag the expected amount as bad std::listint ports(std::numeric_limitsuint16_t::max()); std::iota(ports.begin(), ports.end(), 1); BOOST_CHECK_EQUAL(std::ranges::count_if(ports, IsBadPort), 85); }点检典型坏端口1/22/6000必须命中典型好端口80/443/8333其中 8333 是 Bitcoin 主网默认端口必须不命中对 165535 全部端口穷举断言坏端口总数恰好为 85——任何对IsBadPort列表的增删若未同步更新断言CI 都会失败。这从测试层面锁死了文档、代码与测试三者的数量一致性。六、设计来源与浏览器端口阻塞同源文档末尾指出该清单的进一步参考来源包括早期两个 pull request 的讨论以及三份与浏览器网络栈相关的公开资料WHATWG Fetch 规范的 port-blocking 章节、Chromium 的port_util.cc、Firefox 的nsIOService.cpp。也就是说这个黑名单本质上是借鉴了浏览器世界禁止网页 JS 连接某些敏感端口如 22、5900的既有实践这些端口上运行的服务通常不面向公网未经请求的连接尝试会污染目标主机的安全日志并可能触发告警。Bitcoin Core 把同一份清单用于 P2P 自动连接避免全网的节点流量去敲全球主机的 ssh、数据库或远程桌面端口。七、对节点运维者的实操建议监听端口选择主网节点使用默认端口 8333-port8333该端口不在坏端口列表中如必须换端口先核对上文清单确认所选端口未被列入 85 项之中否则启动日志会出现BadPortWarning且入站连接偏少。验证方式启动 bitcoind 后观察日志中是否出现This port is considered bad and thus it is unlikely that any peer will connect to it字样由 src/init.cpp 的BadPortWarning产生出现即说明监听端口命中黑名单。对非监听方如果你管理一台机器并发现它偶尔收到来自陌生 IP 的、指向 ssh/VNC 等端口的 TCP 连接尝试且源行为符合 Bitcoin 节点特征这就是本文描述的机制——其他节点 addrman 中记录了该地址:端口。该行为自 pull/23306 引入黑名单过滤后已显著收敛但列表之外的端口理论上仍可能出现。八、小结doc/p2p-bad-ports.md定义了 85 个坏端口与 src/netbase.cpp 中IsBadPort的实现逐一对应并由 src/test/netbase_tests.cpp 的穷举断言锁定数量自动出站选路在 src/net.cpp 中避开这些端口仅 IPv4/IPv6且 50 次尝试后有逃生通道启动时对-bind/-port命中坏端口的配置给出警告src/init.cpp文档中 993 等个别条目与源码注释保持同源修改任一侧都应同步另一侧。【免费下载链接】bitcoinBitcoin Core integration/staging tree项目地址: https://gitcode.com/GitHub_Trending/bi/bitcoin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考