内网VSFTP服务器的搭建

  一、背景

    公司的一个产品需要提供上传功能,http不能满足上传速度需求,于是改用FTP上传。

  二、安装与配置

    1.安装命令:

        yum install vsftpd,安装完成后service vsftpd restart启动vsftp。

    2.配置:

    1).vsftp配置

      /etc/vsftpd/vsftpd.conf ,vsftp的主要配置文件,配置文件的全部我就不贴出来了,这里有详细的说明,我只说几个需要修改的参数:

        

        anonymous_enable=NO,是否允许匿名登录,因为我们有账号权限控制,所以不能允许匿名登录



        chroot_local_user=YES  



              chroot_list_enable=YES  



         chroot_list_file=/etc/vsftpd/chroot_list  这三个设置后不在chroot_list中的不给其浏览上层目录的权限。



         userlist_deny=NO



             userlist_file=/etc/vsftpd/user_list 上面两个参数化设置后,效果是只允许user_list中的用户登录

  

      我们知道FTP默认监听的通信端口为21,数据端口为20,但是,网上基本每时每刻都有人在扫这些常用端口,我就有一次在Window上搭建FTP,当时是测试一个功能,没有对配置文件做过多的更改,刚开了一个小时就被软件扫到了,在我网站根目录放了一个jsp文件,我自己调用了下,吓了一身冷汗,服务器目录信息基本都显示出来了,为了防止被这些“黑客”的软件扫到,还是自己设置一个端口吧。

        listen_port=8021   通信端口

        ftp_data_port=8020 数据端口

        pasv_enable=YES  被动模式开启

        pasv_addr_resolve=YES  被动模式是否用设置好的的地址返回给客户端,如果是NO,则从链接的套接字中自己获取地址,如果为YES,则设置为下面这个地址

        pasv_address=222.185.xxx.xxx  被动模式下返回的地址,安全需要,隐掉后面两个地址段

        pasv_min_port=10001   pasv模式下数据端口的下界

        pasv_max_port=10010  pasv模式下数据端口的上界

        local_max_rate=200000 用户传输速度限制,单位为bytes/second,0表示不限制

 

      service vsftpd restart ,重启生效

      2).防火墙配置

     在/etc/sysconfig/iptables中添加vsftp用到的端口

       

        -A INPUT -m state --state NEW -m tcp -p tcp --dport 8021 -j ACCEPT

        -A INPUT -m state --state NEW -m tcp -p tcp --dport 8020 -j ACCEPT

        -A INPUT -m state --state NEW -m tcp -p tcp --dport 10000:10010 -j ACCEPT

 

      service iptables restart ,重启生效

      3).添加VSFTP用户,且禁止用户用SSH登陆

      

      #adduser -d /home/ftp/bruce -g ftp -s /sbin/nologin bruce  新建vsftp用户,/home/ftp/bruce为此用户主目录(可自己随意设置),-g ftp此用户为ftp组员,/sbin/nologin 禁止此用户登录,bruce->用户名(可自己随意设置)



       #passwd bruce  为bruce设置密码



      最后用chmod命令给用户主目录赋予权限
          chmod 755 /home/ftp/bruce

 

 

  到此为止,我们的vsftp服务器的搭建完成了一半,下面是硬件的配置和客户端的编写。

    三、端口映射和客户端编写

    1.端口映射

      这个问题至关重要,也是整个服务器搭建过程中,困扰我最多的地方。在第二部配置完成和客户端编写完成后,我尝试着连接并查询目录中文件列表,客户端总是返回Connectiontimeout,从vsftp配置到程序检查了多遍,都是只能连接不能获取数据,后来我用抓包工具抓包,发现了问题所在,下面是程序错误的时候抓到的包:

        

 

1.[2013/4/27 星期六 16:04:13:129]

   220 (vsFTPd 2.2.2)





2.[2013/4/27 星期六 16:04:13:130]

   USER bruce





3.[2013/4/27 星期六 16:04:13:133]

   331 Please specify the password.





4.[2013/4/27 星期六 16:04:13:133]

   PASS bruce,2013





5.[2013/4/27 星期六 16:04:28:208]

   230 Login successful.





6.[2013/4/27 星期六 16:04:28:209]

   TYPE I





7.[2013/4/27 星期六 16:04:28:211]

   200 Switching to Binary mode.





8.[2013/4/27 星期六 16:04:28:247]

   PASV





9.[2013/4/27 星期六 16:04:28:249]

  227 Entering Passive Mode (192.168.1.122,39,16).



500 OOPS: vsf_sysutil_recv_peek: no data

500 OOPS: child died

   跑到第9步的时候卡住一会,接着报错java.net.ConnectException: Connection timed out: connect,出现上面最后两行500错误。第一反应就是返回的IP错了,因为我映射了外网端口,这里返回客户端的却是一个内网地址,于是加上上面提到过的参数

        

        pasv_addr_resolve=YES  被动模式是否用设置好的的地址返回给客户端,如果是NO,则从链接的套接字中自己获取地址,如果为YES,则设置为下面这个地址

        pasv_address=222.185.xxx.xxx  被动模式下返回的地址,安全需要,隐掉后面两个地址段

  再跑的时候返回的就对了,

      

227 Entering Passive Mode (222,185,xxx,xxx,39,24).

注解:括号里39,24表示连接的端口号,算法为:39*256+24=10008,端口落在vsftp.conf配置文件的上界和下界之间,说明端口设置生效了。可是,问题依然存在,看来不是IP地址这么简单的事情。那就只剩下端口号了,回去重新学习了FTP的两种工作方式:

    

主动FTP:



命令连接:客户端 >1024端口 -> 服务器 21端口(我们这里是8081,外网映射为15321)



数据连接:客户端 >1024端口 <- 服务器 20端口(我们这里是8020,外网映射为15320)



被动FTP(防止服务器主动去连的端口在防火墙后面,连接不上): 命令连接:客户端大于1024的端口 -> 服务器 21端口 (我们这里是8081,外网映射为15321)
数据连接:客户端大于1024的端口 -> 服务器上大于1024的端口(我们限定为10001-10010)

实际情况是,当时在公网对内网端口映射的时候,只映射了8021和8020两个端口,并没有映射vsftp.conf配置文件中的10001-10010,于是跟IT管理部门申请,映射了这10个端口,10001->10010这样严格映射,再执行客户端程序:

[2013/4/27 星期六 16:04:17:114]

220 (vsFTPd 2.2.2)



[2013/4/27 星期六 16:04:17:116]

USER bruce



[2013/4/27 星期六 16:04:17:118]

331 Please specify the password.



[2013/4/27 星期六 16:04:17:119]

PASS bruce,2013



[2013/4/27 星期六 16:04:32:203]

230 Login successful.



[2013/4/27 星期六 16:04:32:203]

TYPE I



[2013/4/27 星期六 16:04:32:206]

200 Switching to Binary mode.



[2013/4/27 星期六 16:04:32:236]

PASV



[2013/4/27 星期六 16:04:32:238]

227 Entering Passive Mode (222,185,xxx,xxx,39,24).



[2013/4/27 星期六 16:04:32:241]

LIST /



[2013/4/27 星期六 16:04:32:243]

150 Here comes the directory listing.

226 Directory send OK.

搞定!!

      2.客户端程序

      

import java.io.IOException;

import java.net.SocketException;



import org.apache.commons.net.ftp.FTP;

import org.apache.commons.net.ftp.FTPClient;

import org.apache.commons.net.ftp.FTPClientConfig;

import org.apache.commons.net.ftp.FTPFile;

import org.apache.commons.net.ftp.FTPReply;





public class FTPTools {

    private FTPClient ftp=new FTPClient();

    /**

     * 连接ftp的方法

     * @param hostname 公网IP

     * @param port  公网端口

     * @param username  ftp用户名

     * @param password  ftp密码

     * @return

     */

    public boolean  connect(String hostname,int port,String username,String password){

        try {

            FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);

            conf.setServerLanguageCode("zh");

            ftp.configure(conf);

            ftp.setControlEncoding("GBK");//避免中文文件名乱码

            ftp.setConnectTimeout(150000);

            ftp.enterLocalPassiveMode();

            ftp.connect(hostname, port);

            int code=ftp.getReplyCode();

            if(FTPReply.isPositiveCompletion(code)){

                if(ftp.login(username, password)){

                    ftp.enterLocalPassiveMode();//切换成pasv被动模式

                    ftp.setFileType(FTP.BINARY_FILE_TYPE);//必须要,设置为2进制传输

                    ftp.setDataTimeout(60000);

                    ftp.setSoTimeout(120000);

                    FTPFile[] files = ftp.listFiles("/");

                    System.out.println(files.length);

                    for(FTPFile file:files){

                        System.out.println(file.getName());

                    }

                    return true;

                }

            }

            

        } catch (SocketException e) {

            e.printStackTrace();

            try {

                ftp.disconnect();

            } catch (IOException e1) {

                e1.printStackTrace();

            }

        } catch (IOException e) {

            e.printStackTrace();

            try {

                ftp.disconnect();

            } catch (IOException e1) {

                e1.printStackTrace();

            }

        }

        try {

            ftp.disconnect();

        } catch (IOException e) {

            e.printStackTrace();

        }

        return false;

        

    }

    public static void main(String[] args) {

        new FTPTools().connect("222.185.xxx.xxx", 15321, "bruce", "bruce,2013");

        

    }

    

}

 

好了,vsftp服务器的搭建就写到这里,客户端代码只放出了简单的连接测试代码,后面随着项目的推进,会把上传、下载、断点续传以及遇到的其它问题解决方法分享给大家,希望能够帮助到刚接触vsftp或者在这上面遇到问题的同学们。

 PS:后来发生个小插曲,我把目录指向到服务器挂载的磁盘阵列上面,能下载,但是死活传不上去,权限也赋了。后来知道了,在挂载机器上面给ftp用户chmod 777是没用的,只有用挂载磁盘的超级管理员赋权限才可以。

 

 

你可能感兴趣的:(vsftp)