diff options
Diffstat (limited to 'libmproxy/proxy.py')
-rw-r--r-- | libmproxy/proxy.py | 60 |
1 files changed, 36 insertions, 24 deletions
diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index 4fdeeb65..ab2cdb7c 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -23,13 +23,14 @@ class Log: class ProxyConfig: - def __init__(self, certfile = None, cacert = None, clientcerts = None, no_upstream_cert=False, body_size_limit = None, reverse_proxy=None, transparent_proxy=None, authenticator=None): + def __init__(self, certfile = None, cacert = None, clientcerts = None, no_upstream_cert=False, body_size_limit = None, reverse_proxy=None, forward_proxy=None, transparent_proxy=None, authenticator=None): self.certfile = certfile self.cacert = cacert self.clientcerts = clientcerts self.no_upstream_cert = no_upstream_cert self.body_size_limit = body_size_limit self.reverse_proxy = reverse_proxy + self.forward_proxy = forward_proxy self.transparent_proxy = transparent_proxy self.authenticator = authenticator self.certstore = certutils.CertStore() @@ -158,6 +159,7 @@ class ProxyHandler(tcp.BaseHandler): if not self.server_conn: try: self.server_conn = ServerConnection(self.config, scheme, host, port, sni) + self.channel.ask(self.server_conn) self.server_conn.connect() except tcp.NetLibError, v: raise ProxyError(502, v) @@ -219,7 +221,12 @@ class ProxyHandler(tcp.BaseHandler): # the case, we want to reconnect without sending an error # to the client. while 1: - sc = self.get_server_connection(cc, scheme, host, port, self.sni) + if self.config.forward_proxy: + forward_scheme, forward_host, forward_port = self.config.forward_proxy + sc = self.get_server_connection(cc, forward_scheme, forward_host, forward_port, self.sni) + else: + sc = self.get_server_connection(cc, scheme, host, port, self.sni) + sc.send(request) if sc.requestcount == 1: # add timestamps only for first request (others are not directly affected) request.tcp_setup_timestamp = sc.tcp_setup_timestamp @@ -258,13 +265,13 @@ class ProxyHandler(tcp.BaseHandler): else: response = response_reply self.send_response(response) - if request and http.request_connection_close(request.httpversion, request.headers): + if request and http.connection_close(request.httpversion, request.headers): return # We could keep the client connection when the server # connection needs to go away. However, we want to mimic # behaviour as closely as possible to the client, so we # disconnect. - if http.response_connection_close(response.httpversion, response.headers): + if http.connection_close(response.httpversion, response.headers): return except (IOError, ProxyError, http.HttpError, tcp.NetLibError), e: if hasattr(e, "code"): @@ -310,6 +317,17 @@ class ProxyHandler(tcp.BaseHandler): raise ProxyError(502, "Unable to generate dummy cert.") return ret + def establish_ssl(self, client_conn, host, port): + dummycert = self.find_cert(client_conn, host, port, host) + sni = HandleSNI( + self, client_conn, host, port, + dummycert, self.config.certfile or self.config.cacert + ) + try: + self.convert_to_ssl(dummycert, self.config.certfile or self.config.cacert, handle_sni=sni) + except tcp.NetLibError, v: + raise ProxyError(400, str(v)) + def get_line(self, fp): """ Get a line, possibly preceded by a blank. @@ -329,15 +347,7 @@ class ProxyHandler(tcp.BaseHandler): if port in self.config.transparent_proxy["sslports"]: scheme = "https" if not self.ssl_established: - dummycert = self.find_cert(client_conn, host, port, host) - sni = HandleSNI( - self, client_conn, host, port, - dummycert, self.config.certfile or self.config.cacert - ) - try: - self.convert_to_ssl(dummycert, self.config.certfile or self.config.cacert, handle_sni=sni) - except tcp.NetLibError, v: - raise ProxyError(400, str(v)) + self.establish_ssl(client_conn, host, port) else: scheme = "http" line = self.get_line(self.rfile) @@ -372,15 +382,7 @@ class ProxyHandler(tcp.BaseHandler): '\r\n' ) self.wfile.flush() - dummycert = self.find_cert(client_conn, host, port, host) - sni = HandleSNI( - self, client_conn, host, port, - dummycert, self.config.certfile or self.config.cacert - ) - try: - self.convert_to_ssl(dummycert, self.config.certfile or self.config.cacert, handle_sni=sni) - except tcp.NetLibError, v: - raise ProxyError(400, str(v)) + self.establish_ssl(client_conn, host, port) self.proxy_connect_state = (host, port, httpversion) line = self.rfile.readline(line) @@ -414,10 +416,12 @@ class ProxyHandler(tcp.BaseHandler): ) def read_request_reverse(self, client_conn): + scheme, host, port = self.config.reverse_proxy + if scheme.lower() == "https" and not self.ssl_established: + self.establish_ssl(client_conn, host, port) line = self.get_line(self.rfile) if line == "": return None - scheme, host, port = self.config.reverse_proxy r = http.parse_init_http(line) if not r: raise ProxyError(400, "Bad HTTP request line: %s"%repr(line)) @@ -427,7 +431,7 @@ class ProxyHandler(tcp.BaseHandler): self.rfile, self.wfile, headers, httpversion, self.config.body_size_limit ) return flow.Request( - client_conn, httpversion, host, port, "http", method, path, headers, content, + client_conn, httpversion, host, port, scheme, method, path, headers, content, self.rfile.first_byte_timestamp, utils.timestamp() ) @@ -595,6 +599,13 @@ def process_proxy_options(parser, options): else: rp = None + if options.forward_proxy: + fp = utils.parse_proxy_spec(options.forward_proxy) + if not fp: + return parser.error("Invalid forward proxy specification: %s"%options.forward_proxy) + else: + fp = None + if options.clientcerts: options.clientcerts = os.path.expanduser(options.clientcerts) if not os.path.exists(options.clientcerts) or not os.path.isdir(options.clientcerts): @@ -624,6 +635,7 @@ def process_proxy_options(parser, options): body_size_limit = body_size_limit, no_upstream_cert = options.no_upstream_cert, reverse_proxy = rp, + forward_proxy = fp, transparent_proxy = trans, authenticator = authenticator ) |