From 5b65dc8ec3a06d95242790877b543979451cef07 Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Tue, 14 Jun 2022 05:15:39 -0700 Subject: [PATCH] support setting a few useful parameters... wrap a few long lines... --- ntunnel/quic.py | 76 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 16 deletions(-) diff --git a/ntunnel/quic.py b/ntunnel/quic.py index 9aef80e..fe040dd 100644 --- a/ntunnel/quic.py +++ b/ntunnel/quic.py @@ -30,9 +30,13 @@ import subprocess import tempfile import unittest +from functools import wraps + from . import parsesockstr, connectsockstr, listensockstr from . import async_test, _awaitfile +import aioquic + from aioquic.asyncio import QuicConnectionProtocol, serve from aioquic.asyncio.client import connect 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)) -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 cert = args.cert @@ -67,6 +94,7 @@ def cmd_quic_serv(args): alpn_protocols=["ntunnel-01"], is_client=False, quic_logger=quic_logger, + **confkwargs, ) quic_conf.load_cert_chain(cert, privkey) @@ -82,8 +110,6 @@ def cmd_quic_serv(args): # XXX - await task - print('foo', repr(slargs)) - loop = asyncio.get_event_loop() loop.run_until_complete(serve(slargs['host'], slargs['port'], 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') # 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): 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? await ssock.serve_forever() -def cmd_quic_client(args): +@common_args_proc +def cmd_quic_client(args, confkwargs): quic_logger = None quic_conf = QuicConfiguration( alpn_protocols=["ntunnel-01"], is_client=True, quic_logger=quic_logger, + **confkwargs, ) if args.ca_certs: @@ -133,21 +161,29 @@ def cmd_quic_client(args): 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, help="load the TLS private key from the specified file") parser_quic_serv.add_argument("-c", "--cert", type=str, required=True, 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_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, 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) class Tests(unittest.IsolatedAsyncioTestCase): @@ -202,12 +238,20 @@ subjectAltName=DNS:localhost,server.example.com return # 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 - 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 await _awaitfile(unixservsock)