Skip to content

Feature - add gl-sdk4-wireguard-ipv4-only — enforce IPv4-only on WireGuard when Global IPv6 is disabled#20

Open
billmcilhargey wants to merge 6 commits into
gl-inet:commonfrom
blackoutsecure:feat_conf_wireguard_ipv4_only
Open

Feature - add gl-sdk4-wireguard-ipv4-only — enforce IPv4-only on WireGuard when Global IPv6 is disabled#20
billmcilhargey wants to merge 6 commits into
gl-inet:commonfrom
blackoutsecure:feat_conf_wireguard_ipv4_only

Conversation

@billmcilhargey

Copy link
Copy Markdown

Summary

Adds a new package, gl-sdk4-wireguard-ipv4-only, that keys IPv4-only WireGuard enforcement off the existing global IPv6 toggle on /#/ipv6 — no new GUI control. When the user disables IPv6, the package strips IPv6 from every WireGuard server / netifd-WG section (kernel device, UCI, live peer programming, firewall) and saves snapshots so the original config can be fully restored when IPv6 is re-enabled or the package is removed.

Use case: customers who want IPv4-only WireGuard without manually editing UCI per peer, and who already use /#/ipv6 as their single source of truth for IPv6 on the router.

What it does, step by step

When wg-noipv6 sync runs:

  1. Reads global IPv6 state via a 5-step detection chain:
    glconfig.general.enable_ipv6network.wan6.disablednetwork.wan6.proto=nonenetwork.wan6.auto=0 → default 1.
  2. If disabled, for every GL.iNet wireguard_server section and every netifd proto=wireguard interface:
    • Snapshot the IPv6 fields about to be stripped (mode 0600 under /etc/wg-noipv6/backup/).
    • Strip address_v6, IPv6 entries from peer client_ip / allowed_ips, and IPv6 entries from netifd addresses. Pin network.<wg>.ipv6=0.
    • Reconcile the live kernel device: re-program peer AllowedIPs to IPv4-only via wg set ... allowed-ips, refusing to clear a peer entirely.
    • Drop a sysctl drop-in (/etc/sysctl.d/99-wg-noipv6-<dev>.conf) setting net.ipv6.conf.<dev>.disable_ipv6 = 1.
    • Install firewall drop-ins: fw4 nft chains under /etc/nftables.d/ if nft/fw4 are present, else fw3 ip6tables script + UCI include.
  3. If enabled, runs the inverse: restores UCI from snapshot, removes drop-ins, kicks wireguard_server to repush peer programming.

Triggers (multiple, defense-in-depth)

The /#/ipv6 toggle behaves inconsistently across firmware revisions, so the package listens through several channels:

  • procd reload triggers on wireguard_server, network, firewall, glconfig.
  • Iface hotplug (/etc/hotplug.d/iface/99-wg-noipv6) — reacts to ifup on tracked WG sections and to ifup/ifdown on wan6 (the most reliable enable-side signal).
  • Net hotplug (/etc/hotplug.d/net/99-wg-noipv6) — required because wireguard_server brings wgserver up without firing netifd ifup.
  • Cron-tick (* * * * * wg-noipv6 cron-tick) — silent unless the global IPv6 state actually changed since last tick. Catches the disable path on firmware revisions where the GUI commits glconfig.general.enable_ipv6=0 without firing any procd/hotplug event.

Surfaces

  • CLI (/usr/sbin/wg-noipv6): sync, apply <dev>, clear <dev>, clear-all, status, cron-tick. status prints PASS/FAIL audit per WG section with extra [INFO] lines (UCI address_v6, peer IPv6 count, live kernel-device IPv6 count) so you can confirm at a glance what's there.
  • JSON-RPC (/usr/lib/oui-httpd/rpc/wireguard_ipv4_only): get_status returns {global_ipv6_enabled, servers: [...]}; sync triggers a reconcile.

Uninstall safety

opkg remove runs wg-noipv6 clear-all, which:

  • Tears down host-side enforcement (sysctl + fw4 nft + fw3 ip6tables drop-ins).
  • Drops our firewall UCI includes.
  • Restores every UCI snapshot.
  • Coalesces all init.d reloads — at most one each of firewallwireguard_servernetwork, in safe order, via a deferred-kick mode on the kick helpers. (Earlier iterations triggered cascading reloads that briefly blackholed the router's own outbound traffic, including DNS.)
  • Cleans up backup dir, state dir, and the cron-tick crontab line.

Validation

  • dash -n clean on all 6 shell files.
  • shellcheck --shell=ash --severity=warning clean (only the long-known SC2034 false-positives on START/STOP/USE_PROCD consumed by /etc/rc.common).
  • luac -p clean on the JSON-RPC module.
  • 13/13 global-IPv6 detection smoke tests pass across all 5 chain steps.
  • 5/5 cron-tick state-machine smoke tests (no log spam on idle ticks; exactly one sync per real state transition).
  • Soak-tested on a real GL-AXT1800 (IPQ60xx, OpenWrt 23.05-SNAPSHOT) across multiple OFF/ON cycles plus install/uninstall cycles.

Files

gl-sdk4-wireguard-ipv4-only/
├── Makefile                                    BuildPackage; postinst enable+start; prerm clear-all
├── version.mk                                  findrev (mirrors gl-sdk4-fan)
├── README.md
└── files/
    ├── etc/init.d/wg-noipv6                    reload-only procd service (no daemon)
    ├── etc/hotplug.d/iface/99-wg-noipv6        netifd ifup/ifdown trigger (incl. wan6)
    ├── etc/hotplug.d/net/99-wg-noipv6          kernel netdev add trigger
    ├── etc/uci-defaults/80-wg-noipv6           first-boot bootstrap + cron install
    ├── usr/sbin/wg-noipv6                      CLI dispatcher
    ├── usr/lib/wg-noipv6/functions.sh          helpers, snapshot/restore, deferred kicks
    └── usr/lib/oui-httpd/rpc/wireguard_ipv4_only   Lua RPC (get_status, sync)

Notes

  • PKGARCH:=all (pure shell + Lua, no compiled artifacts).
  • Only depends on wireguard-tools.
  • No GUI changes required; the existing /#/ipv6 toggle is the user-facing control.
  • All log lines go to syslog as daemon.notice / daemon.warn under tag wg-noipv6 (matches the conventions used by dropbear / mwan3 / dnscrypt-proxy).

- Introduced a new init script `wg-noipv6` to manage IPv4-only enforcement based on the `enable_ipv6` toggle for each WireGuard server.
- Created a UCI defaults script `80-wg-noipv6` to initialize the `enable_ipv6` option for existing WireGuard server configurations.
- Implemented an RPC interface `wireguard_ipv4_only` to read and write the `enable_ipv6` toggle, allowing for dynamic configuration changes.
- Added shared functions in `functions.sh` for managing WireGuard server states, including validation, enforcement, and cleanup.
- Developed the main script `wg-noipv6` to handle commands for syncing, applying, clearing, and checking the status of IPv4-only enforcement.
- Included versioning information in `version.mk` for tracking changes.
- Consolidated logging functions for better readability and consistency.
- Simplified validation checks for interface names and configuration sections.
- Enhanced the global IPv6 state check to streamline enforcement logic.
- Removed redundant comments and improved function documentation.
- Updated the status command to provide clearer output regarding enforcement status.
- Streamlined the application of IPv4-only enforcement for both GL.iNet and netifd interfaces.
- Improved error handling and messaging for invalid device names.
- Removed deprecated code and consolidated similar functionalities for maintainability.
- Bump package release version to 5.
- Improve package description for clarity.
- Update README to reflect new functionality and clarify the restoration process.
- Modify hotplug scripts to ensure quiet logging and handle stale enforcement.
- Enhance init script to maintain clean logs and ensure proper service reloads.
- Add snapshot and restore functionality for UCI configurations to allow seamless re-enabling of IPv6.
- Improve logging functions to provide better feedback on enforcement status.
- Refactor enforcement application logic to streamline the process for both GL.iNet and netifd interfaces.
- Ensure proper cleanup during package removal to restore previous configurations.
@billmcilhargey

billmcilhargey commented Jun 11, 2026

Copy link
Copy Markdown
Author

@gl-fangzekun

Let me know if any concerns or if anything else here to review for inclusion in the next round of updates? Been testing on my current version and builds here

For manual testing until included in main code:

Instructions here:
https://openwrt.blackoutsecure.dev/

Click tab: gl-sdk4-wireguard-ipv4-only

Uses the branch of code referenced here

Then the site mentions everything about it as well

Mainline OpenWrt on Cortex-A53 (ipq60xx / ipq807x)
echo 'src/gz blackoutsecure https://openwrt.blackoutsecure.dev/23.05-SNAPSHOT/packages/aarch64_cortex-a53/blackoutsecure' >> /etc/opkg/customfeeds.conf opkg update

OR

GL.iNet ApNos firmware (AXT1800 / AX1800, 23.05-based)
echo 'src/gz blackoutsecure https://openwrt.blackoutsecure.dev/23.05-SNAPSHOT/packages/aarch64_cortex-a53_neon-vfpv4/blackoutsecure' >> /etc/opkg/customfeeds.conf opkg update

Then once repro is referenced (if using my repro with it built and not one built yourself)

Install the package:

opkg install gl-sdk4-wireguard-ipv4-only

More background opened up here too:
https://forum.gl-inet.com/t/new-feature-submitted-automatic-ipv4-only-mode-for-wireguard-when-ipv6-is-disabled/68615

Let me know if any concerns or need anything else

Thank you again for the time!

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