Skip to main content

windows_wfp/
errors.rs

1//! WFP error types
2//!
3//! Error types for Windows Filtering Platform operations.
4
5use thiserror::Error;
6use windows::Win32::Foundation::WIN32_ERROR;
7
8/// WFP operation errors
9#[derive(Error, Debug)]
10pub enum WfpError {
11    /// Failed to open WFP engine session
12    #[error("Failed to open WFP engine session")]
13    EngineOpenFailed,
14
15    /// Failed to close WFP engine session
16    #[error("Failed to close WFP engine session")]
17    EngineCloseFailed,
18
19    /// Failed to add filter
20    #[error("Failed to add filter: {0}")]
21    FilterAddFailed(String),
22
23    /// Failed to delete filter
24    #[error("Failed to delete filter: {0}")]
25    FilterDeleteFailed(String),
26
27    /// Failed to begin transaction
28    #[error("Failed to begin WFP transaction")]
29    TransactionBeginFailed,
30
31    /// Failed to commit transaction
32    #[error("Failed to commit WFP transaction")]
33    TransactionCommitFailed,
34
35    /// Failed to abort transaction
36    #[error("Failed to abort WFP transaction")]
37    TransactionAbortFailed,
38
39    /// Application path not found or could not be converted to NT kernel format
40    ///
41    /// This error occurs when `FwpmGetAppIdFromFileName0` fails, typically because
42    /// the executable does not exist at the specified path.
43    #[error("Application path not found or invalid: {0}")]
44    AppPathNotFound(String),
45
46    /// Insufficient permissions (must run as administrator)
47    #[error("Insufficient permissions - administrator privileges required")]
48    InsufficientPermissions,
49
50    /// WFP service not available
51    #[error("Windows Filtering Platform service not available")]
52    ServiceNotAvailable,
53
54    /// Win32 API error with code and message
55    #[error("Win32 error {code}: {message}")]
56    Win32Error { code: u32, message: String },
57
58    /// Generic error with description
59    #[error("{0}")]
60    Other(String),
61}
62
63impl From<WIN32_ERROR> for WfpError {
64    fn from(error: WIN32_ERROR) -> Self {
65        let code = error.0;
66        let message = match code {
67            5 => "Access denied".to_string(),
68            1062 => "Service not started".to_string(),
69            1075 => "Service dependency does not exist".to_string(),
70            _ => format!("Unknown Win32 error: {}", code),
71        };
72
73        WfpError::Win32Error { code, message }
74    }
75}
76
77pub type WfpResult<T> = std::result::Result<T, WfpError>;
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn test_error_display_messages() {
85        assert_eq!(
86            WfpError::EngineOpenFailed.to_string(),
87            "Failed to open WFP engine session"
88        );
89        assert_eq!(
90            WfpError::InsufficientPermissions.to_string(),
91            "Insufficient permissions - administrator privileges required"
92        );
93        assert_eq!(
94            WfpError::ServiceNotAvailable.to_string(),
95            "Windows Filtering Platform service not available"
96        );
97        assert_eq!(
98            WfpError::TransactionBeginFailed.to_string(),
99            "Failed to begin WFP transaction"
100        );
101        assert_eq!(
102            WfpError::TransactionCommitFailed.to_string(),
103            "Failed to commit WFP transaction"
104        );
105        assert_eq!(
106            WfpError::TransactionAbortFailed.to_string(),
107            "Failed to abort WFP transaction"
108        );
109        assert_eq!(
110            WfpError::AppPathNotFound(r"C:\missing.exe".into()).to_string(),
111            r"Application path not found or invalid: C:\missing.exe"
112        );
113    }
114
115    #[test]
116    fn test_error_display_with_details() {
117        let err = WfpError::FilterAddFailed("test error".into());
118        assert_eq!(err.to_string(), "Failed to add filter: test error");
119
120        let err = WfpError::FilterDeleteFailed("filter 42".into());
121        assert_eq!(err.to_string(), "Failed to delete filter: filter 42");
122
123        let err = WfpError::Other("something happened".into());
124        assert_eq!(err.to_string(), "something happened");
125    }
126
127    #[test]
128    fn test_win32_error_display() {
129        let err = WfpError::Win32Error {
130            code: 5,
131            message: "Access denied".into(),
132        };
133        assert_eq!(err.to_string(), "Win32 error 5: Access denied");
134    }
135
136    #[test]
137    fn test_win32_error_conversion_access_denied() {
138        let err: WfpError = WIN32_ERROR(5).into();
139        match err {
140            WfpError::Win32Error { code, message } => {
141                assert_eq!(code, 5);
142                assert_eq!(message, "Access denied");
143            }
144            _ => panic!("Expected Win32Error"),
145        }
146    }
147
148    #[test]
149    fn test_win32_error_conversion_service_not_started() {
150        let err: WfpError = WIN32_ERROR(1062).into();
151        match err {
152            WfpError::Win32Error { code, message } => {
153                assert_eq!(code, 1062);
154                assert_eq!(message, "Service not started");
155            }
156            _ => panic!("Expected Win32Error"),
157        }
158    }
159
160    #[test]
161    fn test_win32_error_conversion_dependency_missing() {
162        let err: WfpError = WIN32_ERROR(1075).into();
163        match err {
164            WfpError::Win32Error { code, message } => {
165                assert_eq!(code, 1075);
166                assert_eq!(message, "Service dependency does not exist");
167            }
168            _ => panic!("Expected Win32Error"),
169        }
170    }
171
172    #[test]
173    fn test_win32_error_conversion_unknown() {
174        let err: WfpError = WIN32_ERROR(9999).into();
175        match err {
176            WfpError::Win32Error { code, message } => {
177                assert_eq!(code, 9999);
178                assert!(message.contains("Unknown"));
179            }
180            _ => panic!("Expected Win32Error"),
181        }
182    }
183}