CLAUDE.md · diff
git:20261103.19af490 to git:20261105.09c2adc
3 added, 0 removed. Audit A to A.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
meow-rs is a Rust implementation of the [mihomo](https://github.com/MetaCubeX/mihomo) (Clash Meta) proxy kernel. It provides rule-based tunneling with support for multiple proxy protocols (Shadowsocks, Trojan, Direct, Reject), transparent proxy (nftables/pf), DNS with snooping (IP→domain reverse table), and a REST API for runtime control. Licensed under MIT.
## Build Commands
```bash
# Build (requires Rust 1.89+ via workspace rust-version; the checkout
# resolves the pinned channel in rust-toolchain.toml automatically)
cargo build --release
# Run with config
./target/release/meow -f config.yaml
# Test config validity
./target/release/meow -f config.yaml -t
# Control the running meow over its REST API (`meow-cli --help`); it finds
# the meow running as this user through the file meow publishes at startup
./target/release/meow-cli status
# Run all unit tests
cargo test --lib
# Run specific integration/test suites
cargo test --test rules_test # 100 rule matching tests
cargo test --test trojan_integration # embedded mock server, no external deps
cargo test --test shadowsocks_integration # requires ssserver (see below)
bash tests/test_tproxy_docker.sh # Docker-based tproxy e2e tests
# Install ssserver for SS integration tests
cargo install shadowsocks-rust --features "stream-cipher aead-cipher-2022" --locked
# Run tests for a single crate
cargo test -p meow-dns --lib
# Lint
cargo clippy --all-targets
```
## Architecture
```
Listeners (HTTP/SOCKS5/Mixed/TProxy/TUN)
|
v
Tunnel (routing engine) <--> DNS Resolver (Snooping/Cache/FakeIP)
| ^
Rule Matching Engine |
| DNS Server (:1053)
v
Proxy Adapters / Groups ---> Transport (TLS/WS/gRPC/H2/ECH) ---> Remote
^
| (periodic probes)
Health Check Task
REST API + Web UI (Axum) ---> Runtime control
Subscription Refresh ---> Auto-update proxy lists
```
### Workspace Crates
The workspace has 15 crates (see also [ADR-0009](docs/adr/0009-cleanup-scope.md) for crate-boundary policy):
| Crate | Purpose |
|-------|---------|
| `meow-common` | Core traits and types (`ProxyAdapter`, `Rule`, `Metadata`, `ConnContext`) — the "contracts" crate |
| `meow-trie` | Domain trie for efficient pattern matching |
| `meow-anytls` | Vendored fork of `anytls-rs` (lib name `anytls_rs`); MIT-licensed, in-tree to provide `Stream::close()` (see [#262](https://github.com/madeye/meow-rs/issues/262)). Pulled in only by `meow-proxy`'s opt-in `anytls` feature |
| `meow-lwip` | Vendored fork of `lwip` (madeye/lwip); MIT/Apache-2.0 bindings over BSD-3 lwIP C sources, in-tree because crates.io forbids `git` deps. Lib name `lwip`; pulled in only by `meow-listener`'s `listener-tun` feature |
| `meow-transport` | Composable stream-transport layers (TLS, WebSocket, gRPC, HTTP/2, HTTP Upgrade) — protocol-agnostic, no dep on other meow-rs crates (see [ADR-0001](docs/adr/0001-meow-transport-crate.md)) |
| `meow-proxy` | Proxy protocol implementations (SS, Trojan, VLESS, Direct, Reject), groups (Selector, URLTest, Fallback, LoadBalance, Relay), and health probing |
| `meow-rules` | Rule matching engine and parser (domain, IP-CIDR, GeoIP, process, logic composition) |
| `meow-dns` | DNS resolver, cache, DNS snooping (IP→domain reverse table), UDP server |
| `meow-tunnel` | Core routing engine: TCP/UDP relay, rule matching dispatch, connection statistics |
| `meow-listener` | Inbound protocol handlers (Mixed/HTTP/SOCKS5/TProxy, plus TUN behind the opt-in `listener-tun` feature) |
| `meow-config` | YAML configuration parsing into typed structs |
| `meow-api` | REST API server (Axum) for proxies, rules, connections, configs, traffic, DNS query |
| `meow-app` | CLI entry point (`main.rs`) — wires config → tunnel → listeners → DNS → API → health checks → subscription refresh |
| `meow-cli` | `meow-cli` binary: controls a running meow over its REST API (plain HTTP client; of the engine crates it links only `meow-common`, for `controller_file`, the 0600 file meow writes once its `external-controller` is bound and meow-cli reads to find it with no options); ships its agent skill at `skills/meow-cli/SKILL.md`, which the desktop release archives carry as `skills/meow-cli/` (`desktop: true` in `build.yml`). Unpublished: the crates.io name belongs to an unrelated crate |
| `meow-bench` | Standalone benchmark binary (throughput, latency, connection-rate, DNS, memory, binary-size, config-reload, idle/steady footprint, proxied-outbound via sing-box) |
### Startup Flow
`meow-app/src/main.rs` → parse CLI args → `meow_config::load_config()` → create `Tunnel` → spawn health checks for fallback/url-test groups → spawn DNS server, API server, listeners (Mixed/SOCKS/HTTP/TProxy) as tokio tasks → await SIGINT/SIGTERM.
### Transparent-proxy gateway
The built-in TProxy listener firewall (`meow-listener/src/tproxy/firewall.rs`) is `output`-chain/REDIRECT-based and only covers the **host's own** traffic — it is *not* a forwarding LAN gateway. To proxy *other* devices' traffic you add prerouting rules + a DNS hijack yourself. Helper scripts automate this: `scripts/tproxy-gateway-linux.sh` (nftables) and `scripts/tproxy-gateway-macos.sh` (pf, experimental). Full setup, DNS-mode (fake-ip vs redir-host) trade-offs, and systemd wiring are in [docs/tproxy-gateway.md](docs/tproxy-gateway.md). macOS *local* tproxy (managed pf anchor + manual `route-to lo0` for real outbound traffic, IPv4 TCP only) is documented in [docs/tproxy-macos.md](docs/tproxy-macos.md). Note: the top-level `tproxy-port` hard-binds `127.0.0.1`; a gateway must declare the listener via `listeners:` with a non-loopback `listen`.
A `tproxy` listener can opt into **UDP TPROXY** (`udp: true`, Linux/IPv4 only, requires `firewall: false` since the deployer owns the `prerouting` TPROXY rules + policy routing): `meow-listener/src/tproxy/udp.rs` recovers the original destination via `IP_RECVORIGDSTADDR` cmsg, keys flows on `(client, orig_dst)` — so fake-IP replies keep the fake-IP source identity — and replies from per-destination `IP_TRANSPARENT` sockets. `udp-timeout` bounds idle flows; `max-connections` bounds flow count (`0` = unlimited). A `listeners:` tproxy entry also accepts `firewall: false` (issue #563) to delegate all rule management to an external system — meow installs/probes/removes nothing and only accepts the REDIRECT'd TCP.
### TUN inbound (Windows transparent proxy)
The `tun:` config section (issue #326, feature `listener-tun`, in the `full` bundle) provides transparent proxying via an L3 device — the only transparent option on Windows, also usable on Linux/macOS. Implementation: `meow-listener/src/tun/` (tun-rs device + lwIP userspace stack + route_manager auto-route). On Windows the device is Wintun (`wintun.dll` sidecar or the official DLL embedded in the binary). `auto-route: true` (the default; `global` is an alias) captures everything the host sends on Linux/macOS/Windows, with meow's own sockets bound to the physical interface against loops (`OutboundBinding`); on Linux the device's default routes sit in a table of their own behind policy rules that only take the host's own unsourced flows (`tun/policy_route.rs`, priorities 9200-9205), so replies to accepted connections and forwarded traffic keep the main table, elsewhere (and on a kernel without policy routing) split `/1` routes go in the main table. `auto-route: fake-ip` routes only the fake-ip range, loop-free by construction but blind to IP literals. `dns-hijack` defaults on (`[]` turns it off). TCP accept is post-handshake; a flow then gets a 200 ms sniff window for the client's first bytes (the relay prefix) — silence dials with an empty prefix (server-first protocols, #695), while EOF/RST inside the window drops the flow before `handle_tcp`; UDP is one packet-level netstack socket demuxed by a listener-owned flow table (per-flow tasks mirroring the SOCKS5-UDP routing, idle-evicted after `udp-timeout`); `dns-hijack` answers UDP :53 via `DnsServer::handle_query`. Setup guide: [docs/tun.md](docs/tun.md).
### Key Patterns
- **`ProxyAdapter` trait** (`meow-common/src/adapter.rs`) — all proxy protocols implement this async trait for TCP connect and UDP relay
- **`Rule` trait** (`meow-common/src/rule.rs`) — all rule types implement this for matching against `Metadata`
- **Proxy groups** (`meow-proxy/src/group/`) — Selector, URLTest, Fallback wrap multiple adapters with selection strategies
- **Tunnel** (`meow-tunnel/src/tunnel.rs`) — central `Arc`-shared routing engine; holds proxies, rules, DNS resolver, connection stats
- **Logbook** (`meow-common/src/logbook/`) — persistent record of notable engine events (`GET /logbook`), an SQLite database behind the `logbook` feature (`rusqlite`, bundled except on iOS/tvOS, which link the system libsqlite3; in `full`, not `minimal`, where `disabled.rs` stands in); producers call `logbook::event(kind, level, message).subject(..).record()`, a no-op when none is installed. New kinds go in `logbook::kind` and the [ADR-0014](docs/adr/0014-logbook.md) table; never record traffic destinations, and reference rules by index
- **Traffic ledger** (`meow-common/src/traffic_ledger/`) — per-day bytes and connections by host (registrable domain), leaf policy and interface label, kept 62 days in `<home>/traffic/traffic.db` (`GET|DELETE /traffic/ledger`, [ADR-0015](docs/adr/0015-traffic-ledger.md)); behind the `traffic-ledger` feature (in `full`, not `minimal`). The relay path never touches it: a flow's `ConnCounters` carry a `LedgerTag`, and the tunnel (a `traffic_ledger::Source`) settles live flows every minute and at close. Unlike the logbook it records destinations, deliberately
### Adding New Proxy Protocols
1. Implement `ProxyAdapter` trait in a new file under `meow-proxy/src/`
2. Add the adapter type variant to `AdapterType` enum in `meow-common/src/adapter_type.rs`
3. Register parsing in `meow-config/src/lib.rs` proxy config section
### Adding New Rule Types
1. Implement `Rule` trait in `meow-rules/src/`
2. Add the rule type variant to `RuleType` enum in `meow-common/src/rule.rs`
3. Register parsing in `meow-rules/src/parser.rs`
## Lint Policy
Workspace-wide clippy lints are declared in the root `Cargo.toml` `[workspace.lints.clippy]` table; every member crate opts in via `[lints] workspace = true`. See [ADR-0010](docs/adr/0010-m1-hygiene-and-gates.md) for the full rationale and [ADR-0010 Addendum A](docs/adr/0010-m1-hygiene-and-gates-addendum.md) for the allocation-focused additions.
Curated lint set (all `warn` unless noted):
**Readability / style** — `uninlined_format_args`, `redundant_closure`, `redundant_closure_for_method_calls`, `redundant_clone`, `cloned_instead_of_copied`, `manual_let_else`, `map_unwrap_or`, `semicolon_if_nothing_returned`, `explicit_iter_loop`, `needless_pass_by_value`, `match_same_arms`, `if_not_else`, `unnecessary_wraps`
**Allocation / footprint** (addendum A1, feeds M2 baseline) — `clone_on_ref_ptr`, `needless_collect`, `format_push_string`, `string_add`, `useless_format`, `large_enum_variant`, `large_types_passed_by_value`, `unnecessary_box_returns`, `vec_init_then_push`
Explicitly suppressed workspace-wide (too noisy without benefit): `module_name_repetitions`, `struct_excessive_bools`, `too_many_lines`, `missing_errors_doc`, `missing_panics_doc`.
When a specific site cannot be fixed cleanly, use `#[allow(clippy::lint_name, reason = "…")]` inline — no silent allows.
## Regression Bar
The toolchain is pinned by `rust-toolchain.toml` (issue #533) — rustup
resolves it automatically in the checkout, so the bar below runs on the
same version as CI. Bump the pin deliberately (see the file's header); a
weekly `toolchain-drift` workflow canaries the next stable.
Run before every commit and push:
```bash
cargo fmt --all -- --check
cargo clippy --all-targets -- -D warnings
cargo clippy --all-targets --no-default-features -- -D warnings
cargo clippy --all-targets --all-features -- -D warnings
# `minimal` leaves out `logbook` and `traffic-ledger`, which every run above
# unifies on; their stubs (`logbook/disabled.rs`, `traffic_ledger/disabled.rs`)
# only compile here.
cargo clippy -p meow-common --all-targets -- -D warnings
cargo test -p meow-common --lib -- logbook traffic_ledger
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps
cargo test -p meow-listener --all-features --lib udp_port_53
# The `anytls` feature is opt-in in meow-proxy — the adapter's uot/desync
# tests never compile under its default features.
cargo test -p meow-proxy --features anytls --lib
+ # DNS over QUIC / DoH3 are behind `dns-quic`; the peer is an in-process quiche
+ # server, so this suite needs no network.
+ cargo test -p meow-dns --features quic-dns --test quic_dns_integration
# TrustTunnel is opt-in; its wire tests and parser/adapter integration need
# explicit feature runs, including the disabled-feature parser contract.
cargo test -p meow-proxy --no-default-features --features trusttunnel --lib trusttunnel
cargo test -p meow-proxy --no-default-features --features trusttunnel --test trusttunnel_integration
cargo test -p meow-proxy --no-default-features --features trusttunnel --test trusttunnel_e2e
cargo test -p meow-config --features trusttunnel --test trusttunnel_config_test
cargo test -p meow-config --no-default-features --test trusttunnel_config_test
cargo test -p meow-api --features meow-config/trusttunnel --test api_test trusttunnel_provider
# `trusttunnel-h3` (the `quic: true` transport) is a second opt-in feature on
# top: the quiche driver, its in-tree HTTP/3 peer tests, the official
# endpoint's `[listen_protocols.quic]` interop leg and the `quic:` parser
# contract never compile under the runs above.
cargo test -p meow-proxy --no-default-features --features trusttunnel-h3 --lib trusttunnel
cargo test -p meow-proxy --no-default-features --features trusttunnel-h3 --test trusttunnel_e2e
cargo test -p meow-config --features trusttunnel-h3 --test trusttunnel_config_test
cargo test -p meow-config --features trusttunnel-h3 --lib
# The official TrustTunnel test peer is required for the e2e target.
# Fetch with `bash scripts/fetch-trusttunnel-endpoint.sh /tmp/meow-tt-peer`,
# then export TRUSTTUNNEL_SERVER_BIN=/tmp/meow-tt-peer/trusttunnel_endpoint.
# MEOW_TRUSTTUNNEL_E2E_ALLOW_SKIP=1 prints a loud local-only skip; CI rejects it.
# `ss`-only meow-config: locks the "reserved plugin names never fall back
# to the external spawn path" contract and the compiled-out-name dead-
# placeholder pins (they compile only in this feature set); mirrors the
# CI leg "meow-config ss-only unit tests" in the features job. The
# meow-proxy leg underneath pins the adapter-side reserved-name guard.
cargo test -p meow-config --no-default-features --features ss --lib
cargo test -p meow-proxy --no-default-features --features ss --lib
# Mirrors the "Unit + integration tests (default features)" CI step. `--lib`
# alone is not enough: it skips every `--test` target, so a broken integration
# test (e.g. the ADR-0001 guard in `crate_invariants_test`) passes locally and
# lands `main` red.
cargo test --lib --bin meow --bin meow-bench --bin meow-cli \
--test socks5_udp_user --test ss_listener_integration --test host_validation \
--test direct_udp_binding \
--test common_test --test dns_cache_test --test config_test \
--test tun_config_test --test dialer_proxy_group \
--test statistics_test --test rules_test --test api_test --test meow_cli_test \
--test raii_guard_test --test http_connection_close \
--test config_persistence_test --test systemd_config_test \
--test launchd_config_test \
--test trojan_integration --test vless_config_test --test vless_integration \
--test v2ray_plugin_integration --test gost_plugin_integration \
--test shadow_tls_test --test restls_e2e --test jls_e2e --test kcptun_e2e --test pre_resolve_test \
--test offline_config_test \
--test subscription_refresh_test \
--test tls_test --test boring_tls_test --test ws_test --test crate_invariants_test \
--test crate_publish_metadata_test \
--test yaml_backend_test \
--test yaml_boundary_test \
--test smux_singbox_integration
# `-p meow-api` builds api_test WITHOUT `listener-tun` (meow-app's `full`
# never enters the graph), so the `cfg(not(feature = "listener-tun"))`
# TUN-reconcile tests actually execute — the unified invocation above
# compiles them out via feature unification.
cargo test -p meow-api --test api_test
```
`direct_udp_binding` installs the TUN outbound-interface binding only when
`MEOW_TEST_OUTBOUND_INTERFACE` names the default-route interface (CI sets
it; locally e.g. `MEOW_TEST_OUTBOUND_INTERFACE=$(route -n get default |
awk '/interface:/ {print $2}')` on macOS) — unset, it passes without
exercising the regression and says so on stderr.
`smux_singbox_integration` runs the full stack (config → mixed listener →
tunnel → VLESS adapter + smux) against a real sing-box server and **fails**
(never silently skips) when the binary is missing: install the pinned
version from https://github.com/SagerNet/sing-box/releases or point
`SINGBOX_BIN` at it. `MEOW_SMUX_E2E_ALLOW_SKIP=1` prints a loud explicit
skip for local runs only — CI must never set it.
`restls_e2e`'s upstream-interop leg drives the tagged-record wire protocol
against a real upstream peer (`metacubex/restls-client-go`'s
`RestlsServer`) and likewise **fails** when `RESTLS_SERVER_BIN` is unset —
build the harness from
`crates/meow-transport/tests/support/restls-server` (`go build -o
restls-server .`); `MEOW_RESTLS_E2E_ALLOW_SKIP=1` prints a loud explicit
skip for local runs only — CI builds the harness via `actions/setup-go`
and never sets it.
`jls_e2e`'s upstream-interop leg drives the authenticated TLS 1.3
handshake and data path against a real upstream peer
(`metacubex/jls-tls`'s `JlsServer`) and likewise **fails** when
`JLS_SERVER_BIN` is unset — build the harness from
`crates/meow-transport/tests/support/jls-server` (`go build -o
jls-server .`); `MEOW_JLS_E2E_ALLOW_SKIP=1` prints a loud explicit
skip for local runs only — CI builds the harness via `actions/setup-go`
and never sets it.
`kcptun_e2e` drives the full SS → smux → snappy → KCP → crypt/FEC stack
against a real upstream Go peer (kcp-go + xtaci/smux + go-shadowsocks2).
Every leg is real-peer, so the suite **fails** when `KCPTUN_SERVER_BIN`
is unset — build the harness from
`crates/meow-proxy/tests/support/kcptun-server` (`go build -o kcptun-server .`);
`MEOW_KCPTUN_E2E_ALLOW_SKIP=1` prints a loud explicit skip for local runs
only — CI builds the harness via `actions/setup-go` and never sets it.
`v2ray_plugin_integration` runs `ssserver` with an official v2ray-plugin
release as its server plugin (default options, so Mux.Cool, plus `mux=0`
legs) and **fails** when `V2RAY_PLUGIN_BIN` is unset — fetch the pinned
release with `bash scripts/fetch-v2ray-plugin.sh /tmp/meow-v2rp` and export
`V2RAY_PLUGIN_BIN=/tmp/meow-v2rp/v2ray-plugin` (`ssserver` must be on
`PATH`); `MEOW_V2RAY_PLUGIN_E2E_ALLOW_SKIP=1` prints a loud explicit skip
for local runs only — CI fetches it the same way and never sets it.
Keep the target list in sync with `.github/workflows/test.yml`; a new `tests/`
file that CI runs but this list omits is invisible to the local bar.
The three-way clippy check (default / no-default-features / all-features) is enforced in CI via `.github/workflows/test.yml` (added in M1, per ADR-0010 §3).
M1 exit integration gates (run before closing M1):
```bash
cargo test --test rules_test
cargo test --test trojan_integration
cargo test --test shadowsocks_integration
```
Docker-based tproxy Docker test (`bash tests/test_tproxy_docker.sh`) is CI-only; do not block local work on it.
## Architecture Invariants
These invariants apply to any PR that touches the listed types or subsystems. A PR that violates them must include an ADR amendment or a measured justification in the commit body.
### Footprint / performance axes (ADR-0006, -0007, -0008, -0011)
Four ADRs define the quantitative bar for this codebase:
| ADR | Axis | Gate |
|-----|------|------|
| [ADR-0006](docs/adr/0006-performance-targets.md) | Throughput + latency (W1–W5 workloads) | Median ≥ 0.98× baseline at M2 open |
| [ADR-0007](docs/adr/0007-binary-size-caps.md) | Stripped binary size | Hard caps by profile + target; no breach |
| [ADR-0008](docs/adr/0008-zero-alloc-invariants.md) | Hot-path allocation count | HP-1/HP-2/HP-3 reproducers never increase |
| [ADR-0011](docs/adr/0011-m2-footprint-targets.md) | Key-type struct sizes | Per-type targets; byte delta mandatory in commit body |
Any PR touching these types **must** include before/after byte counts (from `-Zprint-type-sizes`) in the commit body:
- `Metadata` (`crates/meow-common/src/metadata.rs`) — M2 baseline 272 B struct / heap via SmolStr
- `ConnectionInfo` (`crates/meow-tunnel/src/statistics.rs`) — M2 exit 120 B
- `UdpSession` (`crates/meow-tunnel/src/udp.rs`) — M2 exit 40 B
- DNS `CacheEntry` / `ReverseEntry` (`crates/meow-dns/src/cache.rs`) — M2 exit 72 B per `CacheEntry` (the LRU `.val`; full `LruEntry` slot incl. key + links is ~104 B on macOS)
Any PR touching relay code (`crates/meow-tunnel/src/relay.rs`, `tcp.rs`, or call sites in `meow-listener`) must preserve the zero-per-relay-setup-allocation invariant: relay buffers are stack-allocated in the caller's async frame, not heap-allocated per call.
### Rule-engine footprint (docs/benchmarks/rule-engine-footprint-2026-09.md)
The rule matching module is sized for large rule-sets on small devices; keep these properties when touching it:
- **Sealed `DomainTrie`** (`crates/meow-trie/src/trie.rs`) is a flat breadth-first arena: 8 B per node, one deduplicated `.`-terminated label arena, four heap allocations total. Do not reintroduce per-node heap objects; rule-set / geosite / domain-index tries must be sealed after build.
- **IP range matching** (`crates/meow-rules/src/ip_set.rs`) is `IpRangeSet`: sorted coalesced intervals, 8 B per IPv4 interval. GEOIP / IP-ASN / ipcidr rule-sets share one `Arc<IpRangeSet>` per country / ASN / provider. Do not add the `iprange` crate back.
- **Rules own one heap block each**: adapter names are interned `Arc<str>` (`crates/meow-rules/src/adapter.rs`), payloads are inline `SmolStr`.
- **Compiled IR slots** stay at ≤ 40 B / `RuleOp` ≤ 24 B (unit test `compiled_slot_stays_compact` in `rule_ir.rs`); a hit borrows the payload from the source rule rather than copying it into the slot.
- **`.mrs` loaders stream** from the zstd decoder into the set builders; never materialise a `Vec<String>` of every entry on the load path.
Measure before/after with the opt-in harnesses when touching any of the above:
```bash
cargo test -p meow-rules --test footprint_test --release -- --ignored --nocapture
cargo test -p meow-tunnel --test rule_ir_synthetic_footprint --release -- --ignored --nocapture
```
### Benchmark baselines (docs/benchmarks/)
See [docs/benchmarks/index.md](docs/benchmarks/index.md) for a collated table of M2 deltas and pointers to all baseline documents. The full M2 exit gauntlet results live in `docs/benchmarks/m2-exit-summary.md` (produced by QA at M2 close).
## Key Dependencies
- **Async runtime**: tokio (multi-threaded)
- **Proxy protocols**: `shadowsocks` crate for SS; TLS for Trojan/VLESS/VMess/HTTP/SOCKS5 goes through `meow_transport::tls::TlsLayer`
- **TLS/crypto backend**: BoringSSL is the single crypto library. `meow-transport`'s `tls` feature *is* BoringSSL (`boring`/`tokio-boring`; `boring-tls` is a no-op alias); health probes, the internal HTTP fetcher (`meow-config/src/internal_http.rs`, which replaced `reqwest`), DoT/DoH, and the vendored anytls client (via its `TlsConnect` hook) all reuse the same `TlsLayer`. Hysteria2's QUIC uses `quiche` with the `boringssl-boring-crate` feature, so it links the SAME vendored BoringSSL — no rustls, no second crypto lib. **`boring`, `tokio-boring` and `boring-sys` are bumped together** (workspace table, currently 5.2): quiche 0.30+ accepts `boring >=4.19,<6` and detects the major via `DEP_BORINGSSL_VERSION_MAJOR`, so a single `links = "boringssl"` copy is shared; a stale `boring-sys` pin is a second `links` package and cargo refuses to resolve. rustls survives only as a dev-dependency for the loopback TLS test servers. `boring-sys` needs cmake + a C++ compiler on every build
- **DNS**: `hickory-resolver`/`hickory-server`/`hickory-proto`
- **Web framework**: axum + tower
- **GeoIP**: `maxminddb`
- **Logbook storage**: `rusqlite` with `bundled` (SQLite compiled in) on every target but iOS/tvOS, which link the system libsqlite3 to spare the size-capped Network Extension (embedders pass `-lsqlite3`); optional behind meow-common's `logbook` feature; `minimal` leaves it out (ADR-0007)