From 9bc1514aefe524a0c6afceec8e2d2afe15acdf66 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 18 Jul 2016 12:05:10 +1200 Subject: Unify proxy config and options This is step 1 in a gradual "boiling frog" strategy. Decorate ProxyConfig with an Options object. --- mitmproxy/main.py | 68 +++++++++++++-------------- mitmproxy/proxy/config.py | 87 ++++++++++++++++++----------------- test/mitmproxy/test_flow.py | 4 +- test/mitmproxy/test_protocol_http2.py | 6 ++- test/mitmproxy/test_proxy.py | 7 ++- test/mitmproxy/tservers.py | 16 ++++--- 6 files changed, 100 insertions(+), 88 deletions(-) diff --git a/mitmproxy/main.py b/mitmproxy/main.py index 316db91a..9b62b63d 100644 --- a/mitmproxy/main.py +++ b/mitmproxy/main.py @@ -41,14 +41,14 @@ def get_server(dummy_server, options): sys.exit(1) -def process_options(parser, options): - if options.sysinfo: +def process_options(parser, options, args): + if args.sysinfo: print(debug.sysinfo()) sys.exit(0) - if options.quiet: - options.verbose = 0 + if args.quiet: + args.verbose = 0 debug.register_info_dumpers() - return config.process_proxy_options(parser, options) + return config.process_proxy_options(parser, options, args) def mitmproxy(args=None): # pragma: no cover @@ -62,18 +62,18 @@ def mitmproxy(args=None): # pragma: no cover assert_utf8_env() parser = cmdline.mitmproxy() - options = parser.parse_args(args) - proxy_config = process_options(parser, options) - - console_options = console.master.Options(**cmdline.get_common_options(options)) - console_options.palette = options.palette - console_options.palette_transparent = options.palette_transparent - console_options.eventlog = options.eventlog - console_options.follow = options.follow - console_options.intercept = options.intercept - console_options.limit = options.limit - console_options.no_mouse = options.no_mouse - + args = parser.parse_args(args) + + console_options = console.master.Options(**cmdline.get_common_options(args)) + console_options.palette = args.palette + console_options.palette_transparent = args.palette_transparent + console_options.eventlog = args.eventlog + console_options.follow = args.follow + console_options.intercept = args.intercept + console_options.limit = args.limit + console_options.no_mouse = args.no_mouse + + proxy_config = process_options(parser, console_options, args) server = get_server(console_options.no_server, proxy_config) try: @@ -93,16 +93,16 @@ def mitmdump(args=None): # pragma: no cover version_check.check_pyopenssl_version() parser = cmdline.mitmdump() - options = parser.parse_args(args) - proxy_config = process_options(parser, options) - if options.quiet: - options.flow_detail = 0 + args = parser.parse_args(args) + if args.quiet: + args.flow_detail = 0 - dump_options = dump.Options(**cmdline.get_common_options(options)) - dump_options.flow_detail = options.flow_detail - dump_options.keepserving = options.keepserving - dump_options.filtstr = " ".join(options.args) if options.args else None + dump_options = dump.Options(**cmdline.get_common_options(args)) + dump_options.flow_detail = args.flow_detail + dump_options.keepserving = args.keepserving + dump_options.filtstr = " ".join(args.args) if args.args else None + proxy_config = process_options(parser, dump_options, args) server = get_server(dump_options.no_server, proxy_config) try: @@ -130,18 +130,18 @@ def mitmweb(args=None): # pragma: no cover parser = cmdline.mitmweb() - options = parser.parse_args(args) - proxy_config = process_options(parser, options) + args = parser.parse_args(args) - web_options = web.master.Options(**cmdline.get_common_options(options)) - web_options.intercept = options.intercept - web_options.wdebug = options.wdebug - web_options.wiface = options.wiface - web_options.wport = options.wport - web_options.wsingleuser = options.wsingleuser - web_options.whtpasswd = options.whtpasswd + web_options = web.master.Options(**cmdline.get_common_options(args)) + web_options.intercept = args.intercept + web_options.wdebug = args.wdebug + web_options.wiface = args.wiface + web_options.wport = args.wport + web_options.wsingleuser = args.wsingleuser + web_options.whtpasswd = args.whtpasswd web_options.process_web_options(parser) + proxy_config = process_options(parser, web_options, args) server = get_server(web_options.no_server, proxy_config) try: diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index 32d881b0..3aa16174 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -59,6 +59,7 @@ class ProxyConfig: def __init__( self, + options, host='', port=8080, cadir=CA_DIR, @@ -83,6 +84,7 @@ class ProxyConfig: ssl_verify_upstream_trusted_ca=None, add_upstream_certs_to_client_chain=False, ): + self.options = options self.host = host self.port = port self.ciphers_client = ciphers_client @@ -125,79 +127,79 @@ class ProxyConfig: self.add_upstream_certs_to_client_chain = add_upstream_certs_to_client_chain -def process_proxy_options(parser, options): - body_size_limit = options.body_size_limit +def process_proxy_options(parser, options, args): + body_size_limit = args.body_size_limit if body_size_limit: body_size_limit = human.parse_size(body_size_limit) c = 0 mode, upstream_server, upstream_auth = "regular", None, None - if options.transparent_proxy: + if args.transparent_proxy: c += 1 if not platform.resolver: return parser.error("Transparent mode not supported on this platform.") mode = "transparent" - if options.socks_proxy: + if args.socks_proxy: c += 1 mode = "socks5" - if options.reverse_proxy: + if args.reverse_proxy: c += 1 mode = "reverse" - upstream_server = options.reverse_proxy - if options.upstream_proxy: + upstream_server = args.reverse_proxy + if args.upstream_proxy: c += 1 mode = "upstream" - upstream_server = options.upstream_proxy - upstream_auth = options.upstream_auth + upstream_server = args.upstream_proxy + upstream_auth = args.upstream_auth if c > 1: return parser.error( "Transparent, SOCKS5, reverse and upstream proxy mode " "are mutually exclusive. Read the docs on proxy modes to understand why." ) - if options.add_upstream_certs_to_client_chain and options.no_upstream_cert: + if args.add_upstream_certs_to_client_chain and args.no_upstream_cert: return parser.error( "The no-upstream-cert and add-upstream-certs-to-client-chain " "options are mutually exclusive. If no-upstream-cert is enabled " "then the upstream certificate is not retrieved before generating " "the client certificate chain." ) - if options.add_upstream_certs_to_client_chain and options.ssl_verify_upstream_cert: + if args.add_upstream_certs_to_client_chain and args.ssl_verify_upstream_cert: return parser.error( "The verify-upstream-cert and add-upstream-certs-to-client-chain " "options are mutually exclusive. If upstream certificates are verified " "then extra upstream certificates are not available for inclusion " "to the client chain." ) - if options.clientcerts: - options.clientcerts = os.path.expanduser(options.clientcerts) - if not os.path.exists(options.clientcerts): + if args.clientcerts: + args.clientcerts = os.path.expanduser(args.clientcerts) + if not os.path.exists(args.clientcerts): return parser.error( - "Client certificate path does not exist: %s" % options.clientcerts + "Client certificate path does not exist: %s" % args.clientcerts ) - if options.auth_nonanonymous or options.auth_singleuser or options.auth_htpasswd: + if args.auth_nonanonymous or args.auth_singleuser or args.auth_htpasswd: - if options.transparent_proxy: + if args.transparent_proxy: return parser.error("Proxy Authentication not supported in transparent mode.") - if options.socks_proxy: + if args.socks_proxy: return parser.error( "Proxy Authentication not supported in SOCKS mode. " "https://github.com/mitmproxy/mitmproxy/issues/738" ) - if options.auth_singleuser: - if len(options.auth_singleuser.split(':')) != 2: + if args.auth_singleuser: + if len(args.auth_singleuser.split(':')) != 2: return parser.error( "Invalid single-user specification. Please use the format username:password" ) - username, password = options.auth_singleuser.split(':') + username, password = args.auth_singleuser.split(':') password_manager = authentication.PassManSingleUser(username, password) - elif options.auth_nonanonymous: + elif args.auth_nonanonymous: password_manager = authentication.PassManNonAnon() - elif options.auth_htpasswd: + elif args.auth_htpasswd: try: password_manager = authentication.PassManHtpasswd( - options.auth_htpasswd) + args.auth_htpasswd) except ValueError as v: return parser.error(v) authenticator = authentication.BasicProxyAuth(password_manager, "mitmproxy") @@ -205,7 +207,7 @@ def process_proxy_options(parser, options): authenticator = authentication.NullProxyAuth(None) certs = [] - for i in options.certs: + for i in args.certs: parts = i.split("=", 1) if len(parts) == 1: parts = ["*", parts[0]] @@ -215,27 +217,28 @@ def process_proxy_options(parser, options): certs.append(parts) return ProxyConfig( - host=options.addr, - port=options.port, - cadir=options.cadir, - clientcerts=options.clientcerts, - no_upstream_cert=options.no_upstream_cert, + options, + host=args.addr, + port=args.port, + cadir=args.cadir, + clientcerts=args.clientcerts, + no_upstream_cert=args.no_upstream_cert, body_size_limit=body_size_limit, mode=mode, upstream_server=upstream_server, upstream_auth=upstream_auth, - ignore_hosts=options.ignore_hosts, - tcp_hosts=options.tcp_hosts, - http2=options.http2, - rawtcp=options.rawtcp, + ignore_hosts=args.ignore_hosts, + tcp_hosts=args.tcp_hosts, + http2=args.http2, + rawtcp=args.rawtcp, authenticator=authenticator, - ciphers_client=options.ciphers_client, - ciphers_server=options.ciphers_server, + ciphers_client=args.ciphers_client, + ciphers_server=args.ciphers_server, certs=tuple(certs), - ssl_version_client=options.ssl_version_client, - ssl_version_server=options.ssl_version_server, - ssl_verify_upstream_cert=options.ssl_verify_upstream_cert, - ssl_verify_upstream_trusted_cadir=options.ssl_verify_upstream_trusted_cadir, - ssl_verify_upstream_trusted_ca=options.ssl_verify_upstream_trusted_ca, - add_upstream_certs_to_client_chain=options.add_upstream_certs_to_client_chain, + ssl_version_client=args.ssl_version_client, + ssl_version_server=args.ssl_version_server, + ssl_verify_upstream_cert=args.ssl_verify_upstream_cert, + ssl_verify_upstream_trusted_cadir=args.ssl_verify_upstream_trusted_cadir, + ssl_verify_upstream_trusted_ca=args.ssl_verify_upstream_trusted_ca, + add_upstream_certs_to_client_chain=args.add_upstream_certs_to_client_chain, ) diff --git a/test/mitmproxy/test_flow.py b/test/mitmproxy/test_flow.py index 90f7f915..a44353e7 100644 --- a/test/mitmproxy/test_flow.py +++ b/test/mitmproxy/test_flow.py @@ -4,6 +4,7 @@ import io import netlib.utils from netlib.http import Headers from mitmproxy import filt, controller, flow +from mitmproxy.flow import options from mitmproxy.contrib import tnetstring from mitmproxy.exceptions import FlowReadException from mitmproxy.models import Error @@ -640,6 +641,7 @@ class TestSerialize: r = self._treader() s = flow.State() conf = ProxyConfig( + options.Options(), mode="reverse", upstream_server=("https", ("use-this-domain", 80)) ) @@ -753,7 +755,7 @@ class TestFlowMaster: pb = [tutils.tflow(resp=True), f] fm = flow.FlowMaster( flow.options.Options(), - DummyServer(ProxyConfig()), + DummyServer(ProxyConfig(options.Options())), s ) assert not fm.start_server_playback( diff --git a/test/mitmproxy/test_protocol_http2.py b/test/mitmproxy/test_protocol_http2.py index b8f724bd..04ca94bf 100644 --- a/test/mitmproxy/test_protocol_http2.py +++ b/test/mitmproxy/test_protocol_http2.py @@ -9,6 +9,7 @@ import traceback import h2 +from mitmproxy.flow import options from mitmproxy.proxy.config import ProxyConfig from mitmproxy.cmdline import APP_HOST, APP_PORT @@ -88,9 +89,10 @@ class _Http2TestBase(object): @classmethod def setup_class(cls): - cls.config = ProxyConfig(**cls.get_proxy_config()) + cls.masteroptions = options.Options() + cls.config = ProxyConfig(cls.masteroptions, **cls.get_proxy_config()) - tmaster = tservers.TestMaster(cls.config) + tmaster = tservers.TestMaster(cls.masteroptions, cls.config) tmaster.start_app(APP_HOST, APP_PORT) cls.proxy = tservers.ProxyThread(tmaster) cls.proxy.start() diff --git a/test/mitmproxy/test_proxy.py b/test/mitmproxy/test_proxy.py index cd24fc9f..f4f73cf5 100644 --- a/test/mitmproxy/test_proxy.py +++ b/test/mitmproxy/test_proxy.py @@ -7,6 +7,7 @@ from mitmproxy.proxy import ProxyConfig from mitmproxy.proxy.config import process_proxy_options from mitmproxy.models.connections import ServerConnection from mitmproxy.proxy.server import DummyServer, ProxyServer, ConnectionHandler +from mitmproxy.flow import options from netlib.exceptions import TcpDisconnect from pathod import test from netlib.http import http1 @@ -58,8 +59,8 @@ class TestProcessProxyOptions: def p(self, *args): parser = tutils.MockParser() cmdline.common_options(parser) - opts = parser.parse_args(args=args) - return parser, process_proxy_options(parser, opts) + args = parser.parse_args(args=args) + return parser, process_proxy_options(parser, options.Options(), args) def assert_err(self, err, *args): tutils.raises(err, self.p, *args) @@ -159,12 +160,14 @@ class TestProxyServer: @tutils.skip_windows def test_err(self): conf = ProxyConfig( + options.Options(), port=1 ) tutils.raises("error starting proxy server", ProxyServer, conf) def test_err_2(self): conf = ProxyConfig( + options.Options(), host="invalidhost" ) tutils.raises("error starting proxy server", ProxyServer, conf) diff --git a/test/mitmproxy/tservers.py b/test/mitmproxy/tservers.py index 9b830b2d..e236656e 100644 --- a/test/mitmproxy/tservers.py +++ b/test/mitmproxy/tservers.py @@ -32,11 +32,11 @@ def errapp(environ, start_response): class TestMaster(flow.FlowMaster): - def __init__(self, config): + def __init__(self, opts, config): config.port = 0 s = ProxyServer(config) state = flow.State() - flow.FlowMaster.__init__(self, options.Options(), s, state) + flow.FlowMaster.__init__(self, opts, s, state) self.addons.add(*builtins.default_addons()) self.apps.add(testapp, "testapp", 80) self.apps.add(errapp, "errapp", 80) @@ -80,6 +80,7 @@ class ProxyTestBase(object): no_upstream_cert = False authenticator = None masterclass = TestMaster + masteroptions = options.Options() add_upstream_certs_to_client_chain = False @classmethod @@ -91,9 +92,8 @@ class ProxyTestBase(object): ssl=cls.ssl, ssloptions=cls.ssloptions) - cls.config = ProxyConfig(**cls.get_proxy_config()) - - tmaster = cls.masterclass(cls.config) + cls.config = ProxyConfig(cls.masteroptions, **cls.get_proxy_config()) + tmaster = cls.masterclass(cls.masteroptions, cls.config) tmaster.start_app(APP_HOST, APP_PORT) cls.proxy = ProxyThread(tmaster) cls.proxy.start() @@ -284,17 +284,19 @@ class ChainProxyTest(ProxyTestBase): @classmethod def setup_class(cls): + cls.masteroptions = options.Options() cls.chain = [] super(ChainProxyTest, cls).setup_class() for _ in range(cls.n): - config = ProxyConfig(**cls.get_proxy_config()) - tmaster = cls.masterclass(config) + config = ProxyConfig(cls.masteroptions, **cls.get_proxy_config()) + tmaster = cls.masterclass(cls.masteroptions, config) proxy = ProxyThread(tmaster) proxy.start() cls.chain.insert(0, proxy) # Patch the orginal proxy to upstream mode cls.config = cls.proxy.tmaster.config = cls.proxy.tmaster.server.config = ProxyConfig( + cls.masteroptions, **cls.get_proxy_config()) @classmethod -- cgit v1.2.3 From 6908dc4d901fbe23107253535596a14ed2691539 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 18 Jul 2016 14:19:39 +1200 Subject: ProxyConfig refactor Step two of frog boiling: move listening address and port into options. This is the hard bit, because it touches the test suite so deeply. --- mitmproxy/cmdline.py | 71 ++++++++++++++++++----------------- mitmproxy/flow/options.py | 8 ++++ mitmproxy/protocol/base.py | 4 +- mitmproxy/protocol/http_replay.py | 4 +- mitmproxy/proxy/config.py | 6 --- mitmproxy/proxy/server.py | 4 +- test/mitmproxy/test_protocol_http2.py | 9 +++-- test/mitmproxy/test_proxy.py | 6 +-- test/mitmproxy/test_server.py | 4 +- test/mitmproxy/tservers.py | 40 ++++++++++---------- 10 files changed, 82 insertions(+), 74 deletions(-) diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py index 507ddfc7..1e5064f7 100644 --- a/mitmproxy/cmdline.py +++ b/mitmproxy/cmdline.py @@ -131,26 +131,26 @@ def parse_upstream_auth(auth): return b"Basic" + b" " + base64.b64encode(strutils.always_bytes(auth)) -def get_common_options(options): +def get_common_options(args): stickycookie, stickyauth = None, None - if options.stickycookie_filt: - stickycookie = options.stickycookie_filt + if args.stickycookie_filt: + stickycookie = args.stickycookie_filt - if options.stickyauth_filt: - stickyauth = options.stickyauth_filt + if args.stickyauth_filt: + stickyauth = args.stickyauth_filt - stream_large_bodies = options.stream_large_bodies + stream_large_bodies = args.stream_large_bodies if stream_large_bodies: stream_large_bodies = human.parse_size(stream_large_bodies) reps = [] - for i in options.replace: + for i in args.replace: try: p = parse_replace_hook(i) except ParseException as e: raise configargparse.ArgumentTypeError(e) reps.append(p) - for i in options.replace_file: + for i in args.replace_file: try: patt, rex, path = parse_replace_hook(i) except ParseException as e: @@ -164,18 +164,18 @@ def get_common_options(options): reps.append((patt, rex, v)) setheaders = [] - for i in options.setheader: + for i in args.setheader: try: p = parse_setheader(i) except ParseException as e: raise configargparse.ArgumentTypeError(e) setheaders.append(p) - if options.outfile and options.outfile[0] == options.rfile: - if options.outfile[1] == "wb": + if args.outfile and args.outfile[0] == args.rfile: + if args.outfile[1] == "wb": raise configargparse.ArgumentTypeError( "Cannot use '{}' for both reading and writing flows. " - "Are you looking for --afile?".format(options.rfile) + "Are you looking for --afile?".format(args.rfile) ) else: raise configargparse.ArgumentTypeError( @@ -184,33 +184,36 @@ def get_common_options(options): ) return dict( - app=options.app, - app_host=options.app_host, - app_port=options.app_port, - - anticache=options.anticache, - anticomp=options.anticomp, - client_replay=options.client_replay, - kill=options.kill, - no_server=options.no_server, - refresh_server_playback=not options.norefresh, - rheaders=options.rheaders, - rfile=options.rfile, + app=args.app, + app_host=args.app_host, + app_port=args.app_port, + + anticache=args.anticache, + anticomp=args.anticomp, + client_replay=args.client_replay, + kill=args.kill, + no_server=args.no_server, + refresh_server_playback=not args.norefresh, + rheaders=args.rheaders, + rfile=args.rfile, replacements=reps, setheaders=setheaders, - server_replay=options.server_replay, - scripts=options.scripts, + server_replay=args.server_replay, + scripts=args.scripts, stickycookie=stickycookie, stickyauth=stickyauth, stream_large_bodies=stream_large_bodies, - showhost=options.showhost, - outfile=options.outfile, - verbosity=options.verbose, - nopop=options.nopop, - replay_ignore_content=options.replay_ignore_content, - replay_ignore_params=options.replay_ignore_params, - replay_ignore_payload_params=options.replay_ignore_payload_params, - replay_ignore_host=options.replay_ignore_host + showhost=args.showhost, + outfile=args.outfile, + verbosity=args.verbose, + nopop=args.nopop, + replay_ignore_content=args.replay_ignore_content, + replay_ignore_params=args.replay_ignore_params, + replay_ignore_payload_params=args.replay_ignore_payload_params, + replay_ignore_host=args.replay_ignore_host, + + listen_host = args.addr, + listen_port = args.port, ) diff --git a/mitmproxy/flow/options.py b/mitmproxy/flow/options.py index 6c2e3933..8879b01a 100644 --- a/mitmproxy/flow/options.py +++ b/mitmproxy/flow/options.py @@ -36,6 +36,10 @@ class Options(options.Options): replay_ignore_params=(), # type: Sequence[str] replay_ignore_payload_params=(), # type: Sequence[str] replay_ignore_host=False, # type: bool + + # Proxy options + listen_host = "", # type: str + listen_port = 8080, # type: int ): # We could replace all assignments with clever metaprogramming, # but type hints are a much more valueable asset. @@ -66,4 +70,8 @@ class Options(options.Options): self.replay_ignore_params = replay_ignore_params self.replay_ignore_payload_params = replay_ignore_payload_params self.replay_ignore_host = replay_ignore_host + + self.listen_host = listen_host + self.listen_port = listen_port + super(Options, self).__init__() diff --git a/mitmproxy/protocol/base.py b/mitmproxy/protocol/base.py index 11773385..bf0cbbae 100644 --- a/mitmproxy/protocol/base.py +++ b/mitmproxy/protocol/base.py @@ -114,7 +114,7 @@ class ServerConnectionMixin(object): def __init__(self, server_address=None): super(ServerConnectionMixin, self).__init__() - self.server_conn = models.ServerConnection(server_address, (self.config.host, 0)) + self.server_conn = models.ServerConnection(server_address, (self.config.options.listen_host, 0)) self.__check_self_connect() def __check_self_connect(self): @@ -125,7 +125,7 @@ class ServerConnectionMixin(object): address = self.server_conn.address if address: self_connect = ( - address.port == self.config.port and + address.port == self.config.options.listen_port and address.host in ("localhost", "127.0.0.1", "::1") ) if self_connect: diff --git a/mitmproxy/protocol/http_replay.py b/mitmproxy/protocol/http_replay.py index 986de845..27dfb741 100644 --- a/mitmproxy/protocol/http_replay.py +++ b/mitmproxy/protocol/http_replay.py @@ -46,7 +46,7 @@ class RequestReplayThread(basethread.BaseThread): # In all modes, we directly connect to the server displayed if self.config.mode == "upstream": server_address = self.config.upstream_server.address - server = models.ServerConnection(server_address, (self.config.host, 0)) + server = models.ServerConnection(server_address, (self.config.options.listen_host, 0)) server.connect() if r.scheme == "https": connect_request = models.make_connect_request((r.data.host, r.port)) @@ -68,7 +68,7 @@ class RequestReplayThread(basethread.BaseThread): r.first_line_format = "absolute" else: server_address = (r.host, r.port) - server = models.ServerConnection(server_address, (self.config.host, 0)) + server = models.ServerConnection(server_address, (self.config.options.listen_host, 0)) server.connect() if r.scheme == "https": server.establish_ssl( diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index 3aa16174..2f76e23c 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -60,8 +60,6 @@ class ProxyConfig: def __init__( self, options, - host='', - port=8080, cadir=CA_DIR, clientcerts=None, no_upstream_cert=False, @@ -85,8 +83,6 @@ class ProxyConfig: add_upstream_certs_to_client_chain=False, ): self.options = options - self.host = host - self.port = port self.ciphers_client = ciphers_client self.ciphers_server = ciphers_server self.clientcerts = clientcerts @@ -218,8 +214,6 @@ def process_proxy_options(parser, options, args): return ProxyConfig( options, - host=args.addr, - port=args.port, cadir=args.cadir, clientcerts=args.clientcerts, no_upstream_cert=args.no_upstream_cert, diff --git a/mitmproxy/proxy/server.py b/mitmproxy/proxy/server.py index 7e96911a..e5c4c3a1 100644 --- a/mitmproxy/proxy/server.py +++ b/mitmproxy/proxy/server.py @@ -41,7 +41,9 @@ class ProxyServer(tcp.TCPServer): """ self.config = config try: - super(ProxyServer, self).__init__((config.host, config.port)) + super(ProxyServer, self).__init__( + (config.options.listen_host, config.options.listen_port) + ) except socket.error as e: six.reraise( exceptions.ServerException, diff --git a/test/mitmproxy/test_protocol_http2.py b/test/mitmproxy/test_protocol_http2.py index 04ca94bf..dd81ba23 100644 --- a/test/mitmproxy/test_protocol_http2.py +++ b/test/mitmproxy/test_protocol_http2.py @@ -90,9 +90,10 @@ class _Http2TestBase(object): @classmethod def setup_class(cls): cls.masteroptions = options.Options() - cls.config = ProxyConfig(cls.masteroptions, **cls.get_proxy_config()) + cnf, opts = cls.get_proxy_config() + cls.config = ProxyConfig(opts, **cnf) - tmaster = tservers.TestMaster(cls.masteroptions, cls.config) + tmaster = tservers.TestMaster(opts, cls.config) tmaster.start_app(APP_HOST, APP_PORT) cls.proxy = tservers.ProxyThread(tmaster) cls.proxy.start() @@ -103,12 +104,14 @@ class _Http2TestBase(object): @classmethod def get_proxy_config(cls): + opts = options.Options(listen_port=0) cls.cadir = os.path.join(tempfile.gettempdir(), "mitmproxy") - return dict( + d = dict( no_upstream_cert=False, cadir=cls.cadir, authenticator=None, ) + return d, opts @property def master(self): diff --git a/test/mitmproxy/test_proxy.py b/test/mitmproxy/test_proxy.py index f4f73cf5..c87e1ad4 100644 --- a/test/mitmproxy/test_proxy.py +++ b/test/mitmproxy/test_proxy.py @@ -160,15 +160,13 @@ class TestProxyServer: @tutils.skip_windows def test_err(self): conf = ProxyConfig( - options.Options(), - port=1 + options.Options(listen_port=1), ) tutils.raises("error starting proxy server", ProxyServer, conf) def test_err_2(self): conf = ProxyConfig( - options.Options(), - host="invalidhost" + options.Options(listen_host="invalidhost"), ) tutils.raises("error starting proxy server", ProxyServer, conf) diff --git a/test/mitmproxy/test_server.py b/test/mitmproxy/test_server.py index 2e580d47..20372c92 100644 --- a/test/mitmproxy/test_server.py +++ b/test/mitmproxy/test_server.py @@ -484,9 +484,9 @@ class TestHttps2Http(tservers.ReverseProxyTest): @classmethod def get_proxy_config(cls): - d = super(TestHttps2Http, cls).get_proxy_config() + d, opts = super(TestHttps2Http, cls).get_proxy_config() d["upstream_server"] = ("http", d["upstream_server"][1]) - return d + return d, opts def pathoc(self, ssl, sni=None): """ diff --git a/test/mitmproxy/tservers.py b/test/mitmproxy/tservers.py index e236656e..f9e1925f 100644 --- a/test/mitmproxy/tservers.py +++ b/test/mitmproxy/tservers.py @@ -33,7 +33,6 @@ def errapp(environ, start_response): class TestMaster(flow.FlowMaster): def __init__(self, opts, config): - config.port = 0 s = ProxyServer(config) state = flow.State() flow.FlowMaster.__init__(self, opts, s, state) @@ -55,7 +54,8 @@ class ProxyThread(threading.Thread): threading.Thread.__init__(self) self.tmaster = tmaster self.name = "ProxyThread (%s:%s)" % ( - tmaster.server.address.host, tmaster.server.address.port) + tmaster.server.address.host, tmaster.server.address.port + ) controller.should_exit = False @property @@ -80,7 +80,6 @@ class ProxyTestBase(object): no_upstream_cert = False authenticator = None masterclass = TestMaster - masteroptions = options.Options() add_upstream_certs_to_client_chain = False @classmethod @@ -92,8 +91,9 @@ class ProxyTestBase(object): ssl=cls.ssl, ssloptions=cls.ssloptions) - cls.config = ProxyConfig(cls.masteroptions, **cls.get_proxy_config()) - tmaster = cls.masterclass(cls.masteroptions, cls.config) + cnf, opts = cls.get_proxy_config() + cls.config = ProxyConfig(opts, **cnf) + tmaster = cls.masterclass(opts, cls.config) tmaster.start_app(APP_HOST, APP_PORT) cls.proxy = ProxyThread(tmaster) cls.proxy.start() @@ -120,12 +120,13 @@ class ProxyTestBase(object): @classmethod def get_proxy_config(cls): cls.cadir = os.path.join(tempfile.gettempdir(), "mitmproxy") - return dict( + cnf = dict( no_upstream_cert = cls.no_upstream_cert, cadir = cls.cadir, authenticator = cls.authenticator, add_upstream_certs_to_client_chain = cls.add_upstream_certs_to_client_chain, ) + return cnf, options.Options(listen_port=0) class HTTPProxyTest(ProxyTestBase): @@ -199,9 +200,9 @@ class TransparentProxyTest(ProxyTestBase): @classmethod def get_proxy_config(cls): - d = ProxyTestBase.get_proxy_config() + d, opts = ProxyTestBase.get_proxy_config() d["mode"] = "transparent" - return d + return d, opts def pathod(self, spec, sni=None): """ @@ -231,13 +232,13 @@ class ReverseProxyTest(ProxyTestBase): @classmethod def get_proxy_config(cls): - d = ProxyTestBase.get_proxy_config() + d, opts = ProxyTestBase.get_proxy_config() d["upstream_server"] = ( "https" if cls.ssl else "http", ("127.0.0.1", cls.server.port) ) d["mode"] = "reverse" - return d + return d, opts def pathoc(self, sni=None): """ @@ -266,9 +267,9 @@ class SocksModeTest(HTTPProxyTest): @classmethod def get_proxy_config(cls): - d = ProxyTestBase.get_proxy_config() + d, opts = ProxyTestBase.get_proxy_config() d["mode"] = "socks5" - return d + return d, opts class ChainProxyTest(ProxyTestBase): @@ -284,20 +285,19 @@ class ChainProxyTest(ProxyTestBase): @classmethod def setup_class(cls): - cls.masteroptions = options.Options() cls.chain = [] super(ChainProxyTest, cls).setup_class() for _ in range(cls.n): - config = ProxyConfig(cls.masteroptions, **cls.get_proxy_config()) - tmaster = cls.masterclass(cls.masteroptions, config) + cnf, opts = cls.get_proxy_config() + config = ProxyConfig(opts, **cnf) + tmaster = cls.masterclass(opts, config) proxy = ProxyThread(tmaster) proxy.start() cls.chain.insert(0, proxy) # Patch the orginal proxy to upstream mode - cls.config = cls.proxy.tmaster.config = cls.proxy.tmaster.server.config = ProxyConfig( - cls.masteroptions, - **cls.get_proxy_config()) + cnf, opts = cls.get_proxy_config() + cls.config = cls.proxy.tmaster.config = cls.proxy.tmaster.server.config = ProxyConfig(opts, **cnf) @classmethod def teardown_class(cls): @@ -313,13 +313,13 @@ class ChainProxyTest(ProxyTestBase): @classmethod def get_proxy_config(cls): - d = super(ChainProxyTest, cls).get_proxy_config() + d, opts = super(ChainProxyTest, cls).get_proxy_config() if cls.chain: # First proxy is in normal mode. d.update( mode="upstream", upstream_server=("http", ("127.0.0.1", cls.chain[0].port)) ) - return d + return d, opts class HTTPUpstreamProxyTest(ChainProxyTest, HTTPProxyTest): -- cgit v1.2.3 From b1b1a1b9cfad24d62ffc5bf0613927fadd7bc77e Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 18 Jul 2016 14:50:10 +1200 Subject: ProxyConfig: cadir to options --- mitmproxy/cmdline.py | 17 +++++++++-------- mitmproxy/flow/options.py | 7 +++++-- mitmproxy/onboarding/app.py | 4 ++-- mitmproxy/proxy/config.py | 6 +----- test/mitmproxy/test_protocol_http2.py | 3 +-- test/mitmproxy/tservers.py | 3 +-- 6 files changed, 19 insertions(+), 21 deletions(-) diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py index 1e5064f7..cbff5ccd 100644 --- a/mitmproxy/cmdline.py +++ b/mitmproxy/cmdline.py @@ -16,6 +16,7 @@ from netlib.http import url APP_HOST = "mitm.it" APP_PORT = 80 +CA_DIR = "~/.mitmproxy" class ParseException(Exception): @@ -245,8 +246,8 @@ def basic_options(parser): ) parser.add_argument( "--cadir", - action="store", type=str, dest="cadir", default=config.CA_DIR, - help="Location of the default mitmproxy CA files. (%s)" % config.CA_DIR + action="store", type=str, dest="cadir", default=CA_DIR, + help="Location of the default mitmproxy CA files. (%s)" % CA_DIR ) parser.add_argument( "--host", @@ -699,8 +700,8 @@ def mitmproxy(): usage="%(prog)s [options]", args_for_setting_config_path=["--conf"], default_config_files=[ - os.path.join(config.CA_DIR, "common.conf"), - os.path.join(config.CA_DIR, "mitmproxy.conf") + os.path.join(CA_DIR, "common.conf"), + os.path.join(CA_DIR, "mitmproxy.conf") ], add_config_file_help=True, add_env_var_help=True @@ -754,8 +755,8 @@ def mitmdump(): usage="%(prog)s [options] [filter]", args_for_setting_config_path=["--conf"], default_config_files=[ - os.path.join(config.CA_DIR, "common.conf"), - os.path.join(config.CA_DIR, "mitmdump.conf") + os.path.join(CA_DIR, "common.conf"), + os.path.join(CA_DIR, "mitmdump.conf") ], add_config_file_help=True, add_env_var_help=True @@ -784,8 +785,8 @@ def mitmweb(): usage="%(prog)s [options]", args_for_setting_config_path=["--conf"], default_config_files=[ - os.path.join(config.CA_DIR, "common.conf"), - os.path.join(config.CA_DIR, "mitmweb.conf") + os.path.join(CA_DIR, "common.conf"), + os.path.join(CA_DIR, "mitmweb.conf") ], add_config_file_help=True, add_env_var_help=True diff --git a/mitmproxy/flow/options.py b/mitmproxy/flow/options.py index 8879b01a..d8f87133 100644 --- a/mitmproxy/flow/options.py +++ b/mitmproxy/flow/options.py @@ -1,6 +1,7 @@ from __future__ import absolute_import, print_function, division from mitmproxy import options from typing import Tuple, Optional, Sequence # noqa +from mitmproxy import cmdline APP_HOST = "mitm.it" APP_PORT = 80 @@ -38,8 +39,9 @@ class Options(options.Options): replay_ignore_host=False, # type: bool # Proxy options - listen_host = "", # type: str - listen_port = 8080, # type: int + cadir = cmdline.CA_DIR, # type: str + listen_host = "", # type: str + listen_port = 8080, # type: int ): # We could replace all assignments with clever metaprogramming, # but type hints are a much more valueable asset. @@ -71,6 +73,7 @@ class Options(options.Options): self.replay_ignore_payload_params = replay_ignore_payload_params self.replay_ignore_host = replay_ignore_host + self.cadir = cadir self.listen_host = listen_host self.listen_port = listen_port diff --git a/mitmproxy/onboarding/app.py b/mitmproxy/onboarding/app.py index f93b9982..e26efae8 100644 --- a/mitmproxy/onboarding/app.py +++ b/mitmproxy/onboarding/app.py @@ -47,7 +47,7 @@ class PEM(tornado.web.RequestHandler): return config.CONF_BASENAME + "-ca-cert.pem" def get(self): - p = os.path.join(self.request.master.server.config.cadir, self.filename) + p = os.path.join(self.request.master.options.cadir, self.filename) self.set_header("Content-Type", "application/x-x509-ca-cert") self.set_header( "Content-Disposition", @@ -65,7 +65,7 @@ class P12(tornado.web.RequestHandler): return config.CONF_BASENAME + "-ca-cert.p12" def get(self): - p = os.path.join(self.request.master.server.config.cadir, self.filename) + p = os.path.join(self.request.master.options.cadir, self.filename) self.set_header("Content-Type", "application/x-pkcs12") self.set_header( "Content-Disposition", diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index 2f76e23c..942798f3 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -14,7 +14,6 @@ from netlib import tcp from netlib.http import authentication CONF_BASENAME = "mitmproxy" -CA_DIR = "~/.mitmproxy" # We manually need to specify this, otherwise OpenSSL may select a non-HTTP2 cipher by default. # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=apache-2.2.15&openssl=1.0.2&hsts=yes&profile=old @@ -60,7 +59,6 @@ class ProxyConfig: def __init__( self, options, - cadir=CA_DIR, clientcerts=None, no_upstream_cert=False, body_size_limit=None, @@ -101,9 +99,8 @@ class ProxyConfig: self.http2 = http2 self.rawtcp = rawtcp self.authenticator = authenticator - self.cadir = os.path.expanduser(cadir) self.certstore = certutils.CertStore.from_store( - self.cadir, + os.path.expanduser(options.cadir), CONF_BASENAME ) for spec, cert in certs: @@ -214,7 +211,6 @@ def process_proxy_options(parser, options, args): return ProxyConfig( options, - cadir=args.cadir, clientcerts=args.clientcerts, no_upstream_cert=args.no_upstream_cert, body_size_limit=body_size_limit, diff --git a/test/mitmproxy/test_protocol_http2.py b/test/mitmproxy/test_protocol_http2.py index dd81ba23..34e6656a 100644 --- a/test/mitmproxy/test_protocol_http2.py +++ b/test/mitmproxy/test_protocol_http2.py @@ -105,10 +105,9 @@ class _Http2TestBase(object): @classmethod def get_proxy_config(cls): opts = options.Options(listen_port=0) - cls.cadir = os.path.join(tempfile.gettempdir(), "mitmproxy") + opts.cadir = os.path.join(tempfile.gettempdir(), "mitmproxy") d = dict( no_upstream_cert=False, - cadir=cls.cadir, authenticator=None, ) return d, opts diff --git a/test/mitmproxy/tservers.py b/test/mitmproxy/tservers.py index f9e1925f..ddb2922a 100644 --- a/test/mitmproxy/tservers.py +++ b/test/mitmproxy/tservers.py @@ -122,11 +122,10 @@ class ProxyTestBase(object): cls.cadir = os.path.join(tempfile.gettempdir(), "mitmproxy") cnf = dict( no_upstream_cert = cls.no_upstream_cert, - cadir = cls.cadir, authenticator = cls.authenticator, add_upstream_certs_to_client_chain = cls.add_upstream_certs_to_client_chain, ) - return cnf, options.Options(listen_port=0) + return cnf, options.Options(listen_port=0, cadir=cls.cadir) class HTTPProxyTest(ProxyTestBase): -- cgit v1.2.3 From 856e1c2ba938c6fb7639286cb27ae5cf3f63e2c8 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 18 Jul 2016 15:40:40 +1200 Subject: Move clientcers & cadir to Options Also adds a .configure mechanism to ProxyConfig, and hooks it up to the change event. --- mitmproxy/cmdline.py | 2 ++ mitmproxy/flow/options.py | 2 ++ mitmproxy/main.py | 15 ++++++--------- mitmproxy/proxy/config.py | 44 +++++++++++++++++++++++++++++--------------- test/mitmproxy/test_proxy.py | 4 +++- 5 files changed, 42 insertions(+), 25 deletions(-) diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py index cbff5ccd..3c63ec35 100644 --- a/mitmproxy/cmdline.py +++ b/mitmproxy/cmdline.py @@ -215,6 +215,8 @@ def get_common_options(args): listen_host = args.addr, listen_port = args.port, + cadir = args.cadir, + clientcerts = args.clientcerts, ) diff --git a/mitmproxy/flow/options.py b/mitmproxy/flow/options.py index d8f87133..f05d2373 100644 --- a/mitmproxy/flow/options.py +++ b/mitmproxy/flow/options.py @@ -40,6 +40,7 @@ class Options(options.Options): # Proxy options cadir = cmdline.CA_DIR, # type: str + clientcerts = None, # type: Optional[str] listen_host = "", # type: str listen_port = 8080, # type: int ): @@ -74,6 +75,7 @@ class Options(options.Options): self.replay_ignore_host = replay_ignore_host self.cadir = cadir + self.clientcerts = clientcerts self.listen_host = listen_host self.listen_port = listen_port diff --git a/mitmproxy/main.py b/mitmproxy/main.py index 9b62b63d..a245c979 100644 --- a/mitmproxy/main.py +++ b/mitmproxy/main.py @@ -73,10 +73,9 @@ def mitmproxy(args=None): # pragma: no cover console_options.limit = args.limit console_options.no_mouse = args.no_mouse - proxy_config = process_options(parser, console_options, args) - server = get_server(console_options.no_server, proxy_config) - try: + proxy_config = process_options(parser, console_options, args) + server = get_server(console_options.no_server, proxy_config) m = console.master.ConsoleMaster(server, console_options) except exceptions.OptionsError as e: print("mitmproxy: %s" % e, file=sys.stderr) @@ -102,10 +101,9 @@ def mitmdump(args=None): # pragma: no cover dump_options.keepserving = args.keepserving dump_options.filtstr = " ".join(args.args) if args.args else None - proxy_config = process_options(parser, dump_options, args) - server = get_server(dump_options.no_server, proxy_config) - try: + proxy_config = process_options(parser, dump_options, args) + server = get_server(dump_options.no_server, proxy_config) master = dump.DumpMaster(server, dump_options) def cleankill(*args, **kwargs): @@ -141,10 +139,9 @@ def mitmweb(args=None): # pragma: no cover web_options.whtpasswd = args.whtpasswd web_options.process_web_options(parser) - proxy_config = process_options(parser, web_options, args) - server = get_server(web_options.no_server, proxy_config) - try: + proxy_config = process_options(parser, web_options, args) + server = get_server(web_options.no_server, proxy_config) m = web.master.WebMaster(server, web_options) except exceptions.OptionsError as e: print("mitmweb: %s" % e, file=sys.stderr) diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index 942798f3..0a0188a5 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -8,6 +8,7 @@ import six from OpenSSL import SSL from mitmproxy import platform +from mitmproxy import exceptions from netlib import certutils from netlib import human from netlib import tcp @@ -59,7 +60,6 @@ class ProxyConfig: def __init__( self, options, - clientcerts=None, no_upstream_cert=False, body_size_limit=None, mode="regular", @@ -83,7 +83,6 @@ class ProxyConfig: self.options = options self.ciphers_client = ciphers_client self.ciphers_server = ciphers_server - self.clientcerts = clientcerts self.no_upstream_cert = no_upstream_cert self.body_size_limit = body_size_limit self.mode = mode @@ -99,12 +98,6 @@ class ProxyConfig: self.http2 = http2 self.rawtcp = rawtcp self.authenticator = authenticator - self.certstore = certutils.CertStore.from_store( - os.path.expanduser(options.cadir), - CONF_BASENAME - ) - for spec, cert in certs: - self.certstore.add_cert_file(spec, cert) self.openssl_method_client, self.openssl_options_client = \ tcp.sslversion_choices[ssl_version_client] @@ -119,6 +112,34 @@ class ProxyConfig: self.openssl_trusted_ca_server = ssl_verify_upstream_trusted_ca self.add_upstream_certs_to_client_chain = add_upstream_certs_to_client_chain + self.certstore = None + self.clientcerts = None + self.config(options) + options.changed.connect(self) + + for spec, cert in certs: + self.certstore.add_cert_file(spec, cert) + + def config(self, options): + certstore_path = os.path.expanduser(options.cadir) + if not os.path.exists(certstore_path): + raise exceptions.OptionsError( + "Certificate Authority directory does not exist: %s" % + options.cadir + ) + self.certstore = certutils.CertStore.from_store( + os.path.expanduser(options.cadir), + CONF_BASENAME + ) + if options.clientcerts: + clientcerts = os.path.expanduser(options.clientcerts) + if not os.path.exists(clientcerts): + raise exceptions.OptionsError( + "Client certificate path does not exist: %s" % + options.clientcerts + ) + self.clientcerts = clientcerts + def process_proxy_options(parser, options, args): body_size_limit = args.body_size_limit @@ -163,12 +184,6 @@ def process_proxy_options(parser, options, args): "then extra upstream certificates are not available for inclusion " "to the client chain." ) - if args.clientcerts: - args.clientcerts = os.path.expanduser(args.clientcerts) - if not os.path.exists(args.clientcerts): - return parser.error( - "Client certificate path does not exist: %s" % args.clientcerts - ) if args.auth_nonanonymous or args.auth_singleuser or args.auth_htpasswd: if args.transparent_proxy: @@ -211,7 +226,6 @@ def process_proxy_options(parser, options, args): return ProxyConfig( options, - clientcerts=args.clientcerts, no_upstream_cert=args.no_upstream_cert, body_size_limit=body_size_limit, mode=mode, diff --git a/test/mitmproxy/test_proxy.py b/test/mitmproxy/test_proxy.py index c87e1ad4..70ddfd40 100644 --- a/test/mitmproxy/test_proxy.py +++ b/test/mitmproxy/test_proxy.py @@ -60,7 +60,9 @@ class TestProcessProxyOptions: parser = tutils.MockParser() cmdline.common_options(parser) args = parser.parse_args(args=args) - return parser, process_proxy_options(parser, options.Options(), args) + opts = cmdline.get_common_options(args) + pconf = process_proxy_options(parser, options.Options(**opts), args) + return parser, pconf def assert_err(self, err, *args): tutils.raises(err, self.p, *args) -- cgit v1.2.3 From f24f8ce9714bb4014c68275aef36194b6f12c419 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 18 Jul 2016 16:02:54 +1200 Subject: ProxyConfig: --cert to options Also incidentally improve handling of invalid certificate formats. --- mitmproxy/cmdline.py | 14 ++++++++++++-- mitmproxy/flow/options.py | 3 +++ mitmproxy/proxy/config.py | 30 +++++++++++++++--------------- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py index 3c63ec35..9cf8be3c 100644 --- a/mitmproxy/cmdline.py +++ b/mitmproxy/cmdline.py @@ -184,6 +184,15 @@ def get_common_options(args): "That would trigger an infinite loop." ) + + # Proxy config + certs = [] + for i in args.certs: + parts = i.split("=", 1) + if len(parts) == 1: + parts = ["*", parts[0]] + certs.append(parts) + return dict( app=args.app, app_host=args.app_host, @@ -213,10 +222,11 @@ def get_common_options(args): replay_ignore_payload_params=args.replay_ignore_payload_params, replay_ignore_host=args.replay_ignore_host, - listen_host = args.addr, - listen_port = args.port, cadir = args.cadir, + certs = certs, clientcerts = args.clientcerts, + listen_host = args.addr, + listen_port = args.port, ) diff --git a/mitmproxy/flow/options.py b/mitmproxy/flow/options.py index f05d2373..51672f9c 100644 --- a/mitmproxy/flow/options.py +++ b/mitmproxy/flow/options.py @@ -40,6 +40,7 @@ class Options(options.Options): # Proxy options cadir = cmdline.CA_DIR, # type: str + certs = (), # type: Sequence[Tuple[str, str]] clientcerts = None, # type: Optional[str] listen_host = "", # type: str listen_port = 8080, # type: int @@ -74,7 +75,9 @@ class Options(options.Options): self.replay_ignore_payload_params = replay_ignore_payload_params self.replay_ignore_host = replay_ignore_host + # Proxy options self.cadir = cadir + self.certs = certs self.clientcerts = clientcerts self.listen_host = listen_host self.listen_port = listen_port diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index 0a0188a5..ae15a347 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -5,7 +5,7 @@ import os import re import six -from OpenSSL import SSL +from OpenSSL import SSL, crypto from mitmproxy import platform from mitmproxy import exceptions @@ -117,9 +117,6 @@ class ProxyConfig: self.config(options) options.changed.connect(self) - for spec, cert in certs: - self.certstore.add_cert_file(spec, cert) - def config(self, options): certstore_path = os.path.expanduser(options.cadir) if not os.path.exists(certstore_path): @@ -140,6 +137,20 @@ class ProxyConfig: ) self.clientcerts = clientcerts + for spec, cert in options.certs: + cert = os.path.expanduser(cert) + if not os.path.exists(cert): + raise exceptions.OptionsError( + "Certificate file does not exist: %s" % cert + ) + try: + self.certstore.add_cert_file(spec, cert) + except crypto.Error: + raise exceptions.OptionsError( + "Invalid certificate format: %s" % cert + ) + + def process_proxy_options(parser, options, args): body_size_limit = args.body_size_limit @@ -214,16 +225,6 @@ def process_proxy_options(parser, options, args): else: authenticator = authentication.NullProxyAuth(None) - certs = [] - for i in args.certs: - parts = i.split("=", 1) - if len(parts) == 1: - parts = ["*", parts[0]] - parts[1] = os.path.expanduser(parts[1]) - if not os.path.exists(parts[1]): - parser.error("Certificate file does not exist: %s" % parts[1]) - certs.append(parts) - return ProxyConfig( options, no_upstream_cert=args.no_upstream_cert, @@ -238,7 +239,6 @@ def process_proxy_options(parser, options, args): authenticator=authenticator, ciphers_client=args.ciphers_client, ciphers_server=args.ciphers_server, - certs=tuple(certs), ssl_version_client=args.ssl_version_client, ssl_version_server=args.ssl_version_server, ssl_verify_upstream_cert=args.ssl_verify_upstream_cert, -- cgit v1.2.3 From d2268ddb1ebfca2b3314c3bde12d3a356fd6a114 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 18 Jul 2016 16:58:53 +1200 Subject: ProxyConfig: --body-size-limit to Options --- mitmproxy/cmdline.py | 6 +++++- mitmproxy/flow/options.py | 2 ++ mitmproxy/protocol/http1.py | 16 +++++++++++++--- mitmproxy/protocol/http2.py | 15 +++++++++++---- mitmproxy/protocol/http_replay.py | 4 ++-- mitmproxy/proxy/config.py | 15 +++------------ test/mitmproxy/test_protocol_http2.py | 2 +- 7 files changed, 37 insertions(+), 23 deletions(-) diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py index 9cf8be3c..3b54f0ba 100644 --- a/mitmproxy/cmdline.py +++ b/mitmproxy/cmdline.py @@ -184,7 +184,6 @@ def get_common_options(args): "That would trigger an infinite loop." ) - # Proxy config certs = [] for i in args.certs: @@ -193,6 +192,10 @@ def get_common_options(args): parts = ["*", parts[0]] certs.append(parts) + body_size_limit = args.body_size_limit + if body_size_limit: + body_size_limit = human.parse_size(body_size_limit) + return dict( app=args.app, app_host=args.app_host, @@ -222,6 +225,7 @@ def get_common_options(args): replay_ignore_payload_params=args.replay_ignore_payload_params, replay_ignore_host=args.replay_ignore_host, + body_size_limit = body_size_limit, cadir = args.cadir, certs = certs, clientcerts = args.clientcerts, diff --git a/mitmproxy/flow/options.py b/mitmproxy/flow/options.py index 51672f9c..c8839399 100644 --- a/mitmproxy/flow/options.py +++ b/mitmproxy/flow/options.py @@ -39,6 +39,7 @@ class Options(options.Options): replay_ignore_host=False, # type: bool # Proxy options + body_size_limit=None, # type: Optional[int] cadir = cmdline.CA_DIR, # type: str certs = (), # type: Sequence[Tuple[str, str]] clientcerts = None, # type: Optional[str] @@ -76,6 +77,7 @@ class Options(options.Options): self.replay_ignore_host = replay_ignore_host # Proxy options + self.body_size_limit = body_size_limit self.cadir = cadir self.certs = certs self.clientcerts = clientcerts diff --git a/mitmproxy/protocol/http1.py b/mitmproxy/protocol/http1.py index 7055a7fd..8698fe31 100644 --- a/mitmproxy/protocol/http1.py +++ b/mitmproxy/protocol/http1.py @@ -12,12 +12,18 @@ class Http1Layer(http._HttpTransmissionLayer): self.mode = mode def read_request(self): - req = http1.read_request(self.client_conn.rfile, body_size_limit=self.config.body_size_limit) + req = http1.read_request( + self.client_conn.rfile, body_size_limit=self.config.options.body_size_limit + ) return models.HTTPRequest.wrap(req) def read_request_body(self, request): expected_size = http1.expected_http_body_size(request) - return http1.read_body(self.client_conn.rfile, expected_size, self.config.body_size_limit) + return http1.read_body( + self.client_conn.rfile, + expected_size, + self.config.options.body_size_limit + ) def send_request(self, request): self.server_conn.wfile.write(http1.assemble_request(request)) @@ -29,7 +35,11 @@ class Http1Layer(http._HttpTransmissionLayer): def read_response_body(self, request, response): expected_size = http1.expected_http_body_size(request, response) - return http1.read_body(self.server_conn.rfile, expected_size, self.config.body_size_limit) + return http1.read_body( + self.server_conn.rfile, + expected_size, + self.config.options.body_size_limit + ) def send_response_headers(self, response): raw = http1.assemble_response_head(response) diff --git a/mitmproxy/protocol/http2.py b/mitmproxy/protocol/http2.py index ee66393f..1285e10e 100644 --- a/mitmproxy/protocol/http2.py +++ b/mitmproxy/protocol/http2.py @@ -183,14 +183,21 @@ class Http2Layer(base.Layer): return True def _handle_data_received(self, eid, event, source_conn): - if self.config.body_size_limit and self.streams[eid].queued_data_length > self.config.body_size_limit: + bsl = self.config.options.body_size_limit + if bsl and self.streams[eid].queued_data_length > bsl: self.streams[eid].zombie = time.time() - source_conn.h2.safe_reset_stream(event.stream_id, h2.errors.REFUSED_STREAM) - self.log("HTTP body too large. Limit is {}.".format(self.config.body_size_limit), "info") + source_conn.h2.safe_reset_stream( + event.stream_id, + h2.errors.REFUSED_STREAM + ) + self.log("HTTP body too large. Limit is {}.".format(bsl), "info") else: self.streams[eid].data_queue.put(event.data) self.streams[eid].queued_data_length += len(event.data) - source_conn.h2.safe_increment_flow_control(event.stream_id, event.flow_controlled_length) + source_conn.h2.safe_increment_flow_control( + event.stream_id, + event.flow_controlled_length + ) return True def _handle_stream_ended(self, eid): diff --git a/mitmproxy/protocol/http_replay.py b/mitmproxy/protocol/http_replay.py index 27dfb741..ba58075e 100644 --- a/mitmproxy/protocol/http_replay.py +++ b/mitmproxy/protocol/http_replay.py @@ -55,7 +55,7 @@ class RequestReplayThread(basethread.BaseThread): resp = http1.read_response( server.rfile, connect_request, - body_size_limit=self.config.body_size_limit + body_size_limit=self.config.options.body_size_limit ) if resp.status_code != 200: raise exceptions.ReplayException("Upstream server refuses CONNECT request") @@ -83,7 +83,7 @@ class RequestReplayThread(basethread.BaseThread): self.flow.response = models.HTTPResponse.wrap(http1.read_response( server.rfile, r, - body_size_limit=self.config.body_size_limit + body_size_limit=self.config.options.body_size_limit )) if self.channel: response_reply = self.channel.ask("response", self.flow) diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index ae15a347..e0994d34 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -10,7 +10,6 @@ from OpenSSL import SSL, crypto from mitmproxy import platform from mitmproxy import exceptions from netlib import certutils -from netlib import human from netlib import tcp from netlib.http import authentication @@ -61,7 +60,6 @@ class ProxyConfig: self, options, no_upstream_cert=False, - body_size_limit=None, mode="regular", upstream_server=None, upstream_auth=None, @@ -84,7 +82,6 @@ class ProxyConfig: self.ciphers_client = ciphers_client self.ciphers_server = ciphers_server self.no_upstream_cert = no_upstream_cert - self.body_size_limit = body_size_limit self.mode = mode if upstream_server: self.upstream_server = ServerSpec(upstream_server[0], tcp.Address.wrap(upstream_server[1])) @@ -114,10 +111,10 @@ class ProxyConfig: self.certstore = None self.clientcerts = None - self.config(options) - options.changed.connect(self) + self.configure(options) + options.changed.connect(self.configure) - def config(self, options): + def configure(self, options): certstore_path = os.path.expanduser(options.cadir) if not os.path.exists(certstore_path): raise exceptions.OptionsError( @@ -151,12 +148,7 @@ class ProxyConfig: ) - def process_proxy_options(parser, options, args): - body_size_limit = args.body_size_limit - if body_size_limit: - body_size_limit = human.parse_size(body_size_limit) - c = 0 mode, upstream_server, upstream_auth = "regular", None, None if args.transparent_proxy: @@ -228,7 +220,6 @@ def process_proxy_options(parser, options, args): return ProxyConfig( options, no_upstream_cert=args.no_upstream_cert, - body_size_limit=body_size_limit, mode=mode, upstream_server=upstream_server, upstream_auth=upstream_auth, diff --git a/test/mitmproxy/test_protocol_http2.py b/test/mitmproxy/test_protocol_http2.py index 34e6656a..d910ecae 100644 --- a/test/mitmproxy/test_protocol_http2.py +++ b/test/mitmproxy/test_protocol_http2.py @@ -591,7 +591,7 @@ class TestBodySizeLimit(_Http2Test): return True def test_body_size_limit(self): - self.config.body_size_limit = 20 + self.config.options.body_size_limit = 20 client, h2_conn = self._setup_connection() -- cgit v1.2.3 From bd733e12323b02491090e531b6743da0a34b56c6 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 18 Jul 2016 17:09:55 +1200 Subject: Handle command-line argument errors properly At some point we stopped handling exceptions from get_common_options properly. --- mitmproxy/cmdline.py | 20 +++++++++++++------- mitmproxy/main.py | 46 ++++++++++++++++++++++++---------------------- 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py index 3b54f0ba..fcf1f89f 100644 --- a/mitmproxy/cmdline.py +++ b/mitmproxy/cmdline.py @@ -6,6 +6,7 @@ import re import configargparse +from mitmproxy import exceptions from mitmproxy import filt from mitmproxy.proxy import config from netlib import human @@ -149,17 +150,17 @@ def get_common_options(args): try: p = parse_replace_hook(i) except ParseException as e: - raise configargparse.ArgumentTypeError(e) + raise exceptions.OptionsError(e) reps.append(p) for i in args.replace_file: try: patt, rex, path = parse_replace_hook(i) except ParseException as e: - raise configargparse.ArgumentTypeError(e) + raise exceptions.OptionsError(e) try: v = open(path, "rb").read() except IOError as e: - raise configargparse.ArgumentTypeError( + raise exceptions.OptionsError( "Could not read replace file: %s" % path ) reps.append((patt, rex, v)) @@ -169,17 +170,17 @@ def get_common_options(args): try: p = parse_setheader(i) except ParseException as e: - raise configargparse.ArgumentTypeError(e) + raise exceptions.OptionsError(e) setheaders.append(p) if args.outfile and args.outfile[0] == args.rfile: if args.outfile[1] == "wb": - raise configargparse.ArgumentTypeError( + raise exceptions.OptionsError( "Cannot use '{}' for both reading and writing flows. " "Are you looking for --afile?".format(args.rfile) ) else: - raise configargparse.ArgumentTypeError( + raise exceptions.OptionsError( "Cannot use '{}' for both reading and appending flows. " "That would trigger an infinite loop." ) @@ -194,7 +195,12 @@ def get_common_options(args): body_size_limit = args.body_size_limit if body_size_limit: - body_size_limit = human.parse_size(body_size_limit) + try: + body_size_limit = human.parse_size(body_size_limit) + except ValueError, e: + raise exceptions.OptionsError( + "Invalid body size limit specification: %s" % body_size_limit + ) return dict( app=args.app, diff --git a/mitmproxy/main.py b/mitmproxy/main.py index a245c979..fee90d38 100644 --- a/mitmproxy/main.py +++ b/mitmproxy/main.py @@ -64,16 +64,18 @@ def mitmproxy(args=None): # pragma: no cover parser = cmdline.mitmproxy() args = parser.parse_args(args) - console_options = console.master.Options(**cmdline.get_common_options(args)) - console_options.palette = args.palette - console_options.palette_transparent = args.palette_transparent - console_options.eventlog = args.eventlog - console_options.follow = args.follow - console_options.intercept = args.intercept - console_options.limit = args.limit - console_options.no_mouse = args.no_mouse - try: + console_options = console.master.Options( + **cmdline.get_common_options(args) + ) + console_options.palette = args.palette + console_options.palette_transparent = args.palette_transparent + console_options.eventlog = args.eventlog + console_options.follow = args.follow + console_options.intercept = args.intercept + console_options.limit = args.limit + console_options.no_mouse = args.no_mouse + proxy_config = process_options(parser, console_options, args) server = get_server(console_options.no_server, proxy_config) m = console.master.ConsoleMaster(server, console_options) @@ -96,12 +98,12 @@ def mitmdump(args=None): # pragma: no cover if args.quiet: args.flow_detail = 0 - dump_options = dump.Options(**cmdline.get_common_options(args)) - dump_options.flow_detail = args.flow_detail - dump_options.keepserving = args.keepserving - dump_options.filtstr = " ".join(args.args) if args.args else None try: + dump_options = dump.Options(**cmdline.get_common_options(args)) + dump_options.flow_detail = args.flow_detail + dump_options.keepserving = args.keepserving + dump_options.filtstr = " ".join(args.args) if args.args else None proxy_config = process_options(parser, dump_options, args) server = get_server(dump_options.no_server, proxy_config) master = dump.DumpMaster(server, dump_options) @@ -130,16 +132,16 @@ def mitmweb(args=None): # pragma: no cover args = parser.parse_args(args) - web_options = web.master.Options(**cmdline.get_common_options(args)) - web_options.intercept = args.intercept - web_options.wdebug = args.wdebug - web_options.wiface = args.wiface - web_options.wport = args.wport - web_options.wsingleuser = args.wsingleuser - web_options.whtpasswd = args.whtpasswd - web_options.process_web_options(parser) - try: + web_options = web.master.Options(**cmdline.get_common_options(args)) + web_options.intercept = args.intercept + web_options.wdebug = args.wdebug + web_options.wiface = args.wiface + web_options.wport = args.wport + web_options.wsingleuser = args.wsingleuser + web_options.whtpasswd = args.whtpasswd + web_options.process_web_options(parser) + proxy_config = process_options(parser, web_options, args) server = get_server(web_options.no_server, proxy_config) m = web.master.WebMaster(server, web_options) -- cgit v1.2.3 From f9622074ccdfafda384fa3a1466d8363c2a65244 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 18 Jul 2016 18:10:21 +1200 Subject: ProxyConfig: mode, upstream_server and upstream_auth to Options --- mitmproxy/cmdline.py | 74 ++++++++++++++++++++--------------- mitmproxy/console/statusbar.py | 2 +- mitmproxy/flow/master.py | 2 +- mitmproxy/flow/options.py | 6 +++ mitmproxy/main.py | 1 - mitmproxy/protocol/http_replay.py | 2 +- mitmproxy/proxy/config.py | 78 +++++++++++++++++-------------------- mitmproxy/proxy/server.py | 2 +- mitmproxy/web/app.py | 2 +- test/mitmproxy/test_cmdline.py | 29 -------------- test/mitmproxy/test_flow.py | 8 ++-- test/mitmproxy/test_proxy.py | 33 ++++++++-------- test/mitmproxy/test_proxy_config.py | 48 +++++++++++++++++++++++ test/mitmproxy/test_server.py | 5 ++- test/mitmproxy/tservers.py | 20 ++++++---- 15 files changed, 173 insertions(+), 139 deletions(-) create mode 100644 test/mitmproxy/test_proxy_config.py diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py index fcf1f89f..b68de635 100644 --- a/mitmproxy/cmdline.py +++ b/mitmproxy/cmdline.py @@ -1,6 +1,5 @@ from __future__ import absolute_import, print_function, division -import base64 import os import re @@ -9,11 +8,10 @@ import configargparse from mitmproxy import exceptions from mitmproxy import filt from mitmproxy.proxy import config +from mitmproxy import platform from netlib import human -from netlib import strutils from netlib import tcp from netlib import version -from netlib.http import url APP_HOST = "mitm.it" APP_PORT = 80 @@ -109,30 +107,6 @@ def parse_setheader(s): return _parse_hook(s) -def parse_server_spec(spec): - try: - p = url.parse(spec) - if p[0] not in (b"http", b"https"): - raise ValueError() - except ValueError: - raise configargparse.ArgumentTypeError( - "Invalid server specification: %s" % spec - ) - - address = tcp.Address(p[1:3]) - scheme = p[0].lower() - return config.ServerSpec(scheme, address) - - -def parse_upstream_auth(auth): - pattern = re.compile(".+:") - if pattern.search(auth) is None: - raise configargparse.ArgumentTypeError( - "Invalid upstream auth specification: %s" % auth - ) - return b"Basic" + b" " + base64.b64encode(strutils.always_bytes(auth)) - - def get_common_options(args): stickycookie, stickyauth = None, None if args.stickycookie_filt: @@ -197,11 +171,46 @@ def get_common_options(args): if body_size_limit: try: body_size_limit = human.parse_size(body_size_limit) - except ValueError, e: + except ValueError as e: raise exceptions.OptionsError( "Invalid body size limit specification: %s" % body_size_limit ) + # Establish proxy mode + c = 0 + mode, upstream_server = "regular", None + if args.transparent_proxy: + c += 1 + if not platform.resolver: + raise exceptions.OptionsError( + "Transparent mode not supported on this platform." + ) + mode = "transparent" + if args.socks_proxy: + c += 1 + mode = "socks5" + if args.reverse_proxy: + c += 1 + mode = "reverse" + upstream_server = args.reverse_proxy + if args.upstream_proxy: + c += 1 + mode = "upstream" + upstream_server = args.upstream_proxy + if c > 1: + raise exceptions.OptionsError( + "Transparent, SOCKS5, reverse and upstream proxy mode " + "are mutually exclusive. Read the docs on proxy modes " + "to understand why." + ) + if args.add_upstream_certs_to_client_chain and args.no_upstream_cert: + raise exceptions.OptionsError( + "The no-upstream-cert and add-upstream-certs-to-client-chain " + "options are mutually exclusive. If no-upstream-cert is enabled " + "then the upstream certificate is not retrieved before generating " + "the client certificate chain." + ) + return dict( app=args.app, app_host=args.app_host, @@ -237,6 +246,9 @@ def get_common_options(args): clientcerts = args.clientcerts, listen_host = args.addr, listen_port = args.port, + mode = mode, + upstream_server = upstream_server, + upstream_auth = args.upstream_auth, ) @@ -353,7 +365,7 @@ def proxy_modes(parser): group.add_argument( "-R", "--reverse", action="store", - type=parse_server_spec, + type=str, dest="reverse_proxy", default=None, help=""" @@ -376,7 +388,7 @@ def proxy_modes(parser): group.add_argument( "-U", "--upstream", action="store", - type=parse_server_spec, + type=str, dest="upstream_proxy", default=None, help="Forward all requests to upstream proxy server: http://host[:port]" @@ -434,7 +446,7 @@ def proxy_options(parser): parser.add_argument( "--upstream-auth", action="store", dest="upstream_auth", default=None, - type=parse_upstream_auth, + type=str, help=""" Proxy Authentication: username:password diff --git a/mitmproxy/console/statusbar.py b/mitmproxy/console/statusbar.py index 8f039e48..e1c65714 100644 --- a/mitmproxy/console/statusbar.py +++ b/mitmproxy/console/statusbar.py @@ -214,7 +214,7 @@ class StatusBar(urwid.WidgetWrap): if opts: r.append("[%s]" % (":".join(opts))) - if self.master.server.config.mode in ["reverse", "upstream"]: + if self.master.options.mode in ["reverse", "upstream"]: dst = self.master.server.config.upstream_server r.append("[dest:%s]" % netlib.http.url.unparse( dst.scheme, diff --git a/mitmproxy/flow/master.py b/mitmproxy/flow/master.py index 64a242ba..a31840d9 100644 --- a/mitmproxy/flow/master.py +++ b/mitmproxy/flow/master.py @@ -191,7 +191,7 @@ class FlowMaster(controller.Master): Loads a flow """ if isinstance(f, models.HTTPFlow): - if self.server and self.server.config.mode == "reverse": + if self.server and self.options.mode == "reverse": f.request.host = self.server.config.upstream_server.address.host f.request.port = self.server.config.upstream_server.address.port f.request.scheme = self.server.config.upstream_server.scheme diff --git a/mitmproxy/flow/options.py b/mitmproxy/flow/options.py index c8839399..7875e9bf 100644 --- a/mitmproxy/flow/options.py +++ b/mitmproxy/flow/options.py @@ -45,6 +45,9 @@ class Options(options.Options): clientcerts = None, # type: Optional[str] listen_host = "", # type: str listen_port = 8080, # type: int + mode = "regular", # type: str + upstream_server = "", # type: str + upstream_auth = "", # type: str ): # We could replace all assignments with clever metaprogramming, # but type hints are a much more valueable asset. @@ -83,5 +86,8 @@ class Options(options.Options): self.clientcerts = clientcerts self.listen_host = listen_host self.listen_port = listen_port + self.mode = mode + self.upstream_server = upstream_server + self.upstream_auth = upstream_auth super(Options, self).__init__() diff --git a/mitmproxy/main.py b/mitmproxy/main.py index fee90d38..77cce161 100644 --- a/mitmproxy/main.py +++ b/mitmproxy/main.py @@ -98,7 +98,6 @@ def mitmdump(args=None): # pragma: no cover if args.quiet: args.flow_detail = 0 - try: dump_options = dump.Options(**cmdline.get_common_options(args)) dump_options.flow_detail = args.flow_detail diff --git a/mitmproxy/protocol/http_replay.py b/mitmproxy/protocol/http_replay.py index ba58075e..bfde06c5 100644 --- a/mitmproxy/protocol/http_replay.py +++ b/mitmproxy/protocol/http_replay.py @@ -44,7 +44,7 @@ class RequestReplayThread(basethread.BaseThread): if not self.flow.response: # In all modes, we directly connect to the server displayed - if self.config.mode == "upstream": + if self.config.options.mode == "upstream": server_address = self.config.upstream_server.address server = models.ServerConnection(server_address, (self.config.options.listen_host, 0)) server.connect() diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index e0994d34..403a4174 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -1,17 +1,19 @@ from __future__ import absolute_import, print_function, division +import base64 import collections import os import re +from netlib import strutils import six from OpenSSL import SSL, crypto -from mitmproxy import platform from mitmproxy import exceptions from netlib import certutils from netlib import tcp from netlib.http import authentication +from netlib.http import url CONF_BASENAME = "mitmproxy" @@ -54,13 +56,36 @@ class HostMatcher(object): ServerSpec = collections.namedtuple("ServerSpec", "scheme address") +def parse_server_spec(spec): + try: + p = url.parse(spec) + if p[0] not in (b"http", b"https"): + raise ValueError() + except ValueError: + raise exceptions.OptionsError( + "Invalid server specification: %s" % spec + ) + + address = tcp.Address(p[1:3]) + scheme = p[0].lower() + return ServerSpec(scheme, address) + + +def parse_upstream_auth(auth): + pattern = re.compile(".+:") + if pattern.search(auth) is None: + raise exceptions.OptionsError( + "Invalid upstream auth specification: %s" % auth + ) + return b"Basic" + b" " + base64.b64encode(strutils.always_bytes(auth)) + + class ProxyConfig: def __init__( self, options, no_upstream_cert=False, - mode="regular", upstream_server=None, upstream_auth=None, authenticator=None, @@ -82,13 +107,6 @@ class ProxyConfig: self.ciphers_client = ciphers_client self.ciphers_server = ciphers_server self.no_upstream_cert = no_upstream_cert - self.mode = mode - if upstream_server: - self.upstream_server = ServerSpec(upstream_server[0], tcp.Address.wrap(upstream_server[1])) - self.upstream_auth = upstream_auth - else: - self.upstream_server = None - self.upstream_auth = None self.check_ignore = HostMatcher(ignore_hosts) self.check_tcp = HostMatcher(tcp_hosts) @@ -125,6 +143,7 @@ class ProxyConfig: os.path.expanduser(options.cadir), CONF_BASENAME ) + if options.clientcerts: clientcerts = os.path.expanduser(options.clientcerts) if not os.path.exists(clientcerts): @@ -147,39 +166,15 @@ class ProxyConfig: "Invalid certificate format: %s" % cert ) + self.upstream_server = None + self.upstream_auth = None + if options.upstream_server: + self.upstream_server = parse_server_spec(options.upstream_server) + if options.upstream_auth: + self.upstream_auth = parse_upstream_auth(options.upstream_auth) + def process_proxy_options(parser, options, args): - c = 0 - mode, upstream_server, upstream_auth = "regular", None, None - if args.transparent_proxy: - c += 1 - if not platform.resolver: - return parser.error("Transparent mode not supported on this platform.") - mode = "transparent" - if args.socks_proxy: - c += 1 - mode = "socks5" - if args.reverse_proxy: - c += 1 - mode = "reverse" - upstream_server = args.reverse_proxy - if args.upstream_proxy: - c += 1 - mode = "upstream" - upstream_server = args.upstream_proxy - upstream_auth = args.upstream_auth - if c > 1: - return parser.error( - "Transparent, SOCKS5, reverse and upstream proxy mode " - "are mutually exclusive. Read the docs on proxy modes to understand why." - ) - if args.add_upstream_certs_to_client_chain and args.no_upstream_cert: - return parser.error( - "The no-upstream-cert and add-upstream-certs-to-client-chain " - "options are mutually exclusive. If no-upstream-cert is enabled " - "then the upstream certificate is not retrieved before generating " - "the client certificate chain." - ) if args.add_upstream_certs_to_client_chain and args.ssl_verify_upstream_cert: return parser.error( "The verify-upstream-cert and add-upstream-certs-to-client-chain " @@ -220,9 +215,6 @@ def process_proxy_options(parser, options, args): return ProxyConfig( options, no_upstream_cert=args.no_upstream_cert, - mode=mode, - upstream_server=upstream_server, - upstream_auth=upstream_auth, ignore_hosts=args.ignore_hosts, tcp_hosts=args.tcp_hosts, http2=args.http2, diff --git a/mitmproxy/proxy/server.py b/mitmproxy/proxy/server.py index e5c4c3a1..26f2e294 100644 --- a/mitmproxy/proxy/server.py +++ b/mitmproxy/proxy/server.py @@ -85,7 +85,7 @@ class ConnectionHandler(object): self.channel ) - mode = self.config.mode + mode = self.config.options.mode if mode == "upstream": return modes.HttpUpstreamProxy( root_ctx, diff --git a/mitmproxy/web/app.py b/mitmproxy/web/app.py index 8c080e98..e6b95cdf 100644 --- a/mitmproxy/web/app.py +++ b/mitmproxy/web/app.py @@ -336,7 +336,7 @@ class Settings(RequestHandler): self.write(dict( data=dict( version=version.VERSION, - mode=str(self.master.server.config.mode), + mode=str(self.master.options.mode), intercept=self.state.intercept_txt, showhost=self.master.options.showhost, no_upstream_cert=self.master.server.config.no_upstream_cert, diff --git a/test/mitmproxy/test_cmdline.py b/test/mitmproxy/test_cmdline.py index 4fe2cf94..55627408 100644 --- a/test/mitmproxy/test_cmdline.py +++ b/test/mitmproxy/test_cmdline.py @@ -1,5 +1,4 @@ import argparse -import base64 from mitmproxy import cmdline from . import tutils @@ -36,34 +35,6 @@ def test_parse_replace_hook(): ) -def test_parse_server_spec(): - tutils.raises("Invalid server specification", cmdline.parse_server_spec, "") - assert cmdline.parse_server_spec( - "http://foo.com:88") == (b"http", (b"foo.com", 88)) - assert cmdline.parse_server_spec( - "http://foo.com") == (b"http", (b"foo.com", 80)) - assert cmdline.parse_server_spec( - "https://foo.com") == (b"https", (b"foo.com", 443)) - tutils.raises( - "Invalid server specification", - cmdline.parse_server_spec, - "foo.com") - tutils.raises( - "Invalid server specification", - cmdline.parse_server_spec, - "http://") - - -def test_parse_upstream_auth(): - tutils.raises("Invalid upstream auth specification", cmdline.parse_upstream_auth, "") - tutils.raises("Invalid upstream auth specification", cmdline.parse_upstream_auth, ":") - tutils.raises("Invalid upstream auth specification", cmdline.parse_upstream_auth, ":test") - assert cmdline.parse_upstream_auth( - "test:test") == b"Basic" + b" " + base64.b64encode(b"test:test") - assert cmdline.parse_upstream_auth( - "test:") == b"Basic" + b" " + base64.b64encode(b"test:") - - def test_parse_setheaders(): x = cmdline.parse_setheader("/foo/bar/voing") assert x == ("foo", "bar", "voing") diff --git a/test/mitmproxy/test_flow.py b/test/mitmproxy/test_flow.py index a44353e7..ee588a5c 100644 --- a/test/mitmproxy/test_flow.py +++ b/test/mitmproxy/test_flow.py @@ -640,12 +640,12 @@ class TestSerialize: def test_load_flows_reverse(self): r = self._treader() s = flow.State() - conf = ProxyConfig( - options.Options(), + opts = options.Options( mode="reverse", - upstream_server=("https", ("use-this-domain", 80)) + upstream_server="https://use-this-domain" ) - fm = flow.FlowMaster(None, DummyServer(conf), s) + conf = ProxyConfig(opts) + fm = flow.FlowMaster(opts, DummyServer(conf), s) fm.load_flows(r) assert s.flows[0].request.host == "use-this-domain" diff --git a/test/mitmproxy/test_proxy.py b/test/mitmproxy/test_proxy.py index 70ddfd40..16c4821c 100644 --- a/test/mitmproxy/test_proxy.py +++ b/test/mitmproxy/test_proxy.py @@ -85,21 +85,22 @@ class TestProcessProxyOptions: @mock.patch("mitmproxy.platform.resolver") def test_modes(self, _): - self.assert_noerr("-R", "http://localhost") - self.assert_err("expected one argument", "-R") - self.assert_err("Invalid server specification", "-R", "reverse") - - self.assert_noerr("-T") - - self.assert_noerr("-U", "http://localhost") - self.assert_err("expected one argument", "-U") - self.assert_err("Invalid server specification", "-U", "upstream") - - self.assert_noerr("--upstream-auth", "test:test") - self.assert_err("expected one argument", "--upstream-auth") - self.assert_err("Invalid upstream auth specification", "--upstream-auth", "test") - - self.assert_err("mutually exclusive", "-R", "http://localhost", "-T") + # self.assert_noerr("-R", "http://localhost") + # self.assert_err("expected one argument", "-R") + # self.assert_err("Invalid server specification", "-R", "reverse") + # + # self.assert_noerr("-T") + # + # self.assert_noerr("-U", "http://localhost") + # self.assert_err("expected one argument", "-U") + # self.assert_err("Invalid server specification", "-U", "upstream") + # + # self.assert_noerr("--upstream-auth", "test:test") + # self.assert_err("expected one argument", "--upstream-auth") + self.assert_err( + "Invalid upstream auth specification", "--upstream-auth", "test" + ) + # self.assert_err("mutually exclusive", "-R", "http://localhost", "-T") def test_socks_auth(self): self.assert_err("Proxy Authentication not supported in SOCKS mode.", "--socks", "--nonanonymous") @@ -187,7 +188,7 @@ class TestConnectionHandler: config = mock.Mock() root_layer = mock.Mock() root_layer.side_effect = RuntimeError - config.mode.return_value = root_layer + config.options.mode.return_value = root_layer channel = mock.Mock() def ask(_, x): diff --git a/test/mitmproxy/test_proxy_config.py b/test/mitmproxy/test_proxy_config.py new file mode 100644 index 00000000..2f31d502 --- /dev/null +++ b/test/mitmproxy/test_proxy_config.py @@ -0,0 +1,48 @@ +from . import tutils +import base64 +from mitmproxy.proxy import config + + +def test_parse_server_spec(): + tutils.raises( + "Invalid server specification", config.parse_server_spec, "" + ) + assert config.parse_server_spec("http://foo.com:88") == ( + b"http", (b"foo.com", 88) + ) + assert config.parse_server_spec("http://foo.com") == ( + b"http", (b"foo.com", 80) + ) + assert config.parse_server_spec("https://foo.com") == ( + b"https", (b"foo.com", 443) + ) + tutils.raises( + "Invalid server specification", + config.parse_server_spec, + "foo.com" + ) + tutils.raises( + "Invalid server specification", + config.parse_server_spec, + "http://" + ) + + +def test_parse_upstream_auth(): + tutils.raises( + "Invalid upstream auth specification", + config.parse_upstream_auth, + "" + ) + tutils.raises( + "Invalid upstream auth specification", + config.parse_upstream_auth, + ":" + ) + tutils.raises( + "Invalid upstream auth specification", + config.parse_upstream_auth, + ":test" + ) + assert config.parse_upstream_auth("test:test") == b"Basic" + b" " + base64.b64encode(b"test:test") + assert config.parse_upstream_auth("test:") == b"Basic" + b" " + base64.b64encode(b"test:") diff --git a/test/mitmproxy/test_server.py b/test/mitmproxy/test_server.py index 20372c92..ca3f8a97 100644 --- a/test/mitmproxy/test_server.py +++ b/test/mitmproxy/test_server.py @@ -15,7 +15,7 @@ from pathod import pathoc, pathod from mitmproxy.builtins import script from mitmproxy import controller -from mitmproxy.proxy.config import HostMatcher +from mitmproxy.proxy.config import HostMatcher, parse_server_spec from mitmproxy.models import Error, HTTPResponse, HTTPFlow from . import tutils, tservers @@ -485,7 +485,8 @@ class TestHttps2Http(tservers.ReverseProxyTest): @classmethod def get_proxy_config(cls): d, opts = super(TestHttps2Http, cls).get_proxy_config() - d["upstream_server"] = ("http", d["upstream_server"][1]) + s = parse_server_spec(opts.upstream_server) + opts.upstream_server = "http://%s" % s.address.decode("ascii") return d, opts def pathoc(self, ssl, sni=None): diff --git a/test/mitmproxy/tservers.py b/test/mitmproxy/tservers.py index ddb2922a..b7b1f001 100644 --- a/test/mitmproxy/tservers.py +++ b/test/mitmproxy/tservers.py @@ -200,7 +200,7 @@ class TransparentProxyTest(ProxyTestBase): @classmethod def get_proxy_config(cls): d, opts = ProxyTestBase.get_proxy_config() - d["mode"] = "transparent" + opts.mode = "transparent" return d, opts def pathod(self, spec, sni=None): @@ -232,11 +232,15 @@ class ReverseProxyTest(ProxyTestBase): @classmethod def get_proxy_config(cls): d, opts = ProxyTestBase.get_proxy_config() - d["upstream_server"] = ( - "https" if cls.ssl else "http", - ("127.0.0.1", cls.server.port) + opts.upstream_server = "".join( + [ + "https" if cls.ssl else "http", + "://", + "127.0.0.1:", + str(cls.server.port) + ] ) - d["mode"] = "reverse" + opts.mode = "reverse" return d, opts def pathoc(self, sni=None): @@ -267,7 +271,7 @@ class SocksModeTest(HTTPProxyTest): @classmethod def get_proxy_config(cls): d, opts = ProxyTestBase.get_proxy_config() - d["mode"] = "socks5" + opts.mode = "socks5" return d, opts @@ -314,9 +318,9 @@ class ChainProxyTest(ProxyTestBase): def get_proxy_config(cls): d, opts = super(ChainProxyTest, cls).get_proxy_config() if cls.chain: # First proxy is in normal mode. - d.update( + opts.update( mode="upstream", - upstream_server=("http", ("127.0.0.1", cls.chain[0].port)) + upstream_server="http://127.0.0.1:%s" % cls.chain[0].port ) return d, opts -- cgit v1.2.3 From 78e8159007051122de1a1be1467d9261266b288e Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 19 Jul 2016 11:10:37 +1200 Subject: config.parse_server_spec shouldn't pass byts to tcp.Address --- mitmproxy/proxy/config.py | 6 +++--- test/mitmproxy/test_proxy_config.py | 6 +++--- test/mitmproxy/test_server.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index 403a4174..7a5a6863 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -65,9 +65,9 @@ def parse_server_spec(spec): raise exceptions.OptionsError( "Invalid server specification: %s" % spec ) - - address = tcp.Address(p[1:3]) - scheme = p[0].lower() + host, port = p[1:3] + address = tcp.Address((host.decode("ascii"), port)) + scheme = p[0].decode("ascii").lower() return ServerSpec(scheme, address) diff --git a/test/mitmproxy/test_proxy_config.py b/test/mitmproxy/test_proxy_config.py index 2f31d502..d8085eb8 100644 --- a/test/mitmproxy/test_proxy_config.py +++ b/test/mitmproxy/test_proxy_config.py @@ -8,13 +8,13 @@ def test_parse_server_spec(): "Invalid server specification", config.parse_server_spec, "" ) assert config.parse_server_spec("http://foo.com:88") == ( - b"http", (b"foo.com", 88) + "http", ("foo.com", 88) ) assert config.parse_server_spec("http://foo.com") == ( - b"http", (b"foo.com", 80) + "http", ("foo.com", 80) ) assert config.parse_server_spec("https://foo.com") == ( - b"https", (b"foo.com", 443) + "https", ("foo.com", 443) ) tutils.raises( "Invalid server specification", diff --git a/test/mitmproxy/test_server.py b/test/mitmproxy/test_server.py index ca3f8a97..73e070ac 100644 --- a/test/mitmproxy/test_server.py +++ b/test/mitmproxy/test_server.py @@ -486,7 +486,7 @@ class TestHttps2Http(tservers.ReverseProxyTest): def get_proxy_config(cls): d, opts = super(TestHttps2Http, cls).get_proxy_config() s = parse_server_spec(opts.upstream_server) - opts.upstream_server = "http://%s" % s.address.decode("ascii") + opts.upstream_server = "http://%s" % s.address return d, opts def pathoc(self, ssl, sni=None): -- cgit v1.2.3 From f81c53f9bb9ed074f1eae26e1c89c545df9ae3a7 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 19 Jul 2016 11:23:37 +1200 Subject: Fix ca directory creation --- mitmproxy/proxy/config.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index 7a5a6863..7f155528 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -134,13 +134,13 @@ class ProxyConfig: def configure(self, options): certstore_path = os.path.expanduser(options.cadir) - if not os.path.exists(certstore_path): + if not os.path.exists(os.path.dirname(certstore_path)): raise exceptions.OptionsError( - "Certificate Authority directory does not exist: %s" % - options.cadir + "Certificate Authority parent directory does not exist: %s" % + os.path.dirname(options.cadir) ) self.certstore = certutils.CertStore.from_store( - os.path.expanduser(options.cadir), + certstore_path, CONF_BASENAME ) -- cgit v1.2.3 From 0a3839375de80a032f244c62ee254199750e5f91 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 19 Jul 2016 11:41:04 +1200 Subject: ProxyConfig: various SSL options to Options --- mitmproxy/cmdline.py | 6 ++++++ mitmproxy/flow/options.py | 13 ++++++++++++- mitmproxy/options.py | 2 +- mitmproxy/protocol/tls.py | 4 ++-- mitmproxy/proxy/config.py | 29 +++++++---------------------- test/mitmproxy/tservers.py | 7 +++++-- 6 files changed, 33 insertions(+), 28 deletions(-) diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py index b68de635..73508871 100644 --- a/mitmproxy/cmdline.py +++ b/mitmproxy/cmdline.py @@ -249,6 +249,12 @@ def get_common_options(args): mode = mode, upstream_server = upstream_server, upstream_auth = args.upstream_auth, + ssl_version_client = args.ssl_version_client, + ssl_version_server = args.ssl_version_server, + ssl_verify_upstream_cert = args.ssl_verify_upstream_cert, + ssl_verify_upstream_trusted_cadir = args.ssl_verify_upstream_trusted_cadir, + ssl_verify_upstream_trusted_ca = args.ssl_verify_upstream_trusted_ca, + add_upstream_certs_to_client_chain = args.add_upstream_certs_to_client_chain, ) diff --git a/mitmproxy/flow/options.py b/mitmproxy/flow/options.py index 7875e9bf..31150b55 100644 --- a/mitmproxy/flow/options.py +++ b/mitmproxy/flow/options.py @@ -48,6 +48,12 @@ class Options(options.Options): mode = "regular", # type: str upstream_server = "", # type: str upstream_auth = "", # type: str + ssl_version_client="secure", # type: str + ssl_version_server="secure", # type: str + ssl_verify_upstream_cert=False, # type: bool + ssl_verify_upstream_trusted_cadir=None, # type: str + ssl_verify_upstream_trusted_ca=None, # type: str + add_upstream_certs_to_client_chain=False, # type: bool ): # We could replace all assignments with clever metaprogramming, # but type hints are a much more valueable asset. @@ -89,5 +95,10 @@ class Options(options.Options): self.mode = mode self.upstream_server = upstream_server self.upstream_auth = upstream_auth - + self.ssl_version_client = ssl_version_client + self.ssl_version_server = ssl_version_server + self.ssl_verify_upstream_cert = ssl_verify_upstream_cert + self.ssl_verify_upstream_trusted_cadir = ssl_verify_upstream_trusted_cadir + self.ssl_verify_upstream_trusted_ca = ssl_verify_upstream_trusted_ca + self.add_upstream_certs_to_client_chain = add_upstream_certs_to_client_chain super(Options, self).__init__() diff --git a/mitmproxy/options.py b/mitmproxy/options.py index 04353dca..94e5d573 100644 --- a/mitmproxy/options.py +++ b/mitmproxy/options.py @@ -52,7 +52,7 @@ class Options(object): if attr in self._opts: return self._opts[attr] else: - raise AttributeError() + raise AttributeError("No such option: %s" % attr) def __setattr__(self, attr, value): if not self._initialized: diff --git a/mitmproxy/protocol/tls.py b/mitmproxy/protocol/tls.py index 8ef34493..7b8b8301 100644 --- a/mitmproxy/protocol/tls.py +++ b/mitmproxy/protocol/tls.py @@ -368,7 +368,7 @@ class TlsLayer(base.Layer): self._server_tls and not self.config.no_upstream_cert and ( - self.config.add_upstream_certs_to_client_chain or + self.config.options.add_upstream_certs_to_client_chain or self._client_hello.alpn_protocols or not self._client_hello.sni ) @@ -473,7 +473,7 @@ class TlsLayer(base.Layer): self.log("Establish TLS with client", "debug") cert, key, chain_file = self._find_cert() - if self.config.add_upstream_certs_to_client_chain: + if self.config.options.add_upstream_certs_to_client_chain: extra_certs = self.server_conn.server_certs else: extra_certs = None diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index 7f155528..201f7051 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -86,8 +86,6 @@ class ProxyConfig: self, options, no_upstream_cert=False, - upstream_server=None, - upstream_auth=None, authenticator=None, ignore_hosts=tuple(), tcp_hosts=tuple(), @@ -96,12 +94,6 @@ class ProxyConfig: ciphers_client=DEFAULT_CLIENT_CIPHERS, ciphers_server=None, certs=tuple(), - ssl_version_client="secure", - ssl_version_server="secure", - ssl_verify_upstream_cert=False, - ssl_verify_upstream_trusted_cadir=None, - ssl_verify_upstream_trusted_ca=None, - add_upstream_certs_to_client_chain=False, ): self.options = options self.ciphers_client = ciphers_client @@ -115,17 +107,14 @@ class ProxyConfig: self.authenticator = authenticator self.openssl_method_client, self.openssl_options_client = \ - tcp.sslversion_choices[ssl_version_client] + tcp.sslversion_choices[options.ssl_version_client] self.openssl_method_server, self.openssl_options_server = \ - tcp.sslversion_choices[ssl_version_server] + tcp.sslversion_choices[options.ssl_version_server] - if ssl_verify_upstream_cert: + if options.ssl_verify_upstream_cert: self.openssl_verification_mode_server = SSL.VERIFY_PEER else: self.openssl_verification_mode_server = SSL.VERIFY_NONE - self.openssl_trusted_cadir_server = ssl_verify_upstream_trusted_cadir - self.openssl_trusted_ca_server = ssl_verify_upstream_trusted_ca - self.add_upstream_certs_to_client_chain = add_upstream_certs_to_client_chain self.certstore = None self.clientcerts = None @@ -172,6 +161,8 @@ class ProxyConfig: self.upstream_server = parse_server_spec(options.upstream_server) if options.upstream_auth: self.upstream_auth = parse_upstream_auth(options.upstream_auth) + self.openssl_trusted_cadir_server = options.ssl_verify_upstream_trusted_cadir + self.openssl_trusted_ca_server = options.ssl_verify_upstream_trusted_ca def process_proxy_options(parser, options, args): @@ -183,7 +174,6 @@ def process_proxy_options(parser, options, args): "to the client chain." ) if args.auth_nonanonymous or args.auth_singleuser or args.auth_htpasswd: - if args.transparent_proxy: return parser.error("Proxy Authentication not supported in transparent mode.") @@ -205,7 +195,8 @@ def process_proxy_options(parser, options, args): elif args.auth_htpasswd: try: password_manager = authentication.PassManHtpasswd( - args.auth_htpasswd) + args.auth_htpasswd + ) except ValueError as v: return parser.error(v) authenticator = authentication.BasicProxyAuth(password_manager, "mitmproxy") @@ -222,10 +213,4 @@ def process_proxy_options(parser, options, args): authenticator=authenticator, ciphers_client=args.ciphers_client, ciphers_server=args.ciphers_server, - ssl_version_client=args.ssl_version_client, - ssl_version_server=args.ssl_version_server, - ssl_verify_upstream_cert=args.ssl_verify_upstream_cert, - ssl_verify_upstream_trusted_cadir=args.ssl_verify_upstream_trusted_cadir, - ssl_verify_upstream_trusted_ca=args.ssl_verify_upstream_trusted_ca, - add_upstream_certs_to_client_chain=args.add_upstream_certs_to_client_chain, ) diff --git a/test/mitmproxy/tservers.py b/test/mitmproxy/tservers.py index b7b1f001..2bfc27e8 100644 --- a/test/mitmproxy/tservers.py +++ b/test/mitmproxy/tservers.py @@ -123,9 +123,12 @@ class ProxyTestBase(object): cnf = dict( no_upstream_cert = cls.no_upstream_cert, authenticator = cls.authenticator, - add_upstream_certs_to_client_chain = cls.add_upstream_certs_to_client_chain, ) - return cnf, options.Options(listen_port=0, cadir=cls.cadir) + return cnf, options.Options( + listen_port=0, + cadir=cls.cadir, + add_upstream_certs_to_client_chain=cls.add_upstream_certs_to_client_chain + ) class HTTPProxyTest(ProxyTestBase): -- cgit v1.2.3 From 98bf544664dcbf4b8846d1dbe5c07d053baad184 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 19 Jul 2016 12:17:30 +1200 Subject: Regularize naming of upstream_trusted_ca* options --- mitmproxy/protocol/tls.py | 4 ++-- mitmproxy/proxy/config.py | 2 -- test/mitmproxy/test_proxy.py | 4 ++-- test/mitmproxy/test_server.py | 14 +++++++------- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/mitmproxy/protocol/tls.py b/mitmproxy/protocol/tls.py index 7b8b8301..6dc4f64b 100644 --- a/mitmproxy/protocol/tls.py +++ b/mitmproxy/protocol/tls.py @@ -536,8 +536,8 @@ class TlsLayer(base.Layer): method=self.config.openssl_method_server, options=self.config.openssl_options_server, verify_options=self.config.openssl_verification_mode_server, - ca_path=self.config.openssl_trusted_cadir_server, - ca_pemfile=self.config.openssl_trusted_ca_server, + ca_path=self.config.options.ssl_verify_upstream_trusted_cadir, + ca_pemfile=self.config.options.ssl_verify_upstream_trusted_ca, cipher_list=ciphers_server, alpn_protos=alpn, ) diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index 201f7051..df7ca7ad 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -161,8 +161,6 @@ class ProxyConfig: self.upstream_server = parse_server_spec(options.upstream_server) if options.upstream_auth: self.upstream_auth = parse_upstream_auth(options.upstream_auth) - self.openssl_trusted_cadir_server = options.ssl_verify_upstream_trusted_cadir - self.openssl_trusted_ca_server = options.ssl_verify_upstream_trusted_ca def process_proxy_options(parser, options, args): diff --git a/test/mitmproxy/test_proxy.py b/test/mitmproxy/test_proxy.py index 16c4821c..5cceb8c2 100644 --- a/test/mitmproxy/test_proxy.py +++ b/test/mitmproxy/test_proxy.py @@ -149,12 +149,12 @@ class TestProcessProxyOptions: def test_upstream_trusted_cadir(self): expected_dir = "/path/to/a/ca/dir" p = self.assert_noerr("--upstream-trusted-cadir", expected_dir) - assert p.openssl_trusted_cadir_server == expected_dir + assert p.options.ssl_verify_upstream_trusted_cadir == expected_dir def test_upstream_trusted_ca(self): expected_file = "/path/to/a/cert/file" p = self.assert_noerr("--upstream-trusted-ca", expected_file) - assert p.openssl_trusted_ca_server == expected_file + assert p.options.ssl_verify_upstream_trusted_ca == expected_file class TestProxyServer: diff --git a/test/mitmproxy/test_server.py b/test/mitmproxy/test_server.py index 73e070ac..a64a8565 100644 --- a/test/mitmproxy/test_server.py +++ b/test/mitmproxy/test_server.py @@ -369,14 +369,14 @@ class TestHTTPSUpstreamServerVerificationWTrustedCert(tservers.HTTPProxyTest): def test_verification_w_cadir(self): self.config.openssl_verification_mode_server = SSL.VERIFY_PEER - self.config.openssl_trusted_cadir_server = tutils.test_data.path( - "data/trusted-cadir/") - + self.config.options.ssl_verify_upstream_trusted_cadir = tutils.test_data.path( + "data/trusted-cadir/" + ) self.pathoc() def test_verification_w_pemfile(self): self.config.openssl_verification_mode_server = SSL.VERIFY_PEER - self.config.openssl_trusted_ca_server = tutils.test_data.path( + self.config.options.ssl_verify_upstream_trusted_ca = tutils.test_data.path( "data/trusted-cadir/trusted-ca.pem") self.pathoc() @@ -401,21 +401,21 @@ class TestHTTPSUpstreamServerVerificationWBadCert(tservers.HTTPProxyTest): def test_default_verification_w_bad_cert(self): """Should use no verification.""" - self.config.openssl_trusted_ca_server = tutils.test_data.path( + self.config.options.ssl_verify_upstream_trusted_ca = tutils.test_data.path( "data/trusted-cadir/trusted-ca.pem") assert self._request().status_code == 242 def test_no_verification_w_bad_cert(self): self.config.openssl_verification_mode_server = SSL.VERIFY_NONE - self.config.openssl_trusted_ca_server = tutils.test_data.path( + self.config.options.ssl_verify_upstream_trusted_ca = tutils.test_data.path( "data/trusted-cadir/trusted-ca.pem") assert self._request().status_code == 242 def test_verification_w_bad_cert(self): self.config.openssl_verification_mode_server = SSL.VERIFY_PEER - self.config.openssl_trusted_ca_server = tutils.test_data.path( + self.config.options.ssl_verify_upstream_trusted_ca = tutils.test_data.path( "data/trusted-cadir/trusted-ca.pem") assert self._request().status_code == 502 -- cgit v1.2.3 From 77bf092bcd324edd68cffd9f5018198bca938e8a Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 19 Jul 2016 12:32:26 +1200 Subject: ProxyConfig: tcp_hosts and ignore_hosts to Options --- mitmproxy/cmdline.py | 4 +++- mitmproxy/flow/options.py | 8 ++++++-- mitmproxy/proxy/config.py | 11 +++++------ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py index 73508871..b15e0427 100644 --- a/mitmproxy/cmdline.py +++ b/mitmproxy/cmdline.py @@ -240,10 +240,12 @@ def get_common_options(args): replay_ignore_payload_params=args.replay_ignore_payload_params, replay_ignore_host=args.replay_ignore_host, + add_upstream_certs_to_client_chain = args.add_upstream_certs_to_client_chain, body_size_limit = body_size_limit, cadir = args.cadir, certs = certs, clientcerts = args.clientcerts, + ignore_hosts = args.ignore_hosts, listen_host = args.addr, listen_port = args.port, mode = mode, @@ -254,7 +256,7 @@ def get_common_options(args): ssl_verify_upstream_cert = args.ssl_verify_upstream_cert, ssl_verify_upstream_trusted_cadir = args.ssl_verify_upstream_trusted_cadir, ssl_verify_upstream_trusted_ca = args.ssl_verify_upstream_trusted_ca, - add_upstream_certs_to_client_chain = args.add_upstream_certs_to_client_chain, + tcp_hosts = args.tcp_hosts, ) diff --git a/mitmproxy/flow/options.py b/mitmproxy/flow/options.py index 31150b55..78268b89 100644 --- a/mitmproxy/flow/options.py +++ b/mitmproxy/flow/options.py @@ -39,10 +39,12 @@ class Options(options.Options): replay_ignore_host=False, # type: bool # Proxy options + add_upstream_certs_to_client_chain=False, # type: bool body_size_limit=None, # type: Optional[int] cadir = cmdline.CA_DIR, # type: str certs = (), # type: Sequence[Tuple[str, str]] clientcerts = None, # type: Optional[str] + ignore_hosts = (), # type: Sequence[str] listen_host = "", # type: str listen_port = 8080, # type: int mode = "regular", # type: str @@ -53,7 +55,7 @@ class Options(options.Options): ssl_verify_upstream_cert=False, # type: bool ssl_verify_upstream_trusted_cadir=None, # type: str ssl_verify_upstream_trusted_ca=None, # type: str - add_upstream_certs_to_client_chain=False, # type: bool + tcp_hosts = (), # type: Sequence[str] ): # We could replace all assignments with clever metaprogramming, # but type hints are a much more valueable asset. @@ -86,10 +88,12 @@ class Options(options.Options): self.replay_ignore_host = replay_ignore_host # Proxy options + self.add_upstream_certs_to_client_chain = add_upstream_certs_to_client_chain self.body_size_limit = body_size_limit self.cadir = cadir self.certs = certs self.clientcerts = clientcerts + self.ignore_hosts = ignore_hosts self.listen_host = listen_host self.listen_port = listen_port self.mode = mode @@ -100,5 +104,5 @@ class Options(options.Options): self.ssl_verify_upstream_cert = ssl_verify_upstream_cert self.ssl_verify_upstream_trusted_cadir = ssl_verify_upstream_trusted_cadir self.ssl_verify_upstream_trusted_ca = ssl_verify_upstream_trusted_ca - self.add_upstream_certs_to_client_chain = add_upstream_certs_to_client_chain + self.tcp_hosts = tcp_hosts super(Options, self).__init__() diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index df7ca7ad..58c7d1c6 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -87,8 +87,6 @@ class ProxyConfig: options, no_upstream_cert=False, authenticator=None, - ignore_hosts=tuple(), - tcp_hosts=tuple(), http2=True, rawtcp=False, ciphers_client=DEFAULT_CLIENT_CIPHERS, @@ -100,8 +98,6 @@ class ProxyConfig: self.ciphers_server = ciphers_server self.no_upstream_cert = no_upstream_cert - self.check_ignore = HostMatcher(ignore_hosts) - self.check_tcp = HostMatcher(tcp_hosts) self.http2 = http2 self.rawtcp = rawtcp self.authenticator = authenticator @@ -116,12 +112,17 @@ class ProxyConfig: else: self.openssl_verification_mode_server = SSL.VERIFY_NONE + self.check_ignore = None + self.check_tcp = None self.certstore = None self.clientcerts = None self.configure(options) options.changed.connect(self.configure) def configure(self, options): + self.check_ignore = HostMatcher(options.ignore_hosts) + self.check_tcp = HostMatcher(options.tcp_hosts) + certstore_path = os.path.expanduser(options.cadir) if not os.path.exists(os.path.dirname(certstore_path)): raise exceptions.OptionsError( @@ -204,8 +205,6 @@ def process_proxy_options(parser, options, args): return ProxyConfig( options, no_upstream_cert=args.no_upstream_cert, - ignore_hosts=args.ignore_hosts, - tcp_hosts=args.tcp_hosts, http2=args.http2, rawtcp=args.rawtcp, authenticator=authenticator, -- cgit v1.2.3 From 26fa88a338c96a9e57fdbf3943a8936eaac4c5c7 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 19 Jul 2016 13:23:54 +1200 Subject: ProxyConfig: Refactor to move verification mode checks into configure --- mitmproxy/proxy/config.py | 21 +++++++++++---------- test/mitmproxy/test_server.py | 36 ++++++++++++++++++++++-------------- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index 58c7d1c6..2bf044a0 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -102,27 +102,28 @@ class ProxyConfig: self.rawtcp = rawtcp self.authenticator = authenticator - self.openssl_method_client, self.openssl_options_client = \ - tcp.sslversion_choices[options.ssl_version_client] - self.openssl_method_server, self.openssl_options_server = \ - tcp.sslversion_choices[options.ssl_version_server] - - if options.ssl_verify_upstream_cert: - self.openssl_verification_mode_server = SSL.VERIFY_PEER - else: - self.openssl_verification_mode_server = SSL.VERIFY_NONE - self.check_ignore = None self.check_tcp = None self.certstore = None self.clientcerts = None + self.openssl_verification_mode_server = None self.configure(options) options.changed.connect(self.configure) def configure(self, options): + if options.ssl_verify_upstream_cert: + self.openssl_verification_mode_server = SSL.VERIFY_PEER + else: + self.openssl_verification_mode_server = SSL.VERIFY_NONE + self.check_ignore = HostMatcher(options.ignore_hosts) self.check_tcp = HostMatcher(options.tcp_hosts) + self.openssl_method_client, self.openssl_options_client = \ + tcp.sslversion_choices[options.ssl_version_client] + self.openssl_method_server, self.openssl_options_server = \ + tcp.sslversion_choices[options.ssl_version_server] + certstore_path = os.path.expanduser(options.cadir) if not os.path.exists(os.path.dirname(certstore_path)): raise exceptions.OptionsError( diff --git a/test/mitmproxy/test_server.py b/test/mitmproxy/test_server.py index a64a8565..f036fefd 100644 --- a/test/mitmproxy/test_server.py +++ b/test/mitmproxy/test_server.py @@ -368,9 +368,11 @@ class TestHTTPSUpstreamServerVerificationWTrustedCert(tservers.HTTPProxyTest): ]) def test_verification_w_cadir(self): - self.config.openssl_verification_mode_server = SSL.VERIFY_PEER - self.config.options.ssl_verify_upstream_trusted_cadir = tutils.test_data.path( - "data/trusted-cadir/" + self.config.options.update( + ssl_verify_upstream_cert = True, + ssl_verify_upstream_trusted_cadir = tutils.test_data.path( + "data/trusted-cadir/" + ) ) self.pathoc() @@ -401,23 +403,29 @@ class TestHTTPSUpstreamServerVerificationWBadCert(tservers.HTTPProxyTest): def test_default_verification_w_bad_cert(self): """Should use no verification.""" - self.config.options.ssl_verify_upstream_trusted_ca = tutils.test_data.path( - "data/trusted-cadir/trusted-ca.pem") - + self.config.options.update( + ssl_verify_upstream_trusted_ca = tutils.test_data.path( + "data/trusted-cadir/trusted-ca.pem" + ) + ) assert self._request().status_code == 242 def test_no_verification_w_bad_cert(self): - self.config.openssl_verification_mode_server = SSL.VERIFY_NONE - self.config.options.ssl_verify_upstream_trusted_ca = tutils.test_data.path( - "data/trusted-cadir/trusted-ca.pem") - + self.config.options.update( + ssl_verify_upstream_cert = False, + ssl_verify_upstream_trusted_ca = tutils.test_data.path( + "data/trusted-cadir/trusted-ca.pem" + ) + ) assert self._request().status_code == 242 def test_verification_w_bad_cert(self): - self.config.openssl_verification_mode_server = SSL.VERIFY_PEER - self.config.options.ssl_verify_upstream_trusted_ca = tutils.test_data.path( - "data/trusted-cadir/trusted-ca.pem") - + self.config.options.update( + ssl_verify_upstream_cert = True, + ssl_verify_upstream_trusted_ca = tutils.test_data.path( + "data/trusted-cadir/trusted-ca.pem" + ) + ) assert self._request().status_code == 502 -- cgit v1.2.3 From fb6e9c44c82346df2ab434a0aa6db34fb50902b2 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 19 Jul 2016 13:43:53 +1200 Subject: ProxyConfig: ciphers_client and ciphers_server -> Options --- mitmproxy/cmdline.py | 17 +++++++++++++++-- mitmproxy/flow/options.py | 4 ++++ mitmproxy/protocol/tls.py | 4 ++-- mitmproxy/proxy/config.py | 18 ------------------ 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py index b15e0427..f703b8ec 100644 --- a/mitmproxy/cmdline.py +++ b/mitmproxy/cmdline.py @@ -7,7 +7,6 @@ import configargparse from mitmproxy import exceptions from mitmproxy import filt -from mitmproxy.proxy import config from mitmproxy import platform from netlib import human from netlib import tcp @@ -17,6 +16,18 @@ APP_HOST = "mitm.it" APP_PORT = 80 CA_DIR = "~/.mitmproxy" +# We manually need to specify this, otherwise OpenSSL may select a non-HTTP2 cipher by default. +# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=apache-2.2.15&openssl=1.0.2&hsts=yes&profile=old +DEFAULT_CLIENT_CIPHERS = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:" \ + "ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:" \ + "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:" \ + "ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:" \ + "DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:" \ + "DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:" \ + "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:" \ + "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:" \ + "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA" + class ParseException(Exception): pass @@ -244,6 +255,8 @@ def get_common_options(args): body_size_limit = body_size_limit, cadir = args.cadir, certs = certs, + ciphers_client = args.ciphers_client, + ciphers_server = args.ciphers_server, clientcerts = args.clientcerts, ignore_hosts = args.ignore_hosts, listen_host = args.addr, @@ -487,7 +500,7 @@ def proxy_ssl_options(parser): 'as the first entry. Can be passed multiple times.') group.add_argument( "--ciphers-client", action="store", - type=str, dest="ciphers_client", default=config.DEFAULT_CLIENT_CIPHERS, + type=str, dest="ciphers_client", default=DEFAULT_CLIENT_CIPHERS, help="Set supported ciphers for client connections. (OpenSSL Syntax)" ) group.add_argument( diff --git a/mitmproxy/flow/options.py b/mitmproxy/flow/options.py index 78268b89..2586fec7 100644 --- a/mitmproxy/flow/options.py +++ b/mitmproxy/flow/options.py @@ -43,6 +43,8 @@ class Options(options.Options): body_size_limit=None, # type: Optional[int] cadir = cmdline.CA_DIR, # type: str certs = (), # type: Sequence[Tuple[str, str]] + ciphers_client = cmdline.DEFAULT_CLIENT_CIPHERS, # type: str + ciphers_server = None, # type: Optional[str] clientcerts = None, # type: Optional[str] ignore_hosts = (), # type: Sequence[str] listen_host = "", # type: str @@ -92,6 +94,8 @@ class Options(options.Options): self.body_size_limit = body_size_limit self.cadir = cadir self.certs = certs + self.ciphers_client = ciphers_client + self.ciphers_server = ciphers_server self.clientcerts = clientcerts self.ignore_hosts = ignore_hosts self.listen_host = listen_host diff --git a/mitmproxy/protocol/tls.py b/mitmproxy/protocol/tls.py index 6dc4f64b..c44df299 100644 --- a/mitmproxy/protocol/tls.py +++ b/mitmproxy/protocol/tls.py @@ -483,7 +483,7 @@ class TlsLayer(base.Layer): cert, key, method=self.config.openssl_method_client, options=self.config.openssl_options_client, - cipher_list=self.config.ciphers_client, + cipher_list=self.config.options.ciphers_client, dhparams=self.config.certstore.dhparams, chain_file=chain_file, alpn_select_callback=self.__alpn_select_callback, @@ -522,7 +522,7 @@ class TlsLayer(base.Layer): if alpn and b"h2" in alpn and not self.config.http2: alpn.remove(b"h2") - ciphers_server = self.config.ciphers_server + ciphers_server = self.config.options.ciphers_server if not ciphers_server: ciphers_server = [] for id in self._client_hello.cipher_suites: diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index 2bf044a0..6e645b99 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -17,18 +17,6 @@ from netlib.http import url CONF_BASENAME = "mitmproxy" -# We manually need to specify this, otherwise OpenSSL may select a non-HTTP2 cipher by default. -# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=apache-2.2.15&openssl=1.0.2&hsts=yes&profile=old -DEFAULT_CLIENT_CIPHERS = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:" \ - "ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:" \ - "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:" \ - "ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:" \ - "DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:" \ - "DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:" \ - "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:" \ - "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:" \ - "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA" - class HostMatcher(object): @@ -89,13 +77,9 @@ class ProxyConfig: authenticator=None, http2=True, rawtcp=False, - ciphers_client=DEFAULT_CLIENT_CIPHERS, - ciphers_server=None, certs=tuple(), ): self.options = options - self.ciphers_client = ciphers_client - self.ciphers_server = ciphers_server self.no_upstream_cert = no_upstream_cert self.http2 = http2 @@ -209,6 +193,4 @@ def process_proxy_options(parser, options, args): http2=args.http2, rawtcp=args.rawtcp, authenticator=authenticator, - ciphers_client=args.ciphers_client, - ciphers_server=args.ciphers_server, ) -- cgit v1.2.3 From 5cfe783b6c38b9fa6473e57b9567149146829108 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 19 Jul 2016 14:06:02 +1200 Subject: ProxyConfig: http2, rawtcp, no_upstream_cert -> Options --- mitmproxy/cmdline.py | 3 +++ mitmproxy/console/master.py | 2 +- mitmproxy/dump.py | 2 +- mitmproxy/flow/options.py | 6 ++++++ mitmproxy/protocol/tls.py | 6 +++--- mitmproxy/proxy/config.py | 10 ---------- mitmproxy/proxy/root_context.py | 2 +- mitmproxy/web/app.py | 12 ++++++------ test/mitmproxy/test_protocol_http2.py | 5 +---- test/mitmproxy/tservers.py | 2 +- 10 files changed, 23 insertions(+), 27 deletions(-) diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py index f703b8ec..00d71511 100644 --- a/mitmproxy/cmdline.py +++ b/mitmproxy/cmdline.py @@ -258,10 +258,13 @@ def get_common_options(args): ciphers_client = args.ciphers_client, ciphers_server = args.ciphers_server, clientcerts = args.clientcerts, + http2 = args.http2, ignore_hosts = args.ignore_hosts, listen_host = args.addr, listen_port = args.port, mode = mode, + no_upstream_cert = args.no_upstream_cert, + rawtcp = args.rawtcp, upstream_server = upstream_server, upstream_auth = args.upstream_auth, ssl_version_client = args.ssl_version_client, diff --git a/mitmproxy/console/master.py b/mitmproxy/console/master.py index 25a0b83f..86e889cc 100644 --- a/mitmproxy/console/master.py +++ b/mitmproxy/console/master.py @@ -476,7 +476,7 @@ class ConsoleMaster(flow.FlowMaster): sys.exit(1) self.loop.set_alarm_in(0.01, self.ticker) - if self.server.config.http2 and not tcp.HAS_ALPN: # pragma: no cover + if self.options.http2 and not tcp.HAS_ALPN: # pragma: no cover def http2err(*args, **kwargs): signals.status_message.send( message = "HTTP/2 disabled - OpenSSL 1.0.2+ required." diff --git a/mitmproxy/dump.py b/mitmproxy/dump.py index eaa368a0..78dd2578 100644 --- a/mitmproxy/dump.py +++ b/mitmproxy/dump.py @@ -53,7 +53,7 @@ class DumpMaster(flow.FlowMaster): self.set_stream_large_bodies(options.stream_large_bodies) - if self.server and self.server.config.http2 and not tcp.HAS_ALPN: # pragma: no cover + if self.server and self.options.http2 and not tcp.HAS_ALPN: # pragma: no cover print("ALPN support missing (OpenSSL 1.0.2+ required)!\n" "HTTP/2 is disabled. Use --no-http2 to silence this warning.", file=sys.stderr) diff --git a/mitmproxy/flow/options.py b/mitmproxy/flow/options.py index 2586fec7..f1f8c2ed 100644 --- a/mitmproxy/flow/options.py +++ b/mitmproxy/flow/options.py @@ -46,10 +46,13 @@ class Options(options.Options): ciphers_client = cmdline.DEFAULT_CLIENT_CIPHERS, # type: str ciphers_server = None, # type: Optional[str] clientcerts = None, # type: Optional[str] + http2 = True, # type: bool ignore_hosts = (), # type: Sequence[str] listen_host = "", # type: str listen_port = 8080, # type: int mode = "regular", # type: str + no_upstream_cert = False, # type: bool + rawtcp = False, # type: bool upstream_server = "", # type: str upstream_auth = "", # type: str ssl_version_client="secure", # type: str @@ -97,10 +100,13 @@ class Options(options.Options): self.ciphers_client = ciphers_client self.ciphers_server = ciphers_server self.clientcerts = clientcerts + self.http2 = http2 self.ignore_hosts = ignore_hosts self.listen_host = listen_host self.listen_port = listen_port self.mode = mode + self.no_upstream_cert = no_upstream_cert + self.rawtcp = rawtcp self.upstream_server = upstream_server self.upstream_auth = upstream_auth self.ssl_version_client = ssl_version_client diff --git a/mitmproxy/protocol/tls.py b/mitmproxy/protocol/tls.py index c44df299..51f4d80d 100644 --- a/mitmproxy/protocol/tls.py +++ b/mitmproxy/protocol/tls.py @@ -366,7 +366,7 @@ class TlsLayer(base.Layer): # 2.5 The client did not sent a SNI value, we don't know the certificate subject. client_tls_requires_server_connection = ( self._server_tls and - not self.config.no_upstream_cert and + not self.config.options.no_upstream_cert and ( self.config.options.add_upstream_certs_to_client_chain or self._client_hello.alpn_protocols or @@ -519,7 +519,7 @@ class TlsLayer(base.Layer): alpn = [x for x in self._client_hello.alpn_protocols if not deprecated_http2_variant(x)] else: alpn = None - if alpn and b"h2" in alpn and not self.config.http2: + if alpn and b"h2" in alpn and not self.config.options.http2: alpn.remove(b"h2") ciphers_server = self.config.options.ciphers_server @@ -595,7 +595,7 @@ class TlsLayer(base.Layer): use_upstream_cert = ( self.server_conn and self.server_conn.tls_established and - (not self.config.no_upstream_cert) + (not self.config.options.no_upstream_cert) ) if use_upstream_cert: upstream_cert = self.server_conn.cert diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index 6e645b99..ff133084 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -73,17 +73,10 @@ class ProxyConfig: def __init__( self, options, - no_upstream_cert=False, authenticator=None, - http2=True, - rawtcp=False, - certs=tuple(), ): self.options = options - self.no_upstream_cert = no_upstream_cert - self.http2 = http2 - self.rawtcp = rawtcp self.authenticator = authenticator self.check_ignore = None @@ -189,8 +182,5 @@ def process_proxy_options(parser, options, args): return ProxyConfig( options, - no_upstream_cert=args.no_upstream_cert, - http2=args.http2, - rawtcp=args.rawtcp, authenticator=authenticator, ) diff --git a/mitmproxy/proxy/root_context.py b/mitmproxy/proxy/root_context.py index 4d6509d4..81dd625c 100644 --- a/mitmproxy/proxy/root_context.py +++ b/mitmproxy/proxy/root_context.py @@ -102,7 +102,7 @@ class RootContext(object): # expect A-Za-z all(65 <= x <= 90 or 97 <= x <= 122 for x in six.iterbytes(d)) ) - if self.config.rawtcp and not is_ascii: + if self.config.options.rawtcp and not is_ascii: return protocol.RawTCPLayer(top_layer) # 7. Assume HTTP1 by default diff --git a/mitmproxy/web/app.py b/mitmproxy/web/app.py index e6b95cdf..b643f97e 100644 --- a/mitmproxy/web/app.py +++ b/mitmproxy/web/app.py @@ -339,9 +339,9 @@ class Settings(RequestHandler): mode=str(self.master.options.mode), intercept=self.state.intercept_txt, showhost=self.master.options.showhost, - no_upstream_cert=self.master.server.config.no_upstream_cert, - rawtcp=self.master.server.config.rawtcp, - http2=self.master.server.config.http2, + no_upstream_cert=self.master.options.no_upstream_cert, + rawtcp=self.master.options.rawtcp, + http2=self.master.options.http2, anticache=self.master.options.anticache, anticomp=self.master.options.anticomp, stickyauth=self.master.options.stickyauth, @@ -360,13 +360,13 @@ class Settings(RequestHandler): self.master.options.showhost = v update[k] = v elif k == "no_upstream_cert": - self.master.server.config.no_upstream_cert = v + self.master.options.no_upstream_cert = v update[k] = v elif k == "rawtcp": - self.master.server.config.rawtcp = v + self.master.options.rawtcp = v update[k] = v elif k == "http2": - self.master.server.config.http2 = v + self.master.options.http2 = v update[k] = v elif k == "anticache": self.master.options.anticache = v diff --git a/test/mitmproxy/test_protocol_http2.py b/test/mitmproxy/test_protocol_http2.py index d910ecae..e8866643 100644 --- a/test/mitmproxy/test_protocol_http2.py +++ b/test/mitmproxy/test_protocol_http2.py @@ -104,10 +104,9 @@ class _Http2TestBase(object): @classmethod def get_proxy_config(cls): - opts = options.Options(listen_port=0) + opts = options.Options(listen_port=0, no_upstream_cert=False) opts.cadir = os.path.join(tempfile.gettempdir(), "mitmproxy") d = dict( - no_upstream_cert=False, authenticator=None, ) return d, opts @@ -122,8 +121,6 @@ class _Http2TestBase(object): self.server.server.handle_server_event = self.handle_server_event def _setup_connection(self): - self.config.http2 = True - client = netlib.tcp.TCPClient(("127.0.0.1", self.proxy.port)) client.connect() diff --git a/test/mitmproxy/tservers.py b/test/mitmproxy/tservers.py index 2bfc27e8..8df30e34 100644 --- a/test/mitmproxy/tservers.py +++ b/test/mitmproxy/tservers.py @@ -121,12 +121,12 @@ class ProxyTestBase(object): def get_proxy_config(cls): cls.cadir = os.path.join(tempfile.gettempdir(), "mitmproxy") cnf = dict( - no_upstream_cert = cls.no_upstream_cert, authenticator = cls.authenticator, ) return cnf, options.Options( listen_port=0, cadir=cls.cadir, + no_upstream_cert = cls.no_upstream_cert, add_upstream_certs_to_client_chain=cls.add_upstream_certs_to_client_chain ) -- cgit v1.2.3 From be081a24bc1e1d7cd740289775b6de8e1ece2372 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 19 Jul 2016 14:51:12 +1200 Subject: ProxyConf: auth_* into Options --- mitmproxy/cmdline.py | 3 + mitmproxy/flow/options.py | 6 ++ mitmproxy/proxy/config.py | 103 ++++++++++++++++++---------------- test/mitmproxy/test_protocol_http2.py | 4 +- test/mitmproxy/test_proxy.py | 6 +- test/mitmproxy/test_server.py | 7 +-- test/mitmproxy/tservers.py | 5 +- 7 files changed, 73 insertions(+), 61 deletions(-) diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py index 00d71511..696542f6 100644 --- a/mitmproxy/cmdline.py +++ b/mitmproxy/cmdline.py @@ -251,6 +251,9 @@ def get_common_options(args): replay_ignore_payload_params=args.replay_ignore_payload_params, replay_ignore_host=args.replay_ignore_host, + auth_nonanonymous = args.auth_nonanonymous, + auth_singleuser = args.auth_singleuser, + auth_htpasswd = args.auth_htpasswd, add_upstream_certs_to_client_chain = args.add_upstream_certs_to_client_chain, body_size_limit = body_size_limit, cadir = args.cadir, diff --git a/mitmproxy/flow/options.py b/mitmproxy/flow/options.py index f1f8c2ed..726952e2 100644 --- a/mitmproxy/flow/options.py +++ b/mitmproxy/flow/options.py @@ -39,6 +39,9 @@ class Options(options.Options): replay_ignore_host=False, # type: bool # Proxy options + auth_nonanonymous=False, # type: bool + auth_singleuser=None, # type: Optional[str] + auth_htpasswd=None, # type: Optional[str] add_upstream_certs_to_client_chain=False, # type: bool body_size_limit=None, # type: Optional[int] cadir = cmdline.CA_DIR, # type: str @@ -93,6 +96,9 @@ class Options(options.Options): self.replay_ignore_host = replay_ignore_host # Proxy options + self.auth_nonanonymous = auth_nonanonymous + self.auth_singleuser = auth_singleuser + self.auth_htpasswd = auth_htpasswd self.add_upstream_certs_to_client_chain = add_upstream_certs_to_client_chain self.body_size_limit = body_size_limit self.cadir = cadir diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index ff133084..bd9f135d 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -70,15 +70,10 @@ def parse_upstream_auth(auth): class ProxyConfig: - def __init__( - self, - options, - authenticator=None, - ): + def __init__(self, options): self.options = options - self.authenticator = authenticator - + self.authenticator = None self.check_ignore = None self.check_tcp = None self.certstore = None @@ -88,6 +83,20 @@ class ProxyConfig: options.changed.connect(self.configure) def configure(self, options): + conflict = all( + [ + options.add_upstream_certs_to_client_chain, + options.ssl_verify_upstream_cert + ] + ) + if conflict: + raise exceptions.OptionsError( + "The verify-upstream-cert and add-upstream-certs-to-client-chain " + "options are mutually exclusive. If upstream certificates are verified " + "then extra upstream certificates are not available for inclusion " + "to the client chain." + ) + if options.ssl_verify_upstream_cert: self.openssl_verification_mode_server = SSL.VERIFY_PEER else: @@ -141,46 +150,46 @@ class ProxyConfig: if options.upstream_auth: self.upstream_auth = parse_upstream_auth(options.upstream_auth) - -def process_proxy_options(parser, options, args): - if args.add_upstream_certs_to_client_chain and args.ssl_verify_upstream_cert: - return parser.error( - "The verify-upstream-cert and add-upstream-certs-to-client-chain " - "options are mutually exclusive. If upstream certificates are verified " - "then extra upstream certificates are not available for inclusion " - "to the client chain." + self.authenticator = authentication.NullProxyAuth(None) + needsauth = any( + [ + options.auth_nonanonymous, + options.auth_singleuser, + options.auth_htpasswd + ] ) - if args.auth_nonanonymous or args.auth_singleuser or args.auth_htpasswd: - if args.transparent_proxy: - return parser.error("Proxy Authentication not supported in transparent mode.") - - if args.socks_proxy: - return parser.error( - "Proxy Authentication not supported in SOCKS mode. " - "https://github.com/mitmproxy/mitmproxy/issues/738" - ) - - if args.auth_singleuser: - if len(args.auth_singleuser.split(':')) != 2: - return parser.error( - "Invalid single-user specification. Please use the format username:password" + if needsauth: + if options.mode == "transparent": + raise exceptions.OptionsError( + "Proxy Authentication not supported in transparent mode." ) - username, password = args.auth_singleuser.split(':') - password_manager = authentication.PassManSingleUser(username, password) - elif args.auth_nonanonymous: - password_manager = authentication.PassManNonAnon() - elif args.auth_htpasswd: - try: - password_manager = authentication.PassManHtpasswd( - args.auth_htpasswd + elif options.mode == "socks5": + raise exceptions.OptionsError( + "Proxy Authentication not supported in SOCKS mode. " + "https://github.com/mitmproxy/mitmproxy/issues/738" ) - except ValueError as v: - return parser.error(v) - authenticator = authentication.BasicProxyAuth(password_manager, "mitmproxy") - else: - authenticator = authentication.NullProxyAuth(None) - - return ProxyConfig( - options, - authenticator=authenticator, - ) + elif options.auth_singleuser: + parts = options.auth_singleuser.split(':') + if len(parts) != 2: + raise exceptions.OptionsError( + "Invalid single-user specification. " + "Please use the format username:password" + ) + password_manager = authentication.PassManSingleUser(*parts) + elif options.auth_nonanonymous: + password_manager = authentication.PassManNonAnon() + elif options.auth_htpasswd: + try: + password_manager = authentication.PassManHtpasswd( + options.auth_htpasswd + ) + except ValueError as v: + raise exceptions.OptionsError(str(v)) + self.authenticator = authentication.BasicProxyAuth( + password_manager, + "mitmproxy" + ) + + +def process_proxy_options(parser, options, args): + return ProxyConfig(options) diff --git a/test/mitmproxy/test_protocol_http2.py b/test/mitmproxy/test_protocol_http2.py index e8866643..a7a3ba3f 100644 --- a/test/mitmproxy/test_protocol_http2.py +++ b/test/mitmproxy/test_protocol_http2.py @@ -106,9 +106,7 @@ class _Http2TestBase(object): def get_proxy_config(cls): opts = options.Options(listen_port=0, no_upstream_cert=False) opts.cadir = os.path.join(tempfile.gettempdir(), "mitmproxy") - d = dict( - authenticator=None, - ) + d = dict() return d, opts @property diff --git a/test/mitmproxy/test_proxy.py b/test/mitmproxy/test_proxy.py index 5cceb8c2..4127a889 100644 --- a/test/mitmproxy/test_proxy.py +++ b/test/mitmproxy/test_proxy.py @@ -103,7 +103,11 @@ class TestProcessProxyOptions: # self.assert_err("mutually exclusive", "-R", "http://localhost", "-T") def test_socks_auth(self): - self.assert_err("Proxy Authentication not supported in SOCKS mode.", "--socks", "--nonanonymous") + self.assert_err( + "Proxy Authentication not supported in SOCKS mode.", + "--socks", + "--nonanonymous" + ) def test_client_certs(self): with tutils.tmpdir() as cadir: diff --git a/test/mitmproxy/test_server.py b/test/mitmproxy/test_server.py index f036fefd..b8b057fd 100644 --- a/test/mitmproxy/test_server.py +++ b/test/mitmproxy/test_server.py @@ -298,13 +298,8 @@ class TestHTTP(tservers.HTTPProxyTest, CommonMixin, AppMixin): class TestHTTPAuth(tservers.HTTPProxyTest): - authenticator = http.authentication.BasicProxyAuth( - http.authentication.PassManSingleUser( - "test", - "test"), - "realm") - def test_auth(self): + self.master.options.auth_singleuser = "test:test" assert self.pathod("202").status_code == 407 p = self.pathoc() ret = p.request(""" diff --git a/test/mitmproxy/tservers.py b/test/mitmproxy/tservers.py index 8df30e34..495765da 100644 --- a/test/mitmproxy/tservers.py +++ b/test/mitmproxy/tservers.py @@ -78,7 +78,6 @@ class ProxyTestBase(object): ssl = None ssloptions = False no_upstream_cert = False - authenticator = None masterclass = TestMaster add_upstream_certs_to_client_chain = False @@ -120,9 +119,7 @@ class ProxyTestBase(object): @classmethod def get_proxy_config(cls): cls.cadir = os.path.join(tempfile.gettempdir(), "mitmproxy") - cnf = dict( - authenticator = cls.authenticator, - ) + cnf = dict() return cnf, options.Options( listen_port=0, cadir=cls.cadir, -- cgit v1.2.3 From ef380917a89d18d684c03269bae77f6d53dcc1b8 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 19 Jul 2016 15:08:53 +1200 Subject: ProxyConf: adapt mitmproxy console, ditch tcp|host filter attrs on flow.master --- mitmproxy/console/options.py | 54 +++++++++++++++++------------------------- mitmproxy/console/statusbar.py | 10 ++++---- mitmproxy/flow/master.py | 13 ---------- test/mitmproxy/test_flow.py | 9 ------- 4 files changed, 27 insertions(+), 59 deletions(-) diff --git a/mitmproxy/console/options.py b/mitmproxy/console/options.py index e1dd29ee..62564a60 100644 --- a/mitmproxy/console/options.py +++ b/mitmproxy/console/options.py @@ -42,8 +42,8 @@ class Options(urwid.WidgetWrap): select.Option( "Ignore Patterns", "I", - lambda: master.server.config.check_ignore, - self.ignorepatterns + lambda: master.options.ignore_hosts, + self.ignore_hosts ), select.Option( "Replacement Patterns", @@ -82,14 +82,14 @@ class Options(urwid.WidgetWrap): select.Option( "No Upstream Certs", "U", - lambda: master.server.config.no_upstream_cert, - self.toggle_upstream_cert + lambda: master.options.no_upstream_cert, + master.options.toggler("no_upstream_cert") ), select.Option( "TCP Proxying", "T", - lambda: master.server.config.check_tcp, - self.tcp_proxy + lambda: master.options.tcp_hosts, + self.tcp_hosts ), select.Heading("Utility"), @@ -152,21 +152,20 @@ class Options(urwid.WidgetWrap): return super(self.__class__, self).keypress(size, key) def clearall(self): - self.master.server.config.no_upstream_cert = False - self.master.set_ignore_filter([]) - self.master.set_tcp_filter([]) - self.master.options.update( anticache = False, anticomp = False, + ignore_hosts = (), + tcp_hosts = (), kill = False, + no_upstream_cert = False, refresh_server_playback = True, replacements = [], scripts = [], setheaders = [], showhost = False, stickyauth = None, - stickycookie = None + stickycookie = None, ) self.master.state.default_body_view = contentviews.get("Auto") @@ -177,10 +176,6 @@ class Options(urwid.WidgetWrap): expire = 1 ) - def toggle_upstream_cert(self): - self.master.server.config.no_upstream_cert = not self.master.server.config.no_upstream_cert - signals.update_settings.send(self) - def setheaders(self): self.master.view_grideditor( grideditor.SetHeadersEditor( @@ -190,14 +185,21 @@ class Options(urwid.WidgetWrap): ) ) - def ignorepatterns(self): - def _set(ignore): - self.master.set_ignore_filter(ignore) + def tcp_hosts(self): self.master.view_grideditor( grideditor.HostPatternEditor( self.master, - self.master.get_ignore_filter(), - _set + self.master.options.tcp_hosts, + self.master.options.setter("tcp_hosts") + ) + ) + + def ignore_hosts(self): + self.master.view_grideditor( + grideditor.HostPatternEditor( + self.master, + self.master.options.ignore_hosts, + self.master.options.setter("ignore_hosts") ) ) @@ -229,18 +231,6 @@ class Options(urwid.WidgetWrap): def has_default_displaymode(self): return self.master.state.default_body_view.name != "Auto" - def tcp_proxy(self): - def _set(tcp): - self.master.set_tcp_filter(tcp) - signals.update_settings.send(self) - self.master.view_grideditor( - grideditor.HostPatternEditor( - self.master, - self.master.get_tcp_filter(), - _set - ) - ) - def sticky_auth(self): signals.status_prompt.send( prompt = "Sticky auth filter", diff --git a/mitmproxy/console/statusbar.py b/mitmproxy/console/statusbar.py index e1c65714..f0da9dcd 100644 --- a/mitmproxy/console/statusbar.py +++ b/mitmproxy/console/statusbar.py @@ -156,14 +156,14 @@ class StatusBar(urwid.WidgetWrap): r.append(":%s in file]" % self.master.server_playback.count()) else: r.append(":%s to go]" % self.master.server_playback.count()) - if self.master.get_ignore_filter(): + if self.master.options.ignore_hosts: r.append("[") r.append(("heading_key", "I")) - r.append("gnore:%d]" % len(self.master.get_ignore_filter())) - if self.master.get_tcp_filter(): + r.append("gnore:%d]" % len(self.master.options.ignore_hosts)) + if self.master.options.tcp_hosts: r.append("[") r.append(("heading_key", "T")) - r.append("CP:%d]" % len(self.master.get_tcp_filter())) + r.append("CP:%d]" % len(self.master.options.tcp_hosts)) if self.master.state.intercept_txt: r.append("[") r.append(("heading_key", "i")) @@ -200,7 +200,7 @@ class StatusBar(urwid.WidgetWrap): opts.append("norefresh") if self.master.options.kill: opts.append("killextra") - if self.master.server.config.no_upstream_cert: + if self.master.options.no_upstream_cert: opts.append("no-upstream-cert") if self.master.state.follow_focus: opts.append("following") diff --git a/mitmproxy/flow/master.py b/mitmproxy/flow/master.py index a31840d9..088375fe 100644 --- a/mitmproxy/flow/master.py +++ b/mitmproxy/flow/master.py @@ -13,7 +13,6 @@ from mitmproxy.flow import io from mitmproxy.flow import modules from mitmproxy.onboarding import app from mitmproxy.protocol import http_replay -from mitmproxy.proxy.config import HostMatcher class FlowMaster(controller.Master): @@ -48,18 +47,6 @@ class FlowMaster(controller.Master): port ) - def get_ignore_filter(self): - return self.server.config.check_ignore.patterns - - def set_ignore_filter(self, host_patterns): - self.server.config.check_ignore = HostMatcher(host_patterns) - - def get_tcp_filter(self): - return self.server.config.check_tcp.patterns - - def set_tcp_filter(self, host_patterns): - self.server.config.check_tcp = HostMatcher(host_patterns) - def set_stream_large_bodies(self, max_size): if max_size is not None: self.stream_large_bodies = modules.StreamLargeBodies(max_size) diff --git a/test/mitmproxy/test_flow.py b/test/mitmproxy/test_flow.py index ee588a5c..e17a125c 100644 --- a/test/mitmproxy/test_flow.py +++ b/test/mitmproxy/test_flow.py @@ -12,7 +12,6 @@ from mitmproxy.models import Flow from mitmproxy.models import HTTPFlow from mitmproxy.models import HTTPRequest from mitmproxy.models import HTTPResponse -from mitmproxy.proxy.config import HostMatcher from mitmproxy.proxy import ProxyConfig from mitmproxy.proxy.server import DummyServer from mitmproxy.models.connections import ClientConnection @@ -690,14 +689,6 @@ class TestSerialize: class TestFlowMaster: - def test_getset_ignore(self): - p = mock.Mock() - p.config.check_ignore = HostMatcher() - fm = flow.FlowMaster(None, p, flow.State()) - assert not fm.get_ignore_filter() - fm.set_ignore_filter(["^apple\.com:", ":443$"]) - assert fm.get_ignore_filter() - def test_replay(self): s = flow.State() fm = flow.FlowMaster(None, None, s) -- cgit v1.2.3 From 9c9d28d068d5c0aadea2baf10b48435f6283d659 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 19 Jul 2016 15:19:58 +1200 Subject: Remove proxy.config.process_proxy_options --- mitmproxy/main.py | 2 +- mitmproxy/proxy/config.py | 4 ---- test/mitmproxy/test_proxy.py | 4 ++-- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/mitmproxy/main.py b/mitmproxy/main.py index 77cce161..2d7299e4 100644 --- a/mitmproxy/main.py +++ b/mitmproxy/main.py @@ -48,7 +48,7 @@ def process_options(parser, options, args): if args.quiet: args.verbose = 0 debug.register_info_dumpers() - return config.process_proxy_options(parser, options, args) + return config.ProxyConfig(options) def mitmproxy(args=None): # pragma: no cover diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index bd9f135d..7aa4c736 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -189,7 +189,3 @@ class ProxyConfig: password_manager, "mitmproxy" ) - - -def process_proxy_options(parser, options, args): - return ProxyConfig(options) diff --git a/test/mitmproxy/test_proxy.py b/test/mitmproxy/test_proxy.py index 4127a889..7095d9d2 100644 --- a/test/mitmproxy/test_proxy.py +++ b/test/mitmproxy/test_proxy.py @@ -4,10 +4,10 @@ from OpenSSL import SSL from mitmproxy import cmdline from mitmproxy.proxy import ProxyConfig -from mitmproxy.proxy.config import process_proxy_options from mitmproxy.models.connections import ServerConnection from mitmproxy.proxy.server import DummyServer, ProxyServer, ConnectionHandler from mitmproxy.flow import options +from mitmproxy.proxy import config from netlib.exceptions import TcpDisconnect from pathod import test from netlib.http import http1 @@ -61,7 +61,7 @@ class TestProcessProxyOptions: cmdline.common_options(parser) args = parser.parse_args(args=args) opts = cmdline.get_common_options(args) - pconf = process_proxy_options(parser, options.Options(**opts), args) + pconf = config.ProxyConfig(options.Options(**opts)) return parser, pconf def assert_err(self, err, *args): -- cgit v1.2.3