meow-rs

August 10, 2026 · View on GitHub

meow-rs — a ginger cat peeking over a wall

meow-rs

A high-performance Rust implementation of the mihomo (Clash Meta) proxy kernel. Rule-based tunneling with support for multiple proxy protocols, transparent proxy, DNS snooping, a REST API, and a built-in web dashboard.

Features

Proxy Protocols

  • Shadowsocks -- TCP and UDP relay, AEAD and stream ciphers (aes-256-gcm, chacha20-ietf-poly1305, etc.)
  • Trojan -- TLS 1.2/1.3 via rustls, SNI, optional skip-cert-verify
  • Hysteria2 -- QUIC-based TCP and UDP relay, Salamander obfs, port hopping, down bandwidth auth hint, SNI, skip-cert-verify, and certificate pinning
  • VLESS -- Plain VLESS and XTLS-Vision splice; TLS, WebSocket, gRPC, H2, HTTPUpgrade transports
  • VMess -- AEAD VMess outbound with TCP/WebSocket transports
  • HTTP -- HTTP CONNECT outbound proxy with optional TLS and basic auth
  • SOCKS5 -- SOCKS5 outbound proxy with optional TLS and auth
  • Snell -- v3/v4/v5 TCP, UDP-over-TCP, optional HTTP/TLS obfs; v4/v5 connection reuse
  • AnyTLS -- AnyTLS outbound (anytls feature; in the full bundle, so the release binaries include it)
  • Direct -- Direct connection to destination
  • Reject -- Drop connections (with configurable behavior)

TLS & Privacy

  • ECH (Encrypted Client Hello) -- DNS-based ECH config fetching from HTTPS/SVCB records; BoringSSL backend (boring-tls feature)
  • uTLS Fingerprinting -- Chrome, Firefox, Safari, iOS, Android, Edge profiles to bypass TLS fingerprint detection
  • rustls default backend with optional BoringSSL for advanced features

Proxy Groups

  • Selector -- Manual proxy selection via REST API or web UI
  • URLTest -- Automatic selection based on latency with tolerance threshold
  • Fallback -- Automatic failover to first alive proxy
  • LoadBalance -- Round-robin or consistent-hashing distribution
  • Relay -- Chained proxy tunneling through multiple hops

Rule Engine

RuleExampleDescription
DOMAINDOMAIN,google.com,ProxyExact domain match
DOMAIN-SUFFIXDOMAIN-SUFFIX,google.com,ProxyDomain and subdomains
DOMAIN-KEYWORDDOMAIN-KEYWORD,google,ProxySubstring match
DOMAIN-REGEXDOMAIN-REGEX,^ads?\.,ProxyRegex pattern
DOMAIN-WILDCARDDOMAIN-WILDCARD,*.example.com,ProxyWildcard domain pattern
IP-CIDRIP-CIDR,10.0.0.0/8,DIRECT,no-resolveDestination IP range
IP-SUFFIXIP-SUFFIX,0.0.0.1/8,ProxyDestination IP suffix bits
SRC-IP-CIDRSRC-IP-CIDR,192.168.0.0/16,DIRECTSource IP range
SRC-GEOIPSRC-GEOIP,CN,DIRECTSource GeoIP lookup
IP-ASNIP-ASN,15169,ProxyDestination ASN lookup
DST-PORTDST-PORT,80,443,8080,ProxyDestination port(s)
SRC-PORTSRC-PORT,1234,DIRECTSource port(s)
NETWORKNETWORK,udp,ProxyTCP or UDP
PROCESS-NAMEPROCESS-NAME,curl,DIRECTProcess name
PROCESS-PATHPROCESS-PATH,/usr/bin/curl,DIRECTProcess path
GEOIPGEOIP,CN,DIRECT,no-resolveMaxMind GeoIP lookup
GEOSITEGEOSITE,cn,DIRECTMetaCubeX .mrs geosite database
RULE-SETRULE-SET,ads,REJECTRule provider lookup
DSCPDSCP,46,ProxyIP DSCP field
IN-PORTIN-PORT,7890,ProxyInbound listener port
IN-NAMEIN-NAME,mixed,ProxyInbound listener name
IN-TYPEIN-TYPE,SOCKS5,ProxyInbound listener protocol
IN-USERIN-USER,alice,ProxyAuthenticated inbound user
UIDUID,1000,DIRECTProcess UID (Linux)
SUB-RULESUB-RULE,LOCAL-BYPASSNamed rule subset
MATCHMATCH,ProxyCatch-all fallback

Logic composition rules (AND, OR, NOT) are also supported for combining conditions.

DNS

  • UDP DNS server with configurable listen address
  • Main + fallback nameserver groups
  • Response caching and in-flight request deduplication
  • DNS snooping -- reverse IP→domain lookup table for transparent proxy hostname recovery

Inbound Listeners

  • Mixed -- Auto-detects HTTP or SOCKS5 on a single port
  • HTTP Proxy -- HTTP CONNECT and plain HTTP forwarding
  • SOCKS5 -- SOCKS5 with optional authentication
  • Transparent Proxy (TProxy) -- Kernel-level traffic interception via nftables (Linux) or pf (macOS)

Transparent Proxy

Intercept all local TCP traffic at the kernel firewall level without per-app proxy configuration.

  • nftables redirect on Linux, pf anchor on macOS
  • Loop avoidance: SO_MARK on outbound DIRECT sockets (Linux), UID-based bypass (macOS), plus IP bypass for upstream proxy servers
  • SNI extraction: Peek at TLS ClientHello to recover hostname for HTTPS traffic
  • DNS snooping: Reverse IP→domain lookup from recent DNS queries for non-TLS traffic
  • RAII firewall guard: Rules automatically cleaned up on shutdown (SIGINT/SIGTERM)
  • Configurable via tproxy-port, routing-mark, and tproxy-sni in YAML

The built-in firewall transparently proxies the host's own traffic. To build a LAN gateway that forwards and proxies other devices' traffic, see docs/tproxy-gateway.md.

Web Dashboard

Built-in web UI served at http://<api-addr>/ui with:

  • Overview -- Mode selector, listening ports, live traffic stats
  • Proxies -- Click-to-switch selector groups, view all proxy group members
  • Subscriptions -- Add/refresh/delete Clash YAML subscription URLs (auto-cached to disk)
  • Proxy Groups -- Create/edit/delete selector, url-test, fallback groups
  • Rules -- Add/delete/reorder rules with drag-and-drop, search/filter

Subscription Management

  • Fetch and import Clash YAML subscriptions (proxies, groups, rules)
  • Auto-save to disk -- cached data loads on restart without re-fetching
  • Background refresh on configurable intervals
  • Multi-pass group resolution for inter-group references

REST API

EndpointMethodDescription
/GETGreeting ({"hello":"meow"})
/versionGETVersion info
/proxiesGETList all proxies
/proxies/{name}GET/PUT/DELETEGet, switch, or unfix proxy
/proxies/{name}/delayGETRun an on-demand delay probe
/groupGETList proxy groups
/group/{name}GETGet group detail
/group/{name}/delayGETRun a group delay probe
/rulesGET/POST/PUTList, replace, or update rules
/rules/{index}DELETEDelete rule at index
/rules/reorderPOSTReorder rules
/connectionsGET/DELETEActive connections (GET also supports WS upgrade)
/connections/{id}DELETEClose a connection
/configsGET/PATCH/PUTGet config, patch mode, or reload config
/trafficGETUpload/download statistics (also supports WS upgrade)
/logsGETRuntime log stream (HTTP streaming or WS upgrade)
/memoryGETRuntime memory stream (HTTP streaming or WS upgrade)
/metricsGETPrometheus metrics
/dns/queryGET/POSTDirect DNS query
/dns/resultsGETDNS cache dump (?search=, ?limit=)
/cache/dns/flushPOSTFlush DNS cache
/cache/fakeip/flushPOSTFlush fake-IP mappings
/listenersGETList configured named listeners
/providers/proxiesGETList proxy providers
/providers/proxies/{name}GET/PUTGet or refresh a proxy provider
/providers/proxies/{name}/healthcheckGETRun provider health check
/providers/proxies/{provider}/{proxy}GETGet a specific proxy in a provider
/providers/proxies/{provider}/{proxy}/healthcheckGETRun health check for a specific proxy
/providers/rulesGETList rule providers
/providers/rules/{name}GET/PUTGet or refresh a rule provider
/api/config/savePOSTSave running config to disk
/api/subscriptionsGET/POSTList or add subscriptions
/api/subscriptions/{name}DELETEDelete subscription
/api/subscriptions/{name}/refreshPOSTRefresh subscription
/api/proxy-groupsGET/POSTList or create proxy groups
/api/proxy-groups/{name}PUT/DELETEUpdate or delete proxy group
/api/proxy-groups/{name}/selectPUTSwitch selector proxy
/uiGETWeb dashboard

Tunnel

  • Three routing modes: Rule, Global, Direct
  • Bidirectional TCP relay and UDP NAT session tracking
  • Per-connection traffic statistics with connection lifecycle management

Benchmarks

Side-by-side against upstream Go mihomo v1.19.27 on the same host (Apple Silicon arm64, macOS 26.4.1, loopback 127.0.0.1). Both binaries use identical config: mode: direct, SOCKS5 listener on port 17890, DNS disabled. Reproduce with bash bench.sh (auto-downloads the latest Go mihomo release).

Metricmihomo (Go)meow-rs v0.14.0Delta
Binary size (stripped)40.7 MB7.2 MB−82%
RSS idle30.8 MB9.7 MB−69%
RSS under load (peak)30.8 MB9.7 MB−69%
TCP throughput, 64 MB×15.15 Gbps5.23 Gbps+2%
TCP throughput, 1 MB×104.62 Gbps4.15 Gbps−10%
TCP throughput, 4 KB×100000.92 Gbps0.90 Gbps−2%
Latency p50 (connect + 1 B echo)257 µs258 µs±0%
Latency p99332 µs354 µs+7%
Connections/sec (10 s, concurrency 64)709 /s710 /s±0%

Single-run results from bash bench.sh; numbers will vary with host load. For the full methodology, three-run-median protocol, and workload definitions (W1–W5), see ADR-0006 and docs/benchmarks/index.md.

Architecture

flowchart TD
    inbound["Inbound listeners<br/>Mixed / HTTP / SOCKS5 / TProxy"] --> tunnel["Tunnel<br/>routing, relay, connection stats"]
    api["REST API + Web UI<br/>Axum"] --> tunnel
    api --> runtime["Runtime state<br/>config, subscriptions, proxy groups, rules"]
    runtime --> tunnel
    tunnel <--> dns["DNS resolver<br/>cache, fake-IP, policy, snooping"]
    tunnel --> rules["Rule engine<br/>linear / indexed / IR matchers"]
    rules --> outbounds["Proxy adapters and groups<br/>SS, Trojan, VLESS, VMess, Snell, Hysteria2, Direct, Reject"]
    outbounds --> remote["Remote server / DIRECT"]

11 workspace crates with clear separation of concerns:

CratePurpose
meow-commonCore traits and types (ProxyAdapter, Rule, Metadata)
meow-trieDomain trie for efficient pattern matching
meow-transportTLS (rustls + BoringSSL), WebSocket, gRPC, H2, HTTPUpgrade layers
meow-proxyProxy protocol implementations and groups
meow-rulesRule matching engine and parser
meow-dnsDNS resolver, cache, DNS snooping, server
meow-tunnelCore routing, TCP/UDP relay, statistics
meow-listenerInbound protocol handlers (Mixed/HTTP/SOCKS5/TProxy)
meow-configYAML configuration parsing, subscription fetcher, config persistence
meow-apiREST API (Axum) + embedded web UI
meow-appCLI entry point

Quick Start

Build

Requires Rust 1.88+ (the workspace pins rust-version = "1.88" and CI enforces it via a dedicated MSRV job).

cargo build --release

Run

# Copy the example config and edit it
cp config.example.yaml config.yaml
# Edit config.yaml with your proxy servers...

# Run
./target/release/meow -f config.yaml

# Test config validity
./target/release/meow -f config.yaml -t

Install as system service

Linux (systemd):

sudo ./target/release/meow install -f /path/to/config.yaml

# Manage the service
sudo systemctl status meow
sudo systemctl restart meow
sudo journalctl -u meow -f

# Uninstall
sudo ./target/release/meow uninstall

Windows (Service Control Manager):

Open PowerShell as Administrator, then run:

# Install, enable automatic startup, and start the service
.\target\release\meow.exe install -f 'C:\path\to\config.yaml'

# Optional: pin the meow resource/cache home explicitly. The global -d flag
# must appear before the install subcommand.
.\target\release\meow.exe -d 'D:\meow-data' install -f 'C:\path\to\config.yaml'

# Check status
.\target\release\meow.exe status
Get-Service meow

# Manage the service
Stop-Service meow
Start-Service meow
Restart-Service meow

# List the daily rolling logs (the seven newest files are retained)
Get-ChildItem "$env:ProgramData\meow\logs\meow.*.log"

# Follow the newest log
$log = Get-ChildItem "$env:ProgramData\meow\logs\meow.*.log" |
  Sort-Object LastWriteTime | Select-Object -Last 1
Get-Content $log.FullName -Wait

# Uninstall
.\target\release\meow.exe uninstall

Installation keeps using the configuration file at the path passed to -f, starts the service immediately, and configures it to start automatically with Windows. A relative -f follows the same rule as a direct run: it is resolved under -d when a home directory is given, otherwise under the current directory. Running install again updates the registered binary/configuration and restarts the service. When -d is omitted, the installer resolves and records the same default meow home used by a normal CLI launch (for example, E:\test\meow when launched from E:\test); the selected path is printed as Home after installation. The service runs as LocalSystem, so that account must have read/write access to the configuration path and the selected Home. After upgrading from an older service build, run install again to refresh the SCM launch arguments. Uninstalling preserves both the configuration and the logs.

Security notes:

  • The service executes the binary at its install-time location as LocalSystem on every boot. Copy meow.exe to a directory writable only by administrators (for example, C:\Program Files\meow) and run install from there, rather than registering a binary inside a user-writable directory.
  • %ProgramData%\meow\logs inherits the default ProgramData ACLs, so log files (which include destination hosts of proxied connections) are readable by all local users. Tighten the ACL on %ProgramData%\meow if that matters on a shared machine.

macOS (launchd user agent):

./target/release/meow install -f /path/to/config.yaml

# Config is copied to ~/Library/Application Support/meow/config.yaml
# Logs are written to ~/Library/Logs/meow/

# Check status
./target/release/meow status

# View logs
tail -f ~/Library/Logs/meow/meow.log

# Uninstall
./target/release/meow uninstall

OpenWrt (opkg + LuCI):

Official .ipk packages for arm/aarch64 routers — including a luci-app-meow that embeds the built-in web panel in LuCI — are attached to every release. See docs/openwrt.md.

Open the Web UI

After starting, open your browser to:

http://127.0.0.1:9090/ui

From the Subscriptions tab you can add a Clash subscription URL to import proxies, groups, and rules automatically.

Use the Proxy

# HTTP proxy
curl --proxy http://127.0.0.1:7890 https://ipinfo.io

# SOCKS5 proxy
curl --proxy socks5://127.0.0.1:7890 https://ipinfo.io

# Set as system proxy (macOS)
export https_proxy=http://127.0.0.1:7890
export http_proxy=http://127.0.0.1:7890

Example Configuration

mixed-port: 7890
mode: rule
log-level: info

# Transparent proxy (requires root/sudo)
# tproxy-port: 7893
# tproxy-sni: true
# routing-mark: 9527

external-controller: 127.0.0.1:9090

dns:
  enable: true
  listen: 127.0.0.1:1053
  nameserver:
    - 8.8.8.8
  fallback:
    - 8.8.4.4

proxies:
  - name: my-ss
    type: ss
    server: 1.2.3.4
    port: 8388
    cipher: aes-256-gcm
    password: "secret"
    udp: true

  - name: my-trojan
    type: trojan
    server: 5.6.7.8
    port: 443
    password: "secret"
    sni: example.com
    skip-cert-verify: false

  - name: my-snell
    type: snell
    server: ss.example.com
    port: 8443
    psk: "your-psk"
    version: 3
    udp: true
    obfs-opts:
      mode: http
      host: /

  - name: my-hy2
    type: hysteria2
    server: hy2.example.com
    port: 443
    ports: "443,8443-8445"
    hop-interval: 30
    password: "secret"
    sni: hy2.example.com
    skip-cert-verify: false
    udp: true
    up: "100 Mbps"
    down: "100 Mbps"
    obfs: salamander
    obfs-password: "obfs-secret"

proxy-groups:
  - name: Proxy
    type: select
    proxies: [my-ss, my-trojan, my-snell, my-hy2]

  - name: Auto
    type: url-test
    proxies: [my-ss, my-trojan, my-snell, my-hy2]
    url: http://www.gstatic.com/generate_204
    interval: 300

rules:
  - DOMAIN-SUFFIX,local,DIRECT
  - IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - DOMAIN-SUFFIX,google.com,Proxy
  - MATCH,Proxy

See config.example.yaml for a full annotated example.

Testing

# All unit tests
cargo test --lib

# Rules tests (78 tests covering all rule types)
cargo test --test rules_test

# API and config persistence tests (54 tests)
cargo test --test api_test
cargo test --test config_persistence_test

# Trojan integration tests (embedded mock server, no external deps)
cargo test --test trojan_integration

# Hysteria2 Docker integration tests (requires Docker)
MEOW_REQUIRE_DOCKER=1 cargo test -p meow-proxy --features hysteria2 --test hysteria2_integration -- --nocapture

# Shadowsocks integration tests (requires ssserver)
cargo install shadowsocks-rust --features "stream-cipher aead-cipher-2022" --locked
cargo test --test shadowsocks_integration

# Transparent proxy end-to-end tests (requires Docker)
bash tests/test_tproxy_qemu.sh

License

MIT — Copyright (c) 2026 Max Lv. See LICENSE.