
Meds: net healing
High-performance firewall powered by NFQUEUE and Go
It integrates with Linux Netfilter via NFQUEUE, inspects inbound traffic in user space, and applies filtering to block malicious or unwanted traffic in real-time.
Designed to cure your network from malicious traffic.
π Installation
Requirements:
- Linux with iptables + NFQUEUE support
- Root privileges (
sudo) β required for interacting with iptables/NFQUEUE
The application manages iptables rules automatically.
Download
Download the latest binary from Releases or build from sources.
Build from sources
go build -o meds ./cmd/daemon
π§© Quickstart
sudo 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
Command-line options
./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 3m0s)
-rate-limiter-rate uint
max packets per second (per ip) (default 3000)
-reader-queue-len uint
nfqueue queue length (per reader) (default 4096)
-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)
Prometheus metrics
π http://localhost:8000/metrics
The metrics endpoint is protected by the same BasicAuth credentials as the API.
Swagger UI
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.
β¨ Key Features
-
NFQUEUE-based packet interception
Uses Linux Netfilter queues to copy inbound packets into user space with minimal overhead.
-
Lock-free core
Meds itself does not use any mutexes β all filtering, counters, and rate-limiters use atomic operations.
-
Decoupled reader / worker / logger model
- Readers drain NFQUEUE as fast as possible
- Workers perform CPU-intensive filtering
- Logger uses zerolog with async worker-based logging
-
Fast packet parsing with gopacket
Parses traffic efficiently (lazy and no copy modes enabled).
-
Efficient lookups
Uses radix tree and bart for IP/domain matching at scale.
-
Rate Limiting per IP
Uses token bucket algorithm to limit burst and sustained traffic per source IP.
Protects against high-frequency floods (SYN, DNS, ICMP, or generic packet floods).
-
Blacklist-based filtering
-
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:
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 (powered by Gin) allows dynamically adding or removing IP, Domain, or Country entries in global white/black lists.
Auth via BasicAuth using MEDS_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 /metrics via the built-in API server, compatible with Prometheus scrape targets.
-
Extensible design
Modular architecture allows adding new filters.
π How It Works
[Kernel] β [NFQUEUE] β [Meds]
β³ Global IP Filters (white/black lists)
β³ Global Domain Filters (white/black lists)
β³ Rate Limiter (per source IP)
β³ IP Filters
β³ Geo Filters
β³ ASN Filters
β³ Domain Filters
β³ TLS Filters (SNI / JA3)
β³ Decision: ACCEPT / DROP
-
Packet interception
All inbound packets are queued from Netfilter (iptables rule with -j NFQUEUE).
-
Classification pipeline
Packets are processed according to the following pipeline:
- Global IP Filters β checks against white/black lists
- Global Domain Filters β checks against white/black lists
- Rate Limiter β limits packet rate per source IP
- IP Filters β per source IP filtering rules
- Geo Filters β country-based checks using ASN metadata
- ASN Filters β reputation checks against ASN blacklist
- Domain Filters β per domain filtering rules
- TLS Filters β SNI and JA3 fingerprint checks
-
Decision engine
- ACCEPT β packet is safe, passed to kernel stack
- DROP β packet is malicious, discarded immediately
-
Metrics & logging
Every decision is counted and exported for monitoring and alerting.
Metrics are Prometheus-compatible and can be visualized in Grafana.
All events are asynchronously logged to minimize packet processing latency.
π Example Metrics (Prometheus)
# 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"} 21766
meds_core_packets_accepted_total{filter="ip",reason="whitelisted"} 116
# 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"} 12
meds_core_packets_dropped_total{filter="ip",reason="FireHOL"} 1636
meds_core_packets_dropped_total{filter="rate",reason="Limiter"} 6
# HELP meds_core_packets_processed_total Total number of processed packets
# TYPE meds_core_packets_processed_total counter
meds_core_packets_processed_total 23536
π License
Meds is released under the MIT License.
See LICENSE for details.
π€ Contributing
Pull requests and feature suggestions are welcome!
If you find a bug, please open an issue or submit a fix.
Made with β€οΈ in Go