add reverseproxy mode, fix bugs

This commit is contained in:
Maximilian Hils 2015-08-06 12:32:33 +02:00
parent aac0ab23eb
commit 314e0f5839
5 changed files with 35 additions and 15 deletions

View File

@ -1,6 +1,7 @@
from __future__ import (absolute_import, print_function, division) from __future__ import (absolute_import, print_function, division)
from .layer import RootContext from .layer import RootContext
from .socks import Socks5IncomingLayer from .socks import Socks5IncomingLayer
from .reverse_proxy import ReverseProxy
from .rawtcp import TcpLayer from .rawtcp import TcpLayer
from .auto import AutoLayer from .auto import AutoLayer
__all__ = ["Socks5IncomingLayer", "TcpLayer", "AutoLayer", "RootContext"] __all__ = ["Socks5IncomingLayer", "TcpLayer", "AutoLayer", "RootContext", "ReverseProxy"]

View File

@ -176,7 +176,7 @@ def yield_from_callback(fun):
""" """
yield_queue = Queue.Queue() yield_queue = Queue.Queue()
def do_yield(self, msg): def do_yield(msg):
yield_queue.put(msg) yield_queue.put(msg)
yield_queue.get() yield_queue.get()
@ -192,14 +192,14 @@ def yield_from_callback(fun):
threading.Thread(target=run, name="YieldFromCallbackThread").start() threading.Thread(target=run, name="YieldFromCallbackThread").start()
while True: while True:
e = yield_queue.get() msg = yield_queue.get()
if e is True: if msg is True:
break break
elif isinstance(e, Exception): elif isinstance(msg, Exception):
# TODO: Include func name? # TODO: Include func name?
raise ProxyError2("Error from callback: " + repr(e), e) raise ProxyError2("Error in %s: %s" % (fun.__name__, repr(msg)), msg)
else: else:
yield e yield msg
yield_queue.put(None) yield_queue.put(None)
self.yield_from_callback = None self.yield_from_callback = None

View File

@ -0,0 +1,19 @@
from __future__ import (absolute_import, print_function, division)
from .layer import Layer, ServerConnectionMixin
from .ssl import SslLayer
class ReverseProxy(Layer, ServerConnectionMixin):
def __init__(self, ctx, server_address, client_ssl, server_ssl):
super(ReverseProxy, self).__init__(ctx)
self.server_address = server_address
self.client_ssl = client_ssl
self.server_ssl = server_ssl
def __call__(self):
layer = SslLayer(self, self.client_ssl, self.server_ssl)
for message in layer():
if not self._handle_server_message(message):
yield message

View File

@ -14,7 +14,7 @@ class SslLayer(Layer):
self._client_ssl = client_ssl self._client_ssl = client_ssl
self._server_ssl = server_ssl self._server_ssl = server_ssl
self._connected = False self._connected = False
self._sni_from_handshake = None self.client_sni = None
self._sni_from_server_change = None self._sni_from_server_change = None
def __call__(self): def __call__(self):
@ -74,7 +74,7 @@ class SslLayer(Layer):
if self._sni_from_server_change is False: if self._sni_from_server_change is False:
return None return None
else: else:
return self._sni_from_server_change or self._sni_from_handshake return self._sni_from_server_change or self.client_sni
def _establish_ssl_with_client_and_server(self): def _establish_ssl_with_client_and_server(self):
""" """
@ -97,7 +97,7 @@ class SslLayer(Layer):
else: else:
raise RuntimeError("Unexpected Message: %s" % message) raise RuntimeError("Unexpected Message: %s" % message)
if server_err and not self._sni_from_handshake: if server_err and not self.client_sni:
raise server_err raise server_err
def handle_sni(self, connection): def handle_sni(self, connection):
@ -111,14 +111,14 @@ class SslLayer(Layer):
sn = connection.get_servername() sn = connection.get_servername()
if not sn: if not sn:
return return
self._sni_from_handshake = sn.decode("utf8").encode("idna") self.client_sni = sn.decode("utf8").encode("idna")
if old_upstream_sni != self.sni_for_upstream_connection: if old_upstream_sni != self.sni_for_upstream_connection:
# Perform reconnect # Perform reconnect
if self.server_ssl: if self.server_ssl:
self.yield_from_callback(Reconnect()) self.yield_from_callback(Reconnect())
if self._sni_from_handshake: if self.client_sni:
# Now, change client context to reflect possibly changed certificate: # Now, change client context to reflect possibly changed certificate:
cert, key, chain_file = self.find_cert() cert, key, chain_file = self.find_cert()
new_context = self.client_conn.create_ssl_context( new_context = self.client_conn.create_ssl_context(
@ -195,8 +195,8 @@ class SslLayer(Layer):
sans.add(host) sans.add(host)
host = upstream_cert.cn.decode("utf8").encode("idna") host = upstream_cert.cn.decode("utf8").encode("idna")
# Also add SNI values. # Also add SNI values.
if self._sni_from_handshake: if self.client_sni:
sans.add(self._sni_from_handshake) sans.add(self.client_sni)
if self._sni_from_server_change: if self._sni_from_server_change:
sans.add(self._sni_from_server_change) sans.add(self._sni_from_server_change)

View File

@ -79,7 +79,7 @@ class ConnectionHandler2:
self.config, self.config,
self.channel self.channel
) )
root_layer = protocol2.Socks5IncomingLayer(root_context) root_layer = protocol2.ReverseProxy(root_context, ("localhost", 5000), True, True)
try: try:
for message in root_layer(): for message in root_layer():