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():  | 
