Skip to content

add wireguard watchdog - #2242

Open
Puzzak01 wants to merge 7 commits into
OpenIPC:masterfrom
Puzzak01:master
Open

add wireguard watchdog#2242
Puzzak01 wants to merge 7 commits into
OpenIPC:masterfrom
Puzzak01:master

Conversation

@Puzzak01

@Puzzak01 Puzzak01 commented Aug 7, 2026

Copy link
Copy Markdown

No description provided.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Add WireGuard watchdog with cron-based health checks

✨ Enhancement ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Add a cron-scheduled WireGuard watchdog to detect stale/absent handshakes.
• Auto-restart WireGuard when the interface is down, peerless, or stale.
• Make WireGuard setup idempotent by deleting any pre-existing wg0 device.
Diagram

graph TD
  A(["Boot/init system"]) --> B["S98wireguard-watchdog (init)"] --> C["/run/cron/crontabs/root"] --> D(["crond"]) --> E["wireguard-watchdog (script)"] --> F["S98wireguard (init)"] --> G["wireguard (script)"] --> H(("wg0"))
  E --> I["/run/wireguard-watchdog.state"]

  subgraph Legend
    direction LR
    _svc(["Service/init"]) ~~~ _script["Script/file"] ~~~ _iface(("Interface"))
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Run watchdog as a supervised daemon (respawn) instead of cron
  • ➕ Faster reaction time than minute-granularity cron
  • ➕ Simpler interval logic (no parsing crontab)
  • ➕ Easier to add backoff/jitter and structured logging
  • ➖ Requires a supervisor mechanism (procd/inittab/systemd-like) on target
  • ➖ Long-running process footprint vs periodic execution
2. Use WireGuard built-in monitoring signals/hooks (netifd/hotplug/procd triggers)
  • ➕ Event-driven (restart only when link/route changes or interface flaps)
  • ➕ Potentially fewer false positives than handshake-age heuristics
  • ➖ Platform-specific integration complexity
  • ➖ Handshake-staleness still may require polling in many environments
3. Restart only the wg interface (ip link/wg) instead of re-running init script
  • ➕ More targeted recovery; avoids unrelated init side effects
  • ➕ Potentially faster restart
  • ➖ Must duplicate setup logic currently encapsulated in existing scripts
  • ➖ Greater risk of configuration drift vs reusing established start path

Recommendation: The cron-based watchdog is a pragmatic fit for minimal embedded environments and reuses the existing S98wireguard start path, reducing duplicated config logic. If faster recovery or richer health criteria become necessary, consider migrating to a supervised daemon model to avoid crontab parsing and minute-level scheduling granularity.

Files changed (3) +242 / -2

Enhancement (1) +149 / -0
wireguard-watchdogAdd watchdog script to validate wg0 health and restart on staleness +149/-0

Add watchdog script to validate wg0 health and restart on staleness

• Adds a lock-protected watchdog that checks for an UP interface, presence of peers, and recent handshakes using wg show. It persists a zero-handshake timer in /run, derives a stale threshold from persistent-keepalive and cron interval, and restarts WireGuard via S98wireguard when unhealthy.

general/overlay/usr/sbin/wireguard-watchdog

Bug fix (1) +2 / -2
wireguardMake WireGuard bring-up idempotent by deleting wg0 first +2/-2

Make WireGuard bring-up idempotent by deleting wg0 first

• Deletes any existing wg0 interface before loading the kernel module and recreating/configuring the interface. This reduces failures when the interface already exists from prior runs or partial restarts.

general/overlay/usr/sbin/wireguard

Other (1) +91 / -0
S98wireguard-watchdogAdd init script to schedule watchdog via cron in RAM +91/-0

Add init script to schedule watchdog via cron in RAM

• Introduces an init.d script that installs/removes a WireGuard watchdog cron entry in the RAM crontab and restarts crond. It conditionally enables scheduling only when wg_privkey is present in fw_printenv, and supports start/stop/restart/force actions.

general/overlay/etc/init.d/S98wireguard-watchdog

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 7, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Cron directory mismatch 🐞 Bug ≡ Correctness
Description
S98wireguard-watchdog installs the cron entry into /run/cron/crontabs/root, but crond is configured
to read /etc/crontabs, so the watchdog job likely never executes.
Code

general/overlay/etc/init.d/S98wireguard-watchdog[R6-8]

+WIREGUARD_CRONTABS_FLASH="/etc/crontabs/root"
+WIREGUARD_CRONTABS_RAM="/run/cron/crontabs/root"
+WIREGUARD_CRON_MARK="# run wireguard-watchdog every few minutes (autogenerated)"
Evidence
The watchdog init script modifies /run/cron/crontabs/root, but the crond init script explicitly
points crond at /etc/crontabs, and there are no other repo references indicating
/run/cron/crontabs is used by cron.

general/overlay/etc/init.d/S98wireguard-watchdog[6-8]
general/overlay/etc/init.d/S60crond[3-6]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The watchdog installer writes the cron job to `/run/cron/crontabs/root`, but the platform’s `crond` is started with `-c /etc/crontabs`, so it will not read the job file being modified.
### Issue Context
- `S98wireguard-watchdog` currently seeds from `/etc/crontabs/root` but writes updates to `/run/cron/crontabs/root`.
- `S60crond` starts `crond` with `-c /etc/crontabs`.
### Fix Focus Areas
- general/overlay/etc/init.d/S98wireguard-watchdog[6-8]
- general/overlay/etc/init.d/S60crond[3-6]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. wg0 deleted before validation 🐞 Bug ☼ Reliability
Description
The wireguard script now deletes wg0 before verifying modprobe and interface creation succeed; if
either step fails, an existing working tunnel is torn down and not restored.
Code

general/overlay/usr/sbin/wireguard[R3-6]

+ip link del dev wg0 2>/dev/null || true
+
modprobe wireguard || { echo "Error: Failed to load wireguard module." >&2; exit 1; }
ip link add dev wg0 type wireguard || { echo "Error: Failed to create wg0 interface." >&2; exit 1; }
-
Evidence
The new deletion line is executed before the commands that can exit the script on failure, so a
previously existing wg0 will be removed even when the subsequent setup fails.

general/overlay/usr/sbin/wireguard[3-6]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ip link del dev wg0` runs unconditionally before `modprobe wireguard` and `ip link add`. If `modprobe` or `ip link add` fails, the script exits, leaving the device deleted.
### Issue Context
This is especially risky because the new watchdog can trigger restarts; a transient failure becomes a hard outage.
### Fix Focus Areas
- general/overlay/usr/sbin/wireguard[3-6]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Restarts grow wireguard.conf ✓ Resolved 🐞 Bug ☼ Reliability
Description
wireguard-watchdog restarts WireGuard via S98wireguard start, which runs the wireguard script that
appends to /tmp/wireguard.conf without truncating; repeated restarts can accumulate duplicated
config blocks and eventually make configuration application unreliable.
Code

general/overlay/usr/sbin/wireguard-watchdog[R39-43]

+ log_watchdog "$reason; restarting $WIREGUARD_INTERFACE"
+ zero_handshake_since=0
+ save_state
+ /etc/init.d/S98wireguard start >/dev/null 2>&1
+}
Evidence
The watchdog’s restart path calls the WireGuard init script, which in turn runs the wireguard
command that appends to /tmp/wireguard.conf and then uses it for wg setconf. This makes repeated
restarts accumulate config content.

general/overlay/usr/sbin/wireguard-watchdog[37-43]
general/overlay/etc/init.d/S98wireguard[3-8]
general/overlay/usr/sbin/wireguard[7-22]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The watchdog restarts WireGuard by calling `S98wireguard start`. The `wireguard` script builds `/tmp/wireguard.conf` using `>>` (append), so repeated watchdog-triggered restarts keep accumulating content.
### Issue Context
This can cause unbounded file growth and may lead to invalid/duplicated configuration being passed into `wg setconf`.
### Fix Focus Areas
- general/overlay/usr/sbin/wireguard-watchdog[37-43]
- general/overlay/etc/init.d/S98wireguard[3-8]
- general/overlay/usr/sbin/wireguard[7-22]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. State file sourcing risk 🐞 Bug ⛨ Security
Description
wireguard-watchdog sources /run/wireguard-watchdog.state as shell code and overwrites it via cp; if
that path becomes attacker-controlled (e.g., writable/symlinked), it could enable root code
execution or file clobbering.
Code

general/overlay/usr/sbin/wireguard-watchdog[R19-21]

+ zero_handshake_since=0
+ [ -r "$STATE_FILE" ] && . "$STATE_FILE"
+}
Evidence
The state is loaded via . (shell execution) and is written back by copying onto a fixed pathname,
which is not symlink-safe if an attacker can influence that path.

general/overlay/usr/sbin/wireguard-watchdog[18-31]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The watchdog loads state by executing `. "$STATE_FILE"` and writes state with `cp` to a fixed path. If the state file is replaced/tampered with, it can execute arbitrary shell code; `cp` also follows symlinks.
### Issue Context
Exploitability depends on runtime permissions for `/run` and the state file, but the pattern is unsafe by design.
### Fix Focus Areas
- general/overlay/usr/sbin/wireguard-watchdog[18-31]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment on lines +6 to +8
WIREGUARD_CRONTABS_FLASH="/etc/crontabs/root"
WIREGUARD_CRONTABS_RAM="/run/cron/crontabs/root"
WIREGUARD_CRON_MARK="# run wireguard-watchdog every few minutes (autogenerated)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Cron directory mismatch 🐞 Bug ≡ Correctness

S98wireguard-watchdog installs the cron entry into /run/cron/crontabs/root, but crond is configured
to read /etc/crontabs, so the watchdog job likely never executes.
Agent Prompt
### Issue description
The watchdog installer writes the cron job to `/run/cron/crontabs/root`, but the platform’s `crond` is started with `-c /etc/crontabs`, so it will not read the job file being modified.

### Issue Context
- `S98wireguard-watchdog` currently seeds from `/etc/crontabs/root` but writes updates to `/run/cron/crontabs/root`.
- `S60crond` starts `crond` with `-c /etc/crontabs`.

### Fix Focus Areas
- general/overlay/etc/init.d/S98wireguard-watchdog[6-8]
- general/overlay/etc/init.d/S60crond[3-6]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +3 to 6
ip link del dev wg0 2>/dev/null || true

modprobe wireguard || { echo "Error: Failed to load wireguard module." >&2; exit 1; }
ip link add dev wg0 type wireguard || { echo "Error: Failed to create wg0 interface." >&2; exit 1; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Wg0 deleted before validation 🐞 Bug ☼ Reliability

The wireguard script now deletes wg0 before verifying modprobe and interface creation succeed; if
either step fails, an existing working tunnel is torn down and not restored.
Agent Prompt
### Issue description
`ip link del dev wg0` runs unconditionally before `modprobe wireguard` and `ip link add`. If `modprobe` or `ip link add` fails, the script exits, leaving the device deleted.

### Issue Context
This is especially risky because the new watchdog can trigger restarts; a transient failure becomes a hard outage.

### Fix Focus Areas
- general/overlay/usr/sbin/wireguard[3-6]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread general/overlay/usr/sbin/wireguard-watchdog
Comment on lines +19 to +21
zero_handshake_since=0
[ -r "$STATE_FILE" ] && . "$STATE_FILE"
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

4. State file sourcing risk 🐞 Bug ⛨ Security

wireguard-watchdog sources /run/wireguard-watchdog.state as shell code and overwrites it via cp; if
that path becomes attacker-controlled (e.g., writable/symlinked), it could enable root code
execution or file clobbering.
Agent Prompt
### Issue description
The watchdog loads state by executing `. "$STATE_FILE"` and writes state with `cp` to a fixed path. If the state file is replaced/tampered with, it can execute arbitrary shell code; `cp` also follows symlinks.

### Issue Context
Exploitability depends on runtime permissions for `/run` and the state file, but the pattern is unsafe by design.

### Fix Focus Areas
- general/overlay/usr/sbin/wireguard-watchdog[18-31]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant