Patching biblioteca presa incorporato sicuramente non sarà un'opzione per tutti, ma la mia soluzione era quella di rattoppare socket.create_connection()
di utilizzare un proxy HTTP quando il nome host corrisponde a una whitelist:
from base64 import b64encode
from functools import wraps
import socket
_real_create_connection = socket.create_connection
_proxied_hostnames = {} # hostname: (proxy_host, proxy_port, proxy_auth)
def register_proxy (host, proxy_host, proxy_port, proxy_username=None, proxy_password=None):
proxy_auth = None
if proxy_username is not None or proxy_password is not None:
proxy_auth = b64encode('{}:{}'.format(proxy_username or '', proxy_password or ''))
_proxied_hostnames[host] = (proxy_host, proxy_port, proxy_auth)
@wraps(_real_create_connection)
def create_connection (address, *args, **kwds):
host, port = address
if host not in _proxied_hostnames:
return _real_create_connection(address, *args, **kwds)
proxy_host, proxy_port, proxy_auth = _proxied_hostnames[host]
conn = _real_create_connection((proxy_host, proxy_port), *args, **kwds)
try:
conn.send('CONNECT {host}:{port} HTTP/1.1\r\nHost: {host}:{port}\r\n{auth_header}\r\n'.format(
host=host, port=port,
auth_header=('Proxy-Authorization: basic {}\r\n'.format(proxy_auth) if proxy_auth else '')
))
response = ''
while not response.endswith('\r\n\r\n'):
response += conn.recv(4096)
if response.split()[1] != '200':
raise socket.error('CONNECT failed: {}'.format(response.strip()))
except socket.error:
conn.close()
raise
return conn
socket.create_connection = create_connection
ho anche dovuto creare una sottoclasse di ftplib.FTP che ignora la host
restituito dalla PASV
e EPSV
comandi FTP. Esempio di utilizzo:
from ftplib import FTP
import paramiko # For SFTP
from proxied_socket import register_proxy
class FTPIgnoreHost (FTP):
def makepasv (self):
# Ignore the host returned by PASV or EPSV commands (only use the port).
return self.host, FTP.makepasv(self)[1]
register_proxy('ftp.example.com', 'proxy.example.com', 3128, 'proxy_username', 'proxy_password')
ftp_connection = FTP('ftp.example.com', 'ftp_username', 'ftp_password')
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # If you don't care about security.
ssh.connect('ftp.example.com', username='sftp_username', password='sftp_password')
sftp_connection = ssh.open_sftp()
il link nella risposta di cui sopra è 404. avrebbe potuto significare questo: http : //mail.python.org/pipermail/python-list/2004-October/863602.html – AndrewR
La parte "anonymous at ftp.download.com" è pura finzione. Nulla di simile è mai stato menzionato in nessun RFC o implementato/supportato da alcun server, per quanto ne so. In modo nativo, il protocollo FTP non supporta il proxy. AFAIK, l'unico modo per proxy FTP è l'utilizzo di un SOCKS nel qual caso il client deve connettersi al SOCKS e quest'ultimo deve essere istruito su quale sia il vero server FTP. –
Questa risposta mi risolve un vero grande mal di testa. Grazie!!! – dgg32