某些机器访问 freeshell IPv4 SSH 卡死问题

问题一般是由于您到 freeshell 链路上的网络设备(包括路由器、NAT 等)没有正确转发 ICMP Error (Packet Too Big) 包。要验证这个问题,请用下列 ssh -v 命令验证,如果最后两行输出与下面的相同,并且卡住了,则一般是这种问题。还可以用 wireshark 抓包,如果没有收到 ICMP Destination Unreachable 包,则确定是网络问题。

$ ssh -v -p 30xxx root@ssh.freeshell.ustc.edu.cn
OpenSSH_6.6.1, OpenSSL 1.0.1h 5 Jun 2014
debug1: Connecting to ssh.freeshell.ustc.edu.cn [202.141.176.99] port 30xxx.
debug1: Connection established.
...
debug1: sending SSH2_MSG_KEX_ECDH_INIT
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY

问题原因是 ssh.freeshell.ustc.edu.cn 与 freeshell 计算节点之间使用了 GRE tunnel,载荷 MTU 为 1476 字节,略小于以太网通常的 MTU 1500。ssh 密钥交换阶段一次发送的数据一般大于 1500 字节,因此至少填满了一个 MTU,这个长为 1500 字节的包发到 ssh.freeshell.ustc.edu.cn 会被丢弃,并返回一个 ICMP Error (Packet Too Big) 消息,其中包含了可用 MTU 1476。SSH 客户端所在主机收到 ICMP 消息后,会重新对数据拆分为 1476 字节大小的分片并发送。这个 MTU 会在路由表中缓存一段时间,因此短时间内第二次连接 freeshell IPv4 会使用正确的分片大小,不会收到 ICMP Error 消息。

遇有此种问题,请联系您的运营商解决。NAT 设备转发 ICMP Error 包是 RFC 规范的要求

如果想临时解决此问题,可以修改网卡的链路 MTU 为 1476,例如 ifconfig eth0 mtu 1476。请注意网络重新连接后 MTU 设置会恢复原状。

Update (2014-07-31): 此问题已解决。我们在 blog 主机上添加了 iptables -A FORWARD -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu 以修改用户所发起连接的 MSS(Max Segment Size),这样 freeshell 返回的 SYN+ACK 包就会包含用户支持的 MSS 与 blog-freeshell 间的 tunnel 所支持 MSS 的较小者,用户随后发送 SSH 认证数据包时,就会分片成合适大小,从而不会产生 ICMP unreachable 消息。

《某些机器访问 freeshell IPv4 SSH 卡死问题》上有3条评论

  1. 使用这个命令也可以解决这个问题。
    cocobear@UnbutuUSB:~$ sudo ifconfig eth0 mtu 576

    还有修改/etc/ssh/ssh_config为下面:
    Host *
    Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc
    MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160
    SendEnv LANG LC_*
    HashKnownHosts yes
    GSSAPIAuthentication yes
    GSSAPIDelegateCredentials no
    HostKeyAlgorithms ssh-rsa,ssh-dss

    还有连接的时候指定MAC算法也可以:

    ssh -vT -m ‘hmac-sha2-256,’ git@gitcafe.com

    但是不清楚为什么;-(

    1. sudo ifconfig eth0 mtu 576 这个肯定是奏效的,算是一种临时解决方法吧。

      后两种起作用的原因我不清楚,可能是修改密钥交换算法使得单个数据包的长度不超过路径上的最大 MTU。但这个解决方案并不优雅,当 ssh 终端输出大块文本,长度超过路径 MTU 的时候,ssh 就会卡住。

  2. 我现在使用的是:
    sudo ifconfig eth0 mtu 1492

    我的网络环境是电信光纤,PPPOE拨号 ,PPPOE的最大值是1492,所以我把系统中MTU改为1492,这样就可以了。我觉得改为576有点太小了,会影响平时的传输速度。

评论已关闭。