FastAdHunter - GitHub - bobdenaut/FastAdHunter: The fastest network-wide ad blocker with the smallest possible memory footprint · GitHub
Network-wide filtering !
FastAdHunter is an API-first network filter for homes, labs, and other networks. One ARM64 container protects the LAN's phones, browsers, TVs, thermostats, game consoles, and other devices.
It combines DNS filtering, HTTP URL filtering, and HTTPS host filtering at the SNI. HTTPS is relayed as an encrypted connection: FastAdHunter does not decrypt browsing traffic or require a client CA in the production path.
Memory safe proven and fast, really fast! Rust job ![]()
Dashboard:
Live feed:
Mikrotik terminal:
Production status: FastAdHunter 0.4.1 has been running on the reference MikroTik RB5009 since 2026-09-21 in
dns+http+httpsmode. HTTPS interception is disabled by design.
Why FastAdHunter
Browser extensions are effective but device-specific. DNS filters protect more devices, but a domain-only decision cannot distinguish one unwanted path from the rest of a useful host. FastAdHunter puts both decisions at the network boundary:
- Network-wide: one router deployment covers every client on the LAN.
- Precise: DNS rules act on domains; URL rules can use host, path, method, resource type, and client context.
- Privacy-conscious: HTTPS policy uses the TLS SNI and leaves the encrypted connection intact.
- Predictable: caches, queues, and tracking are bounded; request bodies are streamed rather than buffered.
- Operable: REST, WebSocket events, a web dashboard, and a terminal monitor expose the engine without a privileged UI integration.
What it filters
| Layer | What happens |
|---|---|
| DNS | Domains are checked before cache or upstream resolution. Upstream answers are cached; verdicts are not. |
| HTTP | Requests are checked against URL rules before the origin is contacted. Bodies are streamed. |
| HTTPS | The TLS SNI is read, host-level policy is applied, and the encrypted connection is relayed byte for byte. |
| DoT / DoH | Encrypted DNS listeners serve clients that support Private DNS. |
One compiled Rule Engine serves DNS and HTTP. A path rule therefore remains a path rule; it does not become a whole-domain DNS block.
HTTPS without interception
FastAdHunter's production HTTPS path is deliberately limited and explicit:
- The listener reads the TLS ClientHello and extracts the SNI.
- Host-level policy decides whether the connection is blocked or forwarded.
- An allowed connection is relayed without decrypting or rewriting it.
The production path does not install a FastAdHunter CA on client devices. The interception code exists in the build but is disabled because the Interception Document has no clients selected. This keeps ordinary HTTPS browsing opaque to the proxy while still allowing host-level filtering and HTTPS/HTTP3 control at the router boundary.
Production snapshot
These are measurements from the reference RB5009 deployment or its deployed path. They are not universal promises for every device or workload.
| Metric | Observed result | Measurement context | Project target |
|---|---|---|---|
| Rules compiled | 766,499 from 1,198,086 source entries | 0.4.1, 16 public lists | corpus-dependent |
| Ruleset resident heap | 24.48 MiB | 0.4.1, deployed ruleset | <= 40 MB |
| Ruleset compile time | 2.92 s | 0.4.1, 1.20 M parsed rules | < 3 s |
| Sustained DNS throughput | 20k+ QPS | 0.2.x deployed path, synthetic profile | >= 10k QPS |
| HTTP proxy added latency | +344 us p50 | 0.2.x, opaque pass-through workload | < 1 ms budget; statistic differs |
| Opaque HTTP throughput | 208-271 MiB/s | 0.2.x, pass-through workload | >= 100 MiB/s |
| Container image | 14.07 MiB | 0.3.0, ARM64 image with dashboard | <= 30 MB |
The 0.2.x and 0.3.0 rows are historical measurements and are labelled as such; they are not 0.4.1 release measurements. The refresh transient remains a known, bounded cost: rebuilding the ruleset temporarily holds old and new data together and can exceed the steady-state memory budget. See PERFORMANCE.md and the linked measurement records for methodology and limits.
Built for routers
FastAdHunter is a statically linked, non-root ARM64 container. Configuration, certificates, cached lists, and history live on persistent mounts outside the image:
/config TOML configuration, API key, TLS certificate, authentication state
/data cached rule lists, session state, and history
The reference target is a MikroTik RB5009 with four ARMv8 cores and 1 GB of memory shared with RouterOS. The runtime keeps the normal path small and bounded:
- the DNS cache is bounded by entry count and bytes;
- stale answers can be served while one bounded worker refreshes them;
- HTTP and HTTPS bodies are streamed rather than buffered;
- configuration and ruleset changes use atomic swaps;
- HTTP connections can run in dedicated single-thread allocation domains.
Dashboard and API
The dashboard is served by fah-api from the same image and TLS listener. It uses the public API rather than a privileged path into the engine.
The API provides health, authentication, telemetry, statistics, clients, policies, lists, rules, cache, history, configuration, certificates, memory diagnostics, and a live event stream. The terminal monitor uses the same REST and WebSocket interfaces:
cargo run --release -p fah-tui-monitor
See API.md for endpoint shapes.
Security model
The administrative API uses HTTPS by default and supports two authentication paths:
- Bearer API key for automation. It is generated on first boot and stored in
/config. - Argon2id password authentication for the dashboard, issuing a signed session cookie with
HttpOnly,Secure, andSameSite=Strictproperties.
Administrative routes require authentication, except health and login. The deployment has no WAN administration model; expose the API only on a trusted management network. HTTPS interception is disabled in the current production path and does not require a client CA.
Read the complete security model in SECURITY.md.
Quick start
The production workflow is:
- Build an ARM64 image with Docker Buildx.
- Put
/configand/dataon persistent storage. - Start the container with DNS and the configured HTTPS API port.
- Point the LAN resolver at the container and verify DNS filtering.
- Enable
dns+httpordns+http+httpsafter the DNS path is working.
docker buildx build --platform linux/arm64 \
-t fastadhunter:0.4.1 \
-o type=docker,dest=fastadhunter-arm64.tar .
The complete RouterOS procedure includes image format requirements, network placement, verification, and rollback: docs/deploy-rb5009.md.
Configuration precedence is built-in defaults, TOML, environment variables, then validated API changes. See CONFIGURATION.md.
Current scope
FastAdHunter is not:
- a browser extension;
- antivirus software;
- an intrusion detection system;
- a general-purpose firewall;
- a cosmetic DOM filter.
Cosmetic HTML filtering is not part of today's production path. It is planned as a built-dormant, opt-in capability and is not currently built. FastAdHunter is proprietary and currently has no public license.
Documentation
- Deployment on the reference RB5009
- Configuration reference
- API reference
- Security model
- Architecture
- Rule Engine
- Performance budgets and measurements
- Roadmap
Architecture diagrams
Explore the system visually in docs/diagrams:
FastAdHunter is built with Rust, Tokio, Hyper/Axum, Hickory, rustls, rcgen, Argon2id, and Preact. Its design prioritizes measurable latency, bounded memory, streaming, and a small operational surface over feature count.





