aboutsummaryrefslogtreecommitdiffstats
path: root/libmproxy/proxy
diff options
context:
space:
mode:
Diffstat (limited to 'libmproxy/proxy')
-rw-r--r--libmproxy/proxy/config.py58
-rw-r--r--libmproxy/proxy/primitives.py41
-rw-r--r--libmproxy/proxy/server.py42
3 files changed, 72 insertions, 69 deletions
diff --git a/libmproxy/proxy/config.py b/libmproxy/proxy/config.py
index 248808e9..ae24d4c9 100644
--- a/libmproxy/proxy/config.py
+++ b/libmproxy/proxy/config.py
@@ -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,
diff --git a/libmproxy/proxy/primitives.py b/libmproxy/proxy/primitives.py
index 75ad5482..e49d9bb4 100644
--- a/libmproxy/proxy/primitives.py
+++ b/libmproxy/proxy/primitives.py
@@ -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)"""
diff --git a/libmproxy/proxy/server.py b/libmproxy/proxy/server.py
index 5aaabf87..554ee551 100644
--- a/libmproxy/proxy/server.py
+++ b/libmproxy/proxy/server.py
@@ -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.