diff options
Diffstat (limited to 'libmproxy')
-rw-r--r-- | libmproxy/protocol.py | 39 | ||||
-rw-r--r-- | libmproxy/proxy.py | 4 |
2 files changed, 37 insertions, 6 deletions
diff --git a/libmproxy/protocol.py b/libmproxy/protocol.py index d2459257..dcc8b75e 100644 --- a/libmproxy/protocol.py +++ b/libmproxy/protocol.py @@ -136,7 +136,8 @@ class HTTPRequest(HTTPMessage): def is_live(self): return True - def _assemble_request_line(self, form): + def _assemble_request_line(self, form=None): + form = form or self.form_out request_line = None if form == "asterisk" or form == "origin": request_line = '%s %s HTTP/%s.%s' % (self.method, self.path, self.httpversion[0], self.httpversion[1]) @@ -152,7 +153,7 @@ class HTTPRequest(HTTPMessage): return request_line def _assemble(self): - request_line = self._assemble_request_line(self.form_out) + request_line = self._assemble_request_line() return '%s\r\n%s\r\n%s' % (request_line, self._assemble_headers(), self.content) @classmethod @@ -267,7 +268,7 @@ class HTTPHandler(ProtocolHandler): return False if flow.request.form_in == "authority": - self.ssl_upgrade() + self.ssl_upgrade(flow.request) return True except HttpAuthenticationError, e: self.process_error(flow, code=407, message="Proxy Authentication Required", headers=e.auth_headers) @@ -305,10 +306,40 @@ class HTTPHandler(ProtocolHandler): self.c.client_conn.wfile.write(html_content) self.c.client_conn.wfile.flush() - def ssl_upgrade(self): + def ssl_upgrade(self, upstream_request=None): + """ + Upgrade the connection to SSL after an authority (CONNECT) request has been made. + If the authority request has been forwarded upstream (because we have another proxy server there), + money-patch the ConnectionHandler.server_reconnect function to resend the request on reconnect. + + This isn't particular beautiful code, but it isolates this rare edge-case from the + protocol-agnostic ConnectionHandler + """ self.c.mode = "transparent" self.c.determine_conntype() self.c.establish_ssl(server=True, client=True) + + if upstream_request: + self.c.log("Hook reconnect function") + original_reconnect_func = self.c.server_reconnect + + def reconnect_http_proxy(): + self.c.log("Hooked reconnect function") + self.c.log("Hook: Run original redirect") + original_reconnect_func(no_ssl=True) + self.c.log("Hook: Write CONNECT request to upstream proxy", [upstream_request._assemble_request_line()]) + self.c.server_conn.wfile.write(upstream_request._assemble()) + self.c.server_conn.wfile.flush() + self.c.log("Hook: Read answer to CONNECT request from proxy") + resp = HTTPResponse.from_stream(self.c.server_conn.rfile, upstream_request.method) + if resp.code != 200: + raise ProxyError(resp.code, + "Cannot reestablish SSL connection with upstream proxy: \r\n" + str(resp.headers)) + self.c.log("Hook: Establish SSL with upstream proxy") + self.c.establish_ssl(server=True) + + self.c.server_reconnect = reconnect_http_proxy + raise ConnectionTypeChange def process_request(self, request): diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index 6ee3398a..854cc22b 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -242,11 +242,11 @@ class ConnectionHandler: self.client_conn.convert_to_ssl(dummycert, self.config.certfile or self.config.cacert, handle_sni=self.handle_sni) - def server_reconnect(self): + def server_reconnect(self, no_ssl=False): self.log("server reconnect") had_ssl, sni = self.server_conn.ssl_established, self.sni self.establish_server_connection(*self.server_conn.address) - if had_ssl: + if had_ssl and not no_ssl: self.sni = sni self.establish_ssl(server=True) |