1use std::path::PathBuf;
25use std::thread;
26use std::time::Duration;
27use windows_wfp::{
28 initialize_wfp, Action, Direction, FilterBuilder, FilterRule, FilterWeight, NetworkEvent,
29 WfpEngine, WfpEventSubscription, WfpResult,
30};
31
32fn main() -> WfpResult<()> {
33 println!("TRusTY Wall - Live WFP Demo");
34 println!("================================\n");
35
36 if !is_elevated() {
38 eprintln!("ERROR: This demo requires Administrator privileges!");
39 eprintln!(" Please run: cargo run --example live_demo --release");
40 eprintln!(" from an Administrator command prompt.\n");
41 std::process::exit(1);
42 }
43
44 println!("Running with Administrator privileges\n");
45
46 println!("Step 1: Opening WFP Engine session...");
48 let engine = WfpEngine::new()?;
49 println!(" Engine session opened\n");
50
51 println!("Step 2: Registering WFP provider & sublayer...");
53 initialize_wfp(&engine)?;
54 println!(" Provider & sublayer registered\n");
55
56 println!("Step 3: Subscribing to network events...");
58 let event_subscription = WfpEventSubscription::new(&engine)?;
59 println!(" Event subscription active\n");
60
61 println!("Step 4: Adding block filter for curl.exe...");
63 let curl_path = find_curl_path();
64 println!(" Target: {}", curl_path.display());
65
66 let block_rule = FilterRule::new("Block curl.exe", Direction::Outbound, Action::Block)
67 .with_weight(FilterWeight::UserBlock)
68 .with_app_path(curl_path.clone());
69
70 let filter_id = FilterBuilder::add_filter(&engine, &block_rule)?;
71 println!(" Filter added (ID: {})\n", filter_id);
72
73 println!("Step 5: Monitoring network events...");
75 println!(" Press Ctrl+C to stop\n");
76 println!("TIP: In another terminal, run:");
77 println!(" > curl https://google.com");
78 println!(" You should see the connection BLOCKED below!\n");
79 println!("===================================================\n");
80
81 let start_time = std::time::Instant::now();
82 let mut event_count = 0;
83
84 loop {
85 match event_subscription.try_recv() {
86 Ok(event) => {
87 event_count += 1;
88 print_event(&event, event_count);
89 }
90 Err(std::sync::mpsc::TryRecvError::Empty) => {
91 thread::sleep(Duration::from_millis(100));
92 }
93 Err(std::sync::mpsc::TryRecvError::Disconnected) => {
94 println!("\nEvent channel disconnected!");
95 break;
96 }
97 }
98
99 if start_time.elapsed() > Duration::from_secs(60) {
101 println!("\nDemo timeout (60s) - stopping...");
102 break;
103 }
104 }
105
106 println!("\nCleaning up...");
108 FilterBuilder::delete_filter(&engine, filter_id)?;
109 println!(" Filter removed");
110 drop(event_subscription);
111 println!(" Event subscription closed");
112 drop(engine);
113 println!(" Engine session closed\n");
114
115 println!("Demo complete! {} events captured.", event_count);
116 Ok(())
117}
118
119fn print_event(event: &NetworkEvent, count: usize) {
120 println!("Event #{}: {:?}", count, event.event_type);
121 println!(" Timestamp: {:?}", event.timestamp);
122
123 if let Some(ref path) = event.app_path {
124 println!(" Application: {}", path.display());
125 }
126
127 if let Some(local) = event.local_addr {
128 println!(" Local: {}:{}", local, event.local_port);
129 }
130
131 if let Some(remote) = event.remote_addr {
132 println!(" Remote: {}:{}", remote, event.remote_port);
133 }
134
135 println!(" Protocol: {}", event.protocol);
136
137 if let Some(filter_id) = event.filter_id {
138 println!(" Filter ID: {}", filter_id);
139 }
140
141 if let Some(layer_id) = event.layer_id {
142 println!(" Layer ID: {}", layer_id);
143 }
144
145 println!();
146}
147
148fn find_curl_path() -> PathBuf {
149 let candidates = vec![
150 r"C:\Windows\System32\curl.exe",
151 r"C:\Program Files\Git\mingw64\bin\curl.exe",
152 r"C:\tools\curl\bin\curl.exe",
153 ];
154
155 for path in candidates {
156 let p = PathBuf::from(path);
157 if p.exists() {
158 return p;
159 }
160 }
161
162 PathBuf::from(r"C:\Windows\System32\curl.exe")
163}
164
165fn is_elevated() -> bool {
166 #[cfg(windows)]
167 {
168 use std::mem;
169 use windows::Win32::Foundation::{CloseHandle, HANDLE};
170 use windows::Win32::Security::{
171 GetTokenInformation, TokenElevation, TOKEN_ELEVATION, TOKEN_QUERY,
172 };
173 use windows::Win32::System::Threading::{GetCurrentProcess, OpenProcessToken};
174
175 unsafe {
176 let mut token: HANDLE = HANDLE::default();
177 let process = GetCurrentProcess();
178
179 if OpenProcessToken(process, TOKEN_QUERY, &mut token).is_err() {
180 return false;
181 }
182
183 let mut elevation = TOKEN_ELEVATION { TokenIsElevated: 0 };
184 let mut returned_length: u32 = 0;
185
186 let result = GetTokenInformation(
187 token,
188 TokenElevation,
189 Some(&mut elevation as *mut _ as *mut _),
190 mem::size_of::<TOKEN_ELEVATION>() as u32,
191 &mut returned_length,
192 );
193
194 let _ = CloseHandle(token);
195
196 result.is_ok() && elevation.TokenIsElevated != 0
197 }
198 }
199
200 #[cfg(not(windows))]
201 false
202}