Skip to content

Commit

Permalink
switch rama-tls to use a unique handle per sslkeylogfile
Browse files Browse the repository at this point in the history
Closes #341
  • Loading branch information
GlenDC committed Oct 24, 2024
1 parent 6546c33 commit 45848f3
Show file tree
Hide file tree
Showing 12 changed files with 213 additions and 141 deletions.
3 changes: 3 additions & 0 deletions .taplo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[formatting]
array_auto_collapse = false
array_auto_expand = false
47 changes: 37 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,14 @@ opentelemetry = { version = "0.26.0", default-features = false, features = [
"trace",
] }
nom = "7.1.3"
opentelemetry-otlp = { version = "0.26.0", features = [ "tokio" ] }
opentelemetry-otlp = { version = "0.26.0", features = ["tokio"] }
opentelemetry_sdk = { version = "0.26.0", default-features = false, features = [
"trace",
"rt-tokio",
] }
opentelemetry-semantic-conventions = { version = "0.26", features = [ "semconv_experimental" ] }
opentelemetry-semantic-conventions = { version = "0.26", features = [
"semconv_experimental",
] }
quickcheck = "1.0"
quote = "1.0"
rcgen = "0.13.0"
Expand Down Expand Up @@ -122,6 +124,7 @@ hickory-resolver = { version = "0.24.1", default-features = false, features = [
"tokio-runtime",
] }
arc-swap = "1.7.1"
flume = "0.11.1"

[workspace.lints.rust]
unreachable_pub = "deny"
Expand Down
24 changes: 13 additions & 11 deletions rama-net/src/tls/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
//! rama common tls types
//!

use std::{
borrow::Cow,
path::{Path, PathBuf},
};

use rama_utils::str::NonEmptyString;

mod enums;
Expand Down Expand Up @@ -66,18 +61,25 @@ pub enum KeyLogIntent {
/// You can choose to disable the key logging explicitly
Disabled,
/// Request a keys to be logged to the given file path.
File(std::path::PathBuf),
File(String),
}

impl KeyLogIntent {
/// get the file path if intended
pub fn file_path(&self) -> Option<Cow<'_, Path>> {
pub fn file_path(&self) -> Option<String> {
match self {
KeyLogIntent::Disabled => None,
KeyLogIntent::Environment => std::env::var("SSLKEYLOGFILE").ok().clone(),
KeyLogIntent::File(keylog_filename) => Some(keylog_filename.clone()),
}
}

/// consume itself into the file path if intended
pub fn into_file_path(self) -> Option<String> {
match self {
KeyLogIntent::Disabled => None,
KeyLogIntent::Environment => std::env::var("SSLKEYLOGFILE")
.ok()
.map(|s| Cow::Owned(PathBuf::from(s))),
KeyLogIntent::File(keylog_filename) => Some(Cow::Borrowed(keylog_filename.as_path())),
KeyLogIntent::Environment => std::env::var("SSLKEYLOGFILE").ok().clone(),
KeyLogIntent::File(keylog_filename) => Some(keylog_filename),
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion rama-tls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ rustls-ring = ["rustls", "tokio-rustls/ring", "rustls/ring", "rama-net/rustls-ri

[dependencies]
boring = { workspace = true, optional = true }
moka = { workspace = true, features = [ "sync" ], optional = true }
flume = { workspace = true, features = ["async"] }
moka = { workspace = true, features = ["sync"], optional = true }
parking_lot = { workspace = true }
pin-project-lite = { workspace = true }
rama-core = { version = "0.2.0-alpha.4", path = "../rama-core" }
Expand Down
15 changes: 4 additions & 11 deletions rama-tls/src/boring/client/connector_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ use rama_net::{address::Host, tls::client::ServerVerifyMode};
use std::{fmt, sync::Arc};
use tracing::trace;

use crate::keylog::new_key_log_file_handle;

#[derive(Debug, Clone)]
/// Internal data used as configuration/input for the [`super::HttpsConnector`].
///
Expand Down Expand Up @@ -74,20 +76,11 @@ impl TlsConnectorData {
.clone()
.unwrap_or_default()
.file_path()
.as_deref()
{
// open file in append mode and write keylog to it with callback
trace!(path = ?keylog_filename, "boring connector: open keylog file for debug purposes");
let file = std::fs::OpenOptions::new()
.append(true)
.create(true)
.open(keylog_filename)
.context("build (boring) ssl connector: set keylog: open file")?;
let handle = new_key_log_file_handle(keylog_filename)?;
cfg_builder.set_keylog_callback(move |_, line| {
use std::io::Write;
let line = format!("{}\n", line);
let mut file = &file;
let _ = file.write_all(line.as_bytes());
handle.write_log_line(line);
});
}

Expand Down
17 changes: 4 additions & 13 deletions rama-tls/src/boring/server/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use crate::{
boring::ssl::{AlpnError, SslAcceptor, SslMethod, SslRef},
tokio_boring::SslStream,
},
types::client::ClientHello,
types::SecureTransport,
keylog::new_key_log_file_handle,
types::{client::ClientHello, SecureTransport},
};
use parking_lot::Mutex;
use rama_core::{
Expand Down Expand Up @@ -184,19 +184,10 @@ where
}

if let Some(keylog_filename) = tls_config.keylog_intent.file_path() {
trace!(path = ?keylog_filename, "boring acceptor service: open keylog file for debug purposes");
// TODO: do not open a file each time, just use 1 global one
// open file in append mode and write keylog to it with callback
let file = std::fs::OpenOptions::new()
.append(true)
.create(true)
.open(keylog_filename)
.context("build boring ssl acceptor: set keylog: open file")?;
let handle = new_key_log_file_handle(keylog_filename)?;
acceptor_builder.set_keylog_callback(move |_, line| {
use std::io::Write;
let line = format!("{}\n", line);
let mut file = &file;
let _ = file.write_all(line.as_bytes());
handle.write_log_line(line);
});
}

Expand Down
97 changes: 97 additions & 0 deletions rama-tls/src/keylog.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//! Keylog facility used by any tls implementation
//! supported by rama, and which can be used for your owns as well.
//!
//! Center to thsi module is the `KeyLogger` which is a wrapper around
//! a FS file

use parking_lot::RwLock;
use rama_core::error::{ErrorContext, OpaqueError};
use std::{
collections::{hash_map::Entry, HashMap},
fs::OpenOptions,
io::Write,
sync::OnceLock,
};

/// Get a key log file handle for the given path
/// only one file handle will be opened per unique path String.
///
/// # To be unique or ditto
///
/// Paths are case-sensitive by default for rama, as utf-8 compatible.
/// Normalize yourself prior to passing a path to this function if you're concerned.
pub fn new_key_log_file_handle(path: String) -> Result<KeyLogFileHandle, OpaqueError> {
let mapping = GLOBAL_KEY_LOG_FILE_MAPPING.get_or_init(Default::default);
if let Some(handle) = mapping.read().get(&path).cloned() {
return Ok(handle);
}
let mut mut_mapping = mapping.write();
match mut_mapping.entry(path.clone()) {
Entry::Occupied(entry) => Ok(entry.get().clone()),
Entry::Vacant(entry) => {
let handle = try_init_key_log_file_handle(path)?;
entry.insert(handle.clone());
Ok(handle)
}
}
}

fn try_init_key_log_file_handle(path: String) -> Result<KeyLogFileHandle, OpaqueError> {
tracing::trace!(
file = ?path,
"KeyLogFileHandle: try to create a new handle",
);

let mut file = OpenOptions::new()
.append(true)
.create(true)
.open(&path)
.with_context(|| format!("create key log file {path:?}"))?;

let (tx, rx) = flume::unbounded::<String>();

let path_name = path.clone();
std::thread::spawn(move || {
tracing::trace!(
file = ?path_name,
"KeyLogFileHandle[rx]: receiver task up and running",
);
while let Ok(line) = rx.recv() {
if let Err(err) = file.write_all(line.as_bytes()) {
tracing::error!(
file = path_name,
error = %err,
"KeyLogFileHandle[rx]: failed to write file",
);
}
}
});

Ok(KeyLogFileHandle { path, sender: tx })
}

static GLOBAL_KEY_LOG_FILE_MAPPING: OnceLock<RwLock<HashMap<String, KeyLogFileHandle>>> =
OnceLock::new();

#[derive(Debug, Clone)]
/// Handle to a (tls) keylog file.
///
/// See [`new_key_log_file_handle`] for more info,
/// as that is the one creating it.
pub struct KeyLogFileHandle {
path: String,
sender: flume::Sender<String>,
}

impl KeyLogFileHandle {
/// Write a line to the keylogger.
pub fn write_log_line(&self, line: String) {
if let Err(err) = self.sender.send(line) {
tracing::error!(
file = %self.path,
error = %err,
"KeyLogFileHandle[tx]: failed to send log line for writing",
);
}
}
}
2 changes: 2 additions & 0 deletions rama-tls/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub use rustls as std;
#[cfg(feature = "boring")]
pub use boring as std;

pub mod keylog;

pub mod types {
//! common tls types
#[doc(inline)]
Expand Down
Loading

0 comments on commit 45848f3

Please sign in to comment.