0

I'm writing a really simple web proxy through python and right now I'm working on dealing with HTTPS CONNECT requests so I can open HTTPS websites. I'm trying to set up an SSL tunnel but my code is just not quite right. I think I'm close but if someone could take a look and push me in the right direction that would be great. My current understanding of what I'm supposed to do is

  • Recognize that the request is a CONNECT request
  • Send a message back to the browser as I have defined in the variable connect_req in my code
  • That's about it

Here's my code:

def ProxyThread(conn, client_addr):
    request = conn.recv(MAX_BUFFER)
    #print request
    # Parsing
    method, webserver, port = ParseReq(request)
    print 'Request = ' + method + ' ' + webserver + ':' + str(port) + '\n'

    try:
        serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        serverSocket.connect((webserver, port))

        if method == 'CONNECT':
            connect_req = 'HTTP/1.1 200 Connection established\r\n'
            connect_req += 'Proxy-agent: localhost\r\n\r\n'

            conn.send(connect_req.encode())

        serverSocket.send(connect_req)

        while 1:
            data = serverSocket.recv(MAX_BUFFER)

        # while there is data to receive from server
            if len(data) > 0:
                conn.send(data)

            else:
                break

        serverSocket.close()
        conn.close()

    except socket.error, (message):
        print message

        if conn:
            conn.close()

        if serverSocket:
            serverSocket.close()
        return

Edit 1: Updated code to start a thread when I get a HTTPS req

def ProxyThread(conn, client_addr):
    request = conn.recv(MAX_BUFFER)
    method, webserver, port = ParseReq(request)

    #Handle index out of range exception - Throw out the request
    if method is None or webserver is None or port is -1:
        return

    print 'Request = ' + method + ' ' + webserver + ':' + str(port) + ' START\n'

    serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    try:
        if method == 'CONNECT':
            connect_req = 'HTTP/1.0 200 Connection established\r\n'
            connect_req += 'Proxy-agent: ProxyServer/1.0\r\n'
            connect_req += '\r\n'
            print connect_req
            conn.send(connect_req)
            thread = threading.Thread(target=HTTPSProxyThread, args=(conn, serverSocket))
            thread.start()

        serverSocket.connect((webserver, port))
        serverSocket.send(request)

        while 1:
            data = serverSocket.recv(MAX_BUFFER)

        # while there is data to receive from server
            if len(data) > 0:
                conn.send(data)

            else:
                break

        print 'Request = ' + method + ' ' + webserver + ':' + str(port) + ' FINISH\n'
        serverSocket.close()

        conn.close()


def HTTPSProxyThread(conn, serverSocket):
    while 1:
        request = conn.recv(MAX_BUFFER)
        print request
        method, webserver, port = ParseReq(request)
        serverSocket.connect((webserver, port))
        serverSocket.send(request)

        while 1:
            data = serverSocket.recv(MAX_BUFFER)

        # while there is data to receive from server
            if len(data) > 0:
                conn.send(data)

            else:
                break

Terminal Output Firefox

Jack Cassidy
  • 159
  • 2
  • 14

1 Answers1

0

A lot of people seem to be building their own web proxies in Python, or Node.js these days.

As someone who has spent the past 22 years making a web proxy, I wonder why people do it to themselves, especially where there is free product available on all the main platforms where somebody has already dealt with the issues such as (some of these you will have to deal with later)

  • tunneling (CONNECT)
  • chunking
  • HTTP authentication
  • Funky non-compliant behaviour from a surprising number of servers and clients.
  • performance
  • scalability
  • logging
  • caching
  • policy framework and enforcement
  • etc

Whilst it's a fun way to pass the time for a while, the more of these proxies there are out there, the more broken the web becomes overall if the naive implementations are used for more general traffic. If you're just using this for your own specific deployment requirement, the ignore this comment.

I guess the point I'm trying to make is that making a well-behaved (let alone performant) web proxy is non-trivial.

Adrien
  • 1,061
  • 8
  • 11
  • It's a college assignment... ¯\_(ツ)_/¯ – Jack Cassidy Mar 27 '17 at 22:50
  • Cool - yes should have mentioned it's also educational to learn about these things. To understand CONNECT, you first need to consider that it's actually an HTTP message. The client sends the HTTP message to the server, and the server has to send an HTTP response. In the case of CONNECT, the response message indicates whether the upstream connection succeeded or not (so as a proxy you need to connect upstream, if that's successful you need to send a 200 response, then go into pipelining mode). – Adrien Mar 27 '17 at 23:01
  • Could you go into a bit more detail about how to handle the HTTP CONNECT response. My current understanding of what to do is to send a 'HTTP/1.0 200 Connection established\r\nProxy-agent: ProxyServer/1.0\r\n\r\n' message back to the client and then I'm a bit lost as to what do from there. Currently I just have the thread that's running return in anticipation that the client will now send GET requests after the secure connection has been established, but it just hangs and does nothing. – Jack Cassidy Mar 28 '17 at 18:03
  • You mean how to emit the response? You're the proxy server. All you need to do is send the 200 OK message back. The message must be well-formed for a client to accept it, so it needs a Date, Server etc field. there's no such field as Proxy-Agent either. What is the client and what error is it complaining about? – Adrien Mar 29 '17 at 00:13
  • Yeah sorry, I'm not really being clear on the position I'm in. I know the browser is receiving my 200 OK message, I can go into dev mode in firefox and see it happen. The problem is once I send that message the browser does nothing, nada. No more GET requests or anything. I'll update the question with my current code and a few screenshots of my program output on the terminal window and the firefox screen. Thanks! – Jack Cassidy Mar 29 '17 at 10:14
  • Normally if a browser sits doing nothing it's waiting for something more from the server. Are you certain you completed the message? E.g. blank line at end of headers? – Adrien Mar 29 '17 at 13:33