| @@ -30,9 +30,13 @@ import subprocess | |||||
| import tempfile | import tempfile | ||||
| import unittest | import unittest | ||||
| from functools import wraps | |||||
| from . import parsesockstr, connectsockstr, listensockstr | from . import parsesockstr, connectsockstr, listensockstr | ||||
| from . import async_test, _awaitfile | from . import async_test, _awaitfile | ||||
| import aioquic | |||||
| from aioquic.asyncio import QuicConnectionProtocol, serve | from aioquic.asyncio import QuicConnectionProtocol, serve | ||||
| from aioquic.asyncio.client import connect | from aioquic.asyncio.client import connect | ||||
| from aioquic.quic.configuration import QuicConfiguration | from aioquic.quic.configuration import QuicConfiguration | ||||
| @@ -57,7 +61,30 @@ async def run_connect(dst, rdr, wrr): | |||||
| await asyncio.gather(fwd_data(connrdr, wrr), fwd_data(rdr, connwrr)) | await asyncio.gather(fwd_data(connrdr, wrr), fwd_data(rdr, connwrr)) | ||||
| def cmd_quic_serv(args): | |||||
| def common_args(parser): | |||||
| parser.add_argument('-i', '--initial-window', type=int, | |||||
| default=2*1024*1024, help='initial window in bytes (default 2MB)') | |||||
| parser.add_argument('-l', '--loss-reduction', type=float, | |||||
| default=.95, | |||||
| help='factor to reduce the window when loss is detected (default .95)') | |||||
| parser.add_argument('-t', '--timeout', type=float, default=120.0, | |||||
| help='if no packets are received after timeout seconds, connection will terminate') | |||||
| def common_args_proc(fun): | |||||
| @wraps(fun) | |||||
| def wrapper(args): | |||||
| aioquic.quic.recovery.K_INITIAL_WINDOW = args.initial_window | |||||
| aioquic.quic.recovery.K_LOSS_REDUCTION_FACTOR = \ | |||||
| args.loss_reduction | |||||
| confkwargs = dict(idle_timeout=args.timeout) | |||||
| return fun(args, confkwargs) | |||||
| return wrapper | |||||
| @common_args_proc | |||||
| def cmd_quic_serv(args, confkwargs): | |||||
| privkey = args.servkey | privkey = args.servkey | ||||
| cert = args.cert | cert = args.cert | ||||
| @@ -67,6 +94,7 @@ def cmd_quic_serv(args): | |||||
| alpn_protocols=["ntunnel-01"], | alpn_protocols=["ntunnel-01"], | ||||
| is_client=False, | is_client=False, | ||||
| quic_logger=quic_logger, | quic_logger=quic_logger, | ||||
| **confkwargs, | |||||
| ) | ) | ||||
| quic_conf.load_cert_chain(cert, privkey) | quic_conf.load_cert_chain(cert, privkey) | ||||
| @@ -82,8 +110,6 @@ def cmd_quic_serv(args): | |||||
| # XXX - await task | # XXX - await task | ||||
| print('foo', repr(slargs)) | |||||
| loop = asyncio.get_event_loop() | loop = asyncio.get_event_loop() | ||||
| loop.run_until_complete(serve(slargs['host'], slargs['port'], | loop.run_until_complete(serve(slargs['host'], slargs['port'], | ||||
| configuration=quic_conf, retry=True, stream_handler=sh)) | configuration=quic_conf, retry=True, stream_handler=sh)) | ||||
| @@ -100,8 +126,8 @@ async def client_run(conf, liststr, deststr): | |||||
| raise ValueError('protocol for destination must be udp') | raise ValueError('protocol for destination must be udp') | ||||
| # XXX - loop when server restarts? | # XXX - loop when server restarts? | ||||
| async with connect(slargs['host'], slargs['port'], configuration=conf) as \ | |||||
| client: | |||||
| async with connect(slargs['host'], slargs['port'], | |||||
| configuration=conf) as client: | |||||
| async def connmaker(rdr, wrr): | async def connmaker(rdr, wrr): | ||||
| connrdr, connwrr = await client.create_stream() | connrdr, connwrr = await client.create_stream() | ||||
| @@ -113,13 +139,15 @@ async def client_run(conf, liststr, deststr): | |||||
| # XXX - how to break out when new connection needed? | # XXX - how to break out when new connection needed? | ||||
| await ssock.serve_forever() | await ssock.serve_forever() | ||||
| def cmd_quic_client(args): | |||||
| @common_args_proc | |||||
| def cmd_quic_client(args, confkwargs): | |||||
| quic_logger = None | quic_logger = None | ||||
| quic_conf = QuicConfiguration( | quic_conf = QuicConfiguration( | ||||
| alpn_protocols=["ntunnel-01"], | alpn_protocols=["ntunnel-01"], | ||||
| is_client=True, | is_client=True, | ||||
| quic_logger=quic_logger, | quic_logger=quic_logger, | ||||
| **confkwargs, | |||||
| ) | ) | ||||
| if args.ca_certs: | if args.ca_certs: | ||||
| @@ -133,21 +161,29 @@ def cmd_quic_client(args): | |||||
| def quic_parsers(subparsers): | def quic_parsers(subparsers): | ||||
| parser_quic_serv = subparsers.add_parser('quic_serv', help='run a QUIC server') | |||||
| parser_quic_serv = subparsers.add_parser('quic_serv', | |||||
| help='run a QUIC server') | |||||
| parser_quic_serv.add_argument("-k", "--servkey", type=str, | parser_quic_serv.add_argument("-k", "--servkey", type=str, | ||||
| help="load the TLS private key from the specified file") | help="load the TLS private key from the specified file") | ||||
| parser_quic_serv.add_argument("-c", "--cert", type=str, | parser_quic_serv.add_argument("-c", "--cert", type=str, | ||||
| required=True, | required=True, | ||||
| help="load the TLS certificate from the specified file") | help="load the TLS certificate from the specified file") | ||||
| parser_quic_serv.add_argument('servlisten', type=str, help='Connection that the server listens on') | |||||
| parser_quic_serv.add_argument('servtarget', type=str, help='Connection that the server connects to') | |||||
| parser_quic_serv.add_argument('servlisten', type=str, | |||||
| help='Connection that the server listens on') | |||||
| parser_quic_serv.add_argument('servtarget', type=str, | |||||
| help='Connection that the server connects to') | |||||
| common_args(parser_quic_serv) | |||||
| parser_quic_serv.set_defaults(func=cmd_quic_serv) | parser_quic_serv.set_defaults(func=cmd_quic_serv) | ||||
| parser_quic_client = subparsers.add_parser('quic_client', help='run a QUIC client') | |||||
| parser_quic_client = subparsers.add_parser('quic_client', | |||||
| help='run a QUIC client') | |||||
| parser_quic_client.add_argument("--ca-certs", type=str, | parser_quic_client.add_argument("--ca-certs", type=str, | ||||
| help="load CA certificates from the specified file") | help="load CA certificates from the specified file") | ||||
| parser_quic_client.add_argument('clientlisten', type=str, help='Connection that the client listens on') | |||||
| parser_quic_client.add_argument('clienttarget', type=str, help='Connection that the client connects to') | |||||
| parser_quic_client.add_argument('clientlisten', type=str, | |||||
| help='Connection that the client listens on') | |||||
| parser_quic_client.add_argument('clienttarget', type=str, | |||||
| help='Connection that the client connects to') | |||||
| common_args(parser_quic_client) | |||||
| parser_quic_client.set_defaults(func=cmd_quic_client) | parser_quic_client.set_defaults(func=cmd_quic_client) | ||||
| class Tests(unittest.IsolatedAsyncioTestCase): | class Tests(unittest.IsolatedAsyncioTestCase): | ||||
| @@ -202,12 +238,20 @@ subjectAltName=DNS:localhost,server.example.com | |||||
| return | return | ||||
| # start the destination server | # start the destination server | ||||
| servsock = await asyncio.start_unix_server(echofun, path=unixservsock) | |||||
| servsock = await asyncio.start_unix_server(echofun, | |||||
| path=unixservsock) | |||||
| # start up ntunnel quic processes | # 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) | |||||
| serv = await asyncio.create_subprocess_exec('ntunnel', | |||||
| 'quic_serv', | |||||
| '-i', '1024', '-l', '.9', '-t', '15', | |||||
| '-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 | # make sure everything has started | ||||
| await _awaitfile(unixservsock) | await _awaitfile(unixservsock) | ||||