Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,24 @@ journalctl --user -u netboozt-dns.service
./uninstall-systemd.sh
```

### Servicio DNS en Windows

Ejecuta el failover DNS como servicio de Windows — sobrevive reinicios y corre sin usuario logueado:

```powershell
# Compilar (en Windows, con Rust toolchain)
cargo build --release --bin netboozt-service

# Instalar (como Administrador)
.\platforms\tauri\scripts\install-windows-service.ps1

# Estado
Get-Service netboozt-dns

# Desinstalar (como Administrador)
.\platforms\tauri\scripts\uninstall-windows-service.ps1
```

---

## 🎯 Perfiles
Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,24 @@ journalctl --user -u netboozt-dns.service
./uninstall-systemd.sh
```

### Windows DNS Failover Service

Run DNS failover as a Windows Service — survives restarts and runs without a logged-in user:

```powershell
# Build (on Windows, with Rust toolchain)
cargo build --release --bin netboozt-service

# Install (run as Administrator)
.\platforms\tauri\scripts\install-windows-service.ps1

# Status
Get-Service netboozt-dns

# Uninstall (run as Administrator)
.\platforms\tauri\scripts\uninstall-windows-service.ps1
```

---

## 🎯 Profiles
Expand Down
72 changes: 72 additions & 0 deletions platforms/tauri/scripts/install-windows-service.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# install-windows-service.ps1 — Install NetBoozt DNS failover as a Windows Service.
#
# Usage: .\install-windows-service.ps1
# Requires: Administrator privileges, netboozt-service.exe built.
#
# By LOUST (www.loust.pro)

param(
[string]$BinaryPath = "$PWD\target\release\netboozt-service.exe"
)

$ErrorActionPreference = 'Stop'

Write-Host "==> NetBoozt DNS Failover — Windows Service installer" -ForegroundColor Cyan

# Check for admin
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Error "This script requires Administrator privileges. Run as Admin."
exit 1
}

# Find binary
if (-not (Test-Path $BinaryPath)) {
Write-Error "Binary not found at: $BinaryPath"
Write-Host "Build it first: cargo build --release --bin netboozt-service" -ForegroundColor Yellow
exit 1
}

$serviceName = "netboozt-dns"

# Check if already installed
$existing = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
if ($existing) {
Write-Host "Service '$serviceName' already exists. Stopping and removing..." -ForegroundColor Yellow
Stop-Service -Name $serviceName -Force -ErrorAction SilentlyContinue
sc.exe delete $serviceName | Out-Null
Start-Sleep -Seconds 2
}

# Create the service
Write-Host "Creating service '$serviceName'..."
$createResult = sc.exe create $serviceName binPath= "$BinaryPath" DisplayName= "NetBoozt DNS Failover" start= auto type= own
if ($LASTEXITCODE -ne 0) {
Write-Error "Failed to create service: $createResult"
exit 1
}

# Set recovery options
Write-Host "Configuring recovery options..."
sc.exe failure $serviceName reset= 86400 actions= restart/10000/restart/10000/restart/10000 | Out-Null

# Start the service
Write-Host "Starting service..."
Start-Service -Name $serviceName -ErrorAction SilentlyContinue

# Verify
$svc = Get-Service -Name $serviceName
if ($svc.Status -eq 'Running') {
Write-Host ""
Write-Host "✅ Service '$serviceName' is running." -ForegroundColor Green
Write-Host ""
Write-Host "Useful commands:"
Write-Host " Get-Service $serviceName # view status"
Write-Host " sc.exe query $serviceName # detailed status"
Write-Host " Stop-Service $serviceName # stop"
Write-Host " sc.exe delete $serviceName # remove (use uninstall script instead)"
} else {
Write-Host ""
Write-Warning "Service started but may not be fully running yet. Status: $($svc.Status)"
Write-Host "Check: Get-Service $serviceName"
}
49 changes: 49 additions & 0 deletions platforms/tauri/scripts/uninstall-windows-service.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# uninstall-windows-service.ps1 — Remove the NetBoozt DNS failover Windows Service.
#
# Usage: .\uninstall-windows-service.ps1
# Requires: Administrator privileges.
#
# By LOUST (www.loust.pro)

param(
[switch]$Force
)

$ErrorActionPreference = 'Stop'

Write-Host "==> NetBoozt DNS Failover — Windows Service uninstaller" -ForegroundColor Cyan

$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Error "This script requires Administrator privileges. Run as Admin."
exit 1
}

$serviceName = "netboozt-dns"

# Check if service exists
$svc = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
if (-not $svc) {
Write-Host "Service '$serviceName' not found. Nothing to uninstall." -ForegroundColor Yellow
exit 0
}

# Stop
if ($svc.Status -eq 'Running') {
Write-Host "Stopping service..."
Stop-Service -Name $serviceName -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 2
}

# Delete
Write-Host "Deleting service..."
$deleteResult = sc.exe delete $serviceName
if ($LASTEXITCODE -ne 0) {
Write-Error "Failed to delete service: $deleteResult"
exit 1
}

Write-Host ""
Write-Host "✅ Service '$serviceName' uninstalled." -ForegroundColor Green
Write-Host ""
Write-Host "Note: The netboozt-service.exe binary was not modified."
6 changes: 6 additions & 0 deletions platforms/tauri/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ windows = { version = "0.52", features = [
"Win32_System_Registry",
"Win32_NetworkManagement_IpHelper",
"Win32_Networking_WinSock",
"Win32_System_Services",
] }
windows-service = "0.6"

[features]
# This feature is used for production builds or when a dev server is not specified
Expand All @@ -48,3 +50,7 @@ custom-protocol = ["tauri/custom-protocol"]
[[bin]]
name = "netboozt-headless"
path = "src/bin/netboozt-headless.rs"

[[bin]]
name = "netboozt-service"
path = "src/bin/netboozt-service.rs"
22 changes: 22 additions & 0 deletions platforms/tauri/src-tauri/src/bin/netboozt-service.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! `netboozt-service` — Windows Service wrapper for DNS failover.
//!
//! Usage (after install):
//! sc start netboozt-dns
//! sc stop netboozt-dns
//!
//! Build on Windows with:
//! cargo build --release --bin netboozt-service

fn main() {
#[cfg(windows)]
{
netboozt_service_win::run_service();
}

#[cfg(not(windows))]
{
eprintln!("netboozt-service is only available on Windows.");
eprintln!("On Linux, use netboozt-headless with systemd instead.");
std::process::exit(1);
}
}
79 changes: 79 additions & 0 deletions platforms/tauri/src-tauri/src/bin/windows_service/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//! Windows Service implementation — only compiles on Windows.

#[cfg(windows)]
pub fn run_service() {
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;

use windows_service::service::{
ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus,
ServiceType,
};
use windows_service::service_control_handler::{self, ServiceControlHandlerResult};

static STOP_EVENT: AtomicBool = AtomicBool::new(false);

fn service_main(_arguments: Vec<std::ffi::OsString>) {
let status_handle =
service_control_handler::register("netboozt-dns", |event| match event {
ServiceControl::Stop => {
STOP_EVENT.store(true, Ordering::SeqCst);
ServiceControlHandlerResult::NoError
}
ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
_ => ServiceControlHandlerResult::Default,
})
.expect("Failed to register service control handler");

status_handle
.set_service_status(ServiceStatus {
service_type: ServiceType::OWN_PROCESS,
current_state: ServiceState::Running,
controls_accepted: ServiceControlAccept::STOP,
exit_code: ServiceExitCode::Win32(0),
checkpoint: 0,
wait_hint: Duration::default(),
})
.expect("Failed to set service status");

env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info"))
.format_timestamp_millis()
.init();

log::info!(
"netboozt-service v{} starting as Windows Service",
env!("CARGO_PKG_VERSION")
);

std::thread::spawn(|| {
netboozt::start_dns_intelligence();
});

while !STOP_EVENT.load(Ordering::SeqCst) {
std::thread::sleep(Duration::from_secs(1));
}

status_handle
.set_service_status(ServiceStatus {
service_type: ServiceType::OWN_PROCESS,
current_state: ServiceState::StopPending,
controls_accepted: ServiceControlAccept::empty(),
exit_code: ServiceExitCode::Win32(0),
checkpoint: 0,
wait_hint: Duration::default(),
})
.ok();

log::info!("Stopping DNS Intelligence service...");
netboozt::stop_dns_intelligence();
log::info!("netboozt-service stopped");
}

windows_service::define_windows_service!(ffi_service_main, service_main);
}

#[cfg(not(windows))]
pub fn run_service() {
// Stub: this function is never called on non-Windows platforms.
// The main binary already exits early on non-Windows.
}
Loading