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::FWPM_FILTER_CONDITION0;
use windows_sys::Win32::NetworkManagement::WindowsFilteringPlatform::FWPM_FILTER0;
use windows_sys::Win32::NetworkManagement::WindowsFilteringPlatform::FwpmFilterAdd0;
use windows_sys::Win32::NetworkManagement::WindowsFilteringPlatform::FwpmFilterDeleteById0;
use windows_sys::Win32::NetworkManagement::WindowsFilteringPlatform::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>,
_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(),
_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,
_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,
_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,
_pd: std::marker::PhantomData,
}
}
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 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 _;
}
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(())
}
}
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(())
}