首页
/ Bitcoin Core 源码解读:33414 为 Tor 洋葱服务自动启用 PoW 防护

Bitcoin Core 源码解读:33414 为 Tor 洋葱服务自动启用 PoW 防护

2026-09-06 12:32:14作者:曹令琨Iris

在 Bitcoin Core 中,以 -listenonion(默认开启)方式自动创建的 Tor 隐藏服务,从 PR #33414 起会尝试向 Tor 守护进程请求启用 PoW(Proof-of-Work)防护——只要 Tor 版本支持该能力。本文以 release notes 草稿 为线索,结合 Tor 控制接口实现回复码定义fuzz 测试,完整拆解这一改动的命令构造、降级回退机制与验证方式,帮助运维自托管节点的开发者理解洋葱服务的抗 DoS 能力是如何在 Bitcoin Core 与 Tor 之间协商的。

一、变更概述:这条 release note 说了什么

doc/release-notes-33414.md 是挂在下一个版本 release notes 下的待发布条目,其正文只有简短的一行(这是 Bitcoin Core release notes 分片文件的典型形态,最终会在发版时合并进 doc/release-notes 中的版本总文档):

P2P and network changes Tor hidden services that are created automatically by Bitcoin Core will have PoW defenses enabled if the Tor daemon supports that. (#33414)

翻译过来:由 Bitcoin Core 自动创建的 Tor 隐藏服务(onion service),在 Tor 守护进程支持时,将启用 PoW 防护。关键词是 "automatically created" 和 "if the Tor daemon supports that"——它限定了两个边界:

  • 仅影响通过 Tor Control 接口 ADD_ONION 命令动态创建的临时洋葱服务,不影响用户在 torrc 中手动配置的 HiddenServiceDir
  • 存在能力探测式的兼容处理:旧版 Tor 不认识 PoWDefensesEnabled 参数时,Bitcoin Core 会自动降级重试,保证功能不因 Tor 版本过旧而中断。

二、PoW 防护在洋葱服务中的角色

先解释为什么需要这项防御。Tor 的 onion service 对外暴露一个 .onion 地址,任何客户端都可以通过 Tor 网络尝试与它建立电路并发起握手。对 P2P 节点而言,这意味着匿名网络上任意攻击者都能反复对你的节点发起连接尝试,消耗 CPU 和带宽——这是一种经典的连接型 DoS 攻击面。

PoW 防护的思路是:要求连接发起方在建立电路前完成一道轻量级的工作量证明(哈希求逆类问题),把"建立一次连接的边际成本"提高,从而显著抬高大规模连接洪水攻击的成本。这一机制由 Tor 项目实现,Bitcoin Core 侧的职责是在创建洋葱服务时把开关打开,而不是自己实现 PoW 校验。

需要区分两个层面的"PoW",避免混淆:本条变更与比特币共识中的工作量证明、与 pow.cpp 中的 CheckProofOfWork 完全无关,它只是 Tor 网络层的一个抗 DoS 开关。

三、源码拆解:命令如何构造

3.1 MakeAddOnionCmd:把开关拼进 ADD_ONION 命令

改动新增了一个静态函数 MakeAddOnionCmd,统一负责拼出发给 Tor Control 端口的 ADD_ONION 命令:

static std::string MakeAddOnionCmd(const std::string& private_key, const std::string& target, bool enable_pow)
{
    // Note that the 'virtual' 端口 always 使用默认端口,避免用其他端口的节点被"脱匿"。
    return strprintf("ADD_ONION %s%s Port=%i,%s",
                     private_key,
                     enable_pow ? " PoWDefensesEnabled=1" : "",
                     Params().GetDefaultPort(),
                     target);
}

三个要点:

  1. PoWDefensesEnabled=1 是 Tor Control 规范中 ADD_ONION 命令新增的 key=value 选项(由 Tor 在 0.4.9.2-alpha 引入该控制协议能力),Bitcoin Core 只是把开关透传给 Tor 守护进程;
  2. 虚拟端口固定为默认 P2P 端口(主网 8333):注释明确说明这是为了避免"用非默认端口监听的节点被流量特征去匿(decloaking)"——所有自动创建的洋葱服务对外看起来端口一致;
  3. 该函数被抽出来正是因为同一条命令需要生成两个变体(带开关 / 不带开关),服务于后面的降级重试逻辑。

3.2 首次请求:认证通过后带 PoW 开关发起

Tor 控制连接的认证完成回调 TorController::auth_cb 中,生成或复用 ED25519-V3 私钥后,立即以 enable_pow=true 发起请求:

// 请求洋葱服务,重定向端口。
_conn.Command(MakeAddOnionCmd(m_private_key, m_target.ToStringAddrPort(), /*enable_pow=*/true),
              this {
                  add_onion_cb(conn, reply, /*pow_was_enabled=*/true);
              });

这里的策略是乐观启用:先假定 Tor 支持该参数,直接带 PoWDefensesEnabled=1 下发。

3.3 降级回退:收到 512 语法错误时重试

兼容性处理集中在回调 TorController::add_onion_cb。Tor Control 协议对不支持的命令参数返回 512 Syntax Error,Bitcoin Core 据此识别"Tor 版本太旧"并自动重试:

} else if (pow_was_enabled && reply.code == TOR_REPLY_SYNTAX_ERROR) {
    LogDebug(BCLog::TOR, "ADD_ONION failed with PoW defenses, retrying without");
    _conn.Command(MakeAddOnionCmd(m_private_key, m_target.ToStringAddrPort(), /*enable_pow=*/false),
                  this {
                      add_onion_cb(conn, reply, /*pow_was_enabled=*/false);
                  });
}

注意回退的两个限定条件:

  • 仅在 pow_was_enabled 为真时才可能触发重试,避免无限循环(重试后 pow_was_enabled=false,若仍失败则落入最终的 Add onion failed; error code %d 警告分支);
  • 精确匹配 TOR_REPLY_SYNTAX_ERROR,而不是所有错误码——真正的失败(如 551 连接失败)不会被误判为版本问题。

对应的回复码常量定义在 src/torcontrol.h#L30-L32

inline constexpr int TOR_REPLY_OK{250};
inline constexpr int TOR_REPLY_UNRECOGNIZED{510};
inline constexpr int TOR_REPLY_SYNTAX_ERROR{512}; //!< 命令参数语法错误

其中 TOR_REPLY_UNRECOGNIZED(510) 的既有处理逻辑会提示"You probably need to upgrade Tor";本次改动让 512 走一条静默降级路径,只在 -debug=tor 日志里留一条 ADD_ONION failed with PoW defenses, retrying without

成功路径上,日志也区分了防护状态:ADD_ONION successful (PoW defenses enabled/disabled)(见 src/torcontrol.cpp#L518),方便运维确认本节点最终是否启用了防护。

四、适用前提与验证方法

适用前提

  • 该能力只作用于自动创建的洋葱服务,即 doc/tor.md 第 2 节描述的机制:-listenonion 默认开启(只要节点处于 listen 状态且 Tor 可用),通过 -torcontrol / -torpassword(或 cookie 认证)连接 Tor Control 端口后由 Bitcoin Core 编程创建临时洋葱服务;
  • Tor 守护进程需支持 ADD_ONIONPoWDefensesEnabled 参数(该控制协议能力自 Tor 0.4.9.2-alpha 引入);不支持的版本会走上面的降级路径,洋葱服务照常创建,只是没有 PoW 防护;
  • 版本、命令或配置相关的行为以当前仓库源码为准:降级重试是"语法错误才重试一次",没有可配置开关,也没有单独的 RPC 暴露 PoW 状态。

如何验证(沿用 doc/tor.md 中给出的观测手段):

  1. 启动 bitcoind 时加 -debug=tor,在 debug log 中 grep ADD_ONION
    • 看到 ADD_ONION successful (PoW defenses enabled) → Tor 版本受支持且启用成功;
    • 看到 ADD_ONION failed with PoW defenses, retrying without 后接 ... (PoW defenses disabled) → 当前 Tor 不支持,已自动降级;
  2. bitcoin-cli -netinfo 的 "Local addresses" 输出、getnetworkinfolocaladdresses 字段确认 .onion 地址已正常 advertise——降级路径不应影响洋葱服务本身的可用性。

五、手动配置的洋葱服务如何获得同等防护

#33414 顺带更新了 doc/tor.md 第 3 节"手动创建 Bitcoin Core 洋葱服务",为 torrc 配置补充了 PoW 防护提示(见 doc/tor.md#L182-L187):

HiddenServiceDir /var/lib/tor/bitcoin-service/
HiddenServicePort 8333 127.0.0.1:8334
# If `tor --list-modules` shows "pow: yes", then enable PoW protection.
# It is available in tor-0.4.8.1-alpha and newer when configured with
# `./configure --enable-gpl`.
HiddenServicePoWDefensesEnabled 1

与自动创建路径的关键差异在于:手动模式下开关写在 Tor 自己的配置文件里,由 Tor 守护进程直接消费,Bitcoin Core 不介入——因此文档要求先用 tor --list-modules 检查 pow 模块是否存在(注意文档给出的版本线是 tor-0.4.8.1-alpha 且需 --enable-gpl 编译,与自动创建路径所依赖的控制协议能力 0.4.9.2-alpha 不是同一个门槛,二者不要混用)。

六、测试覆盖:fuzz 目标同步扩展

接口签名变化(add_onion_cb 新增 pow_was_enabled 参数)同步落到了 fuzz 目标 src/test/fuzz/torcontrol.cpp

  • 回复码候选集中新增 TOR_REPLY_SYNTAX_ERROR,确保"PoW 请求被拒"这一分支能被模糊输入命中;
  • add_onion_cb 的调用被拆成 pow_was_enabled=true/false 两个分支,覆盖降级重试触发与不触发两种路径。

这意味着该降级逻辑不是仅靠代码审查保证正确性,而是进入了持续运行的 fuzz 覆盖面。

七、小结

维度 说明
变更条目 doc/release-notes-33414.md,PR #33414
生效范围 由 Bitcoin Core 通过 Tor Control ADD_ONION 自动创建的洋葱服务
核心实现 MakeAddOnionCmd 拼接 PoWDefensesEnabled=1auth_cb 乐观启用
兼容策略 收到 TOR_REPLY_SYNTAX_ERROR(512) 自动降级重试一次(add_onion_cb
手动服务 torrc 中自行加 HiddenServicePoWDefensesEnabled 1doc/tor.md#L182-L187
观测手段 -debug=tor 日志中的 ADD_ONION successful (PoW defenses enabled/disabled)
测试 src/test/fuzz/torcontrol.cpp fuzz 目标覆盖降级分支

对运营 Tor 全节点的用户而言,这是一条"零配置生效"的防护增强:升级 Bitcoin Core 与 Tor 后,自动创建的洋葱服务即获得连接级 DoS 抗扰能力;旧版 Tor 上节点行为与之前完全一致,只是多一条 debug 级日志。理解这条调用链(auth_cbADD_ONION 带开关 → add_onion_cb 按 512 降级)之后,也可以据此判断其他 Tor 控制命令的兼容性处理是否遵循了同样的"乐观启用 + 精确错误码回退"模式。

登录后查看全文
热门项目推荐
相关项目推荐