aboutsummaryrefslogtreecommitdiffstats
path: root/mitmproxy/libmproxy/proxy/server.py
diff options
context:
space:
mode:
Diffstat (limited to 'mitmproxy/libmproxy/proxy/server.py')
-rw-r--r--mitmproxy/libmproxy/proxy/server.py157
1 files changed, 157 insertions, 0 deletions
diff --git a/mitmproxy/libmproxy/proxy/server.py b/mitmproxy/libmproxy/proxy/server.py
new file mode 100644
index 00000000..d208cff5
--- /dev/null
+++ b/mitmproxy/libmproxy/proxy/server.py
@@ -0,0 +1,157 @@
+from __future__ import (absolute_import, print_function, division)
+
+import traceback
+import sys
+import socket
+import six
+
+from netlib import tcp
+from netlib.exceptions import TcpException
+from netlib.http.http1 import assemble_response
+from ..exceptions import ProtocolException, ServerException, ClientHandshakeException
+from ..protocol import Kill
+from ..models import ClientConnection, make_error_response
+from .modes import HttpUpstreamProxy, HttpProxy, ReverseProxy, TransparentProxy, Socks5Proxy
+from .root_context import RootContext, Log
+
+
+class DummyServer:
+ bound = False
+
+ def __init__(self, config):
+ self.config = config
+
+ def start_slave(self, *args):
+ pass
+
+ def shutdown(self):
+ pass
+
+
+class ProxyServer(tcp.TCPServer):
+ allow_reuse_address = True
+ bound = True
+
+ def __init__(self, config):
+ """
+ Raises ProxyServerError if there's a startup problem.
+ """
+ self.config = config
+ try:
+ super(ProxyServer, self).__init__((config.host, config.port))
+ except socket.error as e:
+ six.reraise(
+ ServerException,
+ ServerException('Error starting proxy server: ' + repr(e)),
+ sys.exc_info()[2]
+ )
+ self.channel = None
+
+ def start_slave(self, klass, channel):
+ slave = klass(channel, self)
+ slave.start()
+
+ def set_channel(self, channel):
+ self.channel = channel
+
+ def handle_client_connection(self, conn, client_address):
+ h = ConnectionHandler(
+ conn,
+ client_address,
+ self.config,
+ self.channel
+ )
+ h.handle()
+
+
+class ConnectionHandler(object):
+
+ def __init__(self, client_conn, client_address, config, channel):
+ self.config = config
+ """@type: libmproxy.proxy.config.ProxyConfig"""
+ self.client_conn = ClientConnection(
+ client_conn,
+ client_address,
+ None)
+ """@type: libmproxy.proxy.connection.ClientConnection"""
+ self.channel = channel
+ """@type: libmproxy.controller.Channel"""
+
+ def _create_root_layer(self):
+ root_context = RootContext(
+ self.client_conn,
+ self.config,
+ self.channel
+ )
+
+ mode = self.config.mode
+ if mode == "upstream":
+ return HttpUpstreamProxy(
+ root_context,
+ self.config.upstream_server.address
+ )
+ elif mode == "transparent":
+ return TransparentProxy(root_context)
+ elif mode == "reverse":
+ server_tls = self.config.upstream_server.scheme == "https"
+ return ReverseProxy(
+ root_context,
+ self.config.upstream_server.address,
+ server_tls
+ )
+ elif mode == "socks5":
+ return Socks5Proxy(root_context)
+ elif mode == "regular":
+ return HttpProxy(root_context)
+ elif callable(mode): # pragma: no cover
+ return mode(root_context)
+ else: # pragma: no cover
+ raise ValueError("Unknown proxy mode: %s" % mode)
+
+ def handle(self):
+ self.log("clientconnect", "info")
+
+ root_layer = self._create_root_layer()
+ root_layer = self.channel.ask("clientconnect", root_layer)
+ if root_layer == Kill:
+ def root_layer():
+ raise Kill()
+
+ try:
+ root_layer()
+ except Kill:
+ self.log("Connection killed", "info")
+ except ProtocolException as e:
+
+ if isinstance(e, ClientHandshakeException):
+ self.log(
+ "Client Handshake failed. "
+ "The client may not trust the proxy's certificate for {}.".format(e.server),
+ "error"
+ )
+ self.log(repr(e), "debug")
+ else:
+ self.log(repr(e), "info")
+
+ self.log(traceback.format_exc(), "debug")
+ # If an error propagates to the topmost level,
+ # we send an HTTP error response, which is both
+ # understandable by HTTP clients and humans.
+ try:
+ error_response = make_error_response(502, repr(e))
+ self.client_conn.send(assemble_response(error_response))
+ except TcpException:
+ pass
+ except Exception:
+ self.log(traceback.format_exc(), "error")
+ print(traceback.format_exc(), file=sys.stderr)
+ print("mitmproxy has crashed!", file=sys.stderr)
+ print("Please lodge a bug report at: https://github.com/mitmproxy/mitmproxy", file=sys.stderr)
+
+ self.log("clientdisconnect", "info")
+ self.channel.tell("clientdisconnect", root_layer)
+ self.client_conn.finish()
+
+ def log(self, msg, level):
+ msg = "{}: {}".format(repr(self.client_conn.address), msg)
+ self.channel.tell("log", Log(msg, level))