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 ips=() subnets=() ports=() services=()
|
||||
local quiet=false force=false
|
||||
local changed=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
|
|
@ -139,6 +140,26 @@ function cmd::block::run() {
|
|||
log::error "Service not found or has no ports: ${svc}"
|
||||
return 1
|
||||
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
|
||||
if [[ "$resolved" == *:*:* ]]; then
|
||||
local b_ip b_port b_proto
|
||||
|
|
@ -151,21 +172,26 @@ function cmd::block::run() {
|
|||
block::add_rule "$name" "$client_ip" "ip" "$svc" "$resolved"
|
||||
fi
|
||||
done
|
||||
|
||||
changed=true
|
||||
$quiet || log::wg_success "${svc} has been blocked for ${name}"
|
||||
done
|
||||
|
||||
[[ ${#ips[@]} -gt 0 || ${#ports[@]} -gt 0 || \
|
||||
${#subnets[@]} -gt 0 ]] && changed=true
|
||||
|
||||
# Reapply in correct order: rule ACCEPT first, then peer DROP rules
|
||||
# Only reorder if rules were actually added
|
||||
if $changed; then
|
||||
local peer_rule
|
||||
peer_rule=$(peers::get_meta "$name" "rule")
|
||||
if [[ -n "$peer_rule" ]] && rule::exists "$peer_rule"; then
|
||||
fw::flush_peer "$client_ip"
|
||||
rule::apply "$peer_rule" "$client_ip" "$name"
|
||||
block::restore_rules_for "$name" "$client_ip"
|
||||
else
|
||||
# No rule assigned — peer blocks are the only fw rules, order is fine
|
||||
: # no-op
|
||||
fi
|
||||
fi
|
||||
|
||||
$quiet || log::wg_success "${name} — access restricted"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ function cmd::unblock::on_load() {
|
|||
flag::register --proto
|
||||
flag::register --subnet
|
||||
flag::register --all
|
||||
|
||||
# System - NET Services
|
||||
flag::register --service
|
||||
}
|
||||
|
||||
# ============================================
|
||||
|
|
@ -54,6 +57,7 @@ function cmd::unblock::run() {
|
|||
local ips=()
|
||||
local subnets=()
|
||||
local ports=()
|
||||
local services=()
|
||||
local all=false
|
||||
local quiet=false
|
||||
|
||||
|
|
@ -66,6 +70,7 @@ function cmd::unblock::run() {
|
|||
--quiet) quiet=true; shift ;;
|
||||
--subnet) subnets+=("$2"); shift 2 ;;
|
||||
--port) ports+=("$2"); shift 2 ;;
|
||||
--service) services+=("$2"); shift 2 ;;
|
||||
--all) all=true; shift ;;
|
||||
--help) cmd::unblock::help; return ;;
|
||||
*)
|
||||
|
|
@ -91,7 +96,7 @@ function cmd::unblock::run() {
|
|||
fi
|
||||
|
||||
# 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
|
||||
fi
|
||||
|
||||
|
|
@ -105,6 +110,49 @@ function cmd::unblock::run() {
|
|||
return 0
|
||||
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
|
||||
for ip in "${ips[@]}"; do
|
||||
fw::unblock_ip "$client_ip" "$ip"
|
||||
|
|
@ -114,6 +162,7 @@ function cmd::unblock::run() {
|
|||
# Unblock specific subnets
|
||||
for subnet in "${subnets[@]}"; do
|
||||
fw::unblock_subnet "$client_ip" "$subnet"
|
||||
block::remove_rule "$name" "subnet" "$subnet"
|
||||
done
|
||||
|
||||
# Unblock specific ports
|
||||
|
|
@ -122,9 +171,11 @@ function cmd::unblock::run() {
|
|||
IFS=":" read -r target port proto <<< "$entry"
|
||||
proto="${proto:-tcp}"
|
||||
fw::unblock_port "$client_ip" "$target" "$port" "$proto"
|
||||
block::remove_rule "$name" "port" "$b_target" "$b_port" "$b_proto"
|
||||
done
|
||||
|
||||
$quiet || log::wg_success "Unblock rules applied for: ${name}"
|
||||
# Clean up block file if now empty
|
||||
block::cleanup "$name"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1470,6 +1470,19 @@ def net_reverse_lookup(file, ip, port='', proto=''):
|
|||
print(svc_name)
|
||||
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 = {
|
||||
'get': lambda args: get(args[0], args[1]),
|
||||
'set': lambda args: set_key(args[0], args[1], args[2]),
|
||||
|
|
|
|||
|
|
@ -222,6 +222,16 @@ function block::format_rules() {
|
|||
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() {
|
||||
# local name="${1:?}"
|
||||
# block::has_file "$name" || return 0
|
||||
|
|
|
|||
|
|
@ -12,6 +12,30 @@ function fw::on_load() {
|
|||
# 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
|
||||
|
||||
|
|
@ -174,7 +198,7 @@ function fw::nat_remove_dns_redirect() {
|
|||
|
||||
function fw::forward_rules_for_ip() {
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -70,15 +70,14 @@ function rule::is_applied() {
|
|||
local target port proto
|
||||
IFS=":" read -r target port proto <<< "$first_port"
|
||||
proto="${proto:-tcp}"
|
||||
fw::_forward_exists -s "$client_ip" -d "$target" \
|
||||
-p "$proto" --dport "$port" -j DROP
|
||||
fw::has_block_rule "$client_ip" "$target" "$proto" "$port"
|
||||
return $?
|
||||
fi
|
||||
|
||||
local first_ip
|
||||
first_ip=$(rule::get "$rule_name" "block_ips" | head -1)
|
||||
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 $?
|
||||
fi
|
||||
|
||||
|
|
|
|||
3
wgctl
3
wgctl
|
|
@ -52,9 +52,6 @@ declare -A CMD_ALIASES=(
|
|||
[disable]=service
|
||||
)
|
||||
|
||||
block::has_specific_rules "phone-test" && echo "HAS SPECIFIC" || echo "NO SPECIFIC"
|
||||
block::get_rules "phone-test"
|
||||
|
||||
# ============================================
|
||||
# Dispatch
|
||||
# ============================================
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue