关于pyftpdlib建立 FTP服务器的详细内容:
py-FTP服务器之一:虚拟运行环境
py-FTP服务器之二:用户配置文件
py-FTP服务器之三:启用SSL连接
py-FTP服务器之四:ftp主程序
py-FTP服务器之五:其他
- 主程序是
ftp.py
ftp.py
同级要有一个rootftp
文件夹, 作为根目录, ftp上传来的文件全部丢里面
关于是否启用SSL加密和多进程的代码
# 是否启用ssl加密和多进程模式
USE_SSL = False # 是否启用ftps加密传输,通过修改单独的文件设置,默认是不用ssl
if 'ssl' in argv:
USE_SSL = True # 如果要启用ssl,运行时要加参数 ssl
if 'mul' in argv:
USE_MULTIPLE_PROCESS = True # 开启多进程模式, 运行时要增加参数 mul
注意: 在启动程序时需要在后面加参数, 比如要启用ssl, 则应当输入python ftp.py ssl
, 如果还要开启多进程, 则应输入python ftp.py ssl mul
MD5验证函数
这个函数是在官方给的基础上做了一些简化.
# 验证用户密码hash后是否与原来的一样,照着官方文档写的,修改了一点
class DummyMD5Authorizer(DummyAuthorizer):
def validate_authentication(self, username, password, handler):
hash = md5(password.encode('utf-8')).hexdigest() # 与md5USerPassword.py上的算法一致
try:
if self.user_table[username]['pwd'] != hash:
raise KeyError
except KeyError:
raise AuthenticationFailed
从文本文件加载用户信息
# 读取用户权限文件,向虚拟用户管理器添加用户
def add_user(authorizer):
# 用户权限文件
userfile = 'userMD5.txt' # 文件格式如下(md5加密后的文件,运行md5UserPassword.py后自动生成)
'''
# 备注文字(用tab间隔开来)
username md5(password) path perm
username md5(password) path perm
username md5(password) path perm
'''
# 用户列表
user_list = []
split_str = '\t'
# 从userMD5.txt读取用户信息
with open(userfile) as f:
for line in f:
line = line.replace('\n', '') # 去掉最后的\n
if not line.startswith('#') and line: # #后面是备注
if len(line.split(split_str)) == 4: # 用户名/密码/路径/权限
user_list.append(line.split(split_str))
else:
print("userMD5.txt配置错误: %s" % line)
# 添加用户
for user in user_list:
authorizer.add_user(user[0], user[1], './rootftp' + user[2], perm=user[3], msg_login="欢迎光临", msg_quit="欢迎下次光临")
print('[%s\t---\t%s\t%s]' % (user[0], user[3], user[2]))
# 返回虚拟用户管理器
return authorizer
被动模式PASV
- 如果有电脑在局域网中要连接外网的FTP, 则建议使用被动模式PASV进行连接
- 设置一个假的IP地址, 确定一个被动模式端口的范围(默认设置为这个, 服务器的最后5000多个端口号)
# 被动模式配置
# Specify a masquerade address and the range of ports to use for
# passive connections. Decomment in case you're behind a NAT.
# 设置假IP地址发回给ftp客户端,设置被动模式的端口区间(最大65535)
handler.masquerade_address = '151.25.42.11' # ftp服务器的伪IP地址
handler.passive_ports = range(60000, 65535) # 被动模式下的随机端口
完整代码ftp.py
# coding:utf-8
from pyftpdlib.servers import FTPServer, MultiprocessFTPServer
from pyftpdlib.authorizers import DummyAuthorizer, AuthenticationFailed
from hashlib import md5
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.handlers import TLS_FTPHandler # TLS_FTPHandler需要pip安装pyopenssl
from sys import argv # 用来读取启动py文件时的命令行参数
# 是否启用ssl加密
USE_SSL = False # 是否启用ftps加密传输,通过修改单独的文件设置,默认是不用ssl
if 'ssl' in argv:
USE_SSL = True # 如果要启用ssl,运行时要加参数 ssl
if 'mul' in argv:
USE_MULTIPLE_PROCESS = True # 开启多进程模式
# 验证用户密码hash后是否与原来的一样,照着官方文档写的,修改了一点
class DummyMD5Authorizer(DummyAuthorizer):
def validate_authentication(self, username, password, handler):
hash = md5(password.encode('utf-8')).hexdigest() # 与md5USerPassword.py上的算法一致
try:
if self.user_table[username]['pwd'] != hash:
raise KeyError
except KeyError:
raise AuthenticationFailed
# 读取用户权限文件,向虚拟用户管理器添加用户
def add_user(authorizer):
# 用户权限文件
userfile = 'userMD5.txt' # 文件格式如下(md5加密后的文件,运行md5UserPassword.py后自动生成)
'''
# 备注文字(用tab间隔开来)
username md5(password) path perm
username md5(password) path perm
username md5(password) path perm
'''
# 用户列表
user_list = []
split_str = '\t'
# 从userMD5.txt读取用户信息
with open(userfile) as f:
for line in f:
line = line.replace('\n', '') # 去掉最后的\n
if not line.startswith('#') and line: # #后面是备注
if len(line.split(split_str)) == 4: # 用户名/密码/路径/权限
user_list.append(line.split(split_str))
else:
print("userMD5.txt配置错误: %s" % line)
# 添加用户
for user in user_list:
authorizer.add_user(user[0], user[1], './rootftp' + user[2], perm=user[3], msg_login="欢迎光临", msg_quit="欢迎下次光临")
print('[%s\t---\t%s\t%s]' % (user[0], user[3], user[2]))
# 返回虚拟用户管理器
return authorizer
#
def main():
# 用户验证
# Instantiate a dummy authorizer for managing 'virtual' users 创建虚拟用户管理器
# authorizer = DummyAuthorizer()
authorizer = DummyMD5Authorizer() # 因为要验证hash值,所以改成这个了类了,官方写的, 这个类继承自DummyAuthorizer类
# Define a new user having full r/w permissions and a read-only anonymous user
# 读取userMD5.txt文件,绑定 用户-权限
authorizer = add_user(authorizer) # 写成了一个函数add_user()来自动读取userMD5.txt
# authorizer.add_anonymous(os.getcwd()) # 匿名用户,关闭
# ftp主控制器
# Instantiate FTP handler class
# 绑定FTP控制器
if not USE_SSL:
handler = FTPHandler # ftp传输
if USE_SSL:
handler = TLS_FTPHandler # ftps传输 = ftp + ssl
handler.authorizer = authorizer # 绑定用户管理器
# ssl加密
if USE_SSL:
handler.certfile = 'crt_key.pem' # 此处需要插入自签名证书文件base64编码的pem
# requires SSL for both control and data channel
# 启用ssl加密传输
# handler.tls_control_required = True # 控制连接启用ssl加密
handler.tls_data_required = True # 数据连接启用ssl加密
# 锦上添花
# Define a customized banner (string returned when client connects)
# 定义ftp客户端[连接成功欢迎词]
handler.banner = "欢迎你我尊贵的客人莅临指导"
# 被动模式配置
# Specify a masquerade address and the range of ports to use for
# passive connections. Decomment in case you're behind a NAT.
# 设置假IP地址发回给ftp客户端,设置被动模式的端口区间(最大65535)
handler.masquerade_address = '151.25.42.11' # ftp服务器的伪IP地址
handler.passive_ports = range(60000, 65535) # 被动模式下的随机端口
# ip限制及端口设定
# Instantiate FTP server class and listen on 0.0.0.0:8081
# 设置不限制IP地址访问,端口8081,使用TCP端口8081
address = ('0.0.0.0', 8081) # ip限制及连接端口(需要在安全组里放通这个端口)
# 多进程模式是否开启
if USE_MULTIPLE_PROCESS:
server = MultiprocessFTPServer(address, handler)
else:
server = FTPServer(address, handler)
# 最大连接数限制
# set a limit for connections
# 设置最大连接数,和相同IP地址的最大同时连接数
server.max_cons = 50
server.max_cons_per_ip = 20
# 万事俱备,只欠东风
# start ftp server
# 启动ftp服务器
server.serve_forever()
# 启动
if __name__ == '__main__':
main()
启动
启动命令: python ftp.py ssl mul
后台运行: nohup python ftp.py >> log 2>&1 &