基礎知識
FTP只通過TCP連接,FTP不同於其他服務的是它使用了兩個端口, 一個數據端口和一個命令端口(或稱為控制端口)。
通常21端口是命令端口,20端口是數據端口。當混入主動/被動模式的概念時,數據端口就有可能不是20了
FTP主動模式
在主動模式下,FTP客戶端隨機開啟一個大於1024的端口N向服務器的21號端口發起連接,
然后開放N+1號端口進行監聽,並向服務器發出PORT N+1命令。
服務器接收到命令后,會用其本地的FTP數據端口(通常是20)來連接客戶端指定的端口N+1,進行數據傳輸。
- FTP服務器命令(21)端口接受客戶端任意端口(客戶端初始連接)
- FTP服務器命令(21)端口到客戶端端口(>1023)(服務器響應客戶端命令)
- FTP服務器數據(20)端口到客戶端端口(>1023)(服務器初始化數據連接到客戶端數據端口)
- FTP服務器數據(20)端口接受客戶端端口(>1023)(客戶端發送ACK包到服務器的數據端口)
主動模式的優點:
服務端配置簡單,利於服務器安全管理,服務器只需要開放21端口
主動模式的缺點:
如果客戶端開啟了防火牆,或客戶端處於內網(NAT網關之后), 那么服務器對客戶端端口發起的連接可能會失敗
FTP被動模式
在被動模式下,FTP庫戶端隨機開啟一個大於1024的端口N向服務器的21號端口發起連接,同時會開啟N+1號端口。
然后向服務器發送PASV命令,通知服務器自己處於被動模式。
服務器收到命令后,會開放一個大於1024的端口P進行監聽,然后用PORT P命令通知客戶端,自己的數據端口是P。
客戶端收到命令后,會通過N+1號端口連接服務器的端口P,然后在兩個端口之間進行數據傳輸
- FTP服務器命令(21)端口接受客戶端任意端口(客戶端初始連接)
- FTP服務器命令(21)端口到客戶端端口(>1023)(服務器響應客戶端命令)
- FTP服務器數據端口(>1023)接受客戶端端口(>1023)(客戶端初始化數據連接到服務器指定的任意端口)
- FTP服務器數據端口(>1023)到客戶端端口(>1023)(服務器發送ACK響應和數據到客戶端的數據端口)
被動模式缺點:
服務器配置管理稍顯復雜,不利於安全,服務器需要開放隨機高位端口以便客戶端可以連接,因此大多數FTP服務軟件都可以手動配置被動端口的范圍
被動模式的優點:
對客戶端網絡環境沒有要求
總結
主動FTP:
命令連接:客戶端 >1023端口 -> 服務器 21端口
數據連接:客戶端 >1023端口 <- 服務器 20端口
被動FTP:
命令連接:客戶端 >1023端口 -> 服務器 21端口
數據連接:客戶端 >1023端口 -> 服務器 >1023端口
使用python來實現FTP服務
安裝模塊 pyftpdlib
pip3 install pyftpdlib
教程
http://pyftpdlib.readthedocs.io/en/latest/tutorial.html
源碼
https://github.com/giampaolo/pyftpdlib
使用:
from pyftpdlib.authorizers import DummyAuthorizer from pyftpdlib.handlers import FTPHandler from pyftpdlib.servers import FTPServer # 新建一個用戶組 authorizer = DummyAuthorizer() # 將用戶名,密碼,指定目錄,權限 添加到里面 authorizer.add_user("fan", "root", "E:/", perm="elr") # adfmw # 這個是添加匿名用戶,任何人都可以訪問,如果去掉的話,需要輸入用戶名和密碼,可以自己嘗試 authorizer.add_anonymous("E:/") handler = FTPHandler handler.authorizer = authorizer # 開啟服務器 server = FTPServer(("127.0.0.1", 21), handler) server.serve_forever()
然后將程序運行起來,接下來看一下效果,在瀏覽器上ftp://localhost/
用戶權限
讀取權限: "e" =更改目錄(CWD,CDUP命令) "l" =列表文件(LIST,NLST,STAT,MLSD,MLST,SIZE命令) "r" =從服務器檢索文件(RETR命令) 寫入權限: "a" =將數據追加到現有文件(APPE命令) "d" =刪除文件或目錄(DELE,RMD命令) "f" =重命名文件或目錄(RNFR,RNTO命令) "m" =創建目錄(MKD命令) "w" =將文件存儲到服務器(STOR,STOU命令) "M"=更改文件模式/權限(SITE CHMOD命令) "T"=更改文件修改時間(SITE MFMT命令)
開啟被動端口模式
#添加被動端口范圍 handler.passive_ports = range(8300, 8500)
demo
from pyftpdlib.authorizers import DummyAuthorizer from pyftpdlib.handlers import FTPHandler from pyftpdlib.servers import FTPServer # 新建一個用戶組 authorizer = DummyAuthorizer() # 將用戶名,密碼,指定目錄,權限 添加到里面 authorizer.add_user("test", "1234", "E:/", perm="elradfmw") # adfmw # 這個是添加匿名用戶,任何人都可以訪問,如果去掉的話,需要輸入用戶名和密碼,可以自己嘗試 authorizer.add_anonymous("E:/") handler = FTPHandler handler.authorizer = authorizer #添加被動端口范圍 handler.passive_ports = range(8300, 8500) # 開啟服務器 server = FTPServer(("127.0.0.1", 2121), handler) server.serve_forever()
-----------輸出-----------------
[I 2018-08-06 15:37:16] >>> starting FTP server on 127.0.0.1:2121, pid=8564 <<<
[I 2018-08-06 15:37:16] concurrency model: async
[I 2018-08-06 15:37:16] masquerade (NAT) address: None
[I 2018-08-06 15:37:16] passive ports: 8300->8499
[I 2018-08-06 15:37:32] 127.0.0.1:54898-[] FTP session opened (connect)
讀取用戶列表,建立FTP
#-----------user.ini------ [alex] password=123 perm=elradfmwM home=D:/ [egon] password=123456 perm=elradfmwM home=D:/ #------------ftpdemo from pyftpdlib.authorizers import DummyAuthorizer from pyftpdlib.handlers import FTPHandler, ThrottledDTPHandler from pyftpdlib.servers import FTPServer import configparser import logging IP = '127.0.0.1' PORT = '2121' # 上傳速度 100kb/s MAX_UPLOAD = 100 * 1024 # 下載速度 100kb/s MAX_DOWNLOAD = 100 * 1024 # 最大連接數 MAX_CONS = 100 # 最多IP數 MAX_PER_IP = 10 # 被動端口范圍,注意被動端口數量要比最大IP數多,否則可能出現無法連接的情況 PASSIVE_PORTS = (8300, 8500) # 是否開啟匿名訪問 on|off ENABLE_ANONYMOUS = 'off' # 匿名用戶目錄 ANONYMOUS_PATH = 'E:/DEVTOOL/' # 日志文件 LOGING_NAME = 'pyftp.log' # 歡迎信息 WELCOME_MSG = 'Welcome to my ftp' # 新建一個用戶組 authorizer = DummyAuthorizer() # 讀取用戶配置 config = configparser.ConfigParser() config.read('user.ini') user_list = config.sections() for user in user_list: passwd = config[user]["password"] perm = config[user]["perm"] home_dir = config[user]["home"] # 將用戶名,密碼,指定目錄,權限 添加到里面 authorizer.add_user(user, passwd, homedir=home_dir, perm=perm) # 添加匿名用戶 只需要路徑 if ENABLE_ANONYMOUS == 'on': authorizer.add_anonymous(ANONYMOUS_PATH) # 下載上傳速度設置 dtp_handler = ThrottledDTPHandler dtp_handler.read_limit = MAX_DOWNLOAD dtp_handler.write_limit = MAX_UPLOAD # 初始化ftp句柄 handler = FTPHandler handler.authorizer = authorizer # 添加被動端口范圍 handler.passive_ports = range(PASSIVE_PORTS[0], PASSIVE_PORTS[1]) # 歡迎信息 handler.banner = WELCOME_MSG # 監聽ip 和 端口 server = FTPServer((IP, PORT), handler) # 最大連接數 server.max_cons = MAX_CONS server.max_cons_per_ip = MAX_PER_IP # 開始服務 print('FTP開始服務 ', (IP, PORT)) server.serve_forever()
參考網站:
https://www.cnblogs.com/huangxm/p/6274645.html