use crate::constants::{WFP_PROVIDER_GUID, WFP_SUBLAYER_GUID};
use crate::engine::WfpEngine;
use crate::errors::{WfpError, WfpResult};
use crate::transaction::WfpTransaction;
use std::ptr;
use windows::core::PWSTR;
use windows::Win32::Foundation::ERROR_SUCCESS;
use windows::Win32::NetworkManagement::WindowsFilteringPlatform::{
FwpmProviderAdd0, FwpmSubLayerAdd0, FWPM_PROVIDER0, FWPM_SUBLAYER0,
};
pub struct WfpProvider;
impl WfpProvider {
pub fn register(engine: &WfpEngine) -> WfpResult<()> {
let name_wide: Vec<u16> = "windows-wfp"
.encode_utf16()
.chain(std::iter::once(0))
.collect();
let desc_wide: Vec<u16> = "windows-wfp Firewall Provider"
.encode_utf16()
.chain(std::iter::once(0))
.collect();
let provider = FWPM_PROVIDER0 {
providerKey: WFP_PROVIDER_GUID,
displayData:
windows::Win32::NetworkManagement::WindowsFilteringPlatform::FWPM_DISPLAY_DATA0 {
name: PWSTR(name_wide.as_ptr() as *mut u16),
description: PWSTR(desc_wide.as_ptr() as *mut u16),
},
flags: 0,
providerData:
windows::Win32::NetworkManagement::WindowsFilteringPlatform::FWP_BYTE_BLOB {
size: 0,
data: ptr::null_mut(),
},
serviceName: PWSTR::null(),
};
unsafe {
let result = FwpmProviderAdd0(engine.handle(), &provider, None);
if result != ERROR_SUCCESS.0 {
if result != 0x80320009 {
return Err(WfpError::Other(format!(
"Failed to register provider: error code {}",
result
)));
}
}
}
Ok(())
}
}
pub struct WfpSublayer;
impl WfpSublayer {
pub fn register(engine: &WfpEngine) -> WfpResult<()> {
let name_wide: Vec<u16> = "windows-wfp Filters"
.encode_utf16()
.chain(std::iter::once(0))
.collect();
let desc_wide: Vec<u16> = "Sublayer for windows-wfp firewall exception filters"
.encode_utf16()
.chain(std::iter::once(0))
.collect();
let sublayer = FWPM_SUBLAYER0 {
subLayerKey: WFP_SUBLAYER_GUID,
displayData:
windows::Win32::NetworkManagement::WindowsFilteringPlatform::FWPM_DISPLAY_DATA0 {
name: PWSTR(name_wide.as_ptr() as *mut u16),
description: PWSTR(desc_wide.as_ptr() as *mut u16),
},
flags: 0,
providerKey: &WFP_PROVIDER_GUID as *const _ as *mut _,
providerData:
windows::Win32::NetworkManagement::WindowsFilteringPlatform::FWP_BYTE_BLOB {
size: 0,
data: ptr::null_mut(),
},
weight: 0xFFFF, };
unsafe {
let result = FwpmSubLayerAdd0(engine.handle(), &sublayer, None);
if result != ERROR_SUCCESS.0 {
if result != 0x80320009 {
return Err(WfpError::Other(format!(
"Failed to register sublayer: error code {}",
result
)));
}
}
}
Ok(())
}
}
pub fn initialize_wfp(engine: &WfpEngine) -> WfpResult<()> {
let txn = WfpTransaction::begin(engine)?;
WfpProvider::register(engine)?;
WfpSublayer::register(engine)?;
txn.commit()?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[ignore] fn test_provider_registration() {
let engine = WfpEngine::new().expect("Failed to create engine");
let result = WfpProvider::register(&engine);
assert!(result.is_ok(), "Failed to register provider: {:?}", result);
}
#[test]
#[ignore] fn test_sublayer_registration() {
let engine = WfpEngine::new().expect("Failed to create engine");
WfpProvider::register(&engine).expect("Failed to register provider");
let result = WfpSublayer::register(&engine);
assert!(result.is_ok(), "Failed to register sublayer: {:?}", result);
}
#[test]
#[ignore] fn test_initialize_wfp() {
let engine = WfpEngine::new().expect("Failed to create engine");
let result = initialize_wfp(&engine);
assert!(result.is_ok(), "Failed to initialize WFP: {:?}", result);
}
#[test]
#[ignore] fn test_double_registration_is_idempotent() {
let engine = WfpEngine::new().expect("Failed to create engine");
initialize_wfp(&engine).expect("First registration failed");
let result = initialize_wfp(&engine);
assert!(result.is_ok(), "Double registration should be idempotent");
}
}