# Telemt Tuning-Leitfaden: Middle-End und Upstreams Dieses Dokument beschreibt das aktuelle Laufzeitverhalten für Middle-End (ME) und Upstream-Routing basierend auf: - `src/config/types.rs` - `src/config/defaults.rs` - `src/config/load.rs` - `src/transport/upstream.rs` Die unten angegebenen `Default`-Werte sind Code-Defaults (bei fehlendem Schlüssel), nicht zwingend die Werte aus `config.full.toml`. ## Middle-End-Parameter ### 1) ME-Grundmodus, NAT und STUN | Parameter | Typ | Default | Einschränkungen / Validierung | Laufzeiteffekt | Beispiel | |---|---|---:|---|---|---| | `general.use_middle_proxy` | `bool` | `true` | keine | Aktiviert den ME-Transportmodus. Bei `false` wird Direct-Modus verwendet. | `use_middle_proxy = true` | | `general.proxy_secret_path` | `Option` | `"proxy-secret"` | Pfad kann `null` sein | Pfad zur Telegram-Infrastrukturdatei `proxy-secret`. | `proxy_secret_path = "proxy-secret"` | | `general.middle_proxy_nat_ip` | `Option` | `null` | gültige IP bei gesetztem Wert | Manueller Override der öffentlichen NAT-IP für ME-Adressmaterial. | `middle_proxy_nat_ip = "203.0.113.10"` | | `general.middle_proxy_nat_probe` | `bool` | `true` | wird auf `true` erzwungen, wenn `use_middle_proxy=true` | Aktiviert NAT-Probing für ME. | `middle_proxy_nat_probe = true` | | `general.stun_nat_probe_concurrency` | `usize` | `8` | muss `> 0` sein | Maximale parallele STUN-Probes während NAT-Erkennung. | `stun_nat_probe_concurrency = 16` | | `network.stun_use` | `bool` | `true` | keine | Globaler STUN-Schalter. Bei `false` wird STUN deaktiviert. | `stun_use = true` | | `network.stun_servers` | `Vec` | integrierter öffentlicher Pool | Duplikate/leer werden entfernt | Primäre STUN-Serverliste für NAT/Public-Endpoint-Erkennung. | `stun_servers = ["stun1.l.google.com:19302"]` | | `network.stun_tcp_fallback` | `bool` | `true` | keine | Aktiviert TCP-Fallback, wenn UDP-STUN blockiert ist. | `stun_tcp_fallback = true` | | `network.http_ip_detect_urls` | `Vec` | `ifconfig.me` + `api.ipify.org` | keine | HTTP-Fallback zur öffentlichen IPv4-Erkennung, falls STUN ausfällt. | `http_ip_detect_urls = ["https://api.ipify.org"]` | | `general.stun_iface_mismatch_ignore` | `bool` | `false` | keine | Reserviertes Feld in der aktuellen Revision (derzeit kein aktiver Runtime-Verbrauch). | `stun_iface_mismatch_ignore = false` | | `timeouts.me_one_retry` | `u8` | `12` | keine | Anzahl schneller Reconnect-Versuche bei Single-Endpoint-DC-Fällen. | `me_one_retry = 6` | | `timeouts.me_one_timeout_ms` | `u64` | `1200` | keine | Timeout pro schnellem Einzelversuch (ms). | `me_one_timeout_ms = 1500` | ### 2) Poolgröße, Keepalive und Reconnect-Policy | Parameter | Typ | Default | Einschränkungen / Validierung | Laufzeiteffekt | Beispiel | |---|---|---:|---|---|---| | `general.middle_proxy_pool_size` | `usize` | `8` | keine | Zielgröße des aktiven ME-Writer-Pools. | `middle_proxy_pool_size = 12` | | `general.middle_proxy_warm_standby` | `usize` | `16` | keine | Reserviertes Kompatibilitätsfeld in der aktuellen Revision (kein aktiver Runtime-Consumer). | `middle_proxy_warm_standby = 16` | | `general.me_keepalive_enabled` | `bool` | `true` | keine | Aktiviert periodischen ME-Keepalive/Ping-Traffic. | `me_keepalive_enabled = true` | | `general.me_keepalive_interval_secs` | `u64` | `25` | keine | Basisintervall für Keepalive (Sekunden). | `me_keepalive_interval_secs = 20` | | `general.me_keepalive_jitter_secs` | `u64` | `5` | keine | Keepalive-Jitter zur Vermeidung synchroner Peaks. | `me_keepalive_jitter_secs = 3` | | `general.me_keepalive_payload_random` | `bool` | `true` | keine | Randomisiert Keepalive-Payload-Bytes. | `me_keepalive_payload_random = true` | | `general.me_warmup_stagger_enabled` | `bool` | `true` | keine | Aktiviert gestaffeltes Warmup zusätzlicher ME-Verbindungen. | `me_warmup_stagger_enabled = true` | | `general.me_warmup_step_delay_ms` | `u64` | `500` | keine | Basisverzögerung zwischen Warmup-Schritten (ms). | `me_warmup_step_delay_ms = 300` | | `general.me_warmup_step_jitter_ms` | `u64` | `300` | keine | Zusätzlicher zufälliger Warmup-Jitter (ms). | `me_warmup_step_jitter_ms = 200` | | `general.me_reconnect_max_concurrent_per_dc` | `u32` | `8` | keine | Begrenzung paralleler Reconnect-Worker pro DC. | `me_reconnect_max_concurrent_per_dc = 12` | | `general.me_reconnect_backoff_base_ms` | `u64` | `500` | keine | Initiales Reconnect-Backoff (ms). | `me_reconnect_backoff_base_ms = 250` | | `general.me_reconnect_backoff_cap_ms` | `u64` | `30000` | keine | Maximales Reconnect-Backoff (ms). | `me_reconnect_backoff_cap_ms = 10000` | | `general.me_reconnect_fast_retry_count` | `u32` | `16` | keine | Budget für Sofort-Retries vor längerem Backoff. | `me_reconnect_fast_retry_count = 8` | ### 3) Reinit/Hardswap, Secret-Rotation und Degradation | Parameter | Typ | Default | Einschränkungen / Validierung | Laufzeiteffekt | Beispiel | |---|---|---:|---|---|---| | `general.hardswap` | `bool` | `true` | keine | Aktiviert generation-basierte Hardswap-Strategie für den ME-Pool. | `hardswap = true` | | `general.me_reinit_every_secs` | `u64` | `900` | muss `> 0` sein | Intervall für periodische ME-Reinitialisierung. | `me_reinit_every_secs = 600` | | `general.me_hardswap_warmup_delay_min_ms` | `u64` | `1000` | muss `<= me_hardswap_warmup_delay_max_ms` sein | Untere Grenze für Warmup-Dial-Abstände. | `me_hardswap_warmup_delay_min_ms = 500` | | `general.me_hardswap_warmup_delay_max_ms` | `u64` | `2000` | muss `> 0` sein | Obere Grenze für Warmup-Dial-Abstände. | `me_hardswap_warmup_delay_max_ms = 1200` | | `general.me_hardswap_warmup_extra_passes` | `u8` | `3` | Bereich `[0,10]` | Zusätzliche Warmup-Pässe nach dem Basispass. | `me_hardswap_warmup_extra_passes = 2` | | `general.me_hardswap_warmup_pass_backoff_base_ms` | `u64` | `500` | muss `> 0` sein | Basis-Backoff zwischen zusätzlichen Warmup-Pässen. | `me_hardswap_warmup_pass_backoff_base_ms = 400` | | `general.me_config_stable_snapshots` | `u8` | `2` | muss `> 0` sein | Anzahl identischer ME-Config-Snapshots vor Apply. | `me_config_stable_snapshots = 3` | | `general.me_config_apply_cooldown_secs` | `u64` | `300` | keine | Cooldown zwischen angewendeten ME-Map-Updates. | `me_config_apply_cooldown_secs = 120` | | `general.proxy_secret_stable_snapshots` | `u8` | `2` | muss `> 0` sein | Anzahl identischer Secret-Snapshots vor Rotation. | `proxy_secret_stable_snapshots = 3` | | `general.proxy_secret_rotate_runtime` | `bool` | `true` | keine | Aktiviert Runtime-Rotation des Proxy-Secrets. | `proxy_secret_rotate_runtime = true` | | `general.proxy_secret_len_max` | `usize` | `256` | Bereich `[32,4096]` | Obergrenze für akzeptierte Secret-Länge. | `proxy_secret_len_max = 512` | | `general.update_every` | `Option` | `300` | wenn gesetzt: `> 0`; bei `null`: Legacy-Min-Fallback | Einheitliches Refresh-Intervall für ME-Config + Secret-Updater. | `update_every = 300` | | `general.me_pool_drain_ttl_secs` | `u64` | `90` | keine | Zeitraum, in dem stale Writer noch als Fallback zulässig sind. | `me_pool_drain_ttl_secs = 120` | | `general.me_pool_min_fresh_ratio` | `f32` | `0.8` | Bereich `[0.0,1.0]` | Coverage-Schwelle vor Drain der alten Generation. | `me_pool_min_fresh_ratio = 0.9` | | `general.me_reinit_drain_timeout_secs` | `u64` | `120` | `0` = kein Force-Close; wenn `>0 && < TTL`, dann auf TTL angehoben | Force-Close-Timeout für draining stale Writer. | `me_reinit_drain_timeout_secs = 0` | | `general.auto_degradation_enabled` | `bool` | `true` | keine | Reserviertes Kompatibilitätsfeld in aktueller Revision (kein aktiver Runtime-Consumer). | `auto_degradation_enabled = true` | | `general.degradation_min_unavailable_dc_groups` | `u8` | `2` | keine | Reservierter Kompatibilitäts-Schwellenwert in aktueller Revision (kein aktiver Runtime-Consumer). | `degradation_min_unavailable_dc_groups = 2` | ## Deprecated / Legacy Parameter | Parameter | Status | Ersatz | Aktuelles Verhalten | Migrationshinweis | |---|---|---|---|---| | `general.middle_proxy_nat_stun` | Deprecated | `network.stun_servers` | Wird nur dann in `network.stun_servers` gemerged, wenn `network.stun_servers` nicht explizit gesetzt ist. | Wert nach `network.stun_servers` verschieben, Legacy-Key entfernen. | | `general.middle_proxy_nat_stun_servers` | Deprecated | `network.stun_servers` | Wird nur dann in `network.stun_servers` gemerged, wenn `network.stun_servers` nicht explizit gesetzt ist. | Werte nach `network.stun_servers` verschieben, Legacy-Key entfernen. | | `general.proxy_secret_auto_reload_secs` | Deprecated | `general.update_every` | Nur aktiv, wenn `update_every = null` (Legacy-Fallback). | `general.update_every` explizit setzen, Legacy-Key entfernen. | | `general.proxy_config_auto_reload_secs` | Deprecated | `general.update_every` | Nur aktiv, wenn `update_every = null` (Legacy-Fallback). | `general.update_every` explizit setzen, Legacy-Key entfernen. | ## Wie Upstreams konfiguriert werden ### Upstream-Schema | Feld | Gilt für | Typ | Pflicht | Default | Bedeutung | |---|---|---|---|---|---| | `[[upstreams]].type` | alle Upstreams | `"direct" \| "socks4" \| "socks5" \| "shadowsocks"` | ja | n/a | Upstream-Transporttyp. | | `[[upstreams]].weight` | alle Upstreams | `u16` | nein | `1` | Basisgewicht für weighted-random Auswahl. | | `[[upstreams]].enabled` | alle Upstreams | `bool` | nein | `true` | Deaktivierte Einträge werden beim Start ignoriert. | | `[[upstreams]].scopes` | alle Upstreams | `String` | nein | `""` | Komma-separierte Scope-Tags für Request-Routing. | | `interface` | `direct` | `Option` | nein | `null` | Interface-Name (z. B. `eth0`) oder lokale Literal-IP. | | `bind_addresses` | `direct` | `Option>` | nein | `null` | Explizite Source-IP-Kandidaten (strikter Vorrang vor `interface`). | | `address` | `socks4` | `String` | ja | n/a | SOCKS4-Server (`ip:port` oder `host:port`). | | `interface` | `socks4` | `Option` | nein | `null` | Wird nur genutzt, wenn `address` als `ip:port` angegeben ist. | | `user_id` | `socks4` | `Option` | nein | `null` | SOCKS4 User-ID für CONNECT. | | `address` | `socks5` | `String` | ja | n/a | SOCKS5-Server (`ip:port` oder `host:port`). | | `interface` | `socks5` | `Option` | nein | `null` | Wird nur genutzt, wenn `address` als `ip:port` angegeben ist. | | `username` | `socks5` | `Option` | nein | `null` | SOCKS5 Benutzername. | | `password` | `socks5` | `Option` | nein | `null` | SOCKS5 Passwort. | | `url` | `shadowsocks` | `String` | ja | n/a | Shadowsocks-SIP002-URL (`ss://...`). In Runtime-APIs wird nur `host:port` offengelegt. | | `interface` | `shadowsocks` | `Option` | nein | `null` | Optionales ausgehendes Bind-Interface oder lokale Literal-IP. | ### Runtime-Regeln (wichtig) 1. Wenn `[[upstreams]]` fehlt, injiziert der Loader einen Default-`direct`-Upstream. 2. Scope-Filterung basiert auf exaktem Token-Match: - mit Request-Scope -> nur Einträge, deren `scopes` genau dieses Token enthält; - ohne Request-Scope -> nur Einträge mit leerem `scopes`. 3. Unter healthy Upstreams erfolgt die Auswahl per weighted random: `weight * latency_factor`. 4. Gibt es im gefilterten Set keinen healthy Upstream, wird zufällig aus dem gefilterten Set gewählt. 5. `direct`-Bind-Auflösung: - zuerst `bind_addresses` (nur gleiche IP-Familie wie Target); - bei `interface` (Name) + `bind_addresses` wird jede Candidate-IP gegen Interface-Adressen validiert; - ungültige Kandidaten werden mit `WARN` verworfen; - bleiben keine gültigen Kandidaten übrig, erfolgt unbound direct connect (`bind_ip=None`); - wenn `bind_addresses` nicht passt, wird `interface` verwendet (Literal-IP oder Interface-Primäradresse). 6. Für `socks4/socks5` mit Hostname-`address` ist Interface-Binding nicht unterstützt und wird mit Warnung ignoriert. 7. Runtime DNS Overrides werden für Hostname-Auflösung bei Upstream-Verbindungen genutzt. 8. Im ME-Modus wird der gewählte Upstream auch für den ME-TCP-Dial-Pfad verwendet. 9. Im ME-Modus ist bei `direct` mit bind/interface die STUN-Reflection bind-aware für KDF-Adressmaterial. 10. Im ME-Modus werden bei SOCKS-Upstream `BND.ADDR/BND.PORT` für KDF verwendet, wenn gültig/öffentlich und gleiche IP-Familie. 11. `shadowsocks`-Upstreams erfordern `general.use_middle_proxy = false`. Mit aktiviertem ME-Modus schlägt das Laden der Config sofort fehl. ## Upstream-Konfigurationsbeispiele ### Beispiel 1: Minimaler direct Upstream ```toml [[upstreams]] type = "direct" weight = 1 enabled = true ``` ### Beispiel 2: direct mit Interface + expliziten bind IPs ```toml [[upstreams]] type = "direct" interface = "eth0" bind_addresses = ["192.168.1.100", "192.168.1.101"] weight = 3 enabled = true ``` ### Beispiel 3: SOCKS5 Upstream mit Authentifizierung ```toml [[upstreams]] type = "socks5" address = "198.51.100.30:1080" username = "proxy-user" password = "proxy-pass" weight = 2 enabled = true ``` ### Beispiel 4: Shadowsocks-Upstream ```toml [general] use_middle_proxy = false [[upstreams]] type = "shadowsocks" url = "ss://2022-blake3-aes-256-gcm:BASE64_KEY@198.51.100.50:8388" weight = 2 enabled = true ``` ### Beispiel 5: Gemischte Upstreams mit Scopes ```toml [[upstreams]] type = "direct" weight = 5 enabled = true scopes = "" [[upstreams]] type = "socks5" address = "203.0.113.40:1080" username = "edge" password = "edgepass" weight = 3 enabled = true scopes = "premium,me" ``` ### Beispiel 5: ME-orientiertes Tuning-Profil ```toml [general] use_middle_proxy = true proxy_secret_path = "proxy-secret" middle_proxy_nat_probe = true stun_nat_probe_concurrency = 16 middle_proxy_pool_size = 12 me_keepalive_enabled = true me_keepalive_interval_secs = 20 me_keepalive_jitter_secs = 4 me_reconnect_max_concurrent_per_dc = 12 me_reconnect_backoff_base_ms = 300 me_reconnect_backoff_cap_ms = 10000 me_reconnect_fast_retry_count = 10 hardswap = true me_reinit_every_secs = 600 me_hardswap_warmup_delay_min_ms = 500 me_hardswap_warmup_delay_max_ms = 1200 me_hardswap_warmup_extra_passes = 2 me_hardswap_warmup_pass_backoff_base_ms = 400 me_config_stable_snapshots = 3 me_config_apply_cooldown_secs = 120 proxy_secret_stable_snapshots = 3 proxy_secret_rotate_runtime = true proxy_secret_len_max = 512 update_every = 300 me_pool_drain_ttl_secs = 120 me_pool_min_fresh_ratio = 0.9 me_reinit_drain_timeout_secs = 180 [timeouts] me_one_retry = 8 me_one_timeout_ms = 1200 [network] stun_use = true stun_tcp_fallback = true stun_servers = [ "stun1.l.google.com:19302", "stun2.l.google.com:19302" ] http_ip_detect_urls = [ "https://api.ipify.org", "https://ifconfig.me/ip" ] ```