From a05a70d8168a07c92b2a3ecbbb1958d85532efe3 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 30 May 2015 12:03:28 +1200 Subject: Add coding style check, reformat. --- libmproxy/proxy/config.py | 72 +++++++++++++++++++++----------- libmproxy/proxy/connection.py | 32 ++++++++++----- libmproxy/proxy/primitives.py | 15 ++++--- libmproxy/proxy/server.py | 95 ++++++++++++++++++++++++++++++++----------- 4 files changed, 150 insertions(+), 64 deletions(-) (limited to 'libmproxy/proxy') diff --git a/libmproxy/proxy/config.py b/libmproxy/proxy/config.py index dfde2958..3f579669 100644 --- a/libmproxy/proxy/config.py +++ b/libmproxy/proxy/config.py @@ -81,16 +81,27 @@ class ProxyConfig: self.check_tcp = HostMatcher(tcp_hosts) self.authenticator = authenticator self.cadir = os.path.expanduser(cadir) - self.certstore = certutils.CertStore.from_store(self.cadir, CONF_BASENAME) + self.certstore = certutils.CertStore.from_store( + self.cadir, + CONF_BASENAME) for spec, cert in certs: self.certstore.add_cert_file(spec, cert) self.certforward = certforward - self.openssl_method_client, self.openssl_options_client = version_to_openssl(ssl_version_client) - self.openssl_method_server, self.openssl_options_server = version_to_openssl(ssl_version_server) + self.openssl_method_client, self.openssl_options_client = version_to_openssl( + ssl_version_client) + self.openssl_method_server, self.openssl_options_server = version_to_openssl( + ssl_version_server) self.ssl_ports = ssl_ports -sslversion_choices = ("all", "secure", "SSLv2", "SSLv3", "TLSv1", "TLSv1_1", "TLSv1_2") +sslversion_choices = ( + "all", + "secure", + "SSLv2", + "SSLv3", + "TLSv1", + "TLSv1_1", + "TLSv1_2") def version_to_openssl(version): @@ -119,7 +130,8 @@ def process_proxy_options(parser, options): if options.transparent_proxy: c += 1 if not platform.resolver: - return parser.error("Transparent mode not supported on this platform.") + return parser.error( + "Transparent mode not supported on this platform.") mode = "transparent" if options.socks_proxy: c += 1 @@ -133,28 +145,33 @@ def process_proxy_options(parser, options): mode = "upstream" upstream_server = options.upstream_proxy if c > 1: - return parser.error("Transparent, SOCKS5, reverse and upstream proxy mode " - "are mutually exclusive.") + return parser.error( + "Transparent, SOCKS5, reverse and upstream proxy mode " + "are mutually exclusive.") if options.clientcerts: options.clientcerts = os.path.expanduser(options.clientcerts) - if not os.path.exists(options.clientcerts) or not os.path.isdir(options.clientcerts): + if not os.path.exists( + options.clientcerts) or not os.path.isdir( + options.clientcerts): return parser.error( - "Client certificate directory does not exist or is not a directory: %s" % options.clientcerts - ) + "Client certificate directory does not exist or is not a directory: %s" % + options.clientcerts) if (options.auth_nonanonymous or options.auth_singleuser or options.auth_htpasswd): if options.auth_singleuser: if len(options.auth_singleuser.split(':')) != 2: - return parser.error("Invalid single-user specification. Please use the format username:password") + return parser.error( + "Invalid single-user specification. Please use the format username:password") username, password = options.auth_singleuser.split(':') password_manager = http_auth.PassManSingleUser(username, password) elif options.auth_nonanonymous: password_manager = http_auth.PassManNonAnon() elif options.auth_htpasswd: try: - password_manager = http_auth.PassManHtpasswd(options.auth_htpasswd) - except ValueError, v: + password_manager = http_auth.PassManHtpasswd( + options.auth_htpasswd) + except ValueError as v: return parser.error(v.message) authenticator = http_auth.BasicProxyAuth(password_manager, "mitmproxy") else: @@ -203,15 +220,18 @@ def process_proxy_options(parser, options): def ssl_option_group(parser): group = parser.add_argument_group("SSL") group.add_argument( - "--cert", dest='certs', default=[], type=str, - metavar="SPEC", action="append", + "--cert", + dest='certs', + default=[], + type=str, + metavar="SPEC", + action="append", help='Add an SSL certificate. SPEC is of the form "[domain=]path". ' - 'The domain may include a wildcard, and is equal to "*" if not specified. ' - 'The file at path is a certificate in PEM format. If a private key is included in the PEM, ' - 'it is used, else the default key in the conf dir is used. ' - 'The PEM file should contain the full certificate chain, with the leaf certificate as the first entry. ' - 'Can be passed multiple times.' - ) + 'The domain may include a wildcard, and is equal to "*" if not specified. ' + 'The file at path is a certificate in PEM format. If a private key is included in the PEM, ' + 'it is used, else the default key in the conf dir is used. ' + 'The PEM file should contain the full certificate chain, with the leaf certificate as the first entry. ' + 'Can be passed multiple times.') group.add_argument( "--cert-forward", action="store_true", dest="certforward", default=False, @@ -238,11 +258,15 @@ def ssl_option_group(parser): 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=list(TRANSPARENT_SSL_PORTS), + "--ssl-port", + action="append", + type=int, + dest="ssl_ports", + default=list(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) - ) + "Defaults to %s." % + str(TRANSPARENT_SSL_PORTS)) group.add_argument( "--ssl-version-client", dest="ssl_version_client", default="secure", action="store", diff --git a/libmproxy/proxy/connection.py b/libmproxy/proxy/connection.py index 1eeae16f..5219023b 100644 --- a/libmproxy/proxy/connection.py +++ b/libmproxy/proxy/connection.py @@ -7,7 +7,9 @@ from .. import stateobject, utils class ClientConnection(tcp.BaseHandler, stateobject.StateObject): def __init__(self, client_connection, address, server): - if client_connection: # Eventually, this object is restored from state. We don't have a connection then. + # Eventually, this object is restored from state. We don't have a + # connection then. + if client_connection: tcp.BaseHandler.__init__(self, client_connection, address, server) else: self.connection = None @@ -39,15 +41,18 @@ class ClientConnection(tcp.BaseHandler, stateobject.StateObject): def get_state(self, short=False): d = super(ClientConnection, self).get_state(short) d.update( - address={"address": self.address(), "use_ipv6": self.address.use_ipv6}, - clientcert=self.cert.to_pem() if self.clientcert else None - ) + address={ + "address": self.address(), + "use_ipv6": self.address.use_ipv6}, + clientcert=self.cert.to_pem() if self.clientcert else None) return d def load_state(self, state): super(ClientConnection, self).load_state(state) - self.address = tcp.Address(**state["address"]) if state["address"] else None - self.clientcert = certutils.SSLCert.from_pem(state["clientcert"]) if state["clientcert"] else None + self.address = tcp.Address( + **state["address"]) if state["address"] else None + self.clientcert = certutils.SSLCert.from_pem( + state["clientcert"]) if state["clientcert"] else None def copy(self): return copy.copy(self) @@ -114,7 +119,7 @@ class ServerConnection(tcp.TCPClient, stateobject.StateObject): address={"address": self.address(), "use_ipv6": self.address.use_ipv6}, source_address= ({"address": self.source_address(), - "use_ipv6": self.source_address.use_ipv6} if self.source_address else None), + "use_ipv6": self.source_address.use_ipv6} if self.source_address else None), cert=self.cert.to_pem() if self.cert else None ) return d @@ -122,9 +127,12 @@ class ServerConnection(tcp.TCPClient, stateobject.StateObject): def load_state(self, state): super(ServerConnection, self).load_state(state) - self.address = tcp.Address(**state["address"]) if state["address"] else None - self.source_address = tcp.Address(**state["source_address"]) if state["source_address"] else None - self.cert = certutils.SSLCert.from_pem(state["cert"]) if state["cert"] else None + self.address = tcp.Address( + **state["address"]) if state["address"] else None + self.source_address = tcp.Address( + **state["source_address"]) if state["source_address"] else None + self.cert = certutils.SSLCert.from_pem( + state["cert"]) if state["cert"] else None @classmethod def from_state(cls, state): @@ -147,7 +155,9 @@ class ServerConnection(tcp.TCPClient, stateobject.StateObject): def establish_ssl(self, clientcerts, sni, **kwargs): clientcert = None if clientcerts: - path = os.path.join(clientcerts, self.address.host.encode("idna")) + ".pem" + path = os.path.join( + clientcerts, + self.address.host.encode("idna")) + ".pem" if os.path.exists(path): clientcert = path self.convert_to_ssl(cert=clientcert, sni=sni, **kwargs) diff --git a/libmproxy/proxy/primitives.py b/libmproxy/proxy/primitives.py index c0ae424d..9e7dae9a 100644 --- a/libmproxy/proxy/primitives.py +++ b/libmproxy/proxy/primitives.py @@ -1,6 +1,7 @@ from __future__ import absolute_import from netlib import socks + class ProxyError(Exception): def __init__(self, code, message, headers=None): super(ProxyError, self).__init__(message) @@ -61,7 +62,7 @@ class TransparentProxyMode(ProxyMode): def get_upstream_server(self, client_conn): try: dst = self.resolver.original_addr(client_conn.connection) - except Exception, e: + except Exception as e: raise ProxyError(502, "Transparent mode failure: %s" % str(e)) if dst[1] in self.sslports: @@ -87,7 +88,9 @@ class Socks5ProxyMode(ProxyMode): guess = "" raise socks.SocksError( socks.REP.GENERAL_SOCKS_SERVER_FAILURE, - guess + "Invalid SOCKS version. Expected 0x05, got 0x%x" % msg.ver) + guess + + "Invalid SOCKS version. Expected 0x05, got 0x%x" % + msg.ver) def get_upstream_server(self, client_conn): try: @@ -117,13 +120,15 @@ class Socks5ProxyMode(ProxyMode): "mitmproxy only supports SOCKS5 CONNECT." ) - # We do not connect here yet, as the clientconnect event has not been handled yet. + # We do not connect here yet, as the clientconnect event has not + # been handled yet. connect_reply = socks.Message( socks.VERSION.SOCKS5, socks.REP.SUCCEEDED, socks.ATYP.DOMAINNAME, - client_conn.address # dummy value, we don't have an upstream connection yet. + # dummy value, we don't have an upstream connection yet. + client_conn.address ) connect_reply.to_file(client_conn.wfile) client_conn.wfile.flush() @@ -161,4 +166,4 @@ class UpstreamProxyMode(_ConstDestinationProxyMode): class Log: def __init__(self, msg, level="info"): self.msg = msg - self.level = level \ No newline at end of file + self.level = level diff --git a/libmproxy/proxy/server.py b/libmproxy/proxy/server.py index a72f9aba..e1587df1 100644 --- a/libmproxy/proxy/server.py +++ b/libmproxy/proxy/server.py @@ -34,7 +34,7 @@ class ProxyServer(tcp.TCPServer): self.config = config try: tcp.TCPServer.__init__(self, (config.host, config.port)) - except socket.error, v: + except socket.error as v: raise ProxyServerError('Error starting proxy server: ' + repr(v)) self.channel = None @@ -46,16 +46,30 @@ class ProxyServer(tcp.TCPServer): self.channel = channel def handle_client_connection(self, conn, client_address): - h = ConnectionHandler(self.config, conn, client_address, self, self.channel) + h = ConnectionHandler( + self.config, + conn, + client_address, + self, + self.channel) h.handle() h.finish() class ConnectionHandler: - def __init__(self, config, client_connection, client_address, server, channel): + def __init__( + self, + config, + client_connection, + client_address, + server, + channel): self.config = config """@type: libmproxy.proxy.config.ProxyConfig""" - self.client_conn = ClientConnection(client_connection, client_address, server) + self.client_conn = ClientConnection( + client_connection, + client_address, + server) """@type: libmproxy.proxy.connection.ClientConnection""" self.server_conn = None """@type: libmproxy.proxy.connection.ServerConnection""" @@ -70,17 +84,23 @@ class ConnectionHandler: # Can we already identify the target server and connect to it? client_ssl, server_ssl = False, False conn_kwargs = dict() - upstream_info = self.config.mode.get_upstream_server(self.client_conn) + upstream_info = self.config.mode.get_upstream_server( + self.client_conn) if upstream_info: self.set_server_address(upstream_info[2:]) client_ssl, server_ssl = upstream_info[:2] if self.config.check_ignore(self.server_conn.address): - self.log("Ignore host: %s:%s" % self.server_conn.address(), "info") + self.log( + "Ignore host: %s:%s" % + self.server_conn.address(), + "info") self.conntype = "tcp" conn_kwargs["log"] = False client_ssl, server_ssl = False, False else: - pass # No upstream info from the metadata: upstream info in the protocol (e.g. HTTP absolute-form) + # No upstream info from the metadata: upstream info in the + # protocol (e.g. HTTP absolute-form) + pass self.channel.ask("clientconnect", self) @@ -92,11 +112,17 @@ class ConnectionHandler: self.establish_ssl(client=client_ssl, server=server_ssl) if self.config.check_tcp(self.server_conn.address): - self.log("Generic TCP mode for host: %s:%s" % self.server_conn.address(), "info") + self.log( + "Generic TCP mode for host: %s:%s" % + self.server_conn.address(), + "info") self.conntype = "tcp" # Delegate handling to the protocol handler - protocol_handler(self.conntype)(self, **conn_kwargs).handle_messages() + protocol_handler( + self.conntype)( + self, + **conn_kwargs).handle_messages() self.log("clientdisconnect", "info") self.channel.tell("clientdisconnect", self) @@ -104,7 +130,8 @@ class ConnectionHandler: except ProxyError as e: protocol_handler(self.conntype)(self, **conn_kwargs).handle_error(e) except Exception: - import traceback, sys + import traceback + import sys self.log(traceback.format_exc(), "error") print >> sys.stderr, traceback.format_exc() @@ -112,7 +139,8 @@ class ConnectionHandler: print >> sys.stderr, "Please lodge a bug report at: https://github.com/mitmproxy/mitmproxy" finally: # Make sure that we close the server connection in any case. - # The client connection is closed by the ProxyServer and does not have be handled here. + # The client connection is closed by the ProxyServer and does not + # have be handled here. self.del_server_connection() def del_server_connection(self): @@ -122,8 +150,10 @@ class ConnectionHandler: if self.server_conn and self.server_conn.connection: self.server_conn.finish() self.server_conn.close() - self.log("serverdisconnect", "debug", ["%s:%s" % (self.server_conn.address.host, - self.server_conn.address.port)]) + self.log( + "serverdisconnect", "debug", [ + "%s:%s" % + (self.server_conn.address.host, self.server_conn.address.port)]) self.channel.tell("serverdisconnect", self) self.server_conn = None @@ -141,7 +171,9 @@ class ConnectionHandler: if self.server_conn: self.del_server_connection() - self.log("Set new server address: %s:%s" % (address.host, address.port), "debug") + self.log( + "Set new server address: %s:%s" % + (address.host, address.port), "debug") self.server_conn = ServerConnection(address) def establish_server_connection(self, ask=True): @@ -155,12 +187,16 @@ class ConnectionHandler: """ if self.server_conn.connection: return - self.log("serverconnect", "debug", ["%s:%s" % self.server_conn.address()[:2]]) + self.log( + "serverconnect", "debug", [ + "%s:%s" % + self.server_conn.address()[ + :2]]) if ask: self.channel.ask("serverconnect", self) try: self.server_conn.connect() - except tcp.NetLibError, v: + except tcp.NetLibError as v: raise ProxyError(502, v) def establish_ssl(self, client=False, server=False, sni=None): @@ -237,7 +273,8 @@ class ConnectionHandler: self.server_conn.state = state # Receiving new_sni where had_ssl is False is a weird case that happens when the workaround for - # https://github.com/mitmproxy/mitmproxy/issues/427 is active. In this case, we want to establish SSL as well. + # https://github.com/mitmproxy/mitmproxy/issues/427 is active. In this + # case, we want to establish SSL as well. if had_ssl or new_sni: self.establish_ssl(server=True, sni=sni) @@ -246,8 +283,10 @@ class ConnectionHandler: def log(self, msg, level, subs=()): msg = [ - "%s:%s: %s" % (self.client_conn.address.host, self.client_conn.address.port, msg) - ] + "%s:%s: %s" % + (self.client_conn.address.host, + self.client_conn.address.port, + msg)] for i in subs: msg.append(" -> " + i) msg = "\n".join(msg) @@ -255,11 +294,13 @@ class ConnectionHandler: def find_cert(self): if self.config.certforward and self.server_conn.ssl_established: - return self.server_conn.cert, self.config.certstore.gen_pkey(self.server_conn.cert), None + return self.server_conn.cert, self.config.certstore.gen_pkey( + self.server_conn.cert), None else: host = self.server_conn.address.host sans = [] - if self.server_conn.ssl_established and (not self.config.no_upstream_cert): + if self.server_conn.ssl_established and ( + not self.config.no_upstream_cert): upstream_cert = self.server_conn.cert sans.extend(upstream_cert.altnames) if upstream_cert.cn: @@ -291,8 +332,11 @@ class ConnectionHandler: # - We established SSL with the server previously # - We initially wanted to establish SSL with the server, # but the server refused to negotiate without SNI. - if self.server_conn.ssl_established or hasattr(self.server_conn, "may_require_sni"): - self.server_reconnect(sni) # reconnect to upstream server with SNI + if self.server_conn.ssl_established or hasattr( + self.server_conn, + "may_require_sni"): + # reconnect to upstream server with SNI + self.server_reconnect(sni) # Now, change client context to reflect changed certificate: cert, key, chain_file = self.find_cert() new_context = self.client_conn.create_ssl_context( @@ -308,4 +352,7 @@ class ConnectionHandler: # make dang sure it doesn't happen. except: # pragma: no cover import traceback - self.log("Error in handle_sni:\r\n" + traceback.format_exc(), "error") + self.log( + "Error in handle_sni:\r\n" + + traceback.format_exc(), + "error") -- cgit v1.2.3 From 59ec291b6cff1dfa83b316401418b6308df93aac Mon Sep 17 00:00:00 2001 From: iroiro123 Date: Thu, 18 Jun 2015 23:53:27 +0900 Subject: HTTP Transparent Proxy --- libmproxy/proxy/config.py | 7 ++++++- libmproxy/proxy/primitives.py | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'libmproxy/proxy') diff --git a/libmproxy/proxy/config.py b/libmproxy/proxy/config.py index 3f579669..2074d0bf 100644 --- a/libmproxy/proxy/config.py +++ b/libmproxy/proxy/config.py @@ -4,7 +4,7 @@ import re from OpenSSL import SSL from netlib import http_auth, certutils, tcp from .. import utils, platform, version -from .primitives import RegularProxyMode, TransparentProxyMode, UpstreamProxyMode, ReverseProxyMode, Socks5ProxyMode +from .primitives import RegularProxyMode, HTTPTransparentProxyMode, TransparentProxyMode, UpstreamProxyMode, ReverseProxyMode, Socks5ProxyMode TRANSPARENT_SSL_PORTS = [443, 8443] CONF_BASENAME = "mitmproxy" @@ -70,6 +70,8 @@ class ProxyConfig: self.mode = ReverseProxyMode(upstream_server) elif mode == "upstream": self.mode = UpstreamProxyMode(upstream_server) + elif mode == "httptransparent": + self.mode = HTTPTransparentProxyMode() else: self.mode = RegularProxyMode() @@ -144,6 +146,9 @@ def process_proxy_options(parser, options): c += 1 mode = "upstream" upstream_server = options.upstream_proxy + if options.http_transparent_proxy: + c += 1 + mode = "httptransparent" if c > 1: return parser.error( "Transparent, SOCKS5, reverse and upstream proxy mode " diff --git a/libmproxy/proxy/primitives.py b/libmproxy/proxy/primitives.py index 9e7dae9a..a9718051 100644 --- a/libmproxy/proxy/primitives.py +++ b/libmproxy/proxy/primitives.py @@ -51,6 +51,14 @@ class RegularProxyMode(ProxyMode): return None +class HTTPTransparentProxyMode(ProxyMode): + http_form_in = "relative" + http_form_out = "relative" + + def get_upstream_server(self, client_conn): + return None + + class TransparentProxyMode(ProxyMode): http_form_in = "relative" http_form_out = "relative" -- cgit v1.2.3 From 378aa783243cf23d84a39d02dde5420beadc188b Mon Sep 17 00:00:00 2001 From: iroiro123 Date: Sat, 20 Jun 2015 21:43:50 +0900 Subject: Spoof mode --- libmproxy/proxy/config.py | 10 +++++----- libmproxy/proxy/primitives.py | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'libmproxy/proxy') diff --git a/libmproxy/proxy/config.py b/libmproxy/proxy/config.py index 2074d0bf..7305d72a 100644 --- a/libmproxy/proxy/config.py +++ b/libmproxy/proxy/config.py @@ -4,7 +4,7 @@ import re from OpenSSL import SSL from netlib import http_auth, certutils, tcp from .. import utils, platform, version -from .primitives import RegularProxyMode, HTTPTransparentProxyMode, TransparentProxyMode, UpstreamProxyMode, ReverseProxyMode, Socks5ProxyMode +from .primitives import RegularProxyMode, SpoofMode, TransparentProxyMode, UpstreamProxyMode, ReverseProxyMode, Socks5ProxyMode TRANSPARENT_SSL_PORTS = [443, 8443] CONF_BASENAME = "mitmproxy" @@ -70,8 +70,8 @@ class ProxyConfig: self.mode = ReverseProxyMode(upstream_server) elif mode == "upstream": self.mode = UpstreamProxyMode(upstream_server) - elif mode == "httptransparent": - self.mode = HTTPTransparentProxyMode() + elif mode == "spoof": + self.mode = SpoofMode() else: self.mode = RegularProxyMode() @@ -146,9 +146,9 @@ def process_proxy_options(parser, options): c += 1 mode = "upstream" upstream_server = options.upstream_proxy - if options.http_transparent_proxy: + if options.spoof_mode: c += 1 - mode = "httptransparent" + mode = "spoof" if c > 1: return parser.error( "Transparent, SOCKS5, reverse and upstream proxy mode " diff --git a/libmproxy/proxy/primitives.py b/libmproxy/proxy/primitives.py index a9718051..f514d37f 100644 --- a/libmproxy/proxy/primitives.py +++ b/libmproxy/proxy/primitives.py @@ -51,13 +51,17 @@ class RegularProxyMode(ProxyMode): return None -class HTTPTransparentProxyMode(ProxyMode): +class SpoofMode(ProxyMode): http_form_in = "relative" http_form_out = "relative" def get_upstream_server(self, client_conn): return None + @property + def name(self): + return "spoof" + class TransparentProxyMode(ProxyMode): http_form_in = "relative" -- cgit v1.2.3 From fd903673299c050b7b4137aabf6b9265df3d6233 Mon Sep 17 00:00:00 2001 From: iroiro123 Date: Sun, 21 Jun 2015 00:51:56 +0900 Subject: SSL Spoof mode --- libmproxy/proxy/config.py | 16 ++++++++++++---- libmproxy/proxy/primitives.py | 15 +++++++++++++++ libmproxy/proxy/server.py | 19 +++++++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) (limited to 'libmproxy/proxy') diff --git a/libmproxy/proxy/config.py b/libmproxy/proxy/config.py index 7305d72a..07dc5c89 100644 --- a/libmproxy/proxy/config.py +++ b/libmproxy/proxy/config.py @@ -4,7 +4,7 @@ import re from OpenSSL import SSL from netlib import http_auth, certutils, tcp from .. import utils, platform, version -from .primitives import RegularProxyMode, SpoofMode, TransparentProxyMode, UpstreamProxyMode, ReverseProxyMode, Socks5ProxyMode +from .primitives import RegularProxyMode, SpoofMode, SSLSpoofMode, TransparentProxyMode, UpstreamProxyMode, ReverseProxyMode, Socks5ProxyMode TRANSPARENT_SSL_PORTS = [443, 8443] CONF_BASENAME = "mitmproxy" @@ -51,7 +51,8 @@ class ProxyConfig: certforward=False, ssl_version_client="secure", ssl_version_server="secure", - ssl_ports=TRANSPARENT_SSL_PORTS + ssl_ports=TRANSPARENT_SSL_PORTS, + spoofed_ssl_port=None ): self.host = host self.port = port @@ -72,6 +73,8 @@ class ProxyConfig: self.mode = UpstreamProxyMode(upstream_server) elif mode == "spoof": self.mode = SpoofMode() + elif mode == "sslspoof": + self.mode = SSLSpoofMode(spoofed_ssl_port) else: self.mode = RegularProxyMode() @@ -128,7 +131,7 @@ def process_proxy_options(parser, options): body_size_limit = utils.parse_size(options.body_size_limit) c = 0 - mode, upstream_server = None, None + mode, upstream_server, spoofed_ssl_port = None, None, None if options.transparent_proxy: c += 1 if not platform.resolver: @@ -149,6 +152,10 @@ def process_proxy_options(parser, options): if options.spoof_mode: c += 1 mode = "spoof" + if options.ssl_spoof_mode: + c += 1 + mode = "sslspoof" + spoofed_ssl_port = options.spoofed_ssl_port if c > 1: return parser.error( "Transparent, SOCKS5, reverse and upstream proxy mode " @@ -218,7 +225,8 @@ def process_proxy_options(parser, options): certforward=options.certforward, ssl_version_client=options.ssl_version_client, ssl_version_server=options.ssl_version_server, - ssl_ports=ssl_ports + ssl_ports=ssl_ports, + spoofed_ssl_port=spoofed_ssl_port ) diff --git a/libmproxy/proxy/primitives.py b/libmproxy/proxy/primitives.py index f514d37f..b01ddde3 100644 --- a/libmproxy/proxy/primitives.py +++ b/libmproxy/proxy/primitives.py @@ -63,6 +63,21 @@ class SpoofMode(ProxyMode): return "spoof" +class SSLSpoofMode(ProxyMode): + http_form_in = "relative" + http_form_out = "relative" + + def __init__(self, sslport): + self.sslport = sslport + + def get_upstream_server(self, client_conn): + return None + + @property + def name(self): + return "sslspoof" + + class TransparentProxyMode(ProxyMode): http_form_in = "relative" http_form_out = "relative" diff --git a/libmproxy/proxy/server.py b/libmproxy/proxy/server.py index e1587df1..df890f7c 100644 --- a/libmproxy/proxy/server.py +++ b/libmproxy/proxy/server.py @@ -117,6 +117,20 @@ class ConnectionHandler: self.server_conn.address(), "info") self.conntype = "tcp" + + elif not self.server_conn and self.config.mode == "sslspoof": + port = self.config.mode.sslport + self.set_server_address(("-", port)) + self.establish_ssl(client=True) + host = self.client_conn.connection.get_servername() + if host is None: + raise ProxyError( + 400, + "Invalid request: No host information" + ) + self.set_server_address((host, port)) + self.establish_server_connection() + self.establish_ssl(server=True, sni=host) # Delegate handling to the protocol handler protocol_handler( @@ -308,6 +322,9 @@ class ConnectionHandler: host = upstream_cert.cn.decode("utf8").encode("idna") if self.server_conn.sni: sans.append(self.server_conn.sni) + # for ssl spoof mode + if hasattr(self.client_conn, "sni"): + sans.append(self.client_conn.sni) ret = self.config.certstore.get_cert(host, sans) if not ret: @@ -325,6 +342,8 @@ class ConnectionHandler: if not sn: return sni = sn.decode("utf8").encode("idna") + # for ssl spoof mode + self.client_conn.sni = sni if sni != self.server_conn.sni: self.log("SNI received: %s" % sni, "debug") -- cgit v1.2.3 From fbb23b5c9fae6e402d84ddae3c3b8c218def366c Mon Sep 17 00:00:00 2001 From: iroiro123 Date: Tue, 23 Jun 2015 01:49:22 +0900 Subject: changed error handling (ssl spoof mode) --- libmproxy/proxy/server.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'libmproxy/proxy') diff --git a/libmproxy/proxy/server.py b/libmproxy/proxy/server.py index df890f7c..71704413 100644 --- a/libmproxy/proxy/server.py +++ b/libmproxy/proxy/server.py @@ -123,14 +123,10 @@ class ConnectionHandler: self.set_server_address(("-", port)) self.establish_ssl(client=True) host = self.client_conn.connection.get_servername() - if host is None: - raise ProxyError( - 400, - "Invalid request: No host information" - ) - self.set_server_address((host, port)) - self.establish_server_connection() - self.establish_ssl(server=True, sni=host) + if host: + self.set_server_address((host, port)) + self.establish_server_connection() + self.establish_ssl(server=True, sni=host) # Delegate handling to the protocol handler protocol_handler( -- cgit v1.2.3 From 14e49f4fc7a38b63099ab0d42afd213b0d567c0f Mon Sep 17 00:00:00 2001 From: Thomas Kriechbaumer Date: Mon, 22 Jun 2015 20:40:07 +0200 Subject: unify SSL version/method handling --- libmproxy/proxy/config.py | 68 +++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 43 deletions(-) (limited to 'libmproxy/proxy') diff --git a/libmproxy/proxy/config.py b/libmproxy/proxy/config.py index 07dc5c89..b6d73314 100644 --- a/libmproxy/proxy/config.py +++ b/libmproxy/proxy/config.py @@ -49,10 +49,10 @@ class ProxyConfig: ciphers_server=None, certs=[], certforward=False, - ssl_version_client="secure", - ssl_version_server="secure", + ssl_version_client=tcp.SSL_DEFAULT_METHOD, + ssl_version_server=tcp.SSL_DEFAULT_METHOD, ssl_ports=TRANSPARENT_SSL_PORTS, - spoofed_ssl_port=None + spoofed_ssl_port=None, ): self.host = host self.port = port @@ -92,39 +92,19 @@ class ProxyConfig: for spec, cert in certs: self.certstore.add_cert_file(spec, cert) self.certforward = certforward - self.openssl_method_client, self.openssl_options_client = version_to_openssl( - ssl_version_client) - self.openssl_method_server, self.openssl_options_server = version_to_openssl( - ssl_version_server) self.ssl_ports = ssl_ports + if isinstance(ssl_version_client, int): + self.openssl_method_client = ssl_version_client + else: + self.openssl_method_client = tcp.SSL_VERSIONS[ssl_version_client] + if isinstance(ssl_version_server, int): + self.openssl_method_server = ssl_version_server + else: + self.openssl_method_server = tcp.SSL_VERSIONS[ssl_version_server] -sslversion_choices = ( - "all", - "secure", - "SSLv2", - "SSLv3", - "TLSv1", - "TLSv1_1", - "TLSv1_2") - - -def version_to_openssl(version): - """ - Convert a reasonable SSL version specification into the format OpenSSL expects. - Don't ask... - https://bugs.launchpad.net/pyopenssl/+bug/1020632/comments/3 - """ - if version == "all": - return SSL.SSLv23_METHOD, None - elif version == "secure": - # SSLv23_METHOD + NO_SSLv2 + NO_SSLv3 == TLS 1.0+ - # TLSv1_METHOD would be TLS 1.0 only - return SSL.SSLv23_METHOD, (SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3) - elif version in sslversion_choices: - return getattr(SSL, "%s_METHOD" % version), None - else: - raise ValueError("Invalid SSL version: %s" % version) + self.openssl_options_client = tcp.SSL_DEFAULT_OPTIONS + self.openssl_options_server = tcp.SSL_DEFAULT_OPTIONS def process_proxy_options(parser, options): @@ -281,16 +261,18 @@ def ssl_option_group(parser): "Defaults to %s." % str(TRANSPARENT_SSL_PORTS)) group.add_argument( - "--ssl-version-client", dest="ssl_version_client", - default="secure", action="store", - choices=sslversion_choices, - help="Set supported SSL/TLS version for client connections. " - "SSLv2, SSLv3 and 'all' are INSECURE. Defaults to secure." + "--ssl-version-client", dest="ssl_version_client", type=str, default=tcp.SSL_DEFAULT_VERSION, + choices=tcp.SSL_VERSIONS.keys(), + help="""" + Use a specified protocol for client connections: + TLSv1.2, TLSv1.1, TLSv1, SSLv3, SSLv2, SSLv23. + Default to SSLv23.""" ) group.add_argument( - "--ssl-version-server", dest="ssl_version_server", - default="secure", action="store", - choices=sslversion_choices, - help="Set supported SSL/TLS version for server connections. " - "SSLv2, SSLv3 and 'all' are INSECURE. Defaults to secure." + "--ssl-version-server", dest="ssl_version_server", type=str, default=tcp.SSL_DEFAULT_VERSION, + choices=tcp.SSL_VERSIONS.keys(), + help="""" + Use a specified protocol for server connections: + TLSv1.2, TLSv1.1, TLSv1, SSLv3, SSLv2, SSLv23. + Default to SSLv23.""" ) -- cgit v1.2.3