function rule::apply() { local rule_name="$1" local client_ip="$2" rule::require_exists "$rule_name" || return 1 # Check if already applied local peer_name peer_name=$(peers::find_by_ip "$client_ip") if [[ -n "$peer_name" ]]; then # Check if already applied via iptables if rule::is_applied "$rule_name" "$client_ip"; then log::wg "Rule '${rule_name}' already applied to: ${client_ip}" return 0 fi fi local rule_file rule_file="$(ctx::rule::path "${rule_name}.rule")" # Process block_ips while IFS= read -r ip; do [[ -z "$ip" ]] && continue firewall::block_ip "$client_ip" "$ip" done < <(rule::get "$rule_name" "block_ips") # Process block_ports while IFS= read -r entry; do [[ -z "$entry" ]] && continue local target port proto IFS=":" read -r target port proto <<< "$entry" proto="${proto:-tcp}" firewall::block_port "$client_ip" "$target" "$port" "$proto" done < <(rule::get "$rule_name" "block_ports") # Process allow_ips (inserted before blocks) while IFS= read -r ip; do [[ -z "$ip" ]] && continue firewall::allow_ip "$client_ip" "$ip" done < <(rule::get "$rule_name" "allow_ips") # allow_ports (inserted last = highest priority) while IFS= read -r entry; do [[ -z "$entry" ]] && continue local target port proto IFS=":" read -r target port proto <<< "$entry" proto="${proto:-tcp}" firewall::allow_port "$client_ip" "$target" "$port" "$proto" done < <(rule::get "$rule_name" "allow_ports") # Persist rule assignment in meta log::debug "rule::apply: peer_name=$peer_name ip=$client_ip" if [[ -n "$peer_name" ]]; then peers::set_meta "$peer_name" "rule" "$rule_name" log::debug "rule::apply: set meta rule=$rule_name for $peer_name" fi local dns_redirect dns_redirect=$(rule::get "$rule_name" "dns_redirect") if [[ "$dns_redirect" == "true" ]]; then local subnet subnet=$(config::subnet_for "$(peers::get_meta "$peer_name" "subtype")") rule::apply_dns_redirect "${subnet}.0/24" fi log::wg_preset "Applied rule '${rule_name}' to: ${client_ip}" }