今天登陆一个外网的FTP,网页能正常登陆及浏览,但dos窗口下却只能登陆上去,但输入ls命令却被拒绝了,可能是对端采用了NAT转换,主动模式登陆不进去,解决办法如下。 

230 Login successful.
ftp> ls
200 PORT command successful. Consider using PASV.
425 Failed to establish connection.

 

 關於 FTP

事實上﹐僅知道如何操作 iptables 工具﹐還不足以設定好您的防火牆及 NAT ﹐您還要對各種 TCP/IP 服務都要有相當程度的了才行﹕您必須知道一個連線的建立過程是怎樣的﹐每一個封包動作是怎樣從一端送到另一端的。您除了要知道每一個封包的來源和目的位址﹐還要知道它們的來源埠口和目的埠口。而且﹐我們不要忘記了﹕所有連線都是雙向的﹐您除了要照顧從客戶端到伺服器端的請求﹐也要照顧從伺服器到客戶端的回應。下面﹐讓我們看一看火牆的設定如何影響 FTP 的運作的( FTP 是一個非常經典的 NAT/Firewall 設定範例)。

首先﹐我們要知道 FTP 的連線模式有兩種﹕主動模式( active )和被動模式( passive )。要了解這兩個模式的不同﹐得要了解 FTP 的連線是怎樣建立的﹕

在正常模式下﹕

 

  1. FTP client 開啟一個隨機選擇的高於 1024 的 port 呼叫 FTP server 的 port 21請求連線。當順利完成 Three-Way Handshake 之後﹐連線就成功建立﹐但這僅是命令通道的建立。
  2. 當兩端需要傳送資料的時候﹐client 透過命令通道用一個 port 命令告訴 server ﹐客戶端可以用另一個高於 1024 的 port 做數據通道﹐並準備好 socket 資源。
  3. 然後 server 用 port 20 和剛才 client 所告知的 socket 建立數據連線。請注意﹕連線方向這是從 server 到 client 的﹐TCP 封包會有一個 SYN 旗標。
  4. 然後 client 會返回一個帶 ACK 旗標的確認封包﹐並完成另一次的 Three-Way Handshake 手續。這時候﹐數據通道才能成功建立。
  5. 開始數據傳送。

 

在 passive 模式下﹕

 

  1. FTP client 開啟一個隨機選擇的高於 1024 的 port 呼叫 FTP server 的 port 21請求連線﹐並完成命令通道的建立。
  2. 當兩端需要傳送資料的時候﹐client 透過命令通道送一個 PASV 命令給 server﹐要求進入 passive 傳輸模式。
  3. 然後 server 像上述的正常模式之第 2 步驟那樣﹐挑一個高於 1024 的 port ﹐並用命令通道告訴 client 關於 server 端用以做數據通道的 socket。
  4. 然後 client 用另一個高於 1024 的 port 呼叫剛才 server 告知的 scoekt 來建立數據通道。此時封包帶 SYN 標籤。
  5. server 確認後回應一個 ACK 封包。並完成所有交握手續﹑成功建立數據通道。
  6. 開始數據傳送。

 

我們都知道﹕火牆的保護對象是內部網路的 client 主機。防火牆為了擋掉一些來自外面的危險動作﹐通常會限制那些來自外面的主動連線﹐也就是帶 SYN 標籤的封包(請參考 Three-Way Handshake 的過程)。在這樣的情況下﹐iptables 或許有這樣的一個設定﹕

iptables -I INPUT -i ppp0 -p TCP --syn -j DROP 
iptables -I FORWARD -i ppp0 -p TCP ! --syn -j ACCEPT

在第二行中的那個 " ! " 就是 NOT 的意思﹐" ! --syn " 就是 NOT SYN 之意﹐也就是只允許非主動連線的 TCP 封包從外部界面進入﹐這和第一行的意思一樣﹕不接受來自外面主動建立的連線。

 

Tips﹕前面我們已經說過我們可以將傳到 NAT 外部界面的連線轉到 DMZ 裡面去。假如我們有這樣的要求﹐卻繼續沿用前面那行帶 " ! -y " 的規則的話﹐外面的客戶主機就無從建立連線來連接我們的服務主機了。但我們又不想取消它﹐以免危害到其它非 DMZ 的內部網路。

 

還記得 iptables 的行為習慣嗎﹕它會自上而下的對比規則﹐找到符合的就不再往下找了。根據這樣的特性﹐我們可以將 NAT 外部界面進入的某些連線﹐在那行 syn 過濾規則之前 ACCEPT 進來。不過﹐就要非常小心別漏了必要的限制元素﹐有可能的話﹐盡您想象把規則設得嚴密又嚴密吧。

 

假設我們這時候有一個在防火牆之後的 FTP client 要試圖連接外面的 FTP server 。在正常模式下﹐(第 3 步)來自 server 的數據通道之建立請求就會被擋下來﹐這會導致數據通道無從建立。雖然您可以 login 進遠端的 FTP 伺服器﹐但如果輸入 ls 後﹐卻看不到結果的。FTP 的 login 與 ls 是透過命令通道進行的﹐因為命令通道的建立並沒問題﹐所以 server 可以收到命令。但 ls 的結果確需要透過數據通道送回來﹐然而數據通道卻不能建立建立。所以 server 在傳送失敗後﹐再用命令通道告訴您﹕ “Can't build data connection: Connection refused.”

明白了﹖是否解釋了困繞您心目中以久的疑團呢﹖ ^_^

好了﹐如果用 Passive 模式又會如何呢﹖讓我們回去看看正常模式的第 3 步和 Passive 模式的第 4 步﹐然後檢查它們進出防火牆的方向﹐以及防火牆如何處理 SYN 封包就知道了。我不想直接把答案告訴您。自己要懂得思考﹐才會有進步﹗不是嗎﹖

 

Tips﹕不過﹐在 iptables 中有一個 RELATED 的 TCP 連線狀態標籤﹐可以讓 ftp-data 連線順利建立﹕

 

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

 

但是﹐我必須再指出﹕上面談的是基於一個 routing 健全的情形下。如果用 NAT 的話﹐封包的位址將會有所改變。無論用正常模式或 Passive 模式﹐server 都看不到 client 的位址﹐server只看到 NAT 的位址而已。故此﹐就算您取消了入站封包的 SYN 限制﹐在正常模式下來自 server 的數據通道連線﹐封包只會送到 NAT 主機的外面界面那裡。但問題是 NAT 並沒有該連線的 NAT 記錄﹐也就不會將修改封包 socket 將之送回裡面的客戶主機。除非﹐您能夠幫 client 端做 ftp-data 的 DNAT 。然而﹐因為 client 所使用的 ftp-data socket 是隨機挑選的一個大於 1024 的 port ﹐您事先沒辦法在 NAT 上知道 ftp client 用哪個 socket 的。然而﹐更重要的問題在於﹕client 在命令通道中所使用的 port 命令﹐其 IP 是原有的內部位址﹑而 NAT 根本不會將之修改過來﹗所以 server 在建立 ftp-data 連線的時候﹐根本就不可能路由到正確的位址﹗

那是否有辦法解決呢﹖當然有的啦~~ 使用 passive 模式就可以了﹗為什麼﹖不知道您的腦筋是否能轉得過來呢﹖ 那是因為﹕在 passive 模式下面﹐所有連線的建立方向都是從內部的 client 送往外面的 server 的﹔因為這個連線需要做 SNAT﹐那麼﹐NAT 的 table 中有這個 socket 轉換的記錄了﹔然後從 server 所送回的回應封包﹐理所當然也能順利完成 socket 的還原工作。

明白了﹖或許﹐您又會問﹕那如果在 NAT 情況下﹐不使用 passive 模式呢﹖是否還有辦法解決 ftp 數據通道的問題﹖

搭配核心模組

呵~~ 就算不用 passive 也可以啦﹗只要能讓 NAT 抓到 ftp client 在命令通道中送出的 port 命令﹐並修改原本在封包 body 中的 socket ﹐那就可以‘聰明的’在外部界面上建立 DNAT socket﹐以等待 server 那邊的數據通道連線請求了。這工作﹐通常是由核心模組來完成的﹐在 2.4.x 核心上﹐您只需執行如下命令就可以了﹕

modprobe ip_conntrack_ftp 
modprobe ip_nat_ftp

 

Tips﹕在 2.2.x 核心中所使用的模組名稱為 ip_masq_ftp ﹐不過﹐它只能跟 ipchains 配合使用。就算您在 2.4.x 核心中能夠載入 ipchains 模組﹐但因為 2.4.x 核心的 ip_nat_ftp 並不能與 ipchains 合作﹐所以也就沒辦法了。假如您有興趣知道 ip_masq_ftp 這個模組會做些什麼﹖請參考網友 常鍋麵 兄的精解﹕

 

 

常鍋麵 

 

文章雖然是描述 ip_masq_ftp 模組的﹐但其中的原理和 ip_nat_ftp 是一樣的。

 

事實上﹐FTP 服務的設定﹐在防火牆與 NAT 設計中非常具有代表性。如果要測試自己對 NAT 的設定是否及格﹐用 FTP 服務來考自己就對了。如果您有興趣﹐不妨做做下面這個習題哦﹕

 

NAT 的 FTP 設定命題

 

補充﹕在過往的測試中﹐我曾經作過如此猜測﹕

 

如果 server 和 client 兩端都各自躲在 NAT 背後﹐無論用 ipchains 和
iptalbes 都無法用 passive 模式來建立 data channel。

 

然而﹐在最近的測試中﹐我發現 netfilter 所帶來的 ip_conntrack_ftp 以及 ip_nat_ftp 模組 已經能夠成功的進行 server 端與 client 端的連線轉換。

換而言之﹐我之前所提到的過濾﹕“client 與 server 雙方都在 NAT 之後是否能連線﹖”現在已經不是問題了﹗實在非常感謝 netfilter 的工作者們。

p.s. 我所測試的核心為 2.4.16 以及 iptables-1.2.1a-1 。

 

如果您在參考答案之前能夠搞定 FTP 服務的話﹐那基本上您就及格了。否則﹐我勸您還是別急著碰 NAT 的設定。

除了 FTP 之外﹐還有許多其它服務程式﹐也有類似的‘多通道連線’的特性﹐例如 netmeeting ﹑realaudio﹑網路游戲﹑等等。因為這些程式大都沒有所謂的 passive 模式﹐所以﹐只能靠相關的模組幫忙了。如果您有相關問題﹐不妨到下面網站找找﹕

 

http://www.tsmservices.com/masq/

 

這個網站有許多奇奇怪怪的 IP 偽裝技巧與模組﹐相信總會有您感興趣的東西。