「ftp(1)」- ftp: connect: Connection refused(vsftpd)

问题描述

我们使用 vsFTPd 搭建 FTP 服务,以容器方式运行,并使用被动模式。

在连接 ftp 服务时,我们使用 ftp(1) 命令,但是出现 Connection refused 错误:

# ftp -4 -p ftp.example.com 21
Connected to ftp.example.com.
220 (vsFTPd 3.0.2)
Name (ftp.example.com:k4nz): ftp-read
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> dir
227 Entering Passive Mode (127,0,0,1,78,90).
ftp: connect: Connection refused
ftp> close
221 Goodbye.
ftp> quit

但是,Filezailla 客户端能够成功连接 FTP 服务。

原因分析

为了排查问题,我们在华为交换机上搭建 FTP 服务(只是为了快捷搭建 FTP 测试服务),以被动模式运行。此时,ftp(1) 命令能够成功访问 FTP 并下载文件。

通过 Wireshark 抓包,我们对比两个 FTP 交互过程。

我们发现在 vsFTPd 中,在 FTP Server 对 PASV 响应中,Passive port 是正常的,但是 Passive IP Address 字段为 127.0.0.1 地址。 这导致 ftp(1) 使用该地址时,无法连接到 FTP 服务。

而 Filezilla 能够成功连接 vsFTPd 服务,是因为 Filezilla 并未使用该字段,而直接使用远程 FTP Server 地址(这是客户端的特殊行为)。

而返回 127.0.0.1 地址,是因为我们错误的配置 pasv_address=127.0.0.1 地址,而 Filezilla 客户端的特殊行为,让我们没有测试出该错误。

解决方案

针对我们的环境,我们需要修改 vsftpd.conf 配置文件,设置 pasv_address=1.2.3.4 参数。这里 1.2.3.4 是服务器的公网地址。

我们是容器部署,如果为指定 pasv_address 参数,则默认会被 vsftpd 设置为网卡地址(容器网卡地址),所以必须显式指定。

参考文献

Manpage of VSFTPD.CONF
ftp – vsftpd conditional pasv_address (internal ip vs. external ip) – Unix & Linux Stack Exchange