內網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是沒用的,只有用掛載磁盤的超級管理員賦權限才可以。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM