Python:nlst()使用FTP_TLS挂在“清单上来了”

时间:2018-10-08 09:23:32

标签: python ftplib

我被困在这几天。我正在使用python通过 FTP_TLS 连接到服务器。我已经看到过很多关于此错误的文章,并做了几乎所有的更改,但还是很不幸。我可以连接到服务器,创建目录,但是当它出现在清单ftps.nlst()ftps.retrlines('LIST')ftps.dir()上时,它们都卡在/挂在:

  

150这是目录列表。

下面是我的服务器vsftpd配置文件:

listen=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
xferlog_file=/var/log/vsftpd.log
chroot_local_user=YES
allow_writeable_chroot=YES
pam_service_name=vsftpd
pasv_enable=YES
pasv_promiscuous=YES
pasv_min_port=40000
pasv_max_port=55999
pasv_address = ip_address
rsa_cert_file=/etc/ssl/private/vsftpd.pem
rsa_private_key_file=/etc/ssl/private/vsftpd.pem
ssl_enable=YES
allow_anon_ssl=NO
force_local_data_ssl=YES
force_local_logins_ssl=YES
ssl_tlsv1=YES
ssl_sslv2=NO
ssl_sslv3=NO
require_ssl_reuse=NO
ssl_ciphers=HIGH
user_sub_token=abc
local_root=/home/abc/ftp
user_sub_token=username
local_root=/path/to/username/images
userlist_enable=YES
userlist_file=/etc/vsftpd.userlist
userlist_deny=NO

调试日志为:

*get* '220 (vsFTPd 3.0.3)\n'
*resp* '220 (vsFTPd 3.0.3)'
*welcome* '220 (vsFTPd 3.0.3)'
getwelcome >>>220 (vsFTPd 3.0.3)
<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketType.SOCK_STREAM, proto=6, laddr=('192.168.81.11', 59660), raddr=('81.19.0.237', 21)>
*cmd* 'AUTH SSL'
*put* 'AUTH SSL\r\n'
*get* '234 Proceed with negotiation.\n'
*resp* '234 Proceed with negotiation.'
*cmd* 'USER username'
*put* 'USER username\r\n'
*get* '331 Please specify the password.\n'
*resp* '331 Please specify the password.'
*cmd* 'PASS ***************'
*put* 'PASS ***************\r\n'
*get* '230 Login successful.\n'
*resp* '230 Login successful.'
*cmd* 'PBSZ 0'
*put* 'PBSZ 0\r\n'
*get* '200 PBSZ set to 0.\n'
*resp* '200 PBSZ set to 0.'
*cmd* 'PROT P'
*put* 'PROT P\r\n'
*get* '200 PROT now Private.\n'
*resp* '200 PROT now Private.'
Current directory:
*cmd* 'PWD'
*put* 'PWD\r\n'
*get* '257 "/" is the current directory\n'
*resp* '257 "/" is the current directory'
>>>> /
*cmd* 'PWD'
*put* 'PWD\r\n'
*get* '257 "/" is the current directory\n'
*resp* '257 "/" is the current directory'
<<<>>>257 "/" is the current directory
*cmd* 'CWD /uploads/'
*put* 'CWD /uploads/\r\n'
*get* '250 Directory successfully changed.\n'
*resp* '250 Directory successfully changed.'
*cmd* 'TYPE A'
*put* 'TYPE A\r\n'
*get* '200 Switching to ASCII mode.\n'
*resp* '200 Switching to ASCII mode.'
*cmd* 'EPSV'
*put* 'EPSV\r\n'
*get* '229 Entering Extended Passive Mode (|||44788|)\n'
*resp* '229 Entering Extended Passive Mode (|||44788|)'
*cmd* 'NLST'
*put* 'NLST\r\n'
*get* '150 Here comes the directory listing.\n'
*resp* '150 Here comes the directory listing.'
^C 
Traceback (most recent call last):
File "config/timelapse_test.py", line 45, in <module>
    filenames = ftps.nlst()
File "/usr/lib/python3.4/ftplib.py", line 558, in nlst
    self.retrlines(cmd, files.append)
File "/usr/lib/python3.4/ftplib.py", line 467, in retrlines
    with self.transfercmd(cmd) as conn, \
File "/usr/lib/python3.4/ftplib.py", line 398, in transfercmd
    return self.ntransfercmd(cmd, rest)[0]
File "/usr/lib/python3.4/ftplib.py", line 793, in ntransfercmd
    server_hostname=server_hostname)
File "/usr/lib/python3.4/ssl.py", line 364, in wrap_socket
    _context=self)
File "/usr/lib/python3.4/ssl.py", line 577, in __init__
    self.do_handshake()
File "/usr/lib/python3.4/ssl.py", line 804, in do_handshake
    self._sslobj.do_handshake()
KeyboardInterrupt

我在代码中也放置了:

ftps.ssl_version = ssl.PROTOCOL_SSLv23;
ftps.passive = True
ftps.prot_p()

有人可以指导我我做错了什么地方吗?

谢谢

1 个答案:

答案 0 :(得分:0)

问题可能是FTP服务器要求新数据通道中的TLS会话与控制通道相同。这在Python 3.7中尚未修复。为ftplib.FTP_TLS子类,如https://stackoverflow.com/a/43301750此处找到的解决方案,我对此做了一个小修正:

import ftplib


class ReusedSslSocket(SSLSocket):
    def unwrap(self):
        pass


class MyFTP_TLS(ftplib.FTP_TLS):
    """Explicit FTPS, with shared TLS session"""
    def ntransfercmd(self, cmd, rest=None):
        conn, size = ftplib.FTP.ntransfercmd(self, cmd, rest)
        if self._prot_p:
            conn = self.context.wrap_socket(conn,
                                            server_hostname=self.host,
                                            session=self.sock.session)  # reuses TLS session            
            conn.__class__ = ReusedSslSocket  # we should not close reused ssl socket when file transfers finish
        return conn, size
相关问题