1. Overview
This component is a privileged command-line helper responsible for applying or clearing firewall rules derived from a BastionGuard-generated IP blacklist. It is designed to integrate with the Anti-Phishing subsystem (or similar detection pipelines) that produce a list of malicious IP addresses to block at the network perimeter.
The helper supports two firewall backends:
- firewalld (preferred when available) – implemented using a persistent
ipsetand zone source attachment - UFW – implemented using idempotent
deny from <ip>rules
The blacklist input is read from a temporary staging file and is always removed after processing to ensure cleanup and reduce stale state risk.
2. Input File and Data Contract
2.1 Blacklist Staging Path
The helper consumes a plain-text blacklist stored at:
/tmp/bastionguard-firewall-ips.txt
Each non-empty, non-comment line is treated as a single IP address entry. Lines beginning with # are ignored.
2.2 Blacklist Parsing Behavior
The blacklist is parsed by load_blacklist(), which:
- Opens the staging file
- Reads line-by-line
- Skips empty lines and comment lines (
#) - Appends remaining lines to the IP vector
If the file cannot be opened, an error is logged and an empty list is returned.
3. Security Model and Hardening
3.1 Environment Sanitization
Before executing any command, the helper performs privileged hardening steps:
clearenv()– removes all environment variablessetenv("PATH", "/usr/sbin:/usr/bin:/sbin:/bin", 1)– enforces a trusted PATH
This reduces the risk of environment-based privilege escalation when invoking shell commands.
3.2 Root Requirement
The helper requires effective root privileges to manipulate firewall configuration:
- If
geteuid() != 0, it exits with code10.
4. Command Execution Helpers
4.1 Shell Execution
Commands are executed via:
run_cmd(cmd)→ wrapsstd::system()and checksWEXITSTATUS()
A command is considered successful only if it exits cleanly with status 0.
4.2 Backend Detection
Firewall backend availability is detected through:
command -v <cmd>
This check is implemented by command_exists() and is used to determine whether ufw or firewall-cmd is present.
5. Firewall Backend: UFW
5.1 Enable and Rule Application
If UFW is available, the helper:
- Ensures UFW is enabled:
ufw --force enable - Applies a deny rule per IP:
ufw deny from <ip>
The deny operation is treated as idempotent in practice; repeated applications should not break enforcement consistency.
6. Firewall Backend: firewalld
6.1 Persistent IPSet Strategy
If firewalld is available, the helper configures a dedicated persistent ipset:
- IPSet name:
bastionguard-blacklist - Type:
hash:ip
Creation is attempted using:
firewall-cmd --permanent --new-ipset=bastionguard-blacklist --type=hash:ip
Errors from ipset creation are suppressed because the ipset may already exist.
6.2 Zone Integration
The ipset is attached to the public zone as a source set:
firewall-cmd --permanent --zone=public --add-source-ipset=bastionguard-blacklist
This ensures that traffic sourced from any IP contained in the set is handled according to the zone’s source policy.
6.3 Entry Population and Reload
Each IP is inserted into the ipset:
firewall-cmd --permanent --ipset=bastionguard-blacklist --add-entry=<ip>
After population, the firewall configuration is activated via:
firewall-cmd --reload
7. Clear Operation
7.1 UFW Reset
If UFW is available, the helper clears rules using:
ufw --force reset
This resets UFW configuration and removes previously applied rules.
7.2 firewalld IPSet Removal
If firewalld is available, the helper deletes the dedicated ipset:
firewall-cmd --permanent --delete-ipset=bastionguard-blacklist
and then reloads firewalld:
firewall-cmd --reload
7.3 Blacklist File Cleanup
When clearing rules, the helper also removes the staging file:
/tmp/bastionguard-firewall-ips.txt
This prevents reuse of stale IP data and enforces a “one-shot” blacklist application model.
8. Apply Operation and Backend Selection
8.1 Apply Flow
When invoked with apply, the helper:
- Loads the blacklist file into memory
- Fails fast if the list is empty or invalid
- Attempts to apply rules using:
apply_firewalld()first- then
apply_ufw()as fallback
- Always removes the staging file after attempting application
The selection logic uses short-circuit evaluation:
- If firewalld succeeds, UFW is not attempted.
- If firewalld is unavailable or fails, UFW is attempted.
9. Exit Codes and Result Semantics
0– success1– invalid argument count (usage error)2– invalid command argument3– blacklist missing/empty/invalid5– no supported firewall backend found or rule application failed10– not executed as root
10. Runtime and Security Considerations
- Privileged execution: requires root and sanitizes environment before command execution.
- Backend priority: firewalld is preferred when present; UFW is used as fallback.
- State cleanup: the blacklist staging file is always removed after processing to reduce stale state risk.
- Operational impact: UFW reset is broad and may remove unrelated UFW rules; firewalld removal targets only the BastionGuard ipset.
- Input validation: the helper assumes each line is a valid IP string; optional enhancements include strict IP parsing and deduplication.
- Localization: user-visible messages are wrapped using
glib/gi18nfor translation.