Skip to content

BBSFirewall v1.5.0

Latest

Choose a tag to compare

@laudenbachm laudenbachm released this 01 Oct 03:08
· 2 commits to main since this release

✨ Added

  • Host firewall (UFW) rule management (Tools tab, Global Admin only, off by
    default). Preview and then manually apply tagged ufw rules built from your own
    settings — public listeners open to anyone, the config editor and admin SSH port
    limited to Trusted Hosts. Apply is refused if it would leave the admin SSH port
    without an allow rule. BBSFirewall never turns ufw itself on or off. Also shows
    the host's own ufw drop log.
  • Kernel-level block push (UFW_PUSH_BLOCKS, off by default). Blocklist
    entries and trigger auto-blocks are mirrored into ufw as deny from rules, so
    blocked callers are dropped by the kernel even while BBSFirewall restarts.
    Syncs automatically; temporary trigger blocks are removed when they expire.
    Never pushes anything overlapping Trusted Hosts, the Whitelist, or loopback, and
    refuses to push at all with an empty Trusted Hosts list. Capped by
    UFW_BLOCK_MAX_RULES (default 1000). Status, "Sync now" and "Remove pushed
    rules" live in the Tools tab.
  • UFW auto-apply (UFW_AUTO_APPLY, off by default). Applies the host firewall
    rule changes automatically at startup and after each Save, so adding or removing
    a Trusted Host updates ufw right away instead of waiting for Preview + Apply.
    Uses the same checks as Apply, and is stricter: if it can't tell which ports sshd
    listens on, or the change would remove more than half of the rules, it changes
    nothing and the Tools tab shows why. The last run's result is shown in the Tools tab.
  • Log search (Logs tab and GET /api/logs/search). Search every log file at
    once by text, type, level and date range — every word must match, "quotes"
    for a phrase, -word to exclude. Newest matches first, terms highlighted;
    click a result to open that file at that exact line, with the lines around it.
    Download all results as a text file.
  • Better log viewer: line numbers, colour-coded levels with on/off chips per
    level, a live filter box, "Load older / newer lines" to page through files of
    any size (it used to stop at the last 512 KB), and Follow (live) on today's
    file to watch new lines arrive like tail -f.
  • Download log files from the file list or the viewer — the whole file, no
    size limit (GET /api/logs/download) — or every log file at once as one
    .zip with "Download all (.zip)" (GET /api/logs/download-all). Streamed, so
    a big log folder doesn't use extra memory.

🔒 Security

  • New security guide for sysops: locking down the admin editor,
    accounts and MFA, the Management API, SSH modes, PROXY Protocol, ufw and the
    server itself, plus how to report a vulnerability privately.
  • Firewall Admin accounts can no longer change who can reach the editor. The
    Config Editor, Management API and Host Firewall (UFW) settings, every list-file
    path, and the Trusted Hosts / API / Status allowlists are now Global Admin only —
    shown read-only to a Firewall Admin and refused by the server. A Firewall Admin
    could previously set their own API key (which outlives their account) or lock
    the Global Admin out.
  • List-file paths and LOG_DIR must stay inside the BBSFirewall folder, and
    list files must be .txt. A changed path outside it is refused — it previously
    let one Save write any file on the host as root.
  • Turning MFA on asks for your current password, and MFA setup is refused
    while MFA is already on (disable it first to replace an authenticator). A stolen
    session cookie could previously swap in its own authenticator.
  • Login and MFA lockouts now count attempts that arrive at the same moment; the
    password and backup-code checks no longer pause every connected caller.
  • Caller-supplied text (e.g. an SSH username) can no longer forge lines in the log
    files or console output.
  • A role name that isn't recognised now gets the least access, not the most.
  • Trigger regexes with repeated alternation (a|aa)+ or nested groups ((a+))+
    are now refused as catastrophic-backtracking risks, like (a+)+ already was.
  • Installing updates, rolling back, deleting log files and replacing the SSH
    host key are now Global Admin only.
    A Firewall Admin could install an older
    release that didn't have the role rules above, and get around them that way.
  • SSH (terminate mode) now checks callers the moment they connect. The
    blocklist, rate limit, per-IP and global caps, country block and idle timeout
    used to apply only once a caller had sent its SSH banner, so a caller that
    connected and stayed silent was never checked or timed out. Blocked callers
    are now dropped straight away, and every caller must finish logging in
    within 2 minutes.
  • SSH (terminate mode): a caller that trips an auto-block trigger is now
    disconnected completely. Before, only that shell closed and the same
    connection could open a new one straight to the BBS.
  • The SSH banner no longer names the SSH library and its version, and a
    caller can no longer send an unlimited number of environment variables or
    open more than 4 session channels at once on one connection.
  • With UFW management on, a public port can no longer share the admin SSH
    port.
    Setting e.g. HTTPS_REDIRECT_PORT to the admin SSH port made the ufw
    rules open that port to everyone — and a Firewall Admin can change those
    ports. Such a setting is now refused, and the admin SSH port is never opened
    to Anywhere.
  • Admin logins and admin changes are now always in the log file.
    Successful logins, saved settings, GeoIP downloads, SSH host key changes,
    ufw block syncs and "Whitelist my IP" used to be logged only at the info
    level, so by default there was no record of who logged in or changed what.

🐛 Fixed

  • The Tools tab's update Backups list (with Roll back to this) is now
    always shown to a Global Admin, with a note when there are no backups yet —
    one is saved each time Update now runs. It also no longer disappears
    when the GitHub update check fails.
  • Saving no longer drops auto-blocks. Save used to rewrite every list file
    from what the page loaded, silently deleting trigger auto-blocks (and "Whitelist
    my IP") added since. Only lists you actually edited are written now, keeping any
    lines added on disk meanwhile; if a list changed on disk any other way, nothing
    is saved and you're asked to reload.
  • Settings containing \ or " (e.g. an API key) were saved in a form the
    firewall read back differently from what was typed. Values now load exactly as
    entered.
  • A blocked caller that never hung up kept a connection slot until
    CONNECTION_TIMEOUT (forever at 0); refused connections are now dropped at once.
  • SSH (terminate mode) now counts against MAX_CONNECTIONS, honours
    CONNECTION_TIMEOUT (idle = no session data; SSH keepalives don't count), and allows one BBS shell per SSH connection — one caller
    could previously open unlimited BBS sessions over a single connection.
  • SSH (terminate mode) now acts as a proper telnet client toward the BBS: the
    backend's option negotiation no longer shows up as stray characters (e.g.
    √♥ √☺ √ ² before the first screen), and 0xFF bytes are escaped/unescaped
    correctly in both directions instead of being corrupted.
  • Self-update and rollback no longer freeze every telnet/SSH session while
    npm install runs. A rollback no longer restores an old status-trustedhosts.txt
    or copies admin-account backups around, and a pre-release tag (v1.5.0-beta.9)
    can be pinned.
  • An interrupted "Download all (.zip)" no longer leaves the download stuck — two of
    them used to block all further zip downloads until a restart.
  • IPv6 whitelist/blocklist entries now match however they're written
    (2001:DB8:0::1 = 2001:db8::1).
  • Trigger scanning no longer re-scans everything received so far on every
    packet (about 2 s of CPU per caller at a 64 KB TRIGGER_SCAN_BYTES).
  • Kernel block push never denies an address in the Status or API allowlists.
  • UFW Apply refuses to remove the only rule for a port sshd is listening on (e.g.
    after changing Admin SSH port before moving sshd).
  • Changing a list's path now starts the new file with the current list, and
    editing that list in the same Save is refused (it went to the old file).
  • System Stats, log Follow and UFW sync polling no longer keep an idle session
    signed in forever.
  • The plain-HTTP redirect only echoes a well-formed Host header; a log file
    deleted mid-download returns 404 instead of an error.
  • After "Restart firewall" (and self-update / reboot), the editor could reload
    while the old process was still shutting down and come up empty — no settings,
    no version — until a manual refresh. It now waits for the new process before
    reloading, and retries loading its settings instead of giving up on the first
    failed request. The exiting process also tells browsers to drop their
    connection, so on a host running ufw the page no longer stalls for up to a
    minute on a connection to the old process.
  • Host firewall (UFW) Preview/Apply compared Trusted Hosts entries as typed
    (1.2.3.4/32, 0.0.0.0/0) against ufw's own spelling (1.2.3.4, Anywhere),
    so such entries showed a change that never went away — and Apply would have
    deleted the matching rules. Rules are now always compared in ufw's form, and
    "Anywhere" rules are added/removed one address family at a time (removing the
    IPv4 one no longer silently removes the IPv6 one too).
  • The startup banner now shows the version at every LOG_LEVEL.
  • Host firewall (UFW) rules for the config editor port only admitted Trusted
    Hosts, silently blocking uptime monitors listed only in Status Trusted Hosts and
    Management API callers. The rule now admits all three lists (and any IP when the
    API is on with an empty API allowlist, matching the app itself).
  • Logs tab: the search form and the per-category file tables now lay out
    identically on every box — they used to shift depending on which log types
    existed and how long their names were.
  • The self-updater compared versions by splitting on dots only, so a pre-release
    like 1.5.0-beta.1 counted as newer than 1.5.0 and would never have been
    offered the final release. Pre-release tags now sort before their release.
  • Saving only a list (Trusted Hosts, Blocklist, …) no longer rewrites .env or makes
    a .env backup. Each such save used to add an identical backup, pushing out the
    older ones worth keeping. The Save message now asks for a restart only when a
    setting actually changed; list changes take effect immediately.

🗑️ Removed

  • UFW_LIMIT_ADMIN_SSH (rate-limit the admin SSH port with ufw limit). The
    admin SSH port is already limited to Trusted Hosts, and ufw's fixed limit of
    6 connections in 30 seconds locked admins out during ordinary reconnects. A
    leftover UFW_LIMIT_ADMIN_SSH=true is ignored with a warning at startup, and
    the admin port gets plain allow rules at the next Apply.