#!/usr/bin/python
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, msg:
if self.socket:
self.socket.close()
self.socket = None
continue
break
if not self.socket :
raise socket.error, ms
# Ask him to create a tunnel connection to the target host/port
self.socket.send(
("CONNECT %s:%d HTTP/1.1\r\n" +
"Host: %s:%d\r\n\r\n") % (self.host, self.port, self.host, self.port));
# Get the response
resp = self.socket.recv(4096)
# Parse the response
parts = resp.split()
# Not 200 ?
if parts[1] != "200" :
raise Exception("Error response from Proxy server : %s" % 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) :
return self.socket.makefile(*args)
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
Diff to Previous Revision
--- revision 3 2011-06-24 08:51:29
+++ revision 4 2011-11-07 10:25:56
@@ -141,4 +141,4 @@
# Replace the "socket" method by our custom one
socket.socket_formal = socket.socket
- socket.socket = socket_prox
+ socket.socket = socket_proxy