Reputation: 3
Basically, I'm trying to setup an encrypted proxy with sockets in python. currently I'm able to make connection by sending an HTTP CONNECT from my client to the proxy server, and receiving a 'CODE 200 OK' response. The proxy server acts as a tunnel from the client to the desired domain/Ip and works perfectly fine.
The problem is: How can I manage to encrypt the whole connection? the first HTTP Connect isn't encrypted and can be easily sniffed and seen.
Here's the server code:
import socket, threading
MAX_BUFFER = 64 * 512
class ClientThread(threading.Thread):
def __init__(self, clientAddress, clientsocket):
threading.Thread.__init__(self)
self.browser = clientsocket
def run(self):
while True:
request = self.browser.recv(MAX_BUFFER)
# parse the first line
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
webserver, port = self.get_domain_port(request)
if 'CONNECT' in request:
# Connect to port 443
print request
try:
# If successful, send 200 code response
client.connect(( webserver, port ))
reply = "HTTP/1.0 200 Connection established\r\n"
reply += "Proxy-agent: FIMA\r\n"
reply += "\r\n"
self.browser.sendall( reply.encode() )
except socket.error as err:
# If the connection could not be established, exit
# Should properly handle the exit with http error code here
break
# Indiscriminately forward bytes
self.browser.setblocking(0)
client.setblocking(0)
while True:
try:
request = self.browser.recv(MAX_BUFFER)
client.sendall( request )
except socket.error as err:
pass
try:
reply = client.recv(MAX_BUFFER)
self.browser.sendall( reply )
except socket.error as err:
pass
print ("Client at ", self.ssl_browser , " disconnected...")
def get_domain_port(self, request):
first_line = request.split('\n')[0]
# get url
url = first_line.split(' ')[1]
http_pos = url.find("://") # find pos of ://
if (http_pos==-1):
temp = url
else:
temp = url[(http_pos+3):] # get the rest of url
port_pos = temp.find(":") # find the port pos (if any)
# find end of web server
webserver_pos = temp.find("/")
if webserver_pos == -1:
webserver_pos = len(temp)
webserver = ""
port = -1
if (port_pos==-1 or webserver_pos < port_pos):
# default port
port = 80
webserver = temp[:webserver_pos]
else: # specific port
port = int((temp[(port_pos+1):])[:webserver_pos-port_pos-1])
webserver = temp[:port_pos]
return webserver, port
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('192.168.1.107', 80))
sock.listen(5)
while True:
conn, addr = sock.accept()
newthread = ClientThread(addr, conn)
newthread.daemon = True
newthread.start()
sock.shutdown(socket.SHUT_RDWR)
sock.close()
if __name__ == "__main__":
main()
Upvotes: 0
Views: 517
Reputation: 123270
The normal way is to have a HTTP proxy and use plain CONNECT method to create a tunnel. This tunnel is then used for end-to-end encrypted HTTPS between client and server.
It is possible though to also encrypt the connection between client and proxy, which for the HTTPS tunnel then results in encryption between client and proxy on top of encryption between client and server. To do this you need create not a plain socket, but a SSL socket with certificate etc - there are lots of documentation and examples on how to do this.
Note that this setup is not universally supported. Some browsers like Firefox do support this while others don't. Non-browser clients commonly don't support such a setup.
Upvotes: 1