From 1f47f7b6b29cd1229264edf75194652824d94705 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sat, 30 Aug 2014 20:15:19 +0200 Subject: refactor protocol handling, fix #332 --- libmproxy/proxy/config.py | 9 +++++++- libmproxy/proxy/primitives.py | 7 ------ libmproxy/proxy/server.py | 50 ++++++++++++++++++------------------------- 3 files changed, 29 insertions(+), 37 deletions(-) (limited to 'libmproxy/proxy') diff --git a/libmproxy/proxy/config.py b/libmproxy/proxy/config.py index afa7440c..6d4c078b 100644 --- a/libmproxy/proxy/config.py +++ b/libmproxy/proxy/config.py @@ -15,7 +15,7 @@ class ProxyConfig: no_upstream_cert=False, body_size_limit=None, mode=None, upstream_server=None, http_form_in=None, http_form_out=None, authenticator=None, ignore=[], - ciphers=None, certs=[], certforward=False): + ciphers=None, certs=[], certforward=False, ssl_ports=TRANSPARENT_SSL_PORTS): self.ciphers = ciphers self.clientcerts = clientcerts self.no_upstream_cert = no_upstream_cert @@ -49,6 +49,7 @@ class ProxyConfig: for spec, cert in certs: self.certstore.add_cert_file(spec, cert) self.certforward = certforward + self.ssl_ports = ssl_ports def process_proxy_options(parser, options): @@ -157,4 +158,10 @@ def ssl_option_group(parser): "--no-upstream-cert", default=False, action="store_true", dest="no_upstream_cert", help="Don't connect to upstream server to look up certificate details." + ) + group.add_argument( + "--ssl-port", action="append", type=int, dest="ssl_ports", default=TRANSPARENT_SSL_PORTS, + metavar="PORT", + help="Can be passed multiple times. Specify destination ports which are assumed to be SSL. " + "Defaults to %s." % str(TRANSPARENT_SSL_PORTS) ) \ No newline at end of file diff --git a/libmproxy/proxy/primitives.py b/libmproxy/proxy/primitives.py index dc4b7e22..f2c0a984 100644 --- a/libmproxy/proxy/primitives.py +++ b/libmproxy/proxy/primitives.py @@ -6,13 +6,6 @@ class ProxyError(Exception): super(ProxyError, self).__init__(self, message) self.code, self.headers = code, headers -class ConnectionTypeChange(Exception): - """ - Gets raised if the connection type has been changed (e.g. after HTTP/1.1 101 Switching Protocols). - It's up to the raising ProtocolHandler to specify the new conntype before raising the exception. - """ - pass - class ProxyServerError(Exception): pass diff --git a/libmproxy/proxy/server.py b/libmproxy/proxy/server.py index 02b86d71..56e8860b 100644 --- a/libmproxy/proxy/server.py +++ b/libmproxy/proxy/server.py @@ -5,10 +5,9 @@ import socket from OpenSSL import SSL from netlib import tcp -from .primitives import ProxyServerError, Log, ProxyError, ConnectionTypeChange, \ - AddressPriority +from .primitives import ProxyServerError, Log, ProxyError, AddressPriority from .connection import ClientConnection, ServerConnection -from ..protocol.handle import handle_messages, handle_error, handle_server_reconnect +from ..protocol.handle import protocol_handler from .. import version @@ -66,7 +65,6 @@ class ConnectionHandler: """@type: libmproxy.proxy.connection.ServerConnection""" self.channel, self.server_version = channel, server_version - self.close = False self.conntype = "http" self.sni = None @@ -77,28 +75,28 @@ class ConnectionHandler: # Can we already identify the target server and connect to it? client_ssl, server_ssl = False, False if self.config.get_upstream_server: - upstream_info = self.config.get_upstream_server( - self.client_conn.connection) + upstream_info = self.config.get_upstream_server(self.client_conn.connection) self.set_server_address(upstream_info[2:], AddressPriority.FROM_SETTINGS) client_ssl, server_ssl = upstream_info[:2] + if self.check_ignore_address(self.server_conn.address): + self.log("Ignore host: %s:%s" % self.server_conn.address(), "info") + self.conntype = "tcp" + client_ssl, server_ssl = False, False - self.determine_conntype() self.channel.ask("clientconnect", self) + # Check for existing connection: If an inline script already established a + # connection, do not apply client_ssl or server_ssl. if self.server_conn and not self.server_conn.connection: self.establish_server_connection() if client_ssl or server_ssl: self.establish_ssl(client=client_ssl, server=server_ssl) - while not self.close: - try: - handle_messages(self.conntype, self) - except ConnectionTypeChange: - self.log("Connection type changed: %s" % self.conntype, "info") - continue + # Delegate handling to the protocol handler + protocol_handler(self.conntype)(self).handle_messages() except (ProxyError, tcp.NetLibError), e: - handle_error(self.conntype, self, e) + protocol_handler(self.conntype)(self).handle_error(e) except Exception: import traceback, sys @@ -106,7 +104,6 @@ class ConnectionHandler: print >> sys.stderr, traceback.format_exc() print >> sys.stderr, "mitmproxy has crashed!" print >> sys.stderr, "Please lodge a bug report at: https://github.com/mitmproxy/mitmproxy" - raise self.del_server_connection() self.log("clientdisconnect", "info") @@ -124,12 +121,13 @@ class ConnectionHandler: self.server_conn = None self.sni = None - def determine_conntype(self): - if self.server_conn and any(rex.search(self.server_conn.address.host) for rex in self.config.ignore): - self.log("Ignore host: %s" % self.server_conn.address.host, "info") - self.conntype = "tcp" + def check_ignore_address(self, address): + address = tcp.Address.wrap(address) + host = "%s:%s" % (address.host, address.port) + if host and any(rex.search(host) for rex in self.config.ignore): + return True else: - self.conntype = "http" + return False def set_server_address(self, address, priority): """ @@ -175,15 +173,8 @@ class ConnectionHandler: def establish_ssl(self, client=False, server=False): """ Establishes SSL on the existing connection(s) to the server or the client, - as specified by the parameters. If the target server is on the pass-through list, - the conntype attribute will be changed and a ConnTypeChanged exception will be raised. + as specified by the parameters. """ - # If the host is on our ignore list, change to passthrough/ignore mode. - for host in (self.server_conn.address.host, self.sni): - if host and any(rex.search(host) for rex in self.config.ignore): - self.log("Ignore host: %s" % host, "info") - self.conntype = "tcp" - raise ConnectionTypeChange() # Logging if client or server: @@ -224,7 +215,7 @@ class ConnectionHandler: self.establish_server_connection() for s in state: - handle_server_reconnect(s[0], self, s[1]) + protocol_handler(s[0])(self).handle_server_reconnect(s[1]) self.server_conn.state = state if had_ssl: @@ -288,4 +279,5 @@ class ConnectionHandler: # make dang sure it doesn't happen. except Exception: # pragma: no cover import traceback + self.log("Error in handle_sni:\r\n" + traceback.format_exc(), "error") \ No newline at end of file -- cgit v1.2.3