From 9db3ef91579901b4a1bc8aae18888de427cd550b Mon Sep 17 00:00:00 2001 From: Eliezer Croitoru Date: Sun, 15 Feb 2026 14:09:34 +0200 Subject: [PATCH] 1 --- Makefile | 32 +++++++++++++ wg-healthcheck-service.service | 28 +++++++++++ wg-healthcheck.py | 87 ++++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 Makefile create mode 100644 wg-healthcheck-service.service create mode 100755 wg-healthcheck.py diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..95ca3c4 --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ +all: + echo OK + +install: install-service enable-service start-service + cp -vf wg-healthcheck.py /usr/local/bin/ + +uninstall: remove-service + rm -vf /usr/local/bin/wg-healthcheck.py + +install-service: + cp -vf wg-healthcheck-service.service /etc/systemd/system/wg-healthcheck-wg1.service + systemctl daemon-reload + +remove-service: stop-service disable-service + systemctl daemon-reload + +enable-service: + systemctl enable wg-healthcheck-wg1.service + +disable-service: + systemctl disable wg-healthcheck-wg1.service + + +start-service: + systemctl start wg-healthcheck-wg1.service + +stop-service: + systemctl start wg-healthcheck-wg1.service;true + +restart-service: stop-service start-service + + diff --git a/wg-healthcheck-service.service b/wg-healthcheck-service.service new file mode 100644 index 0000000..e81fd02 --- /dev/null +++ b/wg-healthcheck-service.service @@ -0,0 +1,28 @@ +[Unit] +Description=Network Device Health Check Service +After=network.target + +[Service] +# Run as a specific unprivileged user +User=nobody +Group=nobody + +# Path to your Python script +ExecStart=/usr/bin/python3 /usr/local/bin/wg-healthcheck.py --device wg1 --port 18081 + +# Restart settings +Restart=always +RestartSec=5 + +# Security Hardening +# Allows the script to query network state without being root +AmbientCapabilities=CAP_NET_ADMIN +NoNewPrivileges=true + +# Standard isolation +ProtectSystem=full +ProtectHome=true +PrivateTmp=true + +[Install] +WantedBy=multi-user.target diff --git a/wg-healthcheck.py b/wg-healthcheck.py new file mode 100755 index 0000000..dc97487 --- /dev/null +++ b/wg-healthcheck.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 + +import subprocess +import argparse +from http.server import HTTPServer, BaseHTTPRequestHandler + +class HealthCheckHandler(BaseHTTPRequestHandler): + """ + HTTP server that returns 200 if a network device is up, + and 503 if it is down or missing. + """ + + def check_device(self): + device = self.server.device + try: + # -run command: ip link show up + # -check=True ensures we can catch errors easily + # -capture_output=True keeps the terminal clean + result = subprocess.run( + ["ip", "link", "show", device, "up"], + capture_output=True, + text=True, + check=False + ) + # Return True only if exit code is 0 and output is not empty + return result.returncode == 0 and len(result.stdout.strip()) > 0 + except FileNotFoundError: + print("Error: 'ip' command not found. Are you on Linux?") + return False + + def do_GET(self): + if self.check_device(): + self.send_response(200) + self.send_header("Content-Type", "text/plain") + self.end_headers() + self.wfile.write(b"healthy\n") + else: + self.send_response(503) + self.send_header("Content-Type", "text/plain") + self.end_headers() + self.wfile.write(b"unhealthy\n") + + def do_HEAD(self): + self.do_GET() + + # Suppress standard logging to keep console clean, optional + def log_message(self, format, *args): + return + +def main(): + parser = argparse.ArgumentParser( + description="Modern HTTP health check for network devices." + ) + parser.add_argument("-d", "--device", default="wg0", + help="Device name to check (e.g., eth0, wg0). Default: wg0") + parser.add_argument("-p", "--port", type=int, default=8080, + help="Port to listen on. Default: 8080") + parser.add_argument("-t", "--test", action="store_true", + help="Check status once and exit.") + + args = parser.parse_args() + + # logic for --test flag + if args.test: + # Temporary mock-up of the check logic for CLI test + cmd = ["ip", "link", "show", args.device, "up"] + res = subprocess.run(cmd, capture_output=True, text=True) + if res.returncode == 0 and res.stdout: + print(f"Device {args.device}: UP") + exit(0) + else: + print(f"Device {args.device}: DOWN") + exit(1) + + # Start the Server + server = HTTPServer(('', args.port), HealthCheckHandler) + server.device = args.device + print(f"Starting health check server for {args.device} on port {args.port}...") + + try: + server.serve_forever() + except KeyboardInterrupt: + print("\nShutting down server.") + server.server_close() + +if __name__ == "__main__": + main()