Commit Graph
35 Commits
Author SHA1 Message Date
waffle2k dcbcff98a6 Add Rust port of the finger daemon
CI / Build and Test (gcc, g++, ubuntu-latest) (push) Failing after 31s
CI / Code Coverage (push) Skipped
Build and Publish Docker Image / build-and-test (push) Failing after 1m7s
Build and Publish Docker Image / build-and-push-image (push) Skipped
Build and Publish Docker Image / security-scan (push) Skipped
Tokio-based reimplementation in rust/, mirroring the C++ handler and
ban-tracker logic (directory-traversal checks, case-insensitive plan
lookup, rolling-window IP ban tracking, allowlist parsing) along with
its full test suite. Includes a matching multi-stage Dockerfile.
2026-07-23 21:24:55 -07:00
pmb da4fa18525 Add FINGER_BAN_ALLOWLIST to exempt trusted front-end IPs from banning
CI / Build and Test (gcc, g++, ubuntu-latest) (push) Failing after 5m2s
CI / Code Coverage (push) Skipped
Build and Publish Docker Image / build-and-test (push) Failing after 6m13s
Build and Publish Docker Image / build-and-push-image (push) Skipped
Build and Publish Docker Image / security-scan (push) Skipped
The per-IP ban tracker treats every globally-routable client equally, but an
aggregating front-end like the finger-web proxy funnels the whole internet's
federated lookups through a single IP. A burst from any one client of the proxy
(or a load test) is then attributed to the proxy's IP and, once it crosses the
failure threshold, the daemon blocks the proxy — taking out finger lookups for
everyone. Per-client abuse protection for the proxied path belongs in the proxy
(which now rate-limits per real client IP), so the daemon should trust it.

Add a FINGER_BAN_ALLOWLIST env var (comma-separated IPs). Allowlisted addresses
are marked non-trackable in the listener, so their connections are never blocked
and never recorded as offenses. Unset = unchanged behaviour.

- parse_ip_allowlist() in ban.cpp (trims entries, skips blanks) + unit tests
- listener() consults the set when computing 'trackable'
- documented in docker-compose.yml and DOCKER.md
2026-06-17 10:44:47 -07:00
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
waffle2k 268ededc19 Make username lookup case-insensitive
finger [email protected] (or any mixed-case name) failed because the plan
path was built from the raw username while plan files are lower-case on
disk. Lower-case the requested name before resolving the plan path; the
original spelling is still echoed back when no plan file exists. Add a mock
test asserting Pete -> .../pete.
2026-06-15 15:47:55 -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
waffle2k df160fafca meson: fix build for FreeBSD/clang compatibility
Remove GCC-specific static link args (-static, -static-libgcc,
-static-libstdc++) that fail under clang. Add threads_dep via
dependency('threads') to all targets so Boost ASIO's pthread
usage links correctly on FreeBSD where clang does not pull it in
implicitly. Linux/GCC builds are unaffected.
2026-05-06 23:50:54 -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
waffle2k 5261131772 Delete finger.code-workspace 2025-06-24 16:49:59 -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
waffle2k 6291e7a501 Initial commit 2025-06-24 15:09:33 -07:00