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

Add RateLimiter functions to the C FFI #330

Open
wants to merge 3 commits into
base: master
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
127 changes: 126 additions & 1 deletion boringtun/src/ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#![allow(clippy::missing_safety_doc)]

//! C bindings for the BoringTun library
use super::noise::{Tunn, TunnResult};
use super::noise::{Tunn, TunnResult, rate_limiter::RateLimiter, Packet};
use crate::x25519::{PublicKey, StaticSecret};
use base64::{decode, encode};
use hex::encode as encode_hex;
Expand Down Expand Up @@ -53,6 +53,12 @@ pub struct wireguard_result {
pub size: usize,
}

#[repr(C)]
pub struct wireguard_verify_result{
pub result: wireguard_result,
pub idx: i32,
}

#[repr(C)]
pub struct stats {
pub time_since_last_handshake: i64,
Expand Down Expand Up @@ -403,3 +409,122 @@ pub unsafe extern "C" fn wireguard_stats(tunnel: *const Mutex<Tunn>) -> stats {
reserved: [0u8; 56],
}
}

/// Rate Limiter
/// Returns null ptr on error.
#[no_mangle]
pub unsafe extern "C" fn new_rate_limiter(
server_static_public: *const c_char,
limit: u64,
) -> *mut Mutex<RateLimiter> {
let c_str = CStr::from_ptr(server_static_public);
let server_static_public = match c_str.to_str() {
Err(_) => return ptr::null_mut(),
Ok(string) => string,
};

let public_key = match server_static_public.parse::<KeyBytes>() {
Err(_) => return ptr::null_mut(),
Ok(key) => PublicKey::from(key.0),
};

let limiter = Box::new(Mutex::new(RateLimiter::new(
&public_key,
limit,
)));

PANIC_HOOK.call_once(|| {
// FFI won't properly unwind on panic, but it will if we cause a segmentation fault
panic::set_hook(Box::new(move |_| {
raise(SIGSEGV);
}));
});

Box::into_raw(limiter)
}

/// Drops the Rate Limiter object
#[no_mangle]
pub unsafe extern "C" fn rate_limiter_free(rate_limiter: *mut Mutex<RateLimiter>) {
drop(Box::from_raw(rate_limiter));
}

/// Rate limiter verify packet
/// `dst_size` will be zero if no cookie challenge.
/// TODO
#[no_mangle]
pub unsafe extern "C" fn wireguard_verify_packet(
rate_limiter: *const Mutex<RateLimiter>,
src: *const u8,
src_size: u32,
dst: *mut u8,
dst_size: u32,
) -> wireguard_verify_result {
// Slices are not owned, and therefore will not be freed by Rust
let src = slice::from_raw_parts(src, src_size as usize);
let dst = slice::from_raw_parts_mut(dst, dst_size as usize);
// Lock the rate limiter from other use
let rate_limiter = rate_limiter.as_ref().unwrap().lock();
// TODO input IP addr
let rl_result = rate_limiter.verify_packet(None, src, dst);
match rl_result{
Ok(rl_result) => {
match rl_result
{
Packet::HandshakeInit(_) => {
wireguard_verify_result {
result: wireguard_result {
op: result_type::WIREGUARD_DONE,
size: 0,
},
idx: -1,
}
},
Packet::HandshakeResponse(r) => {
wireguard_verify_result {
result: wireguard_result {
op: result_type::WIREGUARD_DONE,
size: 0,
},
idx: r.receiver_idx as i32,
}
},
Packet::PacketCookieReply(r) => {
wireguard_verify_result {
result: wireguard_result {
op: result_type::WIREGUARD_DONE,
size: 0,
},
idx: r.receiver_idx as i32,
}
},
Packet::PacketData(r) => {
wireguard_verify_result {
result: wireguard_result {
op: result_type::WIREGUARD_DONE,
size: 0,
},
idx: r.receiver_idx as i32,
}
},
}
},
Err(rl_result) => {
wireguard_verify_result {
result: wireguard_result::from(rl_result),
idx: -1,
}
},
}
}

/// Reset the wireguard packet count
#[no_mangle]
pub unsafe extern "C" fn wireguard_reset_count(
rate_limiter: *const Mutex<RateLimiter>,
) {
// Lock the rate limiter from other use
let rate_limiter = rate_limiter.as_ref().unwrap().lock();

rate_limiter.reset_count();
}
25 changes: 25 additions & 0 deletions boringtun/src/wireguard_ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <stdbool.h>

struct wireguard_tunnel; // This corresponds to the Rust type
struct wireguard_rate_limiter; // This corresponds to the Rust type

enum
{
Expand All @@ -28,6 +29,12 @@ struct wireguard_result
size_t size;
};

struct wireguard_verify_result
{
wireguard_result result;
int32_t idx; // idx (-1 if not available)
};

struct stats
{
int64_t time_since_last_handshake;
Expand Down Expand Up @@ -104,3 +111,21 @@ struct wireguard_result wireguard_force_handshake(const struct wireguard_tunnel
uint32_t dst_size);

struct stats wireguard_stats(const struct wireguard_tunnel *tunnel);

// Allocate a rate limiter
struct wireguard_rate_limiter *new_rate_limiter(const char *server_static_public,
uint64_t limit);

// Deallocate the rate limiter
void rate_limiter_free(struct wireguard_rate_limiter *);

// Verify a packet.
// May produce a packet to request a cookie from the peer
struct wireguard_verify_result wireguard_verify_packet(const struct wireguard_rate_limiter *rate_limiter,
const uint8_t *src,
uint32_t src_size,
uint8_t *dst,
uint32_t dst_size);

// Reset the wireguard rate limiter
void wireguard_reset_count(struct wireguard_rate_limiter *);