Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QUIC support #98

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
308 changes: 308 additions & 0 deletions Cargo.lock

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand All @@ -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"]

Expand Down Expand Up @@ -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"] }
Expand Down
Binary file added examples/quic/ca.pfx
Binary file not shown.
12 changes: 12 additions & 0 deletions examples/quic/client.toml
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions examples/quic/server.toml
Original file line number Diff line number Diff line change
@@ -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 changes: 19 additions & 0 deletions examples/quic/test_ca.pem
Original file line number Diff line number Diff line change
@@ -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-----
45 changes: 45 additions & 0 deletions examples/quic/test_server.cert.pem
Original file line number Diff line number Diff line change
@@ -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-----
32 changes: 32 additions & 0 deletions examples/quic/test_server.key.pem
Original file line number Diff line number Diff line change
@@ -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 added examples/quic/test_server.pfx
Binary file not shown.
11 changes: 11 additions & 0 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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")
}
}
}

Expand Down
50 changes: 37 additions & 13 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ pub enum TransportType {
Tls,
#[serde(rename = "noise")]
Noise,
#[serde(rename = "quic")]
Quic,
}

impl Default for TransportType {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -140,6 +145,7 @@ impl Default for TransportConfig {
keepalive_interval: default_keepalive_interval(),
tls: None,
noise: None,
quic: None
}
}
}
Expand Down Expand Up @@ -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(()),
Expand All @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}

Expand Down
20 changes: 16 additions & 4 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -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(())
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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() => {
Expand All @@ -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(())
}

Expand Down
8 changes: 7 additions & 1 deletion src/transport/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down
5 changes: 4 additions & 1 deletion src/transport/noise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -103,4 +103,7 @@ impl Transport for NoiseTransport {
.with_context(|| "Failed to do noise handshake")?;
return Ok(conn);
}

async fn close(&self, _: Self::Acceptor) {
}
}
Loading