mitmproxy/libmproxy/proxy/server.py

136 lines
4.2 KiB
Python
Raw Normal View History

2015-07-24 11:31:55 +00:00
from __future__ import absolute_import, print_function
2015-07-24 11:31:55 +00:00
import traceback
import sys
2014-03-09 20:13:08 +00:00
import socket
2014-03-09 20:51:24 +00:00
from netlib import tcp
from netlib.http.http1 import HTTP1Protocol
from netlib.tcp import NetLibError
2015-07-24 16:29:13 +00:00
from .. import protocol2
2015-08-29 23:21:58 +00:00
from ..exceptions import ProtocolException, ServerException
from .primitives import Log, Kill
from .connection import ClientConnection
2014-03-09 20:13:08 +00:00
2014-03-09 20:51:24 +00:00
class DummyServer:
bound = False
2014-01-09 04:34:29 +00:00
2014-03-09 20:51:24 +00:00
def __init__(self, config):
self.config = config
2014-01-09 04:34:29 +00:00
2014-03-09 20:51:24 +00:00
def start_slave(self, *args):
pass
2014-03-09 20:51:24 +00:00
def shutdown(self):
pass
2014-02-04 04:02:17 +00:00
2014-03-09 20:51:24 +00:00
class ProxyServer(tcp.TCPServer):
allow_reuse_address = True
bound = True
2014-03-10 16:01:30 +00:00
def __init__(self, config):
2014-03-09 20:51:24 +00:00
"""
Raises ProxyServerError if there's a startup problem.
"""
self.config = config
try:
2015-08-29 23:21:58 +00:00
super(ProxyServer, self).__init__((config.host, config.port))
except socket.error as e:
raise ServerException('Error starting proxy server: ' + repr(e), e)
2014-03-09 20:51:24 +00:00
self.channel = None
2013-03-24 20:20:26 +00:00
2014-03-09 20:51:24 +00:00
def start_slave(self, klass, channel):
slave = klass(channel, self)
slave.start()
2014-02-07 06:08:59 +00:00
2014-03-09 20:51:24 +00:00
def set_channel(self, channel):
self.channel = channel
2013-02-24 04:35:24 +00:00
2014-03-09 20:51:24 +00:00
def handle_client_connection(self, conn, client_address):
2015-08-29 23:21:58 +00:00
h = ConnectionHandler(
2015-05-30 00:03:28 +00:00
conn,
client_address,
2015-08-29 23:21:58 +00:00
self.config,
self.channel
)
2014-03-09 20:51:24 +00:00
h.handle()
2015-08-29 23:21:58 +00:00
class ConnectionHandler(object):
def __init__(self, client_conn, client_address, config, channel):
2015-07-24 11:31:55 +00:00
self.config = config
"""@type: libmproxy.proxy.config.ProxyConfig"""
self.client_conn = ClientConnection(
client_conn,
client_address,
2015-08-29 23:21:58 +00:00
None)
2015-07-24 11:31:55 +00:00
"""@type: libmproxy.proxy.connection.ClientConnection"""
self.channel = channel
"""@type: libmproxy.controller.Channel"""
2015-08-29 23:21:58 +00:00
def _create_root_layer(self):
2015-07-24 16:29:13 +00:00
root_context = protocol2.RootContext(
2015-07-24 11:31:55 +00:00
self.client_conn,
self.config,
self.channel
)
2015-08-16 21:25:02 +00:00
mode = self.config.mode
if mode == "upstream":
2015-08-29 23:21:58 +00:00
return protocol2.HttpUpstreamProxy(
root_context,
self.config.upstream_server.address
)
elif mode == "transparent":
2015-08-29 23:21:58 +00:00
return protocol2.TransparentProxy(root_context)
elif mode == "reverse":
client_tls = self.config.upstream_server.scheme.startswith("https")
server_tls = self.config.upstream_server.scheme.endswith("https")
2015-08-29 23:21:58 +00:00
return protocol2.ReverseProxy(
root_context,
self.config.upstream_server.address,
client_tls,
server_tls
)
elif mode == "socks5":
2015-08-29 23:21:58 +00:00
return protocol2.Socks5Proxy(root_context)
elif mode == "regular":
2015-08-29 23:21:58 +00:00
return protocol2.HttpProxy(root_context)
elif callable(mode): # pragma: nocover
2015-08-29 23:21:58 +00:00
return mode(root_context)
else: # pragma: nocover
raise ValueError("Unknown proxy mode: %s" % mode)
2015-07-24 11:31:55 +00:00
2015-08-29 23:21:58 +00:00
def handle(self):
self.log("clientconnect", "info")
root_layer = self._create_root_layer()
2015-07-24 11:31:55 +00:00
try:
2015-08-18 13:59:44 +00:00
root_layer()
2015-08-29 23:21:58 +00:00
except Kill:
2015-08-18 13:59:44 +00:00
self.log("Connection killed", "info")
2015-08-11 18:27:34 +00:00
except ProtocolException as e:
2015-07-24 11:31:55 +00:00
self.log(e, "info")
# 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 = protocol2.make_error_response(502, repr(e))
self.client_conn.send(HTTP1Protocol().assemble(error_response))
except NetLibError:
pass
2015-07-24 11:31:55 +00:00
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)
2015-08-25 16:24:17 +00:00
self.log("clientdisconnect", "info")
self.client_conn.finish()
2015-08-29 23:21:58 +00:00
def log(self, msg, level):
msg = "{}: {}".format(repr(self.client_conn.address), msg)
self.channel.tell("log", Log(msg, level))