2 FTP模式

FTP具有两个端口,分别为控制端口(完成诸如登录,目录查询/切换等命令),数据端口(负责具体数据传输).

CentOS上安装vsftpd后,启动服务可发现vsftpd在21端口上监听命令(此时无客户端接入),具体如下图所示:

FTP连接模式具有两种,分别为主动模式(PORT)以及被动模式(PASV)。

主动模式:

(1)当FTP客户端以主动模式连接服务端时,客户端以动态选择的端口号向服务器的命令端口发起连接;

(2)连接建立后,用户在发出列目录或传输文件的命令后,会要求建立数据连接;

(3)FTP客户端在控制连接上发出主动模式指令,告知服务器客户端的数据连接端口号;

(4)服务端收到指令后,会使用20号端口连接客户端指定的数据连接端口号,从而建立数据连接。

被动模式:

被动模式的连接过程与主动模式类似,区别点在于客户端发出列目录或传输文件的命令后,客户端会发送PASV指令至服务端;

服务端收到PASV指令后,告知客户端服务端的数据连接IP地址和端口号;

客户端根据返回的服务端数据连接IP和端口号,发起数据连接。

3 问题 & 解决思路

当前,客户端需要通过Nginx代理方能访问FTP服务端。通过Nginx stream可以实现控制命令的转发,但是对于客户端和服务端协商的数据连接,较难实现代理。

不过查阅相关文档,vsftpd支持设置数据连接的端口范围,亦支持设置数据连接的IP。

因此,我们可以指定vsftpd模式为被动模式(默认即为被动模式),设置数据连接IP地址为Nginx代理地址,合理设置数据连接端口范围(Nginx监听本地此端口范围内数据)。当ftp客户端与vsftpd服务端协商数据连接后,ftp客户端根据数据连接IP(已设置为Nginx代理地址)以及端口号发起连接(实际连接至Nginx服务器),Nginx将此端口上监听的数据转发至vsftpd对应的数据端口。

4 方案示例

机器信息:

  • Nginx代理机: 192.168.56.101;
  • vsftpd服务端: 192.168.56.102;
  • 测试机: 192.168.56.106。
  • 此处,利用开发机上安装的虚拟机完成验证,未具体限制网段。

    vsftpd服务端配置:

    # cat /etc/vsftpd/vsftpd.conf
    listen=YES
    listen_ipv6=NO                  # 修改listen配置,只允许监听在IPv4地址,这是因为在被动模式下,设置pasv_address存在bug(具体可搜索stackoverflow)
    pasv_enable=YES                 # 开启pasv模式
    pasv_min_port=50000             # pasv模式下,数据连接最小端口号
    pasv_max_port=50002             # pasv模式下,数据连接最大端口号
    pasv_address=192.168.56.101     # pasv模式下,告知客户端的数据连接IP
    pasv_promiscuous=YES            # 关闭pasv模式下,关闭对IP地址的检查,此检查确保控制连接和数据连接来自同一IP
    

    pasv_promiscuous关闭存在安全隐患;
    在实际组网情况下,Nginx转发时可设置保留源IP信息,但是客户端与服务端无法直接访问,因此只能放弃保留源IP信息。

    Nginx配置:

    stream {
            upstream ftp {  # FTP控制面转发
                    server 192.168.56.102:21 max_fails=2 fail_timeout=3s weight=1;
            server {    # 转发FTP控制面请求
                    listen 11000;   #监听端口
                    #失败重试
                    proxy_next_upstream on;
                    proxy_next_upstream_timeout 0;
                    proxy_next_upstream_tries 0;
                    #超时配置
                    proxy_connect_timeout 1s;
                    proxy_timeout 10m;
                    #限速配置
                    proxy_upload_rate 1024k;
                    proxy_download_rate 2048k;
                    #上游服务器
                    proxy_pass ftp;
            upstream ftp_pasv1 {    
                    server 192.168.56.102:50000 max_fails=2 fail_timeout=3s weight=1;
            upstream ftp_pasv2 {    
                    server 192.168.56.102:50001 max_fails=2 fail_timeout=3s weight=1;
            upstream ftp_pasv3 {    
                    server 192.168.56.102:50002 max_fails=2 fail_timeout=3s weight=1;
            server {                # 转发客户端发送到Nginx代理机的数据连接
                    listen 50000;
                    proxy_pass ftp_pasv1;
            server {                # 转发客户端发送到Nginx代理机的数据连接
                    listen 50001;
                    proxy_pass ftp_pasv2;
            server {                # 转发客户端发送到Nginx代理机的数据连接
                    listen 50002;
                    proxy_pass ftp_pasv3;
    

    此处省略对FTP数据连接的具体控制(诸如限速)。

    重启vsftpd以及Nginx,从测试机:192.168.56.103发起连接,具体如下所示:

    tcpdump抓包分析:

    使用Nginx代理FTP服务,存在以下缺点:

  • 控制连接和数据连接是否来自同一连接无法验证,存在安全隐患;
  • FTP被动模式下,数据端口范围较宽时,Nginx添加配置比较麻烦;
  • Nginx代理机需要开放较多端口,诸如iptables等安全设置复杂。
  • 使用SFTP,简单又可靠。