feat: complete wgctl v2 — net services, block system M:N, rule inheritance, service annotations, restricted status, 64 tests passing
This commit is contained in:
parent
16b4351313
commit
f32ca5c0a1
9 changed files with 122 additions and 282 deletions
|
|
@ -11,7 +11,8 @@ function cmd::audit::help() {
|
|||
Usage: wgctl audit [options]
|
||||
|
||||
Verify that all peers have the correct iptables firewall rules applied.
|
||||
Checks expected rule count (including inherited rules) vs actual iptables state.
|
||||
Checks expected rule count (including inherited rules and peer-specific blocks)
|
||||
vs actual iptables state.
|
||||
|
||||
Options:
|
||||
--peer <name> Audit specific peer only
|
||||
|
|
@ -21,7 +22,12 @@ Options:
|
|||
Output:
|
||||
✅ pass — peer has correct rule count
|
||||
❌ fail — peer has missing rules (run --fix to repair)
|
||||
⚠️ warn — peer has extra rules (e.g. blocked peers with base rules)
|
||||
⚠️ warn — peer has extra rules or configuration issues
|
||||
|
||||
Notes:
|
||||
Fully blocked peers (removed from WireGuard) show 0 expected fw rules.
|
||||
Restricted peers (peer-specific blocks) have their block rules included
|
||||
in the expected count.
|
||||
|
||||
Examples:
|
||||
wgctl audit
|
||||
|
|
@ -81,53 +87,72 @@ function cmd::audit::run() {
|
|||
}
|
||||
|
||||
function cmd::audit::check_peer() {
|
||||
local peer_name="$1"
|
||||
local fix="$2"
|
||||
local actual="${3:-0}"
|
||||
local peer_name="$1" fix="$2" actual="${3:-0}"
|
||||
local ip rule
|
||||
|
||||
ip=$(peers::get_ip "$peer_name")
|
||||
rule=$(peers::get_meta "$peer_name" "rule")
|
||||
|
||||
# Check rule assigned
|
||||
if [[ -z "$rule" ]]; then
|
||||
test::warn "$peer_name — no rule assigned (effective: $(peers::default_rule "$peer_name"))"
|
||||
return
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check rule exists
|
||||
if ! rule::exists "$rule"; then
|
||||
test::fail "$peer_name — assigned rule '$rule' does not exist"
|
||||
return
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Count expected iptables rules from rule file
|
||||
local rule_file
|
||||
rule_file="$(ctx::rule::path "${rule}.rule")"
|
||||
local block_ports block_ips allow_ports allow_ips expected
|
||||
# Blocked peers have no fw rules (removed from wg0)
|
||||
if block::is_blocked "$peer_name" 2>/dev/null; then
|
||||
if [[ "$actual" -eq 0 ]]; then
|
||||
test::pass "$(printf "%-28s rule=%-15s blocked (no fw rules)" \
|
||||
"$peer_name" "$rule")"
|
||||
else
|
||||
test::warn "$(printf "%-28s rule=%-15s blocked but has %s fw rules" \
|
||||
"$peer_name" "$rule" "$actual")"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Count expected rules from assigned rule (includes inheritance)
|
||||
local block_ports block_ips allow_ports allow_ips
|
||||
block_ports=$(json::count_resolved "$rule" "block_ports")
|
||||
block_ips=$(json::count_resolved "$rule" "block_ips")
|
||||
allow_ports=$(json::count_resolved "$rule" "allow_ports")
|
||||
allow_ips=$(json::count_resolved "$rule" "allow_ips")
|
||||
expected=$(( (block_ports + block_ips) * 2 + allow_ports + allow_ips ))
|
||||
local expected=$(( (block_ports + block_ips) * 2 + allow_ports + allow_ips ))
|
||||
|
||||
# Add peer-specific block rules (each ip/port/subnet = 2 rules: NFLOG+DROP)
|
||||
if block::has_specific_rules "$peer_name" 2>/dev/null; then
|
||||
while IFS="|" read -r bname btype target port proto; do
|
||||
[[ -z "$btype" || "$btype" == "full" ]] && continue
|
||||
(( expected += 2 )) || true
|
||||
done < <(block::get_rules "$peer_name")
|
||||
fi
|
||||
|
||||
# actual is passed in as $3 — no iptables call here
|
||||
if [[ "$actual" -eq "$expected" ]]; then
|
||||
test::pass "$(printf "%-28s rule=%-15s fw: %s/%s" "$peer_name" "$rule" "$actual" "$expected")"
|
||||
test::pass "$(printf "%-28s rule=%-15s fw: %s/%s" \
|
||||
"$peer_name" "$rule" "$actual" "$expected")"
|
||||
elif [[ "$actual" -gt "$expected" ]]; then
|
||||
test::warn "$(printf "%-28s rule=%-15s fw: %s/%s (extra rules)" "$peer_name" "$rule" "$actual" "$expected")"
|
||||
test::warn "$(printf "%-28s rule=%-15s fw: %s/%s (extra rules)" \
|
||||
"$peer_name" "$rule" "$actual" "$expected")"
|
||||
if $fix; then
|
||||
fw::flush_peer "$ip"
|
||||
rule::apply "$rule" "$ip" "$peer_name"
|
||||
block::restore_rules_for "$peer_name" "$ip"
|
||||
test::pass " Fixed: $peer_name"
|
||||
fi
|
||||
else
|
||||
test::fail "$(printf "%-28s rule=%-15s fw: %s/%s (missing rules)" "$peer_name" "$rule" "$actual" "$expected")"
|
||||
test::fail "$(printf "%-28s rule=%-15s fw: %s/%s (missing rules)" \
|
||||
"$peer_name" "$rule" "$actual" "$expected")"
|
||||
if $fix; then
|
||||
rule::apply "$rule" "$ip" "$peer_name"
|
||||
block::restore_rules_for "$peer_name" "$ip"
|
||||
test::pass " Fixed: $peer_name"
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
function cmd::audit::check_wg() {
|
||||
|
|
|
|||
|
|
@ -27,8 +27,10 @@ function cmd::block::help() {
|
|||
cat <<EOF
|
||||
Usage: wgctl block --name <name> [options]
|
||||
|
||||
Block a client entirely or restrict access to specific IPs/ports/subnets.
|
||||
Block rules are persisted and restored on WireGuard restart.
|
||||
Block a client entirely or restrict access to specific IPs/ports/subnets/services.
|
||||
All block rules are persisted and restored on WireGuard restart.
|
||||
Clients blocked via --ip/--port/--subnet/--service remain in WireGuard
|
||||
but have specific traffic restricted (shown as 'restricted' in list).
|
||||
|
||||
Options:
|
||||
--name <name> Client name (e.g. phone-nuno)
|
||||
|
|
@ -36,7 +38,8 @@ Options:
|
|||
--ip <ip> Block access to specific IP (repeatable)
|
||||
--subnet <cidr> Block access to subnet (repeatable)
|
||||
--port <ip:port:proto> Block specific port, e.g. 10.0.0.210:9000:tcp (repeatable)
|
||||
--force Skip confirmation prompt
|
||||
--service <name> Block a named service (e.g. proxmox, truenas:web-ui) (repeatable)
|
||||
--block-name <name> Optional name for this block rule
|
||||
--quiet Suppress output (used by group block)
|
||||
|
||||
Examples:
|
||||
|
|
@ -45,6 +48,8 @@ Examples:
|
|||
wgctl block --name phone-nuno --ip 10.0.0.210
|
||||
wgctl block --name phone-nuno --subnet 10.0.0.0/24
|
||||
wgctl block --name phone-nuno --port 10.0.0.210:9000:tcp
|
||||
wgctl block --name phone-nuno --service proxmox
|
||||
wgctl block --name phone-nuno --service truenas:web-ui --block-name "no truenas ui"
|
||||
wgctl ban --name phone-nuno
|
||||
EOF
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,14 +22,16 @@ function cmd::group::help() {
|
|||
cat <<EOF
|
||||
Usage: wgctl group <subcommand> [options]
|
||||
|
||||
Manage peer groups. Groups are organizational — a peer can belong
|
||||
to multiple groups. Operations like block/unblock act on all peers in a group.
|
||||
Manage peer groups. Operations like block/unblock act on all peers in a group.
|
||||
A peer can belong to multiple groups (M:N relationship).
|
||||
Group blocks track which groups blocked a peer — unblocking one group won't
|
||||
unblock a peer still blocked by another group.
|
||||
|
||||
Subcommands:
|
||||
list, ls List all groups with status
|
||||
list, ls List all groups
|
||||
show Show group members and their status
|
||||
add, new, create Create a new group
|
||||
remove, rm, del Remove a group definition (not the peers)
|
||||
remove, rm, del Remove a group definition
|
||||
rename Rename a group
|
||||
peer add Add a peer to a group
|
||||
peer remove, peer rm Remove a peer from a group
|
||||
|
|
@ -55,7 +57,6 @@ Examples:
|
|||
wgctl group list
|
||||
wgctl group add --name family --desc "Family devices"
|
||||
wgctl group peer add --name family --peer phone-nuno
|
||||
wgctl group peer remove --name family --peer phone-nuno
|
||||
wgctl group show --name family
|
||||
wgctl group block --name family
|
||||
wgctl group unblock --name family
|
||||
|
|
@ -147,79 +148,6 @@ function cmd::group::list() {
|
|||
printf "\n"
|
||||
}
|
||||
|
||||
# function cmd::group::list() {
|
||||
# local groups_dir
|
||||
# groups_dir="$(ctx::groups)"
|
||||
|
||||
# local groups=("${groups_dir}"/*.group)
|
||||
# if [[ ! -f "${groups[0]}" ]]; then
|
||||
# log::wg "No groups configured"
|
||||
# return 0
|
||||
# fi
|
||||
|
||||
# log::section "Groups"
|
||||
|
||||
# printf "\n %-20s %-35s %-8s %s\n" "NAME" "DESCRIPTION" "PEERS" "STATUS"
|
||||
# printf " %s\n" "$(printf '─%.0s' {1..75})"
|
||||
|
||||
# for group_file in "${groups_dir}"/*.group; do
|
||||
# [[ -f "$group_file" ]] || continue
|
||||
|
||||
# local name desc
|
||||
# name=$(json::get "$group_file" "name")
|
||||
# desc=$(json::get "$group_file" "desc")
|
||||
|
||||
# # Count peers
|
||||
# local peers_list=()
|
||||
# mapfile -t peers_list < <(json::get "$group_file" "peers")
|
||||
# # Filter empty entries
|
||||
# local filtered=()
|
||||
# for p in "${peers_list[@]:-}"; do
|
||||
# [[ -n "$p" ]] && filtered+=("$p")
|
||||
# done
|
||||
# peers_list=("${filtered[@]:-}")
|
||||
# local peer_count=${#peers_list[@]}
|
||||
|
||||
# [[ -z "${peers_list[0]}" ]] && peer_count=0
|
||||
|
||||
# # Check block status
|
||||
# local blocked=0 total=0
|
||||
# for peer_name in "${peers_list[@]}"; do
|
||||
# [[ -z "$peer_name" ]] && continue
|
||||
# (( total++ )) || true
|
||||
# peers::is_blocked "$peer_name" && (( blocked++ )) || true
|
||||
# done
|
||||
|
||||
# local status_color=""
|
||||
# local status_str="active"
|
||||
# if [[ "$total" -gt 0 ]]; then
|
||||
# if [[ "$blocked" -eq "$total" ]]; then
|
||||
# status_color="\033[1;31m"
|
||||
# status_str="blocked"
|
||||
# elif [[ "$blocked" -gt 0 ]]; then
|
||||
# status_color="\033[1;33m"
|
||||
# status_str="blocked (${blocked}/${total})"
|
||||
# # status_color="\033[1;33m"
|
||||
# # status_str="${blocked}/${total} blocked"
|
||||
# else
|
||||
# status_color="\033[1;32m"
|
||||
# status_str="active"
|
||||
# fi
|
||||
# fi
|
||||
|
||||
# local short_desc="${desc:0:33}"
|
||||
# [[ ${#desc} -gt 33 ]] && short_desc="${short_desc}..."
|
||||
|
||||
# printf " %-20s %-35s %-8s %b\n" \
|
||||
# "$name" \
|
||||
# "${short_desc:-—}" \
|
||||
# "$peer_count" \
|
||||
# "${status_color}${status_str}\033[0m"
|
||||
# done
|
||||
|
||||
# printf "\n"
|
||||
# }
|
||||
|
||||
# ============================================
|
||||
# Show
|
||||
# ============================================
|
||||
|
|
@ -731,7 +659,6 @@ function cmd::group::_unblock_peer() {
|
|||
return 1
|
||||
fi
|
||||
|
||||
log::debug "_unblock_peer: restoring $peer_name"
|
||||
block::restore_peer "$peer_name" "$client_ip"
|
||||
block::remove_file "$peer_name"
|
||||
|
||||
|
|
@ -740,8 +667,6 @@ function cmd::group::_unblock_peer() {
|
|||
|
||||
[[ -n "$rule" ]] && rule::exists "$rule" && \
|
||||
rule::apply "$rule" "$client_ip" "$peer_name"
|
||||
|
||||
log::debug "_unblock_peer: done"
|
||||
}
|
||||
|
||||
# ============================================
|
||||
|
|
|
|||
|
|
@ -12,12 +12,18 @@ function cmd::inspect::help() {
|
|||
Usage: wgctl inspect --name <name> [options]
|
||||
wgctl inspect <full-name>
|
||||
|
||||
Show detailed information for a WireGuard client including
|
||||
status, rule with inheritance, groups, firewall rules, and activity.
|
||||
Show detailed information for a WireGuard client.
|
||||
|
||||
Sections shown:
|
||||
Client — IP, type, rule, status, activity
|
||||
Groups — group memberships
|
||||
Rule — firewall rule with inheritance tree and service annotations
|
||||
Peer Blocks — peer-specific restrictions (beyond the assigned rule)
|
||||
Firewall — active iptables rules with ACCEPT/DROP counts
|
||||
|
||||
Options:
|
||||
--name <name> Client name (e.g. phone-nuno)
|
||||
--type <type> Device type — combines with --name (e.g. --name nuno --type phone)
|
||||
--type <type> Device type — combines with --name
|
||||
--config Also show raw WireGuard client config
|
||||
--qr Also show QR code
|
||||
|
||||
|
|
@ -112,107 +118,6 @@ function cmd::inspect::_peer_info() {
|
|||
return 0
|
||||
}
|
||||
|
||||
# function cmd::inspect::_rule_info() {
|
||||
# local name="${1:-}"
|
||||
# local rule
|
||||
# rule=$(peers::get_meta "$name" "rule")
|
||||
# [[ -z "$rule" ]] && return 0
|
||||
# rule::exists "$rule" || return 0
|
||||
|
||||
# cmd::inspect::_section "Rule: ${rule}"
|
||||
|
||||
# local rule_file
|
||||
# rule_file="$(rule::path "$rule")"
|
||||
|
||||
# # Check for inheritance
|
||||
# local extends_raw=()
|
||||
# mapfile -t extends_raw < <(json::get "$rule_file" "extends" 2>/dev/null || true)
|
||||
|
||||
# if [[ ${#extends_raw[@]} -gt 0 && -n "${extends_raw[0]:-}" ]]; then
|
||||
# # Show inheritance tree
|
||||
# for base_name in "${extends_raw[@]}"; do
|
||||
# [[ -z "$base_name" ]] && continue
|
||||
# printf "\n \033[0;37m↳ %s\033[0m\n" "$base_name"
|
||||
|
||||
# local base_allows base_blocks
|
||||
# base_allows=$(rule::get "$base_name" "allow_ports")$'\n'$(rule::get "$base_name" "allow_ips")
|
||||
# base_blocks=$(rule::get "$base_name" "block_ips")$'\n'$(rule::get "$base_name" "block_ports")
|
||||
|
||||
# while IFS= read -r e; do
|
||||
# [[ -z "$e" ]] && continue
|
||||
# net::print_entry "+" "$e"
|
||||
# done <<< "$base_allows"
|
||||
|
||||
# while IFS= read -r e; do
|
||||
# [[ -z "$e" ]] && continue
|
||||
# net::print_entry "-" "$e"
|
||||
# done <<< "$base_blocks"
|
||||
|
||||
# local base_dns
|
||||
# base_dns=$(rule::get_own "$base_name" "dns_redirect")
|
||||
# [[ "${base_dns,,}" == "true" ]] && \
|
||||
# printf " \033[0;36m↺\033[0m DNS → %s\n" "$(config::dns)"
|
||||
# done
|
||||
|
||||
# # Own rules
|
||||
# local own_allows own_blocks
|
||||
# own_allows=$(json::get "$rule_file" "allow_ports" 2>/dev/null)$'\n'$(json::get "$rule_file" "allow_ips" 2>/dev/null)
|
||||
# own_blocks=$(json::get "$rule_file" "block_ips" 2>/dev/null)$'\n'$(json::get "$rule_file" "block_ports" 2>/dev/null)
|
||||
# local has_own=false
|
||||
|
||||
# while IFS= read -r e; do [[ -n "$e" ]] && has_own=true && break; done <<< "$own_allows$own_blocks"
|
||||
|
||||
# if $has_own; then
|
||||
# printf "\n \033[0;37mOwn:\033[0m\n"
|
||||
# while IFS= read -r e; do
|
||||
# [[ -z "$e" ]] && continue
|
||||
# net::print_entry "+" "$e"
|
||||
# done <<< "$own_allows"
|
||||
|
||||
# while IFS= read -r e; do
|
||||
# [[ -z "$e" ]] && continue
|
||||
# net::print_entry "-" "$e"
|
||||
# done <<< "$own_blocks"
|
||||
# fi
|
||||
|
||||
# else
|
||||
# # No inheritance — flat view
|
||||
# local allow_ports allow_ips block_ips block_ports
|
||||
# allow_ports=$(rule::get "$rule" "allow_ports")
|
||||
# allow_ips=$(rule::get "$rule" "allow_ips")
|
||||
# block_ips=$(rule::get "$rule" "block_ips")
|
||||
# block_ports=$(rule::get "$rule" "block_ports")
|
||||
|
||||
# if [[ -n "$allow_ports" || -n "$allow_ips" ]]; then
|
||||
# printf "\n"
|
||||
# while IFS= read -r e; do
|
||||
# [[ -z "$e" ]] && continue
|
||||
# net::print_entry "+" "$e"
|
||||
# done <<< "$allow_ports"$'\n'"$allow_ips"
|
||||
# fi
|
||||
|
||||
# if [[ -n "$block_ips" || -n "$block_ports" ]]; then
|
||||
# printf "\n"
|
||||
# while IFS= read -r e; do
|
||||
# [[ -z "$e" ]] && continue
|
||||
# net::print_entry "-" "$e"
|
||||
# done <<< "$block_ips"$'\n'"$block_ports"
|
||||
# fi
|
||||
|
||||
# if [[ -z "$allow_ports" && -z "$allow_ips" && \
|
||||
# -z "$block_ips" && -z "$block_ports" ]]; then
|
||||
# printf "\n full access (no restrictions)\n"
|
||||
# fi
|
||||
|
||||
# local dns_redirect
|
||||
# dns_redirect=$(rule::get_own "$rule" "dns_redirect")
|
||||
# [[ "${dns_redirect,,}" == "true" ]] && \
|
||||
# printf "\n \033[0;36m↺\033[0m DNS → %s\n" "$(config::dns)"
|
||||
# fi
|
||||
|
||||
# return 0
|
||||
# }
|
||||
|
||||
function cmd::inspect::_rule_info() {
|
||||
local name="${1:-}"
|
||||
local rule
|
||||
|
|
@ -252,48 +157,6 @@ function cmd::inspect::_blocks_info() {
|
|||
return 0
|
||||
}
|
||||
|
||||
# function cmd::inspect::_rule_info() {
|
||||
# local name="$1"
|
||||
# local rule
|
||||
# rule=$(peers::get_meta "$name" "rule")
|
||||
# [[ -z "$rule" ]] && return 0
|
||||
|
||||
# rule::exists "$rule" || return 0
|
||||
|
||||
# local rule_file
|
||||
# rule_file="$(ctx::rule::path "${rule}.rule")"
|
||||
|
||||
# ui::section "Rule: ${rule}"
|
||||
|
||||
# local desc dns_redirect
|
||||
# desc=$(json::get "$rule_file" "desc")
|
||||
# dns_redirect=$(json::get "$rule_file" "dns_redirect")
|
||||
# ui::row "Description" "${desc:-—}"
|
||||
# ui::row "DNS Redirect" "${dns_redirect:-false}"
|
||||
|
||||
# local allow_ports allow_ips block_ips block_ports
|
||||
# allow_ports=$(json::get "$rule_file" "allow_ports")
|
||||
# allow_ips=$(json::get "$rule_file" "allow_ips")
|
||||
# block_ips=$(json::get "$rule_file" "block_ips")
|
||||
# block_ports=$(json::get "$rule_file" "block_ports")
|
||||
|
||||
# if [[ -n "$allow_ports" || -n "$allow_ips" ]]; then
|
||||
# printf " %-20s\n" "Allows:"
|
||||
# ui::print_list "+" "$allow_ports"
|
||||
# ui::print_list "+" "$allow_ips"
|
||||
# else
|
||||
# ui::row "Allows" "—"
|
||||
# fi
|
||||
|
||||
# if [[ -n "$block_ips" || -n "$block_ports" ]]; then
|
||||
# printf " %-20s\n" "Blocks:"
|
||||
# ui::print_list "-" "$block_ips"
|
||||
# ui::print_list "-" "$block_ports"
|
||||
# else
|
||||
# ui::row "Blocks" "—"
|
||||
# fi
|
||||
# }
|
||||
|
||||
function cmd::inspect::_group_info() {
|
||||
local name="$1"
|
||||
|
||||
|
|
@ -401,10 +264,10 @@ function cmd::inspect::run() {
|
|||
log::section "Inspect: ${name}"
|
||||
|
||||
cmd::inspect::_peer_info "$name"
|
||||
cmd::inspect::_rule_info "$name"
|
||||
cmd::inspect::_group_info "$name"
|
||||
cmd::inspect::_firewall_info "$name"
|
||||
cmd::inspect::_rule_info "$name"
|
||||
cmd::inspect::_blocks_info "$name"
|
||||
cmd::inspect::_firewall_info "$name"
|
||||
|
||||
if $show_config; then
|
||||
cmd::inspect::_config "$name"
|
||||
|
|
|
|||
|
|
@ -33,12 +33,18 @@ Options:
|
|||
--group <group> Filter by group membership
|
||||
--online Show only connected clients
|
||||
--offline Show only disconnected clients
|
||||
--blocked Show only blocked clients
|
||||
--restricted Show only restricted clients
|
||||
--blocked Show only fully blocked clients (removed from WireGuard)
|
||||
--restricted Show only restricted clients (specific IP/port blocks applied)
|
||||
--allowed Show only unrestricted clients
|
||||
--detailed Show full detail cards for all clients
|
||||
--name <name> Show detail card for a single client
|
||||
|
||||
Status values:
|
||||
online Connected (recent handshake)
|
||||
offline Not connected
|
||||
blocked Removed from WireGuard server (wgctl block --name)
|
||||
restricted In WireGuard but with specific access rules (wgctl block --ip/--service)
|
||||
|
||||
Examples:
|
||||
wgctl list
|
||||
wgctl list --type guest
|
||||
|
|
@ -46,6 +52,7 @@ Examples:
|
|||
wgctl list --group family
|
||||
wgctl list --online
|
||||
wgctl list --blocked
|
||||
wgctl list --restricted
|
||||
wgctl list --detailed
|
||||
wgctl list --name phone-nuno
|
||||
EOF
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ Usage: wgctl rule <subcommand> [options]
|
|||
|
||||
Manage firewall rules with inheritance support.
|
||||
Rules can extend base rules to compose reusable access policies.
|
||||
Service names from 'wgctl net' can be used instead of raw IPs/ports.
|
||||
|
||||
Subcommands:
|
||||
list, ls List all rules
|
||||
|
|
@ -71,6 +72,8 @@ Options for add:
|
|||
--allow-port <ip:port:proto> Allow specific port (repeatable)
|
||||
--block-ip <ip/cidr> Block IP or subnet (repeatable)
|
||||
--block-port <ip:port:proto> Block specific port (repeatable)
|
||||
--block-service <name> Block named service — resolved to IP/port at creation (repeatable)
|
||||
--allow-service <name> Allow named service — resolved to IP/port at creation (repeatable)
|
||||
--dns-redirect Force DNS through Pi-hole
|
||||
|
||||
Options for update:
|
||||
|
|
@ -95,16 +98,13 @@ Examples:
|
|||
wgctl rule list
|
||||
wgctl rule list --tree
|
||||
wgctl rule list --group "VM Rules"
|
||||
wgctl rule list --base
|
||||
wgctl rule show --name guest
|
||||
wgctl rule show --name moonlight-02 --resolved
|
||||
wgctl rule add --name no-proxmox --base --block-service proxmox
|
||||
wgctl rule add --name dev-01 --desc "Dev access" --group "Dev" --extends no-lan
|
||||
wgctl rule add --name no-npm --base --block-ip 10.0.0.101/32
|
||||
wgctl rule add --name restricted-dns --allow-service pihole:dns --block-service pihole
|
||||
wgctl rule update --name user --add-extends no-nginx
|
||||
wgctl rule update --name dev-01 --allow-ip 10.0.0.50/32
|
||||
wgctl rule assign --name dev-01 --peer laptop-nuno
|
||||
wgctl rule unassign --peer laptop-nuno
|
||||
wgctl rule reapply --name user
|
||||
wgctl rule reapply --all
|
||||
EOF
|
||||
}
|
||||
|
|
@ -845,9 +845,7 @@ function cmd::rule::assign() {
|
|||
|
||||
local ip
|
||||
ip=$(peers::get_ip "$peer")
|
||||
log::debug "rule::assign: peer=$peer ip=$ip"
|
||||
[[ -z "$ip" ]] && log::error "Could not resolve IP for: $peer" && return 1
|
||||
log::debug "assign: peer=$peer ip=$ip clients=$(ctx::clients)"
|
||||
|
||||
if [[ -n "$existing_rule" && "$existing_rule" != "$name" ]]; then
|
||||
rule::unapply "$existing_rule" "$ip"
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ function cmd::shell::_is_wgctl_command() {
|
|||
local known=(
|
||||
list add remove rm inspect block unblock
|
||||
rule group audit logs watch fw config qr
|
||||
rename keys ip service shell help test
|
||||
rename keys ip net service shell help test
|
||||
)
|
||||
local c
|
||||
for c in "${known[@]}"; do
|
||||
|
|
@ -85,12 +85,17 @@ function cmd::shell::_banner() {
|
|||
printf " \033[1;37mCommon commands:\033[0m\n"
|
||||
printf " list List all peers\n"
|
||||
printf " list --blocked Show blocked peers\n"
|
||||
printf " list --restricted Show restricted peers\n"
|
||||
printf " list --rule user Filter by rule\n"
|
||||
printf " inspect --name <peer> Full peer details\n"
|
||||
printf " block/unblock --name <peer> Block or restore a peer\n"
|
||||
printf " block --name <peer> Block a peer entirely\n"
|
||||
printf " block --name <peer> --service proxmox Restrict service\n"
|
||||
printf " unblock --name <peer> Restore full access\n"
|
||||
printf " rule list Show firewall rules\n"
|
||||
printf " rule list --tree Show with inheritance tree\n"
|
||||
printf " rule list --tree Show with inheritance\n"
|
||||
printf " rule show --name <rule> Rule details\n"
|
||||
printf " net list Show network services\n"
|
||||
printf " net list --detailed Show services with ports\n"
|
||||
printf " group list Show groups\n"
|
||||
printf " group block --name <group> Block all peers in group\n"
|
||||
printf " logs --follow Live activity log\n"
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ function cmd::unblock::help() {
|
|||
cat <<EOF
|
||||
Usage: wgctl unblock --name <name> [options]
|
||||
|
||||
Remove block rules for a client.
|
||||
Remove block rules for a client. Without specific flags, performs a full unblock.
|
||||
Direct unblock overrides any group blocks.
|
||||
|
||||
Options:
|
||||
--name <name> Client name (e.g. phone-nuno)
|
||||
|
|
@ -35,14 +36,16 @@ Options:
|
|||
--ip <ip> Unblock specific IP (repeatable)
|
||||
--subnet <cidr> Unblock specific subnet (repeatable)
|
||||
--port <ip:port:proto> Unblock specific port (repeatable)
|
||||
--all Remove all block rules for this client
|
||||
--force Skip confirmation prompt
|
||||
--service <name> Unblock a named service (repeatable)
|
||||
--all Remove all block rules (same as no flags)
|
||||
--quiet Suppress output (used by group unblock)
|
||||
|
||||
Examples:
|
||||
wgctl unblock --name phone-nuno
|
||||
wgctl unblock --name nuno --type phone
|
||||
wgctl unblock --name phone-nuno --ip 10.0.0.210
|
||||
wgctl unblock --name phone-nuno --service proxmox
|
||||
wgctl unblock --name phone-nuno --service truenas:web-ui
|
||||
wgctl unban --name phone-nuno
|
||||
EOF
|
||||
}
|
||||
|
|
|
|||
17
wgctl
17
wgctl
|
|
@ -107,21 +107,26 @@ Usage: wgctl <command> [options]
|
|||
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...)
|
||||
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
|
||||
unblock, unban Restore client access
|
||||
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, inspect, add, update, assign, reapply...
|
||||
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
|
||||
|
|
@ -140,12 +145,16 @@ Usage: wgctl <command> [options]
|
|||
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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue