wip commit

This commit is contained in:
Maximilian Hils
2015-08-11 20:27:34 +02:00
parent 026330a3b0
commit aef3b626a7
12 changed files with 170 additions and 57 deletions

View File

@@ -18,5 +18,13 @@ class ProtocolException(ProxyException):
pass
class HttpException(ProtocolException):
pass
class InvalidCredentials(HttpException):
pass
class ServerException(ProxyException):
pass
pass

View File

@@ -1,8 +1,10 @@
from __future__ import (absolute_import, print_function, division)
from .layer import RootContext
from .socks import Socks5IncomingLayer
from .root_context import RootContext
from .socks_proxy import Socks5Proxy
from .reverse_proxy import ReverseProxy
from .upstream_proxy import UpstreamProxy
from .http_proxy import HttpProxy, HttpUpstreamProxy
from .rawtcp import TcpLayer
from .auto import AutoLayer
__all__ = ["Socks5IncomingLayer", "TcpLayer", "AutoLayer", "RootContext", "ReverseProxy", "UpstreamProxy"]
__all__ = [
"Socks5Proxy", "TcpLayer", "RootContext", "ReverseProxy", "HttpProxy", "HttpUpstreamProxy"
]

View File

@@ -1,20 +0,0 @@
from __future__ import (absolute_import, print_function, division)
from .layer import Layer
class AutoLayer(Layer):
def __call__(self):
d = self.client_conn.rfile.peek(1)
if not d:
return
# TLS ClientHello magic, see http://www.moserware.com/2009/06/first-few-milliseconds-of-https.html#client-hello
if d[0] == "\x16":
layer = TlsLayer(self, True, True)
else:
layer = TcpLayer(self)
for m in layer():
yield m
from .rawtcp import TcpLayer
from .tls import TlsLayer

View File

@@ -0,0 +1,90 @@
from __future__ import (absolute_import, print_function, division)
from .layer import Layer, ServerConnectionMixin
from libmproxy import version
from libmproxy.exceptions import InvalidCredentials
from libmproxy.protocol.http import HTTPFlow
from libmproxy.protocol.http_wrappers import HTTPResponse
from libmproxy.protocol2.http_protocol_mock import HTTP1
from netlib import tcp
from netlib.http import status_codes
from netlib import odict
def send_http_error_response(status_code, message, headers=odict.ODictCaseless()):
response = status_codes.RESPONSES.get(status_code, "Unknown")
body = """
<html>
<head>
<title>%d %s</title>
</head>
<body>%s</body>
</html>
""".strip() % (status_code, response, message)
headers["Server"] = [version.NAMEVERSION]
headers["Connection"] = ["close"]
headers["Content-Length"] = [len(body)]
headers["Content-Type"] = ["text/html"]
resp = HTTPResponse(
(1, 1), # if HTTP/2 is used, this value is ignored anyway
status_code,
response,
headers,
body,
)
protocol = self.c.client_conn.protocol or http1.HTTP1Protocol(self.c.client_conn)
self.c.client_conn.send(protocol.assemble(resp))
class HttpLayer(Layer, ServerConnectionMixin):
"""
HTTP 1 Layer
"""
def __init__(self, ctx):
super(HttpLayer, self).__init__(ctx)
self.skip_authentication = False
def __call__(self):
while True:
flow = HTTPFlow(self.client_conn, self.server_conn)
try:
request = HTTP1.read_request(
self.client_conn,
body_size_limit=self.c.config.body_size_limit
)
except tcp.NetLibError:
# don't throw an error for disconnects that happen
# before/between requests.
return
self.c.log("request", "debug", [repr(request)])
self.check_authentication(request)
if self.mode == "regular" and request.form_in == "authority":
raise NotImplementedError
ret = self.process_request(flow, request)
if ret is True:
continue
if ret is False:
return
def check_authentication(self, request):
if self.config.authenticator:
if self.config.authenticator.authenticate(request.headers):
self.config.authenticator.clean(request.headers)
else:
self.send_error()
raise InvalidCredentials("Proxy Authentication Required")
raise http.HttpAuthenticationError(
self.c.config.authenticator.auth_challenge_headers())
return request.headers
def send_error(self, code, message, headers):
pass

View File

@@ -0,0 +1,13 @@
"""
Temporary mock to sort out API discrepancies
"""
from netlib.http.http1 import HTTP1Protocol
class HTTP1(object):
@staticmethod
def read_request(connection, *args, **kwargs):
"""
:type connection: object
"""
return HTTP1Protocol(connection).read_request(*args, **kwargs)

View File

@@ -1,18 +1,23 @@
from __future__ import (absolute_import, print_function, division)
from .layer import Layer, ServerConnectionMixin
#from .http import HttpLayer
from .http import HttpLayer
class UpstreamProxy(Layer, ServerConnectionMixin):
class HttpProxy(Layer):
def __call__(self):
layer = HttpLayer(self)
for message in layer():
yield message
class HttpUpstreamProxy(Layer, ServerConnectionMixin):
def __init__(self, ctx, server_address):
super(UpstreamProxy, self).__init__(ctx)
super(HttpUpstreamProxy, self).__init__(ctx)
self.server_address = server_address
def __call__(self):
#layer = HttpLayer(self)
layer = None
layer = HttpLayer(self)
for message in layer():
if not self._handle_server_message(message):
yield message

View File

@@ -41,21 +41,6 @@ from .messages import Connect, Reconnect, ChangeServer
from ..exceptions import ProtocolException
class RootContext(object):
"""
The outmost context provided to the root layer.
As a consequence, every layer has .client_conn, .channel and .config.
"""
def __init__(self, client_conn, config, channel):
self.client_conn = client_conn # Client Connection
self.channel = channel # provides .ask() method to communicate with FlowMaster
self.config = config # Proxy Configuration
def next_layer(self):
print(type(self))
class _LayerCodeCompletion(object):
"""
Dummy class that provides type hinting in PyCharm, which simplifies development a lot.
@@ -208,4 +193,4 @@ def yield_from_callback(fun):
self.yield_from_callback = None
return wrapper
return wrapper

View File

@@ -0,0 +1,32 @@
from .rawtcp import TcpLayer
from .tls import TlsLayer
class RootContext(object):
"""
The outmost context provided to the root layer.
As a consequence, every layer has .client_conn, .channel, .next_layer() and .config.
"""
def __init__(self, client_conn, config, channel):
self.client_conn = client_conn # Client Connection
self.channel = channel # provides .ask() method to communicate with FlowMaster
self.config = config # Proxy Configuration
def next_layer(self, top_layer):
"""
This function determines the next layer in the protocol stack.
:param top_layer: the current top layer
:return: The next layer.
"""
d = top_layer.client_conn.rfile.peek(1)
if not d:
return
# TLS ClientHello magic, see http://www.moserware.com/2009/06/first-few-milliseconds-of-https.html#client-hello
if d[0] == "\x16":
layer = TlsLayer(top_layer, True, True)
else:
layer = TcpLayer(top_layer)
return layer

View File

@@ -3,9 +3,9 @@ from __future__ import (absolute_import, print_function, division)
from ..exceptions import ProtocolException
from ..proxy import ProxyError, Socks5ProxyMode
from .layer import Layer, ServerConnectionMixin
from .auto import AutoLayer
class Socks5IncomingLayer(Layer, ServerConnectionMixin):
class Socks5Proxy(Layer, ServerConnectionMixin):
def __call__(self):
try:
s5mode = Socks5ProxyMode(self.config.ssl_ports)
@@ -16,7 +16,7 @@ class Socks5IncomingLayer(Layer, ServerConnectionMixin):
self.server_address = address
layer = AutoLayer(self)
layer = self.ctx.next_layer(self)
for message in layer():
if not self._handle_server_message(message):
yield message

View File

@@ -5,7 +5,6 @@ from netlib import tcp
from ..exceptions import ProtocolException
from .layer import Layer, yield_from_callback
from .messages import Connect, Reconnect, ChangeServer
from .auto import AutoLayer
class TlsLayer(Layer):
@@ -55,8 +54,7 @@ class TlsLayer(Layer):
for m in self._establish_tls_with_client():
yield m
self.next_layer()
layer = AutoLayer(self)
layer = self.ctx.next_layer(self)
for message in layer():
if message != Connect or not self._connected:
yield message

View File

@@ -3,7 +3,6 @@ from __future__ import (absolute_import, print_function, division)
from ..exceptions import ProtocolException
from .. import platform
from .layer import Layer, ServerConnectionMixin
from .auto import AutoLayer
class TransparentProxy(Layer, ServerConnectionMixin):
@@ -18,7 +17,7 @@ class TransparentProxy(Layer, ServerConnectionMixin):
except Exception as e:
raise ProtocolException("Transparent mode failure: %s" % repr(e), e)
layer = AutoLayer(self)
layer = self.ctx.next_layer(self)
for message in layer():
if not self._handle_server_message(message):
yield message

View File

@@ -7,6 +7,7 @@ from netlib import tcp
from ..protocol.handle import protocol_handler
from .. import protocol2
from ..exceptions import ProtocolException
from .primitives import ProxyServerError, Log, ProxyError
from .connection import ClientConnection, ServerConnection
@@ -79,12 +80,12 @@ class ConnectionHandler2:
self.config,
self.channel
)
root_layer = protocol2.Socks5IncomingLayer(root_context)
root_layer = protocol2.Socks5Proxy(root_context)
try:
for message in root_layer():
print("Root layer receveived: %s" % message)
except protocol2.ProtocolException as e:
except ProtocolException as e:
self.log(e, "info")
except Exception:
self.log(traceback.format_exc(), "error")