外網訪問內網的FTP伺服器
最近研究如何在內網搭架FTP伺服器,同時要保證外網(公網)能訪問的到。終成正果,但走了一些彎路,在此記下,以饗後人。
FTP 使用 2 個埠,一個數據埠和一個命令埠(也叫做控制埠)。這兩個埠一般是21 (命令埠)和 20 (資料埠),當然你也可以自定義。控制 Socket 用來傳送命令,資料 Socket 是用於傳送資料。每一個 FTP 命令傳送之後,FTP 伺服器都會返回一個字串,其中包括一個響應程式碼和一些說明資訊。其中的返回碼主要是用於判斷命令是否被成功執行了。
一般來說,客戶端有一個 Socket用來連線 FTP 伺服器的相關埠,它負責 FTP 命令的傳送和接收返回的響應資訊。一些操作如“登入”、“改變目錄”、“刪除檔案”,依靠這個連線傳送命令就可完成。
對於有資料傳輸的操作,主要是顯示目錄列表,上傳、下載檔案,我們需要依靠另一個 Socket來完成。
如果使用被動模式,通常伺服器端會返回一個埠號。客戶端需要用另開一個 Socket 來連線這個埠,然後我們可根據操作來發送命令,資料會通過新開的一個埠傳輸。
如果使用主動模式,通常客戶端會發送一個埠號給伺服器端,並在這個埠監聽。伺服器需要連線到客戶端開啟的這個資料埠,並進行資料的傳輸。
下面對 FTP 的主動模式和被動模式做一個簡單的介紹。
主動模式下,客戶端隨機開啟一個大於1024 的埠向伺服器的命令埠 P,即 21 埠,發起連線,同時開放N +1 埠監聽,並向伺服器發出 “port N+1” 命令,由伺服器從它自己的資料埠 (20) 主動連線到客戶端指定的資料埠 (N+1)。
FTP 的客戶端只是告訴伺服器自己的埠號,讓伺服器來連線客戶端指定的埠。對於客戶端的防火牆來說,這是從外部到內部的連線,可能會被阻塞。
為了解決伺服器發起到客戶的連線問題,有了另一種 FTP 連線方式,即被動方式。命令連線和資料連線都由客戶端發起,這樣就解決了從伺服器到客戶端的資料埠的連線被防火牆過濾的問題。
被動模式下,當開啟一個 FTP 連線時,客戶端開啟兩個任意的本地埠 (N > 1024 和 N+1) 。
第一個埠連線伺服器的 21 埠,提交 PASV 命令。然後,伺服器會開啟一個任意的埠 (P > 1024 ),返回如“227 entering passive mode (127,0,0,1,4,18)”。 它返回了 227 開頭的資訊,在括號中有以逗號隔開的六個數字,前四個指伺服器的地址,最後兩個,將倒數第二個乘256 再加上最後一個數字,這就是 FTP 伺服器開放的用來進行資料傳輸的埠。如得到 227 entering passive mode(h1,h2,h3,h4,p1,p2),那麼埠號是 p1*256+p2,ip 地址為h1.h2.h3.h4。這意味著在伺服器上有一個埠被開放。客戶端收到命令取得埠號之後, 會通過 N+1 號埠連線伺服器的埠 P,然後在兩個埠之間進行資料傳輸。
使用Serv-U搭架FTP伺服器很簡單,網上教程也很多,不再累述。我這裡只記錄下我遇到的問題。
作業系統 |
FTP軟體 |
FTP軟體版本 |
|
FTP伺服器 |
Windows XP |
Serv-U |
版本15.0.1.20 |
FTP客戶端 |
Windows XP |
FileZilla |
版本3.8.0 |
FTP伺服器安裝在公司內網的電腦上,FTP客戶端在外網的電腦上(嚴格來說也是在另一外區域網內)。
被動模式(PASV)下,有資料要傳輸時,伺服器會開啟一個數據埠(並處於監聽狀態),然後告知客戶端,客戶端連線這個資料埠傳送資料。但是資料埠是隨機的,那麼伺服器該如何將這些隨機資料埠對映到公網的路由器上呢???總不能讓內部網的一臺機器完全暴露到公網上吧,雖然確實有這樣的方案(稱之為DMZ主機),但這絕對是最愚蠢的選擇。
這就是我遇到的第一個彎路,折騰了很久才知道。雖然資料埠是隨機的,但Serv-U可以指定隨機的範圍。開啟Serv-U管理控制檯 > 管理伺服器 > 伺服器限制和設定 > 伺服器設定 。在“設定”選項卡里找到“PASV埠範圍”,如下圖所示,在這裡就可以指定隨見的範圍了。你只要把這些埠對映到路由器就可以了。
圖表 1 PASV 埠範圍
當然別忘了,還有一個命令埠也得對映。
我遇到的第二個難纏的問題是,FileZilla客戶端獲取不到FTP伺服器的目錄列表。日誌資訊如下:
狀態: 正在連線 125.89.123.99:13000... 狀態: 連線建立,等待歡迎訊息... 響應: 220 Serv-U FTP Server v15.0 ready... 命令: USER zhangsan 響應: 331 User name okay, need password. 命令: PASS *** 響應: 230 User logged in, proceed. 命令: CLNT FileZilla 響應: 200 Noted. 命令: OPTS UTF8 ON 響應: 200 OPTS UTF8 is set to ON. 命令: OPTS MLST type;size;modify;perm; 響應: 200 MLST OPTS Type;Size;Modify;Perm; 狀態: 已連線 狀態: 讀取目錄列表... 命令: PWD 響應: 257 "/" is current directory. 命令: TYPE I 響應: 200 Type set to I. 命令: PASV 響應: 227 Entering Passive Mode (100,100,100,100,50,203) 命令: MLSD 響應: 150 Opening BINARY mode data connection for MLSD. 錯誤: 連線超時 錯誤: 讀取目錄列表失敗 |
也是經過一陣折騰,最後突然發現伺服器對PASV指令的響應是:227Entering Passive Mode (100,100,100,100,50,203),這裡100.100.100.100是FTP伺服器在內網IP,客戶端自然連線不上。開啟Serv-U管理控制檯 > 你自定義的域名 > 域詳細資訊 > 監聽器 > 編輯 ,在PASV IP地址或域名中設定公網IP即可。 如下圖所示。
4. 總結
FTP伺服器至少需要兩個埠:命令埠和資料埠。命令埠是固定的,而資料埠是隨機的。隨機的埠如何對映到公網?Serv-U可以設定PASV埠範圍,隨機也只是在設定的範圍內隨機。另外需要設定PASV IP地址,否者伺服器響應客戶端的PASV 命令時,會把伺服器在內網中的IP地址告知客戶端,這個地址對應客戶端來說是連線不上的。