比特币节点日志里有一行不起眼的句子:connected to self at 203.0.113.5:8333, disconnecting。它出现的时刻很短命但很关键:节点发现自己连上了自己。检测靠的是 version 消息里一个 8 字节随机数 nonce 的回环比对,v31.0 源码顺带还留了一段关于”为什么私有广播连接的 nonce 不参与比对”的隐私攻击注释。本文把这套自检的机制、触发场景和例外讲完。
一、nonce 是谁发的。每条主动外连建立时,节点在自己的 version 消息里放一个当次握手用的随机 nonce——语义是”这是我发起的连接,编号 X”。对方回 version 时带自己的 nonce。于是”收到入站 version”那一刻,只要把消息里的 nonce 与自己全部在途外连的 nonce 比一遍,就能回答一个平时不会去问的问题:对面这个连进来的地址,是不是刚才我自己拨出去的那个电话的回声?
二、命中之后发生什么。net_processing 处理 version 的早期,若本连接是入站、且 nonce 命中自家出站记录,就记一条 connected to self 日志并立刻断开。检测的时点选得极早——在处理地址公告、区块高度、功能协商之前——意思很明白:确认是自我之前,后面任何状态都不该更新。这个顺序也保护了自我公告机制:收到 addrMe 加分、把 addrlocal 记给对端这些动作,都发生在断线决定之后,不会让一条自我回环给本机地址表投出”有邻居看见我”的假票。
三、什么时候会连到自己。最常见的是端口转发错向:路由器把外来的 8333 映射回了发起连接的机器本身;或两台机器在同一个 NAT/同一台虚拟机里互相发现,地址库里的候选恰好是自家公网地址的镜像。还有 IPv6 前缀配置错误、云主机安全组回环这类变体。症状一致:日志零星出现 connected to self,连接数莫名少一条,其他一切正常——这不是故障,是自检在替网络拓扑兜底。
四、一段教科书级的隐私注释。net.cpp 的 CheckIncomingNonce 遍历自家连接比对 nonce 时,特意排除私有广播(private broadcast)连接,注释完整描述了一个反例攻击:节点用短命的私有连接向隐私网络广播交易,version 里的 nonce 暴露了”这条连接很特殊”;恶意对端记下这个 nonce,拿去对全网发起连接,若哪条真绕回本节点,自检会误判成自我回环而断——攻击者由此仅凭一次握手就钓出节点的公网地址。把私有连接的 nonce 排除出比对集,牺牲的回环检测覆盖是局部场景(私有连接本就以用完即关为设计),换来的是这个钓鱼路径被堵死。注释末尾还补了一句:排除后如果确实和同一对端撞上,正常连接逻辑会接管,不会双开。
五、运维读法与边界。第一,把 connected to self 当作网络配置信号而不是软件错误:出现即检查端口转发指向、NAT 反射、同机多实例监听。第二,出现频率高不代表被攻击——自检断的是自己拨给自己的线,对外零暴露。第三,它只防”无意回环”,不防刻意伪装:nonce 是每连接随机数,攻击者无法伪造命中,也不需要伪造——回环检测不是安全边界,只是拓扑卫生。一句总结:这个 8 字节随机数让节点在握手的第一秒就有能力问出”你是我不?“,然后干脆地挂断。
风险提示:本文内容为技术机制科普,不构成任何投资建议、收益承诺或买卖时机判断。涉及协议规则与软件行为的描述以对应软件版本(文中已标注)的官方源码与规范为准。涉及资金操作的,请先在测试网或小额环境验证。

发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。