2015-07-24 11:31:55 +00:00
|
|
|
from __future__ import absolute_import, print_function
|
2014-03-10 21:36:47 +00:00
|
|
|
|
2015-07-24 11:31:55 +00:00
|
|
|
import traceback
|
|
|
|
import sys
|
2014-03-09 20:13:08 +00:00
|
|
|
import socket
|
2015-08-18 13:59:44 +00:00
|
|
|
from libmproxy.protocol2.layer import Kill
|
2014-03-09 20:51:24 +00:00
|
|
|
from netlib import tcp
|
2015-07-24 16:29:13 +00:00
|
|
|
|
2014-08-30 18:15:19 +00:00
|
|
|
from ..protocol.handle import protocol_handler
|
2015-07-24 16:29:13 +00:00
|
|
|
from .. import protocol2
|
2015-08-11 18:27:34 +00:00
|
|
|
from ..exceptions import ProtocolException
|
2015-08-08 14:08:57 +00:00
|
|
|
from .primitives import ProxyServerError, Log, ProxyError
|
2015-07-24 16:29:13 +00:00
|
|
|
from .connection import ClientConnection, ServerConnection
|
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-05 04:25:12 +00:00
|
|
|
|
2014-03-09 20:51:24 +00:00
|
|
|
def shutdown(self):
|
|
|
|
pass
|
2013-01-04 01:19:32 +00:00
|
|
|
|
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
|
|
|
|
2014-09-08 21:34:43 +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:
|
2014-09-08 21:34:43 +00:00
|
|
|
tcp.TCPServer.__init__(self, (config.host, config.port))
|
2015-05-30 00:03:28 +00:00
|
|
|
except socket.error as v:
|
2014-08-08 17:04:58 +00:00
|
|
|
raise ProxyServerError('Error starting proxy server: ' + repr(v))
|
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-07-24 11:31:55 +00:00
|
|
|
h = ConnectionHandler2(
|
2015-05-30 00:03:28 +00:00
|
|
|
self.config,
|
|
|
|
conn,
|
|
|
|
client_address,
|
|
|
|
self,
|
|
|
|
self.channel)
|
2014-03-09 20:51:24 +00:00
|
|
|
h.handle()
|
|
|
|
h.finish()
|
2014-01-30 04:00:13 +00:00
|
|
|
|
2014-02-05 19:26:47 +00:00
|
|
|
|
2015-07-24 11:31:55 +00:00
|
|
|
class ConnectionHandler2:
|
|
|
|
# FIXME: parameter ordering
|
|
|
|
# FIXME: remove server attribute
|
|
|
|
def __init__(self, config, client_conn, client_address, server, channel):
|
|
|
|
self.config = config
|
|
|
|
"""@type: libmproxy.proxy.config.ProxyConfig"""
|
|
|
|
self.client_conn = ClientConnection(
|
|
|
|
client_conn,
|
|
|
|
client_address,
|
|
|
|
server)
|
|
|
|
"""@type: libmproxy.proxy.connection.ClientConnection"""
|
|
|
|
self.channel = channel
|
|
|
|
"""@type: libmproxy.controller.Channel"""
|
|
|
|
|
|
|
|
def handle(self):
|
|
|
|
self.log("clientconnect", "info")
|
|
|
|
|
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
|
|
|
|
|
|
|
# FIXME: properly parse config
|
|
|
|
if self.config.mode == "upstream":
|
|
|
|
root_layer = protocol2.HttpUpstreamProxy(root_context, ("localhost", 8081))
|
|
|
|
else:
|
|
|
|
root_layer = protocol2.HttpProxy(root_context)
|
2015-07-24 11:31:55 +00:00
|
|
|
|
|
|
|
try:
|
2015-08-18 13:59:44 +00:00
|
|
|
root_layer()
|
|
|
|
except Kill as e:
|
|
|
|
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")
|
|
|
|
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-07-24 11:31:55 +00:00
|
|
|
def finish(self):
|
|
|
|
self.client_conn.finish()
|
|
|
|
|
|
|
|
def log(self, msg, level, subs=()):
|
|
|
|
# FIXME: Duplicate code
|
|
|
|
full_msg = [
|
|
|
|
"%s:%s: %s" %
|
|
|
|
(self.client_conn.address.host,
|
|
|
|
self.client_conn.address.port,
|
|
|
|
msg)]
|
|
|
|
for i in subs:
|
|
|
|
full_msg.append(" -> " + i)
|
|
|
|
full_msg = "\n".join(full_msg)
|
|
|
|
self.channel.tell("log", Log(full_msg, level))
|
|
|
|
|
|
|
|
|
2014-01-05 00:03:55 +00:00
|
|
|
class ConnectionHandler:
|
2015-05-30 00:03:28 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
config,
|
|
|
|
client_connection,
|
|
|
|
client_address,
|
|
|
|
server,
|
|
|
|
channel):
|
2012-06-10 04:02:48 +00:00
|
|
|
self.config = config
|
2014-03-10 16:01:30 +00:00
|
|
|
"""@type: libmproxy.proxy.config.ProxyConfig"""
|
2015-05-30 00:03:28 +00:00
|
|
|
self.client_conn = ClientConnection(
|
|
|
|
client_connection,
|
|
|
|
client_address,
|
|
|
|
server)
|
2014-03-10 16:01:30 +00:00
|
|
|
"""@type: libmproxy.proxy.connection.ClientConnection"""
|
2014-01-09 04:34:29 +00:00
|
|
|
self.server_conn = None
|
2014-03-10 16:01:30 +00:00
|
|
|
"""@type: libmproxy.proxy.connection.ServerConnection"""
|
2014-09-08 21:34:43 +00:00
|
|
|
self.channel = channel
|
2015-07-24 11:31:55 +00:00
|
|
|
"""@type: libmproxy.controller.Channel"""
|
2013-12-12 09:00:23 +00:00
|
|
|
|
2014-08-09 01:03:21 +00:00
|
|
|
self.conntype = "http"
|
2013-12-12 09:00:23 +00:00
|
|
|
|
2010-02-16 04:09:07 +00:00
|
|
|
def handle(self):
|
2014-01-09 04:34:29 +00:00
|
|
|
try:
|
2014-09-06 11:09:57 +00:00
|
|
|
self.log("clientconnect", "info")
|
|
|
|
|
2014-05-15 16:16:42 +00:00
|
|
|
# Can we already identify the target server and connect to it?
|
2014-08-09 01:03:21 +00:00
|
|
|
client_ssl, server_ssl = False, False
|
2014-10-18 16:29:35 +00:00
|
|
|
conn_kwargs = dict()
|
2015-05-30 00:03:28 +00:00
|
|
|
upstream_info = self.config.mode.get_upstream_server(
|
|
|
|
self.client_conn)
|
2014-09-08 12:32:42 +00:00
|
|
|
if upstream_info:
|
2014-09-03 18:12:30 +00:00
|
|
|
self.set_server_address(upstream_info[2:])
|
2014-05-15 16:16:42 +00:00
|
|
|
client_ssl, server_ssl = upstream_info[:2]
|
2014-10-18 16:29:35 +00:00
|
|
|
if self.config.check_ignore(self.server_conn.address):
|
2015-05-30 00:03:28 +00:00
|
|
|
self.log(
|
|
|
|
"Ignore host: %s:%s" %
|
|
|
|
self.server_conn.address(),
|
|
|
|
"info")
|
2014-08-30 18:15:19 +00:00
|
|
|
self.conntype = "tcp"
|
2014-10-18 16:29:35 +00:00
|
|
|
conn_kwargs["log"] = False
|
2014-08-30 18:15:19 +00:00
|
|
|
client_ssl, server_ssl = False, False
|
2014-09-08 12:32:42 +00:00
|
|
|
else:
|
2015-05-30 00:03:28 +00:00
|
|
|
# No upstream info from the metadata: upstream info in the
|
|
|
|
# protocol (e.g. HTTP absolute-form)
|
|
|
|
pass
|
2014-08-09 01:03:21 +00:00
|
|
|
|
|
|
|
self.channel.ask("clientconnect", self)
|
|
|
|
|
2014-08-30 18:15:19 +00:00
|
|
|
# Check for existing connection: If an inline script already established a
|
|
|
|
# connection, do not apply client_ssl or server_ssl.
|
2014-08-12 00:55:32 +00:00
|
|
|
if self.server_conn and not self.server_conn.connection:
|
2014-08-09 01:03:21 +00:00
|
|
|
self.establish_server_connection()
|
2014-05-15 16:16:42 +00:00
|
|
|
if client_ssl or server_ssl:
|
|
|
|
self.establish_ssl(client=client_ssl, server=server_ssl)
|
|
|
|
|
2014-10-18 16:29:35 +00:00
|
|
|
if self.config.check_tcp(self.server_conn.address):
|
2015-05-30 00:03:28 +00:00
|
|
|
self.log(
|
|
|
|
"Generic TCP mode for host: %s:%s" %
|
|
|
|
self.server_conn.address(),
|
|
|
|
"info")
|
2014-10-18 16:29:35 +00:00
|
|
|
self.conntype = "tcp"
|
2015-08-01 12:36:31 +00:00
|
|
|
|
2015-06-20 15:51:56 +00:00
|
|
|
elif not self.server_conn and self.config.mode == "sslspoof":
|
|
|
|
port = self.config.mode.sslport
|
|
|
|
self.set_server_address(("-", port))
|
|
|
|
self.establish_ssl(client=True)
|
|
|
|
host = self.client_conn.connection.get_servername()
|
2015-06-22 16:49:22 +00:00
|
|
|
if host:
|
|
|
|
self.set_server_address((host, port))
|
|
|
|
self.establish_server_connection()
|
|
|
|
self.establish_ssl(server=True, sni=host)
|
2014-10-18 16:29:35 +00:00
|
|
|
|
2014-08-30 18:15:19 +00:00
|
|
|
# Delegate handling to the protocol handler
|
2015-05-30 00:03:28 +00:00
|
|
|
protocol_handler(
|
|
|
|
self.conntype)(
|
|
|
|
self,
|
|
|
|
**conn_kwargs).handle_messages()
|
2014-05-15 16:16:42 +00:00
|
|
|
|
2014-09-06 11:09:57 +00:00
|
|
|
self.log("clientdisconnect", "info")
|
|
|
|
self.channel.tell("clientdisconnect", self)
|
|
|
|
|
2014-09-02 16:13:18 +00:00
|
|
|
except ProxyError as e:
|
2014-10-18 16:29:35 +00:00
|
|
|
protocol_handler(self.conntype)(self, **conn_kwargs).handle_error(e)
|
2014-07-22 22:21:33 +00:00
|
|
|
except Exception:
|
2015-05-30 00:03:28 +00:00
|
|
|
import traceback
|
|
|
|
import sys
|
2014-05-15 11:56:09 +00:00
|
|
|
|
2014-03-13 00:04:45 +00:00
|
|
|
self.log(traceback.format_exc(), "error")
|
2015-07-24 11:31:55 +00:00
|
|
|
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)
|
2014-11-14 15:13:45 +00:00
|
|
|
finally:
|
|
|
|
# Make sure that we close the server connection in any case.
|
2015-05-30 00:03:28 +00:00
|
|
|
# The client connection is closed by the ProxyServer and does not
|
|
|
|
# have be handled here.
|
2014-11-14 15:13:45 +00:00
|
|
|
self.del_server_connection()
|
2012-06-30 12:15:03 +00:00
|
|
|
|
2014-02-04 01:56:59 +00:00
|
|
|
def del_server_connection(self):
|
|
|
|
"""
|
2014-03-10 16:01:30 +00:00
|
|
|
Deletes (and closes) an existing server connection.
|
2014-02-04 01:56:59 +00:00
|
|
|
"""
|
|
|
|
if self.server_conn and self.server_conn.connection:
|
|
|
|
self.server_conn.finish()
|
2014-11-14 15:13:45 +00:00
|
|
|
self.server_conn.close()
|
2015-05-30 00:03:28 +00:00
|
|
|
self.log(
|
|
|
|
"serverdisconnect", "debug", [
|
|
|
|
"%s:%s" %
|
|
|
|
(self.server_conn.address.host, self.server_conn.address.port)])
|
2014-02-04 01:56:59 +00:00
|
|
|
self.channel.tell("serverdisconnect", self)
|
|
|
|
self.server_conn = None
|
2014-01-09 04:34:29 +00:00
|
|
|
|
2015-07-22 14:00:32 +00:00
|
|
|
def set_server_address(self, addr):
|
2014-01-05 00:03:55 +00:00
|
|
|
"""
|
2014-02-06 21:16:26 +00:00
|
|
|
Sets a new server address with the given priority.
|
|
|
|
Does not re-establish either connection or SSL handshake.
|
2014-01-05 00:03:55 +00:00
|
|
|
"""
|
2015-07-22 14:00:32 +00:00
|
|
|
address = tcp.Address.wrap(addr)
|
2014-02-04 01:56:59 +00:00
|
|
|
|
2014-09-03 18:12:30 +00:00
|
|
|
# Don't reconnect to the same destination.
|
|
|
|
if self.server_conn and self.server_conn.address == address:
|
|
|
|
return
|
2014-02-04 01:56:59 +00:00
|
|
|
|
2014-09-03 18:12:30 +00:00
|
|
|
if self.server_conn:
|
2014-02-04 01:56:59 +00:00
|
|
|
self.del_server_connection()
|
2014-02-06 21:16:26 +00:00
|
|
|
|
2015-05-30 00:03:28 +00:00
|
|
|
self.log(
|
|
|
|
"Set new server address: %s:%s" %
|
|
|
|
(address.host, address.port), "debug")
|
2014-09-03 18:12:30 +00:00
|
|
|
self.server_conn = ServerConnection(address)
|
2014-02-04 01:56:59 +00:00
|
|
|
|
2014-07-26 10:02:18 +00:00
|
|
|
def establish_server_connection(self, ask=True):
|
2014-02-04 01:56:59 +00:00
|
|
|
"""
|
|
|
|
Establishes a new server connection.
|
|
|
|
If there is already an existing server connection, the function returns immediately.
|
2014-07-26 10:02:18 +00:00
|
|
|
|
|
|
|
By default, this function ".ask"s the proxy master. This is deadly if this function is already called from the
|
|
|
|
master (e.g. via change_server), because this navigates us in a simple deadlock (the master is single-threaded).
|
|
|
|
In these scenarios, ask=False can be passed to suppress the call to the master.
|
2014-02-04 01:56:59 +00:00
|
|
|
"""
|
|
|
|
if self.server_conn.connection:
|
|
|
|
return
|
2015-05-30 00:03:28 +00:00
|
|
|
self.log(
|
|
|
|
"serverconnect", "debug", [
|
|
|
|
"%s:%s" %
|
|
|
|
self.server_conn.address()[
|
2015-07-24 11:31:55 +00:00
|
|
|
:2]])
|
2014-07-26 10:02:18 +00:00
|
|
|
if ask:
|
|
|
|
self.channel.ask("serverconnect", self)
|
2014-01-18 14:35:37 +00:00
|
|
|
try:
|
|
|
|
self.server_conn.connect()
|
2015-05-30 00:03:28 +00:00
|
|
|
except tcp.NetLibError as v:
|
2014-01-18 14:35:37 +00:00
|
|
|
raise ProxyError(502, v)
|
2014-01-05 00:03:55 +00:00
|
|
|
|
2014-12-15 11:46:13 +00:00
|
|
|
def establish_ssl(self, client=False, server=False, sni=None):
|
2014-01-10 00:38:28 +00:00
|
|
|
"""
|
|
|
|
Establishes SSL on the existing connection(s) to the server or the client,
|
2014-08-30 18:15:19 +00:00
|
|
|
as specified by the parameters.
|
2014-01-10 00:38:28 +00:00
|
|
|
"""
|
2014-01-31 02:01:51 +00:00
|
|
|
|
2014-02-04 01:56:59 +00:00
|
|
|
# Logging
|
2014-01-31 02:01:51 +00:00
|
|
|
if client or server:
|
|
|
|
subs = []
|
|
|
|
if client:
|
|
|
|
subs.append("with client")
|
|
|
|
if server:
|
2014-12-15 11:46:13 +00:00
|
|
|
subs.append("with server (sni: %s)" % sni)
|
2014-03-13 00:04:45 +00:00
|
|
|
self.log("Establish SSL", "debug", subs)
|
2014-01-09 16:56:42 +00:00
|
|
|
|
|
|
|
if server:
|
2014-07-26 10:02:18 +00:00
|
|
|
if not self.server_conn or not self.server_conn.connection:
|
|
|
|
raise ProxyError(502, "No server connection.")
|
2014-01-09 16:56:42 +00:00
|
|
|
if self.server_conn.ssl_established:
|
|
|
|
raise ProxyError(502, "SSL to Server already established.")
|
2014-09-02 16:13:18 +00:00
|
|
|
try:
|
2014-12-15 11:46:13 +00:00
|
|
|
self.server_conn.establish_ssl(
|
|
|
|
self.config.clientcerts,
|
|
|
|
sni,
|
2015-03-02 13:35:50 +00:00
|
|
|
method=self.config.openssl_method_server,
|
|
|
|
options=self.config.openssl_options_server,
|
2015-06-29 17:32:57 +00:00
|
|
|
verify_options=self.config.openssl_verification_mode_server,
|
|
|
|
ca_path=self.config.openssl_trusted_cadir_server,
|
|
|
|
ca_pemfile=self.config.openssl_trusted_ca_server,
|
2015-03-02 13:35:50 +00:00
|
|
|
cipher_list=self.config.ciphers_server,
|
2014-12-15 11:46:13 +00:00
|
|
|
)
|
2015-06-29 17:32:57 +00:00
|
|
|
ssl_cert_err = self.server_conn.ssl_verification_error
|
|
|
|
if ssl_cert_err is not None:
|
|
|
|
self.log(
|
2015-08-01 12:36:31 +00:00
|
|
|
"SSL verification failed for upstream server at depth %s with error: %s" %
|
2015-08-16 21:25:02 +00:00
|
|
|
(ssl_cert_err['depth'], ssl_cert_err['errno']),
|
2015-06-29 17:32:57 +00:00
|
|
|
"error")
|
|
|
|
self.log("Ignoring server verification error, continuing with connection", "error")
|
2014-09-02 16:13:18 +00:00
|
|
|
except tcp.NetLibError as v:
|
2014-12-15 12:02:47 +00:00
|
|
|
e = ProxyError(502, repr(v))
|
|
|
|
# Workaround for https://github.com/mitmproxy/mitmproxy/issues/427
|
|
|
|
# The upstream server may reject connections without SNI, which means we need to
|
|
|
|
# establish SSL with the client first, hope for a SNI (which triggers a reconnect which replaces the
|
|
|
|
# ServerConnection object) and see whether that worked.
|
|
|
|
if client and "handshake failure" in e.message:
|
|
|
|
self.server_conn.may_require_sni = e
|
|
|
|
else:
|
2015-06-29 17:32:57 +00:00
|
|
|
ssl_cert_err = self.server_conn.ssl_verification_error
|
|
|
|
if ssl_cert_err is not None:
|
|
|
|
self.log(
|
2015-08-01 12:36:31 +00:00
|
|
|
"SSL verification failed for upstream server at depth %s with error: %s" %
|
2015-08-16 21:25:02 +00:00
|
|
|
(ssl_cert_err['depth'], ssl_cert_err['errno']),
|
2015-06-29 17:32:57 +00:00
|
|
|
"error")
|
|
|
|
self.log("Aborting connection attempt", "error")
|
2014-12-15 12:02:47 +00:00
|
|
|
raise e
|
2014-01-09 16:56:42 +00:00
|
|
|
if client:
|
|
|
|
if self.client_conn.ssl_established:
|
|
|
|
raise ProxyError(502, "SSL to Client already established.")
|
2014-10-08 18:44:52 +00:00
|
|
|
cert, key, chain_file = self.find_cert()
|
2014-09-02 16:13:18 +00:00
|
|
|
try:
|
|
|
|
self.client_conn.convert_to_ssl(
|
|
|
|
cert, key,
|
2015-03-02 13:35:50 +00:00
|
|
|
method=self.config.openssl_method_client,
|
|
|
|
options=self.config.openssl_options_client,
|
2014-09-02 16:13:18 +00:00
|
|
|
handle_sni=self.handle_sni,
|
2015-03-02 13:35:50 +00:00
|
|
|
cipher_list=self.config.ciphers_client,
|
2014-09-02 16:13:18 +00:00
|
|
|
dhparams=self.config.certstore.dhparams,
|
2014-10-08 18:44:52 +00:00
|
|
|
chain_file=chain_file
|
2014-09-02 16:13:18 +00:00
|
|
|
)
|
|
|
|
except tcp.NetLibError as v:
|
|
|
|
raise ProxyError(400, repr(v))
|
2014-01-05 00:03:55 +00:00
|
|
|
|
2014-12-15 12:02:47 +00:00
|
|
|
# Workaround for #427 part 2
|
|
|
|
if server and hasattr(self.server_conn, "may_require_sni"):
|
|
|
|
raise self.server_conn.may_require_sni
|
|
|
|
|
2014-12-15 11:46:13 +00:00
|
|
|
def server_reconnect(self, new_sni=False):
|
2014-02-04 01:56:59 +00:00
|
|
|
address = self.server_conn.address
|
|
|
|
had_ssl = self.server_conn.ssl_established
|
2014-08-08 00:45:24 +00:00
|
|
|
state = self.server_conn.state
|
2014-12-15 11:46:13 +00:00
|
|
|
sni = new_sni or self.server_conn.sni
|
2014-03-13 00:04:45 +00:00
|
|
|
self.log("(server reconnect follows)", "debug")
|
2014-02-04 01:56:59 +00:00
|
|
|
self.del_server_connection()
|
2014-09-03 18:12:30 +00:00
|
|
|
self.set_server_address(address)
|
2014-02-04 01:56:59 +00:00
|
|
|
self.establish_server_connection()
|
2014-08-08 00:45:24 +00:00
|
|
|
|
|
|
|
for s in state:
|
2014-08-30 18:15:19 +00:00
|
|
|
protocol_handler(s[0])(self).handle_server_reconnect(s[1])
|
2014-08-08 00:45:24 +00:00
|
|
|
self.server_conn.state = state
|
|
|
|
|
2014-12-15 12:02:47 +00:00
|
|
|
# Receiving new_sni where had_ssl is False is a weird case that happens when the workaround for
|
2015-05-30 00:03:28 +00:00
|
|
|
# https://github.com/mitmproxy/mitmproxy/issues/427 is active. In this
|
|
|
|
# case, we want to establish SSL as well.
|
2014-12-15 12:02:47 +00:00
|
|
|
if had_ssl or new_sni:
|
2014-12-15 11:46:13 +00:00
|
|
|
self.establish_ssl(server=True, sni=sni)
|
2014-01-18 16:15:33 +00:00
|
|
|
|
2014-02-04 01:56:59 +00:00
|
|
|
def finish(self):
|
|
|
|
self.client_conn.finish()
|
|
|
|
|
2014-03-13 00:04:45 +00:00
|
|
|
def log(self, msg, level, subs=()):
|
2015-07-22 14:00:32 +00:00
|
|
|
full_msg = [
|
2015-05-30 00:03:28 +00:00
|
|
|
"%s:%s: %s" %
|
|
|
|
(self.client_conn.address.host,
|
|
|
|
self.client_conn.address.port,
|
|
|
|
msg)]
|
2012-06-30 12:15:03 +00:00
|
|
|
for i in subs:
|
2015-07-22 14:00:32 +00:00
|
|
|
full_msg.append(" -> " + i)
|
|
|
|
full_msg = "\n".join(full_msg)
|
|
|
|
self.channel.tell("log", Log(full_msg, level))
|
2012-06-30 12:15:03 +00:00
|
|
|
|
2014-01-07 01:29:10 +00:00
|
|
|
def find_cert(self):
|
2015-06-26 11:27:40 +00:00
|
|
|
host = self.server_conn.address.host
|
|
|
|
sans = []
|
|
|
|
if self.server_conn.ssl_established and (
|
|
|
|
not self.config.no_upstream_cert):
|
|
|
|
upstream_cert = self.server_conn.cert
|
|
|
|
sans.extend(upstream_cert.altnames)
|
|
|
|
if upstream_cert.cn:
|
|
|
|
sans.append(host)
|
|
|
|
host = upstream_cert.cn.decode("utf8").encode("idna")
|
|
|
|
if self.server_conn.sni:
|
|
|
|
sans.append(self.server_conn.sni)
|
|
|
|
# for ssl spoof mode
|
|
|
|
if hasattr(self.client_conn, "sni"):
|
|
|
|
sans.append(self.client_conn.sni)
|
|
|
|
|
|
|
|
ret = self.config.certstore.get_cert(host, sans)
|
|
|
|
if not ret:
|
|
|
|
raise ProxyError(502, "Unable to generate dummy cert.")
|
|
|
|
return ret
|
2011-02-08 17:00:59 +00:00
|
|
|
|
2014-01-07 01:29:10 +00:00
|
|
|
def handle_sni(self, connection):
|
2012-06-26 11:51:38 +00:00
|
|
|
"""
|
2014-01-07 01:29:10 +00:00
|
|
|
This callback gets called during the SSL handshake with the client.
|
|
|
|
The client has just sent the Sever Name Indication (SNI). We now connect upstream to
|
|
|
|
figure out which certificate needs to be served.
|
2012-06-26 11:51:38 +00:00
|
|
|
"""
|
2011-01-27 01:19:48 +00:00
|
|
|
try:
|
2014-01-07 01:29:10 +00:00
|
|
|
sn = connection.get_servername()
|
2014-12-15 11:46:13 +00:00
|
|
|
if not sn:
|
|
|
|
return
|
|
|
|
sni = sn.decode("utf8").encode("idna")
|
2015-06-20 15:51:56 +00:00
|
|
|
# for ssl spoof mode
|
|
|
|
self.client_conn.sni = sni
|
2014-12-15 11:46:13 +00:00
|
|
|
|
|
|
|
if sni != self.server_conn.sni:
|
|
|
|
self.log("SNI received: %s" % sni, "debug")
|
2015-02-27 08:17:41 +00:00
|
|
|
# We should only re-establish upstream SSL if one of the following conditions is true:
|
|
|
|
# - We established SSL with the server previously
|
|
|
|
# - We initially wanted to establish SSL with the server,
|
|
|
|
# but the server refused to negotiate without SNI.
|
2015-05-30 00:03:28 +00:00
|
|
|
if self.server_conn.ssl_established or hasattr(
|
|
|
|
self.server_conn,
|
|
|
|
"may_require_sni"):
|
|
|
|
# reconnect to upstream server with SNI
|
|
|
|
self.server_reconnect(sni)
|
2014-01-07 01:29:10 +00:00
|
|
|
# Now, change client context to reflect changed certificate:
|
2014-10-08 18:44:52 +00:00
|
|
|
cert, key, chain_file = self.find_cert()
|
2015-03-07 00:39:01 +00:00
|
|
|
new_context = self.client_conn.create_ssl_context(
|
2014-05-15 11:56:09 +00:00
|
|
|
cert, key,
|
2015-03-02 13:35:50 +00:00
|
|
|
method=self.config.openssl_method_client,
|
|
|
|
options=self.config.openssl_options_client,
|
|
|
|
cipher_list=self.config.ciphers_client,
|
2014-05-20 23:16:22 +00:00
|
|
|
dhparams=self.config.certstore.dhparams,
|
2014-10-08 18:44:52 +00:00
|
|
|
chain_file=chain_file
|
2014-05-15 11:56:09 +00:00
|
|
|
)
|
2014-01-07 01:29:10 +00:00
|
|
|
connection.set_context(new_context)
|
|
|
|
# An unhandled exception in this method will core dump PyOpenSSL, so
|
|
|
|
# make dang sure it doesn't happen.
|
2014-10-08 18:44:52 +00:00
|
|
|
except: # pragma: no cover
|
2014-03-13 00:04:45 +00:00
|
|
|
import traceback
|
2015-05-30 00:03:28 +00:00
|
|
|
self.log(
|
|
|
|
"Error in handle_sni:\r\n" +
|
|
|
|
traceback.format_exc(),
|
|
|
|
"error")
|