我已经有几个星期没法在家访问朋友的 SFTP 服务器了。用 Wireshark 测试了一下,发现我的连接尝试已经从电脑上发出,但没有任何响应(另见下面的 filezilla 日志)。
Trace: CControlSocket::ResetOperation(66)
Trace: CControlSocket::ResetOperation(66)
Trace: CControlSocket::SendNextCommand()
Trace: CSftpConnectOpData::Send() in state 0
Status: Connecting to XXXX:YYYY...
Trace: Going to execute /usr/bin/fzsftp
Response: fzSftp started, protocol_version=11
Trace: CSftpConnectOpData::ParseResponse() in state 0
Trace: CControlSocket::SendNextCommand()
Trace: CSftpConnectOpData::Send() in state 3
Command: open "ZZZZ@XXXX" YYYY
Trace: Looking up host "XXXX" for SSH connection
Trace: Connecting to XXXX port YYYY
Trace: We claim version: SSH-2.0-FileZilla_3.66.5
Error: Connection timed out after 20 seconds of inactivity
Trace: CControlSocket::ResetOperation(2114)
Trace: CSftpConnectOpData::Reset(2114) in state 3
Error: Could not connect to server
当我使用其他路由器、通过手机进行网络共享,或者在我的Fritzbox 7530AX路由器上将设备设置为“暴露主机”时,连接都正常。所以我很确定是我的路由器导致了这个问题(也许是固件更新导致的?!)
在这些工作场景下使用 Wireshark 进一步调查后,我注意到服务器的响应来自一个与我初始请求不同的端口(该端口似乎是在某个范围内随机的)。由于存在潜在的安全风险,我不想转发此范围内的所有端口。
所以,我的问题是:
- 如何在不暴露大量端口或恢复到旧路由器固件的情况下解决此问题?
- 更笼统地说,SFTP 响应怎么可能到达与请求不同的端口?路由器需要做什么才能实现这一点?我的工作方法只是转发所有流量吗?这似乎不对,但如果不对,服务器响应是如何传递到我的电脑的?
任何有助于理解路由器/网络方面以及可能的 Fritzbox 解决方案的帮助都将不胜感激!
仔细检查你的防火墙规则。升级到较新的固件。考虑到新固件可能只是引入了一个错误或其他一些非预期的更改。
实际上所有 TCP 连接都是这样工作的(几乎所有 UDP 流也是如此)。
如果你仔细观察Wireshark,你会发现每个数据包都有两个端口:源端口和目标端口(或者从不同的角度来看,本地/远程端口,或客户端/服务器端口)。客户端端口是随机选择的,而服务器端端口则是你已知的静态端口“22”、“80”或“443”。
由于其中一个端口通常是随机分配的,因此(本地,远程)端口对就像一个唯一的连接 ID,允许相同 IP 之间的多个连接工作。
没什么特别的。如果路由器进行 SNAT 伪装和/或“状态防火墙”出站流量过滤(家用路由器通常如此),则必须跟踪每个 TCP 连接,以便能够相应地转发入站响应,但默认情况下,这是SNAT 和/或防火墙功能的一部分。通常这两个功能共享同一张状态表。
(此外,这也是唯一客户端端口发挥作用的地方——实际上,它充当唯一的连接 ID。)
唯一需要特殊处理的是像传统 FTP 这样的协议(路由器必须监听“控制”流量,以便为入站“数据”连接预先建立防火墙/NAT 状态),或者基于 UDP 的 TFTP(在握手过程中将两个端口都切换为唯一端口)。SSH/SFTP 则不需要特殊处理,因为它们只是普通的单个 TCP 连接,与 HTTPS 网页浏览流量并无二致。
因此,如果出站 HTTP(S) 有效,但出站 SSH/SFTP 无效,那么要么是路由器固件问题,要么可能是您配置了某些必须取消配置的功能 - 绝对不是某些需要启用的功能。
“工作”路由器正在转发与 NAT/防火墙状态表中的条目匹配的所有流量(并使用该条目的信息将这些数据包 DNAT 到正确的内部地址)。
例如,运行以下命令
conntrack -L
查看 Linux 系统的 iptables/nftables 状态表。(特别是如果您有 Docker 或 Libvirt 之类的系统,并且系统会像路由器一样设置 NAT,那么 conntrack 表就会显示用于此匹配的入站“回复”字段。)