refactor: rule::show new layout, assign fix, unblock helpers, test improvements
This commit is contained in:
parent
5702b118b0
commit
51e3443357
10 changed files with 312 additions and 147 deletions
|
|
@ -41,23 +41,6 @@ Examples:
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
# ============================================
|
|
||||||
# Helpers
|
|
||||||
# ============================================
|
|
||||||
|
|
||||||
function cmd::block::get_client_ip() {
|
|
||||||
local name="$1"
|
|
||||||
local conf
|
|
||||||
conf="$(ctx::clients)/${name}.conf"
|
|
||||||
|
|
||||||
if [[ ! -f "$conf" ]]; then
|
|
||||||
log::error "Client not found: ${name}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
grep "^Address" "$conf" | awk '{print $3}' | cut -d'/' -f1
|
|
||||||
}
|
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# Block Run
|
# Block Run
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|
@ -112,7 +95,7 @@ function cmd::block::run() {
|
||||||
endpoint=$(cmd::block::_get_endpoint "$name" "$public_key")
|
endpoint=$(cmd::block::_get_endpoint "$name" "$public_key")
|
||||||
|
|
||||||
local client_ip
|
local client_ip
|
||||||
client_ip=$(cmd::block::get_client_ip "$name") || return 1
|
client_ip=$(peers::get_ip "$name") || return 1
|
||||||
|
|
||||||
# $quiet || log::section "Blocking client: ${name} (${client_ip})"
|
# $quiet || log::section "Blocking client: ${name} (${client_ip})"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -119,9 +119,9 @@ function cmd::list::_format_last_seen() {
|
||||||
local handshake_ts="${6:-0}"
|
local handshake_ts="${6:-0}"
|
||||||
|
|
||||||
if [[ "$is_blocked" == "true" ]]; then
|
if [[ "$is_blocked" == "true" ]]; then
|
||||||
if [[ -n "$last_ts" ]]; then
|
if [[ -n "$last_ts" && "$last_ts" != "0" && "$last_ts" != "null" ]]; then
|
||||||
local formatted
|
local formatted
|
||||||
formatted=$(fmt::datetime "$last_ts")
|
formatted=$(fmt::datetime_iso "$last_ts")
|
||||||
echo "${formatted} (dropped)"
|
echo "${formatted} (dropped)"
|
||||||
else
|
else
|
||||||
echo "—"
|
echo "—"
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ function cmd::rule::on_load() {
|
||||||
flag::register --peer
|
flag::register --peer
|
||||||
flag::register --peers
|
flag::register --peers
|
||||||
flag::register --dns-redirect
|
flag::register --dns-redirect
|
||||||
|
flag::register --color
|
||||||
}
|
}
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|
@ -87,6 +88,7 @@ function cmd::rule::run() {
|
||||||
assign) cmd::rule::assign "$@" ;;
|
assign) cmd::rule::assign "$@" ;;
|
||||||
unassign) cmd::rule::unassign "$@" ;;
|
unassign) cmd::rule::unassign "$@" ;;
|
||||||
migrate) cmd::rule::migrate "$@" ;;
|
migrate) cmd::rule::migrate "$@" ;;
|
||||||
|
reapply) cmd::rule::reapply "$@" ;;
|
||||||
help) cmd::rule::help ;;
|
help) cmd::rule::help ;;
|
||||||
*)
|
*)
|
||||||
log::error "Unknown subcommand: '${subcmd}'"
|
log::error "Unknown subcommand: '${subcmd}'"
|
||||||
|
|
@ -131,87 +133,71 @@ function cmd::rule::list() {
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|
||||||
function cmd::rule::show() {
|
function cmd::rule::show() {
|
||||||
local name="" show_peers=false
|
local name="" show_peers=false color=false
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--name) name="$2"; shift 2 ;;
|
--name) name="$2"; shift 2 ;;
|
||||||
--peers) show_peers=true; shift ;;
|
--peers) show_peers=true; shift ;;
|
||||||
|
--color) color=true; shift ;;
|
||||||
--help) cmd::rule::help; return ;;
|
--help) cmd::rule::help; return ;;
|
||||||
*) log::error "Unknown flag: $1"; return 1 ;;
|
*) log::error "Unknown flag: $1"; return 1 ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ -z "$name" ]]; then
|
[[ -z "$name" ]] && log::error "Missing required flag: --name" && return 1
|
||||||
log::error "Missing required flag: --name"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
rule::require_exists "$name" || return 1
|
rule::require_exists "$name" || return 1
|
||||||
|
|
||||||
local rule_file
|
local rule_file
|
||||||
rule_file="$(ctx::rule::path "${name}.rule")"
|
rule_file="$(ctx::rule::path "${name}.rule")"
|
||||||
|
|
||||||
|
# Precompute peers before any operations
|
||||||
|
local peer_list=()
|
||||||
|
mapfile -t peer_list < <(peers::with_rule "$name")
|
||||||
|
local peer_count=${#peer_list[@]}
|
||||||
|
|
||||||
log::section "Rule: ${name}"
|
log::section "Rule: ${name}"
|
||||||
|
|
||||||
local desc dns_redirect
|
local desc dns_redirect
|
||||||
desc=$(json::get "$rule_file" "desc")
|
desc=$(json::get "$rule_file" "desc")
|
||||||
dns_redirect=$(json::get "$rule_file" "dns_redirect")
|
dns_redirect=$(json::get "$rule_file" "dns_redirect")
|
||||||
|
|
||||||
printf "\n %-20s %s\n" "Description:" "${desc:-—}"
|
printf "\n"
|
||||||
printf " %-20s %s\n" "DNS Redirect:" "${dns_redirect:-false}"
|
ui::row "Description" "${desc:-—}"
|
||||||
|
ui::row "DNS Redirect" "${dns_redirect:-false}"
|
||||||
|
|
||||||
# Allow ports
|
# Load all entries
|
||||||
local allow_ports
|
local allow_ports allow_ips block_ips block_ports
|
||||||
allow_ports=$(json::get "$rule_file" "allow_ports")
|
allow_ports=$(json::get "$rule_file" "allow_ports")
|
||||||
if [[ -n "$allow_ports" ]]; then
|
|
||||||
printf "\n Allow Ports:\n"
|
|
||||||
while IFS= read -r entry; do
|
|
||||||
printf " + %s\n" "$entry"
|
|
||||||
done <<< "$allow_ports"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Allow IPs
|
|
||||||
local allow_ips
|
|
||||||
allow_ips=$(json::get "$rule_file" "allow_ips")
|
allow_ips=$(json::get "$rule_file" "allow_ips")
|
||||||
if [[ -n "$allow_ips" ]]; then
|
|
||||||
printf "\n Allow IPs:\n"
|
|
||||||
while IFS= read -r ip; do
|
|
||||||
printf " + %s\n" "$ip"
|
|
||||||
done <<< "$allow_ips"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Block IPs
|
|
||||||
local block_ips
|
|
||||||
block_ips=$(json::get "$rule_file" "block_ips")
|
block_ips=$(json::get "$rule_file" "block_ips")
|
||||||
if [[ -n "$block_ips" ]]; then
|
|
||||||
printf "\n Block IPs:\n"
|
|
||||||
while IFS= read -r ip; do
|
|
||||||
printf " - %s\n" "$ip"
|
|
||||||
done <<< "$block_ips"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Block ports
|
|
||||||
local block_ports
|
|
||||||
block_ports=$(json::get "$rule_file" "block_ports")
|
block_ports=$(json::get "$rule_file" "block_ports")
|
||||||
if [[ -n "$block_ports" ]]; then
|
|
||||||
printf "\n Block Ports:\n"
|
# Allow section
|
||||||
while IFS= read -r entry; do
|
if [[ -n "$allow_ports" || -n "$allow_ips" ]]; then
|
||||||
printf " - %s\n" "$entry"
|
cmd::rule::_show_section "Allow" "green" "$color"
|
||||||
done <<< "$block_ports"
|
cmd::rule::_show_entries "Ports" "+" "$allow_ports" "$color" "green"
|
||||||
|
cmd::rule::_show_entries "IPs" "+" "$allow_ips" "$color" "green"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Precompute peers before any other operations
|
# Block section
|
||||||
local peer_list=()
|
if [[ -n "$block_ips" || -n "$block_ports" ]]; then
|
||||||
mapfile -t peer_list < <(peers::with_rule "$name")
|
cmd::rule::_show_section "Block" "red" "$color"
|
||||||
local peer_count=${#peer_list[@]}
|
cmd::rule::_show_entries "IPs" "-" "$block_ips" "$color" "red"
|
||||||
|
cmd::rule::_show_entries "Ports" "-" "$block_ports" "$color" "red"
|
||||||
|
fi
|
||||||
|
|
||||||
# Peer count — always shown
|
if [[ -z "$allow_ports" && -z "$allow_ips" && -z "$block_ips" && -z "$block_ports" ]]; then
|
||||||
printf "\n %-20s %s\n" "Assigned Peers:" "$peer_count"
|
printf "\n"
|
||||||
printf " %s\n" "$(printf '─%.0s' {1..40})"
|
ui::row "Access" "full (no restrictions)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Peers section
|
||||||
|
cmd::rule::_show_section "Peers" "white" false
|
||||||
|
ui::row "Assigned" "$peer_count"
|
||||||
|
|
||||||
# Peer details — only with --peers flag
|
|
||||||
if $show_peers && [[ $peer_count -gt 0 ]]; then
|
if $show_peers && [[ $peer_count -gt 0 ]]; then
|
||||||
|
printf "\n"
|
||||||
for peer_name in "${peer_list[@]}"; do
|
for peer_name in "${peer_list[@]}"; do
|
||||||
local ip
|
local ip
|
||||||
ip=$(peers::get_ip "$peer_name")
|
ip=$(peers::get_ip "$peer_name")
|
||||||
|
|
@ -222,6 +208,97 @@ function cmd::rule::show() {
|
||||||
printf "\n"
|
printf "\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# function cmd::rule::show() {
|
||||||
|
# local name="" show_peers=false
|
||||||
|
|
||||||
|
# while [[ $# -gt 0 ]]; do
|
||||||
|
# case "$1" in
|
||||||
|
# --name) name="$2"; shift 2 ;;
|
||||||
|
# --peers) show_peers=true; shift ;;
|
||||||
|
# --help) cmd::rule::help; return ;;
|
||||||
|
# *) log::error "Unknown flag: $1"; return 1 ;;
|
||||||
|
# esac
|
||||||
|
# done
|
||||||
|
|
||||||
|
# if [[ -z "$name" ]]; then
|
||||||
|
# log::error "Missing required flag: --name"
|
||||||
|
# return 1
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# rule::require_exists "$name" || return 1
|
||||||
|
|
||||||
|
# local rule_file
|
||||||
|
# rule_file="$(ctx::rule::path "${name}.rule")"
|
||||||
|
|
||||||
|
# log::section "Rule: ${name}"
|
||||||
|
|
||||||
|
# local desc dns_redirect
|
||||||
|
# desc=$(json::get "$rule_file" "desc")
|
||||||
|
# dns_redirect=$(json::get "$rule_file" "dns_redirect")
|
||||||
|
|
||||||
|
# printf "\n"
|
||||||
|
# ui::row "Description" "${desc:-—}"
|
||||||
|
# ui::row "DNS Redirect" "${dns_redirect:-false}"
|
||||||
|
|
||||||
|
# # Allow ports
|
||||||
|
# local allow_ports
|
||||||
|
# allow_ports=$(json::get "$rule_file" "allow_ports")
|
||||||
|
# if [[ -n "$allow_ports" ]]; then
|
||||||
|
# printf "\n Allow Ports:\n"
|
||||||
|
# ui::print_list "+" "$allow_ports"
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# # Allow IPs
|
||||||
|
# local allow_ips
|
||||||
|
# allow_ips=$(json::get "$rule_file" "allow_ips")
|
||||||
|
# if [[ -n "$allow_ips" ]]; then
|
||||||
|
# printf "\n Allow IPs:\n"
|
||||||
|
# while IFS= read -r ip; do
|
||||||
|
# printf " + %s\n" "$ip"
|
||||||
|
# done <<< "$allow_ips"
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# # Block IPs
|
||||||
|
# local block_ips
|
||||||
|
# block_ips=$(json::get "$rule_file" "block_ips")
|
||||||
|
# if [[ -n "$block_ips" ]]; then
|
||||||
|
# printf "\n Block IPs:\n"
|
||||||
|
# while IFS= read -r ip; do
|
||||||
|
# printf " - %s\n" "$ip"
|
||||||
|
# done <<< "$block_ips"
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# # Block ports
|
||||||
|
# local block_ports
|
||||||
|
# block_ports=$(json::get "$rule_file" "block_ports")
|
||||||
|
# if [[ -n "$block_ports" ]]; then
|
||||||
|
# printf "\n Block Ports:\n"
|
||||||
|
# while IFS= read -r entry; do
|
||||||
|
# printf " - %s\n" "$entry"
|
||||||
|
# done <<< "$block_ports"
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# # Precompute peers before any other operations
|
||||||
|
# local peer_list=()
|
||||||
|
# mapfile -t peer_list < <(peers::with_rule "$name")
|
||||||
|
# local peer_count=${#peer_list[@]}
|
||||||
|
|
||||||
|
# # Peer count — always shown
|
||||||
|
# printf "\n %-20s %s\n" "Assigned Peers:" "$peer_count"
|
||||||
|
# printf " %s\n" "$(printf '─%.0s' {1..40})"
|
||||||
|
|
||||||
|
# # Peer details — only with --peers flag
|
||||||
|
# if $show_peers && [[ $peer_count -gt 0 ]]; then
|
||||||
|
# for peer_name in "${peer_list[@]}"; do
|
||||||
|
# local ip
|
||||||
|
# ip=$(peers::get_ip "$peer_name")
|
||||||
|
# printf " %-28s %s\n" "$peer_name" "$ip"
|
||||||
|
# done
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# printf "\n"
|
||||||
|
# }
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# Add
|
# Add
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|
@ -260,20 +337,15 @@ function cmd::rule::add() {
|
||||||
local rule_file
|
local rule_file
|
||||||
rule_file="$(ctx::rule::path "${name}.rule")"
|
rule_file="$(ctx::rule::path "${name}.rule")"
|
||||||
|
|
||||||
# Build JSON using json_helper
|
local allow_str block_str port_str
|
||||||
python3 -c "
|
|
||||||
import json
|
allow_str=$(IFS=','; echo "${allow_ips[*]}")
|
||||||
rule = {
|
block_str=$(IFS=','; echo "${block_ips[*]}")
|
||||||
'name': '${name}',
|
port_str=$(IFS=','; echo "${block_ports[*]}")
|
||||||
'desc': '${desc}',
|
|
||||||
'dns_redirect': $(${dns_redirect} && echo 'true' || echo 'false'),
|
json::create_rule "$rule_file" "$name" "$desc" \
|
||||||
'allow_ips': [$(printf '"%s",' "${allow_ips[@]}" | sed 's/,$//')] ,
|
"$($dns_redirect && echo true || echo false)" \
|
||||||
'block_ips': [$(printf '"%s",' "${block_ips[@]}" | sed 's/,$//')],
|
"$allow_str" "$block_str" "$port_str" || return 1
|
||||||
'block_ports': [$(printf '"%s",' "${block_ports[@]}" | sed 's/,$//')]
|
|
||||||
}
|
|
||||||
with open('${rule_file}', 'w') as f:
|
|
||||||
json.dump(rule, f, indent=2)
|
|
||||||
"
|
|
||||||
|
|
||||||
log::wg_success "Rule created: ${name}"
|
log::wg_success "Rule created: ${name}"
|
||||||
}
|
}
|
||||||
|
|
@ -369,19 +441,21 @@ function cmd::rule::remove() {
|
||||||
rule::require_exists "$name" || return 1
|
rule::require_exists "$name" || return 1
|
||||||
|
|
||||||
# Check for assigned peers
|
# Check for assigned peers
|
||||||
local peer_count
|
|
||||||
peer_count=$(peers::with_rule "$name" | grep -c . || echo 0)
|
local peer_list=()
|
||||||
|
mapfile -t peer_list < <(peers::with_rule "$name")
|
||||||
|
local peer_count=${#peer_list[@]}
|
||||||
|
|
||||||
if [[ "$peer_count" -gt 0 ]]; then
|
if [[ "$peer_count" -gt 0 ]]; then
|
||||||
log::error "Rule '${name}' is assigned to ${peer_count} peer(s) — unassign first or use --force"
|
log::error "Rule '${name}' is assigned to ${peer_count} peer(s) — unassign first or use --force"
|
||||||
if ! $force; then
|
$force || return 1
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
# Force: unassign from all peers
|
# Force: unassign from all peers
|
||||||
while IFS= read -r peer; do
|
for peer in "${peer_list[@]}"; do
|
||||||
local ip
|
local ip
|
||||||
ip=$(peers::get_ip "$peer")
|
ip=$(peers::get_ip "$peer")
|
||||||
rule::unapply "$name" "$ip"
|
rule::unapply "$name" "$ip"
|
||||||
done < <(peers::with_rule "$name")
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -f "$(ctx::rule::path "${name}.rule")"
|
rm -f "$(ctx::rule::path "${name}.rule")"
|
||||||
|
|
@ -394,7 +468,6 @@ function cmd::rule::remove() {
|
||||||
|
|
||||||
function cmd::rule::assign() {
|
function cmd::rule::assign() {
|
||||||
local name="" peer="" type=""
|
local name="" peer="" type=""
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--name) name="$2"; shift 2 ;;
|
--name) name="$2"; shift 2 ;;
|
||||||
|
|
@ -421,15 +494,19 @@ function cmd::rule::assign() {
|
||||||
# Unapply existing rule first if any
|
# Unapply existing rule first if any
|
||||||
local existing_rule
|
local existing_rule
|
||||||
existing_rule=$(peers::get_meta "$peer" "rule")
|
existing_rule=$(peers::get_meta "$peer" "rule")
|
||||||
if [[ -n "$existing_rule" ]]; then
|
|
||||||
local ip
|
local ip
|
||||||
ip=$(peers::get_ip "$peer")
|
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"
|
rule::unapply "$existing_rule" "$ip"
|
||||||
log::wg "Removed existing rule '${existing_rule}' from: ${peer}"
|
log::wg "Removed existing rule '${existing_rule}' from: ${peer}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local ip
|
|
||||||
ip=$(peers::get_ip "$peer")
|
|
||||||
rule::apply "$name" "$ip"
|
rule::apply "$name" "$ip"
|
||||||
|
|
||||||
log::wg_success "Assigned rule '${name}' to: ${peer}"
|
log::wg_success "Assigned rule '${name}' to: ${peer}"
|
||||||
|
|
@ -502,21 +579,76 @@ function cmd::rule::migrate() {
|
||||||
local count=0
|
local count=0
|
||||||
local lines
|
local lines
|
||||||
mapfile -t lines < "$tmp"
|
mapfile -t lines < "$tmp"
|
||||||
echo "DEBUG: lines count=${#lines[@]}"
|
|
||||||
for line in "${lines[@]}"; do
|
for line in "${lines[@]}"; do
|
||||||
echo "DEBUG: processing line=$line"
|
|
||||||
IFS=" " read -r peer_name default_rule ip <<< "$line"
|
IFS=" " read -r peer_name default_rule ip <<< "$line"
|
||||||
rule::apply "$default_rule" "$ip" "$peer_name" </dev/null
|
rule::apply "$default_rule" "$ip" "$peer_name" </dev/null
|
||||||
echo "DEBUG: after apply, count=$count"
|
|
||||||
(( count++ )) || true
|
(( count++ )) || true
|
||||||
echo "DEBUG: incremented count=$count"
|
|
||||||
done
|
done
|
||||||
echo "DEBUG: loop done, count=$count"
|
|
||||||
|
|
||||||
echo "DEBUG: final count=$count"
|
cat "$tmp"
|
||||||
echo "DEBUG: tmp contents:"
|
|
||||||
cat "$tmp"
|
|
||||||
|
|
||||||
rm -f "$tmp"
|
rm -f "$tmp"
|
||||||
log::wg_success "Migrated ${count} peers"
|
log::wg_success "Migrated ${count} peers"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Reapply Rule
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
function cmd::rule::reapply() {
|
||||||
|
local name=""
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--name) name="$2"; shift 2 ;;
|
||||||
|
*) log::error "Unknown flag: $1"; return 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
[[ -z "$name" ]] && log::error "Missing --name" && return 1
|
||||||
|
rule::require_exists "$name" || return 1
|
||||||
|
rule::reapply_all "$name"
|
||||||
|
log::wg_success "Rule '${name}' reapplied"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Show helpers
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
function cmd::rule::_show_section() {
|
||||||
|
local title="${1:-}" color="${2:-white}" use_color="${3:-false}"
|
||||||
|
local color_code=""
|
||||||
|
if $use_color; then
|
||||||
|
case "$color" in
|
||||||
|
green) color_code="\033[0;32m" ;;
|
||||||
|
red) color_code="\033[0;31m" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
printf "\n ${color_code}── %s ──────────────────────────────────\033[0m\n" "$title"
|
||||||
|
}
|
||||||
|
|
||||||
|
function cmd::rule::_show_entries() {
|
||||||
|
local label="${1:-}" prefix="${2:-}" entries="${3:-}"
|
||||||
|
local use_color="${4:-false}" color="${5:-white}"
|
||||||
|
[[ -z "$entries" ]] && return 0
|
||||||
|
|
||||||
|
local color_code="" reset=""
|
||||||
|
if $use_color; then
|
||||||
|
case "$color" in
|
||||||
|
green) color_code="\033[0;32m" ;;
|
||||||
|
red) color_code="\033[0;31m" ;;
|
||||||
|
esac
|
||||||
|
reset="\033[0m"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf " %-8s" "${label}:"
|
||||||
|
local first=true
|
||||||
|
while IFS= read -r entry; do
|
||||||
|
[[ -z "$entry" ]] && continue
|
||||||
|
if $first; then
|
||||||
|
printf "%b%s %s%b\n" "$color_code" "$prefix" "$entry" "$reset"
|
||||||
|
first=false
|
||||||
|
else
|
||||||
|
printf " %b%s %s%b\n" "$color_code" "$prefix" "$entry" "$reset"
|
||||||
|
fi
|
||||||
|
done <<< "$entries"
|
||||||
|
}
|
||||||
|
|
@ -121,6 +121,7 @@ function cmd::test::run_function() {
|
||||||
cmd::rule::assign) cmd::test::fn_rule_assign ;;
|
cmd::rule::assign) cmd::test::fn_rule_assign ;;
|
||||||
cmd::rename::run) cmd::test::fn_rename ;;
|
cmd::rename::run) cmd::test::fn_rename ;;
|
||||||
cmd::remove::run) cmd::test::fn_remove ;;
|
cmd::remove::run) cmd::test::fn_remove ;;
|
||||||
|
cmd::unblock::run) cmd::test::fn_unblock ;;
|
||||||
*)
|
*)
|
||||||
log::error "No function test defined for: ${fn}"
|
log::error "No function test defined for: ${fn}"
|
||||||
return 1
|
return 1
|
||||||
|
|
@ -166,7 +167,7 @@ function cmd::test::section_rules() {
|
||||||
test::section "Rules"
|
test::section "Rules"
|
||||||
cmd::test::run_cmd "rule list" "guest" rule list
|
cmd::test::run_cmd "rule list" "guest" rule list
|
||||||
cmd::test::run_cmd "rule show --name guest" "Description" rule show --name guest
|
cmd::test::run_cmd "rule show --name guest" "Description" rule show --name guest
|
||||||
cmd::test::run_cmd "rule show --name guest --peers" "Peers:" rule show --name guest --peers
|
cmd::test::run_cmd "rule show --name guest --peers" "Assigned:" rule show --name guest --peers
|
||||||
cmd::test::run_cmd "rule show --name user" "Description" rule show --name user
|
cmd::test::run_cmd "rule show --name user" "Description" rule show --name user
|
||||||
cmd::test::run_cmd "rule show --name admin" "Description" rule show --name admin
|
cmd::test::run_cmd "rule show --name admin" "Description" rule show --name admin
|
||||||
cmd::test::run_cmd_fails "rule show nonexistent" rule show --name nonexistent
|
cmd::test::run_cmd_fails "rule show nonexistent" rule show --name nonexistent
|
||||||
|
|
@ -217,6 +218,9 @@ function cmd::test::section_destructive() {
|
||||||
cmd::test::run_cmd "add phone peer" "added successfully" \
|
cmd::test::run_cmd "add phone peer" "added successfully" \
|
||||||
add --name testunit --type phone
|
add --name testunit --type phone
|
||||||
|
|
||||||
|
# Debug: show what was created
|
||||||
|
"$WGCTL_BINARY" list | grep testunit >&2
|
||||||
|
|
||||||
# Block/unblock
|
# Block/unblock
|
||||||
cmd::test::run_cmd "block peer" "blocked" \
|
cmd::test::run_cmd "block peer" "blocked" \
|
||||||
block --name phone-testunit
|
block --name phone-testunit
|
||||||
|
|
@ -226,10 +230,13 @@ function cmd::test::section_destructive() {
|
||||||
unblock --name phone-testunit
|
unblock --name phone-testunit
|
||||||
|
|
||||||
# Rule assign/unassign
|
# Rule assign/unassign
|
||||||
cmd::test::run_cmd "rule assign" "Assigned" \
|
cmd::test::run_cmd "rule assign" "Assigned" \
|
||||||
rule assign --name admin --peer phone-testunit
|
rule assign --name user --peer phone-testunit
|
||||||
cmd::test::run_cmd "rule unassign" "Unassigned" \
|
cmd::test::run_cmd "rule unassign" "Unassigned" \
|
||||||
rule unassign --peer phone-testunit
|
rule unassign --peer phone-testunit
|
||||||
|
# Re-assign user rule (default) for cleanup
|
||||||
|
/usr/local/bin/wgctl rule assign --name user --peer phone-testunit \
|
||||||
|
> /dev/null 2>&1 || true
|
||||||
|
|
||||||
# Group operations
|
# Group operations
|
||||||
cmd::test::run_cmd "group add" "created" \
|
cmd::test::run_cmd "group add" "created" \
|
||||||
|
|
@ -318,10 +325,43 @@ function cmd::test::fn_rename() {
|
||||||
rename --name phone-testunit2
|
rename --name phone-testunit2
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
/usr/local/bin/wgctl remove --name phone-testunit2 --force \
|
"$WGCTL_BINARY" remove --name phone-testunit2 --force \
|
||||||
> /dev/null 2>&1 || true
|
> /dev/null 2>&1 || true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cmd::test::fn_unblock() {
|
||||||
|
test::section "cmd::unblock::run"
|
||||||
|
|
||||||
|
# Setup — add and block a peer
|
||||||
|
"$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
|
||||||
|
"$WGCTL_BINARY" add --name testunit --type phone > /dev/null 2>&1
|
||||||
|
"$WGCTL_BINARY" block --name phone-testunit > /dev/null 2>&1
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
cmd::test::run_cmd "unblock peer" "unblocked" unblock --name phone-testunit
|
||||||
|
cmd::test::run_cmd "unblock not blocked" "not blocked" unblock --name phone-testunit
|
||||||
|
cmd::test::run_cmd_fails "unblock nonexistent" unblock --name nonexistent-peer
|
||||||
|
cmd::test::run_cmd_fails "unblock missing --name" unblock
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
"$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
|
function cmd::test::fn_rule_assign() {
|
||||||
|
test::section "cmd::rule::assign"
|
||||||
|
|
||||||
|
"$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
|
||||||
|
"$WGCTL_BINARY" add --name testunit --type phone > /dev/null 2>&1
|
||||||
|
|
||||||
|
# Verify peer exists
|
||||||
|
echo "DEBUG peer exists: $("$WGCTL_BINARY" list | grep phone-testunit)"
|
||||||
|
|
||||||
|
cmd::test::run_cmd "rule assign" "Assigned" \
|
||||||
|
rule assign --name admin --peer phone-testunit
|
||||||
|
|
||||||
|
"$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# Run
|
# Run
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|
|
||||||
|
|
@ -40,23 +40,6 @@ Examples:
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
# ============================================
|
|
||||||
# Helpers
|
|
||||||
# ============================================
|
|
||||||
|
|
||||||
function cmd::unblock::get_client_ip() {
|
|
||||||
local name="$1"
|
|
||||||
local conf
|
|
||||||
conf="$(ctx::clients)/${name}.conf"
|
|
||||||
|
|
||||||
if [[ ! -f "$conf" ]]; then
|
|
||||||
log::error "Client not found: ${name}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
grep "^Address" "$conf" | awk '{print $3}' | cut -d'/' -f1
|
|
||||||
}
|
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# Unblock Run
|
# Unblock Run
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|
@ -109,24 +92,12 @@ function cmd::unblock::run() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local client_ip
|
local client_ip
|
||||||
client_ip=$(cmd::unblock::get_client_ip "$name") || return 1
|
client_ip=$(peers::get_ip "$name") || return 1
|
||||||
|
|
||||||
# $quiet || log::section "Unblocking client: ${name} (${client_ip})"
|
# $quiet || log::section "Unblocking client: ${name} (${client_ip})"
|
||||||
|
|
||||||
if $all; then
|
if $all; then
|
||||||
fw::unblock_all "$client_ip"
|
cmd::unblock::_unblock_all "$name" "$client_ip" "$quiet"
|
||||||
fw::remove_block_file "$name"
|
|
||||||
monitor::unwatch_client "$name"
|
|
||||||
|
|
||||||
# Re-add peer to server if missing
|
|
||||||
if ! peers::exists_in_server "$name"; then
|
|
||||||
local public_key
|
|
||||||
public_key=$(keys::public "$name") || return 1
|
|
||||||
peers::add_to_server "$name" "$public_key" "$client_ip"
|
|
||||||
peers::reload
|
|
||||||
fi
|
|
||||||
|
|
||||||
$quiet || log::wg_success "${name} has been unblocked."
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -150,3 +121,24 @@ function cmd::unblock::run() {
|
||||||
|
|
||||||
$quiet || log::wg_success "Unblock rules applied for: ${name}"
|
$quiet || log::wg_success "Unblock rules applied for: ${name}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cmd::unblock::_unblock_all() {
|
||||||
|
local name="${1:-}"
|
||||||
|
local client_ip="${2:-}"
|
||||||
|
local quiet="${3:-false}"
|
||||||
|
|
||||||
|
log::debug "_unblock_all: name=$name ip=$client_ip"
|
||||||
|
fw::unblock_all "$client_ip"
|
||||||
|
fw::remove_block_file "$name"
|
||||||
|
monitor::unwatch_client "$name"
|
||||||
|
|
||||||
|
if ! peers::exists_in_server "$name"; then
|
||||||
|
local public_key
|
||||||
|
public_key=$(keys::public "$name") || return 1
|
||||||
|
log::debug "_unblock_all: adding to server pub=$public_key"
|
||||||
|
peers::add_to_server "$name" "$public_key" "$client_ip"
|
||||||
|
peers::reload
|
||||||
|
fi
|
||||||
|
|
||||||
|
$quiet || log::wg_success "${name} has been unblocked."
|
||||||
|
}
|
||||||
|
|
@ -27,3 +27,4 @@ function json::iso_to_ts() { python3 "$JSON_HELPER" iso_to_ts "$@" </de
|
||||||
function json::rule_list_data() { python3 "$JSON_HELPER" rule_list_data "$@" </dev/null; }
|
function json::rule_list_data() { python3 "$JSON_HELPER" rule_list_data "$@" </dev/null; }
|
||||||
function json::group_list_data() { python3 "$JSON_HELPER" group_list_data "$@" </dev/null; }
|
function json::group_list_data() { python3 "$JSON_HELPER" group_list_data "$@" </dev/null; }
|
||||||
function json::fmt_datetime() { python3 "$JSON_HELPER" fmt_datetime "$@" </dev/null; }
|
function json::fmt_datetime() { python3 "$JSON_HELPER" fmt_datetime "$@" </dev/null; }
|
||||||
|
function json::create_rule() { python3 "$JSON_HELPER" create_rule "$@" </dev/null; }
|
||||||
|
|
@ -625,6 +625,19 @@ def fmt_datetime(iso_str, fmt):
|
||||||
except:
|
except:
|
||||||
print(iso_str)
|
print(iso_str)
|
||||||
|
|
||||||
|
def create_rule(file, name, desc, dns_redirect, allow_ips, block_ips, block_ports):
|
||||||
|
rule = {
|
||||||
|
'name': name,
|
||||||
|
'desc': desc,
|
||||||
|
'dns_redirect': dns_redirect == 'true',
|
||||||
|
'allow_ips': [x for x in allow_ips.split(',') if x] if allow_ips else [],
|
||||||
|
'block_ips': [x for x in block_ips.split(',') if x] if block_ips else [],
|
||||||
|
'block_ports': [x for x in block_ports.split(',') if x] if block_ports else [],
|
||||||
|
'allow_ports': []
|
||||||
|
}
|
||||||
|
with open(file, 'w') as f:
|
||||||
|
json.dump(rule, f, indent=2)
|
||||||
|
|
||||||
commands = {
|
commands = {
|
||||||
'get': lambda args: get(args[0], args[1]),
|
'get': lambda args: get(args[0], args[1]),
|
||||||
'set': lambda args: set_key(args[0], args[1], args[2]),
|
'set': lambda args: set_key(args[0], args[1], args[2]),
|
||||||
|
|
@ -651,6 +664,8 @@ commands = {
|
||||||
'rule_list_data': lambda args: rule_list_data(args[0], args[1]),
|
'rule_list_data': lambda args: rule_list_data(args[0], args[1]),
|
||||||
'group_list_data': lambda args: group_list_data(args[0], args[1]),
|
'group_list_data': lambda args: group_list_data(args[0], args[1]),
|
||||||
'fmt_datetime': lambda args: fmt_datetime(args[0], args[1]),
|
'fmt_datetime': lambda args: fmt_datetime(args[0], args[1]),
|
||||||
|
'create_rule': lambda args: create_rule(args[0], args[1], args[2], args[3], args[4], args[5], args[6]),
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"phone-fred": "94.63.0.129",
|
"phone-fred": "94.63.0.129",
|
||||||
"phone-helena": "148.69.39.194",
|
"phone-helena": "148.69.37.26",
|
||||||
"phone-nuno": "94.63.0.129",
|
"phone-nuno": "94.63.0.129",
|
||||||
"tablet-nuno": "148.69.202.5",
|
"tablet-nuno": "148.69.202.5",
|
||||||
"guest-zephyr": "5.13.82.5",
|
"guest-zephyr": "5.13.82.5",
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,9 @@ function rule::apply() {
|
||||||
local client_ip="$2"
|
local client_ip="$2"
|
||||||
local peer_name="${3:-}" # optional, avoids find_by_ip call
|
local peer_name="${3:-}" # optional, avoids find_by_ip call
|
||||||
|
|
||||||
|
log::debug "rule::apply ENTRY: rule=$rule_name ip=$client_ip peer=$peer_name"
|
||||||
rule::require_exists "$rule_name" || return 1
|
rule::require_exists "$rule_name" || return 1
|
||||||
|
log::debug "rule::apply: exists check passed"
|
||||||
|
|
||||||
# Use provided peer_name or look it up
|
# Use provided peer_name or look it up
|
||||||
if [[ -z "$peer_name" ]]; then
|
if [[ -z "$peer_name" ]]; then
|
||||||
|
|
|
||||||
2
wgctl
2
wgctl
|
|
@ -3,7 +3,7 @@ set -Eeuo pipefail
|
||||||
|
|
||||||
source "$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)/core.sh"
|
source "$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)/core.sh"
|
||||||
|
|
||||||
# LOG_LEVEL=DEBUG
|
LOG_LEVEL=DEBUG
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# Modules
|
# Modules
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue