aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libmproxy/protocol2/http.py38
-rw-r--r--libmproxy/protocol2/http_protocol_mock.py25
-rw-r--r--libmproxy/protocol2/http_proxy.py4
-rw-r--r--libmproxy/protocol2/layer.py13
-rw-r--r--libmproxy/protocol2/messages.py2
-rw-r--r--libmproxy/protocol2/root_context.py10
-rw-r--r--libmproxy/protocol2/tls.py34
-rw-r--r--libmproxy/proxy/server.py2
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():