Created
July 15, 2022 00:21
-
-
Save skiptomyliu/530201594833c35a4f018b6013f28efd to your computer and use it in GitHub Desktop.
ftplib HTTP CONNECT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# This is a quick dirty python3 translation of https://code.activestate.com/recipes/577643-transparent-http-tunnel-for-python-sockets-to-be-u/ | |
import socket | |
# Class that wraps a real socket and changes it to a HTTP tunnel whenever a connection is asked via the "CONNECT" method | |
class ProxySock : | |
def __init__(self, socket, proxy_host, proxy_port) : | |
# First, use the socket, without any change | |
self.socket = socket | |
# Create socket (use real one) | |
self.proxy_host = proxy_host | |
self.proxy_port = proxy_port | |
# Copy attributes | |
self.family = socket.family | |
self.type = socket.type | |
self.proto = socket.proto | |
def connect(self, address) : | |
# Store the real remote adress | |
(self.host, self.port) = address | |
# Try to connect to the proxy | |
for (family, socktype, proto, canonname, sockaddr) in socket.getaddrinfo( | |
self.proxy_host, | |
self.proxy_port, | |
0, 0, socket.SOL_TCP) : | |
try: | |
# Replace the socket by a connection to the proxy | |
self.socket = socket.socket_formal(family, socktype, proto) | |
self.socket.connect(sockaddr) | |
except socket.error: | |
if self.socket: | |
self.socket.close() | |
self.socket = None | |
continue | |
break | |
if not self.socket : | |
raise socket.error | |
# Ask him to create a tunnel connection to the target host/port | |
self.socket.send((f"CONNECT {self.host}:{self.port} HTTP/1.1\r\n" | |
f"Host: {self.host}:{self.port}\r\n\r\n").encode()) | |
# Get the response | |
resp = self.socket.recv(4096) | |
# Parse the response | |
parts = resp.split() | |
# Not 200 ? | |
if parts[1] != b"200" : | |
raise Exception(f"Error response from Proxy server : {resp}") | |
# Wrap all methods of inner socket, without any change | |
def accept(self) : | |
return self.socket.accept() | |
def bind(self, *args) : | |
return self.socket.bind(*args) | |
def close(self) : | |
return self.socket.close() | |
def fileno(self) : | |
return self.socket.fileno() | |
def getsockname(self) : | |
return self.socket.getsockname() | |
def getsockopt(self, *args) : | |
return self.socket.getsockopt(*args) | |
def listen(self, *args) : | |
return self.socket.listen(*args) | |
def makefile(self, *args, **kwargs) : | |
return self.socket.makefile(*args, **kwargs) | |
def recv(self, *args) : | |
return self.socket.recv(*args) | |
def recvfrom(self, *args) : | |
return self.socket.recvfrom(*args) | |
def recvfrom_into(self, *args) : | |
return self.socket.recvfrom_into(*args) | |
def recv_into(self, *args) : | |
return self.socket.recv_into(buffer, *args) | |
def send(self, *args) : | |
return self.socket.send(*args) | |
def sendall(self, *args) : | |
return self.socket.sendall(*args) | |
def sendto(self, *args) : | |
return self.socket.sendto(*args) | |
def setblocking(self, *args) : | |
return self.socket.setblocking(*args) | |
def settimeout(self, *args) : | |
return self.socket.settimeout(*args) | |
def gettimeout(self) : | |
return self.socket.gettimeout() | |
def setsockopt(self, *args): | |
return self.socket.setsockopt(*args) | |
def shutdown(self, *args): | |
return self.socket.shutdown(*args) | |
# Return the (host, port) of the actual target, not the proxy gateway | |
def getpeername(self) : | |
return (self.host, self.port) | |
# Install a proxy, by changing the method socket.socket() | |
def setup_http_proxy(proxy_host, proxy_port) : | |
# New socket constructor that returns a ProxySock, wrapping a real socket | |
def socket_proxy(af, socktype, proto) : | |
# Create a socket, old school : | |
sock = socket.socket_formal(af, socktype, proto) | |
# Wrap it within a proxy socket | |
return ProxySock( | |
sock, | |
proxy_host, | |
proxy_port) | |
# Replace the "socket" method by our custom one | |
socket.socket_formal = socket.socket | |
socket.socket = socket_proxy | |
# Imports | |
from ftplib import FTP | |
# Constants | |
PROXY_HOST="proxy.host" | |
PROXY_PORT=80 | |
FTP_HOST="ftphost.net" | |
FTP_USER="anonymous" | |
FTP_PASS="anonymous" | |
FTP_FILE="/path.to/file.txt" | |
FTP_DIR="/path/to/folder/" | |
# Install the proxy on the "socket" module | |
setup_http_proxy( | |
PROXY_HOST, | |
PROXY_PORT) | |
ftp = FTP(FTP_HOST) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment