diff --git a/Cargo.lock b/Cargo.lock index 1baebf93..633d08c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index eb873ca1..e019ae13 100644 --- a/Cargo.toml +++ b/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"] } diff --git a/examples/quic/ca.pfx b/examples/quic/ca.pfx new file mode 100644 index 00000000..a6bf739d Binary files /dev/null and b/examples/quic/ca.pfx differ diff --git a/examples/quic/client.toml b/examples/quic/client.toml new file mode 100644 index 00000000..02e5d0bb --- /dev/null +++ b/examples/quic/client.toml @@ -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" diff --git a/examples/quic/server.toml b/examples/quic/server.toml new file mode 100644 index 00000000..f78a15e5 --- /dev/null +++ b/examples/quic/server.toml @@ -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" diff --git a/examples/quic/test_ca.pem b/examples/quic/test_ca.pem new file mode 100644 index 00000000..8395bca4 --- /dev/null +++ b/examples/quic/test_ca.pem @@ -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----- diff --git a/examples/quic/test_server.cert.pem b/examples/quic/test_server.cert.pem new file mode 100644 index 00000000..48da65b2 --- /dev/null +++ b/examples/quic/test_server.cert.pem @@ -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----- diff --git a/examples/quic/test_server.key.pem b/examples/quic/test_server.key.pem new file mode 100644 index 00000000..8a031da6 --- /dev/null +++ b/examples/quic/test_server.key.pem @@ -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: +-----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----- diff --git a/examples/quic/test_server.pfx b/examples/quic/test_server.pfx new file mode 100644 index 00000000..c7184ae8 Binary files /dev/null and b/examples/quic/test_server.pfx differ diff --git a/src/client.rs b/src/client.rs index 23af0d45..2ccd86f2 100644 --- a/src/client.rs +++ b/src/client.rs @@ -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::::from(config).await?; + client.run(shutdown_rx, service_rx).await + } + #[cfg(not(feature = "quic"))] + crate::helper::feature_not_compile("quic") + } } } diff --git a/src/config.rs b/src/config.rs index 7304e421..449712d7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -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, pub pkcs12: Option, pub pkcs12_password: Option, + pub pem_server_key: Option, + pub pem_server_cert: Option, } fn default_noise_pattern() -> String { @@ -129,6 +133,7 @@ pub struct TransportConfig { pub keepalive_interval: u64, pub tls: Option, pub noise: Option, + pub quic: Option, // 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 diff --git a/src/lib.rs b/src/lib.rs index 481200a2..19391dc2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,7 +111,9 @@ pub async fn run(args: Cli, shutdown_rx: broadcast::Receiver) -> Result<() } let _ = shutdown_tx.send(true); - + if let Some((h,_)) = last_instance{ + h.await?; + } Ok(()) } diff --git a/src/server.rs b/src/server.rs index 051a856d..2bbb523e 100644 --- a/src/server.rs +++ b/src/server.rs @@ -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::::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, ) -> 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(()) } diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 8660c6ca..f60dd979 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -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(&self, addr: T) -> Result; - 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; async fn connect(&self, addr: &str) -> Result; + 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 diff --git a/src/transport/noise.rs b/src/transport/noise.rs index c9a3e820..2fe5948f 100644 --- a/src/transport/noise.rs +++ b/src/transport/noise.rs @@ -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) { + } } diff --git a/src/transport/quic.rs b/src/transport/quic.rs new file mode 100644 index 00000000..2b9c51af --- /dev/null +++ b/src/transport/quic.rs @@ -0,0 +1,319 @@ +use std::borrow::{BorrowMut}; +use std::fmt::{Debug, Formatter}; +use std::fs::File; +use std::io::{BufReader, 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 crate::transport::SocketOpts; + +pub const ALPN_QUIC_TUNNEL: &[&[u8]] = &[b"qt"]; + +pub struct QuicTransport { + config: TlsConfig, + keepalive_interval: u64, + client_crypto: Option, +} + +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> { + 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> { + 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> { + Pin::new(self.get_mut().send.borrow_mut()).poll_flush(cx) + } + + fn poll_shutdown( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + 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> { + 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 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) -> Result { + 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 = 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) -> Result { + // 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 = 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>> = 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 = 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 { + 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 certs: Result>> = read_all( + &mut BufReader::new( &mut File::open(path) + .with_context(|| "Failed to open the `quic.trusted_root`")?)) + .with_context(|| "Could not parse `quic.trusted_root`")? + .into_iter().map(|item| match item { + Item::X509Certificate(der_cert) => { Ok(der_cert)} + Item::RSAKey(_) | Item::PKCS8Key(_) => { + Err(anyhow!("`quic.trusted_root` should contain certificates, not keys"))} + }) + .collect(); + + let mut roots = rustls::RootCertStore::empty(); + for cert in certs?.into_iter() { + roots.add(&rustls::Certificate(cert)).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(&self, addr: A) -> Result { + 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 { + 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 { + 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); + } +} + + diff --git a/src/transport/tcp.rs b/src/transport/tcp.rs index 6895e077..8d41efa4 100644 --- a/src/transport/tcp.rs +++ b/src/transport/tcp.rs @@ -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) { + } } diff --git a/src/transport/tls.rs b/src/transport/tls.rs index 8d4eb6fd..89e29f97 100644 --- a/src/transport/tls.rs +++ b/src/transport/tls.rs @@ -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) { + } } diff --git a/tests/for_tcp/quic_transport.toml b/tests/for_tcp/quic_transport.toml new file mode 100644 index 00000000..b82d21ba --- /dev/null +++ b/tests/for_tcp/quic_transport.toml @@ -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" diff --git a/tests/for_udp/quic_transport.toml b/tests/for_udp/quic_transport.toml new file mode 100644 index 00000000..0fc77a7c --- /dev/null +++ b/tests/for_udp/quic_transport.toml @@ -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" diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 18115753..9be27843 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -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(()) }