trying to ad rustls support
This commit is contained in:
parent
c30cf3fbe9
commit
ffce1a2b80
17
Cargo.lock
generated
17
Cargo.lock
generated
@ -93,6 +93,12 @@ dependencies = [
|
|||||||
"paste",
|
"paste",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.22.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bindgen"
|
name = "bindgen"
|
||||||
version = "0.69.4"
|
version = "0.69.4"
|
||||||
@ -254,6 +260,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"openssl",
|
"openssl",
|
||||||
"rustls",
|
"rustls",
|
||||||
|
"rustls-pemfile",
|
||||||
"serde_yml",
|
"serde_yml",
|
||||||
"threadpool",
|
"threadpool",
|
||||||
]
|
]
|
||||||
@ -613,6 +620,16 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pemfile"
|
||||||
|
version = "2.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"rustls-pki-types",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pki-types"
|
name = "rustls-pki-types"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
|
@ -6,12 +6,14 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
openssl = { version = "0.10.66", optional = true }
|
openssl = { version = "0.10.66", optional = true }
|
||||||
rustls = { version = "0.23.13", optional = true }
|
rustls = { version = "0.23.13", optional = true }
|
||||||
|
rustls-pemfile = { version = "2.1.3", optional = true }
|
||||||
serde_yml = "0.0.12"
|
serde_yml = "0.0.12"
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
colog = "1.3.0"
|
colog = "1.3.0"
|
||||||
threadpool = "1.8.1"
|
threadpool = "1.8.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["use-openssl"]
|
# default = ["use-openssl"]
|
||||||
|
default = ["use-rustls"]
|
||||||
use-openssl = ["dep:openssl"]
|
use-openssl = ["dep:openssl"]
|
||||||
use-rustls = ["dep:rustls"]
|
use-rustls = ["dep:rustls", "dep:rustls-pemfile"]
|
@ -1,7 +1,6 @@
|
|||||||
use std::{io::{Read, Write}, net::{Shutdown, SocketAddr, TcpListener}, sync::Arc, thread, time::Duration};
|
use std::{io::{Read, Write}, net::{Shutdown, SocketAddr, TcpListener}, sync::Arc, thread, time::Duration};
|
||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use openssl::ssl::{NameType, SniError, SslAcceptor, SslAlert, SslMethod, SslRef};
|
|
||||||
use threadpool::ThreadPool;
|
use threadpool::ThreadPool;
|
||||||
|
|
||||||
use super::Config;
|
use super::Config;
|
||||||
@ -15,7 +14,7 @@ impl FlowgateServer {
|
|||||||
FlowgateServer { config: Arc::new(config) }
|
FlowgateServer { config: Arc::new(config) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(self) {
|
pub fn start(&self) {
|
||||||
thread::spawn({
|
thread::spawn({
|
||||||
let config = Arc::clone(&self.config);
|
let config = Arc::clone(&self.config);
|
||||||
|
|
||||||
@ -67,9 +66,12 @@ impl FlowgateServer {
|
|||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "use-openssl")]
|
||||||
pub fn run_https(
|
pub fn run_https(
|
||||||
config: Arc<Config>
|
config: Arc<Config>
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
|
use openssl::ssl::{NameType, SniError, SslAcceptor, SslAlert, SslMethod, SslRef};
|
||||||
|
|
||||||
let listener = TcpListener::bind(&config.https_host).ok()?;
|
let listener = TcpListener::bind(&config.https_host).ok()?;
|
||||||
|
|
||||||
let mut cert = SslAcceptor::mozilla_intermediate(SslMethod::tls()).ok()?;
|
let mut cert = SslAcceptor::mozilla_intermediate(SslMethod::tls()).ok()?;
|
||||||
@ -119,6 +121,62 @@ impl FlowgateServer {
|
|||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "use-rustls")]
|
||||||
|
pub fn run_https(
|
||||||
|
config: Arc<Config>
|
||||||
|
) -> Option<()> {
|
||||||
|
use std::sync::Arc;
|
||||||
|
use rustls::{server::ResolvesServerCertUsingSni, ServerConfig};
|
||||||
|
use super::ssl_cert::AdoptedConnection;
|
||||||
|
|
||||||
|
let listener = TcpListener::bind(&config.https_host).ok()?;
|
||||||
|
|
||||||
|
let mut cert_resolver = ResolvesServerCertUsingSni::new();
|
||||||
|
|
||||||
|
for site in config.sites.iter() {
|
||||||
|
if let Some(cert) = site.ssl {
|
||||||
|
cert_resolver.add(&site.domain, cert.get_certified_key());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut tls_config = Arc::new(
|
||||||
|
ServerConfig::builder()
|
||||||
|
.with_no_client_auth()
|
||||||
|
.with_cert_resolver(Arc::new(cert_resolver))
|
||||||
|
);
|
||||||
|
|
||||||
|
let pool = ThreadPool::new(10);
|
||||||
|
|
||||||
|
info!("HTTPS server runned on {}", &config.https_host);
|
||||||
|
|
||||||
|
for stream in listener.incoming() {
|
||||||
|
pool.execute({
|
||||||
|
let config = config.clone();
|
||||||
|
let tls_config = tls_config.clone();
|
||||||
|
|
||||||
|
move || {
|
||||||
|
let Ok(mut stream) = stream else { return };
|
||||||
|
|
||||||
|
let Ok(_) = stream.set_write_timeout(Some(Duration::from_secs(10))) else { return };
|
||||||
|
let Ok(_) = stream.set_read_timeout(Some(Duration::from_secs(10))) else { return };
|
||||||
|
|
||||||
|
let Ok(addr) = stream.peer_addr() else { return };
|
||||||
|
|
||||||
|
let Some(mut stream) = AdoptedConnection::from_config(tls_config, stream) else { return };
|
||||||
|
|
||||||
|
Self::accept_stream(
|
||||||
|
config,
|
||||||
|
&mut stream,
|
||||||
|
addr,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn accept_stream(
|
pub fn accept_stream(
|
||||||
config: Arc<Config>,
|
config: Arc<Config>,
|
||||||
stream: &mut (impl Read + Write),
|
stream: &mut (impl Read + Write),
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
use openssl::ssl::{SslContext, SslFiletype, SslMethod};
|
#[cfg(feature = "use-openssl")]
|
||||||
|
use openssl::ssl::SslContext;
|
||||||
|
|
||||||
|
#[cfg(feature = "use-openssl")]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SslCert {
|
pub struct SslCert {
|
||||||
context: Option<SslContext>,
|
context: SslContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "use-openssl")]
|
||||||
fn generate_ctx(cert_file: &str, key_file: &str) -> Option<SslContext> {
|
fn generate_ctx(cert_file: &str, key_file: &str) -> Option<SslContext> {
|
||||||
|
use openssl::ssl::{SslFiletype, SslMethod};
|
||||||
|
|
||||||
let mut ctx = SslContext::builder(SslMethod::tls()).ok()?;
|
let mut ctx = SslContext::builder(SslMethod::tls()).ok()?;
|
||||||
ctx.set_private_key_file(&key_file, SslFiletype::PEM).ok()?;
|
ctx.set_private_key_file(&key_file, SslFiletype::PEM).ok()?;
|
||||||
ctx.set_certificate_file(&cert_file, SslFiletype::PEM).ok()?;
|
ctx.set_certificate_file(&cert_file, SslFiletype::PEM).ok()?;
|
||||||
@ -13,19 +18,94 @@ fn generate_ctx(cert_file: &str, key_file: &str) -> Option<SslContext> {
|
|||||||
Some(ctx.build())
|
Some(ctx.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "use-openssl")]
|
||||||
impl SslCert {
|
impl SslCert {
|
||||||
pub fn new(cert_file: &str, key_file: &str) -> Option<SslCert> {
|
pub fn new(cert_file: &str, key_file: &str) -> Option<SslCert> {
|
||||||
Some(SslCert {
|
Some(SslCert {
|
||||||
context: match generate_ctx(cert_file, key_file) {
|
context: generate_ctx(cert_file, key_file)?
|
||||||
Some(i) => Some(i),
|
|
||||||
None => {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_context(&self) -> SslContext {
|
pub fn get_context(&self) -> SslContext {
|
||||||
self.context.as_ref().unwrap().clone()
|
self.context.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "use-rustls")]
|
||||||
|
use rustls::{sign::CertifiedKey, server::Acceptor, ServerConfig, ServerConnection};
|
||||||
|
#[cfg(feature = "use-rustls")]
|
||||||
|
use std::{net::TcpStream, sync::Arc};
|
||||||
|
|
||||||
|
#[cfg(feature = "use-rustls")]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SslCert {
|
||||||
|
cert_key: CertifiedKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "use-rustls")]
|
||||||
|
fn generate_cert_key(cert_file: &str, key_file: &str) -> Option<CertifiedKey> {
|
||||||
|
use rustls::crypto::CryptoProvider;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::BufReader;
|
||||||
|
|
||||||
|
let key = rustls_pemfile::private_key(&mut BufReader::new(File::open(key_file).ok()?)).ok()??;
|
||||||
|
let key = CryptoProvider::get_default().unwrap().key_provider.load_private_key(key).ok()?;
|
||||||
|
|
||||||
|
let cert =
|
||||||
|
rustls_pemfile::public_keys(&mut BufReader::new(File::open(cert_file).ok()?))
|
||||||
|
.map(|o| o.unwrap().to_vec().into())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
Some(CertifiedKey::new(cert, key))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "use-rustls")]
|
||||||
|
impl SslCert {
|
||||||
|
pub fn new(cert_file: &str, key_file: &str) -> Option<SslCert> {
|
||||||
|
Some(SslCert {
|
||||||
|
cert_key: generate_cert_key(cert_file, key_file)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_certified_key(&self) -> CertifiedKey {
|
||||||
|
self.cert_key.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "use-rustls")]
|
||||||
|
pub struct AdoptedConnection {
|
||||||
|
server_connection: ServerConnection,
|
||||||
|
stream: TcpStream
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "use-rustls")]
|
||||||
|
impl AdoptedConnection {
|
||||||
|
pub fn new(
|
||||||
|
server_connection: ServerConnection,
|
||||||
|
stream: TcpStream
|
||||||
|
) -> AdoptedConnection {
|
||||||
|
AdoptedConnection {
|
||||||
|
server_connection,
|
||||||
|
stream
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_config(
|
||||||
|
server_config: Arc<ServerConfig>,
|
||||||
|
mut stream: TcpStream
|
||||||
|
) -> Option<AdoptedConnection> {
|
||||||
|
let mut acceptor = Acceptor::default();
|
||||||
|
let accepted = loop {
|
||||||
|
acceptor.read_tls(&mut stream).ok()?;
|
||||||
|
if let Some(accepted) = acceptor.accept().ok()? {
|
||||||
|
break accepted;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(AdoptedConnection {
|
||||||
|
server_connection: accepted.into_connection(server_config).ok()?,
|
||||||
|
stream
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement Read and Write to AdoptedConnection
|
Loading…
Reference in New Issue
Block a user