VSFTPD與iptables NAT的設置詳解(申精)
FTP協議的特點就是數據流埠與控制流埠分離,這使得管理員在設置防火牆規則時,需要多考慮一些因素.同時由於FTP伺服器本身的重要性和不安全性,許多管理員想將其置於防火牆機器后,這樣一來就更麻煩了.通常是客戶端能登錄上伺服器,但無法列出目錄,無法傳輸數據等等,讓許多新手管理員摸不清頭腦,到論壇里撒分「跪求」解決辦法.其實這並不是想像的那麼難,看了本文後,你將明白這一切.
第一部分.理解FTP的主動模式與被動模式
網上關於FTP傳輸的主被動模式的講解已很多。要想讓客戶機與伺服器之間暢通無阻的傳輸數據,必須首先理解它們的傳輸原理,這樣我們遇到問題時才可以對症下藥.我們通過抓包分析來理解其轉輸過程.
主動模式(Port模式)
主動模式的傳輸數據流程如下(伺服器ip:192.168.200.1,客戶端ip:192.168.200.8):
1..192.168.200.8.55722 > 192.168.200.1.ftp: PORT 192,168,200,8,178,210
2..192.168.200.1.ftp > 192.168.200.8.55722: 200 PORT command successful. Consider using PASV.
3..192.168.200.8.55722 > 192.168.200.1.ftp: ......ACK
4..192.168.200.8.55722 > 192.168.200.1.ftp: LIST
5..192.168.200.1.ftp-data > 192.168.200.8.45778:......SYN
6..192.168.200.8.45778 > 192.168.200.1.ftp-data: ......SYN.ACK
7..192.168.200.1.ftp-data > 192.168.200.8.45778: ......ACK
8..192.168.200.1.ftp > 192.168.200.8.55722: 150 Here comes the directory listing.
9..192.168.200.1.ftp-data > 192.168.200.8.45778:
-rw-r--r-- 1 0 0 6 Mar 23 08:53 filetest
drwxr-xr-x 2 0 0 4096 Dec 13 2007 pub
從上面的數據得出主動模式的傳輸過程如下:
A.(第1行)客戶端向伺服器申請PORT模式的數據傳輸,並通過PORT命令告知伺服器"我的IP是192.168.200.8,我開放埠45778等你".
(45778是通過PORT命令后的最後兩個數字算出來的.178*256 + 210 = 45778)
B.(第2行)伺服器在檢查所收到的PORT命令的語法和安全性等因素后,向客戶端告知PORT命令成功,並同時建議客戶端考慮使用PASV.
(PASV就是我們接下來要講的被動模式)
C.(第3行)客戶端確認收到從伺服器傳來的信息並應答.
D.(第4行)客戶端向伺服器申請列出目錄信息的數據.
E.(第5,6,7行)伺服器收到客戶端的申請后,主動用自己的20埠去連接客戶端的45778埠,以便傳送數據.
(注意:這是重要的地方,所謂主動模式,就是指伺服器從自己的數據埠主動去連接客戶端)
F.(第8行)當伺服器與客戶端的數據流埠成功連接后,伺服器便通過控制埠21向客戶發送信息:你需要的目錄列表傳來了.
G.(第9行)伺服器通過數據流埠,將用戶所需要的目錄數據信息發向客戶端.
在整個通信過程中,伺服器僅用了兩個固定的低端埠,即控制埠21(ftp)和數據埠20(ftp-data),防火牆規則很好設置,只需放開這兩個埠就行.而客戶端就沒那麼幸運了,動態的開放了一個高端埠等待連接,這讓處於區域網內部,通過共享同一IP上網的用戶而言基本沒轍.但是,有其它的解決辦法么?有!就是我們接下來要談到的被動模式.
被動模式(Passive模式)
被動模式的傳輸數據流程如下(伺服器ip:192.168.200.1,客戶端ip:192.168.200.8):
1..192.168.200.8.40137 > 192.168.200.1.ftp: PASV
2..192.168.200.1.ftp > 192.168.200.8.40137: Entering Passive Mode (192,168,200,1,11,187)
3..192.168.200.8.40137 > 192.168.200.1.ftp: ......ACK
4..192.168.200.8.43422 > 192.168.200.1.3003: ......SYN
5..192.168.200.1.3003 > 192.168.200.8.43422: ......SYN.ACK
6..192.168.200.8.43422 > 192.168.200.1.3003: ......ACK
7..192.168.200.8.40137 > 192.168.200.1.ftp: LIST
8..192.168.200.1.ftp > 192.168.200.8.40137: 150 Here comes the directory listing.
9..192.168.200.1.3003 > 192.168.200.8.43422:
-rw-r--r-- 1 0 0 6 Mar 23 08:53 filetest
drwxr-xr-x 2 0 0 4096 Dec 13 2007 pub
從上面的數據得出主動模式的傳輸教程如下:
A.(第1行)客戶端向伺服器申請PASV模式的數據傳輸.
B.(第2行)伺服器新開放一個數據流埠,進入監聽模式.並告訴客戶"你連接192.168.200.1吧,我開放了3003埠等你呢".
(3003埠是通過第2行最後兩個數字計算出來的,11*256 + 187 = 3003)
C.(第3行)客戶端確認收到從伺服器傳來的信息並應答.
D.(第4,5,6行)當客戶端獲知伺服器已新開了一個數據流埠讓自己去連接后,便從本地隨機選擇一個埠去連接伺服器指定的埠,以便傳送數據.
(注意:這是重要的地方,與主動模式不一樣,伺服器不會去主動連接客戶端,而是新開一個埠,被動的等客戶端來連接,這就是所謂的被動模式)
E.(第7行)當客戶端與伺服器的數據流埠成功連接后,客戶端便向伺服器申請列出目錄信息的數據.
F.(第8行)伺服器便通過控制埠21向客戶發送信息:你需要的目錄列表傳來了.
G.(第9行)伺服器通過數據流埠,將用戶所需要的目錄數據信息發向客戶端.
在整個通信過程中,客戶端都是主動去連接伺服器,並沒有開放埠被連接,這確實為客戶端的防火牆減輕了不少麻煩.但麻煩消失了么?沒有!被動模式只是把麻煩"移"到了伺服器上而已,伺服器則需要動態的開一個高端埠來傳輸數據,怎樣處理這個埠是我們面臨著的困難.不過不用怕,天才的程序員們為我們想好了一切,我們只需要按我們的要求設置參數就行.接下來讓我們分析各種可能存在的情況.
第二部分.伺服器相關設置實戰
(注:本文所有例子均採用RHEL5+VSFTPD伺服器,且默認客戶端無防火牆.)
機器布局如下:
|客戶機|:::::::::::::::::|LINUX網關|------|VSFTPD伺服器|
客戶機的IP: 10.10.10.10/8
LINUX網關IP: 10.10.10.20/8, 192.168.1.1
VSFTPD伺服器IP: 192.168.1.8/24
1.配置VSFTPD伺服器,配置文件如下:
listen=yes
anonymous_enable=yes
port_enable=yes
connect_from_port_20=yes
pasv_enable=yes
pasv_min_port=10000
pasv_max_port=10100
這是一個簡單的VSFTPD配置,第一部分允許匿名用戶訪問,第二部分聲明允許主動模式,第三部分聲明允許被動模式,並把伺服器開放的被動連接的埠限制在10000-10100範圍以內,以便我們設置相應的防火牆規則.我在內網測試了,可以正常使用,更詳細的VSFTPD配置可查看man文檔或訪問http://blog.chinaunix.net/u3/94705/showart_1917230.html.
2.網關設置
首先開啟轉發功能.
#echo 1 > /proc/sys/net/ipv4/ip_forward
再設置相關NAT規則.
#iptables -t nat -A POSTROUTING -p tcp -s 192.168.1.8 --sport 20:21 -j SNAT --to 10.10.10.20
#iptables -t nat -A POSTROUTING -p tcp -s 192.168.1.8 --sport 10000:10100 -j SNAT --to 10.10.10.20
#iptables -t nat -A PREROUTING -p tcp -d 10.10.10.20 --dport 21 -j DNAT --to-destination 192.168.1.8
#iptables -t nat -A PREROUTING -p tcp -d 10.10.10.20 --dport 10000:10100 -j DNAT --to-destination 192.168.1.8
前兩條規則把內網的FTP伺服器的相關埠的數據轉發出去.
后兩條規則把外網對網關的相關埠的數據轉發給FTP伺服器.
3.客戶端登錄測試
登錄10.10.10.10,測試結果如下:
# ftp 10.10.10.20
Connected to 10.10.10.20 (10.10.10.20).
220 (vsFTPd 2.0.5)
Name (10.10.10.20:root): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> passive //關掉被動模式,我們先測試主動模式.
Passive mode off.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
-rw-r--r-- 1 0 0 13 May 06 20:24 filetest
drwxr-xr-x 2 0 0 4096 Dec 13 2007 pub
226 Directory send OK.
(到此,我們發現主動模式是配置無誤了,可以成功連接.可是在上部分我們說過,主動模式的可應用性不高,接著我們再測試一下被動模式)
ftp> passive
Passive mode on.
ftp> ls
227 Entering Passive Mode (192,168,1,8,39,109)
ftp: connect: Connection timed out
當我輸入ls命令后,系統返回了一條信息"227 Entering Passive Mode (192,168,1,8,39,109)".接著我等啊等,等來的是不幸的消息,系統提醒我連接超時了.
這是怎麼回事兒?回過頭去看看第一部分被動模式傳輸過程就知道了,原來我們是"第D步"失敗了!
當然會失敗啊!伺服器告訴我們,可以去連接192.168.1.8的39*256+109=10093埠以便傳輸數據,可是192.168.1.8對客戶端10.10.10.10來說是不可見的,它在10.10.10.20後面躲貓貓呢.
此時,我們的解決辦法有兩個.其一,截獲伺服器傳向客戶端的數據(被動模式傳輸過程的第B步),修改相關數據,以欺騙客戶端讓它連接伺服器的網關10.10.10.20,因為伺服器192.168.1.8在10.10.10.20背後,對客戶端來說是不可見的.其二,由伺服器親自出面發布"假"信息欺騙客戶端,達到同樣的效果.
這兩種解決辦法都很好實現,關於第一種,我們在網關伺服器上載入兩個模塊,以截獲並修改數據.登錄10.10.10.20操作如下:
#modprobe ip_nat_ftp
#modprobe ip_conntrack_ftp
然後我們再在客戶端上測試.
ftp> ls
227 Entering Passive Mode (10,10,10,20,39,108)
150 Here comes the directory listing.
-rw-r--r-- 1 0 0 13 May 06 20:24 filetest
drwxr-xr-x 2 0 0 4096 Dec 13 2007 pub
226 Directory send OK.
怎麼樣,一次性就成功了吧.我們看到第二行的信息,ip已被修改成10.10.10.20,客戶端在收到這信息后,就會去連接10.10.10.20,然後經過10.10.10.20的轉發,於是我們理所當然的成功了.
再看看第二種解決辦法,我們怎樣讓伺服器出面發布"假"消息去欺騙客戶端呢?vsftp的作者早想到這點了,我們只需要在vsftpd的配置文件中加入如下兩行即可.
pasv_addr_resolve=yes //允許vsftpd去欺騙客戶
pasv_address=10.10.10.20 //讓vsftpd以這個地址去欺騙客戶
重啟vsftpd后,我們再從客戶端測試發現也可以正常使用.
4.如果使用了xinetd的redirect怎麼辦?
就在我以為這篇挫文完成了的時候,一個朋友在QQ群里尋求幫助,他的情況是沒有使用NAT,而是使用了xined的redirect(重定向)功能,始終沒有調試成功.他在網關上做了如下的事情.
A.打開轉發功能
#echo 1 > /proc/sys/net/ipv4/ip_forward
B.添加了/etc/xinetd.d/vsftpd文件,內容如下:
service ftp
{
disable = no
wait = no
socket_type = stream
user = root
log_on_failure += USERID
log_on_success += PID HOST EXIT
bind = 10.10.10.20
redirect = 192.168.1.8 21
}
並啟動xinetd監聽相應的埠.
C.然後在客戶端測試.
# ftp 10.10.10.20
Connected to 10.10.10.20 (10.10.10.20).
220 (vsFTPd 2.0.5)
Name (10.10.10.20:root): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> passive
Passive mode off.
ftp> ls
500 Illegal PORT command.
ftp: bind: Address already in use
ftp> passive
Passive mode on.
ftp> ls
227 Entering Passive Mode (192,168,1,8,39,65)
ftp: connect: Connection timed out
正如你所看到的那樣,客戶端能成功連接到伺服器,可是當想從伺服器列出數據的時候,無論主動模式還是被動模式都失敗了.這是正常的,我們只用xinetd重定向了21埠,卻沒有對可能要開啟的數據埠做仍何操作,所以,我們還得藉助NAT把數據埠的事兒搞定.登錄10.10.10.20,執行如下操作
#iptables -t nat -A POSTROUTING -p tcp -s 192.168.1.8 --sport 20 -j SNAT --to 10.10.10.20
#iptables -t nat -A POSTROUTING -p tcp -s 192.168.1.8 --sport 10000:10100 -j SNAT --to 10.10.10.20
#iptables -t nat -A PREROUTING -p tcp -d 10.10.10.20 --dport 10000:10100 -j DNAT --to-destination 192.168.1.8
再登錄客戶端連接測試.鬱悶,與先前的測試一樣,不論是主動模式還是被動模式,都失敗.
控制埠能連接上,數據埠按我們設置的規則也能連接上,可為什麼還是失敗?難道xinetd的redirect有什麼特殊的地方,上網關伺服器一看,還真是有特殊的情況.
在10.10.10.20上執行netstat -antup,顯示結果如下:
tcp 0 0 10.10.10.20:21 10.10.10.10:43039 ESTABLISHED 2303/xinetd
tcp 0 0 192.168.1.1:45459 192.168.1.8:21 ESTABLISHED 2303/xinetd
原來xinetd的轉發機制是:先開啟21埠讓客戶機連接,自己再開啟一個埠去連接內部網路的FTP伺服器,然後自己做中間人,中轉數據.
如果這樣的話,vsftpd伺服器會"發現"是192.168.1.1(網關伺服器的內網ip)在與它連接併發送控制指令的,這在接下來進行數據傳輸的時候會遇到困難,請看第一部分主動模式傳輸過程的第B步.客戶端通過網關xinetd模式向伺服器轉達的PORT命令,通不過vsftpd的安全性檢查,因為vsftpd伺服器只知道192.168.1.1在與它連接.就好像張三給你說,你把這份重要的數據給李四送去吧,這可是十分不安全的啊,vsftpd伺服器號稱最安全的FTP伺服器,可不是那麼"笨"的.不過我們可以將它變"笨",只需給它加個參數,讓它不檢查安全性即可.
我們在vsftpd的配置文件中加上如下一行:
port_promiscuous=yes
重啟vsftpd伺服器,接著在客戶端測試:
ftp> passive
Passive mode off.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
-rw-r--r-- 1 0 0 13 May 06 20:24 filetest
drwxr-xr-x 2 0 0 4096 Dec 13 2007 pub
主動模式測試成功,可被動模式還是不行,原因上一小節已經講了.由於xinetd的redirect機制與NAT沒關係,先前的第一種通過截獲數據並修改數據包的做法行不通了,只得改改伺服器的參數,讓伺服器去忽悠客戶端吧.
同樣,在伺服器上加上這兩行參數:
pasv_addr_resolve=yes //允許vsftpd去欺騙客戶
pasv_address=10.10.10.20 //讓vsftpd以這個地址去欺騙客戶
重啟vsftpd伺服器,在客戶端用被動模式測試連接.
ftp> ls
227 Entering Passive Mode (10,10,10,20,39,21)
425 Security: Bad IP connecting.
崩潰了吧,仍然不能連接.看到Security這個提示信息,我們就明白了,仍然是vsftpd的安全選項在作怪.它正在與192.168.1.1交流著呢,突然來了一個10.10.10.10要來連接它,它當然不願意啦,前文已說過,號稱最安全的FTP伺服器,可不是那麼"笨"的.沒辦法,再次將它變笨吧.給它再設置一個參數,在vsftpd的配置文件中加上如下一行:
pasv_promiscuous=yes
再登錄客戶端測試一下,發現可以正常使用了,大功告成.
5.寫在最後
FTP是在70年代設計出來的,當時的互聯網是一個封閉的網路,與現代網路環境還是有很大的差異,現代網路中不管你使用Port模式還是Passive模式,都可能產生問題.看完本文後,希望你能有所收穫,如果發現本文有錯誤,請回復或者直接加我QQ(864235428)聯繫.同時我再說下,xinetd的redirect是一個很優秀的功能,但他不適合用來處理FTP,數據埠是動態的,它無能為力,還得需要iptables,相反,由於它需要建立兩個連接的這種機制,使得我們一再要更改vsftpd關於安全性的參數,確實有點兒得不償失,如果你看完我的建議,仍然堅持要使用它,那祝你好運.
歡迎訪問http://huabo2008.cublog.cn/
(原創文章,歡迎轉載,轉載請保留上面這行.)
《解決方案》
不錯,寫的很詳細。
支持原創。:mrgreen:
《解決方案》
/etc/xinetd.d/vsftpd
呀,你這是哪個版本的呀?
麻煩LZ說明操作系統版本及vsftpd版本。
謝謝。
《解決方案》
文中有這句話
注:本文所有例子均採用RHEL5+VSFTPD伺服器,且默認客戶端無防火牆.
還有那個文件是是自己新建的。
《解決方案》
哦,看到了,你不說我還真注意不到。
《解決方案》
寫得很詳細,支持原創