MCPcopy Index your code
hub / github.com/cnaize/meds

github.com/cnaize/meds @v1.2.1

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.2.1 ↗ · + Follow
456 symbols 1,329 edges 61 files 106 documented · 23%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Go Version Go Reference License: MIT Platform Version Status Go Report Card


Meds: net healing

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.

Designed to cure your network of malicious traffic


🚀 Installation

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

Download the latest binary from Releases or install via Go.

Install via Go

go install github.com/cnaize/meds/cmd/meds@latest

🧩 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 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)

Prometheus metrics

👉 http://localhost:8000/metrics

The metrics endpoint is protected by the same Basic Auth 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.


🔍 How It Works

                  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. 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.


✨ Key Features

  • 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 using NFQUEUE with balance and bypass options, 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).

  • Blocklist-based filtering

  • IP blocklists: FireHOL, Spamhaus DROP, Abuse.ch
  • ASN blocklists: Spamhaus ASN DROP using IPLocate.io for IP-to-ASN mapping
  • Domain blocklists: 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 allow/block lists.
    Auth via Basic Auth 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.


📊 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"} 12021
meds_core_packets_accepted_total{filter="empty",reason="trusted packet"} 420
meds_core_packets_accepted_total{filter="ip",reason="AllowList"} 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

📜 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

Extension points exported contracts — how you extend this code

Namer (Interface)
(no doc) [10 implementers]
src/core/filter/interfaces.go
Querier (Interface)
(no doc) [3 implementers]
src/database/querier.go
Typer (Interface)
(no doc) [7 implementers]
src/core/filter/interfaces.go
DBTX (Interface)
(no doc)
src/database/db.go
Loader (Interface)
(no doc) [20 implementers]
src/core/filter/interfaces.go
Checker (Interface)
(no doc) [7 implementers]
src/core/filter/interfaces.go
Updater (Interface)
(no doc) [11 implementers]
src/core/filter/interfaces.go

Core symbols most depended-on inside this repo

Raw
called by 39
src/core/logger/logger.go
ExecContext
called by 21
src/database/db.go
Lookup
called by 20
src/types/ip_list.go
Close
called by 20
src/database/database.go
EXPECT
called by 20
src/database/querier_mock.go
Type
called by 20
src/core/filter/interfaces.go
Load
called by 16
src/core/filter/interfaces.go
Upsert
called by 12
src/types/map_list.go

Shape

Method 251
Function 133
Struct 60
Interface 9
TypeAlias 3

Languages

Go100%

Modules by API surface

src/database/querier_mock.go64 symbols
src/database/querier.go31 symbols
src/types/packet.go20 symbols
src/api/subnets.go20 symbols
src/api/ja3.go16 symbols
src/api/domains.go16 symbols
src/api/asns.go16 symbols
src/database/includelist.sql.go12 symbols
src/database/excludelist.sql.go12 symbols
src/core/filter/interfaces.go12 symbols
src/api/countries.go12 symbols
lib/util/get/net.go11 symbols

For agents

$ claude mcp add meds \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact