mod weight;
pub use weight::*;
use std::ffi::OsStr;
use std::io;
use std::os::windows::io::AsRawHandle;
use std::ptr;
use std::sync::Arc;
use windows_sys::Win32::Foundation::ERROR_SUCCESS;
use windows_sys::Win32::Foundation::STATUS_SUCCESS;
use windows_sys::Win32::NetworkManagement::WindowsFilteringPlatform::{
FWP_EMPTY, FWP_UINT8, FWP_UINT64, FWPM_FILTER_CONDITION0, FWPM_FILTER_FLAG_BOOTTIME,
FWPM_FILTER_FLAG_PERSISTENT, FWPM_FILTER0, FwpmFilterAdd0, FwpmFilterDeleteById0,
FwpmFilterDeleteByKey0,
};
use windows_sys::core::GUID;
use crate::action::ActionType;
use crate::condition::Condition;
use crate::layer::Layer;
use crate::transaction::Transaction;
use crate::util::string_to_null_terminated_utf16;
#[derive(Clone)]
pub struct FilterBuilder<Name, Action> {
filter: FWPM_FILTER0,
display_data_name_buffer: Arc<[u16]>,
display_data_desc_buffer: Arc<[u16]>,
conditions: Vec<Condition>,
weight_value: u64,
_pd: std::marker::PhantomData<(Name, Action)>,
}
#[doc(hidden)]
pub struct FilterBuilderMissingName;
#[doc(hidden)]
pub struct FilterBuilderHasName;
#[doc(hidden)]
#[derive(Default)]
pub struct FilterBuilderMissingAction;
#[doc(hidden)]
pub struct FilterBuilderHasAction;
impl Default for FilterBuilder<FilterBuilderMissingName, FilterBuilderMissingAction> {
fn default() -> Self {
FilterBuilder {
filter: Default::default(),
display_data_name_buffer: Default::default(),
display_data_desc_buffer: Default::default(),
conditions: Default::default(),
weight_value: 0,
_pd: Default::default(),
}
}
}
impl<Name, Action> FilterBuilder<Name, Action> {
pub fn name(mut self, name: impl AsRef<OsStr>) -> FilterBuilder<FilterBuilderHasName, Action> {
self.display_data_name_buffer = string_to_null_terminated_utf16(name);
self.filter.displayData.name = self.display_data_name_buffer.as_ptr() as *mut _;
FilterBuilder {
filter: self.filter,
display_data_name_buffer: self.display_data_name_buffer,
display_data_desc_buffer: self.display_data_desc_buffer,
conditions: self.conditions,
weight_value: self.weight_value,
_pd: std::marker::PhantomData,
}
}
pub fn description(mut self, desc: impl AsRef<OsStr>) -> FilterBuilder<Name, Action> {
self.display_data_desc_buffer = string_to_null_terminated_utf16(desc);
self.filter.displayData.description = self.display_data_desc_buffer.as_ptr() as *mut _;
FilterBuilder {
filter: self.filter,
display_data_name_buffer: self.display_data_name_buffer,
display_data_desc_buffer: self.display_data_desc_buffer,
conditions: self.conditions,
weight_value: self.weight_value,
_pd: std::marker::PhantomData,
}
}
pub fn action(mut self, action: ActionType) -> FilterBuilder<Name, FilterBuilderHasAction> {
self.filter.action.r#type = action as u32;
FilterBuilder {
filter: self.filter,
display_data_name_buffer: self.display_data_name_buffer,
display_data_desc_buffer: self.display_data_desc_buffer,
conditions: self.conditions,
weight_value: self.weight_value,
_pd: std::marker::PhantomData,
}
}
pub fn guid(mut self, guid: GUID) -> FilterBuilder<Name, Action> {
self.filter.filterKey = guid;
self
}
pub fn layer(mut self, layer: Layer) -> FilterBuilder<Name, Action> {
self.filter.layerKey = *layer.guid();
self
}
pub fn sublayer(mut self, sublayer: GUID) -> FilterBuilder<Name, Action> {
self.filter.subLayerKey = sublayer;
self
}
pub fn weight(mut self, weight: impl Into<FilterWeight>) -> FilterBuilder<Name, Action> {
match weight.into() {
FilterWeight::Auto => {
self.filter.weight.r#type = FWP_EMPTY;
}
FilterWeight::Range(range) => {
self.filter.weight.r#type = FWP_UINT8;
self.filter.weight.Anonymous.uint8 = range.get();
}
FilterWeight::Exact(val) => {
self.weight_value = val;
self.filter.weight.r#type = FWP_UINT64;
}
}
self
}
pub fn lifetime(mut self, lifetime: FilterLifetime) -> FilterBuilder<Name, Action> {
self.filter.flags &= !(FWPM_FILTER_FLAG_BOOTTIME | FWPM_FILTER_FLAG_PERSISTENT);
match lifetime {
FilterLifetime::Default => {}
FilterLifetime::Boottime => {
self.filter.flags |= FWPM_FILTER_FLAG_BOOTTIME;
}
FilterLifetime::Persistent => {
self.filter.flags |= FWPM_FILTER_FLAG_PERSISTENT;
}
}
self
}
pub fn condition(mut self, condition: Condition) -> FilterBuilder<Name, Action> {
self.conditions.push(condition);
self
}
}
impl FilterBuilder<FilterBuilderHasName, FilterBuilderHasAction> {
pub fn add<'a>(&self, transaction: &Transaction<'a>) -> io::Result<()> {
let fwpm_conditions: Vec<FWPM_FILTER_CONDITION0> = self
.conditions
.iter()
.map(|condition| *condition.raw_condition())
.collect();
let mut filter = self.filter;
if !fwpm_conditions.is_empty() {
filter.numFilterConditions = u32::try_from(fwpm_conditions.len()).unwrap();
filter.filterCondition = fwpm_conditions.as_ptr() as *mut _;
}
if filter.weight.r#type == FWP_UINT64 {
filter.weight.Anonymous.uint64 = &self.weight_value as *const u64 as *mut u64;
}
let status = unsafe {
FwpmFilterAdd0(
transaction.engine.as_raw_handle(),
&filter,
ptr::null_mut(),
ptr::null_mut(),
)
};
if status != ERROR_SUCCESS {
return Err(io::Error::from_raw_os_error(status as i32));
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum FilterLifetime {
#[default]
Default,
Boottime,
Persistent,
}
pub fn delete_filter<'a>(transaction: &Transaction<'a>, id: u64) -> io::Result<()> {
let status = unsafe { FwpmFilterDeleteById0(transaction.engine.as_raw_handle(), id) };
if status != STATUS_SUCCESS as u32 {
return Err(io::Error::from_raw_os_error(status as i32));
}
Ok(())
}
pub fn delete_filter_by_guid<'a>(transaction: &Transaction<'a>, guid: &GUID) -> io::Result<()> {
let status = unsafe { FwpmFilterDeleteByKey0(transaction.engine.as_raw_handle(), guid) };
if status != STATUS_SUCCESS as u32 {
return Err(io::Error::from_raw_os_error(status as i32));
}
Ok(())
}