diff options
-rw-r--r-- | libmproxy/protocol2/http.py | 38 | ||||
-rw-r--r-- | libmproxy/protocol2/http_protocol_mock.py | 25 | ||||
-rw-r--r-- | libmproxy/protocol2/http_proxy.py | 4 | ||||
-rw-r--r-- | libmproxy/protocol2/layer.py | 13 | ||||
-rw-r--r-- | libmproxy/protocol2/messages.py | 2 | ||||
-rw-r--r-- | libmproxy/protocol2/root_context.py | 10 | ||||
-rw-r--r-- | libmproxy/protocol2/tls.py | 34 | ||||
-rw-r--r-- | libmproxy/proxy/server.py | 2 |
8 files changed, 68 insertions, 60 deletions
diff --git a/libmproxy/protocol2/http.py b/libmproxy/protocol2/http.py index 1e774648..f629a6b0 100644 --- a/libmproxy/protocol2/http.py +++ b/libmproxy/protocol2/http.py @@ -4,8 +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 .http_proxy import HttpProxy, HttpUpstreamProxy +from .messages import SetServer, Connect, Reconnect, Kill from libmproxy.protocol import KILL from libmproxy.protocol.http import HTTPFlow @@ -66,20 +65,15 @@ def make_connect_response(httpversion): ) -class HttpLayer(Layer, ServerConnectionMixin): +class HttpLayer(Layer): + """ HTTP 1 Layer """ - def __init__(self, ctx): + def __init__(self, ctx, mode): super(HttpLayer, self).__init__(ctx) - 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: @@ -100,7 +94,7 @@ class HttpLayer(Layer, ServerConnectionMixin): # 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(): @@ -199,7 +193,7 @@ class HttpLayer(Layer, ServerConnectionMixin): self.send_to_server(flow.request) flow.response = HTTP1.read_response( - self.server_conn.protocol, + self.server_conn, flow.request.method, body_size_limit=self.config.body_size_limit, include_body=False, @@ -215,6 +209,7 @@ class HttpLayer(Layer, ServerConnectionMixin): flow.response.content = CONTENT_MISSING else: flow.response.content = HTTP1.read_http_body( + self.server_conn, flow.response.headers, self.config.body_size_limit, flow.request.method, @@ -250,7 +245,7 @@ class HttpLayer(Layer, ServerConnectionMixin): 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) @@ -266,8 +261,8 @@ class HttpLayer(Layer, ServerConnectionMixin): 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() @@ -303,7 +298,7 @@ class HttpLayer(Layer, ServerConnectionMixin): expected_request_forms = { "regular": ("absolute",), # an authority request would already be handled. "upstream": ("authority", "absolute"), - "transparent": ("regular",) + "transparent": ("relative",) } allowed_request_forms = expected_request_forms[self.mode] @@ -314,6 +309,9 @@ class HttpLayer(Layer, ServerConnectionMixin): self.send_to_client(make_error_response(400, err_message)) raise HttpException(err_message) + if self.mode == "regular": + request.form_out = "relative" + def authenticate(self, request): if self.config.authenticator: if self.config.authenticator.authenticate(request.headers): @@ -327,10 +325,10 @@ class HttpLayer(Layer, ServerConnectionMixin): raise InvalidCredentials("Proxy Authentication Required") def send_to_server(self, message): - self.server_conn.wfile.wrie(message) + self.server_conn.send(HTTP1.assemble(message)) + def send_to_client(self, message): # FIXME # - possibly do some http2 stuff here - # - fix message assembly. - self.client_conn.wfile.write(message) + self.client_conn.send(HTTP1.assemble(message)) diff --git a/libmproxy/protocol2/http_protocol_mock.py b/libmproxy/protocol2/http_protocol_mock.py index 5fdb9f2b..22f3dc14 100644 --- a/libmproxy/protocol2/http_protocol_mock.py +++ b/libmproxy/protocol2/http_protocol_mock.py @@ -1,6 +1,7 @@ """ Temporary mock to sort out API discrepancies """ +from libmproxy.protocol.http_wrappers import HTTPResponse, HTTPRequest from netlib.http.http1 import HTTP1Protocol @@ -10,14 +11,14 @@ class HTTP1(object): """ :type connection: object """ - return HTTP1Protocol(connection).read_request(*args, **kwargs) + return HTTPRequest.wrap(HTTP1Protocol(connection).read_request(*args, **kwargs)) @staticmethod def read_response(connection, *args, **kwargs): """ :type connection: object """ - return HTTP1Protocol(connection).read_response(*args, **kwargs) + return HTTPResponse.wrap(HTTP1Protocol(connection).read_response(*args, **kwargs)) @staticmethod def read_http_body(connection, *args, **kwargs): @@ -28,19 +29,13 @@ class HTTP1(object): @staticmethod - def _assemble_response_first_line(connection, *args, **kwargs): - """ - :type connection: object - """ - return HTTP1Protocol(connection)._assemble_response_first_line(*args, **kwargs) + def _assemble_response_first_line(*args, **kwargs): + return HTTP1Protocol()._assemble_response_first_line(*args, **kwargs) @staticmethod - def _assemble_response_headers(connection, *args, **kwargs): - """ - :type connection: object - """ - return HTTP1Protocol(connection)._assemble_response_headers(*args, **kwargs) + def _assemble_response_headers(*args, **kwargs): + return HTTP1Protocol()._assemble_response_headers(*args, **kwargs) @staticmethod @@ -48,4 +43,8 @@ class HTTP1(object): """ :type connection: object """ - return HTTP1Protocol(connection).read_http_body_chunked(*args, **kwargs)
\ No newline at end of file + return HTTP1Protocol(connection).read_http_body_chunked(*args, **kwargs) + + @staticmethod + def assemble(*args, **kwargs): + return HTTP1Protocol().assemble(*args, **kwargs)
\ No newline at end of file diff --git a/libmproxy/protocol2/http_proxy.py b/libmproxy/protocol2/http_proxy.py index b85a65eb..b4c506cb 100644 --- a/libmproxy/protocol2/http_proxy.py +++ b/libmproxy/protocol2/http_proxy.py @@ -5,7 +5,7 @@ from .layer import Layer, ServerConnectionMixin 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 @@ -17,7 +17,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 2775845e..8e985d4d 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 @@ -45,6 +45,7 @@ class _LayerCodeCompletion(object): """ def __init__(self): + super(_LayerCodeCompletion, self).__init__() if True: return self.config = None @@ -94,7 +95,7 @@ class Layer(_LayerCodeCompletion): return [self] + self.ctx.layers def __repr__(self): - return "%s\r\n %s" % (self.__class__.name__, repr(self.ctx)) + return type(self).__name__ class ServerConnectionMixin(object): @@ -103,6 +104,7 @@ class ServerConnectionMixin(object): """ def __init__(self): + super(ServerConnectionMixin, self).__init__() self._server_address = None self.server_conn = None @@ -114,8 +116,11 @@ class ServerConnectionMixin(object): elif message == Connect: self._connect() return True - elif message == ChangeServer: - raise NotImplementedError + elif message == SetServer and message.depth == 1: + if self.server_conn: + self._disconnect() + self.server_address = message.address + return True elif message == Kill: self._disconnect() diff --git a/libmproxy/protocol2/messages.py b/libmproxy/protocol2/messages.py index f6b584a1..17e12f11 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 3b341778..bda8b12b 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 9572912f..9ef72a78 100644 --- a/libmproxy/protocol2/tls.py +++ b/libmproxy/protocol2/tls.py @@ -7,7 +7,7 @@ import netlib.http.http2 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): @@ -15,7 +15,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 @@ -46,9 +45,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(): @@ -58,18 +54,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): @@ -85,7 +90,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() diff --git a/libmproxy/proxy/server.py b/libmproxy/proxy/server.py index defcd464..ffca55ee 100644 --- a/libmproxy/proxy/server.py +++ b/libmproxy/proxy/server.py @@ -80,7 +80,7 @@ class ConnectionHandler2: self.config, self.channel ) - root_layer = protocol2.Socks5Proxy(root_context) + root_layer = protocol2.HttpProxy(root_context) try: for message in root_layer(): |