Patching các thư viện socket BUILTIN chắc chắn sẽ không phải là một lựa chọn cho tất cả mọi người, nhưng giải pháp của tôi là để vá socket.create_connection()
sử dụng một proxy HTTP khi hostname phù hợp với một danh sách trắng:
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
tôi cũng đã phải tạo ra một lớp con của ftplib.FTP mà bỏ qua host
trả về bởi PASV
và EPSV
lệnh FTP. sử dụng ví dụ:
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()
vào liên kết trong câu trả lời trên là 404. Có thể có nghĩa là cái này: http : //mail.python.org/pipermail/python-list/2004-October/863602.html – AndrewR
Phần "ẩn danh tại ftp.download.com" là tiểu thuyết thuần túy. Không có điều gì giống như vậy từng được đề cập trong bất kỳ RFC hoặc nào được triển khai/hỗ trợ bởi bất kỳ máy chủ nào, theo như tôi biết. Tương đối, giao thức FTP không hỗ trợ proxy. AFAIK, cách duy nhất để proxy FTP là bằng cách sử dụng một SOCKS trong trường hợp máy khách được cho là kết nối với SOCKS và lệnh thứ hai cần được hướng dẫn về máy chủ FTP thực. –
Câu trả lời này giải quyết cho tôi một cơn đau đầu lớn. Cảm ơn bạn!!! – dgg32