mirror of
https://github.com/zhigang1992/mitmproxy.git
synced 2026-05-01 21:44:23 +08:00
add advanced proxying options, add SSL-terminating capability to mitmproxy
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
from .. import utils, platform
|
||||
from netlib import http_auth, certutils
|
||||
|
||||
from .primitives import ConstUpstreamServerResolver, TransparentUpstreamServerResolver
|
||||
|
||||
TRANSPARENT_SSL_PORTS = [443, 8443]
|
||||
CONF_BASENAME = "mitmproxy"
|
||||
@@ -10,18 +10,17 @@ CONF_DIR = "~/.mitmproxy"
|
||||
|
||||
class ProxyConfig:
|
||||
def __init__(self, confdir=CONF_DIR, clientcerts=None,
|
||||
no_upstream_cert=False, body_size_limit=None, upstream_server=None,
|
||||
http_form_in="absolute", http_form_out="relative", transparent_proxy=None, authenticator=None,
|
||||
no_upstream_cert=False, body_size_limit=None, get_upstream_server=None,
|
||||
http_form_in="absolute", http_form_out="relative", authenticator=None,
|
||||
ciphers=None, certs=None
|
||||
):
|
||||
self.ciphers = ciphers
|
||||
self.clientcerts = clientcerts
|
||||
self.no_upstream_cert = no_upstream_cert
|
||||
self.body_size_limit = body_size_limit
|
||||
self.upstream_server = upstream_server
|
||||
self.get_upstream_server = get_upstream_server
|
||||
self.http_form_in = http_form_in
|
||||
self.http_form_out = http_form_out
|
||||
self.transparent_proxy = transparent_proxy
|
||||
self.authenticator = authenticator
|
||||
self.confdir = os.path.expanduser(confdir)
|
||||
self.certstore = certutils.CertStore.from_store(self.confdir, CONF_BASENAME)
|
||||
@@ -29,32 +28,34 @@ class ProxyConfig:
|
||||
|
||||
def process_proxy_options(parser, options):
|
||||
body_size_limit = utils.parse_size(options.body_size_limit)
|
||||
if options.reverse_proxy and options.transparent_proxy:
|
||||
return parser.error("Can't set both reverse proxy and transparent proxy.")
|
||||
|
||||
c = 0
|
||||
http_form_in, http_form_out = "absolute", "relative"
|
||||
get_upstream_server = None
|
||||
if options.transparent_proxy:
|
||||
c += 1
|
||||
if not platform.resolver:
|
||||
return parser.error("Transparent mode not supported on this platform.")
|
||||
trans = dict(
|
||||
resolver=platform.resolver(),
|
||||
sslports=TRANSPARENT_SSL_PORTS
|
||||
)
|
||||
else:
|
||||
trans = None
|
||||
|
||||
get_upstream_server = TransparentUpstreamServerResolver(platform.resolver(), TRANSPARENT_SSL_PORTS)
|
||||
http_form_in, http_form_out = "relative", "relative"
|
||||
if options.reverse_proxy:
|
||||
rp = utils.parse_proxy_spec(options.reverse_proxy)
|
||||
if not rp:
|
||||
return parser.error("Invalid reverse proxy specification: %s" % options.reverse_proxy)
|
||||
else:
|
||||
rp = None
|
||||
|
||||
c += 1
|
||||
get_upstream_server = ConstUpstreamServerResolver(options.reverse_proxy)
|
||||
http_form_in, http_form_out = "relative", "relative"
|
||||
if options.forward_proxy:
|
||||
fp = utils.parse_proxy_spec(options.forward_proxy)
|
||||
if not fp:
|
||||
return parser.error("Invalid forward proxy specification: %s" % options.forward_proxy)
|
||||
else:
|
||||
fp = None
|
||||
c += 1
|
||||
get_upstream_server = ConstUpstreamServerResolver(options.forward_proxy)
|
||||
http_form_in, http_form_out = "absolute", "absolute"
|
||||
if options.manual_upstream_server:
|
||||
c += 1
|
||||
get_upstream_server = ConstUpstreamServerResolver(options.manual_upstream_server)
|
||||
if c > 1:
|
||||
return parser.error("Transparent mode, reverse mode, forward mode and "
|
||||
"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:
|
||||
options.clientcerts = os.path.expanduser(options.clientcerts)
|
||||
@@ -94,10 +95,9 @@ def process_proxy_options(parser, options):
|
||||
clientcerts=options.clientcerts,
|
||||
body_size_limit=body_size_limit,
|
||||
no_upstream_cert=options.no_upstream_cert,
|
||||
upstream_server=(rp or fp),
|
||||
http_form_in=("relative" if (rp or trans) else "absolute"),
|
||||
http_form_out=("absolute" if fp else "relative"),
|
||||
transparent_proxy=trans,
|
||||
get_upstream_server=get_upstream_server,
|
||||
http_form_in=http_form_in,
|
||||
http_form_out=http_form_out,
|
||||
authenticator=authenticator,
|
||||
ciphers=options.ciphers,
|
||||
certs = certs,
|
||||
|
||||
@@ -18,17 +18,48 @@ class ProxyServerError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class UpstreamServerResolver(object):
|
||||
def __call__(self, conn):
|
||||
"""
|
||||
Returns the address of the server to connect to.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class ConstUpstreamServerResolver(UpstreamServerResolver):
|
||||
def __init__(self, dst):
|
||||
self.dst = dst
|
||||
|
||||
def __call__(self, conn):
|
||||
return self.dst
|
||||
|
||||
|
||||
class TransparentUpstreamServerResolver(UpstreamServerResolver):
|
||||
def __init__(self, resolver, sslports):
|
||||
self.resolver = resolver
|
||||
self.sslports = sslports
|
||||
|
||||
def __call__(self, conn):
|
||||
dst = self.resolver.original_addr(conn)
|
||||
if not dst:
|
||||
raise ProxyError(502, "Transparent mode failure: could not resolve original destination.")
|
||||
|
||||
if dst[1] in self.sslports:
|
||||
ssl = True
|
||||
else:
|
||||
ssl = False
|
||||
return [ssl, ssl] + list(dst)
|
||||
|
||||
|
||||
class AddressPriority(object):
|
||||
"""
|
||||
Enum that signifies the priority of the given address when choosing the destination host.
|
||||
Higher is better (None < i)
|
||||
"""
|
||||
MANUALLY_CHANGED = 4
|
||||
MANUALLY_CHANGED = 3
|
||||
"""user changed the target address in the ui"""
|
||||
FROM_SETTINGS = 3
|
||||
"""upstream proxy from arguments (reverse proxy or forward proxy)"""
|
||||
FROM_CONNECTION = 2
|
||||
"""derived from transparent resolver"""
|
||||
FROM_SETTINGS = 2
|
||||
"""upstream server from arguments (reverse proxy, forward proxy or from transparent resolver)"""
|
||||
FROM_PROTOCOL = 1
|
||||
"""derived from protocol (e.g. absolute-form http requests)"""
|
||||
|
||||
|
||||
@@ -68,22 +68,13 @@ class ConnectionHandler:
|
||||
try:
|
||||
try:
|
||||
# Can we already identify the target server and connect to it?
|
||||
server_address = None
|
||||
address_priority = None
|
||||
if self.config.upstream_server:
|
||||
server_address = self.config.upstream_server[1:]
|
||||
address_priority = AddressPriority.FROM_SETTINGS
|
||||
elif self.config.transparent_proxy:
|
||||
server_address = self.config.transparent_proxy["resolver"].original_addr(
|
||||
self.client_conn.connection)
|
||||
if not server_address:
|
||||
raise ProxyError(502, "Transparent mode failure: could not resolve original destination.")
|
||||
address_priority = AddressPriority.FROM_CONNECTION
|
||||
self.log("transparent to %s:%s" % server_address)
|
||||
|
||||
if server_address:
|
||||
self.set_server_address(server_address, address_priority)
|
||||
self._handle_ssl()
|
||||
if self.config.get_upstream_server:
|
||||
upstream_info = self.config.get_upstream_server(self.client_conn.connection)
|
||||
self.set_server_address(upstream_info[2:], AddressPriority.FROM_SETTINGS)
|
||||
client_ssl, server_ssl = upstream_info[:2]
|
||||
if client_ssl or server_ssl:
|
||||
self.establish_server_connection()
|
||||
self.establish_ssl(client=client_ssl, server=server_ssl)
|
||||
|
||||
while not self.close:
|
||||
try:
|
||||
@@ -105,25 +96,6 @@ class ConnectionHandler:
|
||||
self.log("clientdisconnect")
|
||||
self.channel.tell("clientdisconnect", self)
|
||||
|
||||
def _handle_ssl(self):
|
||||
"""
|
||||
Helper function of .handle()
|
||||
Check if we can already identify SSL connections.
|
||||
If so, connect to the server and establish an SSL connection
|
||||
"""
|
||||
client_ssl = False
|
||||
server_ssl = False
|
||||
|
||||
if self.config.transparent_proxy:
|
||||
client_ssl = server_ssl = (self.server_conn.address.port in self.config.transparent_proxy["sslports"])
|
||||
elif self.config.upstream_server:
|
||||
client_ssl = server_ssl = (self.config.upstream_server[0] == "https")
|
||||
# TODO: Make protocol generic (as with transparent proxies)
|
||||
# TODO: Add SSL-terminating capatbility (SSL -> mitmproxy -> plain and vice versa)
|
||||
if client_ssl or server_ssl:
|
||||
self.establish_server_connection()
|
||||
self.establish_ssl(client=client_ssl, server=server_ssl)
|
||||
|
||||
def del_server_connection(self):
|
||||
"""
|
||||
Deletes an existing server connection.
|
||||
|
||||
Reference in New Issue
Block a user