Python: nlst () зависает на "здесь идет список" с использованием FTP_TLS - PullRequest
0 голосов
/ 08 октября 2018

Я застрял в этом на пару дней.Я использую 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 голосов
/ 24 ноября 2018

Возможно, проблема в том, что 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
...