## stamparm/maltrail — 3.1.1…3.2

_110 commits._

### Features
- **contributing: write down the bar for a new feed** (7b95560)
- **Revert "Add IPWhois.net community blacklist feed (#19594)"** (f1f069a)
- **Revert "Add ThreatCluster feed (#19605)"** (fd8dfce)
- **Add ThreatCluster feed (#19605)** (44ec276)
- **Add IPWhois.net community blacklist feed (#19594)** (fb254cb)
- **new beaconing heuristic: timer-regular reconnects to one destination** (6b68576)
- **Add SekuriPy Labs link to README** (f3d5eda)

### Fixes
- **Fix CI after the split** (611e750)
- **Fix for "Thank you" list link** (5ed9425)
- **Couple of bug fixes** (73eb328)

### Backend
- **Tell me about generated-constant drift in seconds, not minutes** (10992e5)
- **Release: an apostrophe in a comment broke every build since 3.1.1** (6f5e3f7)
- **Cite a trail's source again, without needing the content tree** (0c9eb3b)
- **3.2: ship a trail-set bootstrap, and bump the version** (c43cb65)
- **Refuse to be quiet about a missing static trail source** (2639503)
- **README: drop the static trail count, it moves daily** (ad488de)
- **README: describe where trails come from now** (04a423b)
- **Fetch the trail set gzipped, and skip the download when it has not changed** (66e3ea6)
- **Static trails move to their own repository** (dfb3bfc)
- **Fixing CI/CD issues** (28168ad)
- **Update ua.txt** (39efde9)
- **Fixing CI/CD issues** (48f30d2)
- **Update ua.txt** (9801b6d)
- **trails: the same checkout must build the same trail set everywhere** (b270826)
- **Removing shitty dependabot** (b7978ec)
- **dashboard: make the selected page size visible in light mode** (96eb9fe)
- **trails: catch typos in the "# Reference:" / "# Aliases:" headers** (93b84ca)
- **Bump pcap (#19606)** (e1876af)
- **dashboard: the drill-down chart uses the panel it is given** (c6ef16c)
- **dashboard: family: pulls a campaign back together** (2430670)
- **console: colour the JA3/JA4 trail types** (04aa8cd)
- **dashboard: the sensor's own guesses rank below what a feed listed** (307e0e8)
- **beaconing: mark the class, and honour the destination whitelist** (08e37b1)
- **Adversarial suites: hostile logs, sidecars, clocks** (453e2ad)
- **Differential ClientHello corpus held to both implementations** (d33cf5d)
- **TLS ClientHello parse: match Python on fatal-vs-tolerable truncation** (35e4d98)
- **trail drawer shows how strongly sources agree** (f0a0830)
- **per-day sidecar event index; /counts exact, /hunt skips non-matching lines** (d7ee736)
- **TLS client fingerprints (JA3/JA4) matched as trails** (c167363)
- **corpus timing test matches pins against the whole event line** (3ed9278)
- **trail-confidence sidecar; /check now reports how strongly sources agree** (a00c5ac)
- **refresh wildcard trail vectors against the current trail set** (fab95f2)
- **server --doctor preflight; both parsers flag unknown config options** (93aa424)
- **Throttle summary reports volume past the held-buffer cap** (9560bc8)
- **Exact static trail beats its whitelisted ancestor (longest match)** (1f42212)
- **Update ua.txt** (3f21a51)
- **Update ua.txt** (17b3ea9)
- **Regenerate settings_gen.rs: ua.txt gained two patterns the Rust sensor could not see** (075ca9d)
- **Gate trail content, and check regex trails against ranked popularity lists** (7c734f4)
- **Update ua.txt** (51966d8)
- **Alert webhook: POST events at or above a severity threshold** (ab07e01)
- **Python 3.13 dedents docstrings, so a test asserted against text it meant to remove** (8876fa4)
- **gen_settings.py: --check was an unrecognised argument, so it silently rewrote the tree** (941abbc)
- **Do not track error.log: running the server from a checkout writes one here** (1c0e3d5)
- **UDP event intake dropped 24% at 10k events/s: a thread and an open() per datagram** (92176a1)
- **Trails: a `\b` boundary deleted domains as bogons, and 3,082 more are shadowed by the whitelist** (274d67e)
- **/hunt: the IP "fast path" was 9x slower than a substring hunt over the same log** (b7e52ea)
- **--smoke-test printed nothing at all and exited 1, and the handler is why** (315b2e0)
- **--detect-test told a healthy install its detection was completely broken** (070b70c)
- **Every IPv6 event was unmapped on the attack map, and the tables were 3x too big** (a74ed0c)
- **The trail-reachability gate reported a live trail as dead, so it ran nowhere** (0f04d83)
- **Reject non-global IPv6 addresses at /ripe too** (fb2c701)
- **Correct the store-size, speedup and updater-path claims** (88ba5c3)
- **Verify the trail store's no-false-negative invariant without a trails file** (97a8c9d)
- **Check html/ for dangling references and orphans, and drop lan.gif** (fe30a44)
- **Proxy RIPEstat through /ripe, and put script-src back to 'self'** (ea720ef)
- **Refuse the private key Maltrail used to ship** (50f946e)
- **Bump to 3.1.2** (667997b)
- **Release: drop --enable-static, which libpcap's configure does not know** (c292417)
- **Release binaries could not start on Debian or Ubuntu, libpcap installed or not** (cece9d3)
- **Minor update** (f085e19)
- **The generated-constants gate skipped every documented constant** (7633a03)
- **Update of docu** (7991871)
- **Update ua.txt** (7bf3da3)
- **Update worst_asns.txt** (c8e8f64)
- **Update whitelist.txt** (ea895de)
- **Update whitelist.txt** (16fdf7a)
- **Review of the preceding three commits: one real hole, and the flaky gate step** (32fe187)
- **Gate: `sensor/tools/check.sh` could not get past its own fmt and clippy steps** (34fecf8)
- **Packet path: work removed per HTTP request and per DNS query** (1fc58c9)
- **Startup: nine doomed forks looking for python, and 75ms of idle regex compiling** (42c684e)
- **Trail load was 1.4s of single-threaded startup on 8 idle cores** (7d8774f)
- **Capture ring: 16MB default was indefensible, and CAPTURE_BUFFER now reaches it** (2d8f4ce)
- **Throttle: key on a digest instead of allocating four strings per event** (5a49fa7)
- **-T reported a capture ring 64x larger than the one it was about to use** (f79d9f3)
- **.dev is a real TLD: 7,658 trails could never fire** (83b7acb)
- **Tests: never let stopping a server subprocess fail the run** (90c7e1c)
- **CSP: frame-src 'none', since the dashboard embeds nothing** (fabf857)
- **Retire the dead pre-commit hook, keep the checks it never ran** (7b9cbbe)
- **Drop 'unsafe-eval' from the dashboard's CSP** (d38e9ca)
- **Never serve demo.js: the strip depended on the tag's exact spelling** (30adfad)
- **maltrail.conf said TLS certificate matching was off by default** (9d53d6f)
- **CITATION.cff was citing 3.0, and nothing checked it** (71bbc92)
- **Sensor hot path: two fixes on the packet that matches nothing** (d02760d)
- **Drop 492K of frontend assets the v3 rewrite left behind** (5281014)
- **ruff.toml: stop claiming py37 is the project's floor** (025a359)
- **Bound the UDP burst digest to a 64-byte prefix** (52bed81)
- **Document the throttle eviction metric for operators** (7398659)
- **Expose throttle evictions as a metric** (b50522d)
- **Throttle: evict in batches instead of one key per full scan** (a00ce9b)
- **/events: honour open-ended and suffix byte ranges** (d024a35)
- **/hunt: stop reporting a half-scanned day as a complete count** (5dc326f)
- **Accept underscores in DNS queries: 134 static trails were unreachable** (96e46fd)
- **Give /live its own budget so SSE cannot starve the request pool** (0218826)
- **Bound HTTP concurrency and stop failed logins parking threads** (071b70f)
- **Parity harness: pin the two deliberate UDP divergences** (011635a)
- **Update of README.md** (71e56f4)
- **Minor update** (e140f2b)
- **HANDOVER: 3.1.1 is out, the one-liner is advertised** (3bb7537)
- **README: lead the quick start with the one-liner** (c6ad46e)

_Recap by [Repo Wrapped](https://repowrapped.com/gh/stamparm/maltrail?utm_source=github-action)._