improve error handling

This commit is contained in:
Maximilian Hils 2014-09-02 18:13:18 +02:00
parent 1a41c15c03
commit 1e4e332ef9
5 changed files with 77 additions and 71 deletions

View File

@ -22,7 +22,7 @@ def get_line(fp):
if line == "\r\n" or line == "\n": # Possible leftover from previous message
line = fp.readline()
if line == "":
raise tcp.NetLibDisconnect
raise tcp.NetLibDisconnect()
return line
@ -927,7 +927,7 @@ class HTTPHandler(ProtocolHandler):
body_size_limit=self.c.config.body_size_limit, include_body=include_body)
return res
except (tcp.NetLibDisconnect, http.HttpErrorConnClosed), v:
self.c.log("error in server communication: %s" % str(v), level="debug")
self.c.log("error in server communication: %s" % repr(v), level="debug")
if i < 1:
# In any case, we try to reconnect at least once.
# This is necessary because it might be possible that we already initiated an upstream connection
@ -1064,23 +1064,23 @@ class HTTPHandler(ProtocolHandler):
def handle_error(self, error, flow=None):
message = repr(error)
code = getattr(error, "code", 502)
headers = getattr(error, "headers", None)
if "tlsv1 alert unknown ca" in message:
message = message + " \nThe client does not trust the proxy's certificate."
message += " The client does not trust the proxy's certificate."
if isinstance(error, tcp.NetLibDisconnect):
self.c.log("TCP connection closed unexpectedly.", "debug", [repr(error)])
else:
self.c.log("error: %s" % message, level="info")
if flow:
flow.error = Error(message)
# FIXME: no flows without request or with both request and response at the moment.
# TODO: no flows without request or with both request and response at the moment.
if flow.request and not flow.response:
flow.error = Error(message)
self.c.channel.ask("error", flow.error)
else:
pass
try:
code = getattr(error, "code", 502)
headers = getattr(error, "headers", None)
self.send_error(code, message, headers)
except:
pass

View File

@ -16,8 +16,9 @@ class TCPHandler(ProtocolHandler):
server = "%s:%s" % self.c.server_conn.address()[:2]
buf = memoryview(bytearray(self.chunk_size))
conns = [self.c.client_conn.rfile, self.c.server_conn.rfile]
try:
while True:
r, _, _ = select.select(conns, [], [], 10)
for rfile in r:
@ -58,9 +59,12 @@ class TCPHandler(ProtocolHandler):
# if one of the peers is over SSL, we need to send bytes/strings
if not src.ssl_established: # only ssl to dst, i.e. we revc'd into buf but need bytes/string now.
contents = buf[:size].tobytes()
self.c.log("%s %s\r\n%s" % (direction, dst_str, cleanBin(contents)), "debug")
# self.c.log("%s %s\r\n%s" % (direction, dst_str, cleanBin(contents)), "debug")
dst.connection.send(contents)
else:
# socket.socket.send supports raw bytearrays/memoryviews
self.c.log("%s %s\r\n%s" % (direction, dst_str, cleanBin(buf.tobytes())), "debug")
# self.c.log("%s %s\r\n%s" % (direction, dst_str, cleanBin(buf.tobytes())), "debug")
dst.connection.send(buf[:size])
except socket.error as e:
self.c.log("TCP connection closed unexpectedly.", "debug", [repr(e)])
return

View File

@ -3,7 +3,6 @@ import copy
import os
from netlib import tcp, certutils
from .. import stateobject, utils
from .primitives import ProxyError
class ClientConnection(tcp.BaseHandler, stateobject.SimpleStateObject):
@ -156,11 +155,8 @@ class ServerConnection(tcp.TCPClient, stateobject.SimpleStateObject):
path = os.path.join(clientcerts, self.address.host.encode("idna")) + ".pem"
if os.path.exists(path):
clientcert = path
try:
self.convert_to_ssl(cert=clientcert, sni=sni)
self.timestamp_ssl_setup = utils.timestamp()
except tcp.NetLibError, v:
raise ProxyError(400, repr(v))
def finish(self):
tcp.TCPClient.finish(self)

View File

@ -95,7 +95,7 @@ class ConnectionHandler:
# Delegate handling to the protocol handler
protocol_handler(self.conntype)(self).handle_messages()
except (ProxyError, tcp.NetLibError), e:
except ProxyError as e:
protocol_handler(self.conntype)(self).handle_error(e)
except Exception:
import traceback, sys
@ -190,11 +190,15 @@ class ConnectionHandler:
raise ProxyError(502, "No server connection.")
if self.server_conn.ssl_established:
raise ProxyError(502, "SSL to Server already established.")
try:
self.server_conn.establish_ssl(self.config.clientcerts, self.sni)
except tcp.NetLibError as v:
raise ProxyError(502, repr(v))
if client:
if self.client_conn.ssl_established:
raise ProxyError(502, "SSL to Client already established.")
cert, key = self.find_cert()
try:
self.client_conn.convert_to_ssl(
cert, key,
handle_sni=self.handle_sni,
@ -202,6 +206,8 @@ class ConnectionHandler:
dhparams=self.config.certstore.dhparams,
ca_file=self.config.ca_file
)
except tcp.NetLibError as v:
raise ProxyError(400, repr(v))
def server_reconnect(self):
address = self.server_conn.address

View File

@ -179,7 +179,7 @@ class TestHTTPConnectSSLError(tservers.HTTPProxTest):
p = self.pathoc_raw()
dst = ("localhost", self.proxy.port)
p.connect(connect_to=dst)
tutils.raises("400 - Bad Request", p.http_connect, dst)
tutils.raises("502 - Bad Gateway", p.http_connect, dst)
class TestHTTPS(tservers.HTTPProxTest, CommonMixin):
@ -244,7 +244,7 @@ class TestTransparentSSL(tservers.TransparentProxTest, CommonMixin):
p = pathoc.Pathoc(("localhost", self.proxy.port))
p.connect()
r = p.request("get:/")
assert r.status_code == 502
assert r.status_code == 400
class TestProxy(tservers.HTTPProxTest):