FTPS with Python ftplib - Session reuse required
ftp, ftplib, ftps, python, python-2.7
Solution
It can be now easily fixed for Python 3.6+ by this class (descendant of FTP_TLS):
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) # this is the fix
return conn, size
It takes the TLS session information from the initial "control" FTP connection and reuses it also for every second "data" connection that is frequently created and closed for every new data transfer of a file body or a directory list. The reuse is advantageous for the server because it does not require a repeated TLS handshake many times. That is exactly what you did see in the message `session reuse required`.
Problem
So, I am trying to connect to an FTP server to get directory listings and download files. But the first command after the `prot_p()` function is raising an exception - Producing these errors from the log: ``` *get* '150 Here comes the directory listing.\r\n' *resp* '150 Here comes the directory listing.' *get* '522 SSL connection failed; session reuse required: see require_ssl_reuse option in vsftpd.conf man page\r\n' *resp* '522 SSL connection failed; session reuse required: see require_ssl_reuse option in vsftpd.conf man page' Traceback (most recent call last): File "C:\temp\download.py", line 29, in <module> files = ftps.dir() File "C:\Python27\lib\ftplib.py", line 522, in dir self.retrlines(cmd, func) File "C:\Python27\lib\ftplib.py", line 725, in retrlines return self.voidresp() File "C:\Python27\lib\ftplib.py", line 224, in voidresp resp = self.getresp() File "C:\Python27\lib\ftplib.py", line 219, in getresp raise error_perm, resp ftplib.error_perm: 522 SSL connection failed; session reuse required: see requir e_ssl_reuse option in vsftpd.conf man page ``` Here is the code: ``` from ftplib import FTP_TLS import os import socket host = 'example.com' port = 34567 user = 'user1' passwd = 'pass123' acct = 'Normal' ftps = FTP_TLS() ftps.set_debuglevel(2) ftps.connect(host, port) print(ftps.getwelcome()) print(ftps.sock) ftps.auth() ftps.login(user, passwd, acct) ftps.set_pasv(True) ftps.prot_p() print('Current directory:') print(ftps.pwd()) files = ftps.dir() ftps.quit() ``` I want to do this securely, hence using FTP over TLS Explicit. I have the idea that I may need to manipulate some settings in the `Socket` class referenced by ftplib. Changing the settings on the server is not a possibility. I have tested the server successfully with FileZilla client, an older version of WinSCP was raising the same error - although an upgrade to the newest version fixed it. Any ideas?