feat: block/unblock --service, fw::has_rule/has_block_rule/has_allow_rule, block::cleanup, restricted status in inspect, net service annotations
This commit is contained in:
parent
9a3ac2ae47
commit
c1d0a9ddd4
7 changed files with 140 additions and 20 deletions
|
|
@ -57,6 +57,7 @@ function cmd::block::run() {
|
||||||
local name="" type="" block_name=""
|
local name="" type="" block_name=""
|
||||||
local ips=() subnets=() ports=() services=()
|
local ips=() subnets=() ports=() services=()
|
||||||
local quiet=false force=false
|
local quiet=false force=false
|
||||||
|
local changed=false
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
|
|
@ -139,6 +140,26 @@ function cmd::block::run() {
|
||||||
log::error "Service not found or has no ports: ${svc}"
|
log::error "Service not found or has no ports: ${svc}"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Check if already blocked
|
||||||
|
local already_blocked=true
|
||||||
|
for resolved in "${resolved_lines[@]}"; do
|
||||||
|
if [[ "$resolved" == *:*:* ]]; then
|
||||||
|
local b_ip b_port b_proto
|
||||||
|
IFS=":" read -r b_ip b_port b_proto <<< "$resolved"
|
||||||
|
fw::has_block_rule "$client_ip" "$b_ip" "$b_proto" "$b_port" 2>/dev/null || \
|
||||||
|
{ already_blocked=false; break; }
|
||||||
|
else
|
||||||
|
fw::has_block_rule "$client_ip" "$resolved" 2>/dev/null || \
|
||||||
|
{ already_blocked=false; break; }
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if $already_blocked; then
|
||||||
|
$quiet || log::wg_warning "${svc} is already blocked for ${name}"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
for resolved in "${resolved_lines[@]}"; do
|
for resolved in "${resolved_lines[@]}"; do
|
||||||
if [[ "$resolved" == *:*:* ]]; then
|
if [[ "$resolved" == *:*:* ]]; then
|
||||||
local b_ip b_port b_proto
|
local b_ip b_port b_proto
|
||||||
|
|
@ -151,21 +172,26 @@ function cmd::block::run() {
|
||||||
block::add_rule "$name" "$client_ip" "ip" "$svc" "$resolved"
|
block::add_rule "$name" "$client_ip" "ip" "$svc" "$resolved"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
changed=true
|
||||||
|
$quiet || log::wg_success "${svc} has been blocked for ${name}"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
[[ ${#ips[@]} -gt 0 || ${#ports[@]} -gt 0 || \
|
||||||
|
${#subnets[@]} -gt 0 ]] && changed=true
|
||||||
|
|
||||||
# Reapply in correct order: rule ACCEPT first, then peer DROP rules
|
# Reapply in correct order: rule ACCEPT first, then peer DROP rules
|
||||||
local peer_rule
|
# Only reorder if rules were actually added
|
||||||
peer_rule=$(peers::get_meta "$name" "rule")
|
if $changed; then
|
||||||
if [[ -n "$peer_rule" ]] && rule::exists "$peer_rule"; then
|
local peer_rule
|
||||||
fw::flush_peer "$client_ip"
|
peer_rule=$(peers::get_meta "$name" "rule")
|
||||||
rule::apply "$peer_rule" "$client_ip" "$name"
|
if [[ -n "$peer_rule" ]] && rule::exists "$peer_rule"; then
|
||||||
block::restore_rules_for "$name" "$client_ip"
|
fw::flush_peer "$client_ip"
|
||||||
else
|
rule::apply "$peer_rule" "$client_ip" "$name"
|
||||||
# No rule assigned — peer blocks are the only fw rules, order is fine
|
block::restore_rules_for "$name" "$client_ip"
|
||||||
: # no-op
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$quiet || log::wg_success "${name} — access restricted"
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ function cmd::unblock::on_load() {
|
||||||
flag::register --proto
|
flag::register --proto
|
||||||
flag::register --subnet
|
flag::register --subnet
|
||||||
flag::register --all
|
flag::register --all
|
||||||
|
|
||||||
|
# System - NET Services
|
||||||
|
flag::register --service
|
||||||
}
|
}
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|
@ -54,9 +57,10 @@ function cmd::unblock::run() {
|
||||||
local ips=()
|
local ips=()
|
||||||
local subnets=()
|
local subnets=()
|
||||||
local ports=()
|
local ports=()
|
||||||
|
local services=()
|
||||||
local all=false
|
local all=false
|
||||||
local quiet=false
|
local quiet=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 ;;
|
||||||
|
|
@ -66,6 +70,7 @@ function cmd::unblock::run() {
|
||||||
--quiet) quiet=true; shift ;;
|
--quiet) quiet=true; shift ;;
|
||||||
--subnet) subnets+=("$2"); shift 2 ;;
|
--subnet) subnets+=("$2"); shift 2 ;;
|
||||||
--port) ports+=("$2"); shift 2 ;;
|
--port) ports+=("$2"); shift 2 ;;
|
||||||
|
--service) services+=("$2"); shift 2 ;;
|
||||||
--all) all=true; shift ;;
|
--all) all=true; shift ;;
|
||||||
--help) cmd::unblock::help; return ;;
|
--help) cmd::unblock::help; return ;;
|
||||||
*)
|
*)
|
||||||
|
|
@ -91,7 +96,7 @@ function cmd::unblock::run() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Default to full unblock if no specific flags given
|
# Default to full unblock if no specific flags given
|
||||||
if [[ ${#ips[@]} -eq 0 && ${#subnets[@]} -eq 0 && ${#ports[@]} -eq 0 ]]; then
|
if [[ ${#ips[@]} -eq 0 && ${#subnets[@]} -eq 0 && ${#ports[@]} -eq 0 && ${#services[@]} -eq 0 ]]; then
|
||||||
all=true
|
all=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -105,6 +110,49 @@ function cmd::unblock::run() {
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Unblock services
|
||||||
|
for svc in "${services[@]}"; do
|
||||||
|
local resolved_lines=()
|
||||||
|
mapfile -t resolved_lines < <(net::resolve "$svc" 2>/dev/null)
|
||||||
|
if [[ ${#resolved_lines[@]} -eq 0 ]]; then
|
||||||
|
log::error "Service not found: ${svc}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if actually blocked
|
||||||
|
local is_blocked=false
|
||||||
|
for resolved in "${resolved_lines[@]}"; do
|
||||||
|
if [[ "$resolved" == *:*:* ]]; then
|
||||||
|
local b_ip b_port b_proto
|
||||||
|
IFS=":" read -r b_ip b_port b_proto <<< "$resolved"
|
||||||
|
fw::has_block_rule "$client_ip" "$b_ip" "$b_proto" "$b_port" 2>/dev/null && \
|
||||||
|
{ is_blocked=true; break; }
|
||||||
|
else
|
||||||
|
fw::has_block_rule "$client_ip" "$resolved" 2>/dev/null && \
|
||||||
|
{ is_blocked=true; break; }
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! $is_blocked; then
|
||||||
|
$quiet || log::wg_warning "${svc} is not blocked for ${name}"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
for resolved in "${resolved_lines[@]}"; do
|
||||||
|
if [[ "$resolved" == *:*:* ]]; then
|
||||||
|
local b_ip b_port b_proto
|
||||||
|
IFS=":" read -r b_ip b_port b_proto <<< "$resolved"
|
||||||
|
fw::unblock_port "$client_ip" "$b_ip" "$b_port" "$b_proto"
|
||||||
|
block::remove_rule "$name" "port" "$b_ip" "$b_port" "$b_proto"
|
||||||
|
else
|
||||||
|
fw::unblock_ip "$client_ip" "$resolved"
|
||||||
|
block::remove_rule "$name" "ip" "$resolved"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
$quiet || log::wg_success "${svc} has been unblocked for ${name}"
|
||||||
|
done
|
||||||
|
|
||||||
# Unblock specific IPs
|
# Unblock specific IPs
|
||||||
for ip in "${ips[@]}"; do
|
for ip in "${ips[@]}"; do
|
||||||
fw::unblock_ip "$client_ip" "$ip"
|
fw::unblock_ip "$client_ip" "$ip"
|
||||||
|
|
@ -114,6 +162,7 @@ function cmd::unblock::run() {
|
||||||
# Unblock specific subnets
|
# Unblock specific subnets
|
||||||
for subnet in "${subnets[@]}"; do
|
for subnet in "${subnets[@]}"; do
|
||||||
fw::unblock_subnet "$client_ip" "$subnet"
|
fw::unblock_subnet "$client_ip" "$subnet"
|
||||||
|
block::remove_rule "$name" "subnet" "$subnet"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Unblock specific ports
|
# Unblock specific ports
|
||||||
|
|
@ -122,9 +171,11 @@ function cmd::unblock::run() {
|
||||||
IFS=":" read -r target port proto <<< "$entry"
|
IFS=":" read -r target port proto <<< "$entry"
|
||||||
proto="${proto:-tcp}"
|
proto="${proto:-tcp}"
|
||||||
fw::unblock_port "$client_ip" "$target" "$port" "$proto"
|
fw::unblock_port "$client_ip" "$target" "$port" "$proto"
|
||||||
|
block::remove_rule "$name" "port" "$b_target" "$b_port" "$b_proto"
|
||||||
done
|
done
|
||||||
|
|
||||||
$quiet || log::wg_success "Unblock rules applied for: ${name}"
|
# Clean up block file if now empty
|
||||||
|
block::cleanup "$name"
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1470,6 +1470,19 @@ def net_reverse_lookup(file, ip, port='', proto=''):
|
||||||
print(svc_name)
|
print(svc_name)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def block_is_empty(file):
|
||||||
|
data = _block_read(file)
|
||||||
|
if not data:
|
||||||
|
print("true")
|
||||||
|
return
|
||||||
|
empty = (
|
||||||
|
not data.get("blocked_direct", False) and
|
||||||
|
not data.get("blocked_by_groups", []) and
|
||||||
|
not data.get("rules", []) and
|
||||||
|
not data.get("services", [])
|
||||||
|
)
|
||||||
|
print("true" if empty else "false")
|
||||||
|
|
||||||
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]),
|
||||||
|
|
|
||||||
|
|
@ -222,6 +222,16 @@ function block::format_rules() {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function block::cleanup() {
|
||||||
|
local name="${1:?}"
|
||||||
|
block::has_file "$name" || return 0
|
||||||
|
local result
|
||||||
|
result=$(json::block_is_empty "$(block::file "$name")")
|
||||||
|
[[ "$result" == "true" ]] && block::remove_file "$name"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# function block::format_rules() {
|
# function block::format_rules() {
|
||||||
# local name="${1:?}"
|
# local name="${1:?}"
|
||||||
# block::has_file "$name" || return 0
|
# block::has_file "$name" || return 0
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,30 @@ function fw::on_load() {
|
||||||
# Rule Management
|
# Rule Management
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Public Interfaces
|
||||||
|
|
||||||
|
function fw::has_rule() {
|
||||||
|
# Generic rule existence check
|
||||||
|
# fw::has_rule <target> <client_ip> <dest> [port] [proto]
|
||||||
|
local action="${1:-DROP}" client_ip="${2:-}" target="${3:-}" \
|
||||||
|
port="${4:-}" proto="${5:-}"
|
||||||
|
if [[ -n "$port" ]]; then
|
||||||
|
fw::_forward_exists -s "$client_ip" -d "$target" \
|
||||||
|
-p "$proto" --dport "$port" -j "$action"
|
||||||
|
else
|
||||||
|
fw::_forward_exists -s "$client_ip" -d "$target" -j "$action"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function fw::has_block_rule() {
|
||||||
|
fw::has_rule "DROP" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
function fw::has_allow_rule() {
|
||||||
|
fw::has_rule "ACCEPT" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# Block / Unblock
|
# Block / Unblock
|
||||||
|
|
||||||
|
|
@ -174,7 +198,7 @@ function fw::nat_remove_dns_redirect() {
|
||||||
|
|
||||||
function fw::forward_rules_for_ip() {
|
function fw::forward_rules_for_ip() {
|
||||||
local ip="${1:-}"
|
local ip="${1:-}"
|
||||||
iptables -L FORWARD -n -v </dev/null | grep -F "$ip"
|
iptables -L FORWARD -n -v </dev/null | grep -F "$ip" || true
|
||||||
}
|
}
|
||||||
|
|
||||||
function fw::proto_name() {
|
function fw::proto_name() {
|
||||||
|
|
|
||||||
|
|
@ -70,15 +70,14 @@ function rule::is_applied() {
|
||||||
local target port proto
|
local target port proto
|
||||||
IFS=":" read -r target port proto <<< "$first_port"
|
IFS=":" read -r target port proto <<< "$first_port"
|
||||||
proto="${proto:-tcp}"
|
proto="${proto:-tcp}"
|
||||||
fw::_forward_exists -s "$client_ip" -d "$target" \
|
fw::has_block_rule "$client_ip" "$target" "$proto" "$port"
|
||||||
-p "$proto" --dport "$port" -j DROP
|
|
||||||
return $?
|
return $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local first_ip
|
local first_ip
|
||||||
first_ip=$(rule::get "$rule_name" "block_ips" | head -1)
|
first_ip=$(rule::get "$rule_name" "block_ips" | head -1)
|
||||||
if [[ -n "$first_ip" ]]; then
|
if [[ -n "$first_ip" ]]; then
|
||||||
fw::_forward_exists -s "$client_ip" -d "$first_ip" -j DROP
|
fw::has_block_rule "$client_ip" "$first_ip"
|
||||||
return $?
|
return $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
3
wgctl
3
wgctl
|
|
@ -52,9 +52,6 @@ declare -A CMD_ALIASES=(
|
||||||
[disable]=service
|
[disable]=service
|
||||||
)
|
)
|
||||||
|
|
||||||
block::has_specific_rules "phone-test" && echo "HAS SPECIFIC" || echo "NO SPECIFIC"
|
|
||||||
block::get_rules "phone-test"
|
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# Dispatch
|
# Dispatch
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue