diff --git a/libmproxy/exceptions.py b/libmproxy/exceptions.py index 6b997041e..7d80ce31b 100644 --- a/libmproxy/exceptions.py +++ b/libmproxy/exceptions.py @@ -33,6 +33,11 @@ class TlsException(ProtocolException): pass +class ClientHandshakeException(TlsException): + # This subclass is quite useful to give hints about cert errors. + pass + + class Socks5Exception(ProtocolException): pass diff --git a/libmproxy/protocol/base.py b/libmproxy/protocol/base.py index 9d8c8bfe4..6793d3df3 100644 --- a/libmproxy/protocol/base.py +++ b/libmproxy/protocol/base.py @@ -1,4 +1,6 @@ from __future__ import (absolute_import, print_function, division) +import six +import sys from netlib import tcp from ..models import ServerConnection from ..exceptions import ProtocolException @@ -172,8 +174,12 @@ class ServerConnectionMixin(object): try: self.server_conn.connect() except tcp.NetLibError as e: - raise ProtocolException( - "Server connection to %s failed: %s" % (repr(self.server_conn.address), e), e) + six.reraise( + ProtocolException, + ProtocolException("Server connection to %s failed: %s" % + (repr(self.server_conn.address), e), e), + sys.exc_info()[2] + ) class Kill(Exception): diff --git a/libmproxy/protocol/rawtcp.py b/libmproxy/protocol/rawtcp.py index 6ab0196ad..8a597a15a 100644 --- a/libmproxy/protocol/rawtcp.py +++ b/libmproxy/protocol/rawtcp.py @@ -1,6 +1,8 @@ from __future__ import (absolute_import, print_function, division) import socket import select +import six +import sys from OpenSSL import SSL @@ -63,4 +65,8 @@ class RawTCPLayer(Layer): ) except (socket.error, NetLibError, SSL.Error) as e: - raise ProtocolException("TCP connection closed unexpectedly: {}".format(repr(e)), e) + six.reraise( + ProtocolException, + ProtocolException("TCP connection closed unexpectedly: {}".format(repr(e)), e), + sys.exc_info()[2] + ) diff --git a/libmproxy/protocol/tls.py b/libmproxy/protocol/tls.py index 2cddb1dd4..6f6c2c789 100644 --- a/libmproxy/protocol/tls.py +++ b/libmproxy/protocol/tls.py @@ -1,18 +1,19 @@ from __future__ import (absolute_import, print_function, division) import struct +import sys from construct import ConstructError import six -import sys from netlib.tcp import NetLibError, NetLibInvalidCertificateError from netlib.http.http1 import HTTP1Protocol from ..contrib.tls._constructs import ClientHello -from ..exceptions import ProtocolException, TlsException +from ..exceptions import ProtocolException, TlsException, ClientHandshakeException from .base import Layer + # taken from https://testssl.sh/openssl-rfc.mappping.html CIPHER_ID_NAME_MAP = { 0x00: 'NULL-MD5', @@ -407,8 +408,17 @@ class TlsLayer(Layer): chain_file=chain_file, alpn_select_callback=self.__alpn_select_callback, ) + # Some TLS clients will not fail the handshake, + # but will immediately throw an "unexpected eof" error on the first read. + # The reason for this might be difficult to find, so we try to peek here to see if it + # raises ann error. + self.client_conn.rfile.peek(0) except NetLibError as e: - raise TlsException("Cannot establish TLS with client: %s" % repr(e), e) + six.reraise( + ClientHandshakeException, + ClientHandshakeException("Cannot establish TLS with client: %s" % repr(e), e), + sys.exc_info()[2] + ) def _establish_tls_with_server(self): self.log("Establish TLS with server", "debug") @@ -457,17 +467,25 @@ class TlsLayer(Layer): (tls_cert_err['depth'], tls_cert_err['errno']), "error") self.log("Aborting connection attempt", "error") - raise TlsException("Cannot establish TLS with {address} (sni: {sni}): {e}".format( - address=repr(self.server_conn.address), - sni=self.sni_for_server_connection, - e=repr(e), - ), e) + six.reraise( + TlsException, + TlsException("Cannot establish TLS with {address} (sni: {sni}): {e}".format( + address=repr(self.server_conn.address), + sni=self.sni_for_server_connection, + e=repr(e), + ), e), + sys.exc_info()[2] + ) except NetLibError as e: - raise TlsException("Cannot establish TLS with {address} (sni: {sni}): {e}".format( - address=repr(self.server_conn.address), - sni=self.sni_for_server_connection, - e=repr(e), - ), e) + six.reraise( + TlsException, + TlsException("Cannot establish TLS with {address} (sni: {sni}): {e}".format( + address=repr(self.server_conn.address), + sni=self.sni_for_server_connection, + e=repr(e), + ), e), + sys.exc_info()[2] + ) self.log("ALPN selected by server: %s" % self.alpn_for_client_connection, "debug") diff --git a/libmproxy/proxy/server.py b/libmproxy/proxy/server.py index 91a12df9d..c00bb815a 100644 --- a/libmproxy/proxy/server.py +++ b/libmproxy/proxy/server.py @@ -3,6 +3,7 @@ from __future__ import (absolute_import, print_function, division) import traceback import sys import socket +import six from netlib import tcp from netlib.http.http1 import HTTP1Protocol @@ -39,7 +40,11 @@ class ProxyServer(tcp.TCPServer): try: super(ProxyServer, self).__init__((config.host, config.port)) except socket.error as e: - raise ServerException('Error starting proxy server: ' + repr(e), e) + six.reraise( + ServerException, + ServerException('Error starting proxy server: ' + repr(e), e), + sys.exc_info()[2] + ) self.channel = None def start_slave(self, klass, channel): @@ -117,6 +122,7 @@ class ConnectionHandler(object): self.log("Connection killed", "info") except ProtocolException as e: self.log(repr(e), "info") + self.log(traceback.format_exc(), "debug") # If an error propagates to the topmost level, # we send an HTTP error response, which is both # understandable by HTTP clients and humans.