Native Host (Browser Integration)

1. Overview

This module implements a Native Messaging Host used to bridge a browser extension (or embedded browser component) with BastionGuard’s local anti-phishing logic. It communicates over stdin/stdout using the Chrome/Chromium Native Messaging framing protocol (4-byte little-endian length + JSON payload).

The host provides a small command dispatcher with multiple actions, including:

  • ping – connectivity/health check
  • check_url – URL analysis against a locally stored phishing blacklist
  • set_lang, restart_scanner, open_page – currently stubbed endpoints (placeholders for future integration)

The anti-phishing decision is computed locally by loading and caching a blacklist file and performing host-based matching with suffix fallbacks.


2. Dependencies

  • nlohmann/json – JSON serialization and parsing
  • C++ standard library – I/O streams, containers, filesystem, time, formatting
  • POSIXunistd.h, wait.h, gmtime_r() (thread-safe UTC conversion)

3. Native Messaging Protocol

3.1 Message Framing

Each incoming request is read as:

  1. 4 bytes: unsigned 32-bit length (little-endian)
  2. Payload: JSON bytes of the specified length

Outgoing messages follow the same framing format.


3.2 read_exact(in, buf, n)

The helper reads exactly n bytes from an input stream, retrying until the buffer is filled or EOF is encountered.

This prevents partial reads from breaking message boundaries.


3.3 read_message()

Reads and parses a single framed message. Behavior:

  • Reads length prefix
  • Allocates a buffer of that size
  • Reads the payload fully
  • Parses JSON using json::parse(..., false) (non-throwing parse)

If EOF is encountered during framing or payload read, the function throws an exception to be handled by the main loop.


3.4 send_message(j)

Serializes a JSON object to string, writes the 4-byte length prefix, then writes the JSON bytes to stdout and flushes.

This function ensures the browser-side extension receives a complete framed response.


4. Time Utilities

4.1 now_iso()

Generates an ISO-8601 UTC timestamp in the format:

YYYY-MM-DDTHH:MM:SSZ

Implementation details:

  • Uses std::chrono::system_clock
  • Converts to UTC via gmtime_r()
  • Formats using std::put_time()

This timestamp is attached to responses as ts and used for diagnostics (e.g., ping responses).


5. Blacklist Loading and Caching

5.1 Blacklist Location

The phishing blacklist is expected at:

~/.local/share/BastionGuard/data/phishing/blacklist.txt

The path is resolved using the HOME environment variable.


5.2 Cache Strategy

Blacklist entries are cached in:

  • static std::unordered_set<std::string> cached_bl
  • static std::time_t cached_bl_mtime – last modification time used to detect changes

The blacklist is reloaded only when:

  • The file exists and its modification time differs from the cached value, or
  • The cache is empty

This reduces disk I/O and improves throughput when the host processes many URL checks.


5.3 Normalization Rules

When loading the blacklist:

  • Each line is trimmed
  • Empty lines and comment lines (#) are ignored
  • Entries are lowercased
  • Entries are inserted into an unordered set to guarantee uniqueness

5.4 file_time_type to time_t Conversion

The module converts filesystem timestamps (std::filesystem::file_time_type) to time_t for simple cache comparisons.

This is done by translating the file clock into std::chrono::system_clock timepoints.


6. URL Host Extraction

6.1 extract_host_from_url(url)

Extracts a host component using lightweight parsing rules:

  • Skips scheme prefix :// if present
  • Strips optional credentials (user@)
  • Stops at / : ? # delimiters
  • Removes port suffix if present (:443)
  • Trims and lowercases the host

This approach is intentionally minimal, designed for performance and compatibility with typical URLs observed by browser extensions.


7. Action Handlers

7.1 ping

Returns a simple health response:

  • ok: true
  • pong_at: ISO timestamp

This is used to validate that the native host is running and responsive.


7.2 check_url

Performs local anti-phishing evaluation of a submitted URL.

Input

The request must contain:

{"action":"check_url","url":"https://example.com/..."}

If url is missing or not a string, the response returns ok:false with an error message.


Blacklist Decision Logic

After ensuring the blacklist is loaded, the module computes a verdict using the following strategy:

  1. Extract host from URL
  2. If host exists:
    • Exact match: block if host equals a blacklist entry
    • Suffix match: block if host ends with a blacklist entry (e.g., login.bad.tld matches bad.tld)
  3. If host extraction fails (empty host):
    • Substring fallback: block if any entry appears as a substring inside the URL

The response includes an extra object containing:

  • block – boolean verdict
  • reason – diagnostic string describing which rule triggered (or not)

Example response structure:

{
  "ok": true,
  "url": "https://bad.example/login",
  "extra": {
    "block": true,
    "reason": "host_suffix: example"
  },
  "ts": "2026-01-21T17:25:27Z"
}

7.3 set_lang / restart_scanner / open_page (stubs)

These actions currently return:

{"ok": true}

They act as placeholders for future integration where the browser extension can request BastionGuard to change language, restart services, or open specific UI pages.


8. Request Dispatching

8.1 dispatch(req)

The dispatcher enforces basic request validity:

  • Request must be a JSON object
  • Must contain a string field action

Unsupported actions produce:

{"ok": false, "error": "unknown action: <action>"}

9. Main Loop

The main process loop:

  1. Reads a request via read_message()
  2. Logs the request to stderr
  3. Dispatches it
  4. Attaches ts timestamp
  5. Sends response via send_message()
  6. Logs the response to stderr

If JSON parsing yields a discarded object, the loop terminates.


10. Error Handling

  • Most handler-level errors return ok:false responses with explicit error strings
  • Fatal errors in the loop are caught and logged to stderr
  • The host attempts to send a final fatal error response if possible

This design avoids silent failures and provides diagnostics for extension developers and system administrators.


11. Runtime and Security Considerations

  • Trust boundary: all inbound JSON fields must be treated as untrusted input; the module enforces minimal validation for required fields
  • Blacklist integrity: decisions rely on the local blacklist file; ensure it is generated/updated by trusted BastionGuard components
  • Suffix matching risk: suffix checks can over-block if the blacklist includes overly generic entries; ensure list entries are normalized and curated
  • Performance: caching avoids repeated file reads; unordered_set lookup provides O(1) average-case exact matching
  • Logging: request/response are printed to stderr, which is helpful for debugging but should be reviewed for privacy impact if URLs may include sensitive query parameters
  • Locale: current implementation logs using plain strings; future localization of error output should be consistent with BastionGuard logging policy

12. Extension Points

  • Action completion: implement the stub actions by integrating with BastionGuard settings and service control mechanisms
  • Robust URL parsing: replace host parsing with a hardened URL parser if required (while preserving performance)
  • Policy model: extend extra payload to include confidence, source list version, and rule identifiers
  • Atomic blacklist reload: optionally use atomic file replace strategies and read-write locks for multi-threaded host variants