From c46e3f90bbc38080a41a278340aaad27d8881fd9 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 6 Aug 2015 11:09:01 +0200 Subject: [PATCH] apply fixes from proxy-refactor-cb branch --- libmproxy/protocol2/__init__.py | 2 +- libmproxy/protocol2/auto.py | 4 +++- libmproxy/protocol2/layer.py | 25 ++++++++++++------------ libmproxy/protocol2/messages.py | 2 +- libmproxy/protocol2/rawtcp.py | 2 +- libmproxy/protocol2/socks.py | 4 ++-- libmproxy/protocol2/ssl.py | 34 +++++++++++++++++---------------- 7 files changed, 38 insertions(+), 35 deletions(-) diff --git a/libmproxy/protocol2/__init__.py b/libmproxy/protocol2/__init__.py index 20e5a8884..95f67c6c6 100644 --- a/libmproxy/protocol2/__init__.py +++ b/libmproxy/protocol2/__init__.py @@ -1,4 +1,4 @@ -from __future__ import (absolute_import, print_function, division, unicode_literals) +from __future__ import (absolute_import, print_function, division) from .layer import RootContext from .socks import Socks5IncomingLayer from .rawtcp import TcpLayer diff --git a/libmproxy/protocol2/auto.py b/libmproxy/protocol2/auto.py index a00f1f521..fc1117582 100644 --- a/libmproxy/protocol2/auto.py +++ b/libmproxy/protocol2/auto.py @@ -1,4 +1,4 @@ -from __future__ import (absolute_import, print_function, division, unicode_literals) +from __future__ import (absolute_import, print_function, division) from .layer import Layer @@ -6,6 +6,8 @@ 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 = SslLayer(self, True, True) diff --git a/libmproxy/protocol2/layer.py b/libmproxy/protocol2/layer.py index 1cc8df707..30aed3505 100644 --- a/libmproxy/protocol2/layer.py +++ b/libmproxy/protocol2/layer.py @@ -31,7 +31,7 @@ Further goals: - Upstream connections should be established as late as possible; inline scripts shall have a chance to handle everything locally. """ -from __future__ import (absolute_import, print_function, division, unicode_literals) +from __future__ import (absolute_import, print_function, division) from netlib import tcp from ..proxy import ProxyError2, Log from ..proxy.connection import ServerConnection @@ -49,12 +49,6 @@ class RootContext(object): self.channel = channel # provides .ask() method to communicate with FlowMaster self.config = config # Proxy Configuration - def __getattr__(self, name): - """ - Accessing a nonexisting attribute does not throw an error but returns None instead. - """ - return None - class _LayerCodeCompletion(object): """ @@ -113,7 +107,7 @@ class ServerConnectionMixin(object): """ def __init__(self): - self.server_address = None + self._server_address = None self.server_conn = None def _handle_server_message(self, message): @@ -128,6 +122,16 @@ class ServerConnectionMixin(object): raise NotImplementedError return False + @property + def server_address(self): + return self._server_address + + @server_address.setter + def server_address(self, address): + self._server_address = tcp.Address.wrap(address) + self.log("Set new server address: " + repr(self.server_address), "debug") + + def _disconnect(self): """ Deletes (and closes) an existing server connection. @@ -145,8 +149,3 @@ class ServerConnectionMixin(object): self.server_conn.connect() except tcp.NetLibError as e: raise ProxyError2("Server connection to '%s' failed: %s" % (self.server_address, e), e) - - def _set_address(self, address): - a = tcp.Address.wrap(address) - self.log("Set new server address: " + repr(a), "debug") - self.server_address = address diff --git a/libmproxy/protocol2/messages.py b/libmproxy/protocol2/messages.py index 52bb5a446..baf4312dc 100644 --- a/libmproxy/protocol2/messages.py +++ b/libmproxy/protocol2/messages.py @@ -1,7 +1,7 @@ """ This module contains all valid messages layers can send to the underlying layers. """ -from __future__ import (absolute_import, print_function, division, unicode_literals) +from __future__ import (absolute_import, print_function, division) class _Message(object): diff --git a/libmproxy/protocol2/rawtcp.py b/libmproxy/protocol2/rawtcp.py index b40c569f4..39e48e242 100644 --- a/libmproxy/protocol2/rawtcp.py +++ b/libmproxy/protocol2/rawtcp.py @@ -1,4 +1,4 @@ -from __future__ import (absolute_import, print_function, division, unicode_literals) +from __future__ import (absolute_import, print_function, division) from ..protocol.tcp import TCPHandler from .layer import Layer from .messages import Connect diff --git a/libmproxy/protocol2/socks.py b/libmproxy/protocol2/socks.py index 7835b1a4b..14564521e 100644 --- a/libmproxy/protocol2/socks.py +++ b/libmproxy/protocol2/socks.py @@ -1,4 +1,4 @@ -from __future__ import (absolute_import, print_function, division, unicode_literals) +from __future__ import (absolute_import, print_function, division) from ..proxy import ProxyError, Socks5ProxyMode, ProxyError2 from .layer import Layer, ServerConnectionMixin @@ -14,7 +14,7 @@ class Socks5IncomingLayer(Layer, ServerConnectionMixin): # TODO: Unmonkeypatch raise ProxyError2(str(e), e) - self._set_address(address) + self.server_address = address layer = AutoLayer(self) for message in layer(): diff --git a/libmproxy/protocol2/ssl.py b/libmproxy/protocol2/ssl.py index e8ff16cf7..c21956b76 100644 --- a/libmproxy/protocol2/ssl.py +++ b/libmproxy/protocol2/ssl.py @@ -1,4 +1,4 @@ -from __future__ import (absolute_import, print_function, division, unicode_literals) +from __future__ import (absolute_import, print_function, division) import Queue import threading import traceback @@ -76,7 +76,7 @@ class SslLayer(Layer): self._establish_ssl_with_server() @property - def sni(self): + def sni_for_upstream_connection(self): if self._sni_from_server_change is False: return None else: @@ -132,21 +132,22 @@ class SslLayer(Layer): The client has just sent the Sever Name Indication (SNI). """ try: + old_upstream_sni = self.sni_for_upstream_connection + sn = connection.get_servername() if not sn: return - sni = sn.decode("utf8").encode("idna") - - if sni != self.sni: - self._sni_from_handshake = sni + self._sni_from_handshake = sn.decode("utf8").encode("idna") + if old_upstream_sni != self.sni_for_upstream_connection: # Perform reconnect if self.server_ssl: reconnect = ReconnectRequest() - self.__client_ssl_queue.put() + self.__client_ssl_queue.put(reconnect) reconnect.done.wait() - # Now, change client context to reflect changed certificate: + if self._sni_from_handshake: + # Now, change client context to reflect possibly changed certificate: cert, key, chain_file = self.find_cert() new_context = self.client_conn.create_ssl_context( cert, key, @@ -183,7 +184,7 @@ class SslLayer(Layer): try: self.server_conn.establish_ssl( self.config.clientcerts, - self.sni, + self.sni_for_upstream_connection, method=self.config.openssl_method_server, options=self.config.openssl_options_server, verify_options=self.config.openssl_verification_mode_server, @@ -206,23 +207,24 @@ class SslLayer(Layer): "error") self.log("Aborting connection attempt", "error") raise ProxyError2(repr(e), e) - except Exception as e: + except tcp.NetLibError as e: raise ProxyError2(repr(e), e) def find_cert(self): host = self.server_conn.address.host - sans = [] + # TODO: Better use an OrderedSet here + sans = set() # Incorporate upstream certificate if self.server_conn.ssl_established and (not self.config.no_upstream_cert): upstream_cert = self.server_conn.cert - sans.extend(upstream_cert.altnames) + sans.update(upstream_cert.altnames) if upstream_cert.cn: - sans.append(host) + sans.add(host) host = upstream_cert.cn.decode("utf8").encode("idna") # Also add SNI values. if self._sni_from_handshake: - sans.append(self._sni_from_handshake) + sans.add(self._sni_from_handshake) if self._sni_from_server_change: - sans.append(self._sni_from_server_change) + sans.add(self._sni_from_server_change) - return self.config.certstore.get_cert(host, sans) \ No newline at end of file + return self.config.certstore.get_cert(host, list(sans)) \ No newline at end of file