refactor: rule::show new layout, assign fix, unblock helpers, test improvements

This commit is contained in:
Nuno Duque Nunes 2026-05-12 04:27:47 +00:00
parent 5702b118b0
commit 51e3443357
10 changed files with 312 additions and 147 deletions

View file

@ -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})"

View file

@ -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 "—"

View file

@ -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"
echo "DEBUG: tmp contents:"
cat "$tmp" 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"
}

View file

@ -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
@ -227,9 +231,12 @@ function cmd::test::section_destructive() {
# 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
# ============================================ # ============================================

View file

@ -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."
}

View file

@ -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; }

View file

@ -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__':

View file

@ -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",

View file

@ -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
View file

@ -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