add QUIC transport based on bi streams

This commit is contained in:
Emil Sauer Lynge 2022-01-08 22:42:39 +01:00
parent 1fe3509536
commit 3a280b0ac0
21 changed files with 902 additions and 23 deletions

308
Cargo.lock generated
View File

@ -180,6 +180,28 @@ dependencies = [
"generic-array",
]
[[package]]
name = "block-modes"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e"
dependencies = [
"block-padding",
"cipher",
]
[[package]]
name = "block-padding"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
[[package]]
name = "bumpalo"
version = "3.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
[[package]]
name = "byteorder"
version = "1.4.3"
@ -437,6 +459,17 @@ dependencies = [
"zeroize",
]
[[package]]
name = "des"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac41dd49fb554432020d52c875fc290e110113f864c6b1b525cd62c7e7747a5d"
dependencies = [
"byteorder",
"cipher",
"opaque-debug",
]
[[package]]
name = "digest"
version = "0.9.0"
@ -455,6 +488,7 @@ dependencies = [
"block-buffer 0.10.0",
"crypto-common",
"generic-array",
"subtle",
]
[[package]]
@ -637,14 +671,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
dependencies = [
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
name = "fxhash"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
dependencies = [
"byteorder",
]
[[package]]
name = "generic-array"
version = "0.14.5"
@ -780,6 +825,15 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hmac"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddca131f3e7f2ce2df364b57949a9d47915cfbd35e46cfee355ccebbf794d6a2"
dependencies = [
"digest 0.10.1",
]
[[package]]
name = "http"
version = "0.2.6"
@ -936,6 +990,15 @@ dependencies = [
"libc",
]
[[package]]
name = "js-sys"
version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "kqueue"
version = "1.0.4"
@ -1214,6 +1277,22 @@ dependencies = [
"memchr",
]
[[package]]
name = "p12"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55a97f513ac60e90aec6d9db783b1924a25839a2635036a3ab64f2ca78cd4518"
dependencies = [
"block-modes",
"des",
"getrandom 0.2.4",
"hmac",
"lazy_static",
"rc2",
"sha-1",
"yasna",
]
[[package]]
name = "parking_lot"
version = "0.11.2"
@ -1417,6 +1496,60 @@ dependencies = [
"prost",
]
[[package]]
name = "quinn"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61a84d97630b137463c8e6802adc1dfe9de81457b41bb1ac59189e6761ab9255"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"fxhash",
"quinn-proto",
"quinn-udp",
"rustls",
"thiserror",
"tokio",
"tracing",
"webpki",
]
[[package]]
name = "quinn-proto"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "063dedf7983c8d57db474218f258daa85b627de6f2dbc458b690a93b1de790e8"
dependencies = [
"bytes",
"fxhash",
"rand",
"ring",
"rustls",
"rustls-native-certs",
"rustls-pemfile",
"slab",
"thiserror",
"tinyvec",
"tracing",
"webpki",
]
[[package]]
name = "quinn-udp"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f7996776e9ee3fc0e5c14476c1a640a17e993c847ae9c81191c2c102fbef903"
dependencies = [
"futures-util",
"libc",
"mio",
"quinn-proto",
"socket2",
"tokio",
"tracing",
]
[[package]]
name = "quote"
version = "1.0.14"
@ -1490,10 +1623,15 @@ dependencies = [
"console-subscriber",
"const_format",
"fdlimit",
"futures-util",
"hex",
"lazy_static",
"notify",
"p12",
"quinn",
"rand",
"rustls",
"rustls-pemfile",
"serde",
"sha2 0.10.1",
"snowstorm",
@ -1506,6 +1644,16 @@ dependencies = [
"vergen",
]
[[package]]
name = "rc2"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48f197c283075d1345c20d5ad172526a7837882cdc998b1fcd2b2f3cfff1cb94"
dependencies = [
"cipher",
"opaque-debug",
]
[[package]]
name = "redox_syscall"
version = "0.2.10"
@ -1550,6 +1698,21 @@ dependencies = [
"winapi",
]
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "rustc_version"
version = "0.3.3"
@ -1559,6 +1722,38 @@ dependencies = [
"semver",
]
[[package]]
name = "rustls"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84"
dependencies = [
"ring",
"sct",
"webpki",
]
[[package]]
name = "rustls-native-certs"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943"
dependencies = [
"openssl-probe",
"rustls-pemfile",
"schannel",
"security-framework",
]
[[package]]
name = "rustls-pemfile"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9"
dependencies = [
"base64",
]
[[package]]
name = "rustversion"
version = "1.0.6"
@ -1596,6 +1791,16 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "sct"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "security-framework"
version = "2.4.2"
@ -1668,6 +1873,17 @@ dependencies = [
"serde",
]
[[package]]
name = "sha-1"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
dependencies = [
"cfg-if",
"cpufeatures",
"digest 0.10.1",
]
[[package]]
name = "sha2"
version = "0.9.9"
@ -1763,6 +1979,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "strsim"
version = "0.10.0"
@ -2195,6 +2417,12 @@ dependencies = [
"subtle",
]
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "url"
version = "2.2.2"
@ -2268,6 +2496,80 @@ version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm-bindgen"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
[[package]]
name = "web-sys"
version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "webpki"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "which"
version = "4.2.2"
@ -2321,6 +2623,12 @@ dependencies = [
"zeroize",
]
[[package]]
name = "yasna"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e262a29d0e61ccf2b6190d7050d4b237535fc76ce4c1210d9caa316f71dffa75"
[[package]]
name = "zeroize"
version = "1.3.0"

View File

@ -11,7 +11,7 @@ build = "build.rs"
include = ["src/**/*", "LICENSE", "README.md", "build.rs"]
[features]
default = ["server", "client", "tls", "noise", "hot-reload"]
default = ["server", "client", "tls", "noise", "quic", "hot-reload"]
# Run as a server
server = []
@ -21,6 +21,9 @@ client = []
tls = ["tokio-native-tls"]
# Noise support
noise = ["snowstorm", "base64"]
#QUIC support
quic = ["quinn", "rustls", "rustls-pemfile", "p12", "futures-util"]
# Configuration hot-reload support
hot-reload = ["notify"]
@ -70,6 +73,11 @@ notify = { version = "5.0.0-pre.13", optional = true }
console-subscriber = { version = "0.1", optional = true, features = ["parking_lot"] }
const_format = "0.2"
atty = "0.2"
quinn = { version = "0.8.0", optional = true}
rustls = { version = "*", default-features = false, features = ["quic"], optional = true }
rustls-pemfile = { version = "*", optional = true }
p12 = { version = "0.4.0", optional = true }
futures-util = { version = "*", optional = true}
[build-dependencies]
vergen = { version = "6.0", default-features = false, features = ["build", "git", "cargo"] }

BIN
examples/quic/ca.pfx Normal file

Binary file not shown.

12
examples/quic/client.toml Normal file
View File

@ -0,0 +1,12 @@
[client]
remote_addr = "localhost:2333"
default_token = "123"
[client.transport]
type = "quic"
[client.transport.quic]
trusted_root = "example/quic/test_ca.pem"
hostname = "testserver"
[client.services.foo1]
local_addr = "127.0.0.1:80"

12
examples/quic/server.toml Normal file
View File

@ -0,0 +1,12 @@
[server]
bind_addr = "0.0.0.0:2333"
default_token = "123"
[server.transport]
type = "quic"
[server.transport.quic]
pkcs12 = "example/quic/test_server.pfx"
pkcs12_password = "1234"
[server.services.foo1]
bind_addr = "0.0.0.0:5202"

19
examples/quic/test_ca.pem Normal file
View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDBzCCAe+gAwIBAgIEYdn6bDANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdU
ZXN0IENBMCAXDTIyMDEwODIwNTYxMloYDzIxMjEwMTA4MjA1NjEyWjASMRAwDgYD
VQQDDAdUZXN0IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0T5h
iSVIVmbsX062PgWb4cQC2sOeB7YXHoYPh41upB5DozRIBpZ87GFFvtS5PrYbf1E7
9n7iVhay0Sh/xSH84pZi+Akh8RvfU2JIJAqPce/tdA+pLo6k1l9XuZyM0Bc5DVu/
9r7wkD1tVgvgar5RV0yYovZAJk7C2IE3owRRog/0VOJPRSLNJoUl/1C2KUznrtlD
ojTBE8UDY3uHC7t9A226EJiH9cwf8iUhGqzDmi1FinPptPFg3UA7YkNYPt2zozoW
neFasEDHwhOo9eYjPUbS5hjaH2COxFiISmSiq7lxBxrIUq+dchkI5VzwCycla55d
lJonUPadS/AtIvIVvQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
/wQEAwIBBjAfBgNVHSMEGDAWgBTURLbYs6qjLPcJ7CaOa/0xhIcm5jAdBgNVHQ4E
FgQU1ES22LOqoyz3Cewmjmv9MYSHJuYwDQYJKoZIhvcNAQELBQADggEBAEvzt38H
Z3e6qJyKh4XdADxQCdpeykDAmAGEGWpDmNK5cqAI7XSyZ2X7NDrkLCWyf2S+GpCH
QU8y1dQm5zZ4FdvsoCbcH9RCBXn6xPsQS3VIdCWAMKcJQoRkZDXUSCGyC6tY/VK0
j+1KIcBpAM2ZjlmG9r5Te4o1M0WAyXiYGuXv3uZ1QOfATa71UKxEO4HmIYg199jy
W0/JNKBUStCK6m2em41Y/X6G2e6ZJVyB4ma0qMaNJp3IAjgiG+luvmK6AsNzoy3s
J5drYWrErtQSWOx9sK84v9yBzZ9psgF6Wm7NbGVcRjBmanYrXLNmwwgKRGFWMyg8
rwvAd2jZnsmpVLQ=
-----END CERTIFICATE-----

View File

@ -0,0 +1,45 @@
Bag Attributes
friendlyName: test server
localKeyID: 54 69 6D 65 20 31 36 34 31 36 37 35 35 33 37 38 34 32
subject=CN = Test Server
issuer=CN = Test CA
-----BEGIN CERTIFICATE-----
MIIDJDCCAgygAwIBAgIEYdn6xzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdU
ZXN0IENBMB4XDTIyMDEwODIwNTc0M1oXDTIzMDEwODIwNTc0M1owFjEUMBIGA1UE
AwwLVGVzdCBTZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCf
tkfv9IKlVLbYiOF94n4bFM1xvoreB4ReNnvVH7qpsYMpsYopVUScwYmEqZLDsmR7
DLIxc3PDqtNGWdrAzyOcLRC9ejw8hDddhN8XyCFRGJ3e3hmOSbuFXm6G/gHpB9xA
AehMHWmYYoAgHkIf0Hf3qsnLTy23E7P809oZ6hQGCQlpHWqLol6hMO0esAnYDXZQ
Y92PZ8qH4C5r8a40l0uex1nQB2wygEq7mEx2gscNkwg38H7cuHDBlDWWZ2j4/Tiz
kpNhKMaNvrAtflMnXbRGS3Nc7iX2pdiSl9w+AYVLueM3Ctuhu1CXkyhHPbpYzrW4
hOhDGs5v91PT7EPgeWYNAgMBAAGjfjB8MA4GA1UdDwEB/wQEAwIFoDAVBgNVHREE
DjAMggp0ZXN0c2VydmVyMB8GA1UdIwQYMBaAFNREttizqqMs9wnsJo5r/TGEhybm
MB0GA1UdDgQWBBQTaoQi9csuSm8KXvog5xSRgGl7yzATBgNVHSUEDDAKBggrBgEF
BQcDATANBgkqhkiG9w0BAQsFAAOCAQEARUb1HYkv3Ned+a8jk0ULcQsnurxCVsvn
DQQASs72vmrV1wAd+B/VgjzTAc95EMvLdbhtDhx0OsYh3955eyRvFIBJ2ZdoL69m
gpR9flXL4V/zd93RyNak7D2/zIP5zFiVGWlpht+WfMKuPEyRd3vwNxHAAG4B6TRp
hTpxTmhPtsQHGn6/SlN8QpCXI579cX7/yCUMK5pXR+A/crkI4UWE0YX/U8KqWXiD
y2pKQ139uMBArRSfo3Z8RD6zxqsCvGQcBKGwb7bwBXJwgTGJAHXte2QnFkoJ02H9
peeYI5MqAw4+iddzcyyxna2jLqJsFUhgnam4iwA60fxtV95rcKCsMQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDBzCCAe+gAwIBAgIEYdn6bDANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdU
ZXN0IENBMCAXDTIyMDEwODIwNTYxMloYDzIxMjEwMTA4MjA1NjEyWjASMRAwDgYD
VQQDDAdUZXN0IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0T5h
iSVIVmbsX062PgWb4cQC2sOeB7YXHoYPh41upB5DozRIBpZ87GFFvtS5PrYbf1E7
9n7iVhay0Sh/xSH84pZi+Akh8RvfU2JIJAqPce/tdA+pLo6k1l9XuZyM0Bc5DVu/
9r7wkD1tVgvgar5RV0yYovZAJk7C2IE3owRRog/0VOJPRSLNJoUl/1C2KUznrtlD
ojTBE8UDY3uHC7t9A226EJiH9cwf8iUhGqzDmi1FinPptPFg3UA7YkNYPt2zozoW
neFasEDHwhOo9eYjPUbS5hjaH2COxFiISmSiq7lxBxrIUq+dchkI5VzwCycla55d
lJonUPadS/AtIvIVvQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
/wQEAwIBBjAfBgNVHSMEGDAWgBTURLbYs6qjLPcJ7CaOa/0xhIcm5jAdBgNVHQ4E
FgQU1ES22LOqoyz3Cewmjmv9MYSHJuYwDQYJKoZIhvcNAQELBQADggEBAEvzt38H
Z3e6qJyKh4XdADxQCdpeykDAmAGEGWpDmNK5cqAI7XSyZ2X7NDrkLCWyf2S+GpCH
QU8y1dQm5zZ4FdvsoCbcH9RCBXn6xPsQS3VIdCWAMKcJQoRkZDXUSCGyC6tY/VK0
j+1KIcBpAM2ZjlmG9r5Te4o1M0WAyXiYGuXv3uZ1QOfATa71UKxEO4HmIYg199jy
W0/JNKBUStCK6m2em41Y/X6G2e6ZJVyB4ma0qMaNJp3IAjgiG+luvmK6AsNzoy3s
J5drYWrErtQSWOx9sK84v9yBzZ9psgF6Wm7NbGVcRjBmanYrXLNmwwgKRGFWMyg8
rwvAd2jZnsmpVLQ=
-----END CERTIFICATE-----

View File

@ -0,0 +1,32 @@
Bag Attributes
friendlyName: test server
localKeyID: 54 69 6D 65 20 31 36 34 31 36 37 35 35 33 37 38 34 32
Key Attributes: <No Attributes>
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCftkfv9IKlVLbY
iOF94n4bFM1xvoreB4ReNnvVH7qpsYMpsYopVUScwYmEqZLDsmR7DLIxc3PDqtNG
WdrAzyOcLRC9ejw8hDddhN8XyCFRGJ3e3hmOSbuFXm6G/gHpB9xAAehMHWmYYoAg
HkIf0Hf3qsnLTy23E7P809oZ6hQGCQlpHWqLol6hMO0esAnYDXZQY92PZ8qH4C5r
8a40l0uex1nQB2wygEq7mEx2gscNkwg38H7cuHDBlDWWZ2j4/TizkpNhKMaNvrAt
flMnXbRGS3Nc7iX2pdiSl9w+AYVLueM3Ctuhu1CXkyhHPbpYzrW4hOhDGs5v91PT
7EPgeWYNAgMBAAECggEADnR1e1LCdks+B0gQPJAAwNu3omlP8Tt17/73YzktcElY
KTBf5FDK1nMvypl8ZojhTj++avpbimSOHappQZUd0HdFshh7ljCTQDwT4veiiE/1
jePFJVsoBTCgSUh5DMnA1ew2RZlN4tRba0zByFZaXUiQXf3LEexPGH1mGn1UlZ0c
J66VzboW3ZiSMx5Mz0GdajjA1FNNv/zTmruFQEGsjAd2EjlC+43ID2IGikmRpRY0
mXK5esjBru2qJUZqLjfdkHtV5YfgSzpu9pZgQq9UOVboTm0oFVrUL2wK6zbDlvNP
scbwNXPmK7vFgPOXNAOSDpL0wksW3gOJgUvCi6zBwwKBgQDPFpMGkJs1jCUsNLX2
CKH7rpahF/hzbZHH717jqR7FWmkf2SLsu4bgNRo58H8QwdkZw2J6xUgUXqB8C8B0
oye5NfokuF6I3wFGXqZcMGEmc9G71t7u91gUb4AAvGgETkTZzFZ8dCw4ofggonvR
PqLkqwCSdNx2z5j15tAR6kx2cwKBgQDFbyUYltaJlCGqcPq/3N4ERkDbqBdmU1EH
cnJ3K6N6AEMeNHd35fKBdR37NDN+Eu9a0mmXskNY1ugGf1d/+MfC2PJWqyFjKXm1
o14RShYLJlmfH8t5yTUOQKXFvip8GpKNM0K2TMe2oRST/QOtxm4bPNGvHP6RPWL7
8KNE9F8RfwKBgH+bqX2iHgIhGcbjtDynlSlBrBAYdUCrg+lv10jyLcPuslittJer
9rCyCDcruyDYUq9NdqGwb3od1Uaa9zzoTNIUMM/vzFELGf4C1QB5z2OietsEzNr0
D5KIIphRgMcmc8bB44lNDPLY281AUovdzQKbXP7ig/eydM8SK6Tee7+BAoGACAjU
3qJMyr5/fDsqySII2u2s+ANoKF7dnkr3A4iAF5fpI1KJRhTSgJguhymBqvDEUtLb
PzQe73+XY6RNAEU0g+ZmPkaqjimC7XRfgJ6eNQfzf7lAg40/nnvdAyYQ/onqStq6
LUcEnZcCil8yhiDcHDmmYtTwOyLfY1dQnZ7AO6sCgYAFa8PTiw9ygDhQcGlrzVeb
s+dv26zrlgZ4YDTd3/rvv4jRm7eMkjk0gcOfC6WuKpm0aKLajOYaQUbDE24DVztQ
X2Y8e7yBl250sSSiQf9T6mtvdWmdiTICnU20yIIl/C1fc5vANJ2BsIclKkoe6lhF
dPpxqoqYGy2kxF8fW8Kn9A==
-----END PRIVATE KEY-----

Binary file not shown.

View File

@ -22,6 +22,8 @@ use tracing::{debug, error, info, instrument, trace, warn, Instrument, Span};
#[cfg(feature = "noise")]
use crate::transport::NoiseTransport;
#[cfg(feature = "quic")]
use crate::transport::QuicTransport;
#[cfg(feature = "tls")]
use crate::transport::TlsTransport;
@ -63,6 +65,15 @@ pub async fn run_client(
#[cfg(not(feature = "noise"))]
crate::helper::feature_not_compile("noise")
}
TransportType::Quic => {
#[cfg(feature = "quic")]
{
let mut client = Client::<QuicTransport>::from(config).await?;
client.run(shutdown_rx, service_rx).await
}
#[cfg(not(feature = "quic"))]
crate::helper::feature_not_compile("quic")
}
}
}

View File

@ -14,6 +14,8 @@ pub enum TransportType {
Tls,
#[serde(rename = "noise")]
Noise,
#[serde(rename = "quic")]
Quic,
}
impl Default for TransportType {
@ -88,6 +90,8 @@ pub struct TlsConfig {
pub trusted_root: Option<String>,
pub pkcs12: Option<String>,
pub pkcs12_password: Option<String>,
pub pem_server_key: Option<String>,
pub pem_server_cert: Option<String>,
}
fn default_noise_pattern() -> String {
@ -129,6 +133,7 @@ pub struct TransportConfig {
pub keepalive_interval: u64,
pub tls: Option<TlsConfig>,
pub noise: Option<NoiseConfig>,
pub quic: Option<TlsConfig>, // reuse TLSconfig since QUIC uses TLS1.3
}
impl Default for TransportConfig {
@ -140,6 +145,7 @@ impl Default for TransportConfig {
keepalive_interval: default_keepalive_interval(),
tls: None,
noise: None,
quic: None
}
}
}
@ -228,6 +234,29 @@ impl Config {
Ok(())
}
fn validate_tls_config(tls_config: &TlsConfig, is_server: bool, is_quic: bool) -> Result<()>{
if is_server {
if tls_config.pem_server_key.is_some() {
if !is_quic {
bail!("`pem_server_key` and `pem_server_cert` are not yet supported for TLS")
}
tls_config.pem_server_cert.as_ref().ok_or(
anyhow!("`pem_server_key` provided but `pem_server_cert` is missing"))?;
} else {
tls_config
.pkcs12
.as_ref()
.and(tls_config.pkcs12_password.as_ref())
.ok_or(anyhow!("Missing `pkcs12` or `pkcs12_password`"))?;
}
} else {
tls_config
.trusted_root
.as_ref()
.ok_or(anyhow!("Missing `trusted_root`"))?;
}
Ok(())
}
fn validate_transport_config(config: &TransportConfig, is_server: bool) -> Result<()> {
match config.transport_type {
TransportType::Tcp => Ok(()),
@ -236,19 +265,14 @@ impl Config {
.tls
.as_ref()
.ok_or(anyhow!("Missing TLS configuration"))?;
if is_server {
tls_config
.pkcs12
.as_ref()
.and(tls_config.pkcs12_password.as_ref())
.ok_or(anyhow!("Missing `pkcs12` or `pkcs12_password`"))?;
} else {
tls_config
.trusted_root
.as_ref()
.ok_or(anyhow!("Missing `trusted_root`"))?;
}
Ok(())
Config::validate_tls_config(tls_config, is_server, false)
}
TransportType::Quic => {
let tls_config = config
.quic
.as_ref()
.ok_or(anyhow!("Missing QUIC configuration"))?;
Config::validate_tls_config(tls_config, is_server, true)
}
TransportType::Noise => {
// The check is done in transport

View File

@ -111,7 +111,9 @@ pub async fn run(args: Cli, shutdown_rx: broadcast::Receiver<bool>) -> Result<()
}
let _ = shutdown_tx.send(true);
if let Some((h,_)) = last_instance{
h.await?;
}
Ok(())
}

View File

@ -26,6 +26,8 @@ use tracing::{debug, error, info, info_span, instrument, warn, Instrument, Span}
use crate::transport::NoiseTransport;
#[cfg(feature = "tls")]
use crate::transport::TlsTransport;
#[cfg(feature = "quic")]
use crate::transport::QuicTransport;
type ServiceDigest = protocol::Digest; // SHA256 of a service name
type Nonce = protocol::Digest; // Also called `session_key`
@ -71,6 +73,15 @@ pub async fn run_server(
#[cfg(not(feature = "noise"))]
crate::helper::feature_not_compile("noise")
}
TransportType::Quic => {
#[cfg(feature = "quic")]
{
let mut server = Server::<QuicTransport>::from(config).await?;
server.run(shutdown_rx, service_rx).await?;
}
#[cfg(not(feature = "tls"))]
crate::helper::feature_not_compile("tls")
}
}
Ok(())
@ -122,7 +133,7 @@ impl<'a, T: 'static + Transport> Server<'a, T> {
mut service_rx: mpsc::Receiver<ServiceChange>,
) -> Result<()> {
// Listen at `server.bind_addr`
let l = self
let mut l = self
.transport
.bind(&self.config.bind_addr)
.await
@ -140,7 +151,7 @@ impl<'a, T: 'static + Transport> Server<'a, T> {
loop {
tokio::select! {
// Wait for incoming control and data channels
ret = self.transport.accept(&l) => {
ret = self.transport.accept(&mut l) => {
match ret {
Err(err) => {
// Detects whether it's an IO error
@ -189,7 +200,7 @@ impl<'a, T: 'static + Transport> Server<'a, T> {
},
// Wait for the shutdown signal
_ = shutdown_rx.recv() => {
info!("Shuting down gracefully...");
info!("Shutting down gracefully...");
break;
},
e = service_rx.recv() => {
@ -200,8 +211,9 @@ impl<'a, T: 'static + Transport> Server<'a, T> {
}
}
// Some transports uses async functions for closing gracefully (QUIC)
self.transport.close(l).await;
info!("Shutdown");
Ok(())
}

View File

@ -27,9 +27,10 @@ pub trait Transport: Debug + Send + Sync {
/// Provide the transport with socket options, which can be handled at the need of the transport
fn hint(conn: &Self::Stream, opts: SocketOpts);
async fn bind<T: ToSocketAddrs + Send + Sync>(&self, addr: T) -> Result<Self::Acceptor>;
async fn accept(&self, a: &Self::Acceptor) -> Result<(Self::RawStream, SocketAddr)>;
async fn accept(&self, a: &mut Self::Acceptor) -> Result<(Self::RawStream, SocketAddr)>;
async fn handshake(&self, conn: Self::RawStream) -> Result<Self::Stream>;
async fn connect(&self, addr: &str) -> Result<Self::Stream>;
async fn close(&self, a: Self::Acceptor);
}
mod tcp;
@ -44,6 +45,11 @@ mod noise;
#[cfg(feature = "noise")]
pub use noise::NoiseTransport;
#[cfg(feature = "quic")]
mod quic;
#[cfg(feature = "quic")]
pub use quic::QuicTransport;
#[derive(Debug, Clone, Copy)]
struct Keepalive {
// tcp_keepalive_time if the underlying protocol is TCP

View File

@ -77,7 +77,7 @@ impl Transport for NoiseTransport {
Ok(TcpListener::bind(addr).await?)
}
async fn accept(&self, a: &Self::Acceptor) -> Result<(Self::RawStream, SocketAddr)> {
async fn accept(&self, a: &mut Self::Acceptor) -> Result<(Self::RawStream, SocketAddr)> {
self.tcp
.accept(a)
.await
@ -103,4 +103,7 @@ impl Transport for NoiseTransport {
.with_context(|| "Failed to do noise handshake")?;
return Ok(conn);
}
async fn close(&self, _: Self::Acceptor) {
}
}

315
src/transport/quic.rs Normal file
View File

@ -0,0 +1,315 @@
use std::borrow::{BorrowMut};
use std::fmt::{Debug, Formatter};
use std::io::{Error, IoSlice};
use std::net::SocketAddr;
use std::pin::Pin;
use std::sync::Arc;
use std::task::Poll;
use std::time::Duration;
use super::Transport;
use crate::config::{TlsConfig, TransportConfig};
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use futures_util::{StreamExt};
use p12::PFX;
use quinn::{Connecting, Connection, Endpoint, EndpointConfig, Incoming};
use rustls::{ConfigBuilder, ServerConfig};
use rustls_pemfile::{Item, read_one, read_all};
use rustls::server::WantsServerCert;
use tokio::fs;
use tokio::io::{AsyncWrite, ReadBuf};
use tokio::net::{ToSocketAddrs, UdpSocket};
use tokio_native_tls::native_tls::Certificate;
use crate::transport::SocketOpts;
pub const ALPN_QUIC_TUNNEL: &[&[u8]] = &[b"qt"];
pub struct QuicTransport {
config: TlsConfig,
keepalive_interval: u64,
client_crypto: Option<rustls::ClientConfig>,
}
impl Debug for QuicTransport {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let client_crypto = &self.client_crypto.as_ref().map(|_| "ClientConfig{}");
f.debug_struct("QuicTransport")
.field("config", &self.config)
.field("client_crypto", client_crypto)
.finish()
}
}
#[derive(Debug)]
pub struct QuicBiStream {
send: quinn::SendStream,
recv: quinn::RecvStream,
conn: Connection,
}
impl QuicBiStream {
fn new((send, recv): (quinn::SendStream, quinn::RecvStream), conn: Connection) -> Self {
Self { send, recv, conn}
}
}
impl tokio::io::AsyncRead for QuicBiStream {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<std::io::Result<()>> {
Pin::new(self.get_mut().recv.borrow_mut()).poll_read(cx, buf)
}
}
impl AsyncWrite for QuicBiStream {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: &[u8],
) -> Poll<std::result::Result<usize, Error>> {
Pin::new(self.get_mut().send.borrow_mut()).poll_write(cx, buf)
}
fn poll_flush(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> Poll<std::result::Result<(), Error>> {
Pin::new(self.get_mut().send.borrow_mut()).poll_flush(cx)
}
fn poll_shutdown(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> Poll<std::result::Result<(), Error>> {
Pin::new(self.get_mut().send.borrow_mut()).poll_shutdown(cx)
}
fn poll_write_vectored(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
bufs: &[IoSlice<'_>],
) -> Poll<std::result::Result<usize, Error>> {
Pin::new(self.get_mut().send.borrow_mut()).poll_write_vectored(cx, bufs)
}
fn is_write_vectored(&self) -> bool {
self.send.is_write_vectored()
}
}
pub struct QuicAcceptor(Endpoint, Incoming);
impl From<QuicAcceptor> for Endpoint {
fn from(a: QuicAcceptor) -> Self {
a.0
}
}
impl Drop for QuicBiStream {
fn drop(&mut self) {
self.conn.close(0u8.into(), &[]);
}
}
async fn read_server_pkcs12(config: &TlsConfig, server_crypto: ConfigBuilder<ServerConfig, WantsServerCert>) -> Result<ServerConfig> {
let buf = fs::read(config.pkcs12.as_ref()
.with_context(|| "Config `quic.pkcs12` was not provided")?)
.await
.with_context(|| "Failed to read the `quic.pkcs12`")?;
let pfx = PFX::parse(buf.as_slice()).with_context(|| "Failed to parse `quic.pkcs12`")?;
let keys = pfx.key_bags(config.pkcs12_password.as_ref()
.with_context(|| "Expected `quic.pkcs12_password` value to be set")?)
.with_context(|| "Could not decrypt `quic.pkcs12 with `quic.pkcs12_password`")?;
let certs = pfx.cert_bags(config.pkcs12_password.as_ref()
.with_context(|| "Config `quic.pkcs12_password` was not provided")?)
.with_context(|| "Could not decrypt `quic.pkcs12` using `quic.pkcs12_password`")?;
let chain: Vec<rustls::Certificate> = certs
.into_iter()
.map(rustls::Certificate)
.collect();
let key = rustls::PrivateKey(keys.into_iter().next()
.with_context(|| "No keys found in `quic.pkcs12`")?);
server_crypto.with_single_cert(chain, key)
.with_context(|| "Server keys invalid")
}
async fn read_server_pem(config: &TlsConfig, server_crypto: ConfigBuilder<ServerConfig, WantsServerCert>) -> Result<ServerConfig> {
// unwrap, since caller should have checked that pem_server_key exists
let buf = fs::read(config.pem_server_key.as_ref().unwrap())
.await
.with_context(|| "Failed to read the `quic.pem_server_key`")?;
let mut bufr = std::io::BufReader::new(buf.as_slice());
let key: Vec<u8> = match read_one(&mut bufr).with_context(|| "Could not parse `quic.pem_server_key`")? {
None => {Err(anyhow!("`quic.pem_server_key` contained no keys"))}
Some(item) => { match item {
Item::X509Certificate(_) => { Err(anyhow!("`quic.pem_server_key` should contain keys, not certificates"))}
Item::RSAKey(der_key) => {Ok(der_key)}
Item::PKCS8Key(der_key) => {Ok(der_key)}
}}}?;
let buf = fs::read(config.pem_server_cert.as_ref()
.with_context(|| "`quic.pem_server_key` was provided, yet `quic.pem_server_cert` is missing")?)
.await
.with_context(|| "Failed to read the `quic.pem_server_cert`")?;
let mut bufr = std::io::BufReader::new(buf.as_slice());
let certs: Result<Vec<Vec<u8>>> = read_all(&mut bufr).with_context(|| "Could not parse `quic.pem_server_cert`")?
.into_iter().map(|item| match item {
Item::X509Certificate(der_cert) => { Ok(der_cert)}
Item::RSAKey(_) | Item::PKCS8Key(_) => {
Err(anyhow!("`quic.pem_server_cert` should contain certificates, not keys"))}
})
.collect();
let certs = certs?;
if certs.is_empty() {
return Err(anyhow!("`quic.pem_server_cert` contained no certs"));
}
let chain: Vec<rustls::Certificate> = certs
.into_iter()
.map(rustls::Certificate)
.collect();
let key = rustls::PrivateKey(key);
server_crypto.with_single_cert(chain, key)
.with_context(|| "Server keys invalid")
}
#[async_trait]
impl Transport for QuicTransport {
type Acceptor = QuicAcceptor;
type RawStream = Connecting;
type Stream = QuicBiStream;
fn new(config: &TransportConfig) -> Result<Self> {
let tls_config = match &config.quic {
Some(v) => v,
None => {
return Err(anyhow!("Missing quic config: {:?}", config));
}
};
let client_crypto = match tls_config.trusted_root.as_ref() {
Some(path) => {
let s = std::fs::read_to_string(path)
.with_context(|| "Failed to read the `quic.trusted_root`")?;
let cert = Certificate::from_pem(s.as_bytes())
.with_context(|| "Failed to read certificate from `quic.trusted_root`")?;
let mut roots = rustls::RootCertStore::empty();
roots.add(&rustls::Certificate(
cert.to_der()
.with_context(|| "could not encode trust root as DER")?,
)).with_context(|| "adding trusted root cert to trust store")?;
let mut client_crypto = rustls::ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(roots)
.with_no_client_auth();
client_crypto.alpn_protocols = ALPN_QUIC_TUNNEL.iter().map(|&x| x.into()).collect();
Some(client_crypto)
}
None => None,
};
Ok(QuicTransport {
keepalive_interval: config.keepalive_interval,
config: tls_config.clone(),
client_crypto,
})
}
fn hint(_: &Self::Stream, _: SocketOpts) {
// keepalive must be set when connection is initiated. nothing to do...
}
async fn bind<A: ToSocketAddrs + Send + Sync>(&self, addr: A) -> Result<Self::Acceptor> {
let server_crypto = rustls::ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth();
let mut server_crypto = match self.config.pem_server_key {
None => {read_server_pkcs12(&self.config, server_crypto).await?}
Some(_) => {read_server_pem(&self.config, server_crypto).await?}
};
server_crypto.alpn_protocols = ALPN_QUIC_TUNNEL.iter().map(|&x| x.into()).collect();
let mut server_config = quinn::ServerConfig::with_crypto(Arc::new(server_crypto));
Arc::get_mut(&mut server_config.transport)
.unwrap()
.datagram_receive_buffer_size(Some(65536))
.datagram_send_buffer_size(65536)
.max_idle_timeout(Some(Duration::from_secs(self.keepalive_interval * 3).try_into()?));
server_config.use_retry(true);
let socket = UdpSocket::bind(addr).await?.into_std()?;
quinn::Endpoint::new(EndpointConfig::default(), Some(server_config), socket)
.with_context(|| "Failed to start server")
.map(|(e, i)| QuicAcceptor(e, i))
}
async fn accept(&self, a: &mut Self::Acceptor) -> Result<(Self::RawStream, SocketAddr)> {
if let Some(connecting) = a.1.next().await {
let addr = connecting.remote_address();
return Ok((connecting, addr));
}
Err(anyhow!("endpoint closed"))
}
async fn handshake(&self, conn: Self::RawStream) -> Result<Self::Stream> {
let mut new_connection = conn.await?; // handshake happens here
// Connection is established now. Wait for client to open a bidirectional stream
if let Some(bi_stream_result) = new_connection.bi_streams.next().await {
Ok(Self::Stream::new(bi_stream_result?, new_connection.connection))
} else {
anyhow::bail!("connection closed before bi stream could be established")
}
}
async fn connect(&self, addr: &str) -> Result<Self::Stream> {
let mut endpoint = quinn::Endpoint::client("[::]:0".parse().unwrap())
.with_context(|| "could not open client socket")?;
let mut config =
quinn::ClientConfig::new(Arc::new(self.client_crypto.as_ref().unwrap().clone()));
// server times out after 10 sec, so send keepalive every 5 sec
Arc::get_mut(&mut config.transport)
.unwrap()
.keep_alive_interval(Some(Duration::from_secs(self.keepalive_interval)))
.datagram_receive_buffer_size(Some(65536))
.datagram_send_buffer_size(65536);
endpoint.set_default_client_config(config);
let connecting = endpoint.connect(
addr.parse().with_context(|| "server address not valid")?,
self.config
.hostname
.as_ref()
.unwrap_or(&String::from(addr.split(':').next().unwrap())),
)?;
let new_conn = connecting.await?;
Ok(QuicBiStream::new(new_conn.connection.open_bi().await?, new_conn.connection))
}
async fn close(&self, a: Self::Acceptor) {
let e: Endpoint = a.into(); // drops Incoming
e.close(0u8.into(), &[]);
// wait for all connections to signal close as per spec
// See https://github.com/quinn-rs/quinn/issues/1102
// this may take a couple of seconds unfortunately, but without it we are not
// guaranteed that the socket is released when we exit this method.
e.wait_idle().await;
drop(e);
}
}

View File

@ -31,7 +31,7 @@ impl Transport for TcpTransport {
Ok(TcpListener::bind(addr).await?)
}
async fn accept(&self, a: &Self::Acceptor) -> Result<(Self::RawStream, SocketAddr)> {
async fn accept(&self, a: &mut Self::Acceptor) -> Result<(Self::RawStream, SocketAddr)> {
let (s, addr) = a.accept().await?;
self.socket_opts.apply(&s);
Ok((s, addr))
@ -46,4 +46,7 @@ impl Transport for TcpTransport {
self.socket_opts.apply(&s);
Ok(s)
}
async fn close(&self, _: Self::Acceptor) {
}
}

View File

@ -79,7 +79,7 @@ impl Transport for TlsTransport {
Ok(l)
}
async fn accept(&self, a: &Self::Acceptor) -> Result<(Self::RawStream, SocketAddr)> {
async fn accept(&self, a: &mut Self::Acceptor) -> Result<(Self::RawStream, SocketAddr)> {
self.tcp
.accept(a)
.await
@ -105,4 +105,7 @@ impl Transport for TlsTransport {
)
.await?)
}
async fn close(&self, _: Self::Acceptor) {
}
}

View File

@ -0,0 +1,29 @@
[client]
remote_addr = "127.0.0.1:2333"
default_token = "default_token_if_not_specify"
[client.transport]
type = "quic"
[client.transport.quic]
trusted_root = "examples/quic/test_ca.pem"
hostname = "testserver"
[client.services.echo]
local_addr = "127.0.0.1:8080"
[client.services.pingpong]
local_addr = "127.0.0.1:8081"
[server]
bind_addr = "0.0.0.0:2333"
default_token = "default_token_if_not_specify"
[server.transport]
type = "quic"
[server.transport.quic]
pkcs12 = "examples/quic/test_server.pfx"
pkcs12_password = "1234"
[server.services.echo]
bind_addr = "0.0.0.0:2334"
[server.services.pingpong]
bind_addr = "0.0.0.0:2335"

View File

@ -0,0 +1,33 @@
[client]
remote_addr = "127.0.0.1:2332"
default_token = "default_token_if_not_specify"
[client.transport]
type = "quic"
[client.transport.quic]
trusted_root = "examples/quic/test_ca.pem"
hostname = "testserver"
[client.services.echo]
type = "udp"
local_addr = "127.0.0.1:8080"
[client.services.pingpong]
type = "udp"
local_addr = "127.0.0.1:8081"
[server]
bind_addr = "0.0.0.0:2332"
default_token = "default_token_if_not_specify"
[server.transport]
type = "quic"
[server.transport.quic]
pem_server_key = "examples/quic/test_server.key.pem"
pem_server_cert = "examples/quic/test_server.cert.pem"
[server.services.echo]
type = "udp"
bind_addr = "0.0.0.0:2334"
[server.services.pingpong]
type = "udp"
bind_addr = "0.0.0.0:2335"

View File

@ -59,6 +59,7 @@ async fn tcp() -> Result<()> {
#[cfg(not(target_os = "macos"))]
test("tests/for_tcp/tls_transport.toml", Type::Tcp).await?;
test("tests/for_tcp/noise_transport.toml", Type::Tcp).await?;
test("tests/for_tcp/quic_transport.toml", Type::Tcp).await?;
Ok(())
}
@ -86,6 +87,7 @@ async fn udp() -> Result<()> {
#[cfg(not(target_os = "macos"))]
test("tests/for_udp/tls_transport.toml", Type::Udp).await?;
test("tests/for_udp/noise_transport.toml", Type::Udp).await?;
test("tests/for_udp/quic_transport.toml", Type::Udp).await?;
Ok(())
}