Skip to content

v0.2.1

Latest

Choose a tag to compare

@LaurenceJJones LaurenceJJones released this 03 Dec 15:44
· 1 commit to main since this release
489bc83

What's Changed

No breaking changes as minor patch version

Warning

We plan to release this around a CrowdSec release make sure to update either CrowdSec OR this remediation firstly, do not update both at the same time as the LAPI will be unavailable when the remediation comes up and will fail to connect unless retry_initial_connect configuration is set.

🚀 New Features

  • BART-Based Trie for Ranges – Replaced O(n) CIDR lookups with a hardware-accelerated path-compressed trie for faster decision matching when dealing with IP ranges. The trie now correctly implements longest prefix match (LPM) so more specific ranges override general ones. In the current hybrid design, BART is only used for range-based remediations, while single IP decisions stay on a simpler, fast path. (#66)
Explanation for BART

Previously, we stored decision ranges as a slice and checked them one by one:

// sudo code example of old approach: linear scan over a slice of CIDR ranges.
for _, cidr := range rangeSet {
    if cidr.Contains(ip) {
        return remediationFor(cidr)
    }
}

This was simple, but had two important drawbacks:

  1. Order-dependent (“first match wins”)
    The first matching CIDR in the slice was used, even if a more specific range existed later. That makes decision order matter and can give surprising results.

  2. O(n) lookup time
    In the worst case, every lookup walks the entire slice. As the number of ranges n grows, misses and broad scans become slower.

With BART we now use a path-compressed trie for range storage and lookups. Instead of scanning all ranges, lookups follow the bits of the IP address through the trie:

  • Lookup complexity is O(k) where k is the number of bits in the address (at most 32 for IPv4, 128 for IPv6).
  • The number of steps depends on the address length, not on how many prefixes you have.
  • The trie naturally performs longest-prefix match, so more specific ranges always win over broader ones, regardless of insertion order. EG: 192.168.0.0/16 vs 192.168.1.0/24 the latter wins for 192.168.1.160.

In practice: even with hundreds or thousands of ranges, lookups stay fast and deterministic.


  • pprof Debug Endpoint – Added an optional HTTP endpoint exposing Go pprof handlers, making it easier to capture CPU/heap profiles from live instances during load tests and production debugging. (#127)

⚡ Performance & Architecture Improvements

  • Global Session Management – Consolidated per-host session managers into a single global manager, reducing goroutine overhead and preparing the ground for future AppSec integration. (#113)

  • Simplified Signal Handling – Improved shutdown reliability using Go’s native signal.NotifyContext, ensuring graceful termination on SIGTERM/SIGINT. (#103)

  • HAProxy SPOE Library Upgrade – Upgraded to v1.0.7 with automatic workgroup handling, simplifying code and improving reliability. (#119)

  • Host Runtime Cleanup – Removed unused runtime operations in the host management logic, simplifying the code and shaving off minor overhead. (#124)

  • Hybrid IP Storage & Parallel Batch Processing – Reworked the dataset backend to split storage between single IPs and ranges. BART is now dedicated to CIDR ranges for true LPM, while single IP decisions are handled via a straightforward map-based fast path. Batch updates are processed in parallel to reduce lock contention and speed up large decision syncs. (#128)

  • Prometheus Metrics Allocation – Switched to WithLabelValues for metric labelling to avoid per-call map allocations in hot paths, reducing overhead in high-traffic environments. (#130)

🔧 Bug Fixes

  • Geo Database Initialization – Fixed database loading issues and improved error handling for missing or invalid GeoIP databases. (#121)

  • Dataset Stability – Fixed a potential nil map panic in dataset handling and removed redundant Clone calls, improving safety and reducing unnecessary allocations in hot paths. (#125)

  • Decision Stream GC Improvements – Broke long-lived string references to DecisionsStreamResponse payloads so large updates can be garbage-collected promptly, reducing memory pressure during intensive syncs. (#126)

📦 Dependencies & Maintenance

  • GeoIP2 Library Upgrade – Updated to v2.0.0 with modern netip.Addr support, improving performance and type safety. (#118)

  • Development Tools – Added .vagrant/ to .gitignore for cleaner development workflows. (#117)

Full Changelog: v0.2.0...v0.2.1