mitmproxy/libmproxy/proxy/server.py

157 lines
4.9 KiB
Python
Raw Normal View History

from __future__ import (absolute_import, print_function, division)
2015-07-24 11:31:55 +00:00
import traceback
import sys
2014-03-09 20:13:08 +00:00
import socket
2015-09-10 23:39:33 +00:00
import six
2015-08-30 13:27:29 +00:00
2014-03-09 20:51:24 +00:00
from netlib import tcp
2015-09-17 00:13:28 +00:00
from netlib.exceptions import TcpException
2015-09-16 16:45:22 +00:00
from netlib.http.http1 import assemble_response
from ..exceptions import ProtocolException, ServerException, ClientHandshakeException
2015-09-03 15:01:25 +00:00
from ..protocol import Kill
2015-08-30 13:27:29 +00:00
from ..models import ClientConnection, make_error_response
from .modes import HttpUpstreamProxy, HttpProxy, ReverseProxy, TransparentProxy, Socks5Proxy
2015-09-03 15:01:25 +00:00
from .root_context import RootContext, Log
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:
2015-09-10 23:39:33 +00:00
six.reraise(
ServerException,
ServerException('Error starting proxy server: ' + repr(e)),
2015-09-10 23:39:33 +00:00
sys.exc_info()[2]
)
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-08-30 13:27:29 +00:00
root_context = 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-30 13:27:29 +00:00
return HttpUpstreamProxy(
root_context,
self.config.upstream_server.address
)
elif mode == "transparent":
2015-08-30 13:27:29 +00:00
return TransparentProxy(root_context)
elif mode == "reverse":
server_tls = self.config.upstream_server.scheme == "https"
2015-08-30 13:27:29 +00:00
return ReverseProxy(
root_context,
self.config.upstream_server.address,
server_tls
)
elif mode == "socks5":
2015-08-30 13:27:29 +00:00
return Socks5Proxy(root_context)
elif mode == "regular":
2015-08-30 13:27:29 +00:00
return 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-08-31 15:05:52 +00:00
root_layer = self.channel.ask("clientconnect", root_layer)
if root_layer == Kill:
def root_layer():
raise Kill()
2015-08-29 23:21:58 +00:00
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:
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), "error")
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:
2015-08-30 13:27:29 +00:00
error_response = make_error_response(502, repr(e))
2015-09-16 16:45:22 +00:00
self.client_conn.send(assemble_response(error_response))
2015-09-17 00:13:28 +00:00
except TcpException:
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")
2015-08-31 15:05:52 +00:00
self.channel.tell("clientdisconnect", root_layer)
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)
2015-09-07 11:51:46 +00:00
self.channel.tell("log", Log(msg, level))