Anti-Phishing Engine Daemon

1. Overview

The Anti-Phishing Engine Daemon is the runtime entry point for the BastionGuard phishing warning infrastructure. Its primary role is to bootstrap and supervise the LocalWarningServer, a local HTTP/HTTPS service that serves a blocking / warning page when a phishing redirection is required.

In addition to starting the local server, the daemon loads and caches a trusted whitelist of domains (e.g., banking and user-defined safe domains). This whitelist is used to bypass enforcement for known trusted targets and avoid false positives during local redirect workflows.


2. Responsibilities

  • Process lifecycle – initializes signal handling, manages the main loop, and performs graceful shutdown.
  • Runtime configuration – parses CLI options (e.g., bind address, ports, warning page path) and applies defaults.
  • Local warning service – constructs and runs LocalWarningServer (HTTP/HTTPS listeners and warning page rendering).
  • Trusted whitelist – loads trusted domains from system and user JSON sources and exposes a fast lookup function.
  • Operational logging – ensures log directory/file existence, permissions, and ownership (when running as root).
  • Privilege diagnostics – detects whether the process can bind privileged ports and prints remediation guidance.

3. Core Utilities and Runtime Controls

3.1 Signal Handling and Main Loop Control

The daemon uses a global running flag as a cooperative shutdown mechanism. Signal handlers (SIGINT, SIGTERM) set running=false, causing the main loop to exit and the service to stop cleanly.

  • static bool running – global runtime flag
  • handle_signal() – sets running=false on termination signals

3.2 CLI Option Parsing

Configuration is passed using a minimal parser for --key=value arguments. Unsupported flags are ignored. This keeps the daemon predictable and avoids runtime dependency on external argument parsing libraries.

Supported options and defaults:

  • --http-port (default: 81)
  • --https-port (default: 444)
  • --bind-address (default: 127.0.0.2)
  • --page-warning (default: /usr/share/BastionGuard/data/blocking/block.html)

Parsed values are immediately printed to stdout to provide an unambiguous startup diagnostic line (useful in systemd logs).


4. Trusted Whitelist (Bank + User Domains)

4.1 Data Sources

Trusted domains are loaded once at startup and cached in memory. The loading mechanism supports both system-provided and user-maintained lists:

  • System list: /usr/share/BastionGuard/data/bank/banks.json
  • User list (optional): ~/.config/BastionGuard/whitelist.json

The JSON loader is tolerant: it accepts multiple schema styles to reduce migration friction:

  • Pure array: [ "domain1", "domain2" ]
  • Object containers with known keys:
    • { "list": [ ... ] }
    • { "domains": [ ... ] }
    • { "whitelist": [ ... ] }

4.2 Normalization Rules

Domains are normalized before insertion to ensure deterministic matching and avoid trivial bypasses. Normalization performed by clean_domain() includes:

  • Lowercasing
  • Stripping a leading dot (e.g., .example.comexample.com)
  • Removing www. prefix
  • Stripping port suffix (e.g., example.com:443)
  • Removing trailing dot

4.3 Matching Strategy

The whitelist lookup supports both exact and parent-domain matching. For example:

  • www.sub.bank.tld matches bank.tld if bank.tld is present in the trusted set

This is implemented by iteratively checking parent labels:

  • Check exact host
  • Then check sub.bank.tld, bank.tld, etc.

Trusted domains are held in an unordered_set<std::string> for constant-time membership checks.


5. Local Warning Server Bootstrap

5.1 Server Construction

Once configuration and whitelist have been initialized, the daemon constructs the warning server:

  • LocalWarningServer(http_port, https_port, bind_address, ..., page_warning)

The daemon then calls:

  • warning_server->start() – begins accepting local traffic
  • warning_server->stop() – stops listeners during shutdown

The server is designed to run on a loopback address, making it inaccessible from external networks by design.


5.2 Warning Page Rendering

The daemon passes a filesystem path for the warning page HTML template:

/usr/share/BastionGuard/data/blocking/block.html

This file is used by LocalWarningServer as the user-facing content to be served on phishing-triggered redirects.


6. Logging and Permissions

6.1 Log File Initialization

The daemon ensures that the log directory and log file exist before starting the server. Default paths:

  • Log directory: /var/log/BastionGuard
  • Log file (phishing scanner): /var/log/BastionGuard/phishing_scanner

If missing, they are created and permissions are applied using std::filesystem::permissions(). The typical intended mode is:

  • 0640 (owner read/write, group read)

6.2 Ownership Adjustment (When Running as Root)

If the daemon is running as root, it attempts to chown() the log file to the service account (default in this implementation: BastionGuard for both user and group). This prevents log write failures when the daemon is launched with mixed privilege contexts.

Errors are not fatal: ownership changes are best-effort and failure is logged with the underlying errno.


7. Privileged Ports Diagnostic

The default ports (81 and 444) may be treated as privileged depending on system policy. The daemon checks whether it can bind privileged ports by evaluating:

  • geteuid() == 0 (root)
  • or process capabilities contain cap_net_bind_service (via getcap /proc/self/exe)

If insufficient privileges are detected, the daemon prints a remediation command:

sudo setcap 'cap_net_bind_service=+ep' /usr/bin/BastionGuard-daemon

This diagnostic does not prevent startup (the server may still fail binding later depending on the actual port policy), but it provides a clear operator instruction in logs.


8. Runtime Behavior (Current Diagnostic Loop)

In the current implementation, the main loop includes a diagnostic section that reads from a hypothetical DNS log file (e.g., /var/log/BastionGuard/dns_query.log) and prints whether each entry is trusted. This is intended for debugging DNS redirect flows and verifying whitelist behavior.

  • Trusted domains: logged as bypass candidates
  • Non-trusted domains: logged as routed toward the local warning address (127.0.0.2)

The loop sleeps periodically (2s) to limit log spam.


9. Error Handling and Failure Modes

  • Whitelist parsing failures – non-fatal; exceptions are caught and ignored to avoid daemon crash.
  • Log initialization failures – non-fatal; errors are printed but startup continues.
  • Server start failures – treated as fatal if propagated as exceptions by LocalWarningServer; caught at top-level and exits with 1.
  • Unexpected exceptions – caught by a generic handler and reported as “unknown error”.

10. Security Considerations

  • Local-only binding: binding to loopback (default 127.0.0.2) prevents remote access to the warning server.
  • Whitelist normalization: reduces trivial bypass vectors using casing, www., or port tricks.
  • Parent-domain matching: intentionally trusts subdomains of trusted roots; this must be curated carefully for banking lists.
  • Privilege minimization: capability-based binding (cap_net_bind_service) is preferable to full root execution.
  • Template integrity: the warning HTML comes from a system path; package integrity and permissions are critical to avoid UI injection.