feat: block/unblock --service, fw::has_rule wrappers, restricted status, net annotations, block system tests, 64 tests passing
This commit is contained in:
parent
c1d0a9ddd4
commit
16b4351313
5 changed files with 80 additions and 51 deletions
|
|
@ -113,6 +113,7 @@ function cmd::block::run() {
|
||||||
ip::require_valid "$ip"
|
ip::require_valid "$ip"
|
||||||
fw::block_ip "$client_ip" "$ip"
|
fw::block_ip "$client_ip" "$ip"
|
||||||
block::add_rule "$name" "$client_ip" "ip" "${block_name:-}" "$ip"
|
block::add_rule "$name" "$client_ip" "ip" "${block_name:-}" "$ip"
|
||||||
|
$quiet || log::wg_success "${ip} has been blocked for ${name}"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Block specific subnets
|
# Block specific subnets
|
||||||
|
|
@ -120,6 +121,7 @@ function cmd::block::run() {
|
||||||
ip::require_valid "$subnet"
|
ip::require_valid "$subnet"
|
||||||
fw::block_subnet "$client_ip" "$subnet"
|
fw::block_subnet "$client_ip" "$subnet"
|
||||||
block::add_rule "$name" "$client_ip" "subnet" "${block_name:-}" "$subnet"
|
block::add_rule "$name" "$client_ip" "subnet" "${block_name:-}" "$subnet"
|
||||||
|
$quiet || log::wg_success "${subnet} has been blocked for ${name}"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Block specific ports
|
# Block specific ports
|
||||||
|
|
@ -130,6 +132,7 @@ function cmd::block::run() {
|
||||||
fw::block_port "$client_ip" "$b_target" "$b_port" "${b_proto:-tcp}"
|
fw::block_port "$client_ip" "$b_target" "$b_port" "${b_proto:-tcp}"
|
||||||
block::add_rule "$name" "$client_ip" "port" "${block_name:-}" \
|
block::add_rule "$name" "$client_ip" "port" "${block_name:-}" \
|
||||||
"$b_target" "$b_port" "${b_proto:-tcp}"
|
"$b_target" "$b_port" "${b_proto:-tcp}"
|
||||||
|
$quiet || log::wg_success "${client_ip}:${b_port}:${b_proto:-tcp} has been blocked for ${name}"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Block services
|
# Block services
|
||||||
|
|
@ -147,7 +150,7 @@ function cmd::block::run() {
|
||||||
if [[ "$resolved" == *:*:* ]]; then
|
if [[ "$resolved" == *:*:* ]]; then
|
||||||
local b_ip b_port b_proto
|
local b_ip b_port b_proto
|
||||||
IFS=":" read -r b_ip b_port b_proto <<< "$resolved"
|
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 || \
|
fw::has_block_rule "$client_ip" "$b_ip" "$b_port" "$b_proto" 2>/dev/null || \
|
||||||
{ already_blocked=false; break; }
|
{ already_blocked=false; break; }
|
||||||
else
|
else
|
||||||
fw::has_block_rule "$client_ip" "$resolved" 2>/dev/null || \
|
fw::has_block_rule "$client_ip" "$resolved" 2>/dev/null || \
|
||||||
|
|
|
||||||
|
|
@ -130,18 +130,16 @@ function cmd::list::show_client() {
|
||||||
subtype=$(peers::get_meta "$name" "subtype")
|
subtype=$(peers::get_meta "$name" "subtype")
|
||||||
|
|
||||||
local endpoint="—"
|
local endpoint="—"
|
||||||
|
local ep
|
||||||
|
ep=$(monitor::endpoint_for_key "$public_key")
|
||||||
|
[[ -z "$ep" ]] && ep=$(monitor::last_endpoint "$name")
|
||||||
|
[[ -n "$ep" ]] && endpoint="$ep"
|
||||||
|
|
||||||
local is_blocked="false"
|
local is_blocked="false"
|
||||||
peers::is_blocked "$name" && is_blocked="true"
|
peers::is_blocked "$name" && is_blocked="true"
|
||||||
|
|
||||||
if [[ "$is_blocked" == "true" ]]; then
|
local is_restricted="false"
|
||||||
local ep
|
peers::is_restricted "$name" && is_restricted="true"
|
||||||
ep=$(monitor::last_endpoint "$name")
|
|
||||||
[[ -n "$ep" ]] && endpoint="$ep"
|
|
||||||
else
|
|
||||||
local ep
|
|
||||||
ep=$(monitor::endpoint_for_key "$public_key")
|
|
||||||
[[ -n "$ep" ]] && endpoint="$ep"
|
|
||||||
fi
|
|
||||||
|
|
||||||
local handshake_ts
|
local handshake_ts
|
||||||
handshake_ts=$(monitor::get_handshake_ts "$public_key")
|
handshake_ts=$(monitor::get_handshake_ts "$public_key")
|
||||||
|
|
@ -151,7 +149,7 @@ function cmd::list::show_client() {
|
||||||
|
|
||||||
local status
|
local status
|
||||||
status=$(peers::format_status "$name" "$public_key" \
|
status=$(peers::format_status "$name" "$public_key" \
|
||||||
"$is_blocked" "false" "$handshake_ts" "$last_ts")
|
"$is_blocked" "$is_restricted" "$handshake_ts" "$last_ts")
|
||||||
|
|
||||||
local last_seen
|
local last_seen
|
||||||
last_seen=$(peers::format_last_seen "$name" "$public_key" \
|
last_seen=$(peers::format_last_seen "$name" "$public_key" \
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,9 @@ function cmd::test::run_cmd() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "$expected" ]] && ! grep -qF "$expected" "$tmp"; then
|
if [[ -n "$expected" ]] && ! grep -qF "$expected" "$tmp"; then
|
||||||
test::fail "${desc} (expected '${expected}' in output)"
|
local actual
|
||||||
|
actual=$(head -3 "$tmp" | tr '\n' ' ' | sed 's/ */ /g' | cut -c1-100)
|
||||||
|
test::fail "${desc} (expected '${expected}', got: '${actual}')"
|
||||||
rm -f "$tmp"
|
rm -f "$tmp"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
@ -240,18 +242,44 @@ function cmd::test::section_destructive() {
|
||||||
"$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
|
"$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
|
||||||
"$WGCTL_BINARY" group remove --name testgroup --force > /dev/null 2>&1 || true
|
"$WGCTL_BINARY" group remove --name testgroup --force > /dev/null 2>&1 || true
|
||||||
"$WGCTL_BINARY" group remove --name testgroup2 --force > /dev/null 2>&1 || true
|
"$WGCTL_BINARY" group remove --name testgroup2 --force > /dev/null 2>&1 || true
|
||||||
|
"$WGCTL_BINARY" net rm --name test-block-svc --force > /dev/null 2>&1 || true
|
||||||
|
"$WGCTL_BINARY" unblock --name phone-testunit > /dev/null 2>&1 || true
|
||||||
|
|
||||||
# ── Add test peer ──────────────────────────
|
# ── Add test peer ──────────────────────────
|
||||||
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
|
||||||
|
|
||||||
# ── Direct block/unblock ───────────────────
|
# ── Direct block/unblock ───────────────────
|
||||||
cmd::test::run_cmd "block peer" "blocked" \
|
cmd::test::run_cmd "block peer" "blocked" block --name phone-testunit
|
||||||
block --name phone-testunit
|
cmd::test::run_cmd "list shows blocked" "blocked" list --blocked
|
||||||
cmd::test::run_cmd "list shows blocked" "blocked" \
|
cmd::test::run_cmd "unblock peer" "unblocked" unblock --name phone-testunit
|
||||||
list --blocked
|
|
||||||
cmd::test::run_cmd "unblock peer" "unblocked" \
|
# ── Specific IP block/unblock ──────────────
|
||||||
unblock --name phone-testunit
|
cmd::test::run_cmd "block peer --ip" "blocked for" \
|
||||||
|
block --name phone-testunit --ip 10.0.0.99
|
||||||
|
cmd::test::run_cmd "list shows restricted" "restricted" \
|
||||||
|
list --name phone-testunit
|
||||||
|
cmd::test::run_cmd "unblock peer --ip" "unblocked" \
|
||||||
|
unblock --name phone-testunit --ip 10.0.0.99
|
||||||
|
|
||||||
|
# ── Service block/unblock ──────────────────
|
||||||
|
"$WGCTL_BINARY" net add --name test-block-svc \
|
||||||
|
--ip 10.0.0.99 > /dev/null 2>&1
|
||||||
|
"$WGCTL_BINARY" net add --name test-block-svc:web \
|
||||||
|
--port 9999:tcp > /dev/null 2>&1
|
||||||
|
cmd::test::run_cmd "block peer --service (ip)" "blocked" \
|
||||||
|
block --name phone-testunit --service test-block-svc
|
||||||
|
cmd::test::run_cmd "block already blocked service" "already" \
|
||||||
|
block --name phone-testunit --service test-block-svc
|
||||||
|
cmd::test::run_cmd "unblock peer --service (ip)" "unblocked" \
|
||||||
|
unblock --name phone-testunit --service test-block-svc
|
||||||
|
cmd::test::run_cmd "unblock not blocked service" "not blocked" \
|
||||||
|
unblock --name phone-testunit --service test-block-svc
|
||||||
|
cmd::test::run_cmd "block peer --service (port)" "blocked" \
|
||||||
|
block --name phone-testunit --service test-block-svc:web
|
||||||
|
cmd::test::run_cmd "unblock peer --service (port)" "unblocked" \
|
||||||
|
unblock --name phone-testunit --service test-block-svc:web
|
||||||
|
"$WGCTL_BINARY" net rm --name test-block-svc --force > /dev/null 2>&1 || true
|
||||||
|
|
||||||
# ── Rule assign/unassign ───────────────────
|
# ── Rule assign/unassign ───────────────────
|
||||||
cmd::test::run_cmd "rule assign" "Assigned" \
|
cmd::test::run_cmd "rule assign" "Assigned" \
|
||||||
|
|
@ -272,24 +300,20 @@ function cmd::test::section_destructive() {
|
||||||
group unblock --name testgroup
|
group unblock --name testgroup
|
||||||
|
|
||||||
# ── M:N group block tracking ───────────────
|
# ── M:N group block tracking ───────────────
|
||||||
# Setup: add testunit to a second group
|
|
||||||
"$WGCTL_BINARY" group add --name testgroup2 \
|
"$WGCTL_BINARY" group add --name testgroup2 \
|
||||||
--desc "Test group 2" > /dev/null 2>&1
|
--desc "Test group 2" > /dev/null 2>&1
|
||||||
"$WGCTL_BINARY" group peer add --name testgroup2 \
|
"$WGCTL_BINARY" group peer add --name testgroup2 \
|
||||||
--peer phone-testunit > /dev/null 2>&1
|
--peer phone-testunit > /dev/null 2>&1
|
||||||
|
|
||||||
# Block from both groups
|
cmd::test::run_cmd "group block first group" "blocked" \
|
||||||
cmd::test::run_cmd "group block first group" "blocked" \
|
|
||||||
group block --name testgroup
|
group block --name testgroup
|
||||||
cmd::test::run_cmd "group block second group" "blocked" \
|
cmd::test::run_cmd "group block second group" "blocked" \
|
||||||
group block --name testgroup2
|
group block --name testgroup2
|
||||||
|
|
||||||
# Unblock from first — should stay blocked (second group still blocking)
|
|
||||||
"$WGCTL_BINARY" group unblock --name testgroup > /dev/null 2>&1
|
"$WGCTL_BINARY" group unblock --name testgroup > /dev/null 2>&1
|
||||||
cmd::test::run_cmd "peer stays blocked after partial unblock" "blocked" \
|
cmd::test::run_cmd "peer stays blocked after partial unblock" "blocked" \
|
||||||
list --blocked
|
list --blocked
|
||||||
|
|
||||||
# Unblock from second — should now be fully unblocked
|
|
||||||
"$WGCTL_BINARY" group unblock --name testgroup2 > /dev/null 2>&1
|
"$WGCTL_BINARY" group unblock --name testgroup2 > /dev/null 2>&1
|
||||||
cmd::test::run_cmd "peer unblocked after all groups unblock" "phone-testunit" \
|
cmd::test::run_cmd "peer unblocked after all groups unblock" "phone-testunit" \
|
||||||
list --allowed
|
list --allowed
|
||||||
|
|
@ -299,12 +323,11 @@ function cmd::test::section_destructive() {
|
||||||
cmd::test::run_cmd "direct unblock overrides group block" "unblocked" \
|
cmd::test::run_cmd "direct unblock overrides group block" "unblocked" \
|
||||||
unblock --name phone-testunit
|
unblock --name phone-testunit
|
||||||
|
|
||||||
# ── Cleanup groups ─────────────────────────
|
# ── Cleanup ────────────────────────────────
|
||||||
cmd::test::run_cmd "group remove" "removed" \
|
cmd::test::run_cmd "group remove" "removed" \
|
||||||
group remove --name testgroup --force
|
group remove --name testgroup --force
|
||||||
"$WGCTL_BINARY" group remove --name testgroup2 --force > /dev/null 2>&1 || true
|
"$WGCTL_BINARY" group remove --name testgroup2 --force > /dev/null 2>&1 || true
|
||||||
|
|
||||||
# ── Remove test peer ───────────────────────
|
|
||||||
cmd::test::run_cmd "remove phone peer" "removed" \
|
cmd::test::run_cmd "remove phone peer" "removed" \
|
||||||
remove --name phone-testunit --force
|
remove --name phone-testunit --force
|
||||||
}
|
}
|
||||||
|
|
@ -406,9 +429,6 @@ function cmd::test::fn_rule_assign() {
|
||||||
|
|
||||||
"$WGCTL_BINARY" remove --name phone-testunit --force > /dev/null 2>&1 || true
|
"$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" 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" \
|
cmd::test::run_cmd "rule assign" "Assigned" \
|
||||||
rule assign --name admin --peer phone-testunit
|
rule assign --name admin --peer phone-testunit
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,30 @@ function cmd::unblock::run() {
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Unblock specific IPs
|
||||||
|
for ip in "${ips[@]}"; do
|
||||||
|
fw::unblock_ip "$client_ip" "$ip"
|
||||||
|
block::remove_rule "$name" "ip" "$ip"
|
||||||
|
$quiet || log::wg_success "${ip} has been unblocked for ${name}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Unblock specific subnets
|
||||||
|
for subnet in "${subnets[@]}"; do
|
||||||
|
fw::unblock_subnet "$client_ip" "$subnet"
|
||||||
|
block::remove_rule "$name" "subnet" "$subnet"
|
||||||
|
$quiet || log::wg_success "${subnet} has been unblocked for ${name}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Unblock specific ports
|
||||||
|
for entry in "${ports[@]}"; do
|
||||||
|
local target port proto
|
||||||
|
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"
|
||||||
|
$quiet || log::wg_success "${client_ip}:${b_port}:${b_proto:-tcp} has been unblocked for ${name}"
|
||||||
|
done
|
||||||
|
|
||||||
# Unblock services
|
# Unblock services
|
||||||
for svc in "${services[@]}"; do
|
for svc in "${services[@]}"; do
|
||||||
local resolved_lines=()
|
local resolved_lines=()
|
||||||
|
|
@ -125,7 +149,7 @@ function cmd::unblock::run() {
|
||||||
if [[ "$resolved" == *:*:* ]]; then
|
if [[ "$resolved" == *:*:* ]]; then
|
||||||
local b_ip b_port b_proto
|
local b_ip b_port b_proto
|
||||||
IFS=":" read -r b_ip b_port b_proto <<< "$resolved"
|
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 && \
|
fw::has_block_rule "$client_ip" "$b_ip" "$b_port" "$b_proto" 2>/dev/null && \
|
||||||
{ is_blocked=true; break; }
|
{ is_blocked=true; break; }
|
||||||
else
|
else
|
||||||
fw::has_block_rule "$client_ip" "$resolved" 2>/dev/null && \
|
fw::has_block_rule "$client_ip" "$resolved" 2>/dev/null && \
|
||||||
|
|
@ -153,27 +177,6 @@ function cmd::unblock::run() {
|
||||||
$quiet || log::wg_success "${svc} has been unblocked for ${name}"
|
$quiet || log::wg_success "${svc} has been unblocked for ${name}"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Unblock specific IPs
|
|
||||||
for ip in "${ips[@]}"; do
|
|
||||||
fw::unblock_ip "$client_ip" "$ip"
|
|
||||||
block::remove_rule "$name" "ip" "$ip"
|
|
||||||
done
|
|
||||||
|
|
||||||
# Unblock specific subnets
|
|
||||||
for subnet in "${subnets[@]}"; do
|
|
||||||
fw::unblock_subnet "$client_ip" "$subnet"
|
|
||||||
block::remove_rule "$name" "subnet" "$subnet"
|
|
||||||
done
|
|
||||||
|
|
||||||
# Unblock specific ports
|
|
||||||
for entry in "${ports[@]}"; do
|
|
||||||
local target port proto
|
|
||||||
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
|
|
||||||
|
|
||||||
# Clean up block file if now empty
|
# Clean up block file if now empty
|
||||||
block::cleanup "$name"
|
block::cleanup "$name"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,11 @@ function peers::is_blocked() {
|
||||||
block::is_blocked "$name"
|
block::is_blocked "$name"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function peers::is_restricted() {
|
||||||
|
local name="${1:-}"
|
||||||
|
block::has_specific_rules "$name" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# Default Rule
|
# Default Rule
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue