This commit is contained in:
Maximilian Hils 2014-08-08 04:43:44 +02:00
parent a3c3e4e504
commit de05484d9d
2 changed files with 64 additions and 46 deletions

View File

@ -11,14 +11,32 @@ CONF_DIR = "~/.mitmproxy"
class ProxyConfig: class ProxyConfig:
def __init__(self, confdir=CONF_DIR, clientcerts=None, def __init__(self, confdir=CONF_DIR, clientcerts=None,
no_upstream_cert=False, body_size_limit=None, get_upstream_server=None, no_upstream_cert=False, body_size_limit=None,
http_form_in="absolute", http_form_out="relative", authenticator=None, mode=None, upstream_server=None, http_form_in=None, http_form_out=None,
ciphers=None, certs=[], certforward = False authenticator=None,
): ciphers=None, certs=[], certforward=False):
self.ciphers = ciphers self.ciphers = ciphers
self.clientcerts = clientcerts self.clientcerts = clientcerts
self.no_upstream_cert = no_upstream_cert self.no_upstream_cert = no_upstream_cert
self.body_size_limit = body_size_limit self.body_size_limit = body_size_limit
if mode == "transparent":
get_upstream_server = TransparentUpstreamServerResolver(platform.resolver(), TRANSPARENT_SSL_PORTS)
http_form_in_default, http_form_out_default = "relative", "relative"
elif mode == "reverse":
get_upstream_server = ConstUpstreamServerResolver(upstream_server)
http_form_in_default, http_form_out_default = "relative", "relative"
elif mode == "upstream":
get_upstream_server = ConstUpstreamServerResolver(upstream_server)
http_form_in_default, http_form_out_default = "absolute", "absolute"
elif upstream_server:
get_upstream_server = ConstUpstreamServerResolver(upstream_server)
http_form_in_default, http_form_out_default = "absolute", "relative"
else:
get_upstream_server, http_form_in_default, http_form_out_default = None, "absolute", "relative"
http_form_in = http_form_in or http_form_in_default
http_form_out = http_form_out or http_form_out_default
self.get_upstream_server = get_upstream_server self.get_upstream_server = get_upstream_server
self.http_form_in = http_form_in self.http_form_in = http_form_in
self.http_form_out = http_form_out self.http_form_out = http_form_out
@ -35,32 +53,27 @@ def process_proxy_options(parser, options):
body_size_limit = utils.parse_size(options.body_size_limit) body_size_limit = utils.parse_size(options.body_size_limit)
c = 0 c = 0
http_form_in, http_form_out = "absolute", "relative" mode, upstream_server = None, None
get_upstream_server = None
if options.transparent_proxy: if options.transparent_proxy:
c += 1 c += 1
if not platform.resolver: if not platform.resolver:
return parser.error("Transparent mode not supported on this platform.") return parser.error("Transparent mode not supported on this platform.")
get_upstream_server = TransparentUpstreamServerResolver(platform.resolver(), TRANSPARENT_SSL_PORTS) mode = "transparent"
http_form_in, http_form_out = "relative", "relative"
if options.reverse_proxy: if options.reverse_proxy:
c += 1 c += 1
get_upstream_server = ConstUpstreamServerResolver(options.reverse_proxy) mode = "reverse"
http_form_in, http_form_out = "relative", "relative" upstream_server = options.reverse_proxy
if options.upstream_proxy: if options.upstream_proxy:
c += 1 c += 1
get_upstream_server = ConstUpstreamServerResolver(options.upstream_proxy) mode = "upstream"
http_form_in, http_form_out = "absolute", "absolute" upstream_server = options.upstream_proxy
if options.manual_destination_server: if options.manual_destination_server:
c += 1 c += 1
get_upstream_server = ConstUpstreamServerResolver(options.manual_destination_server) mode = "manual"
upstream_server = options.manual_destination_server
if c > 1: if c > 1:
return parser.error("Transparent mode, reverse mode, upstream proxy mode and " return parser.error("Transparent mode, reverse mode, upstream proxy mode and "
"specification of an upstream server are mutually exclusive.") "specification of an upstream server are mutually exclusive.")
if options.http_form_in:
http_form_in = options.http_form_in
if options.http_form_out:
http_form_out = options.http_form_out
if options.clientcerts: if options.clientcerts:
options.clientcerts = os.path.expanduser(options.clientcerts) options.clientcerts = os.path.expanduser(options.clientcerts)
@ -93,21 +106,22 @@ def process_proxy_options(parser, options):
parts = ["*", parts[0]] parts = ["*", parts[0]]
parts[1] = os.path.expanduser(parts[1]) parts[1] = os.path.expanduser(parts[1])
if not os.path.exists(parts[1]): if not os.path.exists(parts[1]):
parser.error("Certificate file does not exist: %s"%parts[1]) parser.error("Certificate file does not exist: %s" % parts[1])
certs.append(parts) certs.append(parts)
return ProxyConfig( return ProxyConfig(
clientcerts = options.clientcerts, confdir=options.confdir,
body_size_limit = body_size_limit, clientcerts=options.clientcerts,
no_upstream_cert = options.no_upstream_cert, no_upstream_cert=options.no_upstream_cert,
get_upstream_server = get_upstream_server, body_size_limit=body_size_limit,
confdir = options.confdir, mode=mode,
http_form_in = http_form_in, upstream_server=upstream_server,
http_form_out = http_form_out, http_form_in=options.http_form_in,
authenticator = authenticator, http_form_out=options.http_form_out,
ciphers = options.ciphers, authenticator=authenticator,
certs = certs, ciphers=options.ciphers,
certforward = options.certforward, certs=certs,
certforward=options.certforward,
) )
@ -115,10 +129,10 @@ def ssl_option_group(parser):
group = parser.add_argument_group("SSL") group = parser.add_argument_group("SSL")
group.add_argument( group.add_argument(
"--cert", dest='certs', default=[], type=str, "--cert", dest='certs', default=[], type=str,
metavar = "SPEC", action="append", metavar="SPEC", action="append",
help='Add an SSL certificate. SPEC is of the form "[domain=]path". '\ help='Add an SSL certificate. SPEC is of the form "[domain=]path". ' \
'The domain may include a wildcard, and is equal to "*" if not specified. '\ 'The domain may include a wildcard, and is equal to "*" if not specified. ' \
'The file at path is a certificate in PEM format. If a private key is included in the PEM, '\ 'The file at path is a certificate in PEM format. If a private key is included in the PEM, ' \
'it is used, else the default key in the conf dir is used. Can be passed multiple times.' 'it is used, else the default key in the conf dir is used. Can be passed multiple times.'
) )
group.add_argument( group.add_argument(

View File

@ -2,6 +2,8 @@ import os.path
import threading, Queue import threading, Queue
import shutil, tempfile import shutil, tempfile
import flask import flask
import mock
from libmproxy.proxy.config import ProxyConfig from libmproxy.proxy.config import ProxyConfig
from libmproxy.proxy.server import ProxyServer from libmproxy.proxy.server import ProxyServer
from libmproxy.proxy.primitives import TransparentUpstreamServerResolver from libmproxy.proxy.primitives import TransparentUpstreamServerResolver
@ -88,28 +90,25 @@ class ProxTestBase(object):
cls.server2 = libpathod.test.Daemon(ssl=cls.ssl, ssloptions=cls.ssloptions) cls.server2 = libpathod.test.Daemon(ssl=cls.ssl, ssloptions=cls.ssloptions)
pconf = cls.get_proxy_config() pconf = cls.get_proxy_config()
cls.confdir = os.path.join(tempfile.gettempdir(), "mitmproxy") cls.confdir = os.path.join(tempfile.gettempdir(), "mitmproxy")
config = ProxyConfig( cls.config = ProxyConfig(
no_upstream_cert = cls.no_upstream_cert, no_upstream_cert = cls.no_upstream_cert,
confdir = cls.confdir, confdir = cls.confdir,
authenticator = cls.authenticator, authenticator = cls.authenticator,
certforward = cls.certforward, certforward = cls.certforward,
**pconf **pconf
) )
tmaster = cls.masterclass(config) tmaster = cls.masterclass(cls.config)
tmaster.start_app(APP_HOST, APP_PORT, cls.externalapp) tmaster.start_app(APP_HOST, APP_PORT, cls.externalapp)
cls.proxy = ProxyThread(tmaster) cls.proxy = ProxyThread(tmaster)
cls.proxy.start() cls.proxy.start()
@classmethod
def tearDownAll(cls):
shutil.rmtree(cls.confdir)
@property @property
def master(cls): def master(cls):
return cls.proxy.tmaster return cls.proxy.tmaster
@classmethod @classmethod
def teardownAll(cls): def teardownAll(cls):
shutil.rmtree(cls.confdir)
cls.proxy.shutdown() cls.proxy.shutdown()
cls.server.shutdown() cls.server.shutdown()
cls.server2.shutdown() cls.server2.shutdown()
@ -189,16 +188,21 @@ class TResolver:
class TransparentProxTest(ProxTestBase): class TransparentProxTest(ProxTestBase):
ssl = None ssl = None
resolver = TResolver resolver = TResolver
@classmethod @classmethod
def get_proxy_config(cls): @mock.patch("libmproxy.platform.resolver")
d = ProxTestBase.get_proxy_config() def setupAll(cls, _):
super(TransparentProxTest, cls).setupAll()
if cls.ssl: if cls.ssl:
ports = [cls.server.port, cls.server2.port] ports = [cls.server.port, cls.server2.port]
else: else:
ports = [] ports = []
d["get_upstream_server"] = TransparentUpstreamServerResolver(cls.resolver(cls.server.port), ports) cls.config.get_upstream_server = TransparentUpstreamServerResolver(cls.resolver(cls.server.port), ports)
d["http_form_in"] = "relative"
d["http_form_out"] = "relative" @classmethod
def get_proxy_config(cls):
d = ProxTestBase.get_proxy_config()
d["mode"] = "transparent"
return d return d
def pathod(self, spec, sni=None): def pathod(self, spec, sni=None):
@ -227,7 +231,7 @@ class ReverseProxTest(ProxTestBase):
@classmethod @classmethod
def get_proxy_config(cls): def get_proxy_config(cls):
d = ProxTestBase.get_proxy_config() d = ProxTestBase.get_proxy_config()
d["get_upstream_server"] = lambda c: ( d["upstream_server"] = (
True if cls.ssl else False, True if cls.ssl else False,
True if cls.ssl else False, True if cls.ssl else False,
"127.0.0.1", "127.0.0.1",
@ -264,7 +268,7 @@ class ChainProxTest(ProxTestBase):
""" """
n = 2 n = 2
chain_config = [lambda port: ProxyConfig( chain_config = [lambda port: ProxyConfig(
get_upstream_server = lambda c: (False, False, "127.0.0.1", port), upstream_server= (False, False, "127.0.0.1", port),
http_form_in = "absolute", http_form_in = "absolute",
http_form_out = "absolute" http_form_out = "absolute"
)] * n )] * n