#!/usr/bin/env bash set -uo pipefail source "$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)/core.sh" LOG_LEVEL=DEBUG # ============================================ # Modules # ============================================ load_module ip load_module ui load_module config load_module keys load_module peers load_module firewall load_module monitor load_module rule load_module block load_module net load_module group load_module subnet load_module identity load_module policy load_module hosts load_module resolve # ============================================ # Alias Map # ============================================ declare -A CMD_ALIASES=( # Client [new]=add [create]=add [rm]=remove [del]=remove [delete]=remove [mv]=rename [ls]=list [show]=list [monitor]=watch [ban]=block # Service [up]=service [down]=service [reload]=service [stat]=service [log]=service [start]=service [stop]=service [restart]=service [status]=service [enable]=service [disable]=service ) # ============================================ # Dispatch # ============================================ function wgctl::resolve_alias() { local cmd="$1" echo "${CMD_ALIASES[$cmd]:-$cmd}" } function wgctl::dispatch() { local raw_cmd="${1:-help}" shift || true local cmd cmd="$(wgctl::resolve_alias "$raw_cmd")" case "$cmd" in help) wgctl::help; return ;; shell) : ;; *) config::validate || exit 1 ;; esac # If alias resolved to service, pass original cmd as subcommand if [[ "$cmd" == "service" ]]; then load_command service command::run service "$raw_cmd" "$@" return fi if load_command "$cmd"; then if command::exists "$cmd"; then command::run "$cmd" "$@" else log::error "Command '${cmd}' loaded but $(command::fn "$cmd" run) is not defined" exit 1 fi else log::error "Unknown command: '${raw_cmd}'" echo "Run 'wgctl help' to see available commands." exit 1 fi } # ============================================ # Help # ============================================ function wgctl::help() { cat </dev/null || printf "\n wgctl — WireGuard Management\n") Usage: wgctl [options] Client Commands: add, new Add a new client (--type, --subtype, --rule, --group) remove, rm Remove a client rename, mv Rename a client list, ls List all clients (--type, --rule, --group, --blocked, --restricted...) inspect Show detailed client info (--config, --qr) config Show client config qr Show QR code for a client Access Control: block, ban Block a client entirely or restrict specific IPs/ports/services unblock, unban Restore client access (overrides group blocks) rule Manage firewall rules with inheritance list, show, add, update, assign, reapply... Organization: group Manage peer groups list, show, add, block, unblock, watch, logs... Network Services: net Manage named network services list, show, add, rm Used with block/unblock --service and rule --block-service Monitoring: watch Live monitor — handshakes, fw drops, blocked attempts logs Show and manage activity logs show, remove, rotate, --follow audit Verify firewall rules match configuration fw Inspect iptables firewall rules Service: service Manage WireGuard service (start/stop/restart/status) restart Restart WireGuard shell Interactive wgctl shell Development: test Run the wgctl test suite Common examples: wgctl add --name nuno --type phone --rule admin --group family wgctl list --blocked wgctl list --restricted wgctl list --rule user --group family wgctl block --name phone-nuno wgctl block --name phone-nuno --service proxmox wgctl inspect --name phone-nuno wgctl rule list --tree wgctl rule show --name guest wgctl rule add --name dev-01 --group vm-rules --extends no-lan wgctl net add --name proxmox --ip 10.0.0.100 wgctl net add --name proxmox:web-ui --port 8006:tcp wgctl group block --name family wgctl logs --follow wgctl logs rotate --days 7 wgctl audit --fix wgctl fw list --rule guest Run 'wgctl --help' for command-specific help. EOF } # ============================================ # Main # ============================================ function wgctl::main() { system::require_root wgctl::dispatch "$@" } wgctl::main "$@"