Skip to content

Commit

Permalink
add QUIC transport based on bi streams
Browse files Browse the repository at this point in the history
  • Loading branch information
emillynge committed Jan 17, 2022
1 parent 1fe3509 commit 3a280b0
Show file tree
Hide file tree
Showing 21 changed files with 902 additions and 23 deletions.
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

0 comments on commit 3a280b0

Please sign in to comment.