Intelligent firewall in Go
It integrates with Linux Netfilter via NFQUEUE, inspects inbound traffic in user space, and applies filtering to block malicious traffic in real-time. 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.
Designed to cure your network from malicious traffic
Requirements:
- Linux with iptables + NFQUEUE + conntrack support
- Root privileges (
sudo) — required for interacting with Netfilter/Netlink
The application manages iptables and conntrack rules automatically.
Download the latest binary from Releases or build from sources.
go build -o meds ./cmd/daemonsudo MEDS_USERNAME=admin MEDS_PASSWORD=mypass ./meds
# Metrics available at: http://localhost:8000/metrics
# API available at: http://localhost:8000/swagger/index.html
# Basic Auth: admin / mypass./meds -help
Usage of ./meds:
-api-addr string
api server address (default ":8000")
-db-path string
path to database file (default "meds.db")
-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)
-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-cache-ttl duration
rate limiter cache ttl (per bucket) (default 5m0s)
-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)
👉 http://localhost:8000/metrics
The metrics endpoint is protected by the same BasicAuth credentials as the API.
Interactive API docs:
👉 http://localhost:8000/swagger/index.html
You can browse and test all API endpoints directly from your browser.
OpenAPI spec (JSON):
👉 http://localhost:8000/swagger/doc.json
You can import this spec into Postman, Insomnia, or Hoppscotch.
PACKET
│
┌───────────────────▼───────────────────┐
│ KERNEL SPACE (iptables / Netfilter) │
│ ───────────────────────────────────── │
│ 1. Restore Connmark │
│ │
│ 2. Check Block List ──► DROP ◄─┼──┐
│ (Mark: 0x100000) │ │
│ │ │
│ 3. Check Trust List ──► ACCEPT │ │
│ (Mark: 0x200000) │ │
│ │ │
│ 4. First 10 packets ──┐ │ │
│ │ │ │
│ 5. Save Connmark │ │ │
└─────────────────────────┼─────────────┘ │
│ │
┌─────────────────────────▼─────────────┐ │
│ USER SPACE (Meds Firewall) │ │
│ ───────────────────────────────────── │ │
│ 1. Rate Limiter (per source IP) │ │
│ 2. L3/L4 Filters (IP, Geo, ASN) │ │
│ 3. L7 Inspection (DNS, SNI, TLS JA3) │ │
│ │ │
│ [DECISION ENGINE] │ │
│ * BLOCK: Mark 0x100000 ──► REPEAT ──┼──┘
│ * TRUST: Mark 0x200000 ──► ACCEPT │
└───────────────────────────────────────┘
-
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.
-
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. -
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). -
Blacklist-based filtering
- IP blacklists: FireHOL, Spamhaus DROP, Abuse.ch
- ASN blacklists: Spamhaus ASN DROP using IPLocate.io for IP-to-ASN mapping
- Domain blacklists: StevenBlack hosts, SomeoneWhoCares hosts
-
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 white/black lists.
Auth via BasicAuth 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"} 12021
meds_core_packets_accepted_total{filter="empty",reason="trusted packet"} 420
meds_core_packets_accepted_total{filter="ip",reason="WhiteList"} 139
# 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"} 263
meds_core_packets_dropped_total{filter="domain",reason="StevenBlack"} 3
meds_core_packets_dropped_total{filter="geo",reason="IPLocate"} 43
meds_core_packets_dropped_total{filter="ip",reason="FireHOL"} 1443
# HELP meds_core_packets_processed_total Total number of processed packets
# TYPE meds_core_packets_processed_total counter
meds_core_packets_processed_total 14332
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