fix(client-guardian): Safe defaults + emergency clear + safety limits
BREAKING: Default policy changed from quarantine to open - Disabled by default (was enabled) - Default policy: open (was quarantine - blocked new devices!) - Auto-zoning: disabled by default - Auto-parking zone: lan_private (was guest) - Night block schedule: disabled by default - Threat auto-ban: disabled by default Safety mechanisms added: - MAX_BLOCKED_DEVICES limit (10) prevents mass blocking - check_safety_limit() function validates before blocking - clear_all_cg_rules() emergency function via RPCD - safety_status RPCD method to check current state UI improvements: - Added warnings for restrictive policies - Reordered options (safe options first) - Clearer descriptions of consequences Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
477c2fa162
commit
56afd02d40
@ -27,17 +27,17 @@ return view.extend({
|
||||
s = m.section(form.NamedSection, 'config', 'client-guardian', _('Auto-Zoning Settings'));
|
||||
|
||||
o = s.option(form.Flag, 'auto_zoning_enabled', _('Enable Auto-Zoning'),
|
||||
_('Automatically assign clients to zones using matching rules'));
|
||||
o.default = '1';
|
||||
_('Automatically assign clients to zones using matching rules. WARNING: May restrict network access for new devices!'));
|
||||
o.default = '0';
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.option(form.ListValue, 'auto_parking_zone', _('Auto-Parking Zone'),
|
||||
_('Default zone for clients that don\'t match any rule'));
|
||||
o.value('guest', _('Guest'));
|
||||
o.value('quarantine', _('Quarantine'));
|
||||
o.value('iot', _('IoT'));
|
||||
o.value('lan_private', _('LAN Private'));
|
||||
o.default = 'guest';
|
||||
o.value('lan_private', _('LAN Private (Full Access)'));
|
||||
o.value('guest', _('Guest (Internet Only)'));
|
||||
o.value('iot', _('IoT (Isolated)'));
|
||||
o.value('quarantine', _('Quarantine (No Access - Dangerous!)'));
|
||||
o.default = 'lan_private';
|
||||
o.depends('auto_zoning_enabled', '1');
|
||||
|
||||
o = s.option(form.Flag, 'auto_parking_approve', _('Auto-Approve Parked Clients'),
|
||||
|
||||
@ -29,17 +29,17 @@ return view.extend({
|
||||
s = m.section(form.NamedSection, 'config', 'client-guardian', _('General Settings'));
|
||||
|
||||
o = s.option(form.Flag, 'enabled', _('Enable Client Guardian'));
|
||||
o.default = '1';
|
||||
o.default = '0';
|
||||
o.rmempty = false;
|
||||
o.description = _('Enable or disable the Client Guardian access control system');
|
||||
o.description = _('Enable or disable the Client Guardian access control system. WARNING: Enabling with restrictive policies may block network access!');
|
||||
|
||||
o = s.option(form.ListValue, 'default_policy', _('Default Policy'));
|
||||
o.value('open', _('Open - Allow all clients'));
|
||||
o.value('quarantine', _('Quarantine - Require approval'));
|
||||
o.value('whitelist', _('Whitelist Only - Allow only approved clients'));
|
||||
o.default = 'quarantine';
|
||||
o.value('open', _('Open - Allow all clients (Recommended)'));
|
||||
o.value('quarantine', _('Quarantine - Require approval (Restrictive)'));
|
||||
o.value('whitelist', _('Whitelist Only - Block unknown clients (Very Restrictive)'));
|
||||
o.default = 'open';
|
||||
o.rmempty = false;
|
||||
o.description = _('Default behavior for new/unknown clients');
|
||||
o.description = _('Default behavior for new/unknown clients. WARNING: Quarantine and Whitelist modes will block new devices from accessing the network!');
|
||||
|
||||
o = s.option(form.Flag, 'auto_approve', _('Auto-Approve Known Devices'));
|
||||
o.default = '0';
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
config client-guardian 'config'
|
||||
option enabled '1'
|
||||
option default_policy 'quarantine'
|
||||
option enabled '0'
|
||||
option default_policy 'open'
|
||||
option quarantine_zone 'quarantine'
|
||||
option scan_interval '30'
|
||||
option auto_approve '0'
|
||||
option auto_approve '1'
|
||||
option log_level 'info'
|
||||
# Dashboard Reactiveness
|
||||
option auto_refresh '1'
|
||||
@ -11,11 +11,11 @@ config client-guardian 'config'
|
||||
# Debug Mode
|
||||
option debug_enabled '0'
|
||||
option debug_level 'INFO'
|
||||
option enable_active_scan '1'
|
||||
# Auto-Zoning / Auto-Parking
|
||||
option auto_zoning_enabled '1'
|
||||
option auto_parking_zone 'guest'
|
||||
option auto_parking_approve '0'
|
||||
option enable_active_scan '0'
|
||||
# Auto-Zoning / Auto-Parking - DISABLED BY DEFAULT for safety
|
||||
option auto_zoning_enabled '0'
|
||||
option auto_parking_zone 'lan_private'
|
||||
option auto_parking_approve '1'
|
||||
|
||||
# Alert Configuration
|
||||
config alerts 'alerts'
|
||||
@ -196,7 +196,7 @@ config schedule 'school_hours'
|
||||
|
||||
config schedule 'night_block'
|
||||
option name 'Blocage Nocturne'
|
||||
option enabled '1'
|
||||
option enabled '0'
|
||||
option action 'block'
|
||||
option start_time '22:00'
|
||||
option end_time '07:00'
|
||||
@ -216,11 +216,11 @@ config schedule 'weekend_limit'
|
||||
list days 'sat'
|
||||
list days 'sun'
|
||||
|
||||
# Threat Intelligence Integration
|
||||
# Threat Intelligence Integration - DISABLED by default for safety
|
||||
config threat_policy 'threat_policy'
|
||||
option enabled '1'
|
||||
option auto_ban_threshold '80'
|
||||
option auto_quarantine_threshold '60'
|
||||
option enabled '0'
|
||||
option auto_ban_threshold '95'
|
||||
option auto_quarantine_threshold '90'
|
||||
option threat_check_interval '60'
|
||||
|
||||
# Auto-Zoning Rules
|
||||
|
||||
@ -11,6 +11,49 @@ LOG_FILE="/var/log/client-guardian.log"
|
||||
CLIENTS_DB="/tmp/client-guardian-clients.json"
|
||||
ALERTS_QUEUE="/tmp/client-guardian-alerts.json"
|
||||
|
||||
# SAFETY LIMITS - prevent accidental mass blocking
|
||||
MAX_BLOCKED_DEVICES=10
|
||||
SAFETY_BYPASS_FILE="/tmp/client-guardian-safety-bypass"
|
||||
|
||||
# Count currently blocked devices (CG_NOLAN, CG_BLOCK, CG_QUARANTINE rules)
|
||||
count_blocked_devices() {
|
||||
uci show firewall 2>/dev/null | grep -c "\.name='CG_NOLAN_\|CG_BLOCK_\|CG_QUARANTINE_'" 2>/dev/null || echo "0"
|
||||
}
|
||||
|
||||
# Check if safety limit is reached
|
||||
check_safety_limit() {
|
||||
local force="$1"
|
||||
|
||||
# If safety bypass file exists (set by admin), skip check
|
||||
[ -f "$SAFETY_BYPASS_FILE" ] && return 0
|
||||
|
||||
# If force flag is set, skip check
|
||||
[ "$force" = "1" ] && return 0
|
||||
|
||||
local blocked_count=$(count_blocked_devices)
|
||||
if [ "$blocked_count" -ge "$MAX_BLOCKED_DEVICES" ]; then
|
||||
log_event "warn" "SAFETY LIMIT: Already $blocked_count devices blocked (max: $MAX_BLOCKED_DEVICES)"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Clear all CG firewall rules (emergency restore)
|
||||
clear_all_cg_rules() {
|
||||
log_event "warn" "EMERGENCY: Clearing all Client Guardian firewall rules"
|
||||
|
||||
# Find and delete all CG rules
|
||||
local rules=$(uci show firewall 2>/dev/null | grep "\.name='CG_" | cut -d. -f2 | cut -d= -f1 | sort -ru)
|
||||
for rule in $rules; do
|
||||
uci delete firewall.$rule 2>/dev/null
|
||||
done
|
||||
uci commit firewall
|
||||
/etc/init.d/firewall reload >/dev/null 2>&1
|
||||
|
||||
log_event "info" "All Client Guardian rules cleared"
|
||||
echo '{"success":true,"message":"All CG rules cleared"}'
|
||||
}
|
||||
|
||||
# Logging function with debug support
|
||||
log_event() {
|
||||
local level="$1"
|
||||
@ -1051,9 +1094,18 @@ create_firewall_zone() {
|
||||
apply_client_rules() {
|
||||
local mac="$1"
|
||||
local zone="$2"
|
||||
local force="${3:-0}"
|
||||
|
||||
log_event "info" "Applying rules for MAC: $mac -> Zone: $zone"
|
||||
|
||||
# SAFETY CHECK: If zone would block/quarantine and safety limit reached, skip
|
||||
if [ "$zone" = "blocked" ] || [ "$zone" = "quarantine" ]; then
|
||||
if ! check_safety_limit "$force"; then
|
||||
log_event "error" "SAFETY LIMIT REACHED: Refusing to block MAC $mac. Use force=1 or clear existing rules."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Normalize MAC to uppercase for firewall rules
|
||||
local mac_upper=$(echo "$mac" | tr 'a-f' 'A-F')
|
||||
|
||||
@ -1649,7 +1701,7 @@ get_client() {
|
||||
# Main dispatcher
|
||||
case "$1" in
|
||||
list)
|
||||
echo '{"status":{},"clients":{},"zones":{},"parental":{},"alerts":{},"logs":{"limit":"int","level":"str"},"approve_client":{"mac":"str","name":"str","zone":"str","notes":"str"},"ban_client":{"mac":"str","reason":"str"},"quarantine_client":{"mac":"str"},"update_client":{"section":"str","name":"str","zone":"str","notes":"str","daily_quota":"int","static_ip":"str"},"update_zone":{"id":"str","name":"str","bandwidth_limit":"int","content_filter":"str"},"send_test_alert":{"type":"str"},"get_policy":{},"set_policy":{"policy":"str","auto_approve":"bool","session_timeout":"int"},"get_client":{"mac":"str"},"sync_zones":{},"list_profiles":{},"apply_profile":{"profile_id":"str","auto_refresh":"str","refresh_interval":"str","threat_enabled":"str","auto_ban_threshold":"str","auto_quarantine_threshold":"str"}}'
|
||||
echo '{"status":{},"clients":{},"zones":{},"parental":{},"alerts":{},"logs":{"limit":"int","level":"str"},"approve_client":{"mac":"str","name":"str","zone":"str","notes":"str"},"ban_client":{"mac":"str","reason":"str"},"quarantine_client":{"mac":"str"},"update_client":{"section":"str","name":"str","zone":"str","notes":"str","daily_quota":"int","static_ip":"str"},"update_zone":{"id":"str","name":"str","bandwidth_limit":"int","content_filter":"str"},"send_test_alert":{"type":"str"},"get_policy":{},"set_policy":{"policy":"str","auto_approve":"bool","session_timeout":"int"},"get_client":{"mac":"str"},"sync_zones":{},"list_profiles":{},"apply_profile":{"profile_id":"str","auto_refresh":"str","refresh_interval":"str","threat_enabled":"str","auto_ban_threshold":"str","auto_quarantine_threshold":"str"},"clear_rules":{},"safety_status":{}}'
|
||||
;;
|
||||
call)
|
||||
case "$2" in
|
||||
@ -1677,6 +1729,15 @@ case "$1" in
|
||||
;;
|
||||
list_profiles) list_profiles ;;
|
||||
apply_profile) apply_profile ;;
|
||||
clear_rules) clear_all_cg_rules ;;
|
||||
safety_status)
|
||||
json_init
|
||||
local blocked=$(count_blocked_devices)
|
||||
json_add_int "blocked_devices" "$blocked"
|
||||
json_add_int "max_allowed" "$MAX_BLOCKED_DEVICES"
|
||||
json_add_boolean "safety_limit_reached" $([ "$blocked" -ge "$MAX_BLOCKED_DEVICES" ] && echo 1 || echo 0)
|
||||
json_dump
|
||||
;;
|
||||
*) echo '{"error": "Unknown method"}' ;;
|
||||
esac
|
||||
;;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user