• src/sbbs3/trash.c

    From Rob Swindell (on Windows 11)@VERT to Git commit to main/sbbs/master on Sat May 23 21:25:45 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/43f3b369a8804ccce7b3d320
    Modified Files:
    src/sbbs3/trash.c
    Log Message:
    trash.c: have filter_ip() return false when IP is already in the filter

    filter_ip() returned true both when it newly added the IP to ip.can AND
    when the IP was already present (the dedup-guarded early return). Since
    commit be8ba77c2 ("Only log !BLOCKING IP ADDRESS when filter_ip() actually filters the IP") gated the "!BLOCKING IP ADDRESS" notices on the return
    value, the already-present case kept emitting fresh BLOCKING notices on
    every subsequent connection from a long-since-blocked IP. Observed in a
    recent web server log: 6099 redundant "!BLOCKING IP ADDRESS" lines for a
    single IP in one day.

    Flip the already-present branch to return false. The dedup behavior is preserved (no duplicate append to ip.can), but the return now means
    "this call added the IP", which is what every caller updated by
    be8ba77c2 actually wanted.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Windows 11)@VERT to Git commit to main/sbbs/master on Sat May 23 21:25:45 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/70b10f39aaedbd4738144c8b
    Modified Files:
    src/sbbs3/trash.c
    Log Message:
    trash.c: have filter_ip() prune expired entries before re-blocking

    The previous commit (43f3b369a) made filter_ip() return false when the
    IP was already in the filter file, eliminating the redundant BLOCKING
    IP ADDRESS log spam (6099 lines for a single IP in one day, on vert).
    But that left a latent hole: if the existing entry's `e=` expiry had
    passed, the IP would be silently never re-blocked. trashcan2() already
    treats expired entries as not-listed (connections allowed), and trashman
    only sweeps as a [monthly_event], so a re-offender could go unfiltered
    for up to ~30 days.

    Switch the dup-detection from findstr() to find2strs() with metadata extraction, parse the existing entry's `e=` field, and:

    - If the match is still active (no expiry, future expiry, or
    unparseable metadata): return false, no log, no dup -- same as
    43f3b369a.
    - If the match is expired: call a new remove_expired_filter_entries()
    helper to prune ALL expired entries from the file (not just our IP's
    -- opportunistic cleanup, same shape as trashman's maint() but
    inline), then fall through to append a fresh entry so the IP is
    re-blocked immediately.

    The helper holds the file open O_RDWR across the read/rewrite so a
    concurrent O_APPEND writer can't slip in a new entry between a
    close-and-reopen and have it truncated away. It only rewrites if at
    least one line was actually removed, uses strListDelete() to avoid
    leaking the removed strings, treats strListReadFile() OOM as a hard
    failure (not "nothing to clean"), and honors fflush() failures.

    Match trashcan2()/trash_in_list()'s `expires <= now` semantics (rather
    than trashman's strict `<`): only remove entries that the lookup path
    is already ignoring.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net