From 2a15479cdbda07a4a99f56f6090e479decbeb17c Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sat, 15 Aug 2015 20:20:46 +0200 Subject: [PATCH] fix bugs, make https work --- libmproxy/protocol2/http.py | 24 ++++++-------------- libmproxy/protocol2/http_proxy.py | 4 ++-- libmproxy/protocol2/layer.py | 4 ++-- libmproxy/protocol2/messages.py | 2 +- libmproxy/protocol2/root_context.py | 10 +++++---- libmproxy/protocol2/tls.py | 34 ++++++++++++++++------------- 6 files changed, 37 insertions(+), 41 deletions(-) diff --git a/libmproxy/protocol2/http.py b/libmproxy/protocol2/http.py index 7adeb4195..f629a6b0a 100644 --- a/libmproxy/protocol2/http.py +++ b/libmproxy/protocol2/http.py @@ -4,7 +4,7 @@ from .. import version from ..exceptions import InvalidCredentials, HttpException, ProtocolException from .layer import Layer, ServerConnectionMixin from libmproxy import utils -from .messages import ChangeServer, Connect, Reconnect, Kill +from .messages import SetServer, Connect, Reconnect, Kill from libmproxy.protocol import KILL from libmproxy.protocol.http import HTTPFlow @@ -71,19 +71,9 @@ class HttpLayer(Layer): HTTP 1 Layer """ - def __init__(self, ctx): + def __init__(self, ctx, mode): super(HttpLayer, self).__init__(ctx) - - # FIXME: Imports - from .http_proxy import HttpProxy, HttpUpstreamProxy - - if any(isinstance(l, HttpProxy) for l in self.layers): - self.mode = "regular" - elif any(isinstance(l, HttpUpstreamProxy) for l in self.layers): - self.mode = "upstream" - else: - # also includes socks or reverse mode, which are handled similarly on this layer. - self.mode = "transparent" + self.mode = mode def __call__(self): while True: @@ -104,7 +94,7 @@ class HttpLayer(Layer): # Regular Proxy Mode: Handle CONNECT if self.mode == "regular" and request.form_in == "authority": - self.server_address = (request.host, request.port) + yield SetServer((request.host, request.port), False, None) self.send_to_client(make_connect_response(request.httpversion)) layer = self.ctx.next_layer(self) for message in layer(): @@ -255,7 +245,7 @@ class HttpLayer(Layer): else: flow.request.host = self.ctx.server_address.host flow.request.port = self.ctx.server_address.port - flow.request.scheme = self.server_conn.tls_established + flow.request.scheme = "https" if self.server_conn.tls_established else "http" # TODO: Expose ChangeServer functionality to inline scripts somehow? (yield_from_callback?) request_reply = self.channel.ask("request", flow) @@ -271,8 +261,8 @@ class HttpLayer(Layer): tls = (flow.request.scheme == "https") if self.mode == "regular" or self.mode == "transparent": # If there's an existing connection that doesn't match our expectations, kill it. - if self.server_address != address or tls != self.server_address.ssl_established: - yield ChangeServer(address, tls, address.host) + if self.server_address != address or tls != self.server_conn.ssl_established: + yield SetServer(address, tls, address.host) # Establish connection is neccessary. if not self.server_conn: yield Connect() diff --git a/libmproxy/protocol2/http_proxy.py b/libmproxy/protocol2/http_proxy.py index 51d3763c7..8ac7ea8e8 100644 --- a/libmproxy/protocol2/http_proxy.py +++ b/libmproxy/protocol2/http_proxy.py @@ -6,7 +6,7 @@ from .http import HttpLayer class HttpProxy(Layer, ServerConnectionMixin): def __call__(self): - layer = HttpLayer(self) + layer = HttpLayer(self, "regular") for message in layer(): if not self._handle_server_message(message): yield message @@ -18,7 +18,7 @@ class HttpUpstreamProxy(Layer, ServerConnectionMixin): self.server_address = server_address def __call__(self): - layer = HttpLayer(self) + layer = HttpLayer(self, "upstream") for message in layer(): if not self._handle_server_message(message): yield message diff --git a/libmproxy/protocol2/layer.py b/libmproxy/protocol2/layer.py index f2d6b3fb6..8e985d4dd 100644 --- a/libmproxy/protocol2/layer.py +++ b/libmproxy/protocol2/layer.py @@ -35,7 +35,7 @@ import threading from netlib import tcp from ..proxy import Log from ..proxy.connection import ServerConnection -from .messages import Connect, Reconnect, ChangeServer, Kill +from .messages import Connect, Reconnect, SetServer, Kill from ..exceptions import ProtocolException @@ -116,7 +116,7 @@ class ServerConnectionMixin(object): elif message == Connect: self._connect() return True - elif message == ChangeServer and message.depth == 1: + elif message == SetServer and message.depth == 1: if self.server_conn: self._disconnect() self.server_address = message.address diff --git a/libmproxy/protocol2/messages.py b/libmproxy/protocol2/messages.py index f6b584a14..17e12f112 100644 --- a/libmproxy/protocol2/messages.py +++ b/libmproxy/protocol2/messages.py @@ -27,7 +27,7 @@ class Reconnect(_Message): """ -class ChangeServer(_Message): +class SetServer(_Message): """ Change the upstream server. """ diff --git a/libmproxy/protocol2/root_context.py b/libmproxy/protocol2/root_context.py index 3b3417788..bda8b12b2 100644 --- a/libmproxy/protocol2/root_context.py +++ b/libmproxy/protocol2/root_context.py @@ -2,7 +2,7 @@ from __future__ import (absolute_import, print_function, division) from .rawtcp import RawTcpLayer from .tls import TlsLayer - +from .http import HttpLayer class RootContext(object): """ @@ -38,10 +38,12 @@ class RootContext(object): return if is_tls_client_hello: - layer = TlsLayer(top_layer, True, True) + return TlsLayer(top_layer, True, True) + elif isinstance(top_layer, TlsLayer) and isinstance(top_layer.ctx, HttpLayer): + return HttpLayer(top_layer, "transparent") else: - layer = RawTcpLayer(top_layer) - return layer + return RawTcpLayer(top_layer) + @property def layers(self): diff --git a/libmproxy/protocol2/tls.py b/libmproxy/protocol2/tls.py index 988304aac..55cc97941 100644 --- a/libmproxy/protocol2/tls.py +++ b/libmproxy/protocol2/tls.py @@ -5,7 +5,7 @@ from netlib import tcp from ..exceptions import ProtocolException from .layer import Layer, yield_from_callback -from .messages import Connect, Reconnect, ChangeServer +from .messages import Connect, Reconnect, SetServer class TlsLayer(Layer): @@ -13,7 +13,6 @@ class TlsLayer(Layer): super(TlsLayer, self).__init__(ctx) self._client_tls = client_tls self._server_tls = server_tls - self._connected = False self.client_sni = None self._sni_from_server_change = None @@ -44,9 +43,6 @@ class TlsLayer(Layer): client_tls_requires_server_cert = ( self._client_tls and self._server_tls and not self.config.no_upstream_cert ) - lazy_server_tls = ( - self._server_tls and not client_tls_requires_server_cert - ) if client_tls_requires_server_cert: for m in self._establish_tls_with_client_and_server(): @@ -56,18 +52,27 @@ class TlsLayer(Layer): yield m layer = self.ctx.next_layer(self) + for message in layer(): - if message != Connect or not self._connected: + self.log("TlsLayer: %s" % message,"debug") + if not (message == Connect and self._connected): yield message - if message == Connect: - if lazy_server_tls: - self._establish_tls_with_server() - if message == ChangeServer and message.depth == 1: - self._server_tls = message.server_tls - self._sni_from_server_change = message.sni - if message == Reconnect or message == ChangeServer: - if self._server_tls: + + if message == Connect or message == Reconnect: + if self._server_tls and not self._server_tls_established: self._establish_tls_with_server() + if message == SetServer and message.depth == 1: + if message.server_tls is not None: + self._sni_from_server_change = message.sni + self._server_tls = message.server_tls + + @property + def _server_tls_established(self): + return self.server_conn and self.server_conn.tls_established + + @property + def _connected(self): + return bool(self.server_conn) @property def sni_for_upstream_connection(self): @@ -83,7 +88,6 @@ class TlsLayer(Layer): # First, try to connect to the server. yield Connect() - self._connected = True server_err = None try: self._establish_tls_with_server()