SSH 偶发卡在 KEX_ECDH_REPLY:从链路、IPv6 到算法协商的排查顺序

举报
yd_217417492 发表于 2026/10/28 08:52:39 2026/10/28
【摘要】 SSH 端口通却卡在 KEX_ECDH_REPLY,问题可能在链路、IPv6、算法协商或 MTU。本文给出一套从 -vvv 日志到 mtr、ping、算法组合测试的排查顺序和可复用的绕行参数。

先分清“连不上”和“握手中断”

最常见的误判是把 SSH 故障都归因于“服务器挂了”。实际上,如果 nc -vz host 22 能通,说明 TCP 三次握手已经完成,问题出在更上层的 SSH 协议协商。此时服务器 sshd 可能完全正常,uptime 和 load 也看不出异常。

典型现象是:命令一直挂着,不报错也不退出;加上 -vvv 后,最后一行停在:

debug1: expecting SSH2_MSG_KEX_ECDH_REPLY

这句话的含义很明确:客户端已经把密钥交换的初始化包发给了服务器,正在等服务器返回 ECDH 公钥和签名。卡在这里,既可能是网络路径把包丢了,也可能是服务器响应了但回程被拦,还可能是双方根本没能就会话算法达成一致。

第一步:用 -vvv 找到确切的卡点

不要凭感觉改配置,先拿到完整日志:

ssh -vvv -o ConnectTimeout=20 user@host 2>&1 | tee /tmp/ssh-debug.log

重点看三段时间点:

  • TCP 连接建立:出现 Connection established,说明网络层可达。
  • 版本与算法协商:出现 Remote protocol version、kex: algorithm,说明双方已经交换 banner 并选定算法。
  • 密钥交换:如果停在 expecting SSH2_MSG_KEX_ECDH_REPLY,问题就在服务器回包或回程链路上。

如果连 Remote protocol version 都没出现,先怀疑 22 端口被中间设备劫持、或者连到了错误的地址。

第二步:看链路质量,而不是只看延迟

跨国或跨运营商链路常见“能 ping 通但偶发丢包”。单次 ping 说明不了问题,要看一段时间的统计:

ping -c 100 host
mtr -rwzbc 100 host

判断标准不是平均延迟,而是丢包是否集中在某一跳。如果从第 N 跳开始持续丢包,后面所有节点都跟着丢,基本可以锁定那段链路;如果只有最后一跳丢,反而可能是服务器侧的 ICMP 限速,不代表 TCP 有问题。

SSH 的密钥交换包不大,但对丢包非常敏感:TCP 会重传,客户端表现为“卡十几秒后突然成功”或“一直卡住”。这类故障用 ss -ti 看重传次数更直接:

ss -ti dst :22

第三步:排除 IPv6 与 DNS 的干扰

很多“偶发连不上”其实是客户端优先走了 IPv6,而目标网络没有可用的 IPv6 回程。表现是 SSH 先等 AAAA 记录、再等 IPv6 连接超时,最后才回落到 IPv4。

强制 IPv4 验证:

ssh -4 -o ConnectTimeout=20 user@host

如果 -4 立刻正常,问题就不在加密算法,而在地址选择。可以在 ~/.ssh/config 里固定:

Host myserver
    HostName 203.0.113.10
    User ubuntu
    AddressFamily inet
    ConnectTimeout 20
    ServerAliveInterval 30
    ServerAliveCountMax 3

AddressFamily inet 只走 IPv4;ServerAliveInterval 让空闲连接定期发心跳,避免被 NAT 或防火墙静默回收。

第四步:算法协商与中间盒

有些老防火墙、DDoS 清洗设备或代理会对特定 SSH 算法做深度包检测。一旦识别失败,它可能直接丢弃包含密钥交换数据的包,表现就是握手停在半路。

先看双方支持什么:

ssh -Q kex
ssh -Q cipher
sshd -T | grep -i -E 'kexalgorithms|cipers'

然后用最小组合做对照测试。下面这组参数刻意选了较常见、包结构较简单的算法:

ssh -4 -o KexAlgorithms=ecdh-sha2-nistp256 \
       -o Ciphers=aes128-ctr \
       -o ConnectTimeout=20 user@host

如果这组能稳定连上,而默认配置仍然偶发卡住,基本可以确认是算法协商或中间盒干扰,而不是服务器负载。此时有两个方向:

  • 临时绕行:把上面几行写进 ~/.ssh/config 的对应 Host 段,先恢复工作。
  • 根治:升级 sshd 和客户端,或者换一个不被中间盒重点照顾的端口/入口;如果必须保留默认算法,联系网络管理员确认清洗策略。

第五步:MTU 要不要查

MTU 问题更常出现在认证通过后的大流量阶段,但并不是与握手无关:如果服务器使用了较大的证书链或 banner,密钥交换阶段的单个 TCP 段也可能超过路径 MTU,被中间设备丢弃后表现为“握手卡住”。

用不分片的 ping 逐步试探:

ping -M do -s 1472 host   # 1500 MTU
ping -M do -s 1400 host   # 1428 MTU
ping -M do -s 1200 host   # 1228 MTU

如果 1472 失败、1400 成功,说明路径 MTU 小于 1500。可以在服务器侧临时降低 MTU 验证:

ip link set dev eth0 mtu 1400

或者在网关上做 MSS clamping:

iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
  -j TCPMSS --clamp-mss-to-pmtu

验证完记得恢复,别把临时值当成永久配置。

一套可直接复用的排查顺序

  1. nc -vz host 22:确认端口可达。
  2. ssh -vvv:确认卡在 TCP、banner、算法协商还是 KEX 回包。
  3. ping -c 100 + mtr:看丢包是否集中在固定跳数。
  4. ssh -4:排除 IPv6 和 DNS 回退。
  5. -o KexAlgorithms=... -o Ciphers=...:做算法对照。
  6. ping -M do -s:确认路径 MTU。
  7. 最后才动服务器配置;每次只改一个变量,改完立刻复测。

SSH 握手的每一段都有明确日志,最怕的是一上来就重装 sshd 或重启服务器。先把卡点定位到“网络、地址、算法、MTU”中的某一层,剩下的处理反而很快。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。