Compare commits

...
Author SHA1 Message Date
Ian d786298e2c Build the machine-wide binaries only with the machine-wide feature 2026-10-22 17:35:32 -04:00
ian-at-strix 8d781f3f98 Show a popup when pausing or resuming screening fails (#54)
The service now answers Pause and Continue only after rewriting the hosts
file, returning the write's error so the tray's ControlService call fails
and shows it. The tray's popup includes the error's source, which
windows-service's own message hides.
2026-10-22 17:33:56 -04:00
5 changed files with 36 additions and 9 deletions

No files matched your search

+7
View File
@@ -38,14 +38,17 @@ path = "src/main.rs"
[[bin]]
name = "firewall-service"
path = "src/bin/firewall-service.rs"
required-features = ["machine-wide"]
[[bin]]
name = "firewall-tray"
path = "src/bin/firewall-tray.rs"
required-features = ["machine-wide"]
[[bin]]
name = "firewall-uninstall"
path = "src/bin/firewall-uninstall.rs"
required-features = ["machine-wide"]
[[example]]
name = "proxy-test"
@@ -87,6 +90,10 @@ path = "tests/tpm.rs"
name = "managers"
path = "tests/managers.rs"
[features]
# Builds the machine-wide binaries: the Windows service and tray, and the macOS uninstaller.
machine-wide = []
[dependencies]
clap = "4.6.6"
directories = "6.0.0"
+22 -7
View File
@@ -26,6 +26,7 @@ use std::net::{IpAddr, Ipv4Addr};
use std::sync::Arc;
use std::time::Duration;
use tracing_appender::rolling::{RollingFileAppender, Rotation};
use windows::Win32::Foundation::ERROR_GEN_FAILURE;
use windows_service::service::*;
use windows_service::service_control_handler::{
self, ServiceControlHandlerResult, ServiceStatusHandle,
@@ -73,8 +74,12 @@ fn run_until_stopped() -> Result<(), BoxError> {
| ServiceControl::Shutdown
| ServiceControl::Pause
| ServiceControl::Continue => {
let _ = control_sender.send(control);
ServiceControlHandlerResult::NoError
// Answered once handled, so a failed pause fails the caller's ControlService.
let (reply, handled) = tokio::sync::oneshot::channel();
let _ = control_sender.send((control, reply));
handled
.blocking_recv()
.unwrap_or(ServiceControlHandlerResult::NoError)
}
ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
_ => ServiceControlHandlerResult::NotImplemented,
@@ -89,16 +94,26 @@ fn run_until_stopped() -> Result<(), BoxError> {
}
};
// Only pausing removes our hosts entries; a stop or crash keeps them, failing closed.
while let Some(control) = control_receiver.recv().await {
while let Some((control, reply)) = control_receiver.recv().await {
let (hosts, state) = match control {
ServiceControl::Pause => (&[][..], ServiceState::Paused),
ServiceControl::Continue => (&hosts[..], ServiceState::Running),
_ => break,
};
match write_hosts_entries(hosts) {
Ok(()) => set_status(&status, state, false)?,
Err(error) => tracing::error!(%error, "could not rewrite the hosts file"),
}
let result = match write_hosts_entries(hosts) {
Ok(()) => {
set_status(&status, state, false)?;
ServiceControlHandlerResult::NoError
}
Err(error) => {
tracing::error!(%error, "could not rewrite the hosts file");
let code = error
.raw_os_error()
.map_or(ERROR_GEN_FAILURE.0, |code| code as u32);
ServiceControlHandlerResult::Other(code)
}
};
let _ = reply.send(result);
}
Ok::<_, BoxError>(())
});
+5 -1
View File
@@ -144,7 +144,11 @@ impl Tray {
}
fn show_error(error: BoxError) {
let text = HSTRING::from(error.to_string());
let text = match error.source() {
Some(source) => format!("{error}: {source}"),
None => error.to_string(),
};
let text = HSTRING::from(text);
unsafe { MessageBoxW(None, &text, w!("Strix Firewall"), MB_ICONERROR) };
}
+1
View File
@@ -7,6 +7,7 @@ ci = "github"
installers = ["shell", "powershell", "homebrew", "msi"]
# core/wix/main.wxs is edited to install the service.
allow-dirty = ["msi"]
features = ["machine-wide"]
tap = "usestrix/homebrew-tap"
publish-jobs = ["homebrew", "./publish-crates"]
targets = ["aarch64-apple-darwin", "x86_64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]
+1 -1
View File
@@ -133,7 +133,7 @@ targets:
arm64|arm64e) triple=aarch64-apple-darwin ;;
x86_64) triple=x86_64-apple-darwin ;;
esac
cargo build --bin firewall-uninstall --target $triple $([ "$CONFIGURATION" = Debug ] || echo --release)
cargo build --bin firewall-uninstall --features machine-wide --target $triple $([ "$CONFIGURATION" = Debug ] || echo --release)
bins="$bins target/$triple/$CARGO_PROFILE/firewall-uninstall"
done
lipo -create $bins -output "$TARGET_BUILD_DIR/$EXECUTABLE_FOLDER_PATH/firewall-uninstall"