Skip to content

Commit

Permalink
ffi: add set_logging_function to ffi-bindings (#305)
Browse files Browse the repository at this point in the history
Add set_logging_function to ffi-bindings to allow forwarding tracing events to a custom logging function.
  • Loading branch information
csabol authored Aug 16, 2022
1 parent 1466836 commit 829dae2
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 1 deletion.
3 changes: 2 additions & 1 deletion boringtun/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ edition = "2018"

[features]
jni-bindings = ["ffi-bindings", "jni"]
ffi-bindings = []
ffi-bindings = ["tracing-subscriber"]

[dependencies]
base64 = "0.13"
Expand All @@ -19,6 +19,7 @@ untrusted = "0.9.0"
libc = "0.2"
parking_lot = "0.12"
tracing = "0.1.29"
tracing-subscriber = { version = "0.3", features = ["fmt"], optional = true }
ip_network = "0.4.1"
ip_network_table = "0.2.0"
ring = "0.16"
Expand Down
83 changes: 83 additions & 0 deletions boringtun/src/ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ use hex::encode as encode_hex;
use libc::{raise, SIGSEGV};
use parking_lot::Mutex;
use rand_core::OsRng;
use tracing;
use tracing_subscriber::fmt;
use x25519_dalek::{PublicKey, StaticSecret};

use crate::serialization::KeyBytes;
use std::ffi::{CStr, CString};
use std::io::{Error, ErrorKind, Write};
use std::os::raw::c_char;
use std::panic;
use std::ptr;
Expand Down Expand Up @@ -160,6 +163,86 @@ pub unsafe extern "C" fn check_base64_encoded_x25519_key(key: *const c_char) ->
}
}

/// Custom tracing_subscriber writer to an external function pointer
struct FFIFunctionPointerWriter {
log_func: unsafe extern "C" fn(*const c_char),
}

/// Implements Write trait for use with tracing_subscriber
impl Write for FFIFunctionPointerWriter {
fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
let out_str = String::from_utf8_lossy(buf).to_string();
if let Ok(c_string) = CString::new(out_str) {
unsafe { (self.log_func)(c_string.as_ptr()) }
Ok(buf.len())
} else {
Err(Error::new(
ErrorKind::Other,
"Failed to create CString from buffer.",
))
}
}

fn flush(&mut self) -> Result<(), std::io::Error> {
// no-op
Ok(())
}
}

/// Sets the default tracing_subscriber to write to `log_func`.
///
/// Uses Compact format without level, target, thread ids, thread names, or ansi control characters.
/// Subscribes to TRACE level events.
///
/// This function should only be called once as setting the default tracing_subscriber
/// more than once will result in an error.
///
/// Returns false on failure.
///
/// # Safety
///
/// `c_char` will be freed by the library after calling `log_func`. If the value needs
/// to be stored then `log_func` needs to create a copy, e.g. `strcpy`.
#[no_mangle]
pub unsafe extern "C" fn set_logging_function(
log_func: unsafe extern "C" fn(*const c_char),
) -> bool {
let result = std::panic::catch_unwind(|| -> bool {
let writer = FFIFunctionPointerWriter { log_func };
let format = fmt::format()
// don't include levels in formatted output
.with_level(false)
// don't include targets
.with_target(false)
// don't 'include the thread ID of the current thread
.with_thread_ids(false)
// don't 'include the name of the current thread
.with_thread_names(false)
// use the `Compact` formatting style.
.compact()
// disable terminal escape codes
.with_ansi(false);

if fmt()
.event_format(format)
.with_writer(std::sync::Mutex::new(writer))
.with_max_level(tracing::Level::TRACE)
.with_ansi(false)
.try_init()
.is_ok()
{
return true;
}

return false;
});
if let Ok(value) = result {
return value;
} else {
return false;
}
}

/// Allocate a new tunnel, return NULL on failure.
/// Keys must be valid base64 encoded 32-byte keys.
#[no_mangle]
Expand Down
17 changes: 17 additions & 0 deletions boringtun/src/wireguard_ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#pragma once

#include <stdint.h>
#include <stdbool.h>

struct wireguard_tunnel; // This corresponds to the Rust type

Expand Down Expand Up @@ -56,6 +57,22 @@ void x25519_key_to_str_free(const char *key_str);
// Returns 0 if not
int check_base64_encoded_x25519_key(const char *key);

/// Sets the default tracing_subscriber to write to `log_func`.
///
/// Uses Compact format without level, target, thread ids, thread names, or ansi control characters.
/// Subscribes to TRACE level events.
///
/// This function should only be called once as setting the default tracing_subscriber
/// more than once will result in an error.
///
/// Returns false on failure.
///
/// # Safety
///
/// `c_char` will be freed by the library after calling `log_func`. If the value needs
/// to be stored then `log_func` needs to create a copy, e.g. `strcpy`.
bool set_logging_function(void (*log_func)(const char *));

// Allocate a new tunnel
struct wireguard_tunnel *new_tunnel(const char *static_private,
const char *server_static_public,
Expand Down

0 comments on commit 829dae2

Please sign in to comment.