|
|
@@ -23,9 +23,15 @@ |
|
|
|
# |
|
|
|
|
|
|
|
import asyncio |
|
|
|
import os |
|
|
|
import random |
|
|
|
import shutil |
|
|
|
import subprocess |
|
|
|
import tempfile |
|
|
|
import unittest |
|
|
|
|
|
|
|
from . import parsesockstr, connectsockstr, listensockstr |
|
|
|
from . import async_test, _awaitfile |
|
|
|
|
|
|
|
from aioquic.asyncio import QuicConnectionProtocol, serve |
|
|
|
from aioquic.asyncio.client import connect |
|
|
@@ -37,16 +43,14 @@ async def fwd_data(reader, writer): |
|
|
|
data = await reader.read(16384) |
|
|
|
if data == b'': |
|
|
|
#_debprint('fwd_data eof', repr(reader), repr(writer)) |
|
|
|
# XXX - aioquic doesn't implement close |
|
|
|
#writer.close() |
|
|
|
#await writer.wait_closed() |
|
|
|
writer.close() |
|
|
|
await writer.wait_closed() |
|
|
|
#_debprint('fwd_data done', repr(reader), repr(writer)) |
|
|
|
return |
|
|
|
|
|
|
|
#_debprint('fwd_data data', repr(reader), repr(writer), len(data)) |
|
|
|
writer.write(data) |
|
|
|
# XXX - aioquic doesn't implement is_closing |
|
|
|
#await writer.drain() |
|
|
|
await writer.drain() |
|
|
|
|
|
|
|
async def run_connect(dst, rdr, wrr): |
|
|
|
connrdr, connwrr = await connectsockstr(dst) |
|
|
@@ -147,4 +151,99 @@ def quic_parsers(subparsers): |
|
|
|
parser_quic_client.set_defaults(func=cmd_quic_client) |
|
|
|
|
|
|
|
class Tests(unittest.IsolatedAsyncioTestCase): |
|
|
|
pass |
|
|
|
def setUp(self): |
|
|
|
# setup temporary directory |
|
|
|
d = os.path.realpath(tempfile.mkdtemp()) |
|
|
|
self.basetempdir = d |
|
|
|
self.tempdir = os.path.join(d, 'subdir') |
|
|
|
os.mkdir(self.tempdir) |
|
|
|
|
|
|
|
# Generate key |
|
|
|
self.privkey = os.path.join(self.tempdir, 'example.key') |
|
|
|
self.cert = os.path.join(self.tempdir, 'example.crt') |
|
|
|
conf = ''' |
|
|
|
[req] |
|
|
|
distinguished_name=req |
|
|
|
[san] |
|
|
|
subjectAltName=DNS:localhost,server.example.com |
|
|
|
'''.encode('utf-8') |
|
|
|
k = subprocess.run(['openssl', 'req', '-x509', |
|
|
|
'-newkey', 'rsa:4096', '-sha256', '-days', '3560', |
|
|
|
'-nodes', '-keyout', self.privkey, '-out', self.cert, |
|
|
|
'-subj', '/CN=ntunnel example cert', |
|
|
|
'-config', '/dev/stdin'], input=conf, |
|
|
|
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) |
|
|
|
|
|
|
|
self.assertEqual(k.returncode, 0) |
|
|
|
|
|
|
|
self.assertTrue(os.path.exists(self.privkey)) |
|
|
|
self.assertTrue(os.path.exists(self.cert)) |
|
|
|
|
|
|
|
def tearDown(self): |
|
|
|
shutil.rmtree(self.basetempdir) |
|
|
|
self.tempdir = None |
|
|
|
|
|
|
|
@async_test |
|
|
|
async def test_e2e(self): |
|
|
|
unixservsock = os.path.join(self.tempdir, 'unix.serv.sock') |
|
|
|
unixclientsock = os.path.join(self.tempdir, 'unix.client.sock') |
|
|
|
|
|
|
|
port = random.randint(2000, 65000) |
|
|
|
|
|
|
|
async def echofun(rdr, wrr): |
|
|
|
while True: |
|
|
|
d = await rdr.read(16384) |
|
|
|
if d: |
|
|
|
wrr.write(d) |
|
|
|
await wrr.drain() |
|
|
|
else: |
|
|
|
wrr.close() |
|
|
|
await wrr.wait_closed() |
|
|
|
return |
|
|
|
|
|
|
|
# start the destination server |
|
|
|
servsock = await asyncio.start_unix_server(echofun, path=unixservsock) |
|
|
|
|
|
|
|
# start up ntunnel quic processes |
|
|
|
serv = await asyncio.create_subprocess_exec('ntunnel', 'quic_serv', '-k', self.privkey, '-c', self.cert, 'udp:127.0.0.1:%d' % port, 'unix:' + unixservsock) |
|
|
|
|
|
|
|
client = await asyncio.create_subprocess_exec('ntunnel', 'quic_client', '--ca-certs', self.cert, 'unix:' + unixclientsock, 'udp:127.0.0.1:%d' % port) |
|
|
|
|
|
|
|
# make sure everything has started |
|
|
|
await _awaitfile(unixservsock) |
|
|
|
await _awaitfile(unixclientsock) |
|
|
|
|
|
|
|
# run tests |
|
|
|
rdr, wrr = await asyncio.open_unix_connection(unixclientsock) |
|
|
|
|
|
|
|
data = [ b'asldkfj', b'asldkjfasdklj', b'asdlfkjadsf' ] |
|
|
|
|
|
|
|
for i in data: |
|
|
|
wrr.write(i) |
|
|
|
await wrr.drain() |
|
|
|
|
|
|
|
d = await rdr.read(16384) |
|
|
|
|
|
|
|
self.assertEqual(d, i) |
|
|
|
|
|
|
|
# make sure close hasn't happened yet |
|
|
|
self.assertFalse(rdr.at_eof()) |
|
|
|
|
|
|
|
# close the writer |
|
|
|
wrr.write_eof() |
|
|
|
wrr.close() |
|
|
|
await wrr.wait_closed() |
|
|
|
|
|
|
|
# make sure the reader sees that the client closed |
|
|
|
self.assertFalse(await rdr.read()) |
|
|
|
|
|
|
|
# Done terminate daemons |
|
|
|
serv.terminate() |
|
|
|
client.terminate() |
|
|
|
|
|
|
|
await serv.wait() |
|
|
|
await client.wait() |
|
|
|
|
|
|
|
# termiante unix server |
|
|
|
servsock.close() |
|
|
|
await servsock.wait_closed() |