Test SNI for ordinary proxy connections.

This commit is contained in:
Aldo Cortesi 2013-03-02 14:52:05 +13:00
parent ba674ad551
commit 10db82e9a0
3 changed files with 26 additions and 15 deletions

View File

@ -126,7 +126,7 @@ class HandleSNI:
self.handler.sni = sn.decode("utf8").encode("idna") self.handler.sni = sn.decode("utf8").encode("idna")
# An unhandled exception in this method will core dump PyOpenSSL, so # An unhandled exception in this method will core dump PyOpenSSL, so
# make dang sure it doesn't happen. # make dang sure it doesn't happen.
except Exception, e: except Exception, e: # pragma: no cover
pass pass
@ -141,6 +141,8 @@ class ProxyHandler(tcp.BaseHandler):
def get_server_connection(self, cc, scheme, host, port, sni): def get_server_connection(self, cc, scheme, host, port, sni):
sc = self.server_conn sc = self.server_conn
if not sni:
sni = host
if sc and (scheme, host, port, sni) != (sc.scheme, sc.host, sc.port, sc.sni): if sc and (scheme, host, port, sni) != (sc.scheme, sc.host, sc.port, sc.sni):
sc.terminate() sc.terminate()
self.server_conn = None self.server_conn = None
@ -214,7 +216,7 @@ class ProxyHandler(tcp.BaseHandler):
# the case, we want to reconnect without sending an error # the case, we want to reconnect without sending an error
# to the client. # to the client.
while 1: while 1:
sc = self.get_server_connection(cc, scheme, host, port, host) sc = self.get_server_connection(cc, scheme, host, port, self.sni)
sc.send(request) sc.send(request)
sc.rfile.reset_timestamps() sc.rfile.reset_timestamps()
try: try:
@ -362,14 +364,13 @@ class ProxyHandler(tcp.BaseHandler):
'\r\n' '\r\n'
) )
self.wfile.flush() self.wfile.flush()
certfile = self.find_cert(client_conn, host, port, host) dummycert = self.find_cert(client_conn, host, port, host)
sni = HandleSNI(
self, client_conn, host, port,
dummycert, self.config.certfile or self.config.cacert
)
try: try:
self.convert_to_ssl(certfile, self.config.certfile or self.config.cacert, handle_sni=sni) sni = HandleSNI(
self, client_conn, host, port,
dummycert, self.config.certfile or self.config.cacert
)
self.convert_to_ssl(dummycert, self.config.certfile or self.config.cacert, handle_sni=sni)
except tcp.NetLibError, v: except tcp.NetLibError, v:
raise ProxyError(400, str(v)) raise ProxyError(400, str(v))
self.proxy_connect_state = (host, port, httpversion) self.proxy_connect_state = (host, port, httpversion)

View File

@ -131,10 +131,14 @@ class TestHTTPS(tservers.HTTPProxTest, CommonMixin):
clientcerts = True clientcerts = True
def test_clientcert(self): def test_clientcert(self):
f = self.pathod("304") f = self.pathod("304")
assert f.status_code == 304
assert self.server.last_log()["request"]["clientcert"]["keyinfo"] assert self.server.last_log()["request"]["clientcert"]["keyinfo"]
def test_sni(self): def test_sni(self):
pass f = self.pathod("304", sni="testserver.com")
assert f.status_code == 304
l = self.server.last_log()
assert self.server.last_log()["request"]["sni"] == "testserver.com"
class TestHTTPSCertfile(tservers.HTTPProxTest, CommonMixin): class TestHTTPSCertfile(tservers.HTTPProxTest, CommonMixin):

View File

@ -28,7 +28,7 @@ class TestMaster(flow.FlowMaster):
state = flow.State() state = flow.State()
flow.FlowMaster.__init__(self, s, state) flow.FlowMaster.__init__(self, s, state)
self.testq = testq self.testq = testq
self.log = [] self.clear_log()
def handle_request(self, m): def handle_request(self, m):
flow.FlowMaster.handle_request(self, m) flow.FlowMaster.handle_request(self, m)
@ -38,6 +38,9 @@ class TestMaster(flow.FlowMaster):
flow.FlowMaster.handle_response(self, m) flow.FlowMaster.handle_response(self, m)
m.reply() m.reply()
def clear_log(self):
self.log = []
def handle_log(self, l): def handle_log(self, l):
self.log.append(l.msg) self.log.append(l.msg)
l.reply() l.reply()
@ -96,7 +99,10 @@ class ProxTestBase:
cls.server2.shutdown() cls.server2.shutdown()
def setUp(self): def setUp(self):
self.master.clear_log()
self.master.state.clear() self.master.state.clear()
self.server.clear_log()
self.server2.clear_log()
@property @property
def scheme(self): def scheme(self):
@ -122,20 +128,20 @@ class ProxTestBase:
class HTTPProxTest(ProxTestBase): class HTTPProxTest(ProxTestBase):
def pathoc(self, connect_to = None): def pathoc(self, connect_to = None, sni=None):
""" """
Returns a connected Pathoc instance. Returns a connected Pathoc instance.
""" """
p = libpathod.pathoc.Pathoc("localhost", self.proxy.port, ssl=self.ssl) p = libpathod.pathoc.Pathoc("localhost", self.proxy.port, ssl=self.ssl, sni=sni)
p.connect(connect_to) p.connect(connect_to)
return p return p
def pathod(self, spec): def pathod(self, spec, sni=None):
""" """
Constructs a pathod GET request, with the appropriate base and proxy. Constructs a pathod GET request, with the appropriate base and proxy.
""" """
if self.ssl: if self.ssl:
p = self.pathoc(("127.0.0.1", self.server.port)) p = self.pathoc(("127.0.0.1", self.server.port), sni=sni)
q = "get:'/p/%s'"%spec q = "get:'/p/%s'"%spec
else: else:
p = self.pathoc() p = self.pathoc()