Skip to main content

windows_wfp/
provider.rs

1//! WFP Provider and Sublayer management
2//!
3//! Handles registration of WFP provider and sublayer.
4
5use crate::constants::{WFP_PROVIDER_GUID, WFP_SUBLAYER_GUID};
6use crate::engine::WfpEngine;
7use crate::errors::{WfpError, WfpResult};
8use crate::transaction::WfpTransaction;
9use std::ptr;
10use windows::core::PWSTR;
11use windows::Win32::Foundation::ERROR_SUCCESS;
12use windows::Win32::NetworkManagement::WindowsFilteringPlatform::{
13    FwpmProviderAdd0, FwpmSubLayerAdd0, FWPM_PROVIDER0, FWPM_SUBLAYER0,
14};
15
16/// WFP Provider for windows-wfp
17///
18/// Registers the application as a WFP provider, allowing it to add filters
19/// to the Windows Filtering Platform.
20pub struct WfpProvider;
21
22impl WfpProvider {
23    /// Register windows-wfp as a WFP provider
24    ///
25    /// This must be called before adding any filters. The provider registration
26    /// is persistent and survives reboots.
27    ///
28    /// # Errors
29    ///
30    /// Returns `WfpError::Other` if provider registration fails.
31    ///
32    /// # Examples
33    ///
34    /// ```no_run
35    /// use windows_wfp::{WfpEngine, WfpProvider};
36    ///
37    /// let engine = WfpEngine::new()?;
38    /// WfpProvider::register(&engine)?;
39    /// # Ok::<(), windows_wfp::WfpError>(())
40    /// ```
41    pub fn register(engine: &WfpEngine) -> WfpResult<()> {
42        // Keep wide strings alive for the duration of the function
43        let name_wide: Vec<u16> = "windows-wfp"
44            .encode_utf16()
45            .chain(std::iter::once(0))
46            .collect();
47        let desc_wide: Vec<u16> = "windows-wfp Firewall Provider"
48            .encode_utf16()
49            .chain(std::iter::once(0))
50            .collect();
51
52        let provider = FWPM_PROVIDER0 {
53            providerKey: WFP_PROVIDER_GUID,
54            displayData:
55                windows::Win32::NetworkManagement::WindowsFilteringPlatform::FWPM_DISPLAY_DATA0 {
56                    name: PWSTR(name_wide.as_ptr() as *mut u16),
57                    description: PWSTR(desc_wide.as_ptr() as *mut u16),
58                },
59            flags: 0,
60            providerData:
61                windows::Win32::NetworkManagement::WindowsFilteringPlatform::FWP_BYTE_BLOB {
62                    size: 0,
63                    data: ptr::null_mut(),
64                },
65            serviceName: PWSTR::null(),
66        };
67
68        unsafe {
69            let result = FwpmProviderAdd0(engine.handle(), &provider, None);
70
71            if result != ERROR_SUCCESS.0 {
72                // ERROR_FWP_ALREADY_EXISTS (0x80320009) is acceptable
73                if result != 0x80320009 {
74                    return Err(WfpError::Other(format!(
75                        "Failed to register provider: error code {}",
76                        result
77                    )));
78                }
79            }
80        }
81
82        Ok(())
83    }
84}
85
86/// WFP Sublayer for windows-wfp filters
87///
88/// All windows-wfp filters are added to this sublayer, allowing them to be
89/// managed as a group and ensuring proper priority.
90pub struct WfpSublayer;
91
92impl WfpSublayer {
93    /// Register windows-wfp sublayer
94    ///
95    /// The sublayer groups all windows-wfp filters together and assigns them
96    /// a specific weight for priority ordering.
97    ///
98    /// # Errors
99    ///
100    /// Returns `WfpError::Other` if sublayer registration fails.
101    ///
102    /// # Examples
103    ///
104    /// ```no_run
105    /// use windows_wfp::{WfpEngine, WfpProvider, WfpSublayer};
106    ///
107    /// let engine = WfpEngine::new()?;
108    /// WfpProvider::register(&engine)?;
109    /// WfpSublayer::register(&engine)?;
110    /// # Ok::<(), windows_wfp::WfpError>(())
111    /// ```
112    pub fn register(engine: &WfpEngine) -> WfpResult<()> {
113        // Keep wide strings alive for the duration of the function
114        let name_wide: Vec<u16> = "windows-wfp Filters"
115            .encode_utf16()
116            .chain(std::iter::once(0))
117            .collect();
118        let desc_wide: Vec<u16> = "Sublayer for windows-wfp firewall exception filters"
119            .encode_utf16()
120            .chain(std::iter::once(0))
121            .collect();
122
123        let sublayer = FWPM_SUBLAYER0 {
124            subLayerKey: WFP_SUBLAYER_GUID,
125            displayData:
126                windows::Win32::NetworkManagement::WindowsFilteringPlatform::FWPM_DISPLAY_DATA0 {
127                    name: PWSTR(name_wide.as_ptr() as *mut u16),
128                    description: PWSTR(desc_wide.as_ptr() as *mut u16),
129                },
130            flags: 0,
131            providerKey: &WFP_PROVIDER_GUID as *const _ as *mut _,
132            providerData:
133                windows::Win32::NetworkManagement::WindowsFilteringPlatform::FWP_BYTE_BLOB {
134                    size: 0,
135                    data: ptr::null_mut(),
136                },
137            weight: 0xFFFF, // Maximum weight - highest priority for windows-wfp filters
138        };
139
140        unsafe {
141            let result = FwpmSubLayerAdd0(engine.handle(), &sublayer, None);
142
143            if result != ERROR_SUCCESS.0 {
144                // ERROR_FWP_ALREADY_EXISTS (0x80320009) is acceptable
145                if result != 0x80320009 {
146                    return Err(WfpError::Other(format!(
147                        "Failed to register sublayer: error code {}",
148                        result
149                    )));
150                }
151            }
152        }
153
154        Ok(())
155    }
156}
157
158/// Initialize windows-wfp WFP provider and sublayer
159///
160/// Convenience function that registers both the provider and sublayer
161/// in a single transaction.
162///
163/// # Errors
164///
165/// Returns `WfpError` if registration fails.
166///
167/// # Examples
168///
169/// ```no_run
170/// use windows_wfp::{WfpEngine, initialize_wfp};
171///
172/// let engine = WfpEngine::new()?;
173/// initialize_wfp(&engine)?;
174/// // Now ready to add filters
175/// # Ok::<(), windows_wfp::WfpError>(())
176/// ```
177pub fn initialize_wfp(engine: &WfpEngine) -> WfpResult<()> {
178    let txn = WfpTransaction::begin(engine)?;
179
180    WfpProvider::register(engine)?;
181    WfpSublayer::register(engine)?;
182
183    txn.commit()?;
184
185    Ok(())
186}
187
188#[cfg(test)]
189mod tests {
190    use super::*;
191
192    #[test]
193    #[ignore] // Requires admin privileges
194    fn test_provider_registration() {
195        let engine = WfpEngine::new().expect("Failed to create engine");
196        let result = WfpProvider::register(&engine);
197
198        // Should succeed or already exist
199        assert!(result.is_ok(), "Failed to register provider: {:?}", result);
200    }
201
202    #[test]
203    #[ignore] // Requires admin privileges
204    fn test_sublayer_registration() {
205        let engine = WfpEngine::new().expect("Failed to create engine");
206
207        // Provider must be registered first
208        WfpProvider::register(&engine).expect("Failed to register provider");
209
210        let result = WfpSublayer::register(&engine);
211        assert!(result.is_ok(), "Failed to register sublayer: {:?}", result);
212    }
213
214    #[test]
215    #[ignore] // Requires admin privileges
216    fn test_initialize_wfp() {
217        let engine = WfpEngine::new().expect("Failed to create engine");
218        let result = initialize_wfp(&engine);
219
220        assert!(result.is_ok(), "Failed to initialize WFP: {:?}", result);
221    }
222
223    #[test]
224    #[ignore] // Requires admin privileges
225    fn test_double_registration_is_idempotent() {
226        let engine = WfpEngine::new().expect("Failed to create engine");
227
228        // First registration
229        initialize_wfp(&engine).expect("First registration failed");
230
231        // Second registration should also succeed (idempotent)
232        let result = initialize_wfp(&engine);
233        assert!(result.is_ok(), "Double registration should be idempotent");
234    }
235}