Hybrid firewall using public blocklists
It integrates with Linux Netfilter via NFQUEUE, inspects inbound traffic in user space, and applies filtering based on public blocklists. Once a connection is checked, the engine "teaches" the Linux kernel to handle it. By assigning Conntrack marks, Meds offloads flows back to the kernel space, achieving maximum wire-speed throughput and minimal CPU overhead.
Requirements:
- Linux with iptables + NFQUEUE + conntrack support
- Root privileges (
sudo) — required for interacting with Netfilter/Netlink
The application manages iptables and conntrack rules automatically.
go install github.com/cnaize/meds/cmd/meds@latestsudo MEDS_USERNAME=admin MEDS_PASSWORD=mypass meds👉 http://localhost:8000/metrics
👉 http://localhost:8000/swagger/index.html
Usage of meds:
-accept-on-fail
auto accept packets on nfqueue fail
-api-addr string
api server address (default ":8000")
-db-path string
path to database file (default "meds.db")
-filter-abuseipdb-confidence int
abuseipdb filter minimum confidence (default 100)
-filter-abuseipdb-enable
enable abuseipdb filter
-filter-abuseipdb-report-addr
report quarantine addresses to abuseipdb
-log-level string
zerolog level (default "info")
-logger-queue-len uint
logger queue length (all workers) (default 2048)
-loggers-count uint
logger workers count (default 3)
-nats-enable
enable nats server
-nats-host string
nats server host (default "localhost")
-nats-port int
nats server port (default 4222)
-quarantine-ip-cache-size uint
quarantine ip cache size (all entities) (default 100000)
-quarantine-ip-entity-ttl duration
quarantine ip cache ttl (per entity) (default 15m0s)
-rate-limiter-bucket-ttl duration
rate limiter cache ttl (per bucket) (default 5m0s)
-rate-limiter-burst uint
max packets at once (per ip) (default 1500)
-rate-limiter-cache-size uint
rate limiter cache size (all buckets) (default 100000)
-rate-limiter-rate uint
max packets per second (per ip) (default 3000)
-reader-queue-len uint
nfqueue queue length (per reader) (default 8192)
-readers-count uint
nfqueue readers count (default 12)
-update-interval duration
update frequency (default 4h0m0s)
-update-timeout duration
update timeout (per filter) (default 1m0s)
-workers-count uint
nfqueue workers count (per reader) (default 1)
MEDS_USERNAME=admin_usernameMEDS_PASSWORD=admin_passwordMEDS_NATS_USERNAME=nats_usernameMEDS_NATS_PASSWORD=nats_passwordMEDS_ABUSEIPDB_API_KEY=your_abuseipdb_token
PACKET
│
┌───────────────────▼───────────────────┐
│ KERNEL SPACE (iptables / Netfilter) │
│ ───────────────────────────────────── │
│ 1. Restore Connmark │
│ │
│ 2. Check Blocklist ──► DROP ◄─┼──┐
│ (Mark: 0x100000) │ │
│ │ │
│ 3. Check Trustlist ──► ACCEPT │ │
│ (Mark: 0x200000) │ │
│ │ │
│ 4. First 10 packets ──┐ │ │
│ │ │ │
│ 5. Save Connmark │ │ │
└─────────────────────────┼─────────────┘ │
│ │
┌─────────────────────────▼─────────────┐ │
│ USER SPACE (Meds Firewall) │ │
│ ───────────────────────────────────── │ │
│ 1. Quarantine ◄──[SUB]──┐ │ │
│ 2. Rate Limiter ───[PUB]──┤ │ │
│ 3. L3/L4 Filters │ │ │
│ 4. L7 Inspection ───[PUB]──┤ │ │
│ │ │ │
│ [DECISION ENGINE] │ │ │
│ * BLOCK: 0x100000 ──────────┼───────┼──┘
│ * TRUST: 0x200000 │ │
└───────────────────────────────┼───────┘
[PUB]
┌────────────────┴───────┐
│ EMBEDDED NATS SERVER ◄─┼──[External]
└────────────────────────┘
-
Early Drop: Blocked traffic (
0x100000) is handled by the kernel immediately. This ensures that known threats are dropped at the earliest possible stage, eliminating unnecessary context switches and user-space overhead. -
Stateful Acceleration: Once a connection is verified as Trusted (
0x200000), it is offloaded to the kernel's fast path. Subsequent packets in the flow are processed entirely in-kernel at wire-speed, eliminating user-space overhead for established sessions. -
Deep Inspection: Only new or unclassified traffic (the "Decision Phase") is sent to Meds for deep L3/L4/L7 analysis. This phase is limited to a 10-packet window to extract metadata (DNS, SNI, JA3) before the kernel takes over.
-
Reactive Threat Offloading: External applications or internal filters can stream detected malicious IPs to the embedded NATS server.
-
Hybrid Kernel/User space Processing
Meds utilizes a stateful marking architecture. It "teaches" the Linux kernel how to handle specific flows by assigning Conntrack marks, achieving wire-speed performance for established connections. -
Intelligent NFQUEUE Balancing
Intercepts traffic usingNFQUEUEwithbalanceandbypassoptions, ensuring multi-core scaling and system stability even if the user-space process is restarted. -
Embedded NATS
Exposes an asynchronous reactive API for external applications to offload detected threat vectors to the L3/L4 network layer quarantine:- Publish to
meds.quarantine.ip.add(payload:"1.2.3.4") to add the IP to the quarantine - Publish to
meds.quarantine.ip.del(payload:"1.2.3.4") to delete the IP from the quarantine
- Publish to
-
Lock-free Core Architecture
The core engine is built for high-concurrency performance: no mutexes in the hot path. All filtering, counters, and rate-limiters utilize atomic operations. -
Rate Limiting
Uses token bucket algorithm to limit burst and sustained traffic per source IP, protecting the system against high-frequency floods (SYN, DNS, ICMP, or generic packet floods). -
Blocklist-based filtering
- IP blocklists: FireHOL, Spamhaus DROP, Abuse.ch
- [Optional] AbuseIPDB with the ability to send reports
- ASN blocklists: Spamhaus ASN DROP using IPLocate.io for IP-to-ASN mapping
- Domain blocklists: StevenBlack hosts, SomeoneWhoCares hosts
- IP blocklists: FireHOL, Spamhaus DROP, Abuse.ch
-
Geo-blocking (ASN-based)
Efficiently blocks traffic from specific countries using ASN metadata from IPLocate.io:- Lightweight alternative to heavy GeoIP databases
- Dynamic configuration via API/Swagger
-
TLS SNI & JA3 filtering
Extracts and inspects TLS ClientHello data directly from TCP payload before handshake completion:- Filters by SNI (domain in TLS handshake)
- Filters by JA3 fingerprint using the Abuse.ch SSLBL JA3 database
Enables real-time blocking of malicious TLS clients such as malware beacons, scanners, or C2 frameworks.
-
HTTP API for runtime configuration
Built-in API server allows dynamically adding or removing IP or Country entries in global allow/block lists.
Auth via Basic Auth usingMEDS_USERNAME/MEDS_PASSWORD. -
Prometheus metrics export
Exposes metrics for observability:- Total packets processed
- Dropped packets (with reasons)
- Accepted packets (with reasons)
- Internal errors (with types)
Metrics are available at
/metricsvia the built-in API server, compatible with Prometheus scrape targets.
# HELP meds_core_packets_accepted_total Total number of accepted packets
# TYPE meds_core_packets_accepted_total counter
meds_core_packets_accepted_total{filter="empty",reason="default"} 30317
meds_core_packets_accepted_total{filter="ip",reason="AllowList"} 2299
# HELP meds_core_packets_dropped_total Total number of dropped packets
# TYPE meds_core_packets_dropped_total counter
meds_core_packets_dropped_total{filter="asn",reason="Spamhaus"} 83
meds_core_packets_dropped_total{filter="domain",reason="StevenBlack"} 1
meds_core_packets_dropped_total{filter="ip",reason="AbuseIPDB"} 9514
meds_core_packets_dropped_total{filter="ip",reason="FireHOL"} 5423
meds_core_packets_dropped_total{filter="ip",reason="Quarantine"} 2812
# HELP meds_core_packets_processed_total Total number of processed packets
# TYPE meds_core_packets_processed_total counter
meds_core_packets_processed_total 50449
Meds is released under the MIT License.
See LICENSE for details.
Pull requests and feature suggestions are welcome!
If you find a bug, please open an issue or submit a fix.
Made with ❤️ in Go