Commit Graph
29 Commits
Author SHA1 Message Date
pmb b1e7f5229b docs(docker): run as root under host networking to bind port 79
Host networking shares the host net namespace, so the host's
privileged-port rule applies and the image's non-root user cannot bind 79
-- the daemon fails to listen silently. Add user: "0:0" to the compose and
correct the earlier (wrong) claim that non-root bind still works. Note
setcap as the non-root alternative.
2026-06-15 16:54:47 -07:00
pmb 011f8c4838 Stop logging normal client disconnects as exceptions
Clients that connect and close without sending a request -- health checks
(nc ... < /dev/null), port scanners, reset connections -- made
async_read_some throw eof, which the catch block logged as
"echo exception: End of file [asio.misc:2 ...]", spamming the logs.

Read with as_tuple so the error comes back as an error_code instead of an
exception: on any read error just return quietly. Writes likewise use
as_tuple and ignore errors (best-effort reply). The try/catch remains only
as a backstop for genuinely unexpected exceptions.
2026-06-15 16:43:06 -07:00
pmb 54650af252 Only track bannable (globally-routable) source IPs
The ban logic is per source IP, so it only works where the daemon can see
the real client. Behind Docker's default bridge networking every client is
SNAT'd to the bridge gateway (a 172.16/12 address), so a single IP would
stand in for the whole internet -- counting offenses against it would block
everyone at once.

Add is_bannable_address(): only globally-routable unicast addresses are
tracked. Loopback, RFC1918 private, CGNAT (100.64/10), link-local, IPv6
unique-local, and multicast all return false. main.cpp decides trackability
from the accepted endpoint and skips both the block check and offense
recording for non-global sources. Net effect: banning works where the real
IP is visible (FreeBSD jail via pf rdr; Docker with host networking) and is
inert -- not catastrophic -- where it is not (Docker bridge).

Document the Docker client-IP caveat: docker-compose.yml now defaults to
host networking, with the rationale and alternatives in DOCKER.md.
2026-06-15 16:38:07 -07:00
pmb 946c2b9e01 Block abusive IPs after repeated failed plan lookups
Port 79 mostly attracts HTTP/SIP probes, TLS handshakes, and username
guessers -- none of which resolve to a plan file. Treat any request that
fails to read a plan as an "offense" and timestamp it against the source
IP.

Add BanTracker (ban.hpp/ban.cpp): a per-IP rolling-window offender list.
When an IP has more than 3 offenses still inside a 24h window, its
connections are dropped without being read or answered; timestamps older
than the window are pruned so a blocked IP frees itself automatically.
State is in-memory (single io_context thread, no locking); the clock is
injected for testability. A periodic sweeper keeps the map bounded.

Legitimate lookups that hit a real plan never count, which also
frustrates username enumeration. Unit tests in test_ban.cpp.
2026-06-15 16:23:58 -07:00
pmb 84fc383137 docs(freebsd): capture stdout to /var/log/fingerd.log via daemon -o
Without -o the daemon(8) wrapper redirects stdout to /dev/null, so
the printf-based logging is invisible on BSD.
2026-05-16 21:42:09 -07:00
pmb 35d0f21051 Revert syslog logging back to stdout
Stdout works in both contexts: docker logs captures it directly,
and on FreeBSD daemon(8) / the Bastille jail rc script can
redirect or pipe it to syslog as needed. Going through syslog
from inside the daemon required openlog/closelog and a libc
dependency that broke portability with no real benefit.
2026-05-16 21:32:42 -07:00
pmb 0d5414e03d fix: switch runtime stage to ubuntu to match builder glibc
The Alpine/musl runtime can't exec our glibc-linked binary —
'exec /usr/local/bin/finger: no such file or directory'. The
recent syslog change pulls in fortify-source _chk symbols and
fcntl64 that musl doesn't provide even with gcompat. Matching
the runtime base to the builder (ubuntu:24.04) makes the image
reliably runnable; ship netcat-openbsd for the healthcheck.
2026-05-16 21:23:57 -07:00
pmb 676d1700e1 fix: healthcheck — use IPv4 and busybox-compatible nc
The Alpine runtime stage uses BusyBox nc, which has no -z flag, and
'localhost' resolves to ::1 while finger only binds 0.0.0.0:79. Both
combined caused every healthcheck to fail (35k+ failing streak on
mammut). Use '-w 1 127.0.0.1 79 < /dev/null' instead.
2026-05-16 21:06:05 -07:00
pmb 6d782366f3 log target user along with client ip 2026-05-16 19:32:21 -07:00
pmb cb8a038695 log via syslog (LOG_DAEMON) instead of stdout 2026-05-16 19:25:00 -07:00
pmb 8326367bff log remote endpoint on each accepted connection 2026-05-16 19:21:32 -07:00
pmb 80d8bd55da docs: fix RC script — use procname full path for correct status reporting 2026-05-07 00:12:18 -07:00
pmb 4631c75dad add update script for FreeBSD Bastille jail deployment 2026-05-07 00:07:30 -07:00
pmb acf2ecf61d docs: add FreeBSD build and service setup guide 2026-05-06 23:54:05 -07:00
pmb 88a8ae2a59 Remove test user 2025-07-02 17:11:55 -07:00
pmb 4d97255d3a Docker support 2025-07-02 17:11:31 -07:00
pmb 24b614b97d clang-format 2025-06-25 17:37:15 -07:00
pmb 977ca7ce7b Add tests for the real filesystem path 2025-06-25 17:36:49 -07:00
pmb 2a0c8b6dc8 Code cleanup 2025-06-25 17:25:50 -07:00
pmb e880f6ba1d Switch to using a filesystem class for better testing 2025-06-25 11:59:07 -07:00
pmb 3d35345eb9 ignore errors unused 2025-06-25 11:20:12 -07:00
pmb 46d46523ae idk anymore 2025-06-25 11:17:17 -07:00
pmb 5741b3eb70 more tweaking 2025-06-25 11:12:47 -07:00
pmb b2f1478855 Add --ignore-errors mismatch to all lcov commands 2025-06-25 11:08:42 -07:00
pmb b34b2e6526 Ignore CI errors 2025-06-25 11:03:25 -07:00
pmb 42c3bba68e Add code coverage and testing CI stuff 2025-06-25 10:53:48 -07:00
pmb 2e090e02fb Added some instructions to the README 2025-06-24 17:04:43 -07:00
pmb e648b8e319 Finds the plan file and returns its contents 2025-06-24 15:58:30 -07:00
pmb f71f1c9b11 Initial commit
Add .gitignore to exclude VSCode workspace files and build artifacts
2025-06-24 15:28:09 -07:00