MEHS configuration contract
Status: This document describes design guidance and proposed tuning, not a configuration schema. Some examples or recommendations below may describe behavior that is not implemented and are not accepted JSON keys. The implemented client and server schemas, strict unknown-field behavior, defaults, and evolution rules are defined only in the configuration reference.
1. Configuration lifecycle
- Applications pass configuration and secrets to the core once at startup.
- Configuration is immutable for the lifetime of that connection. Static changes require disconnect/reconnect.
IsHotChangeAvailablecontrols only live TCP↔QUIC transport migration; it does not allow editing other configuration fields.- Server policy has precedence. If it rejects or overrides a client setting, it returns the effective value and reason. The core applies the effective setting and emits a structured application event.
- Secrets must not appear in logs, crash reports, telemetry, or status events. Use protected configuration storage/OS secret storage when available.
2. Connection pools
connection_count is per carrier:
tcp_connection_count: 0–32 TCP-carried data connections.udp_connection_count: 0–32 UDP/QUIC-carried data connections.- Maximum steady-state data connections: 64.
- One temporary control/configuration connection may coexist during startup, so the maximum transient count is 65.
- Data profiles:
mehs-data/1(default),xhttp,trusttunnel,notmehs, over TLS/TCP (HTTP/2) or QUIC (HTTP/3). Per-app routing is configured underapps(bypassoronly); see the configuration reference. - Zero disables that pool. Auto mode with both pools disabled is invalid.
- Recommended default: one TCP and one UDP/QUIC candidate (2 data connections total), not 32 in each pool.
- The server may cap either pool independently.
If the public configuration retains a single connection_count field for compatibility, define it as a per-carrier limit and document this clearly; the preferred schema uses separate tcp_connection_count and udp_connection_count fields to avoid ambiguity.
3. Recommended defaults
| Field | Default | Meaning |
|---|---|---|
mode | auto | Select among server-allowed transports |
tcp_connection_count | 1 | Concurrent TCP-carried candidate/data connections |
udp_connection_count | 1 | Concurrent QUIC-carried candidate/data connections |
connect_timeout_seconds | 15 | Candidate connection setup timeout |
server_unreachable_seconds | 15 | If all allowed paths cannot reach the server for this duration, stop attempts and report terminal failure |
health_check_seconds | 30 | Trigger general reachability and authenticated MEHS path-health checks |
keepalive_seconds | 15 | Idle path keepalive interval; tune per platform/server policy |
migration_drain_timeout_seconds | 60 | Maximum old-path drain time; unacknowledged data must be retransmitted, not discarded |
migration_cooldown_seconds | 10 | Avoid repeated switches unless the active path fails |
selection_improvement_percent | 15 | Minimum sustained improvement to switch from a healthy path |
selection_windows_required | 2 | Number of consecutive windows that must confirm improvement |
rtt_probe_samples | 5 | Minimum RTT samples per candidate |
throughput_probe_samples | 3 | Minimum bounded throughput samples per candidate |
session_negotiation_ttl_seconds | 120 | Validity of temporary negotiation session ID |
transport_cache_ttl_seconds | 86400 | Transport-selection cache lifetime |
max_frame_payload_bytes | 65536 | Initial maximum MEHS frame payload |
max_reassembly_bytes_per_flow | 1048576 | Initial reassembly limit per flow |
max_unacked_bytes_per_direction | 8388608 | Initial retransmission-buffer limit per direction |
tls_version | TLS 1.3 | No downgrade to older TLS versions |
is_hot_change_available | true | Enables live TCP↔QUIC migration in auto mode |
All numeric values are initial engineering defaults. Server policy can lower resource/time limits; it must not raise client hard safety ceilings without an explicit protocol version/capability agreement.
4. Recommended profiles
These are starting points to benchmark, not guaranteed universal optima.
| Profile | Mode | TCP count | UDP/QUIC count | Health check | Keepalive | Drain |
|---|---|---|---|---|---|---|
| Balanced | auto | 1 | 1 | 30 s | 15 s | 60 s |
| Latency-sensitive | auto | 1 | 2 | 15–20 s | 10 s | 20–30 s |
| Bandwidth-focused | auto | 2 | 2 | 30 s | 15 s | 60 s |
| TCP-only | tcp_tls | 1 | 0 | 30 s | 15 s | n/a |
| QUIC-only | QUIC | 0 | 1 | 20–30 s | 15 s | n/a |
The latency-sensitive profile uses more than one UDP/QUIC candidate to compare paths only if the server/network can provide meaningfully distinct routes or connection conditions. Multiple connections to the same endpoint on the same route do not necessarily provide path diversity.
5. Selection and cache
- Evaluate RTT, jitter, throughput, and packet loss per connection.
- Weight packet loss and stability above peak throughput; use median RTT and robust jitter.
- Require sustained quality improvement before switching a healthy path; switch immediately when the active path fails and a healthy replacement is ready.
- Cache the selected policy for 24 hours keyed by a stable hash of static configuration, server identity/policy, credential identity (never the secret itself), protocol version, and transport availability.
- The cache skips the full startup benchmark only when the hash matches. Health checks still run; a path failure or detected network change permits re-evaluation.
- Do not store credentials or session IDs in the cache.
The current selector's version-1 score uses integer arithmetic: 50% packet loss (ppm, capped at 100%), 30% median RTT (capped at 1 s), 15% median absolute deviation of RTT (capped at 500 ms), and 5% throughput (capped at 100 MB/s, higher is better). It requires at least five RTT samples and three throughput samples, rejects unauthenticated/unpermitted candidates, uses a 15% sustained improvement across two windows to leave a healthy path, and applies a 10-second cooldown. An active-path failure bypasses hysteresis/cooldown. The client consumes these measurements: it probes each carrier with authenticated Probe frames (5 RTT probes and 3 throughput probes per window), ranks them with the score above, and applies the improvement/cooldown rules. The CLI therefore supports auto: the choice is cached per configuration for transport_cache_ttl_seconds, a standby link is kept on the other carrier, and migration is make-before-break.
6. Server policy resolution
Server policy may allow, deny, cap, or pin:
- implemented transport modes (
tcp_tls,quic) and TLS policy; - TCP and UDP/QUIC connection counts;
- probe rate and timeouts;
- frame/reassembly/retransmission-buffer limits.
For implemented mode and carrier-count negotiation, the server response contains the compatibility parameter plus path, requested value, effective value, and machine-readable reason_code. The client applies a pinned mode, verifies the effective pool before finalization, checks the finalized mode, and exposes corrections through its client API. Other settings are applied locally by the client.
7. Unsupported profiles
xhttp, trusttunnel, and notmehs carry MEHS frames in HTTP-shaped streams and are not interoperable with third-party servers. Unknown names fail closed; there is no profile fallback.
9. Client mode: proxy or TUN
client_mode selects how applications reach MEHS:
proxy(default): local SOCKS5/HTTP listeners.tun: a virtual interface plus a userspace network stack captures all traffic. Thetunobject hasname(defaultmehs0, max 15 chars),mtu(576-9000, default 1400),routes(CIDRs; empty means full tunnel0.0.0.0/1,128.0.0.0/1,::/1,8000::/1),exclude_routes(CIDRs kept off the tunnel, e.g. a LAN),manage_routes(default true; set false when the platform owns routing),block_quic(default true: UDP/443 is dropped so browsers fall back to TCP), andfd(an existing TUN file descriptor, e.g. AndroidVpnService; disables route management).
Control and data server addresses are automatically excluded from the tunnel. TUN requires root/administrator (Windows also needs wintun.dll beside the executable). The server must have IPv6 egress for IPv6 destinations to work; connections to private addresses are refused by the server. CLI flags (--mode, --tun-*) override the file.
8. Credential and secret handling
- Match Xray-style configuration conventions where useful, but publish an explicit MEHS schema and version. Do not silently accept the entire Xray configuration schema.
- Never log secrets, access tokens, private keys, or
session_id. - Use file permissions or platform secret stores and avoid command-line arguments for secrets where process listings can expose them.
- Server client allowlist entries should be revocable and should support credential rotation.