|
@@ -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) |
|
|