mirror of https://github.com/rapiz1/rathole.git
add QUIC transport based on bi streams
This commit is contained in:
parent
1fe3509536
commit
3a280b0ac0
|
@ -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"
|
||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -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"] }
|
||||
|
|
Binary file not shown.
|
@ -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"
|
|
@ -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"
|
|
@ -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-----
|
|
@ -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-----
|
|
@ -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.
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
|
@ -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"
|
|
@ -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(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue