Implement synlimit = "pf" for PF-based firewalls using per-listener source tracking rules in a Telemt-owned anchor.
PF evaluates max-src-conn-rate through source tracking when creating
tates for completed TCP connections. Telemt installs a rate-limited pass
rule followed by a reject fallback rule in the listener anchor:
- under-limit new connections create PF state and pass;
- over-limit new connections fall through to block return-rst;
- access resumes automatically when the source rate drops below the configured window.
Keep Linux iptables/nftables behavior unchanged.
PF maps synlimit_hitcount / synlimit_seconds to max-src-conn-rate and intentionally has
no direct equivalent for Linux-only burst/hashlimit knobs.
The generic-path SYN limiter default of burst=1 admits only one new
connection per source IP, then refills at 48/minute (0.8/s). Telegram
clients open several connections at once on startup/reconnect, so the
extra SYNs are rejected with TCP RST until a token accrues — clients
intermittently fail to connect until the app is restarted.
The iOS fast-path (meta length 64) does not match real-world traffic
behind carrier NAT/NAT64 (SYNs arrive as 60 bytes), so the generic path
governs all clients, iPhone included. Raise its default burst to 24 —
the value already used by the iOS path — so a legitimate startup fan-out
passes. Steady-state rate (48/minute) is unchanged, preserving the
anti-TSPU posture.
Updates the default constant, the default-assertion test, and the EN/RU/DE
CONFIG_PARAMS docs.
client_mss (e.g. "tspu", MSS=92) fragments the whole connection to evade
DPI on the ServerHello, but it also fragments bulk payload, multiplying
outgoing packets-per-second ~10x. On hosts whose abuse detection counts
pps (not bandwidth) this trips packet-flood limits.
Add an optional [server].client_mss_bulk: keep the low client_mss for the
handshake (ServerHello stays fragmented => DPI bypass intact), then raise
the client socket MSS to client_mss_bulk once the connection enters the
post-handshake (bulk transfer) phase, so bulk data uses normal-size
segments and pps drops back to normal. Same preset/int grammar as
client_mss. Opt-in: when unset, the handshake MSS is kept for the whole
connection (unchanged behavior).
Linux-only (setsockopt TCP_MAXSEG via raw fd, mirroring TCP_USER_TIMEOUT);
no-op on other unix. Documented in CONFIG_PARAMS.{en,ru}.
Add config examples and behavior notes for access.user_source_deny, and clarify that it is configured through config.toml rather than dedicated user API request fields.
Updated the `unknown_sni_action` parameter to include `reject_handshake` as a valid option. Expanded the description for `unknown_sni_action` to clarify its behavior.
Add `rst_on_close` config option (off/errors/always) to control
SO_LINGER(0) behaviour on accepted TCP connections.
- `off` (default): normal FIN on all closes, no behaviour change.
- `errors`: SO_LINGER(0) set on accept, cleared after successful
handshake auth. Pre-handshake failures (scanners, DPI probes,
timeouts) send RST instead of FIN, eliminating FIN-WAIT-1 and
orphan socket accumulation. Authenticated relay sessions still
close gracefully with FIN.
- `always`: SO_LINGER(0) on accept, never cleared — all closes
send RST regardless of handshake outcome.