基础知识
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