我在一台服务器上使用 Perl 脚本,该脚本计划定期使用 FTP 从另一台服务器下载一些文件。不幸的是,Perl FTP 模块中存在一些问题,导致脚本不时失败并意外终止。我发现可以通过从被动模式切换到主动模式轻松解决此问题。
如果我正确理解了这两种 FTP 模式之间的区别,那么使用主动模式就意味着我需要在防火墙内打开某个端口范围。我推测这会带来一些安全风险。所以我的问题是,是否有一些解决方法或好的做法,以便我可以在我的服务器上使用主动模式,而不会造成任何额外的风险。
答案1
简而言之:
- FTP 连接由两个流组成:命令(控制)流和数据流
- 当打开套接字且代码未明确绑定到端口时,操作系统将使用其临时端口范围中的高编号端口(
sysctl -a | grep ip_local_port_range
) - 非 root 进程必须使用 >1024 的端口
主动模式FTP
客户端通过端口 21 连接到服务器并建立命令流:
client:32198 -> server:21
客户端必须发送或接收一些数据,因此它通知服务器在某个端口上重新连接它。为此,它发送类似于以下内容的 PORT 命令:
PORT 1,2,3,4,5,6
这是客户端通知服务器,服务器可以重新连接客户端(地址 1.2.3.4,端口 (5 * 256) + 6 = 1286)。
server:20 -> client:1286
通常,您会看到主动模式 FTP 会话终止;对于防火墙和负载平衡器,通常预计从客户端 -> 服务器流出的流量,但服务器发起到客户端的连接通常会被拒绝(负载平衡器通常足够智能,可以将此数据流与现有命令流关联起来)。
您对需要在防火墙上打开端口范围以促进此行为的理解是完全正确的。
被动模式 FTP
在这种情况下,客户端像以前一样建立命令会话:
client:56221 -> server:21
但是当数据被传送时,客户端会发送一个PASV
命令原语。服务器会以客户端应该连接的 IP:Port 组合进行响应(格式与PORT
之前的请求类似)。因此,客户端随后会按如下方式连接到服务器:
client:12347 -> server:4566
由于连接是以传统和预期的方式建立的,因此这可以绕过上面描述的主动模式的防火墙问题。
被动模式的缺点是它会占用服务器上的更多套接字。PASV
在负载很重的环境中频繁发出原语最终可能会导致端口耗尽。(套接字将停留在某个TIME_WAIT
状态一段时间(我认为在 Redhat 系统上大约 2 分钟)。
关于你的问题
除非您真的遇到了端口耗尽问题,否则被动模式失败而主动模式成功的情况非常罕见。通常情况恰恰相反。如果您能够发布有关您偶尔收到的错误的更多信息,我们可以进一步调试。
我建议尽可能使用被动模式,因此我建议在同意使用主动模式 FTP 之前,先查看被动模式特定的故障以找到问题的根本原因。
答案2
在主动模式下,客户端通过端口 21 连接到服务器以建立控制通道,然后当下载开始时,客户端开始在具有 1024 以上的随机端口号的套接字上监听服务器的连接。
为了允许主动模式 FTP,客户端的防火墙需要允许端口 1024 以上的所有传入流量,这破坏了防火墙的用途。
被动模式意味着服务器监听20端口,客户端发起连接。
您应该始终使用 FTP 的被动模式。或者更好的是,不要使用 FTP。如果您正在下载文件,最好使用 HTTP。如果您需要上传文件,仍然使用 HTTP(或其他协议,如 scp)。
答案3
这个问题与 Perl 本身无关。而且,设置主动 FTP 连接而不是被动连接的解决方案正是证明。
实际上,上述问题会在尝试列出 FTP 目录内容时发生,而不是在连接或上传/下载时发生。因此,问题与防火墙有关。
您必须检查您的防火墙是否允许被动 FTP 连接通过,请阅读上面对 loopforever 的出色描述。
如果使用基于 Linux 的防火墙,则要注意卸载 nf_conntrack_ftp 内存。